/home/techb158/primomovers.ca/wp-content/themes/Divi/includes/builder
Edit: /home/techb158/primomovers.ca/wp-content/themes/Divi/includes/builder/core.php (252365B)
array_get( $_GET, 'post', 0 );
$bfb_settings = get_option( 'et_bfb_settings' );
$is_bfb = et_pb_is_allowed( 'use_visual_builder' ) && isset( $bfb_settings['enable_bfb'] ) && 'on' === $bfb_settings['enable_bfb'];
$is_bfb_used = 'on' === get_post_meta( $post_id, '_et_pb_use_builder', true ) && $is_bfb;
$is_edit_library_page = in_array( $pagenow, array( 'edit.php', 'post.php', 'post-new.php' ), true ) && ( ( isset( $_GET['post_type'] ) && 'et_pb_layout' === $_GET['post_type'] ) || ( $post_id && 'et_pb_layout' === get_post_type( $post_id ) ) );
$is_extra_builder = $post_id && 'layout' === get_post_type( $post_id );
$is_edit_page_not_bfb = in_array( $pagenow, array( 'post-new.php', 'post.php' ), true ) && ! $is_bfb_used;
$is_role_editor_page = 'admin.php' === $pagenow && isset( $_GET['page'] ) && apply_filters( 'et_divi_role_editor_page', 'et_divi_role_editor' ) === $_GET['page'];
$is_theme_builder_page = 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'et_theme_builder' === $_GET['page'];
// phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled -- `$_GET['import']` variable does not contain the 'WordPress' string.
$is_import_page = 'admin.php' === $pagenow && isset( $_GET['import'] ) && 'wordpress' === $_GET['import']; // Page Builder files should be loaded on import page as well to register the et_pb_layout post type properly.
$is_wpml_page = 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'sitepress-multilingual-cms/menu/languages.php' === $_GET['page']; // Page Builder files should be loaded on WPML clone page as well to register the custom taxonomies properly.
$is_edit_layout_category_page = 'edit-tags.php' === $pagenow && isset( $_GET['taxonomy'] ) && in_array( $_GET['taxonomy'], array( 'layout_category', 'layout_tag', 'layout_pack' ), true );
if ( ! $is_admin || ( $is_admin && in_array( $pagenow, $required_admin_pages, true ) && ( ! in_array( $pagenow, $specific_filter_pages, true ) || $is_edit_library_page || $is_role_editor_page || $is_edit_layout_category_page || $is_import_page || $is_wpml_page || $is_edit_page_not_bfb || $is_extra_builder || $is_theme_builder_page ) ) ) {
$should_load = true;
} else {
$should_load = false;
}
/**
* Filters whether or not the Divi Builder codebase should be loaded for the current request.
*
* @since 3.0.99
*
* @param bool $should_load
*/
$should_load = apply_filters( 'et_builder_should_load_framework', $should_load );
return $should_load;
// phpcs:enable
}
endif;
if ( ! function_exists( 'et_builder_load_library' ) ) :
/**
* Load Divi Library and Divi Cloud.
*
* @return void
*/
function et_builder_load_library() {
// Initialize the Divi Library.
require_once ET_BUILDER_DIR . 'feature/Library.php';
require_once ET_BUILDER_DIR . 'feature/SplitLibrary.php';
// Initialize Divi Cloud and AI.
if ( defined( 'ET_BUILDER_PLUGIN_ACTIVE' ) ) {
require_once ET_BUILDER_PLUGIN_DIR . '/cloud/cloud-app.php';
require_once ET_BUILDER_PLUGIN_DIR . '/ai-app/ai-app.php';
} else {
require_once get_template_directory() . '/cloud/cloud-app.php';
require_once get_template_directory() . '/ai-app/ai-app.php';
}
}
endif;
if ( et_builder_should_load_framework() ) {
et_builder_load_library();
}
if ( ! function_exists( 'et_builder_maybe_enable_inline_styles' ) ) :
/**
* Enable builder setting to output css styles inline in the footer.
*/
function et_builder_maybe_enable_inline_styles() {
et_update_option( 'static_css_custom_css_safety_check_done', true );
if ( ! wp_get_custom_css() ) {
return;
}
// This site has Custom CSS that existed prior to v3.0.54 which could contain syntax
// errors that the user is unaware of. Such errors would cause problems in a unified
// static CSS file so let's enable inline styles for the builder's design styles.
et_update_option( 'et_pb_css_in_footer', 'on' );
}
endif;
if ( defined( 'ET_CORE_UPDATED' ) && ! et_get_option( 'static_css_custom_css_safety_check_done', false ) ) {
et_builder_maybe_enable_inline_styles();
}
/**
* AJAX Callback: Generate video thumbnail from video url.
*/
function et_pb_video_get_oembed_thumbnail() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( wp_unslash( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) { // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- wp_verify_nonce() function does sanitation.
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$video_url = isset( $_POST['et_video_url'] ) ? esc_url( sanitize_text_field( $_POST['et_video_url'] ) ) : '';
if ( false !== wp_oembed_get( $video_url ) ) {
// Get image thumbnail.
add_filter( 'oembed_dataparse', 'et_pb_video_oembed_data_parse', 10, 3 );
// Save thumbnail.
$image_src = wp_oembed_get( $video_url );
// If the image src is empty try making a remote call with domain referer in case it's domain-restricted vimeo video.
// Ref: https://developer.vimeo.com/api/oembed/videos#embedding-videos-with-domain-privacy .
$is_vimeo_url = false !== strpos( $video_url, 'vimeo.com' );
if ( $is_vimeo_url && ! $image_src ) {
$vimeo_url = add_query_arg( 'url', $video_url, 'https://vimeo.com/api/oembed.json' );
$vimeo_response = wp_remote_get(
$vimeo_url,
array(
'headers' => array(
'Referer' => get_site_url(),
),
)
);
if ( $vimeo_response ) {
$vimeo_response_body = wp_remote_retrieve_body( $vimeo_response );
if ( $vimeo_response_body ) {
$vimeo_response_body = (array) json_decode( $vimeo_response_body );
if ( ! empty( $vimeo_response_body['thumbnail_url'] ) ) {
$image_src = $vimeo_response_body['thumbnail_url'];
}
}
}
}
// Set back to normal.
remove_filter( 'oembed_dataparse', 'et_pb_video_oembed_data_parse', 10, 3 );
if ( '' === $image_src ) {
die( -1 );
}
echo esc_url( $image_src );
} else {
die( -1 );
}
die();
}
add_action( 'wp_ajax_et_pb_video_get_oembed_thumbnail', 'et_pb_video_get_oembed_thumbnail' );
if ( ! function_exists( 'et_pb_video_oembed_data_parse' ) ) :
/**
* Remove protocol https or http from the video thumbnail url.
*
* @param string $return The returned oEmbed HTML.
* @param object $data A data object result from an oEmbed provider.
* @param string $url The URL of the content to be embedded.
*/
function et_pb_video_oembed_data_parse( $return, $data, $url ) {
if ( isset( $data->thumbnail_url ) ) {
return esc_url( str_replace( array( 'https://', 'http://' ), '//', $data->thumbnail_url ), array( 'http' ) );
} else {
return false;
}
}
endif;
/**
* AJAX Callback: Create widget area from wp dashbaoard Widgets screen.
*/
function et_pb_add_widget_area() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'manage_options' ) ) {
die( -1 );
}
$et_pb_widgets = get_theme_mod( 'et_pb_widgets' );
$number = $et_pb_widgets ? intval( $et_pb_widgets['number'] ) + 1 : 1;
$et_widget_area_name = isset( $_POST['et_widget_area_name'] ) ? sanitize_text_field( $_POST['et_widget_area_name'] ) : '';
$et_pb_widgets['areas'][ 'et_pb_widget_area_' . $number ] = $et_widget_area_name;
$et_pb_widgets['number'] = $number;
set_theme_mod( 'et_pb_widgets', $et_pb_widgets );
et_pb_force_regenerate_templates();
printf(
// translators: %1$s: widget area name.
et_get_safe_localization( __( '
%1$s widget area has been created. You can create more areas, once you finish update the page to see all the areas.', 'et_builder' ) ),
esc_html( $et_widget_area_name )
);
die();
}
add_action( 'wp_ajax_et_pb_add_widget_area', 'et_pb_add_widget_area' );
/**
* AJAX Callback: Remove widget area from wp dashbaoard Widgets screen.
*/
function et_pb_remove_widget_area() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'manage_options' ) ) {
die( -1 );
}
$et_pb_widgets = get_theme_mod( 'et_pb_widgets' );
$et_widget_area_name = isset( $_POST['et_widget_area_name'] ) ? sanitize_text_field( $_POST['et_widget_area_name'] ) : '';
unset( $et_pb_widgets['areas'][ $et_widget_area_name ] );
set_theme_mod( 'et_pb_widgets', $et_pb_widgets );
et_pb_force_regenerate_templates();
die( esc_html( $et_widget_area_name ) );
}
add_action( 'wp_ajax_et_pb_remove_widget_area', 'et_pb_remove_widget_area' );
/**
* AJAX Callback: Check if current user has permission to lock/unlock content.
*/
function et_pb_current_user_can_lock() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$permission = et_pb_is_allowed( 'lock_module' );
$permission = wp_json_encode( (bool) $permission );
die( et_core_esc_previously( $permission ) );
}
add_action( 'wp_ajax_et_pb_current_user_can_lock', 'et_pb_current_user_can_lock' );
/**
* Get the supported post types by default.
*
* @since 3.10
*
* @return string[]
*/
function et_builder_get_default_post_types() {
/**
* Filter default post types that are powered by the builder.
*
* @since 4.0
*
* @param string[]
*/
return apply_filters(
'et_builder_default_post_types',
array(
// WordPress.
'page',
'post',
// Divi/Extra/DBP.
'project',
'et_pb_layout',
)
);
}
/**
* Get the supported third party post types.
*
* @since 3.10
*
* @return string[]
*/
function et_builder_get_third_party_post_types() {
$third_party_post_types = array();
// WooCommerce (https://wordpress.org/plugins/woocommerce/).
if ( class_exists( 'WooCommerce' ) ) {
$third_party_post_types[] = 'product';
}
// The Events Calendar (https://wordpress.org/plugins/the-events-calendar/).
if ( class_exists( 'Tribe__Events__Main' ) ) {
$third_party_post_types[] = 'tribe_events';
}
// Popup Maker (https://wordpress.org/plugins/popup-maker/).
if ( class_exists( 'Popup_Maker' ) ) {
$third_party_post_types[] = 'popup';
}
// All-in-One Event Calendar (https://wordpress.org/plugins/all-in-one-event-calendar/).
if ( function_exists( 'ai1ec_initiate_constants' ) ) {
$third_party_post_types[] = 'ai1ec_event';
}
// Events Manager (https://wordpress.org/plugins/events-manager/).
if ( function_exists( 'em_plugins_loaded' ) ) {
$third_party_post_types[] = 'event';
$third_party_post_types[] = 'location';
}
// Portfolio Post Type (https://wordpress.org/plugins/portfolio-post-type/).
if ( function_exists( 'portfolio_post_type_init' ) ) {
$third_party_post_types[] = 'portfolio';
}
// LifterLMS (https://wordpress.org/plugins/lifterlms/).
if ( class_exists( 'LifterLMS' ) ) {
$third_party_post_types[] = 'course';
}
// LearnDash (https://www.learndash.com/wordpress-course-plugin-features/).
if ( class_exists( 'Semper_Fi_Module' ) ) {
$third_party_post_types[] = 'sfwd-courses';
$third_party_post_types[] = 'sfwd-lessons';
}
/**
* Array of third-party registered post types that should have support enabled by default.
*
* @since 3.10
*
* @param string[]
*/
return apply_filters( 'et_builder_third_party_post_types', $third_party_post_types );
}
/**
* Look for builder's registered third party post type that isn't publicly queryable.
*
* @since 3.19.9
*
* @return array
*/
function et_builder_get_third_party_unqueryable_post_types() {
// Save the value in static variable so if post type's publicly_queryable is modified due to current
// request is BFB request, this function still return correct value.
static $unqueryable_post_types = array();
if ( empty( $unqueryable_post_types ) ) {
// Get third party's unqueryable post types only as default post types have been handled properly.
$valid_third_party_post_types = array_diff(
et_builder_get_builder_post_types(),
et_builder_get_default_post_types()
);
$unqueryable_post_types = array_intersect(
$valid_third_party_post_types,
get_post_types( array( 'publicly_queryable' => false ) )
);
}
return apply_filters( 'et_builder_get_third_party_unqueryable_post_types', $unqueryable_post_types );
}
/**
* Get the list of registered Post Types options.
*
* @since 3.18
* @since 4.0.7 Added the $require_editor parameter.
*
* @param boolean|callable $usort Comparision callback.
* @param boolean $require_editor Optional. Whether to retrieve only post type that has editor support.
*
* @return array
*/
function et_get_registered_post_type_options( $usort = false, $require_editor = true ) {
$require_editor_key = $require_editor ? '1' : '0';
$key = "et_get_registered_post_type_options:{$require_editor_key}";
if ( ET_Core_Cache::has( $key ) ) {
return ET_Core_Cache::get( $key );
}
$blocklist = et_builder_get_blocklisted_post_types();
$allowlist = et_builder_get_third_party_post_types();
// Extra and Library layouts shouldn't appear in Theme Options as configurable post types.
/**
* Get array of post types to prevent from appearing as options for builder usage.
*
* @since 4.0
*
* @param string[] $blocklist Post types to blocklist.
*/
$blocklist = array_merge(
$blocklist,
array(
'et_pb_layout',
'layout',
)
);
$blocklist = apply_filters( 'et_builder_post_type_options_blocklist', $blocklist );
$raw_post_types = get_post_types(
array(
'show_ui' => true,
),
'objects'
);
$post_types = array();
foreach ( $raw_post_types as $post_type ) {
$is_allowlisted = in_array( $post_type->name, $allowlist, true );
$is_blocklisted = in_array( $post_type->name, $blocklist, true );
$supports_editor = $require_editor ? post_type_supports( $post_type->name, 'editor' ) : true;
$is_public = et_builder_is_post_type_public( $post_type->name );
if ( ! $is_allowlisted && ( $is_blocklisted || ! $supports_editor || ! $is_public ) ) {
continue;
}
$post_types[] = $post_type;
}
if ( $usort && is_callable( $usort ) ) {
usort( $post_types, $usort );
}
$post_type_options = array_combine(
wp_list_pluck( $post_types, 'name' ),
wp_list_pluck( $post_types, 'label' )
);
// did_action() actually checks if the action has started, not ended so we
// need to check that we are not currently doing the action as well.
if ( did_action( 'init' ) && ! doing_action( 'init' ) ) {
// Only cache the value after init is done when we are sure all
// plugins have registered their post types.
ET_Core_Cache::add( $key, $post_type_options );
}
return $post_type_options;
}
/**
* Clear post type options cache whenever a custom post type is registered.
*
* @since 3.21.2
*
* @return void
*/
function et_clear_registered_post_type_options_cache() {
ET_Core_Cache::delete( 'et_get_registered_post_type_options' );
}
add_action( 'registered_post_type', 'et_clear_registered_post_type_options_cache' );
/**
* Get the list of unsupported Post Types.
*
* @since 4.5.1
*
* @return array
*/
function et_builder_get_blocklisted_post_types() {
$post_type_blocklist = array(
// LearnDash.
'sfwd-essays',
// bbPress.
'forum',
'topic',
'reply',
);
return apply_filters( 'et_builder_post_type_blocklist', $post_type_blocklist );
}
/**
* Get the list of unsupported Post Types.
*
* @deprecated ?? No longer used by internal code; use `et_builder_get_blocklisted_post_types` instead.
*
* @since 3.10
* @since 4.5.1 Aliased to `et_builder_get_blocklisted_post_types`.
*
* @return array
*/
function et_builder_get_blacklisted_post_types() {
return et_builder_get_blocklisted_post_types();
}
/**
* Check whether the supplied post type is a custom post type as far as the builder is concerned.
*
* @since 3.10
*
* @param string $post_type the post type to be checked.
*
* @return boolean
*/
function et_builder_is_post_type_custom( $post_type ) {
return $post_type && ( ! in_array( $post_type, et_builder_get_default_post_types(), true ) || et_theme_builder_is_layout_post_type( $post_type ) );
}
/**
* Check whether the supplied post is of a custom post type as far as the builder is concerned.
* If no post id is supplied, checks whether the current page is the singular view of a custom post type.
*
* @since 3.10
*
* @param integer $post_id post id.
*
* @return boolean
*/
function et_builder_post_is_of_custom_post_type( $post_id = 0 ) {
$post_types = et_builder_get_default_post_types();
if ( 0 === $post_id ) {
return is_singular() && ! in_array( get_post_type( get_the_ID() ), $post_types, true );
}
return et_builder_is_post_type_custom( get_post_type( $post_id ) );
}
/**
* Check whether the current request is for a custom post type archive.
*
* @since 4.0.5
*
* @return boolean
*/
function et_builder_is_custom_post_type_archive() {
// Use get_the_ID() explicitly so we decide based on the first post of an archive page.
return is_archive() && et_builder_post_is_of_custom_post_type( get_the_ID() );
}
/**
* Get an array of post types the Divi Builder is enabled on.
*
* @since 3.10
*
* @return string[]
*/
function et_builder_get_enabled_builder_post_types() {
$default = array_merge(
et_builder_get_default_post_types(),
et_builder_get_third_party_post_types()
);
/**
* Filter the array of enabled post type options.
* Allows Divi/Extra/DBP to only supply their option value in order to reduce code duplication.
*
* Schema:
* array(
* 'post_type_name' => <'on' or 'off'>,
* // ...
* )
*
* @since 3.10
*
* @param string[] $options
*
* @return string[]
*/
$options = apply_filters( 'et_builder_enabled_builder_post_type_options', array() );
// Ensure $options value type is array.
$options = is_array( $options ) ? $options : array();
foreach ( $default as $post_type ) {
if ( ! isset( $options[ $post_type ] ) ) {
$options[ $post_type ] = 'on';
}
}
$filtered = array();
foreach ( $options as $post_type => $state ) {
if ( 'on' === $state && array_key_exists( $post_type, et_get_registered_post_type_options() ) && ! in_array( $post_type, et_builder_get_blocklisted_post_types(), true ) ) {
$filtered[] = $post_type;
}
}
return $filtered;
}
/**
* Return an array of post types which have the builder enabled.
*
* @return mixed|void
*/
function et_builder_get_builder_post_types() {
/**
* Array of post types which have the builder enabled.
*
* @since 3.10
*
* @param string[]
*/
return apply_filters( 'et_builder_post_types', et_builder_get_enabled_builder_post_types() );
}
/**
* Return an array of post types which have the frontend builder enabled.
*
* @return mixed|void
*/
function et_builder_get_fb_post_types() {
/**
* Array of post types which have the frontend builder enabled.
*
* @since 3.10
*
* @param string[]
*/
return apply_filters( 'et_fb_post_types', et_builder_get_enabled_builder_post_types() );
}
/**
* Check whether the specified post can have the builder enabled.
*
* @since 3.10
*
* @param integer $post_id the post id to be checked.
*
* @return boolean
*/
function et_builder_enabled_for_post( $post_id ) {
if ( et_pb_is_pagebuilder_used( $post_id ) ) {
return true;
}
return et_builder_enabled_for_post_type( get_post_type( $post_id ) );
}
/**
* Check whether the specified post type can have the builder enabled.
*
* @since 3.10
*
* @param string $post_type the registered post type to be checked.
*
* @return boolean
*/
function et_builder_enabled_for_post_type( $post_type ) {
return in_array( $post_type, et_builder_get_builder_post_types(), true );
}
/**
* Check whether the specified post can have the FB enabled.
*
* @since 3.10
*
* @param integer $post_id the post id to be checked for the FB enable.
*
* @return boolean
*/
function et_builder_fb_enabled_for_post( $post_id ) {
$post_type = get_post_type( $post_id );
$enabled = false;
$pto = get_post_type_object( $post_type );
$is_default_post_type = in_array( $post_type, et_builder_get_default_post_types(), true );
$is_public_post_type = et_builder_is_post_type_public( $post_type );
if ( $pto && ( $is_default_post_type || $is_public_post_type ) ) {
$enabled = et_builder_enabled_for_post( $post_id );
}
/**
* Filter whether the FB is enabled for a given post.
*
* @since 3.10
*
* @param boolean $enabled
* @param integer $post_id
*/
$enabled = apply_filters( 'et_builder_fb_enabled_for_post', $enabled, $post_id );
return $enabled;
}
/**
* Check whether the specified post type is public.
*
* @since 3.10
*
* @param string $post_type the post type to be checked.
*
* @return boolean
*/
function et_builder_is_post_type_public( $post_type ) {
$pto = get_post_type_object( $post_type );
// Note: the page post type is not publicly_queryable but we should treat it as such.
return ( $pto && ( $pto->publicly_queryable || 'page' === $pto->name ) );
}
/**
* Check whether the styles for the current request should be wrapped.
* We wrap styles on non-native custom post types and custom post archives.
*
* @since 4.10.6
*
* @return boolean
*/
function et_builder_should_wrap_styles() {
static $should_wrap = null;
if ( null === $should_wrap ) {
$post_id = get_the_ID();
// Warp on custom post type archives and on non-native custom post types when the builder is used.
$should_wrap = et_builder_is_custom_post_type_archive() || ( et_builder_post_is_of_custom_post_type( $post_id ) && et_pb_is_pagebuilder_used( $post_id ) );
}
return $should_wrap;
}
/**
* Determine whether post is of post_type layout or not.
*
* @param integer $post_id the post id to be checked.
*
* @return bool
*/
function et_is_extra_library_layout( $post_id ) {
return 'layout' === get_post_type( $post_id );
}
/**
* Check whether the specified capability allowed for the user.
*
* @param array|string $capabilities capabilities names.
* @param string $role - The user role. If empty the role of the current user is used.
*
* @return bool
*/
function et_pb_is_allowed( $capabilities, $role = '' ) {
$saved_capabilities = et_pb_get_role_settings();
$test_current_user = '' === $role;
$role = $test_current_user ? et_pb_get_current_user_role() : $role;
if ( ! $role ) {
return false;
}
// Disable certain capabilities for non-allowlisted roles by default.
$dangerous = array( 'theme_builder', 'read_dynamic_content_custom_fields' );
$roles_allowlist = array( 'administrator', 'et_support_elevated', 'et_support' );
foreach ( (array) $capabilities as $capability ) {
$is_dangerous = in_array( $capability, $dangerous, true );
$role_not_allowlisted = ! in_array( $role, $roles_allowlist, true );
if ( $test_current_user && $is_dangerous && is_multisite() && is_super_admin() ) {
// Super admins always have access to dangerous capabilities and that cannot be
// changed in the role editor.
return true;
}
if ( ! empty( $saved_capabilities[ $role ][ $capability ] ) ) {
return 'on' === $saved_capabilities[ $role ][ $capability ];
}
if ( $is_dangerous && $role_not_allowlisted ) {
// Allowlisted roles have access to dangerous capabilities by default,
// but that can be changed in the role editor.
return false;
}
}
return true;
}
/**
* Performs a check against ET capabilities before passing on to {@see et_core_security_check()}.
*
* @since 4.0
*
* @param string $et_capability ET Capability name.
* @param string $wp_capability WP Capability name.
* @param string $nonce_action Name of the nonce action to check.
* @param string $nonce_key The key to use to lookup nonce value.
* @param string $nonce_location Where the nonce is stored (_POST|_GET|_REQUEST).
* @param bool $die Whether or not to `die()` on failure.
*
* @return bool
*/
function et_builder_security_check( $et_capability, $wp_capability = 'manage_options', $nonce_action = '', $nonce_key = '', $nonce_location = '_POST', $die = true ) {
if ( ! et_pb_is_allowed( $et_capability ) ) {
if ( $die ) {
et_core_die();
}
return false;
}
return et_core_security_check( $wp_capability, $nonce_action, $nonce_key, $nonce_location, $die );
}
/**
* Gets the array of role settings
*
* @return array
*/
function et_pb_get_role_settings() {
global $et_pb_role_settings;
// if we don't have saved global variable, then get the value from WPDB.
$et_pb_role_settings = isset( $et_pb_role_settings ) ? $et_pb_role_settings : get_option( 'et_pb_role_settings', array() );
return $et_pb_role_settings;
}
/**
* Determines the current user role.
*
* @return string
*/
function et_pb_get_current_user_role() {
$current_user = wp_get_current_user();
$user_roles = $current_user->roles;
// retrieve the role from array if exists or determine it using custom mechanism
// $user_roles array may start not from 0 index. Use reset() to retrieve the first value from array regardless its index.
$role = ! empty( $user_roles ) ? reset( $user_roles ) : et_pb_determine_current_user_role();
return $role;
}
/**
* Generate the list of all roles ( with editing permissions ) registered in current WP.
*
* @return array
*/
function et_pb_get_all_roles_list() {
// get all roles registered in current WP.
if ( ! function_exists( 'get_editable_roles' ) ) {
require_once ABSPATH . 'wp-admin/includes/user.php';
}
$all_roles = get_editable_roles();
$builder_roles_array = array();
if ( ! empty( $all_roles ) ) {
foreach ( $all_roles as $role => $role_data ) {
// add roles with edit_posts capability into $builder_roles_array (but not Support).
if (
! empty( $role_data['capabilities']['edit_posts'] )
&&
1 === (int) $role_data['capabilities']['edit_posts']
&&
! in_array( $role_data['name'], array( 'ET Support', 'ET Support - Elevated' ), true )
) {
$builder_roles_array[ $role ] = $role_data['name'];
}
}
}
// fill the builder roles array with default roles if it's empty.
if ( empty( $builder_roles_array ) ) {
$builder_roles_array = array(
'administrator' => esc_html__( 'Administrator', 'et_builder' ),
'editor' => esc_html__( 'Editor', 'et_builder' ),
'author' => esc_html__( 'Author', 'et_builder' ),
'contributor' => esc_html__( 'Contributor', 'et_builder' ),
);
}
return $builder_roles_array;
}
/**
* Determine the current user role by checking every single registered role via current_user_can().
*
* @return string
*/
function et_pb_determine_current_user_role() {
$all_roles = et_pb_get_all_roles_list();
// go through all the registered roles and return the one current user have.
foreach ( $all_roles as $role => $role_data ) {
if ( current_user_can( $role ) ) {
return $role;
}
}
}
/**
* Retrieve similar post types for the given post type.
*
* @param string $post_type The post type for which retrieve similar post types.
*
* @return array
*/
function et_pb_show_all_layouts_built_for_post_type( $post_type ) {
$similar_post_types = array(
'post',
'page',
'project',
);
if ( in_array( $post_type, $similar_post_types, true ) ) {
return $similar_post_types;
}
return $post_type;
}
add_filter( 'et_pb_show_all_layouts_built_for_post_type', 'et_pb_show_all_layouts_built_for_post_type' );
/**
* AJAX Callback :: Load layouts.
*/
function et_pb_show_all_layouts() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
printf(
'
%1$s
',
esc_html__( 'Replace the existing content with loaded layout', 'et_builder' ),
checked( get_theme_mod( 'et_pb_replace_content', 'on' ), 'on', false )
);
$post_type = ! empty( $_POST['et_layouts_built_for_post_type'] ) ? sanitize_text_field( $_POST['et_layouts_built_for_post_type'] ) : 'post';
$layouts_type = ! empty( $_POST['et_load_layouts_type'] ) ? sanitize_text_field( $_POST['et_load_layouts_type'] ) : 'predefined';
$predefined_operator = 'predefined' === $layouts_type ? 'EXISTS' : 'NOT EXISTS';
$post_type = apply_filters( 'et_pb_show_all_layouts_built_for_post_type', $post_type, $layouts_type );
$query_args = array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => '_et_pb_predefined_layout',
'value' => 'on',
'compare' => $predefined_operator,
),
array(
'key' => '_et_pb_built_for_post_type',
'value' => $post_type,
'compare' => 'IN',
),
array(
'key' => '_et_pb_layout_applicability',
'value' => 'product_tour',
'compare' => 'NOT EXISTS',
),
),
'tax_query' => array(
array(
'taxonomy' => 'layout_type',
'field' => 'slug',
'terms' => array( 'section', 'row', 'module', 'fullwidth_section', 'specialty_section', 'fullwidth_module' ),
'operator' => 'NOT IN',
),
),
'post_type' => ET_BUILDER_LAYOUT_POST_TYPE,
'posts_per_page' => '-1',
'suppress_filters' => 'predefined' === $layouts_type,
);
$query = new WP_Query( $query_args );
if ( $query->have_posts() ) :
echo '
';
while ( $query->have_posts() ) :
$query->the_post();
$button_html = 'predefined' !== $layouts_type ?
sprintf(
'%1$s ',
esc_html__( 'Delete', 'et_builder' )
)
: '';
printf(
'%1$s%3$s %4$s ',
esc_html( get_the_title() ),
esc_attr( get_the_ID() ),
esc_html__( 'Load', 'et_builder' ),
et_core_esc_previously( $button_html )
);
endwhile;
echo ' ';
endif;
wp_reset_postdata();
die();
}
add_action( 'wp_ajax_et_pb_show_all_layouts', 'et_pb_show_all_layouts' );
/**
* AJAX Callback :: Retrieves saved builder layouts.
*/
function et_pb_get_saved_templates() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$layout_type = ! empty( $_POST['et_layout_type'] ) ? sanitize_text_field( $_POST['et_layout_type'] ) : 'layout';
$module_width = ! empty( $_POST['et_module_width'] ) && 'module' === $layout_type ? sanitize_text_field( $_POST['et_module_width'] ) : '';
$is_global = ! empty( $_POST['et_is_global'] ) ? sanitize_text_field( $_POST['et_is_global'] ) : 'false';
$specialty_query = ! empty( $_POST['et_specialty_columns'] ) && 'row' === $layout_type ? sanitize_text_field( $_POST['et_specialty_columns'] ) : '0';
$post_type = ! empty( $_POST['et_post_type'] ) ? sanitize_text_field( $_POST['et_post_type'] ) : 'post';
$templates_data = et_pb_retrieve_templates( $layout_type, $module_width, $is_global, $specialty_query, $post_type );
if ( empty( $templates_data ) ) {
$templates_data = array( 'error' => esc_html__( 'You have not saved any items to your Divi Library yet. Once an item has been saved to your library, it will appear here for easy use.', 'et_builder' ) );
}
$json_templates = wp_json_encode( $templates_data );
die( et_core_esc_previously( $json_templates ) );
}
add_action( 'wp_ajax_et_pb_get_saved_templates', 'et_pb_get_saved_templates' );
/**
* Retrieves saved builder layouts.
*
* @since 2.0
*
* @param string $layout_type Accepts 'section', 'row', 'module', 'fullwidth_section',
* 'specialty_section', 'fullwidth_module'.
* @param string $module_width Accepts 'regular', 'fullwidth'.
* @param string $is_global Filter layouts based on their scope. Accepts 'global' to include
* only global layouts, 'false' to include only non-global layouts,
* or 'all' to include both global and non-global layouts.
* @param string $specialty_query Limit results to layouts of type 'row' that can be put inside
* specialty sections. Accepts '3' to include only 3-column rows,
* '2' for 2-column rows, or '0' to disable the specialty query. Default '0'.
* @param string $post_type Limit results to layouts built for this post type.
* @param string $deprecated Deprecated.
* @param array $boundaries {
*
* Return a subset of the total results.
*
* @type int $offset Start from this point in the results. Default `0`.
* @type int $limit Maximum number of results to return. Default `-1`.
* }
*
* @return array[] $layouts {
*
* @type mixed[] {
*
* Layout Data
*
* @type int $ID The layout's post id.
* @type string $title The layout's title/name.
* @type string $shortcode The layout's shortcode content.
* @type string $is_global The layout's scope. Accepts 'global', 'non_global'.
* @type string $layout_type The layout's type. See {@see self::$layout_type} param for accepted values.
* @type string $applicability The layout's applicability.
* @type string $layouts_type Deprecated. Will always be 'library'.
* @type string $module_type For layouts of type 'module', the module type/slug (eg. et_pb_blog).
* @type string[] $categories This layout's assigned categories (slugs).
* @type string $row_layout For layout's of type 'row', the row layout type (eg. 4_4).
* @type mixed[] $unsynced_options For global layouts, the layout's unsynced settings.
* }
* ...
* }
*/
function et_pb_retrieve_templates( $layout_type = 'layout', $module_width = '', $is_global = 'false', $specialty_query = '0', $post_type = 'post', $deprecated = '', $boundaries = array() ) {
$templates_data = array();
$suppress_filters = false;
$extra_layout_post_type = 'layout';
$module_icons = ET_Builder_Element::get_module_icons();
$utils = ET_Core_Data_Utils::instance();
$similar_post_types = array_keys( ET_Builder_Settings::get_registered_post_type_options() );
// All default and 3rd party post types considered similar and share the same library items, so retrieve all items for any post type from the list.
$post_type = in_array( $post_type, $similar_post_types, true ) ? $similar_post_types : $post_type;
// need specific query for the layouts.
if ( 'layout' === $layout_type ) {
if ( 'all' === $post_type ) {
$meta_query = array(
'relation' => 'AND',
array(
'key' => '_et_pb_built_for_post_type',
'value' => $extra_layout_post_type,
'compare' => 'NOT IN',
),
);
} else {
$meta_query = array(
'relation' => 'AND',
array(
'key' => '_et_pb_built_for_post_type',
'value' => $post_type,
'compare' => 'IN',
),
);
}
$tax_query = array(
array(
'taxonomy' => 'layout_type',
'field' => 'slug',
'terms' => array( 'section', 'row', 'module', 'fullwidth_section', 'specialty_section', 'fullwidth_module' ),
'operator' => 'NOT IN',
),
);
$suppress_filters = 'predefined' === $layout_type;
} else {
$additional_condition = '' !== $module_width ?
array(
'taxonomy' => 'module_width',
'field' => 'slug',
'terms' => $module_width,
) : '';
$meta_query = array();
if ( '0' !== $specialty_query ) {
$columns_val = '3' === $specialty_query ? array( '4_4', '1_2,1_2', '1_3,1_3,1_3' ) : array( '4_4', '1_2,1_2' );
$meta_query[] = array(
'key' => '_et_pb_row_layout',
'value' => $columns_val,
'compare' => 'IN',
);
}
$post_type = apply_filters( 'et_pb_show_all_layouts_built_for_post_type', $post_type, $layout_type );
$meta_query[] = array(
'key' => '_et_pb_built_for_post_type',
'value' => $post_type,
'compare' => 'IN',
);
$tax_query = array(
'relation' => 'AND',
array(
'taxonomy' => 'layout_type',
'field' => 'slug',
'terms' => $layout_type,
),
$additional_condition,
);
if ( 'all' !== $is_global ) {
$global_operator = 'global' === $is_global ? 'IN' : 'NOT IN';
$tax_query[] = array(
'taxonomy' => 'scope',
'field' => 'slug',
'terms' => array( 'global' ),
'operator' => $global_operator,
);
}
}
$start_from = 0;
$limit_to = '-1';
if ( ! empty( $boundaries ) ) {
$start_from = $boundaries[0];
$limit_to = $boundaries[1];
}
/**
* Filter suppress_filters argument.
*
* @since 4.4.5
*
* @param boolean $suppress_filters
*/
$suppress_filters = wp_validate_boolean( apply_filters( 'et_pb_show_all_layouts_suppress_filters', $suppress_filters ) );
$query = new WP_Query(
array(
'tax_query' => $tax_query,
'post_type' => ET_BUILDER_LAYOUT_POST_TYPE,
'posts_per_page' => $limit_to,
'meta_query' => $meta_query,
'offset' => $start_from,
'suppress_filters' => $suppress_filters,
)
);
if ( ! empty( $query->posts ) ) {
// Call the_post() to properly configure post data. Make sure to call the_post() and
// wp_reset_postdata() only if the posts result exist to avoid unexpected issues.
$query->the_post();
wp_reset_postdata();
foreach ( $query->posts as $single_post ) {
if ( 'module' === $layout_type ) {
$module_type = get_post_meta( $single_post->ID, '_et_pb_module_type', true );
} else {
$module_type = '';
}
// add only modules allowed for current user.
if ( '' === $module_type || et_pb_is_allowed( $module_type ) ) {
$categories = wp_get_post_terms( $single_post->ID, 'layout_category' );
$scope = wp_get_post_terms( $single_post->ID, 'scope' );
$global_scope = isset( $scope[0] ) ? $scope[0]->slug : 'non_global';
$categories_processed = array();
$row_layout = '';
$this_layout_type = '';
$this_layout_applicability = '';
if ( ! empty( $categories ) ) {
foreach ( $categories as $category_data ) {
$categories_processed[] = esc_html( $category_data->slug );
}
}
if ( 'row' === $layout_type ) {
$row_layout = get_post_meta( $single_post->ID, '_et_pb_row_layout', true );
}
if ( 'layout' === $layout_type ) {
$this_layout_type = 'on' === get_post_meta( $single_post->ID, '_et_pb_predefined_layout', true ) ? 'predefined' : 'library';
$this_layout_applicability = get_post_meta( $single_post->ID, '_et_pb_layout_applicability', true );
}
// get unsynced global options for module.
if ( 'module' === $layout_type && 'false' !== $is_global ) {
$unsynced_options = get_post_meta( $single_post->ID, '_et_pb_excluded_global_options' );
}
$templates_datum = array(
'ID' => (int) $single_post->ID,
'title' => esc_html( $single_post->post_title ),
'shortcode' => et_core_intentionally_unescaped( $single_post->post_content, 'html' ),
'is_global' => esc_html( $global_scope ),
'layout_type' => esc_html( $layout_type ),
'applicability' => esc_html( $this_layout_applicability ),
'layouts_type' => esc_html( $this_layout_type ),
'module_type' => esc_html( $module_type ),
'categories' => et_core_esc_previously( $categories_processed ),
'row_layout' => esc_html( $row_layout ),
'unsynced_options' => ! empty( $unsynced_options ) ? $utils->esc_array( json_decode( $unsynced_options[0], true ), 'sanitize_text_field' ) : array(),
);
if ( $module_type ) {
// Append icon if there's any.
$template_icon = $utils->array_get( $module_icons, "{$module_type}.icon", false );
if ( $template_icon ) {
$templates_datum['icon'] = $template_icon;
}
// Append svg icon if there's any.
$template_icon_svg = $utils->array_get( $module_icons, "{$module_type}.icon_svg", false );
if ( $template_icon_svg ) {
$templates_datum['icon_svg'] = $template_icon_svg;
}
}
$templates_data[] = $templates_datum;
}
}
}
return $templates_data;
}
/**
* AJAX Callback :: Add template meta.
*/
function et_pb_add_template_meta() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
$post_id = ! empty( $_POST['et_post_id'] ) ? sanitize_text_field( $_POST['et_post_id'] ) : '';
if ( empty( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) {
die( -1 );
}
$value = ! empty( $_POST['et_meta_value'] ) ? sanitize_text_field( $_POST['et_meta_value'] ) : '';
$custom_field = ! empty( $_POST['et_custom_field'] ) ? sanitize_text_field( $_POST['et_custom_field'] ) : '';
$allowlisted_meta_keys = array(
'_et_pb_row_layout',
'_et_pb_module_type',
);
if ( in_array( $custom_field, $allowlisted_meta_keys, true ) ) {
update_post_meta( $post_id, $custom_field, $value );
}
}
add_action( 'wp_ajax_et_pb_add_template_meta', 'et_pb_add_template_meta' );
if ( ! function_exists( 'et_pb_add_new_layout' ) ) {
/**
* AJAX Callback :: Save layout to database.
*/
function et_pb_add_new_layout() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
// phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- et_layout_options is json object, and this function sanitize object values at the time of using it.
$fields_data = isset( $_POST['et_layout_options'] ) ? trim( $_POST['et_layout_options'] ) : '';
if ( empty( $fields_data ) ) {
die();
}
$fields_data_json = str_replace( '\\', '', $fields_data );
$fields_data_array = json_decode( $fields_data_json, true );
$processed_data_array = array();
// prepare array with fields data in convenient format.
if ( ! empty( $fields_data_array ) ) {
foreach ( $fields_data_array as $index => $field_data ) {
$processed_data_array[ $field_data['field_id'] ] = $field_data['field_val'];
}
}
$processed_data_array = apply_filters( 'et_pb_new_layout_data_from_form', $processed_data_array, $fields_data_array );
if ( empty( $processed_data_array ) ) {
die();
}
$layout_location = et_()->array_get_sanitized( $processed_data_array, 'et_pb_template_cloud', 'local' );
$layout_type = et_()->array_get_sanitized( $processed_data_array, 'new_template_type', 'layout' );
$layout_is_global = 'global' === et_()->array_get( $processed_data_array, 'et_pb_template_global', 'not_global' );
if ( 'layout' === $layout_type ) {
// Layouts of type 'layout' are not allowed to be global.
$layout_is_global = false;
}
$args = array(
'layout_type' => $layout_type,
'layout_selected_cats' => ! empty( $processed_data_array['selected_cats'] ) ? sanitize_text_field( $processed_data_array['selected_cats'] ) : '',
'layout_selected_tags' => ! empty( $processed_data_array['selected_tags'] ) ? sanitize_text_field( $processed_data_array['selected_tags'] ) : '',
'built_for_post_type' => ! empty( $processed_data_array['et_builder_layout_built_for_post_type'] ) ? sanitize_text_field( $processed_data_array['et_builder_layout_built_for_post_type'] ) : 'page',
'layout_new_cat' => ! empty( $processed_data_array['et_pb_new_cat_name'] ) ? sanitize_text_field( $processed_data_array['et_pb_new_cat_name'] ) : '',
'layout_new_tag' => ! empty( $processed_data_array['et_pb_new_tag_name'] ) ? sanitize_text_field( $processed_data_array['et_pb_new_tag_name'] ) : '',
'columns_layout' => ! empty( $processed_data_array['et_columns_layout'] ) ? sanitize_text_field( $processed_data_array['et_columns_layout'] ) : '0',
'module_type' => ! empty( $processed_data_array['et_module_type'] ) ? sanitize_text_field( $processed_data_array['et_module_type'] ) : 'et_pb_unknown',
'layout_scope' => $layout_is_global ? 'global' : 'not_global',
'layout_location' => $layout_location,
'module_width' => 'regular',
'layout_content' => ! empty( $processed_data_array['template_shortcode'] ) ? $processed_data_array['template_shortcode'] : '',
'layout_name' => ! empty( $processed_data_array['et_pb_new_template_name'] ) ? sanitize_text_field( $processed_data_array['et_pb_new_template_name'] ) : '',
);
// construct the initial shortcode for new layout.
switch ( $args['layout_type'] ) {
case 'row':
$args['layout_content'] = '[et_pb_row template_type="row"][/et_pb_row]';
break;
case 'section':
$args['layout_content'] = '[et_pb_section template_type="section"][et_pb_row][/et_pb_row][/et_pb_section]';
break;
case 'module':
$args['layout_content'] = '[et_pb_module_placeholder selected_tabs="all"]';
break;
case 'fullwidth_module':
$args['layout_content'] = '[et_pb_fullwidth_module_placeholder selected_tabs="all"]';
$args['module_width'] = 'fullwidth';
$args['layout_type'] = 'module';
break;
case 'fullwidth_section':
$args['layout_content'] = '[et_pb_section template_type="section" fullwidth="on"][/et_pb_section]';
$args['layout_type'] = 'section';
break;
case 'specialty_section':
$args['layout_content'] = '[et_pb_section template_type="section" specialty="on" skip_module="true" specialty_placeholder="true"][/et_pb_section]';
$args['layout_type'] = 'section';
break;
}
$new_layout_meta = et_pb_submit_layout( apply_filters( 'et_pb_new_layout_args', $args ) );
die( et_core_esc_previously( $new_layout_meta ) );
}
}
add_action( 'wp_ajax_et_pb_add_new_layout', 'et_pb_add_new_layout' );
if ( ! function_exists( 'et_pb_submit_layout' ) ) :
/**
* Handles saving layouts to the database for the builder. Essentially just a wrapper for
* {@see et_pb_create_layout()} that processes the data from the builder before passing it on.
*
* @since 1.0
*
* @param array $args {
* Layout Data.
*
* @type string $layout_type Accepts 'layout', 'section', 'row', 'module'.
* @type string $layout_selected_cats Categories to which the layout should be added. This should
* be one or more IDs separated by pipe symbols. Example: '1|2|3'.
* @type string $built_for_post_type The post type for which the layout was built.
* @type string $layout_new_cat Name of a new category to which the layout should be added.
* @type string $columns_layout When 'layout_type' is 'row', the row's columns structure. Example: '1_4'.
* @type string $module_type When 'layout_type' is 'module', the module type. Example: 'et_pb_blurb'.
* @type string $layout_scope Optional. The layout's scope. Accepts: 'global', 'not_global'.
* @type string $module_width When 'layout_type' is 'module', the module's width. Accepts: 'regular', 'fullwidth'.
* @type string $layout_content The layout's content (unprocessed shortcodes).
* @type string $layout_name The layout's name.
* }
*
* @return string $layout_data The 'post_id' and 'edit_link' for the saved layout (JSON encoded).
*/
function et_pb_submit_layout( $args ) {
/**
* Filters the layout data passed to {@see et_pb_submit_layout()}.
*
* @since 3.0.99
*
* @param string[] $args See {@see et_pb_submit_layout()} for array structure definition.
*/
$args = apply_filters( 'et_pb_submit_layout_args', $args );
if ( empty( $args ) ) {
return '';
}
$layout_cats_processed = array();
$layout_tags_processed = array();
if ( '' !== $args['layout_selected_cats'] ) {
$layout_cats_array = explode( ',', $args['layout_selected_cats'] );
$layout_cats_processed = array_map( 'intval', $layout_cats_array );
}
if ( '' !== $args['layout_selected_tags'] ) {
$layout_tags_array = explode( ',', $args['layout_selected_tags'] );
$layout_tags_processed = array_map( 'intval', $layout_tags_array );
}
$meta = array();
if ( 'row' === $args['layout_type'] && '0' !== $args['columns_layout'] ) {
$meta = array_merge( $meta, array( '_et_pb_row_layout' => $args['columns_layout'] ) );
}
if ( 'module' === $args['layout_type'] ) {
$meta = array_merge( $meta, array( '_et_pb_module_type' => $args['module_type'] ) );
// save unsynced options for global modules. Always empty for new modules.
if ( 'global' === $args['layout_scope'] ) {
$meta = array_merge( $meta, array( '_et_pb_excluded_global_options' => wp_json_encode( array() ) ) );
}
}
// et_layouts_built_for_post_type.
$meta = array_merge( $meta, array( '_et_pb_built_for_post_type' => $args['built_for_post_type'] ) );
$tax_input = array(
'scope' => $args['layout_scope'],
'layout_type' => $args['layout_type'],
'module_width' => $args['module_width'],
'layout_category' => $layout_cats_processed,
'layout_tag' => $layout_tags_processed,
'layout_location' => et_()->array_get_sanitized( $args, 'layout_location', 'local' ),
);
$new_layout_id = et_pb_create_layout( $args['layout_name'], $args['layout_content'], $meta, $tax_input, $args['layout_new_cat'], $args['layout_new_tag'] );
$new_post_data['post_id'] = (int) $new_layout_id;
$new_post_data['edit_link'] = esc_url_raw( get_edit_post_link( $new_layout_id ) );
$json_post_data = wp_json_encode( $new_post_data );
return $json_post_data;
}
endif;
if ( ! function_exists( 'et_pb_create_layout' ) ) :
/**
* Create new layout.
*
* @param string $name The layout name.
* @param string $content The layout content.
* @param array $meta The layout meta.
* @param array $tax_input Array of taxonomy terms keyed by their taxonomy name.
* @param string $new_category The layout category.
*/
function et_pb_create_layout( $name, $content, $meta = array(), $tax_input = array(), $new_category = '', $new_tag = '', $post_status = 'publish' ) {
$layout = array(
'post_title' => sanitize_text_field( $name ),
'post_content' => $content,
'post_status' => $post_status,
'post_type' => ET_BUILDER_LAYOUT_POST_TYPE,
);
$layout_id = wp_insert_post( $layout );
if ( ! empty( $meta ) ) {
foreach ( $meta as $meta_key => $meta_value ) {
add_post_meta( $layout_id, $meta_key, sanitize_text_field( $meta_value ) );
}
}
if ( '' !== $new_category ) {
// Multiple categories could be provided.
$category_names = explode( ',', $new_category );
foreach ( $category_names as $term_name ) {
$new_term = wp_insert_term( $term_name, 'layout_category' );
if ( ! is_wp_error( $new_term ) && isset( $new_term['term_id'] ) ) {
$tax_input['layout_category'][] = (int) $new_term['term_id'];
}
}
}
if ( '' !== $new_tag ) {
// Multiple tags could be provided.
$tag_names = explode( ',', $new_tag );
foreach ( $tag_names as $term_name ) {
$new_term = wp_insert_term( $term_name, 'layout_tag' );
if ( ! is_wp_error( $new_term ) && isset( $new_term['term_id'] ) ) {
$tax_input['layout_tag'][] = (int) $new_term['term_id'];
}
}
}
if ( ! empty( $tax_input ) ) {
foreach ( $tax_input as $taxonomy => $terms ) {
wp_set_post_terms( $layout_id, $terms, $taxonomy );
}
return $layout_id;
}
}
endif;
/**
* AJAX Callback :: Save layout to the database for the builder.
*/
function et_pb_save_layout() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
if ( empty( $_POST['et_layout_name'] ) ) {
die();
}
$args = array(
'layout_type' => isset( $_POST['et_layout_type'] ) ? sanitize_text_field( $_POST['et_layout_type'] ) : 'layout',
'layout_selected_cats' => isset( $_POST['et_layout_cats'] ) ? sanitize_text_field( $_POST['et_layout_cats'] ) : '',
'built_for_post_type' => isset( $_POST['et_post_type'] ) ? sanitize_text_field( $_POST['et_post_type'] ) : 'page',
'layout_new_cat' => isset( $_POST['et_layout_new_cat'] ) ? sanitize_text_field( $_POST['et_layout_new_cat'] ) : '',
'layout_new_tag' => isset( $_POST['et_layout_new_tag'] ) ? sanitize_text_field( $_POST['et_layout_new_tag'] ) : '',
'columns_layout' => isset( $_POST['et_columns_layout'] ) ? sanitize_text_field( $_POST['et_columns_layout'] ) : '0',
'module_type' => isset( $_POST['et_module_type'] ) ? sanitize_text_field( $_POST['et_module_type'] ) : 'et_pb_unknown',
'layout_scope' => isset( $_POST['et_layout_scope'] ) ? sanitize_text_field( $_POST['et_layout_scope'] ) : 'not_global',
'module_width' => isset( $_POST['et_module_width'] ) ? sanitize_text_field( $_POST['et_module_width'] ) : 'regular',
'layout_content' => isset( $_POST['et_layout_content'] ) ? $_POST['et_layout_content'] : '', // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- wp_insert_post function does sanitization.
'layout_name' => isset( $_POST['et_layout_name'] ) ? sanitize_text_field( $_POST['et_layout_name'] ) : '',
);
$new_layout_meta = et_pb_submit_layout( $args );
die( et_core_esc_previously( $new_layout_meta ) );
}
add_action( 'wp_ajax_et_pb_save_layout', 'et_pb_save_layout' );
/**
* AJAX Callback :: Get layouts.
*/
function et_pb_get_global_module() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$global_shortcode = array();
$utils = ET_Core_Data_Utils::instance();
$post_id = isset( $_POST['et_global_id'] ) ? (int) $_POST['et_global_id'] : '';
if ( empty( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) {
die( -1 );
}
$global_autop = isset( $_POST['et_global_autop'] ) ? sanitize_text_field( $_POST['et_global_autop'] ) : 'apply';
if ( ! empty( $post_id ) ) {
$query = new WP_Query(
array(
'p' => $post_id,
'post_type' => ET_BUILDER_LAYOUT_POST_TYPE,
)
);
if ( ! empty( $query->post ) ) {
// Call the_post() to properly configure post data. Make sure to call the_post() and
// wp_reset_postdata() only if the posts result exist to avoid unexpected issues.
$query->the_post();
wp_reset_postdata();
if ( 'skip' === $global_autop ) {
$post_content = $query->post->post_content;
} else {
$post_content = $query->post->post_content;
// do prep.
$post_content = et_pb_prep_code_module_for_wpautop( $post_content );
// wpautop does its "thing".
$post_content = wpautop( $post_content );
// undo prep.
$post_content = et_pb_unprep_code_module_for_wpautop( $post_content );
}
$global_shortcode['shortcode'] = et_core_intentionally_unescaped( $post_content, 'html' );
$excluded_global_options = get_post_meta( $post_id, '_et_pb_excluded_global_options' );
$selective_sync_status = empty( $excluded_global_options ) ? '' : 'updated';
$global_shortcode['sync_status'] = et_core_intentionally_unescaped( $selective_sync_status, 'fixed_string' );
// excluded_global_options is an array with single value which is json string, so just `sanitize_text_field`, because `esc_html` converts quotes and breaks the json string.
$global_shortcode['excluded_options'] = $utils->esc_array( $excluded_global_options, 'sanitize_text_field' );
}
}
if ( empty( $global_shortcode ) ) {
$global_shortcode['error'] = 'nothing';
}
$json_post_data = wp_json_encode( $global_shortcode );
die( et_core_esc_previously( $json_post_data ) );
}
add_action( 'wp_ajax_et_pb_get_global_module', 'et_pb_get_global_module' );
/**
* AJAX Callback :: Update layouts.
*/
function et_pb_update_layout() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$post_id = isset( $_POST['et_template_post_id'] ) ? absint( $_POST['et_template_post_id'] ) : '';
$new_content = isset( $_POST['et_layout_content'] ) ? $_POST['et_layout_content'] : ''; // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- wp_insert_post function does sanitization.
$layout_type = isset( $_POST['et_layout_type'] ) ? sanitize_text_field( $_POST['et_layout_type'] ) : '';
if ( empty( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) {
die( -1 );
}
$update = array(
'ID' => $post_id,
'post_content' => $new_content,
);
$result = wp_update_post( $update );
if ( ! $result || is_wp_error( $result ) ) {
wp_send_json_error();
}
ET_Core_PageResource::remove_static_resources( 'all', 'all' );
if ( 'module' === $layout_type && isset( $_POST['et_unsynced_options'] ) ) {
$unsynced_options = stripslashes( sanitize_text_field( $_POST['et_unsynced_options'] ) );
update_post_meta( $post_id, '_et_pb_excluded_global_options', $unsynced_options );
}
die();
}
add_action( 'wp_ajax_et_pb_update_layout', 'et_pb_update_layout' );
/**
* AJAX Callback :: Get/load layout.
*/
function et_pb_load_layout() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$layout_id = ! empty( $_POST['et_layout_id'] ) ? (int) $_POST['et_layout_id'] : 0;
if ( empty( $layout_id ) || ! current_user_can( 'edit_post', $layout_id ) ) {
die( -1 );
}
// sanitize via allowlisting.
$replace_content = isset( $_POST['et_replace_content'] ) && 'on' === $_POST['et_replace_content'] ? 'on' : 'off';
set_theme_mod( 'et_pb_replace_content', $replace_content );
$layout = get_post( $layout_id );
if ( $layout ) {
echo et_core_esc_previously( $layout->post_content );
}
die();
}
add_action( 'wp_ajax_et_pb_load_layout', 'et_pb_load_layout' );
/**
* AJAX Callback :: Delete layout.
*/
function et_pb_delete_layout() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
$layout_id = ! empty( $_POST['et_layout_id'] ) ? (int) $_POST['et_layout_id'] : '';
if ( empty( $layout_id ) ) {
die( -1 );
}
if ( ! current_user_can( 'delete_post', $layout_id ) ) {
die( -1 );
}
wp_delete_post( $layout_id );
die();
}
add_action( 'wp_ajax_et_pb_delete_layout', 'et_pb_delete_layout' );
/**
* Enables zlib compression if needed/supported.
*/
function et_builder_enable_zlib_compression() {
// If compression is already enabled, do nothing.
if ( 1 === intval( ini_get( 'zlib.output_compression' ) ) ) {
return;
}
// We need to be sure no content has been pushed yet before enabling compression
// to avoid decoding errors. To do so, we flush buffer and then check header_sent.
while ( ob_get_level() ) {
ob_end_flush();
}
if ( headers_sent() ) {
// Something has been sent already, could be PHP notices or other plugin output.
return;
}
// We use ob_gzhandler because less prone to errors with WP.
if ( function_exists( 'ob_gzhandler' ) ) {
// phpcs:ignore WordPress.PHP.IniSet -- Faster compression, requires less cpu/memory.
ini_set( 'zlib.output_compression_level', 1 );
ob_start( 'ob_gzhandler' );
}
}
/**
* AJAX Callback :: Get backbone templates.
*/
function et_pb_get_backbone_templates() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$post_type = isset( $_POST['et_post_type'] ) ? sanitize_text_field( $_POST['et_post_type'] ) : '';
$start_from = isset( $_POST['et_templates_start_from'] ) ? sanitize_text_field( $_POST['et_templates_start_from'] ) : 0;
$amount = ET_BUILDER_AJAX_TEMPLATES_AMOUNT;
// Enable zlib compression.
et_builder_enable_zlib_compression();
// get the portion of templates.
$result = wp_json_encode( ET_Builder_Element::output_templates( $post_type, $start_from, $amount ) );
die( et_core_intentionally_unescaped( $result, 'html' ) );
}
add_action( 'wp_ajax_et_pb_get_backbone_templates', 'et_pb_get_backbone_templates' );
/**
* Determine if a post is built by a certain builder.
*
* @param int $post_id The post_id to check.
* @param string $built_by_builder The builder to check if the post is built by. Allowed values: fb, bb.
*
* @return bool
*/
function et_builder_is_builder_built( $post_id, $built_by_builder ) {
$_post = get_post( $post_id );
// a autosave could be passed as $post_id, and an autosave will not have post_meta and then et_pb_is_pagebuilder_used() will always return false.
$parent_post = wp_is_post_autosave( $post_id ) ? get_post( $_post->post_parent ) : $_post;
if ( ! $post_id || ! $_post || ! is_object( $_post ) || ! et_pb_is_pagebuilder_used( $parent_post->ID ) ) {
return false;
}
// ensure this is an allowed builder post_type.
if ( ! in_array( $parent_post->post_type, et_builder_get_builder_post_types(), true ) ) {
return false;
}
// allowlist the builder slug.
$built_by_builder = in_array( $built_by_builder, array( 'fb', 'bb' ), true ) ? $built_by_builder : '';
// the built by slug prepended to the first section automatically, in this format: fb_built="1".
$pattern = '/^\[et_pb_section ' . $built_by_builder . '_built="1"/s';
return preg_match( $pattern, $_post->post_content );
}
/**
* Determine et-editor-available-post-$post_id cookie is set or not.
*
* @return bool
*/
function et_is_builder_available_cookie_set() {
static $builder_available = null;
if ( null !== $builder_available ) {
return $builder_available;
}
foreach ( (array) $_COOKIE as $cookie => $value ) {
if ( 0 === strpos( $cookie, 'et-editor-available-post-' ) ) {
$builder_available = true;
return $builder_available;
}
}
$builder_available = false;
return $builder_available;
}
/**
* Return heartbeat internal value.
*
* @return mixed|void
*/
function et_builder_heartbeat_interval() {
return apply_filters( 'et_builder_heartbeat_interval', 30 );
}
/**
* Ensure hearbeat interval set properly.
*
* @param array $response The Heartbeat response.
* @param string $screen_id The screen id.
*
* @return mixed
*/
function et_builder_ensure_heartbeat_interval( $response, $screen_id ) {
if ( ! current_user_can( 'edit_posts' ) ) {
return $response;
}
if ( ! isset( $response['heartbeat_interval'] ) ) {
return $response;
}
if ( et_builder_heartbeat_interval() === $response['heartbeat_interval'] ) {
return $response;
}
if ( ! et_is_builder_available_cookie_set() ) {
return $response;
}
$response['heartbeat_interval'] = et_builder_heartbeat_interval();
return $response;
}
add_filter( 'heartbeat_send', 'et_builder_ensure_heartbeat_interval', 100, 2 );
/**
* Sync during WP heartbeat to have BB check if changes are made outside of itself, and to re-init with changed content if changes occurred.
*
* @param array $response The Heartbeat response.
*
* @return mixed
*/
function et_pb_heartbeat_post_modified( $response ) {
et_core_nonce_verified_previously();
if ( ! current_user_can( 'edit_posts' ) ) {
return $response;
}
if ( empty( $_POST['data'] ) ) {
return $response;
}
// phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- sanitize_text_fields function does sanitization.
$heartbeat_data = et_()->sanitize_text_fields( $_POST['data'] );
$has_focus = isset( $_POST['has_focus'] ) && 'true' === $_POST['has_focus'] ? true : false;
$heartbeat_data_et = ! empty( $heartbeat_data['et'] ) ? $heartbeat_data['et'] : false;
if ( ! empty( $heartbeat_data_et ) ) {
$post_id = ! empty( $heartbeat_data_et['post_id'] ) ? absint( $heartbeat_data_et['post_id'] ) : '';
if ( empty( $heartbeat_data_et['post_id'] ) || ! current_user_can( 'edit_post', $post_id ) ) {
return $response;
}
$last_post_modified = sanitize_text_field( $heartbeat_data_et['last_post_modified'] );
$built_by = sanitize_text_field( $heartbeat_data_et['built_by'] );
$force_check = isset( $heartbeat_data_et['force_check'] ) && 'true' === $heartbeat_data_et['force_check'] ? true : false;
$force_autosave = isset( $heartbeat_data_et['force_autosave'] ) && 'true' === $heartbeat_data_et['force_autosave'] ? true : false;
$current_user_id = get_current_user_id();
$_post = get_post( $post_id );
if ( ! $post_id || ! $_post || ! is_object( $_post ) ) {
return $response;
}
// minimum sucessful response.
$response['et'] = array(
'received' => true,
'force_check' => $force_check,
'force_autosave' => $force_autosave,
);
// the editor in focus is not going to be receiving an update from the other editor
// so we can return early.
if ( $has_focus && ! $force_check ) {
$response['et']['action'] = 'No actions since this editor has focus'; // dev use.
return $response;
}
if ( $force_autosave ) {
$response['et']['action'] = 'No actions since this is a force autosave request'; // dev use.
return $response;
}
// from here down we know that the following logic applies to the editor
// currently *not* in focus, i.e. the one eligable for a potential sync update.
// sync builder settings.
$builder_settings_autosave = get_post_meta( $post_id, "_et_builder_settings_autosave_{$current_user_id}", true );
if ( ! empty( $builder_settings_autosave ) ) {
$response['et']['builder_settings_autosave'] = $builder_settings_autosave;
}
$post_content = $_post->post_content;
$post_modified = $_post->post_modified;
$autosave = wp_get_post_autosave( $post_id, $current_user_id );
$post_post_modified = gmdate( 'U', strtotime( $post_modified ) );
$response['et']['post_post_modified'] = $_post->post_modified;
if ( ! empty( $autosave ) ) {
$response['et']['autosave_exists'] = true;
$autosave_post_modified = gmdate( 'U', strtotime( $autosave->post_modified ) );
$response['et']['autosave_post_modified'] = $autosave->post_modified;
} else {
$response['et']['autosave_exists'] = false;
}
if ( ! empty( $autosave ) && $autosave_post_modified > $post_post_modified ) {
$response['et']['used_autosave'] = true;
$post_id = $autosave->ID;
$post_content = $autosave->post_content;
$post_modified = $autosave->post_modified;
} else {
$response['et']['used_autosave'] = false;
}
$response['et']['post_id'] = $post_id;
$response['et']['last_post_modified'] = $last_post_modified;
$response['et']['post_modified'] = $post_modified;
// security short circuit.
$_post = get_post( $post_id );
// $post_id could be an autosave.
$parent_post = wp_is_post_autosave( $post_id ) ? get_post( $_post->post_parent ) : $_post;
if ( ! et_pb_is_pagebuilder_used( $parent_post->ID ) || ! in_array( $parent_post->post_type, et_builder_get_builder_post_types(), true ) ) {
return $response;
}
// end security short circuit.
if ( $last_post_modified !== $post_modified ) {
// check if the newly modified was made by opposite builder,
// and if so, send it back in the response.
if ( 'bb' === $built_by ) {
// backend builder in use and in focus.
$response['et']['is_built_by_fb'] = et_builder_is_builder_built( $post_id, 'fb' );
// check if latest post_content is built by fb.
if ( et_builder_is_builder_built( $post_id, 'fb' ) ) {
if ( et_builder_bfb_enabled() ) {
$post_content_obj = et_fb_process_shortcode( $post_content );
$response['et']['post_content_obj'] = $post_content_obj;
} else {
$response['et']['post_content'] = $post_content;
}
$response['et']['action'] = 'current editor is bb, updated to content that was built by fb'; // dev use.
} else {
$response['et']['action'] = 'current editor is bb, content wasnt updated by fb'; // dev use.
}
} else {
// frontend builder in use and in focus.
$response['et']['is_built_by_bb'] = et_builder_is_builder_built( $post_id, 'bb' );
// check if latest post_content is built by bb.
if ( et_builder_is_builder_built( $post_id, et_builder_bfb_enabled() ? 'fb' : 'bb' ) ) {
$post_content_obj = et_fb_process_shortcode( $post_content );
$response['et']['post_content_obj'] = $post_content_obj;
$response['et']['action'] = 'current editor is fb, updated to content that was built by bb'; // dev use.
} else {
$response['et']['action'] = 'current editor is fb, content wasnt updated by bb'; // dev use.
}
}
$global_presets_manager = ET_Builder_Global_Presets_Settings::instance();
$response['et']['global_presets'] = $global_presets_manager->get_global_presets();
} else {
$response['et']['post_not_modified'] = true;
$response['et']['action'] = 'post content not modified externally'; // dev use.
}
}
return $response;
}
add_filter( 'heartbeat_send', 'et_pb_heartbeat_post_modified' );
/**
* Save a post submitted via ETBuilder Heartbeat.
*
* Adapted from WordPress
*
* @copyright 2016 by the WordPress contributors.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* This program incorporates work covered by the following copyright and
* permission notices:
*
* b2 is (c) 2001, 2002 Michel Valdrighi - m@tidakada.com - http://tidakada.com
*
* b2 is released under the GPL
*
* WordPress - Web publishing software
*
* Copyright 2003-2010 by the contributors
*
* WordPress is released under the GPL
*
* @param array $post_data Associative array of the submitted post data.
* @return mixed The value 0 or WP_Error on failure. The saved post ID on success.
* The ID can be the draft post_id or the autosave revision post_id.
*/
function et_fb_autosave( $post_data ) {
if ( ! defined( 'DOING_AUTOSAVE' ) ) {
define( 'DOING_AUTOSAVE', true );
}
$post_id = (int) $post_data['post_id'];
$post_data['ID'] = $post_id;
$post_data['post_ID'] = $post_id;
if ( false === wp_verify_nonce( $post_data['et_fb_autosave_nonce'], 'et_fb_autosave_nonce' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Error while saving.', 'et_builder' ) );
}
$_post = get_post( $post_id );
$current_user_id = get_current_user_id();
if ( ! et_fb_current_user_can_save( $post_id ) ) {
return new WP_Error( 'edit_posts', __( 'Sorry, you are not allowed to edit this item.', 'et_builder' ) );
}
// NOTE, no stripslashes() needed first as it's already been done on the POST'ed $post_data prior.
$shortcode_data = json_decode( $post_data['content'], true );
$options = array(
'post_type' => sanitize_text_field( $post_data['post_type'] ),
);
$post_data['content'] = et_fb_process_to_shortcode( $shortcode_data, $options );
if ( 'auto-draft' === $_post->post_status ) {
$post_data['post_status'] = 'draft';
}
if ( ! wp_check_post_lock( $_post->ID ) && get_current_user_id() === $_post->post_author && ( 'auto-draft' === $_post->post_status || 'draft' === $_post->post_status ) ) {
// Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked.
return edit_post( wp_slash( $post_data ) );
} else {
// Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user.
return wp_create_post_autosave( wp_slash( $post_data ) );
}
}
/**
* Autosave builder settings.
*
* @param integer $post_id post id.
* @param array $builder_settings builder settings.
*
* @return bool|int
*/
function et_pb_autosave_builder_settings( $post_id, $builder_settings ) {
$current_user_id = get_current_user_id();
// Builder settings autosave.
if ( ! empty( $builder_settings ) ) {
// Data is coming from `wp_ajax_heartbeat` which ran `wp_unslash` on it,
// `update_post_meta` will do the same, resulting in legit slashes being removed
// from page settings.
// The solution is to add those slashes back before updating metas.
$builder_settings = wp_slash( $builder_settings );
// Pseudo activate AB Testing for VB draft/builder-sync interface.
if ( isset( $builder_settings['et_pb_use_ab_testing'] ) ) {
// Save autosave/draft AB Testing status.
update_post_meta(
$post_id,
'_et_pb_use_ab_testing_draft',
sanitize_text_field( $builder_settings['et_pb_use_ab_testing'] )
);
// Format AB Testing data, since BB has UI and actual input IDs. FB uses BB's UI ID.
$builder_settings['et_pb_enable_ab_testing'] = $builder_settings['et_pb_use_ab_testing'];
// Unset BB's actual input data.
unset( $builder_settings['et_pb_use_ab_testing'] );
}
// Pseudo save AB Testing subjects for VB draft/builder-sync interface.
if ( isset( $builder_settings['et_pb_ab_subjects'] ) ) {
// Save autosave/draft subjects.
update_post_meta(
$post_id,
'_et_pb_ab_subjects_draft',
sanitize_text_field( et_prevent_duplicate_item( $builder_settings['et_pb_ab_subjects'], ',' ) )
);
// Format subjects data into array.
$builder_settings['et_pb_ab_subjects'] = array_unique( explode( ',', $builder_settings['et_pb_ab_subjects'] ) );
}
$et_builder_settings_autosave_data = get_post_meta( $post_id, "_et_builder_settings_autosave_{$current_user_id}", true );
// Merge incoming post meta changes with saved ones to avoid missing post meta changes that
// has been synced but hasn't been delivered to VB. Let VB drops autosave once it has been
// used / inserted into the layout.
if ( is_array( $et_builder_settings_autosave_data ) && is_array( $builder_settings ) ) {
$et_builder_settings_autosave_data = wp_parse_args(
$builder_settings,
$et_builder_settings_autosave_data
);
} else {
$et_builder_settings_autosave_data = $builder_settings;
}
return update_post_meta(
$post_id,
"_et_builder_settings_autosave_{$current_user_id}",
$et_builder_settings_autosave_data
);
}
}
/**
* Autosave with heartbeat.
*
* Adapted from WordPress.
*
* @copyright 2016 by the WordPress contributors.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* This program incorporates work covered by the following copyright and
* permission notices:
*
* b2 is (c) 2001, 2002 Michel Valdrighi - m@tidakada.com - http://tidakada.com
*
* b2 is released under the GPL
*
* WordPress - Web publishing software
*
* Copyright 2003-2010 by the contributors
*
* WordPress is released under the GPL
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
*
* @return array The Heartbeat response.
*/
function et_fb_heartbeat_autosave( $response, $data ) {
et_core_nonce_verified_previously();
if ( ! current_user_can( 'edit_posts' ) ) {
return $response;
}
if ( ! empty( $data['et_fb_autosave'] ) ) {
$post_id = ! empty( $data['et_fb_autosave']['post_id'] ) ? absint( $data['et_fb_autosave']['post_id'] ) : '';
if ( empty( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) {
return $response;
}
$has_focus = ! empty( $_POST['has_focus'] ) && 'true' === $_POST['has_focus'];
$force_autosave = ! empty( $data['et'] ) && ! empty( $data['et']['force_autosave'] ) && 'true' === $data['et']['force_autosave'];
$editor_1 = 'fb' === $data['et']['built_by'] ? 'fb' : 'bb';
$editor_2 = 'fb' === $editor_1 ? 'bb' : 'fb';
$editor_1_editing_cookie = isset( $_COOKIE[ 'et-editing-post-' . $post_id . '-' . $editor_1 ] ) ? sanitize_text_field( $_COOKIE[ 'et-editing-post-' . $post_id . '-' . $editor_1 ] ) : false;
$editor_2_editor_available_cookie = isset( $_COOKIE[ 'et-editor-available-post-' . $post_id . '-' . $editor_2 ] ) ? sanitize_text_field( $_COOKIE[ 'et-editor-available-post-' . $post_id . '-' . $editor_2 ] ) : false;
$editor_1_autosavable = ! empty( $editor_1_editing_cookie ) && empty( $editor_2_editor_available_cookie );
if ( ! $has_focus && ! $force_autosave && ! $editor_1_autosavable ) {
$response['et_fb_autosave'] = array(
'success' => false,
'message' => __( 'Not saved, editor out of focus', 'et_builder' ),
);
return $response;
}
$saved = et_fb_autosave( $data['et_fb_autosave'] );
if ( ! is_wp_error( $saved ) && ! empty( $data['et_fb_autosave']['builder_settings'] ) ) {
$builder_settings_autosaved = et_pb_autosave_builder_settings( $post_id, $data['et_fb_autosave']['builder_settings'] );
$response['et_pb_autosave_builder_settings'] = array(
'success' => $builder_settings_autosaved,
'message' => __( 'Builder settings synced', 'et_builder' ),
);
}
if ( is_wp_error( $saved ) ) {
$response['et_fb_autosave'] = array(
'success' => false,
'message' => $saved->get_error_message(),
);
} elseif ( empty( $saved ) ) {
$response['et_fb_autosave'] = array(
'success' => false,
'message' => __( 'Error while saving.', 'et_builder' ),
);
} else {
/* translators: draft saved date format, see https://secure.php.net/date */
$draft_saved_date_format = __( 'g:i:s a', 'et_builder' );
/* translators: %s: date and time */
$response['et_fb_autosave'] = array(
'success' => true,
// translators: %s date.
'message' => sprintf( __( 'Draft saved at %s.', 'et_builder' ), date_i18n( $draft_saved_date_format ) ),
);
}
}
return $response;
}
add_filter( 'heartbeat_received', 'et_fb_heartbeat_autosave', 499, 2 );
/**
* Builder settings autosave.
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
*
* @return mixed
*/
function et_bb_heartbeat_autosave( $response, $data ) {
et_core_nonce_verified_previously();
if ( ! current_user_can( 'edit_posts' ) ) {
return $response;
}
if ( ! empty( $data['wp_autosave'] ) ) {
$has_focus = ! empty( $_POST['has_focus'] ) && 'true' === $_POST['has_focus'];
$force_autosave = ! empty( $data['et'] ) && ! empty( $data['et']['force_autosave'] ) && 'true' === $data['et']['force_autosave'];
if ( ! $has_focus && ! $force_autosave ) {
$response['wp_autosave'] = array(
'success' => true,
'message' => __( 'Not saved, editor out of focus', 'et_builder' ),
);
remove_filter( 'heartbeat_received', 'heartbeat_autosave', 500, 2 );
remove_filter( 'heartbeat_received', 'et_bb_heartbeat_builder_settings_autosave', 500, 2 );
} elseif ( $force_autosave ) {
$response['wp_autosave_check'] = array(
'success' => true,
'message' => 'saved, because force_autosave ',
);
}
}
return $response;
}
add_filter( 'heartbeat_received', 'et_bb_heartbeat_autosave', 498, 2 );
/**
* Builder settings sync.
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
*
* @return mixed
*/
function et_bb_heartbeat_builder_settings_autosave( $response, $data ) {
if ( ! current_user_can( 'edit_posts' ) ) {
return $response;
}
if ( ! empty( $data['wp_autosave'] ) ) {
$post_id = ! empty( $data['wp_autosave']['post_id'] ) ? absint( $data['wp_autosave']['post_id'] ) : '';
if ( empty( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) {
return $response;
}
if ( ! empty( $data['wp_autosave']['builder_settings'] ) ) {
$builder_settings_autosaved = et_pb_autosave_builder_settings( $post_id, $data['wp_autosave']['builder_settings'] );
$response['et_pb_autosave_builder_settings'] = array(
'success' => $builder_settings_autosaved,
'message' => __( 'Builder settings synced', 'et_builder' ),
);
}
}
return $response;
}
add_filter( 'heartbeat_received', 'et_bb_heartbeat_builder_settings_autosave', 500, 2 );
/**
* Refresh nonces after user logs back in to an expired session.
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
* @param integer $screen_id The screen id.
*
* @return mixed
*/
function et_fb_wp_refresh_nonces( $response, $data, $screen_id ) {
if ( ! current_user_can( 'edit_posts' ) ) {
return $response;
}
if ( ! isset( $data['et']['built_by'] ) || 'fb' !== $data['et']['built_by'] ) {
return $response;
}
$response['et'] = array(
'exportUrl' => et_fb_get_portability_export_url(),
'nonces' => et_fb_get_nonces(),
'heartbeat_nonce' => wp_create_nonce( 'heartbeat-nonce' ),
);
return $response;
}
add_filter( 'wp_refresh_nonces', 'et_fb_wp_refresh_nonces', 10, 3 );
/**
* Return portability export url.
*
* @return string
*/
function et_fb_get_portability_export_url() {
$admin_url = is_ssl() ? admin_url() : admin_url( '', 'http' );
$args = array(
'et_core_portability' => true,
'context' => 'et_builder',
'name' => 'temp_name',
'nonce' => wp_create_nonce( 'et_core_portability_nonce' ),
);
return add_query_arg( $args, $admin_url );
}
/**
* Return FB nonces.
*
* @return array
*/
function et_fb_get_nonces() {
$nonces = apply_filters( 'et_fb_nonces', array() );
$fb_nonces = array(
'moduleContactFormSubmit' => wp_create_nonce( 'et-pb-contact-form-submit' ),
'et_admin_load' => wp_create_nonce( 'et_admin_load_nonce' ),
'computedProperty' => wp_create_nonce( 'et_pb_process_computed_property_nonce' ),
'renderShortcode' => wp_create_nonce( 'et_pb_render_shortcode_nonce' ),
'updateAssets' => wp_create_nonce( 'et_fb_update_helper_assets_nonce' ),
'loadAssets' => wp_create_nonce( 'et_fb_load_helper_assets_nonce' ),
'renderSave' => wp_create_nonce( 'et_fb_save_nonce' ),
'convertToShortcode' => wp_create_nonce( 'et_fb_convert_to_shortcode_nonce' ),
'dropAutosave' => wp_create_nonce( 'et_fb_drop_autosave_nonce' ),
'prepareShortcode' => wp_create_nonce( 'et_fb_prepare_shortcode_nonce' ),
'processImportedData' => wp_create_nonce( 'et_fb_process_imported_data_nonce' ),
'retrieveLibraryModules' => wp_create_nonce( 'et_fb_retrieve_library_modules_nonce' ),
'saveLibraryModules' => wp_create_nonce( 'et_fb_save_library_modules_nonce' ),
'splitLibraryItem' => wp_create_nonce( 'et_builder_split_library_item' ),
'clearTempPresets' => wp_create_nonce( 'et_fb_clear_temp_presets_nonce' ),
'saveCloudItemContent' => wp_create_nonce( 'et_fb_save_cloud_item_nonce' ),
'removeLibraryModules' => wp_create_nonce( 'et_fb_remove_library_modules_nonce' ),
'preview' => wp_create_nonce( 'et_pb_preview_nonce' ),
'autosave' => wp_create_nonce( 'et_fb_autosave_nonce' ),
'moduleEmailOptinFetchLists' => wp_create_nonce( 'et_builder_email_fetch_lists_nonce' ),
'moduleEmailOptinAddAccount' => wp_create_nonce( 'et_builder_email_add_account_nonce' ),
'moduleEmailOptinRemoveAccount' => wp_create_nonce( 'et_builder_email_remove_account_nonce' ),
'uploadFontNonce' => wp_create_nonce( 'et_fb_upload_font_nonce' ),
'abTestingReport' => wp_create_nonce( 'ab_testing_builder_nonce' ),
'libraryLayoutsData' => wp_create_nonce( 'et_builder_library_get_layouts_data' ),
'libraryGetLayout' => wp_create_nonce( 'et_builder_library_get_layout' ),
'libraryUpdateLayout' => wp_create_nonce( 'et_builder_library_update_layout' ),
'libraryConvertLayout' => wp_create_nonce( 'et_builder_library_convert_layout' ),
'libraryUpdateTerms' => wp_create_nonce( 'et_builder_library_update_terms' ),
'libraryUpdateLocation' => wp_create_nonce( 'et_builder_library_toggle_item_location' ),
'libraryUpdateAccount' => wp_create_nonce( 'et_builder_library_update_account' ),
'libraryGetCloudToken' => wp_create_nonce( 'et_builder_library_get_cloud_token' ),
'fetchAttachments' => wp_create_nonce( 'et_fb_fetch_attachments' ),
'droploaderProcess' => wp_create_nonce( 'et_builder_droploader_process_nonce' ),
'resolvePostContent' => wp_create_nonce( 'et_fb_resolve_post_content' ),
'searchProducts' => wp_create_nonce( 'et_builder_search_products' ),
'searchPosts' => wp_create_nonce( 'et_builder_search_posts' ),
'getPostsList' => wp_create_nonce( 'et_fb_get_posts_list' ),
'sendErrorReport' => wp_create_nonce( 'et_fb_send_error_report' ),
'saveGlobalPresetsHistory' => wp_create_nonce( 'et_builder_save_global_presets_history' ),
'retrieveGlobalPresetsHistory' => wp_create_nonce( 'et_builder_retrieve_global_presets_history' ),
'migrateModuleCustomizerPhaseTwo' => wp_create_nonce( 'et_builder_migrate_module_customizer_phase_two' ),
'getWoocommerceTabs' => wp_create_nonce( 'et_builder_get_woocommerce_tabs' ),
'getPostTypes' => wp_create_nonce( 'et_builder_ajax_get_post_types' ),
'getAuthors' => wp_create_nonce( 'et_builder_ajax_get_authors' ),
'getUserRoles' => wp_create_nonce( 'et_builder_ajax_get_user_roles' ),
'getCategories' => wp_create_nonce( 'et_builder_ajax_get_categories' ),
'getTags' => wp_create_nonce( 'et_builder_ajax_get_tags' ),
'searchProducts' => wp_create_nonce( 'et_builder_ajax_search_products' ),
'getDisplayConditionsStatus' => wp_create_nonce( 'et_builder_ajax_get_display_conditions_status' ),
'getPostMetaFields' => wp_create_nonce( 'et_builder_ajax_get_post_meta_fields' ),
'globalColorsSave' => wp_create_nonce( 'et_builder_global_colors_save' ),
'globalColorsGet' => wp_create_nonce( 'et_builder_global_colors_get' ),
'defaultColorsUpdate' => wp_create_nonce( 'et_builder_default_colors_update' ),
'saveDomainToken' => wp_create_nonce( 'et_builder_ajax_save_domain_token' ),
'beforeAfterComponents' => wp_create_nonce( 'et_fb_fetch_before_after_components_nonce' ),
'aiLayoutSaveDefaults' => wp_create_nonce( 'et_ai_layout_save_defaults' ),
'saveCustomizerFonts' => wp_create_nonce( 'et_pb_save_customizer_fonts_nonce' ),
);
return array_merge( $nonces, $fb_nonces );
}
if ( ! function_exists( 'et_builder_is_product_tour_enabled' ) ) :
/**
* Determine the product tour enabled or not.
*/
function et_builder_is_product_tour_enabled() {
static $product_tour_enabled = null;
if ( null !== $product_tour_enabled ) {
return $product_tour_enabled;
}
if ( ! ( function_exists( 'et_fb_is_enabled' ) && et_fb_is_enabled() ) ) {
// Do not update `$product_tour_enabled` at this point since we can run et_builder_is_product_tour_enabled() check later
// when et_fb_is_enabled() will be available.
return false;
}
/**
* Filters the on/off status of the product tour for the current user.
*
* @since 3.0.64
*
* @param string $product_tour_status_override Accepts 'on', 'off'.
*/
$product_tour_status_override = apply_filters( 'et_builder_product_tour_status_override', false );
if ( false !== $product_tour_status_override ) {
$product_tour_enabled = 'on' === $product_tour_status_override;
} else {
$user_id = (int) get_current_user_id();
$product_tour_settings = et_get_option( 'product_tour_status', array() );
$product_tour_status_global = 'on' === et_get_option( 'et_pb_product_tour_global', 'on' );
$product_tour_enabled = $product_tour_status_global && ( ! isset( $product_tour_settings[ $user_id ] ) || 'on' === $product_tour_settings[ $user_id ] );
}
return $product_tour_enabled;
}
endif;
/**
* Get module backbone template.
*/
function et_pb_get_backbone_template() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
die( -1 );
}
$module_slugs = isset( $_POST['et_modules_slugs'] ) ? json_decode( str_replace( '\\', '', sanitize_text_field( $_POST['et_modules_slugs'] ) ) ) : '';
$post_type = isset( $_POST['et_post_type'] ) ? sanitize_text_field( $_POST['et_post_type'] ) : '';
// Enable zlib compression.
et_builder_enable_zlib_compression();
// get the portion of templates for specified slugs.
$result = wp_json_encode( ET_Builder_Element::get_modules_templates( $post_type, $module_slugs->missing_modules_array ) );
die( et_core_esc_previously( $result ) );
}
add_action( 'wp_ajax_et_pb_get_backbone_template', 'et_pb_get_backbone_template' );
if ( ! function_exists( 'et_builder_email_add_account' ) ) :
/**
* Ajax handler for the Email Opt-in Module's "Add Account" action.
*/
function et_builder_email_add_account() {
et_core_security_check( 'manage_options', 'et_builder_email_add_account_nonce' );
$provider_slug = isset( $_POST['et_provider'] ) ? sanitize_text_field( $_POST['et_provider'] ) : '';
$name_key = "et_{$provider_slug}_account_name";
$account_name = isset( $_POST[ $name_key ] ) ? sanitize_text_field( stripslashes( $_POST[ $name_key ] ) ) : ''; // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- sanitize_text_field() function does sanitation.
if ( isset( $_POST['module_class'] ) && in_array( $_POST['module_class'], array( 'Signup', 'Contact_Form' ), true ) ) {
$module_class = sanitize_text_field( $_POST['module_class'] );
} else {
$module_class = 'Signup';
}
$is_bb = isset( $_POST['et_bb'] );
$is_spam_account = isset( $_POST['is_spam_account'] );
if ( empty( $provider_slug ) || empty( $account_name ) ) {
et_core_die();
}
unset( $_POST[ $name_key ] );
$fields = et_builder_email_get_fields_from_post_data( $provider_slug, $is_spam_account );
if ( false === $fields ) {
et_core_die();
}
if ( $is_spam_account ) {
$result = et_core_api_spam_add_account( $provider_slug, $account_name, $fields );
} else {
$result = et_core_api_email_fetch_lists( $provider_slug, $account_name, $fields );
}
$_ = ET_Core_Data_Utils::instance();
// Get data in builder format.
$list_data = et_builder_email_get_lists_field_data( $provider_slug, $is_bb, $module_class );
if ( 'success' === $result ) {
$result = array(
'error' => false,
'accounts_list' => $_->array_get( $list_data, 'accounts_list', $list_data ),
'custom_fields' => $_->array_get( $list_data, 'custom_fields', array() ),
'predefined_custom_fields' => ET_Core_API_Email_Providers::instance()->custom_fields_data(),
);
} elseif ( is_array( $result ) && isset( $result['redirect_url'] ) ) {
$result = array(
'error' => false,
'redirect_url' => $result['redirect_url'],
'accounts_list' => $_->array_get( $list_data, 'accounts_list', $list_data ),
'custom_fields' => $_->array_get( $list_data, 'custom_fields', array() ),
'predefined_custom_fields' => ET_Core_API_Email_Providers::instance()->custom_fields_data(),
);
} else {
$result = array(
'error' => true,
'message' => esc_html__( 'Error: ', 'et_builder' ) . esc_html( $result ),
'accounts_list' => $_->array_get( $list_data, 'accounts_list', $list_data ),
'custom_fields' => $_->array_get( $list_data, 'custom_fields', array() ),
'predefined_custom_fields' => ET_Core_API_Email_Providers::instance()->custom_fields_data(),
);
}
die( wp_json_encode( $result ) );
//phpcs:enable
}
add_action( 'wp_ajax_et_builder_email_add_account', 'et_builder_email_add_account' );
endif;
if ( ! function_exists( 'et_builder_finish_oauth2_authorization' ) ) :
/**
* Process the Email Optin OAuth2 authorization from builder / VB.
* This will be loaded in a popup window.
*
* @since 4.9.0
*
* @throws Exception If the Provider or Account not exists.
*
* @return void
*/
function et_builder_finish_oauth2_authorization() {
if ( ! isset( $_GET['et-core-api-email-auth'] ) || empty( esc_attr( $_GET['et-core-api-email-auth'] ) ) ) { // // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.NonceVerification.Recommended -- logic for nonce checks are following
return;
}
if ( ! isset( $_GET['state'] ) || 0 !== strpos( $_GET['state'], 'ET_Core' ) ) { // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.NonceVerification.Recommended -- logic for nonce checks are following
return;
}
$authenticated = false;
try {
et_core_nonce_verified_previously();
list( $_, $name, $account, $nonce ) = explode( '|', sanitize_text_field( rawurldecode( $_GET['state'] ) ) ); // @phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with sanitize_text_field
if ( ! $name || ! $account || ! $nonce ) {
return;
}
$_GET['nonce'] = $nonce;
et_core_security_check( 'manage_options', 'et_core_api_service_oauth2', 'nonce', '_GET' );
$providers = ET_Core_API_Email_Providers::instance();
if ( ! $providers->account_exists( $name, $account ) ) {
throw new Exception( __( 'Account not exists.', 'et_builder' ) );
}
$provider = $providers->get( $name, $account, 'builder' );
if ( ! $provider ) {
throw new Exception( __( 'Email provider not exists.', 'et_builder' ) );
}
$authenticated = $provider->is_authenticated();
if ( ! $authenticated ) {
$authenticated = $provider->authenticate();
}
} catch ( Exception $err ) {
$authenticated = false;
}
?>
account_fields( $provider_slug );
} else {
$fields = ET_Core_API_Email_Providers::instance()->account_fields( $provider_slug );
}
$result = array();
$protocol = is_ssl() ? 'https' : 'http';
if ( ! $fields ) {
// If there are no fields to check then the check passes.
return $fields;
}
foreach ( $fields as $field_name => $field_info ) {
$key = "et_{$provider_slug}_{$field_name}";
if ( empty( $_POST[ $key ] ) ) {
$required = true;
if ( isset( $field_info['required'] ) ) {
// Field can be required only when https or http.
$required = $field_info['required'] === $protocol;
}
if ( $required && ! isset( $field_info['not_required'] ) ) {
return false;
}
}
$result[ $field_name ] = sanitize_text_field( $_POST[ $key ] );
}
return $result;
}
endif;
if ( ! function_exists( 'et_builder_email_get_lists_field_data' ) ) :
/**
* Get email list data in a builder's options field format.
*
* @param string $provider_slug The email provider slug.
* @param bool $is_bb Whether is it backbend builder.
* @param string $module_class The ET_Builder_Module_ class suffix.
*
* @return array|string The data in the BB's format if `$is_bb` is `true`, the FB's format otherwise.
*/
function et_builder_email_get_lists_field_data( $provider_slug, $is_bb = false, $module_class = 'Signup' ) {
$module = 'ET_Builder_Module_' . $module_class;
$module = new $module();
$fields = $module->get_fields();
$field_name = $provider_slug . '_list';
$field = $fields[ $field_name ];
if ( $is_bb ) {
$field['only_options'] = true;
$field['name'] = $field_name;
$field_data = $module->render_field( $field );
} else {
$field_data = array(
'accounts_list' => $field['options'],
);
if ( 'Signup' === $module_class ) {
$signup_field = new ET_Builder_Module_Signup_Item();
$field_data['custom_fields'] = $signup_field->get_fields();
}
}
// phpcs:enable
et_pb_force_regenerate_templates();
et_fb_delete_builder_assets();
return $field_data;
}
endif;
if ( ! function_exists( 'et_builder_email_get_lists' ) ) :
/**
* Ajax handler for the Email Opt-in Module's "Fetch Lists" action.
*/
function et_builder_email_get_lists() {
et_core_security_check( 'manage_options', 'et_builder_email_fetch_lists_nonce' );
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- BB is common abbreviation.
$provider_slug = isset( $_POST['et_provider'] ) ? sanitize_text_field( $_POST['et_provider'] ) : '';
$account_name = isset( $_POST['et_account'] ) ? sanitize_text_field( stripslashes( $_POST['et_account'] ) ) : ''; // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- sanitize_text_field() function does sanitation.
$is_bb = isset( $_POST['et_bb'] );
if ( empty( $provider_slug ) || empty( $account_name ) ) {
et_core_die();
}
// Make sure email component group is loaded.
new ET_Core_API_Email_Providers();
$_ = ET_Core_Data_Utils::instance();
// Fetch lists from provider.
$message = et_core_api_email_fetch_lists( $provider_slug, $account_name );
// Get data in builder format.
$list_data = et_builder_email_get_lists_field_data( $provider_slug, $is_bb );
$result = array(
'error' => false,
'accounts_list' => $_->array_get( $list_data, 'accounts_list', $list_data ),
'custom_fields' => $_->array_get( $list_data, 'custom_fields', array() ),
'predefined_custom_fields' => ET_Core_API_Email_Providers::instance()->custom_fields_data(),
);
if ( 'success' !== $message ) {
$result['error'] = true;
$result['message'] = esc_html__( 'Error: ', 'et_core' ) . esc_html( $message );
}
die( wp_json_encode( $result ) );
// phpcs:enable
}
add_action( 'wp_ajax_et_builder_email_get_lists', 'et_builder_email_get_lists' );
endif;
if ( ! function_exists( 'et_builder_email_maybe_migrate_accounts' ) ) :
/**
* Migrate email provider credential.
*/
function et_builder_email_maybe_migrate_accounts() {
$divi_migrated_key = 'divi_email_provider_credentials_migrated';
$builder_migrated_key = 'email_provider_credentials_migrated';
$builder_options = (array) get_option( 'et_pb_builder_options' );
$builder_migrated = isset( $builder_options[ $builder_migrated_key ] );
$divi_migrated = false !== et_get_option( $divi_migrated_key, false );
$data_utils = ET_Core_Data_Utils::instance();
$migrations = array(
'builder' => $builder_migrated,
'divi' => $divi_migrated,
);
$providers = new ET_Core_API_Email_Providers(); // Ensure the email component group is loaded.
if ( $data_utils->all( $migrations, true ) ) {
// We've already migrated accounts data.
return;
}
foreach ( $migrations as $product => $completed ) {
if ( 'builder' === $product ) {
$account_name = 'Divi Builder Plugin';
$mailchimp_api_key = isset( $builder_options['newsletter_main_mailchimp_key'] ) ? $builder_options['newsletter_main_mailchimp_key'] : '';
$consumer_key = isset( $builder_options['aweber_consumer_key'] ) ? $builder_options['aweber_consumer_key'] : '';
$consumer_secret = isset( $builder_options['aweber_consumer_secret'] ) ? $builder_options['aweber_consumer_secret'] : '';
$access_key = isset( $builder_options['aweber_access_key'] ) ? $builder_options['aweber_access_key'] : '';
$access_secret = isset( $builder_options['aweber_access_secret'] ) ? $builder_options['aweber_access_secret'] : '';
} elseif ( 'divi' === $product ) {
$account_name = 'Divi Builder';
$mailchimp_api_key = et_get_option( 'divi_mailchimp_api_key' );
$consumer_key = et_get_option( 'divi_aweber_consumer_key' );
$consumer_secret = et_get_option( 'divi_aweber_consumer_secret' );
$access_key = et_get_option( 'divi_aweber_access_key' );
$access_secret = et_get_option( 'divi_aweber_access_secret' );
} else {
continue; // Satisfy code linter.
}
$aweber_key_parts = array( $consumer_key, $consumer_secret, $access_key, $access_secret );
if ( $data_utils->all( $aweber_key_parts ) ) {
// Typically AWeber tokens have five parts. We don't have the last part (the verifier token) because
// we didn't save it at the time it was originally input by the user. Thus, we add an additional separator
// (|) so that the token passes the processing performed by ET_Core_API_Email_Aweber::_parse_ID().
$aweber_api_key = implode( '|', array( $consumer_key, $consumer_secret, $access_key, $access_secret, '|' ) );
}
if ( ! empty( $mailchimp_api_key ) ) {
et_core_api_email_fetch_lists( 'MailChimp', "{$account_name} MailChimp", $mailchimp_api_key );
}
if ( ! empty( $aweber_api_key ) ) {
$aweber = $providers->get( 'Aweber', "{$account_name} Aweber", 'builder' );
$aweber->data['api_key'] = $aweber_api_key;
$aweber->data['consumer_key'] = $consumer_key;
$aweber->data['consumer_secret'] = $consumer_secret;
$aweber->data['access_key'] = $access_key;
$aweber->data['access_secret'] = $access_secret;
$aweber->data['is_authorized'] = true;
$aweber->save_data();
$aweber->fetch_subscriber_lists();
}
}
// Make sure the BB updates its cached templates.
et_pb_force_regenerate_templates();
$builder_options[ $builder_migrated_key ] = true;
update_option( 'et_pb_builder_options', $builder_options );
et_update_option( $divi_migrated_key, true );
}
endif;
if ( ! function_exists( 'et_builder_email_remove_account' ) ) :
/**
* Ajax handler for the Email Opt-in Module's "Remove Account" action.
*/
function et_builder_email_remove_account() {
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase -- BB is common abbreviation.
et_core_security_check( 'manage_options', 'et_builder_email_remove_account_nonce' );
$provider_slug = isset( $_POST['et_provider'] ) ? sanitize_text_field( $_POST['et_provider'] ) : '';
$account_name = isset( $_POST['et_account'] ) ? sanitize_text_field( stripslashes( $_POST['et_account'] ) ) : ''; // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- sanitize_text_field() function does sanitation.
if ( isset( $_POST['module_class'] ) && in_array( $_POST['module_class'], array( 'Signup', 'Contact_Form' ), true ) ) {
$module_class = sanitize_text_field( $_POST['module_class'] );
} else {
$module_class = 'Signup';
}
$is_bb = isset( $_POST['et_bb'] );
$is_spam_account = isset( $_POST['is_spam_account'] );
if ( empty( $provider_slug ) || empty( $account_name ) ) {
et_core_die();
}
if ( $is_spam_account ) {
et_core_api_spam_remove_account( $provider_slug, $account_name );
} else {
et_core_api_email_remove_account( $provider_slug, $account_name );
}
$_ = ET_Core_Data_Utils::instance();
// Get data in builder format.
$list_data = et_builder_email_get_lists_field_data( $provider_slug, $is_bb, $module_class );
$result = array(
'error' => false,
'accounts_list' => $_->array_get( $list_data, 'accounts_list', $list_data ),
'custom_fields' => $_->array_get( $list_data, 'custom_fields', array() ),
'predefined_custom_fields' => ET_Core_API_Email_Providers::instance()->custom_fields_data(),
);
die( wp_json_encode( $result ) );
// phpcs:enable
}
add_action( 'wp_ajax_et_builder_email_remove_account', 'et_builder_email_remove_account' );
endif;
if ( ! function_exists( 'et_pb_submit_subscribe_form' ) ) :
/**
* Ajax handler for Email Opt-in Module form submissions.
*/
function et_pb_submit_subscribe_form() {
et_core_security_check( '', 'et_frontend_nonce' );
$providers = ET_Core_API_Email_Providers::instance();
$utils = ET_Core_Data_Utils::instance();
$checksum = $utils->array_get_sanitized( $_POST, 'et_checksum' );
$use_spam_service = get_option( 'et_pb_signup_' . $checksum );
$provider_slug = $utils->array_get_sanitized( $_POST, 'et_provider' );
$account_name = stripslashes( $utils->array_get_sanitized( $_POST, 'et_account' ) );
$custom_fields = $utils->array_get( $_POST, 'et_custom_fields', array() );
$provider = $providers->get( $provider_slug, $account_name, 'builder' );
if ( ! $provider || ! $use_spam_service ) {
et_core_die( esc_html__( 'Configuration Error: Invalid data.', 'et_builder' ) );
}
$args = array(
'list_id' => $utils->array_get_sanitized( $_POST, 'et_list_id' ),
'email' => $utils->array_get_sanitized( $_POST, 'et_email' ),
'name' => $utils->array_get_sanitized( $_POST, 'et_firstname' ),
'last_name' => $utils->array_get_sanitized( $_POST, 'et_lastname' ),
'ip_address' => $utils->array_get_sanitized( $_POST, 'et_ip_address' ),
'custom_fields' => $utils->sanitize_text_fields( $custom_fields ),
);
if ( ! is_email( $args['email'] ) ) {
et_core_die( esc_html__( 'Please input a valid email address.', 'et_builder' ) );
}
if ( '' === (string) $args['list_id'] ) {
et_core_die( esc_html__( 'Configuration Error: No list has been selected for this form.', 'et_builder' ) );
}
$signup = ET_Builder_Element::get_module( 'et_pb_signup' );
if ( $signup && 'on' === $use_spam_service && $signup->is_spam_submission() ) {
et_core_die( esc_html__( 'You must be a human to submit this form.', 'et_builder' ) );
}
et_builder_email_maybe_migrate_accounts();
$result = $provider->subscribe( $args );
if ( 'success' === $result ) {
$result = array( 'success' => true );
} else {
$message = esc_html__( 'Subscription Error: ', 'et_builder' );
$result = array( 'error' => $message . $result );
}
die( wp_json_encode( $result ) );
}
add_action( 'wp_ajax_et_pb_submit_subscribe_form', 'et_pb_submit_subscribe_form' );
add_action( 'wp_ajax_nopriv_et_pb_submit_subscribe_form', 'et_pb_submit_subscribe_form' );
endif;
if ( ! function_exists( 'et_builder_has_limitation' ) ) :
/**
* Whether or not the builder currently has a certain limitation.
*
* @since 3.18
*
* @param string $limit The builder limitation key/slug.
*
* @return bool
*/
function et_builder_has_limitation( $limit ) {
if ( 'use_wrapped_styles' === $limit && et_builder_is_post_type_custom( get_post_type() ) ) {
return true;
}
if ( ! et_builder_is_limited_mode() ) {
return false;
}
$limited_builder = et_get_limited_builder();
$limited_builder_limits = et_get_limited_builder_defaults();
switch ( $limited_builder ) {
case 'divi-builder-plugin':
$limited_builder_limits = array_merge(
$limited_builder_limits,
array(
'use_wrapped_styles',
'force_use_global_important',
'use_limited_main',
'use_additional_limiting_styles',
'forced_icon_color_default',
'register_fittext_script',
)
);
break;
}
return in_array( $limit, $limited_builder_limits, true );
}
endif;
/**
* Get the defaults for limited builder limitations.
*
* @since 3.18
*
* @return string[]
*/
function et_get_limited_builder_defaults() {
return apply_filters(
'et_builder_get_limited_builder_defaults',
array(
'force_enqueue_theme_style',
)
);
}
/**
* Get the slug name of the current limited builder.
*
* @since 3.18
*
* @return string The slug name of the current limited builder.
*/
function et_get_limited_builder() {
// phpcs:ignore WordPress.Security.NonceVerification -- This function does not change any state, and is therefore not susceptible to CSRF.
$get = $_GET;
$bfb = '1' === et_()->array_get( $get, 'et_bfb', '0' );
$dbp = et_is_builder_plugin_active();
if ( $dbp ) {
return 'divi-builder-plugin';
}
if ( $bfb ) {
return 'bfb';
}
return '';
}
if ( ! function_exists( 'et_builder_is_limited_mode' ) ) :
/**
* Is Builder in limited mode?
*
* @since 3.18
*
* @return bool True - if the builder is in limited mode.
*/
function et_builder_is_limited_mode() {
$get = $_GET; // phpcs:ignore WordPress.Security.NonceVerification -- This function does not change any state, and is therefore not susceptible to CSRF.
return '' !== et_get_limited_builder();
}
endif;
if ( ! function_exists( 'et_is_builder_plugin_active' ) ) :
/**
* Is Builder plugin active?
*
* @since 3.18
* @deprecated ??
*
* @return bool True - if the plugin is active.
*/
function et_is_builder_plugin_active() {
return (bool) defined( 'ET_BUILDER_PLUGIN_ACTIVE' );
}
endif;
if ( ! function_exists( 'et_is_shortcodes_plugin_active' ) ) :
/**
* Is ET Shortcodes plugin active?
*
* @return bool True - if the plugin is active
*/
function et_is_shortcodes_plugin_active() {
return (bool) defined( 'ET_SHORTCODES_PLUGIN_VERSION' );
}
endif;
/**
* Saves the Role Settings into WP database
*
* @return void
*/
function et_pb_save_role_settings() {
if ( ! isset( $_POST['et_pb_save_roles_nonce'] ) || ! wp_verify_nonce( $_POST['et_pb_save_roles_nonce'], 'et_roles_nonce' ) ) { // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- wp_verify_nonce() function does sanitation.
die( -1 );
}
if ( ! current_user_can( 'manage_options' ) ) {
die( -1 );
}
// handle received data and convert json string to array.
$data_json = isset( $_POST['et_pb_options_all'] ) ? str_replace( '\\', '', sanitize_text_field( $_POST['et_pb_options_all'] ) ) : '';
$data = json_decode( $data_json, true );
$processed_options = array();
// convert settings string for each role into array and save it into et_pb_role_settings option.
if ( ! empty( $data ) ) {
$role_capabilities = array();
foreach ( $data as $role => $settings ) {
parse_str( $data[ $role ], $role_capabilities );
foreach ( $role_capabilities as $capability => $value ) {
$processed_options[ $role ][ $capability ] = $value;
}
}
}
update_option( 'et_pb_role_settings', $processed_options );
// set the flag to reload backbone templates and make sure all the role settings applied correctly right away.
et_update_option( 'et_pb_clear_templates_cache', true );
// Delete cached definitions / helpers.
et_fb_delete_builder_assets();
$response = array(
'success' => true,
);
wp_send_json( $response );
}
add_action( 'wp_ajax_et_pb_save_role_settings', 'et_pb_save_role_settings' );
/**
* Filter callback to determine what shortcodes tags are to be removed.
* Stips all non-builder shortcodes.
*
* @see strip_shortcodes_tagnames
*
* @param array $tags_to_remove An array of tags to be removed during strip_shortcodes() call.
*
* @return array An array of tags to be removed during strip_shortcodes() call.
*/
function et_pb_strip_non_builder_shortcodes_tagnames( $tags_to_remove ) {
// Initial allowlist.
$valid_tags = ET_Builder_Element::get_module_slugs_by_post_type();
/**
* What shortcode tags are valid (and safe) builder shortcodes,
* all other shortcodes will be stripped.
*
* @param array $valid_tags Array of valid shortcode tags.
*/
$valid_tags = apply_filters( 'et_pb_valid_builder_shortcodes', $valid_tags );
// Generate a blocklist, by subtracting the allowlist from all registered shortcodes.
$tags_to_remove = array_diff( $tags_to_remove, $valid_tags );
return $tags_to_remove;
}
if ( ! function_exists( 'et_is_yoast_seo_plugin_active' ) ) :
/**
* Is Yoast SEO plugin active?
*
* @return bool True - if the plugin is active.
*/
function et_is_yoast_seo_plugin_active() {
return class_exists( 'WPSEO_Options' );
}
endif;
/**
* Remove all non-builder shortcodes from builder built post content.
*
* @param string $content Builder built post content.
*
* @return string Sanitized builder built post content.
*/
function et_pb_enforce_builder_shortcode( $content ) {
add_filter( 'strip_shortcodes_tagnames', 'et_pb_strip_non_builder_shortcodes_tagnames' );
$content = strip_shortcodes( $content );
remove_filter( 'strip_shortcodes_tagnames', 'et_pb_strip_non_builder_shortcodes_tagnames' );
// this will parse the shortcode to an array, then run it back through some sanity check and sanitization and reform into a shortcode again.
$content = et_pb_sanitize_shortcode( $content, true );
return $content;
}
if ( ! function_exists( 'et_pb_register_posttypes' ) ) :
/**
* Register 'project' post type, 'project_category' and 'project_tag' taxonomies.
*/
function et_pb_register_posttypes() {
$labels = array(
'name' => esc_html__( 'Projects', 'et_builder' ),
'singular_name' => esc_html__( 'Project', 'et_builder' ),
'add_new' => esc_html__( 'Add New', 'et_builder' ),
'add_new_item' => esc_html__( 'Add New Project', 'et_builder' ),
'edit_item' => esc_html__( 'Edit Project', 'et_builder' ),
'new_item' => esc_html__( 'New Project', 'et_builder' ),
'all_items' => esc_html__( 'All Projects', 'et_builder' ),
'view_item' => esc_html__( 'View Project', 'et_builder' ),
'search_items' => esc_html__( 'Search Projects', 'et_builder' ),
'not_found' => esc_html__( 'Nothing found', 'et_builder' ),
'not_found_in_trash' => esc_html__( 'Nothing found in Trash', 'et_builder' ),
'parent_item_colon' => '',
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'can_export' => true,
'show_in_nav_menus' => true,
'query_var' => true,
'has_archive' => true,
'rewrite' => apply_filters(
'et_project_posttype_rewrite_args',
array(
'feeds' => true,
'slug' => 'project',
'with_front' => false,
)
),
'capability_type' => 'post',
'hierarchical' => false,
'menu_position' => null,
'show_in_rest' => true,
'supports' => array( 'title', 'author', 'editor', 'thumbnail', 'excerpt', 'comments', 'revisions', 'custom-fields' ),
);
register_post_type( 'project', apply_filters( 'et_project_posttype_args', $args ) );
$labels = array(
'name' => esc_html__( 'Project Categories', 'et_builder' ),
'singular_name' => esc_html__( 'Project Category', 'et_builder' ),
'search_items' => esc_html__( 'Search Categories', 'et_builder' ),
'all_items' => esc_html__( 'All Categories', 'et_builder' ),
'parent_item' => esc_html__( 'Parent Category', 'et_builder' ),
'parent_item_colon' => esc_html__( 'Parent Category:', 'et_builder' ),
'edit_item' => esc_html__( 'Edit Category', 'et_builder' ),
'update_item' => esc_html__( 'Update Category', 'et_builder' ),
'add_new_item' => esc_html__( 'Add New Category', 'et_builder' ),
'new_item_name' => esc_html__( 'New Category Name', 'et_builder' ),
'menu_name' => esc_html__( 'Categories', 'et_builder' ),
'not_found' => esc_html__( "You currently don't have any project categories.", 'et_builder' ),
);
$project_category_args = array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'show_in_rest' => true,
);
register_taxonomy( 'project_category', array( 'project' ), $project_category_args );
$labels = array(
'name' => esc_html__( 'Project Tags', 'et_builder' ),
'singular_name' => esc_html__( 'Project Tag', 'et_builder' ),
'search_items' => esc_html__( 'Search Tags', 'et_builder' ),
'all_items' => esc_html__( 'All Tags', 'et_builder' ),
'parent_item' => esc_html__( 'Parent Tag', 'et_builder' ),
'parent_item_colon' => esc_html__( 'Parent Tag:', 'et_builder' ),
'edit_item' => esc_html__( 'Edit Tag', 'et_builder' ),
'update_item' => esc_html__( 'Update Tag', 'et_builder' ),
'add_new_item' => esc_html__( 'Add New Tag', 'et_builder' ),
'new_item_name' => esc_html__( 'New Tag Name', 'et_builder' ),
'menu_name' => esc_html__( 'Tags', 'et_builder' ),
);
$project_tag_args = array(
'hierarchical' => false,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'show_in_rest' => true,
);
register_taxonomy( 'project_tag', array( 'project' ), $project_tag_args );
}
endif;
/**
* Determine whether to load backbone template or not.
*
* @return bool
*/
function et_admin_backbone_templates_being_loaded() {
if ( ! et_core_security_check_passed( '', 'et_admin_load_nonce' ) ) {
return false;
}
if ( ! is_admin() ) {
return false;
}
if ( ! wp_doing_ajax() ) {
return false;
}
if ( ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
return false;
}
if ( ! isset( $_POST['action'] ) || 'et_pb_get_backbone_templates' !== $_POST['action'] ) {
return false;
}
if ( ! current_user_can( 'edit_posts' ) ) {
return false;
}
return true;
}
if ( ! function_exists( 'et_pb_attempt_memory_limit_increase' ) ) :
/**
* AJAX Callback :: Increase memory limit from failure notice .
*/
function et_pb_attempt_memory_limit_increase() {
if ( ! isset( $_POST['et_admin_load_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_admin_load_nonce'] ), 'et_admin_load_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'manage_options' ) ) {
die( -1 );
}
if ( et_increase_memory_limit() ) {
et_update_option( 'set_memory_limit', '1' );
die(
wp_json_encode(
array(
'success' => true,
)
)
);
} else {
die(
wp_json_encode(
array(
'error' => true,
)
)
);
}
die();
}
endif;
add_action( 'wp_ajax_et_pb_increase_memory_limit', 'et_pb_attempt_memory_limit_increase' );
if ( ! function_exists( 'et_reset_memory_limit_increase' ) ) :
/**
* AJAX Callback :: Reset memory limit increase when automatic memory limit increase get disabled.
*/
function et_reset_memory_limit_increase() {
if ( ! isset( $_POST['et_builder_reset_memory_limit_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_POST['et_builder_reset_memory_limit_nonce'] ), 'et_builder_reset_memory_limit_nonce' ) ) {
die( -1 );
}
if ( ! current_user_can( 'manage_options' ) ) {
die( -1 );
}
if ( et_get_option( 'set_memory_limit' ) ) {
et_delete_option( 'set_memory_limit' );
}
die( 'success' );
}
endif;
add_action( 'wp_ajax_et_reset_memory_limit_increase', 'et_reset_memory_limit_increase' );
if ( ! function_exists( 'et_builder_get_core_modal_template' ) ) :
/**
* Return core modal template.
*/
function et_builder_get_core_modal_template() {
return '
';
}
endif;
if ( ! function_exists( 'et_builder_get_core_modal_buttons_template' ) ) :
/**
* Return core modal buttons template.
*/
function et_builder_get_core_modal_buttons_template() {
return '
%1$s
';
}
endif;
if ( ! function_exists( 'et_builder_get_cache_notification_modal' ) ) :
/**
* Return Builder Cache Warning modal template.
*/
function et_builder_get_cache_notification_modal() {
$cache_plugin_message = '';
$cache_plugin = et_pb_detect_cache_plugins();
if ( false !== $cache_plugin ) {
$cache_plugin_message = sprintf(
// translators: %1$s: cache plugin name.
esc_html__( 'You are using the %1$s plugin. We recommend clearing the plugin cache after updating your theme.', 'et_builder' ),
esc_html( $cache_plugin['name'] )
);
$cache_plugin_message = '' . $cache_plugin_message . '
';
if ( ! empty( $cache_plugin['page'] ) ) {
$cache_plugin_message .= sprintf(
'' . esc_html__( 'Builder files may also be cached in your browser. Please clear your browser cache.', 'et_builder' ) . '
';
$browser_cache_message .= sprintf(
' tags and \n that wpautop added!
$content = preg_replace( '/\n/smi', '', $content );
$content = preg_replace( '/
/smi', '', $content );
$content = preg_replace( '/<\/p>/smi', '', $content );
$content = str_replace( '', ' ', $content );
// convert the ', '
', $content );
return $content;
}
/**
* A preg_replace_callback callback.
*
* @param array $matches matched elements.
*
* @return string|string[]
*/
function _et_pb_code_module_unprep_content_regex_cb( $matches ) {
$prepped_content = $matches[1];
$prepped_content = _et_pb_code_module_unprep_content( $prepped_content );
return str_replace( $matches[1], $prepped_content, $matches[0] );
}
/**
* Undo prepared code module content.
*
* @param string $content Content from which to remove prepended.
*
* @return string|string[]|null
*/
function et_pb_unprep_code_module_for_wpautop( $content ) {
$content = preg_replace_callback( '/\[et_pb_code.*?\](.*)\[\/et_pb_code\]/mis', '_et_pb_code_module_unprep_content_regex_cb', $content );
$content = preg_replace_callback( '/\[et_pb_fullwidth_code.*?\](.*)\[\/et_pb_fullwidth_code\]/mis', '_et_pb_code_module_unprep_content_regex_cb', $content );
return $content;
}
/**
* Prepare code modules for wpautop.
*
* @param string $content Content to be prep.
*
* @return string|string[]|null
*/
function _et_pb_code_module_prep_content( $content ) {
// convert