Site icon Hip-Hop Website Design and Development

Super confusing ‘pre_get_posts’ behavior with $query->set

I’ve been pulling my hair over this strange issue for several hours now and need some help figuring out what’s going on. Allow me to explain my setup followed by the behavior and question.

Setup:

  1. I’ve set my ‘posts page’ to domain.com/search/ where I intend to list all my posts.

  2. Since I need a custom layout for displaying my posts, I’ve the following redirect in ‘template_include’ hook:

    /*Use custom template to render posts on /search/ */
    if ( is_home() ) {
        return plugin_dir_path( __FILE__ ) . 'partials/display-speaker-list.php';
    }
    
  3. My posts list also displays tags associated with each post. I want these tags to be clickable. When user clicks on any tag, I want to filter the posts using the clicked tag as keyword. The HTML for my displaying tags for each post looks like this:

     <a href="<?php echo esc_url( home_url('/') . 'search/?tag=' . str_replace(' ', '+', $topic ) ); ?>" class="btn btn-outline-primary" role="button"><?php echo esc_html( $topic ); ?></a>
    

In order to make the search work, I decided to make use of ‘pre_get_posts’ hook. This is where the strange things began to happen. Look at the code I execute with pre_get_posts :

/* Filter posts using the tag   
public function io_speakers_pre_get_posts( $query ) {

    if ( $query->is_main_query() && $query->is_home() ) {
        $query->set('tag', $_GET['tag']);
        return $query;
    }
    return $query;
}

Here’s the Odd behavior:

If I remove the $query->set('query_var', 'value'); statement from the condition, WordPress returns all posts, completely ignoring the search/?tag=xyz query. But it works even if I set it to something random or even empty. That is, WordPress correctly filters the posts if I change that line to $query->set('', '');

In short, WordPress expects me to have a $query->set(WHATEVER); in that condition for it to acknowledge existence of ‘tag’ parameter. Otherwise it just returns all the posts.

My questions are:

  1. What’s really happening with $query->set()?
  2. Why does it require me to set any random stuff in $query->(blah, blah) in order to work properly?
  3. What if I want to search by /search/?topic=someTopic instead of /search/?tag=someTopic?

I hope I’ve explained my question properly. It’s a pretty long explanation and I look forward to your help. Would really appreciate it. Thank you in advance for your time.

-K