Escape {{get}} context in Handlebars to reference the post context

I’m working on a theme and want to add advanced tag relevancy functionality with custom ordering using internal tags. I am sadly up against a wall now - either from lack of experience of via the Ghost arbitrary restrictuions.

Initially I wanted to create the following {{#get}} expression:

{{#get "posts" filter="tags:{{tags[1].slug}}" include="tags" order="{{tags[2].slug}} asc" as |related-posts|}}
    {{#foreach related-posts}}
        {{> post-line}}
    {{/foreach}}
{{/get}}

This would return all posts, including the current one, using the first tag (which by convention would’ve been internal theme tag) whilst then ordering by the second tag (which when ordered alphanumerically would allow the users to order their posts as they want with certain degree of structure, regardless of the last date of update or creation). This has naturally failed, since ghost doesn’t allow any expressions in order. Fair play, I reversed the approach:

{{#get "tags" filter="visibility:internal+slug:~^'hash-chapter-order-'" order="slug asc" include="posts" as |related-tags|}}
    {{#foreach related-tags visibility="all" as |tag|}}
        {{#get "posts" filter="tags:{{../../tags.[1].slug}}" limit="all" as |related-posts|}}
            {{#foreach related-posts}}
                {{> post-line}}
            {{/foreach}}
        {{/get}}
    {{/foreach}} 
{{/get}}

Here, hash-chapter-order-' is the prefix of an internal tag that’s used to define order for posts with the identical tags.[1] (second tag, which is also internal), whilst ../../tags.[1].slug is supposed to represent the actual current post’ tag object. No amount of ../ escaping matters since Ghost doesn’t seem to be too happy with ../ being there in the first place.

Now, this would work, in theory, and does work if I operate within JS against Content API. However, for some unknown reason, Ghost returns an error:

IncorrectUsageError: We detected a misuse. Please read the stack trace.
"registerAsyncThemeHelper: get"

And the stack trace reads:

Error: Parse error on line 1:
    at Object.returnAsync (/ghost-cli/versions/5.79.0/core/frontend/services/helpers/handlebars.js:19:75)
../../tags[1].slug
^
Expecting 'DOLLAR', 'STAR', 'IDENTIFIER', 'SCRIPT_EXPRESSION', 'INTEGER', 'END', got 'DOT_DOT'

My question is - is there something wrong with the request and there IS a way to nest this, or did Ghost just decide that this shouldn’t be allowed because… reasons? I assume there’s a github conversation that can be read about this?

I want to ship it as a theme, therefore simply adding a helper is not viable since, if I understand correctly, these aren’t allowed to be used or “brought in” with a theme.

I would appreciate some enlightenment in this regard, because otherwise, as it stands, my only option would be to use “updated_at” for ordering an it will be incredibly disruptive since any update to a post would throw things entirely out of order in the ordered chapters navigation element I’m working on.

P.S. And yes, I tried {{#with}} and it fails with the same exact error.

Ghost does not like the …/ notation within filters. The workaround is to call a partial and pass in whatever value you need. Here’s an example of doing that:

Two other comments:

  1. tags are zero indexed. I’m not sure from what you said if that’s contributing to your problem. (So the first tag is tags[0].slug.)
  2. In your first attempt with order, you’re substituting in the value of tag 2 (which is the third tag), not ordering by tag 2. I don’t think that approach is going to work anyway (I don’t think you can order by any tag except primary tag - and I’m not 100% sure about that), but if it were to work, you’d be using it without the {{ }}, not within them.
1 Like

You. Are. Incredible.
That’s a very witty way of working around this, kudos for sharing and doing so within some 15 minutes. My lucky day! :purple_heart:

I was able to replicate this and it worked to the T. I did find one thing that I either missed in your post or you haven’t stumbled upon, so for completeness sake: Ghost doesn’t seem to work when you try to name the value you’re passing to the next partial anything that has hyphens in it, i.e. chapter-name-tag. If you d:

#sidebar-post-item.hbs

{{#get "posts" filter="tags:{{chapter-name-tag}}" limit="all" as |related-posts|}}
    {{#foreach related-posts}}
        {{> post-line}}
    {{/foreach}}
{{/get}}

Then you’ll get:

Error: Lexical error on line 1. Unrecognized text.
    at Object.returnAsync (/Users/mneveroff/Development/Web/ghost-cli/versions/5.79.0/core/frontend/services/helpers/handlebars.js:19:75)
chapter-name-tag
-------^

But the fact that it pointed at the first hyphen and not at the beginning of the expression was a quick giveaway. And sure enough, changing the name to chapterNameTag made it work.

It further doesn’t seem to work even when you try to pass the current iterated value (so just one layer):

#sidebar-post.hbs

{{#foreach order-tags visibility="internal" as |tag|}}
    {{> sidebar-post-item chapter-order-tag=tag.slug chapterNameTag=../../chapter-name-tag lazyLoad=true}}
{{/foreach}}

Above results in:

Error: Lexical error on line 1. Unrecognized text.
    at Object.returnAsync (/Users/mneveroff/Development/Web/ghost-cli/versions/5.79.0/core/frontend/services/helpers/handlebars.js:19:75)
chapter-order-tag
-------^

If it’s passed into sidebar-post-item.hbs. It’s interesting because it’s not the case with “normal” partials and usually it’s allowed, so assuming that context switching that happens with {{#get}}, {{#foreach}} and others is to blame.

Final “good” config for anyone stumbling upon this in the future:

# post.hbs

{{> sidebar-post chapter-name-tag=tags.[1].slug}}
# sidebar-post.hbs

{{#get 'tags' filter="slug:~^'hash-chapter-order-'+visibility:internal" order="slug asc" as |order-tags|}}
    {{#foreach order-tags visibility="internal" as |tag|}}
        {{> sidebar-post-item chapterOrderTag=tag.slug chapterNametag=../../chapter-name-tag lazyLoad=true}}
    {{/foreach}}
{{/get}}

and finally

# sidebar-post-item.hbs

{{#get "posts" filter="tags:{{chapterOrderTag}}+tags:{{chapterNametag}}" limit="all" as |related-posts|}}
    {{#foreach related-posts}}
        {{> post-line}}
    {{/foreach}}
{{/get}}

All credit to @Cathy_Sarisky anyways, and thanks again for an amazing blogpost.

P.S. Yeah, you’re exactly right that it’s 0-indexed, great note! From my testing first tag (index 0) can’t be internal otherwise primary-tag won’t get set (even though the docs say that it should) so by convention I’ll expect 2nd and 3rd ([1] and [2]) to be the internal chapter-name and chapter-order tags.
And entirely fair regarding {{}} in order, had to recreate that one from memory as I have re-written this piece of code for the past 5 hours and still am not 100% solid on Ghost HBS foundations.

1 Like