Why not combine shopping carts on user login?

When I first wrote Ubercart's Cart module, we knew we were going to support both anonymous and authenticated shopping carts and checkout. The decision came at a time when there wasn't consensus around the impact of forced login on conversions, but we knew we wanted it to be optional if at all possible. Additionally, for authenticated users, we wanted to preserve items in their shopping carts so they would see the same items when logging in from multiple devices or across multiple sessions.

This resulted in a small conflict that we had to figure out how to deal with: users could have items in their authenticated shopping carts but browse the site anonymously, create a new shopping cart, and then log in. What should happen to the items in their authenticated carts vs. the items in their anonymous carts?

There are three basic resolutions: combine the shopping carts together so the user still has a single shopping cart, remove the items from the previous session and leave it up to the customer to find them again if desired, or retain the old shopping cart but ignore it until the customer has completed checkout for the current cart. In Ubercart, I chose to combine the items, but in Drupal Commerce I changed course to retain the old cart but, from the customer's point of view, treat that anonymously created cart as the current cart after login.

We got some push back for this decision, but ultimately I didn't change the default functionality of Drupal Commerce. We just made sure there was an appropriate hook (hook_commerce_cart_order_convert()) so developers could alter this behavior on a site-by-site basis as need be.

From the merchant's standpoint, the thinking behind combining carts goes that you don't want customers to forget they intended to purchase those products in the past. However, from the customer's standpoint, suddenly having additional items in the cart after logging in during the checkout process is quite jarring.

In fact, I've been bitten by this behavior when shopping online at Barnes & Noble. Weeks prior to placing an order, I had put a Wheel of Time novel in my shopping cart but eventually bought the book in store. When I came back to the site to purchase a gift for my wife, I used a login button on the checkout form to quickly reuse my previous addresses and payment details. Unbeknownst to me, the website combined my old shopping cart with my current one such that my "quick checkout" experience made me accidentally order a book I already owned! I then had to spend 30 minutes with customer service canceling the order and placing it afresh just for the book I actually wanted.

That experience confirmed in my mind we made the correct decision not to combine carts automatically. As eCommerce framework developers, we have no clue where a developer might like to integrate login during the checkout process. Best to let them decide if it's safe to do something with those previous cart items instead of silently making the decision for them.

That said, I believe we can improve the experience even further. Right now, Drupal Commerce retains the old shopping cart order, and after the customer completes checkout they'll see the previous shopping cart as their current cart. This can be confusing as well!

My ideal situation would likely be a user interface component on the shopping cart page where customers can see items they had added to their carts in previous sessions, giving them the option to add those products to their current carts. If they decide not to, I don't see any harm in then just deleting those historical carts and moving on.

There's always room for improvement. Smile

Photo credit: alphageek

Come to DrupalCon Latin America 2015

I've been privileged to attend almost every DrupalCon since Barcelona in 2007. I missed Paris in 2009, but I had a good excuse - my wife was due to give birth to our first child around the same time.

The relocation of the Commerce Guys headquarters to Paris has given me plenty of time to catch up on the missed sightseeing, but I still need to figure out how to get to Sydney after missing that one. Lol

Without access to those hundreds of Drupal developers and enthusiasts in 2007, I never would have known anyone was even using Ubercart. I didn't know how to engage other developers remotely (my early forays into IRC were similar to webchick's, I believe), and there wasn't much going on in Louisville, KY where I called home. Meeting others in the Drupal community, learning from my peers, and being mentored directly by many of the same has grown me personally and professionally in ways I never would have expected.

That's why I'm excited about the opportunity to travel to Bogotá, Colombia for the first DrupalCon in Latin America, February 10-12. I can't wait to hear the keynotes from both Dries and Larry, two of my Drupal heroes, and to learn more about the latest developments in Drupal 8 core and contributed modules.

I'll personally be addressing two topics: Drupal Commerce 2.x for Drupal 8 (on behalf of bojanz) and growing a Drupal based product business. I also look forward to the conversations, shared meals, and sprints that make the conference so rewarding.

I strongly encourage you to come if you're in a position to do so! Smile

With the help of Carlos Ospina, I've recorded a personal invitation in Spanish that I trust doesn't have me saying anything embarrassing. I'm sure my Spanish will be better for at least a week after spending time at the conference. Tongue

Getting to work on a stronger Drupal Commerce 2.x

I don't like being sandy but I love building sand castles. The potential is high but the stakes are low. You have unlimited raw material to build whatever you can imagine, and if you screw up you can just knock it over (to the delight of your children) and start again.

When your constant is impermanence, you adjust your expectations accordingly. If the sands shift or the tide rises, you shrug it off and start again or go back to bocce. However, if you were somehow bound by the fruit of your labor, you'd think twice about the when, where, and how of your building.

Lyle and I started developing Ubercart when Drupal 5 was still in beta, and we put up with the impermanence because we were just two dudes learning a lot and working from a clean slate.

Moving that forward to Drupal 6 took even longer because our codebase grew unwieldy, so I decided at Commerce Guys to trim the fat and start over. We didn't learn every lesson moving to Drupal 7, though, as it was still unstable when we began developing Drupal Commerce. With an unstable Views module. And an unstable Rules module. And an incomplete Entity API. Tongue

I don't think we would've done any differently, as the flip side of the instability is the opportunity to positively impact the development of the projects you depend on. For Drupal 8 we ended up contributing to core in other ways while tackling a full Drupal Commerce rewrite more slowly than we hoped. Even the code that we did develop against Drupal 8 is now outdated, as we had to juggle managing our existing ecosystem, writing new code, and rewriting that code to track changes in Drupal 8 itself.

However, we've recently been given the opportunity to host a variety of developers / documenters in Paris from June 30 - July 4 to re-evaluate our Commerce 2.x roadmap with the direct help and guidance of key members of the Symfony project. Specifically, we'll be looking to both move our code "upstream" from our Drupal modules into generalized libraries and take advantage of existing Symfony projects where possible.

Our target is an even leaner codebase with connections to the broader world of PHP based eCommerce. If you have any insights in this direction, please comment or contact me directly and consider joining us in Paris to learn and contribute.

Photo credit: j.s. clark

Beware InnoDB's auto_increment reset on reboot

Earlier this year I helped my friend Samuel bring his used cell phone resell business online using Drupal Commerce. The site is still in maintenance mode while we finish the self-service features, but his staff currently uses it logged in from their various locations as their point of sale system. Knowing the ins and outs of Commerce, I didn't have any problems tailor making an eCommerce application for his business, but I did have one hiccup during deployment that I'd never seen before.

We built Wikiwoo.com on Pantheon, a Drupal Platform as a Service, using a free developer site until it was ready for use in stores. Pantheon really helped us collaborate on the site build, with me doing the coding and configuring while he filled the product catalog. We did everything on the site's dev environment, including letting his partners take a look around to find things worth fixing, until we were ready to go live.

One of the last things I did to prepare for the launch was update the auto_increment value of the commerce_order table to account for the number of orders they processed in the previous year and a half. However, we weren't really migrating old eCommerce data, so I just expected the first order on the new site to start where we wanted and we'd watch them grow from there. A quick test showed it working as expected, so I deleted the dummy orders and sent him a link to upgrade the account to a paid plan to take it live.

Unfortunately, when I went back to the site the next day, I saw that orders were being created with IDs starting back at 1. I knew there was nothing in Commerce that would effect such a change, so I hit up Pantheon support and got a quick confirmation that nothing they do would intentionally reset auto_increment values either.

Sidebar: I really should emphasize quick. Any time I've ever contacted Pantheon support, they've responded right away. "Groovy," said Josh Koenig in this particular instance when we nailed down what was happening. "Groovy," I say to Pantheon's customer service. Cool

It turns out what I experienced was a result of InnoDB's treatment of auto_increment values. The auto_increment counter is only stored in memory, not on disk, and it is recalculated on server startup. InnoDB simply looks for the highest used ID and sets the counter to the next value, explaining why my order IDs shrunk back down to 1 after I cleared out all of our dummy orders.

In our case, it was the upgrade from a free account to a paid account that restarted the database server, triggering the reset of the counter. However, with cloud based Platforms as a Service, I imagine there are other scenarios where an expected alteration to an auto_increment value is apparently "lost" on migration between environments or builds. This is probably mostly an eCommerce issue with respect to Drupal sites, as merchants often want or need order IDs to account for historical sales, but perhaps the tip can save someone else a bit of head scratching.

To get around my issue, I simply reset the auto_increment to where I wanted it to be, created a cart order for myself, and waited for a real order to be created before deleting my dummy order.

Problem solved, it's been fun to watch the order count grow from there.

Photo credit: Max Barnes

Pages