As we already described in the opening Page -> Folders section, routing in Grav is primarily controlled by the folder structure you use when you build your site content.
There are certain scenarios where you need more flexibility and Grav comes packed with a variety of tools and configuration options to make your life simpler in this regard.
Imagine if you moved your site from some other CMS platform to Grav, you have several choices on how to set up your new site:
There are many other use cases where you may wish to have the Grav site respond to different URLs than the folder structure dictates, and Grav has the following capabilities to help you realize your objectives.
As outlined in the Headers -> Routes section, you can provide explicit routing options for the default route as well as an array of route aliases:
routes:
default: '/my/example/page'
canonical: '/canonical/url/alias'
aliases:
- '/some/other/route'
- '/can-be-any-valid-slug'
These are processed and cached per-page, and are available along with what we call the raw route which is the route based on the slugs of the page hierarchy (which is how Grav works out a route by default). So even if you provide custom page routes, the raw route is still always valid too.
Similar to page level routing, Grav also supports page level redirects by specifying the target page in the page header. See Headers -> Redirect section for more details.
redirect: '/some/custom/route[303]'
Grav has a powerful regex-based mechanism for handling route aliases and redirects from one page to another. This feature is particularly useful when you migrate a site to Grav and want to ensure the old URLs will still work with the new site. This is often best accomplished via rewrite rules using your web server, but sometimes it's more convenient and flexible just to let Grav handle them.
These are handled via the Site Configuration. Grav comes with a sample system/config/site.yaml
but you can override or add any of your own settings by editing the user/config/site.yaml
file.
All redirect rules apply on the slug-path beginning after the language part (if you use multi-language pages)
You must escape certain characters in any routes that you want to match. This is especially important to know if you are migrating an old site that used links containing legacy file extensions (e.g. .php
) or URL parameters (?foo=bar
). In these examples, the period and question mark must be escaped like /index\.php\?foo=bar: '/new/location'
.
The most basic kind of alias is a direct one-to-one mapping. In the routes:
section of the site.yaml
, you can create a list of mappings to indicate the alias and the actual route that should be used.
It's important to note that these aliases are only used if no valid page is found with the route provided
routes:
/something/else: '/blog/focus-and-blur'
If you requested a URL http://mysite.com/something/else
and that was not a valid page, the routes definition would actually serve you the page located at /blog/focus-and-blur
, assuming it exists. This does not actually redirect the user to the provided page, it simply displays the page when you request the alias.
The indentation is key here, without it the route redirect will not work.
A more advanced type of alias redirect allows the use of a simple regex to map part of an alias to a route. For example, if you had:
routes:
/another/(.*): '/blog/$1'
This would route the wildcard from the alias to the route, so http://mysite.com/another/focus-and-blur
would actually display the page found at the /blog/focus-and-blur
route. This is a powerful way to map one set of URLs to another. Great for moving your site from WordPress to Grav :)
You can also perform the match to capture any alias, and map that to a specific route:
routes:
/one-ring/(.*): '/blog/sunshine-in-the-hills'
With this route alias, any URL that confirms to the wildcard: /one-ring/to-rule-them-all
or /one-ring/is-mine.html
will both show the content from the page with the route /blog/sunshine-in-the-hills
.
You can even get much more creative and map multiple items or use any regex syntax:
routes:
/complex/(category|section)/(.*): /blog/$1/folder/$2
This would match and rewrite the following:
/complex/category/article-1 -> /blog/category/folder/article-1
/complex/section/article-2.html -> /blog/section/folder/article-2.html
This route would not match anything that doesn't start with complex/category
or complex/section
. For more information, Regexr.com is a fantastic resource to learn about and test regular expressions.
The other corollary option to route aliases is provided by redirects. These are similar, but rather than keeping the URL and simply serving the content from the aliased route, Grav actually redirects the browser to the mapped page.
There are three system-level configuration options that affect Redirects:
pages:
redirect_default_route: false
redirect_default_code: 302
redirect_trailing_slash: true
redirect_default_route
enables Grav to automatically redirect to the page's default route.redirect_default_code
allows you to set the default HTTP redirect codes:
redirect_trailing_slash
option lets you redirect to a non-trailing slash version of the current URLFor example:
redirects:
/jungle: '/blog/the-urban-jungle'
You can also explicitly pass the redirect code between square brackets []
as part of the URL:
redirects:
/jungle: '/blog/the-urban-jungle[303]'
If you were to point your browser to http://mysite.com/jungle
, you would actually get redirected and end up on the page: http://mysite.com/blog/the-urban-jungle
.
The same regular expression capabilities that exist for Route Aliases, also exist for Redirects. For example:
redirects:
/redirect-test/(.*): /$1
/complex/(category|section)/(.*): /blog/$1/folder/$2
These look almost identical to the Route Alias version, but instead of transparently showing the new page, Grav actually redirects the browser and loads the new page specifically.
When you set a certain page to be your site's home via the system.yaml
file:
home:
alias: '/home'
You are effectively telling Grav to add a route of /
as an alias for that page. This means that when Grav is requesting the page for the /
URL, it finds the page you have set.
However, Grav really doesn't do anything special for pages that are beneath this homepage. So if you have a page called /blog
that displays a list of your blog posts, and you set this to be your homepage, it will work as expected. If however, you click on a blog post that sits beneath the /blog
folder, the URL could be /blog/my-blog-post
. This is expected behavior, but it might not be what you intend. There is a new option available via the system.yaml
that let's you hide this top level /blog
from the route if so enabled.
You can enable this behavior by toggling the following value:
home:
hide_in_urls: true
Found errors? Think you can improve this documentation? Simply click the Edit link at the top of the page, and then the icon on Github to make your changes.
Powered by Grav + with by Trilby Media.