wp_link_pages()WP 1.2.0

Outputs navigation links for paginated posts (the separator used is <!--nextpage-->, one or more times in the content).

To make the function work, you need to separate the post content with HTML comments <!--nextpage-->. After that, the function will split the content into pages. The number of pages will be equal to the number of times the separator <!--nextpage--> was inserted + one page.

nextpage2

Pagination by page content.

This template tag should be used on a separate page. It can be said that it should be used inside the WordPress Loop.

To quickly insert <!--nextpage--> in the visual editor, use the keyboard shortcut: alt + shift + p.

To find out if we are on a pagination page, use the function is_paged().

Returns

String. HTML code for pagination buttons. When the parameter echo=true, it will also output this code on the screen.

Template usage

wp_link_pages( [
	'before'           => '<p>' . __('Pages:'),
	'after'            => '</p>',
	'link_before'      => '',
	'link_after'       => '',
	'next_or_number'   => 'number',
	'nextpagelink'     => __('Next page'),
	'previouspagelink' => __('Previous page'),
	'pagelink'         => '%',
	'echo'             => 1,
] );

Usage

<?php wp_link_pages( $args ); ?>
$args(string/array)
Function parameters passed as an array or string.

Parameter $args arguments

before(string)
Text that will be before the links.
Default: '

Pages: '

after(string)
Text that will be after the links.
Default: '

'
link_before(string)
Text that will be before each link. Since version 2.7.
Default: ''
link_after(string)
Text that will be after each link. Since version 2.7.
Default: ''
next_or_number(string)
A switch that determines whether to show links as numbers of all pages (number) or to show two navigation links: "next", "previous". Can be: number or next.
Default: 'number'
nextpagelink(string)
Text for the "next page" link.
Default: 'Next page'
previouspagelink(string)
Text for the "previous page" link.
Default: 'Previous page'
pagelink(string)
Format of the link text. % will be replaced with the int, so "Page %" will output links with text: "Page 1", "Page 2", etc.
Default: '%'
echo(boolean)
Output to screen (1) or return for processing (0).
Default: 1 (true)

Examples

0

#1 Basic use

Let's display page navigation with default settings, i.e. in the tag

using page links (page 1, page 2) and navigation links "back", "Forward".

<?php wp_link_pages(); ?>
0

#2 Adding a page break button to TyniMCE (Visual Editor)

Such a button is provided by WordPress, but it does not appear. So all we need to do is add the name of this button to the array via hook, WP will do the rest... To do this you need to insert this code in functions.php theme:

## Adding a page break button to TyniMCE 
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 );
		$buttons[] = 'wp_page';
		$mce_buttons = array_merge( $buttons, array_slice($mce_buttons, $pos) );
	}

	return $mce_buttons;
}

The result will be this button:

"Next page" button in the WordPress visual editor
0

#3 Wrap the links in the <div> tag and change the text of each link to "page #":

<?php 
wp_link_pages( [ 
	'before'   => '<div id="page-links">',
	'after'    => '</div>',
	'pagelink' => 'page %'
] );
?>
0

#4 Use previous/next option (instead of page numbers)

<?php
$args = array (
	'before'            => '<div class="page-links-XXX"><span class="page-link-text">' . __( 'More pages: ', 'textdomain' ) . '</span>',
	'after'             => '</div>',
	'link_before'       => '<span class="page-link">',
	'link_after'        => '</span>',
	'next_or_number'    => 'next',
	'separator'         => ' | ',
	'nextpagelink'      => __( 'Next »', 'textdomain' ),
	'previouspagelink'  => __( '« Previous', 'textdomain' ),
);

wp_link_pages( $args );
?>

The above displays on the page as this:

More pages: « Previous | Next »

“Previous” and “Next” links will not print if on the first or last pages, respectively.

0

#5 Display page-links within other HTML tags:

Prints page links as list items within an unordered list, and with custom class names:

<?php
wp_link_pages( [
	'before'      => '<ul class="page-links">',
	'after'       => '</ul>',
	'link_before' => '<li class="page-link">',
	'link_after'  => '</li>',
] );
?>
0

#6 Use this function in content templates

This code snippet can be added directly to your singular.php, single.php, ... files in the position you want your pagination to display.

