WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru Получай пассивный доход от сайта
класс не описан

Automattic\WooCommerce\Internal\ProductAttributesLookup

DataRegenerator{} WC 1.0

This class handles the (re)generation of the product attributes lookup table. It schedules the regeneration in small product batches by itself, so it can be used outside the regular WooCommerce data regenerations mechanism.

After the regeneration is completed a wp_wc_product_attributes_lookup table will exist with entries for all the products that existed when initiate_regeneration was invoked; entries for products created after that are supposed to be created/updated by the appropriate data store classes (or by the code that uses the data store classes) whenever a product is created/updated.

Additionally, after the regeneration is completed a 'woocommerce_attribute_lookup__enabled' option with a value of 'no' will have been created.

This class also adds two entries to the Status - Tools menu: one for manually regenerating the table contents, and another one for enabling or disabling the actual lookup table usage.

Хуков нет.

Возвращает

null. Ничего.

Использование

$DataRegenerator = new DataRegenerator();
// use class methods

Методы

  1. __construct()
  2. add_initiate_regeneration_entry_to_tools_array( array $tools_array )
  3. delete_all_attributes_lookup_data()
  4. do_regeneration_step()
  5. enable_or_disable_lookup_table_usage( $enable )
  6. enqueue_regeneration_step_run()
  7. finalize_regeneration()
  8. init( LookupDataStore $data_store )
  9. initialize_table_and_data()
  10. initiate_regeneration()
  11. initiate_regeneration_from_tools_page()
  12. lookup_table_exists()
  13. regeneration_is_in_progress()
  14. run_regeneration_step_callback()

Код DataRegenerator{} WC 5.5.2

<?php
class DataRegenerator {

	const PRODUCTS_PER_GENERATION_STEP = 10;

	/**
	 * The data store to use.
	 *
	 * @var LookupDataStore
	 */
	private $data_store;

	/**
	 * The lookup table name.
	 *
	 * @var string
	 */
	private $lookup_table_name;

	/**
	 * DataRegenerator constructor.
	 */
	public function __construct() {
		global $wpdb;

		$this->lookup_table_name = $wpdb->prefix . 'wc_product_attributes_lookup';

		add_filter(
			'woocommerce_debug_tools',
			function( $tools ) {
				return $this->add_initiate_regeneration_entry_to_tools_array( $tools );
			},
			1,
			999
		);

		add_action(
			'woocommerce_run_product_attribute_lookup_update_callback',
			function () {
				$this->run_regeneration_step_callback();
			}
		);
	}

	/**
	 * Class initialization, invoked by the DI container.
	 *
	 * @internal
	 * @param LookupDataStore $data_store The data store to use.
	 */
	final public function init( LookupDataStore $data_store ) {
		$this->data_store = $data_store;
	}

	/**
	 * Initialize the regeneration procedure:
	 * deletes the lookup table and related options if they exist,
	 * then it creates the table and runs the first step of the regeneration process.
	 *
	 * This is the method that should be used as a callback for a data regeneration in wc-update-functions, e.g.:
	 *
	 * function wc_update_XX_regenerate_product_attributes_lookup_table() {
	 *   wc_get_container()->get(DataRegenerator::class)->initiate_regeneration();
	 *   return false;
	 * }
	 *
	 * (Note how we are returning "false" since the class handles the step scheduling by itself).
	 */
	public function initiate_regeneration() {
		$this->delete_all_attributes_lookup_data();
		$products_exist = $this->initialize_table_and_data();
		if ( $products_exist ) {
			$this->enqueue_regeneration_step_run();
		} else {
			$this->finalize_regeneration();
		}
	}

	/**
	 * Tells if a regeneration is already in progress.
	 *
	 * @return bool True if a regeneration is already in progress.
	 */
	public function regeneration_is_in_progress() {
		return ! is_null( get_option( 'woocommerce_attribute_lookup__last_products_page_processed', null ) );
	}

