I was asked about WooCommerce’s session handling at WCEU (where I seized up; darn social phobia) so I thought it would be good to give a brief history of our handling of sessions, and how things are changing in 2.1.
Cart sessions have been a long standing source of frustration in WooCommerce. To clarify, the session is the part which tracks a particular user’s cart object – without this the user wouldn’t be able to use the cart nor checkout.
The most obvious solution would be to use PHP’s built in sessions and
session_start(). This was the first thing we used (obviously) and you’d expect this to work perfectly fine…but it doesn’t for the following reasons.
Support and host issues
SESSION related support tickets were too frequent e.g. errors like “No such file or directory”, mainly caused by (bad?) hosting providers not having them configured correctly, or not supporting them at all. Albeit easy to diagnose, most users were reluctant to ask there hosts, and most surprisingly some hosts even tried to blame our platform. Frustrating for all those involved.
WordPress itself is stateless
WordPress core is stateless – it acts the same regardless of which user is using it. It can tell if you are logged in and show you correct pages and screens but thats about it. There is no built in handling for sessions.
Problems with caching
Page cache added by plugins, and by hosts such as WPEngine, can break sessions. Well, not break, just show a page which is cached and as a result doesn’t reflect the current users cart.
When a cart session is present some data needs to be un-cached, as do some pages such as cart, checkout and account.
Problems with load balancers
WPEngine sum this issue up nicely:
For our customers who are set up on clusters, we would have to completely change how our load balancers work, just to make sure that $_SESSION variables were available between different servers.
Load balancers need to be configured to share session data across their servers if used.
WP_SESSION to the rescue?
Eric Mann proposed a system in which a cookie tracks your session, and the session data is stored in transients; http://eamann.com/tech/introducing-wp_session/.
On the back end, the object stores its data in WordPress transients – one transient per user – each with a unique ID provided by WordPress’ PasswordHash object to ensure uniqueness. If you’ve got a caching plugin installed that uses memcached, then transients (like options) can be cached in memory, making the system very performant.
To summarise how it works:
- On page load, a session ID is created for a user (if it doesn’t exist) and is stored in a cookie.
- Functions use WP_SESSION to store data, instead of $_SESSION.
- On shutdown (a WordPress hook, called last) data is written to a transient.
This works well, and we used something similar/adapted in WooCommerce 2.0. Pippin Williamson also used it in Easy Digital Downloads. Our solution was tweaked to use the option table instead of transients, because transients are not persistent – we don’t want cart data disappearing!
Varnish caching issues
WordPress targeted hosting providers such as WPEngine tend to use Varnish caching to improve site loading times. These need to be configured to “ignore” WooCommerce’s cookies to prevent caching when users have carts, otherwise users can potentially see each others carts and the system goes to pot.
Although some of this can be handled by the host themselves, there are still issues. You can read about some of the issues faced and suggestions in this Github Issue, the key ones being the names of our cookies needing special handling, and the existence of the ‘session’ for all visitors preventing caching completely.
We’ve worked on this in WooCommerce 2.1 though!
In 2.1 we’ve made two key changes to our session handling:
- We’ve renamed the cookie used to track customer ID so that it includes
_wp_in the name. This should let plugins like batcache exclude this cookie automatically (WordPress core cookies have this naming structure).
- We’ve tweaked the session and cart handlers to only create a session if the user has a cart. If the user doesn’t have a cart, the site remains stateless. Caching is allowed.
So now is the time to test this out🙂 If you use a host with caching please give us your thoughts, and I hope this post gives you all an understanding to why we’ve gone in this direction.