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