Skip to content

Template inheritance

croxton edited this page Nov 7, 2014 · 37 revisions

The template inheritance pattern allows you to use templates in a modular fashion. It consists of:

  • A base "view" template that contains the skeletal markup of your site and defines placeholders and blocks that child templates can override.

  • A base "viewModel" template that sets up common variables and default content, and loads child viewModel templates on demand when specific functionality is required. Child viewModules are considered to be discrete, self-contained, reusable modules.

In the following example we're using a custom field to optionally choose a 'widget' (child viewModel) to format the page content. The child vM extends the parent vM and can load it's own partial layouts into blocks, and/or overload placeholder variables in the parent view.

EE templates

work
   index.html

Stash templates

layouts    
   standard.html
viewmodels    
   page_vm.html    
   projects_vm.html    
partials
   project_list.html    
   project_detail.html    

/templates/default_site/work.html

Loads the primary viewModel, compiles and caches the rendered templates as a variable, using the page URI as the context.

{stash:embed
    context="@URI"
    name="page_vm"
    file_name="viewmodels:page_vm"
    parse_stage="both"
    stash:_status="open"
    stash:_channel="pages"
    stash:_layout="standard"
}

/stash_templates/viewmodels/page_vm.html

{stash:embed context="layouts" name="{stash:_layout}"}

{!-- capture entry data --}
{exp:channel:entries 
    channel="{stash:_channel}"
    status="{stash:_status}" 
    limit="1" 
    disable="member_data|pagination|categories"
    {if segment_2} require_entry="yes"{/if}
}
    {if no_results}
        {redirect="site/404"}
    {/if}

    {!-- standard entry fields --}
    {exp:stash:set type="snippet"}
        {stash:pg_title}{title}{/stash:pg_title}
        {stash:pg_entry_id}{entry_id}{/stash:pg_entry_id}
        {stash:pg_url_title}{url_title}{/stash:pg_url_title}
    {/exp:stash:set}

    {!-- custom entry fields --}
    {exp:stash:set type="snippet"}
        {stash:pg_intro}{page_intro}{/stash:pg_intro}
        {stash:pg_body}{page_body}{/stash:pg_body}
    {/exp:stash:set}

    {!-- load a widget (child viewModel)? --}
    {exp:switchee variable="{page_widget}" parse="inward"}
        {case value="#^S+#"}
            {!-- load the associated viewModel for the widget --}
            {exp:stash:embed 
                context="viewmodels" 
                name="{page_widget}_vm" 
                process="inline" 
                replace="yes"
            }
        {/case}
    {/exp:switchee}

{/exp:channel:entries}

/stash_templates/viewmodels/projects_vm.html

{exp:switchee variable="{segment_3}" parse="inward"}

    {!-- project listing --}
    {case value=""}

        {!-- load the project_list layout into the pg_content block --}
        {exp:stash:extend name="pg_content" with="partials:project_list"}

        {exp:stash:set_list 
            name="projects" 
            parse_tags="yes" 
        }
            {exp:channel:entries 
                channel="projects"
                status="open" 
                disable="member_data|pagination|categories"
                dynamic="no"
            }
                {stash:project_title}{title}{/stash:project_title}
                {stash:project_url_title}{url_title}{/stash:project_url_title}
            {/exp:channel:entries}   
        {/exp:stash:set_list}
    {/case}

    {!-- project detail --}
    {case default="yes"}

        {!-- load the project_detail layout into the pg_content block --}
        {exp:stash:extend name="pg_content" with="partials:project_detail"}

        {!-- get project data --}
        {exp:channel:entries 
            channel="projects"
            status="{stash:_status}" 
            limit="1" 
            disable="member_data|pagination|categories"
            url_title="{segment_3}"
            dynamic="no"
            require_entry="yes"
        }
            {if switchee_no_results}
                {redirect="site/404"}
            {/if}

            {exp:stash:set type="snippet"}

                {!-- override the heading in the main layout --}
                {stash:pg_title}{title}{/stash:pg_title}

                {!-- capture project custom fields for use in the project_detail partial --}
                {stash:project_image}{project_image}{/stash:project_image}

            {/exp:stash:set}

        {/exp:channel:entries} 

        {!-- prev/next entry links --}
        {exp:channel:next_entry
            channel="projects"
            status="{stash:_status}"
            url_title="{segment_3}"
            parse="inward"
        }
            {exp:stash:set name="project_next_url" type="snippet"}{url_title}{/exp:stash:set}
        {/exp:channel:next_entry}

        {exp:channel:prev_entry
            channel="projects"
            status="{stash:_status}"
            url_title="{segment_3}"
            parse="inward"
        }
            {exp:stash:set name="project_prev_url" type="snippet"}{url_title}{/exp:stash:set}
        {/exp:channel:prev_entry}
    {/case}
    {/exp:switchee}

/stash_templates/layouts/standard.html

    <!DOCTYPE html>
    <html>
        {sn_head}
        <body>   
            <h1>{pg_title}</h1>
            <div class="content">
            {exp:stash:block name="pg_content"}
                {if pg_intro}<p class="intro">{pg_intro}</p>{/if}
                {pg_body}
            {/exp:stash:block}
            </div>
            {sn_footer}
        </body>
    </html>

/stash_templates/partials/project_list.html

    <ul class="list list--projects">
        {exp:stash:get_list name="projects"}
        <li><a href="/{segment_1}/{segment_2}/{project_url_title}">{project_title}</a></li>
        {/exp:stash:get_list}
    </ul>

/stash_templates/partials/project_detail.html

    <img src="{project_image}" alt="">
    <a href="{project_prev}">Previous</a> | <a href="{project_next}">Next</a>
Clone this wiki locally