: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Filters the $outer_wrapper_attrs.
* Adds 'data-button-class', 'data-button-icon', 'data-button-icon-tablet' and 'data-button-icon-phone' attributes if needed.
* @param array $outer_wrapper_attrs Key value pairs of outer wrapper attributes.
* @param ET_Builder_Element $this_class Module's class.
* @return array filtered $outer_wrapper_attrs.
public static function add_custom_button_icons( $outer_wrapper_attrs, $this_class ) {
$custom_icon_values = et_pb_responsive_options()->get_property_values( $this_class->props, 'button_icon' );
$custom_icon = isset( $custom_icon_values['desktop'] ) ? $custom_icon_values['desktop'] : '';
$custom_icon_tablet = isset( $custom_icon_values['tablet'] ) ? $custom_icon_values['tablet'] : '';
$custom_icon_phone = isset( $custom_icon_values['phone'] ) ? $custom_icon_values['phone'] : '';
if ( '' !== $custom_icon || '' !== $custom_icon_tablet || '' !== $custom_icon_phone ) {
$outer_wrapper_attrs['data-button-class'] = esc_attr( $this_class->get_button_classname() );
$outer_wrapper_attrs['data-button-icon'] = esc_attr( et_pb_process_font_icon( $custom_icon ) );
$outer_wrapper_attrs['data-button-icon-tablet'] = esc_attr( et_pb_process_font_icon( $custom_icon_tablet ) );
$outer_wrapper_attrs['data-button-icon-phone'] = esc_attr( et_pb_process_font_icon( $custom_icon_phone ) );
return $outer_wrapper_attrs;
* Gets the columns default.
public static function get_columns_posts_default() {
'et_builder_get_woo_default_columns',
* Gets the columns default value for the current Product.
public static function get_columns_posts_default_value() {
$post_id = et_core_page_resource_get_the_ID();
$post_id = $post_id ? $post_id : (int) et_()->array_get( $_POST, 'current_page.id' );
$page_layout = get_post_meta( $post_id, '_et_pb_page_layout', true );
if ( $page_layout && 'et_full_width_page' !== $page_layout && ! ET_Builder_Element::is_theme_builder_layout() ) {
return '3'; // Set to 3 if page has sidebar.
* Default number is based on the WooCommerce plugin default value.
* @see woocommerce_output_related_products()
* Gets the Title header tag.
* WooCommerce version influences the returned header.
public static function get_title_header() {
if ( ! et_is_woocommerce_plugin_active() ) {
if ( version_compare( $woocommerce->version, '3.0.0', '>=' ) ) {
* Gets the Title selector.
* WooCommerce changed the title tag from h3 to h2 in v3.0.0
* @uses ET_Builder_Module_Helper_Woocommerce_Modules::get_title_header()
public static function get_title_selector() {
return sprintf( 'li.product %s', self::get_title_header() );
* Appends Data Icon attribute to the Outer wrapper.
* @param array $outer_wrapper_attrs Key value pairs of outer wrapper attributes.
* @param mixed $this_class Module's class.
public static function output_data_icon_attrs( $outer_wrapper_attrs, $this_class ) {
$hover_icon = et_()->array_get( $this_class->props, 'hover_icon', '' );
$hover_icon_values = et_pb_responsive_options()->get_property_values( $this_class->props, 'hover_icon' );
$hover_icon_tablet = et_()->array_get( $hover_icon_values, 'tablet', '' );
$hover_icon_phone = et_()->array_get( $hover_icon_values, 'phone', '' );
$overlay_attributes = ET_Builder_Module_Helper_Overlay::get_attributes( array(
'icon_tablet' => $hover_icon_tablet,
'icon_phone' => $hover_icon_phone,
return array_merge( $outer_wrapper_attrs, $overlay_attributes );
* Return all possible product tabs.
* See woocommerce_default_product_tabs() in woocommerce/includes/wc-template-functions.php
public static function get_default_product_tabs() {
'title' => esc_html__( 'Description', 'et_builder' ),
'callback' => 'woocommerce_product_description_tab',
'additional_information' => array(
'title' => esc_html__( 'Additional information', 'et_builder' ),
'callback' => 'woocommerce_product_additional_information_tab',
'title' => esc_html__( 'Reviews', 'et_builder' ),
'callback' => 'comments_template',
public static function get_default_tab_options() {
$tabs = self::get_default_product_tabs();
foreach ( $tabs as $name => $tab ) {
if ( ! isset( $tab['title'] ) ) {
$options[ $name ] = array(
'label' => 'reviews' === $name ? esc_html__( 'Reviews', 'et_builder' ) :
esc_html( $tab['title'] ),
* Get calculated star rating width based on letter spacing value.
* WooCommerce's .star-rating uses `em` based width on float layout;
* any additional width caused by letter-spacing makes the calculation incorrect;
* thus the `width: calc()` overwrite.
public static function get_rating_width_style( $value ) {
$value = et_builder_process_range_value( $value );
$property_value = 'calc(5.4em + (' . $value . ' * 4))';
return sprintf( 'width: %1$s;', esc_html( $property_value ) );
* Get margin properties & values based on current alignment status.
* Default star alignment is not controlled by standard text align system. It uses float to control
* how stars symbol will be displayed based on the percentage. It's not possible to convert it to
* simple text align. We have to use margin left & right to set the alignment.
public static function get_rating_alignment_style( $align, $mode = 'desktop' ) {
// Bail early if mode is desktop and alignment is left or justify.
if ( 'desktop' === $mode && in_array( $align, array( 'left', 'justify' ) ) ) {
$margin_properties = array(
// By default (left or justify), the margin will be left: inherit and right: auto.
$margin_left = et_()->array_get( $margin_properties, "{$align}.left", '0' );
$margin_right = et_()->array_get( $margin_properties, "{$align}.right", 'auto' );
'margin-left: %1$s !important; margin-right: %2$s !important;',
esc_html( $margin_left ),
esc_html( $margin_right )
* Get specific star rating style based on property type.
public static function get_rating_style( $type, $value, $mode = 'desktop' ) {
case 'rating_letter_spacing':
$style = self::get_rating_width_style( $value );
case 'rating_text_align':
$style = self::get_rating_alignment_style( $value, $mode );
* Set styles for Woo's .star-rating element.
* @param string $render_slug
* @param string $selector
* @param string $hover_selector
public static function add_star_rating_style( $render_slug, $attrs, $selector = '%%order_class%% .star-rating', $hover_selector = '%%order_class%%:hover .star-rating', $props = array() ) {
// Supported star rating properties will be handled here.
if ( ! is_array( $props ) || empty( $props ) ) {
$props = array( 'rating_letter_spacing', 'rating_text_align' );
foreach ( $props as $prop ) {
$values = et_pb_responsive_options()->get_property_values( $attrs, $prop );
$hover_value = et_pb_hover_options()->get_value( $prop, $attrs, '' );
$processed_values = array();
// Get specific style value for desktop, tablet, and phone.
foreach ( $values as $device => $value ) {
$processed_values[ $device ] = self::get_rating_style( $prop, $value, $device );
// Generate style for desktop, tablet, and phone.
et_pb_responsive_options()->declare_responsive_css(
// Generate style for hover.
if ( et_builder_is_hover_enabled( $prop, $attrs ) && ! empty( $hover_value ) ) {
ET_Builder_Element::set_style( $render_slug, array(
'selector' => $hover_selector,
'declaration' => self::get_rating_style( $prop, $hover_value, 'hover', true ),
* Get the product default.
public static function get_product_default() {
'et_builder_get_woo_default_product',
* Get the product default value for the current post type.
public static function get_product_default_value() {
$post_id = et_core_page_resource_get_the_ID();
$post_id = $post_id ? $post_id : (int) et_()->array_get( $_POST, 'current_page.id' );
$post_type = get_post_type( $post_id );
if ( 'product' === $post_type || et_theme_builder_is_layout_post_type( $post_type ) ) {
* Converts the special chars in to their entities to be used in :before or :after
* pseudo selector content.
* @see https://github.com/elegantthemes/Divi/issues/16976
public static function escape_special_chars( $chars ) {
switch ( trim( $chars ) ) {
* Gets the WooCommerce Tabs defaults.
* Implementation based on
* @see https://github.com/elegantthemes/submodule-builder/pull/6568
public static function get_woo_default_tabs() {
'et_builder_get_woo_default_tabs',
* Gets the WooCommerce Tabs options for the given Product.
public static function get_woo_default_tabs_options() {
$maybe_product_id = self::get_product_default_value();
$product_id = self::get_product( $maybe_product_id );
$current_product = wc_get_product( $product_id );
if ( ! $current_product ) {
$original_product = $product;
$product = $current_product;
$post = get_post( $product->get_id() );
$tabs = apply_filters( 'woocommerce_product_tabs', array() );
// Reset global $product.
$product = $original_product;
if ( ! empty( $tabs ) ) {
return implode( '|', array_keys( $tabs ) );
* Sets the Display type to render only Products.
* @see https://github.com/elegantthemes/Divi/issues/17998
* @used-by ET_Builder_Module_Woocommerce_Related_Products::render()
* @used-by ET_Builder_Module_Woocommerce_Upsells::render()
* @param string $option_name
* @param string $display_type
public static function set_display_type_to_render_only_products( $option_name,
$existing_display_type = get_option( $option_name );
update_option( $option_name, $display_type );
return $existing_display_type;
* Resets the display type to the existing value.
* @see https://github.com/elegantthemes/Divi/issues/17998
* @used-by ET_Builder_Module_Woocommerce_Related_Products::render()
* @used-by ET_Builder_Module_Woocommerce_Upsells::render()
public static function reset_display_type( $option_name, $display_type ) {
update_option( $option_name, $display_type );
'et_builder_get_woo_default_columns',
'ET_Builder_Module_Helper_Woocommerce_Modules',
'get_columns_posts_default_value',
'et_builder_get_woo_default_product',
'ET_Builder_Module_Helper_Woocommerce_Modules',
'get_product_default_value',
'et_builder_get_woo_default_tabs',
'ET_Builder_Module_Helper_Woocommerce_Modules',
'get_woo_default_tabs_options',