prepare("MATCH (object_text) AGAINST (%s)", $wp_query->get('s')); $query = "SELECT object_id, object_type, $match AS score FROM {$wpdb->prefix}fulltext WHERE $match"; $join .= " RIGHT JOIN ($query) AS ft ON (ID=ft.post_id)"; add_filter('posts_orderby', 'fulltext_posts_orderby_once', 10); } return $join; } function fulltext_posts_orderby_once() { remove_filter('posts_orderby', 'fulltext_posts_orderby_once', 10); return "score DESC"; } function fulltext_init() { global $fulltext_index; $fulltext_index = new fulltext_index(); } add_action('init', 'fulltext_init'); class fulltext_index { // These are populated from the filters of the same names, then used in reconstructing the search query. var $posts_fields = ''; var $posts_join = ''; var $posts_where = ''; var $posts_groupby = ''; var $posts_orderby = ''; var $post_limits = ''; function fulltext_index() { // Actions that trigger indexing a post or comment: add_action( 'delete_post', array( &$this, 'delete_post' ) ); add_action( 'save_post', array( &$this, 'index_post' ) ); add_action( 'delete_comment', array( &$this, 'index_comment' ) ); add_action( 'comment_post', array( &$this, 'index_comment' ) ); add_action( 'edit_comment', array( &$this, 'index_comment' ) ); add_action( 'wp_set_comment_status', array( &$this, 'index_comment' ) ); // WP_Query::get_posts filters for modifying: add_filter( 'posts_search', array(&$this, 'return_blank') ); // WP_Query::get_posts filters for saving: add_filter( 'posts_fields', array(&$this, 'set_posts_fields') ); add_filter( 'posts_join', array(&$this, 'set_posts_join') ); add_filter( 'posts_where', array(&$this, 'set_posts_where') ); add_filter( 'posts_groupby', array(&$this, 'set_posts_groupby') ); add_filter( 'posts_orderby', array(&$this, 'set_posts_orderby') ); add_filter( 'post_limits', array(&$this, 'set_post_limits') ); // WP_Query::get_posts filters for reconstructing: add_filter( 'posts_request', array(&$this, 'posts_request') ); } function return_blank($v) { if ( is_search() ) return ''; return $v; } function set_posts_fields ($v) { $this->posts_fields = $v; return $v; } function set_posts_join ($v) { $this->posts_join = $v; return $v; } function set_posts_where ($v) { $this->posts_where = $v; return $v; } function set_posts_groupby($v) { $this->posts_groupby = $v; return $v; } function set_posts_orderby($v) { $this->posts_orderby = $v; return $v; } function set_post_limits ($v) { $this->post_limits = $v; return $v; } function posts_request($request) { global $wpdb, $wp_query; if ( !is_search() ) return $request; if ( !empty($this->posts_limits) ) $found_rows = 'SQL_CALC_FOUND_ROWS'; $fields = "$wpdb->posts.*, $wpdb->comments.*"; $match = $wpdb->prepare("MATCH (object_text) AGAINST (%s)", $wp_query->get('s')); $subquery = "SELECT object_id, object_type, $match AS score FROM {$wpdb->prefix}fulltext WHERE $match"; $tables = "($subquery) AS ft LEFT JOIN wp_posts ON (ID=object_id AND object_type='post') LEFT JOIN wp_comments ON (comment_id=object_id AND object_type='comment')"; $where = "(1=1 $this->posts_where) OR (comment_post_id IS NOT NULL)"; $orderby = "ORDER BY score DESC"; $limits = $this->post_limits; return "SELECT $found_rows $fields FROM $tables WHERE $where $orderby $limits"; } function delete_post($post_id) { global $wpdb; $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}fulltext WHERE object_id = %d AND object_type='post'", $post_id)); } function index_comment($comment_id) { global $wpdb; $comment = get_comment($comment_id); $post = get_post($comment->comment_post_id); $text = $post->post_title; $text .= ' ' . $comment->comment_author; $text .= ' ' . $comment->comment_content; $wpdb->query($wpdb->prepare("INSERT INTO {$wpdb->prefix}fulltext (object_id, object_type, object_text) VALUES (%d, 'comment', %s) ON DUPLICATE KEY UPDATE object_text=VALUES(object_text)", $comment_id, $text)); } function index_post($post_id) { global $wpdb; $post = get_post($post_id); $text = $post->post_title; $text .= ' ' . $post->post_content; $terms = wp_get_object_terms($post_id, get_object_taxonomies($post)); foreach ( $terms as $term ) $text .= ' ' . $term->name; if ( $comments = get_approved_comments($post_id) ) foreach ( $comments as $comment ) $text .= ' ' . $comment->comment_author . ' ' . $comment->comment_content; $wpdb->query($wpdb->prepare("INSERT INTO {$wpdb->prefix}fulltext (object_id, object_type, object_text) VALUES (%d, 'post', %s) ON DUPLICATE KEY UPDATE object_text=VALUES(object_text)", $post_id, $text)); } function create_table() { global $wpdb; $wpdb->query(" CREATE TABLE IF NOT EXISTS {$wpdb->prefix}fulltext ( object_id INT(11) NOT NULL, object_type VARCHAR(20) NOT NULL, object_text TEXT NOT NULL, PRIMARY KEY (object_id, object_type), FULLTEXT KEY (object_text) ) ENGINE=MyISAM "); $this->index_all(); } function index_all() { global $wpdb; if ( $types = get_post_types( array("exclude_from_search" => false) ) ) { $and_type = "AND post_type IN ("; foreach ( $types as $type ) $and_type .= $wpdb->prepare("%s", $type) . ','; $and_type = substr($and_type, 0, -1) . ')'; } if ( $stati = get_post_stati( array("exclude_from_search" => false) ) ) { $and_status = "AND post_status IN ("; foreach ( $stati as $status ) $and_status .= $wpdb->prepare("%s", $status) . ','; $and_status = substr($and_status, 0, -1) . ')'; } if ( $post_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE 1=1 $and_type $and_status") ) { foreach ( $post_ids as $post_id ) $this->index_post($post_id); } } } $fulltext_index = new fulltext_index(); register_activation_hook( __FILE__, array(&$fulltext_index, 'create_table') );