: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Remove suffix of a string
function remove_suffix( $string, $separator = '_' ) {
$stringAsArray = explode( $separator, $string );
array_pop( $stringAsArray );
return implode( $separator, $stringAsArray );
protected function _is_field_applicable( $field ) {
// Field can be undefined/empty in some 3rd party modules without VB support. Handle this situation
$depends_on = self::$_->array_get( $field, 'depends_on', false );
$depends_show_if = self::$_->array_get( $field, 'depends_show_if', false );
if ( $depends_on && $depends_show_if ) {
foreach ( $depends_on as $attr_name ) {
if ( $result && self::$_->array_get( $this->props, $attr_name ) !== $depends_show_if ) {
* @since 3.23 Add function to process advanced form field options set.
* @param string $function_name String of the function_name
function process_additional_options( $function_name ) {
if ( $function_name && $function_name !== $this->slug ) {
if ( ! $module = self::get_module( $function_name, $this->get_post_type() ) ) {
$module->props = $this->props;
$module->classname = $this->classname;
if ( ! isset( $module->advanced_fields ) || false === $module->advanced_fields ) {
$module->process_advanced_fonts_options( $function_name );
// Process Text Shadow CSS
$module->text_shadow->process_advanced_css( $module, $function_name );
$module->process_advanced_background_options( $function_name );
$module->process_advanced_text_options( $function_name );
$module->process_advanced_borders_options( $function_name );
$module->process_advanced_filter_options( $function_name );
$module->process_height_options( $function_name );
$module->process_overflow_options( $function_name );
$module->process_advanced_custom_margin_options( $function_name );
$module->process_max_width_options( $function_name );
$module->process_advanced_button_options( $function_name );
// Process Form Field CSS.
$module->process_advanced_form_field_options( $function_name );
$this->process_box_shadow( $function_name );
$this->process_position( $function_name );
$this->process_transform( $function_name );
// Process Margin & Padding CSS.
$module->margin_padding->process_advanced_css( $module, $function_name );
$this->setup_hover_transitions( $function_name );
function process_inline_fonts_option( $fonts_list ) {
if ( '' === $fonts_list ) {
$fonts_list_array = explode( ',', $fonts_list );
foreach( $fonts_list_array as $font_name ) {
et_builder_enqueue_font( $font_name );
* Process advanced font styles.
* @since 3.23 Add support to generate responsive styles of font, text color, and text align.
* And also process styles of block elements sub options group.
* @param string $function_name Module slug.
function process_advanced_fonts_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, 'fonts', false ) ) {
$mobile_options_slugs = array(
$slugs = array_merge( $slugs, $mobile_options_slugs ); // merge all slugs into single array to define them in one place
// Separetely defined and merged *_last_edited slugs. It needs to be merged as reference but shouldn't be looped for calling mobile attributes
$mobile_options_last_edited_slugs = array(
'text_color_last_edited',
'line_height_last_edited',
'letter_spacing_last_edited',
'text_align_last_edited',
$slugs = array_merge( $slugs, $mobile_options_last_edited_slugs );
foreach ( $this->advanced_fields['fonts'] as $option_name => $option_settings ) {
$important_options = array();
$is_important_set = isset( $option_settings['css']['important'] );
$is_placeholder = isset( $option_settings['css']['placeholder'] );
$use_global_important = $is_important_set && 'all' === $option_settings['css']['important'];
if ( ! $use_global_important && $is_important_set && 'plugin_only' === $option_settings['css']['important'] && et_builder_has_limitation('force_use_global_important') ) {
$use_global_important = true;
if ( $is_important_set && is_array( $option_settings['css']['important'] ) ) {
$important_options = $option_settings['css']['important'];
if ( et_builder_has_limitation('force_use_global_important') && in_array( 'plugin_all', $option_settings['css']['important'] ) ) {
$use_global_important = true;
foreach ( $slugs as $font_option_slug ) {
if ( isset( $this->props["{$option_name}_{$font_option_slug}"] ) ) {
$font_options["{$option_name}_{$font_option_slug}"] = $this->props["{$option_name}_{$font_option_slug}"];
$field_key = "{$option_name}_{$slugs[0]}";
$global_setting_name = $this->get_global_setting_name( $field_key );
$global_setting_value = ET_Global_Settings::get_value( $global_setting_name );
// Add default parameter to override global setting value, just in case we need to
$field_option_default = isset( $this->fields_unprocessed[ $field_key ]['default'] ) ? $this->fields_unprocessed[ $field_key ]['default'] : $global_setting_value;
$field_option_value = isset( $font_options[ $field_key ] ) ? $font_options[ $field_key ] : '';
if ( '' !== $field_option_value || ! $global_setting_value ) {
$important = in_array( 'font', $important_options ) || $use_global_important ? ' !important' : '';
$font_styles = et_builder_set_element_font( $field_option_value, ( '' !== $important ), $field_option_default );
// Get font custom breakpoint if needed on desktop.
$font_custom_desktop_breakpoint = et_pb_font_options()->get_breakpoint_by_font_value( $font_options, $field_key );
if ( isset( $option_settings['css']['font'] ) || ! empty( $font_custom_desktop_breakpoint ) ) {
// Prepare font styles args.
$font_styles_args = array(
'selector' => et_pb_font_options()->get_font_selector( $option_settings, $this->main_css_element ),
'declaration' => rtrim( $font_styles ),
'priority' => $this->_style_priority,
// Set custom media query if needed.
if ( ! empty( $font_custom_desktop_breakpoint ) ) {
$font_styles_args['media_query'] = ET_Builder_Element::get_media_query( $font_custom_desktop_breakpoint );
self::set_style( $function_name, $font_styles_args );
$size_option_name = "{$option_name}_{$slugs[1]}";
$default_size = isset( $this->fields_unprocessed[ $size_option_name ]['default'] ) ? $this->fields_unprocessed[ $size_option_name ]['default'] : '';
if ( isset( $font_options[ $size_option_name ] ) && ! in_array( trim( $font_options[ $size_option_name ] ), array( '', 'px', $default_size ) ) ) {
$important = in_array( 'size', $important_options ) || $use_global_important ? ' !important' : '';
$size_option_value = et_builder_process_range_value( $font_options[ $size_option_name ] );
esc_html( $size_option_value ),
$size_hover = trim( et_pb_hover_options()->get_value( $size_option_name, $this->props, '' ) );
if ( ! in_array( $size_hover, array( '', 'px', $size_option_value ) ) ) {
$important = in_array( 'size', $important_options ) || $use_global_important ? ' !important' : '';
esc_html( et_builder_process_range_value( $size_hover ) ),
$text_color_option_name = "{$option_name}_{$slugs[2]}";
// Ensure if text color option is not disabled on current font options.
$hide_text_color = isset( $option_settings['hide_text_color'] ) && true === $option_settings['hide_text_color'];
// handle the value from old option
$old_option_ref = isset( $option_settings['text_color'] ) && isset( $option_settings['text_color']['old_option_ref'] ) ? $option_settings['text_color']['old_option_ref'] : '';
$old_option_val = '' !== $old_option_ref && isset( $this->props[ $old_option_ref ] ) ? $this->props[ $old_option_ref ] : '';
$default_value = '' !== $old_option_val && isset( $option_settings['text_color'] ) && isset( $option_settings['text_color']['default'] ) ? $option_settings['text_color']['default'] : '';
if ( isset( $font_options[ $text_color_option_name ] ) && '' !== $font_options[ $text_color_option_name ] && ! $hide_text_color ) {
$important = ' !important';
if ( $default_value !== $font_options[ $text_color_option_name ] ) {
if ( isset( $option_settings['css']['color'] ) ) {
self::set_style( $function_name, array(
'selector' => $option_settings['css']['color'],
'declaration' => sprintf(
esc_html( $font_options[ $text_color_option_name ] ),
'priority' => $this->_style_priority,
esc_html( $font_options[ $text_color_option_name ] ),
$text_color_hover = et_pb_hover_options()->get_value( $text_color_option_name, $this->props );
if ( $default_value !== $text_color_hover && ! empty( $text_color_hover ) && ! $hide_text_color ) {
$important = ' !important';
if ( isset( $option_settings['css']['color'] ) ) {
$sel = et_pb_hover_options()->add_hover_to_selectors( $option_settings['css']['color'] );
self::set_style( $function_name, array(
'selector' => self::$_->array_get( $option_settings, 'css.color_hover', $sel ),
'declaration' => sprintf(
esc_html( $text_color_hover ),
'priority' => $this->_style_priority,
esc_html( $text_color_hover ),
$letter_spacing_option_name = "{$option_name}_{$slugs[3]}";
$default_letter_spacing = isset( $this->fields_unprocessed[ $letter_spacing_option_name ]['default'] ) ? $this->fields_unprocessed[ $letter_spacing_option_name ]['default'] : '';
$letter_spacing_value = '';
if ( isset( $font_options[ $letter_spacing_option_name ] ) && ! in_array( trim( $font_options[ $letter_spacing_option_name ] ), array( '', 'px', $default_letter_spacing ) ) ) {
$important = in_array( 'letter-spacing', $important_options ) || $use_global_important ? ' !important' : '';
$letter_spacing_value = et_builder_process_range_value( $font_options[ $letter_spacing_option_name ], 'letter_spacing' );
'letter-spacing: %1$s%2$s; ',
esc_html( $letter_spacing_value ),
if ( isset( $option_settings['css']['letter_spacing'] ) ) {
self::set_style( $function_name, array(
'selector' => $option_settings['css']['letter_spacing'],
'declaration' => sprintf(
'letter-spacing: %1$s%2$s;',
esc_html( $letter_spacing_value ),
'priority' => $this->_style_priority,
$letter_spacing_hover = trim( et_pb_hover_options()->get_value( $letter_spacing_option_name, $this->props, '' ) );
if ( ! in_array( $letter_spacing_hover, array( '', 'px', $letter_spacing_value ) ) ) {
$important = in_array( 'letter-spacing', $important_options ) || $use_global_important ? ' !important' : '';
if ( et_builder_is_hover_enabled( $letter_spacing_option_name, $this->props ) ) {
if ( isset( $option_settings['css']['letter_spacing_hover'] ) ) {
self::set_style( $function_name, array(
'selector' => $option_settings['css']['letter_spacing_hover'],
'declaration' => sprintf(
'letter-spacing: %1$s%2$s;',
esc_html( et_builder_process_range_value( $letter_spacing_hover ) ),
'priority' => $this->_style_priority,
'letter-spacing: %1$s%2$s; ',
esc_html( et_builder_process_range_value( $letter_spacing_hover ) ),
if ( isset( $option_settings['css']['letter_spacing'] ) ) {
if ( et_builder_is_hover_enabled( $letter_spacing_option_name, $this->props ) ) {
if ( $default_letter_spacing !== $letter_spacing_hover ) {
if ( isset( $option_settings['css']['color'] ) ) {
$sel = et_pb_hover_options()->add_hover_to_selectors( $option_settings['css']['letter_spacing'] );
self::set_style( $function_name, array(
'selector' => self::$_->array_get( $option_settings, 'css.letter_spacing_hover', $sel ),
'declaration' => sprintf(
esc_html( $letter_spacing_hover ),
'priority' => $this->_style_priority,
$line_height_option_name = "{$option_name}_{$slugs[4]}";
if ( isset( $font_options[ $line_height_option_name ] ) ) {
$default_line_height = isset( $this->fields_unprocessed[ $line_height_option_name ]['default'] ) ? $this->fields_unprocessed[ $line_height_option_name ]['default'] : '';
if ( ! in_array( trim( $font_options[ $line_height_option_name ] ), array( '', 'px', $default_line_height ) ) ) {
$important = in_array( 'line-height', $important_options ) || $use_global_important ? ' !important' : '';
$line_height_value = et_builder_process_range_value( $font_options[ $line_height_option_name ], 'line_height' );
'line-height: %1$s%2$s; ',
esc_html( $line_height_value ),
if ( isset( $option_settings['css']['line_height'] ) ) {
self::set_style( $function_name, array(
'selector' => $option_settings['css']['line_height'],
'declaration' => sprintf(
'line-height: %1$s%2$s;',
esc_html( $line_height_value ),
'priority' => $this->_style_priority,
$line_height_hover = trim( et_pb_hover_options()->get_value( $line_height_option_name, $this->props, '' ) );
if ( ! in_array( $line_height_hover, array( '', 'px', $line_height_value ) ) ) {
$important = in_array( 'line-height', $important_options ) || $use_global_important ? ' !important' : '';
if ( et_builder_is_hover_enabled( $line_height_option_name, $this->props ) ) {
'line-height: %1$s%2$s; ',
esc_html( et_builder_process_range_value( $line_height_hover, 'line_height' ) ),
if ( isset( $option_settings['css']['line_height'] ) ) {
if ( et_builder_is_hover_enabled( $line_height_option_name, $this->props ) ) {
if ( isset( $option_settings['css']['color'] ) ) {
$sel = et_pb_hover_options()->add_hover_to_selectors( $option_settings['css']['line_height'] );
self::set_style( $function_name, array(
'selector' => self::$_->array_get( $option_settings, 'css.line_height_hover', $sel ),
'declaration' => sprintf(
'line-height: %1$s%2$s;',
esc_html( $line_height_hover ),
'priority' => $this->_style_priority,
$text_align_option_name = "{$option_name}_{$slugs[5]}";
// Ensure to not print text alignment if current font hide text alignment option.
$hide_text_align = self::$_->array_get( $option_settings, 'hide_text_align', false );
if ( isset( $font_options[ $text_align_option_name ] ) && '' !== $font_options[ $text_align_option_name ] && ! $hide_text_align ) {
$important = in_array( 'text-align', $important_options ) || $use_global_important ? ' !important' : '';
$text_align = et_pb_get_alignment( $font_options[ $text_align_option_name ] );
if ( isset( $option_settings['css']['text_align'] ) ) {
self::set_style( $function_name, array(
'selector' => $option_settings['css']['text_align'],
'declaration' => sprintf(
'priority' => $this->_style_priority,
'text-align: %1$s%2$s; ',
if ( isset( $option_settings['use_all_caps'] ) && $option_settings['use_all_caps'] && 'on' === $this->props["{$option_name}_all_caps"] ) {
$important = in_array( 'all_caps', $important_options ) || $use_global_important ? ' !important' : '';
$style .= sprintf( 'text-transform: uppercase%1$s; ', esc_html( $important ) );
// apply both default and hover styles
$style_states = array( 'default', 'hover' );
foreach ( $style_states as $style_state ) {
$is_hover = 'hover' === $style_state;
$style = $is_hover ? $hover_style : $style;
$css_element = ! empty( $option_settings['css']['main'] ) ? $option_settings['css']['main'] : $this->main_css_element;
// use different selector for plugin if defined
if ( et_builder_has_limitation('use_limited_main') && ! empty( $option_settings['css']['limited_main'] ) ) {
$css_element = $option_settings['css']['limited_main'];