The basic problem for a script solution is: rel_canonical
does not offer any useful filter. So we have to replace that function:
remove_action( 'wp_head', 'rel_canonical' );
add_action( 'wp_head', 't5_canonical_subpages' );
The next problem: $GLOBALS['numpages']
is empty before setup_postdata()
. We could call that function already here, but it might have side-effects.
Here is a solution that adds correct prev/next links too, and it prevents conflicting relations caused by adjacent_posts_rel_link_wp_head
. We have too hook into wp_head
not later than priority 9 to deactivate the latter hook.
remove_action( 'wp_head', 'rel_canonical' );
add_action( 'wp_head', 't5_canonical_subpages', 9 );
/**
* Extend version of the native function rel_canonical()
*
* @wp-hook wp_head
* @return void
*/
function t5_canonical_subpages()
{
if ( ! is_singular() )
return;
if ( ! $id = $GLOBALS['wp_the_query']->get_queried_object_id() )
return;
$post = get_post( $id );
setup_postdata( $post );
# let WordPress do all the work
if ( empty ( $GLOBALS['page'] ) )
return rel_canonical();
$permalink = get_permalink( $id );
$canonical = t5_page_permalink( $permalink, $GLOBALS['page'] );
echo "<link rel="canonical" href="https://wordpress.stackexchange.com/questions/87514/$canonical" />";
# next and prev links
if ( 1 < $GLOBALS['page'] )
{
$prev = t5_page_permalink( $permalink, $GLOBALS['page'] - 1 );
print "<link rel="prev" href="$prev" />";
}
if ( isset ( $GLOBALS['numpages'] ) && $GLOBALS['page'] < $GLOBALS['numpages'] )
{
$next = t5_page_permalink( $permalink, $GLOBALS['page'] + 1 );
print "<link rel="next" href="$next" />";
}
# avoid conflicting pev/next links
remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head' );
}
/**
* Helper to get correct permalinks for sub-pages.
*
* @param string $permalink
* @param int $page
* @return string
*/
function t5_page_permalink( $permalink, $page )
{
if ( 1 == $page )
return $permalink;
# no pretty permalinks
if ( '' === get_option( 'permalink_structure' ) )
return add_query_arg( 'page', $page, $permalink );
return $permalink . user_trailingslashit( $page, 'single_paged' );
}