The CMS Framework and How the Site is Constructed
Since 2006 we have used ExpressionEngine for our CMS. Technically it's not any better or worse than other platforms like Drupal or WordPress, but it does provide more ease of use and flexibility for web designers. For one thing, there is no default markup or CSS, so you are free to build whatever kinds of templates and pages you wish. You can easily mix static pages with database-driven content pages, with very few limits to what kind of site you can build.
Building templates in EE is straightforward and you can use your favorite authoring tools. Templates are saved in the EE database and you can edit them directly in the Control Panel. But the CP gives you a fairly crappy text editor, so it's easier to work with the templates in a dedicated code editor. There are several simple ways of doing this, but on the Mac it's easiest to use a third-party plugin called Mountee, which mounts your EE templates like a drive.
EE templates are php files, so you can set your file handling preferences to open them in whatever code editor you prefer.
A complete EE technical resource and user guide for administrators is available in the ExpressionEngine User Guide.
The WILL website uses the Bootstrap responsive web design framework.
Bootstrap provides a responsive grid and a useful set of element styles like buttons, forms, labels, and navigation. It also has a very useful JavaScript library based on JQuery, for things like carousels, tabs, accordions, etc. Each of these elements can easily be re-styled.
The WILL site currently uses Bootstrap 3.2, but Bootstrap is under rapid development and as of January 1, 2015 is at version 3.3. We will update the core Bootstrap files over time, always first on our dev and staging servers before applying changes to the live server.
Every CMS-driven website consists of a bundle of things, like a file system, a database, scripts, and possibly a framework. Here's what we're using:
/themes/site_themes/will2.1 folder on the server. These files include all the Bootstrap JavaScript, the never-edit-these Bootstrap stylesheets, an images folder containing theme images, and a plugins folder for additional JS and CSS files. You'll also find a 'weather' folder here which contains custom JS and CSS files for the /weather page./themes/site_themes/mediaelement./will2.1/plugins/weather contains the JavaScript used on the weather/index page. Inside this folder, the images folder contains a set of weather icons used by the Yahoo Weather plugin that generates the weather icon seen in the header of every page./ipmsys/expressionengine/third_party, and /themes/third_party, the default location for EE addons./nfs contains a large number of mp3 audio files, plus PDF documents and other allowed filetypes uploaded with entries for use on the site. The NFS share is mapped from the web server, and is not part of the standard EE install.All EE channels throughout the site use the same Custom Field group: items. This allows us to reuse template code for all channels, reducing the complexity of templates, and dramatically improving site performance and ease of maintenance.
Some channels use only a few fields. Entry forms are customized to only show the relevant fields, to simplify the interface for content authors. It's easy to customize the entry form on a per-user group basis. Here are the instructions for customizing the Publish Page layout.
Each section of the site has its own Template Group containing an index page template, and one or more single-entry page templates. Most sections are very simple: a Home page and many entry pages, all generated by two main templates. A few sections are fairly complex, using templates with conditional logic to generate a variety of pages and views.
All web pages and feeds are generated by using markup and logic contained in:
Almost all Templates contain only pre-defined variables that are passed on to Snippets. Snippets contain most of the actual markup and logic, but also make use of embedded Global Variables and Embedded templates. Basically, Snippets are the heart and soul of the site, and they include other elements as needed.
Pre-defined variables are passed from the Templates to Snippets, and sometimes from Snippets to Embeds. Each pre-defined variable has been given a prefix to clarify its role in the logic.
For example in the index page for a given content section, we set the value its channel in the variable {pre_channel}, where the prefix “pre_” shows that the variable is being passed to the Snippet before any logic is applied to anything. In the Snippet, {pre_channel} is replaced by the value defined in the template, for example “news”.
By pre-defining many variables in the Templates, we can re-use the same Snippets to generate pages and feeds for the vast majority of the site.
{preload_replace:pre_title="News"}
{preload_replace:pre_channel="features|news|newsnational|longerlisten|21stshow"}
{preload_replace:pre_logo="IPM_Logo_Main.png"}
{preload_replace:pre_description="In-depth reporting from WILL, NPR, and other sources"}
{preload_replace:pre_keywords="News, Public Affairs, WILL, Illinois Public Media, Radio, Public Radio, University of Illinois, Illinois, NPR"}
{preload_replace:pre_limit="10"}
{preload_replace:pre_show_future="no"}
{preload_replace:pre_show_expired="no"}
{preload_replace:pre_highlights_categories="72"}
{preload_replace:pre_section_template="news"}
{preload_replace:pre_tag_channel_template="news"}
{preload_replace:pre_sidebar_template="embeds/_embed_sidebar_news"}
{preload_replace:pre_channel_item_name="Stories"}
{preload_replace:pre_channel_description_entry_id="19028"}
{preload_replace:pre_offset="3"}
{preload_replace:pre_entry_order="date"}
{preload_replace:pre_entry_sort="desc"}
{preload_replace:pre_player_template="/player/audio"}
{preload_replace:pre_disable="member_data|categories"}
{preload_replace:pre_mp3_download="yes"}
{preload_replace:pre_rss_feed="yes"}
{preload_replace:pre_show_tags="yes"}
{preload_replace:pre_show_date="yes"}
{preload_replace:pre_show_video="no"}
{sn_articles}
As you can see there are many defined variables being passed to the snippets. The most important pieces of this are the variable {pre_channel}, which defines the channel or channels being passed to the snippet, and the last line {sn_articles} which defines which snippet all this is passed to.
If you study the snippet, most of the rest is fairly obvious. For example {pre_logo} defines which image file to use in the header for the logo. {pre_description} and {pre_keywords} supply values for the meta tags in the section.
{pre_channel_description_entry_id} variable contains the Entry ID number of an entry in the Channel Descriptions channel. Ths content of this entry is displayed at the top of the News home page. So "19028" is the entry_id for for that entry, hard-coded into the "news/index" template. Every channel has its own Channel Description entry, which gives you a unique entry_id for the channel's home page.{pre_tag_channel_template} is a variable passed to template in the "tags" template group. Any time you see a tag cloud, or a page using the "tags" template, this variable is important for connecting things.{pre_offset} is used as a conditional value for {sn_articles}. If the value is "3" then three stories will appear at the top of the web page as seen on the News home page: http://will.illinois.edu/news/. If the value is not "3" the the stories will simply flow down the page like most sections do. As seen on the News home page, this allows more than one story to appear above the fold. (The value of this is increasingly dubious with the acsendance of mobile, but for now that's how we're laying this out.){preload_replace} variables are switches used in conditionals in the snippets. You can figure them out pretty easily by reading the snippet code.{pre_something} variables that no are longer used in the snippets, which is something to clean up during the next iteration of the site.Here is the key to how this all works in ExpressionEngine.
Templates, Snippets, and the other elements are parsed by EE in a specific order. It’s important to understand parse order to follow the logic of page generation. Templates define variables, then pass them to Snippets. Snippets contain Embedded Templates, Global Variables, and Low Variables. Each of these elements is parsed by EE in a specific sequence. Here’s a handy guide to EE Parse Order:
http://loweblog.com/downloads/ee-parse-order.pdf
Once you understand EE parse order, you can see how efficient everything fits together. 99 percent of the WILL website is generated by two snippets, {sn_articles} and {sn_article}. The only difference is the variables passed to these two snippets by the {preload_replace} values in the templates.
For an excellent description of this design approach in EE, see the blog post Snippets and Preload Replace Variables by Lodewijk Schutte
Improvements could undoubtedly be made in the way the WILL site is currently put together. EE has evolved since then, with new features like Layouts and Template Routes. The next iteration of the site would be the time to consider this.
Snippets do most of the heavy lifting in pulling content from the database. On the WILL site they contain most of the markup, and most of the EE code that pulls content from chnnel entries. So they can contain dynamic content.
You can name snippet any way you want, but we use the prefix "sn_" to make it obvious they're snippets.
The main snippets used throughout the site are:
These two snippets contain the markup and logic for about 99 percent of the entire site.
The {sn_articles} snippet generates home pages for most of the major WILL content channels. Home pages typically display n number of the most recent entries for that channel, with pagination links to more entries.
The {sn_article} snippet creates single-entry pages for each entry in that channel.
For each content channel, the index template in its template group uses {sn_articles} to create a Home page with entries in short summary form. In the template group for that channel, there will be a “story” or “program” template that uses {sn_article} to generate full, single-entry pages. The {sn_article} snippet is expecting a url_title variable to be passed as part of any links to it (usually as a segment_3), so it can pull in the data for that entry.
For example, here is the News home page url using {sn_articles}:
http://will.illinois.edu/news
And here is a News story url containing a url_title variable as part of its url:
http://will.illinois.edu/news/story/school-consolidation-referendum-sparks-disagreement
So EE sees "/news" in the url so it calls the "news" template group. It sees "/story" so it calls the "story" template in the "news" template group. Finally, it looks for an entry that matches the last segment "/school-consolidation-referendum-sparks-disagreement" and renders the page with the content in that entry.
Any url that only has the first segment, e.g. "/news" in "will.illinois.edu/news", will load the index template in that template group. That is, the home page for that channel.
Embedded templates are used in most pages, providing sidebars and other secondary content. Conditional logic is used in many snippets to determine which embedded template is used.
For example in the {sn_homepage} snippet, different sidebars are displayed depending on what’s in segment_1 of the url. So http://will.illinois.edu/tv gets a sidebar based on the template embeds/_embed_sidebar_tv, while http://will.illinois.edu/am gets the sidebar for WILL-AM which is embeds/_embed_sidebar_am. This kind of logic is used in many snippets.
Because Embeds are processed later in the EE parse order, when they are embedded in a Snippet it’s necessary to pass pre-defined variables to them from the Snippet. For example:
{pre_highlights_categories} and assigns it a value of “66”. {sn_homepage} converts the {pre_highlights_categories} variable instantly to “66” wherever it appears in the Snippet. {pre_hightlights_categories} to pass the value of "66" to an Embed variable, which we also define in the Snippet by saying something like:
{embed="{pre_sidebar_template}" embed_channels="{pre_channel}" embed_path_root="{channel_url}" embed_pre_section_template="{pre_section_template}" embed_highlights_category="{pre_highlights_categories}"}
categories=”{embed_highlights_categories}” which the Embed sees as the value “66” we passed from the Snippet.There are many other embedded templates, and they're all located in the Embeds template group. Once you follow the logic for the sidebars, you'll understand how they all work.
User defined Global Variables contain static content, and are processed very late in the EE parsing order. They are used for links to stylesheets and scripts, or static bits of markup used throughout the site.
We use the prefix “gv_” in the name of Global Variables to make them easy to spot inside Templates and Snippets.
The only exception to the above is in the case of Low Variables, which also appear inside the Global Variables control panel. To keep them straight, we use the prefix “lv_” for all Low Variables.
Low Variables is an Addon Module that provides a different parsing order for variables, depending on how you want to use them. For example, you can set a Low Variable for parsing before Snippets, so they can process dynamic content before the Snippet is parsed.
The Low Variable {lv_edit_this} is used in this way to insert “Edit This” links in content pages if the user is logged in to EE.
But Low Variables can also be used to hold static content we want to allow users to edit, like {lv_card_support} which is the fundraising message on the home page.
Low Variables can use all the different field types installed in the EE instance, including WYGWAM, Related Entires, and all the rest. We might find it useful to expand use of Low Variables, but I’ve kept it to a minimum to avoid complicating the site and adding dependencies on Addons.
Documentation on the Low Variables module is available here: http://gotolow.com/addons/low-variables
Important: The Low Variable {lv_edit_this} contains a string of conditionals like if logged_in_group == "1" OR etc. This means if the person looking at the font-end web page is logged in to the CMS, and they are a member of the specified member group, they'll see a link to "Edit This" entry on the web page. So if a new member group is created, a new conditional for it must be added to this Low Variable. Because this Low Variable contains a great many conditional statements, it's very easy to misplace a character while editing. This will result in very bad things on every page of the site, so be very careful when editing this Low Variable.
A few templates don’t use Snippets, but contain all of their own markup:
These templates rarely if ever change, so don't need to be any more complicated.
The “player/audio” template is used for all audio archives.
player/audio
The player/audio template uses {sn_audioplayer} for the player window markup. {sn_audioplayer} contains the exp:channel:entries tags which pull in the entry_id from channel, which causes the player to display the entry title, an image if available, and the mp3 file url.
Make sure the channel you want audio to play from is added to {sn_audioplayer_channels}.
player/audioplayer_newscast
Used for the WILL Newscast which is always the same file name. This template passes title metadata and a static url for the newscast audio file to {sn_audioplayer_static_audio_url}. The snippet contains the player markup. The same snippet can be used for any other players that need a static audio url, either a file or a live steam.
Newscast audio url: http://audio01.will.illinois.edu/WILLAM580newscast.mp3
player/audioplayer_irr
Used for the Illinois Radio Reader live stream. This also uses {sn_audioplayer_static_audio_url}, and passes the IRR live stream url to the snippet.
IRR live stream url: http://icecast.will.illinois.edu:8000/WILL-IRR
am/willplayer and fm/willplayer
These templates reflect legacy urls from past WILL websites. We kept them the same for that reason. They contain all the markup for the WILL-AM and WILL-FM live stream players, including static links to the stream urls.
These templates can be enhanced in various ways. They contain a “promocard” section that can be used for promotional announcements, underwriting, or anything else. These currently contain a static fundraising message, but the plan is to make them dynamic and editable by Marketing.