Redirect to a page while maintaining search query parameters without causing an infinite loop

I achieved this with a couple filters:

add_filter( 'query_vars', 'addnew_query_vars', 10, 1 );
function addnew_query_vars($vars)
{   
    $vars[] = 'r'; // var1 is the name of variable you want to add       
    return $vars;
}

function redir_cat_match($a) {
   global $wp_query;
   if ($wp_query->is_main_query() && $wp_query->is_search()){
      if ($wp_query->query_vars['s'] != ""){
         if ($_GET['r'] != '0'){
            if (!empty($wp_query->posts[0])){
               $s_value = $wp_query->query_vars['s'];
               $terms = get_the_terms( $wp_query->posts[0]->ID, 'product_cat' );
               $link = get_term_link($terms[0]->term_id) . "?s=" . htmlspecialchars($s_value) . "&r=0";
               wp_redirect($link );
               exit;
            }
         }
      }
   }
}
add_filter('template_redirect','redir_cat_match');

In order for this to work, you need some way for the snippet to detect that a redirect has already occurred. I did this by adding variable r as a potential parameter. In order to retrieve this, you have to use $_GET['r'].

I’m not sure if this is the most efficient way to do this, but it performs ok during testing and gets the desired results. Realistically, it’s effectiveness would rely on the quality of the search results so if you’re using a plugin like SearchWP or even an ElasticSearch implementation you’ll get the best results.