/** * Output widget. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } $_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes(); $min_price = isset($_GET['min_price']) ? wc_clean($_GET['min_price']) : 0; $max_price = isset($_GET['max_price']) ? wc_clean($_GET['max_price']) : 0; $min_rating = isset($_GET['min_rating']) ? absint($_GET['min_rating']) : 0; if (0 < count($_chosen_attributes) || 0 < $min_price || 0 < $max_price || 0 < $min_rating) { $this->widget_start($args, $instance); echo '<ul>'; // Attributes if (!empty($_chosen_attributes)) { foreach ($_chosen_attributes as $taxonomy => $data) { foreach ($data['terms'] as $term_slug) { if (!($term = get_term_by('slug', $term_slug, $taxonomy))) { continue; } $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); $new_filter = array_diff($current_filter, array($term_slug)); $link = remove_query_arg(array('add-to-cart', $filter_name)); if (sizeof($new_filter) > 0) { $link = add_query_arg($filter_name, implode(',', $new_filter), $link); } echo '<li class="chosen"><a title="' . esc_attr__('Remove filter', 'woocommerce') . '" href="' . esc_url($link) . '">' . esc_html($term->name) . '</a></li>'; } } } if ($min_price) { $link = remove_query_arg('min_price'); echo '<li class="chosen"><a title="' . esc_attr__('Remove filter', 'woocommerce') . '" href="' . esc_url($link) . '">' . sprintf(__('Min %s', 'woocommerce'), wc_price($min_price)) . '</a></li>'; } if ($max_price) { $link = remove_query_arg('max_price'); echo '<li class="chosen"><a title="' . esc_attr__('Remove filter', 'woocommerce') . '" href="' . esc_url($link) . '">' . sprintf(__('Max %s', 'woocommerce'), wc_price($max_price)) . '</a></li>'; } if ($min_rating) { $link = remove_query_arg('min_rating'); echo '<li class="chosen"><a title="' . esc_attr__('Remove filter', 'woocommerce') . '" href="' . esc_url($link) . '">' . sprintf(__('Rated %s and above', 'woocommerce'), $min_rating) . '</a></li>'; } echo '</ul>'; $this->widget_end($args); } }
/** * Count products after other filters have occured by adjusting the main query. * @param int $rating * @return int */ protected function get_filtered_product_count($rating) { global $wpdb; $tax_query = WC_Query::get_main_tax_query(); $meta_query = WC_Query::get_main_meta_query(); // Unset current rating filter foreach ($meta_query as $key => $query) { if (!empty($query['rating_filter'])) { unset($meta_query[$key]); } } // Set new rating filter $meta_query[] = array('key' => '_wc_average_rating', 'value' => $rating, 'compare' => '>=', 'type' => 'DECIMAL', 'rating_filter' => true); $meta_query = new WP_Meta_Query($meta_query); $tax_query = new WP_Tax_Query($tax_query); $meta_query_sql = $meta_query->get_sql('post', $wpdb->posts, 'ID'); $tax_query_sql = $tax_query->get_sql($wpdb->posts, 'ID'); $sql = "SELECT COUNT( {$wpdb->posts}.ID ) FROM {$wpdb->posts} "; $sql .= $tax_query_sql['join'] . $meta_query_sql['join']; $sql .= " WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish' "; $sql .= $tax_query_sql['where'] . $meta_query_sql['where']; return absint($wpdb->get_var($sql)); }
/** * Layered Nav Init. */ public static function get_layered_nav_chosen_attributes() { if (!is_array(self::$_chosen_attributes)) { self::$_chosen_attributes = array(); if ($attribute_taxonomies = wc_get_attribute_taxonomies()) { foreach ($attribute_taxonomies as $tax) { $attribute = wc_sanitize_taxonomy_name($tax->attribute_name); $taxonomy = wc_attribute_taxonomy_name($attribute); $filter_terms = !empty($_GET['filter_' . $attribute]) ? explode(',', wc_clean($_GET['filter_' . $attribute])) : array(); if (empty($filter_terms) || !taxonomy_exists($taxonomy)) { continue; } $query_type = !empty($_GET['query_type_' . $attribute]) && in_array($_GET['query_type_' . $attribute], array('and', 'or')) ? wc_clean($_GET['query_type_' . $attribute]) : ''; self::$_chosen_attributes[$taxonomy]['terms'] = array_map('sanitize_title', $filter_terms); // Ensures correct encoding self::$_chosen_attributes[$taxonomy]['query_type'] = $query_type ? $query_type : apply_filters('woocommerce_layered_nav_default_query_type', 'and'); } } } return self::$_chosen_attributes; }
/** * Count products after other filters have occured by adjusting the main query. * @param int $rating * @return int */ protected function get_filtered_product_count($rating) { global $wpdb; $tax_query = WC_Query::get_main_tax_query(); $meta_query = WC_Query::get_main_meta_query(); // Unset current rating filter. foreach ($tax_query as $key => $query) { if (!empty($query['rating_filter'])) { unset($tax_query[$key]); break; } } // Set new rating filter. $product_visibility_terms = wc_get_product_visibility_term_ids(); $tax_query[] = array('taxonomy' => 'product_visibility', 'field' => 'term_taxonomy_id', 'terms' => $product_visibility_terms['rated-' . $rating], 'operator' => 'IN', 'rating_filter' => true); $meta_query = new WP_Meta_Query($meta_query); $tax_query = new WP_Tax_Query($tax_query); $meta_query_sql = $meta_query->get_sql('post', $wpdb->posts, 'ID'); $tax_query_sql = $tax_query->get_sql($wpdb->posts, 'ID'); $sql = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) FROM {$wpdb->posts} "; $sql .= $tax_query_sql['join'] . $meta_query_sql['join']; $sql .= " WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish' "; $sql .= $tax_query_sql['where'] . $meta_query_sql['where']; return absint($wpdb->get_var($sql)); }
/** * Output widget. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { global $wp, $wp_the_query; if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } if (!$wp_the_query->post_count) { return; } // Remember current filters/search if ('' == get_option('permalink_structure')) { $link_url = remove_query_arg(array('page', 'paged'), add_query_arg($wp->query_string, '', home_url($wp->request))); } else { $link_url = preg_replace('%\\/page/[0-9]+%', '', home_url(trailingslashit($wp->request))); } if (get_search_query()) { $link_url = add_query_arg('s', get_search_query(), $link_url); } if (!empty($_GET['post_type'])) { $link_url = add_query_arg('post_type', urlencode($_GET['post_type']), $link_url); } if (!empty($_GET['product_cat'])) { $link_url = add_query_arg('product_cat', urlencode($_GET['product_cat']), $link_url); } if (!empty($_GET['product_tag'])) { $link_url = add_query_arg('product_tag', urlencode($_GET['product_tag']), $link_url); } if (!empty($_GET['orderby'])) { $link_url = add_query_arg('orderby', urlencode($_GET['orderby']), $link_url); } if ($_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes()) { foreach ($_chosen_attributes as $attribute => $data) { $taxonomy_filter = 'filter_' . str_replace('pa_', '', $attribute); $link_url = add_query_arg($taxonomy_filter, urlencode(implode(',', $data['terms'])), $link_url); if ('or' == $data['query_type']) { $link_url = add_query_arg(str_replace('pa_', 'query_type_', $attribute), 'or', $link_url); } } } // Find min and max price in current result set $prices = $this->get_filtered_price(); $min = floor($prices->min_price); $max = ceil($prices->max_price); if ($min === $max) { return; } $this->widget_start($args, $instance); /** * Adjust max if the store taxes are not displayed how they are stored. * Min is left alone because the product may not be taxable. * Kicks in when prices excluding tax are displayed including tax. */ if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); $class_max = $max; foreach ($tax_classes as $tax_class) { if ($tax_rates = WC_Tax::get_rates($tax_class)) { $class_max = $max + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($max, $tax_rates)); } } $max = $class_max; } $minprice = isset($_GET['min_price']) ? esc_attr($_GET['min_price']) : ''; $maxprice = isset($_GET['max_price']) ? esc_attr($_GET['max_price']) : ''; $output = ''; $min_price = 0; $range_size = intval($instance['range_size']); $max_ranges = intval($instance['max_ranges']) - 1; $count = 0; if (strlen($minprice) > 0) { $output .= '<li><a href="' . esc_url($link_url) . '">' . esc_html__('All', 'cruxstore') . '</a></li>'; } else { $output .= '<li class="selected">' . esc_html__('All', 'cruxstore') . '</li>'; } while ($count <= $max_ranges) { $step = $min_price; $min_price += $range_size; if ($count != $max_ranges) { if ($min_price > $max) { $min_price = $max; } $link = add_query_arg(array('min_price' => $step, 'max_price' => $min_price), $link_url); $price_text = wc_price($step) . ' - ' . wc_price($min_price); } else { $link = add_query_arg(array('min_price' => $step, 'max_price' => $max), $link_url); $price_text = wc_price($step) . '+'; } if ($step == $minprice && $min_price == $maxprice) { $output .= '<li class="selected">' . $price_text . '</li>'; } else { $output .= '<li><a href="' . esc_url($link) . '">' . $price_text . '</a></li>'; } $count++; if ($min_price == $max) { break; } } printf('<ul>%s</ul>', $output); $this->widget_end($args); }
/** * Piggyback WooCommerce's Layered Navigation and inject SearchWP results where applicable * * @param $filtered_posts * * @return array */ function post_in($filtered_posts) { global $wp_query; // WooCommerce 2.6 introduced tax/meta query piggybacking that's much better if (function_exists('WC') && !empty(WC()->version) && version_compare(WC()->version, '2.6', '<')) { return $this->legacy_post_in($filtered_posts); } if ($this->is_woocommerce_search() && ($query = get_search_query())) { if (!empty($this->results)) { return $this->results; } $searchwp_engine = 'default'; $swppg = get_query_var('paged') ? get_query_var('paged') : 1; // force SearchWP to only consider the filtered posts if (!empty($filtered_posts)) { $this->filtered_posts = $filtered_posts; add_filter('searchwp_include', array($this, 'include_filtered_posts')); } do_action('searchwp_woocommerce_before_search', $this); // don't log this search, it's redundant add_filter('searchwp_log_search', '__return_false'); $wc_query = new WC_Query(); $args = array('s' => $query, 'engine' => $searchwp_engine, 'page' => $swppg, 'fields' => 'ids', 'posts_per_page' => -1, 'tax_query' => $wc_query->get_tax_query(), 'meta_query' => $wc_query->get_meta_query()); $args = apply_filters('searchwp_woocommerce_query_args', $args); $results = new SWP_Query($args); $this->results = $results->posts; remove_filter('searchwp_log_search', '__return_false'); return $this->results; } elseif (!empty($this->results)) { return $this->results; } return (array) $filtered_posts; }
/** * is_filtered - Returns true when filtering products using layered nav or price sliders. * @return bool */ function is_filtered() { return apply_filters('woocommerce_is_filtered', sizeof(WC_Query::get_layered_nav_chosen_attributes()) > 0 || isset($_GET['max_price']) || isset($_GET['min_price']) || isset($_GET['min_rating'])); }
/** * Output widget. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { global $wp, $wp_the_query; if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } if (!$wp_the_query->post_count) { return; } $min_price = isset($_GET['min_price']) ? esc_attr($_GET['min_price']) : ''; $max_price = isset($_GET['max_price']) ? esc_attr($_GET['max_price']) : ''; wp_enqueue_script('wc-price-slider'); // Remember current filters/search $fields = ''; if (get_search_query()) { $fields .= '<input type="hidden" name="s" value="' . get_search_query() . '" />'; } if (!empty($_GET['post_type'])) { $fields .= '<input type="hidden" name="post_type" value="' . esc_attr($_GET['post_type']) . '" />'; } if (!empty($_GET['product_cat'])) { $fields .= '<input type="hidden" name="product_cat" value="' . esc_attr($_GET['product_cat']) . '" />'; } if (!empty($_GET['product_tag'])) { $fields .= '<input type="hidden" name="product_tag" value="' . esc_attr($_GET['product_tag']) . '" />'; } if (!empty($_GET['orderby'])) { $fields .= '<input type="hidden" name="orderby" value="' . esc_attr($_GET['orderby']) . '" />'; } if (!empty($_GET['min_rating'])) { $fields .= '<input type="hidden" name="min_rating" value="' . esc_attr($_GET['min_rating']) . '" />'; } if ($_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes()) { foreach ($_chosen_attributes as $attribute => $data) { $taxonomy_filter = 'filter_' . str_replace('pa_', '', $attribute); $fields .= '<input type="hidden" name="' . esc_attr($taxonomy_filter) . '" value="' . esc_attr(implode(',', $data['terms'])) . '" />'; if ('or' == $data['query_type']) { $fields .= '<input type="hidden" name="' . esc_attr(str_replace('pa_', 'query_type_', $attribute)) . '" value="or" />'; } } } // Find min and max price in current result set $prices = $this->get_filtered_price(); $min = floor($prices->min_price); $max = ceil($prices->max_price); if ($min === $max) { return; } $this->widget_start($args, $instance); if ('' === get_option('permalink_structure')) { $form_action = remove_query_arg(array('page', 'paged'), add_query_arg($wp->query_string, '', home_url($wp->request))); } else { $form_action = preg_replace('%\\/page/[0-9]+%', '', home_url(trailingslashit($wp->request))); } /** * Adjust max if the store taxes are not displayed how they are stored. * Min is left alone because the product may not be taxable. * Kicks in when prices excluding tax are displayed including tax. */ if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); $class_max = $max; foreach ($tax_classes as $tax_class) { if ($tax_rates = WC_Tax::get_rates($tax_class)) { $class_max = $max + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($max, $tax_rates)); } } $max = $class_max; } echo '<form method="get" action="' . esc_url($form_action) . '"> <div class="price_slider_wrapper"> <div class="price_slider" style="display:none;"></div> <div class="price_slider_amount"> <input type="text" id="min_price" name="min_price" value="' . esc_attr($min_price) . '" data-min="' . esc_attr(apply_filters('woocommerce_price_filter_widget_min_amount', $min)) . '" placeholder="' . esc_attr__('Min price', 'woocommerce') . '" /> <input type="text" id="max_price" name="max_price" value="' . esc_attr($max_price) . '" data-max="' . esc_attr(apply_filters('woocommerce_price_filter_widget_max_amount', $max)) . '" placeholder="' . esc_attr__('Max price', 'woocommerce') . '" /> <button type="submit" class="button">' . __('Filter', 'woocommerce') . '</button> <div class="price_label" style="display:none;"> ' . __('Price:', 'woocommerce') . ' <span class="from"></span> — <span class="to"></span> </div> ' . $fields . ' <div class="clear"></div> </div> </div> </form>'; $this->widget_end($args); }
/** * 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) { // List display echo '<ul>'; $term_counts = $this->get_filtered_term_product_counts(wp_list_pluck($terms, 'term_id'), $taxonomy, $query_type); $_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes(); $found = false; foreach ($terms as $term) { $current_values = isset($_chosen_attributes[$taxonomy]['terms']) ? $_chosen_attributes[$taxonomy]['terms'] : array(); $option_is_set = in_array($term->slug, $current_values); $count = isset($term_counts[$term->term_id]) ? $term_counts[$term->term_id] : 0; // Skip the term for the current archive if ($this->get_current_term_id() === $term->term_id) { continue; } // Only show options with count > 0 if (0 < $count) { $found = true; } elseif (0 === $count && !$option_is_set) { continue; } $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($taxonomy); // 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 ('or' === $query_type && !(1 === sizeof($current_filter) && $option_is_set)) { $link = add_query_arg('query_type_' . sanitize_title(str_replace('pa_', '', $taxonomy)), 'or', $link); } } if ($count > 0 || $option_is_set) { $link = esc_url(apply_filters('woocommerce_layered_nav_link', $link)); $term_html = '<a href="' . $link . '">' . esc_html($term->name) . '</a>'; } else { $link = false; $term_html = '<span>' . esc_html($term->name) . '</span>'; } $term_html .= ' ' . apply_filters('woocommerce_layered_nav_count', '<span class="count">(' . absint($count) . ')</span>', $count, $term); echo '<li class="wc-layered-nav-term ' . ($option_is_set ? 'chosen' : '') . '">'; echo wp_kses_post(apply_filters('woocommerce_layered_nav_term_html', $term_html, $term, $link, $count)); echo '</li>'; } echo '</ul>'; return $found; }
/** * Gets sorting options * * @access public * @return array */ public static function getSorting() { $order = array('orderby' => '', 'order' => '', 'meta_key' => ''); if (self::isActive()) { $query = new WC_Query(); $order = $query->get_catalog_ordering_args(); } return $order; }
/** * This method is used to display the output of the element. * @return void */ function element() { // Check if this is a normal page or the Shop archive page if (!is_shop()) { global $paged; $wc_query = new WC_Query(); // Get the proper page - this resolves the pagination on static frontpage if (get_query_var('paged')) { $paged = get_query_var('paged'); } elseif (get_query_var('page')) { $paged = get_query_var('page'); } else { $paged = 1; } $ordering = $wc_query->get_catalog_ordering_args(); $queryArgs = array('post_type' => 'product', 'paged' => $paged, 'orderby' => $ordering['orderby'], 'order' => $ordering['order']); if (isset($ordering['meta_key'])) { $queryArgs['meta_key'] = $ordering['meta_key']; } query_posts($queryArgs); } // Change the number of columns add_filter('loop_shop_columns', array(&$this, 'zn_woo_loop_columns'), 999); $sidebar_tweak = $this->opt('num_columns', '4') == 3 ? 'left_sidebar' : ''; echo '<div class="zn_woo_archive_elemenent woocommerce ' . $this->data['uid'] . ' ' . $sidebar_tweak . ' ' . $this->opt('css_class', '') . '">'; ?> <?php if ($this->opt('show_page_title', 'yes') == 'yes') { ?> <h1 class="page-title"><?php woocommerce_page_title(); ?> </h1> <?php } ?> <?php /** * woocommerce_archive_description hook * * @hooked woocommerce_taxonomy_archive_description - 10 * @hooked woocommerce_product_archive_description - 10 */ do_action('woocommerce_archive_description'); ?> <?php if (have_posts()) { ?> <?php /** * woocommerce_before_shop_loop hook * * @hooked woocommerce_result_count - 20 * @hooked woocommerce_catalog_ordering - 30 */ do_action('woocommerce_before_shop_loop'); ?> <?php woocommerce_product_loop_start(); ?> <?php woocommerce_product_subcategories(); ?> <?php while (have_posts()) { the_post(); ?> <?php wc_get_template_part('content', 'product'); ?> <?php } // end of the loop. ?> <?php woocommerce_product_loop_end(); ?> <?php /** * woocommerce_after_shop_loop hook * * @hooked woocommerce_pagination - 10 */ do_action('woocommerce_after_shop_loop'); ?> <?php } elseif (!woocommerce_product_subcategories(array('before' => woocommerce_product_loop_start(false), 'after' => woocommerce_product_loop_end(false)))) { ?> <?php wc_get_template('loop/no-products-found.php'); ?> <?php } ?> <?php wp_reset_postdata(); wp_reset_query(); echo '</div>'; }