Page 1 of 1

Digg-like Pagination Links

Posted: Tue Aug 12, 2008 4:51 pm
by jayshields
Just finished up writing this for my current project, wondered if anyone would like to improve it and/or provide criticism. I feel it's something alot of people could make use of, and can be learnt from easily because it's not included in some huge pagination class. Working example shown here (you can grab the CSS from there too). Closely follows the way Digg handle their page links.

There are some minor bugs in it, and the logic isn't great - this is where you come in :lol:

Code: Select all

    //Show the page links
    echo '
    <ul class="pagelinks">';
    
    //Show the previous page link
    if($page == 1)
        echo '<li class="disabled">&#171; Previous</li>';
    else
        echo '<li><a href="' . $_SERVER['PHP_SELF'] . '?page=' . ($page - 1) . '">&#171; Previous</a></li>';
    
    //If the amount of pages is 2 or more
    if($pagetotal >= 2)
        //Show the first 2 page links
        for($x = 1; $x <= 2; $x++)
            if($page == $x)
                echo '<li class="current">' . $x . '</li>';
            else
                echo '<li><a href="' . $_SERVER['PHP_SELF'] . '?page=' . $x . '">' . $x . '</a></li>';
 
    //If the page number is more than 8
    if($page > 8/*SOMEONE REALL Y NEEDS TO SORT OUT "8 )" BEING TURNED INTO A SMILEY AUTOMATICALLY INSIDE CODE TAGS!!!*/)
    {
        //Show a spacer
        echo '<li class="disabled">...</li>';
 
        //Loop through page numbers 5 before the current page, and to a maximum of 5 after
        for($x = ($page - 5); $x <= ($pagetotal - 2) && $x <= ($page + 5); $x++)
            //Show the page link
            if($page == $x)
                echo '<li class="current">' . $x . '</li>';
            else
                echo '<li><a href="' . $_SERVER['PHP_SELF'] . '?page=' . $x . '">' . $x . '</a></li>';
    }
    //If the total amount of pages is 3 or more
    else if($pagetotal >= 3)
    {
        //Loop through page numbers starting from 3 and going to a maximum of 5 after the current page
        for($x = 3; $x <= ($pagetotal - 2) && $x <= ($page + 5); $x++)
            //Show the page link
            if($page == $x)
                echo '<li class="current">' . $x . '</li>';
            else
                echo '<li><a href="' . $_SERVER['PHP_SELF'] . '?page=' . $x . '">' . $x . '</a></li>';
    }
    
    //If the current page is more than 7 pages from the last page
    if($page < ($pagetotal - 7))
    {
        //Show a spacer
        echo '<li class="disabled">...</li>';
    }
    
    //A special case if the page total is 3 (only one ending link is needed instead of 2)
    if($pagetotal == 3)
        //Show the page link
        if($page == 3)
            echo '<li class="current">3</li>';
        else
            echo '<li><a href="' . $_SERVER['PHP_SELF'] . '?page=3">3</a></li>';
    //If it's anything else over 2
    else if($pagetotal > 3)
        //Loop through the final 2 page numbers
        for($x = ($pagetotal - 1); $x <= $pagetotal; $x++)
            //Show the page link
            if($page == $x)
                echo '<li class="current">' . $x . '</li>';
            else
                echo '<li><a href="' . $_SERVER['PHP_SELF'] . '?page=' . $x . '">' . $x . '</a></li>';
 
    //Show the next page link
    if($page == $pagetotal)
        echo '<li class="disabled">Next &#187;</li>';
    else
        echo '<li><a href="' . $_SERVER['PHP_SELF'] . '?page=' . ($page + 1) . '">Next &#187;</a></li>';
 
    echo '
    </ul>';
 
 
 

Re: Digg-like Pagination Links

Posted: Wed Aug 13, 2008 3:33 am
by matthijs
One thing, not related to the logic, is the use of $_SERVER['PHP_SELF'], which is not safe to use (can contain user injected input, XSS). Luke blogged about it here http://www.mc2design.com/blog/php_self- ... ternatives

Re: Digg-like Pagination Links

Posted: Wed Aug 13, 2008 3:40 am
by Christopher
Maybe you could package it up in a class with a nice interface, to make it more usable by others.

Re: Digg-like Pagination Links

Posted: Wed Aug 13, 2008 3:48 am
by onion2k
I really don't like the way it changes the number of available options. It's inconsistent, and that's a very bad thing in an interface. There should always be, for example, 7 paging links. Eg

Code: Select all

Page 1 - _1_ 2 3 4 5 6 ... 20
Page 3 - 1 2 _3_ 4 5 6 ... 20
Page 9 - 1 ... 7 8 _9_ 10 11 ... 20
Page 20 - 1 ... 15 16 17 18 19 _20_
7 links maintains a balance.. there are always 2 links on either side of the page you're on plus the first and last links.

Re: Digg-like Pagination Links

Posted: Wed Aug 13, 2008 5:22 am
by jayshields
@matthijs: Thanks for the heads-up on $_SERVER['PHP_SELF'] - I usually stay away from just # because it makes URL's look ugly, but from now on I'll be using basename(__FILE__).

@onion2k: Yeah, I'm aware of that - although I don't think anyone would notice it when it's actually in use. Besides, I said I was following the way Digg (and, f.e. phpBB forums) handle their page numbers, and as far as I can tell, they too have this same problem. I'll look into fixing that anyway.

@aborint: I'm not really looking to put it in a class; from my point of view, I often re-code things like this to give my brain something to do, and I think some procedural code logic to look at is good to get people started on writing their own. I don't really think it warrants a class (could be a part of a class to handle the whole pagination issue), because all it really is is one function.

Re: Digg-like Pagination Links

Posted: Wed Aug 20, 2008 1:12 pm
by Christopher
jayshields wrote:@aborint: I'm not really looking to put it in a class; from my point of view, I often re-code things like this to give my brain something to do, and I think some procedural code logic to look at is good to get people started on writing their own. I don't really think it warrants a class (could be a part of a class to handle the whole pagination issue), because all it really is is one function.
Here is a very quick hack at turning this into a class. It centralizes some things, but there is still a lot I would want to improve. Ultimately you should be able to replace all of the HTML template with your own code and be able to set all the various options like CSS class names, number of items in the list, number at the beginning and end show, etc. I would also like it to sort out the number of pages based on the number of records and the records per page.

Code: Select all

class Paginator
{  
    public $page = 0;
    public $pagetotal = 0;
    public $base;
    public $prevLabel = '&#171; Previous';
    public $nextLabel = 'Next &#187';
    public $disabledCssClass = 'disabled';
    public $enabledCssClass = 'enabled';
    
   
    function __construct($page, $pagetotal)
    {
        $this->page = isset($page) ? (int)$page : 1;
        $this->pagetotal = $pagetotal;
        $this->base = basename($_SERVER['SCRIPT_NAME']);
    }
   
    public function getLink($page, $label)
    {
        // bounds check
        if ($page < 1) {
            $page = 1;
        }
        if ($page > $this->pagetotal) {
            $page = $this->pagetotal;
        }
        // show label only for current page, or link
        if($page == $this->page) {
            return "<li class=\"disabled\">$label</li>\n";
        } else {
            return '<li><a href="' . $this->base . '?page=' . $page . "\">$label</a></li>\n";
        }
    }
   
    public function render()
    {
        $out = '';
    
        //Show list
        $out .= "<ul class=\"pagelinks\">\n";
       
        //Show the previous page link
        $out .= $this->getLink($this->page - 1, $this->prevLabel);
       
        //If the amount of pages is 2 or more
        if($this->pagetotal >= 2)
            //Show the first 2 page links
            for($x = 1; $x <= 2; $x++) {
                $out .= $this->getLink($x, $x);
            }
             
        //If the page number is more than 8
        if($this->page > 8 )
        {
            //Show a spacer
            $out .= '<li class="disabled">...</li>';
     
            //Loop through page numbers 5 before the current page, and to a maximum of 5 after
            for($x = ($this->page - 5); $x <= ($this->pagetotal - 2) && $x <= ($this->page + 5); $x++) {
                //Show the page link
                $out .= $this->getLink($x, $x);
            }
         }
        //If the total amount of pages is 3 or more
        else if($this->pagetotal >= 3)
        {
            //Loop through page numbers starting from 3 and going to a maximum of 5 after the current page
            for($x = 3; $x <= ($this->pagetotal - 2) && $x <= ($this->page + 5); $x++) {
                //Show the page link
                $out .= $this->getLink($x, $x);
            }
         }
       
        //If the current page is more than 7 pages from the last page
        if($this->page < ($this->pagetotal - 7))
        {
            //Show a spacer
            $out .= '<li class="disabled">...</li>';
        }
       
        //A special case if the page total is 3 (only one ending link is needed instead of 2)
        if($this->pagetotal == 3) {
            //Show the page link
            $out .= $this->getLink($this->pagetotal, $this->pagetotal);
    
        //If it's anything else over 2
        } elseif($this->pagetotal > 3) {
            //Loop through the final 2 page numbers
            for($x = ($this->pagetotal - 1); $x <= $this->pagetotal; $x++) {
                //Show the page link
                $out .= $this->getLink($x, $x);
            }
        }
      
        //Show the next page link
        $out .= $this->getLink($this->page + 1, $this->nextLabel);
     
        $out .= "</ul>\n";
        return $out;
    }   
 
}
 
 
And to use it:

Code: Select all

$paginator = new Paginator($_GET['page'], 10);
echo $paginator->render();

Re: Digg-like Pagination Links

Posted: Wed Aug 20, 2008 3:28 pm
by ghurtado
Your code has been smiley-fied! :)

Re: Digg-like Pagination Links

Posted: Wed Aug 20, 2008 4:49 pm
by Christopher
Just BBcode telling me that I shouldn't have all those constants in the code! ;) They should be properties so that you can make the list of links any size you want.

Re: Digg-like Pagination Links

Posted: Tue Sep 16, 2008 5:33 pm
by thinsoldier
If I were designing a layout that this thing had to fit into I'd be pretty annoyed the first time I went to a page 12.

compare the width of 12
http://www.jay-designs.co.uk/pagelinkse ... hp?page=12

versus 1 or 20
http://www.jay-designs.co.uk/pagelinkse ... php?page=1
http://www.jay-designs.co.uk/pagelinkse ... hp?page=20


*Edit: seems I was late to the party :banghead:

Anyway, turning my pagination code into a class was the best decision I ever made.
The next best decision would be to put my html generating code somewhere else.