Как правильно сформировать пагинацию при AJAX подгрузке постов?

Привет. Есть страница товаров.
Слева параметры фильтрации (по цене и по размеру).
При выборе размера или изменении цен происходит запрос на загрузку постов. В 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() ? '&rarr;' : '&larr;',
				'next_text' => is_rtl() ? '&larr;' : '&rarr;',
				'type'      => 'list',
				'end_size'  => 3,
				'mid_size'  => 3,
			)
		)
	);
?>

  • Вопрос задан
  • 503 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы