: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
'remove_suffix_if_empty' => $placeholder_has_space_suffix ? true : false,
$this->set_cache( $cache_name, $cache_key, $rebuilt_placeholder );
return $rebuilt_placeholder;
// 2. Field attribute value's type is array (sequential)
if ( is_array( $attr_value ) && isset( $attr_value[0] ) ) {
$rebuild_attr_value = array();
foreach ( $attr_value as $array_value ) {
// Array consists of string is most likely used for defining field relationship
// such as `show_if` attribute; Replace prefix and suffix placeholder with
// placeholder replacement also consider that text_shadow advanced field
// automatically adds underscore after prefix so it needs to be adjusted as well
if ( is_string( $array_value ) ) {
$rebuild_attr_value[] = $this->rebuild_string_placeholder( $array_value, $template_data, array(
'remove_suffix_if_empty' => $auto_add_prefix_underscore,
} elseif ( 'presets' === $attr_name ) {
// Handle preset attribute specifically due to how it is structured
$rebuild_attr_value[] = $this->rebuild_preset_placeholder( $array_value, $template_data, array(
'remove_suffix_if_empty' => $auto_add_prefix_underscore,
// Non string and `presets` attribute less likely contains placeholder
$rebuild_attr_value[] = $array_value;
$this->set_cache( $cache_name, $cache_key, $rebuild_attr_value );
return $rebuild_attr_value;
// 3. Field attribute value's type is array (associative)
if ( is_array( $attr_value ) && ! isset( $attr_value[0] ) ) {
// Loop existing attrValue and populate the rebuilt result on `attrObject`.
foreach ( $attr_value as $item_key => $item_value ) {
$attr_object_key = $this->rebuild_string_placeholder( $item_key, $template_data );
// Replaces placeholder with actual value on border's nested composite structure fields
if ( 'composite_structure' === $attr_name ) {
$item_value = $this->rebuild_composite_structure_placeholder( $template_type, $item_value, $template_data );
$attr_object[ $attr_object_key ] = $item_value;
$this->set_cache( $cache_name, $cache_key, $attr_object );
$this->set_cache( $cache_name, $cache_key, $attr_value );
// 4. Unknown attribute value type; directly pass it
public function rebuild_field_template( $template_id, $parent_template_id = false ) {
// Check for cached result first for faster performance
$cache_name = 'field_template';
$cache_key = $parent_template_id ? "{$template_id}-inherits-{$parent_template_id}" : $template_id;
$cache = $this->get_cache( $cache_name, $cache_key );
if ( ! is_null( $cache ) ) {
$template_data = $this->get_data( $template_id );
// No fields will be found without template data. Return early;
if ( empty( $template_data ) ) {
$template_type = self::$_->array_get( $template_data, '0' );
$template_settings = self::$_->array_get( $template_data, '1', array() );
$prefix = self::$_->array_get( $template_settings, 'prefix', '' );
$parent_template_data = false;
// If rebuilt parent template is inside another templateId (ie. Text Shadow inside Font)
// its placeholder is passed for data; The expected structure becomes
// `[templateType, parentTemplateSettings]` instead of `[templateType, templateSettings]`;
// Thus get parent template's settings and use it
if ( $parent_template_id ) {
$parent_template_data = $this->get_data( $parent_template_id );
$parent_template_settings = self::$_->array_get( $parent_template_data, "1", true );
$template_settings_inherits_from_parant = array();
foreach ( $template_settings as $name => $value ) {
$placeholder = $this->get_template_placeholder( $value );
if ( is_array( $placeholder ) && isset( $placeholder[0] ) ) {
$template_settings_inherits_from_parant[ $name ] = self::$_->array_get(
$parent_template_settings,
$parent_template_data = array(
$template_settings_inherits_from_parant
// Get fields template for given template type
$fields_template = $this->get_template( $template_type );
// Loop fields template and replace placeholder with actual value
foreach ( $fields_template as $field_name_template => $field_template ) {
// Certain advanced field (ie. Text Shadow) automatically adds underscore
// Related template type needs to be adjusted
$remove_suffix_if_empty = 'text_shadow' === $template_type && '' === $prefix;
// Replace field attribute name's placeholder
$field_template_data = $parent_template_id ? $parent_template_data : $template_data;
$field_name = $this->rebuild_string_placeholder(
'remove_suffix_if_empty' => $remove_suffix_if_empty,
// placeholder's suffix, not placeholder named %%suffix%%
// Replace field attribute value's placeholder
if ( is_array( $field_template ) ) {
foreach( $field_template as $attr_name => $attr_value ) {
$rebuilt_attr_value = $this->rebuild_field_attr_value(
// Omit attribute with empty value: existance of attribute even with empty
// string value is handled differently in many field (ie, `show_if`)
if ( '' === $rebuilt_attr_value ) {
$field[ $attr_name ] = $rebuilt_attr_value;
$this->rebuild_field_template( $field_name_template, $template_id )
// `name` attribute is dynamically added based on field's array key
$field['name'] = $field_name;
// Populate rebuilt field
$fields[ $field_name ] = $field;
$this->set_cache( $cache_name, $cache_key, $fields );
public function rebuild_default_props( $template_id ) {
// Check for cached result first for faster performance
$cache_name = 'default_props';
$cache_key = $template_id;
$cache = $this->get_cache( $cache_name, $cache_key );
if ( ! is_null( $cache ) ) {
$default_props = array();
$rebuilt_fields = $this->rebuild_field_template( $template_id );
foreach( $rebuilt_fields as $field_name => $field ) {
if ( isset( $field['composite_type'], $field['composite_structure'] ) ) {
require_once ET_BUILDER_DIR . 'module/field/attribute/composite/Parser.php';
$composite_atts = ET_Builder_Module_Field_Attribute_Composite_Parser::parse( $field['composite_type'], $field['composite_structure'] );
$default_props = array_merge( $default_props, $composite_atts );
if ( isset( $field['default_on_front'] ) ) {
$value = $field['default_on_front'];
} else if ( isset( $field['default'] ) ) {
$value = $field['default'];
$default_props[ $field_name ] = $value;
$this->set_cache( $cache_name, $cache_key, $default_props );