SSbits - Home page
Site by Carbon Crayon
Submit a Post >

Tutorials - Big bits of code to help you do more

Creating Previous and Next Buttons on a page

When you have a number of pages which follow on from one another you may find that asking a user to return to an index or select the next item from a side menu each time they want to progress is cumbersome. In this situation having previous and next buttons at the bottom of a page becomes very useful. In this snippet we'll add these buttons and also a counter to show the current page we are on and the total number of pages.

First add this function to your Page_Controller class:

    public function PrevNextPage($Mode = 'next') {
	  
	  if($Mode == 'next'){
	  	$Where = "ParentID = ($this->ParentID) AND Sort > ($this->Sort)";
		$Sort = "Sort ASC";
	  }
	  elseif($Mode == 'prev'){
	  	$Where = "ParentID = ($this->ParentID) AND Sort < ($this->Sort)";
		$Sort = "Sort DESC";
	  }
	  else{
	  	return false;
	  }
	  
	  return DataObject::get("SiteTree", $Where, $Sort, null, 1);
	  	
    }

Let's go through the function. First we pass in a string $Mode. This will be used to decide whether to return the previous or next page.

Then if we have passed in 'next' (the default) we setup the database criteria for that page, which is having the same parent ID and a sort value that is higher than the current page. We also set the database sort to arrange the pages by their Sort value in Ascending order. Otherwise if $Mode is 'prev' then we setup the criteria to fetch the previous page. If $Mode was not equal to either 'next' or 'prev' then we just return false.

Finally we do the database call and grab a single page using the criteria we set in the first part of the function and return the result.

Now we can use this function in our template like so:

<% control PrevNextPage(prev) %>
	  <a href="$Link" title="Go to $Title">&lt; previous page</a>	
<% end_control %>
<% control PrevNextPage(next) %>				
	  <a href="$Link" title="Go to $Title">next page &gt; </a>
<% end_control %>

By wrapping the links in <% control %> blocks instead of using $Variables, we prevent the link from being drawn if there is no page to go to.

Finally we can also add these functions to our Page_Controller to enable us to print the current page's number and the total number of pages:

public function NumberOfSiblings(){
	return DataObject::get("SiteTree","ParentID = ($this->ParentID)")->Count();
}
public function CurrentPageNumber(){
	return (DataObject::get("SiteTree","ParentID = ($this->ParentID) AND Sort <= ($this->Sort)")->Count());
}

And then in our template:

<p>Page $CurrentPage of $NoOfSiblings</p>

Thanks to Rick for suggesting this snippet!

Aram Balakjian avatar

Aram Balakjian

