Wednesday, March 19, 2014

How to build a wordpress post pagination without plugin

HOW TO BUILD A WORDPRESS POST PAGINATION WITHOUT PLUGIN

WordPress only comes bundled with the “next page” and “previous page” links to navigate between different blog overview pages. If you happen to have a blog with a lot of posts or simply want to offer a better user experience I would recommend to remove those links and replace them with a pagination like most people (including me) are using in their templates.
Why should you use them? 
Because they are easier to navigate and the user instantly knows how many posts and pages are available. Its simply good user experience :)

Using a plugin for this task may be an overkill since you really only need to add a few lines of php and css to your theme.
Now I show you how to add custom pagination into twentytwelve theme.

In Function.php

function twentytwelve_content_nav()
{  
// Sets how many pages to show (leave it alone)
$pages = '';
// Sets how many buttons you want to show in the pagination area
$range = 3;

$showitems = ($range * 2)+1;  

global $paged;
if(empty($paged)) $paged = 1;

if($pages == '')
{
global $wp_query;
$pages = $wp_query->max_num_pages;
if(!$pages)
{
$pages = 1;
}
}   

if(1 != $pages)
{
echo '<ul class="pagination">';
if($paged > 2 && $paged > $range+1 && $showitems < $pages) echo '<li><a href="'.get_pagenum_link(1).'">&laquo;</a></li>';
if($paged > 1 && $showitems < $pages) echo '<li>' . previous_posts_link('&laquo; Previous Entries') . '</li>';

for ($i=1; $i <= $pages; $i++)
{
if (1 != $pages &&( !($i >= $paged+$range+1 || $i <= $paged-$range-1) || $pages <= $showitems ))
{
echo ($paged == $i)? '<li class="current">'.$i.'</li>':'<li><a href="'.get_pagenum_link($i).'" class="inactive" >'.$i.'</a></li>';
}
}

if ($paged < $pages && $showitems < $pages) echo '<li>' . next_posts_link('Next &raquo;','') . '</li>';  
if ($paged < $pages-1 &&  $paged+$range-1 < $pages && $showitems < $pages) echo '<li><a href="'.get_pagenum_link($pages).'">&raquo;</a></li>';
echo '</ul>';
}
}


In style.css

.paginationBox {
clear: both;
display: block;
float: left;
margin: 1em 0 2em 0;
}
ul.pagination {
margin: 0px auto 0px auto;
padding: 0px 0px 10px 0px;
position: relative;
font-size: 80%;
line-height: 1em;
list-style-type: none;
}
.pagination li {
float: left;
vertical-align: middle;
background-color: #fff;
margin-right: 1px;
}


.pagination span,
.pagination a {
float: left;
border: 1px #ededed solid;
padding: 3px 9px 4px 9px;
text-decoration: none;
width: auto;
color: #999;
}
.pagination a:hover,
.pagination a:focus {
color: #fff;
background-color: #777;
border-color: #777;
}
.pagination .current{
padding: 3px 9px 4px 9px;
color: #fff;
background-color: #777;
border: 1px #777 solid;

}

Selecting random record from MySQL database table

The simplest way of selecting random rows from the MySQL database is to use "ORDER BY RAND()" clause in the query.
Solution 1 [SQL]
SELECT * FROM `table` ORDER BY RAND() LIMIT 0,1;
The problem with this method is that it is very slow. The reason for it being so slow is that MySQL creates a temporary table with all the result rows and assigns each one of them a random sorting index. The results are then sorted and returned.
There are several workarounds to speed things up.
The basic idea is to get a random number and then select a specific row using this number.
In the case that all the rows have unique ids we will just have to pick a random number between the smallest and the biggest id and then select the row with id that equals that number. To make this method work when ids are not evenly distributed we will have to use ">=" operator instead of "=" in the last query.
To get the minimum and maximum id values in the entire table we will use MAX() and MIN() aggregate functions. These functions will return minimum and maximum value in the specified group. The group in our case is all the values of `id` column in our table.
Solution 2 [PHP]
$range_result = mysql_query( " SELECT MAX(`id`) AS max_id , MIN(`id`) AS min_id FROM `table` ");
$range_row = mysql_fetch_object( $range_result );
$random = mt_rand( $range_row->min_id , $range_row->max_id );
$result = mysql_query( " SELECT * FROM `table` WHERE `id` >= $random LIMIT 0,1 ");
As we mentioned this method is limited to tables with unique id for each row. What to do if it's not the case?
The solution is to use the MySQL LIMIT clause. LIMIT accepts two arguments. The first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1).
To calculate the offset to the first row we will generate a random number between 0 and 1 using MySQL's RAND() function. Then we will multiply this number by number of records in the table, which we will get using COUNT() function. Since LIMIT arguments must be integers and not float values we will round the resulting number using FLOOR() function. FLOOR() is an arithmetic function that calculates the largest integer value that is smaller than or equal to the expression. The resulting code will look like this:
Solution 3 [PHP]
$offset_result = mysql_query( " SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `table` ");
$offset_row = mysql_fetch_object( $offset_result );
$offset = $offset_row->offset;
$result = mysql_query( " SELECT * FROM `table` LIMIT $offset, 1 " );
In MySQL 4.1 and later we can combine two previous methods using subquery like so:
Solution 4 [SQL]
SELECT * FROM `table` WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;
This solution has the same weakness as the solution 2 e.g. it only works for tables with unique ids.
Remember the reason we started looked for alternative ways of selecting random rows? Speed! So how do these methods compare in terms of execution times. I am not going to go into specifics of hardware and software configuration or give precise numbers. The approximate results are:
  • The slowest method is solution 1. Let's say that it took 100% of time to execute.
  • Solution 2 took 79%.
  • Solution 3 - 13%.
  • Solution 4 - 16%.
The winner is solution 3.