: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( ! defined( 'ABSPATH' ) ) {
die( 'Direct access forbidden.' );
* Responsive options helper methods.
* @since 3.23 Add more helper functions. Originally, this class is introduced on Options Harmony v2.
* Class ET_Builder_Module_Helper_ResponsiveOptions
class ET_Builder_Module_Helper_ResponsiveOptions {
const DESKTOP = 'desktop';
public static function instance() {
return $instance ? $instance : $instance = new self();
private function __construct() {
// Now call me if you can
* Get value from an array based on key. However, we can force to return default value if key
* doesn't exist or value is empty.
* @param array $list Array of values.
* @param string $key Target key.
* @param mixed $default Default value, return if the target doesn't exist.
* @param mixed $default_on_empty Force to return default if value is empty.
private function get( $list, $key, $default = null, $default_on_empty = false ) {
$value = isset( $list[ $key ] ) ? $list[ $key ] : $default;
// Return default if we need non empty value to be used.
if ( $default_on_empty && empty( $value ) ) {
* Check if responsive settings is enabled or not on the option.
* @param array $attrs All module attributes.
* @param string $name Option name.
* @return boolean Responsive settings status.
public function is_responsive_enabled( $attrs, $name ) {
$last_edited = $this->get( $attrs, "{$name}_last_edited", '' );
return $this->get_responsive_status( $last_edited );
* Check if responsive settings are enabled on one of the options list.
* @param array $attrs All module attributes.
* @param array $list Options list.
* @return boolean Responsive styles status.
public function is_any_responsive_enabled( $attrs, $list ) {
// Ensure list is not empty and valid array.
if ( empty( $list ) || ! is_array( $list ) ) {
// Check the responsive status one by one.
$is_responsive_enabled = false;
foreach ( $list as $name ) {
if ( $this->is_responsive_enabled( $attrs, $name ) ) {
// Break early if current field enabled responsive is found.
$is_responsive_enabled = true;
return $is_responsive_enabled;
* Get responsive status based one last edited value.
* Parsed *_last_edited value and determine wheter the passed string means it has responsive value
* or not. *_last_edited holds two values (responsive status and last opened tabs) in the following
* format: status|last_opened_tab.
* Copy of et_pb_get_responsive_status() with a little modified and to organize the code.
* @param string $last_edited Last edited field value.
* @return bool Responsive field status.
public function get_responsive_status( $last_edited ) {
if ( empty( $last_edited ) || ! is_string( $last_edited ) ) {
$parsed_last_edited = explode( '|', $last_edited );
return isset( $parsed_last_edited[0] ) ? 'on' === $parsed_last_edited[0] : false;
* Generate video background markup.
* When background support responsive settings, the default callback will be replaced with
* get_video_background() function to retrieve all video values for desktop, hover, tablet,
* @param array $args Background values.
* @param array $conditional_tags Conditional tags.
* @param array $current_page Current page info.
* @return mixed Mixed background content generated as video markup.
public static function get_video_background( $args = array(), $conditional_tags = array(), $current_page = array() ) {
$base_name = isset( $args['computed_variables'] ) && isset( $args['computed_variables']['base_name'] ) ? $args['computed_variables']['base_name'] : 'background';
$attr_prefix = "{$base_name}_";
"{$attr_prefix}video_mp4" => isset( $args["{$attr_prefix}video_mp4"] ) ? $args["{$attr_prefix}video_mp4"] : '',
"{$attr_prefix}video_webm" => isset( $args["{$attr_prefix}video_webm"] ) ? $args["{$attr_prefix}video_webm"] : '',
"{$attr_prefix}video_width" => isset( $args["{$attr_prefix}video_width"] ) ? $args["{$attr_prefix}video_width"] : '',
"{$attr_prefix}video_height" => isset( $args["{$attr_prefix}video_height"] ) ? $args["{$attr_prefix}video_height"] : '',
'computed_variables' => array(
'base_name' => $base_name,
"{$attr_prefix}video_mp4__hover" => isset( $args["{$attr_prefix}video_mp4__hover"] ) ? $args["{$attr_prefix}video_mp4__hover"] : '',
"{$attr_prefix}video_webm__hover" => isset( $args["{$attr_prefix}video_webm__hover"] ) ? $args["{$attr_prefix}video_webm__hover"] : '',
"{$attr_prefix}video_width__hover" => isset( $args["{$attr_prefix}video_width__hover"] ) ? $args["{$attr_prefix}video_width__hover"] : '',
"{$attr_prefix}video_height__hover" => isset( $args["{$attr_prefix}video_height__hover"] ) ? $args["{$attr_prefix}video_height__hover"] : '',
'computed_variables' => array(
'base_name' => $base_name,
"{$attr_prefix}video_mp4_tablet" => isset( $args["{$attr_prefix}video_mp4_tablet"] ) ? $args["{$attr_prefix}video_mp4_tablet"] : '',
"{$attr_prefix}video_webm_tablet" => isset( $args["{$attr_prefix}video_webm_tablet"] ) ? $args["{$attr_prefix}video_webm_tablet"] : '',
"{$attr_prefix}video_width_tablet" => isset( $args["{$attr_prefix}video_width_tablet"] ) ? $args["{$attr_prefix}video_width_tablet"] : '',
"{$attr_prefix}video_height_tablet" => isset( $args["{$attr_prefix}video_height_tablet"] ) ? $args["{$attr_prefix}video_height_tablet"] : '',
'computed_variables' => array(
'base_name' => $base_name,
"{$attr_prefix}video_mp4_phone" => isset( $args["{$attr_prefix}video_mp4_phone"] ) ? $args["{$attr_prefix}video_mp4_phone"] : '',
"{$attr_prefix}video_webm_phone" => isset( $args["{$attr_prefix}video_webm_phone"] ) ? $args["{$attr_prefix}video_webm_phone"] : '',
"{$attr_prefix}video_width_phone" => isset( $args["{$attr_prefix}video_width_phone"] ) ? $args["{$attr_prefix}video_width_phone"] : '',
"{$attr_prefix}video_height_phone" => isset( $args["{$attr_prefix}video_height_phone"] ) ? $args["{$attr_prefix}video_height_phone"] : '',
'computed_variables' => array(
'base_name' => $base_name,
$video_backgrounds = array();
// Get video background markup.
$background_video = ET_Builder_Element::get_video_background( $default_args );
if ( $background_video ) {
$video_backgrounds['desktop'] = $background_video;
$background_video_hover = ET_Builder_Element::get_video_background( $hover_args );
if ( $background_video_hover ) {
$video_backgrounds['hover'] = $background_video_hover;
$background_video_tablet = ET_Builder_Element::get_video_background( $tablet_args );
if ( $background_video_tablet ) {
$video_backgrounds['tablet'] = $background_video_tablet;
$background_video_phone = ET_Builder_Element::get_video_background( $phone_args );
if ( $background_video_phone ) {
$video_backgrounds['phone'] = $background_video_phone;
return $video_backgrounds;
* Returns the field original name by removing the `_tablet` or `_phone` suffix if it exists.
* Only remove tablet/phone string of the last setting name. Doesn't work for other format.
* @param string $name Setting name.
* @return string Base setting name.
public function get_field_base_name( $name ) {
// Do not use rtim as it removes by character not by string. So, cases like `key_tablets`
// will be reduced to `key`.
$regex = "/(.*)(_tablet|_phone)$/";
return preg_replace( $regex, $replace, $name );
* Returns the field responsive name by adding the `_tablet` or `_phone` suffix if it exists.
* @param string $name Setting name.
* @param string $device Device name.
* @return string Field setting name.
public function get_field_name( $name, $device = 'desktop' ) {
// Field name should not be empty.
// Ensure device is not empty.
$device = '' === $device ? 'desktop' : $device;
return 'desktop' !== $device ? "{$name}_{$device}" : $name;
* Returns the device name by removing the `name` prefix. If the result is one of tablet or phone,
* return it. But, if it's empty, return desktop.
* @param string $name Setting name.
* @return string Device name.
public function get_device_name( $name ) {
// Do not use rtim as it removes by character not by string. So, cases like `key_tablets`
// will be reduced to `key`.
$regex = "/(.*)(tablet|phone)$/";
$result = preg_replace( $regex, $replace, $name );
return in_array( $result, array( 'tablet', 'phone' ) ) ? $result : 'desktop';
* Get responsive value based on field base name and device.
* NOTE: Function get_single_value() is different with get_any_value(). It will return only
* current field value without checking the previous device value.
* For example: We have Title Text Font Size -> desktop 30px, tablet 10px, phone 10px. Fetch
* the value for phone, it will return pure 10px even the value is same with tablet.
* We have Subtitle Text Font Size -> desktop 20px, tablet 15px, phone ''. Fetch
* the value for phone, it will return pure '' or default even the value is empty.
* To get tablet or phone value:
* 1. You can pass only field base name and device name as the 4th argument. The parameters
* structure it's made like that to make it similar with other get* method we already have.
* For example: get_single_value( $this->props, 'title_text_font_size', '', 'tablet' ).
* 2. Or you can pass the actual field name with device. If the field name is already contains
* _tablet and _phone, don't pass device parameter because it will be added as suffix.
* For example: get_single_value( $this->props, 'title_text_font_size_tablet', '' ).
* @param array $attrs All module attributes.
* @param string $name Option name.
* @param array $default_value Default value.
* @param string $device Current device name.
* @return mixed Current option value based on active device.
public function get_single_value( $attrs, $name = '', $default_value = '', $device = 'desktop' ) {
// Ensure $device is not empty.
$device = '' === $device ? 'desktop' : $device;
// Ensure always use device as suffix if device is not desktop or empty.
if ( 'desktop' !== $device ) {
$base_name = $this->get_field_base_name( $name );
$name = "{$base_name}_{$device}";
return $this->get( $attrs, $name, $default_value, true );
* Get current active device value from attributes.
* NOTE: Function get_any_value() is different with get_value(). It also compare the value
* with the previous device value to avoid duplication. Or you can also force to return
* either current or previous default value if needed.
* For example: We have Title Text Font Size -> desktop 30px, tablet 30px, phone 10px. When
* we fetch the value for tablet, it will return pure empty string ('') because
* tablet value is equal with desktop value.
* We have Title Text Font Size -> desktop 30px, tablet '', phone ''. When
* we fetch the value for phone and force it to return any value, it will
* return 30px because phone and tablet value is empty and the function will
* look up to tablet or even desktop value.
* To get tablet or phone value:
* 1. You can pass only field base name and device name as the 4th argument. The parameters
* structure it's made like that to make it similar with other get* method we already have.
* For example: get_any_value( $this->props, 'title_text_font_size', '', 'tablet' ).
* 2. Or you can pass the actual field name with device. If the field name is already contains
* _tablet and _phone, don't pass device parameter because it will be added as suffix.
* For example: get_any_value( $this->props, 'title_text_font_size_tablet', '' ).
* 3. You can also force to return any value by passing true on the 5th argument. In some cases
* we need this to fill missing tablet/phone value with desktop value.
* @param array $attrs All module attributes.
* @param string $name Option name.
* @param array $default_value Default value.
* @param bool $force_return Force to return any value.
* @param string $device Current device name.
* @return mixed Current option value based on active device.
public function get_any_value( $attrs, $name = '', $default_value = '', $force_return = false, $device = 'desktop' ) {
// Ensure $device is not empty.
$device = '' === $device ? 'desktop' : $device;
// Ensure always use device as suffix if device is not desktop/empty.
if ( 'desktop' !== $device ) {
$base_name = $this->get_field_base_name( $name );
$name = "{$base_name}_{$device}";
$current_value = $this->get( $attrs, $name, '' );
// Get previous value to be compared.
$prev_value = $this->get_default_value( $attrs, $name, $default_value );
// Force to return any values given.
return ! empty( $current_value ) ? $current_value : $prev_value;
// Ensure current value is different with the previous device or default.
if ( $current_value === $prev_value ) {
* Get property's values for requested device.
* This function is added to summarize how we fetch desktop/hover/tablet/phone value. This
* function still uses get_any_value to get current device values.
* @param array $attrs List of all attributes and values.
* @param string $name Property name.
* @param mixed $default_value Default value.
* @param string $device Device name.
* @param boolean $force_return Force to return any values found.
* @return array Pair of devices and the values.
public function get_property_value( $attrs, $name, $default_value = '', $device = 'desktop', $force_return = false ) {
$default_value = esc_attr( $default_value );
// Ensure $device is not empty.
$device = '' === $device ? 'desktop' : $device;
// Ensure attrs (values list) and name (property name) are not empty.
if ( empty( $attrs ) || '' === $name ) {
$is_enabled = 'desktop' !== $device ? $this->is_responsive_enabled( $attrs, $name ) : true;
$suffix = 'desktop' !== $device ? "_{$device}" : '';
$value = $is_enabled ? $this->get_any_value( $attrs, "{$name}{$suffix}", $default_value, $force_return ) : $default_value;
return esc_attr( $value );
* Get all properties values for all devices.
* This function is added to summarize how we fetch desktop/hover, tablet, and phone values. This
* function still use get_any_value to get current device values.
* @param array $attrs List of all attributes and values.
* @param string $name Property name.
* @param mixed $default_value Default value.
* @param boolean $force_return Force to return any values found.
* @return array Pair of devices and the values.
public function get_property_values( $attrs, $name, $default_value = '', $force_return = false ) {
$default_value = esc_attr( $default_value );
'desktop' => $default_value,
'tablet' => $default_value,
'phone' => $default_value,
// Ensure attrs (values list) and name (property name) are not empty.
if ( empty( $attrs ) || '' === $name ) {
$is_responsive = $this->is_responsive_enabled( $attrs, $name );
// Get values for each devices.
$values['desktop'] = esc_html( $this->get_any_value( $attrs, $name, $default_value, $force_return ) );
$values['tablet'] = esc_html( $this->get_any_value( $attrs, "{$name}_tablet", $default_value, $force_return ) );
$values['phone'] = esc_html( $this->get_any_value( $attrs, "{$name}_phone", $default_value, $force_return ) );
* Get composite property's value for requested device.
* This function is added to summarize how we fetch desktop/hover/tablet/phone value. This
* function still uses get_any_value to get current device values.
* @param array $attrs List of all attributes and values.
* @param string $composite_name Composite property name.
* @param string $name Property name.
* @param mixed $default_value Default value.
* @param string $device Device name.
* @param boolean $force_return Force to return any values found.
* @return array Pair of devices and the values.
public function get_composite_property_value( $attrs, $composite_name, $name, $default_value = '', $device = 'desktop', $force_return = false ) {
$default_value = esc_attr( $default_value );
// Ensure $device is not empty.
$device = '' === $device ? 'desktop' : $device;
// Ensure attrs, composite name (parent property name), name (property name) are not empty.
if ( empty( $attrs ) || '' === $composite_name || '' === $name ) {
$is_enabled = 'desktop' !== $device ? $this->is_responsive_enabled( $attrs, $composite_name ) : true;
$suffix = 'desktop' !== $device ? "_{$device}" : '';
$value = $is_enabled ? $this->get_any_value( $attrs, "{$name}{$suffix}", $default_value, $force_return ) : $default_value;
return esc_attr( $value );
* Get all composite properties values for all devices.
* This function is added to summarize how we fetch desktop/hover, tablet, and phone values. This
* function still use get_any_value to get current device values.
* @param array $attrs List of all attributes and values.
* @param string $composite_name Composite property name.
* @param string $name Property name.
* @param mixed $default_value Default value.
* @param boolean $force_return Force to return any values found.
* @return array Pair of devices and the values.