PluginProbe
Auto Listings – Car Listings & Car Dealership Plugin for WordPress / trunk
Auto Listings – Car Listings & Car Dealership Plugin for WordPress vtrunk
trunk 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.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 2.1.2 All 81 releases
auto-listings / src / SearchQuery.php

SearchQuery.php in Auto Listings – Car Listings & Car Dealership Plugin for WordPress trunk, at src/SearchQuery.php

448 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Listings search query.
4 *
5 * @package Auto Listings.
6 */
7
8 namespace AutoListings;
9
10 /**
11 * Class SearchQuery.
12 */
13 class SearchQuery {
14 /**
15 * Add hooks when module is loaded.
16 */
17 public function __construct() {
18 add_action( 'pre_get_posts', [ $this, 'pre_get_posts' ] );
19 }
20
21 /**
22 * Customize the search query.
23 *
24 * @param WP_Query $query Query object.
25 */
26 public function pre_get_posts( \WP_Query $query ) {
27 if ( is_admin() || ! $query->is_main_query() || ! $query->is_post_type_archive( 'auto-listing' ) || ! $query->is_search() ) {
28 return;
29 }
30
31 $meta_query = [];
32
33 $year_query[] = $this->year_query();
34 $make_query[] = $this->make_query();
35 $model_query[] = $this->model_query();
36 $condition_query[] = $this->condition_query();
37 $odometer_query[] = $this->odometer_query();
38 $transmission_query[] = $this->transmission_query();
39 $engine_query[] = $this->engine_query();
40 $fuel_type_query[] = $this->fuel_type_query();
41 $model_drive_query[] = $this->model_drive_query();
42 $price_query[] = $this->price_meta_query();
43 $body_type_query = $this->body_type_query();
44 $radius_query[] = $this->radius_query( $query );
45
46 $query_1 = array_merge( $year_query, $make_query, $model_query, $condition_query, $price_query, $odometer_query, $transmission_query, $engine_query, $fuel_type_query, $model_drive_query );
47 $query_1 = apply_filters( 'auto_listings_search_query', $query_1 );
48
49 // If our radius query fails, fall back to keyword searching. Will fail with no map API key.
50 $query_2 = $radius_query;
51 if ( empty( $radius_query[0] ) || ! $radius_query[0] ) {
52 $keyword_query[] = $this->keyword_query( $query );
53 $query_2 = $keyword_query;
54 }
55
56 if ( empty( $_GET['s'] ) ) {
57 $query_1['relation'] = 'AND';
58 $meta_query[] = $query_1;
59 }
60
61 if ( ! empty( $_GET['s'] ) ) {
62 $query_2['relation'] = 'OR';
63 $meta_query[] = $query_1;
64
65 global $wpdb;
66 $title = strtolower( sanitize_text_field( $_GET['s'] ) );
67 $ids = $wpdb->get_col(
68 $wpdb->prepare(
69 "SELECT ID FROM $wpdb->posts WHERE LOWER(post_title) LIKE %s AND post_type='auto-listing' AND post_status='publish'",
70 '%' . $wpdb->esc_like( $title ) . '%'
71 )
72 );
73
74 if ( $ids ) {
75 $query->set( 'post__in', $ids );
76 } else {
77 $meta_query[] = $query_2;
78 }
79
80 $meta_query['relation'] = 'AND';
81 }
82
83 $query->set( 'meta_query', $meta_query );
84 $query->set( 'tax_query', $body_type_query );
85 $query->set( 'post_type', 'auto-listing' );
86 do_action( 'auto_listings_search_query_all', $query );
87 }
88
89 /**
90 * Return a meta query for filtering by year.
91 *
92 * @return array
93 */
94 private function year_query() {
95 if ( isset( $_GET['the_year'] ) && ! empty( $_GET['the_year'] ) ) {
96 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['the_year'] ) );
97 return [
98 'key' => '_al_listing_model_year',
99 'value' => $data,
100 'compare' => 'IN',
101 ];
102 }
103 return [];
104 }
105
106 /**
107 * Return a meta query for filtering by make.
108 *
109 * @return array
110 */
111 private function make_query() {
112 if ( isset( $_GET['make'] ) && ! empty( $_GET['make'] ) ) {
113 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['make'] ) );
114 return [
115 'key' => '_al_listing_make_display',
116 'value' => $data,
117 'compare' => 'IN',
118 ];
119 }
120 return [];
121 }
122
123 /**
124 * Return a meta query for filtering by model.
125 *
126 * @return array
127 */
128 private function model_query() {
129 if ( isset( $_GET['model'] ) && ! empty( $_GET['model'] ) ) {
130 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['model'] ) );
131 return [
132 'key' => '_al_listing_model_name',
133 'value' => $data,
134 'compare' => 'IN',
135 ];
136 }
137 return [];
138 }
139
140 /**
141 * Return a meta query for filtering by condition.
142 *
143 * @return array
144 */
145 private function condition_query() {
146 if ( isset( $_GET['condition'] ) && ! empty( $_GET['condition'] ) ) {
147 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['condition'] ) );
148 return [
149 'key' => '_al_listing_condition',
150 'value' => $data,
151 'compare' => 'IN',
152 ];
153 }
154 return [];
155 }
156
157 /**
158 * Return a meta query for filtering by odometer.
159 *
160 * @return array
161 */
162 private function odometer_query() {
163 if ( isset( $_GET['odometer'] ) && ! empty( $_GET['odometer'] ) ) {
164 $min = 0;
165 $max = floatval( $_GET['odometer'] );
166
167 return [
168 'key' => '_al_listing_odometer',
169 'value' => [ $min, $max ],
170 'compare' => 'BETWEEN',
171 'type' => 'NUMERIC',
172 ];
173 }
174 return [];
175 }
176
177 /**
178 * Return a meta query for filtering by transmission.
179 *
180 * @return array
181 */
182 private function transmission_query() {
183 if ( isset( $_GET['transmission'] ) && ! empty( $_GET['transmission'] ) ) {
184 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['transmission'] ) );
185 return [
186 'key' => '_al_listing_model_transmission_type',
187 'value' => $data,
188 'compare' => 'IN',
189 ];
190 }
191 return [];
192 }
193
194 /**
195 * Return a meta query for filtering by engine.
196 *
197 * @return array
198 */
199 private function engine_query() {
200 if ( isset( $_GET['engine'] ) && ! empty( $_GET['engine'] ) ) {
201 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['engine'] ) );
202 return [
203 'key' => '_al_listing_model_engine_type',
204 'value' => $data,
205 'compare' => 'IN',
206 ];
207 }
208 return [];
209 }
210
211 /**
212 * Return a meta query for filtering by fuel type.
213 *
214 * @return array
215 */
216 private function model_drive_query() {
217 if ( isset( $_GET['model_drive'] ) && ! empty( $_GET['model_drive'] ) ) {
218 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['model_drive'] ) );
219 return [
220 'key' => '_al_listing_model_drive',
221 'value' => $data,
222 'compare' => 'IN',
223 ];
224 }
225 return [];
226 }
227
228 /**
229 * Return a meta query for filtering by fuel type.
230 *
231 * @return array
232 */
233 private function fuel_type_query() {
234 if ( isset( $_GET['fuel_type'] ) && ! empty( $_GET['fuel_type'] ) ) {
235 $data = array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['fuel_type'] ) );
236 return [
237 'key' => '_al_listing_model_engine_fuel',
238 'value' => $data,
239 'compare' => 'IN',
240 ];
241 }
242 return [];
243 }
244
245 /**
246 * Return a taxonomy query for filtering by body type.
247 *
248 * @return array
249 */
250 private function body_type_query() {
251 if ( isset( $_GET['body_type'] ) && ! empty( $_GET['body_type'] ) ) {
252 $tax_query[] = [
253 'taxonomy' => 'body-type',
254 'field' => 'slug',
255 'terms' => array_map( 'sanitize_text_field', wp_unslash( (array) $_GET['body_type'] ) ),
256 ];
257 return $tax_query;
258 }
259 return null;
260 }
261
262 /**
263 * Return a meta query for filtering by price.
264 *
265 * @return array
266 */
267 private function price_meta_query() {
268 if ( empty( $_GET['max_price'] ) && empty( $_GET['min_price'] ) ) {
269 return [];
270 }
271 if ( ! empty( $_GET['max_price'] ) && empty( $_GET['min_price'] ) ) {
272 $value = floatval( $_GET['max_price'] );
273 $compare = '<=';
274 } elseif ( empty( $_GET['max_price'] ) && ! empty( $_GET['min_price'] ) ) {
275 $value = floatval( $_GET['min_price'] );
276 $compare = '>=';
277 } else {
278 $min = floatval( $_GET['min_price'] );
279 $max = floatval( $_GET['max_price'] );
280 $value = [ $min, $max ];
281 $compare = 'BETWEEN';
282 }
283 return [
284 'key' => '_al_listing_price',
285 'value' => $value,
286 'compare' => $compare,
287 'type' => 'DECIMAL',
288 'price_filter' => true,
289 ];
290 }
291
292 /**
293 * Return a meta query for filtering by location.
294 *
295 * @param WP_Query $query Query object.
296 */
297 public function radius_query( \WP_Query $query ) {
298 if ( empty( $_GET['s'] ) ) {
299 return false;
300 }
301 $search_term = isset( $query->query_vars['s'] ) ? sanitize_text_field( $query->query_vars['s'] ) : '';
302
303 if ( ! $search_term ) {
304 return false;
305 }
306
307 // We have to remove the "s" parameter from the query, because it will prevent the posts from being found.
308 $query->query_vars['s'] = '';
309
310 $search_radius = $this->geocode( $search_term );
311
312 if ( ! $search_radius ) {
313 return false;
314 }
315
316 $lat = $search_radius['lat']; // get the lat of the requested address.
317 $lng = $search_radius['lng']; // get the lng of the requested address.
318
319 // we'll want everything within, say, 30km distance.
320 $distance = isset( $_GET['within'] ) && ! empty( $_GET['within'] ) ? floatval( $_GET['within'] ) : 50;
321
322 // earth's radius in km = ~6371.
323 $radius = auto_listings_metric() === 'yes' ? 6371 : 3950;
324
325 // latitude boundaries.
326 $maxlat = $lat + rad2deg( $distance / $radius );
327 $minlat = $lat - rad2deg( $distance / $radius );
328
329 // longitude boundaries (longitude gets smaller when latitude increases).
330 $maxlng = $lng + rad2deg( $distance / $radius / cos( deg2rad( $lat ) ) );
331 $minlng = $lng - rad2deg( $distance / $radius / cos( deg2rad( $lat ) ) );
332
333 // build the meta query array.
334 $radius_array = [
335 'relation' => 'AND',
336 ];
337
338 $radius_array[] = [
339 'key' => '_al_listing_lat',
340 'value' => [ $minlat, $maxlat ],
341 'type' => 'DECIMAL(10,5)',
342 'compare' => 'BETWEEN',
343 ];
344 $radius_array[] = [
345 'key' => '_al_listing_lng',
346 'value' => [ $minlng, $maxlng ],
347 'type' => 'DECIMAL(10,5)',
348 'compare' => 'BETWEEN',
349 ];
350
351 return apply_filters( 'auto_listings_search_radius_args', $radius_array );
352 }
353
354 /**
355 * Function to geocode address, it will return false if unable to geocode address.
356 *
357 * @param string $address Listing address.
358 */
359 private function geocode( $address ) {
360 if ( empty( $address ) ) {
361 return false;
362 }
363 // url encode the address.
364 $address = urlencode( esc_html( $address ) );
365
366 // google map geocode api url.
367 $url = auto_listings_google_geocode_maps_url( $address );
368
369 $arr_context_options = [
370 'ssl' => [
371 'verify_peer' => false,
372 'verify_peer_name' => false,
373 ],
374 ];
375
376 // get the json response.
377 $resp_json = file_get_contents( $url, false, stream_context_create( $arr_context_options ) );
378
379 // decode the json.
380 $resp = json_decode( $resp_json, true );
381
382 // response status will be 'OK', if able to geocode given address.
383 if ( 'OK' !== $resp['status'] ) {
384 return false;
385 }
386
387 // get the lat and lng.
388 $lat = $resp['results'][0]['geometry']['location']['lat'];
389 $lng = $resp['results'][0]['geometry']['location']['lng'];
390
391 // verify if data is complete.
392 if ( ! $lat || ! $lng ) {
393 return false;
394 }
395
396 return [
397 'lat' => $lat,
398 'lng' => $lng,
399 ];
400 }
401
402
403 /**
404 * Searches listing through keyword
405 *
406 * @param WP_Query $q Query object.
407 */
408 private function keyword_query( $q ) {
409 if ( empty( $_GET['s'] ) ) {
410 return [];
411 }
412
413 $custom_fields = apply_filters(
414 'auto_listings_keyword_search_fields',
415 [
416 // put all the meta fields you want to search for here.
417 '_al_listing_city',
418 '_al_listing_zip',
419 '_al_listing_state',
420 '_al_listing_route',
421 '_al_listing_displayed_address',
422 ]
423 );
424
425 $searchterm = sanitize_text_field( $_GET['s'] );
426
427 // we have to remove the "s" parameter from the query, because it will prevent the posts from being found.
428 $q->query_vars['s'] = '';
429
430 if ( ! $searchterm ) {
431 return [];
432 }
433
434 $meta_query = [ 'relation' => 'OR' ];
435 foreach ( $custom_fields as $cf ) {
436 array_push(
437 $meta_query,
438 [
439 'key' => $cf,
440 'value' => $searchterm,
441 'compare' => 'LIKE',
442 ]
443 );
444 }
445 return $meta_query;
446 }
447 }
448