352 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			352 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * Divi Split Library.
 | 
						|
 *
 | 
						|
 * @package Builder
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * Core class used to Split library item.
 | 
						|
 */
 | 
						|
class ET_Builder_Split_Library {
 | 
						|
	/**
 | 
						|
	 * Instance of `ET_Builder_Split_Library`.
 | 
						|
	 *
 | 
						|
	 * @var ET_Builder_Split_Library
 | 
						|
	 */
 | 
						|
	private static $_instance;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get the class instance.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 *
 | 
						|
	 * @return ET_Builder_Split_Library
 | 
						|
	 */
 | 
						|
	public static function instance() {
 | 
						|
		if ( ! self::$_instance ) {
 | 
						|
			self::$_instance = new self();
 | 
						|
		}
 | 
						|
 | 
						|
		return self::$_instance;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * ET_Builder_Split_Library constructor.
 | 
						|
	 */
 | 
						|
	public function __construct() {
 | 
						|
		$this->_register_ajax_callbacks();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Registers the Split Library's AJAX callbacks.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 */
 | 
						|
	protected function _register_ajax_callbacks() {
 | 
						|
		add_action( 'wp_ajax_et_builder_split_library_item', array( $this, 'split_library_item' ) );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Split library item based on split type
 | 
						|
	 */
 | 
						|
	public function split_library_item() {
 | 
						|
		et_core_security_check( 'edit_posts', 'et_builder_split_library_item', 'et_cloud_nonce' );
 | 
						|
 | 
						|
		$id         = isset( $_POST['id'] ) ? absint( $_POST['id'] ) : false;
 | 
						|
		$prefix     = isset( $_POST['itemName'] ) ? sanitize_text_field( $_POST['itemName'] ) : false;
 | 
						|
		$to_cloud   = isset( $_POST['cloud'] ) ? sanitize_text_field( $_POST['cloud'] ) : 'off';
 | 
						|
		$split_type = isset( $_POST['updateType'] ) ? sanitize_text_field( $_POST['updateType'] ) : false;
 | 
						|
		$origin     = isset( $_POST['actionOrigin'] ) ? sanitize_text_field( $_POST['actionOrigin'] ) : '';
 | 
						|
 | 
						|
		if ( ! $id || ! $split_type || ! $prefix ) {
 | 
						|
			wp_send_json_error();
 | 
						|
		}
 | 
						|
 | 
						|
		if ( ! in_array( $split_type, array( 'split_layout', 'split_section', 'split_row' ), true ) ) {
 | 
						|
			wp_send_json_error();
 | 
						|
		}
 | 
						|
 | 
						|
		$cloud_content = isset( $_POST['content'] ) ? $_POST['content'] : ''; // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['content'] is an array, it's value sanitization is done at the time of accessing value.
 | 
						|
 | 
						|
		if ( $cloud_content ) {
 | 
						|
			$item_content = wp_unslash( reset( $cloud_content['data'] ) );
 | 
						|
		} else {
 | 
						|
			$post         = get_post( $id );
 | 
						|
			$item_content = $post->post_content;
 | 
						|
		}
 | 
						|
 | 
						|
		switch ( $split_type ) {
 | 
						|
			case 'split_layout':
 | 
						|
				$pattern     = '/\[et_pb_section .+?]?.+?\[\/et_pb_section]/s';
 | 
						|
				$layout_type = 'section';
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'split_section':
 | 
						|
				$pattern     = '/\[et_pb_row(_inner)? .+?].+?\[\/et_pb_row(_inner)?]/s';
 | 
						|
				$layout_type = 'row';
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'split_row':
 | 
						|
				$pattern     = '/\[(et_pb_(?!section|row|column).+?)\s.+?]?\[\/\1]/s';
 | 
						|
				$layout_type = 'module';
 | 
						|
				break;
 | 
						|
		}
 | 
						|
 | 
						|
		// Get the intented content array based on split type pattern.
 | 
						|
		preg_match_all( $pattern, $item_content, $matches );
 | 
						|
 | 
						|
		$args = array(
 | 
						|
			'split_type'           => $split_type,
 | 
						|
			'layout_type'          => $layout_type,
 | 
						|
			'layout_selected_cats' => isset( $_POST['itemCategories'] ) ? array_map( 'sanitize_text_field', $_POST['itemCategories'] ) : array(),
 | 
						|
			'layout_selected_tags' => isset( $_POST['itemTags'] ) ? array_map( 'sanitize_text_field', $_POST['itemTags'] ) : array(),
 | 
						|
			'built_for_post_type'  => 'page',
 | 
						|
			'layout_new_cat'       => isset( $_POST['newCategoryName'] ) ? sanitize_text_field( $_POST['newCategoryName'] ) : '',
 | 
						|
			'layout_new_tag'       => isset( $_POST['newTagName'] ) ? sanitize_text_field( $_POST['newTagName'] ) : '',
 | 
						|
			'columns_layout'       => '0',
 | 
						|
			'module_type'          => 'et_pb_unknown',
 | 
						|
			'layout_scope'         => isset( $_POST['global'] ) && ( 'on' === $_POST['global'] ) ? 'global' : 'not_global',
 | 
						|
			'module_width'         => 'regular',
 | 
						|
		);
 | 
						|
 | 
						|
		$layouts   = array();
 | 
						|
		$processed = false;
 | 
						|
 | 
						|
		foreach ( $matches[0] as $key => $content ) {
 | 
						|
			$title = $prefix;
 | 
						|
 | 
						|
			if ( 'split_row' === $split_type && 'save_modal' === $origin ) {
 | 
						|
				$module_name = explode( ' ', $content )[0];
 | 
						|
				$module_name = str_replace( '[et_pb_', '', $module_name );
 | 
						|
				$module_name = ucfirst( str_replace( '_', ' ', $module_name ) );
 | 
						|
				$title       = str_replace( '%module_type%', $module_name, $prefix );
 | 
						|
			}
 | 
						|
 | 
						|
			$args['layout_name'] = $title . ' ' . ( ++$key );
 | 
						|
 | 
						|
			$content = $this->_get_content_with_type( $content, $layout_type );
 | 
						|
 | 
						|
			if ( 'on' === $to_cloud ) {
 | 
						|
				if ( $cloud_content ) {
 | 
						|
					/* From cloud to cloud */
 | 
						|
					$layouts[] = $this->_get_cloud_to_cloud_formatted_data( $cloud_content, $content, $args );
 | 
						|
				} else {
 | 
						|
					/* From local to cloud */
 | 
						|
					$layouts[] = $this->_get_local_to_cloud_formatted_data( $content, $args );
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				if ( $cloud_content ) {
 | 
						|
					/* From cloud to local */
 | 
						|
					$cloud_content['data']['1'] = $content;
 | 
						|
 | 
						|
					$layouts[] = $this->_get_cloud_to_local_formatted_data( $cloud_content, $content, $args );
 | 
						|
 | 
						|
					// We only need to insert these data once into the database.
 | 
						|
					unset( $cloud_content['presets'] );
 | 
						|
					unset( $cloud_content['global_colors'] );
 | 
						|
					unset( $cloud_content['images'] );
 | 
						|
					unset( $cloud_content['thumbnails'] );
 | 
						|
				} else {
 | 
						|
					/* From local to Local */
 | 
						|
					$args['layout_content']       = $content;
 | 
						|
					$args['layout_selected_cats'] = is_array( $args['layout_selected_cats'] ) ? implode( ',', $args['layout_selected_cats'] ) : '';
 | 
						|
					$args['layout_selected_tags'] = is_array( $args['layout_selected_tags'] ) ? implode( ',', $args['layout_selected_tags'] ) : '';
 | 
						|
 | 
						|
					$new_saved = json_decode( et_pb_submit_layout( $args ) );
 | 
						|
 | 
						|
					// Only need to process once because all the split item's taxonomies are the same.
 | 
						|
					if ( ! $processed ) {
 | 
						|
						$layouts[] = [
 | 
						|
							'newId'         => $new_saved->post_id,
 | 
						|
							'categories'    => $args['layout_selected_cats'],
 | 
						|
							'tags'          => $args['layout_selected_tags'],
 | 
						|
							'updated_terms' => $this->_get_all_updated_terms(),
 | 
						|
						];
 | 
						|
						$processed = true;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		wp_send_json_success( $layouts );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get content with type.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 *
 | 
						|
	 * @param string $content Content to be processed.
 | 
						|
	 * @param string $type    Type of the content.
 | 
						|
	 */
 | 
						|
	private function _get_content_with_type( $content, $type ) {
 | 
						|
		$pattern = '/^(\[\w+\s)/';
 | 
						|
		$replace = '$0template_type="' . $type . '" '; // e.g. [et_pb_row template_type="row" ...].
 | 
						|
 | 
						|
		return preg_replace( $pattern, $replace, $content );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get formatted data for cloud item split to cloud.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 *
 | 
						|
	 * @param array  $cloud_content Cloud Item data.
 | 
						|
	 * @param string $content       Shortcode after split cloud item.
 | 
						|
	 * @param array  $assoc_data    Related data after split cloud item.
 | 
						|
	 */
 | 
						|
	private function _get_cloud_to_cloud_formatted_data( $cloud_content, $content, $assoc_data ) {
 | 
						|
		$data = $this->_get_common_cloud_formatted_data( $content, $assoc_data );
 | 
						|
 | 
						|
		$images        = array();
 | 
						|
		$presets       = array();
 | 
						|
		$global_colors = array();
 | 
						|
 | 
						|
		if ( ! empty( $cloud_content['images'] ) ) {
 | 
						|
			foreach ( $cloud_content['images'] as $url => $img ) {
 | 
						|
				if ( str_contains( $content, $url ) ) {
 | 
						|
					$images[ $url ] = $img;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if ( ! empty( $cloud_content['presets'] ) ) {
 | 
						|
			foreach ( $cloud_content['presets'] as $module => $preset ) {
 | 
						|
				if ( str_contains( $content, $module ) ) {
 | 
						|
					$presets[ $module ] = $preset;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if ( ! empty( $cloud_content['global_colors'] ) ) {
 | 
						|
			foreach ( $cloud_content['global_colors'] as $key => $global_color ) {
 | 
						|
				if ( str_contains( $content, $global_color[0] ) ) {
 | 
						|
					$global_colors[ $key ] = $global_color;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		$data['images']        = $images;
 | 
						|
		$data['presets']       = $presets;
 | 
						|
		$data['global_colors'] = $global_colors;
 | 
						|
 | 
						|
		return $data;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get formatted data for local item split to cloud.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 *
 | 
						|
	 * @param string $content    Shortcode after split cloud item.
 | 
						|
	 * @param array  $assoc_data Related data after split cloud item.
 | 
						|
	 *
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	private function _get_local_to_cloud_formatted_data( $content, $assoc_data ) {
 | 
						|
		return $this->_get_common_cloud_formatted_data( $content, $assoc_data );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get formatted data for cloud item split to local.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 *
 | 
						|
	 * @param array  $cloud_content Cloud Item data.
 | 
						|
	 * @param string $content       Shortcode after split cloud item.
 | 
						|
	 * @param array  $assoc_data    Related data after split cloud item.
 | 
						|
	 *
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	private function _get_cloud_to_local_formatted_data( $cloud_content, $content, $assoc_data ) {
 | 
						|
		return array(
 | 
						|
			'itemName'        => $assoc_data['layout_name'],
 | 
						|
			'itemCategories'  => $assoc_data['layout_selected_cats'],
 | 
						|
			'itemTags'        => $assoc_data['layout_selected_tags'],
 | 
						|
			'newCategoryName' => $assoc_data['layout_new_cat'],
 | 
						|
			'newTagName'      => $assoc_data['layout_new_tag'],
 | 
						|
			'cloud'           => 'off',
 | 
						|
			'global'          => $assoc_data['layout_scope'],
 | 
						|
			'layoutType'      => $assoc_data['layout_type'],
 | 
						|
			'updateType'      => $assoc_data['split_type'],
 | 
						|
			'content'         => $cloud_content,
 | 
						|
			'shortcode'       => wp_json_encode( $content ),
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get common formatted data for cloud item.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 *
 | 
						|
	 * @param string $content    Shortcode after split cloud item.
 | 
						|
	 * @param array  $assoc_data Related data after split cloud item.
 | 
						|
	 *
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	private function _get_common_cloud_formatted_data( $content, $assoc_data ) {
 | 
						|
		$data = array(
 | 
						|
			'post_title'   => $assoc_data['layout_name'],
 | 
						|
			'post_content' => $content,
 | 
						|
			'terms'        => array(
 | 
						|
				array(
 | 
						|
					'name'     => $assoc_data['layout_type'],
 | 
						|
					'slug'     => $assoc_data['layout_type'],
 | 
						|
					'taxonomy' => 'layout_type',
 | 
						|
				),
 | 
						|
			),
 | 
						|
		);
 | 
						|
 | 
						|
		foreach ( $assoc_data['layout_selected_cats'] as $category ) {
 | 
						|
			$data['terms'][] = array(
 | 
						|
				'name'     => $category,
 | 
						|
				'slug'     => $category,
 | 
						|
				'taxonomy' => 'layout_category',
 | 
						|
			);
 | 
						|
		}
 | 
						|
 | 
						|
		foreach ( $assoc_data['layout_selected_tags'] as $tag ) {
 | 
						|
			$data['terms'][] = array(
 | 
						|
				'name'     => $tag,
 | 
						|
				'slug'     => $tag,
 | 
						|
				'taxonomy' => 'layout_tag',
 | 
						|
			);
 | 
						|
		}
 | 
						|
 | 
						|
		return $data;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get all the updated terms.
 | 
						|
	 *
 | 
						|
	 * @since 4.20.3
 | 
						|
	 *
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	private function _get_all_updated_terms() {
 | 
						|
		$updated_terms = array();
 | 
						|
 | 
						|
		foreach ( [ 'layout_category', 'layout_tag' ] as $taxonomy ) {
 | 
						|
			$raw_terms_array   = get_terms( $taxonomy, array( 'hide_empty' => false ) );
 | 
						|
			$clean_terms_array = array();
 | 
						|
 | 
						|
			if ( is_array( $raw_terms_array ) && ! empty( $raw_terms_array ) ) {
 | 
						|
				foreach ( $raw_terms_array as $term ) {
 | 
						|
					$clean_terms_array[] = array(
 | 
						|
						'name' => html_entity_decode( $term->name ),
 | 
						|
						'id'   => $term->term_id,
 | 
						|
						'slug' => $term->slug,
 | 
						|
					);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			$updated_terms[ $taxonomy ] = $clean_terms_array;
 | 
						|
		}
 | 
						|
 | 
						|
		return $updated_terms;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
ET_Builder_Split_Library::instance();
 |