PluginProbe
Gutenify – Visual Site Builder Blocks & Starter Templates / trunk
Gutenify – Visual Site Builder Blocks & Starter Templates vtrunk
1.9.0 1.8.0 1.7.0 1.6.6 1.6.5 1.6.4 trunk 0.0.1 0.0.2 0.0.3 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 74 releases
gutenify / core / dist / blocks / advanced-search / index.php

index.php in Gutenify – Visual Site Builder Blocks & Starter Templates trunk, at core/dist/blocks/advanced-search/index.php

195 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Advanced Search Block
4 *
5 * @package gutenify
6 */
7
8 namespace gutenify\Blocks\Advanced_Search;
9
10 defined( 'ABSPATH' ) || exit;
11
12 class Advanced_Search {
13
14 /**
15 * REST namespace, matching the framework's own
16 * gutenify/v1 convention (see inc/rest-api/class-rest.php).
17 *
18 * @var string
19 */
20 const REST_NAMESPACE = 'gutenify/v1';
21
22 /**
23 * Init function.
24 */
25 public static function init() {
26 add_action( 'init', array( __CLASS__, 'register_block' ) );
27 add_action( 'rest_api_init', array( __CLASS__, 'register_routes' ) );
28 }
29
30 /**
31 * Register the block.
32 *
33 * Skip registering entirely when WooCommerce isn't active — there is
34 * nothing to search. render.php also bails independently, as defense
35 * in depth for a block instance saved from before WooCommerce was
36 * deactivated.
37 */
38 public static function register_block() {
39 if ( ! class_exists( 'woocommerce' ) ) {
40 return;
41 }
42
43 register_block_type( __DIR__ );
44 }
45
46 /**
47 * Register the `/products/search` REST route the frontend
48 * view-script.js fetches from (see render.php's `data-rest-url`).
49 *
50 * Ported from the original "Firefly Blocks Pro" source, which
51 * referenced a `Firefly_Blocks_Pro_Product_Search` REST controller
52 * class that does not exist anywhere in this codebase — the block
53 * would have fatal-errored the moment it rendered. This replaces
54 * that missing dependency with a self-contained route.
55 */
56 public static function register_routes() {
57 if ( ! class_exists( 'woocommerce' ) ) {
58 return;
59 }
60
61 register_rest_route(
62 self::REST_NAMESPACE,
63 '/products/search',
64 array(
65 'methods' => \WP_REST_Server::READABLE,
66 'callback' => array( __CLASS__, 'search_products' ),
67 'permission_callback' => '__return_true',
68 'args' => array(
69 'search' => array(
70 'type' => 'string',
71 'default' => '',
72 'sanitize_callback' => 'sanitize_text_field',
73 ),
74 'limit' => array(
75 'type' => 'integer',
76 'default' => 6,
77 'sanitize_callback' => 'absint',
78 ),
79 ),
80 )
81 );
82 }
83
84 /**
85 * REST callback: search published products by title/SKU and
86 * matching product categories, in the shape view-script.js expects —
87 * `{ products: [ { url, imageHtml, name, priceHtml } ], categories: [ { url, name } ] }`.
88 *
89 * @param \WP_REST_Request $request Request instance.
90 * @return \WP_REST_Response
91 */
92 public static function search_products( $request ) {
93 $search = trim( (string) $request->get_param( 'search' ) );
94 $limit = max( 1, min( 20, absint( $request->get_param( 'limit' ) ) ) );
95
96 if ( '' === $search ) {
97 return new \WP_REST_Response(
98 array(
99 'products' => array(),
100 'categories' => array(),
101 )
102 );
103 }
104
105 $product_ids = self::find_product_ids( $search, $limit );
106
107 $products = array();
108 foreach ( $product_ids as $product_id ) {
109 $product = wc_get_product( $product_id );
110
111 if ( ! $product ) {
112 continue;
113 }
114
115 $products[] = array(
116 'url' => get_permalink( $product_id ),
117 'imageHtml' => $product->get_image( 'woocommerce_gallery_thumbnail' ),
118 'name' => $product->get_name(),
119 'priceHtml' => wp_strip_all_tags( $product->get_price_html() ),
120 );
121 }
122
123 $categories = array();
124 $terms = get_terms(
125 array(
126 'taxonomy' => 'product_cat',
127 'name__like' => $search,
128 'number' => 5,
129 'hide_empty' => true,
130 )
131 );
132
133 if ( ! is_wp_error( $terms ) ) {
134 foreach ( $terms as $term ) {
135 $categories[] = array(
136 'url' => get_term_link( $term ),
137 'name' => $term->name,
138 );
139 }
140 }
141
142 return new \WP_REST_Response(
143 array(
144 'products' => $products,
145 'categories' => $categories,
146 )
147 );
148 }
149
150 /**
151 * Finds published product IDs matching the search term by title or
152 * SKU, title matches ranked first.
153 *
154 * @param string $search Search term.
155 * @param int $limit Max results.
156 * @return int[]
157 */
158 private static function find_product_ids( $search, $limit ) {
159 $title_matches = get_posts(
160 array(
161 'post_type' => 'product',
162 'post_status' => 'publish',
163 's' => $search,
164 'posts_per_page' => $limit,
165 'fields' => 'ids',
166 )
167 );
168
169 if ( count( $title_matches ) >= $limit ) {
170 return $title_matches;
171 }
172
173 $sku_matches = get_posts(
174 array(
175 'post_type' => 'product',
176 'post_status' => 'publish',
177 'posts_per_page' => $limit - count( $title_matches ),
178 'fields' => 'ids',
179 'post__not_in' => $title_matches,
180 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
181 array(
182 'key' => '_sku',
183 'value' => $search,
184 'compare' => 'LIKE',
185 ),
186 ),
187 )
188 );
189
190 return array_merge( $title_matches, $sku_matches );
191 }
192 }
193
194 Advanced_Search::init();
195