: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$flat[ $setting['id'] ] = $setting;
function et_theme_builder_get_template_setting_child_options( $parent, $include = array(), $search = '', $page = 1, $per_page = 30 ) {
$include = array_map( 'intval', $include );
if ( ! empty( $include ) ) {
$page = $page >= 1 ? $page : 1;
* Fires before loading child options from the database.
* @param string $parent_id
* @param string $child_type
* @param string $child_value
do_action( 'et_theme_builder_before_get_template_setting_child_options', $parent['id'], $parent['options']['type'], $parent['options']['value'] );
switch ( $parent['options']['type'] ) {
$posts = get_posts( array(
'post_type' => $parent['options']['value'],
'posts_per_page' => $per_page,
foreach ( $posts as $post ) {
$id = $parent['id'] . $post->ID;
'parent' => $parent['id'],
'label' => et_core_intentionally_unescaped( $post->post_title, 'react_jsx' ),
'title' => et_core_intentionally_unescaped( $post->post_name, 'react_jsx' ),
'priority' => $parent['priority'],
'validate' => $parent['validate'],
$terms = get_terms( array(
'taxonomy' => $parent['options']['value'],
'number' => -1 === $per_page ? false : $per_page,
'offset' => -1 !== $per_page ? ($page - 1) * $per_page : 0,
foreach ( $terms as $term ) {
$id = $parent['id'] . $term->term_id;
'parent' => $parent['id'],
'label' => et_core_intentionally_unescaped( $term->name, 'react_jsx' ),
'title' => et_core_intentionally_unescaped( $term->slug, 'react_jsx' ),
'priority' => $parent['priority'],
'validate' => $parent['validate'],
$users = get_users( array(
foreach ( $users as $user ) {
$id = $parent['id'] . $user->ID;
'parent' => $parent['id'],
'label' => et_core_intentionally_unescaped( $user->display_name, 'react_jsx' ),
'title' => et_core_intentionally_unescaped( $user->user_login, 'react_jsx' ),
'priority' => $parent['priority'],
'validate' => $parent['validate'],
$roles = wp_roles()->get_names();
foreach ( $roles as $role => $label ) {
$id = $parent['id'] . $role;
'parent' => $parent['id'],
'label' => et_core_intentionally_unescaped( $label, 'react_jsx' ),
'title' => et_core_intentionally_unescaped( $role, 'react_jsx' ),
'priority' => $parent['priority'],
'validate' => $parent['validate'],
* Fires after loading child options from the database.
* @param string $parent_id
* @param string $child_type
* @param string $child_value
do_action( 'et_theme_builder_after_get_template_setting_child_options', $parent['id'], $parent['options']['type'], $parent['options']['value'] );
* Get the template and its layouts, if any, for the given request.
* @param ET_Theme_Builder_Request $request Request to check against. Defaults to the current one.
* @param bool $cache Cache the result or not, regardless of whether any layouts should be loaded.
* @param bool $load_from_cache Load the cached result for the given post ID, if available.
* @return array Array of layouts or an empty array if no layouts should be loaded.
function et_theme_builder_get_template_layouts( $request = null, $cache = true, $load_from_cache = true ) {
if ( null === $request ) {
// Ignore TB templates when displaying posts intended for embedding.
if ( is_et_pb_preview() ) {
// Ignore TB templates when previewing.
$request = ET_Theme_Builder_Request::from_current();
if ( null === $request || ET_GB_Block_Layout::is_layout_block_preview() ) {
$cache_key = "{$request->get_type()}:{$request->get_subtype()}:{$request->get_id()}";
if ( $load_from_cache && isset( $store[ $cache_key ] ) ) {
return $store[ $cache_key ];
$post_type = ET_Theme_Builder_Request::TYPE_SINGULAR === $request->get_type() ? $request->get_subtype() : '';
if ( et_theme_builder_is_layout_post_type( $post_type ) ) {
// We are currently editing a layout in the VB.
$layouts = array_replace( array(
ET_THEME_BUILDER_TEMPLATE_POST_TYPE => 0,
ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE => array( 'id' => 0, 'enabled' => false, 'override' => true ),
ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE => array( 'id' => 0, 'enabled' => false, 'override' => true ),
ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE => array( 'id' => 0, 'enabled' => false, 'override' => true ),
$post_type => array( 'id' => $request->get_id(), 'enabled' => true, 'override' => true ),
// We are currently displaying a template in the FE.
$templates = et_theme_builder_get_theme_builder_templates( true );
$settings = et_theme_builder_get_flat_template_settings_options();
$template = $request->get_template( $templates, $settings );
if ( ! empty( $template ) ) {
$is_default = $template['default'];
$override_header = $template['layouts']['header']['override'];
$override_body = $template['layouts']['body']['override'];
$override_footer = $template['layouts']['footer']['override'];
// The Default Website Template has a special case - it should not take over if
// it does not override any areas otherwise it will take over ALL site pages.
if ( ! $is_default || $override_header || $override_body || $override_footer ) {
ET_THEME_BUILDER_TEMPLATE_POST_TYPE => $template['id'],
ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE => $template['layouts']['header'],
ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE => $template['layouts']['body'],
ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE => $template['layouts']['footer'],
* Filter template layouts.
$layouts = apply_filters( 'et_theme_builder_template_layouts', $layouts );
$store[ $cache_key ] = $layouts;
* Get whether TB overrides the specified layout for the current request.
* @param string $layout Layout post type.
function et_theme_builder_overrides_layout( $layout ) {
$layouts = et_theme_builder_get_template_layouts();
return ! empty( $layouts ) && $layouts[ $layout ]['override'];
* Get whether the specified layout will properly render the real post content.
function et_theme_builder_layout_has_post_content( $layout ) {
if ( ! $layout['override'] ) {
// The layout does not override the content so post content will render.
if ( $layout['enabled'] ) {
$content = get_post_field( 'post_content', $layout['id'] );
$modules = et_theme_builder_get_post_content_modules();
foreach ( $modules as $module ) {
if ( has_shortcode( $content, $module ) ) {
* Get the failure modal html for a template that overrides the body but does not display
* post content (e.g. Post Content module is missing or the body has been disabled).
* @param string $template_name
* @param boolean $layout_enabled
function et_theme_builder_get_failure_notification_modal( $template_name, $layout_enabled ) {
$i18n = require ET_BUILDER_DIR . 'frontend-builder/i18n/theme-builder.php';
$error = $i18n['This post has been assigned a template using the Theme Builder, however, the template being used does not contain a Post Content module.'];
$description = $i18n['A Post Content module is required in order to add unique content within the Theme Builder template.'];
if ( ! $layout_enabled ) {
$error = $i18n['Oops, it looks like the current Theme Builder Template body layout is disabled.'];
$description = $i18n['The body layout of a template should not be disabled if you wish to display and edit the content of individual posts using this layout.'];
'<div class="et-core-modal-overlay et-theme-builder-no-post-content et-core-active">
<div class="et-core-modal">
<div class="et-core-modal-header">
<h3 class="et-core-modal-title">%1$s</h3>
<a href="#" class="et-core-modal-close" data-et-core-modal="close"></a>
<div class="et-core-modal-content">
<div class="et_pb_prompt_buttons">
<span class="spinner"></span>
<a href="%6$s" class="et-core-modal-action">%5$s</a>
esc_html__( 'Missing Post Content Module', 'et_builder' ),
esc_html__( $error, 'et_builder' ),
esc_html__( $description, 'et_builder' ),
esc_html( sprintf( __( 'Current template: %1$s', 'et_builder' ), $template_name ) ),
esc_html__( 'Edit Theme Builder', 'et_builder' ),
esc_url( admin_url( 'admin.php?page=et_theme_builder' ) )
* Create or update a Theme Builder template.
* @param integer $theme_builder_id
* @param boolean $allow_default
function et_theme_builder_store_template( $theme_builder_id, $template, $allow_default ) {
$raw_post_id = $_->array_get( $template, 'id', 0 );
$post_id = is_numeric( $raw_post_id ) ? (int) $raw_post_id : 0;
$title = sanitize_text_field( $_->array_get( $template, 'title', '' ) );
$default = $allow_default && '1' === $_->array_get( $template, 'default', '1' );
$enabled = '1' === $_->array_get( $template, 'enabled', '1' );
$header_id = (int) $_->array_get( $template, 'layouts.header.id', 0 );
$header_enabled = (bool) $_->array_get( $template, 'layouts.header.enabled', true );
$body_id = (int) $_->array_get( $template, 'layouts.body.id', 0 );
$body_enabled = (bool) $_->array_get( $template, 'layouts.body.enabled', true );
$footer_id = (int) $_->array_get( $template, 'layouts.footer.id', 0 );
$footer_enabled = (bool) $_->array_get( $template, 'layouts.footer.enabled', true );
$use_on = array_map( 'sanitize_text_field', $_->array_get( $template, 'use_on', array() ) );
$exclude_from = array_map( 'sanitize_text_field', $_->array_get( $template, 'exclude_from', array() ) );
$exists = ET_THEME_BUILDER_TEMPLATE_POST_TYPE === get_post_type( $post_id ) && 'publish' === get_post_status( $post_id );
$autogenerated_title = '1' === $_->array_get( $template, 'autogenerated_title', '1' );
if ( ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE !== get_post_type( $header_id ) || 'publish' !== get_post_status( $header_id ) ) {
if ( ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE !== get_post_type( $body_id ) || 'publish' !== get_post_status( $body_id ) ) {
if ( ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE !== get_post_type( $footer_id ) || 'publish' !== get_post_status( $footer_id ) ) {
$post_id = wp_insert_post( array(
'post_type' => ET_THEME_BUILDER_TEMPLATE_POST_TYPE,
'post_status' => 'publish',
update_post_meta( $post_id, '_et_autogenerated_title', $autogenerated_title ? '1' : '0' );
update_post_meta( $post_id, '_et_default', $default ? '1' : '0' );
update_post_meta( $post_id, '_et_enabled', $enabled ? '1' : '0' );
update_post_meta( $post_id, '_et_header_layout_id', $header_id );
update_post_meta( $post_id, '_et_header_layout_enabled', $header_enabled ? '1' : '0' );
update_post_meta( $post_id, '_et_body_layout_id', $body_id );
update_post_meta( $post_id, '_et_body_layout_enabled', $body_enabled ? '1' : '0' );
update_post_meta( $post_id, '_et_footer_layout_id', $footer_id );
update_post_meta( $post_id, '_et_footer_layout_enabled', $footer_enabled ? '1' : '0' );
delete_post_meta( $post_id, '_et_use_on' );
foreach ( $use_on as $condition ) {
add_post_meta( $post_id, '_et_use_on', $condition );
delete_post_meta( $post_id, '_et_exclude_from' );
foreach ( $exclude_from as $condition ) {
add_post_meta( $post_id, '_et_exclude_from', $condition );
$templates = get_post_meta( $theme_builder_id, '_et_template', false );
if ( ! in_array( $post_id, $templates, true ) ) {
add_post_meta( $theme_builder_id, '_et_template', $post_id );
* Sanitize a Theme Builder template.
function et_theme_builder_sanitize_template( $template ) {
$autogenerated_title = $_->array_get( $template, 'autogenerated_title', '0' );
$default = $_->array_get( $template, 'default', '0' );
$enabled = $_->array_get( $template, 'enabled', '0' );
$use_on = $_->array_get( $template, 'use_on', array() );
$exclude_from = $_->array_get( $template, 'exclude_from', array() );
$header_enabled = $_->array_get( $template, 'layouts.header.enabled', '1' );
$body_enabled = $_->array_get( $template, 'layouts.body.enabled', '1' );
$footer_enabled = $_->array_get( $template, 'layouts.footer.enabled', '1' );
'title' => sanitize_text_field( $_->array_get( $template, 'title', '' ) ),
'autogenerated_title' => true === $autogenerated_title || '1' === $autogenerated_title,
'default' => true === $default || '1' === $default,
'enabled' => true === $enabled || '1' === $enabled,
'use_on' => array_map( 'sanitize_text_field', $use_on ),
'exclude_from' => array_map( 'sanitize_text_field', $exclude_from ),
'id' => (int) $_->array_get( $template, 'layouts.header.id', '0' ),
'enabled' => true === $header_enabled || '1' === $header_enabled,
'id' => (int) $_->array_get( $template, 'layouts.body.id', '0' ),
'enabled' => true === $body_enabled || '1' === $body_enabled,
'id' => (int) $_->array_get( $template, 'layouts.footer.id', '0' ),
'enabled' => true === $footer_enabled || '1' === $footer_enabled,
* Insert a Theme Builder layout post.
* @return integer|WP_Error
function et_theme_builder_insert_layout( $options ) {
$post_id = wp_insert_post(
'post_status' => 'publish',
'post_title' => 'Theme Builder Layout',
if ( is_wp_error( $post_id ) ) {
wp_set_object_terms( $post_id, 'layout', 'layout_type', true );
et_builder_enable_for_post( $post_id );
* Overrides cache post_type so that TB custom post types and 'page' share the same files.
* @param string $post_type
function et_theme_builder_cache_post_type( $post_type ) {
if ( et_theme_builder_is_layout_post_type( $post_type ) ) {
// Use a generic name for all Theme Builder post type modules
// as they are identical for most practical reasons.
add_filter( 'et_builder_cache_post_type', 'et_theme_builder_cache_post_type' );
* Decorate a page resource slug based on the current request and TB.
* @param integer|string $post_id
* @param string $resource_slug