Bypass scheduled actions for customer updates (#37265)
* Bypass scheduler for customer update * Handle case when wc_last_active user meta doesn't exist at all * Bypass scheduler for wc_last_active customer update * Bypass scheduler for delete_user and remove_user_from_blog * Bypass scheduler for woocommerce_privacy_remove_order_personal_data * Bypass scheduler for woocommerce_new_customer * Remove obsolete test for last_active_update sync * Remove assertions for pending wc-admin_import_customers
This commit is contained in:
parent
9ea8b630ee
commit
ffc5b911ee
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: performance
|
||||
|
||||
Bypass Action Scheduler for customer updates.
|
|
@ -84,7 +84,19 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
* Set up all the hooks for maintaining and populating table data.
|
||||
*/
|
||||
public static function init() {
|
||||
add_action( 'woocommerce_new_customer', array( __CLASS__, 'update_registered_customer' ) );
|
||||
|
||||
add_action( 'woocommerce_update_customer', array( __CLASS__, 'update_registered_customer' ) );
|
||||
add_action( 'profile_update', array( __CLASS__, 'update_registered_customer' ) );
|
||||
|
||||
add_action( 'added_user_meta', array( __CLASS__, 'update_registered_customer_via_last_active' ), 10, 3 );
|
||||
add_action( 'updated_user_meta', array( __CLASS__, 'update_registered_customer_via_last_active' ), 10, 3 );
|
||||
|
||||
add_action( 'delete_user', array( __CLASS__, 'delete_customer_by_user_id' ) );
|
||||
add_action( 'remove_user_from_blog', array( __CLASS__, 'delete_customer_by_user_id' ) );
|
||||
|
||||
add_action( 'woocommerce_privacy_remove_order_personal_data', array( __CLASS__, 'anonymize_customer' ) );
|
||||
|
||||
add_action( 'woocommerce_analytics_delete_order_stats', array( __CLASS__, 'sync_on_order_delete' ), 15, 2 );
|
||||
}
|
||||
|
||||
|
@ -775,6 +787,20 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the database if the "last active" meta value was changed.
|
||||
* Function expects to be hooked into the `added_user_meta` and `updated_user_meta` actions.
|
||||
*
|
||||
* @param int $meta_id ID of updated metadata entry.
|
||||
* @param int $user_id ID of the user being updated.
|
||||
* @param string $meta_key Meta key being updated.
|
||||
*/
|
||||
public static function update_registered_customer_via_last_active( $meta_id, $user_id, $meta_key ) {
|
||||
if ( 'wc_last_active' === $meta_key ) {
|
||||
self::update_registered_customer( $user_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user ID is a valid customer or other user role with past orders.
|
||||
*
|
||||
|
@ -835,6 +861,11 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
public static function delete_customer_by_user_id( $user_id ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( (int) $user_id < 1 || doing_action( 'wp_uninitialize_site' ) ) {
|
||||
// Skip the deletion.
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = (int) $user_id;
|
||||
$num_deleted = $wpdb->delete( self::get_db_table_name(), array( 'user_id' => $user_id ) );
|
||||
|
||||
|
@ -843,6 +874,59 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize the customer data for a single order.
|
||||
*
|
||||
* @internal
|
||||
* @param int $order_id Order id.
|
||||
* @return void
|
||||
*/
|
||||
public static function anonymize_customer( $order_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$customer_id = $wpdb->get_var(
|
||||
$wpdb->prepare( "SELECT customer_id FROM {$wpdb->prefix}wc_order_stats WHERE order_id = %d", $order_id )
|
||||
);
|
||||
|
||||
if ( ! $customer_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Long form query because $wpdb->update rejects [deleted].
|
||||
$deleted_text = __( '[deleted]', 'woocommerce' );
|
||||
$updated = $wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}wc_customer_lookup
|
||||
SET
|
||||
user_id = NULL,
|
||||
username = %s,
|
||||
first_name = %s,
|
||||
last_name = %s,
|
||||
email = %s,
|
||||
country = '',
|
||||
postcode = %s,
|
||||
city = %s,
|
||||
state = %s
|
||||
WHERE
|
||||
customer_id = %d",
|
||||
array(
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
'deleted@site.invalid',
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
$customer_id,
|
||||
)
|
||||
)
|
||||
);
|
||||
// If the customer row was anonymized, flush the cache.
|
||||
if ( $updated ) {
|
||||
ReportsCache::invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize query objects.
|
||||
*/
|
||||
|
|
|
@ -27,13 +27,6 @@ class CustomersScheduler extends ImportScheduler {
|
|||
* @internal
|
||||
*/
|
||||
public static function init() {
|
||||
add_action( 'woocommerce_new_customer', array( __CLASS__, 'schedule_import' ) );
|
||||
add_action( 'woocommerce_update_customer', array( __CLASS__, 'schedule_import' ) );
|
||||
add_action( 'updated_user_meta', array( __CLASS__, 'schedule_import_via_last_active' ), 10, 3 );
|
||||
add_action( 'woocommerce_privacy_remove_order_personal_data', array( __CLASS__, 'schedule_anonymize' ) );
|
||||
add_action( 'delete_user', array( __CLASS__, 'schedule_user_delete' ) );
|
||||
add_action( 'remove_user_from_blog', array( __CLASS__, 'schedule_user_delete' ) );
|
||||
|
||||
CustomersDataStore::init();
|
||||
parent::init();
|
||||
}
|
||||
|
@ -47,8 +40,6 @@ class CustomersScheduler extends ImportScheduler {
|
|||
public static function get_dependencies() {
|
||||
return array(
|
||||
'delete_batch_init' => OrdersScheduler::get_action( 'delete_batch_init' ),
|
||||
'anonymize' => self::get_action( 'import' ),
|
||||
'delete_user' => self::get_action( 'import' ),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -120,74 +111,6 @@ class CustomersScheduler extends ImportScheduler {
|
|||
return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_customer_lookup" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available scheduling actions.
|
||||
* Used to determine action hook names and clear events.
|
||||
*
|
||||
* @internal
|
||||
* @return array
|
||||
*/
|
||||
public static function get_scheduler_actions() {
|
||||
$actions = parent::get_scheduler_actions();
|
||||
$actions['anonymize'] = 'wc-admin_anonymize_' . static::$name;
|
||||
$actions['delete_user'] = 'wc-admin_delete_user_' . static::$name;
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule import.
|
||||
*
|
||||
* @internal
|
||||
* @param int $user_id User ID.
|
||||
* @return void
|
||||
*/
|
||||
public static function schedule_import( $user_id ) {
|
||||
self::schedule_action( 'import', array( $user_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule an import if the "last active" meta value was changed.
|
||||
* Function expects to be hooked into the `updated_user_meta` action.
|
||||
*
|
||||
* @internal
|
||||
* @param int $meta_id ID of updated metadata entry.
|
||||
* @param int $user_id ID of the user being updated.
|
||||
* @param string $meta_key Meta key being updated.
|
||||
*/
|
||||
public static function schedule_import_via_last_active( $meta_id, $user_id, $meta_key ) {
|
||||
if ( 'wc_last_active' === $meta_key ) {
|
||||
self::schedule_import( $user_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule an action to anonymize a single Order.
|
||||
*
|
||||
* @internal
|
||||
* @param WC_Order $order Order object.
|
||||
* @return void
|
||||
*/
|
||||
public static function schedule_anonymize( $order ) {
|
||||
if ( is_a( $order, 'WC_Order' ) ) {
|
||||
// Postpone until any pending updates are completed.
|
||||
self::schedule_action( 'anonymize', array( $order->get_id() ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule an action to delete a single User.
|
||||
*
|
||||
* @internal
|
||||
* @param int $user_id User ID.
|
||||
* @return void
|
||||
*/
|
||||
public static function schedule_user_delete( $user_id ) {
|
||||
if ( (int) $user_id > 0 && ! doing_action( 'wp_uninitialize_site' ) ) {
|
||||
// Postpone until any pending updates are completed.
|
||||
self::schedule_action( 'delete_user', array( $user_id ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a single customer.
|
||||
*
|
||||
|
@ -220,68 +143,4 @@ class CustomersScheduler extends ImportScheduler {
|
|||
CustomersDataStore::delete_customer( $customer_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize the customer data for a single order.
|
||||
*
|
||||
* @internal
|
||||
* @param int $order_id Order id.
|
||||
* @return void
|
||||
*/
|
||||
public static function anonymize( $order_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$customer_id = $wpdb->get_var(
|
||||
$wpdb->prepare( "SELECT customer_id FROM {$wpdb->prefix}wc_order_stats WHERE order_id = %d", $order_id )
|
||||
);
|
||||
|
||||
if ( ! $customer_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Long form query because $wpdb->update rejects [deleted].
|
||||
$deleted_text = __( '[deleted]', 'woocommerce' );
|
||||
$updated = $wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}wc_customer_lookup
|
||||
SET
|
||||
user_id = NULL,
|
||||
username = %s,
|
||||
first_name = %s,
|
||||
last_name = %s,
|
||||
email = %s,
|
||||
country = '',
|
||||
postcode = %s,
|
||||
city = %s,
|
||||
state = %s
|
||||
WHERE
|
||||
customer_id = %d",
|
||||
array(
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
'deleted@site.invalid',
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
$deleted_text,
|
||||
$customer_id,
|
||||
)
|
||||
)
|
||||
);
|
||||
// If the customer row was anonymized, flush the cache.
|
||||
if ( $updated ) {
|
||||
ReportsCache::invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the customer data for a single user.
|
||||
*
|
||||
* @internal
|
||||
* @param int $user_id User ID.
|
||||
* @return void
|
||||
*/
|
||||
public static function delete_user( $user_id ) {
|
||||
CustomersDataStore::delete_customer_by_user_id( $user_id );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,26 +104,4 @@ class WC_Admin_Tests_API_Init extends WC_REST_Unit_Test_Case {
|
|||
|
||||
$this->assertEmpty( $this->queue->actions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that updating wc_last_active triggers a customer sync.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_other_last_active_update_customer_sync() {
|
||||
// First call creates the meta key.
|
||||
// These don't use wc_update_user_last_active() because the timestamps will be the same.
|
||||
update_user_meta( 1, 'wc_last_active', time() - 10 );
|
||||
// Second call updates it which triggers the sync.
|
||||
update_user_meta( 1, 'wc_last_active', time() );
|
||||
|
||||
$this->assertCount( 1, $this->queue->actions );
|
||||
$this->assertArraySubset(
|
||||
array(
|
||||
'hook' => CustomersScheduler::get_action( 'import' ),
|
||||
'args' => array( 1 ),
|
||||
),
|
||||
$this->queue->actions[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,7 +207,6 @@ class WC_Admin_Tests_API_Reports_Import extends WC_REST_Unit_Test_Case {
|
|||
$pending_actions
|
||||
);
|
||||
$this->assertContains( 'wc-admin_import_orders', $pending_hooks );
|
||||
$this->assertContains( 'wc-admin_import_customers', $pending_hooks );
|
||||
|
||||
// Cancel outstanding actions.
|
||||
$request = new WP_REST_Request( 'POST', $this->endpoint . '/cancel' );
|
||||
|
@ -226,7 +225,6 @@ class WC_Admin_Tests_API_Reports_Import extends WC_REST_Unit_Test_Case {
|
|||
$pending_actions
|
||||
);
|
||||
$this->assertNotContains( 'wc-admin_import_orders', $pending_hooks );
|
||||
$this->assertNotContains( 'wc-admin_import_customers', $pending_hooks );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue