PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / trunk
WCPOS – Point of Sale (POS) plugin for WooCommerce vtrunk
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 1.9.13 1.9.12 1.9.11 1.9.10 1.9.9 All 158 releases
woocommerce-pos / includes / API / Product_Search.php

Product_Search.php in WCPOS – Point of Sale (POS) plugin for WooCommerce trunk, at includes/API/Product_Search.php

115 lines 3.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Shared product search SQL filters.
4 *
5 * @package WCPOS\WooCommercePOS\API
6 */
7
8 namespace WCPOS\WooCommercePOS\API;
9
10 use WCPOS\WooCommercePOS\Services\Barcode_Field;
11 use WP_Query;
12
13 /**
14 * Keeps v1 and v2 product search fields identical.
15 */
16 final class Product_Search {
17 /**
18 * Search product titles, SKUs, and the configured barcode field.
19 *
20 * @param string $search Search SQL.
21 * @param WP_Query $wp_query Query instance.
22 * @return string
23 */
24 public static function posts_search( string $search, WP_Query $wp_query ): string {
25 global $wpdb;
26 $q = $wp_query->query_vars;
27 $phrase = $q['wcpos_search_phrase'] ?? null;
28 if ( empty( $search ) && null === $phrase ) {
29 return $search;
30 }
31 $terms = null !== $phrase ? array( $phrase ) : (array) $q['search_terms'];
32 $n = ! empty( $q['exact'] ) ? '' : '%';
33 $meta_fields = Barcode_Field::search_keys();
34 $meta_placeholders = implode( ', ', array_fill( 0, \count( $meta_fields ), '%s' ) );
35 $search_conditions = array();
36 foreach ( $terms as $term ) {
37 $term = $n . $wpdb->esc_like( $term ) . $n;
38 // 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.
39 $search_conditions[] = $wpdb->prepare(
40 "( {$wpdb->posts}.post_title LIKE %s OR EXISTS (
41 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
42 ) )",
43 array_merge( array( $term ), $meta_fields, array( $term ) )
44 );
45 // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
46 }
47
48 if ( ! empty( $search_conditions ) ) {
49 $search = ' AND (' . implode( ' AND ', $search_conditions ) . ') ';
50 if ( ! is_user_logged_in() ) {
51 $search .= " AND ($wpdb->posts.post_password = '') ";
52 }
53 }
54 return $search;
55 }
56
57 /**
58 * Join product meta while searching.
59 *
60 * @param string $join JOIN SQL.
61 * @param WP_Query $query Query instance.
62 * @return string
63 */
64 public static function posts_join( string $join, WP_Query $query ): string {
65 global $wpdb;
66 if ( self::is_searching( $query ) && false === strpos( $join, 'pm1' ) ) {
67 $join .= " LEFT JOIN {$wpdb->postmeta} pm1 ON {$wpdb->posts}.ID = pm1.post_id ";
68 }
69 return $join;
70 }
71
72 /**
73 * Group product search results after joining meta.
74 *
75 * @param string $groupby GROUP BY SQL.
76 * @param WP_Query $query Query instance.
77 * @return string
78 */
79 public static function posts_groupby( string $groupby, WP_Query $query ): string {
80 global $wpdb;
81 if ( self::is_searching( $query ) ) {
82 $groupby = "{$wpdb->posts}.ID";
83 }
84 return $groupby;
85 }
86
87 /**
88 * Rank exact SKU or barcode matches ahead of substring matches.
89 *
90 * @param string $orderby ORDER BY SQL.
91 * @param WP_Query $query Query instance.
92 */
93 public static function posts_orderby( string $orderby, WP_Query $query ): string {
94 global $wpdb;
95 if ( ! self::is_searching( $query ) ) {
96 return $orderby;
97 }
98 $keys = Barcode_Field::search_keys();
99 return $wpdb->prepare(
100 'MIN(CASE WHEN pm1.meta_key IN (' . implode( ', ', array_fill( 0, count( $keys ), '%s' ) ) . ') AND pm1.meta_value = %s THEN 0 ELSE 1 END) ASC',
101 array_merge( $keys, array( trim( (string) ( $query->query_vars['wcpos_search_phrase'] ?? $query->query_vars['s'] ) ) ) )
102 ) . ', ' . ( '' === trim( $orderby ) ? "{$wpdb->posts}.ID DESC" : $orderby );
103 }
104
105 /**
106 * Whether the query carries a search term. Not empty(): the literal term "0" is a search.
107 *
108 * @param WP_Query $query Query instance.
109 * @return bool
110 */
111 private static function is_searching( WP_Query $query ): bool {
112 return '' !== (string) ( $query->query_vars['wcpos_search_phrase'] ?? $query->query_vars['s'] ?? '' );
113 }
114 }
115