Проблема с категориями фильтров Ajax и Javascript

Вопрос или проблема

Я создал фильтр категорий Ajax для отображения постов на своем сайте. Фильтр использует флажки input, чтобы пользователь мог выбрать одну или несколько категорий.

Проблема в том, что когда я выбираю категорию (или несколько), показываются все посты, они не фильтруются.

Что я также пытаюсь сделать, так это когда ни одна из категорий не выбрана, должны отображаться все посты по умолчанию.

PHP фильтр:

<?php
if( $terms = get_terms( array( 'taxonomy' => 'category', 'parent' => 0, 'hide_empty' => true ) ) ) :

    echo '
    <form data-ajax-url="'. get_site_url()  .'/wp-admin/admin-ajax.php" method="POST" id="filter" class="js-filter">
        <ul class="js-filter-list">';

            foreach( $terms as $term ) :

                $term_id = $term->term_id;
                $term_name = $term->name;
                $term_slug = $term->slug;

                $term_color = get_term_meta( $term_id, 'post-category-settings__color', true );

                echo '
                <li class="js-filter-item js-filter-term" data-slug="'. esc_attr( $term_slug ) .'">
                    <input type="checkbox" class="c-filter__check" id="' . esc_attr($term_id) . '" name="' . esc_attr($term_id) . '" />
                    <label class="semi-medium" for="' . esc_attr($term_id) . '"><span></span>' . esc_html($term_name) . '</label>
                </li>';
            endforeach;

    echo '
        </ul>
        <input type="hidden" name="action" value="filterpost">
    </form>';
endif;
?>

<div class="js-container"></div>

Javascript:

if (document.querySelector('.js-filter')) {
    const ajax_url = document.querySelector(".js-filter").dataset.ajaxUrl;
    let filterBtn = document.querySelectorAll('.js-filter-term');

    var i;
    for( i = 0; i < filterBtn.length; i++ ){
        filterBtn[i].addEventListener('change', function(){

            const containerTerm = document.querySelector(".js-container");
            const data = new FormData();

            let term_slug = this.dataset.slug;

            data.append( 'action', 'filterpost' );
            data.append( 'category', term_slug );

            fetch(ajax_url, {
            method: "POST",
            body: data
            })
            .then((response) => response.text())
            .then((data) => {
            if (data) {
                containerTerm.innerHTML=data;
            }
            })
            .catch((error) => {

            });
        });
    };
}

Ajax обработчик:

<?php
function site_filter_post() {

    if( $terms = get_terms( array( 'taxonomy' => 'category' ) ) ) :
        $terms_list = array();

        foreach( $terms as $term ) {
        if( isset( $_POST[$term->term_id ] ) && $_POST[$term->term_id] == 'on' )
         $terms_list[] = $term->slug;
        }
    endif;

    $tax_query = array( 'relation' => 'AND' );
  
    if ( ! empty( $terms_list ) ) {
        $tax_query[] = array(
            array(
            'taxonomy'      => 'category',
            'field'         => 'slug',
            'terms'         => $terms_list,
            )
        );
    }
  
    $args = array(
        'post_type'         => 'post',
        'posts_per_page'    => -1,
        'post_status'       => 'publish',
        'orderby'           => 'date',
        'tax_query'         => $tax_query
        
    );

    $query = new WP_Query( $args );
  
    if($query->have_posts()) {

        while($query->have_posts()) : $query->the_post();

            get_template_part( 'template-parts/content', 'archive' );
  
        endwhile;
  
    } else {

        echo 'Нет результатов.';

    }
  
    exit;
}
add_action('wp_ajax_filterpost', 'site_filter_post');
add_action('wp_ajax_nopriv_filterpost', 'site_filter_post');
?>

ИЗМЕНЕНИЕ

Я думаю, что проблема в моем JS коде. Я провел тест с использованием jQuery, и он работает. Однако я не хочу использовать jQuery, только чистый Javascript.

Код jQuery:

$('.js-filter').change(function(){
        var filter = $('.js-filter');
        $.ajax({
            url:filter.attr('action'),
            data:filter.serialize(),
            type:filter.attr('method'),
            beforeSend:function(xhr){
                
            },
            success:function(data){

                $('.js-ajax-response').html(data);
            }
        });
        return false;
    });

