Диагностика проблемы: почему стандартная пагинация WooCommerce не подходит для динамических фильтров
По умолчанию WooCommerce использует стандартную пагинацию, которая обновляет страницу целиком при переходе между страницами каталога. При использовании динамических AJAX-фильтров и сортировок это приводит к перезагрузке страницы, потере состояния фильтров и неудобному UX.
Типичные симптомы:
- Переход по страницам сбрасывает выбранные фильтры.
- Пагинация не работает после применения AJAX-фильтров.
- Перезагрузка страницы при смене страницы пагинации.
Пошаговое решение: реализация AJAX пагинации с учетом динамических фильтров
1. Подключение скриптов и локализация данных
Добавьте в файл functions.php темы или в свой плагин следующий код для подключения собственного JS и передачи параметров AJAX:
function my_enqueue_ajax_pagination_scripts() {
if (is_shop() || is_product_category() || is_product_tag()) {
wp_enqueue_script('my-ajax-pagination', get_template_directory_uri() . '/js/my-ajax-pagination.js', array('jquery'), '1.0', true);
wp_localize_script('my-ajax-pagination', 'my_ajax_params', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('my_ajax_nonce')
));
}
}
add_action('wp_enqueue_scripts', 'my_enqueue_ajax_pagination_scripts');2. Создание AJAX обработчика на PHP
Реализуйте обработчик AJAX запроса, который принимает параметры фильтров и пагинации, формирует WP_Query и возвращает обновленный HTML каталога с пагинацией:
function my_ajax_pagination_handler() {
check_ajax_referer('my_ajax_nonce', 'nonce');
$paged = isset($_POST['paged']) ? intval($_POST['paged']) : 1;
$tax_query = array();
if (!empty($_POST['filters'])) {
foreach ($_POST['filters'] as $taxonomy => $terms) {
$tax_query[] = array(
'taxonomy' => sanitize_text_field($taxonomy),
'field' => 'slug',
'terms' => array_map('sanitize_text_field', $terms),
'operator' => 'IN',
);
}
}
$args = array(
'post_type' => 'product',
'posts_per_page' => 12,
'paged' => $paged,
'tax_query' => $tax_query,
);
$query = new WP_Query($args);
ob_start();
if ($query->have_posts()) {
woocommerce_product_loop_start();
while ($query->have_posts()) {
$query->the_post();
wc_get_template_part('content', 'product');
}
woocommerce_product_loop_end();
// пагинация
echo paginate_links(array(
'total' => $query->max_num_pages,
'current' => $paged
));
} else {
echo '<p>Товары не найдены.</p>';
}
wp_reset_postdata();
$html = ob_get_clean();
wp_send_json_success(array('html' => $html));
}
add_action('wp_ajax_my_ajax_pagination', 'my_ajax_pagination_handler');
add_action('wp_ajax_nopriv_my_ajax_pagination', 'my_ajax_pagination_handler');3. JavaScript для обработки кликов по пагинации и фильтрам
Создайте файл my-ajax-pagination.js с кодом, который перехватывает клики и отправляет AJAX-запрос:
jQuery(document).ready(function($) {
function getSelectedFilters() {
var filters = {};
$('.widget_layered_nav_filters input:checked').each(function() {
var taxonomy = $(this).data('taxonomy');
if (!filters[taxonomy]) {
filters[taxonomy] = [];
}
filters[taxonomy].push($(this).val());
});
return filters;
}
function loadProducts(paged) {
var data = {
action: 'my_ajax_pagination',
nonce: my_ajax_params.nonce,
paged: paged || 1,
filters: getSelectedFilters()
};
$.post(my_ajax_params.ajax_url, data, function(response) {
if (response.success) {
$('.products-grid').html(response.data.html);
history.pushState(null, null, '?paged=' + paged);
}
});
}
// Перехват кликов по пагинации
$(document).on('click', '.woocommerce-pagination a', function(e) {
e.preventDefault();
var href = $(this).attr('href');
var paged = 1;
var match = href.match(/[?&]paged=(\d+)/);
if (match) {
paged = parseInt(match[1]);
}
loadProducts(paged);
});
// Перехват изменений фильтров
$(document).on('change', '.widget_layered_nav_filters input', function() {
loadProducts(1);
});
// Обработка кнопки назад в браузере
window.onpopstate = function() {
var urlParams = new URLSearchParams(window.location.search);
var paged = urlParams.get('paged') || 1;
loadProducts(paged);
};
});Проверка результата после внедрения
- Откройте страницу магазина или категории.
- Выберите один или несколько фильтров — список товаров обновится без перезагрузки.
- Нажмите на номера страниц пагинации — товары сменятся AJAX-запросом, фильтры сохранятся.
- Проверьте, что URL меняется параметром
?paged=и работает кнопка назад браузера.
Частые ошибки и как их исправить
- Пагинация ведет на 404 страницу или перезагружает весь сайт: Убедитесь, что в AJAX запросе правильно передается параметр
pagedи обработчик корректно его использует. - Фильтры сбрасываются при переключении страницы: Проверьте, что в JS собираются и отправляются все активные фильтры вместе с номером страницы.
- Не обновляется URL или не работает кнопка назад: Проверьте реализацию
history.pushStateи обработку событияonpopstate. - Пагинация не отображается: Убедитесь, что функция
paginate_linksвызывается и выводится в AJAX ответе.
Практические советы по производительности и безопасности
- Используйте nonce для безопасности AJAX-запросов, чтобы предотвратить CSRF.
- Кешируйте результаты запросов, если фильтры и страница не меняются, для снижения нагрузки на сервер.
- Проверяйте и фильтруйте входящие данные в AJAX обработчике, особенно параметры фильтров и пагинации.
- Минимизируйте JS и объединяйте скрипты, чтобы снизить время загрузки.
Сравнение вариантов реализации AJAX пагинации WooCommerce
| Способ | Плюсы | Минусы |
|---|---|---|
| Плагин AJAX фильтров и пагинации | Быстрая настройка, готовый UI, поддержка обновлений | Может быть тяжелым, ограничен функционал, платные версии |
| Самописное решение на AJAX (как в статье) | Полный контроль, легковесность, кастомизация | Требует знаний PHP и JS, необходимо тестировать |
| Переход на бесконечный скролл с AJAX | Удобно для UX, плавная загрузка товаров | Может ухудшить SEO, сложнее реализовать фильтры |