Как я могу создать кнопку, которая при нажатии заполняет div списком продуктов, отмеченных как определенный тип ACF?

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

Я раньше здесь не задавал вопросов, так что извините, если я делаю это неправильно. Я новичок в пользовательских темах и шаблонах. Я также новичок в 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.

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

  1. Измените разметку списка типов приемов пищи на

    <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>
    
  2. Измените 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>
    
    1. Затем в 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:

  1. вызвать /wp-admin/admin-ajax.php вместо вашего пользовательского php файла, из js в ajax,

  2. передать переменную 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);
                });
    
  3. в вашем файле темы 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. Объяснение кода

  1. Кнопка и jQuery:

    • Мы создаём кнопку, при нажатии на которую будет отправлен AJAX-запрос на сервер.
    • jQuery использует метод $.ajax() для отправки GET-запроса в admin-ajax.php, где обрабатывается запрос.
  2. PHP и AJAX:

    • Функция my_ajax_load_meals получает параметр mealType, очищая его от лишних символов для безопасности.
    • Мы выполняем WP_Query для получения продуктов и фильтруем их по переданному типу.
    • Рендерим HTML, который затем возвращается в #meal-results на странице.

4. Заключение

Теперь у вас есть полностью работающая система, которая реагирует на нажатие кнопки и динамически загружает контент подлежащих типов продуктов. Это решение может быть адаптировано для разных типов еды, просто изменяя идентификаторы и названия в HTML и JavaScript.

Ресурсы для дальнейшего изучения:

Успехов в вашем обучении и разработке! Если возникнут дополнительные вопросы, всегда рад помочь!

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

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