How to Load WordPress Posts With AJAX

I am running a YouTube Channel where I post videos related to programming and software. Recently, one of subscriber asked me how to load WordPress post with AJAX. In reply to him, I decided to write a post on his question. So in this article, we study how to load WordPress post with AJAX using a load more button and page scroll.

The difference between the load more and a page scroll is quite simple. When using load more button, you need to click on a button to see the next set of posts. And on page scroll, when you scroll to end of a viewport, the next set of posts should automatically get loaded.

Let’s assume you have a couple of posts and you need to display 2 posts on page load and then by clicking on ‘Load More’ or on ‘Page Scroll’ next 2 posts should display. This process would continue until all of your posts are displayed.

Create a new page called ‘Blog’. To display your posts on the Blog page create custom template page-blog.php in your active theme’s directory.

Now when users visit your blog page they should see 2 posts. So, add the code below in your custom template file.

<div class="entry-content">
    <?php
    $args = array(
        'post_type' => 'post',
        'post_status' => 'publish',
        'posts_per_page' => '2',
        'paged' => 1,
    );
    $blog_posts = new WP_Query( $args );
    ?>

    <?php if ( $blog_posts->have_posts() ) : ?>
        <div class="blog-posts">
            <?php while ( $blog_posts->have_posts() ) : $blog_posts->the_post(); ?>
                <h2><?php the_title(); ?></h2>
                <?php the_excerpt(); ?>
            <?php endwhile; ?>
        </div>
        <div class="loadmore">Load More...</div>
    <?php endif; ?>
</div>

Here, I used the ‘paged’ key and passed the value ‘1’ to it. ‘paged’ is a key used in WordPress when it comes to pagination. ‘paged’ => 1 means the first page.

You would notice the div element with the class ‘loadmore’. On clicking on Load More, we will give an Ajax call and get the next set of posts.

Load WordPress Posts with Ajax on Load More Button

To give an Ajax call, you need to include JS file in the WordPress environment. Create a custom.js file inside the js directory and then add below code in the functions.php file.

function blog_scripts() {
    // Register the script
    wp_register_script( 'custom-script', get_stylesheet_directory_uri(). '/js/custom.js', array('jquery'), false, true );

    // Localize the script with new data
    $script_data_array = array(
        'ajaxurl' => admin_url( 'admin-ajax.php' ),
        'security' => wp_create_nonce( 'load_more_posts' ),
    );
    wp_localize_script( 'custom-script', 'blog', $script_data_array );

    // Enqueued script with localized data.
    wp_enqueue_script( 'custom-script' );
}
add_action( 'wp_enqueue_scripts', 'blog_scripts' );

Next, let’s write a little bit of jQuery and give an Ajax call which in return will give the next posts.

custom.js

var page = 2;
jQuery(function($) {
    $('body').on('click', '.loadmore', function() {
        var data = {
            'action': 'load_posts_by_ajax',
            'page': page,
            'security': blog.security
        };

        $.post(blog.ajaxurl, data, function(response) {
            if($.trim(response) != '') {
                $('.blog-posts').append(response);
                page++;
            } else {
                $('.loadmore').hide();
            }
        });
    });
});

What we are doing here is, I took a javascript variable ‘page’ with initial value 2 as we are going to start with second-page pagination. I am incrementing this ‘page’ variable after receiving the Ajax response. After getting the response, I am appending it to the existing posts listing.

I also used the action parameter as ‘load_posts_by_ajax’ to an Ajax call which needs to map with WordPress actions. Open your functions.php file and add the below code to a file.

add_action('wp_ajax_load_posts_by_ajax', 'load_posts_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_posts_by_ajax_callback');

In above WordPress actions, we call the callback function load_posts_by_ajax_callback which I am going to define in the next step. You can define this function in your functions.php.

function load_posts_by_ajax_callback() {
    check_ajax_referer('load_more_posts', 'security');
    $paged = $_POST['page'];
    $args = array(
        'post_type' => 'post',
        'post_status' => 'publish',
        'posts_per_page' => '2',
        'paged' => $paged,
    );
    $blog_posts = new WP_Query( $args );
    ?>

    <?php if ( $blog_posts->have_posts() ) : ?>
        <?php while ( $blog_posts->have_posts() ) : $blog_posts->the_post(); ?>
            <h2><?php the_title(); ?></h2>
            <?php the_excerpt(); ?>
        <?php endwhile; ?>
        <?php
    endif;

    wp_die();
}

