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

4
  • so your rewrite rules are all working? it's not clear what you're having a problem with.
    – Milo
    Nov 20, 2015 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, 2015 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, 2015 at 7:38
  • yes it was, sorry I deleted it while editing the snippet for stackoverflow
    – unfulvio
    Nov 20, 2015 at 7:41

1 Answer 1

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.

3
  • 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, 2015 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, 2015 at 9:47
  • Answer edited ;)
    – cybmeta
    Nov 20, 2015 at 9:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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