1

The idea is to immediately show the post matching the search term. The search term will be alphanumeric and unique for each post (set as title). It could override search in content (for performance), I just need the title.

The search will be provided through a barcode reader, so it will be unique and precise.

I'm trying to immediately show the post, not the search results page, but I can't figure how.

1
  • 1
    Just curious what kind of barcode encoding are you using?
    – birgire
    Jun 22, 2017 at 8:58

2 Answers 2

1

Here's a solution that I came up with that uses a hidden field on the search form which we will later check in our filters to modify WP's default search/redirect behavior.

This is the search form I used. Note the addition of the hidden field barcode-reader with a value of 1. I added the search form to a page template for testing and demonstration purposes.

<form role="search" method="get" class="search-form" action="<?php echo esc_attr( home_url( '/' ) ); ?>">
    <label>
    <span class="screen-reader-text"><?php echo _x( 'Search for:', 'screen reader search label', 'textdomain' ); ?></span>
    <div class="input-group">
        <input type="search" class="search-field input-group-field" placeholder="<?php echo esc_attr_x( 'Search...', 'search placeholder', 'textdomain' ); ?>" value="<?php echo get_search_query(); ?>" name="s" title="<?php echo esc_attr_x( 'Search for:', 'textdomain' ); ?>" />

        <input type="hidden" value="1" name="barcode-reader" />

        <div class="input-group-button">
            <button type="submit" class="search-submit button" value="<?php echo esc_attr_x( 'Search', 'search button', 'textdomain' ); ?>">Search</button>
        </div>
    </div>
    </label>
</form>

(It's not clear from the original post, but from the research I've done, it should be possible for the barcode reader to send a parameter via $_GET which could be used instead of the hidden field I've used for testing.)

Here, we will check if this search is being performed by the barcode scanner using the helper function wpse_is_barcode_search(). The helper function is used so that we don't have to duplicate the logic across the multiple hooks that are used in this implementation.

If we are doing a search using the scanner, we wire up our posts_search filter and do some modifications to the WP_Query instance before the query is performed.

/**
 * Wire up our posts_search filter and change the $query.
 * 
 * @param WP_Query $query The WP_Query instance (passed by reference).
 */
add_action( 'pre_get_posts', 'wpse_barcode_search_pre_get_posts' );
function wpse_barcode_search_pre_get_posts( $query ) {
    // Bail if this search is not performed by the barcode scanner.
    if ( ! wpse_is_barcode_search( $query ) ) {
        return;
    }

    // Wire up the filter to modify the search SQL.
    add_filter( 'posts_search', 'wpse_barcode_posts_search', 10, 2 );

    // Set posts_per_page to one since we're only looking for an exact match anyway.
    $query->set( 'posts_per_page', 1 );

    // (suggestion) Limit search to a particular post type.
    // $query->set( 'post_type', array( 'product', ) );
}

Here is the filter that actually modifies the search SQL. Since we only want this to fire once, the filter is immediately unooked.

/**
 * Modify search query so that the search term looks for an exact
 * match with the post title.
 *
 * @param string   $search Search SQL for WHERE clause.
 * @param WP_Query $wp_query   The current WP_Query object.
 */
function wpse_barcode_posts_search( $search,  $wp_query ) {
    // We only want the search filter to fire once, so unhook it.
    remove_filter( 'posts_search', 'wpse_barcode_posts_search', 10, 2 );

    // Change the search SQL so that it checks if the search is equal to the post title.
    $search = " AND (wp_posts.post_title = '" . esc_sql( $wp_query->query_vars['s'] ) . "')";

    return $search;
}

This code redirects the user to the permalink of our found post rather than the search results page.

/**
 * Redirect to the permalink of the searched item if it was found using
 * the barcode search.
 *
 * @link https://wordpress.stackexchange.com/a/128578/2807
 */
add_action( 'template_redirect', 'wpse_barcode_search_success_redirect' );
function wpse_barcode_search_success_redirect() {
    global $wp_query;
    if ( ! wpse_is_barcode_search( $wp_query ) ) {
        return;
    }

    // If we have a post, redirect to it.
    if ( '1' === $wp_query->found_posts ) {
        wp_redirect( get_permalink( $wp_query->posts['0']->ID ) );
        exit;
    }
}

Finally, here is the helper function used to determine if we are performing a search using the barcode scanner. This should be modified so that it works with the scanner used ( particularly, the check using $_REQUEST['barcode-reader'] ).

/**
 * Helper function used to determine if a search is performed using
 * the barcode scanner.
 *
 * @uses array $_REQUEST
 * @param object $query
 * @return bool
 */
function wpse_is_barcode_search( $query ) {
    // Bail if $query is not an instance of WP_Query.
    if ( ! ( $query instanceof WP_Query ) ) {
        return false;
    }

    // Bail if this is the admin area.  
    if ( $query->is_admin() ) {
        return false;
    }

    // Bail if this is not the search page or main query.
    if ( ! $query->is_search() || ! $query->is_main_query() ) {
        return false;
    }

    // Bail if this is not our special barcode search.
    if ( ! isset( $_REQUEST['barcode-reader'] ) || '1' !== $_REQUEST['barcode-reader'] ) {
        return false;
    }

    return true;
}
3
  • 1
    ps: I think we might get a PHP notice when $_REQUEST['barcode-reader'] isn't set? I also wonder if we should use $wp_query->found_posts instead of $wp_query->post_count if we have e.g. posts_per_page as 1.
    – birgire
    Jun 22, 2017 at 8:59
  • 1
    Great ideas, as always @birgire. Thank you! I've updated the code with your suggestions and refactored it to remove duplication of the code that checks if the scanner is used. Jun 22, 2017 at 18:39
  • 1
    Well explained answer, great job!
    – birgire
    Jun 22, 2017 at 18:50
0

Custom template where You have custom query. This query search only one post and template shows this only post.

3
  • You mean like duplicating the native search page, but show results from an extra secondary query instead of the main search query? OP said:"I'm trying to immediately show the post, not the search results page" so it looks like OP wants to redirect to the found post.
    – birgire
    Jun 22, 2017 at 9:11
  • Now i understand :) Tried to help. Misunderstanding. Sorry Jun 22, 2017 at 9:39
  • 1
    Of course I might be misunderstanding the question in the first place ;-) So don't be discouraged in any way and I look forward to see you around here answering more questions.
    – birgire
    Jun 22, 2017 at 9:47

Your Answer

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

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