Hello,

maybe i missed something simply, maybe there is no option for that.

In product display i want make product selection required. Lets say i have shirt S, M, L, XL.
Default add to cart form looks like in picture "default select" in attachments.
All i want is force customer to select size before he can add in cart any of them, like in picture "required_select" in attachments (if he dont select anything, page will refresh and write message about "please fill required field bla bla")

Some ppl bought products with wrong sizes, because they just used "add to cart" button and didnt care about "size select", even i have it above "add to cart" button.

Comments

marcin.wosinek’s picture

Status: Active » Closed (works as designed)

I don't see how it could be implemented. There should be probably "-none-" option as as a default; and then making product field required would make sense: right now there is always some size selected.

I your use case I would recommend communicating more clearly in what size is a t-shirt. All product fields are available in product display; and when you change product in select box, all product field are updated. So you can add different images to different products (ex. with size written to it) or h1-like information about it's size.

stefok’s picture

thanks for advice, but "-select-" as default option in select list should be pretty standard. Drupal with commerce has lots of advantages and its powerfull, but sometimes i can't achieve so simple things :/

marcin.wosinek’s picture

It would be possible to do this in a module. You can use hook_form_alter to alter 'add to cart' form to add '-select-' option. If you will add short validator it will force people to choose some valid option.

There will be even point in publishing such a module on d.o., as probably other people want the same functionality.

jayemel’s picture

I agree with #2 that this is pretty standard stuff. After needing this, and finding no real way to accomplish it through the backend, I just whipped up an alter and an extra validator per #3.

I'll post my code here, maybe it will be of use to someone. This is for a field called 'shade' that we have on a store. It forces a -Select- as the top option in the shade drop down, and then the validator makes sure to set an error if the user hits 'add to cart' while '-Select-' is selected.

function mymodule_form_alter(&$form, &$form_state, $form_id){
  if(strpos($form_id, "commerce_cart_add_to_cart_form") !== false){
    if(isset($form['attributes']['field_shade']['#options'])){
      //prepend the options select list with -Select- and make it the default value
      $options = &$form['attributes']['field_shade']['#options'];
      $options = array_merge(array('Select' => '- Select -'), $options);
      $form['attributes']['field_shade']['#default_value'] = "Select";
    }
    //add an extra validation handler to force a shade selection
    $form['#validate'][] = 'mymodule_add_to_cart_validate';
  }
}

function mymodule_add_to_cart_validate($form, &$form_state){
  //force a shade selection
  if(isset($form_state['values']['attributes']['field_shade']) && $form_state['values']['attributes']['field_shade'] == "Select"){
    form_set_error('', t('Please select a shade.'));
  }
}
marcin.wosinek’s picture

#4 can be good starting point for creating a module which will fill the gap mentioned in OP.

Sinan Erdem’s picture

Status: Closed (works as designed) » Active

Changing the status from "works as designed" to "active" since this is a feature request. I think the requested feature should be a default behavior. Look into any serious shopping site, you will see this behavior:

http://www.nastygal.com/shoes/inaba-pump
http://www.net-a-porter.com/product/348486
http://www.6pm.com/patagonia-text-logo-t-shirt-black?zfcTest=mat%3A1
http://www.usc.co.uk/soviet-jeff-stripe-t-shirt-590697
http://www.asos.com/ASOS/ASOS-Skinny-Jean-With-Heavy-Tint/Prod/pgeproduc...

etc... etc...

Sinan Erdem’s picture

@jmljunior, Do you know how we can do a similar thing for radio buttons instead of select combobox?

Sinan Erdem’s picture

This is my javascript solution to force the user to select an attribute before adding to cart. Basicly it does:

  1. When the page loads, unchecks my default radio button.
  2. Disables "Add to Cart" button.
  3. Puts an empty div on top of "Add to Cart" button. (Because disabled buttons cannot have click actions)
  4. Gives a JS alert if the user clicks on "Add to cart" button before selecting a size.
  5. Enables the button and removes the empty div if a user selects a size.
<script type="text/javascript">
jQuery(document).ready(function() {
      jQuery(".form-item-attributes-field-size .form-type-radio input").removeAttr('checked');
      jQuery(".commerce-add-to-cart .form-submit").attr('disabled','true');
      jQuery('<div class="buttonDisabler">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>').insertAfter(".commerce-add-to-cart .form-submit");
      jQuery(".buttonDisabler").click(function () {
         alert("Please select size first.");
      });
      jQuery(".form-item-attributes-field-size .form-type-radio input").click(function () {
         jQuery(".commerce-add-to-cart .form-submit").removeAttr('disabled');
         jQuery(".buttonDisabler").hide();
      });
});
</script>

This is my selector for the radio buttons I am using to select size attribute: .form-item-attributes-field-size .form-type-radio input Modify it for your needs.

CSS for buttonDisabler class:

.buttonDisabler{
 margin-top: -26px;
 width: 100%;
 height: 30px;
 position: relative;
 line-height: 30px;
}

