0

I have not asked any questions here before so I'm sorry if I do it wrong. I am new to custom theme template files. I am new to wordpress and php also. This is a learning exercise for me. I am making a page with foods of different types all under a certain number of calories. I'd like there to be buttons that when pressed will list all the foods that are checked as a certain type. I am using a custom post type meals and and ACF to make the custom fields. Here is the page: https://blog.unicornpoint.net/wp/safe-foods-meal-generator-diet-assistant/

I have a button that has a jquery click event.

<script>
            jQuery(document).ready(function($){
                $('#emergency-icon').click(function(){
                    $.ajax({
                        method: 'GET',
                        url: 'my-url.php'
                    }).done(function(data){
                        $("#meal-results").html(data);
                    });
                });
            });
        </script>

When the button is clicked it returns "You have reached the file." in the target div. This is the code in the php file that is being called in the little ajax block. It works on its own and is displayed on the page in a box to show that it works.

<?php echo "You have reached the file.";  ?>
<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="<?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'); ?> calories</h4>
            </div>
        <?php } ?>
    <?php endwhile; endif; ?>
</div>

Can you please help me get this guy working or point me to easy to understand resources so I can better understand how to do this? Thanks a lot.

1 Answer 1

0

First I'd recommend you to make sure $meal_type = get_field('meal_type'); returns array of strings - to do this you can simply call var_dumb($meal_type) after getting this field value. So for example if you've used a Repeater field for meal_type, you'll see array of arrays and not array of strings.

Also It's kind of strange thing with ACF, but when you are in a custom WP_Query loop, and even you've done it well via $meal->the_post() to setup global $post object it may sometimes ignore the one you've just set, so here's a more bulletproof way of calling 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="<?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); ?> calories</h4>
          </div>
      <?php endif; ?>
   <?php endforeach; ?>
<?php endif; ?>

To make sure it gets data from right place you can pass in a second argument as $post object which you'd like to use to get ACF data for.

Also in case you want it to make a more general purpose code, working for all meal types.

  1. Change markup of meal types listing to

    <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" 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="Emergency" class="meal-icon" id="emergency-icon">
        </noscript>
        <span class="meal-icon-caption"> Emergency</span>
      </a>
    </div>
    
  2. Change JS code to

    <script>
        jQuery(document).ready(function($){
            $('a.load-meal-by-type').click(function(event){
                event.preventDefault(); // to prevent browser from trying to navigate via #link
                var $btn = $(this); // quick way to get current clicked link inside handler function
                var mealType = $btn.attr('href'); // we'll pass meal type as variable to ajax
                mealType = mealType.replace('#', ''); // remove # as we don't need it- we keep it in href originally to make link valid and at the same time - if you'd like to have a step further you can make a thing called deeplinking, being able to have shared link which will load exact content as you would click on a link.
    
                $.ajax({
                    method: 'GET',
                    url: 'my-url.php',
                    data: {
                      mealType: mealType // we pass in our mealType string to php as GET parameter.
                    }
                }).done(function(data){
                    $("#meal-results").html(data);
                });
            });
        });
    </script>
    
    1. Then in PHP we will get this mealType variable

      $requested_meal_type = sanitize_text_field( isset( $_GET['mealType'] ) ? $_GET['mealType'] : '' ); It's important to sanitize whatever user input you are reading from requests, otherwise there can be a security breach.

      So having this variable read we can change condition to if ( $meal_type && in_array($requested_meal_type , $meal_type)) to be able to handle different meal types.

      Also you can check for case if mealType $_GET var is empty and show - no meals found message like if ( empty( $requested_meal_type ) ) { echo 'no meals found' } else { // do wp query and other logic as it should be. }

/// UPD

The thing i consider might happen is this, you are calling my-url.php i've thought it's just example and missed it. In Wordpress when you need to handle something generated via php through ajax, works a bit differently then just creating some file my-url.php in site's document root.

Wordpress way is of calling ajax is:

  1. call /wp-admin/admin-ajax.php instead of your custom php file, from js in ajax,

  2. pass in a action variable in to js, this action name will be an action we define in PHP to handle this type of ajax requests. So ajax part of JS code will turn into.

                $.ajax({
                    method: 'GET',
                    url: '/wp-admin/admin-ajax.php', // we send all WP ajax requests to this file, it will load all WP's files, plugins. It's WP Ajax approach.
                    data: {
                      action: 'load_meals', // you can name it whatever just use the same in PHP binding ajax action.
                      mealType: mealType // we pass in our mealType string to php as GET parameter.
                    }
                }).done(function(data){
                    $("#meal-results").html(data);
                });
    
  3. in your theme's functions.php we'll create php ajax handler which will generate your desired html markup and send it back to js. So part of php code we put into functions.php will look like this.

    // this function will render our html and send it back to js, upon ajax request.
    function my_ajax_load_meals() {
      $requested_meal_type = sanitize_text_field( isset( $_GET['mealType'] ) ? $_GET['mealType'] : '' );
      echo 'You have reached the file.'; ?>
    
    ?>
    <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="<?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 ); ?> calories</h4>
                    </div>
                <?php endif; ?>
            <?php endforeach; ?>
        <?php endif; ?>
    </div>
    <?php
      exit(); // important to exit to close output and let js know it has loaded everything already.
    }
    
     // this is where we bind our function to `load_meals` action name.
     // the one with `_nopriv` prefix in wp action name is for not logged in users, and without it for logged in users.
    add_action('wp_ajax_load_meals', 'my_ajax_load_meals');
    add_action('wp_ajax_nopriv_load_meals', 'my_ajax_load_meals');
    
4
  • I think the only user input is the person clicking the button. The forms for creating the meals are admin only. This is more for me to play with than for others to use. The code and explanations in this reply are very well thought out and beautiful and a little beyond me. I added the changes into existing code but, I am still in the same place. It works on the front page but not when the file is called when the button is clicked. There was a typo that caused an error i will fix it in the reply. I also added variables back into the code to see if that made any difference. It didn't seem to. Mar 13, 2020 at 3:55
  • @DawnSummerall, please check Updated answer.
    – Mikhail
    Mar 13, 2020 at 7:48
  • Thank you for working with this. I put the code in yesterday and got a nonce error and an error in this code piece mealType: mealType, . Mar 14, 2020 at 16:40
  • @DawnSummerall for this piece mealType: mealType, please, check updated code above, just remove coma from this line and add to previous.
    – Mikhail
    Mar 15, 2020 at 7:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.