23

I am currently trying to create a wordpress search function that shows live results underneath the search bar. There is an example on the World Bank website (screens below). I'm not looking for an autofill like you would find on Google.com which completes words you type, rather I want it to find actual posts on the site.

I tried doing a scrub through Wordpress Answers and other similar resources but have only run into implementing a Google type search which is not what I am looking for. Any help or points in the right direction would be greatly appreciated.

search-before

search after

3
  • What do you want to happen when user clicks suggestion? Just fill search box with it?
    – Rarst
    Commented Feb 20, 2012 at 9:16
  • Takes you to the respective post. User can still type and get search results normally, only clicking suggestions would direct to the post. Commented Feb 20, 2012 at 9:53
  • I have quick solution in mind for filling, but linking more problematic... Will think about it.
    – Rarst
    Commented Feb 20, 2012 at 9:58

3 Answers 3

20

The following uses jQuery UI Autocomplete, which has been included in WordPress since 3.3. (I've borrowed the format from @Rarst :D).

It's still not precisely what you're after, but gives you a good starting point. The following uses a the basic jQuery UI styling, but you can use the one that's currently worked out on trac and call that from your plug-in folder.

class AutoComplete {

    static $action = 'my_autocomplete';//Name of the action - should be unique to your plugin.

    static function load() {
        add_action( 'init', array( __CLASS__, 'init'));
    }

    static function init() {
        //Register style - you can create your own jQuery UI theme and store it in the plug-in folder
        wp_register_style('my-jquery-ui','http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css');    
        add_action( 'get_search_form', array( __CLASS__, 'get_search_form' ) );
        add_action( 'wp_print_footer_scripts', array( __CLASS__, 'print_footer_scripts' ), 11 );
        add_action( 'wp_ajax_'.self::$action, array( __CLASS__, 'autocomplete_suggestions' ) );
        add_action( 'wp_ajax_nopriv_'.self::$action, array( __CLASS__, 'autocomplete_suggestions' ) );
    }

    static function get_search_form( $form ) {
        wp_enqueue_script( 'jquery-ui-autocomplete' );
        wp_enqueue_style('my-jquery-ui');
        return $form;
    }

    static function print_footer_scripts() {
        ?>
    <script type="text/javascript">
    jQuery(document).ready(function ($){
        var ajaxurl = '<?php echo admin_url( 'admin-ajax.php' ); ?>';
        var ajaxaction = '<?php echo self::$action ?>';
        $("#secondary #searchform #s").autocomplete({
            delay: 0,
            minLength: 0,
            source: function(req, response){  
                $.getJSON(ajaxurl+'?callback=?&action='+ajaxaction, req, response);  
            },
            select: function(event, ui) {
                window.location.href=ui.item.link;
            },
        });
    });
    </script><?php
    }

    static function autocomplete_suggestions() {
        $posts = get_posts( array(
            's' => trim( esc_attr( strip_tags( $_REQUEST['term'] ) ) ),
        ) );
        $suggestions=array();

        global $post;
        foreach ($posts as $post): 
                    setup_postdata($post);
            $suggestion = array();
            $suggestion['label'] = esc_html($post->post_title);
            $suggestion['link'] = get_permalink();

            $suggestions[]= $suggestion;
        endforeach;

        $response = $_GET["callback"] . "(" . json_encode($suggestions) . ")";  
        echo $response;  
        exit;
    }
}
AutoComplete::load();
0
12

Ok, this would be very basic example code that uses native suggest.js, WP core for Ajax and binds to default search form (from unmodified get_search_form() call). It's not precisely what you asked for, but incremental search is huge pain to get perfect. :)

class Incremental_Suggest {

    static function on_load() {

        add_action( 'init', array( __CLASS__, 'init' ) );
    }

    static function init() {

        add_action( 'wp_print_scripts', array( __CLASS__, 'wp_print_scripts' ) );
        add_action( 'get_search_form', array( __CLASS__, 'get_search_form' ) );
        add_action( 'wp_print_footer_scripts', array( __CLASS__, 'wp_print_footer_scripts' ), 11 );
        add_action( 'wp_ajax_incremental_suggest', array( __CLASS__, 'wp_ajax_incremental_suggest' ) );
        add_action( 'wp_ajax_nopriv_incremental_suggest', array( __CLASS__, 'wp_ajax_incremental_suggest' ) );
    }

    static function wp_print_scripts() {

        ?>
    <style type="text/css">
        .ac_results {
            padding: 0;
            margin: 0;
            list-style: none;
            position: absolute;
            z-index: 10000;
            display: none;
            border-width: 1px;
            border-style: solid;
        }

        .ac_results li {
            padding: 2px 5px;
            white-space: nowrap;
            text-align: left;
        }

        .ac_over {
            cursor: pointer;
        }

        .ac_match {
            text-decoration: underline;
        }
    </style>
    <?php
    }

    static function get_search_form( $form ) {

        wp_enqueue_script( 'suggest' );

        return $form;
    }

    static function wp_print_footer_scripts() {

        ?>
    <script type="text/javascript">
        jQuery(document).ready(function ($) {
            $('#s').suggest('<?php echo admin_url( 'admin-ajax.php' ); ?>' + '?action=incremental_suggest');
        });
    </script><?php
    }

    static function wp_ajax_incremental_suggest() {

        $posts = get_posts( array(
            's' => $_REQUEST['q'],
        ) );

        $titles = wp_list_pluck( $posts, 'post_title' );
        $titles = array_map( 'esc_html', $titles );
        echo implode( "\n", $titles );

        die;
    }
}

Incremental_Suggest::on_load();
0

You must do it using Ajax of course, but here there is a problem. Since WordPress uses MySQL, you might over stress your server with searching if you try to fill the search with the real Database queries trough Ajax, but what you might do is develop a system where all the posts are saved in to one big "wp_options" field and then when a search is done you query from that instead of doing a real search. But remember you need to update this chunk of text/serialized variable every time you create or edit a post.

If you are not willing to spend some time to develop this solution, I wouldn't recommend you doing this sort of "live search".

4
  • 2
    In such use case resource usage of MySQL requests would be completely insignificant comparing to hit of loading WP core for Ajax requests.
    – Rarst
    Commented Feb 20, 2012 at 9:15
  • 1
    Depends on how you are trying to do the Ajax Request, in this case you don't really need all the WP core for your answer, the best case scenario would be just to load $wpdb and search for your field. But agreed, using the main WP Ajax url both of them could turn in to a problem, if not well handled.
    – Webord
    Commented Feb 20, 2012 at 9:18
  • 1
    Yes, I am just noting that MySQL performance would not be bottleneck (unless you get into hundreds of thousands of posts and such). WP core is much much slower. Network is also slower.
    – Rarst
    Commented Feb 20, 2012 at 9:23
  • Yes, but doing some sort of Scalling with WP Core machines is much easier and faster. With MySQL machines is slower and harder. But on a normal installation, I agree with you.
    – Webord
    Commented Feb 20, 2012 at 9:36

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.