Skip to content

Conversation

@LuigiPulcini
Copy link
Contributor

All Submissions:

Changes proposed in this Pull Request:

Adding the parameter $item to both the function wc_downloadable_file_permission and the filter hook woocommerce_downloadable_file_permission would provide a further level of customization for the downloadable file being granted, depending on the metadata assigned to the single item when purchasing a product.

How to test the changes in this Pull Request:

  1. add a filter to the hook woocommerce_downloadable_file_permission, including 5 parameters
  2. print the 5th parameter $item to verify that it is passed the data of the single item in each order

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully run tests with your changes locally?

Changelog entry

Added parameter $item (instance of WC_Order_Item) to both the function wc_downloadable_file_permission and the filter hook woocommerce_downloadable_file_permission

Adding the parameter `$item` to both the function `wc_downloadable_file_permission` and the filter hook `woocommerce_downloadable_file_permission` would provide a further level of customization for the downloadable file being granted, depending on the metadata assigned to the single item when purchasing a product.
@LuigiPulcini
Copy link
Contributor Author

LuigiPulcini commented Apr 1, 2019

I fully tested this on a local website I am currently developing and everything is working as expected.
There are possibly several reasons why adding this parameter could be useful in certain scenarios. I am offering the one I am working on at the moment, offering you the reasons why I find it very convenient.

Scenario: MUSIC LICENSING WEBSITE
Let's say I have a website where I want to sell licenses to music tracks.
Every track can be licensed with four different attributes: type (standard or commercial), use (web, radio, TV, all media), territories (local, national, global) and period (up to 3 months and perpetual). Appropriately mixing all the attributes (not every combination is realistic), I have 12 variations.
This means that, if I had 10,000 tracks, I would need to manage 10,000 products with a total of 120,000 variations.

Since I want to avoid all this, especially considering that the client who is going to deal with the backend of the website is not a developer himself, I came up with an idea that is proving absolutely rock solid when it comes to operability and simplicity.

The music tracks are added as items of a custom post type track.
The downloadable files are associated with each track.
I then have one single variable product called "Music license" with its 12 variations and that is pretty much the only one needed to deal with the whole shop.

The most important reason I came up with this idea is that:
– the structure of the licenses is always the same regardless of the selected track;
– if I need to change the price of a certain attribute combination, I can only change one single variation instead of going through to possibly thousands of them.

When a user clicks on the BUY button corresponding to a track, a dialog pops up, letting the user choose the variation they need. When finally added to the cart, a script adds the selected variation to the cart, adding the track ID to the cart_item_data.
When the purchase is finalized, the cart_item_data gets transferred to the corresponding item of the order.

Since neither the product nor its variations have downloadable files associated to them, the whole process of permission granting happens programmatically, through the filter woocommerce_downloadable_file_permission. By including the $item parameter to the function applying that filter, I was finally able to programmatically create the right $download object (instance of WC_Customer_Download), also creating programmatically the association between the download object and the actual downloadable file (located on an AWS S3 bucket).

Simply adding the $item parameter to the wc_downloadable_file_permission makes this whole process possible and the appropriate permissions are added to the wp_woocommerce_downloadable_product_permissions table.

Other filters involved in this whole process are:
woocommerce_get_item_data (filter)
woocommerce_checkout_create_order_line_item (action)
woocommerce_product_variation_get_downloads (filter)
woocommerce_downloadable_file_permission (filter)
woocommerce_product_file_download_path (filter)
woocommerce_product_file (filter)
woocommerce_customer_get_downloadable_products (filter)

I hope this is clear enough and makes sense.

Copy link
Contributor

@claudiosanches claudiosanches left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like that is missing this $item implementation in WC_AJAX::grant_access_to_download.

@claudiosanches claudiosanches added needs: author feedback The issue/PR needs a response from any of the parties involved in the issue. and removed status: needs review labels May 23, 2019
@LuigiPulcini
Copy link
Contributor Author

LuigiPulcini commented May 23, 2019

