Вопрос или проблема
Я раньше здесь не задавал вопросов, так что извините, если я делаю это неправильно. Я новичок в пользовательских темах и шаблонах. Я также новичок в WordPress и PHP. Это учебное упражнение для меня. Я создаю страницу с продуктами различных типов, все с определенным количеством калорий. Я хотел бы, чтобы были кнопки, которые при нажатии будут перечислять все продукты, отмеченные как определенный тип. Я использую пользовательский тип записи “прием пищи” и ACF для создания пользовательских полей. Вот страница: https://blog.unicornpoint.net/wp/safe-foods-meal-generator-diet-assistant/
У меня есть кнопка, которая имеет событие клика jQuery.
<script>
jQuery(document).ready(function($){
$('#emergency-icon').click(function(){
$.ajax({
method: 'GET',
url: 'my-url.php'
}).done(function(data){
$("#meal-results").html(data);
});
});
});
</script>
Когда кнопка нажата, она возвращает “Вы достигли файла.” в целевом div. Это код в php-файле, который вызывается в небольшом блоке ajax. Он работает самостоятельно и отображается на странице в блоке, чтобы показать, что он работает.
<?php echo "Вы достигли файла."; ?>
<div class="d-inline-flex flex-wrap text-center p-2">
<?php
$args = array('post_type' => 'meal');
$meals = new WP_Query($args);
if($meals->have_posts()) : while($meals->have_posts()) : $meals->the_post();
$meal_type = get_field('meal_type');
if ( $meal_type && in_array('emergency', $meal_type)){?>
<div class="text-center p-2 meal-size-posts">
<h4><?php the_field('meal_name'); ?></h4>
<img src="https://wordpress.stackexchange.com/questions/360506/<?php echo get_field("meal_icon'); ?>" class="meal-icon">
<p class="meal-description"><?php the_field('meal_description'); ?></p>
<h4><?php the_field('meal_calories'); ?> калорий</h4>
</div>
<?php } ?>
<?php endwhile; endif; ?>
</div>
Можете ли вы помочь мне сделать это работающим или указать на простые для понимания ресурсы, чтобы я лучше понимал, как это сделать? Большое спасибо.
Во-первых, я бы рекомендовал убедиться, что $meal_type = get_field('meal_type');
возвращает массив строк – для этого вы можете просто вызвать var_dumb($meal_type)
после получения значения этого поля. Например, если вы использовали поле Repeater для meal_type, вы увидите массив массивов, а не массив строк.
Также это довольно странная вещь с ACF, но когда вы находитесь в цикле пользовательского WP_Query, и даже если вы сделали это правильно через $meal->the_post()
, чтобы настроить глобальный объект $post
, иногда он может игнорировать тот, который вы только что установили. Итак, вот более надежный способ вызова get_field()
<?php if( $meals->have_posts() ) :
$meal_posts = $meals->get_posts();
foreach( $meal_posts as $meal_post) :
$meal_type = get_field('meal_type', $meal_post);
if ( $meal_type && in_array('emergency', $meal_type)): ?>
<div class="text-center p-2 meal-size-posts">
<h4><?php the_field('meal_name', $meal_post); ?></h4>
<img src="https://wordpress.stackexchange.com/questions/360506/<?php echo get_field("meal_icon', $meal_post); ?>" class="meal-icon">
<p class="meal-description"><?php the_field('meal_description', $meal_post); ?></p>
<h4><?php the_field('meal_calories', $meal_post); ?> калорий</h4>
</div>
<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
Чтобы убедиться, что он получает данные из правильного места, вы можете передать в качестве второго аргумента объект $post, который вы хотите использовать для получения данных ACF.
Также, если вы хотите, чтобы это код был более общего назначения, работающий для всех типов приемов пищи.
-
Измените разметку списка типов приемов пищи на
<div class="col-6 col-md-3"> <a href="#emergency" class="load-meal-by-type"> <img width="75" height="auto" alt="Эмердженси" id="emergency-icon" data-src="https://blog.unicornpoint.net/wp/wp-content/uploads/2020/02/panic.png" class="meal-icon lazyloaded" src="https://blog.unicornpoint.net/wp/wp-content/uploads/2020/02/panic.png" loading="lazy"> <noscript> <img src="https://blog.unicornpoint.net/wp/wp-content/uploads/2020/02/panic.png" width="75" height="auto" alt="Эмердженси" class="meal-icon" id="emergency-icon"> </noscript> <span class="meal-icon-caption"> Эмердженси</span> </a> </div>
-
Измените JS код на
<script> jQuery(document).ready(function($){ $('a.load-meal-by-type').click(function(event){ event.preventDefault(); // предотвратить переход браузера по #ссылке var $btn = $(this); // быстрый способ получить текущую нажатую ссылку внутри функции обработчика var mealType = $btn.attr('href'); // мы передадим тип приема пищи в качестве переменной для ajax mealType = mealType.replace('#', ''); // уберите #, так как он нам не нужен - мы оставили его в href изначально, чтобы сделать ссылку действительной, и в то же время - если вы хотите сделать шаг дальше, вы можете сделать то, что называется deeplinking, имея возможность иметь общую ссылку, которая загрузит точный контент, как если бы вы нажали на ссылку. $.ajax({ method: 'GET', url: 'my-url.php', data: { mealType: mealType // мы передаем нашу строку mealType в php как GET параметр. } }).done(function(data){ $("#meal-results").html(data); }); }); }); </script>
-
Затем в PHP мы получим эту переменную
mealType
$requested_meal_type = sanitize_text_field( isset( $_GET['mealType'] ) ? $_GET['mealType'] : '' );
Важно очищать любые пользовательские данные, которые вы читаете из запросов, иначе может произойти нарушение безопасности.Итак, имея эту переменную, мы можем изменить условие на
if ( $meal_type && in_array($requested_meal_type , $meal_type))
, чтобы иметь возможность обрабатывать разные типы приемов пищи.Вы также можете проверить случай, если переменная
mealType
в $_GET пуста, и показать –сообщение о том, что приемов пищи не найдено
, например
if ( empty( $requested_meal_type ) ) { echo 'приемов пищи не найдено' } else { // выполнять wp запрос и другую логику, как следует. }
-
/// UPD
Ситуация, которую я считаю может произойти, это то, что вы вызываете my-url.php
, я думал, что это просто пример и пропустил это. В WordPress, когда вам нужно обрабатывать что-то, сгенерированное через php через ajax, это немного по-другому, чем просто создание файла my-url.php
в корневом каталоге сайта.
Способ вызова ajax в WordPress:
-
вызвать
/wp-admin/admin-ajax.php
вместо вашего пользовательского php файла, из js в ajax, -
передать переменную
action
в js, это имя действия будет действием, которое мы определяем в PHP для обработки этого типа ajax-запросов. Так что ajax часть кода JS превратится в.$.ajax({ method: 'GET', url: '/wp-admin/admin-ajax.php', // мы отправляем все WP ajax запросы в этот файл, он загрузит все файлы WP, плагины. Это подход WP Ajax. data: { action: 'load_meals', // вы можете назвать это как угодно, просто используйте то же самое в PHP, привязывая действие ajax. mealType: mealType // мы передаем нашу строку mealType в php как GET параметр. } }).done(function(data){ $("#meal-results").html(data); });
-
в вашем файле темы
functions.php
мы создадим php обработчик ajax, который сгенерирует желаемую html разметку и отправит ее обратно в js. Так что часть php кода, которую мы помещаем вfunctions.php
, будет выглядеть следующим образом.// эта функция будет рендерить наш html и отправлять его обратно в js по запросу ajax. function my_ajax_load_meals() { $requested_meal_type = sanitize_text_field( isset( $_GET['mealType'] ) ? $_GET['mealType'] : '' ); echo 'Вы достигли файла.'; ?> ?> <div class="d-inline-flex flex-wrap text-center p-2"> <?php $args = array( 'post_type' => 'meal' ); $meals = new WP_Query( $args ); if ( $meals->have_posts() ) : $meals_posts = $meals->get_posts(); foreach ( $meals_posts as $meal_post ) : $meal_type = get_field( 'meal_type', $meal_post ); if ( $meal_type && in_array( $requested_meal_type, $meal_type ) ): ?> <div class="text-center p-2 meal-size-posts"> <h4><?php the_field( 'meal_name', $meal_post ); ?></h4> <img src="https://wordpress.stackexchange.com/questions/360506/<?php echo get_field("meal_icon', $meal_post ); ?>" class="meal-icon"> <p class="meal-description"><?php the_field( 'meal_description', $meal_post ); ?></p> <h4><?php the_field( 'meal_calories', $meal_post ); ?> калорий</h4> </div> <?php endif; ?> <?php endforeach; ?> <?php endif; ?> </div> <?php exit(); // важно завершить, чтобы закрыть вывод и дать js знать, что он уже загрузил все. } // это место, где мы связываем нашу функцию с названием действия `load_meals`. // тот, у которого есть префикс `_nopriv` в имени действия wp, предназначен для пользователей, не вошедших в систему, а без него - для вошедших в систему пользователей. add_action('wp_ajax_load_meals', 'my_ajax_load_meals'); add_action('wp_ajax_nopriv_load_meals', 'my_ajax_load_meals');
Ответ или решение
Для создания кнопки, которая при нажатии будет заполнять блок (div) списком продуктов, соответствующих определённому типу при помощи Advanced Custom Fields (ACF) в WordPress, вы можете воспользоваться следующими шагами. Это руководство ориентировано на новичков в WordPress и PHP и поможет вам освоить основные аспекты работы с AJAX и кастомными полями.
1. Создание кнопки с использованием jQuery
Начнём с создания кнопки и соответствующего скрипта для обработки клика. Добавьте следующий HTML-код в ваше шаблонное файл:
<div class="col-6 col-md-3">
<a href="#emergency" class="load-meal-by-type">
<img width="75" height="auto" alt="Emergency" id="emergency-icon" src="https://blog.unicornpoint.net/wp/wp-content/uploads/2020/02/panic.png" class="meal-icon" loading="lazy" />
<span class="meal-icon-caption">Emergency</span>
</a>
</div>
И добавьте следующий jQuery-скрипт для обработки нажатия кнопки:
<script>
jQuery(document).ready(function($){
$('a.load-meal-by-type').click(function(event){
event.preventDefault(); // предотвращает переход по ссылке
var mealType = $(this).attr('href').replace('#', ''); // получаем тип еды
$.ajax({
method: 'GET',
url: '/wp-admin/admin-ajax.php',
data: {
action: 'load_meals', // имя действия для обработки AJAX
mealType: mealType // передаем тип еды в качестве параметра
}
}).done(function(data){
$("#meal-results").html(data); // заполняем блок результатами
});
});
});
</script>
2. Обработка AJAX-запросов на сервере
Теперь нужно настроить обработку AJAX-запросов в вашем файле functions.php
. Добавьте следующий код:
function my_ajax_load_meals() {
$requested_meal_type = sanitize_text_field( isset( $_GET['mealType'] ) ? $_GET['mealType'] : '' );
if (empty($requested_meal_type)) {
echo 'Нет доступных блюд';
exit();
}
$args = array('post_type' => 'meal');
$meals = new WP_Query($args);
if ($meals->have_posts()) {
echo '<div class="d-inline-flex flex-wrap text-center p-2">';
while ($meals->have_posts()) {
$meals->the_post();
$meal_type = get_field('meal_type');
if ($meal_type && in_array($requested_meal_type, $meal_type)) {
echo '<div class="text-center p-2 meal-size-posts">';
echo '<h4>' . get_field('meal_name') . '</h4>';
echo '<img src="' . get_field("meal_icon") . '" class="meal-icon">';
echo '<p class="meal-description">' . get_field('meal_description') . '</p>';
echo '<h4>' . get_field('meal_calories') . ' calories</h4>';
echo '</div>';
}
}
echo '</div>';
} else {
echo 'Нет доступных продуктов';
}
wp_die(); // завершаем выполнение AJAX
}
add_action('wp_ajax_load_meals', 'my_ajax_load_meals');
add_action('wp_ajax_nopriv_load_meals', 'my_ajax_load_meals');
3. Объяснение кода
-
Кнопка и jQuery:
- Мы создаём кнопку, при нажатии на которую будет отправлен AJAX-запрос на сервер.
- jQuery использует метод
$.ajax()
для отправки GET-запроса вadmin-ajax.php
, где обрабатывается запрос.
-
PHP и AJAX:
- Функция
my_ajax_load_meals
получает параметрmealType
, очищая его от лишних символов для безопасности. - Мы выполняем WP_Query для получения продуктов и фильтруем их по переданному типу.
- Рендерим HTML, который затем возвращается в
#meal-results
на странице.
- Функция
4. Заключение
Теперь у вас есть полностью работающая система, которая реагирует на нажатие кнопки и динамически загружает контент подлежащих типов продуктов. Это решение может быть адаптировано для разных типов еды, просто изменяя идентификаторы и названия в HTML и JavaScript.
Ресурсы для дальнейшего изучения:
Успехов в вашем обучении и разработке! Если возникнут дополнительные вопросы, всегда рад помочь!