Loading WordPress Posts Dynamically With AJAX

AJAX has become all the rage in the past couple of years and for good reason. AJAX (Asynchronous JavaScript and XML) is a way to have a “conversation” with the server and display the results without reloading the page.

This technique allows us to refresh “Like” counters, add items to a shopping cart, create dynamic forms and much more – all without reloading the page.

In this post, I’ll show you how to load posts in place with AJAX using the Twenty Fifteen default theme as our base.

We’ll look at why AJAX is used and, starting with a simple example, building AJAX loading functionality into Twenty Fifteen.

Note: If you run into any issues trying to set up AJAX on your site, we can help! Our support team is available 24/7 to help you with any WordPress issue (not just questions about our own plugins!), so whether you’re having problems with AJAX or want some advice on how to do CSS tweaks, get in touch! 

Why Use AJAX?

When WordPress loads the first page of posts on a WordPress site, it requests them from the database and uses a loop to display them using the markup we’ve added. Aside from this, navigation menus, widgets, graphics and other media, javascript files, stylesheets and a bunch of other things are loaded.

Network requests.
Note that 72 requests are made on each page load.

As you can see in the image above (taken from Chrome Developer Tools), a fair number of assets are loaded. There is room for optimization here and some assets like scripts will be cached, but even then it is a lot.

When page two of our posts is loaded it all happens again. WordPress retrieves the posts and displays them using our markup. It also loads all the outlying elements of the page all over again. In many cases (but not all) this is a waste of bandwidth and detrimental to user experience. After all, no one likes waiting around for pages to load.

Getting Started: Creating a Child Theme

Before we modify Twenty Fifteen we should create a child theme. This ensures we can continue updating the theme without losing our changes. You can read all about how to do in in out guide How to Create a WordPress Child Theme.

Hello AJAX!

Let’s begin with a simple example that demonstrates how AJAX Works. We’ll target the links inside the pagination strip at the bottom of the page so that when you click on a page number it will dynamically load that page using AJAX. When a pagination link is clicked we will send a request to the server and alert the result.

We’ll be targeting the number links inside the pagination section.

Enqueuing Our Javascript

Our first port of call is creating the JavaScript file and enqueueing it via our theme’s functions.php file.

I created a js folder and a ajax-pagination.js file in it. Once you have done the same, open your functions file and add the script to the already existing theme_enqueue_assets() function:

If you’re confused about enqueuing read our article on adding scripts and styles to WordPress the right way. In a nutshell, we’ve told WordPress what we’d like to call our script (parameter one), where it is located (parameter two), what the pre-requisites are (parameter three), the version number (parameter four) and that we’d like to load it in the footer (parameter five).

Note that when enqueueing the stylesheet I used get_template_directory_uri(). This function always points to the directory of the parent theme. When enqueueing our script I used get_stylesheet_directory_uri(). This points to the child theme’s directory if used within a child theme.

Since we’re loading the script in the footer you can paste alert( 'Script Is Enqueued' ) into ajax-pagination.js and reload the page to check if it works. If it does, the text should be alerted properly.

Creating an Event

The next task is to create an event which will trigger an AJAX call. In our case the event is the clicking of a specific link. To target the link we’ll need to find out a bit about the element classes and IDs around it.

Pagination Source
The source code for the pagination from Chrome Dev Tools.

In case you’re wondering how I got this to show up, I pressed Shift + Command + C on my Mac (Shift + Control + C on Windows), hovered over the element I wanted to inspect and clicked it.

This tells me that our pagination links have the class page-numbers, the next link also has the class of next and these are all contained in a nav element with the class of nav-links. Not shown here is the previous link, which has the class of prev in addition to the regular page-numbers class.

For the time being, let’s not worry about all that, let’s just target any link within the pagination container. We can create a simple alert like this:

Note that everything is wrapped in an anonymous function. I recommend you do the same. Take a look at this thread on why this is helpful. I’ve created a click event, prevented the default functionality from firing (i.e. loading the page) and I’ve alerted some text.

Creating an AJAX Call

Instead of working with client side data (alerting a preset text) we should grab some dynamic data from the server side. We’ll need to do a tiny amount of prepwork. Here’s why: We need to give the AJAX call a URL to work with. Our Javascript file has no knowledge of our environment, so we can’t use something like get_stylesheet_directory_uri() in there. We can, however, use a localization technique to pass variables to our JavaScript. Let’s do that now in our functions file:

By adding this code inside the my_enqueue_assets() function we will have defined the ajaxpagination object (parameter 2). The object will receive its members according to the array supplied as the third parameter in the wp_localize_script() function. In other words, once we’ve added this code we should be able to use ajaxpagination.ajaxurl to define the URL to the admin-ajax.php which we use to handle AJAX calls.

The reason this works is that the localization function outputs the definition of this object before our JavaScript is loaded. It looks something like this:

Getting back to our JavaScript file, we now have everything we need to build an AJAX call. Here’s how:

As you can see the $.ajax() function is what we’re using here. There are special functions for post and get methods but I prefer using this function because of its flexibility. You can read about all the parameters in the jQuery Documentation.

Using the url parameter we pass the URL of the script we want to send data to. This should be the admin-ajax.php file which can be found in the wp-admin directory. We defined this above via the wp_localize_script() function.

The type is set to post. We could also use get, our query is not too sensitive but I prefer to post data unless the user needs access to the parameters.

The data parameter is an object which contains the data you want to pass. In our case I will be able to access a $_POST['action'] variable, the value of which would be ajax_pagination. You can pass as many as your application requires of course.

AJAX Call Alert
0 is returned if no server-side code is written.

Finally, the success parameter is a function which alerts the result of our AJAX call. We’ll make this a bit fancier below, for now this is sufficient for testing. If you try clicking on a link now it actually works but won’t be very useful since we haven’t defined the server side code. In fact, what you should see alerted is 0.

So why does this happen? When I said “we haven’t defined server side code,” I wasn’t entirely truthful. We haven’t, but WordPress has. There is some content in the admin-ajax.php file we are using. If you take a look at the source code of that file you should see that the script uses die( '0' ) in a couple of cases.

If we don’t supply an action the admin-ajax.php script dies and returns 0. If we do supply an action but we don’t hook into the required WordPress hooks nothing happens and at the very end of the file we die again, returning 0. In conclusion we are already communicating with the server.

Communicating With WordPress

To get a meaningful answer from WordPress we need to define some WordPress actions. This is done using a set pattern. Let’s dive in by continuing our example in the functions file of our theme:

I’ve hooked a function to two hooks. Hooks that take on the wp_ajax_[action_name] format are only executed for logged in users. Hooks that take on the wp_ajax_norpiv_[action_name] format are only executed for non-logged in users. The great benefit of this is that you can very easily separate functionality.

The action names I mentioned above refer to the action defined in our AJAX call in Javascript (action: 'ajax_pagination') – they must match. The function name can be anything you like, I used my_ajax_pagination for clarity.

The function itself can contain anything you’d like. You can log out users, grab their data, publish a post and so on. Whatever you want to return to Javascript you must echo. In the example above I’ve echoed the title of the blog, pulled in dynamically via the get_bloginfo() function.

The final step is to use die(). If we don’t define this, the die function defined in admin-ajax.php at the very end of the file will kick in and you will end up echoing 0 in addition to whatever else you are echoing. If you try out the code above you should now see the title of your website returned.


That concludes our basic example! Before we move on to pulling in posts via AJAX, let’s quickly recap the steps necessary to perform an AJAX action:

  • Enqueue a Javascript file if you don’t already have one
  • Use wp_localize_script() to pass the URL of your admin-ajax.php file
  • Create the AJAX call in Javascript
  • Hook a function using the appropriate hook name
  • Code the function which may return data back to Javascript

Loading Posts With AJAX

Now for the juicy stuff! I started this project by writing the JavaScript code for it. Without further ado, here is the basic version. We’ll expand on it with some tweaked user experience soon.

This is much the same as our basic example. The first thing you’ll notice is that I’ve added a way to detect which page the user wants to request. Each link has a span element in it which is hidden (it is there for screen readers). I make a clone of the element to make sure I don’t modify the original, remove the span and parse the remainder as an integer. This gives us the page number we need.

I will also need to know the query parameters used. On the main page this is pretty simple, it’s just the paged parameter since we’re working with the default query. If we start off on an archive page (like a category archive) we’ll need to know the category name as well.

We’ll pass the query variables using the localization method we learned earlier. For now we’ll use ajaxpagination.query_vars even though this is not yet defined. Finally, on success we remove all article elements from the main container, we remove the pagination element and append the return value of our AJAX call to the main container.

This return value will contain the posts and the new navigation element. Note that I’ve changed the name of the parameter from response to html because it makes a bit more sense. To finish up we use the localization array to pass the original query parameters.

The following function should be placed in our my_enqueue_assets() function replacing the localization we had earlier:

All we need to do now is flesh out the my_ajax_pagination() function. Whatever this function echoes will replace the content on our page. Here’s the final code with an explanation below:

Using our passed parameters we build a custom query. This involves basically taking the query variables we passed and making sure that the page number we passed overwrites the paged parameter. We then use our final $query_vars array to create a new query.

We need to make the $GLOBALS['wp_query'] variable equal to our new posts object. The reason we need to do this is that the the_posts_pagination() function uses this global variable.

Next, notice that I’ve added a function to the editor_max_image_size filter and a few rows down I remove it. This was something unexpected that came up. I actually created a WordPress Trac Ticket. We may see some progress on it! Here’s the issue:

When images are loaded in the post they all look just fine. However, if you complete this tutorial without these filters your images will be narrower, only 660px wide instead of the necessary 825px. The reason for this is that the function that loads the images eventually calls a function named image_constrain_size_for_editor(). This function makes sure that images in the post editor aren’t too wide. To determine weather this size reduction should take place it uses the is_admin() function. Since our code runs through admin-ajax.php which technically is in the admin, WordPress scales our images down, mistakenly thinking we are using them in the editor.

Luckily we can use the editor_max_image_size filter to determine the maximum size for the editor. Since we want to leave everything as is, except for during our AJAX call we add the filter using our custom values (array( 825, 510 )) and then immediately remove it just to make sure it doesn’t cause trouble anywhere else.

The next step is to use our query to list our posts. I copied a lot from the index.php file in the parent theme. if there are no posts we use the template which is meant to handle that, otherwise we loop through the posts and use the post display template. Finally we use the same pagination format we see in the index file.

A Note About AJAX Calls

It’s important to remember that AJAX calls are always considered to originate from the admin. What this means is that draft, scheduled and private posts may be returned with this call. If you don’t want this to happen, you’ll need to control the behaviour with appropriate parameters such as post_status.

Better User Experience

With AJAX solutions like this, it is extremely important to focus on user experience. I’m working in a local environment so everything loads really quickly, but on a production server images and other assets may take more time to load.

Due to this you should at least add a loader or loading text and disable further clicks on the navigation elements. We will take care of these by making the posts and the navigation disappear right after the user clicks and displaying the text “loading new posts.” When the success event fires we remove the loading text and display the posts. Here’s our updated AJAX call:

We now have a separate beforeSend and success function. The former is performed as soon as you click the link, before the AJAX call is sent to the server. The later is performed once we receive data back from the server.

Before the call is sent we remove the articles and the navigation. This makes sure users can’t keep clicking on navigation links while they’re waiting for things to load. Next we scroll to the top of the document. Then, we append a loading notification to make it clear to users what’s going on. I’ve used the same markup as Twenty Fifteen uses on post-not-found pages. In the success function we remove the loader and load our content, all done!

AJAX Pitfalls

AJAX is extremely powerful; apart from loading posts you can perform all sorts of actions via AJAX calls. There are quite a number of dangers and things to look out for while using it, here are a few:

Safety can be a major concern. If you want to delete a post via AJAX you need to make sure the user has the intent and the permission (using nonces), for example. When using regular methods WordPress has built-in protections in some cases but with AJAX you usually have to think of this on your own.

Graceful degradation is another facet of AJAX, although something that is becoming less important. Basically: no JavaScript, no AJAX. If you rely on AJAX heavily, users who have it disabled will not be able to use our application. Javascript has become so ubiquitous that this is almost irrelevant, but may come up in some situations. In this case you need to make sure that clicking on the actual link will work as well.

User experience is very frequently overlooked. AJAX functionality is indeed cool, but a reliably working website is cooler. Users are used to pages loading when they click links. You need to make everything very transparent, users should know what is going on and why. You should use AJAX to enhance your work, not to bring as much bling as you can to the table.


As you can see, implementing AJAX requires a bit of preparation and practice but once it’s second nature you’ll find that it comes easily. It probably took you a while to read through this and it will take even more time to do it for the first time, but I coded the whole example in about 15 minutes.

AJAX is one of those techniques which can be difficult because it encompasses almost all programming languages used in a framework like WordPress. Things are spiced up further by having to adhere to conventions like hooks and localization.

Practice makes perfect. I guarantee you’ll fall in love AJAX if you start to use it.

Have you implemented AJAX on your site? What other uses are there for AJAX in WordPress? Let us know what you think in the comment below.

