Why Your Custom WP_Query Pagination Fails on Live Sites (And How to Fix It)
Content
If you've built a custom query using WP_Query for pagination, you might find it works perfectly on your local development environment but breaks when you move it to a live server. Clicking to page 2 results in a "Page Not Found" error. This is a common and frustrating issue for WordPress developers. This guide will explain why it happens and walk you through the most reliable solutions.
Understanding the Problem
The core of the issue often lies in how WordPress handles main queries versus secondary queries. The main query, which runs before any templates are loaded, is responsible for parsing the request URL and determining what content to show. Pagination parameters like paged are part of this main query.
When you create a custom WP_Query for a page like home.php or a custom template, you are creating a secondary query. The pagination functions you use, like paginate_links(), are built to work with the main query's data by default. If your secondary query uses different parameters (like a different post_type), the main query's pagination data becomes irrelevant, causing conflicts and broken links on the live site where URL rewriting is active.
Common Solutions
1. Use pre_get_posts to Modify the Main Query (Recommended)
The most robust method is to avoid a custom WP_Query for primary post lists and instead use the pre_get_posts action hook to modify the main query before it executes. This ensures all native pagination functions work correctly.
function my_custom_main_query( $query ) {
// Only modify the main query on the front-end homepage
if ( ! is_admin() && $query->is_home() && $query->is_main_query() ) {
$query->set( 'post_type', array( 'arizona_wine', 'arizona_beer' ) );
$query->set( 'posts_per_page', 12 );
$query->set( 'orderby', 'title' );
$query->set( 'order', 'ASC' );
}
}
add_action( 'pre_get_posts', 'my_custom_main_query' );
With this approach, you can then use the standard loop in your home.php template without creating a new WP_Query object. The pagination will just work.
2. Fix the Pagination Base in Your Custom Query
If you must use a custom WP_Query, you need to ensure the paginate_links() function generates the correct URLs. The problem often stems from the 'base' argument. The common snippet using str_replace($big, '%#%', get_pagenum_link($big)) can fail on some server configurations.
A more reliable method is to use esc_url( get_pagenum_link() ) to build the base URL.
$pagination = paginate_links( array(
'base' => esc_url( get_pagenum_link() ) . '%_%',
'format' => '?paged=%#%',
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $all_posts->max_num_pages,
'prev_text' => 'Previous',
'next_text' => 'Next',
) );
if ( $pagination ) {
echo '' . $pagination . '';
}
3. Check Your .htaccess and Permalink Settings
Sometimes, the issue is not your code but your server's configuration. A missing or corrupt .htaccess file can prevent URL rewriting from working, which breaks pagination.
- Go to Settings > Permalinks in your WordPress admin.
- Simply click "Save Changes" without making any modifications. This refreshes the rewrite rules and often regenerates the
.htaccessfile. - Ensure your web server (e.g., Apache) has the
mod_rewritemodule enabled and that the.htaccessfile is writable.
Conclusion
Pagination issues with custom queries are a classic WordPress development challenge. The most sustainable fix is to use the pre_get_posts hook to alter the main query, as this keeps you within the standard WordPress lifecycle. If a custom query is unavoidable, paying close attention to how you generate the pagination base URL is critical. Finally, never forget to reset your permalinks after moving a site to a new server.
Related Support Threads Support
-
Hiding posts from main page/archive but not RSS feedhttps://wordpress.org/support/topic/hiding-posts-from-main-page-archive-but-not-rss-feed/
-
Output post count per category on a custom taxonomy archivehttps://wordpress.org/support/topic/output-post-count-per-category-on-a-custom-taxonomy-archive/
-
Query behaves differently depending on where it runs fromhttps://wordpress.org/support/topic/query-behaves-differently-depending-on-where-it-runs-from/
-
Related Posts – Snippethttps://wordpress.org/support/topic/related-posts-snippet/
-
Adding a language rule and showing posts w/ a taxonomy term on its archive pagehttps://wordpress.org/support/topic/adding-a-language-rule-and-showing-posts-w-a-taxonomy-term-on-its-archive-page/
-
WP_Query not using relation key as expected and not producing any resultshttps://wordpress.org/support/topic/wp_query-not-using-relation-key-as-expected-and-not-producing-any-results/
-
Custom theme on multisite has issues with standard loop outputhttps://wordpress.org/support/topic/custom-theme-on-multisite-has-issues-with-standard-loop-output/
-
Choosing a category name in WordPress that I am on the archive pagehttps://wordpress.org/support/topic/choosing-a-category-name-in-wordpress-that-i-am-on-the-archive-page/
-
category_name not working though tag_name is workinghttps://wordpress.org/support/topic/category_name-not-working-though-tag_name-is-working/
-
Making an arrayhttps://wordpress.org/support/topic/making-an-array/
-
WP_query for a post from a year before today’s datehttps://wordpress.org/support/topic/wp_query-for-a-post-from-a-year-before-todays-date/
-
Why the function get_posts returns the wrong post?https://wordpress.org/support/topic/why-the-function-get_posts-returns-the-wrong-post/
-
How to get WP_Query() to return posts from a subcategoryhttps://wordpress.org/support/topic/how-to-get-wp_query-to-return-posts-from-a-subcategory/
-
Get term id of elementor loop grid itemhttps://wordpress.org/support/topic/get-term-id-of-elementor-loop-grid-item/
-
Configuring a site’s default home URL within a single posthttps://wordpress.org/support/topic/configuring-a-sites-default-home-url-within-a-single-post/
-
Pagination on home.phphttps://wordpress.org/support/topic/pagination-on-home-php/
-
Daily Posts pluginhttps://wordpress.org/support/topic/daily-posts-plugin/
-
Query recent postshttps://wordpress.org/support/topic/query-recent-posts/
-
Polylang code is not given the result in English but it gives ini frenchhttps://wordpress.org/support/topic/polylang-code-is-not-given-the-result-in-english-but-it-gives-ini-french/
-
“tax_query” is ignored when “name” is provided in WP_Queryhttps://wordpress.org/support/topic/tax_query-is-ignored-when-name-is-provided-in-wp_query/
-
Multiple custom post types in one list table viewhttps://wordpress.org/support/topic/multiple-custom-post-types-in-one-list-table-view/
-
Use tax_query to allow searching for results within custom taxonomies.https://wordpress.org/support/topic/use-tax_query-to-allow-searching-for-results-within-custom-taxonomies/
-
Custom Taxonomy with Posts & Custom Posthttps://wordpress.org/support/topic/custom-taxonomy-with-posts-custom-post/
-
Best way: Post Type / Taxonomie. How to stack?https://wordpress.org/support/topic/best-way-post-type-taxonomie-how-to-stack/
-
Filter the_posts_pagination_argshttps://wordpress.org/support/topic/filter-the_posts_pagination_args/
-
Shortcode To Display Subcategory Not Workinghttps://wordpress.org/support/topic/shortcode-to-display-subcategory-not-working/
-
List of users who have a made a post in a cpthttps://wordpress.org/support/topic/list-of-users-who-have-a-made-a-post-in-a-cpt/
-
Making post category read onlyhttps://wordpress.org/support/topic/making-post-category-read-only/
-
function to prevent posts of certain category from appearing in prev/nexthttps://wordpress.org/support/topic/function-to-prevent-posts-of-certain-category-from-appearing-in-prev-next/
-
Output One Image For Post Using Multiple Taxonomies (even CPT)https://wordpress.org/support/topic/output-one-image-for-post-using-multiple-taxonomies-even-cpt/
-
Show Hide post information Based on term Clickhttps://wordpress.org/support/topic/show-hide-post-information-based-on-term-click/
-
get_the_terms() fails after switch_to_blog() in multisite setup (Invalid error)https://wordpress.org/support/topic/get_the_terms-fails-after-switch_to_blog-in-multisite-setup-invalid-error/
-
How to group post by subcategories in archive pages build with Gutenberghttps://wordpress.org/support/topic/how-to-group-post-by-subcategories-in-archive-pages-build-with-gutenberg/
-
Pagination – page 2 not showing postshttps://wordpress.org/support/topic/pagination-page-2-not-showing-posts/
-
Which is the template page for custom taxonomies?https://wordpress.org/support/topic/which-is-the-template-page-for-custom-taxonomies/
-
Custom post type pagination issueshttps://wordpress.org/support/topic/custom-post-type-pagination-issues-2/