Roots Discourse

Update View to Display Feed of CPT Posts Based on AJAX Taxonomy Filter

I am pretty new here and to working with AJAX, and I’m trying to find a good setup for a way to filter custom taxonomy terms for a custom post type (called case studies) in order to display a feed of the posts matching those terms.

I have two select lists that show a list of the taxonomy terms for two different taxonomies I have. The idea is that:

When the user selects a term from either of these two lists, we want to use the values from the two select lists to query/get the posts and then update/show them in the feed of posts displayed on the page. Users can only make a single selection for each select list (ex. not multi-select) in my scenario. So that at any given time there is a single term (or ‘all’) from each taxonomy (ex. industry=real-estate, service=social-media-marketing).

This discussion was the most helpful I found here to get me to a starting point, and I tried to follow some of it as a basic outline. Mostly in my setup.php using wp_localize_script to get my script running when it should.

It seems I have the AJAX working in a very basic way:

I added the following form on the page template that is used as the archive for my custom post type, which is called archive-case-study.blade.php.

<form id="taxonomy-filter">
  	  <?php if( $terms = get_terms( array( 'taxonomy' => 'service', 'orderby' => 'name' ) ) ) :
  			echo '<select name="service" class="selectize-enabled ajax-tax-select" id="service-term"><option value="">Service</option>';
        echo '<option value="All">All</option>';
  			foreach ( $terms as $term ) :
  		  echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the tax term as the value of an option
  			endforeach;
  			echo '</select>';
  		endif;

      if( $terms = get_terms( array( 'taxonomy' => 'industry', 'orderby' => 'name' ) ) ) :
  			echo '<select name="industry" class="selectize-enabled ajax-tax-select" id="industry-term"><option value="">Industry</option>';
  			echo '<option value="All">All</option>';
        foreach ( $terms as $term ) :
  			echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the tax term as the value of an option
  			endforeach;
  			echo '</select>';
  		endif;
  	?>
  </form>

In my scripts I have a route for this page:

scripts > routes > archive-case-study.js

export default {
    init() {
    // JavaScript to be fired on the our work page
    // use selectize to make our select lists nicer
    $('.selectize-enabled').selectize();

    // AJAX for tax terms filter for case studies

    $('.ajax-tax-select').change(function() {
       $.ajax({
            type: 'POST',
            url: $(this).val(),
            success: updatePosts,
      });
    });

    console.log(ajax_object);

    var updatePosts = function(resp) {
      console.log('success');
      var industry = $('#industry-term').val();
      var service = $('#service-term').val();
      console.log('industry: ', industry);
      console.log('service: ', service);
    }
},
finalize() {
    // JavaScript to be fired on the our work page, after the init JS
},
};

Right now I’m successfully able to get the updated values logging to the console whenever the select list is changed by the user, which seems like a good start.

My main question is how and where to use this data to update the part of my view responsible for looping/displaying the feed of posts? Do I make this part of the callback or is there way to pass the response into Controller and do the work there to fetch the new posts? Or should we do that in the view itself? If I’m only updating a specific part of the view, what’s the best way to go about this? Can I pass the new data to a partial and load/update that partial from the callback?

Another question I have is on how best to handle the “All” option in my select lists for each taxonomy. I currently have defaulted to “all” and also hard-coded in an “All” option the user can revert back to. I suppose when I get to the point where we need to refresh/re-run the get posts that I can add a condition for this to either specify a term of the given taxonomy within the request (if the value is a number) or to not include that taxonomy if “All” is the value. Maybe there is an example or better way?

Finally, a related question is how to get the URL/route to work so that we get something hopefully prettier-ish like /case-studies?service=social-media-marketing&industry=real-estate (if possible) I copied the url: $(this).val(), in the AJAX object from another example but not sure how to pass in parameters correctly since currently, for me at least, the URL isn’t updating at all for me. I would need to update this to not just be the value of the changed select list, but to pass in values from both select lists. Do I need to create a route for this?

This is currently how I’m getting posts into the view, albeit just one simple query to get all posts for now, and part of why I’m a little stuck as to how to go from this to what I’m trying to achieve:

Inside controllers > ArchiveCaseStudy.php

public function case_studies_loop()
{
$case_study_items = get_posts([
    'post_type' => 'case-study',
    'posts_per_page'=>'10',
]);


return array_map(function ($post) {
    return [
        'heading' => apply_filters('the_title', $post->post_title),
        'excerpt' => get_field('post_excerpt', $post),
        'permalink' => get_permalink($post),
        'thumbnail' => get_field('posts_additional_fields_thumbnail', $post),
    ];
}, $case_study_items);
}

In archive-case-study.blade.php (default display feed of all custom posts, the part that needs to update via AJAX)

<div class="container taxonomy-filter-response">
<div class="row">
  @foreach($case_studies_loop as $case_study_item)
    <a class="col-md-6 d-flex feed-col cpt-list-item" href="{!! $case_study_item['permalink'] !!}">
      <div class="text-left blog-feed-post-entry-wrapper" style="background-image: url({!! $case_study_item['thumbnail'] !!})">
        <div class="post-title-wrap">
          <p class="lead white feed-entry-title post-title">{!! $case_study_item['heading']!!}</p>
        </div>
      </div>
    </a>
  @endforeach
</div>

Hope I explained clearly what I’m going for and that others may find it a starting point if they’re in the same scenario as a beginner here. Any help on any of the above is greatly appreciated!