/** * This is where the magic happens - tap into the WordPress query and inject our own search * * @param string $request * @return void */ function posts_request( $request ) { global $wpdb, $current_user; $_GET['s'] = get_query_var( 's' ); // Extract search terms $term = trim( $_GET['s'] ); $term = preg_replace_callback( "/['\"](.*?)['\"]/", array( &$this, 'exact_words' ), $term ); $term = preg_replace_callback( preg_encoding( '/(\w*)\s*AND\s*(\w*)/' ), array( &$this, 'logical_and' ), $term ); $term = preg_replace( preg_encoding( '/(\w*)\s*OR\s*(\w*)/' ), '$1 $2', $term ); // Split the words into small and full $words = array_filter( preg_split( '/[\s,]+/', trim( $term ) ) ); foreach ( $words AS $word ) { if ( strlen( $word ) >= 4 ) $this->full[] = $word; else $this->small[] = $word; } include_once dirname( dirname( __FILE__ ) ).'/models/search-module.php'; $modules = Search_Module_Factory::running(); $and = array(); $have_comments = false; foreach ( (array)$modules AS $module ) { if ( $module->is_post() ) $prefix = $wpdb->prefix.'search_post'; else { $have_comments = true; $prefix = $wpdb->prefix.'search_comment'; } if ( isset( $_GET[$module->field_name()] ) ) { $value = $module->field_value( $_GET[$module->field_name()] ); if ( $value !== false ) $and[] = $prefix.'.'.$module->field_name()." LIKE '%".$wpdb->escape( $value )."%'"; } } if ( $have_comments ) $this->fields .= ",{$wpdb->prefix}search_comment.comment_id"; // Any fulltext searches? $priorities = $fields = array(); if ( count( $this->full ) > 0 ) { $term = implode( ' ', $this->full ); $term = trim( $term ); $this->terms = $this->full; $scores = array(); foreach ( (array)$modules AS $module ) { if ( $module->is_post() ) $item = $wpdb->prefix.'search_post.'.$module->field_name(); else $item = $wpdb->prefix.'search_comment.'.$module->field_name(); $fields[] = $item; $scores[] = sprintf( "(%2.2f * (MATCH(%s) AGAINST ('%s' IN BOOLEAN MODE)))", $module->priority, $item, $wpdb->escape( $term ) ); } $this->fields .= ',MAX('.implode( ' + ', $scores ).') AS score'; $this->orderby = 'score DESC,'.$this->orderby; } // Form SQL $sql = "SELECT DISTINCT SQL_CALC_FOUND_ROWS ".$this->fields." FROM {$wpdb->posts} LEFT JOIN {$wpdb->prefix}search_post ON {$wpdb->posts}.ID={$wpdb->prefix}search_post.post_id "; if ( $have_comments ) $sql .= " LEFT JOIN {$wpdb->prefix}search_comment ON {$wpdb->posts}.ID={$wpdb->prefix}search_comment.post_id "; $sql .= ' WHERE 1=1 '; $sql .= $this->get_restricted_posts(); if ( count( $and ) > 0 ) $sql .= ' AND '.implode( ' AND ', $and ); // Add small words foreach ( (array)$this->small AS $small ) { $this->terms[] = $small; foreach ( (array)$modules AS $module ) { if ( $module->is_post() ) $prefix = $wpdb->prefix.'search_post'; else $prefix = $wpdb->prefix.'search_comment'; $priorities[] = $prefix.'.'.$module->field_name()." LIKE '%".$wpdb->escape( $small )."%'"; } } if ( count( $this->full ) > 0 ) $priorities[] = sprintf( "(MATCH(".implode( ',', $fields ).") AGAINST ('%s' IN BOOLEAN MODE))", $wpdb->escape( $term ) ); $sql .= ' AND ('.implode( ' OR ', $priorities ).') '; if ( count( $this->full ) > 0 ) $sql .= " GROUP BY {$wpdb->posts}.ID HAVING score "; $sql .= "ORDER BY ".$this->orderby.' '; $sql .= $this->limits; return $sql; }
/** * Clean a piece of text suitable for indexing * This removes all HTML, removes most entities and empty spaces * * @param string $text Text to clean * @return string Cleaned text **/ function clean_for_search($text) { // Save HREF and ALT attributes preg_match_all('/ href=["\'](.*?)["\']/iu', $text, $href); preg_match_all('/ alt=["\'](.*?)["\']/iu', $text, $alt); preg_match_all('/ title=["\'](.*?)["\']/iu', $text, $title); // Remove comments and JavaScript $text = preg_replace(preg_encoding('/<script(.*?)<\\/script>/s'), '', $text); $text = preg_replace(preg_encoding('/<!--(.*?)-->/s'), '', $text); $text = str_replace('<', ' <', $text); // Insert a space before HTML so the strip will have seperate words $text = preg_replace('/&#\\d*;/', '', $text); $text = addslashes(wp_kses(stripslashes(strip_html($text)), array())); $text = preg_replace(preg_encoding('/&\\w*;/'), ' ', $text); // Removes entities $text = str_replace("'", '', $text); $text = str_replace('­', '', $text); $text = preg_replace(preg_encoding('/[\'!;#$%&\\,_\\+=\\?\\(\\)\\[\\]\\{\\}\\"<>`]/'), ' ', $text); if (count($href) > 0) { $text .= ' ' . implode(' ', $href[1]); } if (count($alt) > 0) { $text .= ' ' . implode(' ', $alt[1]); } if (count($title) > 0) { $text .= ' ' . implode(' ', $title[1]); } while (preg_match(preg_encoding('/\\s{2}/'), $text, $matches) > 0) { $text = preg_replace(preg_encoding('/\\s{2}/'), ' ', $text); } $text = str_replace('"', '', $text); $text = str_replace($this->blog_url, '', $text); return stripslashes(trim($text)); }
/** * Highlight individual words * * @param object $links Not sure * @return string Highlighted text **/ function mark_words( $links = false ) { $text = $this->text; $html = strpos( $text, '<' ) === false ? false : true; $this->mark_links = $links; foreach ( $this->words AS $pos => $word ) { if ( $pos > 5 ) $pos = 1; $this->word_count = 0; $this->word_pos = $pos; if ( $html ) $text = @preg_replace_callback( preg_encoding( '/(?<=>)([^<]+)?('.$word.')(?!=")/i' ), array( &$this, 'highlight_html_word' ), $text ); else $text = preg_replace_callback( '/('.$word.')(?!=")/iu', array( &$this, 'highlight_plain_word' ), $text ); } $this->text = $text; return $text; }