WordPress.org

Make WordPress Core

Opened 8 months ago

Last modified 4 months ago

#40108 new enhancement

Pagination Enhancement wp_link_pages()

Reported by: mshumacher Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.8
Component: Themes Keywords: needs-testing
Focuses: template Cc:

Description

Current implementation of the function is not well suited for posts containing 10+ pages, this creates usability issues for desktop and especially mobile users. Most popular themes which rely on this built-in function are affected. Popular hosting providers such as Wordpress.com do not allow 3rd party plugins or any enhancements to work around this issue.

Example:
http://i.imgur.com/yqLOfD0.jpg
Goal:
Provide theme creators posibility to reduce the number of visible page links and enhance CSS theming by wrapping the current page in CSS selectable tag, allowing improved usability on mobile devices and reducing the reliance of wider community on 3rd party plugins or custom code.

Solution:
Accept additional 'mixed' value for the [next_or_number] parameter and create a helper parameter to control the max number of outputted page links. Wrap the current page in a <span> to allow CSS theming.

The looks/functionality as per the screenshot above can be achieved with only ~20 additional lines of code (below)
It accounts for any edge cases and ensures full backwards compatibility, however, additional testing is needed.

Enhanced wp_link_pages Function:

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

        $defaults = array(
                                /**
                                 *Start of New code for making pagination into CSS friendly
                                 */
                'before'           => '<p>' . __( 'Pages:' ),
                'after'            => '</p>',
                'link_before'      => '',
                'link_after'       => '',
                'next_or_number'   => 'number',
                // new param for controling max link number in 'mixed' mode
                'navwidth'         => '3', //number of links displayed before and after current page
                'separator'        => ' ',
                'separator'        => ' ',
                'nextpagelink'     => __( 'Next page' ),
                'previouspagelink' => __( 'Previous page' ),
                'pagelink'         => '%',
                'echo'             => 1
        );

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

        /**
         * Filters the arguments used in retrieving page links for paginated posts.
         *
         * @since 3.0.0
         *
         * @param array $params An array of arguments for page links for paginated posts.
         */
        $r = apply_filters( 'wp_link_pages_args', $params );

        $output = '';
        if ( $multipage ) {
                if ( 'number' == $r['next_or_number'] ) {
                        $output .= $r['before'];
                        for ( $i = 1; $i <= $numpages; $i++ ) {
                                $link = $r['link_before'] . str_replace( '%', $i, $r['pagelink'] ) . $r['link_after'];
                                if ( $i != $page || ! $more && 1 == $page ) {
                                        $link = _wp_link_page( $i ) . $link . '</a>';
                                }
                                /**
                                 * 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 ) ? ' ' : $r['separator'];
                                $output .= $link;
                        }
                        $output .= $r['after'];
                } elseif ( $more ) {
                        $output .= $r['before'];
                        $prev = $page - 1;
                        if ( $prev > 0 ) {
                                $link = _wp_link_page( $prev ) . $r['link_before'] . $r['previouspagelink'] . $r['link_after'] . '</a>';

                                /** This filter is documented in wp-includes/post-template.php */
                                $output .= apply_filters( 'wp_link_pages_link', $link, $prev );
                        }
                                                /** 
                                                 *Start of New Code for 'mixed' navigation mode
                                                 */
                                                 
                                                // Output number of links equal to $navwidth before current page
                                                if ( 'mixed' == $r['next_or_number'] ) {
                                                                For ( $i = $page - $navwidth; $i < $page; $i++) {
                                                                                if ( $i > 0) {
                                                                                $link = _wp_link_page( $i ) . $r['link_before'] . str_replace( '%', $i, $r['pagelink'] ) . $r['link_after'] . '</a>';
                                                                                $link = apply_filters( 'wp_link_pages_link', $link, $i );
                                                                                
                                                                                // Use the custom links separator beginning with the second link.
                                                                                $output .= ( 1 === $i ) ? ' ' : $r['separator'];
                                                                                $output .= $link
                                                                                }
                                                                }
                                                                // Output current page within <span> tags for enhanced styling capability
                                                                if ( $prev ) {
                                                                                $output .= $r['separator'];
                                                                }
                                                                $output .= $r['link_before'] . ('<span>') . str_replace( '%', $i, $r['pagelink'] ) . ('</span>') . $r['link_after'];
                                                                
                                                                // Output number of links equal to $navwidth after current page
                                                                For ($i = $page + 1; $i <= $numpages; $i++) {
                                                                                $link = _wp_link_page( $i ) . $r['link_before'] . str_replace( '%', $i, $r['pagelink'] ) . $r['link_after'] . '</a>';
                                                                                $link = apply_filters( 'wp_link_pages_link', $link, $i );
                                                                                $output .= $r['separator'] . $link;
                                                                }                       
                                                }
                                                
                                                /** 
                                                 *End of New Code for 'mixed' navigation mode
                                                 */
                                                 
                        $next = $page + 1;
                        
                                                if ( $next <= $numpages ) {
                                if ( $prev ) {
                                        $output .= $r['separator'];
                                }
                                $link = _wp_link_page( $next ) . $r['link_before'] . $r['nextpagelink'] . $r['link_after'] . '</a>';

                                /** This filter is documented in wp-includes/post-template.php */
                                $output .= apply_filters( 'wp_link_pages_link', $link, $next );
                        }
                        $output .= $r['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  $args   An array of arguments.
         */
        $html = apply_filters( 'wp_link_pages', $output, $args );

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

Let me know if I can further help to get this be pushed into the next release.

Martin
https://martinshreder.com

Attachments (1)

40108.patch (2.6 KB) - added by dingo_bastard 8 months ago.

Download all attachments as: .zip

Change History (5)

#1 @dingo_bastard
8 months ago

Hi @mshumacher

You can always submit a patch, and see if it'll pass.

I have one ready with the changes you've made, if you're not familiar with how patches work, I can upload it here.

#2 @mshumacher
8 months ago

  • Keywords needs-testing added

@dingo_bastard thanks a lot for the patch!

I would appreciate if anyone can do a basic test and see if the code works as expected.

Basic test scenario:

  1. Create a 10+ page post using either the <!--nextpage--> tag or Alt+Shift+P keyboard shortcut
  2. Open the post and inspect the resulting pagination HTML (copy it somewhere)
  3. Apply the patch;
  4. Reload the page ignoring cache Control+Shift+R
  5. Compare the resulting pagination HTML

(the only difference between the HTML output should be the current page which will become wrapped in a <span> tag)

Advanced test scenario:

  1. Modify the wp_link_pages() function call inside the theme loop (usually called from content.php in the theme components folder) with the following code:
    <?php
    wp_link_pages( array(
                                            'before'           => '<div class="pagination"> <p>' . __( 'Page ' ) . $page . __( ' of  ' ) . $numpages . __( ' pages' ) . '</p> <ul>',
                                            'after'            => '</ul> </div>',
                                            'link_before'      => '<li>',
                                            'link_after'       => '</li>',
                                            'navwidth'         => 3,
                                            'next_or_number'   => 'mixed',
                                            'separator'        => ' ',
                                            'nextpagelink'     => __( 'Next' ) . ' >',
                                            'previouspagelink' => '< ' . __( 'Previous' ),
                                    ) );
    
  2. Navigate to a multi page page post
  3. Check the pagination html section for errors

(output should be similar to the example provided in my original post)

Themes that call wp_link_pages() function:

  • IXION
  • Twenty Sixteen
  • Twenty Fifteen
  • Others1

[1]: Any theme is suitable for testing as long as it makes a call to the wp_link_pages function

Martin
https://martinshreder.com

This ticket was mentioned in Slack in #core by martinshreder. View the logs.


8 months ago

#4 @mshumacher
4 months ago

Would appreciate if there is a volunteer to help testing this patch.

Note: See TracTickets for help on using tickets.