is_runtime_enabled() ) { return; } if ( ! self::cache_operational() ) { return; } add_action( 'wp_head', array( $this, 'output_custom_css' ), 100 ); add_action( 'wp_head', array( $this, 'output_collapse_secondary_css' ), 101 ); add_action( 'loop_start', array( $this, 'prime_card_loop' ) ); add_action( 'wp_head', array( $this, 'output_early_multi_select_css' ), 1 ); add_action( 'woocommerce_after_variations_table', array( $this, 'print_multi_select_boxes' ) ); add_filter( 'woocommerce_available_variation', array( $this, 'note_variation_stock' ), 10, 3 ); add_filter( 'rooster/used_css/safelist', array( __CLASS__, 'shades_safelist' ) ); add_action( 'wp', array( $this, 'setup_archive_swatches' ) ); add_filter( 'render_block_core/post-title', array( $this, 'title_line_in_title' ), 10, 3 ); add_action( 'woocommerce_single_product_summary', array( $this, 'print_title_line' ), 6 ); add_action( 'wp', array( $this, 'maybe_remove_default_add_to_cart' ), 20 ); add_action( 'wp_footer', array( $this, 'output_cart_variations_data_tag' ) ); add_filter( 'woocommerce_add_to_cart_fragments', array( $this, 'add_cart_variations_fragment' ) ); add_filter( 'body_class', array( $this, 'filter_body_class' ) ); add_filter( 'woocommerce_ajax_variation_threshold', array( $this, 'filter_ajax_variation_threshold' ), 10, 2 ); add_action( 'wc_ajax_aieo_card_form', array( $this, 'ajax_card_form' ) ); add_filter( 'rooster/performance/delay_keep', array( __CLASS__, 'keep_card_script' ) ); add_filter( 'woocommerce_dropdown_variation_attribute_options_html', array( $this, 'filter_variation_attribute_options_html' ), 10, 2 ); if ( class_exists( 'AIEO_Theme_Adapters' ) ) { add_action( 'wp', array( $this, 'arbitrate_with_theme' ), 5 ); } add_filter( 'woocommerce_cart_item_thumbnail', array( $this, 'filter_cart_item_thumbnail' ), 10, 3 ); add_filter( 'style_loader_src', array( $this, 'veto_swatch_skin' ), 10, 2 ); add_action( 'shutdown', array( $this, 'flush_pending_rebuilds' ) ); } private $swatch_mode = null; private $stand_down = null; const SETTINGS_OPTION = 'aieo_dmm_swatches_settings'; const OLD_SWITCH = 'aieo_dmm_swatches_runtime_enabled'; const ONE_SWITCH = 'aieo_dmm_swatches_one_switch'; public static function on() { if ( ! get_option( self::ONE_SWITCH ) ) { self::carry_over(); } $s = get_option( self::SETTINGS_OPTION, array() ); return is_array( $s ) && 'yes' === (string) ( $s['enabled'] ?? 'no' ); } public static function carry_over() { $old = get_option( self::OLD_SWITCH, null ); $s = get_option( self::SETTINGS_OPTION, array() ); $s = is_array( $s ) ? $s : array(); $want = 'yes' === (string) $old ? 'yes' : 'no'; if ( ( $s['enabled'] ?? null ) !== $want ) { $s['enabled'] = $want; $hash = get_option( 'aieo_dmm_swatches_settings_hash', null ); update_option( self::SETTINGS_OPTION, $s, false ); if ( null !== $hash ) { update_option( 'aieo_dmm_swatches_settings_hash', $hash, false ); } } delete_option( self::OLD_SWITCH ); update_option( self::ONE_SWITCH, 1, true ); } private function is_runtime_enabled() { return self::on(); } public static function cache_operational() { $state = get_option( self::CACHE_READY_OPTION, '' ); if ( 'yes' !== $state && 'no' !== $state ) { global $wpdb; $table = $wpdb->prefix . 'aieo_dmm_swatches_cache'; $exists = function_exists( 'aieo_dmm_table_exists' ) ? aieo_dmm_table_exists( $table ) : ( $table === $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) ); $state = ( $exists && $wpdb->get_var( "SELECT 1 FROM {$table} LIMIT 1" ) ) ? 'yes' : 'no'; update_option( self::CACHE_READY_OPTION, $state, true ); } return 'yes' === $state; } private function get_settings() { if ( $this->settings === null ) { $stored = get_option( 'aieo_dmm_swatches_settings', array() ); $this->settings = is_array( $stored ) ? $stored : array(); $this->settings_hash = (string) get_option( 'aieo_dmm_swatches_settings_hash', '' ); if ( $this->settings_hash !== '' && class_exists( 'AIEO_DMM_Swatches' ) ) { $this->settings_hash .= AIEO_DMM_Swatches::SWATCH_PAYLOAD_SUFFIX; } } return $this->settings; } public function output_collapse_secondary_css() { if ( ! wp_style_is( 'aieo-swatches', 'enqueued' ) ) { return; } echo ''; } public function output_custom_css() { if ( class_exists( 'OM_Product_Swatches_Handler' ) ) { return; } $s = $this->get_settings(); $measures = self::theme_swatch_measures(); $v = function ( $key, $default ) use ( $s, $measures ) { $val = ( ! isset( $s[ $key ] ) || $s[ $key ] === '' ) ? $default : $s[ $key ]; return self::themed_value( (string) $key, $val, $default, $measures ); }; $css = ''; $css .= ".om-variation-type-color :is(a,label) {" . "width:{$v('color_width',24)}px;height:{$v('color_height',24)}px;" . "border-radius:{$v('color_border_radius',50)}px;" . "border:{$v('color_border_size',1)}px solid {$v('color_border_color','#dedede')};" . "}"; $css .= ".om-variation-type-color :is(a,label):hover{" . "border:{$v('color_border_size_hover',2)}px solid {$v('color_border_color_hover','#212121')};" . "}"; $css .= ".om-variation-type-color :is(a,label).active,.om-variation-type-color a[aria-checked='true'],.om-variation-type-color label:has(> .om-variation-input:checked){" . "border:{$v('color_border_size_selected',2)}px solid {$v('color_border_color_selected','#212121')};" . "}"; $css .= ".om-variation-type-color{gap:{$v('color_gap',8)}px;}"; $css .= ".om-variation-type-button :is(a,label){" . "color:{$v('button_text_color','#212121')};" . "background-color:{$v('button_bg_color','#ffffff')};" . "border:{$v('button_border_size',1)}px solid {$v('button_border_color','#212121')};" . "border-radius:{$v('button_border_radius',5)}px;" . "padding:{$v('button_padding_top',8)}px {$v('button_padding_right',12)}px {$v('button_padding_bottom',8)}px {$v('button_padding_left',12)}px;" . "}"; $css .= ".om-variation-type-button :is(a,label):hover{" . "color:{$v('button_text_color_hover','#ffffff')};" . "background-color:{$v('button_bg_color_hover','#212121')};" . "border-color:{$v('button_border_color_hover','#212121')};" . "}"; $css .= ".om-variation-type-button :is(a,label).active,.om-variation-type-button a[aria-checked='true'],.om-variation-type-button label:has(> .om-variation-input:checked){" . "color:{$v('button_text_color_selected','#ffffff')};" . "background-color:{$v('button_bg_color_selected','#212121')};" . "border-color:{$v('button_border_color_selected','#212121')};" . "}"; $css .= ".om-variation-type-button{gap:{$v('button_gap',8)}px;}"; $css .= ".om-variation-type-image :is(a,label){" . "width:{$v('image_width',72)}px;height:{$v('image_height',72)}px;" . "border-radius:{$v('image_border_radius',0)}px;" . "border:{$v('image_border_size',1)}px solid {$v('image_border_color','#dedede')};" . "overflow:hidden;}"; $css .= ".om-variation-type-image :is(a,label) img{border-radius:{$v('image_border_radius',0)}px;}"; $css .= ".om-variation-type-image :is(a,label):hover{" . "border:{$v('image_border_size_hover',2)}px solid {$v('image_border_color_hover','#212121')};" . "}"; $css .= ".om-variation-type-image :is(a,label).active,.om-variation-type-image a[aria-checked='true'],.om-variation-type-image label:has(> .om-variation-input:checked){" . "border:{$v('image_border_size_selected',2)}px solid {$v('image_border_color_selected','#212121')};" . "}"; $css .= ".om-variation-type-image{gap:{$v('image_gap',12)}px;}"; $css .= $this->build_archive_css( $v ); $css .= $this->build_recommendation_css( $v ); $css .= 'body.om-multi-select-enabled .variations_form table.variations,' . 'body.om-multi-select-enabled .variations_form table.variations tbody,' . 'body.om-multi-select-enabled .variations_form table.variations tr' . '{display:block;width:100%;}' . 'body.om-multi-select-enabled .variations_form table.variations th.label' . '{display:none;}' . 'body.om-multi-select-enabled .variations_form table.variations td.value' . '{display:block;padding:0;width:100%;}'; $mobile_css = ''; $mw_pdp = (int) $v( 'image_width_mobile', 56 ); $mh_pdp = (int) $v( 'image_height_mobile', 56 ); $mw_arc = (int) $v( 'image_width_shop_archive_mobile', 22 ); $mh_arc = (int) $v( 'image_height_shop_archive_mobile', 22 ); if ( $mw_pdp > 0 || $mh_pdp > 0 ) { $mobile_css .= '.om-variation-type-image :is(a,label){'; if ( $mw_pdp > 0 ) { $mobile_css .= "width:{$mw_pdp}px;"; } if ( $mh_pdp > 0 ) { $mobile_css .= "height:{$mh_pdp}px;"; } $mobile_css .= '}'; } if ( $mw_arc > 0 || $mh_arc > 0 ) { $arc_selectors = '.om-product-swatches--archive .om-variation-type-image a,' . '.related.products .om-variation-type-image a,' . '.cross-sells .om-variation-type-image a,' . '.up-sells .om-variation-type-image a,' . 'section.related .om-variation-type-image a'; $mobile_css .= $arc_selectors . '{'; if ( $mw_arc > 0 ) { $mobile_css .= "width:{$mw_arc}px;"; } if ( $mh_arc > 0 ) { $mobile_css .= "height:{$mh_arc}px;"; } $mobile_css .= '}'; } $bpt = (int) $v( 'button_padding_top_mobile', 4 ); $bpr = (int) $v( 'button_padding_right_mobile', 8 ); $bpb = (int) $v( 'button_padding_bottom_mobile', 4 ); $bpl = (int) $v( 'button_padding_left_mobile', 8 ); $bfs = (int) $v( 'button_font_size_mobile', 11 ); if ( $bpt > 0 || $bpr > 0 || $bpb > 0 || $bpl > 0 || $bfs > 0 ) { $mobile_css .= '.om-variation-type-button :is(a,label){'; if ( $bpt > 0 || $bpr > 0 || $bpb > 0 || $bpl > 0 ) { $mobile_css .= "padding:{$bpt}px {$bpr}px {$bpb}px {$bpl}px;"; } if ( $bfs > 0 ) { $mobile_css .= "font-size:{$bfs}px;"; } $mobile_css .= '}'; } if ( $mobile_css !== '' ) { $css .= '@media (max-width:600px){' . $mobile_css . '}'; } if ( ! empty( $v( 'button_stack_vertical_archive', 0 ) ) ) { $row_sel = '.wc-block-product-template .om-product-swatches--archive .variations tr:has(.om-variation-type-button),' . '.wp-block-woocommerce-product-template .om-product-swatches--archive .variations tr:has(.om-variation-type-button)'; $list_sel = '.wc-block-product-template .om-product-swatches--archive .om-variation-type-button,' . '.wp-block-woocommerce-product-template .om-product-swatches--archive .om-variation-type-button'; $css .= $row_sel . '{' . 'position:absolute !important;' . 'top:25% !important;' . 'transform:translateY(-50%) !important;' . 'left:var(--wp--preset--spacing--3,12px) !important;' . 'right:auto !important;' . 'z-index:5 !important;' . 'width:auto !important;' . 'margin:0 !important;' . '}'; $css .= $list_sel . '{' . 'display:flex !important;' . 'flex-direction:column !important;' . 'align-items:center !important;' . 'justify-content:flex-start !important;' . '}'; if ( ! empty( $v( 'button_circle_archive', 0 ) ) ) { $diam = max( 20, (int) $v( 'button_circle_diameter_archive', 36 ) ); $fs = max( 6, (int) $v( 'button_font_size_shop_archive', 11 ) ); $a_sel = '.wc-block-product-template .om-product-swatches--archive .om-variation-type-button a,' . '.wp-block-woocommerce-product-template .om-product-swatches--archive .om-variation-type-button a'; $css .= $a_sel . '{' . 'width:' . $diam . 'px !important;' . 'height:' . $diam . 'px !important;' . 'border-radius:50% !important;' . 'padding:0 !important;' . 'font-size:' . $fs . 'px !important;' . 'display:flex !important;' . 'align-items:center !important;' . 'justify-content:center !important;' . 'line-height:1 !important;' . 'overflow:hidden !important;' . 'white-space:nowrap !important;' . 'text-align:center !important;' . '}'; } } $css = str_replace( ')px', ')', $css ); if ( 'designer' === $this->look() ) { $css .= self::designer_rows_css(); } if ( $css !== '' && wp_style_is( 'aieo-swatches', 'enqueued' ) ) { echo ''; } } public static function theme_swatch_measures() { static $measures = null; if ( null === $measures ) { $found = function_exists( 'wp_get_global_settings' ) ? wp_get_global_settings( array( 'custom', 'rooster', 'swatch' ) ) : array(); $measures = is_array( $found ) ? array_filter( $found, 'is_scalar' ) : array(); } return (array) apply_filters( 'aieo_swatches_theme_measures', $measures ); } public static function themed_value( $key, $value, $default, array $measures ) { if ( 0 !== strcasecmp( trim( (string) $value ), trim( (string) $default ) ) ) { return $value; } if ( false !== strpos( $key, '_color' ) ) { $roles = array( '#dedede' => 'line', '#212121' => 'fg', '#ffffff' => 'bg' ); $hex = strtolower( trim( (string) $value ) ); return isset( $roles[ $hex ] ) ? 'var(--wp--preset--color--' . $roles[ $hex ] . ',' . $hex . ')' : $value; } $card = false !== strpos( $key, '_shop_archive' ); $name = ''; if ( 1 === preg_match( '/^image_(?:width|height)(?:_shop_archive)?_mobile$/', $key ) ) { return isset( $measures[ $card ? 'size-card' : 'size' ] ) ? '' : $value; } elseif ( 1 === preg_match( '/^(?:color|image)_(?:width|height)(?:_shop_archive)?$/', $key ) ) { $name = $card ? 'size-card' : 'size'; } elseif ( 1 === preg_match( '/^(?:color|image|button)_gap(?:_shop_archive)?$/', $key ) ) { $name = $card ? 'gap-card' : 'gap'; } elseif ( 1 === preg_match( '/^(?:color|image)_border_radius(?:_shop_archive)?$/', $key ) ) { $name = 'shape'; } return ( '' !== $name && isset( $measures[ $name ] ) ) ? 'var(--wp--custom--rooster--swatch--' . $name . ',' . (int) $value . 'px)' : $value; } public static function assets_in_context( $in_context ) { if ( $in_context || self::$assets_wanted ) { return true; } $post = function_exists( 'get_post' ) ? get_post() : null; return $post instanceof WP_Post && ( has_block( 'aieo/product-card-swatches', $post ) || has_shortcode( (string) $post->post_content, 'aieo_product_swatches' ) ); } public static function want_assets() { self::$assets_wanted = true; } private function look() { $s = $this->get_settings(); return 'classic' === (string) ( $s['product_swatch_look'] ?? 'designer' ) ? 'classic' : 'designer'; } private function designer_draws( $is_archive, $control, $attribute_type, $product_id ) { return ! $is_archive && '' !== $control && in_array( $attribute_type, array( 'color', 'image' ), true ) && 'designer' === $this->look() && is_singular( 'product' ) && (int) get_queried_object_id() === (int) $product_id; } private $low_stock = array(); public function note_variation_stock( $data, $product = null, $variation = null ) { if ( $variation instanceof WC_Product && $variation->managing_stock() && $variation->is_in_stock() ) { $left = (int) $variation->get_stock_quantity(); $low = function_exists( 'wc_get_low_stock_amount' ) ? (int) wc_get_low_stock_amount( $variation ) : (int) get_option( 'woocommerce_notify_low_stock_amount', 2 ); if ( $left > 0 && $left <= $low ) { $this->low_stock[ (int) $variation->get_id() ] = $left; } } return $data; } private function cart_variation_ids( $product_id ) { if ( empty( $_COOKIE['woocommerce_items_in_cart'] ) || ! function_exists( 'WC' ) || ! WC()->cart ) { return array(); } $ids = array(); foreach ( WC()->cart->get_cart() as $item ) { if ( (int) ( $item['product_id'] ?? 0 ) === (int) $product_id && ! empty( $item['variation_id'] ) ) { $ids[ (int) $item['variation_id'] ] = ( $ids[ (int) $item['variation_id'] ] ?? 0 ) + max( 1, (int) ( $item['quantity'] ?? 1 ) ); } } return $ids; } private function chip_in_words( $html, $left, $bag ) { if ( ( $left <= 0 && $bag <= 0 ) || ! class_exists( 'WP_HTML_Tag_Processor' ) ) { return $html; } $tags = new WP_HTML_Tag_Processor( $html ); if ( ! $tags->next_tag( 'label' ) ) { return $html; } if ( $left > 0 ) { $tags->set_attribute( 'data-left', (string) $left ); } if ( $bag > 0 ) { $tags->set_attribute( 'data-in-bag', (string) $bag ); } if ( $tags->next_tag( 'input' ) ) { $name = (string) $tags->get_attribute( 'aria-label' ); $words = array(); if ( $left > 0 ) { $words[] = sprintf( __( 'Only %d left', 'ai-eshop-optimizer' ), $left ); } if ( $bag > 0 ) { $words[] = sprintf( __( 'In your bag: %s', 'ai-eshop-optimizer' ), number_format_i18n( $bag ) ); } $tags->set_attribute( 'aria-label', implode( ', ', array_merge( '' !== $name ? array( $name ) : array(), $words ) ) ); } return $tags->get_updated_html(); } public static function designer_rows_css() { $m = self::theme_swatch_measures(); $px = static function ( $value, $fallback ) { return is_scalar( $value ) && 1 === preg_match( '/^\s*(\d+(?:\.\d+)?)\s*(?:px)?\s*$/', (string) $value, $hit ) ? (float) $hit[1] : (float) $fallback; }; $size = max( 8.0, $px( $m['size'] ?? '', 40 ) ); $gap = max( 0.0, $px( $m['gap'] ?? '', 10 ) ); $rows = max( 1, (int) ( $m['rows'] ?? 2 ) ); $root = '.om-variations-wrapper[data-look="designer"]'; $css = ''; for ( $n = 1; $n <= 24; $n++ ) { $from = $n * $size + ( $n - 1 ) * $gap; $to = ( $n + 1 ) * $size + $n * $gap - 0.02; $when = array(); if ( $n > 1 ) { $when[] = '(min-width:' . $from . 'px)'; } if ( $n < 24 ) { $when[] = '(max-width:' . $to . 'px)'; } $past = $rows * $n + 1; $css .= '@container aieo-shades ' . implode( ' and ', $when ) . '{' . $root . ' .aieo-shades__chips>.om-variation-item:nth-child(n+' . $past . '){display:none}' . $root . ':not(:has(.aieo-shades__chips>.om-variation-item:nth-child(' . $past . '))) .aieo-shades__more{display:none}' . '}'; } return $css; } public static function shades_safelist( $list ) { $list = (array) $list; $list[] = '/^aieo-shades/'; $list[] = '/^om-multi-selected$/'; return $list; } public static function shades_i18n() { $quote = self::quote_words(); return array( 'chooseSome' => __( 'choose one or more', 'ai-eshop-optimizer' ), 'chooseShade' => __( 'Choose a shade', 'ai-eshop-optimizer' ), 'chosenOne' => __( '%s chosen', 'ai-eshop-optimizer' ), 'chosenMany' => _x( '%s chosen', 'several shades', 'ai-eshop-optimizer' ), 'bagOne' => __( '%s already in your bag', 'ai-eshop-optimizer' ), 'bagMany' => _x( '%s already in your bag', 'several shades', 'ai-eshop-optimizer' ), 'stockOne' => _n( '%s shade in stock', '%s shades in stock', 1, 'ai-eshop-optimizer' ), 'stockMany' => _n( '%s shade in stock', '%s shades in stock', 2, 'ai-eshop-optimizer' ), 'named' => __( '%1$s: %2$s', 'ai-eshop-optimizer' ), 'inStock' => __( 'In stock', 'ai-eshop-optimizer' ), 'outOfStock' => __( 'Out of stock', 'ai-eshop-optimizer' ), 'inYourBag' => __( 'In your bag: %s', 'ai-eshop-optimizer' ), 'askNone' => $quote['ask'], 'askAddNone' => $quote['add'], 'askOne' => __( 'Request a quote for %s shade', 'ai-eshop-optimizer' ), 'askMany' => __( 'Request a quote for %s shades', 'ai-eshop-optimizer' ), 'askAddOne' => __( 'Add %s shade to my quote', 'ai-eshop-optimizer' ), 'askAddMany' => __( 'Add %s shades to my quote', 'ai-eshop-optimizer' ), 'shadeOne' => _n( '%s shade', '%s shades', 1, 'ai-eshop-optimizer' ), 'shadeMany' => _n( '%s shade', '%s shades', 2, 'ai-eshop-optimizer' ), 'allOne' => _n( 'All %s shade', 'All %s shades', 1, 'ai-eshop-optimizer' ), 'allMany' => _n( 'All %s shade', 'All %s shades', 2, 'ai-eshop-optimizer' ), 'addN' => __( 'Add %1$s to cart · %2$s', 'ai-eshop-optimizer' ), 'find' => __( 'Find a shade', 'ai-eshop-optimizer' ), 'noMatch' => __( 'No shade matches.', 'ai-eshop-optimizer' ), 'less' => __( 'One less %s', 'ai-eshop-optimizer' ), 'more' => __( 'One more %s', 'ai-eshop-optimizer' ), 'quantityOf' => __( 'Quantity of %s', 'ai-eshop-optimizer' ), 'soldOut' => __( 'Sold out', 'ai-eshop-optimizer' ), 'backorder' => __( 'Available on back-order', 'ai-eshop-optimizer' ), 'left' => __( 'Only %d left', 'ai-eshop-optimizer' ), 'chosenSay' => __( 'Chosen: %s.', 'ai-eshop-optimizer' ), 'removedSay' => __( 'Removed: %s.', 'ai-eshop-optimizer' ), 'nothing' => __( 'Nothing chosen.', 'ai-eshop-optimizer' ), 'cleared' => __( 'Selections cleared.', 'ai-eshop-optimizer' ), 'done' => __( 'Done', 'ai-eshop-optimizer' ), 'close' => __( 'Close', 'ai-eshop-optimizer' ), ); } private static function quote_words() { $ask = class_exists( 'AIEO_Catalogue_Mode' ) ? (string) AIEO_Catalogue_Mode::request_label() : ''; $add = class_exists( 'AIEO_Product_Request_Settings' ) ? trim( (string) ( AIEO_Product_Request_Settings::get()['add_button_text'] ?? '' ) ) : ''; return array( 'ask' => '' !== $ask ? $ask : __( 'Request a quote', 'ai-eshop-optimizer' ), 'add' => '' !== $add ? $add : __( 'Add to my quote as well', 'ai-eshop-optimizer' ), ); } private $quote_for = 0; private $quote_one = array(); public function quote_picker_draws( $product_id ) { $product_id = (int) $product_id; if ( $product_id <= 0 || ! function_exists( 'woocommerce_variable_add_to_cart' ) || ! $this->is_runtime_enabled() || ! self::cache_operational() ) { return false; } if ( ! is_singular( 'product' ) || (int) get_queried_object_id() !== $product_id ) { return false; } if ( false === has_filter( 'woocommerce_dropdown_variation_attribute_options_html', array( $this, 'filter_variation_attribute_options_html' ) ) ) { return false; } $ps = $this->resolve_product_settings( $product_id ); if ( ! empty( $ps['multi_select_enabled'] ) && 'dropdown' === (string) ( $ps['display_style'] ?? 'grid' ) ) { return false; } return $this->swatches_draw( $product_id ); } public function quote_form_html( $product_id ) { $product = function_exists( 'wc_get_product' ) ? wc_get_product( (int) $product_id ) : null; if ( ! $product instanceof WC_Product || ! $product->is_type( 'variable' ) || ! $this->quote_picker_draws( (int) $product_id ) ) { return ''; } global $wp_filter; $pid = (int) $product->get_id(); $button = has_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button' ); if ( false !== $button ) { remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', (int) $button ); } $held = array(); foreach ( array( 'woocommerce_before_add_to_cart_form', 'woocommerce_after_add_to_cart_form' ) as $hook ) { if ( isset( $wp_filter[ $hook ] ) ) { $held[ $hook ] = $wp_filter[ $hook ]; unset( $wp_filter[ $hook ] ); } } add_filter( 'woocommerce_available_variation', array( __CLASS__, 'quote_variation_data' ), PHP_INT_MAX ); $previous = $GLOBALS['product'] ?? null; $GLOBALS['product'] = $product; $this->quote_for = $pid; ob_start(); try { woocommerce_variable_add_to_cart(); } finally { $html = trim( (string) ob_get_clean() ); $this->quote_for = 0; $GLOBALS['product'] = $previous; remove_filter( 'woocommerce_available_variation', array( __CLASS__, 'quote_variation_data' ), PHP_INT_MAX ); foreach ( $held as $hook => $callbacks ) { $wp_filter[ $hook ] = $callbacks; } if ( false !== $button ) { add_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', (int) $button ); } } if ( false === strpos( $html, '