Automattic\WooCommerce\Internal\ProductAttributesLookup
LookupDataStore::create_data_for_product_cpt_core() │ private │ WC 1.0
Core version of create_data_for_product_cpt (doesn't catch exceptions).
Метод класса: LookupDataStore{}
Хуков нет.
Возвращает
null
. Ничего (null).
Использование
// private - только в коде основоного (родительского) класса $result = $this->create_data_for_product_cpt_core( $product_id );
- $product_id(int) (обязательный)
- Product or variation id.
Код LookupDataStore::create_data_for_product_cpt_core() LookupDataStore::create data for product cpt core WC 9.3.3
private function create_data_for_product_cpt_core( int $product_id ) { global $wpdb; // phpcs:disable WordPress.DB.PreparedSQL $sql = $wpdb->prepare( "delete from {$this->lookup_table_name} where product_or_parent_id=%d", $product_id ); $wpdb->query( $sql ); // phpcs:enable WordPress.DB.PreparedSQL // * Obtain list of product variations, together with stock statuses; also get the product type. // For a variation this will return just one entry, with type 'variation'. // Output: $product_ids_with_stock_status = associative array where 'id' is the key and values are the stock status (1 for "in stock", 0 otherwise). // $variation_ids = raw list of variation ids. // $is_variable_product = true or false. // $is_variation = true or false. $sql = $wpdb->prepare( "(select p.ID as id, null parent, m.meta_value as stock_status, t.name as product_type from {$wpdb->posts} p left join {$wpdb->postmeta} m on p.id=m.post_id and m.meta_key='_stock_status' left join {$wpdb->term_relationships} tr on tr.object_id=p.id left join {$wpdb->term_taxonomy} tt on tt.term_taxonomy_id=tr.term_taxonomy_id left join {$wpdb->terms} t on t.term_id=tt.term_id where p.post_type = 'product' and p.post_status in ('publish', 'draft', 'pending', 'private') and tt.taxonomy='product_type' and t.name != 'exclude-from-search' and p.id=%d limit 1) union (select p.ID as id, p.post_parent as parent, m.meta_value as stock_status, 'variation' as product_type from {$wpdb->posts} p left join {$wpdb->postmeta} m on p.id=m.post_id and m.meta_key='_stock_status' where p.post_type = 'product_variation' and p.post_status in ('publish', 'draft', 'pending', 'private') and (p.ID=%d or p.post_parent=%d)); ", $product_id, $product_id, $product_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $product_ids_with_stock_status = $wpdb->get_results( $sql, ARRAY_A ); $main_product_row = array_filter( $product_ids_with_stock_status, fn( $item ) => 'variation' !== $item['product_type'] ); $is_variation = empty( $main_product_row ); $main_product_id = $is_variation ? current( $product_ids_with_stock_status )['parent'] : $product_id; $is_variable_product = ! $is_variation && ( 'variable' === current( $main_product_row )['product_type'] ); $product_ids_with_stock_status = ArrayUtil::group_by_column( $product_ids_with_stock_status, 'id', true ); $variation_ids = $is_variation ? array( $product_id ) : array_keys( array_diff_key( $product_ids_with_stock_status, array( $product_id => null ) ) ); $product_ids_with_stock_status = ArrayUtil::select( $product_ids_with_stock_status, 'stock_status' ); $product_ids_with_stock_status = array_map( fn( $item ) => 'instock' === $item ? 1 : 0, $product_ids_with_stock_status ); // * Obtain the list of attributes used for variations and not. // Output: two lists of attribute slugs, all starting with 'pa_'. $sql = $wpdb->prepare( "select meta_value from {$wpdb->postmeta} where post_id=%d and meta_key=%s", $main_product_id, '_product_attributes' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $temp = $wpdb->get_var( $sql ); if ( is_null( $temp ) ) { // The product has no attributes, thus there's no attributes lookup data to generate. return; } // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize $temp = unserialize( $temp ); if ( false === $temp ) { throw new \WC_Data_Exception( 0, 'The product attributes metadata row is not properly serialized' ); } $temp = array_filter( $temp, fn( $item, $slug ) => StringUtil::starts_with( $slug, 'pa_' ) && '' === $item['value'], ARRAY_FILTER_USE_BOTH ); $attributes_not_for_variations = $is_variation || $is_variable_product ? array_keys( array_filter( $temp, fn( $item ) => 0 === $item['is_variation'] ) ) : array_keys( $temp ); // * Obtain the terms used for each attribute. // Output: $terms_used_per_attribute = // [ // 'pa_...' => [ // [ // 'term_id' => <term id>, // 'attribute' => 'pa_...' // 'slug' => <term slug> // ],... // ],... // ] $sql = $wpdb->prepare( "select tt.term_id, tt.taxonomy as attribute, t.slug from {$wpdb->prefix}term_relationships tr join {$wpdb->term_taxonomy} tt on tt.term_taxonomy_id = tr.term_taxonomy_id join {$wpdb->terms} t on t.term_id=tt.term_id where tr.object_id=%d and taxonomy like %s;", $main_product_id, 'pa_%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $terms_used_per_attribute = $wpdb->get_results( $sql, ARRAY_A ); foreach ( $terms_used_per_attribute as &$term ) { $term['attribute'] = strtolower( rawurlencode( $term['attribute'] ) ); } $terms_used_per_attribute = ArrayUtil::group_by_column( $terms_used_per_attribute, 'attribute' ); // * Obtain the actual variations defined (only if variations exist). // Output: $variations_defined = // [ // <variation id> => [ // [ // 'variation_id' => <variation id>, // 'attribute' => 'pa_...' // 'slug' => <term slug> // ],... // ],... // ] // // Note that this does NOT include "any..." attributes! if ( ! $is_variation && ( ! $is_variable_product || empty( $variation_ids ) ) ) { $variations_defined = array(); } else { $sql = $wpdb->prepare( "select post_id as variation_id, substr(meta_key,11) as attribute, meta_value as slug from {$wpdb->postmeta} where post_id in (select ID from {$wpdb->posts} where (id=%d or post_parent=%d) and post_type = 'product_variation') and meta_key like %s and meta_value != ''", $product_id, $product_id, 'attribute_pa_%' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $variations_defined = $wpdb->get_results( $sql, ARRAY_A ); $variations_defined = ArrayUtil::group_by_column( $variations_defined, 'variation_id' ); } // Now we'll fill an array with all the data rows to be inserted in the lookup table. $insert_data = array(); // * Insert data for the main product if ( ! $is_variation ) { foreach ( $attributes_not_for_variations as $attribute_name ) { foreach ( ( $terms_used_per_attribute[ $attribute_name ] ?? array() ) as $attribute_data ) { $insert_data[] = array( $product_id, $main_product_id, $attribute_name, $attribute_data['term_id'], 0, $product_ids_with_stock_status[ $product_id ] ); } } } // * Insert data for the variations defined // Remove the non-variation attributes data first. $terms_used_per_attribute = array_diff_key( $terms_used_per_attribute, array_flip( $attributes_not_for_variations ) ); $used_attributes_per_variation = array(); foreach ( $variations_defined as $variation_id => $variation_data ) { $used_attributes_per_variation[ $variation_id ] = array(); foreach ( $variation_data as $variation_attribute_data ) { $attribute_name = $variation_attribute_data['attribute']; $used_attributes_per_variation[ $variation_id ][] = $attribute_name; $term_id = current( array_filter( ( $terms_used_per_attribute[ $attribute_name ] ?? array() ), fn( $item ) => $item['slug'] === $variation_attribute_data['slug'] ) )['term_id'] ?? null; if ( is_null( $term_id ) ) { continue; } $insert_data[] = array( $variation_id, $main_product_id, $attribute_name, $term_id, 1, $product_ids_with_stock_status[ $variation_id ] ?? false ); } } // * Insert data for variations that have "any..." attributes and at least one defined attribute foreach ( $used_attributes_per_variation as $variation_id => $attributes_list ) { $any_attributes = array_diff_key( $terms_used_per_attribute, array_flip( $attributes_list ) ); foreach ( $any_attributes as $attributes_data ) { foreach ( $attributes_data as $attribute_data ) { $insert_data[] = array( $variation_id, $main_product_id, $attribute_data['attribute'], $attribute_data['term_id'], 1, $product_ids_with_stock_status[ $variation_id ] ?? false ); } } } // * Insert data for variations that have all their attributes defined as "any..." $variations_with_all_any = array_keys( array_diff_key( array_flip( $variation_ids ), $used_attributes_per_variation ) ); foreach ( $variations_with_all_any as $variation_id ) { foreach ( $terms_used_per_attribute as $attribute_name => $attribute_terms ) { foreach ( $attribute_terms as $attribute_term ) { $insert_data[] = array( $variation_id, $main_product_id, $attribute_name, $attribute_term['term_id'], 1, $product_ids_with_stock_status[ $variation_id ] ?? false ); } } } // * We have all the data to insert, let's go and insert it. $insert_data_chunks = array_chunk( $insert_data, 100 ); foreach ( $insert_data_chunks as $insert_data_chunk ) { $sql = 'INSERT INTO ' . $this->lookup_table_name . ' ( product_id, product_or_parent_id, taxonomy, term_id, is_variation_attribute, in_stock) VALUES ('; $values_strings = array(); foreach ( $insert_data_chunk as $dataset ) { $attribute_name = esc_sql( $dataset[2] ); $values_strings[] = "{$dataset[0]},{$dataset[1]},'{$attribute_name}',{$dataset[3]},{$dataset[4]},{$dataset[5]}"; } $sql .= implode( '),(', $values_strings ) . ')'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $result = $wpdb->query( $sql ); if ( false === $result ) { throw new \WC_Data_Exception( 0, 'INSERT statement failed', 0, array( 'db_error' => esc_html( $wpdb->last_error ), 'db_query' => esc_html( $wpdb->last_query ), ) ); } } }