PluginProbe
Filter Everything — WordPress & WooCommerce Filters / 1.9.7
Filter Everything — WordPress & WooCommerce Filters v1.9.7
1.9.7 1.9.6 1.9.5 1.9.4 1.9.3 1.9.2.2 1.9.2.1 trunk 1.2.1 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.4.1 1.4.4 1.4.5 1.4.8 1.4.9 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 All 52 releases
← All changes | src/Entities/PostMetaNumEntity.php +132 -34 1.9.2.11.9.7 View file →
@@ -9,9 +9,17 @@
9 9 class PostMetaNumEntity implements Entity
10 10 {
11 11 use PostMetaTrait;
12 12 public $items = [];
13 + /**
14 + * Declared explicitly: assigned from the outside in
15 + * EntityManager::prepareEntitiesToDisplay(); dynamic properties are
16 + * deprecated since PHP 8.2.
17 + */
18 + public $items_sort = [];
13 19
20 + public $filter = [];
21 +
14 22 protected $product_cache = [];
15 23
16 24 public $entityName = '';
17 25
@@ -175,8 +183,9 @@
175 183 'min' => 0,
176 184 'max' => 0
177 185 ];
178 186 $post_and_types = [];
187 + $post_and_meta_values = [];
179 188 $translatable_post_type_exists = false;
180 189
181 190 /**
182 191 * Set Post types
@@ -194,9 +203,13 @@
194 203 * Set transient key
195 204 */
196 205 $transient_key = flrt_get_terms_transient_key( 'post_meta_num_'. $this->getName() . $key_in );
197 206
198 - if ( false === ( $result = flrt_get_transient( $transient_key ) ) ) {
207 + $result = flrt_get_transient( $transient_key );
208 +
209 + // Cache format v2: ['vals' => [post_id => float|float[]], 'types' => [post_id => post_type]].
210 + // Legacy format cached raw SQL rows — detect and rebuild those.
211 + if ( ! is_array( $result ) || ! isset( $result['vals'], $result['types'] ) ) {
199 212 // Get all post meta values
200 213 $sql[] = "SELECT {$wpdb->postmeta}.post_id,{$wpdb->postmeta}.meta_value,{$wpdb->posts}.post_type";
201 214 $sql[] = "FROM {$wpdb->postmeta}";
202 215 $sql[] = "LEFT JOIN {$wpdb->posts} ON ({$wpdb->postmeta}.post_id = {$wpdb->posts}.ID)";
@@ -259,29 +272,54 @@
259 272 * Filters terms SQL-query and allows to modify it
260 273 */
261 274 $sql = apply_filters( 'wpc_filter_get_post_meta_num_terms_sql', $sql, $e_name );
262 275
263 - $result = $wpdb->get_results( $sql, ARRAY_A );
276 + $rows = $wpdb->get_results( $sql, ARRAY_A );
264 277
265 - $clean_from_non_numeric = [];
266 - foreach ( $result as $single_post ) {
278 + // Aggregate raw rows into the compact v2 maps. A post can have
279 + // several meta rows with different values (e.g. WC variable
280 + // products keep one _price row per distinct child price) — such
281 + // posts get an array of floats instead of a single float.
282 + $vals = [];
283 + $types = [];
284 + foreach ( $rows as $single_post ) {
267 285 if ( preg_match( '/[^\d\.\-]+/', $single_post['meta_value'] ) ) {
268 286 continue;
269 287 }
270 288
271 - $clean_from_non_numeric[] = $single_post;
289 + $post_id = (int) $single_post['post_id'];
290 + $meta_value = (float) $single_post['meta_value'];
291 +
292 + if ( isset( $vals[ $post_id ] ) ) {
293 + if ( ! is_array( $vals[ $post_id ] ) ) {
294 + $vals[ $post_id ] = array( $vals[ $post_id ] );
295 + }
296 + $vals[ $post_id ][] = $meta_value;
297 + } else {
298 + $vals[ $post_id ] = $meta_value;
299 + }
300 +
301 + $types[ $post_id ] = $single_post['post_type'];
272 302 }
273 - $result = $clean_from_non_numeric;
303 + unset( $rows );
274 304
305 + $result = array( 'vals' => $vals, 'types' => $types );
306 + unset( $vals, $types );
307 +
275 308 flrt_set_transient( $transient_key, $result, FLRT_TRANSIENT_PERIOD_HOURS * HOUR_IN_SECONDS );
276 309 }
277 310
278 - if( ! empty( $result ) ) {
311 + $meta_vals = isset( $result['vals'] ) ? $result['vals'] : [];
312 + $meta_types = isset( $result['types'] ) ? $result['types'] : [];
279 313
314 + if( ! empty( $meta_vals ) ) {
315 +
280 316 $postsIn_flipped = array_flip( $alreadyFilteredPosts );
281 317 $wpManager = Container::instance()->getWpManager();
282 318 $queried_values = $wpManager->getQueryVar( 'queried_values', [] );
319 + $fss = Container::instance()->getFilterSetService();
283 320 $filter_slug = false;
321 + $setId = false;
284 322
285 323 /**
286 324 * Check if this filter was queried
287 325 */
@@ -287,8 +325,9 @@
287 325 */
288 326 foreach ( $queried_values as $slug => $filter ) {
289 327 if ( $filter[ 'e_name' ] === $this->getName() ) {
290 328 $filter_slug = $slug;
329 + $setId = $filter['parent'];
291 330 break;
292 331 }
293 332 }
294 333
@@ -311,19 +350,18 @@
311 350 }
312 351
313 352 if($this->is_woo_discount_rules && (strpos($this->entityName, '_price') !== false)){
314 353 $wdr_woo_discount_rules = $this->getWooDiscountRulesClass();
315 - $product_ids = array_map('intval', array_column($result, 'post_id'));
316 - $this->preloadProducts($product_ids);
354 + $this->preloadProducts( array_keys( $meta_vals ) );
317 355 }
318 356
319 - foreach ( $result as $single_post ) {
357 + foreach ( $meta_vals as $post_id => $post_values ) {
320 358 /**
321 359 * If there are already filtered posts, we have to skip posts
322 360 * that are out of the queried list
323 361 */
324 362 if( ! empty( $alreadyFilteredPosts ) ) {
325 - if( ! isset( $postsIn_flipped[ $single_post['post_id'] ] ) ) {
363 + if( ! isset( $postsIn_flipped[ $post_id ] ) ) {
326 364 continue;
327 365 }
328 366 }
329 367
@@ -328,52 +366,89 @@
328 366 }
329 367
330 368 if ($this->is_woo_discount_rules) {
331 369 if (strpos($this->entityName, '_price') !== false) {
332 - $product = $this->getProductCached($single_post['post_id']);
370 + $product = $this->getProductCached($post_id);
333 371 if ($product) {
334 372 $wdr_product_has_sale = $wdr_woo_discount_rules->getProductPriceToDisplay($product);
335 373 if ($wdr_product_has_sale) {
336 - $single_post['meta_value'] = $wdr_product_has_sale['discounted_price'];
374 + $post_values = (float) $wdr_product_has_sale['discounted_price'];
337 375 }
338 376 }
339 377 }
340 378 }
341 379
342 -
343 -
344 380 /**
345 381 * We have to generate and fill two arrays
346 382 * First to detect $min and $max values
347 383 * Second to map post_types with post IDs
348 384 */
349 - $single_post['meta_value'] = (is_float($single_post['meta_value']) ) ? $single_post['meta_value'] : (float) $single_post['meta_value'];
350 - $new_result[] = $single_post['meta_value'];
385 + foreach ( (array) $post_values as $meta_value ) {
386 + $post_and_meta_values[ $post_id ][] = $meta_value;
387 + $new_result[] = $meta_value;
351 388
352 - if ( $min !== false && $single_post['meta_value'] < $min ){
353 - continue;
354 - }
389 + if ( $min !== false && $meta_value < $min ){
390 + continue;
391 + }
355 392
356 - if ( $max !== false && $single_post['meta_value'] > $max ){
357 - continue;
393 + if ( $max !== false && $meta_value > $max ){
394 + continue;
395 + }
396 +
397 + if($this->is_woo_discount_rules){
398 + $this->wdr_product_ids[] = $post_id;
399 + }
400 +
401 + $post_and_types[ $post_id ] = $meta_types[ $post_id ];
358 402 }
359 -
360 - $this->wdr_product_ids[] = (int)$single_post['post_id'];
361 - $post_and_types[ $single_post['post_id'] ] = $single_post['post_type'];
362 403 }
363 404
364 405 }
365 -
406 + $abs_min_and_max = [
407 + 'abs_min' => 0,
408 + 'abs_max' => 0,
409 + ];
366 410 if( ! empty( $new_result ) ){
367 411 $min_and_max = [
368 412 'min' => apply_filters( 'wpc_set_num_shift', min( $new_result ), $this->getName(), 'min' ),
369 413 'max' => apply_filters( 'wpc_set_num_shift', max( $new_result ), $this->getName(), 'max' ),
370 414 ];
415 +
416 + $flat = [];
417 + foreach ($post_and_meta_values as $post_id => $values) {
418 + foreach ($values as $value) {
419 + $flat[$post_id][] = $value;
420 + }
421 + }
422 +
423 + $all_values = array_merge(...array_values($post_and_meta_values));
424 +
425 + $abs_min = min($all_values);
426 + $abs_max = max($all_values);
427 +
428 + $min_post_id = null;
429 + $max_post_id = null;
430 +
431 + foreach ($post_and_meta_values as $post_id => $values) {
432 + if (in_array($abs_min, $values)) {
433 + $min_post_id = $post_id;
434 + }
435 + if (in_array($abs_max, $values)) {
436 + $max_post_id = $post_id;
437 + }
438 + }
439 +
440 + $abs_min_and_max = [
441 + 'abs_min' => $abs_min,
442 + 'abs_max' => $abs_max,
443 + ];
444 +
445 + $post_and_meta_values[$min_post_id] = [$min_and_max['min']];
446 + $post_and_meta_values[$max_post_id] = [$min_and_max['max']];
371 447 }
372 448
373 449 $min_and_max = apply_filters( 'wpc_set_min_max', $min_and_max, $this->getName() );
374 -
375 - return $this->convertSelectResult( $min_and_max, $post_and_types );
450 + return $this->convertSelectResult( $min_and_max, $post_and_types, $post_and_meta_values, $abs_min_and_max);
376 451 }
377 452
378 453 public function updateMinAndMaxValues( $postsIn )
379 454 {
@@ -404,8 +479,11 @@
404 479 $name = $name .' '. $slug;
405 480 }
406 481 }
407 482
483 + $name = ($name === 'min') ? esc_html__('min', 'filter-everything') : $name;
484 + $name = ($name === 'max') ? esc_html__('max', 'filter-everything') : $name;
485 +
408 486 if( isset( $queriedFilter['values'][$edge] ) ) {
409 487 $name = $name .' '. $queriedFilter['values'][$edge];
410 488 }else{
411 489 $name = $name .' '. $value;
@@ -413,9 +491,9 @@
413 491
414 492 return apply_filters( 'wpc_filter_post_meta_num_term_name', $name, $this->getName() );
415 493 }
416 494
417 - public function convertSelectResult( $result, $post_and_types = [] ){
495 + public function convertSelectResult( $result, $post_and_types = [], $post_and_meta_values = [], $abs_min_and_max = [] ){
418 496 $return = [];
419 497
420 498 if( ! is_array( $result ) ){
421 499 return $return;
@@ -432,13 +510,15 @@
432 510 $termObject->slug = $edge;
433 511 $termObject->name = $this->createTermName( $edge, $value, $queried_values );
434 512 $termObject->term_id = $edge . '_' . $this->getName();
435 513 $termObject->posts = array_keys( $post_and_types );
514 + $termObject->meta_values = $post_and_meta_values;
436 515 $termObject->count = 0;
437 516 $termObject->cross_count = 0;
438 517 $termObject->post_types = $post_and_types; //[];
439 518 $termObject->$edge = $value;
440 519 $termObject->wp_queried = false;
520 + $termObject->abs_values = $abs_min_and_max;
441 521
442 522 $return[ $edge ] = $termObject;
443 523
444 524 $i++;
@@ -470,11 +550,32 @@
470 550 if (empty($query_post_in)){
471 551 $wp_query->set('posts_per_page', $query_post_in);
472 552 }
473 553 } else {
474 - if ($min !== false) {
554 + if ($min !== false && $max !== false) {
475 555 $min = apply_filters('wpc_unset_num_shift', $min, $this->getName());
556 + $max = apply_filters('wpc_unset_num_shift', $max, $this->getName());
476 557
558 + $type = ( $this->isDecimal($queried_value['step'], $min) || $this->isDecimal($queried_value['step'], $max) ) ? 'DECIMAL(15,6)' : 'NUMERIC';
559 + /**
560 + * Both bounds must live in ONE clause. WP_Meta_Query gives every
561 + * clause its own postmeta JOIN, so separate >= and <= clauses can
562 + * match two DIFFERENT meta rows: a post with several values of the
563 + * key (e.g. variable product _price rows) passed the range even
564 + * when no single value was inside it, and the results disagreed
565 + * with the term counters. BETWEEN checks the same row.
566 + */
567 + $meta_query = array(
568 + 'key' => $key,
569 + 'value' => array( $min, $max ),
570 + 'compare' => 'BETWEEN',
571 + 'type' => $type
572 + );
573 + $this->addMetaQueryArray($meta_query);
574 +
575 + } elseif ($min !== false) {
576 + $min = apply_filters('wpc_unset_num_shift', $min, $this->getName());
577 +
477 578 $type = $this->isDecimal($queried_value['step'], $min) ? 'DECIMAL(15,6)' : 'NUMERIC';
478 579 $meta_query = array(
479 580 'key' => $key,
480 581 'value' => $min,
@@ -481,11 +582,10 @@
481 582 'compare' => '>=',
482 583 'type' => $type
483 584 );
484 585 $this->addMetaQueryArray($meta_query);
485 - }
486 586
487 - if ($max !== false) {
587 + } elseif ($max !== false) {
488 588 $max = apply_filters('wpc_unset_num_shift', $max, $this->getName());
489 589
490 590 $type = $this->isDecimal($queried_value['step'], $max) ? 'DECIMAL(15,6)' : 'NUMERIC';
491 591 $meta_query = array(
@@ -495,10 +595,8 @@
495 595 'type' => $type
496 596 );
497 597 $this->addMetaQueryArray($meta_query);
498 598 }
499 -
500 - $this->addMetaQueryArray($meta_query);
501 599
502 600 if (count($this->new_meta_query) > 1) {
503 601 $this->new_meta_query['relation'] = 'AND';
504 602 }