add_rewrite_rule not working for page var

OK, let’s first get some definitive clarification on the proper query vars.

Refer to Post and Page parameters on the WP_Query codex page.

name (string) – use post slug.

pagename (string) – use page slug.

We can confirm this with WP_Query:

$args = array(
    'name' => 'mypage'
);
$mypage = new WP_Query( $args );

echo '<pre>';
print_r( $mypage );
echo '</pre>';

which will produce:

SELECT wp_posts.*
FROM wp_posts
WHERE 1=1
AND wp_posts.post_name="mypage"
AND wp_posts.post_type="post"
ORDER BY wp_posts.post_date DESC

It’s looking for mypage slug in the post post type. If we change this to pagename, it looks in the page post type.

The reason it kind of works on the main query with name is due to the redirect_guess_404_permalink function, which kicks in when the original request is a 404. It runs another query to find the closest match and redirect there, if something is found. This also results in any extra parameters getting stripped from the URL.

One important thing to note with hierarchical post types- if your page is a child of another page, you must set the pagename query var with the parent/child path, as different parents can have children with the same slug.

As for your question, changing the query var to pagename works with your original code in v4.7.2 and the Twenty Sixteen theme:

function wpd_mypage_rewrite() {
    add_rewrite_tag(
        '%mycustomvar%',
        '([^/]+)'
    );
    add_rewrite_rule(
        '^mypage/([^/]+)/?',
        'index.php?pagename=mypage&mycustomvar=$matches[1]',
        'top'
    );
}
add_action( 'init', 'wpd_mypage_rewrite' );

Note that I used add_rewrite_tag here. You could instead use the query_vars filter. The reason add_rewrite_tag works is that it internally adds the query var via the same filter.

Don’t forget to flush rewrite rules after adding / changing rules. You can also do this by visiting the Settings > Permalinks page.

You can then echo get_query_var( 'mycustomvar' ); in the template, and the value is output.

Leave a Comment