Move the download permissions adjustment process to a scheduled action.
Also, move all the new code from the 'WC_Product_Data_Store_CPT' class to a new separate 'DownloadPermissionsAdjuster' class.
This commit is contained in:
parent
8944792a69
commit
f0b834d1ec
|
@ -8,6 +8,7 @@
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Internal\DownloadPermissionsAdjuster;
|
||||
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||
|
||||
/**
|
||||
|
@ -202,6 +203,8 @@ final class WooCommerce {
|
|||
add_action( 'switch_blog', array( $this, 'wpdb_table_fix' ), 0 );
|
||||
add_action( 'activated_plugin', array( $this, 'activated_plugin' ) );
|
||||
add_action( 'deactivated_plugin', array( $this, 'deactivated_plugin' ) );
|
||||
|
||||
DownloadPermissionsAdjuster::init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\DownloadPermissionsAdjuster;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
@ -19,23 +20,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
*/
|
||||
class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface, WC_Product_Data_Store_Interface {
|
||||
|
||||
/**
|
||||
* Instance of the downloads data store.
|
||||
*
|
||||
* @var WC_Data_Store
|
||||
*/
|
||||
private $downloads_data_store;
|
||||
|
||||
/**
|
||||
* WC_Product_Data_Store_CPT constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( is_callable( 'parent::__construct' ) ) {
|
||||
parent::__construct();
|
||||
}
|
||||
$this->downloads_data_store = WC_Data_Store::load( 'customer-download' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data stored in meta keys, but not considered "meta".
|
||||
*
|
||||
|
@ -281,102 +265,16 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
$this->update_version_and_type( $product );
|
||||
$this->handle_updated_props( $product );
|
||||
$this->clear_caches( $product );
|
||||
$this->maybe_adjust_download_permissions( $product );
|
||||
|
||||
wc_get_container()
|
||||
->get( DownloadPermissionsAdjuster::class )
|
||||
->maybe_schedule_adjust_download_permissions( $product );
|
||||
|
||||
$product->apply_changes();
|
||||
|
||||
do_action( 'woocommerce_update_product', $product->get_id(), $product );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create additional download permissions for variations if necessary.
|
||||
*
|
||||
* When a simple downloadable product is converted to a variable product,
|
||||
* existing download permissions are still present in the database but they don't apply anymore.
|
||||
* This method creates additional download permissions for the variations based on
|
||||
* the old existing ones for the main product.
|
||||
*
|
||||
* The procedure is as follows. For each existing download permission for the parent product,
|
||||
* check if there's any variation offering the same file for download (the file URL, not name, is checked).
|
||||
* If that is found, check if an equivalent permission exists (equivalent means for the same file and with
|
||||
* the same order id and customer id). If no equivalent permission exists, create it.
|
||||
*
|
||||
* @param WC_Product $product The product to check permissions for.
|
||||
*/
|
||||
private function maybe_adjust_download_permissions( WC_Product $product ) {
|
||||
$children_ids = $product->get_children();
|
||||
if ( ! $children_ids ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parent_downloads = $this->get_download_files_and_permissions( $product );
|
||||
if ( ! $parent_downloads ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$children_with_downloads = array();
|
||||
foreach ( $children_ids as $child_id ) {
|
||||
$child = wc_get_product( $child_id );
|
||||
$children_with_downloads[ $child_id ] = $this->get_download_files_and_permissions( $child );
|
||||
}
|
||||
|
||||
foreach ( $parent_downloads['permission_data_by_file_order_user'] as $parent_file_order_and_user => $parent_download_data ) {
|
||||
foreach ( $children_with_downloads as $child_id => $child_download_data ) {
|
||||
$file_url = $parent_download_data['file'];
|
||||
|
||||
$must_create_permission =
|
||||
// The variation offers the same file as the parent for download...
|
||||
in_array( $file_url, array_keys( $child_download_data['download_ids_by_file_url'] ), true ) &&
|
||||
// ...but no equivalent download permission (same file URL, order id and user id) exists.
|
||||
! array_key_exists( $parent_file_order_and_user, $child_download_data['permission_data_by_file_order_user'] );
|
||||
|
||||
if ( $must_create_permission ) {
|
||||
// The new child download permission is a copy of the parent's,
|
||||
// but with the product and download ids changed to match those of the variation.
|
||||
$new_download_data = $parent_download_data['data'];
|
||||
$new_download_data['product_id'] = $child_id;
|
||||
$new_download_data['download_id'] = $child_download_data['download_ids_by_file_url'][ $file_url ];
|
||||
$this->downloads_data_store->create_from_data( $new_download_data );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the existing downloadable files and download permissions for a given product.
|
||||
* The returned value is an array with two keys:
|
||||
*
|
||||
* - download_ids_by_file_url: an associative array of file url => download_id.
|
||||
* - permission_data_by_file_order_user: an associative array where key is "file_url:customer_id:order_id" and value is the full permission data set.
|
||||
*
|
||||
* @param WC_Product $product The product to get the downloadable files and permissions for.
|
||||
* @return array[] Information about the downloadable files and permissions for the product.
|
||||
*/
|
||||
private function get_download_files_and_permissions( WC_Product $product ) {
|
||||
$result = array(
|
||||
'permission_data_by_file_order_user' => array(),
|
||||
'download_ids_by_file_url' => array(),
|
||||
);
|
||||
|
||||
$downloads = $product->get_downloads();
|
||||
foreach ( $downloads as $download ) {
|
||||
$result['download_ids_by_file_url'][ $download->get_file() ] = $download->get_id();
|
||||
}
|
||||
|
||||
$permissions = $this->downloads_data_store->get_downloads( array( 'product_id' => $product->get_id() ) );
|
||||
foreach ( $permissions as $permission ) {
|
||||
$permission_data = (array) $permission->data;
|
||||
$file = $downloads[ $permission_data['download_id'] ]->get_file();
|
||||
$data = array(
|
||||
'file' => $file,
|
||||
'data' => (array) $permission->data,
|
||||
);
|
||||
$result['permission_data_by_file_order_user'][ "${file}:${permission_data['user_id']}:${permission_data['order_id']}" ] = $data;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to delete a product from the database.
|
||||
*
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
|
||||
namespace Automattic\WooCommerce;
|
||||
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\ProxiesServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\ExtendedContainer;
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\DownloadPermissionsAdjusterServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\ProxiesServiceProvider;
|
||||
|
||||
/**
|
||||
* PSR11 compliant dependency injection container for WooCommerce.
|
||||
|
@ -33,6 +34,7 @@ final class Container implements \Psr\Container\ContainerInterface {
|
|||
*/
|
||||
private $service_providers = array(
|
||||
ProxiesServiceProvider::class,
|
||||
DownloadPermissionsAdjusterServiceProvider::class,
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* DownloadPermissionsAdjusterServiceProvider class file.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
|
||||
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\DownloadPermissionsAdjuster;
|
||||
|
||||
/**
|
||||
* Service provider for the DownloadPermissionsAdjuster class.
|
||||
*/
|
||||
class DownloadPermissionsAdjusterServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The classes/interfaces that are serviced by this service provider.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = array(
|
||||
DownloadPermissionsAdjuster::class,
|
||||
);
|
||||
|
||||
/**
|
||||
* Register the classes.
|
||||
*/
|
||||
public function register() {
|
||||
$this->share( DownloadPermissionsAdjuster::class );
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Proxies class file.
|
||||
* ProxiesServiceProvider class file.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
/**
|
||||
* DownloadPermissionsAdjuster class file.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Internal;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class to adjust download permissions on product save.
|
||||
*/
|
||||
final class DownloadPermissionsAdjuster {
|
||||
|
||||
/**
|
||||
* @var WC_Data_Store
|
||||
*/
|
||||
private $downloads_data_store;
|
||||
|
||||
/**
|
||||
* Class initialization, to be executed when the class is resolved by the container.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->downloads_data_store = WC()->get_instance_of( \WC_Data_Store::class, 'customer-download');
|
||||
add_action('adjust_download_permissions', array($this, 'adjust_download_permissions'), 10, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the hooks used by this class.
|
||||
*/
|
||||
public static function init_hooks()
|
||||
{
|
||||
add_action('adjust_download_permissions', array(wc_get_container()->get(self::class), 'adjust_download_permissions'), 10, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a download permissions adjustment for a product if necessary.
|
||||
* This should be executed whenever a product is saved.
|
||||
*
|
||||
* @param \WC_Product $product The product to schedule a download permission adjustments for.
|
||||
*/
|
||||
public function maybe_schedule_adjust_download_permissions( \WC_Product $product ) {
|
||||
$children_ids = $product->get_children();
|
||||
if (!$children_ids) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scheduled_action_args = array( $product->get_id() );
|
||||
|
||||
$already_scheduled_actions = as_get_scheduled_actions(
|
||||
array(
|
||||
'hook' => 'adjust_download_permissions',
|
||||
'args' => $scheduled_action_args,
|
||||
'status' => \ActionScheduler_Store::STATUS_PENDING
|
||||
)
|
||||
);
|
||||
|
||||
if(empty($already_scheduled_actions)) {
|
||||
as_schedule_single_action(time() + 1, 'adjust_download_permissions', $scheduled_action_args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create additional download permissions for variations if necessary.
|
||||
*
|
||||
* When a simple downloadable product is converted to a variable product,
|
||||
* existing download permissions are still present in the database but they don't apply anymore.
|
||||
* This method creates additional download permissions for the variations based on
|
||||
* the old existing ones for the main product.
|
||||
*
|
||||
* The procedure is as follows. For each existing download permission for the parent product,
|
||||
* check if there's any variation offering the same file for download (the file URL, not name, is checked).
|
||||
* If that is found, check if an equivalent permission exists (equivalent means for the same file and with
|
||||
* the same order id and customer id). If no equivalent permission exists, create it.
|
||||
*
|
||||
* @param int $product_id The id of the product to check permissions for.
|
||||
*/
|
||||
public function adjust_download_permissions( int $product_id ) {
|
||||
$product = wc_get_product( $product_id );
|
||||
|
||||
$children_ids = $product->get_children();
|
||||
if (!$children_ids) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parent_downloads = $this->get_download_files_and_permissions($product);
|
||||
if (!$parent_downloads) {
|
||||
return;
|
||||
}
|
||||
|
||||
$children_with_downloads = array();
|
||||
foreach ( $children_ids as $child_id ) {
|
||||
$child = wc_get_product( $child_id );
|
||||
$children_with_downloads[ $child_id ] = $this->get_download_files_and_permissions( $child );
|
||||
}
|
||||
|
||||
foreach ( $parent_downloads['permission_data_by_file_order_user'] as $parent_file_order_and_user => $parent_download_data ) {
|
||||
foreach ( $children_with_downloads as $child_id => $child_download_data ) {
|
||||
$file_url = $parent_download_data['file'];
|
||||
|
||||
$must_create_permission =
|
||||
// The variation offers the same file as the parent for download...
|
||||
in_array( $file_url, array_keys( $child_download_data['download_ids_by_file_url'] ), true ) &&
|
||||
// ...but no equivalent download permission (same file URL, order id and user id) exists.
|
||||
! array_key_exists( $parent_file_order_and_user, $child_download_data['permission_data_by_file_order_user'] );
|
||||
|
||||
if ( $must_create_permission ) {
|
||||
// The new child download permission is a copy of the parent's,
|
||||
// but with the product and download ids changed to match those of the variation.
|
||||
$new_download_data = $parent_download_data['data'];
|
||||
$new_download_data['product_id'] = $child_id;
|
||||
$new_download_data['download_id'] = $child_download_data['download_ids_by_file_url'][ $file_url ];
|
||||
$this->downloads_data_store->create_from_data( $new_download_data );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the existing downloadable files and download permissions for a given product.
|
||||
* The returned value is an array with two keys:
|
||||
*
|
||||
* - download_ids_by_file_url: an associative array of file url => download_id.
|
||||
* - permission_data_by_file_order_user: an associative array where key is "file_url:customer_id:order_id" and value is the full permission data set.
|
||||
*
|
||||
* @param \WC_Product $product The product to get the downloadable files and permissions for.
|
||||
* @return array[] Information about the downloadable files and permissions for the product.
|
||||
*/
|
||||
private function get_download_files_and_permissions( \WC_Product $product ) {
|
||||
$result = array(
|
||||
'permission_data_by_file_order_user' => array(),
|
||||
'download_ids_by_file_url' => array(),
|
||||
);
|
||||
|
||||
$downloads = $product->get_downloads();
|
||||
foreach ( $downloads as $download ) {
|
||||
$result['download_ids_by_file_url'][ $download->get_file() ] = $download->get_id();
|
||||
}
|
||||
|
||||
$permissions = $this->downloads_data_store->get_downloads( array( 'product_id' => $product->get_id() ) );
|
||||
foreach ( $permissions as $permission ) {
|
||||
$permission_data = (array) $permission->data;
|
||||
$file = $downloads[ $permission_data['download_id'] ]->get_file();
|
||||
$data = array(
|
||||
'file' => $file,
|
||||
'data' => (array) $permission->data,
|
||||
);
|
||||
$result['permission_data_by_file_order_user'][ "${file}:${permission_data['user_id']}:${permission_data['order_id']}" ] = $data;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -52,6 +52,11 @@ class LegacyProxy {
|
|||
return $class_name::instance( ...$args );
|
||||
}
|
||||
|
||||
// If the class has a "load" method, use it.
|
||||
if ( method_exists( $class_name, 'load' ) ) {
|
||||
return $class_name::load( ...$args );
|
||||
}
|
||||
|
||||
// Fallback to simply creating a new instance of the class.
|
||||
return new $class_name( ...$args );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue