3

I have build a custom post_type with "Work items" in order to enter my personal portfolio items. The "Work items" have taxonomies like "Graphics", "Websites" etc.

I am able to display them all in an archive-work.php template but I want to filter them on page with AJAX. I followed this example : http://www.bobz.co/ajax-filter-posts-tag/

I am running into a problem:

  • The first time that the page is displayed, nothing gets fetched from my custom post type taxonomies. If I click on one of my links, then the data get successfully updated. The issue is only in the first page load. What I guess is that the nonce isn't verified because it isn't sent with POST so it fails.

Can anyone tell me where have I done a mistake ?

functions.php

function ajax_filter_posts_scripts() {
  // Enqueue script
  wp_register_script('afp_script', get_template_directory_uri() . 
      '/ajax-work-items.js', false, null, false);
  wp_enqueue_script('afp_script');

  wp_localize_script( 'afp_script', 'afp_vars', array(
        'afp_nonce' => wp_create_nonce( 'afp_nonce' ), // Create nonce which we later will use to verify AJAX request
        'afp_ajax_url' => admin_url( 'admin-ajax.php' ),
      )
  );
}
add_action('wp_enqueue_scripts', 'ajax_filter_posts_scripts', 100);

$result = array();

// Script for getting posts
function ajax_filter_get_posts( $work_item ) {

  // Verify nonce
  if( !isset( $_POST['afp_nonce'] ) || 
      !wp_verify_nonce( $_POST['afp_nonce'], 'afp_nonce' ))
    die('Permission denied');

  $work_item = $_POST['stuff'];

  // WP Query
  $args = array(
    'stuff' => $work_item,
    'post_type' => 'work',
    'posts_per_page' => -1,
  );

  // If taxonomy is not set, remove key from array and get all posts
  if( !$work_item ) {
    unset( $args['stuff'] );
  }

  $query = new WP_Query( $args );

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

       $res = '<div class="col-lg-4">'.
                  '<a href="'.get_permalink().'">'.
                      '<article class="panel panel-default" id="post-'.get_the_id().'">'.
                          '<div class="panel-body">'.
                              get_the_post_thumbnail().
                              '<div class="panel-cover">'.
                                  '<h3>'.get_the_title().'</h3>'.
                                      get_the_content().
                              '</div>'.
                          '</div>'.      
                      '</article>'.
                  '</a>' .     
              '</div>';


       $result['response'][] = $res;
       $result['status'] = 'success';

   endwhile;
   else:
       $result['response'] = '<h2>No posts found</h2>';
       $result['status']   = '404';
   endif;

   $result = json_encode($result);
   echo $result;

  die();
}

add_action('wp_ajax_filter_posts', 'ajax_filter_get_posts');
add_action('wp_ajax_nopriv_filter_posts', 'ajax_filter_get_posts');

//Get Work Filters
function get_work_filters()
{
    $work_items = get_terms('stuff');
    $filters_html = false;
    $count = count( $work_items );

    if( $count > 0 ):
        foreach( $work_items as $work_item )
        {
            $work_item_id = $work_item->term_id;
            $work_item_name = $work_item->name;

            $filters_html .= '<a href="' . 
                get_term_link( $work_item ) . 
                '" class="btn work-filter" title="' . 
                $work_item->slug . '">' . $work_item->name . '</a> ';
        }
        echo $filters_html;
    endif;
}

ajax-work-items.js

$(document).ready(function(){

    // work filters

    $('.work-filter').click( function(event) {

        // Prevent default action - opening tag page
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }

        // Get tag slug from title attirbute
        var stuff = $(this).attr('title');        

        data = {
            action: 'filter_posts', // function to execute
            afp_nonce: afp_vars.afp_nonce, // wp_nonce
            post_type: "work", // selected tag
            stuff: stuff,
            };

        $.ajax({ 
            type: "post",
            dataType: "json",
            url: afp_vars.afp_ajax_url, 
            data: data, 
            success: function(data, textStatus, XMLHttpRequest) {
                console.log(data);
                // Restore div visibility
                $('.work-results').fadeOut()
                    .queue(function(n) {
                            $(this).html(data.response);
                            n();
                }).fadeIn();
            },
            error: function( XMLHttpRequest, textStatus, errorThrown ) {
                /*console.log( MLHttpRequest );
                console.log( textStatus );
                console.log( errorThrown );*/
                $('.work-results').fadeOut()
                    .queue(function(n) {
                            $(this).html("No items found. ");
                            n();
                }).fadeIn();
            }
        });
    });

});

archive-work.php

<?php get_header(); ?>

<div id="workwrapper">  
    <div class="row-bg-page">
        <div class="container">
            <div class="jumbotron">
                <h1>Our work</h1>
                <p class="lead">Providing professional ...
                </p>
            </div>
        </div>
    </div>
    <div class="row-bg-white">
        <div class="container">

            <div id="work-filter" class="text-center">
                <?php get_work_filters(); ?>
            </div>
            <br />

            <div class="work-results">
                <?php ajax_filter_get_posts(""); ?>
            </div>

        </div>
    </div>

</div>

<?php get_footer(); ?>
5

As you guess that's what happening(at least I think).

You should separate your ajax logic from your "first load" logic. You can make a function ie my_get_posts that will be called inside archive-work.php and then inside ajax_filter_get_posts you can call the my_get_posts() function.

archive-work.php

    <div class="work-results">
                    <?php $res = my_get_posts();
                 echo $res['response'];
?>
                </div>

functions.php

    function ajax_filter_get_posts( $work_item ) {

      // Verify nonce
      if( !isset( $_POST['afp_nonce'] ) || 
          !wp_verify_nonce( $_POST['afp_nonce'], 'afp_nonce' ))
        die('Permission denied');

         $work_item = $_POST['stuff'];
         $result = json_encode(my_get_posts($work_item, true));
         echo $result;

         die();

    }

function my_get_posts($work_item = '', $ajax = false){

    // WP Query
      $args = array(
        'stuff' => $work_item,
        'post_type' => 'work',
        'posts_per_page' => -1,
      );

      // If taxonomy is not set, remove key from array and get all posts
      if( !$work_item ) {
        unset( $args['stuff'] );
      }

      $query = new WP_Query( $args );
      $html = '';
      $items = array();

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

           $res = '<div class="col-lg-4">'.
                      '<a href="'.get_permalink().'">'.
                          '<article class="panel panel-default" id="post-'.get_the_id().'">'.
                              '<div class="panel-body">'.
                                  get_the_post_thumbnail().
                                  '<div class="panel-cover">'.
                                      '<h3>'.get_the_title().'</h3>'.
                                          get_the_content().
                                  '</div>'.
                              '</div>'.      
                          '</article>'.
                      '</a>' .     
                  '</div>';


           $ajax ? $items[] = $res : $html .= $res;


       endwhile;

       $result['response'] = $ajax ? $items : $html;
       $result['status'] = 'success';

       else:
           $result['response'] = '<h2>No posts found</h2>';
           $result['status']   = '404';
       endif;
wp_reset_postdata();
return $result;
}

Also I don't think the following code is needed as wordpress will take care of it.

// If taxonomy is not set, remove key from array and get all posts
          if( !$work_item ) {
            unset( $args['stuff'] );
          }

The code is a draft and could be better but you get the idea. Haven't test it but it should work

EDIT

Don't forget to call wp_reset_postdata(); after every custom WP_Query to restore the global $post variable. More here: http://codex.wordpress.org/Function_Reference/wp_reset_postdata

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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