Saturday, November 8th, 2008 (updated 16 Oct ’14)

adam@engaging.net | Brighton, England

Single-template ExpressionEngine site for Websiteforall

 
O

ne of the virtues of many sites recently designed by the Brighton-based creative web agency Websiteforall is that they are comprised of just one page (see for example the award-winning Love’s Restaurant). The new Websiteforall portfolio site is in that tradition, taking the visitor immediately to the heart of matters with a thumbnail list of client sites on the left and a focus on one of those sites to the right. This article explains how that setup is deployed in ExpressionEngine using a single template.

  • Sector
  • Service

Normally, pages within web sites can be classified as either single-entry or multiple-entry. Although Websiteforall is different in that all pages appear to be more or less the same, with multiple entries on the left and a single entry on the right, the key insight for deploying ExpressionEngine elegantly here was that there are indeed two types of pages, even if there appears not to be. One type is single-entry, the other is a categories listing. It’s just that seamless navigation between the two page types requires a little bit of EE magic.

The Header Title

First an overview courtesy of the EE tags within the header title:

<title>
 {if segment_1 != ""}
 {if segment_2 == ""}
 {exp:weblog:entries weblog="clients" limit="1" 
 disable="categories|category_fields|custom_fields|member_data|pagination|trackbacks"}
 {title} : 
 {/exp:weblog:entries}
 {/if}
 {if segment_2 != ""}
 {exp:weblog:category_heading weblog="clients"}{if plural}{plural}{if:else}{category_name}{/if} : {/exp:weblog:category_heading}
 {/if}
 {/if}
 websiteforall : creative web agency, Brighton UK
</title>

Starting with the first line, if the URL’s segment #1 is empty then we’re on the homepage and can exit the conditional. If however segment #1 does contain something then we next check whether segment #2 is empty. If it is then we’re on a single-entry page and run EE’s weblog:entries tag (with all options disabled to improve performance) to display the entry’s title followed by a colon. If however segment #2 is not empty then we’re on a categories page and run EE’s category_heading tag. These then are the three types of pages in the site: the homepage, a single-entry or a categories page.

There are two category groups, Locations and Services, but only Services get their own page, a listing of all entries with that service checked. For this to work, Use Category URL Titles In Links? is set to “Yes” and the Category URL Indicator is changed from the default “categories” to “services”.

Note that in the category_heading tag the field plural is displayed unless it’s empty, in which case the category name is displayed. The plural category field is for services that should be named differently in the plural; “logo” becomes “logos” but “web design” stays as is.

The Right Side

The title header is not the only part of the template that handles all three types of page on the site. The right side also works whether the visitor is on the homepage, a single-entry or a categories page:

{exp:weblog:entries weblog="clients" limit="1" disable="member_data|pagination|trackbacks" url_title="{segment_3}" } 
<div class="container">
 <div class="clientid">
  <h1>{if clients_url}<a target="_blank" href="http://{clients_url}">{/if}{title}{if clients_url}</a>{/if}</h1>
 </div>
 <div class="rightclient"> 
  <div class="clientinfo">
   <p>{if clients_business}{clients_business}, {/if}{categories show="not 16|17|22" show_group="3" backspace="1"}{category_name}, {/categories}</p>
   {if clients_url}<a target="_blank" href="http://{clients_url}">{clients_url}</a>{/if}
  </div>
  {if clients_testimonial}
   <div class="clienttestimonial">
    <p><img src="{site_url}img/quoteopen.png" width="22" />{clients_testimonial}<img src="{site_url}img/quoteclose.png" width="22" /></p>
   <p class="client-name">{if clients_url}<a target="_blank" href="http://{clients_url}">{/if}{clients_author}{if clients_url}</a>{/if}</p>
  </div><!-- /clienttestimonial -->
  {/if}
  <div class="services">
   <h3>what we did for {title}</h3>
   <p>{categories show="not 4|6|50|53" show_group="1" backspace="1"}{if segment_2 != category_url_title}<a href="{path=/}{if segment_3 ==">{/if}{category_name}{if segment_2 != category_url_title}</a>{/if}, {/categories}</p>
  </div>  
  <div class="clientbranding">
   <div class="selector">
    {if clients_logo && clients_business_card}
    <ul id="branding" class="shadetabs">
     {if clients_logo}<li><a href="#" rel="logo" class="selected">logo</a></li>{/if}
     {if clients_business_card}<li><a href="#" rel="businesscard">business card</a></li>{/if}
    </ul>
    {/if}
   </div>  
   {if clients_logo}<div id="logo"><img src="{clients_logo}" width="240" /></div>{/if}
   {if clients_business_card}<div id="businesscard"><img src="{clients_business_card}" width="240" /></div>{/if}
  </div>
 </div><!-- /rightclient -->
 {if clients_screenshot}
 <div class="screen">
  {if clients_url}
  <a target="_blank" href="http://{clients_url}">{/if}<img src="{clients_screenshot}" width="340" border="0" />{if clients_url}</a>
  {/if}
 </div>
 {/if}
