Upgarded to 4.17.4

This commit is contained in:
2022-06-23 13:17:18 +01:00
parent 80f1e87db9
commit a04fb0c7af
404 changed files with 54683 additions and 4417 deletions

View File

@ -85,7 +85,9 @@ class ET_Builder_Library {
$this->_register_hooks();
$this->_register_ajax_callbacks();
self::$_i18n = require ET_BUILDER_DIR . '/frontend-builder/i18n/library.php';
$root_directory = defined( 'ET_BUILDER_PLUGIN_ACTIVE' ) ? ET_BUILDER_PLUGIN_DIR : get_template_directory();
self::$_i18n = require $root_directory . '/cloud/i18n/library.php';
self::$_standard_post_types = self::_standard_post_types();
}
@ -139,7 +141,7 @@ class ET_Builder_Library {
*/
protected static function _get_image_size_name( $type ) {
$names = array(
'thumbnail' => 'et-pb-portfolio-image',
'thumbnail' => 'full',
'thumbnail_small' => 'et-pb-portfolio-image',
'screenshot' => 'et-pb-portfolio-image-single',
);
@ -206,11 +208,11 @@ class ET_Builder_Library {
'id' => $category->term_id,
'name' => $category_name,
'slug' => $category->slug,
'layouts' => array(),
'items' => array(),
);
}
$layout_categories[ $category->term_id ]['layouts'][] = $index;
$layout_categories[ $category->term_id ]['items'][] = $index;
$layout->categories[] = $category_name;
$layout->category_ids[] = $category->term_id;
@ -231,6 +233,57 @@ class ET_Builder_Library {
}
}
/**
* Processes layout tags for inclusion in the library UI layouts data.
*
* @since 3.0.99
*
* @param WP_POST $post Unprocessed layout.
* @param object $layout Currently processing layout.
* @param int $index The layout's index position.
* @param array[] $layout_tags Processed layouts.
*/
protected function _process_layout_tags( $post, $layout, $index, &$layout_tags ) {
$terms = wp_get_post_terms( $post->ID, $this->layout_tags->name );
if ( ! $terms ) {
return;
}
foreach ( $terms as $tag ) {
$tag_name = self::__( html_entity_decode( $tag->name ), '@tags' );
$tag_name = et_core_intentionally_unescaped( $tag_name, 'react_jsx' );
if ( ! isset( $layout_tags[ $tag->term_id ] ) ) {
$layout_tags[ $tag->term_id ] = array(
'id' => $tag->term_id,
'name' => $tag_name,
'slug' => $tag->slug,
'items' => array(),
);
}
$layout_tags[ $tag->term_id ]['items'][] = $index;
$layout->tags[] = $tag_name;
$layout->tag_ids[] = $tag->term_id;
if ( ! isset( $layout->tag_slug ) ) {
$layout->tag_slug = $tag->slug;
}
$id = get_post_meta( $post->ID, self::$_primary_category_key, true );
if ( $id ) {
// $id is a string, $category->term_id is an int.
if ( $id === $tag->term_id ) {
// This is the primary category (used in the layout URL).
$layout->tag_slug = $tag->slug;
}
}
}
}
/**
* Processes layout packs for inclusion in the library UI layouts data.
*
@ -257,7 +310,7 @@ class ET_Builder_Library {
'name' => $pack_name,
'slug' => $pack->slug,
'date' => $layout->date,
'layouts' => array(),
'items' => array(),
);
}
@ -269,11 +322,14 @@ class ET_Builder_Library {
$layout_packs[ $pack->term_id ]['landing_index'] = $index;
}
$layout_packs[ $pack->term_id ]['layouts'][] = $index;
$layout_packs[ $pack->term_id ]['items'][] = $index;
$layout_packs[ $pack->term_id ]['categories'] = $layout->categories;
$layout_packs[ $pack->term_id ]['category_ids'] = $layout->category_ids;
$layout_packs[ $pack->term_id ]['tags'] = $layout->tags;
$layout_packs[ $pack->term_id ]['tag_ids'] = $layout->tag_ids;
$layout->pack = $pack_name;
$layout->pack_id = $pack->term_id;
}
@ -286,7 +342,15 @@ class ET_Builder_Library {
protected function _register_ajax_callbacks() {
add_action( 'wp_ajax_et_builder_library_get_layouts_data', array( $this, 'wp_ajax_et_builder_library_get_layouts_data' ) );
add_action( 'wp_ajax_et_builder_library_get_layout', array( $this, 'wp_ajax_et_builder_library_get_layout' ) );
add_action( 'wp_ajax_et_builder_library_update_terms', array( $this, 'wp_ajax_et_builder_library_update_terms' ) );
add_action( 'wp_ajax_et_builder_library_save_temp_layout', array( $this, 'wp_ajax_et_builder_library_save_temp_layout' ) );
add_action( 'wp_ajax_et_builder_library_update_item', array( $this, 'wp_ajax_et_builder_library_update_item' ) );
add_action( 'wp_ajax_et_builder_library_upload_thumbnail', array( $this, 'wp_ajax_et_builder_library_upload_thumbnail' ) );
add_action( 'wp_ajax_et_builder_library_update_account', array( $this, 'wp_ajax_et_builder_library_update_account' ) );
add_action( 'wp_ajax_et_builder_library_remove_temp_layout', array( $this, 'wp_ajax_et_builder_library_remove_temp_layout' ) );
add_action( 'wp_ajax_et_builder_toggle_cloud_status', array( $this, 'wp_ajax_et_builder_toggle_cloud_status' ) );
add_action( 'wp_ajax_et_builder_library_get_cloud_token', array( $this, 'wp_ajax_et_builder_library_get_cloud_token' ) );
add_action( 'wp_ajax_et_builder_library_clear_temp_presets', array( $this, 'wp_ajax_et_builder_library_clear_temp_presets' ) );
}
/**
@ -306,11 +370,12 @@ class ET_Builder_Library {
$this->layouts = ET_Builder_Post_Type_Layout::instance();
$this->layout_categories = ET_Builder_Post_Taxonomy_LayoutCategory::instance();
$this->layout_tags = ET_Builder_Post_Taxonomy_LayoutTag::instance();
$this->layout_packs = ET_Builder_Post_Taxonomy_LayoutPack::instance();
$this->layout_types = ET_Builder_Post_Taxonomy_LayoutType::instance();
$this->layout_width = ET_Builder_Post_Taxonomy_LayoutWidth::instance();
ET_Builder_Post_Taxonomy_LayoutScope::instance();
ET_Builder_Post_Taxonomy_LayoutWidth::instance();
// We manually call register_all() now to ensure the CPT and taxonomies are registered
// at exactly the same point during the request that they were in prior releases.
@ -327,6 +392,10 @@ class ET_Builder_Library {
public function _register_hooks() {
add_action( 'admin_init', 'ET_Builder_Library::update_old_layouts' );
add_action( 'admin_enqueue_scripts', array( $this, 'wp_hook_admin_enqueue_scripts' ), 4 );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'wp_footer', array( $this, 'render_session_expired_modal' ) );
add_filter( 'et_theme_builder_template_settings_options_term_pages', array( $this, 'tb_remove_unsupported_taxonomies' ), 10, 2 );
}
/**
@ -343,12 +412,13 @@ class ET_Builder_Library {
* @type int[] $packs Layout pack ids sorted alphabetically by pack name.
* }
*/
protected static function _sort_builder_library_data( $categories, $packs ) {
protected static function _sort_builder_library_data( $categories, $packs, $tags ) {
$categories = array_values( $categories );
$packs = array_values( $packs );
$tags = array_values( $tags );
$sorted = array();
foreach ( array( 'categories', 'packs' ) as $taxonomy ) {
foreach ( array( 'categories', 'packs', 'tags' ) as $taxonomy ) {
$sorted[ $taxonomy ] = array();
$$taxonomy = self::$_->array_sort_by( $$taxonomy, 'slug' );
@ -384,9 +454,10 @@ class ET_Builder_Library {
*
* @return array $data
*/
public function builder_library_layouts_data() {
public function builder_library_layouts_data( $library_type = 'layout' ) {
$layout_categories = array();
$layout_packs = array();
$layout_tags = array();
$layouts = array();
$index = 0;
@ -399,7 +470,7 @@ class ET_Builder_Library {
$posts = $this->layouts
->query()
->not()->with_meta( '_et_pb_built_for_post_type', $extra_layout_post_type )
->run();
->run( array( 'post_status' => array( 'publish', 'trash' ) ) );
$posts = self::$_->array_sort_by( is_array( $posts ) ? $posts : array( $posts ), 'post_name' );
@ -419,11 +490,22 @@ class ET_Builder_Library {
$layout->type = $types[0]->name;
// For the initial release of new library UI, only 'layouts' are needed.
if ( 'layout' !== $layout->type ) {
if ( $library_type !== $layout->type ) {
continue;
}
$width_values = wp_get_post_terms( $layout->id, $this->layout_width->name, array( 'fields' => 'names' ) );
$layout->width = ! empty( $width_values ) ? $width_values[0] : 'regular';
$layout->row_layout = get_post_meta( $post->ID, '_et_pb_row_layout', true );
$layout->subtype = get_post_meta( $post->ID, '_et_pb_module_type', true );
if ( '' !== $layout->subtype ) {
$module = ET_Builder_Element::get_module( $layout->subtype );
$layout->subtitle = ! empty( $module->name ) ? $module->name : $layout->type;
}
$title = html_entity_decode( $post->post_title );
$short_name = get_post_meta( $post->ID, '_et_builder_library_short_name', true );
@ -458,14 +540,18 @@ class ET_Builder_Library {
$layout->thumbnail_small = esc_url( get_the_post_thumbnail_url( $post->ID, $thumbnail_small ) );
$layout->screenshot = esc_url( get_the_post_thumbnail_url( $post->ID, $screenshot ) );
$layout->is_global = $this->layouts->is_global( $layout->id );
$layout->is_favorite = $this->layouts->is_favorite( $layout->id );
$layout->is_landing = ! empty( $post->post_excerpt );
$layout->description = '';
$layout->isTrash = 'trash' === $post->post_status; // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- This is valid format for the property in the Cloud App.
$layout->categories = array();
$layout->category_ids = array();
$layout->is_global = $this->layouts->is_global( $layout->id );
$layout->is_landing = ! empty( $post->post_excerpt );
$layout->description = '';
$layout->tags = array();
$layout->tag_ids = array();
$this->_process_layout_categories( $post, $layout, $index, $layout_categories );
$this->_process_layout_tags( $post, $layout, $index, $layout_tags );
$this->_process_layout_packs( $post, $layout, $index, $layout_packs );
wp_reset_postdata();
@ -550,10 +636,10 @@ class ET_Builder_Library {
* }
*/
$saved_layouts_data = array(
'categories' => $layout_categories,
'categories' => $this->_get_processed_terms( 'layout_category' ),
'packs' => $layout_packs,
'layouts' => $layouts,
'sorted' => self::_sort_builder_library_data( $layout_categories, $layout_packs ),
'tags' => $this->_get_processed_terms( 'layout_tag' ),
'items' => $layouts,
);
$saved_layouts_data = apply_filters( 'et_builder_library_saved_layouts', $saved_layouts_data );
@ -585,6 +671,35 @@ class ET_Builder_Library {
);
}
/**
* Gets the terms list and processes it into desired format.
*
* @since 4.17.0
*
* @param string $term_name Term Name.
*
* @return array $terms_by_id
*/
protected function _get_processed_terms( $term_name ) {
$terms = get_terms( $term_name, array( 'hide_empty' => false ) );
$terms_by_id = array();
if ( is_wp_error( $terms ) || empty( $terms ) ) {
return array();
}
foreach ( $terms as $term ) {
$term_id = $term->term_id;
$terms_by_id[ $term_id ]['id'] = $term_id;
$terms_by_id[ $term_id ]['name'] = $term->name;
$terms_by_id[ $term_id ]['slug'] = $term->slug;
$terms_by_id[ $term_id ]['count'] = $term->count;
}
return $terms_by_id;
}
/**
* Filters data for the 'Your Existing Pages' tab.
*
@ -667,9 +782,8 @@ class ET_Builder_Library {
$layouts = array();
$index = 0;
$thumbnail = self::_get_image_size_name( 'thumbnail' );
$thumbnail = self::_get_image_size_name( 'screenshot' );
$thumbnail_small = self::_get_image_size_name( 'thumbnail_small' );
$screenshot = self::_get_image_size_name( 'screenshot' );
/**
* Array of post types that should be listed as categories under "Existing Pages".
@ -700,8 +814,18 @@ class ET_Builder_Library {
// Keep track of slugs in case there are duplicates.
$seen = array();
// List of post types which should be excluded from the Pages tab.
$unsupported_post_types = array(
ET_BUILDER_LAYOUT_POST_TYPE,
ET_THEME_BUILDER_TEMPLATE_POST_TYPE,
ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE,
ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE,
ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE,
ET_THEME_BUILDER_THEME_BUILDER_POST_TYPE,
);
foreach ( $post_types as $post_type ) {
if ( ET_BUILDER_LAYOUT_POST_TYPE === $post_type ) {
if ( in_array( $post_type, $unsupported_post_types, true ) ) {
continue;
}
@ -789,7 +913,6 @@ class ET_Builder_Library {
$layout->thumbnail = esc_url( get_the_post_thumbnail_url( $post->ID, $thumbnail ) );
$layout->thumbnail_small = esc_url( get_the_post_thumbnail_url( $post->ID, $thumbnail_small ) );
$layout->screenshot = esc_url( get_the_post_thumbnail_url( $post->ID, $screenshot ) );
$layout->categories = array();
$layout->category_ids = array( $category_id );
@ -805,7 +928,7 @@ class ET_Builder_Library {
$layout->status = isset( $post_status_object->label ) ? $post_status_object->label : $post->post_status;
$layouts[ $layout_index++ ] = $layout;
$layouts[] = $layout;
$index++;
}
@ -823,7 +946,7 @@ class ET_Builder_Library {
return array(
'categories' => $categories,
'packs' => $packs,
'layouts' => $layouts,
'items' => $layouts,
'options' => array(
'content' => array(
'title' => array(
@ -833,6 +956,7 @@ class ET_Builder_Library {
),
'sidebar' => array(
'title' => et_core_intentionally_unescaped( self::__( 'Find A Page' ), 'react_jsx' ),
'filterTitle' => et_core_intentionally_unescaped( self::__( 'Post Types' ), 'react_jsx' ),
),
'list' => array(
'columns' => array(
@ -1008,7 +1132,10 @@ class ET_Builder_Library {
public function wp_ajax_et_builder_library_get_layout() {
et_core_security_check( 'edit_posts', 'et_builder_library_get_layout', 'nonce' );
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
$id = isset( $_POST['id'] ) ? (int) sanitize_text_field( $_POST['id'] ) : 0;
$content_type = isset( $_POST['contentType'] ) ? (string) sanitize_text_field( $_POST['contentType'] ) : 'processed';
$library_type = isset( $_POST['libraryType'] ) ? (string) sanitize_text_field( $_POST['libraryType'] ) : 'layout';
$built_for = isset( $_POST['postType'] ) ? (string) sanitize_text_field( $_POST['postType'] ) : 'page';
if ( empty( $id ) ) {
wp_send_json_error();
@ -1021,7 +1148,7 @@ class ET_Builder_Library {
switch ( $post_type ) {
case ET_BUILDER_LAYOUT_POST_TYPE:
$layouts = et_pb_retrieve_templates( 'layout', '', 'all', '0', 'all', 'all', array(), $post_type );
$layouts = et_pb_retrieve_templates( $library_type, '', 'all', '0', $built_for, 'all', array() );
foreach ( $layouts as $layout ) {
if ( $id === $layout['ID'] ) {
@ -1032,24 +1159,34 @@ class ET_Builder_Library {
$result['savedShortcode'] = $result['shortcode'];
if ( ! isset( $_POST['is_BB'] ) ) {
$result['savedShortcode'] = et_fb_process_shortcode( $result['savedShortcode'] );
} else {
$post_content_processed = do_shortcode( $result['shortcode'] );
$result['migrations'] = ET_Builder_Module_Settings_Migration::$migrated;
}
if ( 'processed' === $content_type ) {
if ( ! isset( $_POST['is_BB'] ) ) {
$result['savedShortcode'] = et_fb_process_shortcode( $result['savedShortcode'] );
} else {
$post_content_processed = do_shortcode( $result['shortcode'] );
$result['migrations'] = ET_Builder_Module_Settings_Migration::$migrated;
}
unset( $result['shortcode'] );
unset( $result['shortcode'] );
}
break;
default:
$post_content = $post->post_content;
if ( ! isset( $_POST['is_BB'] ) ) {
$post_content = et_fb_process_shortcode( stripslashes( $post_content ) );
if ( 'processed' === $content_type ) {
if ( ! isset( $_POST['is_BB'] ) ) {
$post_content = et_fb_process_shortcode( stripslashes( $post_content ) );
}
}
$result['savedShortcode'] = $post_content;
break;
}
if ( 'exported' === $content_type ) {
$result['exported'] = get_exported_content( $result['shortcode'] );
}
$response = wp_json_encode(
array(
'success' => true,
@ -1079,6 +1216,499 @@ class ET_Builder_Library {
die( et_core_intentionally_unescaped( $response, 'html' ) );
}
/**
* AJAX Callback: Add/Remove Library terms for layout_tag and layout_category taxonomies.
*
* @since 4.17.0
*
* @global $_POST['payload'] Array with the terms list and update type (add/remove) for each.
*
* @return string JSON encoded.
*/
public function wp_ajax_et_builder_library_update_terms() {
et_core_security_check( 'edit_posts', 'et_builder_library_update_terms', 'nonce' );
$payload = isset( $_POST['payload'] ) ? (array) $_POST['payload'] : array(); // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['payload'] is an array, it's value sanitization is done at the time of accessing value.
if ( empty( $payload ) ) {
wp_send_json_success();
return;
}
$new_terms = array();
foreach ( $payload as $single_item ) {
$filter_type = $single_item['filterType'];
$taxonomy = 'tags' === $single_item['filterType'] ? 'layout_tag' : 'layout_category';
switch ( $single_item['updateType'] ) {
case 'remove':
$term_id = (int) $single_item['id'];
wp_delete_term( $term_id, $taxonomy );
break;
case 'rename':
$term_id = (int) $single_item['id'];
$new_name = (string) $single_item['newName'];
if ( '' !== $new_name ) {
$updated_term_data = wp_update_term( $term_id, $taxonomy, array( 'name' => $new_name ) );
if ( ! is_wp_error( $updated_term_data ) ) {
$new_terms[] = array(
'name' => $new_name,
'id' => $updated_term_data['term_id'],
'location' => 'local',
);
}
}
break;
case 'add':
$term_name = (string) $single_item['id'];
$new_term_data = wp_insert_term( $term_name, $taxonomy );
if ( ! is_wp_error( $new_term_data ) ) {
$new_terms[] = array(
'name' => $term_name,
'id' => $new_term_data['term_id'],
'location' => 'local',
);
}
break;
}
}
wp_send_json_success(
array(
'newFilters' => $new_terms,
'filterType' => $filter_type,
'localLibraryTerms' => [
'layout_category' => et_fb_prepare_library_terms(),
'layout_tag' => et_fb_prepare_library_terms( 'layout_tag' ),
],
)
);
}
/**
* AJAX Callback: Remove the Library layout after it was moved to the Cloud.
*
* @since 4.17.0
*
* @global $_POST['payload'] Array with the layout data to remove.
*
* @return void|string JSON encoded in case of empty payload
*/
public function wp_ajax_et_builder_toggle_cloud_status() {
et_core_security_check( 'edit_posts', 'et_builder_library_toggle_item_location', 'nonce' );
$payload = isset( $_POST['payload'] ) ? (array) $_POST['payload'] : array(); // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['payload'] is an array, it's value sanitization is done at the time of accessing value.
if ( empty( $payload ) ) {
wp_send_json_success();
return;
}
$item_id = (int) $payload['id'];
wp_delete_post( $item_id, true );
}
/**
* AJAX Callback: Save the temp layout into database with the 'draft' status
* Uses {@see et_pb_create_layout} to submit the library post
*
* @since 4.17.0
*
* @global $_POST['payload'] Array with the layout data to create.
*
* @return void
*/
public function wp_ajax_et_builder_library_save_temp_layout() {
et_core_security_check( 'edit_posts', 'et_fb_save_library_modules_nonce', 'nonce' );
$payload = isset( $_POST['payload'] ) ? (array) $_POST['payload'] : array(); // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['payload'] is an array, it's value sanitization is done at the time of accessing value.
$is_draft = 'draft' === $payload['postStatus'];
$name = sanitize_text_field( self::$_->array_get( $payload, 'itemName', '' ) );
$content = self::$_->array_get( $payload, 'itemContent', '' );
$prefix = esc_html__( 'Edit Cloud Item', 'et_builder' );
$name = $is_draft ? $prefix . ': ' . $name : $name;
$layout_type = self::$_->array_get( $payload, 'itemType', 'layout' );
$tax_input = array(
'layout_type' => sanitize_text_field( $layout_type ),
'module_width' => sanitize_text_field( self::$_->array_get( $payload, 'moduleWidth', 'regular' ) ),
);
if ( 'row' === $layout_type ) {
$meta_input['_et_pb_row_layout'] = $payload['rowLayout'];
}
if ( 'module' === $layout_type && isset( $payload['moduleType'] ) ) {
$meta_input['_et_pb_module_type'] = $payload['moduleType'];
}
$meta_input['_et_pb_built_for_post_type'] = 'page';
$new_layout_id = et_pb_create_layout( $name, $content, $meta_input, $tax_input, '', '', $post_status = $payload['postStatus'] );
wp_send_json_success(
array(
'layoutId' => $new_layout_id,
)
);
}
/**
* AJAX Callback: Removes temp layout from the website
*
* @since 4.17.0
*
* @global $_POST['payload'] Array with the layout id to remove.
*
* @return void
*/
public function wp_ajax_et_builder_library_remove_temp_layout() {
et_core_security_check( 'edit_posts', 'et_fb_remove_library_modules_nonce', 'nonce' );
$post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : '';
$module_presets_manager = ET_Builder_Global_Presets_Settings::instance();
$module_presets_manager->clear_temp_presets();
if ( 0 === $post_id ) {
$library_layouts = ET_Builder_Post_Type_Layout::instance();
$draft_posts = $library_layouts->query()->run( array( 'post_status' => array( 'draft' ) ) );
if ( ! empty( $draft_posts ) ) {
if ( is_array( $draft_posts ) ) {
// Several posts were returned.
foreach ( $draft_posts as $post ) {
wp_delete_post( $post->ID, true );
}
} else {
// Single post was returned.
wp_delete_post( $draft_posts->ID, true );
}
}
} else {
wp_delete_post( $post_id, true );
}
}
/**
* AJAX Callback: Removes temp presets from the website
*
* @since 4.17.0
*
* @return void
*/
public function wp_ajax_et_builder_library_clear_temp_presets() {
et_core_security_check( 'edit_posts', 'et_fb_clear_temp_presets_nonce', 'nonce' );
$module_presets_manager = ET_Builder_Global_Presets_Settings::instance();
$module_presets_manager->clear_temp_presets();
}
/**
* Returns 'publish' string to set the post correct status for restored library items.
*
* @since 4.17.0
*
* @return string new post status.
*/
public static function et_builder_set_untrash_status() {
return 'publish';
}
/**
* AJAX Callback: Upload thumbnail and assign it to specified post.
*
* @since 4.17.0
*
* @global $_FILES['imageFile'] File to upload.
* @global $_POST['postId'] Post id to set thumbnail for.
*
* @return void
*/
public function wp_ajax_et_builder_library_upload_thumbnail() {
et_core_security_check( 'edit_posts', 'et_builder_library_update_layout', 'nonce' );
$post_id = isset( $_POST['postId'] ) ? (int) $_POST['postId'] : '';
$image_url_raw = isset( $_POST['imageURL'] ) ? esc_url_raw( $_POST['imageURL'] ) : ''; // phpcs:ignore ET.Sniffs.ValidVariableName.VariableNotSnakeCase -- This is valid format for the property in the Cloud App.
// Upload and set featured image.
if ( $image_url_raw && '' !== $image_url_raw ) {
$upload = media_sideload_image( $image_url_raw, $post_id, $post_id, 'id' );
$attachment_id = is_wp_error( $upload ) ? 0 : $upload;
$image_url = get_attached_file( $attachment_id );
$image_metadata = wp_generate_attachment_metadata( $attachment_id, $image_url );
wp_update_attachment_metadata( $attachment_id, $image_metadata );
$result = set_post_thumbnail( $post_id, $attachment_id );
wp_send_json_success();
}
}
/**
* AJAX Callback: Update the library item (layout/section/row/module). Following updates supported:
* - Duplicate
* - Edit Categories/Tags. New categories/tags can be created as well.
* - Rename
* - Toggle Favorite status
* - Delete
*
* @since 4.17.0
*
* @global $_POST['payload'] Array with the update details.
*
* @return string JSON encoded with the updated item details and new terms (which could be created in Duplicate action)
*/
public function wp_ajax_et_builder_library_update_item() {
et_core_security_check( 'edit_posts', 'et_builder_library_update_layout', 'nonce' );
$payload = isset( $_POST['payload'] ) ? (array) $_POST['payload'] : array(); // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['payload'] is an array, it's value sanitization is done at the time of accessing value.
if ( empty( $payload ) ) {
wp_send_json_success();
return;
}
$update_details = $payload['update_details'];
$update_type = $update_details['updateType'];
$item_id = intval( $payload['item_id'] );
$new_id = '';
$categories = empty( $update_details['itemCategories'] ) ? [] : array_unique( array_map( 'intval', $update_details['itemCategories'] ) );
$tags = empty( $update_details['itemTags'] ) ? [] : array_unique( array_map( 'intval', $update_details['itemTags'] ) );
$new_categories = array();
$new_tags = array();
$item_update = array(
'ID' => $item_id,
);
if ( ! empty( $update_details['newCategoryName'] ) ) {
$new_names_array = explode( ',', $update_details['newCategoryName'] );
foreach ( $new_names_array as $new_name ) {
if ( '' !== $new_name ) {
$new_term = wp_insert_term( $new_name, 'layout_category' );
if ( ! is_wp_error( $new_term ) ) {
$categories[] = $new_term['term_id'];
$new_categories[] = array(
'name' => $new_name,
'id' => $new_term['term_id'],
'count' => 1,
);
} elseif ( ! empty( $new_term->error_data ) && ! empty( $new_term->error_data['term_exists'] ) ) {
$categories[] = $new_term->error_data['term_exists'];
}
}
}
}
if ( ! empty( $update_details['newTagName'] ) ) {
$new_names_array = explode( ',', $update_details['newTagName'] );
foreach ( $new_names_array as $new_name ) {
if ( '' !== $new_name ) {
$new_term = wp_insert_term( $new_name, 'layout_tag' );
if ( ! is_wp_error( $new_term ) ) {
$tags[] = $new_term['term_id'];
$new_tags[] = array(
'name' => $new_name,
'id' => $new_term['term_id'],
'count' => 1,
);
} elseif ( ! empty( $new_term->error_data ) && ! empty( $new_term->error_data['term_exists'] ) ) {
$tags[] = $new_term->error_data['term_exists'];
}
}
}
}
switch ( $update_type ) {
case 'duplicate':
case 'duplicate_and_delete':
case 'duplicate_premade_item':
$is_item_from_cloud = isset( $update_details['shortcode'] );
$title = sanitize_text_field( $update_details['itemName'] );
$meta_input = array();
$item_thumbnail = false;
if ( $is_item_from_cloud ) {
$content = $update_details['shortcode'];
$built_for = 'page';
$scope = ! empty( $update_details['global'] ) && 'on' === $update_details['global'] ? 'global' : 'non_global';
$layout_type = isset( $update_details['layoutType'] ) ? sanitize_text_field( $update_details['layoutType'] ) : 'layout';
$module_width = isset( $update_details['moduleWidth'] ) ? sanitize_text_field( $update_details['moduleWidth'] ) : 'regular';
$favorite_status = isset( $update_details['favoriteStatus'] ) && 'on' === sanitize_text_field( $update_details['favoriteStatus'] ) ? 'favorite' : '';
if ( 'row' === $layout_type ) {
$meta_input['_et_pb_row_layout'] = $update_details['rowLayout'];
}
if ( 'module' === $layout_type ) {
$meta_input['_et_pb_module_type'] = $update_details['moduleType'];
}
if ( '' !== $favorite_status ) {
$meta_input['favorite_status'] = $favorite_status;
}
} else {
$content = get_the_content( null, false, $item_id );
$built_for = get_post_meta( $item_id, '_et_pb_built_for_post_type', true );
$module_width = wp_get_post_terms( $item_id, 'module_width', array( 'fields' => 'names' ) );
$module_width = is_wp_error( $module_width ) ? 'regular' : sanitize_text_field( $module_width[0] );
$layout_type = wp_get_post_terms( $item_id, 'layout_type', array( 'fields' => 'names' ) );
$layout_type = is_wp_error( $layout_type ) || '' === $layout_type ? 'layout' : sanitize_text_field( $layout_type[0] );
$item_thumbnail = get_post_thumbnail_id( $item_id );
if ( ! empty( $update_details['global'] ) ) {
$scope = 'on' === $update_details['global'] ? 'global' : 'non_global';
} else {
$scope = wp_get_post_terms( $item_id, 'scope', array( 'fields' => 'names' ) );
$scope = is_wp_error( $scope ) ? 'non_global' : sanitize_text_field( $scope[0] );
}
if ( 'row' === $layout_type ) {
$row_layout = get_post_meta( $item_id, '_et_pb_row_layout', true );
$meta_input['_et_pb_row_layout'] = $row_layout;
}
if ( 'module' === $layout_type ) {
$module_type = get_post_meta( $item_id, '_et_pb_module_type', true );
$meta_input['_et_pb_module_type'] = $module_type;
}
}
$meta_input['_et_pb_built_for_post_type'] = $built_for;
$new_item = array(
'post_title' => $title,
'post_content' => $content,
'post_status' => 'publish',
'post_type' => 'et_pb_layout',
'tax_input' => array(
'layout_category' => $categories,
'layout_tag' => $tags,
'layout_type' => $layout_type,
'scope' => $scope,
'module_width' => $module_width,
),
'meta_input' => $meta_input,
);
$new_id = wp_insert_post( $new_item );
if ( $item_thumbnail ) {
set_post_thumbnail( $new_id, $item_thumbnail );
}
break;
case 'edit_cats':
wp_set_object_terms( $item_id, $categories, 'layout_category' );
wp_set_object_terms( $item_id, $tags, 'layout_tag' );
break;
case 'rename':
$item_update['post_title'] = sanitize_text_field( $update_details['itemName'] );
wp_update_post( $item_update );
break;
case 'toggle_fav':
$favorite_status = 'on' === sanitize_text_field( $update_details['favoriteStatus'] ) ? 'favorite' : '';
update_post_meta( $item_id, 'favorite_status', $favorite_status );
break;
case 'delete':
wp_trash_post( $item_id );
break;
case 'delete_permanently':
wp_delete_post( $item_id, true );
break;
case 'restore':
// wp_untrash_post() restores the post to `draft` by default, we have to set `publish` status via filter.
add_filter( 'wp_untrash_post_status', array( 'ET_Builder_Library', 'et_builder_set_untrash_status' ) );
wp_untrash_post( $item_id );
remove_filter( 'wp_untrash_post_status', array( 'ET_Builder_Library', 'et_builder_set_untrash_status' ) );
break;
}
$processed_new_tags = array();
$processed_new_cats = array();
$updated_tags = get_terms(
array(
'taxonomy' => 'layout_tag',
'hide_empty' => false,
)
);
$updated_categories = get_terms(
array(
'taxonomy' => 'layout_category',
'hide_empty' => false,
)
);
if ( ! empty( $updated_tags ) ) {
foreach ( $updated_tags as $single_tag ) {
$processed_new_tags[] = array(
'name' => $single_tag->name,
'id' => $single_tag->term_id,
'count' => $single_tag->count,
'location' => 'local',
);
}
}
if ( ! empty( $updated_categories ) ) {
foreach ( $updated_categories as $single_category ) {
$processed_new_cats[] = array(
'name' => $single_category->name,
'id' => $single_category->term_id,
'count' => $single_category->count,
'location' => 'local',
);
}
}
wp_send_json_success(
array(
'updatedItem' => $item_id,
'newItem' => $new_id,
'updateType' => $update_type,
'categories' => $categories,
'tags' => $tags,
'updatedTerms' => array(
'categories' => $processed_new_cats,
'tags' => $processed_new_tags,
),
)
);
}
/**
* AJAX Callback: Gets Cloud access token from DB and send it to client.
*
* @since 4.17.0
*
* @return void
*/
public function wp_ajax_et_builder_library_get_cloud_token() {
et_core_security_check( 'edit_posts', 'et_builder_library_get_cloud_token', 'nonce' );
$access_token = get_transient( 'et_cloud_access_token' );
wp_send_json_success(
array(
'accessToken' => $access_token,
)
);
}
/**
* AJAX Callback: Gets layouts data for the builder's library UI.
*
@ -1090,7 +1720,10 @@ class ET_Builder_Library {
*/
public function wp_ajax_et_builder_library_get_layouts_data() {
et_core_security_check( 'edit_posts', 'et_builder_library_get_layouts_data', 'nonce' );
wp_send_json_success( $this->builder_library_layouts_data() );
$library_type = isset( $_POST['et_library_type'] ) ? (string) sanitize_text_field( $_POST['et_library_type'] ) : 'layout';
wp_send_json_success( $this->builder_library_layouts_data( $library_type ) );
}
/**
@ -1125,6 +1758,86 @@ class ET_Builder_Library {
wp_send_json_success();
}
/**
* Filters out library tags and categories from Theme Builder settings.
* These taxonomies are not available on Frontend and user shouldn't be able to select it.
*
* @param bool $initial_value original value.
* @param object $taxonomy taxonomy to check.
*
* @since 4.17.0
*
* @return bool
*/
public function tb_remove_unsupported_taxonomies( $initial_value, $taxonomy ) {
if ( in_array( $taxonomy->name, array( 'layout_category', 'layout_tag' ), true ) ) {
return false;
}
return $initial_value;
}
/**
* Enqueue styles.
*
* @since 4.17.0
*/
public function enqueue_scripts() {
// Enqueue resource for edit session expire page.
if ( $this->vb_is_editing_session_expired() ) {
et_core_register_admin_assets();
wp_enqueue_style( 'et-core-admin' );
wp_enqueue_script( 'et-core-admin' );
}
}
/**
* Render modal to display a message when editing session expire.
*
* @since 4.17.0
*/
public function render_session_expired_modal() {
if ( ! $this->vb_is_editing_session_expired() ) {
return;
}
?>
<div class="et-core-modal-overlay et-builder-session-expired-modal et-core-active">
<div class="et-core-modal">
<div class="et-core-modal-header">
<h3 class="et-core-modal-title">
<?php esc_html_e( 'Session Expired', 'et_builder' ); ?>
</h3>
<a href="#" class="et-core-modal-close" data-et-core-modal="close"></a>
</div>
<div id="et-builder-session-expired-modal-content">
<div class="et-core-modal-content">
<p>
<?php
esc_html_e( 'Your Cloud item editing session has expired.', 'et_builder' );
?>
</p>
</div>
<a class="et-core-modal-action" href="#" data-et-core-modal="close">
<?php esc_html_e( 'Close', 'et_builder' ); ?>
</a>
</div>
</div>
</div>
<?php
}
/**
* Determine whether editing session is expired.
*
* @since 4.17.0
*/
public function vb_is_editing_session_expired() {
global $wp_query;
// phpcs:ignore WordPress.Security.NonceVerification -- This function does not change any state, and is therefore not susceptible to CSRF.
return $wp_query->is_404() && isset( $_GET['cloudItem'] );
}
/**
* Enqueues library-related styles and scripts in the admin.
* {@see 'admin_enqueue_scripts'}