Try to account for and re-create backup posts when syncing orders (#45332)

This commit is contained in:
Jorge A. Torres 2024-03-15 08:31:14 -03:00 committed by GitHub
parent 488bb62d82
commit 72cb02ac47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 68 additions and 35 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: fix
Make sure backup posts are restored during sync when HPOS is enabled.

View File

@ -442,7 +442,7 @@ class DataSynchronizer implements BatchProcessorInterface {
*
* @return int
*/
public function get_current_orders_pending_sync_count_cached() : int {
public function get_current_orders_pending_sync_count_cached(): int {
return $this->get_current_orders_pending_sync_count( true );
}
@ -483,14 +483,14 @@ class DataSynchronizer implements BatchProcessorInterface {
return 0;
}
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.PreparedSQL.NotPrepared --
// -- $order_post_type_placeholder, $orders_table, self::PLACEHOLDER_ORDER_POST_TYPE are all safe to use in queries.
if ( ! $this->get_table_exists() ) {
$count = $wpdb->get_var(
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $order_post_type_placeholder is prepared.
$wpdb->prepare(
"SELECT COUNT(*) FROM $wpdb->posts where post_type in ( $order_post_type_placeholder )",
$order_post_types
)
// phpcs:enable
);
return $count;
}
@ -499,30 +499,28 @@ class DataSynchronizer implements BatchProcessorInterface {
$missing_orders_count_sql = $wpdb->prepare(
"
SELECT COUNT(1) FROM $wpdb->posts posts
INNER JOIN $orders_table orders ON posts.id=orders.id
WHERE posts.post_type = '" . self::PLACEHOLDER_ORDER_POST_TYPE . "'
AND orders.status not in ( 'auto-draft' )
RIGHT JOIN $orders_table orders ON posts.ID=orders.id
WHERE (posts.post_type IS NULL OR posts.post_type = '" . self::PLACEHOLDER_ORDER_POST_TYPE . "')
AND orders.status NOT IN ( 'auto-draft' )
AND orders.type IN ($order_post_type_placeholder)",
$order_post_types
);
$operator = '>';
} else {
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $order_post_type_placeholder is prepared.
$missing_orders_count_sql = $wpdb->prepare(
"
SELECT COUNT(1) FROM $wpdb->posts posts
LEFT JOIN $orders_table orders ON posts.id=orders.id
LEFT JOIN $orders_table orders ON posts.ID=orders.id
WHERE
posts.post_type in ($order_post_type_placeholder)
AND posts.post_status != 'auto-draft'
AND orders.id IS NULL",
$order_post_types
);
// phpcs:enable
$operator = '<';
}
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $missing_orders_count_sql is prepared.
$sql = $wpdb->prepare(
"
SELECT(
@ -604,10 +602,9 @@ SELECT(
$order_post_types = wc_get_order_types( 'cot-migration' );
$order_post_type_placeholders = implode( ', ', array_fill( 0, count( $order_post_types ), '%s' ) );
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.PreparedSQL.NotPrepared
switch ( $type ) {
case self::ID_TYPE_MISSING_IN_ORDERS_TABLE:
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $order_post_type_placeholders is prepared.
$sql = $wpdb->prepare(
"
SELECT posts.ID FROM $wpdb->posts posts
@ -619,23 +616,22 @@ WHERE
ORDER BY posts.ID ASC",
$order_post_types
);
// phpcs:enable WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
break;
case self::ID_TYPE_MISSING_IN_POSTS_TABLE:
$sql = $wpdb->prepare(
"
SELECT posts.ID FROM $wpdb->posts posts
INNER JOIN $orders_table orders ON posts.id=orders.id
WHERE posts.post_type = '" . self::PLACEHOLDER_ORDER_POST_TYPE . "'
AND orders.status not in ( 'auto-draft' )
SELECT orders.id FROM $wpdb->posts posts
RIGHT JOIN $orders_table orders ON posts.ID=orders.id
WHERE (posts.post_type IS NULL OR posts.post_type = '" . self::PLACEHOLDER_ORDER_POST_TYPE . "')
AND orders.status NOT IN ( 'auto-draft' )
AND orders.type IN ($order_post_type_placeholders)
ORDER BY posts.id ASC",
ORDER BY posts.ID ASC",
$order_post_types
);
break;
case self::ID_TYPE_DIFFERENT_UPDATE_DATE:
$operator = $this->custom_orders_table_is_authoritative() ? '>' : '<';
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $order_post_type_placeholders is prepared.
$sql = $wpdb->prepare(
"
SELECT orders.id FROM $orders_table orders
@ -647,7 +643,6 @@ ORDER BY orders.id ASC
",
$order_post_types
);
// phpcs:enable
break;
case self::ID_TYPE_DELETED_FROM_ORDERS_TABLE:
return $this->get_deleted_order_ids( true, $limit );
@ -656,7 +651,7 @@ ORDER BY orders.id ASC
default:
throw new \Exception( 'Invalid $type, must be one of the ID_TYPE_... constants.' );
}
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:enable
// phpcs:ignore WordPress.DB
return array_map( 'intval', $wpdb->get_col( $sql . " LIMIT $limit" ) );
@ -701,7 +696,7 @@ ORDER BY orders.id ASC
*
* @param array $batch Batch details.
*/
public function process_batch( array $batch ) : void {
public function process_batch( array $batch ): void {
if ( empty( $batch ) ) {
return;
}

View File

@ -589,11 +589,24 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements
}
self::$backfilling_order_ids[] = $order->get_id();
// Attempt to create the backup post if missing.
if ( $order->get_id() && is_null( get_post( $order->get_id() ) ) ) {
if ( ! $this->maybe_create_backup_post( $order, 'backfill' ) ) {
// translators: %d is an order ID.
$this->error_logger->warning( sprintf( __( 'Unable to create backup post for order %d.', 'woocommerce' ), $order->get_id() ) );
return;
}
}
$this->update_order_meta_from_object( $order );
$order_class = get_class( $order );
$post_order = new $order_class();
$post_order->set_id( $order->get_id() );
$cpt_data_store->read( $post_order );
if ( $cpt_data_store->order_exists( $order->get_id() ) ) {
$cpt_data_store->read( $post_order );
}
// This compares the order data to the post data and set changes array for props that are changed.
$post_order->set_props( $order->get_data() );
@ -1822,20 +1835,10 @@ FROM $order_meta_table
* @since 6.8.0
*/
protected function persist_order_to_db( &$order, bool $force_all_fields = false ) {
$context = ( 0 === absint( $order->get_id() ) ) ? 'create' : 'update';
$data_sync = wc_get_container()->get( DataSynchronizer::class );
$context = ( 0 === absint( $order->get_id() ) ) ? 'create' : 'update';
if ( 'create' === $context ) {
$post_id = wp_insert_post(
array(
'post_type' => $data_sync->data_sync_is_enabled() ? $order->get_type() : $data_sync::PLACEHOLDER_ORDER_POST_TYPE,
'post_status' => 'draft',
'post_parent' => $order->get_changes()['parent_id'] ?? $order->get_data()['parent_id'] ?? 0,
'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
)
);
$post_id = $this->maybe_create_backup_post( $order, 'create' );
if ( ! $post_id ) {
throw new \Exception( esc_html__( 'Could not create order in posts table.', 'woocommerce' ) );
}
@ -1871,6 +1874,37 @@ FROM $order_meta_table
$this->set_custom_taxonomies( $order, $default_taxonomies );
}
/**
* Takes care of creating the backup post in the posts table (placeholder or actual order post, depending on sync settings).
*
* @since 8.8.0
*
* @param \WC_Abstract_Order $order The order.
* @param string $context The context: either 'create' or 'backfill'.
* @return int The new post ID.
*/
protected function maybe_create_backup_post( &$order, string $context ): int {
$data_sync = wc_get_container()->get( DataSynchronizer::class );
$data = array(
'post_type' => $data_sync->data_sync_is_enabled() ? $order->get_type() : $data_sync::PLACEHOLDER_ORDER_POST_TYPE,
'post_status' => 'draft',
'post_parent' => $order->get_changes()['parent_id'] ?? $order->get_data()['parent_id'] ?? 0,
'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
);
if ( 'backfill' === $context ) {
if ( ! $order->get_id() ) {
return 0;
}
$data['import_id'] = $order->get_id();
}
return wp_insert_post( $data );
}
/**
* Set default taxonomies for the order.
*