Long Read Plugin
Plugin to provide long read functionality for WordPress sites
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/dxw/long-read-plugin/archive/refs/heads/main.zipReadme
Long Read Plugin
This plugin provides the basic functionality for adding "long read" items (i.e. multi-page documents divided into "chapters", with in-chapter and between-chapter navigation) to a WordPress site.
A single "long read" is composed of a parent long read post, and it's direct children. The parent post will function as the first chapter of the long read, and its children as the subsequent chapters.
What this plugin does
- Adds the "long read" post type
- Enforces the block editor for that post type (even if the classic editor plugin is activated)
- Provides access to a static method that returns the data required to build the long read navigation. In-chapter navigation is based on the
h2s used within a single long read post, between-chapter navigation is based on parrent/sibling relationships. The plugin enforces the auto-generation of IDs attached to heading blocks to help with this. - Provides a basic long read template, compatible with the dxw gov.uk theme. This is mainly intended to be used as an example of how you might build your own long read template within your own custom theme.
How to use this plugin
The plugin offers two approaches to creating long reads:
- [default] using multiple nested posts
- using page breaks within a single posts to generate the sub pages
To select the page break approach, set the environment variable DXW_PAGE_BREAK_LONG_READ to true.
Recommended plugin to run alongside the default multiple page approach:
- Nested Pages. Long read chapters are ordered according to the WordPress "menu order". This plugin allows you to set that via clicking & dragging in the admin post listing, rather than having to manually set the menu order on each individual long read post.
- Install this plugin (ideally via Whippet), and activate it
- Add a
single-long-read.phptemplate to your site's theme. This will display all long read content. - Within that template, call
LongReadPlugin\Navigation::getItems()to return the data required to build the navigation. See this repo's example template for how to use the data returned.
If using the default approach, the method returns an array of objects, structured as follows:
[
(object) [
'title' => 'The parent long read post'
'url' => 'http://url-of-parent-long-read-post'
],
(object) [
'title' => 'The first direct child of the parent long read post, by menu order'
'url' => 'http://url-of-first-direct-child'
],
(object) [
'title' => 'The second direct child of the parent long read post, by menu order'
'url' => 'http://url-of-second-direct-child'
],
(object) [
'title' => 'The third direct child, and currently viewed post',
'url' => null //The post currently being viewed will always have a null url
'subItems' => [
// An array of the h2s within the currently viewed post
(object) [
'title' => 'First heading 2'
'id' => 'id-of-first-h2',
],
(object) [
'title' => 'Second heading 2'
'id' => 'id-of-second-h2',
],
...
]
],
(object) []
'title' => 'The fourth direct child of the parent long read post, by menu order'
'url' => 'http://url-of-fourth-direct-child'
],
...
]
If using the page break approach - the structure of the array will be:
[
(object) [
'title' => 'The parent long read post'
'url' => 'http://url-of-parent-long-read-post'
],
(object) [
'title' => 'The first header found after the first page break'
'url' => 'http://url-of-parent-long-read-post/2'
],
(object) [
'title' => 'The first header found after the second page break'
'url' => 'http://url-of-parent-long-read-post/3'
],
(object) [
'title' => 'The first header after the third page break, and currently viewed post',
'url' => null //The post currently being viewed will always have a null url
'subItems' => [
// An array of the h2s within the currently viewed post
(object) [
'title' => 'First heading 2'
'id' => 'id-of-first-h2',
],
(object) [
'title' => 'Second heading 2'
'id' => 'id-of-second-h2',
],
...
]
],
(object) []
'title' => 'The first header after the fourth page break'
'url' => 'http://url-of-parent-long-read-post/5'
],
...
]
i.e. the data structure is the same, it just is split either by parent/child posts, or by page breaks. This should mean that the same template logic can be used in either case.
- Style your long read template as required.
PHP version
This plugin builds on PHP 8.2 and deploys on PHP 8.3.
Development
This plugin implements the scripts-to-rule-them-all pattern.
Install the dependencies:
script/update
Run the tests:
script/test
CHANGELOG and versioning
Please update the CHANGELOG as you develop, and publish and tag new releases.
As well as the individual version tags, we also have a major version tag (currently v1) that tracks the latest release for that major version. That has to be manually updated after you've done the release on GitHub as follows:
(e.g. if you'd just published v1.6.0):
git checkout main
git fetch --tags -f
git tag -f v1 v1.6.0
git push origin -f --tagsRead the full README on GitHub →
Releases
| Tag | Published |
|---|---|
| v3.1.0 | Jul 17, 2026 |
| v3.0.1 | Jul 16, 2026 |
| v2.4.1 | May 28, 2026 |
| v2.3.0 | Apr 29, 2026 |
| v2.2.0 | Apr 7, 2026 |
| v2.0.1 | Jul 22, 2025 |
| v2.0.0 | Mar 25, 2025 |
| v1.1.3 | Jul 18, 2024 |
| v1.1.2 | Jul 18, 2024 |
| v1.1.1 | Sep 8, 2022 |
| v1.1.0 | Aug 16, 2022 |
| v1.0.3 | May 27, 2022 |
| v1.0.2 | May 27, 2022 |
| v1.0.0 | May 19, 2022 |
These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.