Skip to content

Instantly share code, notes, and snippets.

@shrimp2t
Created August 27, 2018 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shrimp2t/9fbd809cd5dcd30be41a8eadd7c5738a to your computer and use it in GitHub Desktop.
Save shrimp2t/9fbd809cd5dcd30be41a8eadd7c5738a to your computer and use it in GitHub Desktop.
WC filter
(function ($, window, document) {
"use strict";
var customifyWCFiterXHR = false;
$.fn.customifyOffCanvas = function ( options ) {
var opts = $.extend({
selector : '.woocommerce-listing',
}, options );
var updateURL = function( url ) {
// IE only supports pushState() in v10 and above, so don't bother if those conditions aren't met.
if ( ! window.history.pushState ) {
return;
}
history.pushState( null, null, url );
};
var offCanvasFilter = function( options, $el ){
/*
$el.on( 'click', '.woocommerce-widget-layered-nav-list li a', function(e){
e.preventDefault();
var url = $( this ).attr( 'href' ) || false;
if ( url ) {
ajax_request( url );
}
} );
*/
$( '.customify-wc-filter-form input', $el ).on( 'change', function(e){
var data = {};
var form = $( '.customify-wc-filter-form' );
$( 'input', form ).each( function(){
var input = $( this );
var input_type = input.attr( 'type' ) || 'text';
var name = false;
switch ( input_type ) {
case 'checkbox':
if ( input.is(':checked') ) {
name = $( this ).attr( 'data-name' ) || false;
if ( name ) {
if ( typeof data[ name ] === "undefined" ) {
data[ name ] = [];
}
}
data[ name ].push( $( this ).val() );
}
break;
case 'hidden':
case 'text':
name = $( this ).attr( 'name' ) || false;
if ( name ) {
if ( typeof data[ name ] === "undefined" ) {
data[ name ] = input.val();
}
}
break;
}
} );
var args = [];
$.each( data, function( key, values ){
var string = '';
if ( typeof values === 'array' || typeof values === 'object' ) {
string = values.join(',');
} else {
string = values;
}
args.push( key+'='+encodeURI( string ) );
} );
var sep = Customify_Pro_JS.wc_filter.shop.indexOf('?') > -1 ? '&' : '?';
var query_url = Customify_Pro_JS.wc_filter.shop+sep+ args.join('&');
ajax_request( query_url );
} );
function ajax_request( desturl ){
console.log( 'Query URL', desturl );
// decode url to prevent error
// desturl = decodeURIComponent(desturl);
// desturl = desturl.replace(/^(?:\/\/|[^\/]+)*\//, "/");
if ( customifyWCFiterXHR ) {
customifyWCFiterXHR.abort();
customifyWCFiterXHR = false;
}
updateURL( desturl );
// ajax call
customifyWCFiterXHR = $.ajax({
// params
url : desturl,
dataType : 'html',
success : function (data) {
var $data = $( data );
var obj;
if ( $( opts.selector, $data ).length ) {
$( opts.selector ).html( $( opts.selector, $data ) );
}
},
error: function (req) {
}
});
}
};
return this.each(function() {
return new offCanvasFilter( options, $( this ) );
});
}
})( jQuery, window, document );
<?php
/**
* Layered nav widget
*
* @package WooCommerce/Widgets
* @version 2.6.0
*/
defined( 'ABSPATH' ) || exit;
require_once ABSPATH.'/wp-admin/includes/class-walker-category-checklist.php';
class Customify_Walker_Category_Checklist extends Walker_Category_Checklist {
/**
* Start the element output.
*
* @see Walker::start_el()
*
* @since 2.5.1
*
* @param string $output Used to append additional content (passed by reference).
* @param object $category The current term object.
* @param int $depth Depth of the term in reference to parents. Default 0.
* @param array $args An array of arguments. @see wp_terms_checklist()
* @param int $id ID of the current term.
*/
public function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
if ( empty( $args['taxonomy'] ) ) {
$taxonomy = 'category';
} else {
$taxonomy = $args['taxonomy'];
}
switch ( $taxonomy ) {
case 'product_cat': case 'product_tag':
$name = 'filter_'.$taxonomy;
break;
case 'category':
$name = 'post_category';
break;
default:
$name = 'filter_'.str_replace('pa_', '', $taxonomy);
}
$args['popular_cats'] = empty( $args['popular_cats'] ) ? array() : $args['popular_cats'];
$class = in_array( $category->term_id, $args['popular_cats'] ) ? ' class="popular-category"' : '';
$args['selected_cats'] = empty( $args['selected_cats'] ) ? array() : $args['selected_cats'];
if ( ! empty( $args['list_only'] ) ) {
$aria_checked = 'false';
$inner_class = 'category';
if ( in_array( $category->term_id, $args['selected_cats'] ) ) {
$inner_class .= ' selected';
$aria_checked = 'true';
}
/** This filter is documented in wp-includes/category-template.php */
$output .= "\n" . '<li' . $class . '>' .
'<div class="' . $inner_class . '" data-term-id=' . $category->slug .
' tabindex="0" role="checkbox" aria-checked="' . $aria_checked . '">' .
esc_html( apply_filters( 'the_category', $category->name, '', '' ) ) . '</div>';
} else {
/** This filter is documented in wp-includes/category-template.php */
$output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" .
'<label class="selectit"><input value="' . $category->slug . '" type="checkbox" data-name="'.esc_attr( $name ).'" name="'.$name.'[]" id="in-'.$taxonomy.'-' . $category->slug . '"' .
checked( in_array( $category->slug, $args['selected_cats'] ), true, false ) .
disabled( empty( $args['disabled'] ), false, false ) . ' /> ' .
esc_html( apply_filters( 'the_category', $category->name, '', '' ) ) . '</label>';
}
}
}
/**
* Widget layered nav class.
* @see WC_Widget_Layered_Nav
*/
class Customify_Pro_WC_Widget_Filter extends WC_Widget {
/**
* Constructor.
*/
public function __construct() {
$this->widget_cssclass = 'customify-wc-filter woocommerce';
$this->widget_description = __( 'Display a filter products in your store.', 'woocommerce' );
$this->widget_id = 'customify_wc_filter';
$this->widget_name = __( 'Customify Woocommerce Filter', 'woocommerce' );
parent::__construct();
}
/**
* Updates a particular instance of a widget.
*
* @see WP_Widget->update
*
* @param array $new_instance New Instance.
* @param array $old_instance Old Instance.
*
* @return array
*/
public function update( $new_instance, $old_instance ) {
$this->init_settings();
return parent::update( $new_instance, $old_instance );
}
/**
* Outputs the settings update form.
*
* @see WP_Widget->form
*
* @param array $instance Instance.
*/
public function form( $instance ) {
$this->init_settings();
parent::form( $instance );
}
/**
* Init settings after post types are registered.
*/
public function init_settings() {
$attribute_array = array();
$attribute_taxonomies = wc_get_attribute_taxonomies();
if ( ! empty( $attribute_taxonomies ) ) {
foreach ( $attribute_taxonomies as $tax ) {
if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
$attribute_array[ $tax->attribute_name ] = $tax->attribute_label;
}
}
}
$attribute_array = array_merge( array( 'product_cat' => __( 'Categories', 'woocommerce' ),
'product_tag' => __( 'Tags', 'woocommerce' ) ),
$attribute_array,
array(
'stock_status' => __( 'Stock status', 'woocommerce' ),
'on_sale' => __( 'On Sale', 'woocommerce' ),
'_weight' => __( 'Weight', 'woocommerce' ),
'_length' => __( 'Length', 'woocommerce' ),
'_width' => __( 'Width', 'woocommerce' ),
'_height' => __( 'Height', 'woocommerce' ),
)
);
$this->settings = array(
'title' => array(
'type' => 'text',
'std' => __( 'Filter by', 'woocommerce' ),
'label' => __( 'Title', 'woocommerce' ),
),
'data_type' => array(
'type' => 'select',
'std' => '',
'label' => __( 'Filter Type', 'woocommerce' ),
'options' => $attribute_array,
),
'query_type' => array(
'type' => 'select',
'std' => 'and',
'label' => __( 'Query type', 'woocommerce' ),
'options' => array(
'and' => __( 'AND', 'woocommerce' ),
'or' => __( 'OR', 'woocommerce' ),
),
),
);
}
/**
* Output an unordered list of checkbox input elements labelled with term names.
*
* Taxonomy-independent version of wp_category_checklist().
*
* @see wp_terms_checklist
*
*
* @param array|string $args {
* Optional. Array or string of arguments for generating a terms checklist. Default empty array.
*
* @type int $descendants_and_self ID of the category to output along with its descendants.
* Default 0.
* @type array $selected_cats List of categories to mark as checked. Default false.
* Default false.
* @type object $walker Walker object to use to build the output.
* Default is a Walker_Category_Checklist instance.
* @type string $taxonomy Taxonomy to generate the checklist for. Default 'category'.
* the top of the list. Default true.
* @type bool $echo Whether to echo the generated markup. False to return the markup instead
* of echoing it. Default true.
* }
*/
function wp_terms_checklist( $args = array() ) {
$defaults = array(
'selected_cats' => false,
'walker' => null,
'taxonomy' => 'category',
'echo' => true,
);
/**
* Filters the taxonomy terms checklist arguments.
*
* @since 3.4.0
*
* @see wp_terms_checklist()
*
* @param array $args An array of arguments.
* @param int $post_id The post ID.
*/
$params = apply_filters( 'wp_terms_checklist_args', $args, null );
$r = wp_parse_args( $params, $defaults );
if ( empty( $r['walker'] ) || ! ( $r['walker'] instanceof Walker ) ) {
$walker = new Customify_Walker_Category_Checklist;
} else {
$walker = $r['walker'];
}
$taxonomy = $r['taxonomy'];
$args = array( 'taxonomy' => $taxonomy );
$tax = get_taxonomy( $taxonomy );
if ( is_array( $r['selected_cats'] ) ) {
$args['selected_cats'] = $r['selected_cats'];
} else {
$args['selected_cats'] = array();
}
$categories = (array) get_terms( $taxonomy, array( 'get' => 'all' ) );
$output = '';
// Then the rest of them
$output .= call_user_func_array( array( $walker, 'walk' ), array( $categories, 0, $args ) );
if ( $r['echo'] ) {
echo $output;
}
return $output;
}
/**
* Output widget.
*
* @see WP_Widget
*
* @param array $args Arguments.
* @param array $instance Instance.
*/
public function widget( $args, $instance ) {
if ( ! is_shop() && ! is_product_taxonomy() ) {
return;
}
$_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes();
$query_type = isset( $instance['query_type'] ) ? $instance['query_type'] : $this->settings['query_type']['std'];
if( ! isset( $instance['data_type'] ) ) {
$instance['data_type'] = 'categories';
}
switch ( $instance['data_type'] ) {
case 'product_cat': case 'product_tag':
$taxonomy = $instance['data_type'];
break;
default:
$taxonomy = $instance['data_type'];
}
if ( ! taxonomy_exists( $taxonomy ) ) {
$taxonomy = wc_attribute_taxonomy_name( $taxonomy );
}
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;
default:
$get_terms_args['orderby'] = 'name';
$get_terms_args['menu_order'] = false;
}
$terms = get_terms( $taxonomy, $get_terms_args );
if ( 0 === count( $terms ) ) {
return;
}
ob_start();
$this->widget_start( $args, $instance );
// List display.
echo '<form class="customify-wc-filter-form">';
echo '<ul class="woocommerce-widget-layered-nav-list">';
if ( ! function_exists('wp_terms_checklist') ) {
require_once ABSPATH.'/wp-admin/includes/template.php';
}
$this->wp_terms_checklist( array( 'taxonomy' => $taxonomy, 'checked_ontop' => false, 'selected' => $_chosen_attributes ) );
echo '</ul>';
echo '<input type="hidden" name="query_type_'.esc_attr( str_replace( 'pa_', '', $taxonomy ) ).'" value="'.esc_attr( $query_type ).'">';
echo '</form>';
$this->widget_end( $args );
echo ob_get_clean(); // @codingStandardsIgnoreLine
}
/**
* Return the currently viewed taxonomy name.
*
* @return string
*/
protected function get_current_taxonomy() {
return is_tax() ? get_queried_object()->taxonomy : '';
}
/**
* Return the currently viewed term ID.
*
* @return int
*/
protected function get_current_term_id() {
return absint( is_tax() ? get_queried_object()->term_id : 0 );
}
/**
* Return the currently viewed term slug.
*
* @return int
*/
protected function get_current_term_slug() {
return absint( is_tax() ? get_queried_object()->slug : 0 );
}
/**
* Count products within certain terms, taking the main WP query into consideration.
*
* This query allows counts to be generated based on the viewed products, not all products.
*
* @param array $term_ids Term IDs.
* @param string $taxonomy Taxonomy.
* @param string $query_type Query Type.
* @return array
*/
protected function get_filtered_term_product_counts( $term_ids, $taxonomy, $query_type ) {
global $wpdb;
$tax_query = WC_Query::get_main_tax_query();
$meta_query = WC_Query::get_main_meta_query();
if ( 'or' === $query_type ) {
foreach ( $tax_query as $key => $query ) {
if ( is_array( $query ) && $taxonomy === $query['taxonomy'] ) {
unset( $tax_query[ $key ] );
}
}
}
$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' );
// Generate query.
$query = array();
$query['select'] = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) as term_count, terms.term_id as term_count_id";
$query['from'] = "FROM {$wpdb->posts}";
$query['join'] = "
INNER JOIN {$wpdb->term_relationships} AS term_relationships ON {$wpdb->posts}.ID = term_relationships.object_id
INNER JOIN {$wpdb->term_taxonomy} AS term_taxonomy USING( term_taxonomy_id )
INNER JOIN {$wpdb->terms} AS terms USING( term_id )
" . $tax_query_sql['join'] . $meta_query_sql['join'];
$query['where'] = "
WHERE {$wpdb->posts}.post_type IN ( 'product' )
AND {$wpdb->posts}.post_status = 'publish'"
. $tax_query_sql['where'] . $meta_query_sql['where'] .
'AND terms.term_id IN (' . implode( ',', array_map( 'absint', $term_ids ) ) . ')';
$search = WC_Query::get_main_search_query_sql();
if ( $search ) {
$query['where'] .= ' AND ' . $search;
}
$query['group_by'] = 'GROUP BY terms.term_id';
$query = apply_filters( 'woocommerce_get_filtered_term_product_counts_query', $query );
$query = implode( ' ', $query );
// We have a query - let's see if cached results of this query already exist.
$query_hash = md5( $query );
// Maybe store a transient of the count values.
$cache = apply_filters( 'woocommerce_layered_nav_count_maybe_cache', true );
if ( true === $cache ) {
$cached_counts = (array) get_transient( 'wc_layered_nav_counts_' . $taxonomy );
} else {
$cached_counts = array();
}
if ( ! isset( $cached_counts[ $query_hash ] ) ) {
$results = $wpdb->get_results( $query, ARRAY_A ); // @codingStandardsIgnoreLine
$counts = array_map( 'absint', wp_list_pluck( $results, 'term_count', 'term_count_id' ) );
$cached_counts[ $query_hash ] = $counts;
if ( true === $cache ) {
set_transient( 'wc_layered_nav_counts_' . $taxonomy, $cached_counts, DAY_IN_SECONDS );
}
}
return array_map( 'absint', (array) $cached_counts[ $query_hash ] );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment