The ExpressionEngine Side of the New Part 2

I’ve already talked about the EE setup for the new, but now I want to talk about the code. It took a little longer than I wanted to get to it, but let’s finally talk templates and custom addon development.


Here is what our template structure looks like:

  • about
    • careers
    • index
    • team
    • _blog_entries
  • core
    • 404
    • author-rss
    • blogs
    • careers_feed
    • index
    • rss
    • twitter
  • advance
    • index
  • extend
    • index
  • flourish
    • index
  • inspire
    • index
  • work
    • case-stories
    • index
  • _layouts
    • basic-page
    • blog
    • blog-preview
    • index
  • newsletter
    • index
  • _functions
    • comment-notification
    • index
  • training
    • index

My main goal when discussing our templates is to show how we use Stash. Seriously go take a look at Stash, it’s so awesome. Stash changes the way you build with EE, in a good way. It’s not like Structure where you have to go all in, but you could selectively use it if you really wanted to.

We used the template partials approach to our templates. The basic concept is that you include a "layout", and then fill in the gaps in the layout.

The Layout

Below is the stripped down version of our “layout” which lives at _layouts/index.

<!DOCTYPE html>
<html class="no-js" id="viget-com" lang="en">
    <title>{exp:stash:get name="title"}</title>
<body{if {exp:stash:not_empty name="body_class"}} class="{exp:stash:get name="body_class"}"{/if}>
    <div role="main">
        {exp:stash:get name="content"}
    <header id="global-header" role="banner">
    <footer id="global-footer">

In the layout, we are using the stash:get method to retrieve pieces of data that have been stored. Line 4 retrieves whatever has been stashed under the name title. Line 6 will add a class to the body, only if something has been stashed at body_class. Finally, line 9 outputs whatever has been stashed under the name of content.

The Work Template

Now let’s take a look at how the work template “stashes” those pieces of data. Here is a stripped down version of work/index.

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

  {!-- Work listing --}
  {case value=""}
    {exp:stash:set_value name="title" value="Our Work | Viget"}
    {exp:stash:set_value name="body_class" value="page-work page-primary page"}
    {!-- Get work items --}
      {!-- Get ALL the work items --}
      {exp:stash:append name="work_listing"}
        <li><a href="/work/{url_title}">{title}</a></li>
      {!-- Get the case stories only too --}
      {exp:stash:append name="case_story_listing" match="#Yes#" against="{work_is_case_story}"}
          <a href="/work/{url_title}">
              <img src="{made}" alt="{title}" class="photo">
    {!-- Get clients --}
      {exp:stash:append name="featured_clients"}
            <img src="{made}" alt="{title}" />
    {exp:stash:set name="content"}
      <section class="section-featured-projects section">
          {exp:stash:get name="case_story_listing"}
      <section class="section-clients section">
          {exp:stash:get name="featured_clients"}
      <div class="section-content col-10 col">
        <ul class="grouping-projects grouping clear">
          {exp:stash:get name="work_listing"}

Note: Using spaces instead of tabs for readibility.

Our first step is to include our layout. Since embeds are parsed later, everything we are doing later in this template will be stored and then retrieved in the layout. Next, we are using Switchee to determine whether this is the work index or a work single entry. For the above example, I’ve only shown the work index.

The first two stash:set_value tags (lines 8-9) are storing the page title and body class that are output in the layout.

Next, we start a channel entries loop (lines 12-37) to get all of the entries in the work channel. Inside of that loop, we are actually storing two different things. The first, is that we are creating a stash called work_listing (lines 18-20) that contains all of the entries from the work channel. The next, called case_story_listing (line 23-35), contains only the items that have the work_is_case_story custom field set to Yes. This is a prime example of why Stash is so awesome: we are handling something that would normally require two separate channel:entries tags in just one.

In the next channel:entries loop (line 40-58), we are just returning the first 12 entries from the client channel, and storing them in a stash named featured_clients.

Finally, we want to take the data that we have stashed and put it all together in the content stash (lines 60-78), which gets output in the layout. The stash:get method (lines 63, 69, 75) is how you retrieve something that you have previously stashed.

That’s the basics of what our templates look like.

Custom Addon Development

I’ve written a few EE addons here and there, but this was by far the most custom addon development I have ever done for a “client” site. I ended up writing an accessory, extension, and plugin.

The Accessory

The Accessory is actually really simple: it just changes the category checkboxes to radio buttons in a couple of instances. This is helpful so that an author can only publish a blog entry to a single blog.

The Extension

The Extension uses the cp_menu_array hook to remove the Homepage channel from the Publish flyout (since this is a single entry channel), and add links to the navigation to Reorder and Freeform if a user has access.

The Plugin

This is the workhorse. There are 15 different methods inside of the plugin that help to keep our templates cleaner. There are some methods that are there to just avoid using PHP in templates and others that are there to actually optimize some of the queries. I could certainly break each method out into a separate plugin, but really it just doesn’t make sense. So much of the code is so specific to the site that we probably wouldn’t be able to take a method and just drop it into another site to use.

Here are all of the methods with a brief description:

  • {exp:viget:blog_info} - Tag Pair
    Pass in an entry_id and get back the blog_url_title and the blog name
  • {exp:viget:blog_entry_count} - Single Tag
    Pass in a category_id and get the total number of entries in that blog category
  • {exp:viget:user_info} - Tag Pair
    Pass in an author_id and get back a user's info
  • {exp:viget:blog_authors} - Tag Pair
    Pass in a category_id and get blog authors for that category
  • {exp:viget:profile_nearby_entries} - Tag Pair
    Pass in an entry_id and get the previous and next url_titles (used with our crazy sorting on the team section)
  • {exp:viget:work_lite_listing} - Tag Pair
    Used for listing of all work entries and denoting which entries are case stories
  • {exp:viget:favorites_json} - Single Tag
    Generate the JSON for the location favorites
  • {exp:viget:popular_interests} - Tag Pair
    Used to return interests where there are at least 8 people with that interest
  • {exp:viget:stream} - Tag Pair
    Gets the most recent blog post from each category, the latest team viget post, and the latest flickr photo
  • {exp:viget:url_encode} - Tag Pair
    URL Encode a string
  • {exp:viget:is_our_ip} - Single Pair
    Determine if it's a viget IP
  • {exp:viget:ga_encode} - Tag Pair
    Remove commas and apostrophes
  • {exp:viget:entry_count} - Single Tag
    Get the number of entries from a channel
  • {exp:viget:newsletter_links} - Tag Pair
    Add the color attribute to links in the HTML email
  • {exp:viget:comment_notification} - Single Tag
    Send email after DISQUS comment is submitted

I’d be happy to go into more detail about the code behind any of the templates or custom addons if anyone has questions.

Trevor is a senior front-end developer who specializes in writing bulletproof code for clients including the World Wildlife Fund and GoPole.

More posts by Trevor