33 Responses

  • New Recruit

    Thanks for the write up.

    How could this impact SEO?

    Is it assumed or known that when crawled, the original links will be followed and still load as if the ajax was not even built or have the search engines evolved to the point that they now follow the course of the manipulated DOM and js events?

    Clicking the nav links doesn’t change the url so we should also consider how this might also affect things like clicking a “share this” link that may now not have the correct url to get to that specific page level, right?

    • Hi There :)

      Let me address the share this link issue. Generally there is no share this link for paginated archives since the articles on any given page change all the time. The articles themselves do have share this links but these are loaded with the articles so they should point to the correct place.

      In general, AJAX can impact SEO negatively. However, there are ways to circumvent this, take a look here for example:

      Also, I would argue that SEO is less important in many cases (not all) than user experience. I’m sure many people would argue against me so this is just my view. If I’m looking to buy headphones I really don’t care about who comes up first on Google. I will buy from the company who has a website that allows me to browse through headphones nicely.


      • New Recruit

        You’re absolutely right about the share link not typically being used in this type of view and I should have clarified I was only using that as an example as something that may reference the current document url which in this example doesn’t change with the content.

        I agree with you regarding user experience being “top dog” but that will never come into play if the traffic never follows =)

        Based on my initial inquiry and reading the article you referenced, should I be ok seo-wise provided all ajax-ified links can be followed and indexed normally, such as “real” paths that present the same content as the “ajax” counter-part that prevents the default event normally?

      • Hello again :)

        Quick warning: do take everything I say about SEO with a pinch of salt, i am nowhere near an expert on it. In addition I have a built in aversion to it because I feel that too many people focus too much on SEO instead of providing quality content. I have no issues with folks writing great content going for SEO but it should be content first, SEO second, not the other way around :)

        I have the feeling we’re on one page about this so enough said :)

        I believe that yes, you should be ok seo-wise if you make sure everything works based on the article. In addition, you may not need to do anything in some cases. With pagination the link actually exists anyway so Google CAN parse all the pages, even if the user sees them loading with AJAX.

        I usually follow this tactic: If you switch of javascript can you navigate to the page? If so, I don’t worry about SEO losses because of AJAX too much.

  • New Recruit


    Nice tutorial, I used some parts of it on my new website!

    Only one problem with this: If you schedule posts, it will cause duplicate posts with a custom theme (didn’t test it with the default themes). This is because the post status is not defined in the AJAX function.

    A solution for this is to add this $query_vars[‘post_status’] = ‘publish’; after $query_vars[‘paged’] = $_POST[‘page’];

  • New Recruit

    Many thanks for this article. I’m in the process of redesigning my photoblog (http://www.pixelfan.be/) and was looking for a comprehensive tutorial about ajax. Some of my archive pages with pictures take much too long to load and I didn’t know how to implement ajax and pagination… now I know thanks to your article. It’s clear, not too long or technical… and even an amateur like me was able to understand it :-)
    Thanks for this !

  • New Recruit

    Hi Daniel,

    Thank you so much for publishing this article! We ALL appreciate it.

    The Better UX section is great and with a Font Awesome spinner icon, it’s even funner. The only I’m having is, the initial AJAX call is so short that the “Loading New Posts…” is only visible for a moment and then proceeds to loading large images slowly.

    Is there a better way to handle the individual content that’s loaded (e.g. large images) AFTER the success function in the AJAX call?

    Thanks again,

        • Hi Nik,

          Yep, there is! I recommend always printing things out when in doubt to see what info you have. Just print the value of $wp_query, I like to use this format:

          You can also take a look at the docs: https://codex.wordpress.org/Class_Reference/WP_Query

          There are two properties you’ll need: post_count and found_posts. $found_posts contains the number of posts that are found in the database in total, the $post_count property shows the number on the current page.

          So if you have 18 posts in category A and you query for them, on page two found_posts will be 18 and post_count will be 8.

          You can also look at the $max_num_pages which is probably better in your case, this shows the total amount of pages you need to display the results.

          Hope this helps,


          • New Recruit

            Hey Daniel,

            I really appreciate you taking the time to respond. It’s a rarity these days.

            I guess the only issue is passing the $found_posts back to the JS if my function to query the posts is outside the function to enqueue my assets (wp_localize_script). If there was a way to pass $found_posts to wp_localize_script much like ajaxurl is passed to JS, then that would solve everything.

            It’s interesting because the topic of this blog post is a fairly common use case and yet, there are very few articles on the subject, and even less so with the quality of your article.

            Thank you again.

          • Hi Nik,

            Thanks for the kind words :) Ah, I see. There are a few ways around this. If pagination is the only “filter” you have then you could output the pagination itself via jQuery as well.

            Instead of just loading the posts you put the pagination functionality in there are well. That way the correct structure is returned back and you don’t need to worry about it.

            In general, there are two ways you can solve this. One is to just return all the UI components. This is a bit wasteful but isn’t THAT bad.

            The other way is to store the current query variables somewhere in the DOM. Instead of returning HTML with your jQuery you could return an array. The first member would return the HTML, the second a json encoded string of the query variables. You could stash this in a hidden div and pass it to the AJAX call each time.

            There are some more elegant ways of handling this by adding the variables as data parameters to a parent element perhaps.

            Hope this helps!


  • New Recruit

    Codex seems to say that the parent css needs to be queue as well:-

    add_action( ‘wp_enqueue_scripts’, ‘theme_enqueue_styles’ );
    function theme_enqueue_styles() {
    wp_enqueue_style( ‘parent-style’, get_template_directory_uri() . ‘/style.css’ );
    wp_enqueue_style( ‘child-style’,
    get_stylesheet_directory_uri() . ‘/style.css’,

  • New Recruit

    Thanks for this great tutorial!
    I am having difficulties getting the “previous posts” and “next posts” link to work. If i click on “Page 1” or “Page 2” everything works as intended, but if i click on “next posts” or “previous posts” nothing happens. I am pretty knew to ajax and cant figure how to fix this problem. Any help is greatly appreciated.

  • New Recruit

    I’m trying to do something similar, I have removed the post content on comment pages that exceed comment page # 1 by adding the following php statement.

    global $cpage; if( $cpage <= 1 ) get_template_part( 'content', get_post_format() );

    Actually I just added " global $cpage; if( $cpage <= 1 )" to the default statement and it works like a charm, figure removing the post content is a good way to avoid duplicate content and most forums are laid out like that anyway. Now If deemed necessary I would like to load the post content back into the page by adding a link that says "load original post".

    Strangely enough, I found a function in the function.php that is name ajax_show_post and when I call it, it loads the post content, but not-in-the-page.

    I know you probably already have in your tutorial above, but I'm having trouble converting it for my needs. If you can give a brief summary of what I need to do to get it to work for my situation, I'll see if I can sort it out.

    In the mean time I'm going to go through your tutorial again and again. thxs

  • New Recruit

    Uh…where’s the code???

    OK you got it and since this post might get a bit lengthy, let me make it more so, by re-summarizing what I’m trying to accomplish.

    When viewing single posts I removed the post content to display just the remaining comments, if, comments are paged and the comment page is greater than (1). Reasoning: cuts down on redundancy, speeds page load, avoids duplicate content, etc..

    That was the simple part, now I’d like to provide a link to load the missing content back into the page. My reasoning there is, maybe you’re twenty pages into the comments and need to double check some minutia that was implied in the original post to base your response on. In my case since I’m only displaying the comment form on the page that the last comment resides, loading the post content in-line can save a lot needless navigation. Etcetera wise, there’re to many to list, so lets just take the main one, “I WANT THIS FUNCTIONALITY”.

    I can’t believe that upon the millions upon millions of WordPress installs out there… I’m the only one trying to implement this feature, but that seems to be the case?

    Anyways, a few days ago when I made my first comment here, I thought I was 60% of the way towards having a working solution, now due to some inexplicable bug I hadn’t noticed with the preexisting function I confessed to having,,, I might have to revise the 60% downward significantly. Maybe not though, maybe the problem is something simple that I’m over looking, more on the problem when I get that far. Now to borrow a phrase that Daniel used in his tutorial above…

    “Without any further ado” here’s what I do have so far.

    I have created and placed in my theme’s js folder a java-script file aptly named “show_post.js”. I haven’t really started on it yet and what I do have may look something like this…

    if (code == poetry) Dean < Poetic;
    echo " A script of a thousand characters begins with a single keystroke”;
    // eof

    Next, pretending the java script is in working order and if I’ve read the tutorial right, we need to add a snippet to functions.php to enqueue and localize the script. Realistically most posts are not going to garner enough comments to ever generate additional comment pages, so a conditional statement might be prudent to prevent unnecessary loading of the script.

    global $cpage;
    if ( is_singular() && $cpage > 1 ) {
    wp_enqueue_script( ‘show_post’, get_stylesheet_directory_uri() . ‘/js/show_post.js’, array( ‘jquery’ ), ‘1.0’, true );

    wp_localize_script( ‘show_post’, ‘showpost’, array(‘ajaxurl’ => admin_url( ‘admin-ajax.php’ )));

    Here is the problematic function that echos the post content.

    * Show a single post via admin-ajax.php
    * Use a url like this to call this function:
    * /wp-admin/admin-ajax.php?action=show_post&p=514
    function show_post() {

    $id = ( isset( $_GET[‘p’] ) ) ? (int) $_GET[‘p’] : false;
    query_posts( array( ‘p’ => $id ) );
    if ( have_posts() ) :
    // Start the Loop.
    while ( have_posts() ) : the_post();
    get_template_part( ‘content’, get_post_format() );

    else :
    // If no content, include the “No posts found” template.
    get_template_part( ‘content’, ‘none’ );

    add_action( ‘wp_ajax_show_post’, ‘show_post’ );
    add_action( ‘wp_ajax_nopriv_show_post’, ‘show_post’ );

    Can someone tell me what the H-E-(TOOTHPICK X 2) is wrong with that? What I’m experiencing is when the function is called as prescribed, it only works correctly if the user is logged in as admin. All other users end up with the…

    else : get_template_part( ‘content’, ‘none’ ); // makes no sense.

    LASTLY: Remove the post content where appropriate and provide a link to trigger the javascript. Can’t say I’ve got that completely done either, what’s left is not an issue. For testing purposes what I do have calls the function directly. The code below replaces the ” get_template_part( ‘content’, get_post_format() ); ” in the single.php.

    global $cpage;
    if( $cpage <= 1 ) get_template_part( 'content', get_post_format() );
    elseif( $cpage > 1)
    echo '<a ID="',$post->ID,'" class="show-post" rel="nofollow" href="',get_site_url(),'/wp-admin/admin-ajax.php?action=show_post&p=',$post->ID,'">Load Original Post</a>';

    Getting my head wrapped around what I need to do to make any headway on this project has now annoyed me to the point where it’s no longer about enhancing the user’s experience, getting it to work has become a matter of principle. And with that haughty declaration I’d also like to humbly add, I’m not adverse to cheating, any help anyone can provide will be greatly appreciated!

  • New Recruit

    Hi Daniel and thank you for your post. Would their be a way to adapt your solution to open post through AJAX from a list of post ? instead of using the script just to load new pages.
    I am trying to adapt your code and for instance:
    When a post link is clicked:

    $(document).on( ‘click’, ‘.project-link’, function( event ) {

    function do_ajax_request(element,event,$) {
    var url = $(element).attr( ‘href’ );
    history.pushState(null, null, url);

    So you can see that I’m trying to get the page URL and to pass this in the ajax request instead of a page number.. Unfortunately i’m not sure how to adapt the action sent in the ajax since the one you are saying to do seems to be working only for pages number… How could it work for post slugs instead ?

    With something like that (not sure if it does work yet… ) we could retrieve the slug:
    return String(project_slug.substr(project_slug.lastIndexOf(‘/’) + 1));
    and use that slug to pass to the PHP side, instead of a page number… But I’m stuck at that point.. !

    Thank you for your time,
    Hope you can help!

    • Hi Michael,

      Do I understand correctly that you essentially want to load a whole URL via AJAX? If this is the case, there is no real benefit to using AJAX, since the while page needs to be loaded. The other solution – a bit too complex for a comment here – is to just load the content of the post.

      I suggest using templates to display all your posts. So essentially this is how your posts are loaded via PHP regularly:

      <?php while( have_posts() ) : the_post() ?>
      <div id=”post-container”>
      <?php get_template_part( ‘single’, $post->post_type ) ?>
      <?php endwhile() ?>

      Now, whenever you click on a link, pass the ID via AJAX, just like I did. Instead of showing a list of posts, just load a single one on the AJAX side and pass the content to Javascript, then display it within the #post-container div. Something like this:

      function my_post_loader() {
      $post_id = $_POST[‘post_id’]; // this was passed via AJAX
      $args = array(
      ‘include’ => array( $post_id ),
      ‘post_type’ => ‘any’
      $posts = new WP_Query( $args );

      while( $posts->have_posts() ) {
      get_template_part( ‘single’, $post->post_type )
      $content = ob_get_clean();

      echo $content;


      Hope this helps!


      • New Recruit

        Yes Daniel. I might have not been clear (english is not my native language eheh). But I found the answer to my problem somewhere else. (in french sorry, but great article if ever wanting to adapt in english: http://www.seomix.fr/ajax-wordpress/)

        It is basically doing the same idea that you answered in your comment. Using main template, then “ajax-templates” that are shrinked in content. It is also giving a solution to make all of that seo friendly (with push state / pop state as described in one of your comment above) and making the navigation “full ajax” (what I was looking for). There is also a solution in case someone doesn’t have javascript activated, which is great!

        thank you for your time and your comment :)

  • New Recruit

    Thanks for the excellent post. This covers the main thing that many other tutorials don’t – how to make the pagination apply to all of your archives (dynamically populating the query vars), rather than, just say, the homepage, where you can hard code the query.

    However, I have one question – is this actually safe? If you use the code you’ve shown, I can pass my own custom query parameters, thus getting the results of any call to query_posts that I like. For example, I could request draft posts, or private posts, or media items, or anything at all that I probably shouldn’t have access to.

    I guess the handling code could override some variables – such as always setting post_status to publish – but it’s hard to know what should be allowed and what shouldn’t when you’re wanting pagination throughout your whole blog, categories, tags, custom post types, etc.

    What do you recommend to avoid this?

Comments are closed.