: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$body_classes = get_body_class();
// Add Class only to WooCommerce Shop page if built using Divi (i.e. Divi Shop page).
if ( ! ( function_exists( 'is_shop' ) && is_shop() ) ) {
// Add Class only when the WooCommerce Shop page is built using Divi.
if ( ! et_builder_wc_is_non_product_post_type() ) {
// Precautionary check: $body_classes should always be an array.
if ( ! is_array( $body_classes ) ) {
// Add Class only when the <body> tag does not contain them.
$woocommerce_classes = array( 'woocommerce', 'woocommerce-page' );
$common_classes = array_intersect( $body_classes, array(
if ( is_array( $common_classes )
&& count( $woocommerce_classes ) === count( $common_classes ) ) {
// Precautionary check: $classes should always be an array.
if ( ! is_array( $classes ) ) {
$classes[] = 'woocommerce';
$classes[] = 'woocommerce-page';
* Sets the Product page layout post meta on two occurrences.
* They are 1) On WP Admin Publish/Update post 2) On VB Save.
function et_builder_set_product_page_layout_meta( $post_id ) {
$post = get_post( $post_id );
* The Product page layout post meta adds no meaning to the Post when the Builder is not used.
* Hence the meta key/value is removed, when the Builder is turned off.
if ( ! et_pb_is_pagebuilder_used( $post_id ) ) {
delete_post_meta( $post_id, ET_BUILDER_WC_PRODUCT_PAGE_LAYOUT_META_KEY );
// Do not update Product page layout post meta when it contains a value.
$product_page_layout = get_post_meta(
ET_BUILDER_WC_PRODUCT_PAGE_LAYOUT_META_KEY,
if ( $product_page_layout ) {
$product_page_layout = et_get_option(
'et_pb_woocommerce_page_layout',
ET_BUILDER_WC_PRODUCT_PAGE_LAYOUT_META_KEY,
sanitize_text_field( $product_page_layout )
* Sets the Product content status as modified during VB save.
* This avoids setting the default WooCommerce Modules layout more than once.
* @link https://github.com/elegantthemes/Divi/issues/16420
* @param int $post_id Post ID.
function et_builder_set_product_content_status( $post_id ) {
if ( 0 === absint( $post_id ) ) {
if ( 'product' !== get_post_type( $post_id ) || 'modified' === get_post_meta( $post_id,
ET_BUILDER_WC_PRODUCT_PAGE_CONTENT_STATUS_META_KEY, true ) ) {
update_post_meta( $post_id, ET_BUILDER_WC_PRODUCT_PAGE_CONTENT_STATUS_META_KEY, 'modified' );
* Gets Woocommerce Tabs for the given Product ID.
function et_builder_get_woocommerce_tabs() {
et_core_security_check( 'edit_posts', 'et_builder_get_woocommerce_tabs', 'nonce' );
$product_id = $_->array_get( $_POST, 'product', 0 );
if ( null === $product_id || ! et_is_woocommerce_plugin_active() ) {
// Allow Latest Product ID which is a string 'latest'.
// `This Product` tabs are defined in et_fb_current_page_params()
if ( ! in_array( $product_id, array( 'current', 'latest' ) ) && 0 === absint( $product_id ) ) {
$tabs = ET_Builder_Module_Woocommerce_Tabs::get_tabs( array( 'product' => $product_id ) );
wp_send_json_success( $tabs );
* Returns alternative hook to make Woo Extra Product Options display fields in FE when TB is
* - The Woo Extra Product Options addon does not display the extra fields on the FE.
* - This is because the original hook i.e. `woocommerce_before_single_product` in the plugin
* is not triggered when TB is enabled.
* - Hence return a suitable hook that is fired for all types of Products i.e. Simple, Variable,
* @see WEPOF_Product_Options_Frontend::define_public_hooks()
* @return string WooCommerce Hook that is being fired on TB enabled Product pages.
function et_builder_trigger_extra_product_options( $hook ) {
return 'woocommerce_before_add_to_cart_form';
* Strip Builder shortcodes to avoid nested parsing.
* @see https://github.com/elegantthemes/Divi/issues/18682
function et_builder_avoid_nested_shortcode_parsing( $content ) {
// Strip shortcodes only on non-builder pages that contain Builder shortcodes.
if ( et_pb_is_pagebuilder_used( get_the_ID() ) ) {
// WooCommerce layout loads when builder is not enabled.
// So strip builder shortcodes from Post content.
if ( function_exists( 'is_product' ) && is_product() ) {
return et_strip_shortcodes( $content );
// Strip builder shortcodes from non-product pages.
// Only Tabs shortcode is checked since that causes nested rendering.
if ( has_shortcode( $content, 'et_pb_wc_tabs' ) ) {
return et_strip_shortcodes( $content );
* Parses Product description to
* - converts any [embed][/embed] shortcode to its respective HTML.
* - strips `et_` shortcodes to avoid nested rendering in Woo Tabs module.
* - adds <p> tag to keep the paragraph sanity.
* - runs other shortcodes if any using do_shortcode.
* @param string $description
function et_builder_wc_parse_description( $description ) {
if ( ! is_string( $description ) ) {
$parsed_description = et_strip_shortcodes( $description );
$parsed_description = $wp_embed->run_shortcode( $parsed_description );
$parsed_description = do_shortcode( $parsed_description );
$parsed_description = wpautop( $parsed_description );
return $parsed_description;
* Entry point for the woocommerce-modules.php file.
function et_builder_wc_init() {
// global $post won't be available with `after_setup_theme` hook and hence `wp` hook is used.
add_action( 'wp', 'et_builder_wc_override_default_layout' );
// Add WooCommerce class names on non-`product` CPT which uses builder
add_filter( 'body_class', 'et_builder_wc_add_body_class' );
add_filter( 'et_builder_inner_content_class', 'et_builder_wc_add_inner_content_class' );
add_filter( 'et_builder_outer_content_class', 'et_builder_wc_add_outer_content_class' );
// Load WooCommerce related scripts
add_action( 'wp_enqueue_scripts', 'et_builder_wc_load_scripts', 15 );
'et_builder_skip_content_activation',
'et_builder_wc_skip_initial_content',
// Show Product Content dropdown settings under
// Divi Theme Options ⟶ Builder ⟶ Post TYpe Integration.
add_filter( 'et_builder_settings_definitions', 'et_builder_wc_add_settings' );
* Adds the metabox only to Product post type.
* This is achieved using the post type hook - add_meta_boxes_{post_type}.
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/add_meta_boxes
add_action( 'add_meta_boxes_product', 'et_builder_wc_long_description_metabox_register' );
// Saves the long description metabox data.
// Since `et_pb_metabox_settings_save_details()` already uses `save_post` hook
// to save `_et_pb_old_content` post meta,
// we use this additional hook `et_pb_old_content_updated`.
add_action( 'et_pb_old_content_updated', 'et_builder_wc_long_description_metabox_save', 10, 3 );
// 01. Sets the initial Content when `Use Divi Builder` button is clicked
// in the Admin dashboard.
// 02. Sets the initial Content when `Enable Visual Builder` is clicked.
'et_fb_load_raw_post_content',
'et_builder_wc_set_initial_content',
add_action( 'et_save_post', 'et_builder_set_product_page_layout_meta' );
* Set the Product modified status as modified upon save to make sure default layout is not
* loaded more than one time.
* @see https://github.com/elegantthemes/Divi/issues/16420
add_action( 'et_update_post', 'et_builder_set_product_content_status' );
* Handle get Woocommerce tabs AJAX call initiated by Tabs checkbox in settings modal.
add_action( 'wp_ajax_et_builder_get_woocommerce_tabs', 'et_builder_get_woocommerce_tabs' );
* Fix Woo Extra Product Options addon compatibility.
* @see https://github.com/elegantthemes/Divi/issues/17909
add_filter( 'thwepof_hook_name_before_single_product', 'et_builder_trigger_extra_product_options' );
* Fix nested parsing on non-builder product pages w/ shortcode content.
* @see https://github.com/elegantthemes/Divi/issues/18682
add_filter( 'the_content', 'et_builder_avoid_nested_shortcode_parsing' );
add_filter( 'et_builder_wc_description', 'et_builder_wc_parse_description' );