phphtmlpaginationsilverstripesilverstripe-4

SilverStripe 4 (cms4 / SS4): How to make Next / Previous navigation of sibling pages?


I'm looking to create a simple Next and Previous navigation on sibling pages to allow the user to click through them. They are all on a single level. I've found some docs and an add-on (link below) but these are aimed at displaying data lists no pages. I cant seem to find any tutorial or information on how this can be achieved. I was advised on the following starting point but not sure how to finish it:

$nextlink = SiteTree::get()->filter(['ParentID' => $this->ParentID, 'Sort:GreaterThan' => $this->Sort])->first()->Link();

https://github.com/fromholdio/silverstripe-paged

https://docs.silverstripe.org/en/4/developer_guides/search/searchcontext/


Solution

  • uhm, yeah, the code you have there is exactly what you need to get the link of the next page.
    Let me break it down:

    $nextlink = SiteTree::get()->filter(['ParentID' => $this->ParentID, 'Sort:GreaterThan' => $this->Sort])->first()->Link();
    

    is the one liner version of:

    $allPages = SiteTree::get();
    $allPagesOnTheSameLevel = $allPages->filter(['ParentID' => $this->ParentID]);
    // SilverStripe uses the DB Field "Sort" to decide how to sort Pages. 
    // Sort 0 is at the top/beginning, Sort 999... at the end. So if we want the next
    // page, we just need to get the first page that has a higher "Sort" value than 
    // the current page. Normally ->filter() would search for equal values, but if you 
    // add the modifier `:GreaterThan` than it will search with >. And for PreviousPage 
    // you can use :LessThan
    $currentPageSortValue = $this->Sort;
    $allPagesAfterTheCurrentPage = $allPagesOnTheSameLevel->filter(['Sort:GreaterThan' => $currentPageSortValue]);
    $nextPageAfterTheCurrentPage = $allPagesAfterTheCurrentPage->first();
    if ($nextPageAfterTheCurrentPage && $nextPageAfterTheCurrentPage->exists()) {
      $nextlink = $nextPageAfterTheCurrentPage->Link();
    }
    

    this is PHP code, and it assumes that $this is the current page you are viewing.
    Assuming you have a standard setup with pages being rendered, you could use it the following way:

    (though, I made 1 small modification. Instead of calling ->Link() in php, in the example below I call it in the Template. Instead, I return the full $nextPageAfterTheCurrentPage to the template, this allows me to also use $Title in the template if that is needed)

    <?php
    // in your app/srv/Page.php
    
    namespace \;
    
    use SilverStripe\CMS\Model\SiteTree;
    
    class Page extends SiteTree {
        // other code here
        
        // add this function:
        public function NextPage() {
            $allPages = SiteTree::get();
            $allPagesAfterTheCurrentPage = $allPages->filter(['ParentID' => $this->ParentID, 'Sort:GreaterThan' => $this->Sort]);
            $nextPageAfterTheCurrentPage = $allPagesAfterTheCurrentPage->first();
            return $nextPageAfterTheCurrentPage;
        }
    
        // other code here
    }
    

    and then, in the template (probably Page.ss), you can do:

    <!-- other html here -->
    <% if $NextPage %>
        <!-- you can use any propery/method of a page here. $NextPage.ID, $NextPage.MenuTitle, ... -->
        <!-- if you use something inside an html attribute like title="", then add .ATT at the end, this will remove other " characters to avoid invalid html -->
        <a href="$NextPage.Link" title="$NextPage.Title.ATT">To the next Page</a>
    <% end_if %>
    <!-- other html here -->
    

    For previous page, just do the same thing again, but instead of searching/filtering for GraterThan the current Sort, you have to search/filter LessThan.