How to Display Next and Previous Article Links in Symphony CMS 2
When a single content entry is displayed on a web page it is often desired that links be provided to the next and previous chronological entries. (This can apply to any content with a date field, not just articles.) This article attempts to explain how this can be done using a single custom data source. It is difficult (impossible?) to do this using only the backend data source creator.
The following assumptions are made in the remainder of this article:
- The single entry data source and the single entry display page are both named article.
- The article title field is in table 23.
- The article date field is in table 26.
- The article publish field is in table 30.
The first step is to add the identification of the currently displayed article to the parameter pool. This is done by requiring the article data source to output the article's entry_id: In the backend data source editor select System ID under Parameter Output, or add the line
public $dsParamPARAMOUTPUT = 'system:id'
to the params near the top of the article data source file.
Then copy the following custom data source, paste it into a file and name it data.nextprevarticle.php, place the file in your workspace/data-sources folder and add this new NextPrevArticle data source to your article page.
<?php
Class datasourcenextprevarticle extends Datasource{
public function __construct(&$parent, $env=NULL, $process_params=true){
parent::__construct($parent, $env, $process_params);
$this->_dependencies = array('$ds-article');
}
public function about(){
return array(
'name' => 'NextPrevArticle',
'author' => array(
'name' => 'Carson Sasser',
'website' => 'http://tech.carsonsasser.com',
'email' => 'sassercw@cox.net'),
'version' => '1.0',
'release-date' => '2011-03-23T21:05:11+00:00');
}
public function allowEditorToParse(){
return false;
}
// Gets the previous and next articles given a current article (ds-article contains
// the entry_id of the current article and comes from the article data source).
public function grab(&$param_pool=NULL){
$result = new XMLElement('next_prev_article');
// Get the entry_id and date (table 26) of the current article.
$entry_id = (int)$param_pool['ds-article'][0];
$sql = "SELECT `local` FROM `tbl_entries_data_26`
WHERE `entry_id` = $entry_id LIMIT 1";
$entry_date = $this->_Parent->Database->fetchVar('local', 0, $sql);
// Get the entry_id of the next published (table 30) article.
$sql = "SELECT t1.`entry_id`
FROM `tbl_entries_data_26` AS t1
LEFT JOIN `tbl_entries_data_30` AS t2 ON t1.entry_id = t2.entry_id
WHERE t1.`local` > $entry_date
AND t2.value = 'yes'
ORDER BY t1.`local` ASC LIMIT 1";
$next_article_id = $this->_Parent->Database->fetchVar('entry_id', 0, $sql);
// Get the title and handle (table 23) of the next article and add them to the XML.
if ($next_article_id) {
$sql = "SELECT handle,value FROM tbl_entries_data_23
WHERE entry_id = $next_article_id LIMIT 1";
$row = $this->_Parent->Database->fetchRow(0, $sql);
$next = new XMLElement('next', $row['value']);
$next->setAttributeArray(array('entry_id' => $next_article_id,
'handle' => $row['handle']));
$result->appendChild($next);
}
// Get the entry_id of the previous published (table 30) article.
$sql = "SELECT t1.`entry_id`
FROM `tbl_entries_data_26` AS t1
LEFT JOIN `tbl_entries_data_30` AS t2 ON t1.entry_id = t2.entry_id
WHERE t1.`local` < $entry_date
AND t2.value = 'yes'
ORDER BY t1.`local` DESC LIMIT 1";
$prev_article_id = $this->_Parent->Database->fetchVar('entry_id', 0, $sql);
// Get the title and handle (table 23) of the previous article and add them to the XML.
if ($prev_article_id) {
$sql = "SELECT handle,value FROM tbl_entries_data_23
WHERE entry_id = $prev_article_id LIMIT 1";
$row = $this->_Parent->Database->fetchRow(0, $sql);
$prev = new XMLElement('previous', $row['value']);
$prev->setAttributeArray(array('entry_id' => $prev_article_id,
'handle' => $row['handle']));
$result->appendChild($prev);
}
return $result;
}
}
?>
If your single article data source is not named Article you will have to edit the two references to ds-article. You will also have to change the table numbers to agree with your article section design.
Here is an example of the XML produced by the above data source:
<next_prev_article>
<next entry_id="9" handle="the-next-article-title">The Next Article Title</next>
<previous entry_id="7" handle="the-previous-article-title">The Previous Article Title</previous>
</next_prev_article>
And here is an example of the XSLT that can be used to display the links:
<xsl:template match="data">
<div class="next_prev_post">
<xsl:apply-templates select="next_prev_article"/>
</div>
</xsl:template>
<xsl:template match="next_prev_article">
<div class='prev_post'>
<xsl:if test="previous">
<a href="{$root}/article/{previous/@handle}"
title="{previous}">Previous article</a>
</xsl:if>
</div>
<div class='next_post'>
<xsl:if test="next">
<a href="{$root}/article/{next/@handle}"
title="{next}">Next article </a>
</xsl:if>
</div>
</xsl:template>
And here is an example of the CSS:
div.next_prev_post {
width: 100%;
height: 30px;
}
div.prev_post {
float: left;
}
div.next_post {
float: right;
}