Pagination with CodeIgniter

When you perform a search on Google, the results are displayed in a list and you have the option to click through pages of the results. That is an example of pagination. Pagination simply means the user has the ability to click through the pages of results, viewing a subset of them each time, rather than having to scroll down the screen for ages.

Pagination is particularly useful when you are coding an application that interfaces with a database. A large dataset might have hundreds of possible results for one query, and pagination creates a much nicer user experience.

In this tutorial, I’ll use CodeIgniter’s pagination library to show you how you can create a paginated list of results from a MySQL database. Along the way, you’ll also see how to fix a problem with the pagination links that the library might produce.

I’ll assume you have an installation of CodeIgniter 2.1 ready to go. For the database, I’ll use the official sample database provided by MySQL that available for download as an SQL file.

The Model

We’ll start by creating a model in the application which needs to do two things: provide a count of all the records in the Country table, and retrieve a list of countries from the table. Save the following as models/countries.php:

class Countries extends CI_Model
{
    public function __construct() {
        parent::__construct();
    }

    public function record_count() {
        return $this->db->count_all("Country");
    }

    public function fetch_countries($limit, $start) {
        $this->db->limit($limit, $start);
        $query = $this->db->get("Country");

        if ($query->num_rows() > 0) {
            foreach ($query->result() as $row) {
                $data[] = $row;
            }
            return $data;
        }
        return false;
   }
}

CodeIgniter’s database class with Active Record is used to count and retrieve the data from the database.

The record_count() method returns the number of records and is needed because one of the options in the $config array for the pagination library is $config["total_rows"]. The library will use this along with other options we set to work out how to divide the results up into pages.

The fetch_countries() method retrieves a list of all the records from the Country table. There are two arguments for this method: $limit and $start. They will be passed into the query to determine how many records to return, and what record to start from. The arguments will be set in the controller.

The Controller

Next, we need to create a method in the default Welcome controller (controllers/welcome.php) called example1(). But just before we do that, we’ll need to load the model and also the pagination library in the class’ constructor.

<?php
class Welcome extends CI_Controller 
{
    public function __construct() {
        parent:: __construct();
        $this->load->helper("url");
        $this->load->model("Countries");
        $this->load->library("pagination");
    }

    public function example1() {
        $config = array();
        $config["base_url"] = base_url() . "welcome/example1";
        $config["total_rows"] = $this->Countries->record_count();
        $config["per_page"] = 20;
        $config["uri_segment"] = 3;

        $this->pagination->initialize($config);

        $page = ($this->uri->segment(3)) ? $this->uri->segment(3) : 0;
        $data["results"] = $this->Countries->
            fetch_countries($config["per_page"], $page);
        $data["links"] = $this->pagination->create_links();

        $this->load->view("example1", $data);
    }
}

The example1() method starts by providing some of the most common configuration options for the pagination library. The options are placed in an array which is then passed as an argument to the library’s initialize method. The library requires the options must pass a base URL, a total row count, how many rows per page we want, and which part of the URL will contain the page section the user is using.

Remember those parameters that were set required by the query for a list of countries ($limit and $start)? Those are set next in the call to the model’s fetch_countries() method. The $page variable uses the ternary operator to either set its value to whatever is in the third segment of the URI string or to zero (meaning the user is on the first page).

Finally, the create_links() method of the pagination library creates the pagination links and then we load the view to display the outcome.

The View

For the view file, we can copy the views/welcome_message.php and called it example1.php and replace most of the content of the body with the following:

<body>
 <div id="container">
  <h1>Countries</h1>
  <div id="body">
<?php
foreach($results as $data) {
    echo $data->Name . " - " . $data->Continent . "<br>";
}
?>
   <p><?php echo $links; ?></p>
  </div>
  <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds</p>
 </div>
</body>

So now when you visit http://yourdomain/welcome/example1 you should see something like this:

More Config Options

Click the pagination links and you should find yourself moving through the 239 records in the Country table. But you may notice that the number of linked digits change. Initially there were there digits, and later there five!

There is a config item that might help to solve this problem. It’s probably useful at this stage to remember that we are retrieving records from a database and CodeIgniter has to re-calculate the digit links as each page is accessed. The first thing we can do is to disable the first/last previous/next links to tidy up the navigation. It doesn’t stop the expanding digits, but it does tidy things up.

The second thing we can do is calculate how many pages there are by dividing the total rows by the number of rows required per page, round the result, and pass it to the $config["num_links"] parameter.

Here’s what the example1() method looks like with those changes:

