Hugo: .Site.BaseURL is not available in one context, but not another

Created on 28 Dec 2014  Â·  11Comments  Â·  Source: gohugoio/hugo

Getting the error: "BaseURL is not a field of struct type *hugolib.SiteInfo" when I use it in one template, as such:

{{ partial "header.html" . }}

<h1><a href="{ .Site.BaseURL }}/artists/{{ .Params.artistdirectory }}">{{ .Params.artistname }}</a> - {{ .Params.releasename }}</h1>
Released: {{ .Params.releaseyear }}<br />
{{ .Content }}

But in this peer template, it works fine:

{{ partial "header.html" . }}

        <h1>{{ .Params.artistname }}</h1>
        {{ .Content }}

        {{ if isset .Params "albums" }}
            <h1>Releases</h1>
            {{ range index .Params "albums" }}
                <a href="{{ .Site.BaseURL }}/releases/{{ .catalogid }}">{{ .name }}</a>
            {{ end }}
        {{ end }}

{{ partial "footer.html" . }}

The only thing I can think of is that for some reason, it isn't available in the higher context, but it the deeper one.

Most helpful comment

Hey,

This is Go templates, and I doubt there is a bug in there about this, but it's hard to test your case without a complete sample (test project).

I have experienced this myself, and I'm pretty sure this is related to some "template oddities" I've experienced myself. I will take an commented example of "wrong", "looks right" and "is right":

Wrong:

{{ with .Params.myparam }}
{{ .Site.BaseURL }} // the "." is now at myparam so this will fail
{{ partial "mypartial.html" . }} // again, wrong "." sent in param to partial
{{ end }}

Looks right:

{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $ctx.Site.BaseURL }} // this should work fine
{{ partial "mypartial.html" . }} // easy to miss
{{ end }}

Is right:

{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $ctx.Site.BaseURL }}
{{ partial "mypartial.html" $ctx }}
{{ end }}

Another pitfall that took me some time to figure out (that I have a pull request in to compensate for, see #746), is the visibility of variables:

{{ $var := 1 }}
{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $var := 2 }}
{{ partial "mypartial.html" $ctx }} // $var will not be available to mypartial.html 
{{ end }}
{{ $var }} // => 1

@anthonyfok some of these common pitfalls should have a place in the documentation. I'm not sure that all of the above is 100% runnable code, but it shows the point.

All 11 comments

It's available in the top level context (Node or Page), so you're correct - it's not available in others, but that is by design, but can be a little bit confusing -- basically the dot pointer (".") has changed.

In some cases doing {{ $baseUrl := .Site.BaseURL }} and then use $baseUrl later on may clear some confusion.

It's a little bit hard to see what's going on in your samples, I would suspect the latter example to fail...

Thanks for your help! Unfortunately, I'm still not sure why this isn't a bug.

In both cases these are from single.html templates in peer directories in layout. I'm not sure how they have different contexts.The latter example works fine, the former fails. In the latter example, isn't that the Node context?

I will check your samples later, I put the "question" label on this because this works fine for me.

The latter (as the last) example, you're in the "param" context -- and hence I would expect the .Site.BaseURL not to be available.

But I hear what you say, and will check it out. But you would have to admit that the title of this issue is confusing.

ok, this gets weirder. I just updated that template that was working and now I get an on the first use of .Site.BaseURL, but if I remove it then no error on the second usage. Why would a more limited context (inside the if and range blocks) have access to a "global" scoped variable that is not accessible in the top-level scope?

{{ partial "header.html" . }}

        <h1>{{ .Params.artistname }}</h1>
        <img src="{{ .Site.BaseURL }}/img/{{.Params.image}}">
        {{ .Content }}

        {{ if isset .Params "albums" }}
            <h1>Releases</h1>
            {{ range index .Params "albums" }}
                <a href="{{ .Site.BaseURL }}/releases/{{ .catalogid }}">{{ .name }}</a>
            {{ end }}
        {{ end }}

        {{ if isset .Params "artistlinks" }}
            <h1>Links</h1>
            {{ range .Params.artistlinks }}
                <a href="{{ .url }}">{{ .name }}</a> 
            {{ end }}
        {{ end }}