	/**
	 * Delete all the existing data related to the lookup table, including the table itself.
	 *
	 * Shortcut to run this method in case the debug tools UI isn't available or for quick debugging:
	 *
	 * wp eval "wc_get_container()->get(Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator::class)->delete_all_attributes_lookup_data();"
	 */
	public function delete_all_attributes_lookup_data() {
		global $wpdb;

		delete_option( 'woocommerce_attribute_lookup__enabled' );
		delete_option( 'woocommerce_attribute_lookup__last_product_id_to_process' );
		delete_option( 'woocommerce_attribute_lookup__last_products_page_processed' );

		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->lookup_table_name );
	}

	/**
	 * Create the lookup table and initialize the options that will be temporarily used
	 * while the regeneration is in progress.
	 *
	 * @return bool True if there's any product at all in the database, false otherwise.
	 */
	private function initialize_table_and_data() {
		global $wpdb;

		// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
		$wpdb->query(
			'
CREATE TABLE ' . $this->lookup_table_name . '(
  product_id bigint(20) NOT NULL,
  product_or_parent_id bigint(20) NOT NULL,
  taxonomy varchar(32) NOT NULL,
  term_id bigint(20) NOT NULL,
  is_variation_attribute tinyint(1) NOT NULL,
  in_stock tinyint(1) NOT NULL
 );
		'
		);
		// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared

		$last_existing_product_id =
			WC()->call_function(
				'wc_get_products',
				array(
					'return'  => 'ids',
					'limit'   => 1,
					'orderby' => array(
						'ID' => 'DESC',
					),
				)
			);

		if ( ! $last_existing_product_id ) {
			// No products exist, nothing to (re)generate.
			return false;
		}

		update_option( 'woocommerce_attribute_lookup__last_product_id_to_process', current( $last_existing_product_id ) );
		update_option( 'woocommerce_attribute_lookup__last_products_page_processed', 0 );

		return true;
	}

	/**
	 * Action scheduler callback, performs one regeneration step and then
	 * schedules the next step if necessary.
	 */
	private function run_regeneration_step_callback() {
		if ( ! $this->regeneration_is_in_progress() ) {
			return;
		}

		$result = $this->do_regeneration_step();
		if ( $result ) {
			$this->enqueue_regeneration_step_run();
		} else {
			$this->finalize_regeneration();
		}
	}

	/**
	 * Enqueue one regeneration step in action scheduler.
	 */
	private function enqueue_regeneration_step_run() {
		$queue = WC()->get_instance_of( \WC_Queue::class );
		$queue->schedule_single(
			WC()->call_function( 'time' ) + 1,
			'woocommerce_run_product_attribute_lookup_update_callback',
			array(),
			'woocommerce-db-updates'
		);
	}

	/**
	 * Perform one regeneration step: grabs a chunk of products and creates
	 * the appropriate entries for them in the lookup table.
	 *
	 * @return bool True if more steps need to be run, false otherwise.
	 */
	private function do_regeneration_step() {
		$last_products_page_processed = get_option( 'woocommerce_attribute_lookup__last_products_page_processed' );
		$current_products_page        = (int) $last_products_page_processed + 1;

		$product_ids = WC()->call_function(
			'wc_get_products',
			array(
				'limit'   => self::PRODUCTS_PER_GENERATION_STEP,
				'page'    => $current_products_page,
				'orderby' => array(
					'ID' => 'ASC',
				),
				'return'  => 'ids',
			)
		);

		if ( ! $product_ids ) {
			return false;
		}

		foreach ( $product_ids as $id ) {
			$this->data_store->update_data_for_product( $id );
		}

		update_option( 'woocommerce_attribute_lookup__last_products_page_processed', $current_products_page );

		$last_product_id_to_process = get_option( 'woocommerce_attribute_lookup__last_product_id_to_process' );
		return end( $product_ids ) < $last_product_id_to_process;
	}

	/**
	 * Cleanup/final option setup after the regeneration has been completed.
	 */
	private function finalize_regeneration() {
		delete_option( 'woocommerce_attribute_lookup__last_product_id_to_process' );
		delete_option( 'woocommerce_attribute_lookup__last_products_page_processed' );
		update_option( 'woocommerce_attribute_lookup__enabled', 'no' );
	}

	/**
	 * Check if the lookup table exists in the database.
	 *
	 * @return bool True if the lookup table exists in the database.
	 */
	private function lookup_table_exists() {
		global $wpdb;
		$query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $this->lookup_table_name ) );

		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		return $this->lookup_table_name === $wpdb->get_var( $query );
	}

	/**
	 * Add a 'Regenerate product attributes lookup table' entry to the Status - Tools page.
	 *
	 * @param array $tools_array The tool definitions array that is passed ro the woocommerce_debug_tools filter.
	 * @return array The tools array with the entry added.
	 */
	private function add_initiate_regeneration_entry_to_tools_array( array $tools_array ) {
		if ( ! $this->data_store->is_feature_visible() ) {
			return $tools_array;
		}

		$lookup_table_exists       = $this->lookup_table_exists();
		$generation_is_in_progress = $this->regeneration_is_in_progress();

		// Regenerate table.

		if ( $lookup_table_exists ) {
			$generate_item_name   = __( 'Regenerate the product attributes lookup table', 'woocommerce' );
			$generate_item_desc   = __( 'This tool will regenerate the product attributes lookup table data from existing products data. This process may take a while.', 'woocommerce' );
			$generate_item_return = __( 'Product attributes lookup table data is regenerating', 'woocommerce' );
			$generate_item_button = __( 'Regenerate', 'woocommerce' );
		} else {
			$generate_item_name   = __( 'Create and fill product attributes lookup table', 'woocommerce' );
			$generate_item_desc   = __( 'This tool will create the product attributes lookup table data and fill it with existing products data. This process may take a while.', 'woocommerce' );
			$generate_item_return = __( 'Product attributes lookup table is being filled', 'woocommerce' );
			$generate_item_button = __( 'Create', 'woocommerce' );
		}

		$entry = array(
			'name'             => $generate_item_name,
			'desc'             => $generate_item_desc,
			'requires_refresh' => true,
			'callback'         => function() use ( $generate_item_return ) {
				$this->initiate_regeneration_from_tools_page();
				return $generate_item_return;
			},
		);

		if ( $generation_is_in_progress ) {
			$entry['button'] = sprintf(
				/* translators: %d: How many products have been processed so far. */
				__( 'Filling in progress (%d)', 'woocommerce' ),
				get_option( 'woocommerce_attribute_lookup__last_products_page_processed', 0 ) * self::PRODUCTS_PER_GENERATION_STEP
			);
			$entry['disabled'] = true;
		} else {
			$entry['button'] = $generate_item_button;
		}

		$tools_array['regenerate_product_attributes_lookup_table'] = $entry;

		if ( $lookup_table_exists ) {

			// Delete the table.

			$tools_array['delete_product_attributes_lookup_table'] = array(
				'name'             => __( 'Delete the product attributes lookup table', 'woocommerce' ),
				'desc'             => sprintf(
					'<strong class="red">%1$s</strong> %2$s',
					__( 'Note:', 'woocommerce' ),
					__( 'This will delete the product attributes lookup table. You can create it again with the "Create and fill product attributes lookup table" tool.', 'woocommerce' )
				),
				'button'           => __( 'Delete', 'woocommerce' ),
				'requires_refresh' => true,
				'callback'         => function () {
					$this->delete_all_attributes_lookup_data();
					return __( 'Product attributes lookup table has been deleted.', 'woocommerce' );
				},
			);
		}

		if ( $lookup_table_exists && ! $generation_is_in_progress ) {

			// Enable or disable table usage.

			if ( 'yes' === get_option( 'woocommerce_attribute_lookup__enabled' ) ) {
				$tools_array['disable_product_attributes_lookup_table_usage'] = array(
					'name'             => __( 'Disable the product attributes lookup table usage', 'woocommerce' ),
					'desc'             => __( 'The product attributes lookup table usage is currently enabled, use this tool to disable it.', 'woocommerce' ),
					'button'           => __( 'Disable', 'woocommerce' ),
					'requires_refresh' => true,
					'callback'         => function () {
						$this->enable_or_disable_lookup_table_usage( false );
						return __( 'Product attributes lookup table usage has been disabled.', 'woocommerce' );
					},
				);
			} else {
				$tools_array['enable_product_attributes_lookup_table_usage'] = array(
					'name'             => __( 'Enable the product attributes lookup table usage', 'woocommerce' ),
					'desc'             => __( 'The product attributes lookup table usage is currently disabled, use this tool to enable it.', 'woocommerce' ),
					'button'           => __( 'Enable', 'woocommerce' ),
					'requires_refresh' => true,
					'callback'         => function () {
						$this->enable_or_disable_lookup_table_usage( true );
						return __( 'Product attributes lookup table usage has been enabled.', 'woocommerce' );
					},
				);
			}
		}

		return $tools_array;
	}

	/**
	 * Callback to initiate the regeneration process from the Status - Tools page.
	 *
	 * @throws \Exception The regeneration is already in progress.
	 */
	private function initiate_regeneration_from_tools_page() {
		if ( $this->regeneration_is_in_progress() ) {
			throw new \Exception( 'Product attributes lookup table is already regenerating.' );
		}

		$this->initiate_regeneration();
	}

	/**
	 * Enable or disable the actual lookup table usage.
	 *
	 * @param bool $enable True to enable, false to disable.
	 * @throws \Exception A lookup table regeneration is currently in progress.
	 */
	private function enable_or_disable_lookup_table_usage( $enable ) {
		if ( $this->regeneration_is_in_progress() ) {
			throw new \Exception( "Can't enable or disable the attributes lookup table usage while it's regenerating." );
		}

		update_option( 'woocommerce_attribute_lookup__enabled', $enable ? 'yes' : 'no' );
	}
}