I'm wondering if anyone can help me out here?

Basically, I think I need to use add_rewrite_rule() to get pagination working in my search results, as I've gone beyond the default query due to a bunch of extra stuff that needs to happen when fetching results (querying posts and users, in this case).

The first page of my search results works fine.
Example: /?s=lighting&post_type=service.

However, when I go to the second page of results, I get a 404.
Example: /?s=lighting&post_type=service&paged=2.

Any help would be greatly appreciated!


Here's a condensed version of my query and any relevant code:

// Working with the query string
global $query_string;
$user_query_args = explode('&', $query_string );
$user_query_array = array();
if ( strlen( $query_string ) > 0 ) {
    foreach ( $user_query_args as $key => $string ) {
        $user_query_split = explode( '=', $string );
        $user_query_array[$user_query_split[0]] = urldecode( $user_query_split[1] );

// Setting up `$paged`
global $paged;
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
if ( $paged === 1 ) {
    $offset = 0;
} else {
    $offset = ( $paged - 1 ) * $per_page;

// Args for user query
$user_args = array(
    'number' => $per_page,
    'offset' => $offset,
    'role' => 'Subscriber',
    'meta_query' => array(
        'relation' => 'OR',
            'key' => 'profile_service_1',
            'value' => $posts_str, // string of post IDs
            'compare' => 'IN'
            'key' => 'profile_service_2',
            'value' => $posts_str, // string of post IDs
            'compare' => 'IN'

// Creating the user query
$users_query = new WP_User_Query( array_merge( $user_query_array, $user_args ) );
$users = $users_query->get_results();

if ( sizeof( $users ) > 0 ) {
    foreach ( $users as $user ) {
        // Here's where I show the user stuff

// Setting up pagination
$total_users = $users_query->total_users;
$total_pages = ceil( $total_users / $per_page );

$pagination_args = array(
    'base' => @add_query_arg('paged','%#%'),
    'format' => '?paged=%#%',
    'current' => $paged,
    'total' => $total_pages,
    'prev_text' => 'Previous',
    'next_text' => 'Next',
    'type'     => 'list',

if ( $wp_rewrite->using_permalinks() ) {
    $pagination['base'] = user_trailingslashit( trailingslashit( remove_query_arg( 's', get_pagenum_link( 1 ) ) ).'page/%#%/', 'paged' );

if ( ! empty( $wp_query->query_vars['s'] ) ) {
    $pagination['add_args'] = array( 's' => get_query_var( 's' ) );

echo paginate_links( $pagination_args );
  • that's because you're asking WP for page 2 of the main post query, not your new secondary additional query. Have you considered using pre_get_posts instead? Rewrite rules will not fix this if raw URL parameters can't
    – Tom J Nowell
    Commented Apr 25, 2023 at 9:37
  • Yep, I did play around with pre_get_posts with a check for the search query, but I didn't have much luck on that front. Commented Apr 28, 2023 at 8:50
  • without knowing what you tried, or seeing the code for your attempt or the query you've written on the search page it's not possible to advise, but this is expected when you use that particular method, it's just rare that people notice
    – Tom J Nowell
    Commented Apr 28, 2023 at 10:30
  • Yeah fair enough. I was initially just looking for pointers, hence me not adding the query etc. However, I've just updated my question with all relevant code, if that helps you to understand what's happening. Thanks Commented May 4, 2023 at 10:00
  • You did not mention it's a WP_User_Query not a post query, that was super important and critical to know. In this situation you should not have used the s parameter as that is for post queries, you should not be repurposing the search.php template either. I also spotted that you used the @ operator which is extremely bad, @ does not swallow errors, it only silences error messages, the error still happens! Only now they don't appear in error logs so it's ultra difficult to debug fatal errors, it would be easier and safer to fix the problem @ is trying to hide
    – Tom J Nowell
    Commented May 4, 2023 at 10:39

1 Answer 1


The root of the problem is that you're using s, the post query search parameter, but the code is for a user query.

This means if your user query has 5 pages, but only 2 pages of posts are found, page 3 will 404.

Instead, use a dedicated parameter with $_GET that isn't a reserved query var already. This does mean the search.php template won't be used, but that can be fixed in many ways, e.g. a page template, rewrite rules, template filters, etc

A sidenote on performance

meta_query has very poor performance. If the values you are searching for are not fuzzy, consider using user taxonomies to store them. This will provide a dramatic performance boost. Post/User/Term meta are optimised for get_post_meta type calls where you already know the post ID, the tables are not structured in a way that makes searches/filtering/grouping posts by meta performant.

Keep this in mind as there is a tradeoff here, meta is fast in get_post_meta type situations, and gets significantly slower at meta_query type situations as the table increases in size. Taxonomies aren't as fast for retrieval but they're orders of magnitude faster than meta_query type queries. This is why categories and tags aren't stored in post meta, but stuff like the featured image ID are.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.