Save permissions + revoke access after xx days feature.

This commit is contained in:
Mike Jolley 2012-02-25 21:11:06 +00:00
parent eaef280e75
commit 95fe36cd07
8 changed files with 275 additions and 192 deletions

View File

@ -21,7 +21,7 @@ function woocommerce_order_downloads_meta_box() {
<div class="wc-metaboxes">
<?php
$i = 0;
$i = -1;
$download_permissions = $wpdb->get_results("
SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
@ -37,7 +37,7 @@ function woocommerce_order_downloads_meta_box() {
<h3 class="fixed">
<button type="button" rel="<?php echo $download->product_id; ?>" class="revoke_access button"><?php _e('Revoke Access', 'woocommerce'); ?></button>
<div class="handlediv" title="<?php _e('Click to toggle'); ?>"></div>
<strong><?php echo '#' . $product->id . ' &mdash; ' . $product->get_title(); ?></strong>
<strong><?php echo '#' . $product->id . ' &mdash; ' . $product->get_title() . ' &mdash; ' . sprintf(_n('Downloaded %s time', 'Downloaded %s times', $download->download_count), $download->download_count); ?></strong>
</h3>
<table cellpadding="0" cellspacing="0" class="wc-metabox-content">
<tbody>
@ -45,11 +45,11 @@ function woocommerce_order_downloads_meta_box() {
<td>
<label><?php _e('Downloads Remaining', 'woocommerce'); ?>:</label>
<input type="hidden" name="download_id[<?php echo $i; ?>]" value="<?php echo $download->product_id; ?>" />
<input type="text" class="short" name="downloads_remaining[<?php echo $i; ?>]" value="<?php ?>" placeholder="<?php _e('Unlimited', 'woocommerce'); ?>" />
<input type="text" class="short" name="downloads_remaining[<?php echo $i; ?>]" value="<?php echo $download->downloads_remaining ?>" placeholder="<?php _e('Unlimited', 'woocommerce'); ?>" />
</td>
<td>
<label><?php _e('Access Expires', 'woocommerce'); ?>:</label>
<input type="text" class="short date-picker" name="access_expires[<?php echo $i; ?>]" value="<?php ?>" maxlength="10" placeholder="<?php _e('Never', 'woocommerce'); ?>" />
<input type="text" class="short date-picker" name="access_expires[<?php echo $i; ?>]" value="<?php echo ($download->access_expires>0) ? date('Y-m-d', strtotime($download->access_expires)) : ''; ?>" maxlength="10" placeholder="<?php _e('Never', 'woocommerce'); ?>" />
</td>
</tr>
</tbody>
@ -234,4 +234,45 @@ function woocommerce_order_downloads_meta_box() {
<?php
$javascript = ob_get_clean();
$woocommerce->add_inline_js( $javascript );
}
/**
* Order Downloads Save
*
* Function for processing and storing all order downloads.
*/
add_action('woocommerce_process_shop_order_meta', 'woocommerce_order_downloads_save', 5, 2);
function woocommerce_order_downloads_save( $post_id, $post ) {
global $wpdb, $woocommerce;
if (isset($_POST['download_id'])) :
// Download data
$download_ids = $_POST['download_id'];
$downloads_remaining = $_POST['downloads_remaining'];
$access_expires = $_POST['access_expires'];
// Order data
$order_key = get_post_meta($post->ID, '_order_key', true);
$customer_email = get_post_meta($post->ID, '_billing_email', true);
$customer_user = (int) get_post_meta($post->ID, '_customer_user', true);
for ($i=0; $i<sizeof($download_ids); $i++) :
$wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array(
'user_id' => $customer_user,
'user_email' => $customer_email,
'downloads_remaining' => $downloads_remaining[$i],
'access_expires' => ($access_expires[$i]) ? date('Y-m-d', strtotime($access_expires[$i])) : ''
), array(
'order_id' => $post_id,
'product_id' => $download_ids[$i]
), array( '%d', '%s', '%s', '%s' ), array( '%d', '%d' ) );
endfor;
endif;
update_post_meta( $post_id, '_order_taxes', $order_taxes );
}

View File

@ -148,11 +148,10 @@ function woocommerce_product_data_box() {
</p>';
// Download Limit
$download_limit = get_post_meta($post->ID, '_download_limit', true);
$field = array( 'id' => '_download_limit', 'label' => __('Download Limit', 'woocommerce') );
echo '<p class="form-field">
<label for="'.$field['id'].'">'.$field['label'].':</label>
<input type="text" class="short" name="'.$field['id'].'" id="'.$field['id'].'" value="'.$download_limit.'" placeholder="'.__('Unlimited', 'woocommerce').'" /> <span class="description">' . __('Leave blank for unlimited re-downloads.', 'woocommerce') . '</span></p>';
woocommerce_wp_text_input( array( 'id' => '_download_limit', 'label' => __('Download Limit', 'woocommerce'), 'placeholder' => __('Unlimited', 'woocommerce'), 'description' => __('Leave blank for unlimited re-downloads.', 'woocommerce') ) );
// Expirey
woocommerce_wp_text_input( array( 'id' => '_download_expiry', 'label' => __('Download Expiry', 'woocommerce'), 'placeholder' => __('Never', 'woocommerce'), 'description' => __('Enter the number of days before a download link expires, or leave blank.', 'woocommerce') ) );
do_action('woocommerce_product_options_downloads');
@ -763,6 +762,7 @@ function woocommerce_process_product_meta( $post_id, $post ) {
if (isset($_POST['_file_path']) && $_POST['_file_path']) update_post_meta( $post_id, '_file_path', esc_attr($_POST['_file_path']) );
if (isset($_POST['_download_limit'])) update_post_meta( $post_id, '_download_limit', esc_attr($_POST['_download_limit']) );
if (isset($_POST['_download_expiry'])) update_post_meta( $post_id, '_download_expiry', esc_attr($_POST['_download_expiry']) );
endif;

View File

@ -33,7 +33,7 @@ function woocommerce_meta_boxes() {
add_meta_box( 'woocommerce-order-items', __('Order Items <small>&ndash; Note: if you edit quantities or remove items from the order you will need to manually change the item\'s stock levels.</small>', 'woocommerce'), 'woocommerce_order_items_meta_box', 'shop_order', 'normal', 'high');
add_meta_box( 'woocommerce-order-totals', __('Order Totals', 'woocommerce'), 'woocommerce_order_totals_meta_box', 'shop_order', 'side', 'default');
add_meta_box( 'woocommerce-order-notes', __('Order Notes', 'woocommerce'), 'woocommerce_order_notes_meta_box', 'shop_order', 'side', 'default');
add_meta_box( 'woocommerce-order-downloads', __('Downloadable Product Permissions <small>&ndash; Note: Permissions for line items will automatically be granted when the order status changes to processing/completed.</small>', 'woocommerce'), 'woocommerce_order_downloads_meta_box', 'shop_order', 'normal', 'default');
add_meta_box( 'woocommerce-order-downloads', __('Downloadable Product Permissions <small>&ndash; Note: Permissions for order items will automatically be granted when the order status changes to processing/completed.</small>', 'woocommerce'), 'woocommerce_order_downloads_meta_box', 'shop_order', 'normal', 'default');
add_meta_box( 'woocommerce-order-actions', __('Order Actions', 'woocommerce'), 'woocommerce_order_actions_meta_box', 'shop_order', 'side', 'high');
remove_meta_box( 'commentsdiv', 'shop_order' , 'normal' );

View File

@ -227,7 +227,8 @@ function woocommerce_tables_install() {
user_id mediumint(9) NULL,
downloads_remaining varchar(9) NULL,
access_granted datetime NOT NULL default '0000-00-00 00:00:00',
access_expires datetime NULL,
access_expires datetime NULL default null,
download_count mediumint(9) NOT NULL DEFAULT 0,
PRIMARY KEY id (product_id,order_id,order_key)) $collate;";
dbDelta($sql);

View File

@ -146,6 +146,9 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
= 1.4.5 =
* Quick edit products
* Bulk edit products
* Downloadable Product Permissions management via orders page - grant and revoke access to files
* See how many times a download has been downloaded
* Option for downloadable files to expire after X days
* PayPal standard goes straight to PayPal via a GET request - no more pay page/forms
* Better mixed cart handling - option to give access to downloads after payment (processing order status)
* Added basic API for payment gateways to hook into (for IPN etc)

View File

@ -513,7 +513,13 @@ function woocommerce_grant_access_to_download() {
endif;
$limit = trim(get_post_meta($product_id, '_download_limit', true));
$expiry = trim(get_post_meta($product_id, '_download_expiry', true));
$limit = (empty($limit)) ? '' : (int) $limit;
$expiry = (empty($expiry)) ? '' : (int) $expiry;
if ($expiry) $expiry = date("Y-m-d", strtotime('NOW + ' . $expiry . ' DAY'));
$wpdb->hide_errors();
$success = $wpdb->insert( $wpdb->prefix . 'woocommerce_downloadable_product_permissions', array(
@ -522,14 +528,20 @@ function woocommerce_grant_access_to_download() {
'user_email' => $user_email,
'order_id' => $order->id,
'order_key' => $order->order_key,
'downloads_remaining' => $limit
'downloads_remaining' => $limit,
'access_granted' => current_time('mysql'),
'access_expires' => $expiry,
'download_count' => 0
), array(
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
'%s',
'%s',
'%s',
'%d'
) );
if ($success) {
@ -537,7 +549,7 @@ function woocommerce_grant_access_to_download() {
'success' => 1,
'download_id' => $product_id,
'title' => get_the_title($product_id),
'expires' => '',
'expires' => $expiry,
'remaining' => $limit
));
}

View File

@ -443,7 +443,7 @@ if (get_option('woocommerce_downloads_grant_access_after_payment')=='yes') add_a
function woocommerce_downloadable_product_permissions( $order_id ) {
global $wpdb;
if (get_post_meta( $order_id, '_downloadable_product_permissions_granted', true)==1) return; // Only do this once
if (get_post_meta( $order_id, __('Download Permissions Granted', 'woocommerce'), true)==1) return; // Only do this once
$order = new WC_Order( $order_id );
@ -468,28 +468,34 @@ function woocommerce_downloadable_product_permissions( $order_id ) {
endif;
$limit = trim(get_post_meta($download_id, '_download_limit', true));
$expiry = trim(get_post_meta($download_id, '_download_expiry', true));
if (!empty($limit)) :
$limit = (int) $limit;
else :
$limit = '';
endif;
$limit = (empty($limit)) ? '' : (int) $limit;
$expiry = (empty($expiry)) ? '' : (int) $expiry;
if ($expiry) $expiry = date("Y-m-d", strtotime('NOW + ' . $expiry . ' DAY'));
// Downloadable product - give access to the customer
$wpdb->insert( $wpdb->prefix . 'woocommerce_downloadable_product_permissions', array(
'product_id' => $download_id,
'user_id' => $order->user_id,
'user_email' => $user_email,
'order_id' => $order->id,
'order_key' => $order->order_key,
'downloads_remaining' => $limit
'product_id' => $download_id,
'user_id' => $order->user_id,
'user_email' => $user_email,
'order_id' => $order->id,
'order_key' => $order->order_key,
'downloads_remaining' => $limit,
'access_granted' => current_time('mysql'),
'access_expires' => $expiry,
'download_count' => 0
), array(
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
'%s',
'%s',
'%s',
'%d'
) );
endif;
@ -498,7 +504,7 @@ function woocommerce_downloadable_product_permissions( $order_id ) {
endforeach;
update_post_meta( $order_id, '_downloadable_product_permissions_granted', 1);
update_post_meta( $order_id, __('Download Permissions Granted', 'woocommerce'), 1);
}
/**

View File

@ -744,7 +744,9 @@ function woocommerce_download_product() {
$order_id = $download_result->order_id;
$downloads_remaining = $download_result->downloads_remaining;
$download_count = $download_result->download_count;
$user_id = $download_result->user_id;
$access_expires = $download_result->access_expires;
if ($user_id && get_option('woocommerce_downloads_require_login')=='yes'):
if (!is_user_logged_in()):
@ -759,7 +761,6 @@ function woocommerce_download_product() {
endif;
endif;
if ($order_id) :
$order = new WC_Order( $order_id );
if ($order->status!='completed' && $order->status!='processing' && $order->status!='publish') :
@ -769,173 +770,192 @@ function woocommerce_download_product() {
endif;
if ($downloads_remaining=='0') :
wp_die( __('Sorry, you have reached your download limit for this file', 'woocommerce') . ' <a href="'.home_url().'">' . __('Go to homepage &rarr;', 'woocommerce') . '</a>' );
else :
if ($downloads_remaining>0) :
$wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array(
'downloads_remaining' => $downloads_remaining - 1,
), array(
'user_email' => $email,
'order_key' => $order_key,
'product_id' => $download_file
), array( '%d' ), array( '%s', '%s', '%d' ) );
endif;
// Get the downloads URL and try to replace the url with a path
$file_path = apply_filters('woocommerce_file_download_path', get_post_meta($download_file, '_file_path', true), $download_file);
if (!$file_path) exit;
$file_download_method = apply_filters('woocommerce_file_download_method', get_option('woocommerce_file_download_method'), $download_file);
if ($file_download_method=='redirect') :
header('Location: '.$file_path);
exit;
endif;
// Get URLS with https
$site_url = site_url();
$network_url = network_admin_url();
if (is_ssl()) :
$site_url = str_replace('https:', 'http:', $site_url);
$network_url = str_replace('https:', 'http:', $network_url);
endif;
if (!is_multisite()) :
$file_path = str_replace(trailingslashit($site_url), ABSPATH, $file_path);
else :
$upload_dir = wp_upload_dir();
// Try to replace network url
$file_path = str_replace(trailingslashit($network_url), ABSPATH, $file_path);
// Now try to replace upload URL
$file_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $file_path);
endif;
// See if its local or remote
if (strstr($file_path, 'http:') || strstr($file_path, 'https:') || strstr($file_path, 'ftp:')) :
$remote_file = true;
else :
$remote_file = false;
$file_path = realpath($file_path);
endif;
// Download the file
$file_extension = strtolower(substr(strrchr($file_path,"."),1));
$ctype = "application/force-download";
foreach (get_allowed_mime_types() as $mime => $type) :
$mimes = explode('|', $mime);
if (in_array($file_extension, $mimes)) :
$ctype = $type;
break;
endif;
endforeach;
if ($file_download_method=='xsendfile') :
if (getcwd()) :
// Path fix - kudos to Jason Judge
$file_path = trim(preg_replace( '`^' . getcwd() . '`' , '', $file_path ), '/');
endif;
header("Content-Disposition: attachment; filename=\"".basename($file_path)."\";");
if (function_exists('apache_get_modules') && in_array( 'mod_xsendfile', apache_get_modules()) ) :
header("X-Sendfile: $file_path");
exit;
elseif (stristr(getenv('SERVER_SOFTWARE'), 'lighttpd') ) :
header("X-Lighttpd-Sendfile: $file_path");
exit;
elseif (stristr(getenv('SERVER_SOFTWARE'), 'nginx') || stristr(getenv('SERVER_SOFTWARE'), 'cherokee')) :
header("X-Accel-Redirect: $file_path");
exit;
endif;
endif;
/**
* readfile_chunked
*
* Reads file in chunks so big downloads are possible without changing PHP.INI - http://codeigniter.com/wiki/Download_helper_for_large_files/
*
* @access public
* @param string file
* @param boolean return bytes of file
* @return void
*/
if ( ! function_exists('readfile_chunked')) {
function readfile_chunked($file, $retbytes=TRUE) {
$chunksize = 1 * (1024 * 1024);
$buffer = '';
$cnt = 0;
$handle = fopen($file, 'r');
if ($handle === FALSE) return FALSE;
while (!feof($handle)) :
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) $cnt += strlen($buffer);
endwhile;
$status = fclose($handle);
if ($retbytes AND $status) return $cnt;
return $status;
}
}
@session_write_close();
if (function_exists('apache_setenv')) @apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 'Off');
@set_time_limit(0);
@set_magic_quotes_runtime(0);
@ob_end_clean();
if (ob_get_level()) @ob_end_clean(); // Zip corruption fix
header("Pragma: no-cache");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Robots: none");
header("Content-Type: ".$ctype."");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=\"".basename($file_path)."\";");
header("Content-Transfer-Encoding: binary");
if ($size = @filesize($file_path)) header("Content-Length: ".$size);
// Serve it
if ($remote_file) :
@readfile_chunked("$file_path") or header('Location: '.$file_path);
else :
@readfile_chunked("$file_path") or wp_die( __('File not found', 'woocommerce') . ' <a href="'.home_url().'">' . __('Go to homepage &rarr;', 'woocommerce') . '</a>' );
endif;
exit;
exit;
endif;
if ($access_expires > 0 && strtotime($access_expires) > current_time('timestamp')) :
wp_die( __('Sorry, this download has expired', 'woocommerce') . ' <a href="'.home_url().'">' . __('Go to homepage &rarr;', 'woocommerce') . '</a>' );
exit;
endif;
if ($downloads_remaining>0) :
$wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array(
'downloads_remaining' => $downloads_remaining - 1,
), array(
'user_email' => $email,
'order_key' => $order_key,
'product_id' => $download_file
), array( '%d' ), array( '%s', '%s', '%d' ) );
endif;
// Count the download
$wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array(
'download_count' => $download_count + 1,
), array(
'user_email' => $email,
'order_key' => $order_key,
'product_id' => $download_file
), array( '%d' ), array( '%s', '%s', '%d' ) );
// Get the downloads URL and try to replace the url with a path
$file_path = apply_filters('woocommerce_file_download_path', get_post_meta($download_file, '_file_path', true), $download_file);
if (!$file_path) exit;
$file_download_method = apply_filters('woocommerce_file_download_method', get_option('woocommerce_file_download_method'), $download_file);
if ($file_download_method=='redirect') :
header('Location: '.$file_path);
exit;
endif;
// Get URLS with https
$site_url = site_url();
$network_url = network_admin_url();
if (is_ssl()) :
$site_url = str_replace('https:', 'http:', $site_url);
$network_url = str_replace('https:', 'http:', $network_url);
endif;
if (!is_multisite()) :
$file_path = str_replace(trailingslashit($site_url), ABSPATH, $file_path);
else :
$upload_dir = wp_upload_dir();
// Try to replace network url
$file_path = str_replace(trailingslashit($network_url), ABSPATH, $file_path);
// Now try to replace upload URL
$file_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $file_path);
endif;
// See if its local or remote
if (strstr($file_path, 'http:') || strstr($file_path, 'https:') || strstr($file_path, 'ftp:')) :
$remote_file = true;
else :
$remote_file = false;
$file_path = realpath($file_path);
endif;
// Download the file
$file_extension = strtolower(substr(strrchr($file_path,"."),1));
$ctype = "application/force-download";
foreach (get_allowed_mime_types() as $mime => $type) :
$mimes = explode('|', $mime);
if (in_array($file_extension, $mimes)) :
$ctype = $type;
break;
endif;
endforeach;
if ($file_download_method=='xsendfile') :
if (getcwd()) :
// Path fix - kudos to Jason Judge
$file_path = trim(preg_replace( '`^' . getcwd() . '`' , '', $file_path ), '/');
endif;
header("Content-Disposition: attachment; filename=\"".basename($file_path)."\";");
if (function_exists('apache_get_modules') && in_array( 'mod_xsendfile', apache_get_modules()) ) :
header("X-Sendfile: $file_path");
exit;
elseif (stristr(getenv('SERVER_SOFTWARE'), 'lighttpd') ) :
header("X-Lighttpd-Sendfile: $file_path");
exit;
elseif (stristr(getenv('SERVER_SOFTWARE'), 'nginx') || stristr(getenv('SERVER_SOFTWARE'), 'cherokee')) :
header("X-Accel-Redirect: $file_path");
exit;
endif;
endif;
/**
* readfile_chunked
*
* Reads file in chunks so big downloads are possible without changing PHP.INI - http://codeigniter.com/wiki/Download_helper_for_large_files/
*
* @access public
* @param string file
* @param boolean return bytes of file
* @return void
*/
if ( ! function_exists('readfile_chunked')) {
function readfile_chunked($file, $retbytes=TRUE) {
$chunksize = 1 * (1024 * 1024);
$buffer = '';
$cnt = 0;
$handle = fopen($file, 'r');
if ($handle === FALSE) return FALSE;
while (!feof($handle)) :
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) $cnt += strlen($buffer);
endwhile;
$status = fclose($handle);
if ($retbytes AND $status) return $cnt;
return $status;
}
}
@session_write_close();
if (function_exists('apache_setenv')) @apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 'Off');
@set_time_limit(0);
@set_magic_quotes_runtime(0);
@ob_end_clean();
if (ob_get_level()) @ob_end_clean(); // Zip corruption fix
header("Pragma: no-cache");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Robots: none");
header("Content-Type: ".$ctype."");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=\"".basename($file_path)."\";");
header("Content-Transfer-Encoding: binary");
if ($size = @filesize($file_path)) header("Content-Length: ".$size);
// Serve it
if ($remote_file) :
@readfile_chunked("$file_path") or header('Location: '.$file_path);
else :
@readfile_chunked("$file_path") or wp_die( __('File not found', 'woocommerce') . ' <a href="'.home_url().'">' . __('Go to homepage &rarr;', 'woocommerce') . '</a>' );
endif;
exit;
endif;
}