: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
"{$base_name}_video_webm",
"{$base_name}_video_width",
"{$base_name}_video_height",
'computed_minimum' => array(
"{$base_name}_video_mp4",
"{$base_name}_video_webm",
'computed_variables' => array(
'base_name' => $base_name,
'mobile_options' => true,
foreach ( $options as $option_name => &$option ) {
$option['context'] = null == $context ? $base_name : $context;
* Get string of background fields UI. Used in place of background_color fields UI
* @param array list of all module fields
* @return string background fields UI
function wrap_settings_background_fields( $all_fields, $base_name = 'background' ) {
$tab_structure = $this->get_background_fields_structure( $base_name );
$tab_names = array_keys( $tab_structure );
$background_fields = $this->get_background_fields( $all_fields, $base_name );
// Concatenate background fields UI
'<label for="et_pb_background">%1$s</label>',
esc_html__( 'Background:', 'et_builder' )
'<div class="et-pb-option-container et-pb-option-container-inner et-pb-option-container--background" data-base_name="%s">',
$tab_names_processed = array();
foreach ( $tab_names as $tab_nav_name ) {
if ( ! empty( $background_fields[ $tab_nav_name ] ) ) {
$tab_names_processed[] = sanitize_text_field( $tab_nav_name );
// Apply background UI if the module has more than one backgroundFields to avoid 3rd party module's field which uses `background_color` field and incorrectly rendered as background UI
if ( count( $tab_names_processed ) < 2 ) {
$background .= sprintf( '<%%= window.et_builder.options_template_output("background_tabs_nav",%1$s) %%>', wp_json_encode( $tab_names_processed ) );
foreach ( $tab_names as $tab_name ) {
'<div class="et_pb_background-tab et_pb_background-tab--%1$s" data-tab="%1$s">',
$tab_fields = $background_fields[ $tab_name ];
// Render gradient tab's preview
if ( 'gradient' === $tab_name ) {
$background .= '<%= window.et_builder.options_template_output("background_gradient_buttons") %>';
foreach ( $tab_fields as $tab_field_name => $tab_field ) {
if ( 'skip' === $tab_field['type'] ) {
$tab_field['name'] = $tab_field_name;
// Append preview class name
if ( in_array( $tab_field['name'], array( "{$base_name}_color", "{$base_name}_image", "{$base_name}_url", "{$base_name}_video_mp4", "{$base_name}_video_webm" ) ) ) {
$tab_field['has_preview'] = true;
$preview_class = ' et-pb-option--has-preview';
// Prepare field list attribute
if ( isset( $tab_field['depends_show_if'] ) || isset( $tab_field['depends_show_if_not'] ) ) {
if ( isset( $tab_field['depends_show_if_not'] ) ) {
$depends_show_if_not = is_array( $tab_field['depends_show_if_not'] ) ? implode( ',', $tab_field['depends_show_if_not'] ) : $tab_field['depends_show_if_not'];
$depends_attr = sprintf( ' data-depends_show_if_not="%s"', esc_attr( $depends_show_if_not ) );
$depends_attr = sprintf( ' data-depends_show_if="%s"', esc_attr( $tab_field['depends_show_if'] ) );
'<div class="et_pb_background-option et_pb_background-option--%1$s et_pb_background-template--%6$s %5$s et-pb-option--%1$s%2$s"%3$s data-option_name="%4$s">',
esc_attr( $tab_field_name ),
esc_attr( $preview_class ),
esc_attr( $tab_field['name'] ),
$tab_field['name'] === "{$base_name}_color" && 'background' !== $base_name ? 'et-pb-option-main' : 'et-pb-option',
isset( $tab_field['field_template'] ) ? esc_attr( $tab_field['field_template'] ) : ''
// This adds a CSS class based on whether it is `true` or `false`
$this->is_background = true;
$background .= $this->wrap_settings_option_label( $tab_field );
$background .= $this->wrap_settings_option_field( $tab_field );
$this->is_background = false;
function get_field_name( $field ) {
// Option template convert array field into string id; return early to prevent error
if ( is_string( $field ) ) {
return $prefix . 'option_template_' . $field;
// Don't add 'et_pb_' prefix to the "Admin Label" field.
if ( 'admin_label' === $field['name'] ) {
// Make sure the prefix is not doubled.
if ( strpos( $field['name'], $prefix ) === 0 ) {
return $prefix . $field['name'];
* Get field name for use in underscore templates.
function get_field_variable_name( $field ) {
$name = $this->get_field_name( $field );
if ( isset( $this->type ) && 'child' === $this->type ) {
$name = str_replace( '-', '_', $name );
function process_html_attributes( $field, &$attributes ) {
if ( is_array( $field['attributes'] ) ) {
foreach( $field['attributes'] as $attribute_key => $attribute_value ) {
$attributes .= ' ' . esc_attr( $attribute_key ) . '="' . esc_attr( $attribute_value ) . '"';
$attributes = ' '.$field['attributes'];
* Returns an underscore template for the options settings.
* @since 3.23 Disable mobile options (responsive settings) on unsupported field types. It's
* added to adapt Options Harmony v2. Fix unexpected token because composite fields
* with range type load empty last edited value.
* @param array $field Associative array.
'description' => (string),
'validate_input' => (bool),
'option_category' => (string),
'attributes' => (string),
'display_if' => (string),
'depends_on' => (string),
'depends_show_if' => (string),
'depends_show_if_not' => (string),
'show_if_not' => (string),
'toggle_slug' => (string),
'composite_type' => (string),
'composite_structure' => (array),
* @return string HTML underscore template.
function render_field( $field, $name = '' ) {
$is_custom_color = isset( $field['custom_color'] ) && $field['custom_color'];
$reset_button_html = '<span class="et-pb-reset-setting"></span>';
$need_mobile_options = isset( $field['mobile_options'] ) && $field['mobile_options'] ? true : false;
$only_options = isset( $field['only_options'] ) ? $field['only_options'] : false;
$is_child = isset( $this->type ) && 'child' === $this->type;
// Option template convert array field into string id; return early to prevent error
if ( is_string( $field ) ) {
// Make sure 'type' is always set to prevent PHP notices
if ( empty( $field['type'] ) ) {
$field['type'] = 'no-type';
// Disable mobile options for unsupported types. Before Options Harmony v2, only custom
// margin/padding, text/number, and range support responsive settings. Later on, we added
// responsive settings to all settings. However BB is no longer supported, so we need to
// disable mobile options on those selected field types.
$unsupported_mobile_options = array( 'upload-gallery', 'background-field', 'warning', 'tiny_mce', 'codemirror', 'textarea', 'custom_css', 'options_list', 'sortable_list', 'conditional_logic', 'text_align', 'align', 'select', 'divider', 'yes_no_button', 'multiple_buttons', 'font', 'select_with_option_groups', 'select_animation', 'presets_shadow', 'select_box_shadow', 'presets', 'color', 'color-alpha', 'upload', 'checkbox', 'multiple_checkboxes', 'hidden' );
if ( $need_mobile_options && in_array( $field['type'], $unsupported_mobile_options ) ) {
$need_mobile_options = false;
if ( $need_mobile_options ) {
$mobile_settings_tabs = et_pb_generate_mobile_settings_tabs();
if ( 0 !== strpos( $field['type'], 'select' ) ) {
$classes = array( 'regular-text' );
foreach( $this->get_validation_class_rules() as $rule ) {
if ( ! empty( $field[ $rule ] ) ) {
$this->validation_in_use = true;
if ( isset( $field['validate_unit'] ) && $field['validate_unit'] ) {
$classes[] = 'et-pb-validate-unit';
if ( ! empty( $field['class'] ) ) {
if ( is_string( $field['class'] ) ) {
$field['class'] = array( $field['class'] );
$classes = array_merge( $classes, $field['class'] );
$field['class'] = implode(' ', $classes );
$field_name = $this->get_field_name( $field );
$field['id'] = ! empty( $field['id'] ) ? $field['id'] : $field_name;
$field['name'] = $field_name;
$field_name = "data.{$field_name}";
$field_var_name = $this->get_field_variable_name( $field );
$default_on_front = self::$_->array_get( $field, 'default_on_front', '' );
$default_arr = self::$_->array_get( $field, 'default', $default_on_front );
// Inform that default value is array and last edited value maybe empty string. Decided to
// create new variable, just in case $default_arr will be modified later.
$default_last_edited_is_arr = false;
if ( is_array( $default_arr ) && isset( $default_arr[1] ) && is_array( $default_arr[1] ) ) {
list($default_parent_id, $defaults_list) = $default_arr;
$default_parent_id = sprintf( '%1$set_pb_%2$s', $is_child ? 'data.' : '', $default_parent_id );
$default = esc_attr( wp_json_encode( $default_arr ) );
$default_value = sprintf(
'(typeof(%1$s) !== \'undefined\' ? ( typeof(%1$s) === \'object\' ? (%2$s)[jQuery(%1$s).val()] : (%2$s)[%1$s] ) : \'\')',
wp_json_encode( $defaults_list )
$default_last_edited_is_arr = true;
$default = $default_value = $default_arr;
if ( 'font' === $field['type'] ) {
$default = '' === $default ? '||||||||' : $default;
$default_value = '' === $default_value ? '||||||||' : $default_value;
$font_icon_options = array( 'et_pb_font_icon', 'et_pb_button_icon', 'et_pb_button_one_icon', 'et_pb_button_two_icon', 'et_pb_hover_icon' );
if ( in_array( $field_name, $font_icon_options ) ) {
$field_value = esc_attr( $field_var_name );
$field_value = esc_attr( $field_var_name ) . '.replace(/%91/g, "[").replace(/%93/g, "]").replace(/%22/g, "\"")';
$value_html = $default_is_arr
? ' value="<%%- typeof( %1$s ) !== \'undefined\' ? %2$s : %3$s %%>" '
: ' value="<%%- typeof( %1$s ) !== \'undefined\' ? %2$s : \'%3$s\' %%>" ';
esc_attr( $field_var_name ),
if ( ! empty( $field['attributes'] ) ) {
$this->process_html_attributes( $field, $attributes );
if ( ! empty( $field['affects'] ) ) {
$field['class'] .= ' et-pb-affects';
$attributes .= sprintf( ' data-affects="%s"', esc_attr( implode( ', ', $field['affects'] ) ) );
if ( ! empty( $field['responsive_affects'] ) ) {
$field['class'] .= ' et-pb-responsive-affects';
' data-responsive-affects="%1$s" data-responsive-desktop-name="%2$s"',
esc_attr( implode( ', ', $field['responsive_affects'] ) ),
esc_attr( $field['name'] )
if ( 'font' === $field['type'] ) {
$field['class'] .= ' et-pb-font-select';
if ( in_array( $field['type'], array( 'font', 'hidden', 'multiple_checkboxes', 'select_with_option_groups', 'select_animation', 'presets', 'presets_shadow', 'select_box_shadow' ) ) && ! $only_options ) {
'<input type="hidden" name="%1$s" id="%2$s" class="et-pb-main-setting %3$s" data-default="%4$s" %5$s %6$s/>',
esc_attr( $field['name'] ),
esc_attr( $field['id'] ),
esc_attr( $field['class'] ),
if ( 'select_with_option_groups' === $field['type'] ) {
// Since we are using a hidden field to manage the value, we need to clear the data-affects attribute so that
// it doesn't appear on both the `$field` AND the hidden field. This should probably be done for all of these
// field types but don't want to risk breaking anything :-/
$attributes = preg_replace( '/data-affects="[\w\s,-]*"/', 'data-affects=""', $attributes );
foreach ( $this->get_validation_attr_rules() as $rule ) {
if ( ! empty( $field[ $rule ] ) ) {
$this->validation_in_use = true;
$attributes .= ' data-rule-' . esc_attr( $rule ). '="' . esc_attr( $field[ $rule ] ) . '"';
if ( isset( $field['before'] ) && ! $only_options ) {
$field_el .= $this->render_field_before_after_element( $field['before'] );
switch( $field['type'] ) {
'<input type="button" class="button button-upload et-pb-gallery-button" value="%1$s" />' .
'<input type="hidden" name="%3$s" id="%4$s" class="et-pb-gallery" %2$s />',
esc_attr__( 'Update Gallery', 'et_builder' ),
esc_attr( $field['name'] ),
$field_el .= $this->wrap_settings_background_fields( $field['background_fields'], $field['base_name'] );
'<div class="et-pb-option-warning" data-name="%2$s" data-display_if="%3$s">%1$s</div>',
html_entity_decode( esc_html( $field['message'] ) ),
esc_attr( $field['name'] ),
esc_attr( $field['display_if'] )
if ( ! empty( $field['tiny_mce_html_mode'] ) ) {
$field['class'] .= ' html_mode';
$main_content_property_name = $main_content_field_name = 'et_pb_content';
if ( isset( $this->type ) && 'child' === $this->type ) {
$main_content_property_name = "data.{$main_content_property_name}";
if ( 'et_pb_signup' === $this->slug ) {
$main_content_property_name = $main_content_field_name = $field['name'];
'<div id="%1$s" class="et_pb_tiny_mce_field"><%%= typeof( %2$s ) !== \'undefined\' ? %2$s : \'\' %%></div>',
esc_attr( $main_content_field_name ),
esc_html( $main_content_property_name )
$field_custom_value = esc_html( $field_var_name );
if ( in_array( $field['type'], array( 'custom_css', 'options_list', 'sortable_list' ) ) ) {
$field_custom_value .= '.replace( /\|\|/g, "\n" ).replace( /%22/g, """ ).replace( /%92/g, "\\\" )';
$field_custom_value .= '.replace( /%91/g, "[" ).replace( /%93/g, "]" )';
if ( in_array( $field_name, array( 'et_pb_custom_message' ) ) ) {
// escape html to make sure it's not rendered inside the Textarea field in Settings Modal.
$field_custom_value = sprintf( '_.escape( %1$s )', $field_custom_value );
'<textarea class="et-pb-main-setting large-text code%1$s" rows="4" cols="50" id="%2$s"><%%= typeof( %3$s ) !== \'undefined\' ? %4$s : \'\' %%></textarea>',
esc_attr( $field['class'] ),
esc_attr( $field['id'] ),
esc_html( $field_var_name ),
et_core_esc_previously( $field_custom_value )
if ( 'options_list' === $field['type'] || 'sortable_list' === $field['type'] ) {
$row_class = 'et_options_list_row';
if ( isset( $field['checkbox'] ) && true === $field['checkbox'] ) {
$radio_check = '<a href="#" class="et_options_list_check"></a>';
$row_class .= ' et_options_list_row_checkbox';
if ( isset( $field['radio'] ) && true === $field['radio'] ) {
$radio_check = '<a href="#" class="et_options_list_check"></a>';
$row_class .= ' et_options_list_row_radio';
'<div class="et_options_list">
<div class="et_options_list_actions">
<a href="#" class="et_options_list_move"></a>
<a href="#" class="et_options_list_copy"></a>
<a href="#" class="et_options_list_remove"></a>
<textarea class="et-pb-main-setting large-text code%1$s" rows="4" cols="50" id="%2$s"><%%= typeof( %3$s ) !== \'undefined\' ? %4$s : \'\' %%></textarea>
<a href="#" class="et-pb-add-sortable-option"><span>%7$s</span></a>
esc_attr( $field['class'] ),
esc_attr( $field['id'] ),
esc_html( $field_var_name ),
et_core_esc_previously( $field_custom_value ),
esc_html__( 'Add New Item', 'et_builder' )