Привет. Есть страница товаров.
Слева параметры фильтрации (по цене и по размеру).
При выборе размера или изменении цен происходит запрос на загрузку постов. В AJAX коллбэке (в functions.php) эти данные принимаются и передаются в WP_Query, чтобы загрузить посты (нужного размера и в диапазоне выбранных цен). После получения постов обратно высылаем разметку постов вместе с пагинацией.
Фильтр работает как надо, но вот ссылки пагинации формируются неправильно.
1. Если просто зайти на страницу товаров (не применяя фильтры), то в пагинации такие ссылки:
http:// example .com/page/номер_страницы/
2. Если применить фильтр (подгрузить новую разметку) в ссылках вот такие адреса (использую GET запрос):
http:// example .com/wp-admin/admin-ajax.php?action=my_ajax_action&minPrice=3000&maxPrice=20000&sizes[]=216&paged=номер_страницы
И при переходе по ним ничего не работает.
3. Мне же нужно что-то вроде:
http:// example .com/page/номер_страницы/?minPrice=3000&maxPrice=20000&sizes[]=216
Внимание. Я
не хочу, чтобы при клике на ссылки пагинации посты загружались AJAX'ом. При клике на ссылку будет просто перезагружаться страница и будут показываться товары выбранной страницы с примененными фильтром.
Код с комментариями.
script.js:
// функция отправляет запрос на подгрузку нужных товаров
// вызывается, когда пользователь меняет диапазон цен или выбирает размер товара
function updateProducts(minPrice, maxPrice, sizes) {
$.ajax({
url: ajaxurl,
type: "GET",
data: {
action: 'my_ajax_action',
minPrice: minPrice,
maxPrice: maxPrice,
sizes: sizes,
},
success: function (html) {
const shop = document.querySelector(".shop-catalog"); // элемент с постами и пагинацией
shop.innerHTML = html; // полученную разметку помещаем заместо старых постов и старой пагинации
}
});
}
functions.php
add_action("wp_ajax_my_ajax_action", "filter_products");
add_action("wp_ajax_nopriv_my_ajax_action", "filter_products");
function filter_products() {
$minPrice = $_GET['minPrice'];
$maxPrice = $_GET['maxPrice'];
$sizes = $_GET['sizes'];
$query = new WP_Query([
'post_type' => 'product',
'paged' => 1, // пока что 1, потом буду подставлять нужную страницу
'posts_per_page' => 15,
'orderby' => 'date',
'order' => 'DESC',
// получаем товары с ценами от minPrice до maxPrice
'meta_query' => [
[
'key' => '_price',
'value' => [$minPrice, $maxPrice],
'compare' => 'BETWEEN',
'type' => 'NUMERIC'
],
],
// с атрибутами (размерами), указанными в массиве $sizes
'tax_query' => [
[
'taxonomy' => 'pa_размер',
'field' => 'id',
'terms' => $sizes,
]
]
]);
// пришлось вызывать это, т. к. без этого не формировалась пагинация, т. к. wc_get_loop_prop('total') не возвращал правильное значение и цикл внизу не запускался
wc_setup_loop([
'current_page' => 1,
'total' => $query->found_posts,
'total_pages' => $query->max_num_pages,
'per_page' => $query->post_count,
]);
// этот код вырван из archive-product.php, чтобы товары посты выводились точно также как там (как на странице товара, когда заходим в первый раз)
if ($query->have_posts()) {
woocommerce_product_loop_start(); // <ul>
if (wc_get_loop_prop('total')) {
while ($query->have_posts()) {
$query->the_post();
do_action('woocommerce_shop_loop'); // не помню, да и не особо важно, что это
wc_get_template_part('content', 'product'); // сам товар
}
}
wp_reset_postdata();
woocommerce_product_loop_end(); // </ul>
do_action('woocommerce_after_shop_loop'); // сама пагинация, ниже оставлю код
} else {
do_action('woocommerce_no_products_found');
}
wp_die();
}
Для пагинации используется стандартный шаблон woocommerce - pagination.php
Короче говоря вместо do_action('woocommerce_after_shop_loop'); в коде выше, будет следующий html для пагинации
стандартный шаблон пагинации woocommerce
$total = isset( $total ) ? $total : wc_get_loop_prop( 'total_pages' );
$current = isset( $current ) ? $current : wc_get_loop_prop( 'current_page' );
$base = isset( $base ) ? $base : esc_url_raw( str_replace( 999999999, '%#%', remove_query_arg( 'add-to-cart', get_pagenum_link( 999999999, false ) ) ) );
$format = isset( $format ) ? $format : '';
if ( $total <= 1 ) {
return;
}
?>
<nav class="woocommerce-pagination">
<?php
echo paginate_links(
apply_filters(
'woocommerce_pagination_args',
array( // WPCS: XSS ok.
'base' => $base,
'format' => $format,
'add_args' => false,
'current' => max( 1, $current ),
'total' => $total,
'prev_text' => is_rtl() ? '→' : '←',
'next_text' => is_rtl() ? '←' : '→',
'type' => 'list',
'end_size' => 3,
'mid_size' => 3,
)
)
);
?>