Commit 1d9de854795 for woocommerce
commit 1d9de8547954e03fda251e7015f5c6ab56b1c063
Author: Jorge A. Torres <jorge.torres@automattic.com>
Date: Wed Sep 23 23:18:28 2026 +0100
Revert "Fix HPOS migration leaving orders without a created date when post_date_gmt is zero" (#68772) (#69025)
diff --git a/plugins/woocommerce/changelog/fix-hpos-migration-zero-gmt-dates b/plugins/woocommerce/changelog/fix-hpos-migration-zero-gmt-dates
deleted file mode 100644
index 0163552b161..00000000000
--- a/plugins/woocommerce/changelog/fix-hpos-migration-zero-gmt-dates
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix orders losing their created date when migrating to HPOS from posts with an empty GMT date.
diff --git a/plugins/woocommerce/changelog/revert-fix-hpos-migration-zero-gmt-dates b/plugins/woocommerce/changelog/revert-fix-hpos-migration-zero-gmt-dates
new file mode 100644
index 00000000000..f1e01c323d0
--- /dev/null
+++ b/plugins/woocommerce/changelog/revert-fix-hpos-migration-zero-gmt-dates
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Revert PR #68772 (HPOS migration zero GMT date fix); unreleased, so no production change.
diff --git a/plugins/woocommerce/includes/class-wc-install.php b/plugins/woocommerce/includes/class-wc-install.php
index d4b6233ce15..24ee797294b 100644
--- a/plugins/woocommerce/includes/class-wc-install.php
+++ b/plugins/woocommerce/includes/class-wc-install.php
@@ -361,7 +361,6 @@ class WC_Install {
'wc_update_11203_normalize_stock_notification_emails',
),
'11.3.0' => array(
- 'wc_update_1130_repair_hpos_order_dates_from_posts',
'wc_update_1130_set_legacy_variation_price_hash_option',
),
);
diff --git a/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php
index 9b602afb4e2..03593403e73 100644
--- a/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php
@@ -153,8 +153,8 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
$order,
array(
'parent_id' => $post_object->post_parent,
- 'date_created' => $this->post_date_to_timestamp( $post_object->post_date_gmt, $post_object->post_date ),
- 'date_modified' => $this->post_date_to_timestamp( $post_object->post_modified_gmt, $post_object->post_modified ),
+ 'date_created' => $this->string_to_timestamp( $post_object->post_date_gmt ),
+ 'date_modified' => $this->string_to_timestamp( $post_object->post_modified_gmt ),
'status' => $post_object->post_status,
)
);
@@ -426,26 +426,6 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
return wc_generate_order_key();
}
- /**
- * Convert a post's GMT datetime to a timestamp, using the local one when the GMT column holds the zero date.
- *
- * WordPress leaves the GMT columns at the zero date for some posts (drafts, imports) and treats the local
- * column as the truth. The HPOS migrator applies the same rule, so both stores read the same date.
- *
- * @since 11.3.0
- *
- * @param string $gmt_date Datetime in GMT, possibly the zero date.
- * @param string $local_date The same datetime in the site timezone.
- * @return int|null
- */
- protected function post_date_to_timestamp( $gmt_date, $local_date ) {
- $timestamp = $this->string_to_timestamp( $gmt_date );
- if ( null === $timestamp && '' !== $local_date && '0000-00-00 00:00:00' !== $local_date ) {
- $timestamp = $this->string_to_timestamp( get_gmt_from_date( $local_date ) );
- }
- return $timestamp;
- }
-
/**
* Read order data. Can be overridden by child classes to load other props.
*
@@ -1001,6 +981,8 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
add_filter( 'wp_insert_post_data', array( $this, 'update_post_modified_data' ), 10, 2 );
$post_data = array(
'ID' => $order->get_id(),
+ '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_status' => $this->get_post_status( $order ),
'post_parent' => $order->get_parent_id(),
'edit_date' => true,
@@ -1009,13 +991,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
'order_modified' => ! is_null( $order->get_date_modified() ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getOffsetTimestamp() ) : '',
'order_modified_gmt' => ! is_null( $order->get_date_modified() ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getTimestamp() ) : '',
);
- // An order with no created date leaves the post's date columns to WordPress, which keeps them unless they are zero too.
- $date_created = $order->get_date_created( 'edit' );
- if ( ! is_null( $date_created ) ) {
- $post_data['post_date'] = gmdate( 'Y-m-d H:i:s', $date_created->getOffsetTimestamp() );
- $post_data['post_date_gmt'] = gmdate( 'Y-m-d H:i:s', $date_created->getTimestamp() );
- }
- $updated = wp_update_post( $post_data );
+ $updated = wp_update_post( $post_data );
remove_filter( 'wp_insert_post_data', array( $this, 'update_post_modified_data' ) );
return $updated;
}
diff --git a/plugins/woocommerce/includes/wc-update-functions.php b/plugins/woocommerce/includes/wc-update-functions.php
index b7d19919e03..26c280f504a 100644
--- a/plugins/woocommerce/includes/wc-update-functions.php
+++ b/plugins/woocommerce/includes/wc-update-functions.php
@@ -4011,167 +4011,6 @@ function wc_update_11203_normalize_stock_notification_emails() {
return false;
}
-/**
- * Give HPOS orders migrated without a created or updated date the dates their posts still hold.
- *
- * Earlier migrations copied a zero post_date_gmt verbatim, so the HPOS row ended up with no created date and the next
- * save stamped it with the current time. Only rows whose date is NULL or the zero date are touched, and only when the
- * order's post has a usable date. Placeholder posts count too: legacy cleanup keeps the date columns when it converts a
- * post, and placeholders created for new HPOS orders carry the order's own date. Repaired orders are dropped from the
- * order caches and queued for the Analytics import, which skipped them while they had no date. Batched, returns true
- * while rows remain.
- *
- * @return bool True to run again.
- */
-function wc_update_1130_repair_hpos_order_dates_from_posts() {
- global $wpdb;
-
- $orders_table = \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore::get_orders_table_name();
- if ( $orders_table !== $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $orders_table ) ) ) {
- return false;
- }
-
- $last_id_option = 'woocommerce_update_1130_last_repaired_order_id';
- $batch_size = 500;
- $zero = '0000-00-00 00:00:00';
- $type_list = array();
- $post_types = array_merge( wc_get_order_types( 'cot-migration' ), array( \Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer::PLACEHOLDER_ORDER_POST_TYPE ) );
- foreach ( $post_types as $post_type ) {
- $escaped = esc_sql( $post_type );
- if ( is_string( $escaped ) ) {
- $type_list[] = "'" . $escaped . "'";
- }
- }
- $type_list = implode( ',', $type_list );
-
- // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table names and the escaped type list cannot be prepared.
- $rows = $wpdb->get_results(
- $wpdb->prepare(
- "SELECT o.id, o.date_created_gmt, o.date_updated_gmt, p.post_date, p.post_date_gmt, p.post_modified, p.post_modified_gmt
- FROM {$orders_table} o
- INNER JOIN {$wpdb->posts} p ON p.ID = o.id AND p.post_type IN ({$type_list})
- WHERE o.id > %d
- AND ( o.date_created_gmt IS NULL OR o.date_created_gmt = %s OR o.date_updated_gmt IS NULL OR o.date_updated_gmt = %s )
- ORDER BY o.id ASC
- LIMIT %d",
- (int) get_option( $last_id_option, 0 ),
- $zero,
- $zero,
- $batch_size
- )
- );
- // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-
- if ( '' !== $wpdb->last_error ) {
- wc_get_logger()->error( sprintf( 'Stopped repairing HPOS order dates: %s', $wpdb->last_error ), array( 'source' => 'wc-updater' ) );
- delete_option( $last_id_option );
- return false;
- }
-
- // The rule WordPress applies to its own posts: the GMT column, or the local one when the GMT one is the zero date.
- $gmt_from_post = function ( $gmt_date, $local_date ) use ( $zero ) {
- if ( $gmt_date && $zero !== $gmt_date ) {
- return $gmt_date;
- }
- if ( ! $local_date || $zero === $local_date ) {
- return null;
- }
- $datetime = date_create( $local_date, wp_timezone() );
- return $datetime ? $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' ) : null;
- };
-
- // Repaired orders leave the caches (a cached object still has no date and would stamp the current time on its next save)
- // and get queued for the Analytics import, which skipped them while they had no date.
- $forget_and_import = function ( array $order_ids ) {
- if ( ! $order_ids ) {
- return;
- }
- wc_get_container()->get( \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore::class )->clear_cached_data( $order_ids );
- $order_cache = wc_get_container()->get( \Automattic\WooCommerce\Caches\OrderCache::class );
- // With Analytics disabled nothing handles the import action, and queueing it would only leave failed actions behind.
- $import_hook = \Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler::get_action( 'import' );
- $import_handled = is_string( $import_hook ) && has_action( $import_hook );
- /**
- * Filters whether Analytics runs its imports inline instead of queueing them.
- *
- * @since 4.0.0
- * @param bool $disable Whether Action Scheduler is bypassed.
- */
- $import_inline = ! get_option( 'schema-ActionScheduler_StoreSchema' ) || apply_filters( 'woocommerce_analytics_disable_action_scheduling', false );
- foreach ( $order_ids as $order_id ) {
- $order_cache->remove( $order_id );
- if ( ! $import_handled ) {
- continue;
- }
- if ( $import_inline ) {
- \Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler::import( $order_id );
- continue;
- }
- // Queued directly: OrdersScheduler::schedule_action() first searches every pending action for a duplicate, which gets
- // slower with each order queued here. A duplicate import only rewrites the same stats row.
- WC()->queue()->schedule_single( time() + 5, $import_hook, array( $order_id ), (string) \Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler::$group );
- }
- };
-
- $repaired_ids = array();
- foreach ( $rows as $row ) {
- $columns = array();
- if ( ! $row->date_created_gmt || $zero === $row->date_created_gmt ) {
- $columns['date_created_gmt'] = $gmt_from_post( $row->post_date_gmt, $row->post_date );
- }
- if ( ! $row->date_updated_gmt || $zero === $row->date_updated_gmt ) {
- $columns['date_updated_gmt'] = $gmt_from_post( $row->post_modified_gmt, $row->post_modified );
- }
- $columns = array_filter( $columns );
- if ( empty( $columns ) ) {
- continue;
- }
- // Each column is written only while it is still empty, so a save that lands between the read and the write wins.
- $assignments = array();
- $values = array();
- foreach ( $columns as $column => $value ) {
- $assignments[] = "{$column} = IF( {$column} IS NULL OR {$column} = %s, %s, {$column} )";
- $values[] = $zero;
- $values[] = $value;
- }
- $values[] = (int) $row->id;
- // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Table and column names are code-defined, values go through prepare().
- $updated = $wpdb->query( $wpdb->prepare( "UPDATE {$orders_table} SET " . implode( ', ', $assignments ) . ' WHERE id = %d', $values ) );
- if ( false === $updated ) {
- wc_get_logger()->error( sprintf( 'Stopped repairing HPOS order dates at order #%d: %s', (int) $row->id, $wpdb->last_error ), array( 'source' => 'wc-updater' ) );
- $forget_and_import( $repaired_ids );
- delete_option( $last_id_option );
- return false;
- }
- // Zero rows means a save or another run filled the dates first, and that writer already took care of the rest.
- if ( $updated > 0 ) {
- $repaired_ids[] = (int) $row->id;
- }
- }
-
- $forget_and_import( $repaired_ids );
-
- if ( count( $rows ) === $batch_size ) {
- // The cursor only ever moves forward: a concurrent run (the queue plus `wp wc update`) may already have saved this id or a
- // later one, and update_option() reports that as false just like a failed write. Without a saved cursor the next run would
- // pick the same rows again, and rows whose post has no date never leave the selection.
- $cursor = (int) end( $rows )->id;
- if ( (int) get_option( $last_id_option, 0 ) < $cursor && ! update_option( $last_id_option, $cursor, false ) ) {
- wp_cache_delete( $last_id_option, 'options' );
- if ( (int) get_option( $last_id_option, 0 ) < $cursor ) {
- wc_get_logger()->error( 'Stopped repairing HPOS order dates: the progress cursor could not be saved.', array( 'source' => 'wc-updater' ) );
- delete_option( $last_id_option );
- return false;
- }
- }
- return true;
- }
-
- delete_option( $last_id_option );
-
- return false;
-}
-
/**
* Persist the legacy variation price hash option for existing stores so get_option returns an explicit value.
*
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 8d4f5a6ce09..bb71ed432d4 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -16546,13 +16546,13 @@ parameters:
-
message: '#^Cannot call method getOffsetTimestamp\(\) on WC_DateTime\|null\.$#'
identifier: method.nonObject
- count: 4
+ count: 5
path: includes/data-stores/abstract-wc-order-data-store-cpt.php
-
message: '#^Cannot call method getTimestamp\(\) on WC_DateTime\|null\.$#'
identifier: method.nonObject
- count: 4
+ count: 5
path: includes/data-stores/abstract-wc-order-data-store-cpt.php
-
@@ -60058,6 +60058,18 @@ parameters:
count: 1
path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
+ -
+ message: '#^Cannot call method getOffsetTimestamp\(\) on WC_DateTime\|null\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
+
+ -
+ message: '#^Cannot call method getTimestamp\(\) on WC_DateTime\|null\.$#'
+ identifier: method.nonObject
+ count: 1
+ path: src/Internal/DataStores/Orders/OrdersTableDataStore.php
+
-
message: '#^Cannot call method get_download_permissions_granted\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
identifier: method.nonObject
diff --git a/plugins/woocommerce/src/Database/Migrations/CustomOrderTable/PostToOrderTableMigrator.php b/plugins/woocommerce/src/Database/Migrations/CustomOrderTable/PostToOrderTableMigrator.php
index 8af67d980f2..f524ce438f5 100644
--- a/plugins/woocommerce/src/Database/Migrations/CustomOrderTable/PostToOrderTableMigrator.php
+++ b/plugins/woocommerce/src/Database/Migrations/CustomOrderTable/PostToOrderTableMigrator.php
@@ -69,18 +69,13 @@ class PostToOrderTableMigrator extends MetaToCustomTableMigrator {
'type' => 'string',
'destination' => 'status',
),
- // WordPress leaves the GMT columns at the zero date for some posts (drafts, imports) and treats the local
- // columns as the truth in that case. Without the fallback such orders arrive here with no date at all, and the
- // next save stamps them with the current time.
'post_date_gmt' => array(
- 'type' => 'date',
- 'destination' => 'date_created_gmt',
- 'fallback_column' => 'post_date',
+ 'type' => 'date',
+ 'destination' => 'date_created_gmt',
),
'post_modified_gmt' => array(
- 'type' => 'date',
- 'destination' => 'date_updated_gmt',
- 'fallback_column' => 'post_modified',
+ 'type' => 'date',
+ 'destination' => 'date_updated_gmt',
),
'post_parent' => array(
'type' => 'int',
diff --git a/plugins/woocommerce/src/Database/Migrations/MetaToCustomTableMigrator.php b/plugins/woocommerce/src/Database/Migrations/MetaToCustomTableMigrator.php
index 2f0f82678f0..597703121cc 100644
--- a/plugins/woocommerce/src/Database/Migrations/MetaToCustomTableMigrator.php
+++ b/plugins/woocommerce/src/Database/Migrations/MetaToCustomTableMigrator.php
@@ -13,11 +13,6 @@ namespace Automattic\WooCommerce\Database\Migrations;
*/
abstract class MetaToCustomTableMigrator extends TableMigrator {
- /**
- * The value MySQL stores for a DATETIME that was never set.
- */
- private const ZERO_DATE = '0000-00-00 00:00:00';
-
/**
* Config for tables being migrated and migrated from. See __construct() for detailed config.
*
@@ -84,7 +79,6 @@ abstract class MetaToCustomTableMigrator extends TableMigrator {
* '$source_column_name_1' => array( // $source_column_name_1 is column name in source table, or a select statement.
* 'type' => 'type of value, could be string/int/date/float.',
* 'destination' => 'name of the column in column name where this data should be inserted in.',
- * 'fallback_column' => 'optional, for the date type only: source column holding the same datetime in the site timezone, used when the source column is empty or the zero date.',
* ),
* '$source_column_name_2' => array(
* ......
@@ -450,11 +444,8 @@ WHERE source.`$source_primary_key_column` IN ( $entity_id_placeholder ) $additio
} else {
$entity_keys[] = "$source_entity_table.$column_name";
}
- if ( isset( $column_schema['fallback_column'] ) ) {
- $entity_keys[] = "$source_entity_table.{$column_schema['fallback_column']}";
- }
}
- $entity_column_string = implode( ', ', array_unique( $entity_keys ) );
+ $entity_column_string = implode( ', ', $entity_keys );
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $source_meta_rel_id_column, $source_destination_rel_id_column etc is escaped for backticks. $where clause and $order_by should already be escaped.
$query = $wpdb->prepare(
"
@@ -545,11 +536,7 @@ WHERE
foreach ( $this->core_column_mapping as $column_name => $schema ) {
$custom_table_column_name = $schema['destination'] ?? $column_name;
$value = $entity->$column_name;
- if ( isset( $schema['fallback_column'] ) && ( null === $value || '' === $value || self::ZERO_DATE === $value ) ) {
- // With nothing to fall back to, the original value is stored as it always was.
- $value = $this->local_date_to_gmt( $entity->{$schema['fallback_column']} ?? null ) ?? $value;
- }
- $value = $this->validate_data( $value, $schema['type'] );
+ $value = $this->validate_data( $value, $schema['type'] );
if ( is_wp_error( $value ) ) {
$error_records[ $entity->primary_key_id ][ $custom_table_column_name ] = $value->get_error_code();
} else {
@@ -668,9 +655,6 @@ WHERE
$source_select_column = isset( $schema['select_clause'] ) ? $schema['select_clause'] : "$source_table.$column_name";
$source_select_clauses[] = "$source_select_column as {$source_table}_{$column_name}";
$destination_select_clauses[] = "$destination_table.{$schema['destination']} as {$destination_table}_{$schema['destination']}";
- if ( isset( $schema['fallback_column'] ) ) {
- $source_select_clauses[] = "$source_table.{$schema['fallback_column']} as {$source_table}_{$schema['fallback_column']}";
- }
}
foreach ( $this->meta_column_mapping as $meta_key => $schema ) {
@@ -882,44 +866,13 @@ WHERE $where_clause
} else {
$row[ $alias ] = ( new \DateTime( "@{$row[ $alias ]}" ) )->format( 'Y-m-d H:i:s' );
}
- if ( self::ZERO_DATE === $row[ $destination_alias ] ) {
- $row[ $destination_alias ] = null;
- }
- }
- if ( 'date' === $schema['type'] ) {
- if ( '' === $row[ $alias ] || self::ZERO_DATE === $row[ $alias ] ) {
- $row[ $alias ] = null;
- }
- if ( null === $row[ $alias ] && isset( $schema['fallback_column'] ) ) {
- $fallback_alias = "{$this->schema_config['source']['entity']['table_name']}_{$schema['fallback_column']}";
- $row[ $alias ] = $this->local_date_to_gmt( $row[ $fallback_alias ] ?? null );
- }
- if ( self::ZERO_DATE === $row[ $destination_alias ] ) {
+ if ( '0000-00-00 00:00:00' === $row[ $destination_alias ] ) {
$row[ $destination_alias ] = null;
}
}
return $row;
}
- /**
- * Convert a datetime string expressed in the site's timezone to its GMT equivalent.
- *
- * Unlike get_gmt_from_date(), an empty, zero or unparsable value yields null rather than the Unix epoch.
- *
- * @param string|null $value Datetime string in the site's timezone.
- * @return string|null GMT datetime string, or null when there is no usable value.
- */
- private function local_date_to_gmt( ?string $value ): ?string {
- if ( null === $value || '' === $value || self::ZERO_DATE === $value ) {
- return null;
- }
- $datetime = date_create( $value, wp_timezone() );
- if ( false === $datetime ) {
- return null;
- }
- return $datetime->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
- }
-
/**
* Helper method to get default value of a type.
*
diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
index 5d481d63b96..ace31dd00ef 100644
--- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
+++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
@@ -2347,18 +2347,13 @@ FROM $order_meta_table
$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_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() ),
);
- // An order with no created date leaves the post dates to WordPress rather than failing the whole sync batch.
- $date_created = $order->get_date_created( 'edit' );
- if ( ! is_null( $date_created ) ) {
- $data['post_date'] = gmdate( 'Y-m-d H:i:s', $date_created->getOffsetTimestamp() );
- $data['post_date_gmt'] = gmdate( 'Y-m-d H:i:s', $date_created->getTimestamp() );
- }
-
if ( 'backfill' === $context ) {
if ( ! $order->get_id() ) {
return 0;
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php
index f4fbe8c3b5e..3ac20437fea 100644
--- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php
@@ -57,52 +57,6 @@ class WC_Order_Data_Store_CPT_Test extends WC_Unit_Test_Case {
parent::tearDown();
}
- /**
- * @testdox Should read the created and modified dates from the local post columns when the GMT ones hold the zero date.
- */
- public function test_read_falls_back_to_local_dates_when_gmt_dates_are_zero(): void {
- global $wpdb;
-
- update_option( 'timezone_string', 'Europe/Amsterdam' );
- $order = OrderHelper::create_order();
- $wpdb->update(
- $wpdb->posts,
- array(
- 'post_date_gmt' => '0000-00-00 00:00:00',
- 'post_modified_gmt' => '0000-00-00 00:00:00',
- ),
- array( 'ID' => $order->get_id() )
- );
- clean_post_cache( $order->get_id() );
- $post = get_post( $order->get_id() );
-
- $read = new WC_Order();
- $read->set_id( $order->get_id() );
- ( new WC_Order_Data_Store_CPT() )->read( $read );
-
- $this->assertSame( get_gmt_from_date( $post->post_date ), $read->get_date_created()->setTimezone( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' ), 'The created date should come from post_date.' );
- $this->assertSame( get_gmt_from_date( $post->post_modified ), $read->get_date_modified()->setTimezone( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' ), 'The modified date should come from post_modified.' );
- }
-
- /**
- * @testdox Should leave the post dates untouched when backfilling an order that has no created date.
- */
- public function test_update_order_from_object_keeps_post_dates_for_order_without_created_date(): void {
- $order = OrderHelper::create_order();
- $before = get_post( $order->get_id() );
- $dateless = new WC_Order();
- $dateless->set_id( $order->get_id() );
- $dateless->set_status( OrderStatus::COMPLETED );
- $dateless->set_date_created( null );
-
- $this->assertNotFalse( ( new WC_Order_Data_Store_CPT() )->update_order_from_object( $dateless ) );
-
- $after = get_post( $order->get_id() );
- $this->assertSame( $before->post_date, $after->post_date, 'post_date should be kept.' );
- $this->assertSame( $before->post_date_gmt, $after->post_date_gmt, 'post_date_gmt should be kept.' );
- $this->assertSame( 'wc-completed', $after->post_status, 'Other fields should still be written.' );
- }
-
/**
* Test that refund cache are invalidated correctly when refund is deleted.
*/
diff --git a/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
index 3a7c144b8f0..3512d225c7a 100644
--- a/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
@@ -5,12 +5,6 @@
* @package WooCommerce\Tests\Functions.
*/
-use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
-use Automattic\WooCommerce\Caches\OrderCache;
-use Automattic\WooCommerce\Utilities\OrderUtil;
-use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper;
-use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
-use Automattic\WooCommerce\Database\Migrations\CustomOrderTable\PostsToOrdersMigrationController;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Admin\Notes\Note;
@@ -27,30 +21,10 @@ use Automattic\WooCommerce\Internal\VariationGallery\Package as VariationGallery
*/
class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
- /**
- * Whether HPOS was authoritative before the test.
- *
- * @var bool
- */
- private $previous_hpos_state;
-
- /**
- * Set up test fixtures.
- */
- public function setUp(): void {
- parent::setUp();
- // Tests that migrate orders leave the two storages out of sync, which would otherwise block restoring the storage setting.
- add_filter( 'wc_allow_changing_orders_storage_while_sync_is_pending', '__return_true' );
- $this->previous_hpos_state = OrderUtil::custom_orders_table_usage_is_enabled();
- OrderHelper::create_order_custom_table_if_not_exist();
- }
-
/**
* Tear down test fixtures.
*/
public function tearDown(): void {
- OrderHelper::toggle_cot_feature_and_usage( $this->previous_hpos_state );
- remove_filter( 'wc_allow_changing_orders_storage_while_sync_is_pending', '__return_true' );
Constants::clear_single_constant( 'WOOCOMMERCE_BIS_ALPHA_ENABLED' );
delete_option( 'woocommerce_feature_customer_stock_notifications_enabled' );
parent::tearDown();
@@ -752,169 +726,6 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
return $variation_id;
}
- /**
- * @testdox wc_update_1130_repair_hpos_order_dates_from_posts should fill HPOS dates that an earlier migration left empty from the order's post.
- */
- public function test_wc_update_1130_repairs_hpos_dates_from_posts(): void {
- global $wpdb;
-
- include_once WC_ABSPATH . 'includes/wc-update-functions.php';
-
- update_option( 'timezone_string', 'Europe/Amsterdam' );
- $order_id = OrderHelper::create_complex_wp_post_order();
- $wpdb->update(
- $wpdb->posts,
- array(
- 'post_date_gmt' => '0000-00-00 00:00:00',
- 'post_modified_gmt' => '0000-00-00 00:00:00',
- ),
- array( 'ID' => $order_id )
- );
- clean_post_cache( $order_id );
- wc_get_container()->get( PostsToOrdersMigrationController::class )->migrate_orders( array( $order_id ) );
- $orders_table = OrdersTableDataStore::get_orders_table_name();
- // The shape earlier migrations left behind.
- $wpdb->update(
- $orders_table,
- array(
- 'date_created_gmt' => '0000-00-00 00:00:00',
- 'date_updated_gmt' => null,
- ),
- array( 'id' => $order_id )
- );
- $post = get_post( $order_id );
-
- // A second order whose legacy data was cleaned up: the post is a placeholder but keeps its date columns.
- $cleaned_id = OrderHelper::create_complex_wp_post_order();
- $wpdb->update( $wpdb->posts, array( 'post_date_gmt' => '0000-00-00 00:00:00' ), array( 'ID' => $cleaned_id ) );
- clean_post_cache( $cleaned_id );
- wc_get_container()->get( PostsToOrdersMigrationController::class )->migrate_orders( array( $cleaned_id ) );
- $wpdb->update( $orders_table, array( 'date_created_gmt' => '0000-00-00 00:00:00' ), array( 'id' => $cleaned_id ) );
- $wpdb->update( $wpdb->posts, array( 'post_type' => DataSynchronizer::PLACEHOLDER_ORDER_POST_TYPE ), array( 'ID' => $cleaned_id ) );
- clean_post_cache( $cleaned_id );
- $cleaned_post = get_post( $cleaned_id );
-
- // A cached order object without a date must not survive the repair.
- $order_cache = wc_get_container()->get( OrderCache::class );
- $order_cache->set( wc_get_order( $order_id ), $order_id );
- // Creating the orders queued their own imports: clear them so the assertion below is about the routine.
- as_unschedule_all_actions( 'wc-admin_import_orders' );
-
- $this->assertFalse( wc_update_1130_repair_hpos_order_dates_from_posts(), 'A single small batch should not request another run' );
-
- $row = $wpdb->get_row( $wpdb->prepare( "SELECT date_created_gmt, date_updated_gmt FROM {$orders_table} WHERE id = %d", $order_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- $this->assertSame( get_gmt_from_date( $post->post_date ), $row->date_created_gmt, 'Created date should come from post_date converted with the site timezone' );
- $this->assertSame( get_gmt_from_date( $post->post_modified ), $row->date_updated_gmt, 'Updated date should come from post_modified' );
- $this->assertNotSame( $post->post_date, $row->date_created_gmt, 'The local date must have been converted' );
- $this->assertSame( get_gmt_from_date( $cleaned_post->post_date ), $wpdb->get_var( $wpdb->prepare( "SELECT date_created_gmt FROM {$orders_table} WHERE id = %d", $cleaned_id ) ), 'A cleaned-up order is repaired from its placeholder post' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- $this->assertFalse( $order_cache->is_cached( $order_id ), 'The cached order object must be dropped' );
- $this->assertNotFalse( as_next_scheduled_action( 'wc-admin_import_orders', array( $order_id ) ), 'The Analytics import must be queued for the repaired order' );
- }
-
- /**
- * @testdox wc_update_1130_repair_hpos_order_dates_from_posts should import repaired orders inline when Analytics scheduling is disabled.
- */
- public function test_wc_update_1130_imports_inline_when_analytics_scheduling_is_disabled(): void {
- global $wpdb;
-
- include_once WC_ABSPATH . 'includes/wc-update-functions.php';
-
- $order_id = OrderHelper::create_complex_wp_post_order();
- wc_get_container()->get( PostsToOrdersMigrationController::class )->migrate_orders( array( $order_id ) );
- $orders_table = OrdersTableDataStore::get_orders_table_name();
- $wpdb->update( $orders_table, array( 'date_created_gmt' => '0000-00-00 00:00:00' ), array( 'id' => $order_id ) );
- OrderHelper::toggle_cot_feature_and_usage( true );
- // Creating the order queued its own import. Start from a clean slate so only the routine's behaviour is measured.
- as_unschedule_all_actions( 'wc-admin_import_orders' );
- $wpdb->delete( $wpdb->prefix . 'wc_order_stats', array( 'order_id' => $order_id ) );
- add_filter( 'woocommerce_analytics_disable_action_scheduling', '__return_true' );
-
- wc_update_1130_repair_hpos_order_dates_from_posts();
-
- $this->assertFalse( as_next_scheduled_action( 'wc-admin_import_orders', array( $order_id ) ), 'Nothing should be queued when scheduling is disabled' );
- $this->assertNotNull( $wpdb->get_var( $wpdb->prepare( "SELECT order_id FROM {$wpdb->prefix}wc_order_stats WHERE order_id = %d", $order_id ) ), 'The order should have been imported inline' );
- }
-
- /**
- * Insert a full batch of HPOS rows with no created date whose posts have no date either, so the repair has to advance its cursor.
- *
- * @return int The id of the last row in the batch.
- */
- private function insert_full_batch_of_unrepairable_orders(): int {
- global $wpdb;
-
- $orders_table = OrdersTableDataStore::get_orders_table_name();
- $first_id = (int) $wpdb->get_var( "SELECT GREATEST( COALESCE( ( SELECT MAX( ID ) FROM {$wpdb->posts} ), 0 ), COALESCE( ( SELECT MAX( id ) FROM {$orders_table} ), 0 ) )" ) + 1; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- $posts = array();
- $orders = array();
- for ( $id = $first_id; $id < $first_id + 500; $id++ ) {
- $posts[] = "( {$id}, 'shop_order', 'wc-completed', '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', '', '', '', '', '', '' )";
- $orders[] = "( {$id}, 'shop_order', 'wc-completed', NULL, '2026-01-01 00:00:00' )";
- }
- // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Generated integers and literals only.
- $wpdb->query( "INSERT INTO {$wpdb->posts} ( ID, post_type, post_status, post_date, post_date_gmt, post_modified, post_modified_gmt, post_content, post_title, post_excerpt, to_ping, pinged, post_content_filtered ) VALUES " . implode( ',', $posts ) );
- $wpdb->query( "INSERT INTO {$orders_table} ( id, type, status, date_created_gmt, date_updated_gmt ) VALUES " . implode( ',', $orders ) );
- // phpcs:enable
-
- return $first_id + 499;
- }
-
- /**
- * @testdox wc_update_1130_repair_hpos_order_dates_from_posts should keep going when another run has already saved the same or a later cursor.
- *
- * @testWith [0]
- * [1000]
- *
- * @param int $ahead How far past this batch the other run has already moved the cursor.
- */
- public function test_wc_update_1130_accepts_a_cursor_saved_by_a_concurrent_run( int $ahead ): void {
- include_once WC_ABSPATH . 'includes/wc-update-functions.php';
-
- $last_id = $this->insert_full_batch_of_unrepairable_orders();
- $option = 'woocommerce_update_1130_last_repaired_order_id';
- $orders_table = OrdersTableDataStore::get_orders_table_name();
- // The other run saves its cursor right after this one has read its batch.
- $concurrent_save = function ( $query ) use ( $option, $last_id, $ahead, $orders_table ) {
- if ( false !== strpos( $query, "FROM {$orders_table} o" ) ) {
- update_option( $option, $last_id + $ahead, false );
- }
- return $query;
- };
- add_filter( 'query', $concurrent_save );
-
- $this->assertTrue( wc_update_1130_repair_hpos_order_dates_from_posts(), 'A cursor saved by another run is progress, not a failure' );
- $this->assertSame( $last_id + $ahead, (int) get_option( $option ), 'The cursor must never move backwards' );
- }
-
- /**
- * @testdox wc_update_1130_repair_hpos_order_dates_from_posts should leave rows alone when they have dates or their post has none.
- */
- public function test_wc_update_1130_leaves_dated_rows_and_dateless_posts_alone(): void {
- global $wpdb;
-
- include_once WC_ABSPATH . 'includes/wc-update-functions.php';
-
- $dated_id = OrderHelper::create_complex_wp_post_order();
- $dateless_id = OrderHelper::create_complex_wp_post_order();
- $wpdb->update(
- $wpdb->posts,
- array(
- 'post_date' => '0000-00-00 00:00:00',
- 'post_date_gmt' => '0000-00-00 00:00:00',
- ),
- array( 'ID' => $dateless_id )
- );
- clean_post_cache( $dateless_id );
- wc_get_container()->get( PostsToOrdersMigrationController::class )->migrate_orders( array( $dated_id, $dateless_id ) );
- $orders_table = OrdersTableDataStore::get_orders_table_name();
- $dated_before = $wpdb->get_var( $wpdb->prepare( "SELECT date_created_gmt FROM {$orders_table} WHERE id = %d", $dated_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-
- $this->assertFalse( wc_update_1130_repair_hpos_order_dates_from_posts() );
-
- $this->assertSame( $dated_before, $wpdb->get_var( $wpdb->prepare( "SELECT date_created_gmt FROM {$orders_table} WHERE id = %d", $dated_id ) ), 'A dated row must not change' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- $this->assertSame( '0000-00-00 00:00:00', $wpdb->get_var( $wpdb->prepare( "SELECT date_created_gmt FROM {$orders_table} WHERE id = %d", $dateless_id ) ), 'A post with no date gives nothing to repair from' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- }
-
/**
* @testdox Migration rewrites stored stock notification emails in canonical form and leaves canonical rows alone.
*/
diff --git a/plugins/woocommerce/tests/php/src/Database/Migrations/CustomOrderTable/PostsToOrdersMigrationControllerTest.php b/plugins/woocommerce/tests/php/src/Database/Migrations/CustomOrderTable/PostsToOrdersMigrationControllerTest.php
index 35c54b87dcf..bbfc038375d 100644
--- a/plugins/woocommerce/tests/php/src/Database/Migrations/CustomOrderTable/PostsToOrdersMigrationControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Database/Migrations/CustomOrderTable/PostsToOrdersMigrationControllerTest.php
@@ -4,7 +4,6 @@ declare( strict_types = 1 );
namespace Automattic\WooCommerce\Tests\Database\Migrations\CustomOrderTable;
use Automattic\WooCommerce\Database\Migrations\CustomOrderTable\PostsToOrdersMigrationController;
-use Automattic\WooCommerce\Database\Migrations\CustomOrderTable\PostToOrderTableMigrator;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper;
@@ -125,72 +124,6 @@ class PostsToOrdersMigrationControllerTest extends \WC_Unit_Test_Case {
$this->assert_metadata_is_migrated( $order );
}
- /**
- * @testdox Should derive the GMT created and modified dates from the local ones when the post holds the zero date in the GMT columns.
- */
- public function test_migration_for_order_with_zero_gmt_dates(): void {
- global $wpdb;
-
- update_option( 'timezone_string', 'Europe/Amsterdam' );
- $order = wc_get_order( OrderHelper::create_complex_wp_post_order() );
- $this->clear_all_orders();
- $wpdb->update(
- $wpdb->posts,
- array(
- 'post_date_gmt' => '0000-00-00 00:00:00',
- 'post_modified_gmt' => '0000-00-00 00:00:00',
- ),
- array( 'ID' => $order->get_id() )
- );
- clean_post_cache( $order->get_id() );
- $post = get_post( $order->get_id() );
-
- $this->sut->migrate_order( $order->get_id() );
-
- $db_order = $this->get_order_from_cot( $order );
- $this->assertEquals( get_gmt_from_date( $post->post_date ), $db_order->date_created_gmt, 'The created date should be derived from post_date.' );
- $this->assertEquals( get_gmt_from_date( $post->post_modified ), $db_order->date_updated_gmt, 'The modified date should be derived from post_modified.' );
- $this->assertNotEquals( $post->post_date, $db_order->date_created_gmt, 'The local date should have been converted to GMT.' );
-
- $migrator = new PostToOrderTableMigrator();
- $this->assertEmpty( $migrator->verify_migrated_data( array( $order->get_id() ) ), 'Verification should accept the derived dates.' );
-
- // A row migrated before the fallback existed still holds the zero date: verification must report it.
- $wpdb->update( $this->data_store::get_orders_table_name(), array( 'date_created_gmt' => '0000-00-00 00:00:00' ), array( 'id' => $order->get_id() ) );
- $failures = $migrator->verify_migrated_data( array( $order->get_id() ) );
- $this->assertSame( 'post_date_gmt', $failures[ $order->get_id() ][0]['column'] ?? null, 'Verification should flag a created date that was not derived.' );
- }
-
- /**
- * @testdox Should keep the zero date when both the GMT and the local columns hold the zero date.
- */
- public function test_migration_for_order_with_zero_gmt_and_local_dates(): void {
- global $wpdb;
-
- $order = wc_get_order( OrderHelper::create_complex_wp_post_order() );
- $this->clear_all_orders();
- $wpdb->update(
- $wpdb->posts,
- array(
- 'post_date' => '0000-00-00 00:00:00',
- 'post_date_gmt' => '0000-00-00 00:00:00',
- 'post_modified' => '0000-00-00 00:00:00',
- 'post_modified_gmt' => '0000-00-00 00:00:00',
- ),
- array( 'ID' => $order->get_id() )
- );
- clean_post_cache( $order->get_id() );
-
- $this->sut->migrate_order( $order->get_id() );
-
- $db_order = $this->get_order_from_cot( $order );
- $this->assertSame( '0000-00-00 00:00:00', $db_order->date_created_gmt, 'With no date to derive the created date from, the zero date is stored as before.' );
- $this->assertSame( '0000-00-00 00:00:00', $db_order->date_updated_gmt, 'With no date to derive the modified date from, the zero date is stored as before.' );
-
- $migrator = new PostToOrderTableMigrator();
- $this->assertEmpty( $migrator->verify_migrated_data( array( $order->get_id() ) ), 'Verification should accept the empty dates.' );
- }
-
/**
* Test that already migrated order isn't migrated twice.
*/
diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
index 877c187b13f..ad4decc7ad4 100644
--- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
+++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
@@ -1478,30 +1478,6 @@ class OrdersTableDataStoreTests extends \HposTestCase {
}
}
- /**
- * @testDox Backfilling an order that has no created date and no post row should create the post instead of failing.
- */
- public function test_backfill_post_record_for_order_without_created_date_or_post() {
- global $wpdb;
- $this->toggle_cot_feature_and_usage( true );
- $this->disable_cot_sync();
- $order = $this->create_complex_cot_order();
- $wpdb->delete( $wpdb->posts, array( 'ID' => $order->get_id() ) );
- $wpdb->update( $this->sut::get_orders_table_name(), array( 'date_created_gmt' => null ), array( 'id' => $order->get_id() ) );
- clean_post_cache( $order->get_id() );
- $this->sut->clear_cached_data( array( $order->get_id() ) );
-
- $dateless = new WC_Order();
- $dateless->set_id( $order->get_id() );
- $this->switch_data_store( $dateless, $this->sut );
- $this->sut->read( $dateless );
- $this->assertNull( $dateless->get_date_created(), 'Precondition: the order has no created date.' );
-
- $this->sut->backfill_post_record( $dateless );
-
- $this->assertInstanceOf( \WP_Post::class, get_post( $order->get_id() ), 'The backup post should exist after the backfill.' );
- }
-
/**
* @testDox Test `get_unpaid_orders()`.
*/
@@ -1582,29 +1558,6 @@ class OrdersTableDataStoreTests extends \HposTestCase {
remove_all_filters( 'woocommerce_hpos_enable_sync_on_read' );
}
- /**
- * @testDox Sync on read should keep the created date when the post's GMT date column holds the zero date.
- */
- public function test_sync_on_read_keeps_created_date_when_post_gmt_date_is_zero() {
- global $wpdb;
- $this->toggle_cot_feature_and_usage( true );
- $this->enable_cot_sync();
- add_filter( 'woocommerce_hpos_enable_sync_on_read', '__return_true' );
- $order = $this->create_complex_cot_order();
- $created = $order->get_date_created()->getTimestamp();
- $wpdb->update( $wpdb->posts, array( 'post_date_gmt' => '0000-00-00 00:00:00' ), array( 'ID' => $order->get_id() ) );
- clean_post_cache( $order->get_id() );
-
- $refreshed_order = new WC_Order();
- $refreshed_order->set_id( $order->get_id() );
- $this->switch_data_store( $refreshed_order, $this->sut );
- $this->sut->read( $refreshed_order );
-
- $this->assertSame( $created, $refreshed_order->get_date_created()->getTimestamp(), 'The posts reader must agree with HPOS, so nothing is copied back.' );
- $this->assertSame( gmdate( 'Y-m-d H:i:s', $created ), $wpdb->get_var( $wpdb->prepare( "SELECT date_created_gmt FROM {$this->sut::get_orders_table_name()} WHERE id = %d", $order->get_id() ) ), 'The HPOS row must keep its date.' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- remove_all_filters( 'woocommerce_hpos_enable_sync_on_read' );
- }
-
/**
* @testDox When there are direct writes to posts data, order should synced upon reading.
*/