Issue with routes.yaml

I have a english / french blog. I would like blog posts tagged with “fr” to be hidden from the main page and instead show up at /blog/fr.

I am trying with routes.yaml but am running into error when I try to upload the routes.yaml from Labs.

here is the modified routes.yaml:

routes:
collections:
  /:
    permalink: /{slug}/
    filter: "-tag:fr"
    template: index

  /blog/fr/:
    permalink: /blog/fr/{slug}/
    filter: "tag:fr"
    template: index

taxonomies:
  tag: /tag/{slug}/
  author: /author/{slug}/
Error from ghost log:
[2025-01-21 15:27:49] ERROR "POST /blog/ghost/api/admin/settings/routes/yaml/" 500 7074ms

NAME: InternalServerError
MESSAGE: Could not load routes.yaml file.

level: critical

InternalServerError: Could not load routes.yaml file.
    at /var/www/html/ghost/versions/5.105.0/core/server/services/route-settings/RouteSettings.js:129:35
    at async Object.query (/var/www/html/ghost/versions/5.105.0/core/server/api/endpoints/settings.js:158:13)
    at async getResponse (/var/www/html/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:259:34)
    at async ImplWrapper (/var/www/html/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:264:30)
    at async Http (/var/www/html/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/http.js:70:28)

I have tried 3-4 variants of this routes.yaml, it always breaks something, am I doing this the right way?

filter: tag:-fr

Try that ?

I tried with:

routes:
collections:
  /:
    permalink: /{slug}/
    filter: -tag:fr
    template: index

  /blog/fr/:
    permalink: /blog/fr/{slug}/
    filter: tag:-fr
    template: index

taxonomies:
  tag: /tag/{slug}/
  author: /author/{slug}/

Now I get:

[2025-01-21 15:56:58] ERROR

MESSAGE: begin.toISOString is not a function

TypeError: begin.toISOString is not a function
at #fetchEvents (/var/www/html/ghost/versions/5.105.0/node_modules/@tryghost/email-analytics-service/lib/EmailAnalyticsService.js:293:64)
at EmailAnalyticsService.fetchMissing (/var/www/html/ghost/versions/5.105.0/node_modules/@tryghost/email-analytics-service/lib/EmailAnalyticsService.js:185:39)
at async EmailAnalyticsServiceWrapper.fetchMissing (/var/www/html/ghost/versions/5.105.0/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js:107:29)
at async EmailAnalyticsServiceWrapper.startFetch (/var/www/html/ghost/versions/5.105.0/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js:148:24)
at async /var/www/html/ghost/versions/5.105.0/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js:63:13
at async EventEmitter. (/var/www/html/ghost/versions/5.105.0/node_modules/@tryghost/domain-events/lib/DomainEvents.js:34:17)

One more fix is needed.

2 Likes

Thank you @Raki that worked. Could you help me with the format to do the same with multiple tags?

for example I want to hide also posts which use tag “tree-species” from the main page.

I have tried this and different variants of this yaml but I always receive an error about trailing slash being required:

  collections:
    /:
      permalink: /{slug}/
      filter: tag:-fr+tag:-tree-species
      template: index

    /blog/fr/:
      permalink: /blog/fr/{slug}/
      filter: tag:-fr
      template: index

  taxonomies:
    tag: /tag/{slug}/
    author: /author/{slug}/

Welcome to the club, routes are so much fun. I use AI support for routes, try Claude Sonnet or Gemini Flash 2, here’s Gemini thought on your routes …


The Problem: Conflicting Filters and the Root Collection

  • The Root Collection (/) and Universality: The root collection (/) is generally designed to be a catch-all for posts not belonging to any specific collection. It’s intended to handle the default routing for your blog. Applying a restrictive filter to the root collection is often problematic.

  • Conflicting Exclusion Filters: The filter: tag:-fr+tag:-tree-species attempts to exclude both posts tagged with -fr AND posts tagged with -tree-species. This means only posts that have neither of these tags will be included in this collection. This is almost certainly not what you want. Usually, + in a filter means “AND”, but here you’re effectively creating a highly exclusive filter at your site’s root.

  • Conflict with /blog/fr/: The second collection /blog/fr/ has a filter: tag:-fr. If a post has the fr tag, it will be excluded from the root collection (due to tag:-fr) and excluded from the /blog/fr/ collection as well. This means posts with the fr tag will not be displayed anywhere.

  • Permalink Collision: The permalink: /{slug}/ in the root collection makes every post’s URL /slug-name/. The /blog/fr/ collection attempts to create URLs like /blog/fr/slug-name/, but because every slug is already used by the root collection, Ghost will have routing conflicts.

