Codeigniter application bug: turning the default pagination into a pager fails

  codeigniter, php

I am working on an online newspaper/blogging application with CodeIgniter 3.1.8 and Bootstrap 4.

The application has themes. One of the themes uses a pager instead of pagination, so the Codeigniter default pagination is not well suited for it.

The "hack" I found for this problem relies mostly on CSS.

In the Posts controller I have:

class Posts extends CI_Controller
    public function __construct()
    private function _initPagination($path, $totalRows, $query_string_segment = 'page')
        //load and configure pagination 
        $config['base_url']             = base_url($path);
        $config['query_string_segment'] = $query_string_segment;
        $config['enable_query_strings'] = TRUE;
        $config['reuse_query_string']   = TRUE;
        $config['total_rows']           = $totalRows;
        $config['per_page']             = 12;
        if (!isset($_GET[$config['query_string_segment']]) || $_GET[$config['query_string_segment']] < 1) {
            $_GET[$config['query_string_segment']] = 1;
        $limit  = $config['per_page'];
        $offset = ($this->input->get($config['query_string_segment']) - 1) * $limit;
        return array(
            'limit' => $limit,
            'offset' => $offset
    public function index()
        //call initialization method
        $config = $this->_initPagination("/", $this->Posts_model->get_num_rows());
        $data                  = $this->Static_model->get_static_data();
        $data['base_url']      = base_url("/");
        $data['pages']         = $this->Pages_model->get_pages();
        $data['categories']    = $this->Categories_model->get_categories();
        $data['search_errors'] = validation_errors();
        //use limit and offset returned by _initPaginator method
        $data['posts'] = $this->Posts_model->get_posts($config['limit'], $config['offset']);
        $this->twig->addGlobal('pagination', $this->pagination->create_links());
        // featured posts
        if ($data['is_featured']) {
            $data['featured'] = $this->Posts_model->featured_posts();
            $this->twig->addGlobal('featuredPosts', "themes/{$data['theme_directory']}/partials/hero.twig");
        $this->twig->display("themes/{$data['theme_directory']}/layout", $data);
    public function search()
        // Force validation since the form's method is GET
        $this->form_validation->set_rules('search', 'search term', 'required|trim|min_length[3]', array(
            'min_length' => 'The search term must be at least 3 characters long.'
        $this->form_validation->set_error_delimiters('<p class = "error search-error">', '</p>');
        // If search fails
        if ($this->form_validation->run() === FALSE) {
            $data['search_errors'] = validation_errors();
            return $this->index();
        } else {
            $expression           = $this->input->get('search');
            $posts_count          = $this->Posts_model->search_count($expression);
            $query_string_segment = 'page';
            $config               = $this->_initPagination("/posts/search", $posts_count, $query_string_segment);
            $data                 = $this->Static_model->get_static_data();
            $data['base_url']     = base_url("/");
            $data['pages']        = $this->Pages_model->get_pages();
            $data['categories']   = $this->Categories_model->get_categories();
            //use limit and offset returned by _initPaginator method
            $data['posts']        = $this->Posts_model->search($expression, $config['limit'], $config['offset']);
            $data['expression']   = $expression;
            $data['posts_count']  = $posts_count;
            $this->twig->addGlobal('pagination', $this->pagination->create_links());
            $this->twig->display("themes/{$data['theme_directory']}/layout", $data);

I the stylesheet, I hide the page items except the "Previous" and "Next" buttons:

.pagination li:first-child {
  display: inline-block;
  margin-right: auto;

.pagination + li {
  display: inline-block;
  margin-left: auto;

.pagination li,
.pagination {
  display: none;
  position: relative;

.pagination li:first-child a::before,
.pagination + li a::before {
  display: inline-block;
  font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  background-color: #0085a1;
  border: 1px solid #006d83;
  color: #fff;
  font-size: 14px;
  font-weight: 800;
  padding: 15px 25px;
  letter-spacing: 1px;
  text-transform: uppercase;

.pagination li:first-child a::before {
  content: 'Newer Posts';
  padding-left: 35px;

.pagination + li a::before {
  content: 'Older Posts';
  padding-right: 35px;

.pagination li:first-child a::after,
.pagination + li a::after {
  color: #fff;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);

.pagination li:first-child a::after {
  content: '90';
  left: 7px;

.pagination + li a::after {
  content: 'F812';
  right: 7px;

The problem with this approach is that it is inconsistent: when I am on the last page, the "Newer Posts" button is linked to the first page instead of the previous.

Question: Is there a more reliable way to add a pager option?

Source: Ask PHP