Now when you click on the ‘Load More’ button it will load the next posts through Ajax and return back it in response. The JavaScript code written above would handle the remaining stuff.

Load WordPress Posts with Ajax on Page Scroll

Some users may don’t want a load more button to display the posts with Ajax. Instead, they prefer that the posts should display once the user reaches the end of a viewport.

To achieve this, you need to write logic that captures the event at the end of a viewport, the rest of the code is the same as the ‘Load More’ button. Below is the jQuery code for page scroll.

jQuery(window).scroll(function($) {
    if (jQuery(window).scrollTop() + jQuery(window).height() > jQuery(document).height()) {
        var data = {
            'action': 'load_posts_by_ajax',
            'page': page,
            'security': blog.security
        };

        $.post(blog.ajaxurl, data, function(response) {
            if($.trim(response) != '') {
                $('.blog-posts').append(response);
                page++;
            } else {
                $('.loadmore').hide();
            }
        });
    }
});

That’s it! You can go ahead and try it. I would like to know your thoughts and suggestions in the comments below.

Related Articles

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

103 thoughts on “How to Load WordPress Posts With AJAX

  1. Sir the JS code isn’t working.
    Console error
    custom.js?ver=1:10 Uncaught ReferenceError: blog is not defined

    Sir please help what did I wrong?

  2. Thank you for the tutorial, it helped me a lot. On my website I’d like the page load ALL the posts when the Load more-button is clicked. Do you have any idea how could I do this? I can get it to load next page or the one after that, but can’t get them to load at the same time… I really appreciate your help Sajid.

    1. It seems you want to load all posts on click of Load More button. In that case, set -1 value for the ‘posts_per_page’ key in the Ajax callback method.
      -1 means returns all posts.

  3. Thanks a lot for this, it works great. I’m having an issue though where the first post is displayed last. I’m using ‘orderby’ => ‘date’ with a custom post type but apart from that the code is the same. Any ideas?

  4. Hi,

    First of all thanks for the loading more code 🙂

    Can you please guide me how to add loading icon when you click on Load more button?

    Thanks

  5. Hi,
    Thanks. who is looking will find 🙂
    It works and lists all products as it should.
    I would like to use it to list taxonomy but I can’t get terms ID there.
    When I do it manually, it works.
    $category = ’63’;
    $ args = array (
    ‘post_type’ => ‘products’,
    ‘tax_query’ => array (
    array (
    ‘taxonomy’ => ‘category’,
    ‘terms’ => $category
    )
    ),
    ‘post_status’ => ‘publish’,
    ‘posts_per_page’ => ‘4’,
    ‘paged’ => $ paged,
    );

    Can you please advise me how to get that variable there?

    Thanks

  6. Got it. For everyone needing button to disappear automatically here is the code:

    var publication = 2;
    jQuery(function($) {
    function appendPost(data, callback) {
    $.post(blog.ajaxurl, data, function(response) {
    if ($.trim(response) == ”) {
    $(‘.load_more_publications’).hide();
    }
    $(‘.publications-wrapper’).append(response);
    publication++;
    data.page = publication;
    $.post(blog.ajaxurl, data, function(response) {
    if ($.trim(response) == ”) {
    $(‘.load_more_publications’).hide();
    }
    });
    });
    }

    $(‘body’).on(‘click’, ‘.load_more_publications’, function() {
    var data = {
    action: ‘load_posts_by_ajax’,
    page: publication,
    security: blog.security,
    };
    appendPost(data);
    });
    });

    1. Hi, just wanted to thank you for your comment. The code is working fine, the load more button dissapears when there is no more posts to be loaded.

  7. Hey guys, did anybody figured out how to automatically hide button when there is no more posts without clicking the button?

  8. Hi there,
    Thank you so much for sharing with us.

    But I want to use it for two different post types. How can I get this?

    #Help.

  9. Hi, I have a problem. When I click the “Load more …” button, the posts are shown in duplicate. How can I solve that? I am new to ajax … thank you very much

  10. This part of the code:

    if(response != ”) {
    $(‘.blog-posts’).append(response);
    page++;

    }

    Does not return an empty string ( ‘ ‘ ) even if there are no more posts, and this is why the button does not disappear.

    Use if($.trim(response) != ”) to remove whitespace and allow checking for non-response

  11. Is there a way to have a message say “loading” or something when you click the button, there is a slight delay as it gathers the content and so it would be nice to have a “loading” message so users know its working and not broken

  12. Hi, thanks for the post!
    Works great but I would like to load more posts on scroll when reaching the end of an container element.
    What’s the best practice here?

  13. Perfect tutorial! One question, how do I hide the Load more button when it’s reached the max number of posts? Thanks

      1. Thanks for replying. I changed my script to the following.

        It shows the button and loads more on click as it should do.
        But it still shows when there is no more to load, It only hides when I click the button again.
        Your help is much appreciated.

        $.post(ajaxurl, data, function(response) {
        if(response != ”) {
        $(‘.my-posts’).append(response);
        page++;
        } else {
        $(‘.load-more’).hide();
        }
        });

      2. Here is my full script:

        $(‘body’).on(‘click’, ‘.loadmore’, function() {
        var data = {
        ‘action’: ‘load_posts_by_ajax’,
        ‘page’: page,
        ‘security’: ”
        };

        $.post(ajaxurl, data, function(response) {
        if(response != ”) {
        $(‘.my-posts’).append(response);
        page++;
        } else {
        $(‘.loadmore’).hide();
        }
        });
        });

  14. I have got the basic version working, but how do I adapt it for my needs… ?

    – I have a custom query – how do I accommodate this? Actually, multiple similar query blocks on the same taxonomy template, each output with foreach, and each of which has slightly different arguments. One problem with the code as-is is that it does not discriminate. How can I made the call specific to the section in which it was clicked and to use the same query?
    – Also, when I click “Load more”, *all* sections load new posts. But it should only be the section which was clicked.
    – I could adapt the .my-posts class in the HTML to something like .my-posts-somethingunique – but how can I make the Javascript service anything more than .my-posts, and how can I ensure that load comes from the correct “Load more” link click? Something to do with a data= parameter in the tag… ?

    More about my case at https://wordpress.stackexchange.com/questions/328685/how-to-load-more-posts-via-ajax from before I got this basic version working.

    Thanks.

  15. Hi Sir,
    Implemented the steps you mentioned, but i have showing :-
    wp-admin/admin-ajax.php 500 (Internal Server Error)
    I had installed Ajax Load More plugin.. but now i removed it , also i increased the memmory limit in wp-config.php

  16. Hi, I find a solution for loadmore button. It will be hidden if no more post.
    var data = {
    ‘action’: ‘load_posts_by_ajax’,
    ‘page’: page,
    ‘security’: ‘@php echo wp_create_nonce(“load_more_posts”); @endphp’,
    ‘max_page’: ‘@php echo $posts->max_num_pages + 1; @endphp’
    };
    if(response != ”) {
    $(‘.post-boxs’).append(response);
    page++;
    }

    if (page == data[‘max_page’]) {
    $(‘.load-more’).hide();
    }

  17. Thank you for the code but I have problems with metabox data in my-posts div wrapper.

    For some reason the_content() or the_title() works well but for example values like $dayevent = get_post_meta( $post->ID, ‘dayevent’, true ); no.
    Any help appreciated.

  18. Hi !
    Great article !
    But i had a problem with posts_per_page
    If i set defaulft show post are 9 post, then click load more 3 post but it not work.
    What happen with that? and how can i fix them?
    Need your help ! Thanks. 🙁

  19. Hi! in the loop of repeated entries, tell me how to remove? $my_posts = new WP_Query( $args );
    if ( $my_posts->have_posts() ) :
    ?>
    have_posts() ) : $my_posts->the_post() ?>

  20. 1. How can I use load more button for custom posts type taxonomy term like category. I use filtering option of custom post category
    2. How can I remove load more button when all of my posts are loaded. Please send coding script of above query.

    1. When I click load more button always show 0.every click a 0 is added. How can i remove or hide this 0 value. Please give me a suggestion.

  21. Hi Its a nice article, which helps me to achieve something I wanted very long time. Even non coder can learn this and try this out.

    Here is my request:
    Can you add Lazy load image before loading posts and hide after loaded. Also is the any chance we can add the fadeIn effect to the posts when they added?

  22. How can we add select dropdown to select categories and load posts from that category ?
    Im trying to add this functionality here in this code

  23. With this idea the button is not hide automatically. Here user must be click on Button, then after if There is no posts then button will be hide.
    if(response != ”) {
    $(‘.my-posts’).append(response);
    page++;
    } else {
    $(‘.load-more’).hide();
    }

    But i want that without clicking the button at last, the button should automatically hide, if there is no posts.
    How to do that? any idea?

      1. $.post(ajaxurl, data, function(response) {
        console.log(response);
        if(response == ”){
        $(‘.loadmore’).hide();
        }
        $(‘.jmasonry’).append(response);
        page++;
        });

  24. Hello, I think it is working but with some caveats…. The initial button doesn’t get hided after click and the button doesn’t move, meaning it should be at the end of the loaded posts… oddly if there are no more posts and the actual already used button gets clicked it populates duplicated entries Mmm. Any fix?

    1. We have written $(‘.my-posts’).append(response); And our Load More button is outside of div with class my-posts. So Load More will always stick at the end. And after each response, we are incrementing page variable so there is no chance of duplicate records. Maybe in your case you are missing the position of Load More.

      1. Oh you are right I fixed that it is working ok 😉
        What do you recomend for hiding the load more button when there are no more posts to display and after clicking the load more button?
        For the second maybe I should mix the following code:

        $(function(){
        $(“.loadmore”).on(‘click’,function() {
        $(this).css(‘visibility’,’hidden’);
        });
        });

        with the code in the guide:

        var ajaxurl = “”;
        var page = 2;
        jQuery(function($) {
        $(‘body’).on(‘click’, ‘.loadmore’, function() {
        var data = {
        ‘action’: ‘load_posts_by_ajax’,
        ‘page’: page,
        ‘security’: ”
        };

        $.post(ajaxurl, data, function(response) {
        $(‘.my-posts’).append(response);
        page++;
        });
        });
        });

        1. You should manage it from ajax callback functions. Check where WP_Query returns records. If not send flag(like noresult) in response else send next posts(which we are currently returning).
          And then in JavaScript, you can hide the Load more on the basis of a flag.

          1. Ok really wish I knew that much enough to follow that instructions, for which I’m afraid I don’t. If you guide me (like pointing me to the reference) I will read it/learn and try it out. Regards.

          2. When no posts are available we get empty ajax response which you can use to hide load more button. In the JavaScript code of ajax response change the code like
            if(response != ”) {
            $(‘.my-posts’).append(response);
            page++;
            } else {
            $(‘.load-more’).hide();
            }

          3. Ok edited the code as follows:

            var ajaxurl = “”;
            var page = 2;
            jQuery(function($) {
            $(‘body’).on(‘click’, ‘.loadmore’, function() {
            var data = {
            ‘action’: ‘load_posts_by_ajax’,
            ‘page’: page,
            ‘security’: ”

            };

            $.post(ajaxurl, data, function(response) {
            if(response != ”) {
            $(‘.my-posts’).append(response);
            page++;
            } else {
            $(‘.load-more’).hide();
            }
            });
            });
            });

            But the button is not loading more posts.. will keep trying changes..

  25. Hi,
    I’m using this script in my blog section button click is working but i am going to implement window scroll is not firing please advise to me.

  26. Hi Artisan,

    Now I’m wondering something else. I would like for the button to dissapear when all posts are loaded, it that possible?

    Thank you!

    1. Yes, it is possible. Wrap your each post in a div with the common class.
      By this way, calling ‘length’ method we come to know the count of post divs.
      On the top of a front page PHP file, fetch the count of all posts and assign it to a variable.
      Assign this PHP variable to JavaScript variable. Now on each Ajax response check if a count of post divs reaches a value of a variable. If both values are same then hide load more button.
      Let me know if you understand this or need more help.

      1. Hi,
        I’m also interested n this, but i’m lost on details, can you help me with hiding load more button at the end of posts ?

        Thanks

        1. I’ve solved this by adding “else” to the loop to creating a new “div” that will show a message if no more posts. After Edit this:

          No More Posts!
          0 ) $(‘.loadmore’).hide();

  27. Hi again!

    I figured it out!
    I had the same .class on my div in my first query as in my second query!

    1. “I had the same .class on my div in my first query as in my second query!” Hello Victor! Can you share the steps on how you did it?

    2. Yes got it working as well… in case someone wonders how:
      Rename all “my-posts” for the second instance of ajax for something like “my-posts2”, same with “security2”, “loadmore2”,
      wp_ajax_load_posts_by_ajax2′, ‘load_posts_by_ajax_callback2’);
      add_action(‘wp_ajax_nopriv_load_posts_by_ajax2’, ‘load_posts_by_ajax_callback2, ‘load_posts_by_ajax2, “load_more_posts2”, “.my-posts2” Hope it helps…

      1. Forgot to add you may need to create a second instance of the code for each ajax instance. For example for three ajax buttons you should have:
        For the first ajax button:

        var ajaxurl = “”;
        var page = 2;
        jQuery(function($) {
        $(‘body’).on(‘click’, ‘.loadmore’, function() {
        var data = {
        ‘action’: ‘load_posts_by_ajax’,
        ‘page’: page,
        ‘security’: ”

        };

        $.post(ajaxurl, data, function(response) {
        $(‘.my-posts’).append(response);
        page++;
        });
        });
        });

        For the second ajax button:

        var ajaxurl = “”;
        var page = 2;
        jQuery(function($) {
        $(‘body’).on(‘click’, ‘.loadmore2’, function() {
        var data = {
        ‘action’: ‘load_posts_by_ajax2’,
        ‘page’: page,
        ‘security2’: ”

        };

        $.post(ajaxurl, data, function(response) {
        $(‘.my-posts2’).append(response);
        page++;
        });
        });
        });

        For the third ajax button:

        var ajaxurl = “”;
        var page = 2;
        jQuery(function($) {
        $(‘body’).on(‘click’, ‘.loadmore3’, function() {
        var data = {
        ‘action’: ‘load_posts_by_ajax3’,
        ‘page’: page,
        ‘security3’: ”

        };

        $.post(ajaxurl, data, function(response) {
        $(‘.my-posts3’).append(response);
        page++;
        });
        });
        });

        Maybe this could be done in a more efficient way.. but thats at least should work

        1. I realized there’s a problem with using in the same page two ajax buttons… they share the page, so that if for example I use the first button once and ten use the other button, the later will load not the second page but the third… Haven’t figured out yet how to solve it… must be something like assigning a different name for each page?

          1. So far the second button looks like this:

            1. in header:
            var page1 = 2;
            ‘page1’: page1,

            2. in functions.php
            $paged1 = $_POST[‘page1’];
            ‘paged1’ => $paged1,

            3. in the template
            $paged1 = ( get_query_var( ‘paged1’ ) );
            ‘paged1’ => 1,

          2. Use 3 different pages variables for each ajax call so it does not get repeated for each other.
            var page1 = 2;var page2 = 2;var page3 = 2;

          3. @Sajid Can you elaborate more because I don’t think you mean the above… like dummy proof it may serve others as well

          4. I got it, the values that have to be modified are (I added an extra “7”):
            in footer or header
            var page7
            ‘page7’: page7,
            page7++;
            in functions
            $paged7 = $_POST[‘page7’];
            ‘paged’ => $paged7,

  28. Hi Artisan,

    I’ve implemented your code and it works great when the query is on a page with no other queries. However, I would like to implement it on my front page. On that page I have two other queries. When i press the Load More-button, the ajax-function loads the correct posts but it loads the posts twice.

    I’ve tried to use the wp_post_reset but it doesn’t work.
    Have you noticed this before?

  29. John, It is possible to apply load more post of different categories multiple times. In you case need to work on some logic to achieve the final goal.

  30. Great bro !

    What if: Let`s assume, I do have posts slider on my page, then I want to display the content of a post that I clicked, but I want it to be shown below the post slider.

Leave a Reply

Your email address will not be published. Required fields are marked *