</div><!-- /container -->
{/exp:weblog:entries}

This is where the magic is — in the parameters of the weblog:entries tag. The url_title parameter is set to contain the contents of segment #3. This of course only works if we indeed have a segment #3, that is, if we’re on a services page. Service pages always have a fixed URL structure: segment #1 is “services”, segment #2 is the url_title of the particular service, and segment #3 is the url_title of the client to feature on the right. But what if there is no segment #3? The url_title parameter is empty, therefore ignored, and the tag falls back to its default behavior, which is to treat the final segment in the URL as the url_title. If we have a segment #1 then we’re on a single-entry page and the entry corresponding to the url_title in segment #1 is displayed. If however segment #1 is also empty, then the limit parameter ensures that only one client is featured on the right, that is, the latest one — or any that is set as sticky.

Most of the remaining conditionals in the right side simply control whether to display various fields — logo, business card, screenshot, url — depending on whether they are empty for this particular entry. Both services (category group 1) and locations (category group 3) are displayed with hardcoded suppression of their top-level categories.

Under “what we did”, the entry’s services are displayed using the categories tag. If the service’s url_title appears in segment #2 of the URL — that is, if we’re on the service’s own page — then there is no link to it. Because we’re within the categories tag, EE automatically adds segments #1 and #2 to any links, with segment #1 being the reserved Category URL Indicator (“services”) and segment #2 the category’s url_title. Within the conditional is another that tests whether to set the link’s segment #3 as the contents of the current URL’s segment #1 if the current page is a single-entry one or as the current URL’s segment #3 if we’re on a services page.

The Left Side

The left side is quite different depending on our current page type.

{if segment_2 == ""}
<h1>our clients</h1>
<div class="selectorclient">
 <ul id="clients" class="shadetabs">
  <li><a href="#" rel="uk" class="selected">UK</a></li>
  <li><a href="#" rel="france">France</a></li>
  <li><a href="#" rel="belgium">Belgium</a></li>
 </ul>
</div>
<div id="uk">
 <ul class="thumb">
  {exp:weblog:entries weblog="clients" dynamic="off" category="16" limit="99" orderby="title" sort="asc" sticky="off"}
  <li {switch="||class='last'"}>{if segment_1 != url_title}<a href="{path=/}{url_title}">{/if}<img src="{clients_thumbnail}" alt="{title}" border="0" />{title}{if segment_1 != url_title}</a>{/if}</li>
   {/exp:weblog:entries}
 </ul>
</div>
<div id="france">
 <ul class="thumb">
  {exp:weblog:entries weblog="clients" dynamic="off"  category="17" limit="99" orderby="title" sort="asc" sticky="off"}
  <li {switch="||class='last'"}>{if segment_1 != url_title}<a href="{path=/}{url_title}">{/if}<img src="{clients_thumbnail}" alt="{title}" border="0" />{title}{if segment_1 != url_title}</a>{/if}</li>
   {/exp:weblog:entries}
 </ul>
