Custom search with pagination using query_posts() in WordPress

The number of posts per page is set in Settings > Reading in WordPress. Once this is set, specific number of posts are shown on home page, archive pages, search results page, and so on.

An alternate and custom method to set number of records per page is by setting “showposts” parameter of WP_Query in specific page template such as in archives or index page with latest posts.

I was working on a project in which i wanted to show posts from a specific post category named “Articles” on a page. I wanted to put a search form on this page and wanted to search posts by title or description. I also wanted to search posts by two custom fields/values which i had created using a WordPress plugin. Values of these two custom fields filled and saved while creating new posts in post category named “Articles”.

To search the title and the description, i would use the default search parameter “s”. I would perform search on custom fields using “meta_query” parameter. I will paginate records using a very handy pagination function (kriesi_pagination) written by kriesi with due credit. I will also display some more useful information on page such as “Displaying 1-10 of 78 records”. I will also display pagination links in numerical order with proper linking and search parameters passed. I will do all this stuff without using a plugin. Intended output is in figure below:

wordpress-custom-query-posts-search

Creating pages and code

Create a Template Page on which listings/posts from “Articles” category would be listed. For this i would create a new file in my current theme folder and name it articles.php. At the top of this page would name the template as “Articles” like the following and remove other code:

<?php
/*
* Template Name: Articles
*/
?>

Now create a new page by name “Articles” from admin end. When created it will be opened at http://mytestwebsite.com/articles (if permalinks are turned on, as such) or http://mytestwebsite.com/?page_id=60. In “Page Attributes” box in right panel select “Articles” template under “Template”. After saving, this new created page should work fine at like http://mytestwebsite.com/articles like your archive page did.

Next, just below get_header() call add three lines to initilize some variables required for custom search page. Be noted that i am skipping any reference to the page layout here(HTML tags like DIV, P and any of them). Right after the get_header() call in Articles Template define:

[php]$meta_query = array();$fname=”;$num_art_per_page = 10;
$paged = isset($_REQUEST[‘paged’]) ? $_REQUEST[‘paged’] : 1;
$args = array(
‘cat’=>’9’,
‘showposts’=>$num_art_per_page,
‘paged’=>$paged
);[/php]

In the first line above three variables are initialized. $meta_query, $keyword and $num_art_per_page respectively. First two of them start with empty value while third is assigned the number of posts one would like to list (Remember that you can also supply the value of $num_art_per_page from admin settings). Next line code checks for ‘paged’ parameter in page request, and if found its value is assigned to $paged variable which is otherwise set to 1. Next five lines contain the definition of popular $args variable. “cat” has default post category which is 9 here, “showposts” is set to required number of records which is defined in form of $num_art_per_page and so is the paged parameter.

[php]if(isset($_REQUEST[‘se’])) {
$keyword = mysql_real_escape_string(trim($_REQUEST[‘keyword’]));
$cust_field_1 = mysql_real_escape_string(trim($_REQUEST[‘cust-field-1’]));
$cust_field_2 = mysql_real_escape_string(trim($_REQUEST[‘cust-field-2’]));
if($keyword) {
$args[‘s’] = $keyword;
}
if($cust_field_1) {
array_push($meta_query, array(‘key’=>’cust_field_1’, ‘value’=>$cust_field_1));
}
if($cust_field_2) {
array_push($meta_query, array(‘key’=>’cust_field_2’, ‘value’=>$cust_field_2));
}
$args[‘meta_query’]=$meta_query;
}
[/php]

The above code block does take care of submitted search form and prepares input value for main search keyword parameter “s” and values of two custom fields named ‘cust_field_1’ and ‘cust_field_2’. Remember value of these two custom fields are saved when actual post was saved.

Next we perform the query alteration action, that is “query_post()” by passing $args parameter. Remember $args parameter may or may not have been altered depending on the submission of search form. In any case we will have $args parameter set.

[php]query_posts($args);
$start_art = (($paged-1)*$num_art_per_page)+1;
$end_art = $paged*$num_art_per_page;
[/php]

In addition, this code block prepares start and end offset of searched pages. $start_art is the offset number of the articles which the results page should start displaying records with and $end_art is the offset number of the articles or post which the results/records would terminate with. For example for the second page having 10 records on each page would say like ‘Displaying 11-20 of … records’ and so on.

Displaying of results

Next step is to check whether there are at least some records to show. That is, the most popular wordpress “if(have_posts())” statement.

[html]if(have_posts()):
global $wp_query; $total_art = $wp_query-&gt;found_posts;
if($total_art&lt;$num_art_per_page) {
$end_art = $total_art;
}
<div class="articles-pagination">
<div class="pagination"><!–?php previous_posts_link(‘<< Previous’) ?–> | <!–?php next_posts_link(‘Next –>&gt;’) ?&gt;</div>
<div class="counter">Displyaing <!–?=$start_art? –>-<!–?=$end_art?–> of <!–?=$total_art? –> articles</div>
</div>
while(have_posts()) : the_post();
//put display post logic here.. for example, get custom fields etc..
//$post_metas = get_post_meta($post-&gt;ID);
endwhile;
kriesi_pagination();
else:
_e(‘Not Found’);
endif;[/html]

If there are some records found we use $wp_query to get number of posts and assign its value to $total_art variable. Then we check whether we have got at least as many records as we display per page. If not set the end offset to the total number of records which is obviously less than that of we display on a page, so that it would say “Displaying 1-7 of 7 articles”. I hope that makes sense.

And here is the kriesi_pagination() function with little addition which i required to do in order to show << Previous and Next >> along side pagination numbers.

[php]function kriesi_pagination($pages = ”, $range = 2) {
$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 "</pre>
<div class="articles-navigation">";
previous_posts_link(‘<< Previous’); if($paged > 2 && $paged > $range+1 && $showitems < $pages) echo "<a href="&quot;.get_pagenum_link(1).&quot;">«</a>";
if($paged > 1 && $showitems < $pages) echo "<a href="&quot;.get_pagenum_link($paged – 1).&quot;">‹</a>";
for ($i=1; $i <= $pages; $i++) { if (1 != $pages &&( !($i >= $paged+$range+1 || $i <= $paged-$range-1) || $pages <= $showitems )) {
echo ($paged == $i)? "<span class="current">".$i."</span>":"<a class="inactive" href="&quot;.get_pagenum_link($i).&quot;">".$i."</a>";
}
}
if ($paged < $pages && $showitems < $pages) echo "<a href="&quot;.get_pagenum_link($paged + 1).&quot;">›</a>";
if ($paged < $pages-1 && $paged+$range-1 < $pages && $showitems < $pages) echo "<a href="&quot;.get_pagenum_link($pages).&quot;">»</a>";
next_posts_link(‘Next >>’);
echo "</div>
<pre>
\n";
}
}[/php]

Leave a Reply