An Infinite Scroll plugin
Seamlessly load more content as users scroll, improving engagement and session depth on category archives and single posts.
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/xwp/an-infinite-scroll/archive/refs/heads/main.zipReadme
An Infinite Scroll
Seamlessly load more content as users scroll, improving engagement and session depth on category archives and single posts.
Features
- 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
How It Works
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/postswith 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
Category Archives
- Behavior: Unlimited infinite scroll
- Posts Per Load: Configurable number of posts
- Category Filter: Only shows posts from the current category
Single Posts
- 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
Installation
Using Composer
To install the plugin via Composer, follow these steps:
-
Add the Repository:
-
Open your project's
composer.jsonfile. -
Add the following under the
repositoriessection:"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.
Manual Installation
- Download the plugin files
- Upload to
/wp-content/plugins/an-infinite-scroll/ - Activate through the WordPress admin
Usage
The plugin works automatically once activated and configured. By default, both category archives and single posts have infinite scroll enabled.
Configuring Infinite Scroll
- 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
Default Behavior
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)
Theme Customization
You can override the default card template by creating a custom template in your theme:
- Copy
templates/card-template.phpfrom 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>
Technical Details
Performance Optimizations
- Field Filtering: Only requests
id,link,title,date, andfeatured_image_urlfrom the REST API - Public Caching: Sets
Cache-Control: public, s-maxage={duration}, stale-while-revalidate=30headers where duration is configurable via admin settings (default: 900 seconds / 15 minutes) - Image Optimization: Automatically appends
?w=700parameter 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-heightfor grid to prevent layout shift - Memory Management: Uses
content-visibility: autowithcontain-intrinsic-sizefor performance - Deferred Loading: Scripts load with
deferattribute for non-blocking page load
API Configuration
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.
Grid Layout
- 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.
Browser Compatibility
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.
Admin Configuration
Settings Page
Navigate to Settings → Infinite Scroll to configure all options:
Enable on Category Archives
- Enables unlimited infinite scroll on category archive pages
- Only shows posts from the current category
- Default: Enabled
Enable on Single Posts
- 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:
Posts Per Page (Single)
- 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 Loads (Single Posts)
- 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
"More" Button Page Number
- 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
Cache Duration
- 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)
Technical Settings
The following values are hardcoded in the JavaScript:
- Loader Trigger Distance: 800px before end of content
Known Limitations
- 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
Plugin Structure
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
Requirements
- WordPress: Version 5.0 or higher
- PHP: Version 8.1 or higher
- Browser: IntersectionObserver support (95%+ browsers) or graceful fallback
Hooks & Filters
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)
Support
For issues, feature requests, or contributions:
- Issues: https://github.com/xwp/an-infinite-scroll/issues
- Source: https://github.com/xwp/an-infinite-scroll
License
This plugin is licensed under the GPLv3 or later.