This one was a doozy to figure out how to reproduce:
- Create a product display referencing two products, such that both products can be chosen via the Add to Cart form dropdowns.
- Turn on page caching for anonymous users at admin/config/development/performance.
- Clear all caches. (This is necessary to make sure the next steps decide what goes in the cache.)
- 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).
- 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.)
- Close the Incognito window/browser, and open a new Incognito window (or another new browser with no cookies/cache/etc).
- 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
Comment #1
rszrama CreditAttribution: rszrama commentedI 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.
Comment #2
jessepinho CreditAttribution: jessepinho commentedSounds 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.
Comment #3
rszrama CreditAttribution: rszrama commentedI'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.
Comment #4
jessepinho CreditAttribution: jessepinho commentedAh, true. In the meantime, I'll see if I can come up with something for asynchronous form loading.
Comment #5
jessepinho CreditAttribution: jessepinho commentedHere'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...
Comment #5.0
jessepinho CreditAttribution: jessepinho commentedFix HTML element that was hidden.
Comment #6
jessepinho CreditAttribution: jessepinho commentedFix hidden HTML element
Comment #7
znerol CreditAttribution: znerol commentedThis 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.
Comment #8
rszrama CreditAttribution: rszrama commentedOooh, good call. I forgot we had this issue in Commerce itself. : )
Comment #9
mglamanNo patch, moving to "Active." Added related issues mentioned in description.
Comment #10
peterx CreditAttribution: peterx commentedYou 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.
Comment #11
Sebastien M. CreditAttribution: Sebastien M. commentedThe new release of Authcache seems to support such feature.
https://www.drupal.org/node/2482653