#ajax #wordpress #woocommerce #hook-woocommerce #woocommerce-theming
Вопрос:
Я использую ajax-фильтрацию таксономии. Я основал его давным — давно и изменил для себя-свой собственный html и стиль, заставил его работать со многими другими сценариями. Но теперь мне нужно сделать собственный заказ woocommerce, выбрав его часть. Я добавил его двумя способами — как функцию woocommerce_catalog_ordering(), а также как чистый html, но он отлично работает только на первой странице после фильтрации, на второй странице сортировка уже некорректна. Установка виджета
function cosmetic_init_widgets() { register_widget('cosmetic_Filter_Widget'); } add_action('widgets_init', 'cosmetic_init_widgets'); //Woo Filter function cosmetic_show_products(){ $query_data = $_GET; $paged = (isset($query_data['paged']) ) ? intval($query_data['paged']) : 1; $pages = $wp_query-gt;max_num_pages; $orderby = 'date'; $orderby = $query_data['order']; $posts_per_page = get_option('woocommerce_catalog_columns') * get_option('woocommerce_catalog_rows'); //filter by category id $cats = ($query_data['category']) ? explode(',',$query_data['category']) : false; $pa_color = ($query_data['pa_color']) ? explode(',',$query_data['pa_color']) : false; $pa_size = ($query_data['pa_size']) ? explode(',',$query_data['pa_size']) : false; $tax_query_cat = ($cats) ? array( array( 'taxonomy' =gt; 'product_cat', 'field' =gt; 'id', 'terms' =gt; $cats ) ) : false; $tax_query_pa_color = ($pa_color) ? array( array( 'taxonomy' =gt; 'pa_color', 'field' =gt; 'id', 'terms' =gt; $pa_color ) ) : false; $tax_query_pa_size = ($pa_size) ? array( array( 'taxonomy' =gt; 'pa_size', 'field' =gt; 'id', 'terms' =gt; $pa_size ) ) : false; $args = array( 'post_type' =gt; ['product_variation','product'], 'paged' =gt; $paged, 'posts_per_page' =gt; $posts_per_page, 'tax_query' =gt; array( 'relation' =gt; 'AND', $tax_query_cat, $tax_query_pa_color, $tax_query_pa_size ), 'meta_query' =gt; array( array( 'key' =gt; '_price', 'value' =gt; array($query_data['min'], $query_data['max']), 'compare' =gt; 'BETWEEN', 'type' =gt; 'NUMERIC' ), ), ); switch ( $orderby ) { case 'date': $args['orderby'] = 'date'; //$args['meta_key'] = 'date'; $args['order'] = 'desc'; break; case 'price': $args['orderby'] = 'meta_value_num'; $args['meta_key'] = '_price'; $args['order'] = 'asc'; break; case 'price-desc': $args['orderby'] = 'meta_value_num'; $args['meta_key'] = '_price'; $args['order'] = 'desc'; break; case 'popularity': $args['orderby'] = 'meta_value_num'; $args['meta_key'] = 'total_sales'; $args['order'] = 'desc'; break; case 'rating': $args['orderby'] = 'meta_value_num'; $args['meta_key'] = '_wc_average_rating'; $args['order'] = 'desc'; break; } $loop = new WP_Query( $args ); if ( $loop-gt;have_posts() ) {?gt; lt;div class="mb-20 justify-content-center d-flex"gt; lt;a href="lt;?php echo $filterreset; ?gt;" class="reset-filter"gt;lt;?php echo get_theme_mod('reset_filter_text');?gt;lt;/agt; lt;/divgt; lt;?php woocommerce_product_loop_start(); while ( $loop-gt;have_posts() ) : $loop-gt;the_post(); wc_get_template_part( 'content', 'product' ); endwhile; woocommerce_product_loop_end(); ?gt; lt;div class="mt-20 justify-content-center d-flex d-lg-none"gt; lt;a href="lt;?php echo $filterreset; ?gt;" class="reset-filter"gt;Сбросить фильтрlt;/agt; lt;/divgt; lt;nav class="woocommerce-pagination"gt; lt;?php if($loop-gt;max_num_pages gt; 1){ ?gt; lt;?php //Pagination $big = 999999999; // need an unlikely integer $pages = paginate_links( array( 'base' =gt; str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ), 'format' =gt; '?paged=%#%', 'current' =gt; max( 1, $paged ), 'prev_text' =gt; 'amp;larr;', 'next_text' =gt; 'amp;rarr;', 'first_page_text' =gt; '« ', 'last_page_text' =gt; ' »', 'total' =gt; $loop-gt;max_num_pages, 'type' =gt; 'array', ) ); if( is_array( $pages ) ) { $paged = ( $paged == 0 ) ? 1 : $paged; echo 'lt;ul class="ajax-page-numbers"gt;'; foreach ( $pages as $page ) { echo "lt;ligt;$pagelt;/ligt;"; } echo 'lt;/ulgt;'; } ; ?gt; lt;?php } ?gt; lt;/navgt; lt;div class="mt-20 justify-content-center d-flex d-lg-none"gt; lt;a href="lt;?php echo $filterreset; ?gt;" class="reset-filter"gt;lt;?php echo get_theme_mod('reset_filter_text');?gt;lt;/agt; lt;/divgt; lt;?php } else {?gt; lt;div class="mt-20 justify-content-center d-flex filter-not-found"gt; lt;?php echo get_theme_mod('no_products_found') . 'lt;brgt;lt;a href="' . $filterreset .'" class="reset-filter" style="margin-top:20px;"gt;' . get_theme_mod('reset_filter_text') . 'lt;/agt;'; }?gt; lt;/divgt; lt;?php wp_reset_postdata(); die(); } add_action('wp_ajax_cosmetic_filter', 'cosmetic_show_products'); add_action('wp_ajax_nopriv_cosmetic_filter', 'cosmetic_show_products');
Сам виджет
lt;?php class cosmetic_Filter_Widget extends WP_Widget { /** * General Setup */ public function __construct() { /* Widget settings. */ $widget_ops = array( 'classname' =gt; 'cosmetic_filter_widget', 'description' =gt; 'Ajax Filter Widget' ); /* Widget control settings. */ $control_ops = array( 'width' =gt; 500, 'height' =gt; 450, 'id_base' =gt; 'cosmetic_filter_widget' ); /* Create the widget. */ parent::__construct( 'cosmetic_filter_widget', 'Ajax Фильтрация', $widget_ops, $control_ops ); } /** * Display Widget * @param array $args * @param array $instance */ public function widget( $args, $instance ) { extract( $args ); $title1 = $instance['title1']; $title2 = $instance['title2']; $prices = $this-gt;get_filtered_price(); $min = floor( $prices-gt;min_price ); $max = ceil( $prices-gt;max_price ); $step = ($min $max)/2; $stepp = $step $step/4; $stept = $step $step/8; $stepr = $min $min/4; global $woocommerce; // Display Widget ?gt; lt;div class="categories side-nav log"gt; lt;h5 class="categories__title"gt;lt;?php echo get_theme_mod('filter_product_cat_heading') ?gt;lt;/h5gt; lt;div id="st-accordion-cat" class="st-accordion"gt; lt;ul class="st-accordion-cat-list"gt; lt;?php $categories = get_terms( 'product_cat', array( 'orderby' =gt; 'menu_order', 'order' =gt; 'ask', 'hierarchical' =gt; true, 'hide_empty' =gt; 1, 'parent' =gt; 0 ) ); foreach($categories as $cat){ ?gt; lt;li class="cosmetic_filter_check"gt; lt;?php $temp_cat = get_terms( 'product_cat', array( 'orderby' =gt; 'menu_order', 'order' =gt; 'ask', 'hierarchical' =gt; true, 'hide_empty' =gt; 1, 'parent' =gt; $cat-gt;term_id ) ); $class=''; if($temp_cat) {$class='has_child';} else {$class='no_child';} ?gt; lt;input id="term_lt;?php echo $cat-gt;term_id; ?gt;" type="checkbox" name="category" value="lt;?php echo $cat-gt;term_id; ?gt;"gt; lt;label style="display:inline-block;" class="lt;?php echo $class; ?gt;"gt;lt;?php echo $cat-gt;name; ?gt;lt;/labelgt; lt;?php if($temp_cat){ echo 'lt;div class="st-content cat-list"gt;'; foreach($temp_cat as $temp){?gt; lt;div class="log__group check" style="margin-left:10px; font-weight: 400;"gt; lt;input id="term_lt;?php echo $temp-gt;term_id; ?gt;" type="checkbox" name="category" value="lt;?php echo $temp-gt;term_id; ?gt;"gt; lt;label for="term_lt;?php echo $temp-gt;term_id; ?gt;"gt;lt;?php echo $temp-gt;name; ?gt;lt;/labelgt; lt;/divgt; lt;?php } echo 'lt;/divgt;'; }?gt; lt;/ligt; lt;?php } ?gt; lt;/ulgt; lt;/divgt; lt;/divgt; lt;div class="categories side-nav log"gt; lt;h5 class="categories__title"gt;lt;?php echo get_theme_mod('filter_pa_color_heading') ?gt;lt;/h5gt; lt;div id="st-accordion-color" class="st-accordion"gt; lt;ul class="st-accordion-color-list"gt; lt;?php $categories = get_terms( 'pa_color', array( 'orderby' =gt; 'name', 'hierarchical' =gt; true, 'hide_empty' =gt; 1, 'parent' =gt; 0 ) ); foreach($categories as $cat){ ?gt; lt;li class="cosmetic_filter_pa_color_check"gt; lt;?php $temp_cat = get_terms( 'pa_color', array( 'orderby' =gt; 'name', 'hierarchical' =gt; true, 'hide_empty' =gt; 1, 'parent' =gt; $cat-gt;term_id ) ); $class=''; if($temp_cat) {$class='has_child';} else {$class='no_child';} ?gt; lt;input id="term_lt;?php echo $cat-gt;term_id; ?gt;" type="checkbox" name="category" value="lt;?php echo $cat-gt;term_id; ?gt;"gt; lt;label for="term_lt;?php echo $cat-gt;term_id; ?gt;"gt; lt;div class="pa_color-bg" style=" border: 1px solid grey; margin-right: 5px; background: lt;?php echo get_term_meta( $cat-gt;term_id, 'cosmetic_pa_color', true ); ?gt; "gt;lt;a href="#" style="display:inline-block;" class="lt;?php echo $class; ?gt;"gt;lt;/agt; lt;/divgt; lt;div class="color-label"gt;lt;?php echo $cat-gt;name; ?gt;lt;/divgt; lt;/labelgt; lt;?php if($temp_cat){ echo 'lt;div class="st-content cat-list"gt;'; foreach($temp_cat as $temp){?gt; lt;div class="log__group check" style="margin-left:10px; font-weight: 400;"gt; lt;input id="term_lt;?php echo $temp-gt;term_id; ?gt;" type="checkbox" name="category" value="lt;?php echo $temp-gt;term_id; ?gt;"gt; lt;label for="term_lt;?php echo $temp-gt;term_id; ?gt;"gt;lt;?php echo $temp-gt;name; ?gt;lt;/labelgt; lt;/divgt; lt;?php } echo 'lt;/divgt;'; } ?gt; lt;/ligt; lt;?php } ?gt; lt;/ulgt; lt;/divgt; lt;/divgt; lt;div class="categories side-nav log"gt; lt;h5 class="categories__title"gt;lt;?php echo get_theme_mod('filter_pa_size_heading') ?gt;lt;/h5gt; lt;div id="st-accordion-size" class="st-accordion"gt; lt;ul class="st-accordion-size-list"gt; lt;?php $categories = get_terms( 'pa_size', array( 'orderby' =gt; 'menu_order', 'order' =gt; 'ask', 'hierarchical' =gt; true, 'hide_empty' =gt; 1, 'parent' =gt; 0 ) ); foreach($categories as $cat){ ?gt; lt;li class="cosmetic_filter_pa_size_check"gt; lt;?php $temp_cat = get_terms( 'pa_size', array( 'orderby' =gt; 'id', 'order' =gt; 'ask', 'hierarchical' =gt; true, 'hide_empty' =gt; 1, 'parent' =gt; $cat-gt;term_id ) ); $class=''; if($temp_cat) {$class='has_child';} else {$class='no_child';} ?gt; lt;input id="term_lt;?php echo $cat-gt;term_id; ?gt;" type="checkbox" name="category" value="lt;?php echo $cat-gt;term_id; ?gt;"gt; lt;label for="term_lt;?php echo $cat-gt;term_id; ?gt;"gt; lt;a href="#" style="display:inline-block;" class="lt;?php echo $class; ?gt;"gt;lt;?php echo $cat-gt;name; ?gt;lt;/agt;lt;/labelgt; lt;?php if($temp_cat){ echo 'lt;div class="st-content cat-list"gt;'; foreach($temp_cat as $temp){?gt; lt;div class="log__group check" style="margin-left:10px; font-weight: 400;"gt; lt;input id="term_lt;?php echo $temp-gt;term_id; ?gt;" type="checkbox" name="category" value="lt;?php echo $temp-gt;term_id; ?gt;"gt; lt;label for="term_lt;?php echo $temp-gt;term_id; ?gt;"gt;lt;?php echo $temp-gt;name; ?gt;lt;/labelgt; lt;/divgt; lt;?php } echo 'lt;/divgt;'; } ?gt; lt;/ligt; lt;?php } ?gt; lt;/ulgt; lt;/divgt; lt;/divgt; lt;div class="sortby cosmetic_sortby" data-minprice="lt;?php echo $min; ?gt;" data-maxprice="lt;?php echo $max; ?gt;"gt; lt;h5 class="sortby__title categories__title"gt;lt;?php echo get_theme_mod('filter_price_range_heading') ?gt;lt;/h5gt; lt;p class="sortby__price"gt; lt;label for="amount"gt;Price:lt;/labelgt; lt;div class="price-slider"gt;lt;span class="field"gt;from lt;input type="number" value="lt;?php echo $min; ?gt;" min="lt;?php echo $min; ?gt;" max="lt;?php echo $max; ?gt;" id="priceMin" class="min_price"/gt;lt;?php echo get_woocommerce_currency_symbol(); ?gt;lt;brgt; до lt;input type="number" value="lt;?php echo $max; ?gt;" min="lt;?php echo $min; ?gt;" max="lt;?php echo $max; ?gt;" class="max_price" id="priceMax"/gt;lt;?php echo get_woocommerce_currency_symbol(); ?gt;lt;/spangt; lt;div class="min-max-slider" data-legendnum="3"gt; lt;label for="min"gt;Minimum pricelt;/labelgt; lt;input id="min" class="min" name="min" type="range" step="1" min="lt;?php echo $min; ?gt;" max="lt;?php echo $max; ?gt;" /gt; lt;label for="max"gt;Maximum pricelt;/labelgt; lt;input id="max" class="max" name="max" type="range" step="1" min="lt;?php echo $min; ?gt;" max="lt;?php echo $max; ?gt;" /gt; lt;/divgt; lt;/divgt; lt;/pgt; lt;/divgt; //!!!!!!!!!!!!!THERE IS THE SORTING HAS TO BE!!!!!!!!!!!!!!!!!!!!!!!// lt;form class="woocommerce-ordering" method="get"gt; lt;select name="orderby" class="orderby" aria-label="Shop order"gt; lt;option value="menu_order" selected="selected"gt;Default sortinglt;/optiongt; lt;option value="popularity"gt;Sort by popularitylt;/optiongt; lt;option value="rating"gt;Sort by average ratinglt;/optiongt; lt;option value="date"gt;Sort by latestlt;/optiongt; lt;option value="price"gt;Sort by price: low to highlt;/optiongt; lt;option value="price-desc"gt;Sort by price: high to lowlt;/optiongt; lt;/selectgt; lt;input type="hidden" name="paged" value="1"gt; lt;/formgt; lt;?php } protected function get_filtered_price() { global $wpdb; $args = wc()-gt;query-gt;get_main_query()-gt;query_vars; $tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array(); $meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array(); if ( ! is_post_type_archive( 'product' ) amp;amp; ! empty( $args['taxonomy'] ) amp;amp; ! empty( $args['term'] ) ) { $tax_query[] = array( 'taxonomy' =gt; $args['taxonomy'], 'terms' =gt; array( $args['term'] ), 'field' =gt; 'slug', ); } foreach ( $meta_query $tax_query as $key =gt; $query ) { if ( ! empty( $query['price_filter'] ) || ! empty( $query['rating_filter'] ) ) { unset( $meta_query[ $key ] ); } } $meta_query = new WP_Meta_Query( $meta_query ); $tax_query = new WP_Tax_Query( $tax_query ); $meta_query_sql = $meta_query-gt;get_sql( 'post', $wpdb-gt;posts, 'ID' ); $tax_query_sql = $tax_query-gt;get_sql( $wpdb-gt;posts, 'ID' ); $sql = "SELECT min( FLOOR( price_meta.meta_value ) ) as min_price, max( CEILING( price_meta.meta_value ) ) as max_price FROM {$wpdb-gt;posts} "; $sql .= " LEFT JOIN {$wpdb-gt;postmeta} as price_meta ON {$wpdb-gt;posts}.ID = price_meta.post_id " . $tax_query_sql['join'] . $meta_query_sql['join']; $sql .= " WHERE {$wpdb-gt;posts}.post_type IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_price_filter_post_type', array( 'product' ) ) ) ) . "') AND {$wpdb-gt;posts}.post_status = 'publish' AND price_meta.meta_key IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_price_filter_meta_keys', array( '_price' ) ) ) ) . "') AND price_meta.meta_value gt; '' "; $sql .= $tax_query_sql['where'] . $meta_query_sql['where']; $search = WC_Query::get_main_search_query_sql(); if ( $search ) { $sql .= ' AND ' . $search; } return $wpdb-gt;get_row( $sql ); // WPCS: unprepared SQL ok. } /** * Update Widget * @param array $new_instance * @param array $old_instance * @return array */ public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title1'] = strip_tags( $new_instance['title1'] ); $instance['title2'] = strip_tags( $new_instance['title2'] ); return $instance; } /** * Widget Settings * @param array $instance */ public function form( $instance ) { //default widget settings. $defaults = array( 'title1' =gt; 'Сортировать по цене', 'title2' =gt; 'Категории товаров', ); $instance = wp_parse_args( (array) $instance, $defaults ); ?gt; lt;pgt; lt;label for="lt;?php echo $this-gt;get_field_id( 'title1' ); ?gt;"gt;The filtration headinglt;/labelgt; lt;input type="text" class="widefat" id="lt;?php echo $this-gt;get_field_id( 'title1' ); ?gt;" name="lt;?php echo $this-gt;get_field_name( 'title1' ); ?gt;" value="lt;?php echo $instance['title1']; ?gt;" /gt; lt;/pgt; lt;pgt; lt;label for="lt;?php echo $this-gt;get_field_id( 'title2' ); ?gt;"gt;The filtration headinglt;/labelgt; lt;input type="text" class="widefat" id="lt;?php echo $this-gt;get_field_id( 'title2' ); ?gt;" name="lt;?php echo $this-gt;get_field_name( 'title2' ); ?gt;" value="lt;?php echo $instance['title2']; ?gt;" /gt; lt;/pgt; lt;?php } }
Js part
jQuery(function($) { $('.categories.side-nav.loggt;.st-accordiongt;ulgt;li input, .cosmetic_sortby input, select.orderby').on('change',function(e){ e.preventDefault(); cosmetic_get_posts(); jQuery('html, body').animate({scrollTop:0}, 1); }); $(document).on("click",".ajax-page-numbers .page-numbers",function(e){ e.preventDefault(); var url = $(this).attr('href'); //Grab the URL destination as a string var paged = url.split('amp;paged='); //Split the string at the occurance of amp;paged= if(~url.indexOf('amp;paged=')){ paged = url.split('amp;paged='); } else { paged = url.split('/page/'); } cosmetic_get_posts(paged[1]); //Load Posts (feed in paged value) }); function getCats() { var cats = []; //Setup empty array $(".cosmetic_filter_check input:checked").each(function() { var val = $(this).val(); cats.push(val); //Push value onto array }); return cats; //Return all of the selected genres in an array } function getColor() { var cats = []; //Setup empty array $(".cosmetic_filter_pa_color_check input:checked").each(function() { var val = $(this).val(); cats.push(val); //Push value onto array }); return cats; //Return all of the selected genres in an array } function getSize() { var cats = []; //Setup empty array $(".cosmetic_filter_pa_size_check input:checked").each(function() { var val = $(this).val(); cats.push(val); //Push value onto array }); return cats; //Return all of the selected genres in an array } function getPricesMin(){ return $('#priceMin').val(); } function getPriceMax(){ return $('#priceMax').val(); } function cosmetic_order(){ return $('.orderby option:selected').val(); } function cosmetic_get_posts(paged) { var paged_value = paged; //Store the paged value if it's being sent through when the function is called var ajax_url = woocommerce_params.ajax_url; jQuery.ajax({ type: 'GET', url: ajax_url, data: { action: 'cosmetic_filter', category: getCats, pa_color: getColor, pa_size: getSize, min: getPricesMin, max: getPriceMax, order: cosmetic_order, paged: paged_value //If paged value is being sent through with function call, store here }, beforeSend: function () { jQuery('.main-products-wrapper').html('lt;div class="text-center" style="height:50vh;"gt;Searching...lt;/divgt;'); }, success: function(data) { //Hide loader here jQuery('.main-products-wrapper').html(data); jQuery('.main-products-wrapper ul.products').addClass('row align-items-start'); jQuery('.product').addClass('col-lg-4 col-6'); }, error: function() { //If an ajax error has occured, do something here... jQuery(".main-products-wrapper").html('lt;div class="text-center" style="height:50vh;"gt;Something is wronglt;/divgt;'); } }); } });
Я знаю, что это очень долго, но, может быть, кому-то это пригодится. Я просто хочу выяснить, как заставить выбор по умолчанию правильно работать внутри фильтра. Обычно ли сортировка по умолчанию работает с ajax?