Hi,
here is a solution that seems to work to create previous/next links. I have to admit that it's not a very elegant, though.
First of all, if you only need a previous/next link within a section of a page use the Previous or Next Recipe. It's much nicer code.
However, if you want to flip from page to page regardless of the hierarchy level you can use the method below (or come up with a better one; I know there must be a nicer way).
Add this to the Page_Controller class in /mysite/code/Page.php
function PreviousNext(){
// set $max_depth to the maximum level of your site hierarchy (/home/ would be level 0, /home/subpage/ would be level 1, etc...)
$max_depth = 4;
// constructing a SQL query (see the query below *)
$sqlQuery = new SQLQuery();
// the fields to select
for($i=0; $i<=$max_depth; $i++){
$select[] = 't'.$i.'.ID AS ID'.$i;
$select[] = 't'.$i.'.URLSegment AS URLSegment'.$i;
$select[] = 't'.$i.'.Title AS Title'.$i;
$select[] = 't'.$i.'.MenuTitle AS MenuTitle'.$i;
}
$sqlQuery->select = $select;
// we select from the SiteTree table and join the SiteTree table a few times to itself
$from[] = 'SiteTree as t0 ';
for($i=1; $i<=$max_depth; $i++){
$from[] = 'LEFT JOIN SiteTree AS t'.$i.' ON t'.$i.'.ParentID = t'.($i-1).'.ID ';
}
$sqlQuery->from = $from;
// a few WHERE clauses to only return the pages that show in the menus
$where[] = 't0.ParentID = 0 ';
for($i=0; $i<=$max_depth; $i++){
$where[] = '( t'.$i.'.ShowInMenus = 1 OR t'.$i.'.ShowInMenus is null ) ';
}
$sqlQuery->where = $where;
// defining the sort order
$comma = '';
$orderby = '';
for($i=0; $i<=$max_depth; $i++){
$orderby .= $comma.'t'.$i.'.Sort ASC ';
$comma = ', ';
}
$sqlQuery->orderby = $orderby;
// finally execute the query ...
$result = $sqlQuery->execute();
// and create a more useful array from it
$page = array();
foreach($result as $row) {
for($i=0; $i<=$max_depth; $i++){
if(!array_key_exists('URLSegment'.$i, $page) && !is_null($row['URLSegment'.$i])) {
$page[$row['ID'.$i]]['URLSegment'] = $row['URLSegment'.$i];
$page[$row['ID'.$i]]['Title'] = $row['Title'.$i];
$page[$row['ID'.$i]]['MenuTitle'] = $row['MenuTitle'.$i];
}
}
}
// set the array pointer to the current page
while (key($page) != $this->ID) {
if (next($page) === false) return '';
}
// set the array pointer to the previous page; if there is no previous page it means we are on the home page - in this case set the array pointer to the last page
if (!$previousPage = prev($page)) {
$previousPage = end($page);
reset($page);
} else {
// this is a prep step for the next page (setting the array pointer back to the current page)
next($page);
}
// if there is no next page it means we reached the last page; in this case set the array pointer to the first page
if (!$nextPage = next($page)) {
$nextPage = reset($page);
}
// return two links for the previous and next page
$output = '<a href="'.$previousPage['URLSegment'].'" title="Go to the previous page: '.$previousPage['Title'].'">previous page</a> <a href="'.$nextPage['URLSegment'].'" title="Go to the next page: '.$nextPage['Title'].'">next page</a>';
return $output;
}
Then simply add this to the template wherever you need it:
$PreviousNext
Quite messy but it seems to work. I especially would like to get a DataObject as a result to have more control in the template without touching the PHP code, but I didn't have enough time to look that up.
* FYI: the generated SQL query of the code above (for max 4 hierarchy levels) is:
SELECT
t0.Title,
t1.Title,
t2.Title,
t3.Title,
t4.Title
FROM
SiteTree as t0
LEFT JOIN SiteTree AS t1 ON t1.ParentID = t0.ID
LEFT JOIN SiteTree AS t2 ON t2.ParentID = t1.ID
LEFT JOIN SiteTree AS t3 ON t3.ParentID = t2.ID
LEFT JOIN SiteTree AS t4 ON t4.ParentID = t3.ID
WHERE
(
t0.ParentID = 0
) AND (
t0.ShowInMenus = 1 OR t0.ShowInMenus is null
) AND (
t1.ShowInMenus = 1 OR t1.ShowInMenus is null
) AND (
t2.ShowInMenus = 1 OR t2.ShowInMenus is null
) AND (
t3.ShowInMenus = 1 OR t3.ShowInMenus is null
) AND (
t4.ShowInMenus = 1 OR t4.ShowInMenus is null
)
ORDER BY
t0.Sort ASC,
t1.Sort ASC,
t2.Sort ASC,
t3.Sort ASC,
t4.Sort ASC
You can run this query to see the result. The foreach($result as $row) loop then creates something useful from the result.
If you have a better and cleaner way for the whole thing please post it.
Cheers!
Anatol