WordPress Ajax Request with Axios (Timber templating)

Published:

Previously when making a server-side Ajax request you would send a post request with something like this:

//data contains your action and whatever other variables you are sending over

$.post(ajaxurl, data,function(res){
  var json_obj = JSON.parse(res);  
        
  if(json_obj.message === "nomore") {

    //out of posts, maybe fade out the load more button

  } else { 
                // append the content to whatever element you want
    $('#more-posts-here').append(json_obj.message); 
        
  }

  }).done(function(){

      // anything else you want or need
  });

 

In this example, I’ll touch on the how to load additional posts using Axios.js, with Timber (Twig) Templating, as well as a way to keep it DRY to start, assuming we are re-using certain layouts/partials etc.

We’ll start with the initial .twig markup

 

<button id="data-parameters" data-action="more_all_posts" data-posts_per_page="9" data-pageCount="2" {% if fn('is_category') %}data-cat="{{cat_id}}"{% endif %}>
  {% autoescape %}
    Load More 
  {% endautoescape %}
</button>

 

In the markup you’ll there are several attributes.

  • action (what function are we using)
  • posts_per_page (how many posts do we want to show)
  • pageCount (what page are we getting)
  • cat (if on the category page, get specific category ID to use)

The PHP function for this would be as follows (you could just dump this in your functions.php):

add_action('wp_ajax_more_all_posts', __NAMESPACE__ . '\\ajax_more_all_posts');
add_action('wp_ajax_nopriv_more_all_posts', __NAMESPACE__ . '\\ajax_more_all_posts');
function ajax_more_all_posts()
{ 

    $cat_id = $_REQUEST[ 'cat' ] or $_GET[ 'cat' ];
    $paged = $_REQUEST['pagecount'];
    $cat = $_REQUEST['dataCat'];


    $postCount = $_POST['posts_per_page'];

    

    $args = [
        'cat' => $cat_id,
        'posts_per_page' => $postCount,
        'post_status' => 'publish'
    ];

    if($paged != ""){
        $args['paged'] = $paged; 
    }

    $posts = Timber::get_posts($args);
    $message = [];
    if($posts){
        foreach($posts as $post){
            $response = array(
                'data' => Timber::compile('templates/blocks/content.twig', ['post' => $post])
            );
            $message[] = $response;
        }
    } else {
        $message = "nomore";
    }
    wp_reset_query();
    wp_reset_postdata();

    wp_send_json($message);
    die();
}

In the above code, we are passing numerous values, such as the category ID (if we were on a Category page), how many posts we want to receive, and only if they are published.

Us the following JS to call that action and bring it all together:

 

function fancySquaresLoadMore (argument) {
  
  

  let fancySquaresRestUrl = $('body').data('rest'),
    $loadMoreButton = $('#data-parameters'),
    $archiveLayout = $('[data-js="blog"]'),
    loadMoreButtonID = '#data-parameters',
    $loader = $('#loader');
  

  // start click
  $archiveLayout.on('click',loadMoreButtonID,function(){

  
    let $this = $(this),
      pageCount = $(this).attr('data-pageCount'),
      nextPage = parseInt($(this).attr('data-page')) + 1;

    $loader.fadeIn();
    $loadMoreButton.fadeOut();

    let form_data = new FormData,
      dataValues = $(this).data();
      for (var key in dataValues) {
          // all_values.push([key, data[key]]);
          // key[pagecount] = pageCount;
          if (key === 'pagecount'){

          	dataValues[key] = Number(pageCount);
          	form_data.append(key, dataValues[key]);
          	// console.log(key, data[Number(pageCount)+1]);
          } else {
          	form_data.append(key, dataValues[key]);
          }
          // console.log(key, dataValues[key]);
      }

    axios.post(ajaxurl, form_data)
      .then(function(response){
        // console.log(response);
        // console.log(response.data);

        let postData = response.data;

          if(postData === 'nomore'){
          	$loadMoreButton.fadeOut();
          } else {
          	for(var z = 0; z < postData.length; z++){
          $('[data-js="append-content"]').append(postData[z].data);
          $this.attr('data-pagecount', Number(pageCount)+1);
          // console.log(postData[z]);
        }

          $loadMoreButton.fadeIn();
          }


          $loader.fadeOut();
      })
      .catch(function (response) {
            //handle error
            console.log(response);
        });

            

  });
  // end click
}


module.exports = {
  fancySquaresLoadMore: fancySquaresLoadMore
};

(this is using WebPack, so you technically just pull the function out and call it)

You’ll want to amend the code to your our situation, but to go over it.  I am getting the values from my button (that’s above) and passing them along in my request.  In Axios, you’ll need to pass the data as FormData for this to work.

In my, for-loop we are taking care of that for you (it’s going through the data attributes to get the names and values).

This is just the first round of this particular post.  So I’ll be touching on this in greater detail shortly! In the meantime, good luck!