</div>
<div id="belgium">
 <ul class="thumb">
  {exp:weblog:entries weblog="clients" dynamic="off"  category="22" limit="99" orderby="title" sort="asc" sticky="off"}
  <li {switch="||class='last'"}>{if segment_1 != url_title}<a href="{path=/}{url_title}">{/if}<img src="{clients_thumbnail}" alt="{title}" border="0" />{title}{if segment_1 != url_title}</a>{/if}</li>
  {/exp:weblog:entries}
 </ul>
</div>
{/if}

If segment #2 is empty — that is, if we’re on the homepage or a single-entry page, then we display our clients by country. Since it’s unlikely that Websiteforall will spread to dozens more countries in the very near future, country listings are handled only semi-automatically in that each has its own weblog:entries tag filtered using the category parameter with that particular country’s category_id hardcoded in (we can’t use EE’s out-the-box category_archives tag because it doesn’t handle custom fields). If the number of countries suddenly explodes we can automate things by looping through all the entries in the country category group and within that loop embed each one’s weblog:entries tag in a sub-template — though then we could no longer claim a single-template deployment.

If segment #2 is not empty and — just to double-check — segment #1 is “services”, then we’re on a categories page:

{if segment_1 "services"}
<h1><a href="{path=/}{segment_3}">our clients</a> / {exp:weblog:category_heading weblog="clients"}{if plural}{plural}{if:else}{category_name}{/if}{/exp:weblog:category_heading}</h1>
<div id="uk">
 <ul class="thumb">
  {exp:weblog:entries weblog="clients" orderby="title" sort="asc" 
  disable="member_data|pagination|trackbacks" sticky="off"}
  <li {switch="||class='last'"}><a href="{path=/}services/{segment_2}/{url_title}"><img src="{if segment_2  " alt="&#123;title&#125;" border="0" /&gt;&#123;title&#125;&lt;/a&gt;&lt;/li&gt;
  &#123;/exp:weblog:entries&#125;
 &lt;/ul&gt;
&lt;/div&gt;  
&#123;/if&#125;

Here the word “our clients” in the h1 is now a link to a single-entry client page. We bring along into segment #1 the magic ingredient: the entry currently in segment #3 and displayed on the right. So upon clicking here the left side will change from the current category to a list of clients, but the right side will stay the same, providing continuity.

If we haven’t clicked and are still here, next is the category_heading tag to display the current service, with the conditional for the plural field just like in the header title.

The next tag is weblog:entries which, because we’re on a categories page, only displays entries in our category.

For both single-entry and services pages, the switch tag enables every third thumbnail to get a class of “last”, thereby enabling three columns, and the conditional that tests whether segment #1 differs from the url_title ensures that a page does not link to itself.

Services Menu

An EE tag is used in one final place on the template: to display the menu of services:

&lt;div id="navi2"&gt;
 &#123;exp:weblog:categories style="nested" weblog="clients" category_group="1"&#125;
 &#123;if segment_2 != category_url_title&#125;&lt;a href="&#123;path=/&#125;"&gt;&#123;/if&#125;&#123;category_name&#125;&#123;if segment_2 != category_url_title&#125;&lt;/a&gt;&#123;/if&#125;
 &#123;/exp:weblog:categories&#125;
&lt;/div&gt;&lt;!-- /navi2 --&gt;

The list is spread across four columns using CSS.

Conclusion

We didn’t set out to build the site in conformity with how ExpressionEngine’s categories work. Instead, the things Stephen wanted for the site dovetailed with EE’s natural setup.

Post a comment

Name:

Email:

Location:

URL:

Your comment:

Remember my personal information
Notify me of follow-up comments?

Please enter the word you see in the image below: