Properly add pagination to your WordPress Plugin

It has been quite a long I am doing stuffs with WordPress. The one of the nice thing about WordPress is, we get a ready to use admin backend with almost all possible css’ needed! Nice table structure, nested menu, Title with nice icons, pagination…you just name it! WordPress has them all! To use them, what we need to do is code our plugin so that it generates the proper xhtml code with proper css classes. Finding the correct CSS for the correct XHTML can be a little hectic sometimes as it involves reading the source code of WP a bit, but when you are done with it, trust me you will find that you will never need to code CSS for your Admin backend again!

So, in this tutorial, I am going to tell you How to properly add pagination to your WordPress Plugin! Of course, properly in the sense of proper xHTML structure with proper CSS. Even better is, I have created a class file which you can directly use on your plugins to create pagination in no time. So enough of this introduction, let us get into the business!

#1: WordPress backend pagination, Looks and Source code:

The pagination is basically a way to split long list of records into several pages, so that it reduces the load on the browser and the server, while displaying a humanly easy to interpret list of data. For example, if you have quite a number of posts, then you should have seen links above and below the post tables to different pages.

WordPress deals nicely with the pagination design. In order to get that, you need to have the following piece of XHTML code in your plugin:

<div class="tablenav">
    <div class="alignleft actions">
        <input type="submit" value="Bulk Delete" class="button-secondary">
    </div>
    <div class="tablenav-pages">
        <span class="displaying-num">28 items</span>
        <span class="pagination-links">
            <a class="disabled" href="javascript: void(0)">« Previous</a>
        <a class="current" href="javascript: void(0)">1</a>
            <a href="admin.php?page=itgdb_iwifm_admin_show_form&amp;p=2">2</a>
            <a class="next" href="admin.php?page=itgdb_iwifm_admin_show_form&amp;p=2">Next »</a>
        </span>
    </div>
</div>

Seems easy enough? Now, let us make it a bit more easier.

#2: A pagination class for using with WordPress:

Depending on this xhtml structure, I created a pagination class. This class is actually ported from the famous Digg Style Pagination Class by Victor De la Rocha.

class pagination {
    /**
     *  Script Name: WP Style Pagination Class
     *  Created From: *Digg Style Paginator Class
     *  Script URI: https://www.intechgrity.com/?p=794
     *  Original Script URI: http://www.mis-algoritmos.com/2007/05/27/digg-style-pagination-class/
     *  Description: Class in PHP that allows to use a pagination like WP in your WP Plugins
     *  Script Version: 1.0.0
     *
     *  Author: Swashata Ghosh <swashata4u@gmail.com
     *  Author URI: https://www.intechgrity.com/
     *  Original Author: Victor De la Rocha
     */

    /* Default values */

    var $total_pages = -1; //items
    var $limit = null;
    var $target = "";
    var $page = 1;
    var $adjacents = 2;
    var $showCounter = false;
    var $className = "pagination-links";
    var $parameterName = "p";

    /* Buttons next and previous */
    var $nextT = "Next";
    var $nextI = "&#187;"; //&#9658;
    var $prevT = "Previous";
    var $prevI = "&#171;"; //&#9668;

    /*     * ** */
    var $calculate = false;

    #Total items

    function items($value) {
        $this->total_pages = (int) $value;
    }

    #how many items to show per page

    function limit($value) {
        $this->limit = (int) $value;
    }

    #Page to sent the page value

    function target($value) {
        $this->target = $value;
    }

    #Current page

    function currentPage($value) {
        $this->page = (int) $value;
    }

    #How many adjacent pages should be shown on each side of the current page?

    function adjacents($value) {
        $this->adjacents = (int) $value;
    }

    #show counter?

    function showCounter($value="") {
        $this->showCounter = ($value === true) ? true : false;
    }

    #to change the class name of the pagination div

    function changeClass($value="") {
        $this->className = $value;
    }

    function nextLabel($value) {
        $this->nextT = $value;
    }

    function nextIcon($value) {
        $this->nextI = $value;
    }

    function prevLabel($value) {
        $this->prevT = $value;
    }

    function prevIcon($value) {
        $this->prevI = $value;
    }

    #to change the class name of the pagination div

    function parameterName($value="") {
        $this->parameterName = $value;
    }

    var $pagination;

    function pagination() {

    }

    function show() {
        if (!$this->calculate)
            if ($this->calculate())
                echo "<span class=\"$this->className\">$this->pagination</span>\n";
    }

    function getOutput() {
        if (!$this->calculate)
            if ($this->calculate())
                return "<span class=\"$this->className\">$this->pagination</span>\n";
    }

    function get_pagenum_link($id) {
        if (strpos($this->target, '?') === false)
            return "$this->target?$this->parameterName=$id";
        else
            return "$this->target&$this->parameterName=$id";
    }

    function calculate() {
        $this->pagination = "";
        $this->calculate == true;
        $error = false;

        if ($this->total_pages < 0) {
            echo "It is necessary to specify the <strong>number of pages</strong> (\$class->items(1000))<br />";
            $error = true;
        }
        if ($this->limit == null) {
            echo "It is necessary to specify the <strong>limit of items</strong> to show per page (\$class->limit(10))<br />";
            $error = true;
        }
        if ($error)
            return false;

        $n = trim($this->nextT . ' ' . $this->nextI);
        $p = trim($this->prevI . ' ' . $this->prevT);

        /* Setup vars for query. */
        if ($this->page)
            $start = ($this->page - 1) * $this->limit;             //first item to display on this page
        else
            $start = 0;                                //if no page var is given, set start to 0

        /* Setup page vars for display. */
        $prev = $this->page - 1;                            //previous page is page - 1
        $next = $this->page + 1;                            //next page is page + 1
        $lastpage = ceil($this->total_pages / $this->limit);        //lastpage is = total pages / items per page, rounded up.
        $lpm1 = $lastpage - 1;                        //last page minus 1

        /*
          Now we apply our rules and draw the pagination object.
          We're actually saving the code to a variable in case we want to draw it more than once.
         */

        if ($lastpage > 1) {
            if ($this->page) {
                //anterior button
                if ($this->page > 1)
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link($prev) . "\" class=\"prev\">$p</a>";
                else
                    $this->pagination .= "<a href=\"javascript: void(0)\" class=\"disabled\">$p</a>";
            }
            //pages
            if ($lastpage < 7 + ($this->adjacents * 2)) {//not enough pages to bother breaking it up
                for ($counter = 1; $counter <= $lastpage; $counter++) {
                    if ($counter == $this->page)
                        $this->pagination .= "<a href=\"javascript: void(0)\" class=\"current\">$counter</a>";
                    else
                        $this->pagination .= "<a href=\"" . $this->get_pagenum_link($counter) . "\">$counter</a>";
                }
            }
            elseif ($lastpage > 5 + ($this->adjacents * 2)) {//enough pages to hide some
                //close to beginning; only hide later pages
                if ($this->page < 1 + ($this->adjacents * 2)) {
                    for ($counter = 1; $counter < 4 + ($this->adjacents * 2); $counter++) {
                        if ($counter == $this->page)
                            $this->pagination .= "<a href=\"javascript: void(0)\" class=\"current\">$counter</a>";
                        else
                            $this->pagination .= "<a href=\"" . $this->get_pagenum_link($counter) . "\">$counter</a>";
                    }
                    $this->pagination .= "<span>...</span>";
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link($lpm1) . "\">$lpm1</a>";
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link($lastpage) . "\">$lastpage</a>";
                }
                //in middle; hide some front and some back
                elseif ($lastpage - ($this->adjacents * 2) > $this->page && $this->page > ($this->adjacents * 2)) {
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link(1) . "\">1</a>";
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link(2) . "\">2</a>";
                    $this->pagination .= "<span>...</span>";
                    for ($counter = $this->page - $this->adjacents; $counter <= $this->page + $this->adjacents; $counter++)
                        if ($counter == $this->page)
                            $this->pagination .= "<a href=\"javascript: void(0)\" class=\"current\">$counter</a>";
                        else
                            $this->pagination .= "<a href=\"" . $this->get_pagenum_link($counter) . "\">$counter</a>";
                    $this->pagination .= "<span>...</span>";
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link($lpm1) . "\">$lpm1</a>";
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link($lastpage) . "\">$lastpage</a>";
                }
                //close to end; only hide early pages
                else {
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link(1) . "\">1</a>";
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link(2) . "\">2</a>";
                    $this->pagination .= "<span>...</span>";
                    for ($counter = $lastpage - (2 + ($this->adjacents * 2)); $counter <= $lastpage; $counter++)
                        if ($counter == $this->page)
                            $this->pagination .= "<a href=\"javascript: void(0)\" class=\"current\">$counter</a>";
                        else
                            $this->pagination .= "<a href=\"" . $this->get_pagenum_link($counter) . "\">$counter</a>";
                }
            }
            if ($this->page) {
                //siguiente button
                if ($this->page < $counter - 1)
                    $this->pagination .= "<a href=\"" . $this->get_pagenum_link($next) . "\" class=\"next\">$n</a>";
                else
                    $this->pagination .= "<a href=\"javascript: void(0)\" class=\"disabled\">$n</a>";
            }
        }

        return true;
    }

}

