3

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)

  • name is the query var for post type post, pagename is for post type page. – Milo Feb 25 '17 at 15:53
  • interesting, because this is a page, not a post, and name worked better, at least for the first variable... – Stephen Feb 25 '17 at 15:55
  • What do you mean by worked better? If it redirects, that means the original query failed and it found the closest match. – Milo Feb 25 '17 at 16:45
  • I mean that when using name, it rewrote at least the first part of my url correctly, whereas using pagename it did not. – Stephen Feb 25 '17 at 17:25
  • If you have a link with just query string arguments, it's not going to redirect to the pretty version, that's not what rewrite rules do. You may see a partially rewritten URL when you incorrectly use name, because that query is failing, and WP is querying for any post type that matches mypage, and redirecting there. Rewrite rules just match requests against rules and convert them to query vars, outputting that rewritten URL is a separate and unrelated task. – Milo Feb 25 '17 at 18:16
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.

  • Thanks for the explanation. I had exactly that code in there (as you can see in my original question above) and for some reason it wasn't working (even after flushing the permalinks), but for some reason now it does. I am stumped, but I like your explanation of the redirect guess function (which is new to me), so I will accept this as the answer. (perhaps in my combo tries of pagename, name, and page I left out the rewrite tag or query vars, but in any event it now works and thanks) – Stephen Feb 26 '17 at 6:26
0

UGH I (maybe) just figured it out. I didn't need my variable to have a name, just a location.

So changing my rewrite rule to this worked:

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

NOW my page will properly load the URL:

http://example.com/mypage/someword

ALTHOUGH that said, I have no way now other than url placement to read my variable someword and do something with it, but I guess that is good enough unless someone can point me to a better way that will allow me to query that var by its name....

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.