Ghost: Navigation URL and Current Handlebar helpers inconsistent results

Created on 19 Apr 2015  路  20Comments  路  Source: TryGhost/Ghost

When using @blog.navigation directly (outside of a navigation.hbs partial) the {{url}} and {{current}}} handlebars helpers do not work correctly.

When using the {{navigation}} template driven helper to pull in the navigation.hbs partial the {{url}} and {{current}}} handlebars helpers work as expected.

Both cases iterated over the navigation items using {{#foreach navigation}}. In both cases {{label}} worked as expected.

Tested this on index.hbs, page.hbs, post.hbs.

bug help wanted server / core themes / frontend

All 20 comments

@matt-d-rat Would love to hear what the use case is here, it's always easier to solve problems when we understand how and why people are using things in ways we don't expect :)

In short, I can totally see from a user perspective that this behaviour is odd, however from a technical perspective it is expected. This is because the {{navigation}} helper is doing magic behind the scenes to make those helpers work.

The difference here is that using the {{navigation}} helper does extra leg work to calculate dynamic properties like {{current}} whereas using @blog.navigation directly gives you access to the raw data from the form.

The {{url}} helper is a bit of an anomaly here, and something that we definitely need to fix. The weird behaviour here is in part related to #4989. Making the current helper work without using the navigation helper is considerably more tricky, hence being interested in the 'why' :)

@ErisDS thank you for your reply. The use case I have is that I need to output the navigation container slightly differently for the index page compared to other pages. Ideally I would prefer to include the navigation container in the navigation.hbs partial and use some sort of helper to determine whether I am on the index page or another page etc.. so I can toggle the relevant attributes and classes for this case.

I settled on just having the navigation links themselves in the partial, but this means I get significant code duplication for the navigation container for where this is output, which is not ideal.

Hey @matt-d-rat thanks for coming back and updating the issue :+1:

Ideally I would prefer to include the navigation container in the navigation.hbs partial and use some sort of helper to determine whether I am on the index page or another page etc..

Does the is helper not solve this for you? Let me know!

@ErisDS I completely missed the is helper. I will give this a go tonight and report back.

Thanks for your previous explanation though, I understand from a technical perspective why this is happening now, was just a bit of a weird user experience given that the {{label}} helper worked as expected in both cases, but the {{url}} and {{current}} didn't.

I just ran into this same issue. Our use case is that we have 2 types of navigation, mobile and desktop that have different structure. We can't support both of them through the navigation helper unless we were able to pass extra information into the helper (my original thought was {{navigation mobile="true"}}) so I was going to tackle this using the @blog.navigation variable, but found these problems and did a search for any solutions.

@phated very interesting! Out of interest, how would using the @blog.navigation data outside of the {{navigation}} template help in your case over having both inside? I'm thinking you could change the navigation template to output both structures and hide one or the other using CSS. Even if you had to output them twice, the overhead would be minimal.

It seems to me that there's definitely a case for allowing the passthrough of attributes, like the suggestion of mobile=true. I can also imagine having header=true and footer=true to output slightly different information for header and footer navigation. I believe handlebars partials supports this, so making our navigation helper support it would be pretty natural I think.

@ErisDS ha, I actually didn't even think about using 2 iterations to create the disjoint navigation menus. That should work for my use case, but I like your other use cases for passing values through. Handlebars supports that through an options property called hash; do you think that could be used to extend the locals for the navigation partial?

@phated @ErisDS +1 for being able to pass attributes through, that would make the code a lot cleaner.

Although outputting two sets and hiding one with CSS is an option, I prefer to keep the DOM as lightweight as possible, and avoid rendering nodes in the first place if they are never going to be used.

Same issue for me.
I also discovered is helper now. Very interesting but I finally used the solution proposed including all navigation links and showing or not depending on the container class via CSS.

probably I have the same issue, or something like that.
My case I write {{> "navigation"}} in index.hbs. It doesn't work, but if I change {{navigation}} to {{@blog.navigation}} in navigation.hbs, then it work. But the {{url}} return /

Sorry my bad english.

{{> "navigation"}} is incorrect. To use the navigation helper, you need to call {{navigation}}. You do not need to specify a navigation.hbs partial unless you want to change the default output, in which case you should base your partial on the default one in Ghost: https://github.com/TryGhost/Ghost/blob/master/core/server/helpers/tpl/navigation.hbs

As my issue #8972 was closed as duplicate of this one, are we going to get any kind of resolution in foreseeable future, please? Thanks.

@rbukovansky can you provide a full reproduction case with code? I'm not sure what the problem you described in #8972 actually was.

@ErisDS this is still an issue. In footer.hbs run this

               {{#foreach @blog.navigation}}
                        <li class="nav-{{slug}}{{#if current}} nav-current{{/if}}" role="presentation">
                            <a href="{{url}}">{{{label}}}</a>
                        </li>
                    {{/foreach}}

All navigation items are printed with labels but url is equal to the base url.
We need the {{url}} in this block to render correct links.

this is still an issue.

This issue hasn't been closed, that's usually a good indication that everyone knows it's still an issue so there's no need to ping people 馃槈

In footer.hbs run this

@mordka What you are suggesting to run has been explicitly called out as not supported at the beginning of this issue. You need to use the {{navigation}} helper and use the {{current}} and {{url}} helpers inside of navigation.hbs for them to work.

What's stopping you from using the {{navigation}} helper?

Hi @kevinansfield thanks for looking at this. I emphasized it's still an issue because it's been for 3 years around.
I can't use {{navigation}} because as previous posters and how it's explained in #8972 I'm trying to list navigation items in other parts of the website in a different form and purpose. Maybe it's hacking the blog system but I expected the core to have persistent behaviour and I find this as a flaw.
Not a priority, I can workaround this by hardcoding few things but wanted to share the use case scenario.

From my understanding, the issue is basically that the navigation helper is itself a function of @blog.navigation and some extra logic concerning what page user is on. So just using the former isn't enough.

The current workaround is to put logic in navigation.hbs that will conditionally render depending on its' context, by using {{#is}}.


To avoid the workaround, the proposed use case is changing or add an API to allow exposing both the current navigation data and the extra logic.

One solution discussed is to pass through the hash to the navigation.hbs template so the current workaround is more powerful (ie. {{navigation my_signal="true"}}).

Another solution I was thinking of is to expose the extra logic part directly by expanding navigation into an optional block helper, with a similar API as other block helpers for accessing nested attributes (such as {{#author}{{/author}}, basically just a proxy to with)

{{#navigation}}
  {{! Now current context is the properly calculated navigation list }}
  {{#foreach this}}
    <li class="nav-{{slug}}{{#if current}} nav-current{{/if}}" role="presentation">
        <a href="{{url}}">{{{label}}}</a>
    </li>
  {{/foreach}}
{{/navigation}}

Let me know what you think and if it addresses the use cases and open for API iteration of course. Otherwise I can setup a PR for this as it shouldn't be too involved.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

2 weeks ago I took another good look at this issue. The refactor needed to make the behaviour between @site.navigation and the {{navigation}} helper the same is fairly complex, which is why this issue is still open almost 4 years later. I still don't see that there's a particularly clear path to it right now.

In Ghost 2.17 we added the ability to pass attributes to the {{navigation}} and {{pagination}} so that it's possible to do {{navigation header=true}}, which will solve the main use case here, allowing for different markup in different locations.

We are also experimenting with adding a link helper to handle the concept of "current". I think between these features, we'll have enough to cover most use cases. I'll close this issue once the link helper goes in.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  3Comments

RadoslavGatev picture RadoslavGatev  路  3Comments

krokofant picture krokofant  路  3Comments

PaszaVonPomiot picture PaszaVonPomiot  路  3Comments

rishabhgrg picture rishabhgrg  路  3Comments