Спасибо!

.

Ответ или решение

Проблема, описанная в вашем вопросе, связана с фильтрацией постов по категориям с помощью Ajax и JavaScript. Система фильтрации, основанная на Ajax, позволяет пользователям выбирать одну или несколько категорий через флажки, но возникает проблема: ваши фильтры не работают должным образом, и вместо конкретных постов выводятся все посты. Давайте разберем потенциал проблемы и возможные решения более детально.

Теория

Основная задача системы фильтрации на основе Ajax — динамически загружать и отображать контент в зависимости от выбранных пользователем категорий без перезагрузки страницы. Это достигается с использованием комбинации HTML, JavaScript и PHP. Основные этапы этого процесса:

  1. HTML и JavaScript: Генерация интерфейса с чекбоксами для выбора категорий. JavaScript обрабатывает события изменения состояния этих чекбоксов и отправляет соответствующие данные AJAX-запросом на сервер.
  2. PHP: Серверный язык, который получает данные от JavaScript, выполняет запрос к базе данных WordPress с учетом выбранных категорий и возвращает результаты для отображения на веб-странице.

Пример

В вашем случае JavaScript код отправляет AJAX-запрос на сервер при каждом изменении состояния чекбокса, используя fetch. Этот код создает FormData объект, который отправляется на сервер. Однако проблема в вашем подходе заключается в том, что вы отправляете только по одному значению категории за раз (term_slug), и одно из наиболее вероятных мест возникновения ошибки — формирование неправильного POST-запроса, из-за чего фильтрация не происходит надлежащим образом.

Применение

Лучший способ решения данной проблемы состоит в следующем:

  1. Изменения в JavaScript:

    • Убедитесь, что собираете все выбранные категории перед отправкой запроса и передаете их как массив. Это поможет гарантировать, что все выбранные категории обрабатываются на сервере.
if (document.querySelector('.js-filter')) {
    const ajax_url = document.querySelector(".js-filter").dataset.ajaxUrl;
    const filters = document.querySelectorAll('.js-filter-list input[type="checkbox"]');

    filters.forEach(filter => filter.addEventListener('change', function() {
        const data = new FormData(document.querySelector('#filter'));

        fetch(ajax_url, {
            method: "POST",
            body: data
        })
        .then(response => response.text())
        .then(html => {
            document.querySelector('.js-container').innerHTML = html;
        })
        .catch(error => {
            console.error('Ошибка:', error);
        });
    }));
}

В этом коде используется FormData(document.querySelector('#filter')), что автоматически соберет все выбранные чекбоксы и отправит их как часть запроса. Это означает, что PHP-скрипт должен быть готов обработать массив значений.

  1. Изменения в обработчике PHP:

    В PHP обработчик должен корректно обрабатывать массив идентификаторов или имен категорий. В вашем случае, если все категории отправляются как масса, вы можете изменить обработчик следующим образом:

function site_filter_post() {
    $terms_list = isset($_POST['category']) ? $_POST['category'] : array();

    $tax_query = array();

    if (!empty($terms_list)) {
        $tax_query[] = array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => $terms_list,
        );
    }

    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'post_status'    => 'publish',
        'orderby'        => 'date',
        'tax_query'      => $tax_query,
    );

    $query = new WP_Query($args);

    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            get_template_part('template-parts/content', 'archive');
        }
    } else {
        echo 'No result.';
    }
    wp_reset_postdata();
    exit;
}
add_action('wp_ajax_filterpost', 'site_filter_post');
add_action('wp_ajax_nopriv_filterpost', 'site_filter_post');

Этот код предполагает, что параметры с переданными категориями находятся в массиве $_POST['category'].

Заключение

Проблема, вероятно, заключается в JavaScript, который создавал не совсем корректный запрос, отправляя только одну категорию. Исправив JavaScript, чтобы он отправлял массив чекбоксов, и обеспечив правильную обработку массива в PHP, вы сможете решить проблему фильтрации. Оптимизация кода таким образом обеспечит правильную работу фильтров без необходимости использования jQuery, если ваша цель — минимизировать зависимость от сторонних библиотек.

Оцените материал
Добавить комментарий

Капча загружается...