Skip to Content
Docs
Routing
Custom Routes

Custom Routes

In cases where we need a custom route, which does not necessarily map to a content type, you can use the ED()->addCustomRoute() function.

This is mostly useful for sites which include app-like functionality — like login or checkout screens — where the URL should be fixed, and it shouldn’t be removable by a client. It can also be useful for providing URLs to content which isn’t a WordPress post or page, or for advanced customisation of routing.

The ED()->addCustomRoute() function takes two arguments:

  1. The route pattern (a string), which is a simple PHP regular expression. Parenthesised groups can be extracted using dollar sign formatting.
  2. Options for the custom route:
    • template (string, required) — pointing to the .tsx template file to be used, starting with views/
    • queryVars (array, optional) — allows you to map a URL segment to a GraphQL parameter.
    • extraVars (function) — accepts a PHP function which takes the queryVars from the previous step, and can return additional GraphQL parameters. This can be useful if you need to search the database for an ID.
    • title (string or function, required) — the page title to use when viewing this route. If you pass a function, you can use the first parameter to read the query var values — allowing you to look up a title if necessary.
    • is404 (function, optional) - An optional callback function, which will be passed the query parameters, and should return a truthy value if the page should be a 404.

Example:

/backend/routes.php
<?php // Adding a simple '/search' route, with an optional trailing slash. ED()->addCustomRoute("search/?$", [ 'template' => 'views/search.tsx', 'title' => function() { return 'Search'; } ]); // Adding a custom route which uses a Regex pattern // The pattern is made available to a paired GraphQL file via a 'listId' variable. ED()->addCustomRoute("wishlist/([A-Za-z0-9\-\_]+)/?$", [ 'template' => 'views/user-wishlist.tsx', 'queryVars' => [ 'listId' => '$1' ], 'title' => function($params) { $wishlist = Wishlists::getWishlist($params['listId']); return $wishlist->title; }, 'is404' => function($params) { return Wishlists::wishlistExists($params['listId']) == false; } ]);

Inside views/user-wishlist.graphql, the $listId variable will be populated with the regular expression match from the custom route.

/views/user-wishlist.graphql
query UserWishlist($listId: String!) { wishlist(id: $listId) { title items { title } } }

Extra Vars

You can use the extraVars option if you need to calculate some additional GraphQL parameters based on the URL.

Say you want to use /films/{festival}/{film}/ as the pathname for Films, where film slugs are only unique to that festival. The best way to accomplish this would be to:

  • Disable the default item pages, using "rewrite" => false on the Films post type
  • Use the post_type_link filter to ensure that Film URL’s are generated correctly.
  • Add a custom route for the pattern, which handles 404s correctly.

Your custom route might look something like this:

ED()->addCustomRoute('films/([a-z0-9-]+)/([a-z0-9-]+)/?$', [ // Use the 'single-film' template by convention, even though it could be anything 'template' => 'views/single-film.tsx', // Map the URL params -> query vars 'queryVars' => [ 'festivalSlug' => "$1", 'filmSlug' => "$2", ], 'extraVars' => function ($vars) { global $wp_query; $post = get_post([/*...*/]); if (!$post) return []; // Optionally set the global queried_object_id, so that WordPress will handle the page title/SEO metadata as normal $wp_query->queried_object_id = $post->ID; $wp_query->queried_object = $post; // Return the `postId` param return [ 'postId' => $post->ID ]; }, 'is404' => function ($vars) { return empty($vars['postId']); } ]);

TODO: OpenGraph Metadata

Last updated on