: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// $css_element might be an array, for example to apply the css for placeholders
if ( is_array( $css_element ) ) {
foreach( $css_element as $selector ) {
$selector = self::$_->array_get( $option_settings, 'css.hover', $this->add_hover_to_selectors( $selector, $is_hover ) );
self::set_style( $function_name, array(
'declaration' => rtrim( $style ),
'priority' => $this->_style_priority,
$this->maybe_push_element_to_letter_spacing_fix_list( $selector, array( 'body.safari ', 'body.iphone ', 'body.uiwebview ' ), rtrim( $style ), $default_letter_spacing );
$css_element = self::$_->array_get( $option_settings, 'css.hover', $this->add_hover_to_selectors( $css_element, $is_hover ) );
self::set_style( $function_name, array(
'selector' => $css_element,
'declaration' => rtrim( $style ),
'priority' => $this->_style_priority,
$this->maybe_push_element_to_letter_spacing_fix_list( $css_element, array( 'body.safari ', 'body.iphone ', 'body.uiwebview ' ), rtrim( $style ), $default_letter_spacing );
self::set_style( $function_name, array(
'selector' => $this->_maybe_add_hover_to_order_class( $css_element . '::-webkit-input-placeholder', $is_hover ),
'declaration' => rtrim( $style ),
'priority' => $this->_style_priority,
self::set_style( $function_name, array(
'selector' => $this->_maybe_add_hover_to_order_class( $css_element . '::-moz-placeholder', $is_hover ),
'declaration' => rtrim( $style ),
'priority' => $this->_style_priority,
self::set_style( $function_name, array(
'selector' => $this->_maybe_add_hover_to_order_class( $css_element . '::-ms-input-placeholder', $is_hover ),
'declaration' => rtrim( $style ),
'priority' => $this->_style_priority,
// process mobile options
foreach( $mobile_options_slugs as $mobile_option ) {
$current_option_name = "{$option_name}_{$mobile_option}";
if ( isset( $font_options[ $current_option_name ] ) && '' !== $font_options[ $current_option_name ] ) {
$current_desktop_option = $this->remove_suffix($mobile_option);
$current_last_edited_slug = "{$option_name}_{$current_desktop_option}_last_edited";
$current_last_edited = isset( $font_options[ $current_last_edited_slug ] ) ? $font_options[ $current_last_edited_slug ] : '';
$current_responsive_status = et_pb_get_responsive_status( $current_last_edited );
// Don't print mobile styles if responsive UI isn't toggled on
if ( ! $current_responsive_status ) {
$current_media_query = false === strpos( $mobile_option, 'phone' ) ? 'max_width_980' : 'max_width_767';
$main_option_name = str_replace( array( '_tablet', '_phone' ), '', $mobile_option );
// 1. Generate CSS property.
$css_property = str_replace( '_', '-', $main_option_name );
if ( 'text_color' === $main_option_name ) {
$css_option_name = 'font-size' === $css_property ? 'size' : $css_property;
$important = in_array( $css_option_name, $important_options ) || $use_global_important ? ' !important' : '';
// As default, text color should be important on tablet and phone.
if ( 'text_color' === $main_option_name ) {
$important = ' !important';
// Allow specific selector tablet and mobile, simply add _tablet or _phone suffix
if ( isset( $option_settings['css'][ $mobile_option ] ) && "" !== $option_settings['css'][ $mobile_option ] ) {
$selector = $option_settings['css'][ $mobile_option ];
} elseif ( 'text_color' === $main_option_name && ! empty( $option_settings['css']['color'] ) ) {
// We define custom selector for text color as 'color', not 'text_color'.
$selector = $option_settings['css']['color'];
} elseif ( isset( $option_settings['css'][ $main_option_name ] ) || isset( $option_settings['css']['main'] ) ) {
$selector = isset( $option_settings['css'][ $main_option_name ] ) ? $option_settings['css'][ $main_option_name ] : $option_settings['css']['main'];
} elseif ( et_builder_has_limitation( 'use_limited_main' ) && ! empty( $option_settings['css']['limited_main'] ) ) {
$selector = $option_settings['css']['limited_main'];
$selector = $this->main_css_element;
// 3. Process value based on property name.
$text_range_inputs = array( 'font_size', 'line_height', 'letter_spacing' );
$processed_value = $font_options[ $current_option_name ];
if ( in_array( $main_option_name, $text_range_inputs ) ) {
$processed_value = et_builder_process_range_value( $font_options[ $current_option_name ] );
// 4. Declare CSS property, value, and important status.
if ( 'font' === $main_option_name ) {
$global_font_name = $this->get_global_setting_name( $current_option_name );
$global_font_value = ET_Global_Settings::get_value( $global_font_name );
$declaration = et_builder_set_element_font( $processed_value, ( '' !== $important ), $global_font_value );
esc_html( $css_property ),
esc_html( $processed_value ),
// Reset font style: italic/normal, uppercase/normal/smallcaps, underline/
// linethrough. There is a case where a font option group inherit font style
// value from another font option group. Most of the time, we can't toggle
// on/off the inherited options.
if ( 'font' === $main_option_name ) {
$processed_prev_value = et_pb_responsive_options()->get_default_value( $this->props, $current_option_name );
$reset_declaration = et_builder_set_reset_font_style( $processed_value, $processed_prev_value, '' !== $important );
$declaration .= ! empty( $reset_declaration ) ? $reset_declaration : '';
// $selector might be an array, for example to apply the css for placeholders
if ( is_array( $selector ) ) {
foreach( $selector as $selector_item ) {
self::set_style( $function_name, array(
'selector' => $selector_item,
'declaration' => $declaration,
'priority' => $this->_style_priority,
'media_query' => ET_Builder_Element::get_media_query( $current_media_query ),
self::set_style( $function_name, array(
'declaration' => $declaration,
'priority' => $this->_style_priority,
'media_query' => ET_Builder_Element::get_media_query( $current_media_query ),
if( ! empty( $selector ) && in_array( $mobile_option, array( 'letter_spacing_phone', 'letter_spacing_tablet' ) ) ) {
switch( $mobile_option ) {
case 'letter_spacing_phone':
$css_prefix = 'body.iphone ';
case 'letter_spacing_tablet':
$css_prefix = 'body.uiwebview ';
$this->maybe_push_element_to_letter_spacing_fix_list( $selector, $css_prefix, $declaration, $default_letter_spacing );
self::set_style( $function_name, array(
'selector' => $selector . '::-webkit-input-placeholder',
'declaration' => $declaration,
'priority' => $this->_style_priority,
'media_query' => ET_Builder_Element::get_media_query( $current_media_query ),
self::set_style( $function_name, array(
'selector' => $selector . '::-moz-placeholder',
'declaration' => $declaration,
'priority' => $this->_style_priority,
'media_query' => ET_Builder_Element::get_media_query( $current_media_query ),
self::set_style( $function_name, array(
'selector' => $selector . '::-ms-input-placeholder',
'declaration' => $declaration,
'priority' => $this->_style_priority,
'media_query' => ET_Builder_Element::get_media_query( $current_media_query ),
$sub_toggle = isset( $option_settings['sub_toggle'] ) ? $option_settings['sub_toggle'] : '';
// Ignore the process if the current module is Text since the process will be handled
if ( 'et_pb_text' !== $function_name ) {
// Build sub toggle selector.
$sub_toggle_selector = '';
if ( et_builder_has_limitation( 'use_limited_main' ) && ! empty( $option_settings['css']['limited_main'] ) ) {
$sub_toggle_selector = $option_settings['css']['limited_main'];
} elseif ( isset( $option_settings['css']['main'] ) ) {
$sub_toggle_selector = $option_settings['css']['main'];
// Additional ul and ol option slugs.
if ( in_array( $sub_toggle, array( 'ul', 'ol' ) ) ) {
$list_selector = '' !== $sub_toggle_selector ? $sub_toggle_selector : "{$this->main_css_element} {$sub_toggle}";
$list_type_name = "{$option_name}_type";
$is_list_type_responsive = et_pb_responsive_options()->is_responsive_enabled( $this->props, $list_type_name );
$list_type_values = array(
'desktop' => esc_html( et_pb_responsive_options()->get_any_value( $this->props, $list_type_name, '', false, 'desktop' ) ),
'tablet' => $is_list_type_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$list_type_name}_tablet" ) ) : '',
'phone' => $is_list_type_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$list_type_name}_tablet" ) ) : '',
et_pb_responsive_options()->generate_responsive_css( $list_type_values, $list_selector, 'list-style-type', $function_name, ' !important;', 'select' );
// Option ul / ol position.
$list_position_name = "{$option_name}_position";
$is_list_position_responsive = et_pb_responsive_options()->is_responsive_enabled( $this->props, $list_position_name );
$list_position_values = array(
'desktop' => esc_html( et_pb_responsive_options()->get_any_value( $this->props, $list_position_name ) ),
'tablet' => $is_list_position_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$list_position_name}_tablet" ) ) : '',
'phone' => $is_list_position_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$list_position_name}_phone" ) ) : '',
et_pb_responsive_options()->generate_responsive_css( $list_position_values, $list_selector, 'list-style-position', $function_name, '', 'select' );
// Option ul / ol indent.
$list_indent_name = "{$option_name}_item_indent";
$is_list_indent_responsive = et_pb_responsive_options()->is_responsive_enabled( $this->props, $list_indent_name );
$list_indent_values = array(
'desktop' => esc_html( et_pb_responsive_options()->get_any_value( $this->props, $list_indent_name ) ),
'tablet' => $is_list_indent_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$list_indent_name}_tablet" ) ) : '',
'phone' => $is_list_indent_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$list_indent_name}_phone" ) ) : '',
$list_item_indent_selector = et_()->array_get( $option_settings, 'css.item_indent', $list_selector );
et_pb_responsive_options()->generate_responsive_css( $list_indent_values, $list_item_indent_selector, 'padding-left', $function_name, ' !important;' );
// Additional quote option slugs.
if ( 'quote' === $sub_toggle ) {
$quote_selector = '' !== $sub_toggle_selector ? $sub_toggle_selector : "{$this->main_css_element} blockquote";
// Option quote border weight.
$border_weight_name = "{$option_name}_border_weight";
$is_border_weight_responsive = et_pb_responsive_options()->is_responsive_enabled( $this->props, $border_weight_name );
$border_weight_values = array(
'desktop' => esc_html( et_pb_responsive_options()->get_any_value( $this->props, $border_weight_name ) ),
'tablet' => $is_border_weight_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$border_weight_name}_tablet" ) ) : '',
'phone' => $is_border_weight_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$border_weight_name}_phone" ) ) : '',
et_pb_responsive_options()->generate_responsive_css( $border_weight_values, $quote_selector, 'border-width', $function_name );
// Option quote border weight on hover.
$border_weight_hover_value = et_pb_hover_options()->get_value( $border_weight_name, $this->props );
if ( '' !== $border_weight_hover_value && et_builder_is_hover_enabled( $border_weight_name, $this->props ) ) {
self::set_style( $function_name, array(
'selector' => "{$quote_selector}:hover",
'declaration' => sprintf(
'border-width: %1$s%2$s;',
esc_html( et_builder_process_range_value( $border_weight_hover_value ) ),
// Option quote border color.
$border_color_name = "{$option_name}_border_color";
$is_border_color_responsive = et_pb_responsive_options()->is_responsive_enabled( $this->props, $border_color_name );
$border_color_values = array(
'desktop' => esc_html( et_pb_responsive_options()->get_any_value( $this->props, $border_color_name ) ),
'tablet' => $is_border_color_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$border_color_name}_tablet" ) ) : '',
'phone' => $is_border_color_responsive ? esc_html( et_pb_responsive_options()->get_any_value( $this->props, "{$border_color_name}_phone" ) ) : '',
et_pb_responsive_options()->generate_responsive_css( $border_color_values, $quote_selector, 'border-color', $function_name, '', 'color' );
// Option quote border weight on hover.
$border_color_hover_value = et_pb_hover_options()->get_value( $border_color_name, $this->props );
if ( '' !== $border_color_hover_value && et_builder_is_hover_enabled( $border_color_name, $this->props ) ) {
self::set_style( $function_name, array(
'selector' => "{$quote_selector}:hover",
'declaration' => sprintf(
'border-color: %1$s%2$s;',
esc_html( $border_color_hover_value ),
// sets ligatures disabling for all selectors
// from the list $this->letter_spacing_fix_selectors
foreach ($this->letter_spacing_fix_selectors as $selector_with_prefix) {
self::set_style( $function_name, array(
'selector' => $selector_with_prefix,
'declaration' => 'font-variant-ligatures: no-common-ligatures;',
'priority' => $this->_style_priority
* Maybe push element to the letter spacing fix list
* @since 4.4.7 Checks a element for the having of the letter-spacing property,
* adds a prefix to all its selectors, push prefixed selector
* to the array ($this->letter_spacing_fix_selectors) of elements
* that need to have ligature fix (same elements will be overridden).
* @param string $selector CSS selector of the current element.
* @param array $css_prefixes array or string of CSS prefixes which will be added to the current element selector.
* @param string $declaration CSS declaration of the current element.
* @param string $default_letter_spacing default letter-spacing value at the current element.
function maybe_push_element_to_letter_spacing_fix_list( $selector, $css_prefixes, $declaration, $default_letter_spacing ) {
if ( false === strpos( trim( $declaration ), 'letter-spacing' ) || empty( $css_prefixes ) || empty( $selector ) ) {
$selectors = ! is_array( $selector ) ? array( $selector ) : $selector;
foreach ( $selectors as $selector ) {
if ( empty( $selector ) ) {
$css_value = str_replace( 'letter-spacing', '', $declaration );
$css_value = preg_replace( '/[^a-zA-Z0-9]/', '', $css_value );
if ( ! is_array( $css_prefixes ) ) {
$css_prefixes = array( $css_prefixes );
foreach ( $css_prefixes as $css_prefix ) {
$selector_with_prefix = '';
$selector_elements = explode( ',', $selector );
if ( is_array( $selector_elements ) && count( $selector_elements ) > 0 ) {
$selector_with_prefix = implode( ',', preg_filter( '/^/', $css_prefix, $selector_elements ) );
if ( ! empty( $selector_with_prefix ) ) {
$hash_id_for_fix_selectors = crc32( $selector_with_prefix );
// Checking: if the current value of the sector is the default,
// given that the default value can be set in a different css-unit
// (px, em, rem... etc) than the current value
// (for example, the predefined default value can be '0px', while the current selector value is '0em')
$maybe_selector_has_default_value = 0 === intval( $default_letter_spacing ) && 0 === intval( $css_value ) || ( $css_value === $default_letter_spacing );
if ( ! ( $maybe_selector_has_default_value ) ) {
$this->letter_spacing_fix_selectors[ $hash_id_for_fix_selectors ] = $selector_with_prefix;
} elseif ( isset ( $this->letter_spacing_fix_selectors[ $hash_id_for_fix_selectors ] ) ) {
// If the selector has a default value, should delete it from
// array of selectors ($this->letter_spacing_fix_selectors) that need to be fixed,
// if it was added earlier.
unset( $this->letter_spacing_fix_selectors[ $hash_id_for_fix_selectors ] );
* Process background CSS styles.
* @since 3.23 Add responsive support.
* @param string $function_name Module slug.
function process_advanced_background_options( $function_name ) {
// Disable if module doesn't set advanced_fields property and has no VB support
if ( ! $this->has_vb_support() && ! $this->has_advanced_fields ) {
if ( ! self::$_->array_get( $this->advanced_fields, 'background', false ) ) {
// Reset processed background
if ( $this->save_processed_background ) {
$this->processed_background = array();
$settings = $this->advanced_fields['background'];
$important = isset( $settings['css']['important'] ) && $settings['css']['important'] ? ' !important' : '';
// Possible values for use_background_* variables are true, false, or 'fields_only'
$has_background_color_toggle_options = $this->advanced_fields['background']['has_background_color_toggle'];
$use_background_color_gradient_options = $this->advanced_fields['background']['use_background_color_gradient'];
$use_background_image_options = $this->advanced_fields['background']['use_background_image'];
$use_background_color_options = $this->advanced_fields['background']['use_background_color'];
$use_background_color_reset_options = self::$_->array_get( $this->advanced_fields, 'background.use_background_color_reset', true );
// Place to store processed background. It will be compared with the smaller device background
// processed value to avoid rendering the same styles.
$processed_background_color = '';
$processed_background_image = '';
$gradient_properties_desktop = array();
$processed_background_blend = '';
$background_color_gradient_overlays_image_desktop = 'off';
// Store background images status because the process is extensive.
$background_image_status = array(
// Background Desktop, Tablet, and Phone.
foreach ( et_pb_responsive_options()->get_modes() as $device ) {
$is_desktop = 'desktop' === $device;
$suffix = ! $is_desktop ? "_{$device}" : '';
$has_background_color_gradient = false;
$has_background_image = false;
$has_background_gradient_and_image = false;
$is_background_color_gradient_disabled = false;
$is_background_image_disabled = false;
// Ensure responsive settings is enabled on mobile.
if ( ! $is_desktop && ! et_pb_responsive_options()->is_responsive_enabled( $this->props, 'background' ) ) {
$background_image_style = '';
$background_color_style = '';
$background_images = array();
$background_color_gradient_overlays_image = 'off';
// A. Background Gradient.
if ( $use_background_color_gradient_options && 'fields_only' !== $use_background_color_gradient_options ) {
$use_background_color_gradient = et_pb_responsive_options()->get_inheritance_background_value( $this->props, 'use_background_color_gradient', $device, 'background', $this->fields_unprocessed );
// 1. Ensure gradient color is active.
if ( 'on' === $use_background_color_gradient ) {
$background_color_gradient_overlays_image = et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_overlays_image{$suffix}", '', true );
$gradient_properties = array(
'type' => et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_type{$suffix}", '', true ),
'direction' => et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_direction{$suffix}", '', true ),
'radial_direction' => et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_direction_radial{$suffix}", '', true ),
'color_start' => et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_start{$suffix}", '', true ),
'color_end' => et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_end{$suffix}", '', true ),
'start_position' => et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_start_position{$suffix}", '', true ),
'end_position' => et_pb_responsive_options()->get_any_value( $this->props, "background_color_gradient_end_position{$suffix}", '', true ),
// Will be used as default of Gradient hover.
$gradient_properties_desktop = $gradient_properties;
$background_color_gradient_overlays_image_desktop = $background_color_gradient_overlays_image;
// Save background gradient into background images list.
$background_gradient = $this->get_gradient( $gradient_properties );
$background_images[] = $background_gradient;
// Save resulted gradient into property for later usage
if ( $this->save_processed_background ) {
et_()->array_set( $this->processed_background, "{$device}.gradient", $background_gradient );
// Flag to inform BG Color if current module has Gradient.
$has_background_color_gradient = true;
} else if ( 'off' === $use_background_color_gradient ) {
$is_background_color_gradient_disabled = true;
if ( $use_background_image_options && 'fields_only' !== $use_background_image_options ) {
$background_image = et_pb_responsive_options()->get_inheritance_background_value( $this->props, 'background_image', $device, 'background', $this->fields_unprocessed );
$parallax = et_pb_responsive_options()->get_any_value( $this->props, "parallax{$suffix}", 'off' );
// Featured image as background is in higher priority.
if ( $this->featured_image_background ) {
$featured_image = self::$_->array_get( $this->props, 'featured_image', '' );
$featured_placement = self::$_->array_get( $this->props, 'featured_placement', '' );
$featured_image_src_obj = wp_get_attachment_image_src( get_post_thumbnail_id( self::_get_main_post_id() ), 'full' );
$featured_image_src = isset( $featured_image_src_obj[0] ) ? $featured_image_src_obj[0] : '';
if ( 'on' === $featured_image && 'background' === $featured_placement && '' !== $featured_image_src ) {
$background_image = $featured_image_src;
// BG image and parallax status.
$is_background_image_active = '' !== $background_image && 'on' !== $parallax;
$background_image_status[ $device ] = $is_background_image_active;
// 1. Ensure image exists and parallax is off.