How to create working Breadcrumbs for Hugo? - breadcrumbs

It's unbelievable how difficult is to find solid information about slightly more advanced techniques with Hugo.
After quite a while searching I’ve found this article with a very nice way to implement breadcrumbs for Hugo.
I modified it a little bit to not add an unnecessary link to the last trail and to make use of i18n to translate the URL segments into something more human-readable. I also made a small workaround to remove some unwanted trails that doesn't match a translated entry:
{{- $url := replace .Permalink ( printf "%s" ( "/" | absLangURL ) ) "" -}}
{{- $url := replace .Permalink ( printf "%s" ( "/" | absLangURL ) ) "" -}}
{{- $.Scratch.Add "path" ( "/" | absLangURL ) -}}
{{- $.Scratch.Add "breadcrumb" (slice (dict "url" ( "/" | absLangURL ) "name" "home" "position" 1 )) -}}
{{- range $index, $element := split $url "/" -}}
{{- $.Scratch.Add "path" $element -}}
{{- $.Scratch.Add "path" "/" -}}
{{- if ne $element "" -}}
{{- $.Scratch.Add "breadcrumb" (slice (dict "url" ($.Scratch.Get "path") "name" . "position" (add $index 2))) -}}
{{- end -}}
{{- end -}}
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "BreadcrumbList",
"itemListElement": [{{ range $.Scratch.Get "breadcrumb" }}{{ if ne .position 1 }},{{ end }}{
"#type": "ListItem",
"position": {{ .position }},
"item": {
"#id": "{{ .url }}",
"name": "{{ .name }}"
}
}{{ end }}]
}
</script>
<nav class="breadcrumb">
{{- $length := len ($.Scratch.Get "breadcrumb") -}}
{{- range $index, $.Scratch.Get "breadcrumb" -}}
<!--
Assigning a constant as default value for i18n function
if it doesn't match any entry
Then check if current Breadcrumb item matches this constant,
which means that part shouldn't be one of Breadcrumb's trail
-->
{{- $i18n := i18n ( print "breadcrumbs-" .name ) | default "__INTERNAL__" -}}
{{- if not ( eq ($i18n) "__INTERNAL__" ) -}}
{{ if eq ( (int .position) ) $length }}
<span class="breadcrumb-item active">{{ $i18n }}</span>
{{- else -}}
<a class="breadcrumb-item" href="{{ .url }}" >{{ $i18n }}</a>
{{- end -}}
{{- end -}}
{{ end }}
</nav>
It works very nicely except that as far as I could notice so far while navigating through Pagination links everything starts duplicating N times as far as the Pagination Page increases (i.e twice of Page 2, thrice for Page 3 and so on).
I've searched even more and found a similar implementation in which there's no duplication... but the links are all messed up, the URL of each trail is a concatenation of all links of all trails o.O
I try to avoid asking things on Hugo's "forum" because the answers given there are most of the times hard to understand, incomplete or with "pseudo-pseudo-codes".
Does anyone know how to make this work and could lend me a hand?

From the Hugo documentation and building on Lars's answer:
Create a file named breadcrumbs.html in the folder layouts/partials of your Hugo project or theme
<ol class="nav navbar-nav">
{{ template "breadcrumbnav" (dict "p1" . "p2" .) }}
</ol>
{{ define "breadcrumbnav" }}
{{ if .p1.Parent }}
{{ template "breadcrumbnav" (dict "p1" .p1.Parent "p2" .p2 ) }}
{{ else if not .p1.IsHome }}
{{ template "breadcrumbnav" (dict "p1" .p1.Site.Home "p2" .p2 ) }}
{{ end }}
<li{{ if eq .p1 .p2 }} class="active"{{ end }}>
{{ .p1.Title }}
</li>
{{ end }}
Include breadcrumbs.html where you need it with:
{{ partial "breadcrumbs.html" . }}
This produces links (including the sections) that are all valid.

It only takes 2 steps, inspired by: http://hugocodex.org/add-ons/breadcrumbs/
Create a file named breadcrumbs.html in the folder layouts/partials of your Hugo project
<span>
Home
{{ range (split .URL "/") }}
{{ if gt (len . ) 0 }}
/ {{ humanize (replace . "posts" "blog") }}
{{ end }}
{{ end }}
</span>
Include breadcrumbs.html where you need it with:
{{ partial "breadcrumbs.html" . }}

I wrote blog post on adding breadcrumb partial for hugo with strucutred data.
Don't just show machine readable breadcrumb to search engine crawler but also show the same to user also. My blog post goes into detail on the topic.
To answer this question here is my partial for only crawlers.
{{ $url := replace .Permalink (printf "%s" .Site.BaseURL) ""}}
{{ .Scratch.Add "path" .Site.BaseURL }}
{{ .Scratch.Add "breadcrumb" (slice (dict "url" .Site.BaseURL "name" "Home"))}}
{{ .Scratch.Add "permalink" .Permalink }}
{{ .Scratch.Add "title" .Title }}
{{ $pScratch := .Scratch }}
{{ range $index, $element := split $url "/" }}
{{ $pScratch.Add "path" $element }}
{{ $pScratch.Add "path" "/" }}
{{ if ne $element "" }}
{{ if eq ($pScratch.Get "path") ($pScratch.Get "permalink") }}
{{ $pScratch.Add "breadcrumb" (slice (dict "url" ($pScratch.Get "path") "name" ($pScratch.Get "title")))}}
{{ else }}
{{ $pScratch.Add "breadcrumb" (slice (dict "url" ($pScratch.Get "path") "name" (humanize .)))}}
{{ end }}
{{ end }}
{{ end }}
<script type="application/ld+json">
[{
"#context": "https://schema.org",
"#type": "BreadcrumbList",
"itemListElement": [
{{ range $index, $breadcrumb := .Scratch.Get "breadcrumb" }}
{{ if ne $index 0 }},{{ end }}
{
"#type": "ListItem",
"position": {{ add $index 1 }},
"name": "{{ $breadcrumb.name }}",
{{ if ne $breadcrumb.url ($pScratch.Get "permalink") }}
"item": {{ printf "%s" $breadcrumb.url }},
{{ end }}
}
{{ end }}
]
}
{{ range $index, $category := .Params.categories }}
,
{
"#context": "https://schema.org",
"#type": "BreadcrumbList",
"itemListElement": [
{
"#type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{$.Site.BaseURL}}",
},
{
"#type": "ListItem",
"position": 2,
"name": "Categories",
"item": "{{$.Site.BaseURL}}categories/",
},
{
"#type": "ListItem",
"position": 3,
"name": "{{ humanize . }}",
"item": "{{$.Site.BaseURL}}categories/{{.}}",
},
{
"#type": "ListItem",
"position": 4,
"name": "{{ $pScratch.Get "title" }}",
},
]
}
{{ end }}
]
</script>

I've been forced to stop coding but since this question popped up a notification for me today, let me show what I did to solve the problem proposed in the question back there, even though I can't really explain why this happens -OR- if this still happens nowadays in newer versions of Hugo (I stopped using v0.28)
Well, after MUCH testing, I simply initialized a Template Variable with the scope of the “dot” that’s passed to the Partial Template when it's called and, in the Partial, instead of calling the Scratch from the context of the dollar-sign (or whatever it’s called in Hugo/Go) I used this variable I initialized:
list.html
{{ partial "breadcrumbs.html" . }}
partials/breadcrumbs.html
{{ $dot := . }}
{{ $dot.Scratch.Set "path" "" }}
{{ $dot.Scratch.Set "breadcrumb" slice }}
<!-- Rest of the code in the original question -->
And from them on, instead of, for example:
{{ $.Scratch.Add "path" $element }}
I used:
{{ $dot.Scratch.Add "path" $element }}
And all Pagination elements worked without duplicates.

Well, this can easily be solved by replacing.URL to .RelPermalink from Lark Blumberg's solution earlier from this timeline.
Step 1:
<div class="container" id="breadcrumbs">
Home
{{ range (split .RelPermalink "/") }}
{{ if gt (len . ) 0 }}
<i class="fas fa-chevron-right"></i>{{ humanize (replace . "posts" "blog") }}
{{ end }}
{{ end }}
</div>
Step 2:
Include breadcrumbs.html where you need it with:
{{ partial "breadcrumbs.html" . }}
For more information goto Breadcrumbs | HugoCodex

Related

Saving render result to use it again

I'm trying to build a form in my controller, my form contain two "select" options which use the same database table field "villes"
I want to to use this field twice, one time for city departure and another time for city arrival
$form = $this->createFormBuilder($vol)
->add('hor_dep')
->add('villes')
->add('villes')
->add('prix')
->add('reduc', CheckboxType::class, array('required' => true, 'label' => 'Réduction'))
->add('nbr_place')
->getForm();
but when I try to render this form.html.twig
<div class="col-lg-6">
{{ form_label(form.hor_dep,'Heure de départ') }}
{{ form_widget(form.hor_dep) }}
{{ form_label(form.villes,'Ville de départ') }}
{{ form_row(form.villes) }}
{{ form_label(form.hor_arrivee,"Heure d'arrivée") }}
{{ form_widget(form.hor_arrivee) }}
{{ form_label(form.villes,"Ville d'arrivée") }}
{{ form_widget(form.villes) }}
</div>
<div class="col-lg-6">
{{ form_label(form.prix,'Prix') }}
{{ form_widget(form.prix) }}
{{ form_label(form.reduc,'possède une réduction ?') }}
{{ form_widget(form.reduc) }}
{{ form_label(form.nbr_place,'Nombre de place') }}
{{ form_widget(form.nbr_place) }}
</div>
it throws this error
An exception has been thrown during the rendering of a template ("Field "villes" has already been rendered, save the result of previous render call to a variable and output that instead.").
In your case, you have to add two fields in your formType: villeDepart & villeArrivee (like what you did with the heure) because you don't want the first form field be overwritten by the second one.
In your mapping, the two fields will point to the same villes table, but each one will have a different value.

