Adapting Latest Loop to Display Based on Tag(s)

Using Edition 1.0.0 theme. On the default home page, I’d like to Latest loop to display only posts tagged with one tag. In the template files, I see where the loop displays. But I don’t see where to modify the query that outputs what is displayed. Is that query accessible and, if so, where can I modify it?

I’m a newbie to Ghost but have used WordPress, MovableType, etc for a few decades. Thanks in advance for any guidance.

The query comes from your routing configuration, which renders everything by default. I haven’t tried this, but adding a second route might configure the filter:

## routes.yaml

routes:

collections:
  /:
    permalink: /{slug}/
    template: index
    filter: tag:latest
  /not-latest:
    permalink: /{slug}/
    template: index
    # No need for a filter since this is the catch-all route

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

If that doesn’t work, you can use the get helper to fetch the posts and use them instead of the default post list.

That looks interesting to try, thank you! Might take a day or two. The get helper also sounds like a possible solution. I’ll let you know what I find.

Also, the Editions theme doesn’t appear to have a routes file. I’ll look into that as well.

A theme might require certain Dynamic Routes to function, but it’s not required. Dynamic Routes are install-specific :slight_smile:

Thanks again @vikaspotluri123! I figured this out with your help and routes link plus trial and error. The routes.yaml file turned out to work in the simplest most efficient way.

Here’s my routes.yaml file updated which works on all my pages:

routes:

collections:
  /:
    permalink: /{slug}/
    template: index
    filter: tag:newsletters

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

The only interesting additional tweak could’ve been using the primary-tag:newsletters bit to specific a 100% specific tag. Don’t need it in my case. And I like that Ghost rejects malformed routes.yaml files instead of blindly uploading it and trashing my site.

Your routing URL was the source of the answer, thanks again!

Any post not tagged newsletters won’t have a URL in this case, is that what you’re looking to do?

Now I see that effect. I couldn’t figure out how to adapt your code:

/not-latest:
    permalink: /{slug}/
    template: index

Does that work as is? Or is the not-latest bit related to the use of latest in the tag:latest bit? I took latest as an example tag.

@vikaspotluri123 or anyone, after a lot of reading, this is where I net out. I’m unable to see the detail page for page that displays posts tagged with the tag called extras.

My routes.yaml file:

routes:
  /features/extras/:
    template: tags
    data: tag.extras
  /features/newsletters/:
    template: tags
    data: tag.newsletters

collections:
  /:
    permalink: /{slug}/
    template: index

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

