Posted on

WooCommerce Downloads Dev Cheat Sheet

WooCommerce Products Banner

While writing my WooCommerce Premium Plugin System (Woops) I was having issues finding simple documentation on the hooks and filters I needed to build my plugin.  This is where I’ve stored my “working papers”.  The cheat sheet and notes about the stuff I need to remember or want to track while building the plugin.   It may help some other devs build their own WooCommerce add-ons as well.

Downloadable Products

My account has a different mechanism to list downloads than viewing order details.

Observations

When a product has a download attached to it a unique download ID is assigned.  This download ID is attached to the order via a unique download_id that is tracked in the woocommerce_downloadable_product_permissions table.

Questions

Q1) If the product download file is changed to a different file, will the user be able to download the new file or just the original version of the file?

Simple Answer) It will allow downloads to the new file.

A1) If you use a static URL like they will always be able to get the latest version of the download whenever the source download.zip is updated.   The download_id and all records in the woocommerce_downloadable_product_permissions table remain static.

A2) When changing the download file by editing a product and choosing “upload file” the content of the file paths will change.  When this changes WooCommerce copies all records in the woocommerce_downloadable_product_permissions table that have the old download ID to add a new record with a new download ID, in essence doubling all the download records for download orders for that product ID.  This happens in the writepanels-init.php via the woocommerce_process_product_file_download_paths() method.

Notes:

I) NOT changing the upload file by editing the product and choosing a new download file is far more efficient. For the reason noted in A2.

II) woocommerce_process_product_file_download_paths() uses the woocommerce_file_download_paths filter to modify the EXISTING file path(s) for a product.  That is the content of the file path(s) field on the product BEFORE editing/saving the product.  Thus you can only make it appear as there was no file prior to adding a new one, however the mechanism that duplicates the records in A2) above does an array diff to determine what records to change.

III) To disable the duplicate download copies the action woocommerce_process_product_file_download_paths() needs to be overridden.

Updating Product Download Files Methodology

When a product is updated via the admin panel and the file paths (downloads) entry is changed, WooCommerce runs through the writepanel-* procedural code.   Buried deep in that nest of code is the woocommerce_process_product_file_download_paths interface.

Notes:

I) If you prevent the automatic update of the downloadable_product_permissions table via a remove_action() call then the users will lose access to their downloads when a new download file comes online.    Using this method to remove access to newer downloads means a new method must be implemented to allow access to older versions of the files.

In version 2.X of WooCommerce some of the hooks and filters to manipulate the process includes:

woocommerce_process_product_file_download_path() – called from the writepanel-product-type-variable and writepanel-product_data procedural code.   Also called from the product->has_file() call, which is used to build the list of available downloads.

woocommerce_process_product_file_download_paths() – called from the writepanel-product-type-variable and writepanel-product_data procedural code.   Also called from the product->has_file() call, which is used to build the list of available downloads.   Called FIRST in the has_file() method which sets a variable that is the first parameter in the download_path() (singular) filter noted above.

My Account Download List Methodology

My account uses the WC_Customer.get_downloadable_products() method. This method loops over the woocommerce_downloadable_products_permissions table and iterates once for each order_id, product_id, download_id combination.

In version 2.X of WooCommerce this only has 3 potential hooks or filters to manipulate the results:

woocommerce_order_is_download_permitted – called once for each order being processed in the get_downloadable_products method
woocommerce_downloadable_product_name – called multiple times while building the downloads stack
woocommerce_customer_get_downloadable_products – called at exit of get_downloadable_products method

Hooks and Filters

My unofficial documentation on WooCommerce version 2.x hooks and filters that I need to manipulate the product downloads and related information.

woocommerce_order_is_download_permitted

A simple filter that determines if a current order is allowed to download stuff.

parameters:
[0] - boolean based on current download permission
[1] - the current WC_Order object

woocommerce_customer_get_downloadable_products

Gets the “stack” of downloads available to the user, shown on the “my account” page. Downloads is a named array:

Properties:
download_url
download_id
product_id
download_name - filtered per woocommerce_downloadable_product_name
order_id
order_key
downloads_remaining

woocommerce_file_download_path

Parameters:
[0] - fully qualified URL of the download file
[1] - the product ID 
[2] - the download id, the MD5 style key in the woocommerce_downloadable_product_permissions table

This is called whenever a file is requested directly from a URL, as in when a user clicks a download link on their order. The file path can be modified by using this filter.

woocommerce_file_download_paths

Parameters:
[0] - stack of file paths, the key is an MD5 key to downloadable_product_permissions table, value is the file path
[1] - the product ID 
[2] - the order ID (null for the product->has_file method)
[3] - the item (null for the product->has_file method)

Called at the START of the product->has_file method, which then gets tested before setting file_path for the woocommerce_file_download_path (singular) filter noted above.

woocommerce_process_product_file_download_paths

Parameters:
[0] - post_id
[1] - variation id (or 0)
[2] - file paths stack

This action manages the updates to the downloadable product permissions table. It is called by the writepanel-product-type-variable and writepanel-product_data processors via the do_action WordPress function. Both procedural scripts fire the writepanels-init function of the same name.

woocommerce_downloadable_product_name

Parameters:
[0] - Title + file Number
[1] - Product object
[2] - Download ID
[3] - File Number

Used to set the download name that renders when a user views “my account”.

Posted on

Continuing Work on Tagalong / SLP 3.9.2

Tagalong and Core SLP

As I’ve been working on the Tagalong updates I have been working on some new “foundation elements” in Store Locator Plus.    Things like a consolidated location class that will lay the groundwork for being able to add custom fields and discrete searches in the future.   Since the Tagalongcategories are essentially a custom field, I decided to backup a few steps and “do it right” versus tacking on to the legacy systems that are much harder to extend.  Progress is being made, though a bit more slowly than I’d like.   Party because I’m keeping the legacy stuff intact and functional while adding on the new classes to extend the base product.   It is more work but it ensures existing installs have far less chances of breaking even though the product will become slightly “heavier” during the transition period.

Hooks & Filters (for dev geeks)

Along with the new class are some new hooks & filters for third party plugins.  That will make it easier for future add-on packs to augment the system without hacking the core of SLP.   That means upgrade to SLP should be possible without breaking the add-on packs as long as they rely purely on hooks and filters v. direct feature/function calls.  Even I’ve had to do that myself but avoiding “core hacking” at all costs is the ultimate goal here.  That ensures updates don’t break add-ons.

Product Packages

Today I turned on something existing users probably won’t be interested in but more than a couple of potential new add-on pack buyers have asked for recently; SLP Packages on the CSA website.   Packages simply turn the multi-step process of buying multiple Store Locator Plus add-on packs into a 1-click operation.   The first two packages are the “Everything But The Kitchen Sink” package which puts all the add-on packs that add functionality into your shopping cart.  The other packages is the “Cream of the Crop” which puts the top 3 most-often purchased products in your cart.

Random Musings

Some people in my tech circles have been commenting on some of the articles I’ve been posting to my private Facebook and Google Groups threads.   Here are some of the things I’ve been researching or reading about that are getting the most commentary.

 

 

Back to the code…