Is there a way to yield to variable section in statamic?

I have a layout with several identical columns which should yield to respective sections:
<div class="column_1">
some column content here
{{ yield:column_1 }}
some more column stuff
</div>
<div class="column_2">
some column content here
{{ yield:column_2 }}
some more column stuff
</div>
...
Now I would like to put that into its own partial:
****** LAYOUT ******
{{ partial:column column_name="column_1" }}
{{ partial:column column_name="column_2" }}
...
****** PARTIALS/COLUMN.HTML ******
<div class="{{ column_name }}">
some column content here
{{ yield to-section="{column_name}" }}
some more column stuff
</div>
****** TEMPLATE *****
{{ section:column_1 }} **Additional stuff for column 1** {{ /section:column_1 }}
{{ section:column_2 }} **Additional stuff for column 2** {{ /section:column_2 }}
But in the documentation I can only find the colon syntax {{ yield:section }} and no hint to a possible variable syntax {{ yield unknown_word_here="section" }}. Most tags have a variable syntax, so I am hoping there is one. Or another solution...
I believe you're looking for the Section tag, which pairs nicely with the Yield tag.

How define textarea content on form edit (Symfony2/TWIG)

I want to display a specific content in my editForm textarea so I try like text field but it doesn't work :
{{ form_widget(edit_form.description, { 'attr': {'value': 'content'} }) }} {{ form_errors(edit_form.description) }}
How can I do it in TWIG ?
This should work according to the doc.
{{ form_widget(edit_form.description, { 'value': 'content'}) }} {{ form_errors(edit_form.description) }}
But I've never tested it.

Collection Type Field with a File Field to generate their own respective download link

I having a problem with getting/generating the download link from a Collection Type Field in a form, inside the collection type I have a File Field. Everything works fine with uploading files but in order to generate their own respective download link is where I'm stucked right now.
Is there any way to get the url from the file field? What can I do?
<ul>
<li><ul class="preguntas" data-prototype="{{ form_widget(form.seguimientos.vars.prototype)|e }}">
{% for pregunta in form.seguimientos %}
<li>
{{ form_row(pregunta.seguimientoTipo) }}
{{ form_row(pregunta.fecha_entrega) }}
{{ form_row(pregunta.fecha_prorroga) }}
{{ form_row(pregunta.descripcion) }}
{{ form_row(pregunta.loQueSeEspera) }}
{{ form_row(pregunta.isRecibido) }}
{{ form_row(pregunta.contactos) }}
{{ form_row(pregunta.comentarios) }}
{{ form_row(pregunta.archivo) }}
</li>
{% endfor %}
</ul></li>
This is what I got with {{ dump(pregunta.archivo.vars.value) }}
object(Proxies\__CG__\daci\contratosBundle\Entity\Document)#596 (5) { ["__isInitialized__"]=> bool(true) ["id":protected]=> int(160) ["path":protected]=> string(44) "1feb865f404cba0567e075c76bf6c0b402621e8e.png" ["file":"daci\contratosBundle\Entity\Document":private]=> NULL ["temp":"daci\contratosBundle\Entity\Document":private]=> NULL }
What I want to get is "path" from the object and create the download link
To access to the field I just needed to use {{ pregunta.archivo.value.path }}
From that I created the download link

FOSUserBundle issues with plainPassword on twig form

I am defining my own twig layout for new user registration and I have everything laid out the way I want it with the exception of the plainPassword field from the FOSUserBundle.
<p class="left">
{{ form_widget(form.plainPassword) }}
</p>
<div class="clearfix"></div>
The code above displays both the password and verification block. I would like to break this up into the 4 elements of form.plainPassword.label, form.plainPassword.field, form.plainPassword2.label, and form.plainPassword2.field. I cannot figure out what to put in the form_label() and form_widget() calls.
<p class="left">
{{ form_label( ??? ) }}
{{ form_widget( ??? ) }}
</p>
<p class="left">
{{ form_label( ??? ) }}
{{ form_widget( ??? ) }}
</p>
<div class="clearfix"></div>
I am assuming this can be done.
I had the same problem. My solution (seems to be official :) :
{{ form_label (form.plainPassword.first) }}
{{ form_widget (form.plainPassword.first) }}
{{ form_label (form.plainPassword.second) }}
{{ form_widget (form.plainPassword.second) }}
Hope it can helps !
This blog post shows how to output a repeated field in twig.
http://blogsh.de/2011/10/19/how-to-use-the-repeated-field-type-in-symfony/
But in short this worked for me:
{{ form_label (form.plainPassword.children['New Password']) }}
{{ form_widget (form.plainPassword.children['New Password']) }}
{{ form_label (form.plainPassword.children['Confirm Password']) }}
{{ form_widget (form.plainPassword.children['Confirm Password']) }}
I have to say I'm sure using .children isnt the best/official way of doing it, but it works!