Load More Posts with AJAX for WordPress Multisite
Here is a screenshot how I did it for WordPress default TwentySeventeen theme. You can also download my child theme with the ready code.

Below I will guide you step by step how to implement it on your own WordPress Multisite Network.
Step 1. Creating a Load More Button
If you’re going to use it not for WordPress Multisite but for your custom queries, just replace Network_Query
with WP_Query
– that’s all.
$args = array( 'posts_per_page' => 5 // you can add any query parameters here ); $query = new Network_Query( $args ); if( $query->have_posts() ) : while( $query->have_posts() ... // the posts will be displayed here ... endwhile; // if there is more than 1 page of posts – display the button if ( $query->max_num_pages > 1 ) : echo '<div class="misha_loadmore">More posts</div>'; endif; endif; network_reset_postdata();
Network_Query
accepts all the parameters which are supported by WordPressWP_Query
.Network_Query
andnetwork_reset_postdata()
are the parts of my plugin, so you have to install the plugin first.
Step 2. How to Pass Parameters to the AJAX request correctly?
When I publish my first tutorial about creating a load more button for WordPress archive pages and search results, I passed all the parameters using wp_localize_script()
function. And it is OK when you create load more buttons for the main loop.
But we can not do the same for custom queries.
So I’m going to break it down into two parts.
wp_localize_script()
We still have to use wp_localize_script()
for some of the parameters. Well, only for ajaxurl
😁Anyway passing it for every loop doesn’t make any sense for me.
add_action( 'wp_enqueue_scripts', function(){ // I hope you do not forget that we create all of this with the help of jQuery wp_enqueue_script('jquery'); // This script will contain all the code which will process our load more button wp_register_script( 'multisite_loadmore', get_stylesheet_directory_uri() .'/multisite_loadmore.js', array('jquery') ); // And finally creating object of parameters with wp_localize_script() wp_localize_script( 'multisite_loadmore', 'misha_loadmore_params', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); wp_enqueue_script( 'multisite_loadmore' ); } );
- Many people ask me, where to download
multisite_loadmore.js
file… 😂 Guys, you have to create it yourselves! At this moment it is just an empty file, but we’ll fill it with the code in the next step, - Also keep in mind, that your browser is going to cache
multisite_loadmore.js
, but you can pass the 4th parameter towp_register_script()
function –time()
, so it won’t be cached during your developer work.time()
is the simplest way, another option isfilemtime( $file_path )
function;
Data Attributes
Obviously, ajaxurl
is not enough data to pass to our AJAX script. We have to pass some information related to our query as well. Here they are:
args
– the array ofWP_Query
/Network_Query
arguments,current-page
– depending on this parameter WordPress knows what posts to load next,max-page
– the maximum number of available pages for a specific query,- if you are using different custom queries on the same page, consider passing AJAX
action
here too;
Let’s come back to the first step and add all of these parameters as data attributes for our button.
... endwhile; // if there is more than 1 page of posts – display the button if ( $query->max_num_pages > 1 ) { echo '<div class="misha_loadmore" data-args="' . esc_attr( json_encode( $args ) ) . '" data-max-page="' . $query->max_num_pages . '" data-current-page="1">More posts</div>'; } endif; network_reset_postdata();
You probably noticed that I set a static value current-page
parameter. What do you think why?
Because it is always going to be equal to 1
. I suppose that you’re not going to use pagination functionality for custom queries. But if you are, you can get the current page from the query var get_query_var( 'paged' )
. More info about implementing it is in this tutorial.
Step 3. Creating an AJAX request in multisite_loadmore.js
My purpose was to create a code which will work for you regardless of how many custom queries you are going to use on the same page.
That’s why I passed the current page value in a data attribute too.
jQuery(function($){ /* * Button click event */ $('body').on('click', '#misha_loadmore', function(){ var button = $(this), queryArgs = button.data( 'args' ), maxPage = button.data( 'max-page' ), currentPage = button.data( 'current-page' ); $.ajax({ url : misha_loadmore_params.ajaxurl, // AJAX handler data : { 'action': 'multisiteloadmore', // the parameter for admin-ajax.php 'query': queryArgs, 'page' : currentPage, }, type : 'POST', beforeSend : function ( xhr ) { button.text('Loading...'); // some type of preloader }, success : function( data ){ currentPage++; button.text('More Posts').data( 'current-page', currentPage ).before(data); if( currentPage == maxPage ) { button.remove(); } } }); return false; }); });
Step 4. wp_ajax_ and wp_ajax_nopriv_
The code for your functions.php
:
add_action('wp_ajax_multisiteloadmore', 'misha_multisite_loadmore'); // wp_ajax_{action} add_action('wp_ajax_nopriv_multisiteloadmore', 'misha_multisite_loadmore'); // wp_ajax_nopriv_{action} function misha_multisite_loadmore(){ $args = $_POST['query']; $args['paged'] = $_POST['page'] + 1; // next page of posts $query = new Network_Query( $args ); // or you can use query_posts() for custom queries if( $query->have_posts() ) : // run the loop while( $query->have_posts() ): $query->the_post(); // post template endwhile; endif; die; }
If you remember my previous tutorial, to got the $args inside wp_ajax_
hooks we used json_decode()
function. Why we don’t use it here?
Because $_POST['query']
is already a ready-to-use array. Thankfully to data()
method:
queryArgs = button.data( 'args' ),
But if instead of data()
method you decide to use attr()
, you still have to json_decode()
the value before creating $args
array for Network_Query
.
Comments — 3
I’m so happy and grateful for this tutorial Misha! Thank you so much for helping me out.
The only thing I’m missing so that I can finish implementing it into my project, is a way to exclude certain blogs, for instance, the main blog, from being indexed through the custom Network_Query(). The reason for this is that I’m already using another query for the purpose of displaying the latest two posts from the main blog, and I don’t want to have duplicated posts into two different sections.
I tried adding the ‘blog__not_in’ argument into the multiquery args, similar to WP_Query’s ‘post__not_in’ argument, like so
But of course it can’t work since there’s no such argument within the Network_Query class – found that out by inspecting the code of the plugin 😀
What can be done in this case?
Thanks a lot Misha!
Hey Daniel,
blog__not_in
feature is not available yet. Maybe I will add it later 😉Here is what you can do:
Awesome, that fixed it! Best support ever! ⭐️⭐️⭐️⭐️⭐️
Comments are closed.