plugin updates

This commit is contained in:
Tony Volpe
2024-09-05 11:04:01 -04:00
parent ed6b060261
commit 50cd64dd3d
925 changed files with 16918 additions and 13003 deletions

View File

@@ -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.
*

View File

@@ -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'] ) ) {

View File

@@ -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();
}

View File

@@ -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 ) ),