wordpress.htaccesshttp-redirecturl-rewritingpermalinks

Wordpress permalinks and redirection


I work with WordPress daily and haven't seen this issue before. Perhaps the SO community has some insight.

I have a standard WordPress install v4.3, which is the current version. I have no rewrite modules active. No base category or tags set. Permalinks are set to "Post name" for clean URLs, which works well for the whole site except everything under /blog

I have tried to rewrite /blog/* to index.php?page_id=xxx and wrote a custom parser to handle the URI segments, which seems to work locally. On the server, however, all /blog/xxx just redirects to /blog/ even though at no point do I specifically tell it to do this.

I have tried setting this in .htaccess:

RewriteRule blog/(category|tag|page|search)/(.+)/?$ index.php?page_id=123

which didn't work even though the regex checks out and every other rewrite rule I have for custom post types works.

When that failed I tried writing a rewrite rule hook:

// pathetic hack to fix wp permalink horror for blogs
add_filter( 'rewrite_rules_array','my_insert_rewrite_rules' );
add_action( 'wp_loaded','my_flush_rules' );

// flush_rules() if our rules are not yet included
function my_flush_rules(){
    $rules = get_option( 'rewrite_rules' );

    if(isset($_GET['rules']))
    {
        echo '<pre>';
        print_r($rules);
        echo '</pre>';
    }

    if ( ! isset( $rules['blog/(category|tag|page|search)/(.+)/?$'] ) ) {
        global $wp_rewrite;
        $wp_rewrite->flush_rules();
    }
}

// Adding a new rule
function my_insert_rewrite_rules( $rules )
{
    $newrules = array();
    $newrules['blog/(category|tag|page|search)/(.+)/?$'] = 'index.php?page_id=123';
    return $newrules + $rules;
}

If you run "?rules" in the browser displays the current rewrite array and it indeed is adding it to the array. Yet for some reason the action WP is taking is to redirect to index.php?page_id=123 instead of loading it and letting me parse out the URI myself. Like the word "blog" is somehow reserved.

Has anyone else seen anything like this? The only relevant plugin I can imagine might be disrupting things would be CCTM but the blogs are not custom content types. /blog is just a normal page like any other that fetches posts according to the URI segments.

I suggested trying to use the standard WP architecture for these pages but the client insists everything is under /blog/category/category_name/page/x for example. They don't want to budge on that and I understand because locally it works as expected. Yeah there are minor differences in the server settings but the common core elements are the same - htaccess is enabled, wp is the root and not installed in a directory, etc.

I've tried disabling all plugins, switching to 2015 theme, flushing permalinks, clearing cache, etc. Very strange.

Any input or similar stories may lead to the solution so I welcome what you have.


Solution

  • I'm answering my own question because it looks like a lot of others have similar issues and accepted answers were scarce. So for my particular case, this was the answer:

    First, following huksley's answer I wrote the alternate index_pass.php file in web root. That file contains only this:

    <?php $_SERVER["REQUEST_URI"] = $_SERVER["REDIRECT_URI"]; include("index.php");
    

    Next I add the htaccess rule before wordpress defaults. The E=URI: part is the key here:

    RewriteEngine On
    RewriteBase /
    
    RewriteRule ^blog/(category|tag|page|search)/(.+)/?$ index_pass.php?page_id=123 [NC,L,E=URI:somedomain.com/blog/$1/$2/$3/$4]
    
    #wordpress defaults below
    

    Then in functions.php in the theme I add this to prevent the new hacky trash solution from throwing a 404:

    add_filter('template_redirect', 'my_404_override' );
    function my_404_override() {
        global $wp_query;
    
        if (strpos($_SERVER['REQUEST_URI'], "blog/category") > -1 || strpos($_SERVER['REQUEST_URI'], "blog/tag") > -1 || strpos($_SERVER['REQUEST_URI'], "blog/search") > -1) {
            status_header( 200 );
            $wp_query->is_404=false;
            $bypass = true;
            include('page-blog-index.php');
            exit;
        }
    }
    

    The rogue $bypass in there just tells me to fill in the voids caused by this whack solution in page-blog-index.php

    So there we have it. It works. I'm not totally positive why and I am a little uncomfortable with that but ultimately I don't care so long as it works. I would much preferred to have an actual solution that doesn't violate every logical shred of any sane programmer's mind and well within the actual skeleton of a multiple PhD derived CMS, but hey, we can't win all the time, right?

    Hope it helps someone else.