/** * Output widget. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { global $_chosen_attributes; if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } $current_term = is_tax() ? get_queried_object()->term_id : ''; $current_tax = is_tax() ? get_queried_object()->taxonomy : ''; $taxonomy = isset($instance['attribute']) ? wc_attribute_taxonomy_name($instance['attribute']) : $this->settings['attribute']['std']; $query_type = isset($instance['query_type']) ? $instance['query_type'] : $this->settings['query_type']['std']; $display_type = isset($instance['display_type']) ? $instance['display_type'] : $this->settings['display_type']['std']; if (!taxonomy_exists($taxonomy)) { return; } $get_terms_args = array('hide_empty' => '1'); $orderby = wc_attribute_orderby($taxonomy); switch ($orderby) { case 'name': $get_terms_args['orderby'] = 'name'; $get_terms_args['menu_order'] = false; break; case 'id': $get_terms_args['orderby'] = 'id'; $get_terms_args['order'] = 'ASC'; $get_terms_args['menu_order'] = false; break; case 'menu_order': $get_terms_args['menu_order'] = 'ASC'; break; } $terms = get_terms($taxonomy, $get_terms_args); if (0 < count($terms)) { ob_start(); $found = false; $this->widget_start($args, $instance); // Force found when option is selected - do not force found on taxonomy attributes if (!is_tax() && is_array($_chosen_attributes) && array_key_exists($taxonomy, $_chosen_attributes)) { $found = true; } if ('dropdown' == $display_type) { // skip when viewing the taxonomy if ($current_tax && $taxonomy == $current_tax) { $found = false; } else { $taxonomy_filter = str_replace('pa_', '', $taxonomy); $found = false; echo '<select class="dropdown_layered_nav_' . $taxonomy_filter . '">'; echo '<option value="">' . sprintf(__('Any %s', 'woocommerce'), wc_attribute_label($taxonomy)) . '</option>'; foreach ($terms as $term) { // If on a term page, skip that term in widget list if ($term->term_id == $current_term) { continue; } // Get count based on current view $_products_in_term = wc_get_term_product_ids($term->term_id, $taxonomy); $option_is_set = isset($_chosen_attributes[$taxonomy]) && in_array($term->term_id, $_chosen_attributes[$taxonomy]['terms']); // If this is an AND query, only show options with count > 0 if ('and' == $query_type) { $count = sizeof(array_intersect($_products_in_term, WC()->query->filtered_product_ids)); if (0 < $count) { $found = true; } if (0 == $count && !$option_is_set) { continue; } // If this is an OR query, show all options so search can be expanded } else { $count = sizeof(array_intersect($_products_in_term, WC()->query->unfiltered_product_ids)); if (0 < $count) { $found = true; } } echo '<option value="' . esc_attr($term->term_id) . '" ' . selected(isset($_GET['filter_' . $taxonomy_filter]) ? $_GET['filter_' . $taxonomy_filter] : '', $term->term_id, false) . '>' . esc_html($term->name) . '</option>'; } echo '</select>'; wc_enqueue_js("\n\t\t\t\t\t\tjQuery( '.dropdown_layered_nav_{$taxonomy_filter}' ).change( function() {\n\t\t\t\t\t\t\tvar term_id = parseInt( jQuery( this ).val(), 10 );\n\t\t\t\t\t\t\tlocation.href = '" . preg_replace('%\\/page\\/[0-9]+%', '', str_replace(array('&', '%2C'), array('&', ','), esc_js(add_query_arg('filtering', '1', remove_query_arg(array('page', 'filter_' . $taxonomy_filter)))))) . "&filter_{$taxonomy_filter}=' + ( isNaN( term_id ) ? '' : term_id );\n\t\t\t\t\t\t});\n\t\t\t\t\t"); } } else { // List display echo '<ul>'; // flip the filtered_products_ids array so that we can use the more efficient array_intersect_key $filtered_product_ids = array_flip(WC()->query->filtered_product_ids); foreach ($terms as $term) { // Get count based on current view - uses transients $_products_in_term = wc_get_term_product_ids($term->term_id, $taxonomy); $option_is_set = isset($_chosen_attributes[$taxonomy]) && in_array($term->term_id, $_chosen_attributes[$taxonomy]['terms']); // skip the term for the current archive if ($current_term == $term->term_id) { continue; } // If this is an AND query, only show options with count > 0 if ('and' == $query_type) { // flip the product_in_term array so that we can use array_intersect_key $_products_in_term = array_flip($_products_in_term); // Intersect both arrays now they have been flipped so that we can use their keys $count = sizeof(array_intersect_key($_products_in_term, $filtered_product_ids)); if (0 < $count && $current_term !== $term->term_id) { $found = true; } if (0 == $count && !$option_is_set) { continue; } // If this is an OR query, show all options so search can be expanded } else { $count = sizeof(array_intersect($_products_in_term, WC()->query->unfiltered_product_ids)); if (0 < $count) { $found = true; } } $arg = 'filter_' . sanitize_title($instance['attribute']); $current_filter = isset($_GET[$arg]) ? explode(',', $_GET[$arg]) : array(); if (!is_array($current_filter)) { $current_filter = array(); } $current_filter = array_map('esc_attr', $current_filter); if (!in_array($term->term_id, $current_filter)) { $current_filter[] = $term->term_id; } // Base Link decided by current page if (defined('SHOP_IS_ON_FRONT')) { $link = home_url(); } elseif (is_post_type_archive('product') || is_page(wc_get_page_id('shop'))) { $link = get_post_type_archive_link('product'); } else { $link = get_term_link(get_query_var('term'), get_query_var('taxonomy')); } // All current filters if ($_chosen_attributes) { foreach ($_chosen_attributes as $name => $data) { if ($name !== $taxonomy) { // Exclude query arg for current term archive term while (in_array($current_term, $data['terms'])) { $key = array_search($current_term, $data); unset($data['terms'][$key]); } // Remove pa_ and sanitize $filter_name = sanitize_title(str_replace('pa_', '', $name)); if (!empty($data['terms'])) { $link = add_query_arg('filter_' . $filter_name, implode(',', $data['terms']), $link); } if ('or' == $data['query_type']) { $link = add_query_arg('query_type_' . $filter_name, 'or', $link); } } } } // Min/Max if (isset($_GET['min_price'])) { $link = add_query_arg('min_price', $_GET['min_price'], $link); } if (isset($_GET['max_price'])) { $link = add_query_arg('max_price', $_GET['max_price'], $link); } // Orderby if (isset($_GET['orderby'])) { $link = add_query_arg('orderby', $_GET['orderby'], $link); } // Current Filter = this widget if (isset($_chosen_attributes[$taxonomy]) && is_array($_chosen_attributes[$taxonomy]['terms']) && in_array($term->term_id, $_chosen_attributes[$taxonomy]['terms'])) { $class = 'class="chosen"'; // Remove this term is $current_filter has more than 1 term filtered if (sizeof($current_filter) > 1) { $current_filter_without_this = array_diff($current_filter, array($term->term_id)); $link = add_query_arg($arg, implode(',', $current_filter_without_this), $link); } } else { $class = ''; $link = add_query_arg($arg, implode(',', $current_filter), $link); } // Search Arg if (get_search_query()) { $link = add_query_arg('s', get_search_query(), $link); } // Post Type Arg if (isset($_GET['post_type'])) { $link = add_query_arg('post_type', $_GET['post_type'], $link); } // Query type Arg if ($query_type == 'or' && !(sizeof($current_filter) == 1 && isset($_chosen_attributes[$taxonomy]['terms']) && is_array($_chosen_attributes[$taxonomy]['terms']) && in_array($term->term_id, $_chosen_attributes[$taxonomy]['terms']))) { $link = add_query_arg('query_type_' . sanitize_title($instance['attribute']), 'or', $link); } echo '<li ' . $class . '>'; echo $count > 0 || $option_is_set ? '<a href="' . esc_url(apply_filters('woocommerce_layered_nav_link', $link)) . '">' : '<span>'; echo $term->name; echo $count > 0 || $option_is_set ? '</a>' : '</span>'; echo ' <span class="count">(' . $count . ')</span></li>'; } echo '</ul>'; } // End display type conditional $this->widget_end($args); if (!$found) { ob_end_clean(); } else { echo ob_get_clean(); } } }
/** * Show list based layered nav. * @param array $terms * @param string $taxonomy * @param string $query_type * @return bool Will nav display? */ protected function layered_nav_list($terms, $taxonomy, $query_type) { global $_chosen_attributes; // List display echo '<ul>'; // flip the filtered_products_ids array so that we can use the more efficient array_intersect_key $filtered_product_ids = array_flip(WC()->query->filtered_product_ids); $unfiltered_product_ids = array_flip(WC()->query->unfiltered_product_ids); $found = false; foreach ($terms as $term) { // Get count based on current view - uses transients // flip the product_in_term array so that we can use array_intersect_key $_products_in_term = array_flip(wc_get_term_product_ids($term->term_id, $taxonomy)); $current_values = isset($_chosen_attributes[$taxonomy]['terms']) ? $_chosen_attributes[$taxonomy]['terms'] : array(); $option_is_set = in_array($term->slug, $current_values); // skip the term for the current archive if ($this->get_current_term_id() === $term->term_id) { continue; } // If this is an AND query, only show options with count > 0 if ('and' === $query_type) { // Intersect both arrays now they have been flipped so that we can use their keys $count = sizeof(array_intersect_key($_products_in_term, $filtered_product_ids)); if (0 < $count) { $found = true; } if (0 === $count && !$option_is_set) { continue; } // If this is an OR query, show all options so search can be expanded } else { // Intersect both arrays now they have been flipped so that we can use their keys $count = sizeof(array_intersect_key($_products_in_term, $unfiltered_product_ids)); if (0 < $count) { $found = true; } } $filter_name = 'filter_' . sanitize_title(str_replace('pa_', '', $taxonomy)); $current_filter = isset($_GET[$filter_name]) ? explode(',', wc_clean($_GET[$filter_name])) : array(); $current_filter = array_map('sanitize_title', $current_filter); if (!in_array($term->slug, $current_filter)) { $current_filter[] = $term->slug; } $link = $this->get_page_base_url(); // Add current filters to URL. foreach ($current_filter as $key => $value) { // Exclude query arg for current term archive term if ($value === $this->get_current_term_slug()) { unset($current_filter[$key]); } // Exclude self so filter can be unset on click. if ($option_is_set && $value === $term->slug) { unset($current_filter[$key]); } } if (!empty($current_filter)) { $link = add_query_arg($filter_name, implode(',', $current_filter), $link); // Add Query type Arg to URL if ($query_type === 'or' && !(1 === sizeof($current_filter) && $option_is_set)) { $link = add_query_arg('query_type_' . sanitize_title(str_replace('pa_', '', $taxonomy)), 'or', $link); } } echo '<li class="wc-layered-nav-term ' . ($option_is_set ? 'chosen' : '') . '">'; echo $count > 0 || $option_is_set ? '<a href="' . esc_url(apply_filters('woocommerce_layered_nav_link', $link)) . '">' : '<span>'; echo esc_html($term->name); echo $count > 0 || $option_is_set ? '</a>' : '</span>'; echo ' <span class="count">(' . absint($count) . ')</span></li>'; } echo '</ul>'; return $found; }