Closed (fixed)
Project:
Commerce File
Version:
8.x-2.x-dev
Component:
Code
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
5 May 2017 at 05:31 UTC
Updated:
7 Feb 2020 at 23:54 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
j9 commentedCurious about this too.
Or is this feature being ported into Commerce core?
If there is a disucssion already somewhere, please tell, thanks!
Comment #3
bojanz commentedIt stays here. As far as I know nobody has volunteered to port it yet. Would be best to wait for a functional License port, which is in progress.
Comment #4
j9 commentedExcellent!
Sounds like the plan!
Comment #5
trigdog commented@bojanz
I see license 8.x is at an alpha2 now so I thought I would look through the code to see what it would take to get this module ported. Are you wanting to do a straight port of the 7.x-2.x branch? If so, I have a few questions about how you think that should work now that License is using Entity Traits.
In 7.x the commerce_file field was added/removed to the product type when the admin form was submitted. In the 8.x version, will the commerce_file field be attached to the license type file plugin or will it be added directly to the product_varation_type through something like hook_ENTITY_TYPE_update (hook_commerce_product_variation_type_update) checking whether the license trait & file license type were selected on the product variation type?
thoughts?
Comment #6
bojanz commented@trigdog
All good questions.
The two basic dilemmas are:
1) Does commerce_file interact with files, or with media entities (the spiritual successor to file entity from D7)
2) Can we pull off a form element for the file/media type that could live in the license type? If not, it makes sense to simply provide a File trait and require the merchant to enable it along with the License trait.
I'd also ping joachim, who might have more mature thoughts on this than me.
Comment #7
trigdog commentedThanks for the feedback bojanz.
1) I haven't done much with the media entities but I am going to look into that further today. At a quick glance, we definitely need the file field widget to land - https://www.drupal.org/project/drupal/issues/2831940 - because the best widget there is right now for it is IEF but that over complicates UX.
2) I will check with joachim.
Comment #8
joachim commented> Can we pull off a form element for the file/media type that could live in the license type?
That would get pretty messy, as the license provides just the serialized plugin field, and I don't think putting a file field inside that is going to be simple or pretty.
For one thing, I don't know how the file widget would handle that, and for another, you wouldn't be able to easily query for which product has which files.
Comment #9
joachim commentedMy rough idea of how this would work overall -- and bear in mind I could be way off course here -- is that you'd implement the entity access hook for the file/media entity, and in that hook you'd query for an active file license for the current user which targets the file entity in question.
Comment #10
_dcre_ commentedIs there any commerce 2 core functionality in place to handle, even roughly, file products?
If not, would you suggest any workarounds,
e.g.
1. create a file product with a non visible file attached
2. create a copy of this file assigning it the customer uid, upon successful checkout.
3. enable customer to access his files, when logged in
Would the above solution or any other similar make sense, in the commerce context? At least to handle file products while commerce_file is being implemented correctly.
BR
Comment #11
joachim commentedI don't really know what the use case of file products is anyway, so I'm not the best person to ask.
I would say that developing this module is probably a more efficient use of time than workarounds, as they will probably end up being quite complex themselves.
Comment #12
biigniick commentedI'm also interested in this. The module for Commerce License has a 8.x-2.0-alpha release, like #5 mentioned.
Are we waiting for the file field widget from https://www.drupal.org/project/drupal/issues/2831940 before working on porting this?
Comment #13
CryptoKiwi commentedI'm also interested. In our case we want to sell e-books in our store.
I am willing to contribute to this as well, although I'm not yet very experienced in Drupal (8) development.
I've been looking in to a few possible approaches, and it appears that the best approach would be to use the Media module. I was thinking of integrating with Content Access to give customers permissions to view a certain File entity. Perhaps this could then also be extended to provide access to other entity types as well?
Comment #14
WebWalker3D commentedI am also expressing interest in this, as I sell e-books and very much would prefer to not move away from d8 :)
Comment #15
Bojan Zivkov commentedI started with porting this module. Right now it's pretty basic, but it's working (missing UI/settings and generally needs scalability/tests/etc)
I added new commerce license type for file and attached a file field to a license, then i control the access to licensed file with hook_file_access and custom license query based on uid and fid.
Sandbox project: https://www.drupal.org/sandbox/bojanzivkov/2975782
Comment #16
damienmckennaComment #17
tonypaulbarkerI need something like this that is going to work for anonymous users as well as logged in. I'm exploring whether State Machine could provide a good approach.
Comment #18
joachim commented> I need something like this that is going to work for anonymous users as well as logged in.
I don't really understand how anonymous licensing can work. The only way you can identify the user is by their session, which will expire. So you're expecting them to pay for something that's only going to last until their session expires...? I suppose you could give them an access code... but then, that's functionally the same as having an account password, so you might as well create them an account!
Comment #19
tonypaulbarkerHi joachim
In this case it's for downloading an ebook (other use case might be music files). Most users for the website in question will download and read the book and never need or want to come back to download it again (they can get in touch at any point if they do want it again, which is better than an expired license). So it's not that dissimilar to shipping a physical product from a user perspective. In most cases people don't want to go through the extra steps to create an account that they will never use again (and even if they regularly buy from a store they often prefer not to register) - but of course in an ideal world we want the option of a registration to be available too. Current workaround is to link to other services and we are looking at sending an email with a link, but a download link on the order confirm page would be a lot better.
Comment #20
joachim commentedAh, right, I didn't think of that!
> Current workaround is to link to other services and we are looking at sending an email with a link, but a download link on the order confirm page would be a lot better.
Add a new checkout pane that shows the download link.
You then need a way for that download link to allow the download. You could stick a token on it, that's hashed from the session ID & the file ID.
Then you need the license entity's uid field to not be required. That's a change I'd consider in the core module, with some sort of constraint.
To check the license, you could add a field to the license for the session ID, or you could just store the license ID in the session and then verify the license is active when you check the download link.
Comment #21
tonypaulbarkerThere could be an argument for auto creating an account but that will feel invasive to some and unnecessary. An access token I don't think would feel invasive so this is definitely an approach worth exploring.
Comment #22
mlecha commentedAre there any other known options to offer digital downloads with Drupal Commerce on Drupal 8?
Comment #23
tonypaulbarkermlecha at the moment I don't believe there are any options for this.
Comment #24
chris matthews commented@CryptoKiwi, check out Commerce License Access Control. I'm not 100% sure it will fit your particular use case, but it sounds like it will.
Comment #25
nathaniel commentedI started the initial port for D8. After testing a couple options and reading the comments here I went with the file field as an entity trait for Commerce Product Variation. This seems to work well and allows adding different file types for different variations. It works with attributes for selecting different file types or options.
Where possible I tried to keep all the 7.x-2.x functionality the same. I removed icon from the download link theme / field options since it is now preferred to add the file icons with CSS through the theme. I guess the option could still be used to exclude the classes for file icon if needed?
I started migrating the default view for user/%user/my-files and will attach it here, but I ran into some issues trying to enable it automatically when the module is installed. It seems the file relationship doesn’t exist until a product variation with the commerce file option is created. A possible solution for this might be to include a default product variation in config install, but I haven’t tried that yet. Someone else might have a better solution or workaround for this?
Notes: create a new product variation. Select traits “Provides a file for download” and “Provides a license”. Under available license types select “Commerce File”. If "Provides a file for download" is checked a new hook form alter will validate the form and check if all the other options are selected.
Comment #26
nadavoid commented@Nathaniel Your timing is impeccable. Over the last week or so I was starting to strategize on how I was going to offer purchasable downloads. I hope to test your patch in the next few days. So glad you're working on this!
Comment #27
mlecha commented@Nathaniel Your patch in #25 should be applied to 7.x-2.x-dev?
I'm not used to patching on Windows but I'll figure it out to take a look at this Drupal 8 port. I'm trying patch from Git Bash but it's a little broken. I'll try something else.
Thanks!
Comment #28
nathaniel commentedYes, 7.x-2.x-dev.
Comment #29
jmoruziThanks for working on this Nathaniel, patched and installed. I'll test it over the next little while.
Comment #30
jmoruzi@Nathaniel so far so good. I had some issues getting this set up initially but I think they were related more to Commerce License. I was able to install and configure Commerce File, but initially the File field was locked and I was unable to change it, I needed to change the approved file types but couldn't. If I created any product variations with a file attached I could not delete those product variations so I was unable to uninstall/reinstall Commerce File. I'm not sure what caused this, but eventually i just wiped the whole thing out and started over, being very careful to configure everything in Commerce first so that all I needed to do at the end was enable the file download on a particular variation and it all worked.
The only hiccup was when creating the first product variation an error was thrown by the Recurring Time Period module but the patch at #5 in this issue fixed it. https://www.drupal.org/project/recurring_period/issues/3034378
Order and checkout process using the Stripe test gateway worked well and download link appeared on the order confirmation page.
Now I have a question. Once the order is placed, the file download link appears in the checkout confirmation screen (good), but once you leave that screen the link appears to be gone, never to be seen again (bad). I've had a number of customers over the years on another site contact me saying they cannot find their file and need to download it again.
Where do I find the link with the token so it can be included in the confirmation email to the customer, and appear on their order summary page in their account so that they can download the file again?
When can we get an official dev version so it can be tested by the wider community?
Comment #31
nathaniel commentedHi @jmoruzi, thanks for the feedback, this is great! If you haven't already, there is a view attached along with the patch. That can be imported at /admin/config/development/configuration/full/import click "Single item" select "View" and paste the code there. Update user permissions to "View own licenses" and a tab should appear on their account page called "Files" (/user/%user/my-files) the view should list all files that user has purchased.
Comment #32
jmoruzi@Nathaniel, awesome, view works great.
I have not tried deleting/editing files or product variations or anything like that yet, I've only created one product with a file attached and tested the purchase and checkout process which all works well. The file is there in the user account page and can be downloaded again. I'm working in some other things this week but will get back to testing this more extensively next week.
Comment #33
nadavoid commented@Nathaniel, I've finally gotten around to testing this. I can confirm that it works! Your approach makes tons of sense, of using a field on the product variation, along with the "Provides a license" trait and the new "Provides a file for download" trait.
I think the next step for this would be to kick off an actual 8.x branch for development. @bojanz or @recrit Would that be possible? That would make it much easier to test and develop D8 code. For example, we could point our composer config at the 8.x version.
Comment #34
nadavoid commented@Nathaniel For the issue regarding enabling the default view, I have a couple of thoughts:
config/install, so that it doesn't cause problems when its dependencies aren't met at install time.Comment #35
nadavoid commentedMarking this RTBC since there are two (myself included) confirmations of this working. Pending an 8.x branch though. Still, this is exciting to have this feature so close to being available!
Comment #36
msypes commentedAdd me to the list of people interested in setting up Commerce2 for selling access to downloadable files/books.
I'm getting confused even with the basic set up. I'd certainly appreciate any advice or "recipes" people have used so far.
From my reading of the Commerce Guys v2 docs, it would seem that I'd have a Product Attribute of "File Pointer" as an entity reference to a specific file, a Product Variation Type wrapping that, and finally a Product Type to wrap that, such that each Product Variant would point to a specific file, have a price and a unique SKU. However, I don't see how you'd create the attribute without specific values as options. (This isn't like T-shirts; I'm not starting off with a known set of colors.) I ended up creating a simple entity reference for a media type with the file on a Product Variant Type, which at least looks promising.
I already have Book Nodes with media entities for the actual files. With Commerce 1, I'd've expected these to function as "Display Nodes," but with Commerce2's structure getting rid of those in favor of a dedicated Product Entity, I'm not sure they fit in at all. I also created a dedicated Order Type (because I only want one downloadable file purchased at a time, and figured that might be a way to handle that. I also created a dedicated Order Item Type, which sounds like a replacement for the old Line Items/Customized Line Items, but couldn't find a way to connect those to anything, expecting something that would indicate a purchase of particular Product or Product Type would generate a specified Order Item Type and/ or Order Type.
I installed Commerce File & License, and applied the patch. Added a License field for Commerce File to the Product Variation Type with the Media File Entity Reference. I'm not seeing anything mentioning traits “Provides a file for download” nor “Provides a license.”
If someone who's traveled this path before can help guide me, I'll be happy to assist in getting this ported. Ultimately, I'm going to have added idiosyncratic complexities, but I need to get the basics working first.
Thanks.
Comment #37
nadavoid commentedI've reviewed what I did when testing this, and wrote up what I did so that other people can have a good starting point. There may be some gaps or misunderstandings on my part, so please feel free to offer corrections, and I'll update the comment. Note that media entities are not part of the setup.
Module setup:
Entity setup:
Order Type
Order Item Type
Product Variation Type
Product Type
Products should now be able to be created, with references to downloadable files.
Views setup
The view provided with the patch in comment 25, provides a way to access the purchased file, at `/user/[uid]/my-files`. To create one from scratch:
Comment #38
burtondev commentedI'm also interested in this module to sell digital files online.
I'm new to Drupal and Drupal Commerce. The only site builder I could find that currently supports product variants for digital products was Shopify, but it is quite limited (max 100 variants and 3 options per product).
The products that I am looking to sell are printables. So while they are digital, the user uses them to create physical products (the printouts).
For this reason the attributes are similar to those of physical products - color, size, etc. (size referring to different page sizes).
There are other attributes and options that when combined could easily yield over 1500 product variations.
In such a case, is it possible to batch-link the product variations to the files rather than manually? Perhaps via a CSV file or something?
Also, how are the files uploaded? Is there a batch process for this as well?
Thanks to everyone that has contributed!
Comment #39
msypes commentedThanks @nadavoid!
I apparently had several broken items in my Commerce Set up (It doesn't clean up well after itself.), but I now have what appears to be a working system.
I followed @nadavoid's directions with the following exceptions:
Everything else was defaults or according to @nadavoid's list.
I did get an odd notice upon the Product Type:
Notice: Undefined index: login in Drupal\commerce_license\FormAlter\ProductVariationTypeFormAlter->formValidate() (line 141 of modules/contrib/commerce_license/src/FormAlter/ProductVariationTypeFormAlter.php).I also, previously had experimented with the Media module, but that doesn't work well in embedded forms. (There are several issue threads on D.O.[1][2]) I did see this in the browser console upon clicking the "Add Media" botton:
An AJAX HTTP error occurred. HTTP Result Code: 500 Debugging information follows. Path: /product/add/downloadable_file?ajax_form=1 StatusText: 500 Service unavailable (with message) ResponseText: The website encountered an unexpected error. Please try again later.Exception: The current form must not have button-level #validate handlers in Drupal\commerce\Element\PluginConfiguration::validateElementSubmit() (line 66 of modules/contrib/commerce/src/Element/CommerceElementTrait.php). call_user_func_array(Array, Array) (Line: 282) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238) Drupal\Core\Form\FormValidator->doValidateForm(Array, Object, 'commerce_product_downloadable_file_add_form') (Line: 118) Drupal\Core\Form\FormValidator->validateForm('commerce_product_downloadable_file_add_form', Array, Object) (Line: 576) Drupal\Core\Form\FormBuilder->processForm('commerce_product_downloadable_file_add_form', Array, Object) (Line: 319) Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 93) Drupal\Core\Controller\FormController->getContentResult(Object, Object) call_user_func_array(Array, Array) (Line: 123) Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 582) Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124) Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97) Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151) Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68) Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57) Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106) Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85) Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52) Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23) Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 693) Drupal\Core\DrupalKernel->handle(Object) (Line: 19)I don't want to hijack this thread however; just putting it out there. If, down the road, there's a desire the shift from "Commerce File" to "Commerce Media", this is the kind of thing we'll have to tackle.
Comment #40
msypes commented@burtondev: You should be able to batch import large numbers of products and variations using the Migrate module. I haven't used it myself, so can't give advice, but the basic idea of using a CSV to import and generate entities is certainly doable. (In the distant past, I've written quickie scripts to generate nodes and the like from legacy databases too.)
Comment #41
burtondev commented@msypes: Thanks for letting me know about the Migrate module. I will look into it!
Comment #42
morbus iffI didn't know Commerce File was being actively developed/ported. Useful. I had an implementation question, though: I sell books. I need to sell "War and Peace" with the following product attribute options: "Hardcover", "Softcover", "ePub", "PDF", "ePub + PDF", and "Hardcover + PDF". However, based on the testing script from @nadavoid, it seems that:
1:
A mixed media cart ("a softcover of issue 17 of this journal" and "a PDF of War and Peace" and a "Hardcover + PDF package of Alice in Wonderland") is not possible because files require their own Order Type and Order Item Type different from a normal physical product workflow. Is that true?
2:
Product variations can either sell files or not (based on the product variation "provides a file for download: yes"). If that forces the file to be REQUIRED for every product variation, then I can't have a "Hardcover" product variation (no file download) alongside a "PDF" product variation (file download) on the same product. Is that true?
3:
Does commerce_file used File field types or Media field types? Can I attach additional metadata to the file uploads (such as remote file hash, which would be used to associate the file with a remote storage system like Adobe Content Server or RedShelf)? That's primarily why we're using Media entity types in Drupal 8 instead of normal File/Image field types.
Comment #43
msypes commented@morbus:
The only question I can answer with absolute certainty for you is the last one - Commerce File uses file fields, not Media. I did post earlier with the output from an experimental attempt to use Media. Commerce File creates a required file field on the variation type. If you want to attach additional meta data you could conceivably add those as fields directly to the product variation type.
As for the other questions -
I believe you're correct, at least partially. I'm using a distinct Order Item Type and Order Type, but I don't think it's absolutely required to do so, especially for the Order Type. I would expect a shopping cart/order to be able to include multiple order item types (What I believe used to be called "line item types").
Displaying a mixture of file and on-file variations of a product is trickier. I think you'd have to incorporate some sort of work-around on your own for that. You could separate them as distinct product types and just display them on a common page, if necessary. If you really need everything combined, I think a workaround would be to have your non-file variations reference some dummy filler file, and then write code to hide the fact that there's a file associated with it at all.
Comment #44
msypes commentedI'm definitely closer, but still have an issue:
I've tested a user going through the full purchase process and when done, there's a proper completion page; however, the file is not downloadable. Instead of a link, the name of the file is presented. The view provided in the patch also shows no files.
After a small amount of digging I realized that this is because the license is being assigned to user 0 (anonymous) instead of the newly minted user account. Manually updating the owner in the database fixes both issues.
Can anyone tell me why I'm getting the wrong user assignment and how to correct it?
Comment #45
nathaniel commented@msypes, I was able to reproduce the same issue with "Guest registration after checkout". A possible workaround is to edit the "Checkout flows" > "Login or continue as guest" uncheck "Allow guest checkout" and check "Allow registration" that seems to fix the issue, but registration is required at the first step instead of the last step.
It looks like we can tap into guest registration after checkout with an Event Subscriber:
$events[CheckoutEvents::COMPLETION_REGISTER][] = 'onRegister';Then update the uid there with the new account and order details.
At this point I'm not sure if that would be useful as a patch for commerce_license or better handled here.
Comment #46
msypes commentedThanks @Nathaniel!
Switching that configuration looks like it did the trick.
The Event Subscriber sounds like a useful option, if not the default behavior, but I think it belongs, as you say, as a patch to commerce_license, not here.
Comment #47
nathaniel commented@Morbus
Good point, that is going to be a problem on my end as well. I see this issue:
https://www.drupal.org/project/commerce/issues/2880602
But it doesn't look like it is going anywhere for now.
Comment #48
ipwa commentedThe patch works great. The only problem I have is that the user registration form on the checkout pane does not send an email, but if a user register through user/register it does send the welcome user email. That might be related to my configuraqtion though and not have anything to do with this patch or this module.
What would be amazing is to include the download link on the order email the user gets, does anyone know how to do that?
Thanks!
Comment #49
BetoXrp commented@Nathaniel thank you so much, i had some problems with the installation but im using it now... Thank you @nadavoid to for those steps...
Comment #50
chris matthews commentedThis issue currently has a RTBC status, but is that really the case? The reason I ask is the most recent patch is in #25 and there have been quite a few comments/questions that have been brought up since the patch was posted.
Comment #51
nadavoid commentedYes, I believe this issue really is justifiably set to RTBC. The comments after the latest patch are more about how to use it and where to take it next.
I think that the next steps here are for a maintainer to review the patch and start a D8 branch. And if the patch looks good to the maintainer, use it to start the D8 branch.
Comment #53
nathaniel commentedA new dev branch for 8.x-2.x is now available! Note that if you are updating from the current patch, cache will have to be cleared. Marking this issue as fixed. Please open separate issues as needed for 8.x-2.x-dev.
We'll need some documentation, tests and it would probably be nice to include some default order item type, product variation type and product type.
Comment #54
nadavoid commentedYaaayyy!! This is fantastic. Thank you for committing this, Nathaniel. And for writing the patch to begin with. Nice work!