Pagination for WordPress Single Post (Post Content)

Not everyone knows that in WordPress a single post or page can be divided into several parts, thus organizing the pagination for the post. To do this you need to use the shotcode <!--nextpage--> in the content. This code will divide the text of the post into multiple pages. And URL, for example, the second page will look like this: http://example.com/hello-world/2/.

This feature is useful for those who plan to post long entries with lots of images or text. In this case it's convenient to divide such a long content into parts (subpages).

See also the description of the linked function: wp_link_pages().

Such pagination is not often used, so there is no button in the standard WordPress editor (TinyMCE) for such pagination. Pagination is achieved by pasting the following html code in the post content in the right place:

<!--nextpage-->

Or by pressing key combination Shift + Alt + P in visual editor, the same HTML comment will be inserted into post content: <!--nextpage-->.

After inserting this comment code, the following pagination will appear in the frontend page (it depends on the theme design):

And every pagination page will have a such URL:

  • http://example.com/hello-world/2/
  • http://example.com/hello-world/3/

<!--nextpage--> Doesn't work inside shortcodes:

The tag will NOT work if used within shortcode code. For example:

Published page:

<p>Page split check</p>

<!--nextpage-->

[pag-test].

This also has <!--nextpage--> inside [pag-test] shortcode.

The pagination-split only happens in the first place.

The point here is that the tag <!--nextpage--> is processed at the very beginning of post data processing, before any hooks, and shortcodes are processed on hook. I.e. when the shortcode is embedded into the content, <!--nextpage--> tags in it is not processed because they have been processed earlier, more details see below.

Adding a button to the visual editor

When you need frequent insertion of such a tag splitting the page into several subpages, it is convenient to have a button to insert the needed tag.

To add an appropriate button to the WordPress editor, you need to add a small snippet of code to the functions.php file:

## Adding a page break button to TyniMCE Editor
add_filter( 'mce_buttons', 'mce_page_break' );

function mce_page_break( $mce_buttons ){
	$pos = array_search('wp_more', $mce_buttons, true );
	if( $pos !== false ){
		$buttons     = array_slice( $mce_buttons, 0, $pos + 1 );
		$buttons[]   = 'wp_page';
		$mce_buttons = array_merge( $buttons, array_slice($mce_buttons, $pos + 1) );
	}
	return $mce_buttons;
}

After that, a new button will appear in the editor:

The same result can be achieved by installing the plugin TinyMCE Page Break Button

Theme support

Note that not all WordPress themes provide page or post pagination output.

Your theme's corresponding template file must contain the function wp_link_pages() after page content output:

wp_link_pages( array(
	'before'      => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfifteen' ) . '</span>',
	'after'       => '</div>',
	'link_before' => '<span>',
	'link_after'  => '</span>',
	'pagelink'    => '<span class="screen-reader-text">' . __( 'Page', 'twentyfifteen' ) . ' </span>%',
	'separator'   => '<span class="screen-reader-text">, </span>',
) );

Global variables

When you want to check if a post is paginated, how many pages there are, get the content of a particular page, etc. You can use global variables, which are defined inside WordPress Loop, by function setup_postdata(), which in turn is called either directly or via function the_post().

A list of such global variables inside the loop:

$page(number).
The page of the current post when the post is paginated using the <!--nextpage--> tag.
$pages(array)
The page content of the current post. Each page here is separated by the <!--nextpage--> tag.
$multipage(bool)
Determines whether the current entry is paginated with the <!--nextpage--> tag. Contains true or false.
$numpages(number).
The number of pages if the post is paginated using the <!--nextpage--> tag.

You can use these global variables to do these checks, inside the loop:

# Verification of post pagination

Example 1

$paged = $wp_query->get( 'page' );

if ( $paged < 2 ){
	// This is the first page or the post is not divided into pages
}
else {
	// This is page 2,3,4 ... page of a split post.
}

Example 2

$paged = get_query_var( 'page' ) ?: false;
if ( $paged < 2 ){
	// The post is not divided into pages or it is not the first page.
}
else {
	// This is page 2,3,4 ... page of a split post.

}

Example 3

Let's check if the post is paginated.

the_post();

if( ! empty( $GLOBALS['multipage'] ) ){
	// the post is divided into pages
}

Find out how many pages the entry has

the_post();

if( ! empty( $GLOBALS['numpages'] ) ){

	if( $GLOBALS['numpages'] === 1 ){
		// post is divided into pages
	}
	else {
		// post is divided into pages
		echo "Number of pages {$GLOBALS['numpages']}";
	}
}

How to get all the content of a page divided into subpages

The standard WP functions the_content() and get_the_content() return only the part of the content matching the current pagination page.

If you want to print all the text despite text separation, you can use this hack:

global $post;

$content = apply_filters( 'the_content', $post->post_content );

echo $content;

How it works

When the_post() or setup_postdata( $post ) function is called, the generate_postdata( $post ) method is triggered. This method, among other things, parses the current content of the post ($post->post_content) into pages and puts this data into the global $pages variable.

Then when you call the_content() or get_the_content() the global $pages variable is used to get current post content (content of the post pagination page).

And now all the the_content hooks are applied to the chosen pagination part of the post content only (not to all of the post content).