I have a page called mypage and a custom query var called mycustomvar, I am trying to rewrite the following url:

http://example.com/index.php?name=mypage&mycustomvar=someword

to

http://example.com/mypage/someword

using

add_rewrite_rule( '^mypage/([^/]+)/?', 'index.php?name=mypage&mycustomvar=$matches[1]', 'top' );

But all I get is:

http://example.com/mypage/?mycustomvar=someword

showing in the url. I have also tried adding both

add_rewrite_tag( '%mycustomvar%', '([^/]+)' );

as well as making sure that mycustomvar is added to my custom query vars via the query_vars filter

(and I have tried various combos with and without page name, and using page or pagename in place of name, all with no luck)

2 Answers
2

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 Reply

Your email address will not be published. Required fields are marked *