<?php wp_link_pages( array(
	'before'      => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
	'after'       => '</div>',
	'link_before' => '<span>',
	'link_after'  => '</span>',
	) );
?>

Alternative to wp_link_pages

Navigation like in pagenavi. When you need to create navigation like in this article, here is the code modified for pages:

/**
 * Alternative to wp_link_pages.
 *
 * ver: 2.0
 *
 * @param array $args {
 *
 *     @type string $text_num_page   Text for the number of pages.
 *                                   {current} will be replaced with the current, and {last} with the last.
 *                                   Example: 'Page {current} of {last}' = Page 4 of 60
 *     @type int    $num_pages       How many links to show.
 *     @type int    $step_link       Step for additional links. Example: 1,2,3...10,20,30
 *     @type string $dotright_text   Intermediate text before.
 *     @type string $dotright_text2  Intermediate text after.
 *     @type string $back_text       Text "back". Set '', to not show.
 *     @type string $next_text       Text "next". Set '', to not show.
 *     @type string $first_page_text Text for the first page. Set '', to not show.
 *     @type string $last_page_text  Text for the last page. Set '', to not show.
 * }
 * @return string|false
 */
function kama_link_pages( array $args = [] ): string {
	global $page, $numpages;

	$defaults = [
		'text_num_page'   => '',
		'num_pages'       => 10,
		'step_link'       => 10,
		'dotright_text'   => '…',
		'dotright_text2'  => '…',
		'back_text'       => '« back',
		'next_text'       => 'next »',
		'first_page_text' => '« to the beginning',
		'last_page_text'  => 'to the end »',
	];
	$r = wp_parse_args( $args, $defaults );

	$paged = max( 1, (int) $page );
	$max_page = (int) $numpages;
	if( $max_page < 2 ){
		return '';
	}

	$pages_to_show         = (int) $r['num_pages'];
	$pages_to_show_minus_1 = $pages_to_show - 1;

	$half_page_start = floor( $pages_to_show_minus_1 / 2 );
	$half_page_end   = ceil( $pages_to_show_minus_1 / 2 );

	$start_page = max( 1, $paged - $half_page_start );
	$end_page   = $paged + $half_page_end;

	if( ( $end_page - $start_page ) !== $pages_to_show_minus_1 ){
		$end_page = $start_page + $pages_to_show_minus_1;
	}

	if( $end_page > $max_page ){
		$start_page = max( 1, $max_page - $pages_to_show_minus_1 );
		$end_page   = $max_page;
	}

	$out = '';

	if( $r['text_num_page'] ){
		$out .= strtr( "<span class=\"pages\">{$r['text_num_page']}</span>", [
			'{current}' => $paged,
			'{last}'    => $max_page,
		] );
	}

	if( $r['back_text'] && $paged !== 1 ){
		$out .= _wp_link_page( $paged - 1 ) . $r['back_text'] . '</a>';
	}

	if( $start_page >= 2 && $pages_to_show < $max_page ){
		$out .= _wp_link_page( 1 ) . ( $r['first_page_text'] ?: 1 ) . '</a>';
		if( $r['dotright_text'] && $start_page !== 2 ){
			$out .= '<span class="extend">' . $r['dotright_text'] . '</span>';
		}
	}

	for( $i = $start_page; $i <= $end_page; $i++ ){
		$out .= ( $i === $paged )
			? '<span class="current">' . $i . '</span>'
			: _wp_link_page( $i ) . $i . '</a>';
	}

	// step links
	if( $r['step_link'] && $end_page < $max_page ){
		$dd = 0;
		for( $i = $end_page + 1; $i <= $max_page; $i++ ){
			if( ( $i % $r['step_link'] ) === 0 && $i !== $r['num_pages'] ){
				if( ++$dd === 1 ){
					$out .= '<span class="extend">' . $r['dotright_text2'] . '</span>';
				}
				$out .= _wp_link_page( $i ) . $i . '</a>';
			}
		}
	}

	if( $end_page < $max_page ){
		if( $r['dotright_text2'] && $end_page !== ( $max_page - 1 ) ){
			$out .= '<span class="extend">' . $r['dotright_text2'] . '</span>';
		}
		$out .= _wp_link_page( $max_page ) . ( $r['last_page_text'] ?: $max_page ) . '</a>';
	}

	if( $r['next_text'] && $paged !== $end_page ){
		$out .= _wp_link_page( $paged + 1 ) . $r['next_text'] . '</a>';
	}

	$out = '<div class="wp-pagenavi">' . $out . '</div>';

	return apply_filters( 'kama_link_pages', $out, $r, $paged, $max_page );
}

