diff --git a/includes/abstracts/abstract-wc-product.php b/includes/abstracts/abstract-wc-product.php
index 2d1279a053a..2aa01d358b7 100644
--- a/includes/abstracts/abstract-wc-product.php
+++ b/includes/abstracts/abstract-wc-product.php
@@ -1196,6 +1196,9 @@ class WC_Product extends WC_Abstract_Legacy_Product {
$download_object->set_id( md5( $download['file'] ) );
$download_object->set_name( $download['name'] );
$download_object->set_file( $download['file'] );
+ if ( isset( $download['previous_hash'] ) ) {
+ $download_object->set_previous_hash( $download['previous_hash'] );
+ }
}
// Validate the file extension
diff --git a/includes/admin/class-wc-admin-post-types.php b/includes/admin/class-wc-admin-post-types.php
index 562e4ddd30c..75300bd9420 100644
--- a/includes/admin/class-wc-admin-post-types.php
+++ b/includes/admin/class-wc-admin-post-types.php
@@ -88,9 +88,6 @@ class WC_Admin_Post_Types {
// Meta-Box Class
include_once( dirname( __FILE__ ) . '/class-wc-admin-meta-boxes.php' );
- // Download permissions
- add_action( 'woocommerce_process_product_file_download_paths', array( $this, 'process_product_file_download_paths' ), 10, 3 );
-
// Disable DFW feature pointer
add_action( 'admin_footer', array( $this, 'disable_dfw_feature_pointer' ) );
@@ -2057,58 +2054,10 @@ class WC_Admin_Post_Types {
* @param int $product_id product identifier
* @param int $variation_id optional product variation identifier
* @param array $downloadable_files newly set files
+ * @deprecated and moved to post-data class.
*/
public function process_product_file_download_paths( $product_id, $variation_id, $downloadable_files ) {
- if ( $variation_id ) {
- $product_id = $variation_id;
- }
- $product = wc_get_product( $product_id );
- $existing_download_ids = array_keys( (array) $product->get_downloads() );
- $updated_download_ids = array_keys( (array) $downloadable_files );
- $new_download_ids = array_filter( array_diff( $updated_download_ids, $existing_download_ids ) );
- $removed_download_ids = array_filter( array_diff( $existing_download_ids, $updated_download_ids ) );
- $data_store = WC_Data_Store::load( 'customer-download' );
-
- if ( ! empty( $new_download_ids ) || ! empty( $removed_download_ids ) ) {
- // determine whether downloadable file access has been granted via the typical order completion, or via the admin ajax method
- $order_ids = wc_list_pluck( $data_store->get_downloads( array(
- 'product_id' => $product_id,
- ) ), 'get_order_id' );
-
- if ( $order_ids ) {
- foreach ( $order_ids as $order_id ) {
- $order = wc_get_order( $order_id );
-
- if ( $order->get_id() ) {
- // Remove permissions
- if ( ! empty( $removed_download_ids ) ) {
- foreach ( $removed_download_ids as $download_id ) {
- if ( apply_filters( 'woocommerce_process_product_file_download_paths_remove_access_to_old_file', true, $download_id, $product_id, $order ) ) {
-
-
-
-
- $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d AND product_id = %d AND download_id = %s", $order->get_id(), $product_id, $download_id ) );
- }
- }
- }
- // Add permissions
- if ( ! empty( $new_download_ids ) ) {
-
- foreach ( $new_download_ids as $download_id ) {
-
- if ( apply_filters( 'woocommerce_process_product_file_download_paths_grant_access_to_new_file', true, $download_id, $product_id, $order ) ) {
- // grant permission if it doesn't already exist
- if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT 1=1 FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d AND product_id = %d AND download_id = %s", $order->get_id(), $product_id, $download_id ) ) ) {
- wc_downloadable_file_permission( $download_id, $product, $order );
- }
- }
- }
- }
- }
- }
- }
- }
+ WC_Post_Data::process_product_file_download_paths( $product_id, $variation_id, $downloadable_files );
}
/**
diff --git a/includes/admin/meta-boxes/class-wc-meta-box-order-downloads.php b/includes/admin/meta-boxes/class-wc-meta-box-order-downloads.php
index 5ab96baf399..a1eef217a1f 100644
--- a/includes/admin/meta-boxes/class-wc-meta-box-order-downloads.php
+++ b/includes/admin/meta-boxes/class-wc-meta-box-order-downloads.php
@@ -41,7 +41,7 @@ class WC_Meta_Box_Order_Downloads {
if ( $download_permissions && sizeof( $download_permissions ) > 0 ) {
foreach ( $download_permissions as $download ) {
if ( ! $product || $product->get_id() !== $download->get_product_id() ) {
- $product = wc_get_product( absint( $download->get_product_id() ) );
+ $product = wc_get_product( $download->get_product_id() );
$file_counter = 1;
}
@@ -89,36 +89,16 @@ class WC_Meta_Box_Order_Downloads {
$downloads_remaining = $_POST['downloads_remaining'];
$access_expires = $_POST['access_expires'];
$product_ids_max = max( array_keys( $product_ids ) );
+ $data_store = WC_Data_Store::load( 'customer-download' );
for ( $i = 0; $i <= $product_ids_max; $i ++ ) {
if ( ! isset( $product_ids[ $i ] ) ) {
continue;
}
-
- // @todo $download = new WC_Customer_Download( $data );
-
- $data = array(
- 'downloads_remaining' => wc_clean( $downloads_remaining[ $i ] ),
- );
-
- $format = array(
- '%s',
- );
-
- $expiry = ( array_key_exists( $i, $access_expires ) && '' != $access_expires[ $i ] ) ? date_i18n( 'Y-m-d', strtotime( $access_expires[ $i ] ) ) : null;
-
- $data['access_expires'] = $expiry;
- $format[] = '%s';
-
- $wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions",
- $data,
- array(
- 'order_id' => $post_id,
- 'product_id' => absint( $product_ids[ $i ] ),
- 'download_id' => wc_clean( $download_ids[ $i ] ),
- ),
- $format, array( '%d', '%d', '%s' )
- );
+ $download = $data_store::get_download_from_order( $post_id, absint( $product_ids[ $i ] ), $download_ids[ $i ] );
+ $download->set_downloads_remaining( wc_clean( $downloads_remaining[ $i ] ) );
+ $download->set_access_expires( array_key_exists( $i, $access_expires ) && '' !== $access_expires[ $i ] ? strtotime( $access_expires[ $i ] ) : '' );
+ $download->save();
}
}
}
diff --git a/includes/admin/meta-boxes/class-wc-meta-box-product-data.php b/includes/admin/meta-boxes/class-wc-meta-box-product-data.php
index d346d5cab58..a9952cf236a 100644
--- a/includes/admin/meta-boxes/class-wc-meta-box-product-data.php
+++ b/includes/admin/meta-boxes/class-wc-meta-box-product-data.php
@@ -142,7 +142,7 @@ class WC_Meta_Box_Product_Data {
* Prepare downloads for save.
* @return array
*/
- private static function prepare_downloads( $file_names, $file_urls ) {
+ private static function prepare_downloads( $file_names, $file_urls, $file_hashes ) {
$downloads = array();
if ( ! empty( $file_urls ) ) {
@@ -151,8 +151,9 @@ class WC_Meta_Box_Product_Data {
for ( $i = 0; $i < $file_url_size; $i ++ ) {
if ( ! empty( $file_urls[ $i ] ) ) {
$downloads[] = array(
- 'name' => wc_clean( $file_names[ $i ] ),
- 'file' => wp_unslash( trim( $file_urls[ $i ] ) ),
+ 'name' => wc_clean( $file_names[ $i ] ),
+ 'file' => wp_unslash( trim( $file_urls[ $i ] ) ),
+ 'previous_hash' => wc_clean( $file_hashes[ $i ] ),
);
}
}
@@ -286,7 +287,11 @@ class WC_Meta_Box_Product_Data {
'stock_quantity' => wc_stock_amount( $_POST['_stock'] ),
'download_limit' => '' === $_POST['_download_limit'] ? '' : absint( $_POST['_download_limit'] ),
'download_expiry' => '' === $_POST['_download_expiry'] ? '' : absint( $_POST['_download_expiry'] ),
- 'downloads' => self::prepare_downloads( isset( $_POST['_wc_file_names'] ) ? $_POST['_wc_file_names'] : array(), isset( $_POST['_wc_file_urls'] ) ? $_POST['_wc_file_urls'] : array() ),
+ 'downloads' => self::prepare_downloads(
+ isset( $_POST['_wc_file_names'] ) ? $_POST['_wc_file_names'] : array(),
+ isset( $_POST['_wc_file_urls'] ) ? $_POST['_wc_file_urls'] : array(),
+ isset( $_POST['_wc_file_hashes'] ) ? $_POST['_wc_file_hashes'] : array()
+ ),
'product_url' => esc_url_raw( $_POST['_product_url'] ),
'button_text' => wc_clean( $_POST['_button_text'] ),
'children' => 'grouped' === $product_type ? self::prepare_children() : null,
@@ -334,7 +339,11 @@ class WC_Meta_Box_Product_Data {
'description' => wp_kses_post( wc_sanitize_textarea( $_POST['variable_description'][ $i ] ) ),
'download_limit' => wc_clean( $_POST['variable_download_limit'][ $i ] ),
'download_expiry' => wc_clean( $_POST['variable_download_expiry'][ $i ] ),
- 'downloads' => self::prepare_downloads( isset( $_POST['_wc_variation_file_names'][ $variation_id ] ) ? $_POST['_wc_variation_file_names'][ $variation_id ] : array(), isset( $_POST['_wc_variation_file_urls'][ $variation_id ] ) ? $_POST['_wc_variation_file_urls'][ $variation_id ] : array() ),
+ 'downloads' => self::prepare_downloads(
+ isset( $_POST['_wc_variation_file_names'][ $variation_id ] ) ? $_POST['_wc_variation_file_names'][ $variation_id ] : array(),
+ isset( $_POST['_wc_variation_file_urls'][ $variation_id ] ) ? $_POST['_wc_variation_file_urls'][ $variation_id ] : array(),
+ isset( $_POST['_wc_variation_file_hashes'][ $variation_id ] ) ? $_POST['_wc_variation_file_hashes'][ $variation_id ] : array()
+ ),
'manage_stock' => isset( $_POST['variable_manage_stock'][ $i ] ),
'stock_quantity' => wc_clean( $_POST['variable_stock'][ $i ] ),
'backorders' => wc_clean( $_POST['variable_backorders'][ $i ] ),
diff --git a/includes/admin/meta-boxes/views/html-product-download.php b/includes/admin/meta-boxes/views/html-product-download.php
index 5bbcc023c06..1e7cade40c3 100644
--- a/includes/admin/meta-boxes/views/html-product-download.php
+++ b/includes/admin/meta-boxes/views/html-product-download.php
@@ -1,6 +1,9 @@
|
- |
+
+
+
+ |
" name="_wc_file_urls[]" value="" /> |
|
|
diff --git a/includes/admin/meta-boxes/views/html-product-variation-download.php b/includes/admin/meta-boxes/views/html-product-variation-download.php
index 18cb2de00b9..ca8a0516b19 100644
--- a/includes/admin/meta-boxes/views/html-product-variation-download.php
+++ b/includes/admin/meta-boxes/views/html-product-variation-download.php
@@ -1,5 +1,8 @@
- |
+
+
+
+ |
" name="_wc_variation_file_urls[][]" value="" /> |
|
|
diff --git a/includes/class-wc-cart.php b/includes/class-wc-cart.php
index 59c051f9aba..eaf30e5d914 100644
--- a/includes/class-wc-cart.php
+++ b/includes/class-wc-cart.php
@@ -936,7 +936,7 @@ class WC_Cart {
if ( $product_data->managing_stock() ) {
$products_qty_in_cart = $this->get_cart_item_quantities();
- if ( ! $product_data->has_enough_stock( $products_qty_in_cart[ $product_data->get_stock_managed_by_id() ] + $quantity ) ) {
+ if ( isset( $products_qty_in_cart[ $product_data->get_stock_managed_by_id() ] ) && ! $product_data->has_enough_stock( $products_qty_in_cart[ $product_data->get_stock_managed_by_id() ] + $quantity ) ) {
throw new Exception( sprintf(
'%s %s',
wc_get_cart_url(),
diff --git a/includes/class-wc-customer-download.php b/includes/class-wc-customer-download.php
index 9420c7abf24..60802632377 100644
--- a/includes/class-wc-customer-download.php
+++ b/includes/class-wc-customer-download.php
@@ -38,15 +38,15 @@ class WC_Customer_Download extends WC_Data implements ArrayAccess {
* @param int|object|array $download
*/
public function __construct( $download = 0 ) {
- parent::__construct( $order );
+ parent::__construct( $download );
if ( is_numeric( $download ) && $download > 0 ) {
$this->set_id( $download );
} elseif ( $download instanceof self ) {
$this->set_id( absint( $download->get_id() ) );
- } elseif ( is_array( $download ) && $download['permission_id'] ) {
- $this->set_id( absint( $download['permission_id'] ) );
- $this->set_props( $download );
+ } elseif ( is_object( $download ) && ! empty( $download->permission_id ) ) {
+ $this->set_id( $download->permission_id );
+ $this->set_props( (array) $download );
$this->set_object_read( true );
} else {
$this->set_object_read( true );
diff --git a/includes/class-wc-data-store.php b/includes/class-wc-data-store.php
index a74c8efeb4e..7753d3ba951 100644
--- a/includes/class-wc-data-store.php
+++ b/includes/class-wc-data-store.php
@@ -30,7 +30,7 @@ class WC_Data_Store {
private $stores = array(
'coupon' => 'WC_Coupon_Data_Store_CPT',
'customer' => 'WC_Customer_Data_Store',
- 'customer-download' => 'WC_Customer_Download_Data_Store_Session',
+ 'customer-download' => 'WC_Customer_Download_Data_Store',
'customer-session' => 'WC_Customer_Data_Store_Session',
'order' => 'WC_Order_Data_Store_CPT',
'order-refund' => 'WC_Order_Refund_Data_Store_CPT',
diff --git a/includes/class-wc-download-handler.php b/includes/class-wc-download-handler.php
index f734b9aa924..3db7caa5176 100644
--- a/includes/class-wc-download-handler.php
+++ b/includes/class-wc-download-handler.php
@@ -41,7 +41,7 @@ class WC_Download_Handler {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
- $download_ids = $data_store->get_download_ids( array(
+ $download_ids = $data_store->get_downloads( array(
'user_email' => sanitize_email( str_replace( ' ', '+', $_GET['email'] ) ),
'order_key' => wc_clean( $_GET['order'] ),
'product_id' => $product_id,
@@ -49,6 +49,7 @@ class WC_Download_Handler {
'orderby' => 'downloads_remaining',
'order' => 'DESC',
'limit' => 1,
+ 'return' => 'ids',
) );
if ( empty( $download_ids ) ) {
diff --git a/includes/class-wc-order-item-product.php b/includes/class-wc-order-item-product.php
index 6b1805a2a6a..6f62bb1a456 100644
--- a/includes/class-wc-order-item-product.php
+++ b/includes/class-wc-order-item-product.php
@@ -188,10 +188,11 @@ class WC_Order_Item_Product extends WC_Order_Item {
if ( $product && $order && $product->is_downloadable() && $order->is_download_permitted() ) {
$data_store = WC_Data_Store::load( 'customer-download' );
- $download_ids = $data_store->get_download_ids( array(
+ $download_ids = $data_store->get_downloads( array(
'user_email' => $order->get_billing_email(),
'order_key' => $order->get_order_key(),
'product_id' => $this->get_variation_id() ? $this->get_variation_id() : $this->get_product_id(),
+ 'return' => 'ids',
) );
foreach ( $download_ids as $download_id ) {
diff --git a/includes/class-wc-post-data.php b/includes/class-wc-post-data.php
index b2527197d59..7d869cdfb75 100644
--- a/includes/class-wc-post-data.php
+++ b/includes/class-wc-post-data.php
@@ -47,6 +47,9 @@ class WC_Post_Data {
add_action( 'untrashed_post', array( __CLASS__, 'untrash_post' ) );
add_action( 'before_delete_post', array( __CLASS__, 'delete_order_items' ) );
add_action( 'before_delete_post', array( __CLASS__, 'delete_order_downloadable_permissions' ) );
+
+ // Download permissions
+ add_action( 'woocommerce_process_product_file_download_paths', array( __CLASS__, 'process_product_file_download_paths' ), 10, 3 );
}
/**
@@ -375,6 +378,32 @@ class WC_Post_Data {
do_action( 'woocommerce_deleted_order_downloadable_permissions', $postid );
}
}
+
+ /**
+ * Update changed downloads.
+ *
+ * @param int $product_id product identifier
+ * @param int $variation_id optional product variation identifier
+ * @param array $downloads newly set files
+ */
+ public static function process_product_file_download_paths( $product_id, $variation_id, $downloads ) {
+ if ( $variation_id ) {
+ $product_id = $variation_id;
+ }
+ $product = wc_get_product( $product_id );
+ $data_store = WC_Data_Store::load( 'customer-download' );
+
+ if ( $downloads ) {
+ foreach ( $downloads as $download ) {
+ $new_hash = md5( $download->get_file() );
+
+ if ( $download->get_previous_hash() && $download->get_previous_hash() !== $new_hash ) {
+ // Update permissions.
+ $data_store->update_download_id( $product_id, $download->get_previous_hash(), $new_hash );
+ }
+ }
+ }
+ }
}
WC_Post_Data::init();
diff --git a/includes/class-wc-product-download.php b/includes/class-wc-product-download.php
index 552e8e7acf4..c05dc07f32c 100644
--- a/includes/class-wc-product-download.php
+++ b/includes/class-wc-product-download.php
@@ -19,9 +19,10 @@ class WC_Product_Download implements ArrayAccess {
* @var array
*/
protected $data = array(
- 'id' => '',
- 'name' => '',
- 'file' => '',
+ 'id' => '',
+ 'name' => '',
+ 'file' => '',
+ 'previous_hash' => '',
);
/**
@@ -122,6 +123,14 @@ class WC_Product_Download implements ArrayAccess {
$this->data['name'] = wc_clean( $value );
}
+ /**
+ * Set previous_hash.
+ * @param string $value
+ */
+ public function set_previous_hash( $value ) {
+ $this->data['previous_hash'] = wc_clean( $value );
+ }
+
/**
* Set file.
* @param string $value
@@ -159,6 +168,14 @@ class WC_Product_Download implements ArrayAccess {
return $this->data['name'];
}
+ /**
+ * Get previous_hash.
+ * @return string
+ */
+ public function get_previous_hash() {
+ return $this->data['previous_hash'];
+ }
+
/**
* Get file.
* @return string
diff --git a/includes/data-stores/class-wc-customer-download-data-store.php b/includes/data-stores/class-wc-customer-download-data-store.php
index dbd22e1dd92..bc69539edf9 100644
--- a/includes/data-stores/class-wc-customer-download-data-store.php
+++ b/includes/data-stores/class-wc-customer-download-data-store.php
@@ -182,22 +182,40 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
return new WC_Customer_Download( $data );
}
+ /**
+ * Get a download object from an order.
+ *
+ * @param int $order_id
+ * @param int $product_id
+ * @param string $download_id
+ * @return WC_Customer_Download
+ */
+ private function get_download_from_order( $order_id, $product_id, $download_id ) {
+ global $wpdb;
+
+ $raw_download = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d AND product_id = %d AND download_id = %s", $order_id, $product_id, $download_id ) );
+
+ return $raw_download ? new WC_Customer_Download( $raw_download ) : false;
+ }
+
/**
* Get array of download ids by specified args.
*
* @param array $args
- * @return array of WC_Customer_Download
+ * @return array
*/
public function get_downloads( $args = array() ) {
global $wpdb;
$args = wp_parse_args( $args, array(
'user_email' => '',
+ 'order_id' => '',
'order_key' => '',
'product_id' => '',
'orderby' => 'permission_id',
'order' => 'DESC',
'limit' => -1,
+ 'return' => 'objects',
) );
extract( $args );
@@ -209,6 +227,10 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
$query[] = $wpdb->prepare( "AND user_email = %s", $user_email );
}
+ if ( $order_id ) {
+ $query[] = $wpdb->prepare( "AND order_id = %d", $order_id );
+ }
+
if ( $order_key ) {
$query[] = $wpdb->prepare( "AND order_key = %s", $order_key );
}
@@ -221,23 +243,45 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
$order = esc_sql( $order );
$query[] = "ORDER BY {$orderby} {$order}";
- if ( $limit ) {
+ if ( 0 < $limit ) {
$query[] = $wpdb->prepare( "LIMIT %d", $limit );
}
$raw_downloads = $wpdb->get_results( implode( ' ', $query ) );
- return array_map( array( $this, 'get_download' ), $raw_downloads );
+ switch ( $return ) {
+ case 'ids' :
+ return wp_list_pluck( $raw_downloads, 'permission_id' );
+ default :
+ return array_map( array( $this, 'get_download' ), $raw_downloads );
+ }
}
+ /**
+ * Update download ids if the hash changes.
+ *
+ * @param int $product_id
+ * @param string $old_id
+ * @param string $new_idn
+ */
+ public function update_download_id( $product_id, $old_id, $new_id ) {
+ global $wpdb;
- //@todo get_download_ids
-
-
-
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
+ array(
+ 'download_id' => $new_id,
+ ),
+ array(
+ 'download_id' => $old_id,
+ 'product_id' => $product_id,
+ )
+ );
+ }
/**
* Get a customers downloads.
+ *
* @param int $customer_id
* @return array
*/
@@ -265,9 +309,16 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
$customer_id,
date( 'Y-m-d', current_time( 'timestamp' ) )
)
- )
+ );
}
+ /**
+ * Update user prop for downloads based on order id.
+ *
+ * @param int $order_id
+ * @param int $customer_id
+ * @param string $email
+ */
public function update_user_by_order_id( $order_id, $customer_id, $email ) {
global $wpdb;
$wpdb->update( $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
@@ -287,7 +338,4 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
)
);
}
-
-
-
}
diff --git a/includes/data-stores/class-wc-order-data-store-cpt.php b/includes/data-stores/class-wc-order-data-store-cpt.php
index 8b5635295fb..3362fbab41c 100644
--- a/includes/data-stores/class-wc-order-data-store-cpt.php
+++ b/includes/data-stores/class-wc-order-data-store-cpt.php
@@ -249,6 +249,7 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
/**
* Return count of orders with type.
+ *
* @param string $type
* @return int
*/
@@ -324,6 +325,7 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
/**
* Generate meta query for wc_get_orders.
+ *
* @param array $values
* @param string $relation
* @return array
@@ -367,6 +369,7 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
/**
* Get unpaid orders after a certain date,
+ *
* @param int timestamp $date
* @return array
*/
@@ -386,6 +389,7 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
/**
* Search order data for a term and return ids.
+ *
* @param string $term
* @return array of ids
*/
@@ -433,55 +437,121 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
/**
* Gets information about whether permissions were generated yet.
- * @param WC_Order $order
+ *
+ * @param WC_Order|int $order
* @return boolet
*/
public function get_download_permissions_granted( $order ) {
- return wc_string_to_bool( get_post_meta( $order->get_id(), '_download_permissions_granted', true ) );
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ return wc_string_to_bool( get_post_meta( $order_id, '_download_permissions_granted', true ) );
}
/**
* Stores information about whether permissions were generated yet.
- * @param WC_Order $order
+ *
+ * @param WC_Order|int $order
* @param bool $set
*/
public function set_download_permissions_granted( $order, $set ) {
- update_post_meta( $order->get_id(), '_download_permissions_granted', wc_bool_to_string( $set ) );
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ update_post_meta( $order_id, '_download_permissions_granted', wc_bool_to_string( $set ) );
}
/**
* Gets information about whether sales were recorded.
- * @param WC_Order $order
+ *
+ * @param WC_Order|int $order
* @return boolet
*/
public function get_recorded_sales( $order ) {
- return wc_string_to_bool( get_post_meta( $order->get_id(), '_recorded_sales', true ) );
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ return wc_string_to_bool( get_post_meta( $order_id, '_recorded_sales', true ) );
}
/**
* Stores information about whether sales were recorded.
- * @param WC_Order $order
+ *
+ * @param WC_Order|int $order
* @param bool $set
*/
public function set_recorded_sales( $order, $set ) {
- update_post_meta( $order->get_id(), '_recorded_sales', wc_bool_to_string( $set ) );
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ update_post_meta( $order_id, '_recorded_sales', wc_bool_to_string( $set ) );
}
/**
* Gets information about whether coupon counts were updated.
- * @param WC_Order $order
+ *
+ * @param WC_Order|int $order
* @return boolet
*/
public function get_recorded_coupon_usage_counts( $order ) {
- return wc_string_to_bool( get_post_meta( $order->get_id(), '_recorded_sales', true ) );
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ return wc_string_to_bool( get_post_meta( $order_id, '_recorded_sales', true ) );
}
/**
* Stores information about whether coupon counts were updated.
- * @param WC_Order $order
+ *
+ * @param WC_Order|int $order
* @param bool $set
*/
public function set_recorded_coupon_usage_counts( $order, $set ) {
- update_post_meta( $order->get_id(), '_recorded_sales', wc_bool_to_string( $set ) );
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ update_post_meta( $order_id, '_recorded_sales', wc_bool_to_string( $set ) );
+ }
+
+ /**
+ * Gets information about whether stock was reduced.
+ *
+ * @param WC_Order|int $order
+ * @return boolet
+ */
+ public function get_stock_reduced( $order ) {
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ return wc_string_to_bool( get_post_meta( $order_id, '_order_stock_reduced', true ) );
+ }
+
+ /**
+ * Stores information about whether stock was reduced.
+ *
+ * @param WC_Order|int $order
+ * @param bool $set
+ */
+ public function set_stock_reduced( $order, $set ) {
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ } else {
+ $order_id = $order;
+ }
+ update_post_meta( $order_id, '_order_stock_reduced', wc_bool_to_string( $set ) );
}
}
diff --git a/includes/data-stores/class-wc-product-data-store-cpt.php b/includes/data-stores/class-wc-product-data-store-cpt.php
index 825ec2dbffb..cb128db41d6 100644
--- a/includes/data-stores/class-wc-product-data-store-cpt.php
+++ b/includes/data-stores/class-wc-product-data-store-cpt.php
@@ -320,7 +320,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_CPT implements WC_Object_D
'_download_expiry' => 'download_expiry',
'_featured' => 'featured',
'_thumbnail_id' => 'image_id',
- '_downloadable_files' => 'downloads',
'_stock' => 'stock_quantity',
'_stock_status' => 'stock_status',
'_wc_average_rating' => 'average_rating',
@@ -344,15 +343,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_CPT implements WC_Object_D
case 'gallery_image_ids' :
$updated = update_post_meta( $product->get_id(), $meta_key, implode( ',', $value ) );
break;
- case 'downloads' :
- // grant permission to any newly added files on any existing orders for this product prior to saving.
- if ( $product->is_type( 'variation' ) ) {
- do_action( 'woocommerce_process_product_file_download_paths', $product->get_parent_id(), $product->get_id(), $value );
- } else {
- do_action( 'woocommerce_process_product_file_download_paths', $product->get_id(), 0, $value );
- }
- $updated = update_post_meta( $product->get_id(), $meta_key, $value );
- break;
case 'image_id' :
if ( ! empty( $value ) ) {
set_post_thumbnail( $product->get_id(), $value );
@@ -477,6 +467,13 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_CPT implements WC_Object_D
$meta_values[ $key ] = $download->get_data();
}
}
+
+ if ( $product->is_type( 'variation' ) ) {
+ do_action( 'woocommerce_process_product_file_download_paths', $product->get_parent_id(), $product->get_id(), $downloads );
+ } else {
+ do_action( 'woocommerce_process_product_file_download_paths', $product->get_id(), 0, $downloads );
+ }
+
update_post_meta( $product->get_id(), '_downloadable_files', $meta_values );
}
diff --git a/includes/data-stores/interfaces/wc-customer-download-data-store-interface.php b/includes/data-stores/interfaces/wc-customer-download-data-store-interface.php
index 6c402281da2..010da8f1878 100644
--- a/includes/data-stores/interfaces/wc-customer-download-data-store-interface.php
+++ b/includes/data-stores/interfaces/wc-customer-download-data-store-interface.php
@@ -11,4 +11,59 @@ if ( ! defined( 'ABSPATH' ) ) {
* @author WooThemes
*/
interface WC_Customer_Download_Data_Store_Interface {
+
+ /**
+ * Method to delete a download permission from the database by ID.
+ *
+ * @param int $id
+ */
+ public function delete_by_id( $id );
+
+ /**
+ * Method to delete a download permission from the database by order ID.
+ *
+ * @param int $id
+ */
+ public function delete_by_order_id( $id );
+
+ /**
+ * Method to delete a download permission from the database by download ID.
+ *
+ * @param int $id
+ */
+ public function delete_by_download_id( $id );
+
+ /**
+ * Get array of download ids by specified args.
+ *
+ * @param array $args
+ * @return array of WC_Customer_Download
+ */
+ public function get_downloads( $args = array() );
+
+ /**
+ * Update download ids if the hash changes.
+ *
+ * @param int $product_id
+ * @param string $old_id
+ * @param string $new_idn
+ */
+ public function update_download_id( $product_id, $old_id, $new_id );
+
+ /**
+ * Get a customers downloads.
+ *
+ * @param int $customer_id
+ * @return array
+ */
+ public function get_downloads_for_customer( $customer_id );
+
+ /**
+ * Update user prop for downloads based on order id.
+ *
+ * @param int $order_id
+ * @param int $customer_id
+ * @param string $email
+ */
+ public function update_user_by_order_id( $order_id, $customer_id, $email );
}
diff --git a/includes/wc-order-functions.php b/includes/wc-order-functions.php
index 38321e5e4d5..2c243b9b2c8 100644
--- a/includes/wc-order-functions.php
+++ b/includes/wc-order-functions.php
@@ -364,7 +364,7 @@ function wc_downloadable_file_permission( $download_id, $product, $order, $qty =
$download->set_product_id( $product->get_id() );
$download->set_user_id( $order->get_customer_id() );
$download->set_order_id( $order->get_id() );
- $download->set_user_email();
+ $download->set_user_email( $order->get_billing_email() );
$download->set_order_key( $order->get_order_key() );
$download->set_downloads_remaining( 0 > $product->get_download_limit() ? '' : $product->get_download_limit() * $qty );
$download->set_access_granted( current_time( 'timestamp' ) );
diff --git a/includes/wc-stock-functions.php b/includes/wc-stock-functions.php
index 8798aa4824d..ee7025dc43d 100644
--- a/includes/wc-stock-functions.php
+++ b/includes/wc-stock-functions.php
@@ -29,15 +29,13 @@ function wc_update_product_stock( $product, $stock_quantity = null, $operation =
if ( ! is_null( $stock_quantity ) && $product->managing_stock() ) {
// Some products (variations) can have their stock managed by their parent. Get the correct ID to reduce here.
$product_id_with_stock = $product->get_stock_managed_by_id();
- $product_with_stock = $product->get_id() !== $product_id_with_stock ? wc_get_product( $product_id_with_stock ) : $product;
-
- $data_store = WC_Data_Store::load( 'product' );
+ $data_store = WC_Data_Store::load( 'product' );
$data_store->update_product_stock( $product_id_with_stock, $stock_quantity, $operation );
delete_transient( 'wc_low_stock_count' );
delete_transient( 'wc_outofstock_count' );
// Re-read product data after updating stock, then have stock status calculated and saved.
- $product_with_stock = wc_get_product( $product_with_stock->get_id() );
+ $product_with_stock = wc_get_product( $product_id_with_stock );
$product_with_stock->set_stock_status();
$product_with_stock->save();
@@ -68,9 +66,10 @@ function wc_update_product_stock_status( $product_id, $status ) {
* @param int $order_id
*/
function wc_maybe_reduce_stock_levels( $order_id ) {
- if ( apply_filters( 'woocommerce_payment_complete_reduce_order_stock', ! get_post_meta( $order_id, '_order_stock_reduced', true ), $order_id ) ) {
+ $data_store = WC_Data_Store::load( 'order' );
+ if ( apply_filters( 'woocommerce_payment_complete_reduce_order_stock', ! $data_store->get_stock_reduced( $order_id ), $order_id ) ) {
wc_reduce_stock_levels( $order_id );
- add_post_meta( $order_id, '_order_stock_reduced', '1', true );
+ $data_store->set_stock_reduced( $order_id, true );
}
}
add_action( 'woocommerce_payment_complete', 'wc_maybe_reduce_stock_levels' );
@@ -88,7 +87,7 @@ function wc_reduce_stock_levels( $order_id ) {
if ( $item->is_type( 'line_item' ) && ( $product = $item->get_product() ) && $product->managing_stock() ) {
$qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item );
$item_name = $product->get_formatted_name();
- $new_stock = wc_update_product_stock( $product, $qty, 'subtract' );
+ $new_stock = wc_update_product_stock( $product, $qty, 'decrease' );
if ( ! is_wp_error( $new_stock ) ) {
/* translators: 1: item name 2: old stock quantity 3: new stock quantity */
diff --git a/readme.txt b/readme.txt
index 2db2dc5bed9..66193c8b739 100644
--- a/readme.txt
+++ b/readme.txt
@@ -189,8 +189,7 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woocommerce/wo
* CRUD - Optimised variable product sync. Upper/lower price meta is no longer stored, just the main prices, if a child has weight, and if a child has dimensions.
* CRUD - Removed WP_Query from up-sells.php and related.php and replaced with PHP foreach loop (since we already have the product IDs).
-* CRUD - Optimised variable product sync. Upper/lower price meta is no longer stored, just the main prices, if a child has weight, and if a child has dimensions.
-* CRUD - Removed WP_Query from up-sells.php and related.php and replaced with PHP foreach loop (since we already have the product IDs).
+* Performance - Removed the feature where old orders get access to new downloads on product edit. Looping potentially thousands of orders to do this is too much of a performance burden for stores and this can sometimes be unexpected behavior too. This does however updates *edited* downloads.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce/master/CHANGELOG.txt).