WordPress add_rewrite_rule works locally but not on server

I’m able to get add_rewrite_rule to work locally with MAMP, but not on my DreamHost production server.

I’m attempting to prettify the URLs for individual pets at http://www.pawsnewengland.com/our-dogs-list/. The ugly URLs follow this structure: our-dogs-list/?view=pet-details&id=12345, and a custom function uses $_GET variables to process in the information.

Read More

In my functions.php file, I’ve included this:

function rewrite_pet_url() {
    add_rewrite_rule(
        "our-dogs-list/pet-details/([0-9]+)/?$",
        "index.php/our-dogs-list/?view=pet-details&id=$1",
        "top"
    );
}
add_action( 'init', 'rewrite_pet_url');

I’ve also tried this with the same results:

function rewrite_pet_url() {
    add_rewrite_rule(
        "our-dogs-list/pet-details/([0-9]+)/?$",
        "index.php/our-dogs-list/?view=pet-details&id=$matches[1]",
        "top"
    );
}
add_action( 'init', 'rewrite_pet_url');

And in an effort to simply test that rewrites would work at all, tried this:

function rewrite_pet_url() {
    add_rewrite_rule(
        "fake",
        "index.php/about",
        "top"
    );
}
add_action( 'init', 'rewrite_pet_url');

I’m flushing rewrite rules prior to testing, and have confirmed that the rewrite rules were added to the .htaccess file. For some reason, though, I’m seeing either a 404 page or a white screen and “No input file specified.”

I’m able to get this working locally, so I have no idea what’s breaking on a live server. Any insights?

Update 1

I’ve gotten the rewrite “working” in the sense that it no longer causes any errors. Unfortunately, it now causes an unwanted redirect to the root URL.

function rewrite_pet_url() {
    add_rewrite_tag('%view%','([^&]+)');
    add_rewrite_tag('%id%','([^&]+)');
    add_rewrite_rule(
        'our-dogs-list/pet-details/([0-9]+)?$',
        'index.php/?page_id=1663&view=pet-details&id=$1',
        'top'
    );
}
add_action( 'init', 'rewrite_pet_url' );

With this, I can access the view and id variables using get_query_var(). However, instead of honoring example.com/our-dogs-list/pet-details/12345, WordPress redirects the page to example.com/our-dogs-list/.

Any idea what could be causing that? It’s effectively making the rewrite rule useless.

Related posts

Leave a Reply

