Commit c949ec0f006 for woocommerce
commit c949ec0f00649cc35f0259bb767ab0326c616e14
Author: Darren Ethier <darren@roughsmootheng.in>
Date: Fri Sep 4 15:05:10 2026 -0400
Scope PHPCS suppressions on extension-facing SQL queries (#68298)
diff --git a/plugins/woocommerce/changelog/fix-woo6-117-extensible-sql-contract-suppressions b/plugins/woocommerce/changelog/fix-woo6-117-extensible-sql-contract-suppressions
new file mode 100644
index 00000000000..a470dcf8455
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-woo6-117-extensible-sql-contract-suppressions
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Replace legacy WPCS suppression comments on extension-facing SQL and order note queries with scoped phpcs:ignore annotations.
diff --git a/plugins/woocommerce/includes/admin/reports/class-wc-report-downloads.php b/plugins/woocommerce/includes/admin/reports/class-wc-report-downloads.php
index e59e7dd1193..e0e3ff2bf49 100644
--- a/plugins/woocommerce/includes/admin/reports/class-wc-report-downloads.php
+++ b/plugins/woocommerce/includes/admin/reports/class-wc-report-downloads.php
@@ -330,7 +330,7 @@ class WC_Report_Downloads extends WP_List_Table {
$query_from = apply_filters( 'woocommerce_report_downloads_query_from', $query_from );
$query_order = $wpdb->prepare( 'ORDER BY timestamp DESC LIMIT %d, %d;', ( $current_page - 1 ) * $per_page, $per_page );
- $this->items = $wpdb->get_results( "SELECT * {$query_from} {$query_order}" ); // WPCS: cache ok, db call ok, unprepared SQL ok.
- $this->max_items = $wpdb->get_var( "SELECT COUNT( DISTINCT download_log_id ) {$query_from};" ); // WPCS: cache ok, db call ok, unprepared SQL ok.
+ $this->items = $wpdb->get_results( "SELECT * {$query_from} {$query_order}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Core builds both fragments with $wpdb->prepare(); the woocommerce_report_downloads_query_from filter lets extensions supply their own SQL.
+ $this->max_items = $wpdb->get_var( "SELECT COUNT( DISTINCT download_log_id ) {$query_from};" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Core builds the fragment with $wpdb->prepare(); the woocommerce_report_downloads_query_from filter lets extensions supply their own SQL.
}
}
diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php
index 2861539e792..54ed6e36fc5 100644
--- a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php
+++ b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php
@@ -47,7 +47,7 @@ class WC_REST_Order_Notes_V2_Controller extends WC_REST_Order_Notes_V1_Controlle
// Allow filter by order note type.
if ( 'customer' === $request['type'] ) {
- $args['meta_query'] = array( // WPCS: slow query ok.
+ $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to one order's notes; the customer flag exists only as commentmeta, so a meta join is the only way to filter on it.
array(
'key' => 'is_customer_note',
'value' => 1,
@@ -55,7 +55,7 @@ class WC_REST_Order_Notes_V2_Controller extends WC_REST_Order_Notes_V1_Controlle
),
);
} elseif ( 'internal' === $request['type'] ) {
- $args['meta_query'] = array( // WPCS: slow query ok.
+ $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to one order's notes; internal notes are identified by the absence of the is_customer_note meta, so NOT EXISTS is the only way to filter on them.
array(
'key' => 'is_customer_note',
'compare' => 'NOT EXISTS',
diff --git a/plugins/woocommerce/includes/wc-order-functions.php b/plugins/woocommerce/includes/wc-order-functions.php
index c38072d2b1b..028062a4f39 100644
--- a/plugins/woocommerce/includes/wc-order-functions.php
+++ b/plugins/woocommerce/includes/wc-order-functions.php
@@ -1253,7 +1253,7 @@ function wc_get_order_notes( $args ) {
// Set WooCommerce order type.
if ( isset( $args['type'] ) && 'customer' === $args['type'] ) {
- $args['meta_query'] = array( // WPCS: slow query ok.
+ $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Order notes live in wp_comments under both HPOS and legacy storage; the customer flag exists only as commentmeta, so a meta join is the only way to filter on it.
array(
'key' => 'is_customer_note',
'value' => 1,
@@ -1261,7 +1261,7 @@ function wc_get_order_notes( $args ) {
),
);
} elseif ( isset( $args['type'] ) && 'internal' === $args['type'] ) {
- $args['meta_query'] = array( // WPCS: slow query ok.
+ $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Order notes live in wp_comments under both HPOS and legacy storage; internal notes are identified by the absence of the is_customer_note meta, so NOT EXISTS is the only way to filter on them.
array(
'key' => 'is_customer_note',
'compare' => 'NOT EXISTS',
diff --git a/plugins/woocommerce/includes/widgets/class-wc-widget-price-filter.php b/plugins/woocommerce/includes/widgets/class-wc-widget-price-filter.php
index cba01a08109..31e2330d360 100644
--- a/plugins/woocommerce/includes/widgets/class-wc-widget-price-filter.php
+++ b/plugins/woocommerce/includes/widgets/class-wc-widget-price-filter.php
@@ -185,6 +185,6 @@ class WC_Widget_Price_Filter extends WC_Widget {
$sql = apply_filters( 'woocommerce_price_filter_sql', $sql, $meta_query_sql, $tax_query_sql );
- return $wpdb->get_row( $sql ); // WPCS: unprepared SQL ok.
+ return $wpdb->get_row( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Core assembles $sql from prepared WP_Meta_Query/WP_Tax_Query clauses and esc_sql'd post types; the woocommerce_price_filter_sql filter lets extensions replace the statement.
}
}
diff --git a/plugins/woocommerce/includes/widgets/class-wc-widget-products.php b/plugins/woocommerce/includes/widgets/class-wc-widget-products.php
index 50f1d6b3bf3..d061b4db9fd 100644
--- a/plugins/woocommerce/includes/widgets/class-wc-widget-products.php
+++ b/plugins/woocommerce/includes/widgets/class-wc-widget-products.php
@@ -104,8 +104,8 @@ class WC_Widget_Products extends WC_Widget {
'post_type' => 'product',
'no_found_rows' => 1,
'order' => $order,
- 'meta_query' => array(), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- The empty query container does not add a database join.
- 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- The empty query container does not add a database join.
+ 'meta_query' => array(), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Optional container; populated only when the hide-free-products option is on.
+ 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Catalog visibility and out-of-stock exclusion are stored only in the product_visibility taxonomy; term_taxonomy_id lookups use the term_relationships index.
'relation' => 'AND',
),
);
@@ -137,7 +137,7 @@ class WC_Widget_Products extends WC_Widget {
'terms' => $product_visibility_term_ids[ ProductStockStatus::OUT_OF_STOCK ],
'operator' => 'NOT IN',
),
- ); // WPCS: slow query ok.
+ );
}
switch ( $show ) {