By default, in any given context, WordPress uses the main query to determine pagination. The main query object is stored in the
$wp_query global, which is also used to output the main query loop.
Pagination template tags, including
paginate_links(), base their output on the main query object,
$wp_query. That main query may or may not be paginated. If the current context is a custom page template, for example, the main
$wp_query object will consist of only a single post – that of the ID of the page to which the custom page template is assigned.
If the current context is an archive index of some sort, the main
$wp_query may consist of enough posts to cause pagination, which leads to the next part of the problem: for the main
$wp_query object, WordPress will pass a paged parameter to the query, based on the paged URL query variable. When the query is fetched, that paged parameter will be used to determine which set of paginated posts to return. If a displayed pagination link is clicked, and the next page loaded, your custom query won’t have any way to know that the pagination has changed.
This is a common problem when you are using pagination in a custom loop with a custom page template, thus we always see WordPress users get frustrated and wonder why “pagination not working”.
In order for pagination functions to yield the correct output – i.e. previous/next/page links relative to the custom query – WordPress needs to be forced to recognize the custom query. This requires a bit of a “hack”: replacing the main
$wp_query object with the custom query object,
$custom_query(or whatever you are naming it).
The following is a basic construct of a custom query loop with properly functioning pagination functions. Look at the comments for clarification.
The idea of this solution is to swap the
$wp_query object with
$custom_query, and reset
$custom_query is finished.
Courtesy to @ChipBennet’s answer in this post.