October 29, 2024

Implementing Infinite Scroll in WordPress with HTMX

HTMX is a powerful JavaScript library that allows you to define client-side behavior directly in HTML using hx-* attributes. In this article, we’ll show how to use HTMX to implement an Infinite Scroll effect in a WordPress theme—without relying on traditional plugins or writing custom JavaScript.

What Is Infinite Scroll?

Infinite Scroll is a common UX pattern that allows users to continuously load more content as they scroll, without refreshing the page. This is especially useful for blogs or article lists where each item is short, and users prefer smooth, uninterrupted browsing.

In the past, developers often relied on plugins or libraries like Infinite Ajax Scroll. With HTMX, we can now implement this functionality in a much simpler and more native way.


Step 1: Update the WordPress Loop Template

First, modify the template that outputs your post list. You’ll wrap the loop in a container and add a Load More button with HTMX attributes:

<div id="posts-container">
    <?php if (have_posts()) : ?>
        <?php while (have_posts()) : the_post(); ?>
            <?php get_template_part('template-parts/content', get_post_format()); ?>
        <?php endwhile; ?>
    <?php endif; ?>
</div>

<?php if ($wp_query->max_num_pages > 1) : ?>
    <button hx-get="<?php echo admin_url('admin-ajax.php'); ?>?action=load_more_posts&page=2"
            hx-target="#posts-container"
            hx-trigger="click, intersect once"
            hx-swap="beforeend"
            hx-indicator="#loading">
        Load More
    </button>
    <div id="loading" class="htmx-indicator">Loading...</div>
<?php endif; ?>

HTMX Attribute Breakdown:

  • hx-get: The AJAX request URL.
  • hx-target: Where to insert the new content (here, inside #posts-container).
  • hx-trigger: Events that trigger the request—click or when the button enters the viewport (intersect once).
  • hx-swap: How to insert the content—beforeend means append to the end.
  • hx-indicator: Displays a loading indicator while the request is in progress.

Step 2: Add the Backend Handler

Next, create the AJAX handler that HTMX will call. It will return additional posts and a new “Load More” button if there are more pages.

Add this to your theme’s functions.php file or a custom plugin:

add_action('wp_ajax_load_more_posts', 'load_more_posts');
add_action('wp_ajax_nopriv_load_more_posts', 'load_more_posts');

function load_more_posts() {
    $page = intval($_GET['page'] ?? 1);

    $args = array(
        'post_type'      => 'post',
        'post_status'    => 'publish',
        'posts_per_page' => get_option('posts_per_page'),
        'paged'          => $page,
    );

    $query = new WP_Query($args);

    if ($query->have_posts()) :
        while ($query->have_posts()) : $query->the_post();
            get_template_part('template-parts/content', get_post_format());
        endwhile;
    endif;

    wp_reset_postdata();

    if ($page < $query->max_num_pages) {
        echo '<button hx-get="' . admin_url('admin-ajax.php') . '?action=load_more_posts&page=' . ($page + 1) . '"
                      hx-target="#posts-container"
                      hx-trigger="click, intersect once"
                      hx-swap="beforeend"
                      hx-indicator="#loading">
                Load More
              </button>';
    }

    wp_die();
}

Final Notes

This implementation leverages HTMX to create a smooth and fully functional infinite scroll system, using only PHP and HTML—no custom JavaScript is required.

If you’re also using Tailwind CSS, you likely won’t need to write any custom styles either. This approach significantly reduces context switching between languages and streamlines the development workflow.