1 Like

I have been trying AI for this as well, but it seems to struggle with ghosts routing. I have tried probably 20 different variations and no matter what I break one thing or another. Ghost really does not me hiding stuff it seems, kinda funny considering the name.

  collections:
    /:
      permalink: /{slug}/
      filter: tags:-[fr,tree-species]
      template: index

    /blog/fr/:
      permalink: /blog/fr/{slug}/
      filter: tag:fr
      template: index

  taxonomies:
    tag: /tag/{slug}/
    author: /author/{slug}/

See if the tags:[ ] notation works better for you. Also, I’m assuming you want the posts tagged ‘fr’ on the /blog/fr collection, so I removed a stray - for you.

You still need a route where posts tagged tree species can live.

One other thought - I’m not 100% sure you can put a collection at /blog/fr. I’m sure the permalinks are fine, but it’s possible that the collection needs to sit at /fr/ or /blog-fr/ instead. If it’s still throwing that error, you might try making that change and see if it fixes it.

1 Like

This seems to have done the trick. I had to fix indentation on “taxonomies” and than voila.

Thanks!

Ok, I was wrong, it partially works. Posts with tag “tree-species” are now hidden from the main page, but the posts themselves are now inaccessible.

Clicking “View Post” from in the editor leads to “https://boisafeudunord.com/blog/p/”, when the post URL is “https://boisafeudunord.com/blog/atlas-cedar-firewood-profile/”. If I visit that URL directly it is “404”.

Current routes file:

collections:
    /:
      permalink: /{slug}/
      filter: tags:-[fr,tree-species]
      template: index

    /blog/fr/:
      permalink: /blog/fr/{slug}/
      filter: tag:fr
      template: index

taxonomies:
    tag: /tag/{slug}/
    author: /author/{slug}/

Yep. I added that to my previous post, but you might not have seen the update. :slight_smile:

All posts need to be in exactly one collection. Currently, non-french posts about tree-species don’t have a collection. So…

The collections can share a permalink if you prefer, but each needs a different url for the index page (that’s the /blog/fr for example)

collections:
    /:
      permalink: /{slug}/
      filter: tags:-[fr,tree-species]
      template: index

    /blog/fr/:
      permalink: /blog/fr/{slug}/
      filter: tag:fr
      template: index

    /trees/:
      permalink: /{slug}/
      filter: tags:[tree-species]
      template: index

taxonomies:
    tag: /tag/{slug}/
    author: /author/{slug}/
2 Likes

Ah, yeah, that makes sense, I start to see the picture now. All working, thank you.

2 Likes

So, I am back, not sure what happened but this is no longer working. Any time I tag a post with “fr” and visit the post, it is a 404. Here is what the URL looks like when tagged with “fr”:
https://boisafeudunord.com/blog/fr/a-quel-point-votre-feu-est-il-chaud-2/

Untag it and no problem it works fine without the “fr” in the url.

The routes.yaml is this:

collections:
    /:
      permalink: /{slug}/
      filter: tags:-[fr,tree-species]
      template: index

    /blog/fr/:
      permalink: /blog/fr/{slug}/
      filter: tag:fr
      template: index

    /trees/:
      permalink: /{slug}/
      filter: tags:[tree-species]
      template: index

taxonomies:
    tag: /tag/{slug}/
    author: /author/{slug}/

I have a hard time getting my head around ghosts routes.

Routes don’t get updated if a post is tagged with the bulk edit from the list of posts. Could that have happened here? Try either restarting ghost or loading a new copy of the routes file to trigger.

1 Like

It wasn’t bulk edit, it was from inside the specific posts editor. I have done as you suggested and restarted ghost, I also reuploaded the routes file to be sure.

The problem persists.

Interesting! I see from https://boisafeudunord.com/blog/sitemap-posts.xml that you’ve got a subdirectory install. I wonder if there’s some ah… quirky… behavior for subdirectory installs and routing.

Wait.. Hang on. Your trees posts are actually at blog/trees. Etc. So you need to change the routing for the middle section to

    /fr/:
      permalink: /fr/{slug}/
      filter: tag:fr
      template: index

Which, because of the subdirectory install will result in things at /blog/fr, but… yeah. Try that please.

1 Like

That was it!

Thank you.

1 Like