This one was a doozy to figure out how to reproduce:

  1. Create a product display referencing two products, such that both products can be chosen via the Add to Cart form dropdowns.
  2. Turn on page caching for anonymous users at admin/config/development/performance.
  3. Clear all caches. (This is necessary to make sure the next steps decide what goes in the cache.)
  4. Open Incognito mode (or a new browser with NO cookies for the given site—i.e., so that you're an anonymous user and Drupal turns on caching for you).
  5. Navigate to the product display, and choose the second option from the dropdown in the Add to Cart form. (You don't even have to actually click the "Add to cart" button; just select the second option so that an Ajax refresh of the form occurs.)
  6. Close the Incognito window/browser, and open a new Incognito window (or another new browser with no cookies/cache/etc).
  7. Go back to the same product display. Leaving the FIRST (default) option selected in the Add to Cart form, click the Add to Cart button.

Expected behavior: The first option is added to the cart.

Actual behavior: The second option is added to the cart.

I did a bit of research, and issues #1694574: drupal_process_form() deletes cached form + form_state despite still needed for later POSTs with enabled page caching and #343415: Form cache is not cleared on submit when page cache is activated seem related. It seems that, when anonymous page caching is turned on, the form_build_id of the add to cart form is cached (due to the hidden input field). So, when you change the option in the add to cart form, it updates the cache_form entry connected to that form_build_id. I checked the cache_form table to find the form build that was being referenced by the form_build_id, and it indeed reflected the changed value of the Add to Cart dropdown. (However, this changed value isn't reflected in the actual <select> element; the <select>'s first option is still selected, but the second option is used after clicking Add to Cart! I haven't figured out why this is yet.)

For the time being, I've simply enabled the Cache Exclude module on my site, turned on page caching for anonymous users, and excluded caching on product display nodes. This isn't ideal, though, as the site ends up being significantly slower on product display pages. I've also thought about using something like ESI with Ajax to load just the Add to cart form asynchronously, but there's no way to do this out of the box. Any ideas?

Comments

rszrama’s picture

Title: "Add to cart" form adds wrong product to form when page caching is turned on » Provide a way to generate Add to Cart forms asynchronously to support page caching
Version: 7.x-1.7 » 7.x-1.x-dev
Category: bug » feature

I think what you've done is what I'd recommend, to be honest. But let's go ahead and turn this into a feature request to asynchronously load the Add to Cart form. I'm not entirely sure that's possible, but it's worth pursuing.

jessepinho’s picture

Sounds good; and of course, it would need to be able to gracefully degrade (assuming you're thinking of using Ajax). I'm not sure it's possible without something with ESI, with which I'm not very familiar.

At the very least, though, shouldn't Commerce issue a warning when page caching is turned on, so that site admins are aware of the pitfalls? I had no way of knowing about this issue until customers experienced it.

rszrama’s picture

I'm not really sure it's worth the effort - there are a variety of ways a cache might be enabled. Perhaps it's something we can more prominently document, but you have to consider Drupal page caching, block caching, Views caching, etc.

Perhaps an FAQ or something on DrupalCommerce.org? A related issue is people using random sorts in Views and that causing the Add to Cart to fail b/c the form is no longer present on the page it submits to.

jessepinho’s picture

Ah, true. In the meantime, I'll see if I can come up with something for asynchronous form loading.

jessepinho’s picture

Here's a thought: use Cache Actions or Flush Page Cache to delete the cache for just the product display page every time one of the dropdown options is changed. The only problem is, this could hurt page performance...

jessepinho’s picture

Issue summary: View changes

Fix HTML element that was hidden.

jessepinho’s picture

Issue summary: View changes

Fix hidden HTML element

znerol’s picture

This issue likely is caused by the problem addressed in Drupal 7.27. Update to the latest version and the add-to-cart form should work for anonymous users on cached pages.

rszrama’s picture

Status: Active » Needs review

Oooh, good call. I forgot we had this issue in Commerce itself. : )

mglaman’s picture

peterx’s picture

You could use JS/Ajax to add the Add to cart link on page load. The page can be cached. Only the link is changed. The changed link can then add through Ajax using a fresh id.

Sebastien M.’s picture

The new release of Authcache seems to support such feature.
https://www.drupal.org/node/2482653