PluginProbe
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce / 3.3.0
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce v3.3.0
3.3.0 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.1 trunk 1.0.4 1.1.0 1.1.0.1 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 All 162 releases
cartflows / classes / class-cartflows-coupon-search.php

class-cartflows-coupon-search.php in CartFlows – Funnel Builder & Checkout Plugin for WooCommerce 3.3.0, at classes/class-cartflows-coupon-search.php

157 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Coupon code search for the admin pickers.
4 *
5 * See `architecture.md` in this folder for why both admin trees share it.
6 *
7 * @package CartFlows
8 * @since x.x.x
9 */
10
11 // Exit if accessed directly.
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Class Cartflows_Coupon_Search.
18 *
19 * Stateless helper — every method is static and there is no instance.
20 *
21 * @since x.x.x
22 */
23 class Cartflows_Coupon_Search {
24
25 /**
26 * Object cache group for coupon search results.
27 *
28 * @since x.x.x
29 * @var string
30 */
31 const CACHE_GROUP = 'wcf_funnel_Cart';
32
33 /**
34 * Search published coupon codes, exact match then prefix then the rest.
35 *
36 * @since x.x.x
37 *
38 * @param string $term Raw search term.
39 * @param int $limit Maximum rows to read from the database.
40 * @return array<int, int> Coupon IDs, best match first.
41 */
42 public static function search_coupon_ids( $term, $limit = 100 ) {
43
44 global $wpdb;
45
46 $term = trim( (string) $term );
47 $limit = max( 1, (int) $limit );
48
49 if ( '' === $term ) {
50 return array();
51 }
52
53 $cache_key = self::get_cache_key( $term, $limit );
54 $cached = wp_cache_get( $cache_key, self::CACHE_GROUP );
55
56 if ( is_array( $cached ) ) {
57 return $cached;
58 }
59
60 $rows = $wpdb->get_results(
61 $wpdb->prepare(
62 "SELECT ID
63 FROM {$wpdb->posts}
64 WHERE post_type = %s
65 AND post_status = %s
66 AND post_title LIKE %s
67 ORDER BY
68 CASE
69 WHEN post_title = %s THEN 0
70 WHEN post_title LIKE %s THEN 1
71 ELSE 2
72 END ASC, post_title ASC
73 LIMIT %d",
74 'shop_coupon',
75 'publish',
76 '%' . $wpdb->esc_like( $term ) . '%',
77 $term,
78 $wpdb->esc_like( $term ) . '%',
79 $limit
80 )
81 ); // db call ok.
82
83 $ids = is_array( $rows ) ? array_map( 'intval', wp_list_pluck( $rows, 'ID' ) ) : array();
84
85 // A short TTL bounds the entries the posts namespace leaves orphaned.
86 wp_cache_set( $cache_key, $ids, self::CACHE_GROUP, MINUTE_IN_SECONDS * 5 );
87
88 return $ids;
89 }
90
91 /**
92 * Cache key for one coupon search.
93 *
94 * Folds in the posts namespace so writing any post rolls every stored key.
95 *
96 * @since x.x.x
97 *
98 * @param string $term Raw search term.
99 * @param int $limit Row limit the cached result was read with.
100 * @return string Cache key.
101 */
102 private static function get_cache_key( $term, $limit ) {
103
104 // Without the namespace a created, renamed or unpublished coupon stays missing until the cache is flushed.
105 $last_changed = wp_cache_get_last_changed( 'posts' );
106
107 return 'wcf_search_coupons_' . md5( $term . '|' . $limit . '|' . $last_changed );
108 }
109
110 /**
111 * Format matched coupons for the picker, dropping unknown discount types.
112 *
113 * @since x.x.x
114 *
115 * @param array<int, int> $ids Coupon IDs, best match first.
116 * @param int $limit Maximum rows to return.
117 * @return array<int, array<string, string>> Picker rows.
118 */
119 public static function format_for_picker( $ids, $limit ) {
120
121 $limit = max( 1, (int) $limit );
122 $found = array();
123
124 if ( empty( $ids ) ) {
125 return $found;
126 }
127
128 // One prime beats the post and meta read each get_the_title() and get_post_meta() would make per candidate.
129 _prime_post_caches( $ids, false, true );
130
131 $discount_types = wc_get_coupon_types();
132
133 foreach ( $ids as $coupon_id ) {
134
135 $discount_type = get_post_meta( $coupon_id, 'discount_type', true );
136
137 if ( empty( $discount_types[ $discount_type ] ) ) {
138 continue;
139 }
140
141 $title = get_the_title( $coupon_id );
142
143 $found[] = array(
144 'value' => $title,
145 'label' => $title . ' (Type: ' . $discount_types[ $discount_type ] . ')',
146 );
147
148 // The candidate set is deliberately wider than the cap; stop as soon as the cap is met.
149 if ( count( $found ) >= $limit ) {
150 break;
151 }
152 }
153
154 return $found;
155 }
156 }
157