Commit 01c8ca8304 for woocommerce
commit 01c8ca8304985e271792f7f8eadcda34b5dcdcab
Author: Albert Juhé Lluveras <contact@albertjuhe.com>
Date: Wed Dec 31 10:20:56 2025 +0100
Disable add to cart button in variable products until the script has loaded (#62631)
* Disabled add to cart button in variable products until the script has loaded
* Autoformatting
* Add changelog file
* Simplify logic
diff --git a/plugins/woocommerce/changelog/fix-62448-disable-add-to-cart-button-variable-products b/plugins/woocommerce/changelog/fix-62448-disable-add-to-cart-button-variable-products
new file mode 100644
index 0000000000..299c7b31ee
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-62448-disable-add-to-cart-button-variable-products
@@ -0,0 +1,4 @@
+Significance: patch
+Type: enhancement
+
+Disable add to cart button in variable products until the script has loaded
diff --git a/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js b/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js
index 5f6de5e031..2df4717f71 100644
--- a/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js
+++ b/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js
@@ -1,49 +1,97 @@
/*global wc_add_to_cart_variation_params */
-;(function ( $, window, document, undefined ) {
+( function ( $, window, document, undefined ) {
/**
* VariationForm class which handles variation forms and attributes.
*/
- var VariationForm = function( $form ) {
+ var VariationForm = function ( $form ) {
var self = this;
- self.$form = $form;
- self.$attributeFields = $form.find( '.variations select' );
- self.$singleVariation = $form.find( '.single_variation' );
+ self.$form = $form;
+ self.$attributeFields = $form.find( '.variations select' );
+ self.$singleVariation = $form.find( '.single_variation' );
self.$singleVariationWrap = $form.find( '.single_variation_wrap' );
- self.$resetVariations = $form.find( '.reset_variations' );
- self.$resetAlert = $form.find( '.reset_variations_alert' );
- self.$product = $form.closest( '.product' );
- self.variationData = $form.data( 'product_variations' );
- self.useAjax = false === self.variationData;
- self.xhr = false;
- self.loading = true;
+ self.$resetVariations = $form.find( '.reset_variations' );
+ self.$resetAlert = $form.find( '.reset_variations_alert' );
+ self.$product = $form.closest( '.product' );
+ self.variationData = $form.data( 'product_variations' );
+ self.useAjax = false === self.variationData;
+ self.xhr = false;
+ self.loading = true;
// Initial state.
self.$singleVariationWrap.show();
self.$form.off( '.wc-variation-form' );
// Methods.
- self.getChosenAttributes = self.getChosenAttributes.bind( self );
- self.findMatchingVariations = self.findMatchingVariations.bind( self );
- self.isMatch = self.isMatch.bind( self );
- self.toggleResetLink = self.toggleResetLink.bind( self );
- self.showNoMatchingVariationsMsg = self.showNoMatchingVariationsMsg.bind( self );
+ self.getChosenAttributes = self.getChosenAttributes.bind( self );
+ self.findMatchingVariations = self.findMatchingVariations.bind( self );
+ self.isMatch = self.isMatch.bind( self );
+ self.toggleResetLink = self.toggleResetLink.bind( self );
+ self.showNoMatchingVariationsMsg =
+ self.showNoMatchingVariationsMsg.bind( self );
// Events.
- $form.on( 'click.wc-variation-form', '.reset_variations', { variationForm: self }, self.onReset );
- $form.on( 'reload_product_variations', { variationForm: self }, self.onReload );
+ $form.on(
+ 'click.wc-variation-form',
+ '.reset_variations',
+ { variationForm: self },
+ self.onReset
+ );
+ $form.on(
+ 'reload_product_variations',
+ { variationForm: self },
+ self.onReload
+ );
$form.on( 'hide_variation', { variationForm: self }, self.onHide );
$form.on( 'show_variation', { variationForm: self }, self.onShow );
- $form.on( 'click', '.single_add_to_cart_button', { variationForm: self }, self.onAddToCart );
- $form.on( 'reset_data', { variationForm: self }, self.onResetDisplayedVariation );
- $form.on( 'reset_focus', { variationForm: self }, self.onResetVariationFocus );
- $form.on( 'announce_reset', { variationForm: self }, self.onAnnounceReset );
- $form.on( 'clear_reset_announcement', { variationForm: self }, self.onClearResetAnnouncement );
+ $form.on(
+ 'click',
+ '.single_add_to_cart_button',
+ { variationForm: self },
+ self.onAddToCart
+ );
+ $form.on(
+ 'reset_data',
+ { variationForm: self },
+ self.onResetDisplayedVariation
+ );
+ $form.on(
+ 'reset_focus',
+ { variationForm: self },
+ self.onResetVariationFocus
+ );
+ $form.on(
+ 'announce_reset',
+ { variationForm: self },
+ self.onAnnounceReset
+ );
+ $form.on(
+ 'clear_reset_announcement',
+ { variationForm: self },
+ self.onClearResetAnnouncement
+ );
$form.on( 'reset_image', { variationForm: self }, self.onResetImage );
- $form.on( 'change.wc-variation-form', '.variations select', { variationForm: self }, self.onChange );
- $form.on( 'found_variation.wc-variation-form', { variationForm: self }, self.onFoundVariation );
- $form.on( 'check_variations.wc-variation-form', { variationForm: self }, self.onFindVariation );
- $form.on( 'update_variation_values.wc-variation-form', { variationForm: self }, self.onUpdateAttributes );
+ $form.on(
+ 'change.wc-variation-form',
+ '.variations select',
+ { variationForm: self },
+ self.onChange
+ );
+ $form.on(
+ 'found_variation.wc-variation-form',
+ { variationForm: self },
+ self.onFoundVariation
+ );
+ $form.on(
+ 'check_variations.wc-variation-form',
+ { variationForm: self },
+ self.onFindVariation
+ );
+ $form.on(
+ 'update_variation_values.wc-variation-form',
+ { variationForm: self },
+ self.onUpdateAttributes
+ );
$form.on(
'keydown.wc-variation-form',
'.reset_variations',
@@ -52,9 +100,16 @@
);
// Init after gallery.
- setTimeout( function() {
+ setTimeout( function () {
$form.trigger( 'check_variations' );
$form.trigger( 'wc_variation_form', self );
+
+ // For variable products, we disable the button by default to avoid
+ // shoppers submitting the form with invalid data. We remove the
+ // disabled attribute as soon as the script is loaded and let the
+ // script handle the button state.
+ // @see https://github.com/woocommerce/woocommerce/issues/62448
+ $form.find( '.single_add_to_cart_button' ).removeAttr( 'disabled' );
self.loading = false;
}, 100 );
};
@@ -62,7 +117,7 @@
/**
* Reset all fields.
*/
- VariationForm.prototype.onReset = function( event ) {
+ VariationForm.prototype.onReset = function ( event ) {
event.preventDefault();
event.data.variationForm.$attributeFields.val( '' ).trigger( 'change' );
event.data.variationForm.$form.trigger( 'announce_reset' );
@@ -73,17 +128,17 @@
/**
* Reload variation data from the DOM.
*/
- VariationForm.prototype.onReload = function( event ) {
- var form = event.data.variationForm;
+ VariationForm.prototype.onReload = function ( event ) {
+ var form = event.data.variationForm;
form.variationData = form.$form.data( 'product_variations' );
- form.useAjax = false === form.variationData;
+ form.useAjax = false === form.variationData;
form.$form.trigger( 'check_variations' );
};
/**
* When a variation is hidden.
*/
- VariationForm.prototype.onHide = function( event ) {
+ VariationForm.prototype.onHide = function ( event ) {
event.preventDefault();
event.data.variationForm.$form
.find( '.single_add_to_cart_button' )
@@ -98,12 +153,18 @@
/**
* When a variation is shown.
*/
- VariationForm.prototype.onShow = function( event, variation, purchasable ) {
+ VariationForm.prototype.onShow = function (
+ event,
+ variation,
+ purchasable
+ ) {
event.preventDefault();
if ( purchasable ) {
event.data.variationForm.$form
.find( '.single_add_to_cart_button' )
- .removeClass( 'disabled wc-variation-selection-needed wc-variation-is-unavailable' );
+ .removeClass(
+ 'disabled wc-variation-selection-needed wc-variation-is-unavailable'
+ );
event.data.variationForm.$form
.find( '.woocommerce-variation-add-to-cart' )
.removeClass( 'woocommerce-variation-add-to-cart-disabled' )
@@ -121,13 +182,12 @@
// If present, the media element library needs initialized on the variation description.
if ( wp.mediaelement ) {
- event.data.variationForm.$form.find( '.wp-audio-shortcode, .wp-video-shortcode' )
+ event.data.variationForm.$form
+ .find( '.wp-audio-shortcode, .wp-video-shortcode' )
.not( '.mejs-container' )
- .filter(
- function () {
- return ! $( this ).parent().hasClass( 'mejs-mediaelement' );
- }
- )
+ .filter( function () {
+ return ! $( this ).parent().hasClass( 'mejs-mediaelement' );
+ } )
.mediaelementplayer( wp.mediaelement.settings );
}
};
@@ -135,14 +195,18 @@
/**
* When the cart button is pressed.
*/
- VariationForm.prototype.onAddToCart = function( event ) {
- if ( $( this ).is('.disabled') ) {
+ VariationForm.prototype.onAddToCart = function ( event ) {
+ if ( $( this ).is( '.disabled' ) ) {
event.preventDefault();
- if ( $( this ).is('.wc-variation-is-unavailable') ) {
- window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text );
- } else if ( $( this ).is('.wc-variation-selection-needed') ) {
- window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text );
+ if ( $( this ).is( '.wc-variation-is-unavailable' ) ) {
+ window.alert(
+ wc_add_to_cart_variation_params.i18n_unavailable_text
+ );
+ } else if ( $( this ).is( '.wc-variation-selection-needed' ) ) {
+ window.alert(
+ wc_add_to_cart_variation_params.i18n_make_a_selection_text
+ );
}
}
};
@@ -150,14 +214,18 @@
/**
* When displayed variation data is reset.
*/
- VariationForm.prototype.onResetDisplayedVariation = function( event ) {
+ VariationForm.prototype.onResetDisplayedVariation = function ( event ) {
var form = event.data.variationForm;
form.$product.find( '.product_meta' ).find( '.sku' ).wc_reset_content();
form.$product
- .find( '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' )
+ .find(
+ '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value'
+ )
.wc_reset_content();
form.$product
- .find( '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' )
+ .find(
+ '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value'
+ )
.wc_reset_content();
form.$form.trigger( 'reset_image' );
form.$singleVariation.slideUp( 200 ).trigger( 'hide_variation' );
@@ -166,35 +234,43 @@
/**
* Announce reset to screen readers.
*/
- VariationForm.prototype.onAnnounceReset = function( event ) {
- event.data.variationForm.$resetAlert.text( wc_add_to_cart_variation_params.i18n_reset_alert_text );
- }
+ VariationForm.prototype.onAnnounceReset = function ( event ) {
+ event.data.variationForm.$resetAlert.text(
+ wc_add_to_cart_variation_params.i18n_reset_alert_text
+ );
+ };
/**
* Focus variation reset
*/
- VariationForm.prototype.onResetVariationFocus = function( event ) {
- event.data.variationForm.$attributeFields[0].focus();
- }
+ VariationForm.prototype.onResetVariationFocus = function ( event ) {
+ event.data.variationForm.$attributeFields[ 0 ].focus();
+ };
/** Clear reset announcement */
- VariationForm.prototype.onClearResetAnnouncement = function( event ) {
+ VariationForm.prototype.onClearResetAnnouncement = function ( event ) {
event.data.variationForm.$resetAlert.text( '' );
- }
+ };
/**
* When the product image is reset.
*/
- VariationForm.prototype.onResetImage = function( event ) {
+ VariationForm.prototype.onResetImage = function ( event ) {
event.data.variationForm.$form.wc_variations_image_update( false );
};
/**
* Looks for matching variations for current selected attributes.
*/
- VariationForm.prototype.onFindVariation = function( event, chosenAttributes ) {
- var form = event.data.variationForm,
- attributes = 'undefined' !== typeof chosenAttributes ? chosenAttributes : form.getChosenAttributes(),
+ VariationForm.prototype.onFindVariation = function (
+ event,
+ chosenAttributes
+ ) {
+ var form = event.data.variationForm,
+ attributes =
+ 'undefined' !== typeof chosenAttributes
+ ? chosenAttributes
+ : form.getChosenAttributes(),
currentAttributes = attributes.data;
if ( attributes.count && attributes.count === attributes.chosenCount ) {
@@ -202,16 +278,27 @@
if ( form.xhr ) {
form.xhr.abort();
}
- form.$form.block( { message: null, overlayCSS: { background: '#fff', opacity: 0.6 } } );
- currentAttributes.product_id = parseInt( form.$form.data( 'product_id' ), 10 );
- currentAttributes.custom_data = form.$form.data( 'custom_data' );
- form.xhr = $.ajax( {
- url: wc_add_to_cart_variation_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_variation' ),
+ form.$form.block( {
+ message: null,
+ overlayCSS: { background: '#fff', opacity: 0.6 },
+ } );
+ currentAttributes.product_id = parseInt(
+ form.$form.data( 'product_id' ),
+ 10
+ );
+ currentAttributes.custom_data =
+ form.$form.data( 'custom_data' );
+ form.xhr = $.ajax( {
+ url: wc_add_to_cart_variation_params.wc_ajax_url
+ .toString()
+ .replace( '%%endpoint%%', 'get_variation' ),
type: 'POST',
data: currentAttributes,
- success: function( variation ) {
+ success: function ( variation ) {
if ( variation ) {
- form.$form.trigger( 'found_variation', [ variation ] );
+ form.$form.trigger( 'found_variation', [
+ variation,
+ ] );
} else {
form.$form.trigger( 'reset_data' );
attributes.chosenCount = 0;
@@ -221,15 +308,18 @@
}
}
},
- complete: function() {
+ complete: function () {
form.$form.unblock();
- }
+ },
} );
} else {
form.$form.trigger( 'update_variation_values' );
- var matching_variations = form.findMatchingVariations( form.variationData, currentAttributes ),
- variation = matching_variations.shift();
+ var matching_variations = form.findMatchingVariations(
+ form.variationData,
+ currentAttributes
+ ),
+ variation = matching_variations.shift();
if ( variation ) {
form.$form.trigger( 'found_variation', [ variation ] );
@@ -254,20 +344,22 @@
/**
* Triggered when a variation has been found which matches all attributes.
*/
- VariationForm.prototype.onFoundVariation = function( event, variation ) {
- var form = event.data.variationForm,
- $sku = form.$product.find( '.product_meta' ).find( '.sku' ),
- $weight = form.$product.find(
+ VariationForm.prototype.onFoundVariation = function ( event, variation ) {
+ var form = event.data.variationForm,
+ $sku = form.$product.find( '.product_meta' ).find( '.sku' ),
+ $weight = form.$product.find(
'.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value'
),
- $dimensions = form.$product.find(
+ $dimensions = form.$product.find(
'.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value'
),
- $qty_input = form.$singleVariationWrap.find( '.quantity input.qty[name="quantity"]' ),
- $qty = $qty_input.closest( '.quantity' ),
- purchasable = true,
- variation_id = '',
- template = false,
+ $qty_input = form.$singleVariationWrap.find(
+ '.quantity input.qty[name="quantity"]'
+ ),
+ $qty = $qty_input.closest( '.quantity' ),
+ purchasable = true,
+ variation_id = '',
+ template = false,
$template_html = '';
if ( variation.sku ) {
@@ -284,7 +376,9 @@
if ( variation.dimensions ) {
// Decode HTML entities.
- $dimensions.wc_set_content( $.parseHTML( variation.dimensions_html )[0].data );
+ $dimensions.wc_set_content(
+ $.parseHTML( variation.dimensions_html )[ 0 ].data
+ );
} else {
$dimensions.wc_reset_content();
}
@@ -294,63 +388,89 @@
if ( ! variation.variation_is_visible ) {
template = wp_template( 'unavailable-variation-template' );
} else {
- template = wp_template( 'variation-template' );
+ template = wp_template( 'variation-template' );
variation_id = variation.variation_id;
}
$template_html = template( {
- variation: variation
+ variation: variation,
} );
$template_html = $template_html.replace( '/*<![CDATA[*/', '' );
$template_html = $template_html.replace( '/*]]>*/', '' );
- form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( variation.variation_id ).trigger( 'change' );
+ form.$form
+ .find( 'input[name="variation_id"], input.variation_id' )
+ .val( variation.variation_id )
+ .trigger( 'change' );
// Hide or show qty input
if ( variation.is_sold_individually === 'yes' ) {
- $qty_input.val( '1' ).attr( 'min', '1' ).attr( 'max', '' ).trigger( 'change' );
+ $qty_input
+ .val( '1' )
+ .attr( 'min', '1' )
+ .attr( 'max', '' )
+ .trigger( 'change' );
$qty.hide();
} else {
-
- var qty_val = parseFloat( $qty_input.val() );
+ var qty_val = parseFloat( $qty_input.val() );
if ( isNaN( qty_val ) ) {
qty_val = variation.min_qty;
} else {
- qty_val = qty_val > parseFloat( variation.max_qty ) ? variation.max_qty : qty_val;
- qty_val = qty_val < parseFloat( variation.min_qty ) ? variation.min_qty : qty_val;
+ qty_val =
+ qty_val > parseFloat( variation.max_qty )
+ ? variation.max_qty
+ : qty_val;
+ qty_val =
+ qty_val < parseFloat( variation.min_qty )
+ ? variation.min_qty
+ : qty_val;
}
- $qty_input.attr( 'min', variation.min_qty ).attr( 'max', variation.max_qty ).val( qty_val ).trigger( 'change' );
+ $qty_input
+ .attr( 'min', variation.min_qty )
+ .attr( 'max', variation.max_qty )
+ .val( qty_val )
+ .trigger( 'change' );
$qty.show();
}
// Enable or disable the add to cart button
- if ( ! variation.is_purchasable || ! variation.is_in_stock || ! variation.variation_is_visible ) {
+ if (
+ ! variation.is_purchasable ||
+ ! variation.is_in_stock ||
+ ! variation.variation_is_visible
+ ) {
purchasable = false;
}
// Add a delay before updating the live region to ensure screen readers pick up the content changes.
- setTimeout( function() {
+ setTimeout( function () {
form.$singleVariation.html( $template_html );
// Reveal
if ( form.$singleVariation.text().trim() ) {
- form.$singleVariation.slideDown( 200 ).trigger( 'show_variation', [ variation, purchasable ] );
+ form.$singleVariation
+ .slideDown( 200 )
+ .trigger( 'show_variation', [ variation, purchasable ] );
} else {
- form.$singleVariation.show().trigger( 'show_variation', [ variation, purchasable ] );
+ form.$singleVariation
+ .show()
+ .trigger( 'show_variation', [ variation, purchasable ] );
}
- }, 300);
-
+ }, 300 );
};
/**
* Triggered when an attribute field changes.
*/
- VariationForm.prototype.onChange = function( event ) {
+ VariationForm.prototype.onChange = function ( event ) {
var form = event.data.variationForm;
- form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( '' ).trigger( 'change' );
+ form.$form
+ .find( 'input[name="variation_id"], input.variation_id' )
+ .val( '' )
+ .trigger( 'change' );
form.$form.trigger( 'clear_reset_announcement' );
form.$form.find( '.wc-no-matching-variations' ).parent().remove();
@@ -370,18 +490,18 @@
* @param {string} string
* @return {string}
*/
- VariationForm.prototype.addSlashes = function( string ) {
- string = string.replace( /'/g, '\\\'' );
- string = string.replace( /"/g, '\\\"' );
+ VariationForm.prototype.addSlashes = function ( string ) {
+ string = string.replace( /'/g, "\\'" );
+ string = string.replace( /"/g, '\\"' );
return string;
};
/**
* Updates attributes in the DOM to show valid values.
*/
- VariationForm.prototype.onUpdateAttributes = function( event ) {
- var form = event.data.variationForm,
- attributes = form.getChosenAttributes(),
+ VariationForm.prototype.onUpdateAttributes = function ( event ) {
+ var form = event.data.variationForm,
+ attributes = form.getChosenAttributes(),
currentAttributes = attributes.data;
if ( form.useAjax ) {
@@ -389,21 +509,27 @@
}
// Loop through selects and disable/enable options based on selections.
- form.$attributeFields.each( function( index, el ) {
- var current_attr_select = $( el ),
- current_attr_name = current_attr_select.data( 'attribute_name' ) || current_attr_select.attr( 'name' ),
- show_option_none = $( el ).data( 'show_option_none' ),
- option_gt_filter = ':gt(0)',
- attached_options_count = 0,
- new_attr_select = $( '<select/>' ),
- selected_attr_val = current_attr_select.val() || '',
+ form.$attributeFields.each( function ( index, el ) {
+ var current_attr_select = $( el ),
+ current_attr_name =
+ current_attr_select.data( 'attribute_name' ) ||
+ current_attr_select.attr( 'name' ),
+ show_option_none = $( el ).data( 'show_option_none' ),
+ option_gt_filter = ':gt(0)',
+ attached_options_count = 0,
+ new_attr_select = $( '<select/>' ),
+ selected_attr_val = current_attr_select.val() || '',
selected_attr_val_valid = true;
// Reference options set at first.
if ( ! current_attr_select.data( 'attribute_html' ) ) {
var refSelect = current_attr_select.clone();
- refSelect.find( 'option' ).removeAttr( 'attached' ).prop( 'disabled', false ).prop( 'selected', false );
+ refSelect
+ .find( 'option' )
+ .removeAttr( 'attached' )
+ .prop( 'disabled', false )
+ .prop( 'selected', false );
// Legacy data attribute.
current_attr_select.data(
@@ -413,7 +539,9 @@
current_attr_select.data( 'attribute_html', refSelect.html() );
}
- new_attr_select.html( current_attr_select.data( 'attribute_html' ) );
+ new_attr_select.html(
+ current_attr_select.data( 'attribute_html' )
+ );
// The attribute of this select field should not be taken into account when calculating its matching variations:
// The constraints of this attribute are shaped by the values of the other attributes.
@@ -421,16 +549,19 @@
checkAttributes[ current_attr_name ] = '';
- var variations = form.findMatchingVariations( form.variationData, checkAttributes );
+ var variations = form.findMatchingVariations(
+ form.variationData,
+ checkAttributes
+ );
// Loop through variations.
for ( var num in variations ) {
- if ( typeof( variations[ num ] ) !== 'undefined' ) {
+ if ( typeof variations[ num ] !== 'undefined' ) {
var variationAttributes = variations[ num ].attributes;
for ( var attr_name in variationAttributes ) {
if ( variationAttributes.hasOwnProperty( attr_name ) ) {
- var attr_val = variationAttributes[ attr_name ],
+ var attr_val = variationAttributes[ attr_name ],
variation_active = '';
if ( attr_name === current_attr_name ) {
@@ -440,25 +571,43 @@
if ( attr_val ) {
// Decode entities.
- attr_val = $( '<div/>' ).html( attr_val ).text();
+ attr_val = $( '<div/>' )
+ .html( attr_val )
+ .text();
// Attach to matching options by value. This is done to compare
// TEXT values rather than any HTML entities.
- var $option_elements = new_attr_select.find( 'option' );
+ var $option_elements =
+ new_attr_select.find( 'option' );
if ( $option_elements.length ) {
- for (var i = 0, len = $option_elements.length; i < len; i++) {
- var $option_element = $( $option_elements[i] ),
- option_value = $option_element.val();
+ for (
+ var i = 0,
+ len = $option_elements.length;
+ i < len;
+ i++
+ ) {
+ var $option_element = $(
+ $option_elements[ i ]
+ ),
+ option_value =
+ $option_element.val();
if ( attr_val === option_value ) {
- $option_element.addClass( 'attached ' + variation_active );
+ $option_element.addClass(
+ 'attached ' +
+ variation_active
+ );
break;
}
}
}
} else {
// Attach all apart from placeholder.
- new_attr_select.find( 'option:gt(0)' ).addClass( 'attached ' + variation_active );
+ new_attr_select
+ .find( 'option:gt(0)' )
+ .addClass(
+ 'attached ' + variation_active
+ );
}
}
}
@@ -467,21 +616,24 @@
}
// Count available options.
- attached_options_count = new_attr_select.find( 'option.attached' ).length;
+ attached_options_count =
+ new_attr_select.find( 'option.attached' ).length;
// Check if current selection is in attached options.
if ( selected_attr_val ) {
selected_attr_val_valid = false;
if ( 0 !== attached_options_count ) {
- new_attr_select.find( 'option.attached.enabled' ).each( function() {
- var option_value = $( this ).val();
-
- if ( selected_attr_val === option_value ) {
- selected_attr_val_valid = true;
- return false; // break.
- }
- });
+ new_attr_select
+ .find( 'option.attached.enabled' )
+ .each( function () {
+ var option_value = $( this ).val();
+
+ if ( selected_attr_val === option_value ) {
+ selected_attr_val_valid = true;
+ return false; // break.
+ }
+ } );
}
}
@@ -490,17 +642,26 @@
// - The current selection is non-empty.
// - The current selection is valid.
// - Placeholders are not set to be permanently visible.
- if ( attached_options_count > 0 && selected_attr_val && selected_attr_val_valid && ( 'no' === show_option_none ) ) {
+ if (
+ attached_options_count > 0 &&
+ selected_attr_val &&
+ selected_attr_val_valid &&
+ 'no' === show_option_none
+ ) {
new_attr_select.find( 'option:first' ).remove();
option_gt_filter = '';
}
// Detach unattached.
- new_attr_select.find( 'option' + option_gt_filter + ':not(.attached)' ).remove();
+ new_attr_select
+ .find( 'option' + option_gt_filter + ':not(.attached)' )
+ .remove();
// Finally, copy to DOM and set value.
current_attr_select.html( new_attr_select.html() );
- current_attr_select.find( 'option' + option_gt_filter + ':not(.enabled)' ).prop( 'disabled', true );
+ current_attr_select
+ .find( 'option' + option_gt_filter + ':not(.enabled)' )
+ .prop( 'disabled', true );
// Choose selected value.
if ( selected_attr_val ) {
@@ -513,7 +674,7 @@
} else {
current_attr_select.val( '' ); // No change event to prevent infinite loop.
}
- });
+ } );
// Custom event for when variations have been updated.
form.$form.trigger( 'woocommerce_update_variation_values' );
@@ -523,37 +684,41 @@
* Get chosen attributes from form.
* @return array
*/
- VariationForm.prototype.getChosenAttributes = function() {
- var data = {};
- var count = 0;
+ VariationForm.prototype.getChosenAttributes = function () {
+ var data = {};
+ var count = 0;
var chosen = 0;
- this.$attributeFields.each( function() {
- var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
- var value = $( this ).val() || '';
+ this.$attributeFields.each( function () {
+ var attribute_name =
+ $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
+ var value = $( this ).val() || '';
if ( value.length > 0 ) {
- chosen ++;
+ chosen++;
}
- count ++;
+ count++;
data[ attribute_name ] = value;
- });
+ } );
return {
- 'count' : count,
- 'chosenCount': chosen,
- 'data' : data
+ count: count,
+ chosenCount: chosen,
+ data: data,
};
};
/**
* Find matching variations for attributes.
*/
- VariationForm.prototype.findMatchingVariations = function( variations, attributes ) {
+ VariationForm.prototype.findMatchingVariations = function (
+ variations,
+ attributes
+ ) {
var matching = [];
for ( var i = 0; i < variations.length; i++ ) {
- var variation = variations[i];
+ var variation = variations[ i ];
if ( this.isMatch( variation.attributes, attributes ) ) {
matching.push( variation );
@@ -566,13 +731,22 @@
* See if attributes match.
* @return {Boolean}
*/
- VariationForm.prototype.isMatch = function( variation_attributes, attributes ) {
+ VariationForm.prototype.isMatch = function (
+ variation_attributes,
+ attributes
+ ) {
var match = true;
for ( var attr_name in variation_attributes ) {
if ( variation_attributes.hasOwnProperty( attr_name ) ) {
var val1 = variation_attributes[ attr_name ];
var val2 = attributes[ attr_name ];
- if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
+ if (
+ val1 !== undefined &&
+ val2 !== undefined &&
+ val1.length !== 0 &&
+ val2.length !== 0 &&
+ val1 !== val2
+ ) {
match = false;
}
}
@@ -583,10 +757,13 @@
/**
* Show or hide the reset link.
*/
- VariationForm.prototype.toggleResetLink = function( on ) {
+ VariationForm.prototype.toggleResetLink = function ( on ) {
if ( on ) {
if ( this.$resetVariations.css( 'visibility' ) === 'hidden' ) {
- this.$resetVariations.css( 'visibility', 'visible' ).hide().fadeIn();
+ this.$resetVariations
+ .css( 'visibility', 'visible' )
+ .hide()
+ .fadeIn();
}
} else {
this.$resetVariations.css( 'visibility', 'hidden' );
@@ -596,15 +773,15 @@
/**
* Show no matching variation message.
*/
- VariationForm.prototype.showNoMatchingVariationsMsg = function() {
+ VariationForm.prototype.showNoMatchingVariationsMsg = function () {
this.$form
.find( '.single_variation' )
.after(
'<div role="alert">' +
'<p class="wc-no-matching-variations woocommerce-info">' +
- wc_add_to_cart_variation_params.i18n_no_matching_variations_text +
+ wc_add_to_cart_variation_params.i18n_no_matching_variations_text +
'</p>' +
- '</div>'
+ '</div>'
)
.next( 'div' )
.find( '.wc-no-matching-variations' )
@@ -625,7 +802,7 @@
/**
* Function to call wc_variation_form on jquery selector.
*/
- $.fn.wc_variation_form = function() {
+ $.fn.wc_variation_form = function () {
new VariationForm( this );
return this;
};
@@ -633,7 +810,7 @@
/**
* Stores the default text for an element so it can be reset later
*/
- $.fn.wc_set_content = function( content ) {
+ $.fn.wc_set_content = function ( content ) {
if ( undefined === this.attr( 'data-o_content' ) ) {
this.attr( 'data-o_content', this.text() );
}
@@ -643,7 +820,7 @@
/**
* Stores the default text for an element so it can be reset later
*/
- $.fn.wc_reset_content = function() {
+ $.fn.wc_reset_content = function () {
if ( undefined !== this.attr( 'data-o_content' ) ) {
this.text( this.attr( 'data-o_content' ) );
}
@@ -652,9 +829,12 @@
/**
* Stores a default attribute for an element so it can be reset later
*/
- $.fn.wc_set_variation_attr = function( attr, value ) {
+ $.fn.wc_set_variation_attr = function ( attr, value ) {
if ( undefined === this.attr( 'data-o_' + attr ) ) {
- this.attr( 'data-o_' + attr, ( ! this.attr( attr ) ) ? '' : this.attr( attr ) );
+ this.attr(
+ 'data-o_' + attr,
+ ! this.attr( attr ) ? '' : this.attr( attr )
+ );
}
if ( false === value ) {
this.removeAttr( attr );
@@ -666,7 +846,7 @@
/**
* Reset a default attribute for an element so it can be reset later
*/
- $.fn.wc_reset_variation_attr = function( attr ) {
+ $.fn.wc_reset_variation_attr = function ( attr ) {
if ( undefined !== this.attr( 'data-o_' + attr ) ) {
this.attr( attr, this.attr( 'data-o_' + attr ) );
}
@@ -675,12 +855,13 @@
/**
* Reset the slide position if the variation has a different image than the current one
*/
- $.fn.wc_maybe_trigger_slide_position_reset = function( variation ) {
- var $form = $( this ),
- $product = $form.closest( '.product' ),
- $product_gallery = $product.find( '.images' ),
+ $.fn.wc_maybe_trigger_slide_position_reset = function ( variation ) {
+ var $form = $( this ),
+ $product = $form.closest( '.product' ),
+ $product_gallery = $product.find( '.images' ),
reset_slide_position = false,
- new_image_id = ( variation && variation.image_id ) ? variation.image_id : '';
+ new_image_id =
+ variation && variation.image_id ? variation.image_id : '';
if ( $form.attr( 'current-image' ) !== new_image_id ) {
reset_slide_position = true;
@@ -689,28 +870,42 @@
$form.attr( 'current-image', new_image_id );
if ( reset_slide_position ) {
- $product_gallery.trigger( 'woocommerce_gallery_reset_slide_position' );
+ $product_gallery.trigger(
+ 'woocommerce_gallery_reset_slide_position'
+ );
}
};
/**
* Sets product images for the chosen variation
*/
- $.fn.wc_variations_image_update = function( variation ) {
- var $form = this,
- $product = $form.closest( '.product' ),
- $product_gallery = $product.find( '.images' ),
- $gallery_nav = $product.find( '.flex-control-nav' ),
- $gallery_img = $gallery_nav.find( 'li:eq(0) img' ),
+ $.fn.wc_variations_image_update = function ( variation ) {
+ var $form = this,
+ $product = $form.closest( '.product' ),
+ $product_gallery = $product.find( '.images' ),
+ $gallery_nav = $product.find( '.flex-control-nav' ),
+ $gallery_img = $gallery_nav.find( 'li:eq(0) img' ),
$product_img_wrap = $product_gallery
- .find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' )
+ .find(
+ '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder'
+ )
.eq( 0 ),
- $product_img = $product_img_wrap.find( '.wp-post-image' ),
- $product_link = $product_img_wrap.find( 'a' ).eq( 0 );
-
- if ( variation && variation.image && variation.image.src && variation.image.src.length > 1 ) {
+ $product_img = $product_img_wrap.find( '.wp-post-image' ),
+ $product_link = $product_img_wrap.find( 'a' ).eq( 0 );
+
+ if (
+ variation &&
+ variation.image &&
+ variation.image.src &&
+ variation.image.src.length > 1
+ ) {
// See if the gallery has an image with the same original src as the image we want to switch to.
- var galleryHasImage = $gallery_nav.find( 'li img[data-o_src="' + variation.image.gallery_thumbnail_src + '"]' ).length > 0;
+ var galleryHasImage =
+ $gallery_nav.find(
+ 'li img[data-o_src="' +
+ variation.image.gallery_thumbnail_src +
+ '"]'
+ ).length > 0;
// If the gallery has the image, reset the images. We'll scroll to the correct one.
if ( galleryHasImage ) {
@@ -718,12 +913,14 @@
}
// See if gallery has a matching image we can slide to.
- var slideToImage = $gallery_nav.find( 'li img[src="' + variation.image.gallery_thumbnail_src + '"]' );
+ var slideToImage = $gallery_nav.find(
+ 'li img[src="' + variation.image.gallery_thumbnail_src + '"]'
+ );
if ( slideToImage.length > 0 ) {
slideToImage.trigger( 'flexslider-click' );
$form.attr( 'current-image', variation.image_id );
- window.setTimeout( function() {
+ window.setTimeout( function () {
$( window ).trigger( 'resize' );
$product_gallery.trigger( 'woocommerce_gallery_init_zoom' );
}, 20 );
@@ -731,25 +928,64 @@
}
$product_img.wc_set_variation_attr( 'src', variation.image.src );
- $product_img.wc_set_variation_attr( 'height', variation.image.src_h );
- $product_img.wc_set_variation_attr( 'width', variation.image.src_w );
- $product_img.wc_set_variation_attr( 'srcset', variation.image.srcset );
- $product_img.wc_set_variation_attr( 'sizes', variation.image.sizes );
- $product_img.wc_set_variation_attr( 'title', variation.image.title );
- $product_img.wc_set_variation_attr( 'data-caption', variation.image.caption );
+ $product_img.wc_set_variation_attr(
+ 'height',
+ variation.image.src_h
+ );
+ $product_img.wc_set_variation_attr(
+ 'width',
+ variation.image.src_w
+ );
+ $product_img.wc_set_variation_attr(
+ 'srcset',
+ variation.image.srcset
+ );
+ $product_img.wc_set_variation_attr(
+ 'sizes',
+ variation.image.sizes
+ );
+ $product_img.wc_set_variation_attr(
+ 'title',
+ variation.image.title
+ );
+ $product_img.wc_set_variation_attr(
+ 'data-caption',
+ variation.image.caption
+ );
$product_img.wc_set_variation_attr( 'alt', variation.image.alt );
- $product_img.wc_set_variation_attr( 'data-src', variation.image.full_src );
- $product_img.wc_set_variation_attr( 'data-large_image', variation.image.full_src );
- $product_img.wc_set_variation_attr( 'data-large_image_width', variation.image.full_src_w );
- $product_img.wc_set_variation_attr( 'data-large_image_height', variation.image.full_src_h );
- $product_img_wrap.wc_set_variation_attr( 'data-thumb', variation.image.src );
- $gallery_img.wc_set_variation_attr( 'src', variation.image.gallery_thumbnail_src );
- $product_link.wc_set_variation_attr( 'href', variation.image.full_src );
+ $product_img.wc_set_variation_attr(
+ 'data-src',
+ variation.image.full_src
+ );
+ $product_img.wc_set_variation_attr(
+ 'data-large_image',
+ variation.image.full_src
+ );
+ $product_img.wc_set_variation_attr(
+ 'data-large_image_width',
+ variation.image.full_src_w
+ );
+ $product_img.wc_set_variation_attr(
+ 'data-large_image_height',
+ variation.image.full_src_h
+ );
+ $product_img_wrap.wc_set_variation_attr(
+ 'data-thumb',
+ variation.image.src
+ );
+ $gallery_img.wc_set_variation_attr(
+ 'src',
+ variation.image.gallery_thumbnail_src
+ );
+ $product_link.wc_set_variation_attr(
+ 'href',
+ variation.image.full_src
+ );
} else {
$form.wc_variations_image_reset();
}
- window.setTimeout( function() {
+ window.setTimeout( function () {
$( window ).trigger( 'resize' );
$form.wc_maybe_trigger_slide_position_reset( variation );
$product_gallery.trigger( 'woocommerce_gallery_init_zoom' );
@@ -759,17 +995,19 @@
/**
* Reset main image to defaults.
*/
- $.fn.wc_variations_image_reset = function() {
- var $form = this,
- $product = $form.closest( '.product' ),
- $product_gallery = $product.find( '.images' ),
- $gallery_nav = $product.find( '.flex-control-nav' ),
- $gallery_img = $gallery_nav.find( 'li:eq(0) img' ),
+ $.fn.wc_variations_image_reset = function () {
+ var $form = this,
+ $product = $form.closest( '.product' ),
+ $product_gallery = $product.find( '.images' ),
+ $gallery_nav = $product.find( '.flex-control-nav' ),
+ $gallery_img = $gallery_nav.find( 'li:eq(0) img' ),
$product_img_wrap = $product_gallery
- .find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' )
+ .find(
+ '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder'
+ )
.eq( 0 ),
- $product_img = $product_img_wrap.find( '.wp-post-image' ),
- $product_link = $product_img_wrap.find( 'a' ).eq( 0 );
+ $product_img = $product_img_wrap.find( '.wp-post-image' ),
+ $product_link = $product_img_wrap.find( 'a' ).eq( 0 );
$product_img.wc_reset_variation_attr( 'src' );
$product_img.wc_reset_variation_attr( 'width' );
@@ -788,13 +1026,13 @@
$product_link.wc_reset_variation_attr( 'href' );
};
- $(function() {
+ $( function () {
if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) {
- $( '.variations_form' ).each( function() {
+ $( '.variations_form' ).each( function () {
$( this ).wc_variation_form();
- });
+ } );
}
- });
+ } );
/**
* Matches inline variation objects to chosen attributes
@@ -802,30 +1040,41 @@
* @type {Object}
*/
var wc_variation_form_matcher = {
- find_matching_variations: function( product_variations, settings ) {
+ find_matching_variations: function ( product_variations, settings ) {
var matching = [];
for ( var i = 0; i < product_variations.length; i++ ) {
- var variation = product_variations[i];
-
- if ( wc_variation_form_matcher.variations_match( variation.attributes, settings ) ) {
+ var variation = product_variations[ i ];
+
+ if (
+ wc_variation_form_matcher.variations_match(
+ variation.attributes,
+ settings
+ )
+ ) {
matching.push( variation );
}
}
return matching;
},
- variations_match: function( attrs1, attrs2 ) {
+ variations_match: function ( attrs1, attrs2 ) {
var match = true;
for ( var attr_name in attrs1 ) {
if ( attrs1.hasOwnProperty( attr_name ) ) {
var val1 = attrs1[ attr_name ];
var val2 = attrs2[ attr_name ];
- if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) {
+ if (
+ val1 !== undefined &&
+ val2 !== undefined &&
+ val1.length !== 0 &&
+ val2.length !== 0 &&
+ val1 !== val2
+ ) {
match = false;
}
}
}
return match;
- }
+ },
};
/**
@@ -834,7 +1083,7 @@
* @param {string} templateId
* @return {Function}
*/
- var wp_template = function( templateId ) {
+ var wp_template = function ( templateId ) {
var html = document.getElementById( 'tmpl-' + templateId ).textContent;
var hard = false;
// any <# #> interpolate (evaluate).
@@ -845,27 +1094,29 @@
// data.variation.object.item
// data.variation.object['item']
// data.variation.array[0]
- hard = hard || /{{{?\s?data\.variation\.[\w-]*[^\s}]/.test ( html );
+ hard = hard || /{{{?\s?data\.variation\.[\w-]*[^\s}]/.test( html );
if ( hard ) {
return wp.template( templateId );
}
- return function template ( data ) {
+ return function template( data ) {
var variation = data.variation || {};
- return html.replace( /({{{?)\s?data\.variation\.([\w-]*)\s?(}}}?)/g, function( _, open, key, close ) {
- // Error in the format, ignore.
- if ( open.length !== close.length ) {
- return '';
- }
- var replacement = variation[ key ] || '';
- // {{{ }}} => interpolate (unescaped).
- // {{ }} => interpolate (escaped).
- // https://codex.wordpress.org/Javascript_Reference/wp.template
- if ( open.length === 2 ) {
- return window.escape( replacement );
+ return html.replace(
+ /({{{?)\s?data\.variation\.([\w-]*)\s?(}}}?)/g,
+ function ( _, open, key, close ) {
+ // Error in the format, ignore.
+ if ( open.length !== close.length ) {
+ return '';
+ }
+ var replacement = variation[ key ] || '';
+ // {{{ }}} => interpolate (unescaped).
+ // {{ }} => interpolate (escaped).
+ // https://codex.wordpress.org/Javascript_Reference/wp.template
+ if ( open.length === 2 ) {
+ return window.escape( replacement );
+ }
+ return replacement;
}
- return replacement;
- });
+ );
};
};
-
-})( jQuery, window, document );
+} )( jQuery, window, document );
diff --git a/plugins/woocommerce/templates/single-product/add-to-cart/variation-add-to-cart-button.php b/plugins/woocommerce/templates/single-product/add-to-cart/variation-add-to-cart-button.php
index 162c6fad6c..6161e1104f 100644
--- a/plugins/woocommerce/templates/single-product/add-to-cart/variation-add-to-cart-button.php
+++ b/plugins/woocommerce/templates/single-product/add-to-cart/variation-add-to-cart-button.php
@@ -4,7 +4,7 @@
*
* @see https://woocommerce.com/document/template-structure/
* @package WooCommerce\Templates
- * @version 10.2.0
+ * @version 10.5.0
*/
defined( 'ABSPATH' ) || exit;
@@ -28,7 +28,7 @@ global $product;
do_action( 'woocommerce_after_add_to_cart_quantity' );
?>
- <button type="submit" class="single_add_to_cart_button button alt<?php echo esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ); ?>"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
+ <button type="submit" class="single_add_to_cart_button button alt<?php echo esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ); ?>" disabled><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
<?php do_action( 'woocommerce_after_add_to_cart_button' ); ?>