Problem/Motivation
I have a use case where a product needs multiple variation types. For example a book with the following variations:
1. Hardcopy (variation type 1)
2. Paperback (variation type 1)
3. PDF file (variation type 2)
4. Audio file (variation type 2)
Where variation type 1 works fine as a regular product variation, but variation type 2 is working with commerce_license and a D8 port of commerce_file. Product option 1 and 2 (Hardcopy and Paperback) will be shipped and will NOT include a file or license. Where options 3 and 4 will NOT be shipped, but will include a downloadable file and a license (handled by commerce_license / commerce_file).
Proposed resolution
It would be great if I could use different variation types for the same product, then they can be used as different options for the same product, instead of splitting the different options into two different products (when they are the same product – same title, description, images etc.).
Remaining tasks
Figure out the best approach and write some codes.
User interface changes
This may include checkboxes or multi-select field for product variation type on the product type settings page. But also maybe a way to select default variation type. If the current product variation type is used as the default that might help make the change a little less intrusive.
Maybe a select box for product variation type on the add variation page that appears only if a product type has more than one variation type option.
Original report
I’m adding what looks like a related issue #2880602: One Product types for many Product variation types. Also adding the commerce_file port as a related issue. I realize that there will be other issues to face for this use case, but this seems like a good start.
https://www.drupal.org/project/commerce_file/issues/2875904#comment-1330...
Any feedback on this issue, reasons not to use this approach, or maybe direction on where to start if an additional contrib module is a better option, or where to start for a patch, would be appreciated.
| Comment | File | Size | Author |
|---|---|---|---|
| #59 | 3089040-59.patch | 61.71 KB | jsacksick |
| #57 | interdiff_55-57.txt | 12.13 KB | jsacksick |
| #57 | 3089040-57.patch | 59.31 KB | jsacksick |
Issue fork commerce-3089040
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
xandeadx commented+1 for feature.
Comment #3
carlitus commentedanother +1
Comment #4
mahtabalam+1
Comment #5
scorpionghost commented+1
Comment #6
john.oltman commented+1
Comment #7
calmforce commented+1
Comment #8
brunomolica commented+1
Comment #9
dilovan commented+1
Comment #10
dwkitchen commentedI think we have a solution for this, but you won't be able to use the Commerce Core Add to Cart From in the Book/eBook scenario.
The standard form assumes that all the products are going to use the same order item type, and physical and digital products have different order item type.
Individual variations will need their own Form, but this can be done with https://www.drupal.org/project/commerce_variation_cart_form is this an acceptable solution for most people?
Here is an example product:

Comment #11
tahiticlic commented@dwkitchen but how do you associate multiple variations of different types to the product ?
Comment #12
carsteng commented@dwkitchen The solution to your problem with the order_item_types can be found here:
https://www.drupal.org/project/commerce/issues/3017662
Comment #14
jsidigital commentedDid anyone get this working without having to give each variation its own separate form? I’m not a fan of the UI/look of that.
Really need to be able to have one product with both shippable and download variation.
Comment #15
dwkitchen commented@jsidigital you can use Inline Entity Form on the main product form if that is better than using the variations tab.
I'm going to be making some updates to make this a better transition feature so it might go into 2.x as experimental.
Comment #16
dwkitchen commentedMaking this more transitional-able; so it can be released in an experimental feature in 2.x, so here is the expected update that will need to be part of 3.x
Comment #17
recidive commented@dwkitchen attached is a "work in progress" patch on top of your MR for making the build-in add to cart form work with multiple variation types.
Let's discuss how we can approach that taking into account backwards compatibility. Maybe this can be done in a custom set of formatters/widgets.
Let me know what you think. And if you have the chance, please test it on your setup and let me know if it works or not.
Thanks!
Comment #18
griz commented+1 for this feature which we relied on in Commerce 1 and is now missing in Commerce 2.
I've read the reasoning around removing this and really wish I'd been around to point out the importance of being able to reference multiple variation types from a product type for this exact reason.
I suspect the core commerce team will be reluctant to make such a large change at this stage, even if the community provide a solid and well-tested patch.
An alternative method may be to get the 'shippable' status of a product variation from one of its attributes.
For those of us who sell documents, that attribute would be 'Document Format' or something similar. Though I don't know if it would be possible to hide the shipping pane in checkout, and this would also depend on the weight field not being required in the variation edit form (and preferably being hidden by AJAX when a non-shippable attribute value is selected). The simplest and solution really seems to be to have a separate variation type. So again, please, +1.
Comment #19
ginovski commentedAgreed, this is needed, a lot. +1
Comment #20
nathaniel commented@griz as a workaround I ended up adding a custom shipping information checkout pane with the following code and setting the weight to 0 on digital variations.
... extends ShippingInformation {
...
Comment #21
sander wemagine commented+1
I need it for the same reason. Having a webshop that ships physical books ánd e-books. Would be awesome if we can select a shippable and non-shippable product variation on the same product, to prevent having 2 identical products-entity with all the same fields.
Comment #22
recidive commentedGot this error when trying to create a new product type without multiple variation types behavior. Looks like the old variation type select is not working.
Comment #23
recidive commentedA re-roll of my patch in #17 which applies on top of the issue MR. I added a check for changing the order item type before rebuilding the form with a different form display.
It's still not working when the product variation has a different set of attribute types, e.g. one variation has color and the other has color + size variations. I'm fixing it and will incorporate it in the MR.
Comment #24
jsidigital commented@recidive
Is your patch similar to the preview image on comment #10?
Just wondering if this shows multiple "Add to cart" buttons on the same product page like comment #10 or if it works more like product variations where only one "Add to cart" button is visible at a time?
Thanks.
Comment #25
recidive commented@jsidigital it works like the standard Commerce add to cart form. My patch makes it compatible, but it's not ready. It works in the case your product variations have the same set of attributes, like "size" and "color" with different attribute values.
Comment #27
recidive commentedJust found a problem with the code introduced in #2952529: Support for Layout Builder module. I'm unable to create products from a user different than
uid 1with patch from the the merge request. I get:"NOTICE: PHP message: Uncaught PHP Exception Drupal\Core\Entity\Exception\AmbiguousEntityClassException: "Multiple entity types found for "Collection" supports multiple variation types.." at /var/www/html/docroot/modules/contrib/commerce/modules/product/src/Entity/ProductType.php line 130"There are calls to
$product_type->getVariationTypeId()that needs to be handled properly.Comment #28
danmer commentedI have faced an issue with this patch.
In dblogs we have errors like this:
Notice: Undefined index: target_bundles in Drupal\commerce_product\Plugin\Field\FieldFormatter\AddToCartFormatter::isApplicable() (line 111 of /var/www/html/web/modules/contrib/commerce/modules/product/src/Plugin/Field/FieldFormatter/AddToCartFormatter.php)Notice: Undefined index: target_bundles in Drupal\commerce_product\Plugin\Field\FieldFormatter\ProductAttributesOverview::isApplicable() (line 243 of /var/www/html/web/modules/contrib/commerce/modules/product/src/Plugin/Field/FieldFormatter/ProductAttributesOverview.php)It happens because for some fields $handler_settings in isApplicable() can be empty array.
We can add something like this:
$target_bundles = array_key_exists('target_bundles', $handler_settings) ? $handler_settings['target_bundles'] : NULL;or similar code.
We need to provide additional checking to avoid such issues.
Comment #29
danmer commentedI have updated the patch because AddToCartFormatter already has the changes from previos patch
Comment #30
dwkitchen commentedPatch #29 is missing many of the other changes in the MR: https://git.drupalcode.org/project/commerce/-/merge_requests/25
Comment #31
danmer commentedHere is the updated patch
Comment #34
dwkitchen commentedComment #36
b_sharpe commentedSeems the MR is failing a lot of tests on
Notice: Undefined index: target_bundles in /var/www/html/modules/contrib/commerce/modules/product/src/Plugin/Field/FieldFormatter/AddToCartFormatter.php on line 111Comment #39
jsacksick commentedWithout reviewing the rest, I just pushed a commit that should in theory address some of the test failures.
Comment #40
geek-merlinGreat, we are green! A quick vgrep through the comments does not give me reasons for NW, so setting NR.
Can anyone who is deeper in this issue list what is needed.
- Code review
- Additional tests?
- ...?
Comment #41
jsacksick commentedHm, noticed the patch has now changes from @recidive, without the changes to the
AddToCartFormatter::isApplicable()method, which means the changes made to the product variation widget are basically unnecessary as is :p.Comment #42
jsacksick commentedThis needs more work, focused on fixing the tests, then manually started to test the actual changes, and stumbled upon an access denied on the route for adding variations (i.e product/{commerce_product}/variations/add). See screenshot below, as user 1:
Comment #43
jsacksick commentedOk, this was probably related to the fact that I didn't rebuild caches, prior to creating a new product type.
Then realized the strict check that doesn't allow changing the variation type setting is really annoying, that probably needs to be revisited, but leaving it for now.
Also, we need to pass the variation types setting through array_filter before saving it, instead of doing that everywhere in the code.
Comment #44
jsacksick commentedPushed additional fixes, I filter the list of variation types from
ProductTypeForm::validateForm()instead of saving the setting incorrectly, so that we don't have to call array_filter() everytime we call$product_type->getVariationTypeIds();.Note that I remove the additions to
as the Product variation title widget seems to work thanks to the changes made to
ProductVariationWidgetBase::ajaxRefresh()although it doesn't feel like the right place for this code... Rebuilding the order item should probably happen from the add to cart form itself (or perhaps the ProductLazyBuilder?), but well, tried that, and couldn't figure it out quickly.Comment #45
b_sharpe commentedSimply posting current MR patch for composer stability. Still needs further review.
Comment #46
jsacksick commentedI'm not sure we'd want to do anything on hook_modules_installed().
I'm pretty sure we could implement a preSave() method in ProductType.
If the variation type setting is set, and not the variation types, we basically sett he variation types setting.
Comment #47
jsacksick commented@b_sharpe: Your diff seems incorrect, how did you produce it? The code looks wrong there....
There's no update hook in the merge request...
This isn't the right version of the patch, for sure...
Comment #48
b_sharpe commentedWell, I learned something today... I'm still not quite sure WHY this is, but I grabbed it from https://git.drupalcode.org/project/commerce/-/merge_requests/25.patch which I thought was correct, but it turns out it is https://git.drupalcode.org/project/commerce/-/merge_requests/25.diff (diff vs patch extension)
This is extremely confusing and I can't find any docs as to what the difference actually is here... but anyhow heres the diff version which I THINK is correct.
Comment #49
jsacksick commentedWe now have a 3.0.x branch, we could try squezing this in, though this needs additional changes. The previous setting would probably need to be removed.
$role->grantPermission("manage {$product_type->getVariationTypeIds()} commerce_product_variation");This doesn't look correct as well.
If we remove the setting, that also means we need to remove the associated methods, which could probably break custom/contrib code.
I need to review this afresh.
Comment #50
bradjones1Regarding the question in #48 - I tried to find a deep link in GitLab to explain the difference, but I can say from knowledge and experience that the patch version is basically each commit's patchfile appended in sequence, so they are applied in that same order. The diff only contains the diff from the HEAD of the MR to the target branch. So if for instance there were files or lines added and then deleted/reverted in commits "along the way," you won't see any of that in the diff. But you'll get all that noise in the patch. From my experience, even if they get you to the same endpoint there can be dragons in applying the patch instead of the diff, if you "just want to get the MR as a patch."
Comment #51
bradjones1The MR looks like it handles the add-to-cart "fine" with a pretty vanilla implementation, despite the warning message displayed when enabling multiple variation types on the product type.
However, after some testing it looks like we need to:
Error with two product variation types, one of which does not have the "size" attribute:
InvalidArgumentException: Unknown attribute field name "attribute_size". in Drupal\commerce_product\Entity\ProductVariation->getAttributeValue() (line 343 of modules/contrib/commerce/modules/product/src/Entity/ProductVariation.php).Comment #52
jsacksick commentedCame back to this today. Decided to take a stab at:
InvalidArgumentException: Unknown attribute field name "attribute_size". in Drupal\commerce_product\Entity\ProductVariation->getAttributeValue() (line 343 of modules/contrib/commerce/modules/product/src/Entity/ProductVariation.php).What I did was simply falling back to the "title" widget when a product references more than a single variation type. It's a simple approach, but I'd say this is good enough for now to get this feature released...
Thoughts? :p
Comment #54
jsacksick commentedHad a discussion with @rszrama and it was decided to remove the "multipleVariationTypes" setting. From the product type form the user has to choose between using one or multiple existing product variation types or create a new one.
Hopefully this patch doesn't fail like the previous one :).
Comment #55
jsacksick commentedComment #56
dwkitchen commentedFeels like we are 99% there; I have found one issue.
In a site with multiple product types including apparel and media, it will generally have
physical_productorder item type set to use the "Product Variation Atributes" widget on the add to cart form to account for the apparel.However, if this is the case the add to cart form on a media product with two variation types each using a different order item type i.e.
physical_productandlicense_productyou can only add the first variation to the cart.If all order item types use the "Product Variation Title" widget the add to cart works fine, and the current workaround is to add an additional order item type.
Comment #57
jsacksick commentedThe attached patch should resolve the issue from #56.
Also decided to change the logic that consists in rebuilding the form if the the new selected variation is supposed to use a different order item type, this is no longer done from the ajax callback (it seemed like an odd place to do this).
Rebuilding the form a second time surely has a performance impact, but not really sure we can skip this...
Let's see if the existing tests pass, though we could definitely use additional tests to ensure the add to cart works properly when a product references variations of a different type.
Comment #58
dwkitchen commentedThe issue I found in #56 has now been resolved. Add to cart works with both Title and Attribute options.
Comment #59
jsacksick commentedI added tests coverage, this now can be safely committed. One thing that isn't customizable is the title widget settings when we're forcing the use of the title widget when the product references variations of a different type, but I guess this could be addressed in a followup.
Comment #62
jsacksick commentedCommitted!! Yay!
Comment #63
geek-merlinYay! 🍾
Thanks everyone, this is so useful.
Comment #65
mrweiner commentedIs it expected that we should be able to assign additional product variation types to a product type for which products already exist? If I apply the patch and edit a product type, the Variations section is greyed out and I see "Products exist for this product type, you can no longer edit this setting."
Comment #66
jsacksick commentedThe current behavior was kept... But this kind of makes this feature unusable for existing product types... Now that I think of it. I can't remember what the rationale was behind the initial decision...
@mrweiner: Would you mind opening a new issue? We should probably just make sure that you can't unselect a variation type that was previously selected, but allow choosing "new" ones.
Comment #67
mrweiner commentedYeah looking through the issue it seems like maybe the feature was just forgotten about/overlooked. Just opened up #3270838: Allow additional variation types to be added to a product type with existing products..
Comment #68
adam1 commentedI'm going to set up a book shop with Drupal 10, which offers printed books and open access books for download, so I came across this issue. Can some one tell me if this patch is incorporated in Drupal 10 or do I have to patch? Since it's a community project that has not much funding, I don't like to do patches because future maintenance may get harder.
Comment #69
john.oltman commentedHey adam1, as noted in comments 60-62 and the issue status of "Closed (fixed)" a patch is not necessary - this feature has been released.
Comment #70
adam1 commentedThank you for clarifying!
Comment #71
ccjjmartin commentedI am proposing a change to the code that was added in this issue. Would appreciate some more eyes on this bug to verify it doesn't break anything introduced here: https://www.drupal.org/project/commerce/issues/3511232