d7uc: The Future of Products

This is the second in a series of posts outlining the ideas driving the Ubercore Initiative forward. We've had a lot of positive feedback from developers eager to dig into Drupal 7 to re-implement Ubercart's features like the awesome vision of products outlined below.

For starters, when we gathered for the Ubercore planning sprint in San Francisco, we began by nailing down the core systems without which we wouldn't have an e-commerce system and which we needed to build out other essential features. The links above are our whiteboard scribblings based on Ubercart's current features, but the one we gave the most time to was the core product system. The resultant notes and discussion summarized in this post may be viewed here.

In short... it's gonna be awesome, and it's all thanks to Drupal 7's Fields API. Cool Products are already great in Ubercart, but as one person recently tweeted, the implementation thus far has been a little awkward. Furthermore, from a data standpoint, it's been quite limiting.

How about a visual? It's my first go at Omnigraffle... Smile

d7uc product

Currently, Ubercart defines a new product node type on install and gives you the opportunity to clone multiple new product node types called "product classes." These can then have default attributes assigned to them, which are customer selectable alterations to products at the point of purchase. For example, your merchandise store can have a t-shirt product class with a size attribute attached to it that your customers choose when adding the shirt to the cart. Each of these attributes can result in a price, weight, or SKU adjustment as well. There are also multiple product types defined at the module level, so that regular products function differently from product kits, each having their own add to cart form and functionality in the cart.

Problems come in you try to define just what a product is. Is it a node? Well, with SKU adjustments, aren't more than one products visible on a single node? How does Ubercart know those altered SKUs exist? There are implications here adversely affecting the development of stock control systems, sales and product reports, the shopping cart and order product handling, representing non-tangible products, and more. Happily, we have a plan we think will address these shortcomings without losing any of our current features.

So, what is the future of products? As fago hinted in his post, the future of products is entities, not nodes. We're separating "what a product is" from "how a product is displayed" and making products themselves top level, fieldable entities. Thanks to bundles, we'll still have multiple product types with various attributes, but instead of the current system where attributes are very loosely defined, we'll be moving more toward a product database where each individual product is defined and described by fields you add. Whereas before you might have had a single t-shirt product node with three variations thanks to a size attribute, you would now define a t-shirt product bundle and enter in the three variations with their SKUs and sizes set.

To handle product display, we'll be using a field that lets you specify which products to show on whatever the field is attached to (like a product display node) and how to prepare them for display. The products selected might all be listed individually for the user to select from a radio list. They might be grouped on their size field so that a size select list appears on the add to cart form as it does now. They might be sold all together at a set price as a product kit. We want this product display field to be flexible and to correct the difficulties people have in working with the current add to cart form.

This approach will clarify what a product is (a bundle of fields, including at least a SKU and a default title / price) and provide greater flexibility in how it is displayed (contributed field formatters, anyone?). Modules working with the product system, like stock control modules, will now have a unique product ID to refer to instead of a node ID with an array of attribute selections. We'll have better Views integration and end up with a product entry field that could attach an add to cart form to any entity.

Honestly, I could go on, but I'll stop here. This is already more gushing than I was planning to include in a single post. If you want to read more, hear what other people are thinking, and provide some feedback, you can check out the brainstorming thread, comment here, or keep an eye on the fieldable product meta issue as we flesh out the development tasks.

If you want to help make it happen, don't be shy. Wink


Consider allowing initial stock level to be set when a class is set up. This may sound odd but for date based products with finite resources to sell it makes sense. For example you may have a small theatre or conference facility that seats:
100 people in the stalls SKU 001sta
50 in the circle SKU 001cir
150 in the gallery SKU 001gal

The ability to specify this at class stage would be very helpful (even if it defaults to 0 stock for most people)

As I was reading this post I was thinking about the theater ticket scenario and also classes or workshops.

There are three theater scenarios:
1. Theaters that are 100% general admission
2. Theaters that sell tickets by section, and are general admission within each section
3. Theaters that sell individual seats.

Scenario 1 and 2 seem like they may be easier to implement, as described in the comment above, you could set stock for the product variants (tickets by section).

Scenario 3 seems like the trickiest, and most specialized. Each theater would need to have a set of product variants, there could be literally thousands of variants (one for each seat), and when ordering, a customer would likely want to sort by section or price and then buy contiguous tickets.

I wonder if the Theater Ticket use case requires its own contributed module for managing seating arrangements and presenting a purchase interface that caters to the task, allowing a user to select by section, or by price and then pick contiguous tickets, perhaps even limiting results to only those where there are n# of contiguous tickets (where n# is the the number of tickets the customer has indicated they wish to buy).

The larger issue though is that the ubercart product infrastructure should be able to support this specialized use case.

