Useful Entry URIs with Headless Craft

Last night I decided to try and fix a minor irritation I have with using Craft in a headless configuration[1]: broken entry URIs. Let me explain. I use Redactor for pretty much all my text input on Craft, which gives me a handy option when creating hyperlinks to select an entry directly from the CMS. Personally, that's a much better solution than using an <a href=""> element for two reasons:

  • I can do it directly from the text box I'm already typing in, rather than having to open a new tab and find the entry on the live site to copy/paste a URL;
  • If I ever update that entry's slug in the future the change will be flooded across all my posts and links.

Of course, Redactor still outputs an <a href=""> element with a full URL, so it has to dynamically build that URL from information provided by the CMS. Each entry in Craft has a slug field – so that part's obvious – but the rest of the structure comes from a combination of the base URL and the relevant section settings. Because I'm using Craft headless, I need to amend the base URL to something it, well, technically isn't. You can do that directly from the Admin CP in the following location:

Settings -> Sites -> {site name} -> Base URL

All I had to do was change the input value to my actual web domain e.g.

Base URL configuration showing "this site has its own base URL" checked and the full domain name in the "Base URL" text box.
I'm not actually sure if you need that checkbox checked, but it's what I have so figured I'd include it.

With that in place, selecting an "entry link" within a Redactor field now points at the correct domain. However, I also have a bespoke URL structure on this site that's determined by the content type. Personally, all my main content (articles, journal entries, and notes) are set up in Craft as entry types within a single "content" section[2]. That means they all derive their URI structure from the same settings page, which made this next step a little tricky. On the live site, articles and journal entries are prefixed by /wrote/, whereas notes are prefixed by /note/, so that's what I need my URI pattern to match.

Luckily, Craft allows you to use the Twig templating language pretty much anywhere, including within some Admin CP input boxes. That means I can use Twig's logic operators within the Entry URI field like so:

{% if type.handle != 'notes' %}wrote{% else %}note{% endif %}/{slug}

To break down what that's saying: if the entry type for the post has a value of "notes" then add a URL prefix of "note", otherwise add a prefix of "wrote". Either way, it should be followed by a backslash and then the entry's slug.

I'm using a not equals to operator (!=) simply because it's the quickest way to phrase that logic given my particular setup. And that works fine. If it feels a little clunky to you, it can actually be further simplified into a Twig ternary like so:

{type.handle != 'notes' ? 'wrote' : 'note'}/{slug}

Personally, I've kept the full-fat version just because it's a useful reminder of how Twig can be used, and it's slightly more universal in terms of notation. Oh, and incidentally it doesn't matter if you use single- or double-quotes, it works either way, hence why my actual settings look like this:

Site settings table showing the "entry URI format" with the code as above.
Who knows, maybe I'll switch to the ternary version in the future...

Seems pretty simple, right? Well, whilst that's sort of true, I did actually run into a bunch of issues setting this up, so here are two tips to keep an eye on if you're doing something similar:

  • When you save a new URI format, keep an eye on the left-hand sidebar in the Admin CP. You may see an error pop up saying that the operation failed; alternatively, you should see it processing through your entries. It's a good indicator of what's actually going on and something I always forget to use because it's not somewhere I often look.
  • Once you have a new URI format in place, I'd recommend testing that you can actually create a new entry before considering things done. I had a few instances where a URI format showed no errors, actively worked if I edited old articles, but for some reason prevented me creating any new ones. From what I gather, this is due to the way Craft deals with draft/new entries as of v3.3 but I honestly never got to the bottom of why my particular setup was erroring. I ended up just going in a big loop of testing and then it just started working 🤷‍♂️

Explore Other Articles


Structuring Reviews

It turns out that there are a lot of gotchas to creating a clear category structure for media reviews. Well, after a year of messing around with various setups behind the scenes, I think I'm starting to get somewhere.

Further Reading & Sources


Want to take part?

Comments are powered by Webmentions; if you know what that means, do your thing 👍


  • <p>When using Craft in a headless configuration, your entry URIs will default to the wrong domain and won't be properly configured to match your actual site structure, but that can be fixed.</p>
  • Murray Adcock.
Article permalink

Made By Me, But Made Possible By:


Build: Gatsby

Deployment: GitHub

Hosting: Netlify

Connect With Me:

Twitter Twitter

Instagram Instragram

500px 500px

GitHub GitHub

Keep Up To Date:

All Posts RSS feed.

Articles RSS feed.

Journal RSS feed.

Notes RSS feed.