modify to suit your needs.

mrpauldriver’s picture

This really should be a module. All this hacky stuff is not very user friendly.

The default behaviour of an attribute being pre-selected must give rise to a great many incorrect orders.

rszrama’s picture

Version: 7.x-1.3 » 7.x-1.x-dev

I'd assume we'd have heard about them by now. : )

I don't think anyone is opposed to this, and in fact I was pretty sure there was a separate issue where pcambra had a solution for it. It just remains to be seen how it can be squared away with the Add to Cart form's required assumption of a "default product."

Sinan Erdem’s picture

Hello Ryan,

It just remains to be seen how it can be squared away with the Add to Cart form's required assumption of a "default product."

I didn't quite get this one?

I applied my solution I proposed above here: http://web.fracasnoir.com/shop/narcisistic-supply-beige-pencil-skirt

The default product variation is already loaded as usual. I just prevent the user from "adding to cart" before selecting an attribute by JS.

rszrama’s picture

Does your store have any products with multiple attributes? (i.e. sizes depending on color selected)

Also... nice site! : )

Sinan Erdem’s picture

Thanks...

Yes they all have. Each product have variations with different sizes, colors, price, etc... I display the color and the price of the first (default) variation when the page first opens. If the user clicks on attribute (size in my case) the other attributes of the variation loads.

mrpauldriver’s picture

Thanks for the reply Ryan. Regarding incorrect orders, if not a great many, I'm sure there would be a few : )

I notice that you have changed the version to dev. Can we look forward to a solution in the near future?

mrpauldriver’s picture

Another disadvantage (with kickstart at least) is with simple stock control.

If the default variation is out of stock, then the 'out of stock' button is displayed rather than the default 'add to cart' button.

rszrama’s picture

Ahh, interesting. I didn't consider the opportunity for the Stock module at the time, but in Commerce 1.7 we added a hook to determine the default product instead of just grabbing the first one. The Stock module could be updated to use this hook to select an in stock product when there are additional options available.

Also, just moved it to -dev b/c that's where feature requests should be. Not hinting at an imminent feature commit. : )

mrpauldriver’s picture

Does anyone know whether this feature has been included in any module as yet?

mrpauldriver’s picture

Cross referencing the following Stock issue https://drupal.org/node/1952520

I wonder whether this issue should be renamed 'Provide better option widget for product variation selection' ?

gambry’s picture

Version: 7.x-1.x-dev » 7.x-1.7

I'm struggling with this feature since last year.
Solution on #4 seems to work fine with only one attributes, with two attributes AJAX breaks for no clear reasons.

Just when you select any option from the first dropdown, the second (and probably all the other if you have more than two attributes) doesn't refresh.

This is very dangerous because If the second dropdown has more/less options the user won't be able to see them and he will probably select wrong ones.

I'm working on it to find out the reason. The problem should be on the ajax function but I don't see any errors or warning, neither any malfunction.

gambry’s picture

Issue summary: View changes

ad

gambry’s picture

Hi to all,

Finally my solution.
As done above in a different way: if no option has been selected, normally after page loading, I just show the first dropdown and hide the second one.

As soon as any valid option on first dropdown has been selected, second shows up.

function mymodule_form_alter(&$form, &$form_state, $form_id){
  
  if(strpos($form_id, "commerce_cart_add_to_cart_form") !== false){
    
    if(@empty($form_state['values']['attributes']['field_size'])) {
      array_unshift_assoc($form['attributes']['field_size']['#options'],'','- Select -');
      $form['attributes']['field_size']['#default_value'] = '';
      $form['attributes']['field_size']['#attributes'] = array('autocomplete' => 'off');
      $form['attributes']['field_colour']['#field_suffix'] = '<p style="font-style:italic;color:#aaa;">Please select size first</p>';
      $form['attributes']['field_colour']['#attributes'] = array('style'=>'display:none;');
      
    }
    
    //add an extra validation handler to force a shade selection
    $form['#validate'][] = 'mymodule_add_to_cart_validate';
    
    
  }
}

function mymodule_add_to_cart_validate($form, &$form_state){
  //force a shade selection
  if(isset($form_state['values']['attributes']['field_size']) && empty($form_state['values']['attributes']['field_size'])){
    form_set_error('', t('Please select a size.'));
  }
}
summit’s picture

Issue summary: View changes

Hi,
Is it possible to make this product depended?
So on t-shirts you need to select a size, but on cups not?

thanks a lot in advance for your reply!
Greetings,
Martijn

aonqdesign’s picture

Solution #20 doesn't work for me. We need to show colour and size all time. And also when only the colour is selected we need to load images for that colour eventhough size haven't been selected yet

maxplus’s picture

Thanks!

#4 works perfect for my situation (only one attribute)

maxplus’s picture

Sorry guys,

I was a bit to enthusiastic, #4 does not work for me because it also breaks the ajax load and always adds the first variation in to the cart.

I have tried a customized version of #20 but the function "array_unshift_assoc" does not work.
=> After some modifications, I get it to work but the ajax loads always the previous value, so in my case when I select the size 40, the product that gets selected is size 38...

dan_metille’s picture

StatusFileSize
new13.87 KB
new17.47 KB

Hi, I'm getting into the same trouble as @maxplus: looking fine with #4, but always adds the first variation in to the cart only.

In my case, I have only 1 option field (size) and I would like to have the Quantity/Add to cart form hidden until a size is selected (see screenshots or http://sansform.com/shop/sweatshirts/cowboy-sweatshirt/).

Thanks for help.

andrej galuf’s picture

Sadly, the solution at #4 breaks cart ajax at array_merge. This code works for us:

function mymodule_form_alter(&$form, &$form_state, $form_id){
  if(strpos($form_id, "commerce_cart_add_to_cart_form") !== FALSE) {
    if(isset($form['attributes']['field_color']['#options'])) {

      // Prepend the options select list with proper select and make it the default value
      $options = &$form['attributes']['field_color']['#options'];
      $options = _mymodule_prepend_select_none($options, t('- Select Color -'));
      $form['attributes']['field_color']['#default_value'] = 'none';
    }
    // Add an additional validation handler to force the field validation
    $form['#validate'][] = '_mymodule_add_to_cart_validate';
  }
}

function _mymodule_prepend_select_none($options, $value) {
  $options = array_reverse($options, true);
  $options['none'] = $value;
  return array_reverse($options, true);
}

function _mymodule_add_to_cart_validate($form, &$form_state){
  //force an option selection
  if(isset($form_state['values']['attributes']['field_color']) && $form_state['values']['attributes']['field_color'] == 'none') {
    form_set_error('', t('Please select a color.'));
  }
}

Reversed array is delegated to external function in order to ensure reusability for other attributes.

Core module could easily be extended to provide this mechanism by default and/or be disabled in settings or even on a field basis.

agileadam’s picture

Here's my variation on #20. It's working well to force a user to select a size before selecting a color.
It still drops the user on a default color (after choosing a size), which I may have to deal with later.

I am using commerce_product_urls for unique URLs per SKU.
If a user hits a URL with a SKU param I do not override the select lists.

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mymodule_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state, $form_id) {
  $params = drupal_get_query_parameters();
  if (!isset($params['sku']) && isset($form['attributes']['field_size']) && isset($form['attributes']['field_color'])) {
    $form['#validate'][] = '_mymodule_add_to_cart_attribute_validate';

    if (!isset($form_state['values']['attributes']['field_size'])) {
      $form['attributes']['field_size']['#options'] = array('' => t('- Select Size -')) + $form['attributes']['field_size']['#options'];
      $form['attributes']['field_size']['#default_value'] = '';
      $form['attributes']['field_color']['#field_suffix'] = t('Please select a size');
      $form['attributes']['field_color']['#attributes'] = array('style' => 'display:none;');
    }
  }
}

/**
 * Validates add to cart form submissions that contain attributes
 */
function _mymodule_add_to_cart_attribute_validate($form, &$form_state) {
  if (isset($form_state['values']['attributes']['field_size']) && empty($form_state['values']['attributes']['field_size'])) {
    form_set_error('', t('Please select a size.'));
  }
}
ANDiTKO’s picture

#26 Worked fine. Thanks!

TravisJohnston’s picture

I am looking for this as well, though I don't have attributes in the $form, only $form['product_id'] is set and within that are the options for the 2 Product Variations attached to the Product Display.

Here is my version of the example shown:

if(isset($form['product_id']['#options'])){
    //prepend the options select list with -Select- and make it the default value
     $options = &$form['product_id']['#options'];
     $options = array_merge(array('Select' => '- Select -'), $options);
     $form['product_id']['#default_value'] = "Select";
}

When I try the code above, it places a new "Select an option" option in the $form['product_id']['#options'] array but it throws an error and kills the site. The error appears to be:

EntityMetadataWrapperException: Invalid data value given. Be sure it matches the required data type and format. in EntityDrupalWrapper->set() (line 737 of /mnt/gfs/webmaster04dev/livedev/docroot/sites/all/modules/entity/includes/entity.wrapper.inc).

Any help appreciated since I am trying to stop people from blindly choosing the first option and adding to their cart. I am also going to add in (once I get this part working) the ability to also disable the add to cart submit button until an option is selected.

TravisJohnston’s picture

I got it, it looks like the $key needed to be set to a specific one that doesn't match a product ID already created and needed to also match the type of an ID. So if I changed the key to 111 which doesn't exists and validates as an ID, it worked!

dhruva2’s picture

Hi guys please let me know where to add this code. Should we need to add in template.php ?

TravisJohnston’s picture

Dhruva2,

You need to create a new module and add the code, changing instances of "mymodule" with the name of yours.

dirodriguez’s picture

How can I make the selected value show in the cart form?