My index.hbs file has this get helper (thanks Vikas) to display only posts tagged with the newsletters tag:

        {{#get "posts" filter="primary_tag:newsletters" limit="12"}}
            {{#foreach posts}}
                {{> "loop"}}
            {{/foreach}}
        {{/get}}

Here’s my problem: The home page displays correctly. The Newsletters page displays correctly. The Extras page displays entries but clicking the post link on that page generates a 404 error. From reading the dev docs, that should not be happening. Curious if anyone can figure out the reason.

For example, I’m using the admin UI to upload updated yaml and theme zip files. Is it possible that Ghost gets confused at a point and doesn’t update file contents?

Appreciate any help or thoughts. Thanks in advance!

Can you share the contents of your tags.hbs template?

To be really sure that there’s not some kind of state issue, you can restart your instance (assuming you’re self-hosting)

Here’s my tags.hbs template. Only change I’ve made is to hard code a class definition for the div that wraps around the loop.

{{!< default}}

<main class="site-main">

    {{#tag}}
    <section class="taxonomy">

        {{#if feature_image}}
            <div class="taxonomy-media u-placeholder square">
                <img class="u-object-fit" src="{{img_url feature_image size="s"}}" alt="{{name}}">
            </div>
        {{/if}}

        <header class="single-header gh-canvas">
            <h1 class="single-title">{{name}}</h1>
            {{#if description}}
                <div class="single-excerpt">{{description}}</div>
            {{/if}}
        </header>

    </section>
    {{/tag}}

    <div class="post-feed expanded gh-feed gh-canvas">
        {{#foreach posts}}
            {{> "loop"}}
        {{/foreach}}
    </div>

    {{pagination}}

</main>

Also, today, my two /features/newsletters and /features/extras URLs now generate 400 errors. Despite everything being exactly the same. I’m also using hosted Ghost Pro. While I have a VPS and other sites, for this project I don’t want that hassle.

A 400 error often means an error in the handlebars file responsible for serving that page. Unfortunately, on Ghost Pro there’s no way to see the actual error message. If you can try installing this theme either locally (my preference for theme development) or on one of your VPS setups, that should let you see the actual error message, which will make debugging a LOT easier.

Debugging on Ghost Pro is super painful…

I have some suspicion that the problem is that creating a route with data tag.extras doesn’t actually get the posts with that tag available on that route. (Which means that either the foreach has no data - shouldn’t cause a 400, just blank, or the pagination can’t paginate, which will cause a 400…)
But that’s a guess. The actual error message is going to be really helpful here.

Hi Cathy, thanks for responding. Took awhile to set up a Ghost instance on my VPS server. I appear to get this error at that location:

‘Missing template tags.hbs for route “/features/newsletters/”.’

When I search the Ghost forum, there’s a complicated question/responses for a custom template. I’m trying to make things as simple as possible.

In my case, the error sounds like it might be a subtle syntax error in my routes.yaml file? Look at the routes definitions, everything seems the same as what’s in the Ghost dev docs.

Let me know if you have any thoughts given this result. Grateful for any ideas. And thank you!

PS if it helps or matters, if I copy the tags.hbs file twice and rename them extras.hbs and newsletters.hbs then update the template definition to extras and newsletters, I get the same error. That makes it somehow a syntax error.

This error is saying that in your route /features/newsletters, you configured the template to be tags.hbs, but that file doesn’t exist. From post 10 I thought it was part of your theme. Can you clarify?

Just calling this out - there’s a difference between tag.hbs - the template for a tag page, and tag**s**.hbs - a generic template.

Part of this is a an error on my part, as you point out @vikaspotluri123: in my routes.yaml file I mistakenly added an s to tag. Having fixed that on my local Ghost test site, I now get this error:

[tag.hbs] The {{pagination}} helper was used outside of a paginated context. See Ghost Handlebars Theme Helpers: pagination.

When I go to that page, I don’t see anything that suggests an answer. I haven’t touched the location of content in the tag.hbs file, as you can see in comment #9 above. The contents of the tag.hbs file are the default contents from the edition template files.

If it helps, this is what’s in the pagination.hbs file in the partials folder:

<nav class="load-more">
    <button class="button button-secondary gh-loadmore">Load more</button>
</nav>

I think you’re getting that error because routes don’t support pagination, but tag pages do. The tag template uses the pagination helper, thus causing this error on the route

Well that’s really interesting. I didn’t get that subtle point in the dev docs. It appears that, if collections are used, the home page / must be a route? Otherwise, the / definition in the collections section applies to every post regardless of any definitions below it?

This routes file appears to work except in one key detail: the Extras page displays at the specified URL but only the tag name and description display and only with the data specification. The single post tagged with the extras tag doesn’t display on my production site. Meanwhile, the Newsletters page displays fine without specifying data source and the pagination works too.

Ultimately, I need the Extras page content to display so I can test that the detail post page also displays. Any ideas how to tweak this?

routes:
  /: index

collections:
  /features/extras/:
    permalink: /features/extras/{slug}/
    template: tag
    filter: primary_tag:extras
    data: tag.extras
  /features/newsletters/:
    permalink: /features/newsletters/{slug}/
    template: tag
    filter: primary_tag:newsletters

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

As an FYI, I found two other anomalies.

One, I got the Extras topic to display on the Extras page by unpublishing the post and then publishing it again. Maybe there’s a database flag that was somehow not set properly, either for the tag or more likely status.

Second, I was able to use the / definition in the collections section if it is the last entry. The collections definitions appear to work like an if/elseif/else statement.

Not sure if either of these statements is accurate and canonical. But they work on my production site and dev site. And the post detail pages display from the home page and features/tag pages.

Last, here’s my routes file that works if it’s helpful to anyone. I also discovered that adding the data definition is needed to display the tag name and description at the top of each of the Newsletters and Extras pages.

routes:

collections:
  /features/extras/:
    permalink: /features/extras/{slug}/
    template: tag
    filter: primary_tag:extras
    data: tag.extras
  /features/newsletters/:
    permalink: /features/newsletters/{slug}/
    template: tag
    filter: primary_tag:newsletters
    data: tag.newsletters
  /:
    permalink: /{slug}/
    template: index

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

Had a busy week, but it looks like you figured it out!

You’re right that collections are like an if/else block - each post will try to “fall” into the first bucket it matches :slight_smile:

Yes, I figured it out thanks to your help and a hint from @Cathy_Sarisky. Grateful for the help. Now I’m free to wrestle the next problems with my website and business…

2 Likes