0

I want to create an archive endpoint page that will have a dynamic slug, based on the taxonomy term slug.

e.g. If the taxonomy is Food and the current term is Onion, I want the endpoint slug to look like onion-recipes.

www.domain.com/food/vegetables/onion/onion-recipes Gives me a 404 even after flushing permalinks.

Code:

add_action( 'init', function() {
    $term = get_queried_object();
    $ep_slug = $term->slug.'-recipes';
    add_rewrite_endpoint( $ep_slug, EP_PAGES );
} );

1 Answer 1

3

add_rewrite_endpoint() only supports static endpoint names like trackback and recipes, so if you need a dynamic endpoint name/slug, then you would want to use add_rewrite_rule() instead.

And just so that you know, even if add_rewrite_endpoint() did support dynamic names/slugs, your code would not work because your function runs too early (via the init hook) and thus get_queried_object() would return a null, which means that $term is not actually an object (even if you were on a term archive page).

So for the food/onion/onion-recipes structure or endpoint, where onion is the term slug, you could use add_rewrite_rule() like so:

add_action( 'init', function () {
    // Adds a rewrite rule for /food/<term slug>/<term slug>-recipes where "food"
    // here is a custom taxonomy.
    add_rewrite_rule(
        'food/(.+?)/([^/]+)-recipes/?$',
        'index.php?food=$matches[1]',
        'top'
    );
} );

Things to note:

  1. (.+?) is a term slug or path which is read from the current URL path, and the slug could be onion or a "directory"/path like onion/child if your taxonomy is hierarchical.

  2. ([^/]+) is also a term slug, but without a / (slash). (I purposely put it in a group in case you'd need to access $matches[2])

  3. In the above regular expression (RegEx) pattern (which is the 1st parameter for add_rewrite_rule()), I used 2 capturing groups or subpatterns, and each group/subpattern match from the URL will be stored in an array named $matches.

    So if the current URL is https://example.com/food/onion/child/child-recipes, then $matches[1] is onion/child, whereas $matches[2] is child. I.e. food/(onion/child)/(child)-recipes — note the parentheses.

You can test and play with the above RegEx here on regex101.com.

Also, remember to flush the rewrite rules! Simply visit the Permalink Settings admin page.

Update

If you want to create a query var for your endpoint, just like what add_rewrite_endpoint() does by default, and so that you can use get_query_var() to retrieve the term slug from the endpoint name, you can use the query_vars hook to register your query var.

Here's an example where the query var (name) is food_recipe (make sure the name is not already in use, e.g. by an existing post type or taxonomy):

add_filter( 'query_vars', function ( $vars ) {
    $vars[] = 'food_recipe';
    return $vars;
} );

After that,

  1. Change the rewrite rule's query (the 2nd parameter for add_rewrite_rule()) from index.php?food=$matches[1] to index.php?food=$matches[1]&food_recipe=$matches[2]

  2. Then flush the rewrite rules, again. :)

And as for using &food-info=recipes in the above query, where food-info is a custom taxonomy name/slug, yes, you can. Any query args that WP_Query accepts, and even custom ones, can be used there, but whether the query would return any posts would of course depend on whether there are posts that matched the query. :)

15
  • 1
    PS: Sorry, I deleted my original answer.. but I hope this one helped you more. Also, as for using recipes-with-onion instead, just change the ([^/]+)-recipes above to recipes-with-([^/]+) :)
    – Sally CJ
    Commented Jan 30, 2022 at 10:59
  • 1
    See the Update part in my revised answer, but I assumed that you only wanted to retrieve the term slug from the endpoint name? If you wanted to capture the entire endpoint name, then you can change the regex to food/(.+?)/([^/]+-recipes)/?$, then use food_endpoint as the query var, so change the query to index.php?food=$matches[1]&food_endpoint=$matches[2], and of course, register the query var (food_endpoint).
    – Sally CJ
    Commented Jan 31, 2022 at 11:32
  • 1
    That is because (.+?) matches anything before the /onion-recipes part. So you really just need to play with the regex.. :) and if necessary, change the query (the food=$matches[1] part).
    – Sally CJ
    Commented Feb 1, 2022 at 0:32
  • 1
    So for example, to match vegetables/**onion** only, i.e. vegetables/<term slug>, then (assuming your taxonomy is hierarchical), change the (.+?) to (vegetables/[^/]+) and then it will only match vegetables/onion, vegetables/carrot, vegetables/green-bean, etc, but not vegetables/foo/bar because foo/bar contains a slash. Demo here
    – Sally CJ
    Commented Feb 1, 2022 at 0:34
  • 1
    @harvey Yes, and that's a limitation in the WordPress rewriting system - add_rewrite_rule() simply adds the rewrite rule. Same goes with add_rewrite_endpoint(), except that it also automatically creates a query var by default. Matters like checking whether the URL actually points to a valid resource (like a term that actually exists in the database) has to be handled manually, e.g. via the pre_handle_404 hook. And btw, are you @Edegist?
    – Sally CJ
    Commented Feb 3, 2022 at 0:49

Your Answer

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

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