Aram is a web developer running London based agency Aab Web. He has a strong passion for developing attractive, usable sites around the SilverStripe CMS.

  • bazilio
    14/10/2010 12:40pm (4 years ago)

    cant post any code to comment, if fails (% or $)

  • Aram Balakjian
    14/10/2010 1:02pm (4 years ago)

    Hi Bazilio, it seems to work ok for me?

    function test(){
    $CommentTest = $this->MyComment()->Test;
    %f = % 5;
    }

  • Prawnstar
    20/05/2011 8:11pm (4 years ago)

    Hi, Aram,

    I followed your tutorial here and have noted that when PrevNextPage() returns false (i.e., no more previous or next records) the link is still printed in the template.ss because it lacks an 'if' statement. Even though the function is returning false, the link gets printed. For me the link takes me to the home page.

    Something like this solved my issue (could use an else statement):
    <% if Link %>
    <a href="$Link" title="Go to $Title">previous page</a>
    <% end_if %>

  • R Estar
    01/01/2012 1:49pm (3 years ago)

    Thanks, I was really hoping to find something like this! Only problem for me is that, in applying Prawnstar's suggestion and adding in an <% else %> tag, I CANNOT use $Parent.Link. I have tried putting plain text after then 'else' tag, and that works fine (which is what I have right now). I also tried creating a link using $Parent.Link in a different spot on the page (so, not inside this <% control ... %>) and that works fine. But no matter what I try, I cannot create a Parent link inside the control!!! Please help... I have searched for a solution and I cannot find one.

  • R Estar
    01/01/2012 1:54pm (3 years ago)

    Sorry, let me edit that... As soon as I hit 'Post' I realized that I had not tried using $Parent.Link inside the <% if .... %> but before the <% else %> tag. Sure enough, it works inside the control as long as it's not after the 'else' tag. Of course, that still doesn't help me because I am still unable to do what I need to... So confused!

  • benshu
    14/06/2012 8:06am (3 years ago)

    Great article, was very usefull.

    Just for those copy pasting, the last snippet:
    <p>Page $CurrentPage of $NoOfSiblings</p>

    should be:
    <p>Page $CurrentPageNumber of $NumberOfSiblings</p>

  • Matty Balaam
    09/02/2013 12:29pm (2 years ago)

    I updated this to work with the new DataList in Silverstripe 3. Any improvements welcome:

    public function PrevNextPage($Mode = 'next') {


    if($Mode == 'next'){
    $Direction = "Sort:GreaterThan";
    $Sort = "Sort ASC";
    }
    elseif($Mode == 'prev'){
    $Direction = "Sort:LessThan";
    $Sort = "Sort DESC";
    }
    else{
    return false;
    }

    $PrevNext = SiteTree::get()
    ->filter(array(
    'ParentID' => $this->ParentID,
    $Direction => $this->Sort
    ))
    ->sort($Sort)
    ->First()
    ;

    if ($PrevNext) return $PrevNext;
    }

  • Reece Cropley
    01/10/2013 4:02pm (1 year ago)

    Hi Matty Balaam,

    I have tried to use your version of the code on my site. Im pretty useless when developing SilverStripe.

    I have the function in my controller, as so:

    public function PrevNextPage($Mode = 'next') {
    if($Mode == 'next'){
    $Direction = "Sort:GreaterThan";
    $Sort = "Sort ASC";
    }
    elseif($Mode == 'prev'){
    $Direction = "Sort:LessThan";
    $Sort = "Sort DESC";
    }
    else{
    return false;
    }

    $PrevNext = SiteTree::get()->filter(array('ParentID' => $this->ParentID, $Direction => $this->Sort))->sort($Sort)->First();

    if ($PrevNext) return $PrevNext;
    }

    And then in my page.ss, i have the following:

    <% control PrevNextPage(prev) %>
    <a href="$Link" title="Go to $Title">&lt; previous page</a>
    <% end_control %>
    <% control PrevNextPage(next) %>
    <a href="$Link" title="Go to $Title">next page &gt; </a>
    <% end_control %>

    But when I go to view the site it produces the following:

    <a href="" title="Go to ">&lt; previous page</a>
    <a href="" title="Go to ">next page &gt; </a>

    This makes me think that the $Link and $Title, aren't working. I don't suppose by looking on what I have you can tell me. I think maybe becuase im using code from two versions of SS its not working?

    All help is greatly appreciated.

  • Matty Balaam
    01/10/2013 9:32pm (1 year ago)

    if you change from <% control foo %> .... <% end_control %> to <% loop foo %> ,,, <% end_foo %> it should work.

    Control blocks have been depreciated now and are replace with 'loop' for a list or 'with' for single items.

  • Reece Cropley
    14/10/2013 4:17pm (1 year ago)

    Hi Matty, thanks for a reply and apologies for getting back so late. This still isn't working

    I have changed it over to:

    <% loop PrevNextPage(prev) %>
    <a href="$Link" title="Go to $Title">&lt; previous page</a>
    <% end_loop %>
    <% loop PrevNextPage(next) %>
    <a href="$Link" title="Go to $Title">next page &gt; </a>
    <% end_loop %>

    this is in my VirtualPage.ss.

    I then have the following code in my Controller class, is this all correct?

    public function PrevNextPage($Mode = 'next') {
    if($Mode == 'next'){
    $Direction = "Sort:GreaterThan";
    $Sort = "Sort ASC";
    }
    elseif($Mode == 'prev'){
    $Direction = "Sort:LessThan";
    $Sort = "Sort DESC";
    }
    else{
    return false;
    }

    $PrevNext = SiteTree::get()->filter(array('ParentID' => $this->ParentID, $Direction => $this->Sort))->sort($Sort)->First();

    if ($PrevNext) return $PrevNext;
    }

    im still getting broken links, as if nothing is returned as $Link or $Title. Can you see anything that incorrect at all?

  • Reece Cropley
    14/10/2013 4:37pm (1 year ago)

    Scrap that previous comment its working now (not sure how). I also changed it slightly in the .ss so that it doesnt print the prev/next if it doesnt exist:

    <% if PrevNextPage(prev) %>
    <% loop PrevNextPage(prev) %>
    <a href="$Link" title="Go to $Title">&lt; previous page</a>
    <% end_loop %>
    <% end_if %>
    <% if PrevNextPage(next) %>
    <% loop PrevNextPage(next) %>
    <a href="$Link" title="Go to $Title">next page &gt; </a>
    <% end_loop %>
    <% end_if %>

  • codemonkey88
    19/12/2013 12:08pm (1 year ago)

    I have done this for news articles by simply using get_one;

    public function articlelink($type)
    {
    switch($type)
    {
    case "prev": $filter = "Sort = $this->Sort - 1"; break;
    case "next": $filter = "Sort = $this->Sort + 1"; break;
    default: $filter = "";
    }
    return DataObject::get_one("Article", $filter);
    }

    On the first and last pages, it returns false, so again just wrap in a
    <% if articlelink(prev) %>

Post a comment ...

You cannot post comments until you have logged in. Login Here.

Advertisement

Site of the Month

Find SSbits on

Top Contributers

Rank Avatar Name
1 article image Aram Balakjian
2 article image Daniel Hensby
3 article image Marcus Dalgren
4 article image Hamish Campbell
5 article image Ty Barho
6 article image Martijn van Nieuwenhoven
7 article image Darren-Lee
8 article image Roman Schmid
9 article image Matt Clegg
10 article image dalesaurus

View full leaderboard


Advertisement