1

I'm trying to create a permalink rule which is a few levels deep.

I have a basic page /page-slug/ - I'm appending to it a new endpoint: /page-slug/my-endpoint/ - from here I need to nest one id and one string that contain $_GET variables, such as /page-slug/my-endpoint/?some_id=123&some_string=string which should become: /page-slug/my-endpoint/123/string/

I got all the query vars successfully registered and I can grab them for use in my methods (e.g if I do var_dump( $wp_query->query_vars ) they will show up where set via $_GET).

What I can't get to work is the rewrite rule to turn a URL in a pretty permalink (this snippet is run at init hook time):

    foreach ( $this->query_vars as $key => $var ) {

        add_rewrite_endpoint( $var, EP_PERMALINK | EP_PAGES, $var );

        if ( 'my-endpoint' == $key ) {

            add_rewrite_tag( '%some_id%',   '([^&]+)' );
            add_rewrite_tag( '%some_string%', '([^&]+)' );

            $page_id   = get_some_page_id(); 
            $page_slug = get_post( $page_id )->post_name;

            // e.g. /page-slug/my-endpoint/123/some-string/
            add_rewrite_rule(
                "{$page_slug}/{$var}/([^/]*)/([^/]*)/?$",
                'index.php?page_id=' . $page_id . '&some_id=$matches[1]&some_string=$matches[2]',
                'top'
            );

        }
    }

I tested the regex and does not look wrong, it catches what I need (123 and some-string).

Up to 'page-slug/' and also 'page-slug/my-query-var/ (2 levels deep) it works just fine, it's the two rewrite tags that don't work when used in a pretty permalink structure.

I tried with https://wordpress.org/plugins/monkeyman-rewrite-analyzer/ and the rules show up there - but I'm not sure about their interpretation

  • so your rewrite rules are all working? it's not clear what you're having a problem with. – Milo Nov 20 '15 at 7:15
  • partially, query vars are working, rewrite rules for the part after the endpoint are not - if I head over /page-slug/my-endpoint/123/some-string and check for isset( $wp_query->query_vars['some_id'] ) it returns false (but no 404), if I do the same with /page-slug/my-endpoint/?some_id=123&some_string=some-string it returns true – unfulvio Nov 20 '15 at 7:23
  • 1
    I'm assuming the missing % in the 2nd add_rewrite_tag is a typo here? I can't test your code exactly, since parts are missing, but if I hardcode a page slug and endpoint name in the rewrite rule, it works for me. – Milo Nov 20 '15 at 7:38
  • yes it was, sorry I deleted it while editing the snippet for stackoverflow – unfulvio Nov 20 '15 at 7:41
2

I think you are using endpoints incorrectly. When a endopoint is created, a new rewrite rule is created using a query var with the same name of the endpoint; its value is taken from the string that follows the endpoint definition. So, if you register "my-endpoint" and build this URL:

/page-slug/my-endpoint/123/some-string

The endpoint is passed as my-endpoint=123/some-string.

As far I understand from your code, you don't need the my-endpoint query var, so you don't need to register it; or you can register it with false value for query var argument (this argument is not currently documented in codex but exists in source code):

add_rewrite_endpoint( $var, EP_PERMALINK | EP_PAGES, false );

Or, if you want the endpoint only in pages:

add_rewrite_endpoint( $var, EP_PAGES, false );

Also, you check 'my-endpoint' == $key buth then include $var as endpoint name and as part in the URL, not $key.

Without knowing what $this->query_vars and get_some_page_id() are, I can not test your code exactly but this should work:

foreach ( $this->query_vars as $key => $var ) {

    if ( 'my-endpoint' == $key ) {

        add_rewrite_tag( '%some_id%',   '([^&]+)' );
        add_rewrite_tag( '%some_string%', '([^&]+)' );

        $page_id   = get_some_page_id(); 
        $page_slug = get_post( $page_id )->post_name;

        // e.g. /page-slug/my-endpoint/123/some-string/
        // $key is equal to my-endpoint here because of the previous check
        add_rewrite_rule(
            "^{$page_slug}/{$key}/([^/]*)/([^/]*)/?$",
            'index.php?page_id=' . $page_id . '&some_id=$matches[1]&some_string=$matches[2]',
            'top'
        );

    }
}

Note: Do not forget to flush rewrite rules before testing this code.

  • 1
    thanks cybmeta while you were answering I also found a solution - not only I had to write add_rewrite_endpoint( 'my-endpoint', EP_PAGES, false ); but in my case the false arg was very important - there is a third parameter in add_rewrite_endpoint and that tells whether adding a query var for the endpoint or not in my case I didn't need it and it was messing up with the rest of the url with the rewrite rule (passing the rest of the url as query var value) - please edit your answer – unfulvio Nov 20 '15 at 9:07
  • I see that third parameter in the source code of add_rewrite_endpoint() but it is not documented in the codex. I didn't know about it. – cybmeta Nov 20 '15 at 9:47
  • Answer edited ;) – cybmeta Nov 20 '15 at 9:53

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.