The other usecase that I am very interested in is the selling of courses or workshops. These are a little less tricky in that often they only have a limited qty available (seats) with the potential to waitlist (backorder). Where some complexity comes in is that a course or workshop may be offered multiple times, consecutively or concurrently (spring semester / fall semester or tuesdays and thursdays / saturdays all day). Some attributes may be the same: Instructor, course description, pre-requisites, credit options, costs... while other attributes may be different: location, meeting times, meeting days, instructor, costs. To drive the point home: sometimes some attributes are the same, and sometimes those attributes can be different.

The question becomes: are these different sessions of a course the same "product" or are the different. When do they go from being the same product with different attributes, to being different (but related) products with the same attributes? You certainly may want to display the courses together so that a user can choose to signup for tuesday/thursay, or for saturday all day. The same may not be true for the spring semester/fall semester scenario, however in this latter scenario you may want to indicate that the course is offered spring/fall even if a customer cannot buy (register) for the fall course in the spring.

The last bit about courses: often the same course is offered year after year with some attribute changes, like location and meeting dates. The same question in the paragraph above exists: is this a new version or variant of an extant product? or a new product all together? There are benefits to the former, especially reporting benefits if you want to see how course registrations change overtime for a particular course, or determine the sales stats and thus success of a workshop offered multiple times.

I do realize that all of the above are scenarios very different than selling widgets, or downloads, or node access or user roles, however in my work, scenarios such as the above are some of the most frequent ecommerce requests that I see.

why on earth did mollom think this post, with not a single link, was spam?

I just wanted to mention another use case for event ticketing. Tables at Dinners/Galas.

1 - Tables often have different levels, similar to sections for seating

2 - Tables also allow admission for more than one person. You buy a table and get tickets for 8-10 people. One of the primary tricks is getting the names(and hopefully email) of all the guests beyond the purchaser so we can have them on the guest-list, and maybe contact them is any last minute changes.

I agree that it is tricky to think about things like event tickets, hotel stays, car rental, bookable products, products that you don't by
Ubercore should make enough abstraction to make it possible to address most scenarios.
Of course it can't address all use cases so it has to have APIs that let developers implement handlers for different use cases.
A base product module that defines APIs and default implementation. The APIs would let you plug in modules that offer different product behaviors. (special stock management, special pricing scheme...etc)
Then when the user adds a new product class (type?) he is given the oportunity to choose diffrent handlers for different behaviours.
How do you handle prices ?
- default, fixed price handler
- context variables, time dependent price handler (third party module, like for bookable products)
- ...etc
How do you manage stock ?
- default, normal stock per SKU
- special bookable product stock handler (third party module)
How do you handle payments ?
- default, full at checkout
- recurring (third party module)
- complexe (ex. 10% or $10 deposit at checkout, rest at delivery or at date or at workflow state)

Also, for variations, i think that not all properties qualify for beeing attributes that make variations. Properties related to time ( like in courses on tuesday/thursday, hotel rooms, bookable products...etc) are more of a stock/availability management issue than a product variations one.

Course is only available one the specified meeting dates

oops! Ignore the last line.

furthermore, the fact that a product <> a node will be useful as with the multilingual option "i18n", you'll have X nodes for X languages but for the same product... (see ubercart forums)

Great point! I hadn't even thought of that benefit. Smile

That will pretty much go away with translatable fields, assuming a decent API will be available for D7.

Products as their own entity and not nodes would still need this capability.

Corrections I meant to say UI, not API, the API is in place and ready to go.

I am a little concerned by moving products away from being nodes. I did read that right, right?

What about node import and export? Any idea how many other UC modules work together and rely on the "node" setup? And, is there a plan for UC users to migrate to D7 UC flawlessly?

Oh yeah, there's absolutely a plan to maintain an upgrade path. However, I think you might be overestimating the ability of Ubercart to import / export. It's never really worked, even with products as nodes. Wink

I'm pretty sure that the import / export modules will be updated on D7 to incorporate the entire concept of entities on D7 and not remain limited to nodes. Technically, I don't see why they wouldn't.

On D6 I am importing products on the fly. That is one reason for the question.

Am I assuming correctly that most of the UC "node" related contributed modules would have to be re-written?

Why are product "sets" (or whatever you call them) nodes? They don't have a user, revision, etc either.

I'm not exactly sure what you're referring to above, unless you're thinking about my quick thought about how a product kit could be achieved using the product display field. The idea is that instead of having a set node type that includes an add to cart form, we'll have a new field with a formatter that builds an add to cart form based on whatever products you've selected for display. This is comparable to a node reference field displaying a list of referenced nodes, but we would have a formatter that changed the list of nodes (or in our case, products) into a form to let the user select one.

So, a product display might be a node on your site with a product display field, and you would want an author uid, revision history, published status, etc. to track changes in the description or whatever other CCK fields you add to the node. Does that make sense?