PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.19
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.19
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
← All changes | includes/API/V1/Product_Variations_Controller.php +36 -72 1.10.151.10.19 View file →
@@ -20,8 +20,9 @@
20 20 use WCPOS\WooCommercePOS\Services\Barcode_Field;
21 21 use WCPOS\WooCommercePOS\Sync\Collection_Rules;
22 22 use WCPOS\WooCommercePOS\Sync\Collection_Rules_Plan;
23 23 use WCPOS\WooCommercePOS\Sync\Pos_Visibility;
24 +use WCPOS\WooCommercePOS\Sync\Product_Search;
24 25 use WP_Error;
25 26 use WP_Query;
26 27 use WP_REST_Request;
27 28 use WP_REST_Response;
@@ -63,8 +64,9 @@
63 64 */
64 65 private const WCPOS_SORT_PARAM_MAP = array(
65 66 'orderby' => 'orderby',
66 67 'order' => 'order',
68 + 'search' => 'search',
67 69 );
68 70
69 71 /**
70 72 * Dispatch request to parent controller, or override if needed.
@@ -79,10 +81,8 @@
79 81
80 82 add_filter( 'woocommerce_rest_prepare_product_variation_object', array( $this, 'wcpos_variation_response' ), 10, 3 );
81 83 add_action( 'woocommerce_rest_insert_product_variation_object', array( $this, 'wcpos_insert_product_variation_object' ), 10, 3 );
82 84 add_filter( 'woocommerce_rest_product_variation_object_query', array( $this, 'wcpos_product_variation_query' ), 10, 2 );
83 - add_filter( 'posts_search', array( $this, 'wcpos_posts_search' ), 10, 2 );
84 - add_filter( 'posts_clauses', array( $this, 'wcpos_posts_clauses' ), 10, 2 );
85 85
86 86 /*
87 87 * Check if the request is for all products and if the 'posts_per_page' is set to -1.
88 88 * Optimised query for getting all product IDs.
@@ -94,8 +94,23 @@
94 94 return $dispatch_result;
95 95 }
96 96
97 97 /**
98 + * Apply the collection's declared rules for nested and flat direct reads.
99 + *
100 + * @param WP_REST_Request $request Full details about the request.
101 + * @return \WP_Error|\WP_REST_Response
102 + */
103 + public function get_items( $request ) {
104 + $plan = Collection_Rules::for_request( 'variations', $request, self::WCPOS_SORT_PARAM_MAP );
105 + return $plan->around(
106 + function () use ( $request ) {
107 + return parent::get_items( $request );
108 + }
109 + );
110 + }
111 +
112 + /**
98 113 * Register routes.
99 114 */
100 115 public function register_routes(): void {
101 116 parent::register_routes();
@@ -185,8 +200,14 @@
185 200 if ( isset( $params['per_page'] ) && \is_array( $params['per_page'] ) ) {
186 201 $params['per_page']['minimum'] = -1;
187 202 }
188 203
204 + // Search text is literal on every lane: `sanitize_text_field` would strip `%30`
205 + // and blank malformed UTF-8 before the declared search rule ever saw them.
206 + if ( isset( $params['search'] ) && \is_array( $params['search'] ) ) {
207 + $params['search']['sanitize_callback'] = 'rest_sanitize_request_arg';
208 + }
209 +
189 210 // Ensure 'orderby' is set and is an array before attempting to modify it.
190 211 if ( isset( $params['orderby']['enum'] ) && \is_array( $params['orderby']['enum'] ) ) {
191 212 // DECLARED once, in Sync\Collection_Rules, and projected here — so a sort cannot
192 213 // be advertised on one lane and rejected on the other.
@@ -270,51 +291,12 @@
270 291 * @param string $search Search string.
271 292 * @param WP_Query $wp_query WP_Query object.
272 293 *
273 294 * @return string
295 + * @deprecated Collection Rules now installs this behavior.
274 296 */
275 297 public function wcpos_posts_search( string $search, WP_Query $wp_query ) {
276 - global $wpdb;
277 -
278 - if ( empty( $search ) ) {
279 - return $search; // skip processing - no search term in query.
280 - }
281 -
282 - $q = $wp_query->query_vars;
283 - $n = ! empty( $q['exact'] ) ? '' : '%';
284 - $search_terms = (array) $q['search_terms'];
285 -
286 - // Fields in the main 'posts' table.
287 - $post_fields = array(); // nothing at the moment for variations.
288 -
289 - // Meta fields to search.
290 - $meta_fields = Barcode_Field::search_keys();
291 -
292 - $meta_placeholders = implode( ', ', array_fill( 0, \count( $meta_fields ), '%s' ) );
293 - $search_conditions = array();
294 -
295 - foreach ( $search_terms as $term ) {
296 - $term = $n . $wpdb->esc_like( $term ) . $n;
297 -
298 - // Search in meta fields.
299 - // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table names come from $wpdb; $meta_placeholders is a generated list of %s placeholders, and the keys themselves are passed to prepare() as arguments.
300 - $search_conditions[] = $wpdb->prepare(
301 - "EXISTS (
302 - SELECT 1 FROM {$wpdb->postmeta} AS wcpos_search_meta WHERE wcpos_search_meta.post_id = {$wpdb->posts}.ID AND wcpos_search_meta.meta_key IN ($meta_placeholders) AND wcpos_search_meta.meta_value LIKE %s
303 - )",
304 - array_merge( $meta_fields, array( $term ) )
305 - );
306 - // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
307 - }
308 -
309 - if ( ! empty( $search_conditions ) ) {
310 - $search = ' AND (' . implode( ' AND ', $search_conditions ) . ') ';
311 - if ( ! is_user_logged_in() ) {
312 - $search .= " AND ($wpdb->posts.post_password = '') ";
313 - }
314 - }
315 -
316 - return $search;
298 + return Product_Search::variation_posts_search( $search, $wp_query->query_vars, Collection_Rules::rules( 'variations' )['search'] );
317 299 }
318 300
319 301 /**
320 302 * Filters the JOIN clause of the query.
@@ -322,17 +304,12 @@
322 304 * @param string $join The JOIN clause of the query.
323 305 * @param WP_Query $query The WP_Query instance (passed by reference).
324 306 *
325 307 * @return string
308 + * @deprecated Collection Rules now installs this behavior.
326 309 */
327 310 public function wcpos_posts_join_to_posts_search( string $join, WP_Query $query ) {
328 - global $wpdb;
329 -
330 - if ( ! empty( $query->query_vars['s'] ) && false === strpos( $join, 'pm1' ) ) {
331 - $join .= " LEFT JOIN {$wpdb->postmeta} pm1 ON {$wpdb->posts}.ID = pm1.post_id ";
332 - }
333 -
334 - return $join;
311 + return empty( $query->query_vars['s'] ) ? $join : Product_Search::posts_join( $join, $query->query_vars );
335 312 }
336 313
337 314 /**
338 315 * Filters the GROUP BY clause of the query.
@@ -340,17 +317,12 @@
340 317 * @param string $groupby The GROUP BY clause of the query.
341 318 * @param WP_Query $query The WP_Query instance (passed by reference).
342 319 *
343 320 * @return string
321 + * @deprecated Collection Rules now installs this behavior.
344 322 */
345 323 public function wcpos_posts_groupby_posts_search( string $groupby, WP_Query $query ) {
346 - global $wpdb;
347 -
348 - if ( ! empty( $query->query_vars['s'] ) ) {
349 - $groupby = "{$wpdb->posts}.ID";
350 - }
351 -
352 - return $groupby;
324 + return empty( $query->query_vars['s'] ) ? $groupby : Product_Search::posts_groupby( $groupby, $query->query_vars );
353 325 }
354 326
355 327 /**
356 328 * Filter the query arguments for a request.
@@ -360,21 +332,10 @@
360 332 *
361 333 * @return array $args Key value array of query var to query value.
362 334 */
363 335 public function wcpos_product_variation_query( array $args, WP_REST_Request $request ) {
364 - if ( ! empty( $request['search'] ) ) {
365 - // We need to set the query up for a postmeta join.
366 - add_filter( 'posts_join', array( $this, 'wcpos_posts_join_to_posts_search' ), 10, 2 );
367 - add_filter( 'posts_groupby', array( $this, 'wcpos_posts_groupby_posts_search' ), 10, 2 );
368 - }
369 -
370 - // if POS only products are enabled, exclude online-only products.
371 - if ( $this->wcpos_pos_only_products_enabled() ) {
372 - add_filter( 'posts_where', array( $this, 'wcpos_posts_where_product_variation_exclude_online_only' ), 10, 2 );
373 - }
374 -
375 336 // Check for wcpos_include/wcpos_exclude parameter.
376 - // NOTE: do this after POS visibility filter so that takes precedence.
337 + // The Collection Rules visibility backstop runs first, at priority 10.
377 338 if ( isset( $request['wcpos_include'] ) || isset( $request['wcpos_exclude'] ) ) {
378 339 add_filter( 'posts_where', array( $this, 'wcpos_posts_where_product_variation_include_exclude' ), 20, 2 );
379 340 }
380 341
@@ -390,8 +351,9 @@
390 351 * @param string $where The WHERE clause of the query.
391 352 * @param WP_Query $query The WP_Query instance (passed by reference).
392 353 *
393 354 * @return string
355 + * @deprecated Collection Rules now installs this behavior.
394 356 */
395 357 public function wcpos_posts_where_product_variation_exclude_online_only( string $where, WP_Query $query ) {
396 358 global $wpdb;
397 359
@@ -473,9 +435,9 @@
473 435 *
474 436 * @param WP_REST_Request $request Full details about the request.
475 437 */
476 438 public function wcpos_get_all_items( $request ) {
477 - return parent::get_items( $request );
439 + return $this->get_items( $request );
478 440 }
479 441
480 442
481 443 /**
@@ -488,8 +450,9 @@
488 450 * @param array $clauses Associative array of the clauses for the query.
489 451 * @param WP_Query $wp_query The WP_Query instance.
490 452 *
491 453 * @return array
454 + * @deprecated Collection Rules now installs this behavior.
492 455 */
493 456 public function wcpos_posts_clauses( array $clauses, WP_Query $wp_query ): array {
494 457 if ( ! isset( $this->wcpos_request ) ) {
495 458 return $clauses;
@@ -518,11 +481,12 @@
518 481 /*
519 482 * The POS sorts (`sku`, `barcode`, `stock_quantity`, `stock_status`) are NOT mapped
520 483 * onto `meta_key` + `orderby => meta_value` here any more. That pair INNER JOINs
521 484 * postmeta, so it dropped every variation with no value for the key — a sort acting
522 - * as a filter. `Sync\Collection_Rules` declares them and `wcpos_posts_clauses()`
485 + * as a filter. `Sync\Collection_Rules` declares them and its scoped plan
523 486 * applies them as a LEFT JOIN, on this lane and on `wcpos/v2` alike.
524 487 */
525 488
526 - return $args;
489 + $plan = Collection_Rules::for_request( 'variations', $request, self::WCPOS_SORT_PARAM_MAP );
490 + return $plan->filter( Collection_Rules_Plan::HOOK_PREPARE_ARGS, $args );
527 491 }
528 492 }