public function example1() {
    $config["base_url"] = base_url() . "welcome/example1";
    $config["total_rows"] = $this->Countries->record_count();
    $config["per_page"] = 20;
    $config["uri_segment"] = 3;
    $choice = $config["total_rows"] / $config["per_page"];
    $config["num_links"] = round($choice);

    $this->pagination->initialize($config);

    $page = ($this->uri->segment(3))? $this->uri->segment(3) : 0;
    $data["results"] = $this->Countries
        ->fetch_countries($config["per_page"], $page);
    $data["links"] = $this->pagination->create_links();

    $this->load->view("example1", $data);
}

This will improve the links now.

Summary

Now you know how to use the most useful configuration options for the CodeIgniter pagination library, and you can also fix the way the pagination links are displayed to provide a consistent experience for your users. A user guide comes with every download of CodeIgniter, so be sure to check the other configuration options for the library there. It contains options for styling the pagination links, and changing the way the links are rendered on the page.

Image via Alexis Puentes / Shutterstock

And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Jump Start PHP.

Comments on this article are closed. Have a question about PHP frameworks? Why not ask it on our forums?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • pablo

    Thanks! Please more CI tutorial/articles ;)

  • http://www.andredublin.com Andre Dublin

    Wow, just in time. Writing a realtor search engine and needed pagination, gonna upgrade this with some ajax functionality. Thanks so much for this!

  • Mark

    FYI on setting configs: there is a bug in the pagination class that everyone should be aware of in regard to setting a class on all of your page link anchor tags ($config['anchor_class']).

    This addition to the pagination class was implemented rather poorly and came about in version 2 if I remember correctly. Currently the only way anchor_class will be set properly is if you put all of your configs in their own config file within the application/config folder (must be named ‘pagination.php’). The logic for properly setting the ‘anchor_class’ config item resides within the pagination class’ constructor. So, if you try to set it the way you’ve illustrated setting configs above within the controller, the class in the anchor tag won’t be set properly because you’ve passed all of the configs manually through ‘initialize($config)’ post class load (which is post constructor call).

    If you want to make sure that ‘anchor_class’ is set properly using the initialize method then you need to edit Pagination.php. Make a copy Pagination.php and put in the application/libraries folder. This will be your version of the pagination class. Simply move the anchor class conditional from the constructor to the bottom of the initialize method. Save your file and you’re good to go. Now ‘anchor_class’ will be set whether you use initialize or a separate config file.

    Personally, I wouldn’t have done it this way at all. I would have left all of the logic in the constructor and the initialize method the same. All that they should have done was add the class variable and then use a ternary within the anchor tag creation within the ‘create_links()’ method. Example: (( ! empty($this->anchor_class)) ? ‘class=”‘.$this->anchor_class.'”‘ : ”)

    Anyway, just wanted to make mention of that. Sorry about the rant. Hope the code example makes it through this form.

  • http://www.makeITspendIT.com Les

    Good article, well written. Does ‘$this->db->limit’ in the Model work with MS SQLServer? I know it works ok with MySQL.

  • http://www.junwatu.com Eq

    thank you so much!..it’s really helpfull!

  • http://twitter.com/gbaldera Gustavo Rodriguez

    You should use site_url(‘welcome/example1′) rather than base_url() . “welcome/example1″ because if the $config['index_page'] is set in the config.php the url will not be complete.

  • http://twitter.com/jc1arke John

    Good tutorial!
    Just one thing: you have to set your limit to be

    $this->db->limit($limit, $start * $limit);

    Otherwise if you pass 10 as the limit and the page number such as 3, it will read from record 3 for 10 records :)

    • Henry

      I have 10 entries. I need to show 2 per page.
      It works just fine, but in the URL, I dont have page number, I have the items per page… Its weird.. it works fine, but I would like to have page number instead.

      $config = array();
      $config['base_url'] = site_url(‘profile/list’);
      $config["total_rows"] = $total_rows;
      $config["per_page"] = $items_per_page;
      $config["uri_segment"] = 3;

  • engiball

    Thanks for good tutorial,Can you help me about textbox postback. I have problem when I change page then textbox value is lost.Can I keep textbox value.

  • http://localhost MVC Noob

    Hey all, I typed out all the code to try and ramp up my understanding of CodeIgniter and the MVC concept, however when I was all finished I had this following error, can anyone tell me where I should check to figure it out? I thought it was in my typed out code but even after I copy and pasted the provided code, it was still the same result. Here’s what I’m staring at:

    “class Countries extends CI_Model { public function __construct() { parent::__construct(); } public function record_count() { return $this->db->count_all(“Country”); } public function fetch_countries($limit, $start) { $this->db->limit($limit, $start); $query = $this->db->get(“Country”); if ($query->num_rows() > 0) { foreach ($query->result() as $row) { $data[] = $row; } return $data; } return false; } }
    Fatal error: Class ‘Countries’ not found in C:xampphtdocsCIsystemcoreLoader.php on line 303″

  • fred

    Hi, I’ve tried the codes here but I got an error message “The requested URL /2 was not found on this server.” when I click on the next page. Could someone pls help me. tnx.

    • shibu

      hello Erica;
      set basic url $config["base_url"] = “http://localhost/CI/index.php/welcome/example1/

  • shafiq

    hi..
    My sql query is like this
    Select * from users where userId = $_POST['id'];
    its generate proper pagination but when i like next page then its shows me error about $_POST so how i can maintain this data in pagination without using session

  • http://www.willis-owen.co.uk Richard

    It is a shame that the CodeIgniter manual doesn’t cover what to do in the controller and model to achive pagination.
    This is a great tutorial – thanks.

  • slon842

    it helped me to save a lot of time :) thanks
    But I wonder what is a point of doing foreach loop in model file? I see it everywhere but I don’t why its done this why? Why can not return $query->result() directly without foreach loop? I’ve checked it with var_dump() and both of them look exactly the same $data and $query->result? Thank for the answer :)

  • Iqbal Munahar

    Thnks dude, good article, post another tut about CI

  • http://www.go2myaccount.com Shashi

    Thanks for this excellent tutorial… really the best tutorial i have read on codeigniter pagination..

  • Erica

    Everything seems to work (correct number of results, correct number of pagination links, etc) but if I click on one, I get a 404 error. Any idea why? The url, for example is: erica.com/pizza which becomes erica.com/pizza/5

    • Erica

      I actually figured it out, silly mistake. base_url(). controller/function rather than just the page URL for me. How would you make a “view all” for this though?

  • Sudipto Karmoker

    Very very thanks for this article. I’ve saved a lot of things by using your this article. Thanks.

    • dhaval

      Pagination doesn’t work for me.Links are showing but when clicking on it,Data doesn’t seem to be appear.Thanks

  • http://tokoadit.16mb.com/ aditya

    I’ve followed the tutorial that you wrote, I succeeded, but when I click a link, an error message appears,
    “Object not found!The requested URL was not found on this server. The link on the referring page seems to be wrong or outdated. Please inform the author of that page about the error.
    If you think this is a server error, please contact the webmaster.” can you explain why the object appears not found??
    I desperately need a solution, please help

  • http://www.sammymoshe.com Sammy Moshe

    Very nice article. I was wondering how this piece of codeIgniter worked. Thank you for the insights.

  • Lee

    Thank you so much Andy… It helped me a lot for clearly understanding pagination in codeigniter’s way…

  • http://www.facebook.com/anjanasilva Anjana Silva

    Thanks Andy. This works very well :)

  • http://localhost/CodeIgniter_2.1.0/application/welcome/example1/2 Neeraj Sharma

    http://localhost/CodeIgniter_2.1.0/application/welcome/example1/
    Hi,
    This pagination is nice and easy to understand. I am new on codeigniter and in learning phase so I am getting an issue. when I click on 2 in pagination and redirected to page (http://localhost/CodeIgniter_2.1.0/application/welcome/example1/2), It gives me below error. Can u help me to solve out this issue.

    Error : You don’t have permission to access /CodeIgniter_2.1.0/application/welcome/example1/2 on this server.

    Thanks,

  • wahmal

    nice tutor! but how make number on table always increase or decrease each the pagination clicked???

  • Fiseha

    On the controller line# 20, you should change the default value that should be passed to the url to 1, in that case the first page will not contain the whole list.
    Thank you, this was very helpful.

  • http://achieveee.com Devendra Verma

    Thanks,It worked like a charm :)

  • tim lu

    Thank you,Conditional query paging:controllers:
    function view() {
    if ($_POST) {
    $url_array = array();
    if ($_POST['sname']) {
    $url_array['name'] = $_POST['sname'];
    }
    redirect(‘admin/size/view/’ . $this->uri->assoc_to_uri($url_array));
    }
    $url_param = $this->uri->uri_to_assoc(4);
    $fileds = array(‘name’);
    $where = NULL;
    foreach ($fileds as $k) {
    if (!empty($url_param[$k])) {
    $where[$k] = $url_param[$k];
    }
    }
    if ($where['name']) {
    $data['name'] = $where['name'];
    }
    $page = $url_param['page'] + 0;
    $url_param = $this->uri->assoc_to_uri($where);
    $config['base_url'] = site_url(‘admin/size/view/’.$url_param.’/page’);
    $config['total_rows'] = $this->size_model->get_num_rows($where[name]);
    $config['per_page'] = $this->limit;
    $config['cur_page'] = $page;
    $this->pagination->initialize($config);
    $data['pagination'] =$this->pagination->create_links();
    $data["result"] = $this->size_model->get_size($config["per_page"], $page,$where[name]);
    // print_r( $data["result"]);exit;
    $data['condition']=$where[name];
    $this->load->view(“admin/size/list”, $data);}
    model:
    function get_size($limit,$start,$where) {
    if($where){
    $this->db->like(‘name’, $where);
    }
    $this->db->limit($limit, $start);
    $query = $this->db->get(“size”);
    if ($query->num_rows() > 0) {
    foreach ($query->result_array() as $row) {
    $data[] = $row;
    }
    return $data;
    }
    return false;
    }

    function get_num_rows($where=””) {
    if ($where) {
    $this->db->like(‘name’, $where);
    }
    return $this->db->count_all_results(‘size’);
    }
    read your paging,thank you very much

  • http://www.ebali-tour.com gusmang

    very nice tutorial .. i have a problem to create pagination when searching data .. it’s show all data when we click the number of pagination . can you tell me how to solve this problem ??

  • Hidayat

    Nice tutorial….Thanks

  • http://- jihed boucnak

    excellent job it nice and easy tutorial

  • VIDYA

    Fatal error: Unsupported operand types in D:ProgramsxampphtdocstestersystemlibrariesPagination.php on line 124

  • Sara

    Amazing tutorial, thanks a lot!

  • Roark

    Thanks for the tutorial,
    I found the following problem:
    fetch_countries($config["per_page"], $page); //this is passing 20 and 3 respectively (if you are on page 3)
    The resulting query will be:
    $this->db->limit(20, 3); // Limit the result to 20 results starting from 3rd result
    You can see how this will throw your results
    The following will works in my application:
    $offset = $page==0? 0: ($page-1)*$config["per_page"];
    fetch_countries($config["per_page"], $offset);
    The resulting query will be:
    $this->db->limit(20, 60); // Limit the result to 20 results starting from 60th result
    Hope this helps

  • Roark

    Apologies
    The resulting query will be:
    $this->db->limit(20, 40); // Limit the result to 20 results starting from 40th result

  • Chris

    It doesn’t work when you want to show one row-result per page

  • Alex

    Hello,
    and a million thanks for you great solution.
    I have been using your it successfully with my webforms.
    Today, I came across an added difficulty: it turns out that my webform has a Multiple select dropdown. Alright. The problem is that I don’t know how I can deal with the sessions now because before $city would hold only one value, now $city is an array of up to 3 possible cities:
    I do this at the controller:
    $cities[] = $this->getresults_m->cities_handler($this->input->get_post(‘cities’, TRUE));
    but I am confused as to how to go about in here:

    public function cities_handler($cities)
    {
    if($cities)
    {
    $this->session->set_userdata(‘id’, $cities);
    return $cities;
    }
    elseif($this->session->userdata(‘id’))
    {
    $cities = $this->session->userdata(‘id’);
    return $cities;
    }
    else
    {
    $cities =””;
    return $cities;
    }

    }
    I cannot mentally visualize what goes on in there. I could so a foreach loop of $cities that would wrap up the body of the handler function, ..and that would result in the controller getting again the array values so that it can send them to the model ? (I also intend to do a foreach loop in the SQL query function) ..buff.. kind of tough, although I faintly and timidly think that that is how it should be done..

    I understand you can’t answer the world, but ..this is really useful for everybody.

    thanks a lot

  • Ashwini

    The view to be loaded is welcome_message replace $this->load->view(“example1″, $data); by $this->load->view(“welcome_message”, $data);

  • http://vibeink.com Solomon Tulio

    Awesome, i was actually looking for how to poppulate the data in my view. codeigniter documentation on pagination is poor. Thanks for help.

  • manjiri

    hello, thank for ur solution.
    i have one problem that if m on 2 page and view that record after return i want to land my page on same 2 page of pagination but it land on 1 page .please give me solution for same

  • tanveer alam

    Great work