geminilabs

[site-reviews-filters] Multiple category and custom field filters

Sep 16th, 2022 (edited)
1,686
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 6.39 KB | None | 0 0
  1. /**
  2.  * @updated 2026-04-11
  3.  *
  4.  * Example usage:
  5.  *
  6.  * new CustomReviewFilters([
  7.  *     // Add a custom filter for some child categories
  8.  *     'filter_by_food' => [                    // filter name (must start with "filter_by_")
  9.  *         'parent_term' => 'foods',            // parent category ID or slug (must be a Site Reviews category!)
  10.  *         'placeholder' => 'All Foods',        // dropdown placeholder
  11.  *         'type' => 'term',                    // type of filter (term or custom)
  12.  *     ],
  13.  *     // Add a custom filter for a custom field named "surcharge"
  14.  *     'filter_by_surcharge' => [               // filter name (must start with "filter_by_")
  15.  *         'cast' => 'string',                  // What to cast the value as (string or int)
  16.  *         'type' => 'custom',                  // type of filter (term or custom)
  17.  *         'placeholder' => 'Any Surcharge',    // dropdown placeholder
  18.  *         'options' => [                       // dropdown options
  19.  *             'Yes' => 'Surcharge: Yes',
  20.  *             'No' => 'Surcharge: No',
  21.  *         ],
  22.  *     ],
  23.  * ]);
  24.  *
  25.  */
  26.  
  27. class CustomReviewFilters
  28. {
  29.     public $filters = [];
  30.  
  31.     public function __construct(array $filters = [])
  32.     {
  33.         add_action('init', function () use ($filters) {
  34.             if (!function_exists('glsr')
  35.                 || !function_exists('glsr_get')
  36.                 || !glsr()->addon('site-reviews-filters')
  37.                 || !class_exists('\GeminiLabs\SiteReviews\Addon\Filters\Defaults\FilteredDefaults')) {
  38.                 return;
  39.             }
  40.             $this->filters = $this->normalize($filters);
  41.             foreach ($this->filters as $filter => $values) {
  42.                 if ('custom' === $values['type']) {
  43.                     add_action('site-reviews-filters/sql-and/build/'.$filter, [$this, 'filterSqlAndForCustom'], 10, 3);
  44.                     add_action('site-reviews-filters/sql-join/build/'.$filter, [$this, 'filterSqlJoinForCustom'], 10, 3);
  45.                 }
  46.             }
  47.             add_filter('site-reviews-filters/defaults/filtered/defaults', [$this, 'filterDefaults']);
  48.             add_filter('site-reviews-filters/defaults/filtered/casts', [$this, 'filterCasts']);
  49.             add_filter('site-reviews-filters/config/forms/filters-form', [$this, 'filterConfig']);
  50.             add_filter('site-reviews-filters/status/filtered-by', [$this, 'filterFilteredBy'], 10, 2);
  51.             add_filter('site-reviews/shortcode/args/site_reviews', [$this, 'filterShortcodeAttributes']);
  52.         });
  53.     }
  54.    
  55.     public function filterDefaults(array $defaults)
  56.     {
  57.         foreach ($this->filters as $filter => $values) {
  58.             $defaults[$filter] = '';
  59.         }
  60.         return $defaults;
  61.     }
  62.  
  63.     public function filterCasts(array $casts)
  64.     {
  65.         foreach ($this->filters as $filter => $values) {
  66.             $casts[$filter] = glsr_get($values, 'cast', 'string');
  67.         }
  68.         return $casts;
  69.     }
  70.  
  71.     public function filterConfig(array $config)
  72.     {
  73.         foreach ($this->filters as $filter => $values) {
  74.             $config[$filter] = [
  75.                 'options' => ['' => $values['placeholder']] + $values['options'],
  76.                 'type' => 'select',
  77.                 'value' => filter_input(INPUT_GET, $filter, FILTER_SANITIZE_FULL_SPECIAL_CHARS),
  78.             ];
  79.         }
  80.         return $config;
  81.     }
  82.  
  83.     public function filterFilteredBy(array $filteredBy, array $filters)
  84.     {
  85.         foreach ($filters as $filter => $value) {
  86.             if (array_key_exists($filter, $this->filters)) {
  87.                 $filteredBy[] = $this->filters[$filter]['name'] ?? $this->filters[$filter]['options'][$value] ?? $value;
  88.             }
  89.         }
  90.         return $filteredBy;
  91.     }
  92.  
  93.     public function filterShortcodeAttributes(array $attributes)
  94.     {
  95.         $parameters = glsr('Addon\Filters\Defaults\FilteredDefaults')->merge();
  96.         $terms = [$attributes['assigned_terms'] ?? ''];
  97.         foreach ($this->filters as $filter => $values) {
  98.             if ('term' === $values['type'] && !empty($parameters[$filter])) {
  99.                 $terms[] = $parameters[$filter];
  100.             }
  101.         }
  102.         $attributes['assigned_terms'] = implode(',', $terms);
  103.         return $attributes;
  104.     }
  105.  
  106.     public function filterSqlAndForCustom($value, $key, $modifier)
  107.     {
  108.         $tablekey = str_replace('filters/', '', $key);
  109.         $metakey = str_replace('filters/filter_by_', '_custom_', $key);
  110.         $modifier->values[$key] = sprintf("AND (%s.meta_key = '%s' AND %s.meta_value = '%s')", $tablekey, $metakey, $tablekey, $value);
  111.     }
  112.  
  113.     public function filterSqlJoinForCustom($value, $key, $modifier)
  114.     {
  115.         global $wpdb;
  116.         $tablekey = str_replace('filters/', '', $key);
  117.         $modifier->values[$key] = "INNER JOIN {$wpdb->posts} AS p ON r.review_id = p.ID";
  118.         $modifier->values[$key] = sprintf("INNER JOIN {$wpdb->postmeta} AS %s ON r.review_id = %s.post_id", $tablekey, $tablekey);
  119.     }
  120.  
  121.     public function normalize(array $filters)
  122.     {
  123.         $normalized = [];
  124.         foreach ($filters as $filter => $values) {
  125.             $filter = sanitize_key($filter);
  126.             if (!str_starts_with($filter, 'filter_by_')) {
  127.                 continue;
  128.             }
  129.             $values = wp_parse_args($values, [
  130.                 'cast' => '',
  131.                 'name' => null,
  132.                 'options' => [],
  133.                 'parent_term' => '',
  134.                 'placeholder' => '',
  135.                 'type' => '',
  136.             ]);
  137.             if ('custom' === $values['type']) {
  138.                 $normalized[$filter] = $this->normalizeCustomFilter($values);
  139.             } elseif ('term' === $values['type']) {
  140.                 $term = term_exists($values['parent_term'], glsr()->taxonomy);
  141.                 if (!empty($term)) {
  142.                     $normalized[$filter] = $this->normalizeTermFilter($values, $term['term_id']);
  143.                 }
  144.             }
  145.         }
  146.         return $normalized;
  147.     }
  148.  
  149.     protected function normalizeCustomFilter(array $values)
  150.     {
  151.         $values['options'] = is_array($values['options']) ? $values['options'] : [];
  152.         return $values;
  153.     }
  154.  
  155.     protected function normalizeTermFilter(array $values, int $termId)
  156.     {
  157.         $values['cast'] = 'int';
  158.         $values['options'] = get_terms([
  159.             'count' => false,
  160.             'fields' => 'id=>name',
  161.             'hide_empty' => true,
  162.             'parent' => $termId,
  163.             'taxonomy' => glsr()->taxonomy,
  164.         ]);
  165.         $values['parent_term'] = $termId;
  166.         return $values;
  167.     }
  168. }
Advertisement
Add Comment
Please, Sign In to add comment