Plugin Updates
This commit is contained in:
@@ -11,7 +11,6 @@ use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
|
||||
use Automattic\WooCommerce\Internal\Features\FeaturesController;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use Automattic\WooCommerce\Utilities\PluginUtil;
|
||||
use ActionScheduler;
|
||||
use WC_Admin_Settings;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
@@ -68,6 +67,13 @@ class CustomOrdersTableController {
|
||||
*/
|
||||
private $data_synchronizer;
|
||||
|
||||
/**
|
||||
* The data cleanup instance to use.
|
||||
*
|
||||
* @var LegacyDataCleanup
|
||||
*/
|
||||
private $data_cleanup;
|
||||
|
||||
/**
|
||||
* The batch processing controller to use.
|
||||
*
|
||||
@@ -116,7 +122,7 @@ class CustomOrdersTableController {
|
||||
private function init_hooks() {
|
||||
self::add_filter( 'woocommerce_order_data_store', array( $this, 'get_orders_data_store' ), 999, 1 );
|
||||
self::add_filter( 'woocommerce_order-refund_data_store', array( $this, 'get_refunds_data_store' ), 999, 1 );
|
||||
self::add_filter( 'woocommerce_debug_tools', array( $this, 'add_initiate_regeneration_entry_to_tools_array' ), 999, 1 );
|
||||
self::add_filter( 'woocommerce_debug_tools', array( $this, 'add_hpos_tools' ), 999 );
|
||||
self::add_filter( 'updated_option', array( $this, 'process_updated_option' ), 999, 3 );
|
||||
self::add_filter( 'pre_update_option', array( $this, 'process_pre_update_option' ), 999, 3 );
|
||||
self::add_action( 'woocommerce_after_register_post_type', array( $this, 'register_post_type_for_order_placeholders' ), 10, 0 );
|
||||
@@ -131,6 +137,7 @@ class CustomOrdersTableController {
|
||||
* @internal
|
||||
* @param OrdersTableDataStore $data_store The data store to use.
|
||||
* @param DataSynchronizer $data_synchronizer The data synchronizer to use.
|
||||
* @param LegacyDataCleanup $data_cleanup The legacy data cleanup instance to use.
|
||||
* @param OrdersTableRefundDataStore $refund_data_store The refund data store to use.
|
||||
* @param BatchProcessingController $batch_processing_controller The batch processing controller to use.
|
||||
* @param FeaturesController $features_controller The features controller instance to use.
|
||||
@@ -141,6 +148,7 @@ class CustomOrdersTableController {
|
||||
final public function init(
|
||||
OrdersTableDataStore $data_store,
|
||||
DataSynchronizer $data_synchronizer,
|
||||
LegacyDataCleanup $data_cleanup,
|
||||
OrdersTableRefundDataStore $refund_data_store,
|
||||
BatchProcessingController $batch_processing_controller,
|
||||
FeaturesController $features_controller,
|
||||
@@ -150,6 +158,7 @@ class CustomOrdersTableController {
|
||||
) {
|
||||
$this->data_store = $data_store;
|
||||
$this->data_synchronizer = $data_synchronizer;
|
||||
$this->data_cleanup = $data_cleanup;
|
||||
$this->batch_processing_controller = $batch_processing_controller;
|
||||
$this->refund_data_store = $refund_data_store;
|
||||
$this->features_controller = $features_controller;
|
||||
@@ -218,11 +227,15 @@ class CustomOrdersTableController {
|
||||
* @param array $tools_array The array of tools to add the tool to.
|
||||
* @return array The updated array of tools-
|
||||
*/
|
||||
private function add_initiate_regeneration_entry_to_tools_array( array $tools_array ): array {
|
||||
private function add_hpos_tools( array $tools_array ): array {
|
||||
if ( ! $this->data_synchronizer->check_orders_table_exists() ) {
|
||||
return $tools_array;
|
||||
}
|
||||
|
||||
// Cleanup tool.
|
||||
$tools_array = array_merge( $tools_array, $this->data_cleanup->get_tools_entries() );
|
||||
|
||||
// Delete HPOS tables tool.
|
||||
if ( $this->custom_orders_table_usage_is_enabled() || $this->data_synchronizer->data_sync_is_enabled() ) {
|
||||
$disabled = true;
|
||||
$message = __( 'This will delete the custom orders tables. The tables can be deleted only if the "High-Performance order storage" is not authoritative and sync is disabled (via Settings > Advanced > Features).', 'woocommerce' );
|
||||
@@ -336,6 +349,7 @@ class CustomOrdersTableController {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->data_cleanup->toggle_flag( false );
|
||||
$this->batch_processing_controller->enqueue_processor( DataSynchronizer::class );
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +281,7 @@ class DataSynchronizer implements BatchProcessorInterface {
|
||||
}
|
||||
|
||||
if ( $this->data_sync_is_enabled() ) {
|
||||
wc_get_container()->get( LegacyDataCleanup::class )->toggle_flag( false );
|
||||
$this->batch_processing_controller->enqueue_processor( self::class );
|
||||
} else {
|
||||
$this->batch_processing_controller->remove_processor( self::class );
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
/**
|
||||
* LegacyDataCleanup class file.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
|
||||
|
||||
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
|
||||
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessorInterface;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* This class handles the background process in charge of cleaning up legacy data for orders when HPOS is authoritative.
|
||||
*/
|
||||
class LegacyDataCleanup implements BatchProcessorInterface {
|
||||
|
||||
use AccessiblePrivateMethods;
|
||||
|
||||
/**
|
||||
* Option name for this feature.
|
||||
*/
|
||||
public const OPTION_NAME = 'woocommerce_hpos_legacy_data_cleanup_in_progress';
|
||||
|
||||
/**
|
||||
* The default number of orders to process per batch.
|
||||
*/
|
||||
private const BATCH_SIZE = 25;
|
||||
|
||||
/**
|
||||
* The batch processing controller to use.
|
||||
*
|
||||
* @var BatchProcessingController
|
||||
*/
|
||||
private $batch_processing;
|
||||
|
||||
/**
|
||||
* The legacy handler to use for the actual cleanup.
|
||||
*
|
||||
* @var LegacyHandler
|
||||
*/
|
||||
private $legacy_handler;
|
||||
|
||||
/**
|
||||
* The data synchronizer object to use.
|
||||
*
|
||||
* @var DataSynchronizer
|
||||
*/
|
||||
private $data_synchronizer;
|
||||
|
||||
/**
|
||||
* Logger object to be used to log events.
|
||||
*
|
||||
* @var \WC_Logger
|
||||
*/
|
||||
private $error_logger;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::add_filter( 'pre_update_option_' . self::OPTION_NAME, array( $this, 'pre_update_option' ), 999, 2 );
|
||||
self::add_action( 'add_option_' . self::OPTION_NAME, array( $this, 'process_added_option' ), 999, 2 );
|
||||
self::add_action( 'update_option_' . self::OPTION_NAME, array( $this, 'process_updated_option' ), 999, 2 );
|
||||
self::add_action( 'delete_option_' . self::OPTION_NAME, array( $this, 'process_deleted_option' ), 999 );
|
||||
self::add_action( 'shutdown', array( $this, 'maybe_reset_state' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class initialization, invoked by the DI container.
|
||||
*
|
||||
* @param BatchProcessingController $batch_processing The batch processing controller to use.
|
||||
* @param LegacyDataHandler $legacy_handler Legacy order data handler instance.
|
||||
* @param DataSynchronizer $data_synchronizer Data synchronizer instance.
|
||||
* @internal
|
||||
*/
|
||||
final public function init( BatchProcessingController $batch_processing, LegacyDataHandler $legacy_handler, DataSynchronizer $data_synchronizer ) {
|
||||
$this->legacy_handler = $legacy_handler;
|
||||
$this->data_synchronizer = $data_synchronizer;
|
||||
$this->batch_processing = $batch_processing;
|
||||
$this->error_logger = wc_get_logger();
|
||||
}
|
||||
|
||||
/**
|
||||
* A user friendly name for this process.
|
||||
*
|
||||
* @return string Name of the process.
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return 'Order legacy data cleanup';
|
||||
}
|
||||
|
||||
/**
|
||||
* A user friendly description for this process.
|
||||
*
|
||||
* @return string Description.
|
||||
*/
|
||||
public function get_description(): string {
|
||||
return 'Cleans up order data from legacy tables.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total number of pending records that require update.
|
||||
*
|
||||
* @return int Number of pending records.
|
||||
*/
|
||||
public function get_total_pending_count(): int {
|
||||
return $this->should_run() ? $this->legacy_handler->count_orders_for_cleanup() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the batch with records that needs to be processed for a given size.
|
||||
*
|
||||
* @param int $size Size of the batch.
|
||||
* @return array Batch of records.
|
||||
*/
|
||||
public function get_next_batch_to_process( int $size ): array {
|
||||
return $this->should_run()
|
||||
? array_map( 'absint', $this->legacy_handler->get_orders_for_cleanup( array(), $size ) )
|
||||
: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process data for current batch.
|
||||
*
|
||||
* @param array $batch Batch details.
|
||||
*/
|
||||
public function process_batch( array $batch ): void {
|
||||
// This is a destructive operation, so check if we need to bail out just in case.
|
||||
if ( ! $this->should_run() ) {
|
||||
$this->toggle_flag( false );
|
||||
return;
|
||||
}
|
||||
|
||||
$batch_failed = true;
|
||||
|
||||
foreach ( $batch as $order_id ) {
|
||||
try {
|
||||
$this->legacy_handler->cleanup_post_data( absint( $order_id ) );
|
||||
$batch_failed = false;
|
||||
} catch ( \Exception $e ) {
|
||||
$this->error_logger->error(
|
||||
sprintf(
|
||||
// translators: %1$d is an order ID, %2$s is an error message.
|
||||
__( 'Order %1$d legacy data could not be cleaned up during batch process. Error: %2$s', 'woocommerce' ),
|
||||
$order_id,
|
||||
$e->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $batch_failed ) {
|
||||
$this->error_logger->error( __( 'Order legacy cleanup failed for an entire batch of orders. Aborting cleanup.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
if ( ! $this->orders_pending() || $batch_failed ) {
|
||||
$this->toggle_flag( false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default batch size to use.
|
||||
*
|
||||
* @return int Default batch size.
|
||||
*/
|
||||
public function get_default_batch_size(): int {
|
||||
return self::BATCH_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the cleanup process can be initiated. Legacy data cleanup requires HPOS to be authoritative and
|
||||
* compatibility mode to be disabled.
|
||||
*
|
||||
* @return boolean TRUE if the cleanup process can be enabled, FALSE otherwise.
|
||||
*/
|
||||
public function can_run() {
|
||||
return $this->data_synchronizer->custom_orders_table_is_authoritative() && ! $this->data_synchronizer->data_sync_is_enabled() && ! $this->batch_processing->is_enqueued( get_class( $this->data_synchronizer ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the cleanup process should run. That is, it must be activated and {@see can_run()} must return TRUE.
|
||||
*
|
||||
* @return boolean TRUE if the cleanup process should be run, FALSE otherwise.
|
||||
*/
|
||||
public function should_run() {
|
||||
return $this->can_run() && $this->is_flag_set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user has initiated the cleanup process.
|
||||
*
|
||||
* @return boolean TRUE if the user has initiated the cleanup process, FALSE otherwise.
|
||||
*/
|
||||
public function is_flag_set() {
|
||||
return 'yes' === get_option( self::OPTION_NAME, 'no' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag that indicates that the cleanup process should be initiated.
|
||||
*
|
||||
* @param boolean $enabled TRUE if the process should be initiated, FALSE if it should be canceled.
|
||||
*/
|
||||
public function toggle_flag( bool $enabled ) {
|
||||
if ( $enabled ) {
|
||||
update_option( self::OPTION_NAME, wc_bool_to_string( $enabled ) );
|
||||
} else {
|
||||
delete_option( self::OPTION_NAME );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array in format required by 'woocommerce_debug_tools' to register the cleanup tool in WC.
|
||||
*
|
||||
* @return array Tools entries to register with WC.
|
||||
*/
|
||||
public function get_tools_entries() {
|
||||
$orders_for_cleanup_exist = ! empty( $this->legacy_handler->get_orders_for_cleanup( array(), 1 ) );
|
||||
$entry_id = $this->is_flag_set() ? 'hpos_legacy_cleanup_cancel' : 'hpos_legacy_cleanup';
|
||||
$entry = array(
|
||||
'name' => __( 'Clean up order data from legacy tables', 'woocommerce' ),
|
||||
'desc' => __( 'This tool will clear the data from legacy order tables in WooCommerce.', 'woocommerce' ),
|
||||
'requires_refresh' => true,
|
||||
'button' => __( 'Clear data', 'woocommerce' ),
|
||||
'disabled' => ! ( $this->can_run() && ( $orders_for_cleanup_exist || $this->is_flag_set() ) ),
|
||||
);
|
||||
|
||||
if ( ! $this->can_run() ) {
|
||||
$entry['desc'] .= '<br />';
|
||||
$entry['desc'] .= sprintf(
|
||||
'<strong class="red">%1$s</strong> %2$s',
|
||||
__( 'Note:', 'woocommerce' ),
|
||||
__( 'Only available when HPOS is authoritative and compatibility mode is disabled.', 'woocommerce' )
|
||||
);
|
||||
} else {
|
||||
if ( $this->is_flag_set() ) {
|
||||
$entry['status_text'] = sprintf(
|
||||
'%1$s %2$s',
|
||||
'<span class="dashicons dashicons-update spin"></span>',
|
||||
__( 'Clearing data...', 'woocommerce' )
|
||||
);
|
||||
$entry['button'] = __( 'Cancel', 'woocommerce' );
|
||||
$entry['callback'] = function() {
|
||||
$this->toggle_flag( false );
|
||||
return __( 'Order legacy data cleanup has been canceled.', 'woocommerce' );
|
||||
};
|
||||
} elseif ( ! $orders_for_cleanup_exist ) {
|
||||
$entry['button'] = __( 'No orders in need of cleanup', 'woocommerce' );
|
||||
} else {
|
||||
$entry['callback'] = function() {
|
||||
$this->toggle_flag( true );
|
||||
return __( 'Order legacy data cleanup process has been started.', 'woocommerce' );
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return array( $entry_id => $entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked onto 'add_option' to enqueue the batch processor (if needed).
|
||||
*
|
||||
* @param string $option Name of the option to add.
|
||||
* @param mixed $value Value of the option.
|
||||
*/
|
||||
private function process_added_option( string $option, $value ) {
|
||||
$this->process_updated_option( false, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked onto 'delete_option' to remove the batch processor.
|
||||
*/
|
||||
private function process_deleted_option() {
|
||||
$this->process_updated_option( false, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked onto 'update_option' to enqueue the batch processor as needed.
|
||||
*
|
||||
* @param mixed $old_value Previous option value.
|
||||
* @param mixed $new_value New option value.
|
||||
*/
|
||||
private function process_updated_option( $old_value, $new_value ) {
|
||||
$enable = wc_string_to_bool( $new_value );
|
||||
|
||||
if ( $enable ) {
|
||||
$this->batch_processing->enqueue_processor( self::class );
|
||||
} else {
|
||||
$this->batch_processing->remove_processor( self::class );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked onto 'pre_update_option' to prevent enabling of the cleanup process when conditions aren't met.
|
||||
*
|
||||
* @param mixed $new_value New option value.
|
||||
* @param mixed $old_value Previous option value.
|
||||
*/
|
||||
private function pre_update_option( $new_value, $old_value ) {
|
||||
return $this->can_run() ? $new_value : 'no';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there are any orders in need of cleanup and cleanup can run.
|
||||
*
|
||||
* @return bool TRUE if there are orders in need of cleanup, FALSE otherwise.
|
||||
*/
|
||||
private function orders_pending() {
|
||||
return ! empty( $this->get_next_batch_to_process( 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked onto 'shutdown' to clean up or set things straight in case of failures (timeouts, etc).
|
||||
*/
|
||||
private function maybe_reset_state() {
|
||||
$is_enqueued = $this->batch_processing->is_enqueued( self::class );
|
||||
$is_flag_set = $this->is_flag_set();
|
||||
|
||||
if ( $is_enqueued xor $is_flag_set ) {
|
||||
$this->toggle_flag( false );
|
||||
$this->batch_processing->remove_processor( self::class );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
|
||||
|
||||
use Automattic\WooCommerce\Database\Migrations\CustomOrderTable\PostsToOrdersMigrationController;
|
||||
use Automattic\WooCommerce\Utilities\ArrayUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
@@ -28,17 +29,26 @@ class LegacyDataHandler {
|
||||
*/
|
||||
private DataSynchronizer $data_synchronizer;
|
||||
|
||||
/**
|
||||
* Instance of the PostsToOrdersMigrationController.
|
||||
*
|
||||
* @var PostsToOrdersMigrationController
|
||||
*/
|
||||
private PostsToOrdersMigrationController $posts_to_cot_migrator;
|
||||
|
||||
/**
|
||||
* Class initialization, invoked by the DI container.
|
||||
*
|
||||
* @param OrdersTableDataStore $data_store HPOS datastore instance to use.
|
||||
* @param DataSynchronizer $data_synchronizer DataSynchronizer instance to use.
|
||||
* @param OrdersTableDataStore $data_store HPOS datastore instance to use.
|
||||
* @param DataSynchronizer $data_synchronizer DataSynchronizer instance to use.
|
||||
* @param PostsToOrdersMigrationController $posts_to_cot_migrator Posts to HPOS migration controller instance to use.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final public function init( OrdersTableDataStore $data_store, DataSynchronizer $data_synchronizer ) {
|
||||
$this->data_store = $data_store;
|
||||
$this->data_synchronizer = $data_synchronizer;
|
||||
final public function init( OrdersTableDataStore $data_store, DataSynchronizer $data_synchronizer, PostsToOrdersMigrationController $posts_to_cot_migrator ) {
|
||||
$this->data_store = $data_store;
|
||||
$this->data_synchronizer = $data_synchronizer;
|
||||
$this->posts_to_cot_migrator = $posts_to_cot_migrator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,10 +161,13 @@ class LegacyDataHandler {
|
||||
throw new \Exception( sprintf( __( 'Data in posts table appears to be more recent than in HPOS tables.', 'woocommerce' ) ) );
|
||||
}
|
||||
|
||||
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->postmeta} WHERE post_id = %d", $order->get_id() ) );
|
||||
foreach ( $meta_ids as $meta_id ) {
|
||||
delete_metadata_by_mid( 'post', $meta_id );
|
||||
}
|
||||
// Delete all metadata.
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"DELETE FROM {$wpdb->postmeta} WHERE post_id = %d",
|
||||
$order->get_id()
|
||||
)
|
||||
);
|
||||
|
||||
// wp_update_post() changes the post modified date, so we do this manually.
|
||||
// Also, we suspect using wp_update_post() could lead to integrations mistakenly updating the entity.
|
||||
@@ -208,7 +221,7 @@ class LegacyDataHandler {
|
||||
$diff = array();
|
||||
|
||||
$hpos_order = $this->get_order_from_datastore( $order_id, 'hpos' );
|
||||
$cpt_order = $this->get_order_from_datastore( $order_id, 'cpt' );
|
||||
$cpt_order = $this->get_order_from_datastore( $order_id, 'posts' );
|
||||
|
||||
if ( $hpos_order->get_type() !== $cpt_order->get_type() ) {
|
||||
$diff['type'] = array( $hpos_order->get_type(), $cpt_order->get_type() );
|
||||
@@ -252,8 +265,9 @@ class LegacyDataHandler {
|
||||
* @since 8.6.0
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param string $data_store_id Datastore to use. Should be either 'hpos' or 'cpt'. Defaults to 'hpos'.
|
||||
* @param string $data_store_id Datastore to use. Should be either 'hpos' or 'posts'. Defaults to 'hpos'.
|
||||
* @return \WC_Order Order instance.
|
||||
* @throws \Exception When an error occurs.
|
||||
*/
|
||||
public function get_order_from_datastore( int $order_id, string $data_store_id = 'hpos' ) {
|
||||
$data_store = ( 'hpos' === $data_store_id ) ? $this->data_store : $this->data_store->get_cpt_data_store_instance();
|
||||
@@ -265,7 +279,14 @@ class LegacyDataHandler {
|
||||
$data_store->prime_caches_for_orders( array( $order_id ), array() );
|
||||
}
|
||||
|
||||
$classname = wc_get_order_type( $data_store->get_order_type( $order_id ) )['class_name'];
|
||||
$order_type = wc_get_order_type( $data_store->get_order_type( $order_id ) );
|
||||
|
||||
if ( ! $order_type ) {
|
||||
// translators: %d is an order ID.
|
||||
throw new \Exception( sprintf( __( '%d is not an order or has an invalid order type.', 'woocommerce' ), $order_id ) );
|
||||
}
|
||||
|
||||
$classname = $order_type['class_name'];
|
||||
$order = new $classname();
|
||||
$order->set_id( $order_id );
|
||||
|
||||
@@ -292,6 +313,38 @@ class LegacyDataHandler {
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backfills an order from/to the CPT or HPOS datastore.
|
||||
*
|
||||
* @since 8.7.0
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param string $source_data_store Datastore to use as source. Should be either 'hpos' or 'posts'.
|
||||
* @param string $destination_data_store Datastore to use as destination. Should be either 'hpos' or 'posts'.
|
||||
* @return void
|
||||
* @throws \Exception When an error occurs.
|
||||
*/
|
||||
public function backfill_order_to_datastore( int $order_id, string $source_data_store, string $destination_data_store ) {
|
||||
$valid_data_stores = array( 'posts', 'hpos' );
|
||||
|
||||
if ( ! in_array( $source_data_store, $valid_data_stores, true ) || ! in_array( $destination_data_store, $valid_data_stores, true ) || $destination_data_store === $source_data_store ) {
|
||||
throw new \Exception( sprintf( 'Invalid datastore arguments: %1$s -> %2$s.', $source_data_store, $destination_data_store ) );
|
||||
}
|
||||
|
||||
$order = $this->get_order_from_datastore( $order_id, $source_data_store );
|
||||
|
||||
switch ( $destination_data_store ) {
|
||||
case 'posts':
|
||||
$order->get_data_store()->backfill_post_record( $order );
|
||||
break;
|
||||
case 'hpos':
|
||||
$this->posts_to_cot_migrator->migrate_orders( array( $order_id ) );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all metadata in an order object as an array.
|
||||
*
|
||||
|
||||
@@ -2550,6 +2550,9 @@ FROM $order_meta_table
|
||||
}
|
||||
|
||||
$this->persist_order_to_db( $order );
|
||||
|
||||
$this->update_order_meta( $order );
|
||||
|
||||
$order->save_meta_data();
|
||||
|
||||
if ( $backfill ) {
|
||||
@@ -2882,6 +2885,8 @@ CREATE TABLE $meta_table (
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_meta( &$object, $meta ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( $this->should_backfill_post_record() && isset( $meta->id ) ) {
|
||||
// Let's get the actual meta key before its deleted for backfilling. We cannot delete just by ID because meta IDs are different in HPOS and posts tables.
|
||||
$db_meta = $this->data_store_meta->get_metadata_by_id( $meta->id );
|
||||
@@ -2896,7 +2901,23 @@ CREATE TABLE $meta_table (
|
||||
|
||||
if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() && isset( $meta->key ) ) {
|
||||
self::$backfilling_order_ids[] = $object->get_id();
|
||||
delete_post_meta( $object->get_id(), $meta->key, $meta->value );
|
||||
if ( is_object( $meta->value ) && '__PHP_Incomplete_Class' === get_class( $meta->value ) ) {
|
||||
$meta_value = maybe_serialize( $meta->value );
|
||||
$wpdb->delete(
|
||||
_get_meta_table( 'post' ),
|
||||
array(
|
||||
'post_id' => $object->get_id(),
|
||||
'meta_key' => $meta->key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
||||
'meta_value' => $meta_value, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
|
||||
),
|
||||
array( '%d', '%s', '%s' )
|
||||
);
|
||||
wp_cache_delete( $object->get_id(), 'post_meta' );
|
||||
$logger = wc_get_container()->get( LegacyProxy::class )->call_function( 'wc_get_logger' );
|
||||
$logger->warning( sprintf( 'encountered an order meta value of type __PHP_Incomplete_Class during `delete_meta` in order with ID %d: "%s"', $object->get_id(), var_export( $meta_value, true ) ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export
|
||||
} else {
|
||||
delete_post_meta( $object->get_id(), $meta->key, $meta->value );
|
||||
}
|
||||
self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user