@claudiosanches, you are absolutely right.
Analyzing the code of grant_access_to_download, it is not clear to me why we need product_ids as a POST parameter of the AJAX call when the order_id is also provided. Couldn't we just derive the list of products from the order, as it is in the function wc_downloadable_product_permissions?

$order = wc_get_order( $order_id );
[...]
foreach ( $order->get_items() as $item ) {
	$product = $item->get_product();
	[...]
	$downloads = $product->get_downloads();
	foreach ( array_keys( $downloads ) as $download_id ) {
		wc_downloadable_file_permission( $download_id, $product, $order, $item->get_quantity() );
		[...]

If the same mechanism could be used, the function grant_access_to_download could be rewritten as follows, which would allow to add the $item object as a parameter for wc_downloadable_file_permission:

    $order_id     = intval( $_POST['order_id'] );
    $loop         = intval( $_POST['loop'] );
    $file_counter = 0;
    $order        = wc_get_order( $order_id );
    foreach ( $order->get_items() as $item ) {
        $product = $item->get_product();
        $files   = $product->get_downloads();
        if ( ! $order->get_billing_email() ) {
            wp_die();
        }
        if ( ! empty( $files ) ) {
            foreach ( $files as $download_id => $file ) {
                $inserted_id = wc_downloadable_file_permission( $download_id, $product_id, $order, $item->get_quantity(), $item );
                if ( $inserted_id ) {
                    $download = new WC_Customer_Download( $inserted_id );
                    $loop ++;
                    $file_counter ++;
                    if ( $file->get_name() ) {
                        $file_count = $file->get_name();
                    } else {
                        /* translators: %d file count */
                        $file_count = sprintf( __( 'File %d', 'woocommerce' ), $file_counter );
                    }
                    include 'admin/meta-boxes/views/html-order-download-permission.php';
                }
            }
        }
    }

LuigiPulcini added a commit to LuigiPulcini/woocommerce that referenced this pull request May 23, 2019
Adding $item to wc_downloadable_file_permission would make `grant_access_to_download` compatible with the changes in woocommerce#23188
@LuigiPulcini
Copy link
Contributor Author

HERE you can find a possible change to grant_access_to_download that would make it compatible with this change to wc_downloadable_file_permission.

@claudiosanches
Copy link
Contributor

@LuigiPulcini in this case we use product_ids because we allow grant access just for specific products instead of all at the same time. Maybe we could revisit this interface and grant for all products at the same time.

Still for what you are trying to do seems like that could alternate this methods or even create a new one, passing the line_item instead $product, since we can recover the product data from a order item, but isn't possible to find the order item with an product ID. This one will require some code refactor.

Those are the solutions that I can think of, still both requires code refactor.

@LuigiPulcini
Copy link
Contributor Author

LuigiPulcini commented Jun 3, 2019

Thanks for your inputs, @claudiosanches

Regarding the $product_ids, we could use both methods at the same time, allowing developers to send a list of $product_ids within the AJAX call and, if that parameter is left unset, use all the $product_ids linked to the specific order. That would not affect the possibility to add the $item to the grant_access_to_download function.

Actually, I have a working installation where, after applying the proposed changes, everything works flawlessly and as expected.

From what I can see, this refactor would already be enough to keep the functions consistent with the current implementation, while opening them to the new approach.

@rodrigoprimo rodrigoprimo added status: needs review and removed needs: author feedback The issue/PR needs a response from any of the parties involved in the issue. labels Jul 4, 2019
@claudiosanches
Copy link
Contributor

This is still not good to merge, since all occurrences of wc_downloadable_file_permission() doesn't require or include order items.

cc @rodrigoprimo

@claudiosanches claudiosanches removed this from the 3.7.0 milestone Jul 8, 2019
@LuigiPulcini
Copy link
Contributor Author

Hi, @claudiosanches

The function wc_downloadable_file_permission is present in only three files. I can prepare a change for all of them that would work with the idea I outlined in this PR.

What would you recommend? Using this PR or creating a new one with all the file changes required?

@claudiosanches
Copy link
Contributor

@LuigiPulcini better put all in just one PR, since it's for the same reason. Like I said, no problem including a new parameter on it, but we need to make it consistent. Thanks for your help!

@claudiosanches claudiosanches added the needs: author feedback The issue/PR needs a response from any of the parties involved in the issue. label Aug 27, 2019
@kloon kloon added this to the 3.8.0 milestone Sep 3, 2019
@vedanshujain vedanshujain modified the milestones: 3.8.0, 3.9.0 Oct 2, 2019
@kloon
Copy link
Contributor

kloon commented Nov 18, 2019

@LuigiPulcini Just checking if you saw @claudiosanches last comment and if you are still willing to make the changes so we can get this merged?

@claudiosanches claudiosanches removed this from the 3.9.0 milestone Dec 2, 2019
@rodrigoprimo
Copy link
Contributor

Closing due to inactivity. Please leave a comment if you still plan to work on this and we will reopen. Thanks.

LuigiPulcini added a commit to LuigiPulcini/woocommerce that referenced this pull request Oct 15, 2020
Please refer to woocommerce#23188 for the whole conversation about this.
LuigiPulcini referenced this pull request in LuigiPulcini/woocommerce Oct 15, 2020
Please refer to woocommerce#23188 for the whole conversation about this.
@LuigiPulcini
Copy link
Contributor Author

First of all, sorry for the mess with the commits. :)

These new commits include the changes to the class-wc-ajax.php that @claudiosanches recommended at the beginning of this conversation.

The main change to the grant_access_to_download function replaces the for loop through the product_ids with a for loop through the items of the order. To ensure the compatibility with the provided list of product_ids, every iteration first checks whether the current item object refers to a product ID included in the product_ids array.

...
$items        = $order->get_items();

foreach ( $items as $item ) {
	$product = $item->get_product();
	if ( ! in_array( $product->get_id(), $product_ids, true ) ) {
		continue;
	}
...

This should complete the adjustments requested above.

Let me know if this can work for you.

Best,
Luigi.

@LuigiPulcini
Copy link
Contributor Author

Hi, @claudiosanches
Would you be so kind to explain why this PR keeps failing? Am I missing something or did I do something wrong with the commits?

Thanks,
Luigi.

@LuigiPulcini
Copy link
Contributor Author

LuigiPulcini commented Jan 14, 2021

I am wondering if it is possible to move forward with this PR.
At the moment, I am absolutely clueless about the failing check. 😄

Thanks!

@rrennick
Copy link
Contributor

@LuigiPulcini If you merge the current version of master into the PR you will trigger a Travis build. The build that failed is on travis.org and we cannot restart it because the project was moved to use travis.com.

Base automatically changed from master to trunk February 25, 2021 22:17
@claudiosanches claudiosanches self-requested a review March 3, 2021 20:43
Copy link
Contributor

@claudiosanches claudiosanches left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thank you very much!

@claudiosanches claudiosanches added this to the 5.3.0 milestone Mar 25, 2021
@claudiosanches claudiosanches merged commit 50e036f into woocommerce:trunk Mar 25, 2021
@woocommercebot woocommercebot added release: add changelog Mark all PRs that have not had their changelog entries added. [auto] release: add testing instructions PRs that have not had testing instructions added to the wiki. [auto] labels Mar 25, 2021
@claudiosanches claudiosanches removed the release: add testing instructions PRs that have not had testing instructions added to the wiki. [auto] label Mar 25, 2021
raicem added a commit to raicem/woocommerce that referenced this pull request Apr 9, 2021
…duct id

With the PR woocommerce#23188, "$product_id" variable become undefined.
Konamiman pushed a commit that referenced this pull request Apr 9, 2021
…duct id

With the PR #23188, "$product_id" variable become undefined.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release: add changelog Mark all PRs that have not had their changelog entries added. [auto]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants