PluginProbe
YayExtra – WooCommerce Extra Product Options / trunk
YayExtra – WooCommerce Extra Product Options vtrunk
2.1.0 trunk 1.1.4 1.1.5 1.1.8 1.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.5.2 1.5.3 1.5.5 1.5.6 All 30 releases
yayextra / includes / Helper / Database.php

Database.php in YayExtra – WooCommerce Extra Product Options trunk, at includes/Helper/Database.php

478 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace YayExtra\Helper;
3
4 defined( 'ABSPATH' ) || exit;
5
6 /**
7 * Main class of plugin
8 *
9 * @class Database
10 */
11 class Database {
12
13 protected $filters = array();
14 protected $apply = 'any';
15 protected $get_all = true;
16 protected $limit = 10;
17 protected $offset = 1;
18 protected $params = array();
19
20 /**
21 * Create query for product name filter
22 *
23 * @param object $filter Product name filter.
24 *
25 * @return string
26 */
27 public static function get_product_name_query( $filter ) {
28 global $wpdb;
29 $comparation = 'is_one_of' === $filter['comparation']['value'] ? 'IN' : 'NOT IN';
30 $array_values = array_map(
31 function( $member ) {
32 return $member['label'];
33 },
34 $filter['value']
35 );
36
37 $query = '';
38 if ( ! empty( $array_values ) ) {
39 $placeholders = implode( ',', array_fill( 0, count( $array_values ), '%s' ) );
40 $query = $wpdb->prepare( "{$wpdb->prefix}posts.post_title {$comparation} ({$placeholders})", $array_values );
41 }
42
43 return $query;
44 }
45
46 /**
47 * Create query for product id filter
48 *
49 * @param object $filter Product id filter.
50 *
51 * @return string
52 */
53 public static function get_product_id_query( $filter ) {
54 global $wpdb;
55 $comparation = 'is_one_of' === $filter['comparation']['value'] ? 'IN' : 'NOT IN';
56 $array_values = array_map(
57 function( $member ) {
58 return (int) $member['value'];
59 },
60 $filter['value']
61 );
62 $int_array_values = join( ',', $array_values );
63
64 $query = '';
65 if ( ! empty( $int_array_values ) ) {
66 $query = "{$wpdb->prefix}posts.ID {$comparation} ({$int_array_values})";
67 }
68
69 return $query;
70 }
71
72 /**
73 * Create query for product category filter
74 *
75 * @param object $filter Product category filter.
76 *
77 * @return string
78 */
79 public static function get_product_category_query( $filter ) {
80 global $wpdb;
81 $comparation = 'is_one_of' === $filter['comparation']['value'] ? 'IN' : 'NOT IN';
82 $array_values = array_map(
83 function( $member ) {
84 return $member['label'];
85 },
86 $filter['value']
87 );
88 $query = '';
89 if ( ! empty( $array_values ) ) {
90 $placeholders = implode( ',', array_fill( 0, count( $array_values ), '%s' ) );
91 $query = $wpdb->prepare( "( term_taxonomy.taxonomy = 'product_cat' AND terms.name {$comparation} ({$placeholders}) )", $array_values );
92 }
93
94 return $query;
95 }
96
97 /**
98 * Create query for product tag filter
99 *
100 * @param object $filter Product tag filter.
101 *
102 * @return string
103 */
104 public static function get_product_tag_query( $filter ) {
105 global $wpdb;
106 $comparation = 'is_one_of' === $filter['comparation']['value'] ? 'IN' : 'NOT IN';
107 $array_values = array_map(
108 function( $member ) {
109 return $member['label'];
110 },
111 $filter['value']
112 );
113
114 $query = '';
115 if ( ! empty( $array_values ) ) {
116 $placeholders = implode( ',', array_fill( 0, count( $array_values ), '%s' ) );
117 $query = "( {$wpdb->prefix}posts.ID IN (
118 SELECT term_relationships.object_id as id
119 FROM {$wpdb->prefix}term_relationships AS term_relationships
120 JOIN {$wpdb->prefix}term_taxonomy AS term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id
121 JOIN {$wpdb->prefix}terms AS terms ON terms.term_id = term_taxonomy.term_id
122
123 WHERE ( term_taxonomy.taxonomy = 'product_tag' AND terms.name {$comparation} ({$placeholders}) )
124 GROUP BY term_relationships.object_id
125 ))";
126 $query = $wpdb->prepare( $query, $array_values );
127 }
128
129 return $query;
130 }
131
132 /**
133 * Create query for product price filter
134 *
135 * @param object $filter Product price filter.
136 *
137 * @return string
138 */
139 public static function get_product_price_query( $filter ) {
140 global $wpdb;
141 switch ( $filter['comparation']['value'] ) {
142 case 'equal':
143 $comparation = '=';
144 break;
145 case 'not_equal':
146 $comparation = '<>';
147 break;
148 case 'greater_than':
149 $comparation = '>';
150 break;
151 case 'less_than':
152 $comparation = '<';
153 break;
154 default:
155 $comparation = '=';
156 }
157
158 $query = $wpdb->prepare( "( postmeta.meta_key = '_price' AND postmeta.meta_value {$comparation} %f )", $filter['value'] );
159 return $query;
160 }
161
162 /**
163 * Create query for product in stock filter
164 *
165 * @param object $filter Product in stock filter.
166 *
167 * @return string
168 */
169 public static function get_product_in_stock_query( $filter ) {
170 global $wpdb;
171 switch ( $filter['comparation']['value'] ) {
172 case 'equal':
173 $comparation = '=';
174 break;
175 case 'not_equal':
176 $comparation = '<>';
177 break;
178 case 'greater_than':
179 $comparation = '>';
180 break;
181 case 'less_than':
182 $comparation = '<';
183 break;
184 default:
185 $comparation = '=';
186 }
187
188 $is_out_of_stock = false;
189
190 if ( 0 == $filter['value'] && ( '=' === $comparation ) ) {
191 $is_out_of_stock = true;
192 }
193
194 if ( in_array( $filter['value'], array( 0, 1 ), true ) && ( '<' === $comparation ) ) {
195 $is_out_of_stock = true;
196 }
197
198 if ( $is_out_of_stock ) {
199 $query = "( stock_status = 'outofstock' )";
200 } else {
201 $query = $wpdb->prepare( "( stock_quantity {$comparation} %d OR ( stock_quantity IS NULL AND stock_status = 'instock' ) )", $filter['value'] );
202 }
203
204 return $query;
205 }
206
207 public function parse_filters_to_query( $filter ) {
208 $query = ' FALSE';
209 if ( 'prod_name' === $filter['type']['value'] ) {
210 $query = self::get_product_name_query( $filter );
211 }
212 if ( 'prod_category' === $filter['type']['value'] ) {
213 $query = self::get_product_category_query( $filter );
214 }
215 if ( 'prod_tag' === $filter['type']['value'] ) {
216 $query = self::get_product_tag_query( $filter );
217 }
218
219 return " {$query}";
220 }
221
222 public function get_where_clause() {
223
224 if ( empty( $this->filters ) ) {
225 if ( ! empty( $this->params ) ) {
226 return ' TRUE';
227 }
228 return ' FALSE';
229 }
230
231 $filters = $this->filters;
232 $apply = $this->apply;
233 $query = '';
234 foreach ( $filters as $key => $filter ) {
235 if ( 0 < $key ) {
236 if ( ! empty( $apply['value'] ) && $apply['value'] === 'all') {
237 $query .= ' AND';
238 } else {
239 $query .= ' OR';
240 }
241 }
242 $query .= $this->parse_filters_to_query( $filter );
243 }
244
245 if ( empty ( $query ) ) {
246 return " FALSE";
247 } else {
248 return "( {$query} )";
249 }
250 }
251
252 public function get_join_clause() {
253 global $wpdb;
254 $query = "JOIN {$wpdb->prefix}postmeta AS postmeta ON {$wpdb->prefix}posts.ID = postmeta.post_id";
255 $query .= " LEFT JOIN {$wpdb->prefix}wc_product_meta_lookup AS wc_product_meta_lookup ON {$wpdb->prefix}posts.ID = wc_product_meta_lookup.product_id";
256 $query .= " LEFT JOIN {$wpdb->prefix}term_relationships AS term_relationships ON term_relationships.object_id = {$wpdb->prefix}posts.ID";
257 $query .= " JOIN {$wpdb->prefix}term_taxonomy AS term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id";
258 $query .= " JOIN {$wpdb->prefix}terms AS terms ON terms.term_id = term_taxonomy.term_id";
259 return $query;
260 }
261
262 public function get_search_query() {
263
264 if ( ! isset( $this->params ) ) {
265 return ' TRUE';
266 }
267
268 global $wpdb;
269 $params = $this->params;
270
271 $product_name = ! empty( $params['product_name'] ) ? $params['product_name'] : '';
272 $category_id = ! empty( $params['category_id'] ) ? (int) $params['category_id'] : '';
273 $tag_id = ! empty( $params['tag_id'] ) ? (int) $params['tag_id'] : '';
274
275 $option_set_id = ! empty( $params['option_set_id'] ) ? (int) $params['option_set_id'] : '';
276 $product_type = ! empty( $params['product_type'] ) ? $params['product_type'] : 'all'; // all, assigned, unassigned.
277
278 $product_filter_one_by_one = array();
279 if ( ! empty( $option_set_id ) ) {
280 $products_option_set = get_post_meta( $option_set_id, '_yaye_products', true );
281 $product_filter_one_by_one = $products_option_set['product_filter_one_by_one'];
282 }
283 $string_product_filter_one_by_one = join( ',', $product_filter_one_by_one );
284
285 $search_product_type_where = 'TRUE';
286 $search_product_name_where = 'TRUE';
287 $search_category_where = 'TRUE';
288 $search_tag_where = 'TRUE';
289
290 if ( 'assigned' === $product_type ) {
291 if ( '' === $string_product_filter_one_by_one ) {
292 $search_product_type_where = 'FALSE';
293 } else {
294 // Sanitize the product IDs array
295 $product_ids = array_map( 'intval', $product_filter_one_by_one );
296 $product_ids = array_filter( $product_ids ); // Remove any non-numeric values
297 if ( ! empty( $product_ids ) ) {
298 $placeholders = implode( ',', array_fill( 0, count( $product_ids ), '%d' ) );
299 $search_product_type_where = $wpdb->prepare( "( {$wpdb->prefix}posts.ID IN ({$placeholders}) )", $product_ids );
300 } else {
301 $search_product_type_where = 'FALSE';
302 }
303 }
304 } elseif ( 'unassigned' === $product_type && '' !== $string_product_filter_one_by_one ) {
305 // Sanitize the product IDs array
306 $product_ids = array_map( 'intval', $product_filter_one_by_one );
307 $product_ids = array_filter( $product_ids ); // Remove any non-numeric values
308 if ( ! empty( $product_ids ) ) {
309 $placeholders = implode( ',', array_fill( 0, count( $product_ids ), '%d' ) );
310 $search_product_type_where = $wpdb->prepare( "( {$wpdb->prefix}posts.ID NOT IN ({$placeholders}) )", $product_ids );
311 } else {
312 $search_product_type_where = 'TRUE';
313 }
314 }
315
316 if ( ! empty( $product_name ) ) {
317 $search_product_name_where = $wpdb->prepare( "( {$wpdb->prefix}posts.post_title LIKE %s )", '%' . $wpdb->esc_like( $product_name ) . '%' );
318 };
319
320 if ( ! empty( $category_id ) ) {
321 $search_category_where = "( term_taxonomy.taxonomy = 'product_cat' AND terms.term_id = {$category_id} )";
322 };
323
324 if ( ! empty( $tag_id ) ) {
325 $search_tag_where = "( {$wpdb->prefix}posts.ID IN (
326 SELECT term_relationships.object_id as id
327 FROM {$wpdb->prefix}term_relationships AS term_relationships
328 JOIN {$wpdb->prefix}term_taxonomy AS term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id
329 JOIN {$wpdb->prefix}terms AS terms ON terms.term_id = term_taxonomy.term_id
330 WHERE ( term_taxonomy.taxonomy = 'product_tag' AND terms.term_id = {$tag_id} )
331 GROUP BY term_relationships.object_id
332 ))";
333 };
334
335 $search_where = $search_product_type_where . ' AND ' . $search_product_name_where . ' AND ' . $search_category_where . ' AND ' . $search_tag_where;
336 return $search_where;
337 }
338
339 /**
340 * WHERE fragment for product listing queries (shared by posts_clauses and count).
341 *
342 * @return string
343 */
344 private function get_products_sql_where() {
345 global $wpdb;
346 return " AND {$wpdb->prefix}posts.post_type IN ('product') AND {$wpdb->prefix}posts.post_status = 'publish' AND {$this->get_where_clause()} AND {$this->get_search_query()}";
347 }
348
349 public function posts_clauses( $args, $wp_query ) {
350 global $wpdb;
351
352 $args['fields'] = "{$wpdb->prefix}posts.ID as id, wc_product_meta_lookup.stock_quantity, wc_product_meta_lookup.stock_status";
353 $args['join'] = $this->get_join_clause();
354 $args['where'] = $this->get_products_sql_where();
355 $args['groupby'] = "{$wpdb->prefix}posts.ID";
356 $args['orderby'] = 'post_title';
357 $args['limits'] = '';
358 if ( ! $this->get_all ) {
359 $args['limits'] = "LIMIT {$this->offset}, {$this->limit}";
360 }
361 return $args;
362 }
363
364 /**
365 * Get Products in database.
366 *
367 * @param object $filters Rule filters.
368 * @param object $apply Any or All conditions.
369 * @param object $params Params.
370 *
371 * @return array
372 */
373 public function get_products( $filters = null, $apply = null, $params = array() ) {
374 global $wpdb;
375 $limit = ! empty( $params['page_size'] ) && is_numeric( $params['page_size'] ) ? (int) $params['page_size'] : 10;
376 $page = ! empty( $params['current'] ) && is_numeric( $params['current'] ) ? (int) $params['current'] : 1;
377 $offset = ( $page - 1 ) * $limit;
378 $this->filters = $filters;
379 $this->params = $params;
380 $this->apply = $apply;
381 $this->limit = $limit;
382 $this->offset = $offset;
383
384 // Get total count
385 $countQuery = $wpdb->prepare("SELECT COUNT(*) FROM {$wpdb->prefix}posts WHERE TRUE {$this->get_products_sql_where()}");
386 $total_items = (int) $wpdb->get_var( $countQuery );
387
388 $this->get_all = false;
389 add_filter( 'posts_clauses', array( $this, 'posts_clauses' ), 10, 2 );
390 $query = new \WP_Query();
391 $query_result = $query->query( array() );
392 remove_filter( 'posts_clauses', array( $this, 'posts_clauses' ), 10 );
393
394 $result = array(
395 'product_list' => $query_result,
396 'current_page' => $page,
397 'total_items' => $total_items,
398 );
399
400 return $result;
401 }
402
403 /**
404 * Get Products in database.
405 *
406 * @param object $filters Rule filters.
407 * @param object $apply Any or All conditions.
408 *
409 * @return array
410 */
411 public function get_product_match_option_set_list( $filters = null, $apply = null ) {
412 global $wpdb;
413
414 $filters = $this->expand_category_conditions( $filters );
415
416 $this->filters = $filters;
417 $this->apply = $apply;
418
419 add_filter( 'posts_clauses', array( $this, 'posts_clauses' ), 10, 2 );
420 $query = new \WP_Query();
421 $result_query_all = $query->query( array() );
422 remove_filter( 'posts_clauses', array( $this, 'posts_clauses' ), 10 );
423
424 return $result_query_all;
425 }
426
427 /**
428 * Expand product_category conditions to include children categories automatically.
429 *
430 * @param array $filters
431 * @return array
432 */
433 public function expand_category_conditions( $filters ) {
434 if ( empty( $filters ) || ! is_array( $filters ) ) {
435 return $filters;
436 }
437
438 foreach ( $filters as &$cond ) {
439
440 if (
441 isset( $cond['type']['value'] ) &&
442 $cond['type']['value'] === 'prod_category' &&
443 ! empty( $cond['value'] )
444 ) {
445 $selected_ids = array_map(
446 'intval',
447 wp_list_pluck( $cond['value'], 'value' )
448 );
449
450 $all_cat_ids = [];
451
452 foreach ( $selected_ids as $cid ) {
453
454 $children = get_term_children( $cid, 'product_cat' );
455
456 if ( is_array( $children ) ) {
457 $all_cat_ids = array_merge( $all_cat_ids, $children );
458 }
459
460 $all_cat_ids[] = $cid;
461 }
462
463 $all_cat_ids = array_unique( array_map( 'intval', $all_cat_ids ) );
464
465 $cond['value'] = array_map( function ( $id ) {
466 $term = get_term( $id );
467 return [
468 'value' => $id,
469 'label' => $term && ! is_wp_error( $term ) ? $term->name : '',
470 ];
471 }, $all_cat_ids );
472 }
473 }
474
475 return $filters;
476 }
477 }
478