Seamlessly load more content as users scroll, improving engagement and session depth on category archives and single posts.
- Category Archives: Unlimited infinite scroll for browsing posts
- Single Posts: Limited infinite scroll (configurable number of loads) with category-scoped content
- Performance Optimized: Built-in lazy loading, public caching, and memory management
- Theme Customizable: Override card templates in your theme for custom styling
- Admin Controls: Enable/disable infinite scroll independently for categories and posts
- Accessibility: ARIA attributes and semantic HTML structure
- Anonymous Requests: No authentication required, fully cacheable responses
The plugin uses the WordPress REST API and IntersectionObserver API to automatically load more posts as users scroll down the page. When a user reaches the bottom of the content:
- Scroll Detection: IntersectionObserver detects when the user approaches the end of content
- API Request: Makes an anonymous, cacheable request to
/wp-json/wp/v2/posts
with filtered fields - Render Content: Clones a template and populates it with post data (title, image, date, link)
- Repeat: Process continues until load limit is reached or no more posts are available
- Behavior: Unlimited infinite scroll
- Posts Per Load: Configurable number of posts
- Category Filter: Only shows posts from the current category
- Behavior: Limited to a configurable number of automatic loads
- Category Filter: Shows posts from the same category as the current post
- After Limit: Displays a "More {Category}" button linking to a configurable page of the category archive
- Current Post: Automatically hidden from the infinite scroll results
This results in:
- Improved Engagement: Users discover more content without clicking pagination
- Better Session Depth: Increased pages per session and time on site
- Reduced Bounce Rate: Keep users engaged with related content
- Performance: Efficient loading with field filtering and public caching
To install the plugin via Composer, follow these steps:
-
Add the Repository:
-
Open your project's
composer.json
file. -
Add the following under the
repositories
section:"repositories": [ { "type": "vcs", "url": "https://github.com/xwp/an-infinite-scroll" } ]
-
-
Require the Plugin:
-
Run the following command in your terminal:
composer require xwp/an-infinite-scroll
-
-
Activate the Plugin:
- Once installed, activate the plugin through the 'Plugins' menu in WordPress.
- Download the plugin files
- Upload to
/wp-content/plugins/an-infinite-scroll/
- Activate through the WordPress admin
The plugin works automatically once activated and configured. By default, both category archives and single posts have infinite scroll enabled.
- Go to Settings → Infinite Scroll in the WordPress admin
- Configure your preferences:
- Enable on Category Archives: Unlimited scrolling through category posts (enabled by default)
- Enable on Single Posts: Limited scrolling through same-category posts (enabled by default)
- Click Save Changes
Category Archives:
[X posts] → scroll → [X more posts] → scroll → [X more posts] → ...
(Loads 12 posts per scroll by default, configurable)
Single Posts:
[X posts] → scroll → [X more] → scroll → [X more] → ... → [after Y loads]
→ "More {Category Name}" button linking to /page/Z/
(All values are configurable via admin settings)
You can override the default card template by creating a custom template in your theme:
- Copy
templates/card-template.php
from the plugin directory - Create a directory in your theme:
an-infinite-scroll/
- Save your customized version as
an-infinite-scroll/card-template.php
The plugin will automatically use your theme's version if it exists. Your custom template should maintain the same class structure for JavaScript functionality:
<template id="an-card-template">
<article class="an-card">
<a href="#" class="an-card-link">
<img src="" alt="" class="an-card-image" loading="lazy" />
<h2 class="an-card-title"></h2>
<time class="an-card-date" datetime=""></time>
</a>
</article>
</template>
- Field Filtering: Only requests
id
,link
,title
,date
, andfeatured_image_url
from the REST API - Public Caching: Sets
Cache-Control: public, s-maxage={duration}, stale-while-revalidate=30
headers where duration is configurable via admin settings (default: 900 seconds / 15 minutes) - Image Optimization: Automatically appends
?w=700
parameter to featured images, loads full-size images on sites without Photon - Lazy Loading: Uses native
loading="lazy"
attribute on images - CLS Prevention: Pre-allocated
min-height
for grid to prevent layout shift - Memory Management: Uses
content-visibility: auto
withcontain-intrinsic-size
for performance - Deferred Loading: Scripts load with
defer
attribute for non-blocking page load
REST API Endpoint:
GET /wp-json/wp/v2/posts?per_page=12&page=2&_fields=id,link,title,date,featured_image_url&categories=42
Response Headers:
Cache-Control: public, s-maxage={configurable}, stale-while-revalidate=30
The s-maxage
value is configurable via the admin settings (default: 900 seconds).
Detection Method:
The plugin detects infinite scroll requests by checking for the presence of the featured_image_url
field in the _fields
parameter. This triggers the custom caching headers.
Authentication:
Anonymous requests only (credentials: 'omit'
). No authentication required for improved caching.
- Desktop (≥769px): 3 columns
- Mobile (<769px): 1 column
- Gap: configurable via CSS variables between cards (eg.
:root:root {--an-infinite-scroll-grid-gap: 1rem;}
) - Card Aspect Ratio: 16:9 for images, images are added as background covers.
The IntersectionObserver API is supported by modern browsers.
Graceful Degradation:
For browsers without IntersectionObserver support, the plugin automatically displays the "More {Category}" button (on single posts) without infinite scrolling functionality.
Navigate to Settings → Infinite Scroll to configure all options:
- Enables unlimited infinite scroll on category archive pages
- Only shows posts from the current category
- Default: Enabled
- Enables limited infinite scroll on single post pages
- Shows posts from the same category as the current post
- Hides the current post from results
- Displays "More {Category}" button after reaching the maximum number of loads
- Default: Enabled
When this option is enabled, the following settings become available:
- Number of posts to load with each scroll
- Range: 1-50
- Default: 12
- Applies to single posts.
- Category infinite scroll per page respects the site's global per page configuration such that pagination is matched.
- Maximum number of times to automatically load posts on single post pages
- After reaching this limit, the "More" button is displayed
- Range: 1-20
- Default: 5
- Category archive page number to link to when the "More" button appears
- For example, setting this to "3" links to
/category-name/page/3/
- Range: 1-100
- Default: 3
- How long infinite scroll API responses should be cached
- Shorter durations show fresher content, longer durations improve performance
- Options: 1 minute, 5 minutes, 15 minutes, 30 minutes, 1 hour, 4 hours, 12 hours, 24 hours
- Default: 15 minutes (900 seconds)
The following values are hardcoded in the JavaScript:
- Loader Trigger Distance: 800px before end of content
- Paginated Archives: Infinite scroll is disabled on paginated URLs (e.g.,
/category/news/page/2/
) - Multiple Categories: When a post has multiple categories, only the first category is used for filtering
- Error Handling: API request errors fail silently (logged to console)
- Single Category Only: On single posts, only shows related posts from the first assigned category
an-infinite-scroll/
├── an-infinite-scroll.php # Main plugin file
├── includes/
│ ├── class-infinite-scroll.php # Core functionality
│ ├── class-rest-api.php # REST API customizations
│ └── class-settings.php # Admin settings page
├── templates/
│ └── card-template.php # Default card template
├── assets/
│ ├── js/
│ │ └── infinite-scroll.js # Frontend JavaScript
│ └── css/
│ └── infinite-scroll.css # Frontend styles
└── README.md
- WordPress: Version 5.0 or higher
- PHP: Version 8.1 or higher
- Browser: IntersectionObserver support (95%+ browsers) or graceful fallback
Currently, the plugin doesn't provide custom hooks or filters. All customization is done through:
- Theme template overrides
- Admin settings page
- Direct code modification (for advanced users)
For issues, feature requests, or contributions:
- Issues: https://github.com/xwp/an-infinite-scroll/issues
- Source: https://github.com/xwp/an-infinite-scroll
This plugin is licensed under the GPLv3 or later.