You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
10 KiB
PHTML

<?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();