Jim Westergren
About me, my projects, SEO, Web Development and Personal Development since 2005
"If we did all the things we are capable of, we would literally astound ourselves." - Thomas A. Edison

Tutorial: RSS Feed inside Smarty Template files

Some while ago I wanted to set up an RSS feed according to this post on a directory of mine. The problem was that the directory is run by a smarty engine and the templates files are of the .tpl type and so the normal way to do it with simple PHP won't work.

After numerous attempts of different sort and probably an hour or more of googling I gave up after not being able to find the solution. The next day I got help from a good fellow, Scott at BanPro NET and he worked out a solution - all credits to him please.

This tutorial will add the RSS feed into a MySQL database, assign it to smarty arrays and then display it on your smarty template file.

This has been tested and worked without error. However, PLEASE be cautious and backup your database and files prior to using this just on the off chance there is some problem. It's always the best practice to be safe before sorry.

Here are the steps:

  1. Create a new database, or add a table to an existing one. Either option is fine. Here is the sql command for creating the table, if your hosting account has access to phpMyAdmin then you can just run this on the database you want to use from there:

    CREATE TABLE `rssfeed` (
    `title` TEXT NOT NULL ,
    `description` TEXT NOT NULL ,
    PRIMARY KEY ( `id` ) ,
    `title` ,
    ) TYPE = MYISAM ;

  2. Copy the following text in a file and name it rss.inc.php:



    #### This is the URL of the feed: $file = "https://www.jimwestergren.com/category/online-marketing/feed/";

    $rss_channel = array(); $currently_writing = ""; $main = ""; $item_counter = 0;

    function startElement($parser, $name, $attrs) { global $rss_channel, $currently_writing, $main; switch($name) { case "RSS": case "RDF:RDF": case "ITEMS": $currently_writing = ""; break; case "CHANNEL": $main = "CHANNEL"; break; case "IMAGE": $main = "IMAGE"; $rss_channel["IMAGE"] = array(); break; case "ITEM": $main = "ITEMS"; break; default: $currently_writing = $name; break; } }

    function endElement($parser, $name) { global $rss_channel, $currently_writing, $item_counter; $currently_writing = ""; if ($name == "ITEM") { $item_counter++; } }

    function characterData($parser, $data) { global $rss_channel, $currently_writing, $main, $item_counter; if ($currently_writing != "") { switch($main) { case "CHANNEL": if (isset($rss_channel[$currently_writing])) { $rss_channel[$currently_writing] .= $data; } else { $rss_channel[$currently_writing] = $data; } break; case "IMAGE": if (isset($rss_channel[$main][$currently_writing])) { $rss_channel[$main][$currently_writing] .= $data; } else { $rss_channel[$main][$currently_writing] = $data; } break; case "ITEMS": if (isset($rss_channel[$main][$item_counter][$currently_writing])) { $rss_channel[$main][$item_counter][$currently_writing] .= $data; } else { $rss_channel[$main][$item_counter][$currently_writing] = $data; } break; } } }

    $xml_parser = xml_parser_create(); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData"); if (!($fp = fopen($file, "r"))) { die("could not open XML input"); }

    while ($data = fread($fp, 4096)) { if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } } xml_parser_free($xml_parser);

    // Set up mysql connection

    // database access host $dbhost = "localhost"; // database username $dbuser = "user_username"; // password $dbpass = "password"; // database name $dbname = "user_dbname";

    // make connection to mysql server $conn = mysql_connect($dbhost, $dbuser, $dbpass) or die ('Error connecting to mysql'); // select which database on mysql server mysql_select_db($dbname);

    // empty out previous items (if any) and reset table $query = 'DELETE FROM rssfeed WHERE id>0'; $result = mysql_query($query); $query = 'ALTER TABLE rssfeed DROP COLUMN ID'; $result = mysql_query($query); $query = 'ALTER TABLE rssfeed ADD COLUMN ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY'; $result = mysql_query($query);

    // output HTML ### NOTE NEEDED #### print ("<div class="channelname">" . $rss_channel["TITLE"] . "</div>");

    if (isset($rss_channel["ITEMS"])) { if (count($rss_channel["ITEMS"]) > 0) { for($i = 0;$i < 5;$i++) { if (isset($rss_channel["ITEMS"][$i]["LINK"])) { $title = "n<div class="itemtitle"><a href="" . $rss_channel["ITEMS"][$i]["LINK"] . "">" . $rss_channel["ITEMS"][$i]["TITLE"] . "</a>"; } else { $title = "n<div class="itemtitle">" . $rss_channel["ITEMS"][$i]["TITLE"] . "</div>"; } $description = "<div class="itemdescription">" . $rss_channel["ITEMS"][$i]["DESCRIPTION"] . "</div><br />";

    // place the items into your database $query = 'INSERT INTO rssfeed (title, description) VALUES ("'.mysql_real_escape_string($title).'", "'.mysql_real_escape_string($description).'")';

    $result = mysql_query($query);

    } } else { // print ("<b>There are no articles in this feed.</b>"); } }

    // close mysql connection @mysql_close($conn);


    You should place the rss.inc.php file on your account where you want to store the feed data into your database. Make sure to edit the database access information in it first. I've commented it with "Set up mysql connection".

  3. Now, just setup a CRON job on the hosting account that will run the rss.inc.php file once per day, per hour or however often you feel is right based on how often you update the feed content. When it runs it will delete the previous data from the rssfeed table and replace it with the updated.

    If you use cPanel this is very easy to do. It should look something like this: (this would run the script every day at 12:30pm)

    30 12 * * * php -q /home/USER/public_html/rss.inc.php >/dev/null 2>&1

  4. In the index.php file or whatever file is applicable that runs the script add these lines:

    $query = 'SELECT id, title, description FROM rssfeed WHERE id>0';
    $result = mysql_query($query);
    while($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
    $conid[] = stripslashes($row['id']);
    $title[] = stripslashes($row['title']);
    $description[] = stripslashes($row['description']);

    $tpl->assign('conid',$conid); $tpl->assign('feedtitle',$title); $tpl->assign('feeddescription',$description);

    Sometimes $tpl->assign is supposed to be $smarty->assign, you would have to look at the index.php and see on other places what the correct word is.

  5. Usually there is a MySQL connection already being done when this file is being run but in case it is not then you must also do this step. If there is then these code lines are not needed.

    Add these lines before the lines in the step before:

    // database access host
    $dbhost = "localhost";
    // database username
    $dbuser = "user_username";
    // password
    $dbpass = "password";
    // database name
    $dbname = "user_dbname";

    // make connection to mysql server $conn = mysql_connect($dbhost, $dbuser, $dbpass) or die ('Error connecting to mysql'); // select which database on mysql server mysql_select_db($dbname);

    With the correct connection parameters.

    And at the end of all those lines:

    // close mysql connection

    If you are accessing the database feed from a separate domain other than the one where the rss.inc.php file is run from you should use the domain name for $dbhost ex. $dbname = "www.jimwestergren.com";

    Also, on your ogirinal domain, the one where the rss.inc.php file is run from you should add the calling domains/IP's/servers to your "Access Hosts". If you use cPanel, this is easy, just login to cPanel for the original domain, click on mysql, at the bottom of the page you will see the "Access Hosts" section, just add calling domains/IP's/servers there.

  6. Now go to the template file (*.tpl) in which you want to display the feed and just add these lines:

    {section name=content loop=$conid}

This is now completed. To see the feed immediately the first time it is probably necessary that you bypass the CRON job by going to rss.inc.php on your server to get the feed content inserted in the database without having to wait for the CRON job to do it.

A revised example of this can be found on the category pages of my directory at www.addurl-free.com. I have however not finalized how it should look like.

It would be nice if you, if you do use this, that you comment and show me how it looks like.

6 Jan 2006

About the Author Jim Westergren Jim Westergren is a Swedish web entrepreneur currently living in Spain. He is happily married and has three lovely children. Some of his interests are web development, SEO and writing.
He is the Founder of DomainStats and N.nu. Read his .