| @@ -1,10 +1,10 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace FilterEverything\Filter; |
| 4 | 4 | |
| 5 | -if ( ! defined('WPINC') ) { | |
| 6 | - wp_die(); | |
| 5 | +if ( ! defined('ABSPATH') ) { | |
| 6 | + exit; | |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | 9 | class Chips |
| 10 | 10 | { |
| @@ -13,12 +13,16 @@ | ||
| 13 | 13 | private $queried; |
| 14 | 14 | |
| 15 | 15 | private $showReset; |
| 16 | 16 | |
| 17 | + private $use_apply_button; | |
| 18 | + | |
| 17 | 19 | private $counter = 1; |
| 18 | 20 | |
| 19 | 21 | private $setFilterKeys = []; |
| 20 | 22 | |
| 23 | + private $chipKeys = []; | |
| 24 | + | |
| 21 | 25 | public function __construct( $showReset = false, $setIds = [] ) |
| 22 | 26 | { |
| 23 | 27 | $em = Container::instance()->getEntityManager(); |
| 24 | 28 | $wpManager = Container::instance()->getWpManager(); |
| @@ -25,27 +29,26 @@ | ||
| 25 | 29 | |
| 26 | 30 | $this->queried = $wpManager->getQueryVar('queried_values'); |
| 27 | 31 | $sets = $wpManager->getQueryVar('wpc_page_related_set_ids'); |
| 28 | 32 | |
| 29 | - if( ! $wpManager->getQueryVar( 'allowed_filter_page' ) ){ | |
| 30 | - return false; | |
| 31 | - } | |
| 32 | - | |
| 33 | 33 | $this->showReset = $showReset; |
| 34 | 34 | |
| 35 | 35 | if( ! $setIds || empty( $setIds ) ){ |
| 36 | - foreach ( $sets as $set ){ | |
| 37 | - $setIds[] = $set['ID']; | |
| 36 | + if(!empty($sets) && is_array( $sets ) ) { | |
| 37 | + foreach ($sets as $set) { | |
| 38 | + $setIds[] = $set['ID']; | |
| 39 | + } | |
| 38 | 40 | } |
| 39 | 41 | } |
| 40 | 42 | |
| 41 | 43 | if( $setIds ){ |
| 42 | 44 | $this->setFilterKeys = $em->getSetFilterKeys( $setIds ); |
| 43 | - | |
| 44 | - foreach ($sets as $set) { | |
| 45 | - if( in_array( $set['ID'], $setIds ) ){ | |
| 46 | - $postType = $set['filtered_post_type']; | |
| 47 | - $this->fillChips( $postType ); | |
| 45 | + if(!empty($sets) && is_array( $sets ) ) { | |
| 46 | + foreach ($sets as $set) { | |
| 47 | + if (in_array($set['ID'], $setIds)) { | |
| 48 | + $postType = $set['filtered_post_type']; | |
| 49 | + $this->fillChips($set['ID'], $postType ); | |
| 50 | + } | |
| 48 | 51 | } |
| 49 | 52 | } |
| 50 | 53 | } |
| 51 | 54 | |
| @@ -52,77 +55,183 @@ | ||
| 52 | 55 | unset( $em ); |
| 53 | 56 | |
| 54 | 57 | } |
| 55 | 58 | |
| 56 | - private function fillChips( $postType = '' ) | |
| 59 | + /** | |
| 60 | + * Chips are collected across all page-related Sets; the same queried | |
| 61 | + * value must produce ONE chip even when the Sets disagree on | |
| 62 | + * mode-dependent attributes (e.g. Apply-button link classes), | |
| 63 | + * so deduplication goes by identity key, not by the whole array. | |
| 64 | + */ | |
| 65 | + private function addChip( $key, $toAdd ) | |
| 57 | 66 | { |
| 67 | + if ( ! isset( $this->chipKeys[ $key ] ) ) { | |
| 68 | + $this->chips[ $this->counter ] = $toAdd; | |
| 69 | + $this->chipKeys[ $key ] = true; | |
| 70 | + $this->counter++; | |
| 71 | + } | |
| 72 | + } | |
| 58 | 73 | |
| 59 | - if( $this->queried ){ | |
| 60 | - $em = Container::instance()->getEntityManager(); | |
| 61 | - $urlManager = new UrlManager(); | |
| 74 | + private function fillChips( $setId, $postType = '' ) | |
| 75 | + { | |
| 76 | + if( $this->queried || ( isset( $_GET['srch'] ) && $_GET['srch'] ) ) { | |
| 77 | + $em = Container::instance()->getEntityManager(); | |
| 78 | + $urlManager = Container::instance()->getUrlManager(); | |
| 79 | + $filterSet = Container::instance()->getFilterSetService(); | |
| 80 | + $filter_set_params = $filterSet->getSet($setId); | |
| 81 | + $use_apply_button = (isset($filter_set_params['use_apply_button'] ) && $filter_set_params['use_apply_button']['value'] === 'yes') && flrt_instant_recount(); | |
| 62 | 82 | |
| 63 | - if( $this->showReset ){ | |
| 83 | + // Crawler-links option: in free every term chip becomes a <span> | |
| 84 | + // (filter pages are noindex there by design); in PRO (smart spans) a | |
| 85 | + // term chip keeps its real <a> only when its removal target is indexable | |
| 86 | + $hide_chip_links = flrt_get_option('disable_filter_links_for_bots') === 'on'; | |
| 87 | + $judge_chip_links = $hide_chip_links && function_exists('flrt_indexable_link_target'); | |
| 64 | 88 | |
| 89 | + if ($this->showReset) { | |
| 90 | + $reset_button_class = 'wpc-chip-reset-all'; | |
| 91 | + if ($use_apply_button) { | |
| 92 | + $reset_button_class .= ' wpc-apply-button-chip wpc-apply-button-chips-reset'; | |
| 93 | + } | |
| 65 | 94 | $toAdd = array( |
| 66 | 95 | 'link' => $urlManager->getResetUrl(), |
| 67 | 96 | 'name' => esc_html__('Reset all', 'filter-everything'), |
| 68 | - 'class' => 'wpc-chip-reset-all' | |
| 97 | + 'class' => $reset_button_class, | |
| 98 | + 'link_class' => $reset_button_class | |
| 69 | 99 | ); |
| 70 | 100 | |
| 71 | - if( ! in_array( $toAdd, $this->chips ) ){ | |
| 72 | - $this->chips[$this->counter] = $toAdd; | |
| 73 | - $this->counter++; | |
| 74 | - } | |
| 101 | + $this->addChip( 'reset-all', $toAdd ); | |
| 75 | 102 | |
| 76 | 103 | } |
| 77 | 104 | |
| 78 | - foreach ( $this->queried as $slug => $filter ) { | |
| 105 | + if ( $this->queried ) { | |
| 106 | + foreach ($this->queried as $slug => $filter) { | |
| 79 | 107 | |
| 80 | - if( isset( $filter['show_chips'] ) && ( $filter['show_chips'] !== 'yes' ) ){ | |
| 81 | - continue; | |
| 82 | - } | |
| 108 | + if (isset($filter['show_chips']) && ($filter['show_chips'] !== 'yes')) { | |
| 109 | + continue; | |
| 110 | + } | |
| 83 | 111 | |
| 84 | - if( ! empty( $this->setFilterKeys ) ){ | |
| 85 | - $queried_value_key = $filter['entity'].'#'.$filter['e_name']; | |
| 86 | - if( ! in_array( $queried_value_key, $this->setFilterKeys ) ){ | |
| 87 | - continue; | |
| 112 | + if (!empty($this->setFilterKeys)) { | |
| 113 | + $queried_value_key = $filter['entity'] . '#' . $filter['e_name']; | |
| 114 | + if (!in_array($queried_value_key, $this->setFilterKeys)) { | |
| 115 | + continue; | |
| 116 | + } | |
| 88 | 117 | } |
| 89 | - } | |
| 90 | 118 | |
| 91 | - $entityObj = $em->getEntityByFilter( $filter, $postType ); | |
| 119 | + $entityObj = $em->getEntityByFilter($filter, $postType); | |
| 92 | 120 | |
| 93 | - foreach( $filter['values'] as $key => $termSlug ){ | |
| 121 | + foreach ($filter['values'] as $key => $termSlug) { | |
| 122 | + $tempSlug = $termSlug; | |
| 123 | + if ( in_array($filter['entity'], ['post_meta_num', 'tax_numeric'] ) ) { | |
| 124 | + $termSlug = $key; | |
| 125 | + $tempSlug = $key . $filter['e_name']; | |
| 126 | + } | |
| 94 | 127 | |
| 95 | - if( $filter['entity'] === 'post_meta_num' ){ | |
| 96 | - $termSlug = $key; | |
| 97 | - } | |
| 128 | + if ( in_array($filter['entity'], ['post_date', 'post_meta_date'] ) ) { | |
| 129 | + $termSlug = $key; | |
| 130 | + $tempSlug = flrt_range_input_name( $filter['slug'], $key, 'date' ); | |
| 131 | + } | |
| 98 | 132 | |
| 99 | - $termId = $entityObj->getTermId( $termSlug ); | |
| 100 | - $term = $entityObj->getTerm( $termId ); | |
| 101 | 133 | |
| 102 | - // In case if we have no terms for this post type | |
| 103 | - if( ! $term ){ | |
| 104 | - continue; | |
| 105 | - } | |
| 134 | + $termId = $entityObj->getTermId( $termSlug ); | |
| 135 | + $term = $entityObj->getTerm( $termId ); | |
| 106 | 136 | |
| 107 | - $toAdd = array( | |
| 108 | - 'link' => $urlManager->getTermUrl( $termSlug, $filter['e_name'] ), | |
| 109 | - 'name' => $term->name, | |
| 110 | - 'class' => 'wpc-chip-' . $filter['e_name'] .'-'. $termId, | |
| 111 | - 'label' => $filter['label'] | |
| 112 | - ); | |
| 137 | + // In case if we have no terms for this post type | |
| 138 | + if (!$term) { | |
| 139 | + continue; | |
| 140 | + } | |
| 113 | 141 | |
| 114 | - if( ! in_array( $toAdd, $this->chips ) ){ | |
| 115 | - $this->chips[$this->counter] = $toAdd; | |
| 116 | - $this->counter++; | |
| 142 | + $chips_button_class = ''; | |
| 143 | + if ($use_apply_button) { | |
| 144 | + $chips_button_class .= 'wpc-apply-button-chip'; | |
| 145 | + } | |
| 146 | + | |
| 147 | + $toAdd = array( | |
| 148 | + 'link' => $urlManager->getTermUrl($termSlug, $filter['e_name'], $filter['entity']), | |
| 149 | + 'link_class' => $chips_button_class, | |
| 150 | + 'name' => apply_filters('wpc_chips_term_name', $term->name, $term, $filter), | |
| 151 | + 'class' => 'wpc-chip-' . $filter['e_name'] . '-' . $termId, | |
| 152 | + 'e_name' => $filter['e_name'], | |
| 153 | + 'slug' => $tempSlug, | |
| 154 | + 'label' => $filter['label'] | |
| 155 | + ); | |
| 156 | + | |
| 157 | + if ( $judge_chip_links ) { | |
| 158 | + $toAdd['crawlable'] = flrt_indexable_link_target( $term, $filter ); | |
| 159 | + | |
| 160 | + // Removing one value of an OR multi-selection NARROWS the | |
| 161 | + // results to the remaining values — a zero-result target | |
| 162 | + // gets noindexed at runtime (SeoFrontend::countTerms). The | |
| 163 | + // remaining term's cross_count is exactly that target count. | |
| 164 | + if ( $toAdd['crawlable'] | |
| 165 | + && isset( $filter['logic'] ) && $filter['logic'] === 'or' | |
| 166 | + && count( $filter['values'] ) > 1 ) { | |
| 167 | + | |
| 168 | + $remaining_alive = false; | |
| 169 | + foreach ( $filter['values'] as $otherSlug ) { | |
| 170 | + if ( $otherSlug === $termSlug ) { | |
| 171 | + continue; | |
| 172 | + } | |
| 173 | + $otherTerm = $entityObj->getTerm( $entityObj->getTermId( $otherSlug ) ); | |
| 174 | + if ( $otherTerm && ( ! isset( $otherTerm->cross_count ) || (int) $otherTerm->cross_count > 0 ) ) { | |
| 175 | + $remaining_alive = true; | |
| 176 | + break; | |
| 177 | + } | |
| 178 | + } | |
| 179 | + | |
| 180 | + if ( ! $remaining_alive ) { | |
| 181 | + $toAdd['crawlable'] = false; | |
| 182 | + } | |
| 183 | + } | |
| 184 | + } elseif ( $hide_chip_links ) { | |
| 185 | + // Free: no indexability judge — every term chip is a span | |
| 186 | + $toAdd['crawlable'] = false; | |
| 187 | + } | |
| 188 | + | |
| 189 | + if ( $filter['e_name'] === 'product_visibility') { | |
| 190 | + $rating_slugs = array( | |
| 191 | + 'rated-1', | |
| 192 | + 'rated-2', | |
| 193 | + 'rated-3', | |
| 194 | + 'rated-4', | |
| 195 | + 'rated-5' | |
| 196 | + ); | |
| 197 | + | |
| 198 | + if(in_array($termSlug, $rating_slugs)){ | |
| 199 | + $pieces = explode("-", $termSlug); | |
| 200 | + $rating = isset( $pieces[1] ) ? $pieces[1] : 0; | |
| 201 | + if ($rating){ | |
| 202 | + $toAdd['link'] = $urlManager->getTermUrl( $termSlug, $filter['e_name'], $filter['entity'], '', ['rating_slug' => $termSlug]); | |
| 203 | + $toAdd['rating'] = $rating; | |
| 204 | + } | |
| 205 | + } | |
| 206 | + } | |
| 207 | + | |
| 208 | + $this->addChip( 'term:' . $filter['e_name'] . ':' . $tempSlug, $toAdd ); | |
| 117 | 209 | } |
| 118 | 210 | } |
| 119 | 211 | } |
| 120 | 212 | |
| 213 | + $srch = isset( $_GET['srch'] ) ? filter_input( INPUT_GET, 'srch', FILTER_SANITIZE_SPECIAL_CHARS ) : ''; | |
| 214 | + if ( $srch ){ | |
| 215 | + | |
| 216 | + $clear_search_url = $urlManager->getTermUrl( '', '', '', '', [ 'srch'=> true ] ); | |
| 217 | + | |
| 218 | + $toAdd = array( | |
| 219 | + 'link' => $clear_search_url, | |
| 220 | + 'name' => sprintf( __( 'search: %s', 'filter-everything' ), $srch ), | |
| 221 | + 'class' => 'wpc-chip-search', | |
| 222 | + 'label' => $srch, | |
| 223 | + ); | |
| 224 | + | |
| 225 | + $this->addChip( 'search:' . $srch, $toAdd ); | |
| 226 | + } | |
| 227 | + | |
| 121 | 228 | if( count( $this->chips ) === 1 ){ |
| 122 | 229 | $singleChip = reset( $this->chips ); |
| 123 | - if( $singleChip['class'] === 'wpc-chip-reset-all' ){ | |
| 124 | - $this->chips = []; | |
| 230 | + // strpos: the Apply-button variant carries extra classes after 'wpc-chip-reset-all' | |
| 231 | + if( strpos( $singleChip['class'], 'wpc-chip-reset-all' ) === 0 ){ | |
| 232 | + $this->chips = []; | |
| 233 | + $this->chipKeys = []; | |
| 125 | 234 | } |
| 126 | 235 | } |
| 127 | 236 | |
| 128 | 237 | unset( $em, $urlManager ); |