4 comments

  1. This was to long to add as a comment.

    I would add this to functions.php. I’ve changed your permalink a bit, my demo plugin explains what each function does:

    add_filter('generate_rewrite_rules', 'pet_rewrite_url');
    add_filter('query_vars', 'pet_query_vars'));
    add_filter('admin_init',  'pet_flush_rewrite_rules');
    add_action("parse_request", "pet_parse_request");
    
    
    function pet_rewrite_url( $wp_rewrite ) {
        $new_rules = array(
             'our-dogs-list/pet-details/([0-9]+)/?$' => sprintf("index.php?pet-details=%s",$wp_rewrite->preg_index(1))
        );
    
        $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
        return $wp_rewrite->rules;
    }
    
    function pet_query_vars( $query_vars ) {
        $query_vars[] = 'pet-details';
        return $query_vars;
    }
    
    function pet_flush_rewrite_rules() {
        $rules = $GLOBALS['wp_rewrite']->wp_rewrite_rules();
        if ( ! isset( $rules['our-dogs-list/pet-details/([0-9]+)/?$'] ) ) { // must be the same rule as in pet_rewrite_url($wp_rewrite)
            global $wp_rewrite;
            $wp_rewrite->flush_rules();
        }
    }
    
    function pet_parse_request($wp_query) {
        if (isset($wp_query->query_vars['pet-details'])) { // same as the first custom variable in pet_query_vars( $query_vars )
            // add your code here, code below is for this demo
            printf("<pre>%s</pre>",print_r($wp_query->query_vars,true));
            exit(0);
        }
    }
    
  2. I’ve written a guide on how to add custom permalinks, here’s the example plugin (also available at my site):

    <?php
    /*
    Plugin Name: My Permalink Demo
    Plugin URI: http://soderlind.no/archives/2012/11/01/wordpress-plugins-and-permalinks-how-to-use-pretty-links-in-your-plugin/
    Description: Demo plugin to show how to implement your custom permalink for your plugin. To test, add the [mypermalink] or [mypermalink val="ipsum"] shortcode to a page or post.
    Version: 1.0.1
    Author: Per Soderlind
    Author URI: http://soderlind.no/
    */
    
    if (!class_exists('my_permalink')) {
        class my_permalink {
    
            function __construct(){
                // demo shortcode
                add_shortcode('mypermalink', array(&$this,'my_permalink_demo_shortcode'));
    
                // permalink hooks:
                add_filter('generate_rewrite_rules', array(&$this,'my_permalink_rewrite_rule'));
                add_filter('query_vars', array(&$this,'my_permalink_query_vars'));
                add_filter('admin_init', array(&$this, 'my_permalink_flush_rewrite_rules'));
                add_action("parse_request", array(&$this,"my_permalink_parse_request"));
            }
    
            /**************************************************************************
             * Demo shortcode
             * A simple shortcode used to demonstrate the plugin.
             *
             * @see http://codex.wordpress.org/Shortcode_API
             * @param array $atts shortcode parameters
             * @return string URL to demonstrate custom permalink
             **************************************************************************/
            function my_permalink_demo_shortcode($atts) {
                extract(shortcode_atts(array(
                    // default values
                    'val'       =>   'lorem'
                ), $atts));
                return sprintf('<a href="%s">My permalink</a>',$this->my_permalink_url($val));
            }
    
            /**************************************************************************
             * Create your URL
             * If the blog has a permalink structure, a permalink is returned. Otherwise
             * a standard URL with param=val.
             *
             * @param sting $val Parameter to custom url
             * @return string URL
             **************************************************************************/
            function my_permalink_url($val) {
                if ( get_option('permalink_structure')) { // check if the blog has a permalink structure
                    return sprintf("%s/my-permalink/%s",home_url(),$val);
                } else {
                    return sprintf("%s/index.php?my_permalink_variable_01=%s",home_url(),$val);
                }
            }
    
            /**************************************************************************
             * Add your rewrite rule.
             * The rewrite rules array is an associative array with permalink URLs as regular
             * expressions (regex) keys, and the corresponding non-permalink-style URLs as values
             * For the rule to take effect, For the rule to take effect, flush the rewrite cache,
             * either by re-saving permalinks in Settings->Permalinks, or running the
             * my_permalink_flush_rewrite_rules() method below.
             *
             * @see http://codex.wordpress.org/Custom_Queries#Permalinks_for_Custom_Archives
             * @param object $wp_rewrite
             * @return array New permalink structure
             **************************************************************************/
            function my_permalink_rewrite_rule( $wp_rewrite ) {
                $new_rules = array(
                     'my-permalink/(.*)$' => sprintf("index.php?my_permalink_variable_01=%s",$wp_rewrite->preg_index(1))
                     /*
                     // a more complex permalink:
                     'my-permalink/([^/]+)/([^.]+).html$' => sprintf("index.php?my_permalink_variable_01=%s&my_permalink_variable_02=%s",$wp_rewrite->preg_index(1),$wp_rewrite->preg_index(2))
                     */
                );
    
                $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
                return $wp_rewrite->rules;
            }
    
            /**************************************************************************
             * Add your custom query variables.
             * To make sure that our parameter value(s) gets saved,when WordPress parse the URL,
             * we have to add our variable(s) to the list of query variables WordPress
             * understands (query_vars filter)
             *
             * @see http://codex.wordpress.org/Custom_Queries
             * @param array $query_vars
             * @return array $query_vars with custom query variables
             **************************************************************************/
            function my_permalink_query_vars( $query_vars ) {
                $query_vars[] = 'my_permalink_variable_01';
                /*
                // need more variables?:
                $query_vars[] = 'my_permalink_variable_02';
                $query_vars[] = 'my_permalink_variable_03';
                */
                return $query_vars;
            }
    
            /**************************************************************************
             * Parses a URL into a query specification
             * This is where you should add your code.
             *
             * @see http://codex.wordpress.org/Query_Overview
             * @param array $atts shortcode parameters
             * @return string URL to demonstrate custom permalink
             **************************************************************************/
            function my_permalink_parse_request($wp_query) {
                if (isset($wp_query->query_vars['my_permalink_variable_01'])) { // same as the first custom variable in my_permalink_query_vars( $query_vars )
                    // add your code here, code below is for this demo
                    printf("<pre>%s</pre>",print_r($wp_query->query_vars,true));
                    exit(0);
                }
            }
    
            /**************************************************************************
             * Flushes the permalink structure.
             * flush_rules is an extremely costly function in terms of performance, and
             * should only be run when changing the rule.
             *
             * @see http://codex.wordpress.org/Rewrite_API/flush_rules
             **************************************************************************/
            function my_permalink_flush_rewrite_rules() {
                $rules = $GLOBALS['wp_rewrite']->wp_rewrite_rules();
                if ( ! isset( $rules['my-permalink/(.*)$'] ) ) { // must be the same rule as in my_permalink_rewrite_rule($wp_rewrite)
                    global $wp_rewrite;
                    $wp_rewrite->flush_rules();
                }
            }
        } //End Class
    } //End if class exists statement
    
    if (class_exists('my_permalink')) {
        $my_permalink_var = new my_permalink();
    }
    ?>
    
  3. Your replacements look incorrect, try:

    function rewrite_pet_url() {
        add_rewrite_rule(
            "our-dogs-list/pet-details/([0-9]+)/?$",
            "index.php?view=pet-details&id=$1",
            "top"
        );
    }
    add_action( 'init', 'rewrite_pet_url');
    

    Note the use of index.php and not index.php/our-dogs-list/ as the destination.

    Or maybe it’s like this:

    function rewrite_pet_url() {
        add_rewrite_rule(
            "our-dogs-list/pet-details/([0-9]+)/?$",
            "our-dogs-list/index.php?view=pet-details&id=$1",
            "top"
        );
    }
    add_action( 'init', 'rewrite_pet_url');
    
  4. edit in your .htaccess

    RewriteRule ^our-dogs-list/pet-details/([0-9]+)?$ /index.php?page_id=1663&view=pet-details&id=$1 [L] add this for RewriteRule ^index.php$ - [L] so you .hatcces would something like:

    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /wordpress/
    RewriteRule ^our-dogs-list/pet-details/([0-9]+)?$ /wordpress/index.php?page_id=2&view=pet-details&id=$1 [L]
    RewriteRule ^index.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /wordpress/index.php [L]
    </IfModule>
    

    update

    from: http://codex.wordpress.org/Rewrite_API/add_rewrite_rule

    IMPORTANT: By default, WordPress will not recognize custom querystring
    variables used for rewrites. You must register your querystring
    variables with WordPress. Simply use add_rewrite_tag() to do this, or
    the above rewrite will not work! More information about capturing
    querystring variable values after a rewrite can be found here.

    so far i understand you should use: add_rewrite_tag() for view and id in your first example.