Merge pull request #32893 from woocommerce/fix/product_attributes_lookup_table_update

Fix: product attributes lookup table not being updated on WooCommerce update and on REST API batch requests
This commit is contained in:
Barry Hughes 2022-05-06 09:58:10 -07:00 committed by GitHub
commit 8000a9b0ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 18 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Product attributes lookup table is now properly updated on WooCommerce upgrade and when using REST API batch endpoints

View File

@ -227,7 +227,7 @@ abstract class WC_REST_Controller extends WP_REST_Controller {
if ( ! empty( $items['create'] ) ) { if ( ! empty( $items['create'] ) ) {
foreach ( $items['create'] as $item ) { foreach ( $items['create'] as $item ) {
$_item = new WP_REST_Request( 'POST' ); $_item = new WP_REST_Request( 'POST', $request->get_route() );
// Default parameters. // Default parameters.
$defaults = array(); $defaults = array();
@ -264,7 +264,7 @@ abstract class WC_REST_Controller extends WP_REST_Controller {
if ( ! empty( $items['update'] ) ) { if ( ! empty( $items['update'] ) ) {
foreach ( $items['update'] as $item ) { foreach ( $items['update'] as $item ) {
$_item = new WP_REST_Request( 'PUT' ); $_item = new WP_REST_Request( 'PUT', $request->get_route() );
$_item->set_body_params( $item ); $_item->set_body_params( $item );
$_response = $this->update_item( $_item ); $_response = $this->update_item( $_item );
@ -291,7 +291,7 @@ abstract class WC_REST_Controller extends WP_REST_Controller {
continue; continue;
} }
$_item = new WP_REST_Request( 'DELETE' ); $_item = new WP_REST_Request( 'DELETE', $request->get_route() );
$_item->set_query_params( $_item->set_query_params(
array( array(
'id' => $id, 'id' => $id,

View File

@ -2358,9 +2358,9 @@ function wc_update_630_create_product_attributes_lookup_table() {
/** /**
* If the table exists and contains data, it was manually created by user before the migration ran. * If the table exists and contains data, it was manually created by user before the migration ran.
* If the table exists but is empty, it was likely created right now via dbDelta, so a table regenerations is needed. * If the table exists but is empty, it was likely created right now via dbDelta, so a table regenerations is needed (unless one is in progress already).
*/ */
if ( ! $data_store->check_lookup_table_exists() || ! $data_store->lookup_table_has_data() ) { if ( ! $data_store->check_lookup_table_exists() || ( ! $data_store->lookup_table_has_data() && ! $data_store->regeneration_is_in_progress() ) ) {
$data_regenerator->initiate_regeneration(); $data_regenerator->initiate_regeneration();
} }

View File

@ -137,7 +137,26 @@ class DataRegenerator {
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$wpdb->query( $this->get_table_creation_sql() ); $wpdb->query( $this->get_table_creation_sql() );
$last_existing_product_id = $last_existing_product_id = $this->get_last_existing_product_id();
if ( ! $last_existing_product_id ) {
// No products exist, nothing to (re)generate.
return false;
}
$this->data_store->set_regeneration_in_progress_flag();
update_option( 'woocommerce_attribute_lookup_last_product_id_to_process', $last_existing_product_id );
update_option( 'woocommerce_attribute_lookup_processed_count', 0 );
return true;
}
/**
* Get the highest existing product id.
*
* @return int|null Highest existing product id, or null if no products exist at all.
*/
private function get_last_existing_product_id(): ?int {
$last_existing_product_id_array =
WC()->call_function( WC()->call_function(
'wc_get_products', 'wc_get_products',
array( array(
@ -149,16 +168,7 @@ class DataRegenerator {
) )
); );
if ( ! $last_existing_product_id ) { return empty( $last_existing_product_id_array ) ? null : current( $last_existing_product_id_array );
// No products exist, nothing to (re)generate.
return false;
}
$this->data_store->set_regeneration_in_progress_flag();
update_option( 'woocommerce_attribute_lookup_last_product_id_to_process', current( $last_existing_product_id ) );
update_option( 'woocommerce_attribute_lookup_processed_count', 0 );
return true;
} }
/** /**
@ -493,12 +503,25 @@ class DataRegenerator {
} }
/** /**
* Run additional setup needed after a clean WooCommerce install finishes. * Run additional setup needed after a WooCommerce install or update finishes.
*/ */
private function run_woocommerce_installed_callback() { private function run_woocommerce_installed_callback() {
// The table must exist at this point (created via dbDelta), but we check just in case. // The table must exist at this point (created via dbDelta), but we check just in case.
if ( $this->data_store->check_lookup_table_exists() ) { if ( ! $this->data_store->check_lookup_table_exists() ) {
return;
}
// If a table regeneration is in progress, leave it alone.
if ( $this->data_store->regeneration_is_in_progress() ) {
return;
}
// If the lookup table has data, or if it's empty because there are no products yet, we're good.
// Otherwise (lookup table is empty but products exist) we need to initiate a regeneration if one isn't already in progress.
if ( $this->data_store->lookup_table_has_data() || ! $this->get_last_existing_product_id() ) {
$this->finalize_regeneration( true ); $this->finalize_regeneration( true );
} else {
$this->initiate_regeneration();
} }
} }
} }

View File

@ -6,6 +6,7 @@
namespace Automattic\WooCommerce\Internal\ProductAttributesLookup; namespace Automattic\WooCommerce\Internal\ProductAttributesLookup;
use Automattic\WooCommerce\Utilities\ArrayUtil; use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
defined( 'ABSPATH' ) || exit; defined( 'ABSPATH' ) || exit;
@ -66,6 +67,15 @@ class LookupDataStore {
1 1
); );
add_action(
'woocommerce_rest_insert_product',
function ( $product_post, $request ) {
$this->on_product_created_or_updated_via_rest_api( $product_post, $request );
},
100,
2
);
add_filter( add_filter(
'woocommerce_get_settings_products', 'woocommerce_get_settings_products',
function ( $settings, $section_id ) { function ( $settings, $section_id ) {
@ -633,6 +643,20 @@ class LookupDataStore {
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
} }
/**
* Handler for the woocommerce_rest_insert_product hook.
* Needed to update the lookup table when the REST API batch insert/update endpoints are used.
*
* @param WP_Post $product The post representing the created or updated product.
* @param \WP_REST_Request $request The REST request that caused the hook to be fired.
* @return void
*/
private function on_product_created_or_updated_via_rest_api( WP_Post $product, \WP_REST_Request $request ): void {
if ( StringUtil::ends_with( $request->get_route(), '/batch' ) ) {
$this->on_product_changed( $product->ID );
}
}
/** /**
* Tells if a lookup table regeneration is currently in progress. * Tells if a lookup table regeneration is currently in progress.
* *