plugin updates
This commit is contained in:
@@ -149,10 +149,10 @@ class WC_Customer_Download_Log_Data_Store implements WC_Customer_Download_Log_Da
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of download log ids by specified args.
|
||||
* Get array of download logs, or the count of existing logs, by specified args.
|
||||
*
|
||||
* @param array $args Arguments to define download logs to retrieve.
|
||||
* @return array
|
||||
* @param array $args Arguments to define download logs to retrieve. If $args['return'] is 'count' then the count of existing logs will be returned.
|
||||
* @return array|int
|
||||
*/
|
||||
public function get_download_logs( $args = array() ) {
|
||||
global $wpdb;
|
||||
@@ -171,9 +171,11 @@ class WC_Customer_Download_Log_Data_Store implements WC_Customer_Download_Log_Da
|
||||
)
|
||||
);
|
||||
|
||||
$is_count = 'count' === $args['return'];
|
||||
|
||||
$query = array();
|
||||
$table = $wpdb->prefix . self::get_table_name();
|
||||
$query[] = "SELECT * FROM {$table} WHERE 1=1";
|
||||
$query[] = 'SELECT ' . ( $is_count ? 'COUNT(1)' : '*' ) . " FROM {$table} WHERE 1=1";
|
||||
|
||||
if ( $args['permission_id'] ) {
|
||||
$query[] = $wpdb->prepare( 'AND permission_id = %d', $args['permission_id'] );
|
||||
@@ -197,7 +199,13 @@ class WC_Customer_Download_Log_Data_Store implements WC_Customer_Download_Log_Da
|
||||
$query[] = $wpdb->prepare( 'LIMIT %d, %d', absint( $args['limit'] ) * absint( $args['page'] - 1 ), absint( $args['limit'] ) );
|
||||
}
|
||||
|
||||
$raw_download_logs = $wpdb->get_results( implode( ' ', $query ) ); // WPCS: unprepared SQL ok.
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||
if ( $is_count ) {
|
||||
return absint( $wpdb->get_var( implode( ' ', $query ) ) );
|
||||
}
|
||||
|
||||
$raw_download_logs = $wpdb->get_results( implode( ' ', $query ) );
|
||||
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
switch ( $args['return'] ) {
|
||||
case 'ids':
|
||||
@@ -226,6 +234,26 @@ class WC_Customer_Download_Log_Data_Store implements WC_Customer_Download_Log_Da
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count of download logs for a given download permission.
|
||||
*
|
||||
* @param int $permission_id Permission to get logs count for.
|
||||
* @return int
|
||||
*/
|
||||
public function get_download_logs_count_for_permission( $permission_id ) {
|
||||
// If no permission_id is passed, return an empty array.
|
||||
if ( empty( $permission_id ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this->get_download_logs(
|
||||
array(
|
||||
'permission_id' => $permission_id,
|
||||
'return' => 'count',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to delete download logs for a given permission ID.
|
||||
*
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* @package WooCommerce\Classes
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
@@ -100,6 +102,12 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
|
||||
$order->set_order_key( wc_generate_order_key() );
|
||||
}
|
||||
parent::create( $order );
|
||||
|
||||
// Do not fire 'woocommerce_new_order' for draft statuses.
|
||||
if ( in_array( $order->get_status( 'edit' ), array( 'auto-draft', 'draft', 'checkout-draft' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_new_order', $order->get_id(), $order );
|
||||
}
|
||||
|
||||
@@ -183,22 +191,37 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
|
||||
|
||||
// Also grab the current status so we can compare.
|
||||
$previous_status = get_post_status( $order->get_id() );
|
||||
// If the order doesn't exist in the DB, we will consider it as new.
|
||||
if ( ! $previous_status && $order->get_id() === 0 ) {
|
||||
$previous_status = 'new';
|
||||
}
|
||||
|
||||
// Update the order.
|
||||
parent::update( $order );
|
||||
|
||||
// Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
|
||||
$new_status = $order->get_status( 'edit' );
|
||||
$current_status = $order->get_status( 'edit' );
|
||||
|
||||
if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
|
||||
do_action( 'woocommerce_new_order', $order->get_id(), $order );
|
||||
} else {
|
||||
do_action( 'woocommerce_update_order', $order->get_id(), $order );
|
||||
// We need to remove the wc- prefix from the status for comparison and proper evaluation of new vs updated orders.
|
||||
$previous_status = OrderUtil::remove_status_prefix( $previous_status );
|
||||
$current_status = OrderUtil::remove_status_prefix( $current_status );
|
||||
|
||||
$draft_statuses = array( 'new', 'auto-draft', 'draft', 'checkout-draft' );
|
||||
|
||||
// This hook should be fired only if the new status is not one of draft statuses and the previous status was one of the draft statuses.
|
||||
if (
|
||||
$current_status !== $previous_status
|
||||
&& ! in_array( $current_status, $draft_statuses, true )
|
||||
&& in_array( $previous_status, $draft_statuses, true )
|
||||
) {
|
||||
do_action( 'woocommerce_new_order', $order->get_id(), $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_update_order', $order->get_id(), $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that updates all the post meta for an order based on it's settings in the WC_Order class.
|
||||
* Helper method that updates all the post meta for an order based on its settings in the WC_Order class.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @since 3.0.0
|
||||
@@ -997,6 +1020,40 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
|
||||
* @return array|object
|
||||
*/
|
||||
public function query( $query_vars ) {
|
||||
/**
|
||||
* Allows 3rd parties to filter query args that will trigger an unsupported notice.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @param array $unsupported_args Array of query arg names.
|
||||
*/
|
||||
$unsupported_args = (array) apply_filters(
|
||||
'woocommerce_order_data_store_cpt_query_unsupported_args',
|
||||
array( 'meta_query', 'field_query' )
|
||||
);
|
||||
|
||||
// Trigger doing_it_wrong() for query vars only supported in HPOS.
|
||||
$unsupported_args_in_query = array_keys( array_filter( array_intersect_key( $query_vars, array_flip( $unsupported_args ) ) ) );
|
||||
|
||||
if ( $unsupported_args_in_query && __CLASS__ === get_class( $this ) ) {
|
||||
wc_doing_it_wrong(
|
||||
__METHOD__,
|
||||
esc_html(
|
||||
sprintf(
|
||||
// translators: %s is a comma separated list of query arguments.
|
||||
_n(
|
||||
'Order query argument (%s) is not supported on the current order datastore.',
|
||||
'Order query arguments (%s) are not supported on the current order datastore.',
|
||||
count( $unsupported_args_in_query ),
|
||||
'woocommerce'
|
||||
),
|
||||
implode( ', ', $unsupported_args_in_query )
|
||||
)
|
||||
),
|
||||
'9.2.0'
|
||||
);
|
||||
}
|
||||
|
||||
$args = $this->get_wp_query_args( $query_vars );
|
||||
|
||||
if ( ! empty( $args['errors'] ) ) {
|
||||
|
||||
@@ -29,6 +29,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
protected $internal_meta_keys = array(
|
||||
'_visibility',
|
||||
'_sku',
|
||||
'_global_unique_id',
|
||||
'_price',
|
||||
'_regular_price',
|
||||
'_sale_price',
|
||||
@@ -96,6 +97,46 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
*/
|
||||
protected $updated_props = array();
|
||||
|
||||
|
||||
/**
|
||||
* Method to obtain DB lock on SKU to make sure we only
|
||||
* create product with unique SKU for concurrent requests.
|
||||
*
|
||||
* We are doing so by inserting a row in the wc_product_meta_lookup table
|
||||
* upfront with the SKU of the product we are trying to insert.
|
||||
*
|
||||
* If the SKU is already present in the table, it means that another
|
||||
* request is processing the same SKU and we should not proceed
|
||||
* with the insert.
|
||||
*
|
||||
* Using $wpdb->options as it always has some data, if we select from a table
|
||||
* that does not have any data, then our query will always return null set
|
||||
* and the where subquery won't be fired, effectively bypassing any lock.
|
||||
*
|
||||
* @param WC_Product $product Product object.
|
||||
* @return bool True if lock is obtained (unique SKU), false otherwise.
|
||||
*/
|
||||
private function obtain_lock_on_sku_for_concurrent_requests( $product ) {
|
||||
global $wpdb;
|
||||
$product_id = $product->get_id();
|
||||
$sku = $product->get_sku();
|
||||
|
||||
$query = $wpdb->prepare(
|
||||
"INSERT INTO $wpdb->wc_product_meta_lookup (product_id, sku)
|
||||
SELECT %d, %s FROM $wpdb->options
|
||||
WHERE NOT EXISTS (
|
||||
SELECT * FROM $wpdb->wc_product_meta_lookup WHERE sku = %s LIMIT 1
|
||||
) LIMIT 1;",
|
||||
$product_id,
|
||||
$sku,
|
||||
$sku
|
||||
);
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$result = $wpdb->query( $query );
|
||||
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| CRUD Methods
|
||||
@@ -106,6 +147,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
* Method to create a new product in the database.
|
||||
*
|
||||
* @param WC_Product $product Product object.
|
||||
* @throws Exception If SKU is already under processing.
|
||||
*/
|
||||
public function create( &$product ) {
|
||||
if ( ! $product->get_date_created( 'edit' ) ) {
|
||||
@@ -137,6 +179,19 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
|
||||
if ( $id && ! is_wp_error( $id ) ) {
|
||||
$product->set_id( $id );
|
||||
$sku = $product->get_sku();
|
||||
|
||||
/**
|
||||
* If SKU is already under processing aka Duplicate SKU
|
||||
* because of concurrent requests, then we should not proceed
|
||||
* Delete the product and throw an exception only if the request is
|
||||
* initiated via REST API
|
||||
*/
|
||||
if ( ! empty( $sku ) && WC()->is_rest_api_request() && ! $this->obtain_lock_on_sku_for_concurrent_requests( $product ) ) {
|
||||
$product->delete( true );
|
||||
// translators: 1: SKU.
|
||||
throw new Exception( esc_html( sprintf( __( 'The SKU (%1$s) you are trying to insert is already under processing', 'woocommerce' ), $sku ) ) );
|
||||
}
|
||||
|
||||
// get the post object so that we can set the status
|
||||
// to the correct value; it is possible that the status was
|
||||
@@ -332,6 +387,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
$post_meta_values = get_post_meta( $id );
|
||||
$meta_key_to_props = array(
|
||||
'_sku' => 'sku',
|
||||
'_global_unique_id' => 'global_unique_id',
|
||||
'_regular_price' => 'regular_price',
|
||||
'_sale_price' => 'sale_price',
|
||||
'_price' => 'price',
|
||||
@@ -523,6 +579,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
protected function update_post_meta( &$product, $force = false ) {
|
||||
$meta_key_to_props = array(
|
||||
'_sku' => 'sku',
|
||||
'_global_unique_id' => 'global_unique_id',
|
||||
'_regular_price' => 'regular_price',
|
||||
'_sale_price' => 'sale_price',
|
||||
'_sale_price_dates_from' => 'date_on_sale_from',
|
||||
@@ -689,7 +746,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
}
|
||||
}
|
||||
|
||||
if ( array_intersect( $this->updated_props, array( 'sku', 'regular_price', 'sale_price', 'date_on_sale_from', 'date_on_sale_to', 'total_sales', 'average_rating', 'stock_quantity', 'stock_status', 'manage_stock', 'downloadable', 'virtual', 'tax_status', 'tax_class' ) ) ) {
|
||||
if ( array_intersect( $this->updated_props, array( 'sku', 'global_unique_id', 'regular_price', 'sale_price', 'date_on_sale_from', 'date_on_sale_to', 'total_sales', 'average_rating', 'stock_quantity', 'stock_status', 'manage_stock', 'downloadable', 'virtual', 'tax_status', 'tax_class' ) ) ) {
|
||||
$this->update_lookup_table( $product->get_id(), 'wc_product_meta_lookup' );
|
||||
}
|
||||
|
||||
@@ -1015,6 +1072,37 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if product sku is found for any other product IDs.
|
||||
*
|
||||
* @since 9.1.0
|
||||
* @param int $product_id Product ID.
|
||||
* @param string $global_unique_id Will be slashed to work around https://core.trac.wordpress.org/ticket/27421.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_existing_global_unique_id( $product_id, $global_unique_id ) {
|
||||
global $wpdb;
|
||||
|
||||
// phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
|
||||
return (bool) $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT posts.ID
|
||||
FROM {$wpdb->posts} as posts
|
||||
INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id
|
||||
WHERE
|
||||
posts.post_type IN ( 'product', 'product_variation' )
|
||||
AND posts.post_status != 'trash'
|
||||
AND lookup.global_unique_id = %s
|
||||
AND lookup.product_id <> %d
|
||||
LIMIT 1
|
||||
",
|
||||
wp_slash( $global_unique_id ),
|
||||
$product_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return product ID based on SKU.
|
||||
*
|
||||
@@ -1045,6 +1133,42 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
return (int) apply_filters( 'woocommerce_get_product_id_by_sku', $id, $sku );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return product ID based on Unique ID.
|
||||
*
|
||||
* @since 9.1.0
|
||||
* @param string $global_unique_id Product Unique ID.
|
||||
* @return int
|
||||
*/
|
||||
public function get_product_id_by_global_unique_id( $global_unique_id ) {
|
||||
global $wpdb;
|
||||
|
||||
// phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
|
||||
$id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT posts.ID
|
||||
FROM {$wpdb->posts} as posts
|
||||
INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id
|
||||
WHERE
|
||||
posts.post_type IN ( 'product', 'product_variation' )
|
||||
AND posts.post_status != 'trash'
|
||||
AND lookup.global_unique_id = %s
|
||||
LIMIT 1
|
||||
",
|
||||
$global_unique_id
|
||||
)
|
||||
);
|
||||
/**
|
||||
* Hook woocommerce_get_product_id_by_global_unique_id.
|
||||
*
|
||||
* @since 9.1.0
|
||||
* @param mixed $id List of post statuses.
|
||||
* @param string $global_unique_id Unique ID.
|
||||
*/
|
||||
return (int) apply_filters( 'woocommerce_get_product_id_by_global_unique_id', $id, $global_unique_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of IDs of products that have sales starting soon.
|
||||
*
|
||||
@@ -2113,7 +2237,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
$stock = 'yes' === $manage_stock ? wc_stock_amount( get_post_meta( $id, '_stock', true ) ) : null;
|
||||
$price = wc_format_decimal( get_post_meta( $id, '_price', true ) );
|
||||
$sale_price = wc_format_decimal( get_post_meta( $id, '_sale_price', true ) );
|
||||
return array(
|
||||
$product_data = array(
|
||||
'product_id' => absint( $id ),
|
||||
'sku' => get_post_meta( $id, '_sku', true ),
|
||||
'virtual' => 'yes' === get_post_meta( $id, '_virtual', true ) ? 1 : 0,
|
||||
@@ -2129,6 +2253,10 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
'tax_status' => get_post_meta( $id, '_tax_status', true ),
|
||||
'tax_class' => get_post_meta( $id, '_tax_class', true ),
|
||||
);
|
||||
if ( get_option( 'woocommerce_schema_version', 0 ) >= 920 ) {
|
||||
$product_data['global_unique_id'] = get_post_meta( $id, '_global_unique_id', true );
|
||||
}
|
||||
return $product_data;
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -367,6 +367,7 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
|
||||
'image_id' => get_post_thumbnail_id( $id ),
|
||||
'backorders' => get_post_meta( $id, '_backorders', true ),
|
||||
'sku' => get_post_meta( $id, '_sku', true ),
|
||||
'global_unique_id' => get_post_meta( $id, '_global_unique_id', true ),
|
||||
'stock_quantity' => get_post_meta( $id, '_stock', true ),
|
||||
'weight' => get_post_meta( $id, '_weight', true ),
|
||||
'length' => get_post_meta( $id, '_length', true ),
|
||||
@@ -403,6 +404,7 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
|
||||
'title' => $parent_object ? $parent_object->post_title : '',
|
||||
'status' => $parent_object ? $parent_object->post_status : '',
|
||||
'sku' => get_post_meta( $product->get_parent_id(), '_sku', true ),
|
||||
'global_unique_id' => get_post_meta( $product->get_parent_id(), '_global_unique_id', true ),
|
||||
'manage_stock' => get_post_meta( $product->get_parent_id(), '_manage_stock', true ),
|
||||
'backorders' => get_post_meta( $product->get_parent_id(), '_backorders', true ),
|
||||
'stock_quantity' => wc_stock_amount( get_post_meta( $product->get_parent_id(), '_stock', true ) ),
|
||||
|
||||
Reference in New Issue
Block a user