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)
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.