Newscoop 3 Cookbook

RSS, sitemap, KML and XML

The Newscoop template engine allows you deliver many kinds of structured content, including HTML, XML, CSV, vCard and more. In this chapter we will explain a few of these formats and how they are created. The process is always the same: develop your business logic, and then wrap the presentation logic around it.  

RSS Feed 

We will start with producing an RSS feed for syndication of the latest 15 articles from the current section in the publication. First, let's look at the basic structure of an RSS document. The channel tag contains three elements; channel metadata, an image block and an items list:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        [channel metadata]
        [image block]
        [items list]
    </channel>
</rss>

Channel metadata is a required element which can include the channel's name or title, description, language, URL and copyright information.

<title>{{ $gimme->publication->name }}</title>
<link>http://{{ $gimme->publication->site }}</link>
<description>{{ $siteinfo.description }}</description>
<language>{{ $gimme->language->code }}</language>
<copyright>Copyright {{ $smarty.now|date_format:"%Y" }, {{ $gimme->publication->name }}</copyright>
<lastBuildDate>{{ $smarty.now|date_format:"%a, %d %b %Y %H:%M:%S" }} +0100</lastBuildDate>
<generator>Newscoop</generator>

The Newscoop snippet above grabs the name and site attributes of the publication, as well as the language code. Also, we make use of Smarty with some special modifiers to display the current date and time in two different formats (for more information on this, please read the Smarty manual).

Image block - the image's URL, title, link, width, and height tags allow RSS viewers to translate the file into HTML. This block is very straight forward, using the site and name attributes of the Newscoop publication.

<image>
    <url>http://{{ $gimme->publication->site }}/templates/classic/img/logo-rss.jpg</url>
    <title>{{ $gimme->publication->name }}</title>
    <link>http://{{ $gimme->publication->site }}</link>
    <width>144</width>
    <height>19</height>
</image>

Items list - this is the most important piece of the RSS document, as the actual feeds are generated here. For this purpose we will use the list_articles statement with $gimme to request the latest 15 published articles. The list is built using the current language, publication, issue and section from the context.

{{ list_articles length="15" order="bypublishdate desc" }}
    [list of items]
{{ /list_articles }}

Now we need to define the list of items.

<item>
 <title>{{ $gimme->article->name }}</title>
  <link>{{ url options="article" }}</link>
   <description>
   {{ $gimme->article->intro|strip_tags:false|strip|escape:'html':'utf-8' }}
   </description>
    <category domain="{{ url options="section" }}">
    {{ $gimme->section->name }}
    </category>
   {{ if $gimme->article->author->name }}
   <atom:author>
   <atom:name>{{ $gimme->article->author->name }}</atom:name>
   </atom:author>
   {{ /if }}
  <pubDate>
  {{ $gimme->article->publish_date|date_format:"%a, %d %b %Y %H:%M:%S" }} +0100
  </pubDate>
 <guid isPermaLink="true">{{ url options="article" }}</guid>
</item>

Let's explain where we get the data from for each item tag:

title: The article name.

link: The article URL from Newscoop.

description: The text of the article introduction, which is a custom field for the particular article type used here. In addition, we use some Smarty modifiers in order to clean up the text, making sure it will be displayed properly.

category: We use the section name here.

atom author: If the article has an author defined, then we display their full name.

pubDate: The publication date of the article, with some special formatting. Please read up on the Smarty date_format modifier if you aren't sure about this.

guid: The article URL as global unique identifier for the item.

Finally, this is how the whole template file should look:

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title>{{ $gimme->publication->name }}</title>
        <link>http://{{ $gimme->publication->site }}</link>
        <description>{{ $siteinfo.description }}</description>
        <language>{{ $gimme->language->code }}</language>
        <copyright>Copyright {{ $smarty.now|date_format:"%Y" }}, {{ $gimme->publication->name }}</copyright>
        <lastBuildDate>{{ $smarty.now|date_format:"%a, %d %b %Y %H:%M:%S" }} +0100</lastBuildDate>
        <generator>Newscoop</generator>
        <image>
            <url>http://{{ $gimme->publication->site }}/templates/classic/img/logo-rss.jpg</url>
            <title>{{ $gimme->publication->name }}</title>
            <link>http://{{ $gimme->publication->site }}</link>
            <width>144</width>
            <height>19</height>
        </image>
        <atom:link href="http://{{ $gimme->publication->site }}/templates/feed/index-en.rss" rel="self" type="application/rss+xml" />
        {{ list_articles length="20" order="bypublishdate desc" }}
        <item>
            <title>{{ $gimme->article->name|html_entity_decode|regex_replace:'/&(.*?)quo;/':'&quot;' }}</title>
            <link>http://{{ $gimme->publication->site }}/ru/{{ $gimme->issue->number }}/{{ $gimme->section->url_name }}/{{ $gimme->article->number }}</link>
            <description>
                {{ $gimme->article->intro|strip_tags:false|strip|escape:'html':'utf-8' }}
            </description>
            <category domain="http://{{ $gimme->publication->site }}/{{ $gimme->language->code }}/{{ $gimme->issue->number }}/{{ $gimme->section->url_name }}">{{ $gimme->section->name }}</category>
            {{ if $gimme->article->author->name }}
            <atom:author><atom:name>{{ $gimme->article->author->name }}</atom:name></atom:author>
            {{/if}}
            <pubDate>{{ $gimme->article->publish_date|date_format:"%a, %d %b %Y %H:%M:%S" }} +0100</pubDate>
            <guid isPermaLink="true">http://{{ $gimme->publication->site }}/{{ $gimme->language->code }}/{{ $gimme->issue->number }}/{{ $gimme->section->url_name }}/{{ $gimme->article->number }}</guid>
        </item>
    {{/list_articles}}
    </channel>
</rss>

How to get it working

There are different ways to achieve this, however what we recommend is to use Google FeedBurner as it provides significant benefits like statistics, social sharing, among others. Read more about FeedBurner at http://feedburner.google.com/.

Now that you already have your RSS template file you need to configure it in FeedBurner. You can do this easily by inputting the URL to the RSS in your site. Usually the URL looks like this, as it is a direct reference to the RSS template file:

http://your.site.url/?tpl=123

FeedBurner will give you back a new "burned" URL that looks something like this:

http://feeds.feedburner.com/YourFeedName

Where YourFeedName is the name you input when burning your RSS feed in FeedBurner. Now all what you need to do is to include the following line in the header template of your site.

<link rel="alternate" type="application/rss+xml" title="Newscoop News" href="http://feeds.feedburner.com/YourFeedName" />

Google Sitemaps

The Sitemaps protocol, introduced by Google, allows you to inform search engines about links on your site that are available for crawling. A Sitemap is a file in a specific XML format that lists the URLs of your site, including metadata about each URL carrying data like last updated, the relevance of the resource compared to other URLs in the site, and so on. This allows search engines to index the site in a more optimal way.

How to build a site map depends on the content structure you have designed for your specific site, but whatever it is, $gimme will allow you to generate it.

Goal / Task

To display the Site Map for our particular use case, listing: All articles regardless of language, issue and section, of type news, All articles regardless of language, issue and section, of type show, All subtopics in English and French languages with parent topic equal to Countries, All sections from the current issue in English and French languages.

Implementation

All articles regardless of language, issue and section, of type news.

{{ list_articles ignore_language="true" ignore_issue="true" ignore_section="true" order="bypublishdate desc" constraints="type is news" }}
<url>
    <loc>http://wadr.org{{ uri options="article" }}</loc>
    <lastmod>{{ $gimme->article->publish_date|camp_date_format:"%Y-%m-%d" }}</lastmod>
    <changefreq>daily</changefreq>
    <priority>0.6</priority>
</url>
{{ /list_articles }}

Notice the use of ignore_language, ignore_issue and ignore_section. All these are set to true so that those values from the context are ignored when building the list. We use the same approach for the next list.

All articles regardless of language, issue and section, of type show.

{{ list_articles ignore_issue="true" ignore_section="true" ignore_language="true" order="bypublishdate desc" constraints="type is show" }}
<url>
    <loc>http://wadr.org{{ uri options="article" }}</loc>
    <lastmod>{{ $gimme->article->publish_date|camp_date_format:"%Y-%m-%d" }}</lastmod>
    <changefreq>daily</changefreq>
    <priority>0.8</priority>
</url>
{{ /list_articles }}

This list is similar to the first one. The only difference is we are requesting articles of a different type: show this time.

All subtopics in the English language with parent topic equal to Countries.

{{ set_language name="English" }}
{{ set_topic name="Countries:en" }}
{{ list_subtopics }}
<url>
    <loc>http://wadr.org/{{ $gimme->language->code }}/?tpid={{ $gimme->topic->identifier }}&amp;tpl=1442/</loc>
    <changefreq>daily</changefreq>
    <priority>0.4</priority>
</url>
{{ /list_subtopics }}

All subtopics in the French language with parent topic equal to Countries.

{{ set_language name="French" }}
{{ set_topic name="Countries:en" }}
{{ list_subtopics }}
<url>
    <loc>http://wadr.org/{{ $gimme->language->code }}/?tpid={{ $gimme->topic->identifier }}&amp;tpl=1442/</loc>
    <changefreq>daily</changefreq>
    <priority>0.4</priority>
</url>
{{ /list_subtopics }}

All sections from the current issue in the English language.

{{ set_current_issue }}
{{ set_language name="English" }}
{{ list_sections }}
<url>
    <loc>http://wadr.org/{{ $gimme->language->code }}/{{ $gimme->issue->url_name }}/{{ $gimme->section->url_name }}/</loc>
    <changefreq>weekly</changefreq>
    <priority>0.3</priority>
</url>
{{ /list_sections }}

All sections from the current issue in the French language.

{{ set_language name="French" }}
{{ list_sections }}
<url>
    <loc>http://wadr.org/{{ $gimme->language->code }}/{{ $gimme->issue->url_name }}/{{ $gimme->section->url_name }}/</loc>
    <changefreq>weekly</changefreq>
    <priority>0.3</priority>
</url>
{{ /list_sections }}

This is how the full Sitemap file should look:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{{ list_articles ignore_language="true" ignore_issue="true" ignore_section="true" order="bypublishdate desc" constraints="type is news" }}
    <url>
        <loc>http://wadr.org{{ uri options="article" }}</loc>
        <lastmod>{{ $gimme->article->publish_date|camp_date_format:"%Y-%m-%d" }}</lastmod>
        <changefreq>daily</changefreq>
        <priority>0.6</priority>
    </url>
{{ /list_articles }}
{{ list_articles ignore_issue="true" ignore_section="true" ignore_language="true" order="bypublishdate desc" constraints="type is show" }}
    <url>
        <loc>http://wadr.org{{ uri options="article" }}</loc>
        <lastmod>{{ $gimme->article->publish_date|camp_date_format:"%Y-%m-%d" }}</lastmod>
        <changefreq>daily</changefreq>
        <priority>0.8</priority>
    </url>
{{ /list_articles }}
{{ set_language name="English" }}
{{ set_topic name="Countries:en" }}
{{ list_subtopics }}
    <url>
        <loc>http://wadr.org/{{ $gimme->language->code }}/?tpid={{ $gimme->topic->identifier }}&amp;tpl=1442/</loc>
        <changefreq>daily</changefreq>
        <priority>0.4</priority>
    </url>
{{ /list_subtopics }}
{{ set_language name="French" }}
{{ set_topic name="Countries:en" }}
{{ list_subtopics }}
    <url>
        <loc>http://wadr.org/{{ $gimme->language->code }}/?tpid={{ $gimme->topic->identifier }}&amp;tpl=1442/</loc>
        <changefreq>daily</changefreq>
        <priority>0.4</priority>
    </url>
{{ /list_subtopics }}
{{ set_current_issue }}
{{ set_language name="English" }}
{{ list_sections }}
    <url>
        <loc>http://wadr.org/{{ $gimme->language->code }}/{{ $gimme->issue->url_name }}/{{ $gimme->section->url_name }}/</loc>
        <changefreq>weekly</changefreq>
        <priority>0.3</priority>
    </url>
{{ /list_sections }}
{{ set_language name="French" }}
{{ list_sections }}
    <url>
        <loc>http://wadr.org/{{ $gimme->language->code }}/{{ $gimme->issue->url_name }}/{{ $gimme->section->url_name }}/</loc>
        <changefreq>weekly</changefreq>
        <priority>0.3</priority>
    </url>
{{ /list_sections }}
</urlset>

How to get it working

There are different ways to inform the search engines to crawl your site using the XML Sitemap we just created. However, this is out of the scope of this guide as it has nothing to do with Newscoop templating.

You can find detailed information on how to do it in these following links:

http://www.sitemaps.org/

https://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=78808&ctx=cb

KML Documents for exporting map locations

KML is like an RSS feed for geo-location data. It is a XML specific notation for expressing geographic annotation and visualization within maps, Earth browsers and other applications.

One of the sample Template Packages on the Sourcefabric website is the "Ushahidi Cooker" which is dedicated to mapping content and generating KML feeds. You will come across KML feeds when you export from mapping services or - in the case of Ushahidi - when you want to import additional information into a map. Newscoop handles maps, and using the following code it can deliver valid KML feeds.

Goal / Task

To generate a simple KML file containing the list of locations for the current article.

Implementation

The structure of a basic KML file breaks down as follows:

  • An XML header and a KML namespace declaration. You will see these two lines in the full version of the KML file at the end of this section.
  • A Placemark object that contains the following elements: A name used as the label for the Placemark, a description that appears in the "balloon" attached to the Placemark, and a Point that specifies the position of the Placemark on the Earth's surface.

KML is much more complex than this, and allows you to provide more information about the locations in your map and style those as much as you want, but that is KML-specific and out of the scope of this document. What we want to show you here is how you can use $gimme to pull the data and display the locations, which ultimately is what matters the most.

First you need to provide basic info about the article. In this case we use the article name and section name as the name for our KML document, and the custom field intro as the description.

<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
  <name>{{ $gimme->article->name }} in {{ $gimme->section->name }}</name>
  <description><![CDATA[{{ $gimme->article->intro }}]]></description>
Next, we provide some custom styling for the marker icons. For this we need to generate a unique id per location, so we use the article number plus the incremental index in the list. We also validate inside the list if the location is enabled or not.
{{ list_article_locations }}
    {{ if $gimme->location->enabled }}
    <Style id="style{{ $gimme->article->number }}-{{ $gimme->current_list->index }}">
        <IconStyle>
            <Icon>
                <href>http://www.sourcefabric.org/geolocation/markers/marker-gold.png</href>
            </Icon>
        </IconStyle>
    </Style>
    {{ /if }}
{{ /list_article_locations }}

Now the most important section, the list of locations to be displayed on the map. We use list_article_locations, and after making sure the location is enabled we build the Placemark block. For the Placemark name we are using the location name together with the article name. Then we use styleUrl to reference the custom style defined in the block above.

The last sub-block is Point, which is where we actually specify the location positioning on the map. Notice the use of $gimme->location->longitude and $gimme->location->latitude, it could not be more intuitive :-) The value 0.000000 after latitude corresponds to altitude, which is not relevant for this example but must be there as per KML specifications.

{{ list_article_locations }}
    {{ if $gimme->location->enabled }}
    <Placemark>
        <name>{{ $gimme->location->name }} @ {{ $gimme->article->name }}</name>
        <description></description>
        <styleUrl>#style{{ $gimme->article->number }}-{{ $gimme->current_list->index }}</styleUrl>
        <Point>
            <coordinates>{{ $gimme->location->longitude }},{{ $gimme->location->latitude }},0.000000</coordinates>
        </Point>
    </Placemark>
    {{ /if }}
{{ /list_article_locations }}

This is how the full KML file should look:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
    <name>{{ $gimme->section->name }} in {{ $gimme->article->name }}</name>
    <description><![CDATA[{{ $gimme->article->description }}]]></description>
    {{ list_article_locations }}
        {{ if $gimme->location->enabled }}
        <Style id="style{{ $gimme->article->number }}-{{ $gimme->current_list->index }}">
            <IconStyle>
                <Icon>
                    <href>http://www.sourcefabric.org/geolocation/markers/marker-gold.png</href>
                </Icon>
            </IconStyle>
        </Style>
        {{ /if }}
    {{ /list_article_locations }}

    {{ list_article_locations }}
        {{ if $gimme->location->enabled }}
        <Placemark>
            <name>{{ $gimme->location->name }} @ {{ $gimme->article->name }}</name>
            <description></description>
            <styleUrl>#style{{ $gimme->article->number }}-{{ $gimme->current_list->index }}</styleUrl>
            <Point>
                <coordinates>{{ $gimme->location->longitude }},{{ $gimme->location->latitude }},0.000000</coordinates>
            </Point>
        </Placemark>
        {{ /if }}
    {{ /list_article_locations }}
</Document>
</kml>

Put KML feeds into action

KML files are meant to be used in browsers and any other kind of application supporting this format, like for example Google Earth, Google Maps, or Ushahidi Layers. So, once Newscoop generates this file for you, you just need to use it in any of these tools, depending on your needs.

You can try this with the Template Package "Ushahidi Cooker". You will also find a video tutorial about the "Ushahidi Cooker" here:

http://www.sourcefabric.org/en/products/newscoop_templates/