Derek Jones
President/CTO, EllisLab, Inc.

Behind the Curtain Part III

I promised more meat in the next installment of entries peeking behind the curtain of the ExpressionEngine.com redesign, and I shall deliver.  Meatier, but still lean: this design decision was low fat.  If you subscribe to our feeds, you’ll notice that the URLs all begin as http://expressionengine.com/feeds/atom/ and http://expressionengine.com/feeds/rss/.  The reason quite simply is that we have only two templates for feeds, which saved us quite a bit of template creation and cut and pasting.

We could have used Part II’s method of globals and embeds, and Part I’s embed variables to limit the amount of work required, but we offer a lot of different feeds on this site, and I just didn’t like the idea of having to have feed templates in each template group—even if they were just holding embed tags and global variables.  So I decided that we would have two feed templates: one Atom, and one RSS, and just use URL segments to determine the content.  The stickler in this approach is that different weblogs may have different categories, different statuses, custom fields, etc.  So the template needs to be able to handle that.  I decided to use PHP on Input to handle it.  Here’s our Atom template (PHP required on Input parsing):

<?php
global $IN;

$seg3 = (isset($IN->SEGS['3'])) ? $IN->SEGS['3''';
$weblog         '';
$entry_path     '';
$category_path    '';
$statuses        '';
$fields            '';
$use_entry_id    FALSE;

if (
$seg3 == '')
    
$seg3 'full';
    
switch (
$seg3)
{
    
case 'knowledge_base':
        
$weblog            'knowledge_base';
        
$entry_path        'knowledge_base/article';
        
$category_path    'knowledge_base';
        
$fields            '{summary}{body}';
        
$statuses        'open';
        break;
    case 
'addons':
        
$weblog            'add_ons';
        
$entry_path        'downloads/details';
        
$category_path     'downloads/addons';
        
$fields            '{description}';
        
$statuses        'open|featured|popular';
        break;
    case 
'eeblog':
        
$weblog            'ee_blog';
        
$entry_path        'blog/entry';
        
$category_path     'blog/index';
        
$fields            '{body}';
        
$statuses        'open';
        break;
    case 
'devblog':
        
$weblog            'devblog';
        
$entry_path        'blog/entry';
        
$category_path     'blog/index';
        
$fields            '{body}';
        
$statuses        'open';
        break;
    case 
'network':
        
$weblog            'network_announcements';
        
$entry_path     'blog/entry';
        
$category_path     'blog/index';
        
$fields            '{network_content}';
        
$statuses        'open';
        break;
    case 
'full':
        
$weblog            'devblog|ee_blog|network_announcements';
        
$entry_path     'blog/entry';
        
$category_path     'blog/index';
        
$fields            '{body}{network_content}';
        
$statuses        'open';
        break;
    case 
'bug_tracker':
        
$weblog            'bug_tracker';
        
$entry_path     'bug_tracker/bug';
        
$category_path     'bug_tracker/list';
        
$fields            '{bug_details}';
        
$statuses        'not Hidden';
        
$use_entry_id    TRUE;
        break;        
}
?>

{exp
:rss:feed weblog="<?=$weblog?>status="<?php echo $statuses;?>"}

<?xml version
="1.0" encoding="{encoding}"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{weblog_language}">

    <
title type="text">{exp:xml_encode}{weblog_name}{/exp:xml_encode}</title>
    <
subtitle type="text">{exp:xml_encode}{weblog_name}:{weblog_description}{/exp:xml_encode}</subtitle>
    <
link rel="alternate" type="text/html" href="{weblog_url}" />
    <
link rel="self" type="application/atom+xml" href="{path=xml/atom/{segment_3}}" />
    <
updated>{gmt_edit_date format='%Y-%m-%dT%H:%i:%sZ'}</updated>
    <
rights>Copyright (c{gmt_date format="%Y"}{author}</rights>
    <
generator uri="http://expressionengine.com/" version="{version}">ExpressionEngine</generator>
    <
id>tag:{trimmed_url},{gmt_date format="%Y:%m:%d"}</id>

{exp:weblog:entries site="expressionengine|ellislab" weblog="<?=$weblog?>limit="15" rdf="off" dynamic_start="on" disable="member_data|trackbacks" status="<?=$statuses?>"}
    
<entry>
      <
title>{exp:xml_encode}{title}{/exp:xml_encode}</title>
      <
link rel="alternate" type="text/html" href="<?php if ($use_entry_id === TRUE): ?>{entry_id_path='<?=$entry_path?>'}<?php else: ?>{url_title_path='<?=$entry_path?>'}<?php endif; ?>" />
      <
id>tag:{trimmed_url},{gmt_entry_date format="%Y"}:{relative_url}/{weblog_id}.{entry_id}</id>
      <
published>{gmt_entry_date format="%Y-%m-%dT%H:%i:%sZ"}</published>
      <
updated>{gmt_edit_date format='%Y-%m-%dT%H:%i:%sZ'}</updated>
      <
author>
            <
name>{author}</name>
            
{if url}<uri>{url}</uri>{/if}
      
</author>
{categories}
      
<category term="{exp:xml_encode}{category_name}{/exp:xml_encode}"
        
scheme="{path='<?=$category_path?>'}"
        
label="{exp:xml_encode}{category_name}{/exp:xml_encode}" />{/categories}
      
<content type="html"><![CDATA[
        <?
=$fields?>
      ]]
></content>
    </
entry>
{/exp:weblog:entries}

</feed>

{/exp:rss:feed} 

The key elements being:

switch ($seg3)
{
    
case 'knowledge_base':
        
$weblog            'knowledge_base';
        
$entry_path        'knowledge_base/article';
        
$category_path    'knowledge_base';
        
$fields            '{summary}{body}';
        
$statuses        'open';
        break;
...

Here, depending on the third URL segment, we set the weblog parameter, the entry path, the category path, what custom fields we want used, and what statuses to display.  Then we create the RSS and weblog entries tags with this information:

{exp:rss:feed weblog="<?=$weblog?>status="<?php echo $statuses;?>"}
    
...
{exp:weblog:entries site="expressionengine|ellislab" weblog="<?=$weblog?>limit="15" rdf="off" dynamic_start="on" disable="member_data|trackbacks" status="<?=$statuses?>"

The categories tag pair makes use of the category path variable:

{path='<?=$category_path?>'

And the content uses our assigned custom fields:

<content type="html"><![CDATA[
  <?
=$fields?>
]]
></content

There is one special case for links to the entries that we made for the Bug Tracker, as it uses entry ids instead of URL titles.

<?php if ($use_entry_id === TRUE): ?>{entry_id_path='<?=$entry_path?>'}<?php else: ?>{url_title_path='<?=$entry_path?>'}<?php endif; ?> 

Not all of these things will be necessary on a site wishing to do something similar, so if all of your weblogs share custom fields, statuses, or paths, you can trim this up a bit.  Still, if you have multiple weblogs that are each displayed apart from one another in separate template groups, this can save you from creating two extra templates per template group, and facilitate making global changes to your feed templates.  Oh, and if you don’t like PHP, you could accomplish the same thing with cleverly named path.php global variables that would use {segment_3} to pull the correct path.php global.

Next time on BTC, less tags and how-to and more discussion on theory and organization, specifically with ::drum roll:: relationships!