: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
class ET_Builder_Module_Field_Transform extends ET_Builder_Module_Field_Base {
private $processing_props = array();
public $defaults = array(
public $allTransforms = array(
public function get_fields( array $args = array() ) {
if ( ! isset( $i18n ) ) {
// phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
'label' => esc_html__( 'Transform Scale', 'et_builder' ),
'label' => esc_html__( 'Transform Translate', 'et_builder' ),
'label' => esc_html__( 'Transform Rotate', 'et_builder' ),
'label' => esc_html__( 'Transform Skew', 'et_builder' ),
'label' => esc_html__( 'Transform Origin', 'et_builder' ),
'label' => esc_html__( 'Transform', 'et_builder' ),
'description' => esc_html__( 'Using the transform controls, you can performance visual adjustments to any element using a combination of Scale, Translation, Rotation and Skew settings. This allows you to create advanced design effects without the need of a separate graphic design program.', 'et_builder' ),
$settings = wp_parse_args( array(
'option_category' => 'layout',
'tab_slug' => 'advanced',
'toggle_slug' => 'transform',
'depends_show_if' => null,
'defaults' => $this->defaults,
$additional_options = array();
$defaults = $settings['defaults'];
'transform_scale' => array(
'label' => $i18n['scale']['label'],
'default' => "${defaults['scale']}|${defaults['scale']}",
'range_settings' => array(
'context' => 'transform_styles',
'mobile_options' => true,
'transform_translate' => array(
'label' => $i18n['translate']['label'],
'default' => "${defaults['translate']}|${defaults['translate']}",
'range_settings' => array(
'context' => 'transform_styles',
'mobile_options' => true,
'transform_rotate' => array(
'label' => $i18n['rotate']['label'],
'default' => "${defaults['rotate']}|${defaults['rotate']}|${defaults['rotate']}",
'range_settings' => array(
'context' => 'transform_styles',
'mobile_options' => true,
'transform_skew' => array(
'label' => $i18n['skew']['label'],
'default' => "${defaults['skew']}|${defaults['skew']}",
'range_settings' => array(
'context' => 'transform_styles',
'mobile_options' => true,
'icon' => 'transform-origin',
'transform_origin' => array(
'label' => $i18n['origin']['label'],
'default' => "${defaults['origin']}|${defaults['origin']}",
'range_settings' => array(
'context' => 'transform_styles',
'mobile_options' => true,
$additional_options['transform_styles'] = array(
'label' => $i18n['styles']['label'],
'tab_slug' => $settings['tab_slug'],
'toggle_slug' => $settings['toggle_slug'],
'composite_type' => 'transforms',
'mobile_options' => true,
'description' => $i18n['styles']['description'],
'composite_structure' => $tabs,
//Register responsive options
'tab_slug' => $settings['tab_slug'],
'toggle_slug' => $settings['toggle_slug'],
$linkedSkip = $skip + array( 'default' => 'on' );
foreach ( $additional_options['transform_styles']['composite_structure'] as $tab_name => $tab ) {
foreach ( $tab['controls'] as $field_name => $field_options ) {
$controls = $additional_options['transform_styles']['composite_structure'][ $tab_name ]['controls'];
$controls["${field_name}_tablet"] = $skip;
$controls["${field_name}_phone"] = $skip;
$controls["${field_name}_last_edited"] = $skip;
if ( in_array( $field_name, array( 'transform_scale', 'transform_translate', 'transform_skew' ) ) ) {
$controls["${field_name}_linked"] = $linkedSkip;
$controls["${field_name}_linked_tablet"] = $linkedSkip;
$controls["${field_name}_linked_phone"] = $linkedSkip;
$controls["${field_name}_linked__hover"] = $linkedSkip;
$additional_options['transform_styles']['composite_structure'][ $tab_name ]['controls'] = $controls;
$additional_options['transform_styles_last_edited'] = $skip;
return $additional_options;
public function percent_to_unit( $percent = 0 ) {
if ( strpos( $percent, '%' ) === false ) {
$value = (float) trim( str_replace( '%', '', $percent ) );
public function set_props( $props ) {
$this->processing_props = $props;
public function get_setting( $value, $default ) {
if ( ! empty( $this->processing_props[ $value ] ) ) {
return $this->processing_props[ $value ];
public function get_option( $typeAxis, $type = 'desktop' ) {
$setting = "transform_$typeAxis[0]";
$interpreter = array( 'X' => 0, 'Y' => 1, 'Z' => 2 );
$index = $interpreter[ $typeAxis[1] ];
$optionValue = $this->get_setting( $setting, false );
if ( 'hover' === $type ) {
$defaultValue = $this->get_setting( $setting, false );
$optionValue = $this->get_setting( $setting . '__hover', false );
} elseif ( 'tablet' === $type ) {
$defaultValue = $this->get_setting( $setting, false );
$optionValue = $this->get_setting( $setting . '_tablet', false );
} elseif ( 'phone' === $type ) {
$defaultValue = $this->get_setting( $setting . '_tablet', false );
$optionValue = $this->get_setting( $setting . '_phone', false );
if ( $defaultValue == false ) {
$defaultValue = $this->get_setting( $setting, false );
if ( false === $optionValue ) {
if ( false !== $defaultValue ) {
$optionValue = $defaultValue;
if ( false === $optionValue ) {
$valueArray = explode( '|', $optionValue );
$value = $valueArray[ $index ];
if ( 'scale' === $typeAxis[0] ) {
return $this->percent_to_unit( $value );
public function get_elements( $type ) {
if ( empty( $this->processing_props ) ) {
wp_die( new WP_Error( '666', 'Run set_props first' ) );
$transformElements = array();
foreach ( $this->allTransforms as $option ) {
$typeAxis[0] = substr( $option, 0, -1 );
$typeAxis[1] = substr( $option, -1 );
$value = esc_attr( $this->get_option( $typeAxis, $type ) );
if ( ! empty( $value ) ) {
if ( 'origin' === $typeAxis[0] ) {
if ( 'originY' === $option && empty( $originArray ) ) {
//default value of originX
array_push( $originArray, '50%' );
array_push( $originArray, $value );
$transformElements[ $option ] = $value;
'transform' => $transformElements,
'origin' => $originArray,
public function getTransformDeclaration( $transformElements, $view = 'desktop' ) {
unset( $transformElements['originX'], $transformElements['originY'] );
// Perspective is included on when combining with some animations
if ( ! empty( $transformElements['perspective'] ) ) {
array_push( $declaration, sprintf( 'perspective(%s)', $transformElements['perspective'] ) );
// Transforms must maintain this order to blend correctly with animation rules
foreach ( $this->allTransforms as $option ) {
if ( ! empty( $transformElements[ $option ] ) ) {
array_push( $declaration, sprintf( '%s(%s)', $option, $transformElements[ $option ] ) );
if ( ! empty( $declaration ) ) {
if ( $this->processing_props['transforms_important'] || 'hover' === $view ) {
array_push( $declaration, '!important' );
return sprintf( "transform: %s;", implode( ' ', $declaration ) );
public function transformedAnimation( $animationType, $elements, $function_name, $device ) {
if ( 'hover' === $device ) {
$utils = ET_Core_Data_Utils::instance();
$startElements = $elements['transform'];
$responsive = ET_Builder_Module_Helper_ResponsiveOptions::instance();
$direction = $responsive->get_any_value( $this->processing_props, 'animation_direction', 'center', true, $device );
$animation_intensity = $utils->array_get( $this->processing_props, "animation_intensity_$animationType", 50 );
$module_class = ET_Builder_Element::get_module_order_class( $function_name );
$animationName = "et_pb_${animationType}_${direction}_$module_class";
$newKeyframe = "@keyframes $animationName";
$newAnimationSelector = ".$module_class.et_animated.transformAnim";
$newAnimationRules = "animation-name: $animationName;";
$transformDeclaration = $this->getTransformDeclaration( $elements['transform'] );
$originDeclaration = sprintf( 'transform-origin:%s;', implode( ' ', $elements['origin'] ) );
$intensity = ! is_numeric( str_replace( '%', '', $animation_intensity ) )
: (int) str_replace( '%', '', $animation_intensity );
// slide animation direction center is the same animation as zoom center
if ( 'slide' === $animationType && 'center' === $direction ) {
// animation transform gets combined with transform settings as described on et-builder-custom-output.jsx processTransform method
switch ( $animationType ) {
$scale = ( 100 - $intensity ) * 0.01;
$startElements['scaleX'] = $scale * $utils->array_get( $elements['transform'], 'scaleX', 1 );
$startElements['scaleY'] = $scale * $utils->array_get( $elements['transform'], 'scaleY', 1 );
$startDeclaration = $this->getTransformDeclaration( $startElements );
// replace origin declaration to preserve animation direction setting only if transform origin is not set
if ( empty( $elements['origin'] ) ) {
$originDeclaration = "transform-origin: $direction;";
$originDeclaration = sprintf( 'transform-origin: %s;', implode( ' ', $elements['origin'] ) );
$newKeyframeRules = "0%{ $startDeclaration }";
$newKeyframeRules .= "100%{opacity:1;$transformDeclaration}";
$newAnimationRules .= $originDeclaration;
$translateY = $utils->array_get( $elements['transform'], 'translateY', '0%' );
$translateX = $utils->array_get( $elements['transform'], 'translateX', '0%' );
$startElements['translateY'] = sprintf( 'calc(%s%% + %s)', $intensity * -2, $translateY );
$startElements['translateX'] = $translateX;
$startElements['translateY'] = sprintf( 'calc(%s%% + %s)', $intensity * 2, $translateY );
$startElements['translateX'] = $translateX;
$startElements['translateX'] = sprintf( 'calc(%s%% + %s)', $intensity * -2, $translateX );
$startElements['translateY'] = $translateY;
$startElements['translateX'] = sprintf( 'calc(%s%% + %s)', $intensity * 2, $translateX );
$startElements['translateY'] = $translateY;
$startDeclaration = $this->getTransformDeclaration( $startElements );
$newKeyframeRules = "0%{ $startDeclaration }";
$newKeyframeRules .= "100%{opacity:1;$transformDeclaration}";
$translateX = $utils->array_get( $elements['transform'], 'translateX', '0px' );
$translateY = $utils->array_get( $elements['transform'], 'translateY', '0px' );
$scaleX = (float) $utils->array_get( $elements['transform'], 'scaleX', 1 );
$scaleY = (float) $utils->array_get( $elements['transform'], 'scaleY', 1 );
$newKeyframeRules = 'from, 20%, 40%, 60%, 80%, to {animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);}';
$startElements['scaleX'] = 0.3 * $scaleX;
$startElements['scaleY'] = 0.3 * $scaleY;
$newKeyframeRules .= sprintf( '0%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['scaleX'] = 1.1 * $scaleX;
$startElements['scaleY'] = 1.1 * $scaleY;
$newKeyframeRules .= sprintf( '20%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['scaleX'] = 0.9 * $scaleX;
$startElements['scaleY'] = 0.9 * $scaleY;
$newKeyframeRules .= sprintf( '40%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['scaleX'] = 1.03 * $scaleX;
$startElements['scaleY'] = 1.03 * $scaleY;
$newKeyframeRules .= sprintf( '60%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['scaleX'] = 0.97 * $scaleX;
$startElements['scaleY'] = 0.97 * $scaleY;
$newKeyframeRules .= sprintf( '80%%{%s}', $this->getTransformDeclaration( $startElements ) );
$newKeyframeRules .= "100%{opacity: 1;$transformDeclaration}";
$newKeyframeRules = 'from, 60%, 75%, 90%, to {animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);}';
$startElements['translateY'] = "calc(-200px + $translateY)";
$newKeyframeRules .= sprintf( '0%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateY'] = "calc(25px + $translateY)";
$newKeyframeRules .= sprintf( '60%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateY'] = "calc(-10px + $translateY)";
$newKeyframeRules .= sprintf( '75%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateY'] = "calc(5px + $translateY)";
$newKeyframeRules .= sprintf( '90%%{%s}', $this->getTransformDeclaration( $startElements ) );
$newKeyframeRules .= "100%{opacity: 1;$transformDeclaration}";
$newKeyframeRules = 'from, 60%, 75%, 90%, to {animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);}';
$startElements['translateY'] = "calc(200px + $translateY)";
$newKeyframeRules .= sprintf( '0%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateY'] = "calc(-25px + $translateY)";
$newKeyframeRules .= sprintf( '60%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateY'] = "calc(10px + $translateY)";
$newKeyframeRules .= sprintf( '75%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateY'] = "calc(-5px + $translateY)";
$newKeyframeRules .= sprintf( '90%%{%s}', $this->getTransformDeclaration( $startElements ) );
$newKeyframeRules .= "100%{opacity: 1;$transformDeclaration}";
$newKeyframeRules = 'from, 60%, 75%, 90%, to {animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);}';
$startElements['translateX'] = "calc(-200px + $translateX)";
$newKeyframeRules .= sprintf( '0%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateX'] = "calc(25px + $translateX)";
$newKeyframeRules .= sprintf( '60%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateX'] = "calc(-10px + $translateX)";
$newKeyframeRules .= sprintf( '75%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateX'] = "calc(5px + $translateX)";
$newKeyframeRules .= sprintf( '90%%{%s}', $this->getTransformDeclaration( $startElements ) );
$newKeyframeRules .= "100%{opacity: 1;$transformDeclaration}";
$newKeyframeRules = 'from, 60%, 75%, 90%, to {animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);}';
$startElements['translateX'] = "calc(200px + $translateX)";
$newKeyframeRules .= sprintf( '0%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateX'] = "calc(-25px + $translateX)";
$newKeyframeRules .= sprintf( '60%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateX'] = "calc(10px + $translateX)";
$newKeyframeRules .= sprintf( '75%%{%s}', $this->getTransformDeclaration( $startElements ) );
$startElements['translateX'] = "calc(-5px + $translateX)";
$newKeyframeRules .= sprintf( '90%%{%s}', $this->getTransformDeclaration( $startElements ) );
$newKeyframeRules .= "100%{opacity: 1;$transformDeclaration}";
$intensityAngle = ceil( ( 90 / 100 ) * $intensity );
$startElements['perspective'] = '2000px';
$rotateX = (float) str_replace( 'deg', '', $utils->array_get( $elements['transform'], 'rotateX', '0' ) );
$rotateY = (float) str_replace( 'deg', '', $utils->array_get( $elements['transform'], 'rotateY', '0' ) );
$intensityAngle += $rotateX;
$startElement['rotateX'] = "{$intensityAngle}deg";