1

Let's say client wants button "Ask about" for chosen product instead of "Add to cart" (he requires personal contact for some products). It should be based on data from a specific product field, so he could choose for what products he requires personal contact. It would be also nice if that optional button would redirect user to webform, that would automatically contain name and attributes of chosen product. How can I approach this?

Added: I can disable "add to cart" form, from hook_preprocess_node, or hook_node_view_alter, but I wonder if it can be ajaxified, so only if user will choose specific product, from configuration of attributes, the "add to cart" button, would disappear and "Ask about product" would appear. I also need to turn off possibility of adding that product to cart by forged POST requests. Anyone know how to do it?

2 Answers 2

10

I figured out answer, and it's not that bad as I though. I decided to write a tutorial for it as it looks like very useful feature. So here it is:

Tutorial

  1. Install everything, I mean, Commerce and Webforms,
  2. Create example webform - let's name it "Contact",
  3. Create Product Display, create some product with few attributes, and one boolean field (not attribute) "Contact required",
  4. Configure webform, specifically, create there a field that will have default value, fetched from GET query string (how to do this: http://drupal.org/node/296453#webform-url-default ), we will pass to our Contact form a SKU of our product by using GET method.

Now create your own module, I will not elaborate on that, as there is a lot of info out there. The hooks that we will need are:

HOOK_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state)

HOOK_commerce_cart_attributes_refresh_alter(&$commands, $form, $form_state)

The first one will allow us to manipulate our form initially (if default product will have "Contact required = true"), the latter will allow us to adjust our form to AJAX calls.

Yes, that means that, our "Add to cart" button will be dynamically changing based on current product "Contact required" field. Looks promising doesn't it? :)

We will also use two helper functions that are not hooks:

MODULE_ask_for_product($product)

MODULE_contact_required_validate($form, &$form_state)

The first one will return HTML of our new button "Ask for product" (I encapsulated it in function, because we will need that data in both above hooks), and the second one will validate our form, so if "Contact require" field on product, will be set to 1, the form will not validate, and product will not be added to cart. The submit button for regular user will be removed, but this is only against smart guys that would like to annoy you by sending this form even if you hide submit button.

Those are the functions:

    function HOOK_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state) {
    // Adding new class to our button, that will allow us, to target it by jQuery
    $form['submit']['#attributes']['class'][] = 'add-to-cart-button';
    // Adding new validator, that will make sure that our products with required contact, will not be added to cart
    $form['#validate'][] = 'MODULE_is_contact_required_validate';

    // Getting value of field_is_contact_required of default product
    $product = $form_state['default_product'];
    $field = field_get_items('commerce_product', $product, 'field_is_contact_required');

    // If value is 1, then replace our button with markup.
    if($field[0]['value'] == 1) {
        unset($form['submit']);
        $form['ask_for_product'] = array(
            '#markup' => MODULE_ask_for_product($product),
            '#weight' => 50,
        );
    }
    }

Now we need to do something with AJAX:

    function HOOK_commerce_cart_attributes_refresh_alter(&$commands, $form, $form_state) {

    if (!empty($form_state['context'])) {
        // Getting value of field_is_contact_required of new chosen product
        $product = $form_state['default_product'];
        $field = field_get_items('commerce_product', $product, 'field_is_contact_required');

        // If field_is_contact_required is set to 1, then replace a container that have class ".add-to-cart-button" (we just added that class), with our markup
        if($field[0]['value'] == 1) {
            $replacement = '.add-to-cart-button';
            $commands[] = ajax_command_replace($replacement, MODULE_ask_for_product($product));
        }

    }

    }

And our helpers:

// Return markup of our new button. 'node/7' is node of our contact form, 'subject' is a key of our query string
function MODULE_ask_for_product($product) {
    return '<div class="ask-for-product">' . l(t('Ask about product.'), drupal_get_path_alias('node/7'), array('query' => array('subject' => 'Ask about product with SKU: ' . $product->sku))) . '</div>';
}



// Prevent some products from be added to cart.
function MODULE_contact_required_validate($form, &$form_state) {

    $product = $form_state['default_product'];
    $field = field_get_items('commerce_product', $product, 'field_is_contact_required');

    if($field[0]['value'] == 1) {
        form_set_error('', t('Don\'t try to be annoying! :P'));
    }

}

That's all, you can customize it, or by extending the idea, do much more with it (maybe by using webform api).

1

One approach would be to add a payment plugin that would check for product property and then disallow payment until client asks for contact, and site operator marks all products as "contacted". That would allow client to keep products in a shopping cart and only ask when he feels pretty much decided. It would also allow to ask about all products that are supposed to go in one shipment, and that seems to be a good thing. Maybe there is an option to write commerce plugin that works at cart level, too, but I never tried it. Way faster, Q'n'D approach would be to test for a given property at tpl.php level and substitute buttons. Of course it has some drawbacks, smart people still could get around it and try to force-feed their choice to basket and checkout.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.