1

I meet serveral problems when building my custom wordpress theme:

1 Avoid hard code the search url in the searchform.php.

A typical template may looks like this:

<form class="search" method="get" action="<?php echo get_search_link(); ?>" role="search">
    <input class="search-input" type="search" name="s">
    <button class="search-submit" type="submit" role="button">Search</button>
</form>

However notice the action="<?php echo get_search_link(); ?> the action is hardcoded, it assume that the search path is http://homeurl/?s=xxx, how about if a plugin change the search path to something like http://homeurl/search?s=xxx?

2 Change the search url

I do not like the default /?s=xxx path for search, I like something like /search?s=xxx

3 Advanced search with more query variables

I want to search with keywords+category+tag+meta value, like this:

enter image description here

I have to set the search url form each link in the panel and hightlight it once it is the current query variable.

Is this possible,?


(The updated problem have been post in a new post here)

According to cybmeta's answer, I make the following change:

add_action('pre_get_posts', 'include_any_post_type_in_search');
function include_any_post_type_in_search($query)
{

    if (!is_admin() && $query->is_search && $query->is_main_query()) {

        $tax_query = array(
            'relation' => 'AND'
        );

        if (isset($_REQUEST['c'])) {
            $cate = $_REQUEST['c'];
            array_push($tax_query, array(
                'taxonomy' => 'category',
                'terms' => sanitize_text_field($cate)
            ));
        }


        if (isset($_REQUEST['t'])) {
            $tag = $_REQUEST['t'];
            array_push($tax_query, array(
                'taxonomy' => 'post_tag',
                'terms' => sanitize_text_field($tag)
            ));
        }
        $query->set('tax_query', $tax_query);

    }
}

add_filter('query_vars', 'cyb_query_vars');
function cyb_query_vars($vars)
{
    array_push($vars, "t", "c");
    return $vars;
}

function my_get_search_url($key, $val)
{
    $query = array();

    $supported = array("c", "t", "k");
    foreach ($supported as $s) {
        if ($s == $key) {
            array_push($query, "$s=$val");
        } else {
            $old_val = get_query_var($s);
            if (isset($old_val) && !empty($old_val)) {
                array_push($query, "$s=$old_val");
            }

        }
    }
    return get_search_link(join("&", $query));
}

Then use it like this:

                <?php
                $cates = get_categories();
                foreach ($cates as $cate) { ?>
                    <li>
                        <a href="<?php echo my_get_search_url('c', $cate->term_id); ?>"><?php echo $cate->name; ?></a>
                    </li>
                <?php } ?>

It generate url like:/search/c%3D9:

1 The c=9 is encoded

2 It render the index page rather than the search result page.

And once I visit /?c=9&s=1 I can get results with keyword 1 and category 9 .

Got the index page for /?c=9.

Got 404 for /search?c=9

Seems like there are some rewrite problem.

  • 1. yes, it is possible. 2. Questions should be about code or core concepts there is no point in asking broad theoretical questions as the answer is usually short and not very helpful – Mark Kaplun Oct 26 '16 at 5:41
2

If you use get_search_link() and someone filter the search URL and change it, get_search_link() will return the filtered URL; that is the great of non-hardcoded URL. You or third party plugin may modify the URL and it will always return the correct value. So, issues 1 and 2 seems to not exist.

The issue 3 has different approachs:

1.- Use inputs in the search form with a name equal to some query argument directly accepted by WP_Query as query string. For example, category_name:

<form class="search" method="get" action="<?php echo get_search_link(); ?>" role="search">
    <input class="search-input" type="search" name="s">
   <select name="category_name">
        <option value="">All categories</option>
        <option value="politics">Politics</option>
        <option value="economy">Economy</option>
    </select>
    <button class="search-submit" type="submit" role="button">Search</button>
</form>

2.- Use whatever query string you want and hook WP_Query on search request in pre_get_posts action:

The HTML:

<form class="search" method="get" action="<?php echo get_search_link(); ?>" role="search">
    <input class="search-input" type="search" name="s">
   <select name="a_search_filter">
        <option value="">All categories</option>
        <option value="politics">Politics</option>
        <option value="economy">Economy</option>
    </select>
    <button class="search-submit" type="submit" role="button">Search</button>
</form>

And the action:

add_action( 'pre_get_posts', 'cyb_advanced_search' );
function cyb_advanced_search( $query ) {

    if ( ! is_admin() && $query->is_search && $query->is_main_query() ) {

        // Set query parameters you need
        // For example
        $search_filter = $_REQUEST[ 'a_search_filter' ];
        $tax_query = [
            'taxonomy' => 'news',
            'field'    => 'slug',
            'terms'    =>  sanitize_text_field( $search_filter ),
        ];
        $query->set( 'tax_query', $tax_query );

    }
}

I would add the query string to WP Rewrite system:

add_filter( 'query_vars', 'cyb_query_vars' );
function cyb_query_vars( $vars ) {
  $vars[] = 'a_search_filter';
  return $vars;
}

Now you use get_query_var() to get the value of the custom query variable:

add_action( 'pre_get_posts', 'cyb_advanced_search' );
function cyb_advanced_search( $query ) {

    if ( ! is_admin() && $query->is_search && $query->is_main_query() ) {

        // Set query parameters you need
        // For example
        $search_filter = get_query_var( 'a_search_filter' );
        $tax_query = [
            'taxonomy' => 'news',
            'field'    => 'slug',
            'terms'    =>  sanitize_text_field( $search_filter ),
        ];
        $query->set( 'tax_query', $tax_query );

    }
}

Finally, you can get the current request and add/remove classes to your links and highliting them as you wish using CSS:

if( get_query_var(  'a_search_filter' ) ==  'category1' ) {
    $class = 'selected';
}

<a href="..." class=".<?php esc_attr_e( $class ); ?>.">Category 1</a>
  • Thanks for your detailed answer. And do you mean that all the accepted query arguments can be used directly in the search url as query variables like the category_name ? I never know that :( – hguser Oct 26 '16 at 6:17
  • Not all query argument, only the accepted as query string. For example, you can use https://example.com/?s=keyword&category_name=politics and the search results will look for keyword in posts that belong to politics category. Unfortunately, I don't know the exact list of the arguments than can be used directly as query string, but the argumetns you see in documentation with the format key=value should work, including post_type, author and lot more. – cybmeta Oct 26 '16 at 6:40
  • OK, I got it. I will have a try. BTW, seems there are some inconsistent function calls in your codes. – hguser Oct 26 '16 at 6:49
  • Sure, I didn't test it, just written here. Fixed. – cybmeta Oct 26 '16 at 6:58
  • I almost make it work, with just one problem, I have update the post, can you have a check if possible? – hguser Oct 26 '16 at 7:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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