After inserting the code into the theme's functions.php file, call the function like this:

<?php
echo kama_link_pages( [
	'num_pages' => 5
] );
?>

Notes

  • Global. Int. $page
  • Global. Int. $numpages
  • Global. Int. $multipage
  • Global. Int. $more

Changelog

Since 1.2.0 Introduced.
Since 5.1.0 Added the aria_current argument.

wp_link_pages() code WP 6.9.1

function wp_link_pages( $args = '' ) {
	global $page, $numpages, $multipage, $more;

	$defaults = array(
		'before'           => '<p class="post-nav-links">' . __( 'Pages:' ),
		'after'            => '</p>',
		'link_before'      => '',
		'link_after'       => '',
		'aria_current'     => 'page',
		'next_or_number'   => 'number',
		'separator'        => ' ',
		'nextpagelink'     => __( 'Next page' ),
		'previouspagelink' => __( 'Previous page' ),
		'pagelink'         => '%',
		'echo'             => 1,
	);

	$parsed_args = wp_parse_args( $args, $defaults );

	/**
	 * Filters the arguments used in retrieving page links for paginated posts.
	 *
	 * @since 3.0.0
	 *
	 * @param array $parsed_args An array of page link arguments. See wp_link_pages()
	 *                           for information on accepted arguments.
	 */
	$parsed_args = apply_filters( 'wp_link_pages_args', $parsed_args );

	$output = '';
	if ( $multipage ) {
		if ( 'number' === $parsed_args['next_or_number'] ) {
			$output .= $parsed_args['before'];
			for ( $i = 1; $i <= $numpages; $i++ ) {
				$link = $parsed_args['link_before'] . str_replace( '%', $i, $parsed_args['pagelink'] ) . $parsed_args['link_after'];

				if ( $i !== $page || ! $more && 1 === $page ) {
					$link = _wp_link_page( $i ) . $link . '</a>';
				} elseif ( $i === $page ) {
					$link = '<span class="post-page-numbers current" aria-current="' . esc_attr( $parsed_args['aria_current'] ) . '">' . $link . '</span>';
				}

				/**
				 * Filters the HTML output of individual page number links.
				 *
				 * @since 3.6.0
				 *
				 * @param string $link The page number HTML output.
				 * @param int    $i    Page number for paginated posts' page links.
				 */
				$link = apply_filters( 'wp_link_pages_link', $link, $i );

				// Use the custom links separator beginning with the second link.
				$output .= ( 1 === $i ) ? ' ' : $parsed_args['separator'];
				$output .= $link;
			}
			$output .= $parsed_args['after'];
		} elseif ( $more ) {
			$output .= $parsed_args['before'];
			$prev    = $page - 1;
			if ( $prev > 0 ) {
				$link = _wp_link_page( $prev ) . $parsed_args['link_before'] . $parsed_args['previouspagelink'] . $parsed_args['link_after'] . '</a>';

				/** This filter is documented in wp-includes/post-template.php */
				$output .= apply_filters( 'wp_link_pages_link', $link, $prev );
			}
			$next = $page + 1;
			if ( $next <= $numpages ) {
				if ( $prev ) {
					$output .= $parsed_args['separator'];
				}
				$link = _wp_link_page( $next ) . $parsed_args['link_before'] . $parsed_args['nextpagelink'] . $parsed_args['link_after'] . '</a>';

				/** This filter is documented in wp-includes/post-template.php */
				$output .= apply_filters( 'wp_link_pages_link', $link, $next );
			}
			$output .= $parsed_args['after'];
		}
	}

	/**
	 * Filters the HTML output of page links for paginated posts.
	 *
	 * @since 3.6.0
	 *
	 * @param string       $output HTML output of paginated posts' page links.
	 * @param array|string $args   An array or query string of arguments. See wp_link_pages()
	 *                             for information on accepted arguments.
	 */
	$html = apply_filters( 'wp_link_pages', $output, $args );

	if ( $parsed_args['echo'] ) {
		echo $html;
	}
	return $html;
}