WordPress: How to 301 Redirect Pagination Pages to the Parent URL

It may be anecdotal, but I’m finding that Google Search Console is becoming more comprehensive in its reporting. So much so that I’ve begun to lean on it more and more… especially to identify pages not found on the site that might negatively impact search rankings.

My site’s theme incorporates an approach where visitors can click load more if they’d like to see additional posts for the home page, category archives, tag archives, or even search results. This user experience (UX) enhancement does away with pagination, where a user (or search crawler) would iterate through pages and blog post results.

However, despite enabling this functionality on my site, Google still believes that I have pagination and that there are errors on the site where those pages are no longer found. If I went to one of those pages listed in Google Search Console, it resulted in a 404. Google believes there’s a problem with my site when there isn’t.

To remedy this, I needed to build a custom redirect in my child theme functions.php that takes any of those /pages/# and redirects them to their parent. One exception that I needed was my custom post type for my acronyms.

Today, I pushed this enhancement to my child theme which accommodates any of the scenarios above:

  • /page/{number} – My home page is my blog archive, so this would result in a 404 with my load more feature. Now any page will redirect to my home page.
  • /tag/{tag-slug}/page/{number} – My tag pages would result in a 404 with my load feature. Now any page will redirect to parent /tag/{tag-slug}/
  • /category/{category-slug}/page/{number} – My category pages would result in a 404 with my load feature. Now any category page will redirect to parent /category/{category-slug}/
  • /{category-slug}/page/{number} – My category pages strip out /category/ and would result in a 404 with my load feature. Now any category page will redirect to parent /{category-slug}/

However, my acronym pages are still indexable:

  • /acronym/page/{number} still exists and can be crawled and indexed.

Child Theme Code

add_action('init', 'custom_redirect_with_exceptions');
function custom_redirect_with_exceptions() {
    // Regular expression to match paths ending with /page/number
    if (preg_match('/^(/[^/]+)/page/d+/', $_SERVER['REQUEST_URI'], $matches)) {
        $base_path = $matches[1]; // Capture the base path
        // List of base paths to exclude from redirection (e.g., custom post types)
        $exclusions = ['/acronyms']; // Replace with your actual base paths

        // Check if the base path is not in the exclusions list
        if (!in_array($base_path, $exclusions)) {
            // Check for tag or general slug
            if (preg_match('/^/tag/', $_SERVER['REQUEST_URI'])) {
                // Specific logic for tag redirection: remove '/tag' prefix
                $redirect_base = str_replace('/tag', '', $base_path);
            } else {
                // General slug logic: use the base path as is
                $redirect_base = $base_path;
            // Construct the new URL to redirect to the base path without pagination
            $new_url = home_url($redirect_base);
            // Redirect to the new URL with a 301 permanent redirect status
            wp_redirect($new_url, 301);
        // No action is taken if the URL is in the exclusions list
    // Check if the URL is just a paginated home URL
    else if (preg_match('/^/page/d+/', $_SERVER['REQUEST_URI'])) {
        // Redirect paginated home URLs to the home page
        wp_redirect(home_url('/'), 301);

The code first checks if the URL matches a paginated format excluding specified paths. If it does, and it’s not an excluded path, it redirects to a non-paginated version of that path. If the URL is a paginated home URL, it redirects to the home page. Explanation:

  • add_action('init', 'custom_redirect_with_exceptions');: Hooks the function custom_redirect_with_exceptions into WordPress’s initialization process.
  • function custom_redirect_with_exceptions() { ... }: Defines the function that will handle the redirection logic.
  • Inside the function:
  • preg_match('/^(/[^/]+)/page/d+/', $_SERVER['REQUEST_URI'], $matches): Uses a regular expression to check if the current URL follows the pattern of a base path followed by /page/ and a number (e.g., /category-name/page/2). If it does, the base path is captured and stored in $matches[1].
  • $base_path = $matches[1];: Stores the captured base path from the URL into the variable $base_path.
  • $exclusions = ['/acronyms'];: Defines an array of base paths that should not be redirected if they match the current URL’s base path.
  • if (!in_array($base_path, $exclusions)) { ... }: Checks if the captured base path is not in the list of exclusions.
    • Inside this conditional:
    • if (preg_match('/^/tag/', $_SERVER['REQUEST_URI'])) { ... }: Determines if the URL starts with /tag/, indicating it’s a tag URL.
      • If true: $redirect_base = str_replace('/tag', '', $base_path);: Removes /tag from the base path, preparing it for redirection to the tag’s main page.
      • Else: $redirect_base = $base_path;: If it’s not a tag URL, uses the base path as is for redirection.
    • $new_url = home_url($redirect_base);: Constructs the new URL to redirect to, removing the pagination but preserving the base path.
    • wp_redirect($new_url, 301);: Redirects the user to the constructed URL with a 301 (Moved Permanently) status code.
    • exit;: Stops further processing to ensure the redirection takes effect immediately.
  • else if (preg_match('/^/page/d+/', $_SERVER['REQUEST_URI'])) { ... }: Checks if the URL is a paginated home URL format, like /page/2.
    • Inside this conditional:
    • wp_redirect(home_url('/'), 301);: Redirects paginated home URLs back to the home page.
    • exit;: Stops further processing, ensuring the redirection is executed.

©2024 DK New Media, LLC, All rights reserved.

Originally Published on Martech Zone: WordPress: How to 301 Redirect Pagination Pages to the Parent URL