14

I have split my post content into mutiple pages using the <! - nextpage -> code. I want to give my paginated links their own title instead of the regular 1,2,3. How can I do this? cause on this doc https://codex.wordpress.org/Styling_Page-Links it only mentions method to adding suffix or prefix. I just want to give each paged number their own custom title

17
+50

Here's a way to support pagination titles of the form:

<!--nextpage(.*?)?--> 

in a simlar way as the core supports <!--more(.*?)?-->.

Here's an example:

<!--nextpage Planets -->
Let's talk about the Planets
<!--nextpage Mercury -->
Exotic Mercury
<!--nextpage Venus-->
Beautiful Venus
<!--nextpage Earth -->
Our Blue Earth
<!--nextpage Mars -->
The Red Planet

with the output similar to:

Pagination titles

This was tested on the Twenty Sixteen theme, where I had to adjust the padding and width a little bit:

.page-links a, .page-links > span {
    width:   auto;
    padding: 0 5px;
}

Demo plugin

Here's a demo plugin that uses the content_pagination, wp_link_pages_link, pre_handle_404 and wp_link_pages_args filters to support this extenstion of the nextpage marker (PHP 5.4+):

<?php
/**
 * Plugin Name: Content Pagination Titles
 * Description: Support for &lt;!--nextpage(.*?)?--&gt; in the post content
 * Version:     1.0.1
 * Plugin URI:  http://wordpress.stackexchange.com/a/227022/26350
 */

namespace WPSE\Question202709;

add_action( 'init', function()
{
    $main = new Main;
    $main->init();
} );

class Main
{
    private $pagination_titles;

    public function init()
    {
        add_filter( 'pre_handle_404',       [ $this, 'pre_handle_404' ],        10, 2       );
        add_filter( 'content_pagination',   [ $this, 'content_pagination' ],    -1, 2       );
        add_filter( 'wp_link_pages_link',   [ $this, 'wp_link_pages_link' ],    10, 2       );
        add_filter( 'wp_link_pages_args',   [ $this, 'wp_link_pages_args' ],    PHP_INT_MAX );
    }

    public function content_pagination( $pages, $post )
    {
        // Empty content pagination titles for each run
        $this->pagination_titles = [];

        // Nothing to do if the post content doesn't contain pagination titles
        if( false === stripos( $post->post_content, '<!--nextpage' ) )
            return $pages;

        // Collect pagination titles
        preg_match_all( '/<!--nextpage(.*?)?-->/i', $post->post_content, $matches );
        if( isset( $matches[1] ) )
            $this->pagination_titles = $matches[1];     

        // Override $pages according to our new extended nextpage support
        $pages = preg_split( '/<!--nextpage(.*?)?-->/i', $post->post_content );

        // nextpage marker at the top
        if( isset( $pages[0] ) && '' == trim( $pages[0] ) )
        {
            // remove the empty page
            array_shift( $pages );
        }       
        // nextpage marker not at the top
        else
        {
            // add the first numeric pagination title 
            array_unshift( $this->pagination_titles, '1' );
        }           
        return $pages;
    }

    public function wp_link_pages_link( $link, $i )
    {
        if( ! empty( $this->pagination_titles ) )
        {
            $from  = '{{TITLE}}';
            $to    = ! empty( $this->pagination_titles[$i-1] ) ? $this->pagination_titles[$i-1] : $i;
            $link  = str_replace( $from, $to, $link );
        }

        return $link;
    }

    public function wp_link_pages_args( $params )
    {       
        if( ! empty( $this->pagination_titles ) )
        {
            $params['next_or_number'] = 'number';
            $params['pagelink'] = str_replace( '%', '{{TITLE}}', $params['pagelink'] );
        }
        return $params;
    }

    /**
     * Based on the nextpage check in WP::handle_404()
     */
    public function pre_handle_404( $bool, \WP_Query $q )
    {
        global $wp;

        if( $q->posts && is_singular() )
        {
            if ( $q->post instanceof \WP_Post ) 
                $p = clone $q->post;

            // check for paged content that exceeds the max number of pages
            $next = '<!--nextpage';
            if (   $p 
                 && false !== stripos( $p->post_content, $next ) 
                 && ! empty( $wp->query_vars['page'] ) 
            ) {
                $page = trim( $wp->query_vars['page'], '/' );
                $success = (int) $page <= ( substr_count( $p->post_content, $next ) + 1 );

                if ( $success )
                {
                    status_header( 200 );
                    $bool = true;
                }
            }
        }
        return $bool;
    }

} // end class