{{ partial "footer.html" . }}

FWIW, I tried adding "{{ $baseUrl := .Site.BaseURL }}" into the template and got the same error that it isn't a field of the struct. If I add it into "header.html" it works, but if I try to reference $baseUrl where I tried to reference .Site.BaseURL I get an error saying that I have an incomplete template.

And adding {{ $baseUrl := .Site.BaseURL }} in header.html is bad why?

it works in the header, but when I reference it from the template that includes the header as a partial, I get an error from hugo that i have an incomplete template.

Hey,

This is Go templates, and I doubt there is a bug in there about this, but it's hard to test your case without a complete sample (test project).

I have experienced this myself, and I'm pretty sure this is related to some "template oddities" I've experienced myself. I will take an commented example of "wrong", "looks right" and "is right":

Wrong:

{{ with .Params.myparam }}
{{ .Site.BaseURL }} // the "." is now at myparam so this will fail
{{ partial "mypartial.html" . }} // again, wrong "." sent in param to partial
{{ end }}

Looks right:

{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $ctx.Site.BaseURL }} // this should work fine
{{ partial "mypartial.html" . }} // easy to miss
{{ end }}

Is right:

{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $ctx.Site.BaseURL }}
{{ partial "mypartial.html" $ctx }}
{{ end }}

Another pitfall that took me some time to figure out (that I have a pull request in to compensate for, see #746), is the visibility of variables:

{{ $var := 1 }}
{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $var := 2 }}
{{ partial "mypartial.html" $ctx }} // $var will not be available to mypartial.html 
{{ end }}
{{ $var }} // => 1

@anthonyfok some of these common pitfalls should have a place in the documentation. I'm not sure that all of the above is 100% runnable code, but it shows the point.

Thanks for your continuing help. At the moment I am just working around this so that I can finish the project I am working on. Once that is done, I will try to clean this up and either come back with a better case I can put on github or I will figure out what my mental block is with Go scoping rules :)

Warning: may contain auto-correct frijoles.

On Jan 5, 2015, at 11:16 AM, Bjørn Erik Pedersen [email protected] wrote:

Hey,

This is Go templates, and I doubt there is a bug in there about this, but it's hard to test your case without a complete sample (test project).

I have experienced this myself, and I'm pretty sure this is related to some "template oddities" I've experienced myself. I will take an commented example of "wrong", "looks right" and "is right":

Wrong:

{{ with .Params.myparam }}
{{ .Site.BaseURL }} // the "." is now at myparam so this will fail
{{ partial "mypartial.html" . }} // again, wrong "." sent in param to partial
{{ end }}
Looks right:

{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $ctx.Site.BaseURL }} // this should work fine
{{ partial "mypartial.html" . }} // easy to miss
{{ end }}
Is right:

{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $ctx.Site.BaseURL }}
{{ partial "mypartial.html" $ctx }}
{{ end }}
Another pitfall that took me some time to figure out (that I have a pull request in to compensate for, see #746), is the visibility of variables:

{{ $var := 1 }}
{{ $ctx := . }}
{{ with .Params.myparam }}
{{ $var := 2 }}
{{ partial "mypartial.html" $ctx }} // $var will not be available to mypartial.html
{{ end }}
{{ $var }} // => 1
@anthonyfok some of these common pitfalls should have a place in the documentation. I'm not sure that all of the above is 100% runnable code, but it shows the point.

—
Reply to this email directly or view it on GitHub.

OK, please reopen this or open another issue when that time comes.

Is it possible that this issue is related to a {{partial "location" .SomeVariable}}.. and then from within the partial, $.Site or .Site is not available anymore ? Passing {{partial "location" . }} keeps the same variables within the partial, but anything other than . as a second parameter will "out-scope" variables, $. included.

I've hit an issue that seems like this one, can you confirm my understanding ? If it is such, I'll add some docs to https://gohugo.io/templates/partials/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tjamet picture tjamet  Â·  3Comments

mumblecrunch picture mumblecrunch  Â·  3Comments

crash-dive picture crash-dive  Â·  3Comments

chrissparksnj picture chrissparksnj  Â·  3Comments

bep picture bep  Â·  3Comments