Вопрос или проблема
Я создал фильтр категорий 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. Основные этапы этого процесса:
- HTML и JavaScript: Генерация интерфейса с чекбоксами для выбора категорий. JavaScript обрабатывает события изменения состояния этих чекбоксов и отправляет соответствующие данные AJAX-запросом на сервер.
- PHP: Серверный язык, который получает данные от JavaScript, выполняет запрос к базе данных WordPress с учетом выбранных категорий и возвращает результаты для отображения на веб-странице.
Пример
В вашем случае JavaScript код отправляет AJAX-запрос на сервер при каждом изменении состояния чекбокса, используя fetch
. Этот код создает FormData
объект, который отправляется на сервер. Однако проблема в вашем подходе заключается в том, что вы отправляете только по одному значению категории за раз (term_slug
), и одно из наиболее вероятных мест возникновения ошибки — формирование неправильного POST
-запроса, из-за чего фильтрация не происходит надлежащим образом.
Применение
Лучший способ решения данной проблемы состоит в следующем:
-
Изменения в 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-скрипт должен быть готов обработать массив значений.
-
Изменения в обработчике 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, если ваша цель — минимизировать зависимость от сторонних библиотек.