Just copy the above code to your Plugin files and use it something like this:

<?php
//get the number of records in the database table
$pagination_count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(`id`) FROM `" . $wpdb->prefix . "my_plugin_table`"));
if($pagination_count > 0) {
    //get current page
    $this_page = ($_GET['p'] && $_GET['p'] > 0)? (int) $_GET['p'] : 1;
    //Records per page
    $per_page = 25;
    //Total Page
    $total_page = ceil($pagination_count/$per_page);

    //initiate the pagination variable
    $pag = new pagination();
    //Set the pagination variable values
    $pag->Items($pagination_count);
    $pag->limit($per_page);
    $pag->target("admin.php?page=itgdb_iwifm_admin_show_form");
    $pag->currentPage($this_page);

    //Done with the pagination
    //Now get the entries
    //But before that a little anomaly checking
    $list_start = ($this_page - 1)*$per_page;
    if($list_start >= $pagination_count)  //Start of the list should be less than pagination count
        $list_start = ($pagination_count - $per_page);
    if($list_start < 0) //list start cannot be negative
        $list_start = 0;
    $list_end = ($this_page * $per_page) - 1;

    //Get the data from the database
    $records = $wpdb->get_results($wpdb->prepare("SELECT * FROM `" . $wpdb->prefix . "my_plugin_table` ORDER BY `my_field1` DESC LIMIT %d, %d", $list_start, $per_page));

    if($records) {
        //Do something with it! Probably display table
        ?>
        <table class="widefat">
            <thead>
                <tr>
                    <td>Field 1</td>
                    <td>Field 2</td>
                </tr>
            </thead>
            <tbody>
                <?php
                //loop through
                foreach($records as $record) {
                    ?>
                <tr>
                    <td>
                        <?php echo $record->field1; ?>
                    </td>
                    <td>
                        <?php echo $record->field2; ?>
                    </td>
                </tr>
                    <?php
                }
                ?>
            </tbody>
        </table>
        <?php
        //Now display the pagiantion links
        ?>
            <div class="tablenav">
                <div class="alignleft actions">
                    <input type="submit" class="button-secondary" value="Bulk Delete" />
                </div>
                <div class="tablenav-pages">
                    <span class="displaying-num"><?php echo $pagination_count; ?> items</span>
                    <?php $pag->show(); ?>
                </div>
            </div>
        <?php
    }
    else {
        echo '<div class="error"><p>Something Went wrong! Check</p></div>';
    }
}
else {
    echo '<div class="error"><p>No Data</p></div>';
}
?>

The best thing is, you don’t even have to code any sort of other CSS for this pagination. The WordPress admin.css file has all the codes needed to style up the markups! So just get the class and enjoy coding your WordPress plugin the way it is meant to be!

I hope, you have found this tutorial helpful! If you need any help then feel free to ask, and as usual, don’t forget to give your feedback!

11 comments

  1. 5 year mortgage rates

    “Add styled pagination to your WordPress Plugin admin backend | InTechgrity” Strange this post is totaly irrelevant to the search query I entered in google but it was listed on the first page. You lucky sucker!

  2. Prakash

    Hi,

    This is excellent tutorials for who want pagination in any where in the wordpress. Thanks to all off us who are behind this wonderful article.

    one thing i want to tell,

    //Get the data from the database
    $records = $wpdb->get_results($wpdb->prepare(“SELECT * FROM `” . $wpdb->prefix . “my_plugin_table` ORDER BY `my_field1` DESC LIMIT %d, %d”, $list_start, $list_end));

    instead of “$list_end” variable in query use “$per_page” then we will get perfect pagination with requested items per page.

    Thanks
    Prakash

  3. Raymond

    Nice write up, however how can we take this one step further and add SEARCH into the mix? Let’s say our plugin creates custom post types where eventually there could be a long list of posts and we may want to have a search field.

    Any idea?

  4. nomikos

    Just to say that at this time WP3.4.1 works perfectly out of the box.
    Many Thanks Swashata.-

  5. Gurpreet kaur

    hello Swashata, thanks for your coding.i completely understand this coding and i m using it in my plugin. but i have an problem, when i clicked on 2nd page link i got the statement “You do not have sufficient permissions to access this page.” and no data is visible. plzzzz…help me. why this error?? i checked all the coding very well but didn’t found any error…did i have to make some changes??plzzzz… reply as soon as possible.

Comments are closed.