1
votes

I'm working through a scenario where I have a variable product and I'm attempting to disable select options for the variation based upon the user's selection. You'll notice, I have multiple values in for height and width. What I would like to achieve is that when a user selects a specific height, only the widths available are displayed. The same is true for height, if the height is a certain amount, I need to limit the width's that are available.

Illustrating variation options.

Initially I thought I could enqueue a piece of JavaScript to run if the product was a single product and if the product category matched the items I'm targeting for this specific functionality.

I then used basic jQuery to listen to change events on the height and width form items for the variation.

$( "#width" ).change(event, function(event) {
  console.log(event);
  console.log(this);
  console.log($(this));
  
  currentWidth = parseInt($(this).val().replace('"',''));
  console.log(currentWidth);

  isWidthSet = true;

  if(currentWidth == 80){
    //width is 80, must restrict max height.
    if(isHeightSet == false){
        $("#height").children().each(function(){
            if(parseInt($(this).val().replace('"','')) > 47){
                console.log(this);
                console.log($(this));
                $(this).removeClass('enabled');
                $(this).removeClass('attached');
                $(this).remove();
                $(this).attr('disabled','disabled');
            }
        });
    }else{
        //set alert somewhere. 
    }

  }
  
  
});

This does fire when different form options are selected, the issue is that there is additional functionality that appears to be rebuilding the variation options each time a attribute value is changed in the variation form.

While I understand this is part of how variations are designed, I'm looking for a solution that will allow me to disable these options based upon what the user selects. Since we're working with measurements, it would be very cumbersome to create variations and restrict the heights and widths based on the number of available measurements. This is why I'm seeing a programatic solution.

I've also tried to hook into WooCommerce's JavaScript events for the variation form, thinking that this was potentially firing after my first approach above and resetting the form.

$( ".variations_form" ).on( "woocommerce_variation_select_change", function () {
// Fires whenever variation selects are changed
});

This method of modifying the available variation attributes also fails as they are modified after similar Javascript sets the attributes to disabled.

Are there any other JS hooks, or settings that I should look into in order to hide variation attribute variables programmatically?

Any advice would be greatly appreciated.

1

1 Answers

1
votes

I stepped through the JavaScript contained in https://github.com/woocommerce/woocommerce/blob/master/assets/js/frontend/add-to-cart-variation.js

Knowing that WooCommerce is interacting with attribute and variation data set within the CMS for the specific product, the onFindVariation led me to a somewhat acceptable solution that achieves what I'm trying to do.

Seeing that WooCommerce looks at user selections, finds appropriate attribute values based on how the variation is configured and displays these when users change their variation selections, it appears as if this was resetting the form.

Instead I changed the event hook to use reset_data instead of woocommerce_variation_select_change.

New code is as follows:

var currentWidth = 0;
var currentHeight = 0;
var isWidthSet = false;
var isHeightSet = false;

$( ".variations_form" ).on( "reset_data", function () {
// Fires whenever variation selects are changed
    console.log("THIS IS WORKING JS HOOK.");

          console.log(event);
          console.log(this);
          console.log($(this));
          
          currentWidth = parseInt($('#width').val().replace('"',''));
          console.log(currentWidth);

          isWidthSet = true;

          if(currentWidth == 80){
            //width is 80, must restrict max height.
            if(isHeightSet == false){
                $("#height").children().each(function(){
                    if(parseInt($(this).val().replace('"','')) > 47){
                        console.log(this);
                        console.log($(this));
                        //$(this).removeClass('enabled');
                        //$(this).removeClass('attached');
                        //$(this).remove();
                        //$(this).attr('disabled','disabled');
                        $(this).css('display','none');
                    }
                });
            }else{
                //set alert somewhere. 
            }

          }
          
          
        

} );

You'll note I'm simply turning off their visibility so that a user cannot select the values I want to eliminate.

This is just a proof of concept at this point and has not been throughly tested, but am willing to leave this question open so that others can provide input on any better ways to achieve the desired functionality.

Thanks, always appreciate the insight.