2

I am puzzling the best way to implement hero images per 'section' of a site. I can set a global default hero image no problem. But I want to set one header image for the root and children of a particular section. I can't use url segments as the site is multi-lingual and it will change.

I've tried detecting the root of the current structure to base my template code on.

{% set rootEntry = entry.getAncestors().first() %}

But this returns null - like there is no model returned.

UPDATE: NO answer yet but a repharasing of the question. IN order to do this you need to get the top level entry based on where you are in the site structure/tree. This link Building a nav from the top level page of a structure demonstrates great working code.

However the assumption in the above posts and many others is that the structure is built out of the actual entry pages themselves.

I have two structures. Pages and menus. The menu structure has related entry fields that 'point' to the pages.

So in in my scenario the menu structure is built out of related entry fields - not the entry being viewed. Hence, the reasons getAncestors was not working was because it was taking the existing entry a visitor was viewing and looking for a hierarchy structure that was flat.

So the question is now more complex - how do you get the top level tree branch of your structure menu based on the current entry viewed when that current entry is a related entry field in your structure menu? It seems very complicated to achieve. Especially just for flexible headers per sections....

FINAL UPDATE Thanks Mats - i couldn't have done this without your diligent replies. Below is my final solution to find out what the top level root is. It is expressed as sub navigation for structure menu but it does two things - build s the sub nav and identifies the root of the tree where you are. NB macro is used for active links.

{# Get the sidebar structure subnavigation #}
{# check for entry so channels do not break #}
{% if entry is defined %}
    {% set navEntry = craft.entries.section('menu').relatedTo({
    targetElement: entry,
    field: 'entryLink'
    }).first() %}

    {# get the root entry of the structure set to null if we are at top #}
    {% set root = navEntry ? craft.entries.ancestorOf(navEntry).level(1).first() : null %}

    {# setup variables in switch for ouput of heading and sub links#}
    {% switch root %}
        {% case null %}
            {% if navEntry.hasDescendants() %}
                {% set heading = navEntry.title %}
                {% set thisSubMenu = craft.entries.descendantOf(navEntry) %}
            {% endif %}
            {% set rootEntry = navEntry %}
        {% case true %}
            {% set heading = root.title %}
            {% set thisSubMenu = craft.entries.descendantOf(root) %}
            {% set rootEntry = root %}
    {% endswitch %}
{% endif %}

{% if heading is defined %}
    <h3>{{ heading }}</h3>
{% endif %}

{# Get entries to build the sub-menu #}
{% if thisSubMenu is defined %}
{% set subMenu = thisSubMenu %}
<ul>
    {% for entry in subMenu %}

        {% if entry.entryLink.first|length %}

            {% set subNavLink = entry.entryLink.first().uri %}

        {% elseif entry.customMenuUrl|length %}

            {% set subNavLink = entry.customMenuUrl %}

    {% endif %}
    <li>
        <a  href="{{ siteUrl }}{{ subNavLink }}" class="{{ macros.isActiveChildClass(entry.slug) | trim }} level{{ entry.level }}">{{ entry.title }}</a>
    </li>
    {% endfor %}
</ul>

{% endif %}

1

Something like this should do the trick (obviously, change navStructureHandle and entriesFieldHandle to real values):

{# Get the related nav entry for the current entry being viewed #}
{% set navEntry = craft.entries.section('navStructureHandle').relatedTo({
    targetElement: entry,
    field: 'entriesFieldHandle'
}).first() %}

{# Get the root (top level parent) structure entry for the nav entry #}
{% set rootEntry = navEntry ? craft.entries.ancestorOf(navEntry).level(1).first() : null %}

{# If a root entry was found, print out the title #}
{% if rootEntry %}
    <span class="nav-header-title">{{ rootEntry.title }}</span>
{% endif %}

With the above, rootEntry will be null if the current entry doesn't have a related nav structure entry, or if a top level parent can't be found for the nav entry (i.e. the nav entry is top level).

I wouldn't worry too much about the performance with the above, but if you do feel it's too complex for printing a header, you could consider using the Preparse plugin instead. Preparse basically lets you create a custom field containing Twig code that will be parsed whenever the entry is saved. This basically lets you "cache" the result of costly Twig operations to a plain text, custom field on an actual entry.

Using Preparse, you could add a field called navHeaderTitle to your child entries (i.e. not the nav section). The field should contain the Twig code above, in addition to actually printing out the rootEntry title if a root entry is found (note that it's a good idea to wrap the whole thing in a {% spaceless %} tag pair):

{% spaceless %} 
    {% set navEntry = craft.entries.section('navStructureHandle').relatedTo({
    targetElement: entry,
    field: 'entriesFieldHandle'
}).first() %}
    {% set rootEntry = navEntry ? craft.entries.ancestorOf(navEntry).level(1).first() : null %}
    {{ rootEntry ? rootEntry.title }}
{% endspaceless %}

Then, you could simply do something like this in your template:

{# No need to pull any entries; just test for the `navHeaderTitle` field #}
{% if entry.navHeaderTitle %}
    <span class="nav-header-title">{{ entry.navHeaderTitle }}</span>
{% endif %}

Of course, the caveat with the Preparse approach is that if you ever change your root entry's title, you'll have to re-save all your child entries in order to re-parse the Twig and update the entries' navHeaderTitle value.

A good compromise could be to use Preparse, but echo out the root entry ID instead of the title – then you could do this in your template:

{% set rootEntry = entry.navHeaderEntryId ? craft.entries.id(entry.navHeaderEntryId).first() : null %}
{% if rootEntry %}
    <span class="nav-header-title">{{ rootEntry.title }}</span>
{% endif %}
  • Nope that's still null too .....Mmmmm – joomkit Jul 13 '16 at 13:25
  • In a child entry template, that should definitely work, so there's something else going on. We're talking about a Structure section here, right? Not a Channel with an Entries field? You're also 100% sure that you're testing this on a child template, not the actual root/top level entry? – Mats Mikkel Rummelhoff Jul 13 '16 at 13:32
  • Definitely a structure. I was putting this in an included file base ->includes/header.html site extends base but i just tried it all over and i still get null..... – joomkit Jul 13 '16 at 13:42
  • Right, then I don't know. Just tested the above code and it works on my end. – Mats Mikkel Rummelhoff Jul 13 '16 at 13:43
  • Is the top level entry disabled, perhaps? – Mats Mikkel Rummelhoff Jul 13 '16 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.