: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$additional_fields .= sprintf( '<input id="%2$s" type="%11$s" class="%3$s%5$s et_pb_setting_mobile et_pb_setting_mobile_%9$s"%6$s%8$s%1$s data-device="%9$s" %4$s%10$s/>%7$s',
esc_attr( $field['id'] ) . '_' . $device_type,
esc_attr( $field['class'] ),
( $validate_number ? ' et-validate-number' : '' ), // #5
( $validate_number ? ' maxlength="3"' : '' ),
( ! empty( $field['additional_button'] ) ? $field['additional_button'] : '' ),
? sprintf( ' data-default="%1$s"', esc_attr( $default ) )
esc_attr( $device_type ),
$has_saved_value, // #10,
// Replace value HTML of last edited field. Last edited value maybe an empty
// string on some range input under Shadow settings.
$last_edited_value_html = $default_last_edited_is_arr
? ' value="<%%- typeof( %1$s ) !== \'undefined\' ? %2$s : \'%3$s\' %%>" '
$value_last_edited = sprintf(
esc_attr( $field_var_name . '_last_edited' ),
esc_attr( $field_var_name . '_last_edited' ),
$class_last_edited = array(
'et_pb_mobile_last_edited_field',
if ( ! empty( $field['responsive_affects'] ) ) {
$class_last_edited[] = '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'] )
// additional field to save the last edited field which will be opened automatically
$additional_fields .= sprintf( '<input id="%1$s" type="hidden" class="%3$s"%2$s%4$s>',
esc_attr( $field_name . '_last_edited' ),
esc_attr( implode( ' ', $class_last_edited ) ),
if ( 'range' === $field['type'] ) {
$range_value_html = $default_is_arr
? ' value="<%%- typeof( %1$s ) !== \'undefined\' ? %2$s :parseFloat(%3$s) %%>" '
: ' value="<%%- typeof( %1$s ) !== \'undefined\' ? %2$s : parseFloat(\'%3$s\') %%>" ';
esc_attr( $field_var_name ),
esc_attr( sprintf( 'parseFloat( %1$s )', $field_var_name ) ),
$fixed_range = isset($field['fixed_range']) && $field['fixed_range'];
$range_settings_html = '';
$range_properties = apply_filters( 'et_builder_range_properties', array( 'min', 'max', 'step' ) );
foreach ( $range_properties as $property ) {
if ( isset( $field['range_settings'][ $property ] ) ) {
$range_settings_html .= sprintf( ' %2$s="%1$s"',
esc_attr( $field['range_settings'][ $property ] ),
'<input type="range" data-name="%7$s" class="et-pb-main-setting et-pb-range%4$s%6$s" data-default="%2$s"%1$s%3$s%5$s %8$s />',
$need_mobile_options ? ' et_pb_setting_mobile et_pb_setting_mobile_desktop et_pb_setting_mobile_active' : '',
$need_mobile_options ? ' data-device="desktop"' : '',
$fixed_range ? ' et-pb-fixed-range' : '',
esc_attr( $field['name'] ),
if ( $need_mobile_options ) {
foreach( array( 'tablet', 'phone' ) as $device_type ) {
// additional data attribute to handle default values for the responsive options
$has_saved_value = sprintf( ' data-has_saved_value="<%%- typeof( %1$s ) !== \'undefined\' ? \'yes\' : \'no\' %%>" ',
esc_attr( $field_var_name . '_' . $device_type )
$value_mobile_range = sprintf(
esc_attr( $field_var_name . '_' . $device_type ),
esc_attr( sprintf( 'parseFloat( %1$s )', $field_var_name . '_' . $device_type ) ),
'<input type="range" class="et-pb-main-setting et-pb-range et_pb_setting_mobile et_pb_setting_mobile_%3$s%6$s" data-default="%1$s"%4$s%2$s data-device="%3$s"%5$s %7$s/>',
esc_attr( $device_type ),
$fixed_range ? ' et-pb-fixed-range' : '',
$field_el = $range_el . "\n" . $field_el;
if ( $need_mobile_options ) {
$field_el = $field_el . $additional_fields;
if ( isset( $field['has_preview'] ) && $field['has_preview'] ) {
'<%%= window.et_builder.options_template_output("option_preview_buttons") %%>
if ( $need_mobile_options ) {
$field_el = $mobile_settings_tabs . "\n" . $field_el;
$field_el .= '<span class="et-pb-mobile-settings-toggle"></span>';
if ( isset( $field['type'] ) && isset( $field['tab_slug'] ) && 'advanced' === $field['tab_slug'] && ! $is_custom_color ) {
$field_el .= $reset_button_html;
if ( isset( $field['after'] ) && ! $only_options ) {
$field_el .= $this->render_field_before_after_element( $field['after'] );
public function render_field_before_after_element( $elements ) {
$elements = is_array( $elements ) ? $elements : array( $elements );
foreach ( $elements as $element ) {
if ( ! empty( $element['attributes'] ) ) {
$this->process_html_attributes( $element, $attributes );
switch ( $element['type'] ) {
$class = isset( $element['class'] ) ? esc_attr( $element['class'] ) : '';
$text = isset( $element['text'] ) ? et_core_esc_previously( $element['text'] ) : '';
$field_el .= sprintf( '<button class="button %1$s"%2$s>%3$s</button>', $class, $attributes, $text );
function render_font_select( $name, $id = '', $group_label ) {
$options_output = '<%= window.et_builder.fonts_template() %>';
$font_weight_output = '<%= window.et_builder.fonts_weight_template() %>';
'<div class="et-pb-select-font-outer" data-group_label="%6$s">
<div class="et-pb-settings-custom-select-wrapper et-pb-settings-option-select-searchable">
<div class="et_pb_select_placeholder"></div>
<ul class="et-pb-settings-option-select et-pb-settings-option-select-advanced et-pb-main-setting">
<li class="et-pb-select-options-filter">
<input type="text" class="et-pb-settings-option-input et-pb-main-setting regular-text et-pb-menu-filter" placeholder="Search Fonts">
<li class="et_pb_selected_item_container select-option-item">
<li class="et-pb-option-subgroup et-pb-recent-fonts">
<p class="et-pb-subgroup-title">%4$s</p>
( ! empty( $id ) ? sprintf(' id="%s"', esc_attr( $id ) ) : '' ),
$options_output . "\n\t\t\t\t\t",
esc_html__( 'Recent', 'et_builder' ),
function render_select( $name, $options, $id = '', $class = '', $attributes = '', $field_type = '', $button_options = array(), $default = '', $only_options = false ) {
$processed_options = $options;
if ( 'select_with_option_groups' === $field_type ) {
foreach ( $processed_options as $option_group_name => $option_group ) {
$option_group_name = esc_attr( $option_group_name );
$options_output .= '0' !== $option_group_name ? "<optgroup label='{$option_group_name}'>" : '';
$options_output .= sprintf( '<%%= window.et_builder.options_template_output("select",%1$s,this.model.toJSON()) %%>',
'{select_name: "%1$s", list: %2$s, default: %3$s, }',
wp_json_encode( $option_group ),
$options_output .= '0' !== $option_group_name ? '</optgroup>' : '';
$class = rtrim( $class );
$class = rtrim( 'et-pb-main-setting ' . $class );
$options_output .= sprintf( '<%%= window.et_builder.options_template_output("select",%1$s,this.model.toJSON()) %%>',
'{select_name: "%1$s", list: %2$s, default: %3$s, }',
wp_json_encode( $options ),
<select name="%1$s"%2$s%3$s%4$s class="%3$s %8$s"%9$s>%5$s</select>
( ! empty( $id ) ? sprintf(' id="%s"', esc_attr( $id ) ) : '' ),
( ! empty( $class ) ? esc_attr( $class ) : '' ),
( ! empty( $attributes ) ? $attributes : '' ),
$options_output . "\n\t\t\t\t\t",
'yes_no_button' === $field_type ?
'<div class="et_pb_yes_no_button_wrapper %2$s">
sprintf( '<%%= window.et_builder.options_template_output("yes_no_button",%1$s) %%>',
'on' => esc_html( $processed_options['on'] ),
'off' => esc_html( $processed_options['off'] ),
( ! empty( $button_options['button_type'] ) && 'equal' === $button_options['button_type'] ? ' et_pb_button_equal_sides' : '' )
'yes_no_button' === $field_type ? '</div>' : '',
'' !== $name ? sprintf( ' data-saved_value="<%%= typeof( %1$s ) !== \'undefined\' ? %1$s : \'\' %%>"', esc_attr( str_replace( '-', '_', $name ) ) ) : ''
return $only_options ? $options_output : $output;
function render_multiple_buttons( $name, $options, $id = '', $class = '', $attributes = '', $value = '', $default = '' ) {
$class = rtrim( 'et-pb-main-setting ' . $class );
'<div class="et_pb_multiple_buttons_wrapper">
<input id="%1$s" name="%7$s" type="hidden" class="%2$s" %3$s%5$s %4$s/>
? sprintf( ' data-default=%1$s', esc_attr( $default ) )
sprintf( '<%%= window.et_builder.options_template_output("multiple_buttons",%1$s) %%>',
wp_json_encode( $options )
function get_main_tabs() {
'general' => et_builder_i18n( 'Content' ),
'advanced' => et_builder_i18n( 'Design' ),
'custom_css' => et_builder_i18n( 'Advanced' ),
return apply_filters( 'et_builder_main_tabs', $tabs );
function get_validation_attr_rules() {
function get_validation_class_rules() {
function sort_fields( $fields ) {
$sorted_fields = array();
// Sort fields array by tab name
foreach ( $fields as $field_slug => $field_options ) {
// Option template replaces field's array configuration into string which refers to
// saved template data & template id; thus add index order if $field_options is array.
if ( is_array( $field_options ) ) {
$field_options['_order_number'] = $i;
$tab_slug = ! empty( $field_options['tab_slug'] ) ? $field_options['tab_slug'] : 'general';
$tabs_fields[ $tab_slug ][ $field_slug ] = $field_options;
// Sort fields within tabs by priority
foreach ( $tabs_fields as $tab_fields ) {
uasort( $tab_fields, array( 'self', 'compare_by_priority' ) );
$sorted_fields = array_merge( $sorted_fields, $tab_fields );
$toggle_all_options_slug = 'all_options';
$toggles_used = isset( $this->settings_modal_toggles );
$tabs_output = array( 'general' => array() );
$all_fields = $this->sort_fields( $this->_get_fields() );
$all_fields_keys = array_keys( $all_fields );
$background_fields_names = $this->get_background_fields_names();
$module_has_background_color_field = in_array( 'background_color', $all_fields_keys );
$all_toggles = self::get_toggles( 'post' );
foreach( $all_fields as $field_name => $field ) {
if ( ! empty( $field['type'] ) && ( 'skip' === $field['type'] || 'computed' === $field['type'] ) ) {
if ( ! self::$_->array_get( $field, 'bb_support', true ) ) {
// add only options allowed for current user
( ! et_pb_is_allowed( 'edit_colors' ) && ( ! empty( $field['type'] ) && in_array( $field['type'], array( 'color', 'color-alpha' ) ) || ( ! empty( $field['option_category'] ) && 'color_option' === $field['option_category'] ) ) )
( ! et_pb_is_allowed( 'edit_content' ) && ! empty( $field['option_category'] ) && 'basic_option' === $field['option_category'] )
( ! et_pb_is_allowed( 'edit_layout' ) && ! empty( $field['option_category'] ) && 'layout' === $field['option_category'] )
( ! et_pb_is_allowed( 'edit_configuration' ) && ! empty( $field['option_category'] ) && 'configuration' === $field['option_category'] )
( ! et_pb_is_allowed( 'edit_fonts' ) && ! empty( $field['option_category'] ) && ( 'font_option' === $field['option_category'] || ( 'button' === $field['option_category'] && ! empty( $field['type'] ) && 'font' === $field['type'] ) ) )
( ! et_pb_is_allowed( 'edit_buttons' ) && ! empty( $field['option_category'] ) && 'button' === $field['option_category'] )
( ! et_pb_is_allowed( 'edit_borders' ) && ! empty( $field['option_category'] ) && 'border' === $field['option_category'] )
// check for allowed 3rd party custom options categories
if ( ! empty( $field['option_category'] ) && ! et_pb_is_allowed( $field['option_category'] ) ) {
if ( 'background_color' === $field_name ) {
$background_fields_ui = $this->wrap_settings_background_fields( $all_fields );
// Append background fields UI if applicable. Append standard option otherwise
if ( '' !== $background_fields_ui ) {
// unset depends_show_if because background fields visibility handled in Background UI.
unset( $field['depends_show_if'] );
$option_output .= $background_fields_ui;
$field['skip_background_ui'] = true;
$option_output .= $this->wrap_settings_option_label( $field );
$option_output .= $this->wrap_settings_option_field( $field );
} elseif ( $module_has_background_color_field && in_array( $field_name , $background_fields_names ) ) {
// remove background-related fields from setting modals since it'll be printed by background UI
$option_output .= $this->wrap_settings_option_label( $field );
$option_output .= $this->wrap_settings_option_field( $field );
$tab_slug = ! empty( $field['tab_slug'] ) ? $field['tab_slug'] : 'general';
$is_toggle_option = isset( $field['toggle_slug'] ) && $toggles_used && isset( $this->settings_modal_toggles[ $tab_slug ] );
$toggle_slug = $is_toggle_option ? $field['toggle_slug'] : $toggle_all_options_slug;
$sub_toggle_slug = 'all_options' !== $toggle_slug && isset( $field['sub_toggle'] ) && '' !== $field['sub_toggle'] ? $field['sub_toggle'] : 'main';
$tabs_output[ $tab_slug ][ $toggle_slug ][ $sub_toggle_slug ][] = $this->wrap_settings_option( $option_output, $field, $field_name );
if ( isset( $field['toggle_slug'] ) && ! isset( $this->settings_modal_toggles[ $tab_slug ]['toggles'][ $toggle_slug ] ) ) {
if ( $toggle = self::$_->array_get( $all_toggles, "{$this->slug}.{$tab_slug}.toggles.{$field['toggle_slug']}" ) ) {
self::$_->array_set( $this->settings_modal_toggles, "{$tab_slug}.toggles.{$toggle_slug}", $toggle );
$default_tabs_keys = array_keys( $this->main_tabs );
$module_tabs_keys = array_keys( $tabs_output );
$module_default_tabs = array_intersect( $default_tabs_keys, $module_tabs_keys );
$module_custom_tabs = array_diff( $module_tabs_keys, $default_tabs_keys );
// Make sure tabs order is correct for BB, i.e. custom tabs goes after default tabs and default tabs in following order:
// `Content`, `Design`, `Advanced`
$module_tabs_sorted = array_merge( $module_default_tabs, $module_custom_tabs );
$tabs_output_processed = array();
// reorder tabs to be sure they're correct
foreach( $module_tabs_sorted as $tab_slug ) {
$tabs_output_processed[ $tab_slug ] = $tabs_output[ $tab_slug ];
foreach ( $tabs_output_processed as $tab_slug => $tab_settings ) {
// Add only tabs allowed for current user
if ( ! et_pb_is_allowed( $tab_slug . '_settings' ) ) {
$this->used_tabs[] = $tab_slug;
if ( isset( $tabs_output_processed[ $tab_slug ] ) ) {
// Group field with no explicit toggle_slug then append it on top of other toggles
if ( isset( $tabs_output_processed[ $tab_slug ][ $toggle_all_options_slug ] ) ) {
$toggle_unclassified_output = '';
foreach ( $tabs_output_processed[ $tab_slug ][ $toggle_all_options_slug ] as $no_toggle_option_data ) {
foreach( $no_toggle_option_data as $subtoggle_id => $no_toggle_option_output ) {
$toggle_unclassified_output .= $no_toggle_option_output;
'<div class="et-pb-options-toggle-container et-pb-options-toggle-disabled">
<h3 class="et-pb-option-toggle-title">%1$s</h3>
<div class="et-pb-option-toggle-content">
esc_html__( $this->name, 'et_builder' ),
et_core_esc_previously( $toggle_unclassified_output ),
'et-pb-options-toggle-disabled'
if ( isset( $this->settings_modal_toggles[ $tab_slug ] ) ) {
$this->settings_modal_toggles[ $tab_slug ]['toggles'] = self::et_pb_order_toggles_by_priority( $this->settings_modal_toggles[ $tab_slug ]['toggles'] );
foreach ( $this->settings_modal_toggles[ $tab_slug ]['toggles'] as $toggle_slug => $toggle_data ) {
$toggle_heading = is_array( $toggle_data ) ? $toggle_data['title'] : $toggle_data;