Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Add a "download all" option to emails for WooCommerce downloadable products. Zips all the files and stores the zip in a specified directory.
<?php
/**
* Utility function to create a zip file from an array of file URLs
* Used for download links in emails
* @param array $files
* @param string $filename
*
* @return string
*/
function doublee_zip_order_files(array $files, string $filename) {
$upload_dir = $YOUR_DIRECTORY_HERE; // IMPORTANT: Ensure protection on this directory to ensure only authorised users can download the zip file.
$zip_path = $upload_dir['path'] . '/' . $filename;
$zip_url = $upload_dir['url'] . '/' . $filename;
$zip = new ZipArchive;
// Create the zip file
$zip->open($zip_path, ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Loop through the files, get the WP attachment and path, and use these to add the files to the zip
foreach($files as $url) {
$url_pieces = parse_url($url);
$url_path = $url_pieces['path'];
$path_pieces = explode('/', $url_path);
$year_month_file = array_splice($path_pieces, -3);
$year = $year_month_file[0];
$month = $year_month_file[1];
$file = $year_month_file[2];
$args = array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'meta_query' => array(
array(
'key' => '_wp_attached_file',
'value' => $year . '/' . $month . '/' . $file,
'compare' => 'LIKE',
)
),
'fields' => 'ids'
);
$query = new WP_Query($args);
$attachment_id = $query->posts[0];
$path = get_attached_file($attachment_id);
$zip->addFile($path, basename($path));
}
// Close the zip, we're done here
$zip->close();
// Return the zip URL
return $zip_url;
}
<?php
/**
* Email Downloads.
*
* This template can be overridden by copying it to yourtheme/woocommerce/emails/email-downloads.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce/Templates
* @version 3.4.0
*/
defined( 'ABSPATH' ) || exit;
$text_align = is_rtl() ? 'right' : 'left';
// Create an array of unique downloads for the single-file list
$unique_downloads = array_unique_multidimensional($downloads, 'product_id');
// Prepare filename for our "Download All" zip file
// My client requested site name and order number, but for other use cases something random would provide more security through obscurity
$order_number = $order->get_order_number();
$filename = str_replace(' ', '-', get_bloginfo('name')) . '-' . $order_number . '.zip';
// Put all the file URLs into an array
$files = array();
foreach($downloads as $download) {
array_push($files, $download['file']['file']);
}
// Only include each file once
$files = array_unique($files);
// Zip them and return the URL using our utility function
$zip_url = doublee_zip_order_files($files, $filename);
?>
<h2 class="woocommerce-order-downloads__title"><?php esc_html_e( 'Downloads', 'woocommerce' ); ?></h2>
<table class="td" cellspacing="0" cellpadding="6" style="width: 100%; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; margin-bottom: 40px;" border="1">
<thead>
<tr>
<?php foreach ( $columns as $column_id => $column_name ) : ?>
<?php
// Add the "Download all" link
if($column_name=='Download'): ?>
<th class="td" scope="col" style="text-align:<?php echo esc_attr( $text_align ); ?>;">
<a href="<?= $zip_url ?>">Download All</a>
</th>
<?php else: ?>
<th class="td" scope="col" style="text-align:<?php echo esc_attr( $text_align ); ?>;"><?php echo esc_html( $column_name ); ?></th>
<?php endif; ?>
<?php endforeach; ?>
</tr>
</thead>
<?php
// List the individual downloads
foreach ($unique_downloads as $download) : ?>
<tr>
<?php foreach ( $columns as $column_id => $column_name ) : ?>
<td class="td" style="text-align:<?php echo esc_attr( $text_align ); ?>;">
<?php
if ( has_action( 'woocommerce_email_downloads_column_' . $column_id ) ) {
do_action( 'woocommerce_email_downloads_column_' . $column_id, $download, $plain_text );
} else {
switch ( $column_id ) {
case 'download-product':
?>
<?php echo wp_kses_post( $download['product_name'] ); ?>
<?php
break;
case 'download-file':
?>
<a href="<?php echo esc_url( $download['download_url'] ); ?>" class="woocommerce-MyAccount-downloads-file button alt"><?php echo esc_html( $download['download_name'] ); ?></a>
<?php
break;
case 'download-expires':
if ( ! empty( $download['access_expires'] ) ) {
?>
<time datetime="<?php echo esc_attr( date( 'Y-m-d', strtotime( $download['access_expires'] ) ) ); ?>" title="<?php echo esc_attr( strtotime( $download['access_expires'] ) ); ?>"><?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $download['access_expires'] ) ) ); ?></time>
<?php
} else {
esc_html_e( 'Never', 'woocommerce' );
}
break;
}
}
?>
</td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</table>
<?php
/**
* array_unique for a multi-dimensional array
* @see https://stackoverflow.com/a/34283567/6913674
* @param $array
* @param $key
*
* @return array
*/
function array_unique_multidimensional($array, $key) {
$i = 0;
$new_array = array();
$key_array = array();
foreach($array as $val) {
if(!in_array($val[$key],$key_array)){
$key_array[$i] = $val[$key];
$new_array[$i] = $val;
}
$i++;
}
return $new_array;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment