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:
- The route pattern (a string), which is a simple PHP regular expression. Parenthesised groups can be extracted using dollar sign formatting.
- Options for the custom route:
template(string, required) — pointing to the.tsxtemplate file to be used, starting withviews/queryVars(array, optional) — allows you to map a URL segment to a GraphQL parameter.extraVars(function) — accepts a PHP function which takes thequeryVarsfrom 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:
<?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.
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" => falseon the Films post type - Use the
post_type_linkfilter 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