The ExpressionEngine Side of the New Viget.com: Part 2
Trevor Davis, Former Front-End Development Technical Director
Article Category:
Posted on
I’ve already talked about the EE setup for the new viget.com, 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.
Templates
Here is what our template structure looks like:
- about
- careers
- index
- team
- _blog_entries
- core
- 404
- author-rss
- blogs
- careers_feed
- index
- rss
- 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"> <head> <title>{exp:stash:get name="title"}</title> </head> <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"} </div> <header id="global-header" role="banner"> … </header> <footer id="global-footer"> … </footer> </body> </html>
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.
{embed="_layouts/index"} {preload_replace:channel="work"} {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 --} {exp:channel:entries channel="{channel}" {gv_channel_disable_basic} } {!-- Get ALL the work items --} {exp:stash:append name="work_listing"} <li><a href="/work/{url_title}">{title}</a></li> {/exp:stash:append} {!-- Get the case stories only too --} {exp:stash:append name="case_story_listing" match="#Yes#" against="{work_is_case_story}"} <li> <a href="/work/{url_title}"> {exp:ce_img:pair src="{work_carousel_thumbnail}" height="190" width="300" } <img src="{made}" alt="{title}" class="photo"> {/exp:ce_img:pair} </a> </li> {/exp:stash:append} {/exp:channel:entries} {!-- Get clients --} {exp:channel:entries channel="client" {gv_channel_disable_most} orderby="client_sort_order" sort="asc" limit="12" } {exp:stash:append name="featured_clients"} <li> {exp:ce_img:pair src="{client_logo}" height="130" width="220" } <img src="{made}" alt="{title}" /> {/exp:ce_img:pair} </li> {/exp:stash:append} {/exp:channel:entries} {exp:stash:set name="content"} <section class="section-featured-projects section"> <ul> {exp:stash:get name="case_story_listing"} </ul> </section> <section class="section-clients section"> <ul> {exp:stash:get name="featured_clients"} </ul> </section> <div class="section-content col-10 col"> <ul class="grouping-projects grouping clear"> {exp:stash:get name="work_listing"} </ul> </div> {/exp:stash:set} {/case} … {/exp:switchee}
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 viget.com 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.