Let's say you have a very simple setup and you may not need product nodes at all, it should be easier to add an item by it's SKU to a users cart. Here's a simple module to achieve this, but it would be lovely to have something like this in commerce_cart core.

<?php
// $Id$
/**
* @file
* Allows adding products to a users cart through a link.
*/
/**
* Implements hook_menu().
*/
function commerce_cart_links_menu() {
  $items = array();
  $items['cart/add/%commerce_product_sku'] = array(
    'title' => t('Add to cart'),
    'page callback' => 'commerce_cart_links_addtocart',
    'page arguments' => array(2),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}
/**
* Add items to the users cart
*/
function commerce_cart_links_addtocart($product) {
  global $user;
  commerce_cart_product_add($user->uid, $product->product_id, 1);
  drupal_goto('checkout');
}
/**
* Argument loader for a commerce sku
*/
function commerce_product_sku_load($sku) {
  return commerce_product_load_by_sku($sku);
}

Comments

Great idea. I think that some stores will not need a fancy front-end with multiple attributes on product nodes, and can just use the product entities directly.

Component:Developer experience» Contributed modules
Status:Active» Postponed

I don't think we'll be making cart links a core feature, although this is undoubtedly a handy snippet. My goal instead is to see Cart Links working through Rules, which we're discussing in #823466: Enable cart links through Rules. For your post, one thing I might recommend is that instead of a custom wildcard with an autoloader in the menu item, why not just use a % and let your callback load by SKU? You can get rid of the third function here, and then you can take appropriate action if the product fails to load (i.e. instead of showing a 404 redirect to your catalog page or something).

The reason this won't be a core feature isn't because it isn't useful, but it's just that everyone will have slightly different needs... so if we can use Rules, everyone wins. : )

I'm marking this postponed so others can see your use of the API, but eventually I'll close it as duplicate. I have switched the component to contributed modules, though, so feel free to make a utility module that defines cart links like this if you think it's a useful feature others might want to use. There's always room for simple solutions as alternatives to something heavyweight like Rules.

Nice code snippet... keeping track of this.

I'm also wondering about combining this with some functionality to hide the cart itself. I can envision adding a Rule on the "Before adding a product to the cart" event that triggers a "Page redirect" action to /checkout.

But is there a more elegant solution for one-click checkout?

--Ben

Yeah, for one click checkout where you really don't want the shopping cart, I'd tend to prefer some alternate form perhaps (i.e. an entirely different display formatter for the product reference field instead of the Add to Cart form) that create the order for the user and sent them straight to the checkout form.

However, thinking about this now, it should be possible for you to totally disable the shopping cart form View if we stopped defining the menu item in the Cart module and instead just made that a default display of the View... then you could use the "After adding a product to the cart" event for the page redirect... oooh, but I bet it would still link to the disabled View and show the Add to Cart message. Hmm... so it seems there's some additional work that needs to be done here. ; )

(That also wouldn't automatically rename the Add to Cart submit button.)

Hey Ryan,

Thanks for the really helpful info. In some ways, both of the solutions you proposed could be quite useful:

1. The first solution (alternate display formatter for going directly to checkout) is handy because of the flexibility it allows: Some items for sale could have one-click checkout while others could still be added to the cart the usually way (by choosing the Add to Cart formatter). In fact, if you defined two separate product reference fields, you could actually do both just like Amazon (offer one button to add to cart and a separate button to go directly to checkout). Or alternately, there could be a third display formatter that provides both buttons/options.

2. Being able to disable the shopping cart view (and related links and messages) would be helpful for use cases in which you don't want a cart at all on the entire site. As for the Add to Cart message and the link to the disabled view, would it be possible to define those as Rules actions instead? This would make them easier to disable. For instance, the Add to Cart confirmation message could be a pre-configured Rules action using the "After adding a product to the cart" event and the standard "Show a message on the site" Rules action. Likewise, the link to the View could be something similar to the standard "Set breadcrumb" action.

Which solution do you think is "lower hanging fruit"? ;-)

--Ben

Ryan,

Just had one other thought: Is it possible for Drupal Commerce to add a "Create a new order" action?

If this action were available, then you could use the Flag module to simulate your own "one click" link or button (since the Flag module has Rules integration). You would basically use the Flag module to allow an individual user to "flag" a product (for instance, you could call the flag "One Click Checkout". That would create a Rules event when the product was flagged. Then, you could add a Rules action to "Create a new order" on that event and a follow-up "Page Redirect" action to re-direct them to checkout. In this scenario, the item would never enter the shopping cart.

Anyway, just an idea...

--Ben

Ahh, interesting idea. You actually can theoretically create a new order using the "Create an entity" action in Rules. I think I remember someone saying they had trouble with it saving, though... and I could never nail down if it was our fault or not. It'd be worth looking into and could be a pretty elegant solution!

Really nice snippet. Subscribe.

This simple rule should add a line item to the cart whenever a product is added to the cart. It succeeds in creating the line item (appears in the commerce_line_item table), but it does not get saved to the field_commerce_line_items table.

{ "rules_test" : {
"LABEL" : "Test",
"PLUGIN" : "reaction rule",
"REQUIRES" : [ "rules", "commerce_cart" ],
"ON" : [ "commerce_cart_product_add" ],
"DO" : [
{ "entity_create" : {
"USING" : {
"type" : "commerce_line_item",
"param_order" : [ "commerce-order" ],
"param_type" : "product",
"param_line_item_label" : "Test Line Item",
"param_quantity" : "1",
"param_commerce_unit_price" : { "value" : { "amount" : "2500.00", "currency_code" : "USD" } },
"param_commerce_total" : { "value" : { "amount" : "2500.00", "currency_code" : "USD" } }
},
"PROVIDE" : { "entity_created" : { "lineitem_created" : "Created lineitem" } }
}
},
{ "list_add" : {
"list" : [ "commerce-order:commerce-line-items" ],
"item" : [ "lineitem-created" ]
}
}
]
}
}

0 ms Reacting on event Calculating the sell price of a product.
7.081 ms Evaluating conditions of rule Unset the price of disabled products in the cart. [edit]
8.436 ms The condition data_is_empty evaluated to TRUE [edit]
8.452 ms AND evaluated to FALSE.
8.484 ms Finished reacting on event Calculating the sell price of a product.

0 ms Reacting on event Calculating the sell price of a product.
0.261 ms Evaluating conditions of rule Unset the price of disabled products in the cart. [edit]
0.486 ms The condition data_is_empty evaluated to TRUE [edit]
0.499 ms AND evaluated to FALSE.
0.523 ms Finished reacting on event Calculating the sell price of a product.

0 ms Reacting on event Calculating the sell price of a product.
0.274 ms Evaluating conditions of rule Unset the price of disabled products in the cart. [edit]
0.526 ms The condition data_is_empty evaluated to FALSE [edit]
1.383 ms The condition entity_has_field evaluated to TRUE [edit]
3.293 ms The condition data_is evaluated to FALSE [edit]
3.308 ms AND evaluated to FALSE.
3.338 ms Finished reacting on event Calculating the sell price of a product.

0 ms Reacting on event After adding a product to the cart.
0.537 ms Evaluating conditions of rule Test. [edit]
0.551 ms AND evaluated to TRUE.
0 ms Rule Test fires.
0.842 ms Evaluating the action entity_create. [edit]
1.8 ms Added the provided variable lineitem_created of type commerce_line_item [edit]
2.48 ms Evaluating the action list_add. [edit]
2.694 ms Rule Test has fired.

3.309 ms Evaluating conditions of rule Reset the cart order status on product add or remove. [edit]
3.322 ms AND evaluated to TRUE.
0 ms Rule Reset the cart order status on product add or remove fires.
0.13 ms Evaluating the action commerce_order_update_status. [edit]
1.107 ms Rule Reset the cart order status on product add or remove has fired.
4.496 ms Saved lineitem_created of type commerce_line_item.
16.775 ms Finished reacting on event After adding a product to the cart.

0 ms Reacting on event Calculating the sell price of a product.
7.442 ms Evaluating conditions of rule Unset the price of disabled products in the cart. [edit]
8.713 ms The condition data_is_empty evaluated to TRUE [edit]
8.727 ms AND evaluated to FALSE.
8.753 ms Finished reacting on event Calculating the sell price of a product.

0 ms Reacting on event Calculating the sell price of a product.
0.344 ms Evaluating conditions of rule Unset the price of disabled products in the cart. [edit]
0.581 ms The condition data_is_empty evaluated to TRUE [edit]
0.595 ms AND evaluated to FALSE.
0.621 ms Finished reacting on event Calculating the sell price of a product.

Status:Postponed» Closed (won't fix)