: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$bfb_settings = get_option( 'et_bfb_settings' );
$enabled = isset( $bfb_settings['enable_bfb'] ) && 'on' === $bfb_settings['enable_bfb'];
$toggled = isset( $bfb_settings['toggle_bfb'] ) && 'on' === $bfb_settings['toggle_bfb'];
if ( $enabled || $toggled ) {
// Enable BFB for all users.
et_builder_toggle_bfb( true );
// set the flag to not force toggle BFB more than once.
et_update_option( '', 'on', true, 'et_bfb_settings', 'toggle_bfb' );
set_transient( 'et_builder_show_bfb_welcome_modal', true, 0 );
add_action( 'after_switch_theme', 'et_builder_prepare_bfb' );
add_action( 'upgrader_process_complete', 'et_builder_prepare_bfb' );
add_action( 'activated_plugin', 'et_builder_prepare_bfb', 10, 0 );
add_action( 'deactivated_plugin', 'et_builder_prepare_bfb', 10, 0 );
* Add the divi builder body class.
function et_builder_add_body_class( $classes ) {
add_filter( 'body_class', 'et_builder_add_body_class' );
* Add builder inner content wrapper classes.
function et_builder_add_builder_inner_content_class( $classes ) {
$page_custom_gutter = get_post_meta( get_the_ID(), '_et_pb_gutter_width', true );
$valid_gutter_width = array( '1', '2', '3', '4' );
$gutter_width = in_array( $page_custom_gutter, $valid_gutter_width ) ? $page_custom_gutter : '3';
$classes[] = "et_pb_gutters{$gutter_width}";
add_filter( 'et_builder_inner_content_class', 'et_builder_add_builder_inner_content_class' );
* Get the opening wrappers for builder-powered content.
function et_builder_get_builder_content_opening_wrapper() {
$outer_class = apply_filters( 'et_builder_outer_content_class', array( 'et-boc' ) );
$outer_classes = implode( ' ', $outer_class );
$outer_id = apply_filters( 'et_builder_outer_content_id', 'et-boc' );
$is_dbp = et_is_builder_plugin_active();
$dbp_compat_wrapper_open = $is_dbp ? '<div id="et_builder_outer_content" class="et_builder_outer_content">' : '';
'<div id="%1$s" class="%2$s">
esc_attr( $outer_classes ),
et_core_intentionally_unescaped( $dbp_compat_wrapper_open, 'fixed_string' )
* Get the opening wrappers for individual builder-powered layouts.
function et_builder_get_layout_opening_wrapper() {
$post_type = get_post_type();
$layout_class = array( 'et-l' );
case ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE:
$layout_class[] = 'et-l--header';
case ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE:
$layout_class[] = 'et-l--body';
case ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE:
$layout_class[] = 'et-l--footer';
$layout_class[] = 'et-l--post';
$layout_id = apply_filters( 'et_builder_layout_id', $layout_id, $post_type );
$layout_id = !empty( $layout_id ) ? sprintf( 'id="%s" ', esc_attr( $layout_id ) ) : '';
$layout_class = apply_filters( 'et_builder_layout_class', $layout_class );
$layout_classes = implode( ' ', $layout_class );
$inner_class = apply_filters( 'et_builder_inner_content_class', array( 'et_builder_inner_content' ) );
$inner_classes = implode( ' ', $inner_class );
esc_attr( $layout_classes ),
esc_attr( $inner_classes ),
et_core_esc_previously( $layout_id )
* Get the closing wrappers for individual builder-powered layouts.
function et_builder_get_layout_closing_wrapper() {
$post_type = get_post_type();
case ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE:
case ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE:
</div><!-- .et_builder_inner_content -->
* Get the closing wrappers for builder-powered content.
function et_builder_get_builder_content_closing_wrapper() {
$is_dbp = et_is_builder_plugin_active();
$dbp_compat_wrapper_close = $is_dbp ? '</div><!-- .et_builder_outer_content -->' : '';
et_core_intentionally_unescaped( $dbp_compat_wrapper_close, 'fixed_string' )
* Wrap post builder content.
function et_builder_add_builder_content_wrapper( $content ) {
$is_bfb_new_page = isset( $_GET['is_new_page'] ) && '1' === $_GET['is_new_page'];
$has_layout_block = has_block( 'divi/layout', get_the_ID() );
if ( ! et_pb_is_pagebuilder_used( get_the_ID() ) && ! is_et_pb_preview() && ! $is_bfb_new_page && ! $has_layout_block ) {
// Divi builder layout should only be used in singular template unless we are rendering
// a theme builder layout as they can appear on any page.
if ( ! is_singular() && ! $is_bfb_new_page && ! et_theme_builder_is_layout_post_type( get_post_type( get_the_ID() ) ) ) {
$content = et_builder_get_layout_opening_wrapper() . $content . et_builder_get_layout_closing_wrapper();
* Filter whether to add the outer builder content wrapper or not.
$wrap = apply_filters( 'et_builder_add_outer_content_wrap', true );
$content = et_builder_get_builder_content_opening_wrapper() . $content . et_builder_get_builder_content_closing_wrapper();
add_filter( 'the_content', 'et_builder_add_builder_content_wrapper' );
add_filter( 'et_builder_render_layout', 'et_builder_add_builder_content_wrapper' );
* Wraps a copy of a css selector and then returns both selectors.
* Wrapping a copy of a selector instead of the original is necessary for selectors
* that target elements both inside AND outside the wrapper element.
* @param string $selector CSS selector to wrap.
* @param string $suffix Selector partial to add to the wrapped selector after the wrapper (a space will be added first).
* @param boolean $clone Duplicate the selector, wrap the duplicate, and then return both selectors. Default `true`.
function et_builder_maybe_wrap_css_selector( $selector, $suffix = '', $clone = true ) {
static $should_wrap_selectors = [];
$post_id = ET_Builder_Element::get_theme_builder_layout_id();
if ( ! isset( $should_wrap_selectors[ $post_id ] ) ) {
$is_builder_used = et_pb_is_pagebuilder_used( $post_id ) || has_block( 'divi/layout', get_the_ID() );
$should_wrap_selectors[ $post_id ] = et_is_builder_plugin_active() || et_builder_is_custom_post_type_archive() || ( $is_builder_used && ( et_builder_post_is_of_custom_post_type( $post_id ) || et_theme_builder_is_layout_post_type( get_post_type( $post_id ) ) ) );
if ( is_bool( $suffix ) ) {
if ( ! $should_wrap_selectors[ $post_id ] ) {
return trim( "{$selector} {$suffix}" );
$wrapper = ET_BUILDER_CSS_PREFIX;
$result .= $suffix ? "{$selector} {$suffix}, " : "{$selector}, ";
// $suffix param allows caller to split selector into two parts (1. outside builder and 2. inside builder)
// so that it can be wrapped properly. It was implemented before the regex solution below.
if ( preg_match( '/et_fb_preview|et_fb_desktop_mode/', $selector ) ) {
// Selector targets html element using a custom class
$result .= "{$selector} {$wrapper} {$suffix}";
// Selector targets body element either directly or using a custom class
$result .= "{$selector}{$wrapper} {$suffix}";
} else if ( preg_match('/^(html[^ ]*)?(?: *)(body[^ ]*)?(?: *)(.*?)(?: *)([^ ]*\.et[_-](?:pb|fb)[_-].+)/', $selector, $matches ) ) {
// The selector includes elements outside builder content so we can't just prepend the wrapper to it.
list( $_, $html, $body, $outside_builder, $inside_builder ) = $matches;
$parts = array_filter( array(
// Intentionally glued together to produce "body.et-db", for example.
$body . ET_BUILDER_CSS_WRAPPER_PREFIX,
ET_BUILDER_CSS_LAYOUT_PREFIX,
$result .= implode( ' ', $parts );
$result .= "{$wrapper} {$selector}";
* Wrapper for {@see et_builder_maybe_wrap_css_selector()} to support multiple selectors
* at once (eg. selector1, selector2, selector3)
* @param string $selector CSS selectors to wrap.
* @param bool $clone {@see et_builder_maybe_wrap_css_selector()}
function et_builder_maybe_wrap_css_selectors( $selector, $clone = true ) {
static $should_wrap_selectors = [];
$post_id = ET_Builder_Element::get_theme_builder_layout_id();
$wrap_post_id = $post_id;
if ( ! isset( $should_wrap_selectors[ $post_id ] ) ) {
if ( et_theme_builder_is_layout_post_type( get_post_type( $post_id ) ) ) {
$main_post_id = ET_Post_Stack::get_main_post_id();
$wrap_post_id = $main_post_id;
// GB editor + layout block is considered using builder
$is_builder_used = et_pb_is_pagebuilder_used( $wrap_post_id ) || has_block( 'divi/layout', get_the_ID() );
$should_wrap_selectors[ $post_id ] = et_is_builder_plugin_active() || et_builder_is_custom_post_type_archive() || ( $is_builder_used && et_builder_post_is_of_custom_post_type( $wrap_post_id ) );
if ( ! $should_wrap_selectors[ $post_id ] ) {
$selectors = explode( ',', $selector );
foreach ( $selectors as $css_selector ) {
$result[] = et_builder_maybe_wrap_css_selector( $css_selector, $clone );
return implode( ',', $result );
function _et_pb_code_module_unprep_content( $content ) {
// before we swap out the placeholders,
// remove all the <p> tags and \n that wpautop added!
$content = preg_replace( '/\n/smi', '', $content );
$content = preg_replace( '/<p>/smi', '', $content );
$content = preg_replace( '/<\/p>/smi', '', $content );
$content = str_replace( '<!–- [et_pb_br_holder] -–>', '<br />', $content );
// convert the <pee tags back to <p
// see et_pb_prep_code_module_for_wpautop()
$content = str_replace( '<pee', '<p', $content );
$content = str_replace( '</pee>', '</p> ', $content );
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] );
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 );
function _et_pb_code_module_prep_content( $content ) {
// convert <br /> tags into placeholder so wpautop will leave them alone
$content = preg_replace( '|<br[\s]?[\/]?>|', '<!–- [et_pb_br_holder] -–>', $content );
// convert <p> tag to <pee> tag, so wpautop will leave them alone,
// *and* so that we can clearly spot the <p> tags that wpautop adds
// so we can quickly remove them.
$content = preg_replace( '|<p |', '<pee ', $content );
$content = preg_replace( '|<p>|', '<pee>', $content );
$content = preg_replace( '|<\/p>|', '</pee>', $content );
function _et_pb_code_module_prep_content_regex_cb( $matches ) {
$prepped_content = $matches[1];
$prepped_content = _et_pb_code_module_prep_content( $prepped_content );
return str_replace( $matches[1], $prepped_content, $matches[0] );
function et_pb_prep_code_module_for_wpautop( $content ) {
$content = preg_replace_callback('/\[et_pb_code(?:(?![^\]]*\/\])[^\]]*)\](.*?)\[\/et_pb_code\]/mis', '_et_pb_code_module_prep_content_regex_cb', $content );
$content = preg_replace_callback('/\[et_pb_fullwidth_code(?:(?![^\]]*\/\])[^\]]*)\](.*?)\[\/et_pb_fullwidth_code\]/mis', '_et_pb_code_module_prep_content_regex_cb', $content );
function et_fb_dynamic_asset_exists( $prefix, $post_type = false ) {
// Get post type if it isn't being defined
$post_type = isset( $_REQUEST['et_post_type'] ) ? $_REQUEST['et_post_type'] : 'post';
$post_type = sanitize_text_field( $post_type );
$post_type = isset( $post->post_type ) ? $post->post_type : 'post';
$post_type = apply_filters( 'et_builder_cache_post_type', $post_type, $prefix );
$prefix = esc_attr( $prefix );
$cache = sprintf( '%s/%s', ET_Core_PageResource::get_cache_directory(), get_locale() );
$files = glob( sprintf( '%s/%s-%s-*.js', $cache, $prefix, $post_type ) );
return is_array( $files ) && count( $files ) > 0;
if ( ! function_exists( 'et_fb_delete_builder_assets' ) ):
function et_fb_delete_builder_assets() {
$cache = ET_Core_PageResource::get_cache_directory();
// Old cache location, make sure we clean that one too
$old_files = glob( sprintf( '%s/*.js', $cache ) );
$old_files = is_array( $old_files ) ? $old_files : array();
// New, per language location
$new_files = glob( sprintf( '%s/*/*.js', $cache ) );
$new_files = is_array( $new_files ) ? $new_files : array();
$modules_files = glob( sprintf( '%s/*/*.data', $cache ) );
$modules_files = is_array( $modules_files ) ? $modules_files : array();
foreach ( array_merge( $old_files, $new_files, $modules_files ) as $file ) {
$image_cache_keys = array(
'image_responsive_metadata',
'attachment_size_by_url',
foreach ( $image_cache_keys as $image_cache_key ) {
@unlink( ET_Core_Cache_File::get_cache_file_name( $image_cache_key ) );
do_action( 'et_builder_ajax_cache_clear' );
// Since Google data is included in static helpers, we have to delete assets
// whenever the option is updated to avoid Builder reloads.
add_action( 'update_option_et_google_api_settings', 'et_fb_delete_builder_assets' );
if ( ! function_exists( 'et_fb_enqueue_open_sans' ) ):
* @deprecated See {@see et_builder_enqueue_open_sans()}
function et_fb_enqueue_open_sans() {
$protocol = is_ssl() ? 'https' : 'http';
'family' => 'Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800',
'subset' => 'latin,latin-ext',
wp_enqueue_style( 'et-fb-fonts', esc_url_raw( add_query_arg( $query_args, "{$protocol}://fonts.googleapis.com/css" ) ), array(), null );
* Wrapper for et_core_portability_link() which does ET capability checks as well.
* @param string|array $attributes
function et_builder_portability_link( $context, $attributes = array() ) {
$product = (string) $shortname;
'et_builder' => 'et_builder_portability',
'et_builder_layouts' => 'et_builder_layouts_portability',
"et_{$product}_mods" => "et_{$product}_mods_portability",
'et_pb_roles' => 'et_pb_roles_portability',