Installation: Create the /wp-content/plugins/content-pagination-titles/content-pagination-titles.php file and activate the plugin. Always a good idea to backup before testing any plugin.

If the top nextpage marker is missing, then the first pagination title is numeric.

Also if a content pagination title is missing, i.e. <!--nextpage-->, then it will be numeric, just as expected.

I first forgot about the nextpage bug in the WP class, that shows up if we modify the number of pages via the content_pagination filter. This was recently reported by @PieterGoosen here in #35562.

We try to overcome that in our demo plugin with a pre_handle_404 filter callback, based on the WP class check here, where we check for <!--nextpage instead of <!--nextpage-->.

Tests

Here are some further tests:

Test #1

<!--nextpage-->
Let's talk about the Planets
<!--nextpage-->
Exotic Mercury
<!--nextpage-->
Beautiful Venus
<!--nextpage-->
Our Blue Earth
<!--nextpage-->
The Red Planet

Output for 1 selected:

test1

as expected.

Test #2

Let's talk about the Planets
<!--nextpage-->
Exotic Mercury
<!--nextpage-->
Beautiful Venus
<!--nextpage-->
Our Blue Earth
<!--nextpage-->
The Red Planet

Output for 5 selected:

test2

as expected.

Test #3

<!--nextpage-->
Let's talk about the Planets
<!--nextpage Mercury-->
Exotic Mercury
<!--nextpage-->
Beautiful Venus
<!--nextpage Earth -->
Our Blue Earth
<!--nextpage Mars -->
The Red Planet

Output for 3 selected:

test3

as expected.

Test #4

Let's talk about the Planets
<!--nextpage Mercury-->
Exotic Mercury
<!--nextpage Venus-->
Beautiful Venus
<!--nextpage Earth -->
Our Blue Earth
<!--nextpage Mars -->
The Red Planet

Output with Earth selected:

test4

as expected.

Alternatives

Another way would be to modify it to support pagination titles to be added with:

<!--pt Earth-->

It might also be handy to support a single comment for all pagination titles (pts):

<!--pts Planets|Mercury|Venus|Earth|Mars -->

or perhaps via custom fields?

| improve this answer | |
  • This looks interesting and quite dynamic. ;-) – Pieter Goosen May 18 '16 at 10:50
  • +1 for closure technique ;) Before that I only knew that we are limited to apply_filter arguments :D – Sumit May 18 '16 at 13:57
  • 1
    It can be handy when writing short code snippets here on WPSE, but we could also just write a class to support this in a proper plugin ;-) @Sumit – birgire May 18 '16 at 14:02
  • @PieterGoosen I first forgot about the #35562 bug, tried to adjust it via the pre_handle_404 filter. – birgire May 18 '16 at 16:48
  • @birgire I thought of that issue, but could not test anything to confirm or disregard the influence of that issue, I''m so caught up with other projects which does not require a pc. It seems like the bug will remain for a long time. I previously did test on new and old versions, and my conclusions is that the code causing the bug can be removed from core until someone finds a proper solution... ;-) – Pieter Goosen May 18 '16 at 17:53
5

You can use filter wp_link_pages_link

First pass our custom string placeholder (This can be anything you like except string containing %, just for now I am using #custom_title#).

wp_link_pages( array( 'pagelink' => '#custom_title#' ) );

Then add our filter in functions.php. In callback function make an array of titles then check for the current page number and replace #custom_title# with value corresponding to current page number.

Example:-

add_filter('wp_link_pages_link', 'wp_link_pages_link_custom_title', 10, 2);
/**
 * Replace placeholder with custom titles
 * @param string $link Page link HTML
 * @param int $i Current page number
 * @return string $link Page link HTML
 */
function wp_link_pages_link_custom_title($link, $i) {

    //Define array of custom titles
    $custom_titles = array(
        __('Custom title A', 'text-domain'),
        __('Custom title B', 'text-domain'),
        __('Custom title C', 'text-domain'),
    );

    //Default title when title is not set in array
    $default_title = __('Page', 'text-domain') . ' ' . $i; 

    $i--; //Decrease the value by 1 because our array start with 0

    if (isset($custom_titles[$i])) { //Check if title exist in array if yes then replace it
        $link = str_replace('#custom_title#', $custom_titles[$i], $link);
    } else { //Replace with default title
        $link = str_replace('#custom_title#', $default_title, $link);
    }

    return $link;
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.