function relevanssi_search($q, $tax_query = NULL, $relation = NULL, $post_query = array(), $meta_query = array(), $expost = NULL, $post_type = NULL, $operator = "AND", $search_blogs = NULL, $author = NULL, $orderby = NULL, $order = NULL)
{
    global $wpdb, $relevanssi_variables;
    $relevanssi_table = $relevanssi_variables['relevanssi_table'];
    $values_to_filter = array('q' => $q, 'tax_query' => $tax_query, 'relation' => $relation, 'post_query' => $post_query, 'meta_query' => $meta_query, 'expost' => $expost, 'post_type' => $post_type, 'operator' => $operator, 'search_blogs' => $search_blogs, 'author' => $author, 'orderby' => $orderby, 'order' => $order);
    $filtered_values = apply_filters('relevanssi_search_filters', $values_to_filter);
    $q = $filtered_values['q'];
    $tax_query = $filtered_values['tax_query'];
    $post_query = $filtered_values['post_query'];
    $meta_query = $filtered_values['meta_query'];
    $relation = $filtered_values['relation'];
    $expost = $filtered_values['expost'];
    $post_type = $filtered_values['post_type'];
    $operator = $filtered_values['operator'];
    $search_blogs = $filtered_values['search_blogs'];
    $author = $filtered_values['author'];
    $orderby = $filtered_values['orderby'];
    $order = $filtered_values['order'];
    $hits = array();
    $o_tax_query = $tax_query;
    $o_relation = $relation;
    $o_post_query = $post_query;
    $o_meta_query = $meta_query;
    $o_expost = $expost;
    $o_post_type = $post_type;
    $o_author = $author;
    $o_operator = $operator;
    $o_search_blogs = $search_blogs;
    $o_orderby = $orderby;
    $o_order = $order;
    $query_restrictions = "";
    if (!isset($relation)) {
        $relation = "or";
    }
    $relation = strtolower($relation);
    $term_tax_id = array();
    $term_tax_ids = array();
    $not_term_tax_ids = array();
    $and_term_tax_ids = array();
    if (is_array($tax_query)) {
        foreach ($tax_query as $row) {
            if ($row['field'] == 'id' || $row['field'] == 'term_id') {
                $id = $row['terms'];
                $term_id = $id;
                if (is_array($id)) {
                    $id = implode(',', $id);
                }
                $term_tax_id = $wpdb->get_col("SELECT tt.term_taxonomy_id\n\t\t\t\t\tFROM {$wpdb->terms} AS t, {$wpdb->term_taxonomy} AS tt\n\t\t\t\t\tWHERE tt.term_id = t.term_id AND tt.taxonomy = '" . $row['taxonomy'] . "' AND t.term_id IN ({$id})");
            }
            if ($row['field'] == 'slug') {
                $slug = $row['terms'];
                if (is_array($slug)) {
                    $slugs = array();
                    $term_id = array();
                    foreach ($slug as $t_slug) {
                        $term = get_term_by('slug', $t_slug, $row['taxonomy']);
                        $term_id[] = $term->term_id;
                        $slugs[] = "'{$t_slug}'";
                    }
                    $slug = implode(',', $slugs);
                } else {
                    $term = get_term_by('slug', $slug, $row['taxonomy']);
                    $term_id = $term->term_id;
                    $slug = "'{$slug}'";
                }
                $term_tax_id = $wpdb->get_col("SELECT tt.term_taxonomy_id\n\t\t\t\t\tFROM {$wpdb->terms} AS t, {$wpdb->term_taxonomy} AS tt\n\t\t\t\t\tWHERE tt.term_id = t.term_id AND tt.taxonomy = '" . $row['taxonomy'] . "' AND t.slug IN ({$slug})");
            }
            if (!isset($row['include_children']) || $row['include_children'] == true) {
                if (!is_array($term_id)) {
                    $term_id = array($term_id);
                }
                foreach ($term_id as $t_id) {
                    $kids = get_term_children($t_id, $row['taxonomy']);
                    foreach ($kids as $kid) {
                        $term = get_term_by('id', $kid, $row['taxonomy']);
                        $term_tax_id[] = relevanssi_get_term_tax_id('id', $kid, $row['taxonomy']);
                    }
                }
            }
            $term_tax_id = array_unique($term_tax_id);
            if (!empty($term_tax_id)) {
                $n = count($term_tax_id);
                $term_tax_id = implode(',', $term_tax_id);
                $tq_operator = 'IN';
                if (isset($row['operator'])) {
                    $tq_operator = strtoupper($row['operator']);
                }
                if ($tq_operator != 'IN' && $tq_operator != 'NOT IN' && $tq_operator != 'AND') {
                    $tq_operator = 'IN';
                }
                if ($relation == 'and') {
                    if ($tq_operator == 'AND') {
                        $query_restrictions .= " AND relevanssi.doc IN (\n\t\t\t\t\t\t\tSELECT ID FROM {$wpdb->posts} WHERE 1=1 \n\t\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\t\tSELECT COUNT(1) \n\t\t\t\t\t\t\t\tFROM {$wpdb->term_relationships} AS tr\n\t\t\t\t\t\t\t\tWHERE tr.term_taxonomy_id IN ({$term_tax_id}) \n\t\t\t\t\t\t\t\tAND tr.object_id = {$wpdb->posts}.ID ) = {$n}\n\t\t\t\t\t\t\t)";
                    } else {
                        $query_restrictions .= " AND relevanssi.doc {$tq_operator} (SELECT DISTINCT(tr.object_id) FROM {$wpdb->term_relationships} AS tr\n\t\t\t\t\t\tWHERE tr.term_taxonomy_id IN ({$term_tax_id}))";
                    }
                } else {
                    if ($tq_operator == 'IN') {
                        $term_tax_ids[] = $term_tax_id;
                    }
                    if ($tq_operator == 'NOT IN') {
                        $not_term_tax_ids[] = $term_tax_id;
                    }
                    if ($tq_operator == 'AND') {
                        $and_term_tax_ids[] = $term_tax_id;
                    }
                }
            } else {
                global $wp_query;
                $wp_query->is_category = false;
            }
        }
        if ($relation == 'or') {
            $term_tax_ids = array_unique($term_tax_ids);
            if (count($term_tax_ids) > 0) {
                $term_tax_ids = implode(',', $term_tax_ids);
                $query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(tr.object_id) FROM {$wpdb->term_relationships} AS tr\n\t\t\t    \tWHERE tr.term_taxonomy_id IN ({$term_tax_ids}))";
            }
            if (count($not_term_tax_ids) > 0) {
                $not_term_tax_ids = implode(',', $not_term_tax_ids);
                $query_restrictions .= " AND relevanssi.doc NOT IN (SELECT DISTINCT(tr.object_id) FROM {$wpdb->term_relationships} AS tr\n\t\t\t    \tWHERE tr.term_taxonomy_id IN ({$not_term_tax_ids}))";
            }
            if (count($and_term_tax_ids) > 0) {
                $and_term_tax_ids = implode(',', $and_term_tax_ids);
                $n = count(explode(',', $and_term_tax_ids));
                $query_restrictions .= " AND relevanssi.doc IN (\n\t\t\t\t\tSELECT ID FROM {$wpdb->posts} AS posts WHERE 1=1 \n\t\t\t\t\tAND (\n\t\t\t\t\t\tSELECT COUNT(1) \n\t\t\t\t\t\tFROM {$wpdb->term_relationships} AS tr\n\t\t\t\t\t\tWHERE tr.term_taxonomy_id IN ({$and_term_tax_ids}) \n\t\t\t\t\t\tAND tr.object_id = {$wpdb->posts}.ID ) = {$n}\n\t\t\t\t\t)";
            }
        }
    }
    if (is_array($post_query)) {
        if (!empty($post_query['in'])) {
            $posts = implode(',', $post_query['in']);
            $query_restrictions .= " AND relevanssi.doc IN ({$posts})";
        }
        if (!empty($post_query['not in'])) {
            $posts = implode(',', $post_query['not in']);
            $query_restrictions .= " AND relevanssi.doc NOT IN ({$posts})";
        }
    }
    if (is_array($meta_query)) {
        isset($meta_query['relation']) ? $meta_relation = strtoupper($meta_query['relation']) : ($meta_relation = strtoupper(apply_filters('relevanssi_default_meta_query_relation', 'AND')));
        $meta_query_restrictions = "";
        foreach ($meta_query as $array_key => $meta) {
            if ($array_key === 'relation') {
                continue;
            }
            if (!empty($meta['key'])) {
                $key = "postmeta.meta_key = '" . $meta['key'] . "'";
            } else {
                $key = '';
            }
            isset($meta['compare']) ? $compare = strtoupper($meta['compare']) : ($compare = '=');
            if (isset($meta['type'])) {
                if (strtoupper($meta['type']) == 'NUMERIC') {
                    $meta['type'] = "SIGNED";
                }
                $meta_value = "CAST(postmeta.meta_value AS " . $meta['type'] . ")";
            } else {
                $meta_value = 'postmeta.meta_value';
            }
            if ($compare == 'BETWEEN' || $compare == 'NOT BETWEEN') {
                if (!is_array($meta['value'])) {
                    continue;
                }
                if (count($meta['value']) < 2) {
                    continue;
                }
                $compare == 'BETWEEN' ? $compare = "IN" : ($compare = "NOT IN");
                $low_value = $meta['value'][0];
                $high_value = $meta['value'][1];
                !empty($key) ? $and = " AND " : ($and = "");
                $meta_query_restrictions .= " {$meta_relation} relevanssi.doc {$compare} (\n\t\t\t\t\tSELECT DISTINCT(postmeta.post_id) FROM {$wpdb->postmeta} AS postmeta\n\t\t\t\t\tWHERE {$key} {$and} {$meta_value} BETWEEN {$low_value} AND {$high_value})";
            } else {
                if ($compare == 'EXISTS' || $compare == 'NOT EXISTS') {
                    $compare == 'EXISTS' ? $compare = "IN" : ($compare = "NOT IN");
                    $meta_query_restrictions .= " {$meta_relation} relevanssi.doc {$compare} (\n\t\t\t\t\tSELECT DISTINCT(postmeta.post_id) FROM {$wpdb->postmeta} AS postmeta\n\t\t\t\t\tWHERE {$key})";
                } else {
                    if ($compare == 'IN' || $compare == 'NOT IN') {
                        if (!is_array($meta['value'])) {
                            continue;
                        }
                        $values = array();
                        foreach ($meta['value'] as $value) {
                            $values[] = "'{$value}'";
                        }
                        $values = implode(',', $values);
                        !empty($key) ? $and = " AND " : ($and = "");
                        $meta_query_restrictions .= " {$meta_relation} relevanssi.doc IN (\n\t\t\t\t\tSELECT DISTINCT(postmeta.post_id) FROM {$wpdb->postmeta} AS postmeta\n\t\t\t\t\tWHERE {$key} {$and} {$meta_value} {$compare} ({$values}))";
                    } else {
                        isset($meta['value']) ? $value = " {$meta_value} " . $meta['compare'] . " '" . $meta['value'] . "' " : ($value = '');
                        !empty($key) && !empty($value) ? $and = " AND " : ($and = "");
                        if (empty($key) && empty($and) && empty($value)) {
                            // do nothing
                        } else {
                            $meta_query_restrictions .= " {$meta_relation} relevanssi.doc IN (\n\t\t\t\t\t\tSELECT DISTINCT(postmeta.post_id) FROM {$wpdb->postmeta} AS postmeta\n\t\t\t\t\t\tWHERE {$key} {$and} {$value})";
                        }
                    }
                }
            }
        }
        if ($meta_relation == 'OR') {
            $meta_query_restrictions = substr($meta_query_restrictions, 3);
            // strip the first OR
            $meta_query_restrictions = "AND (" . $meta_query_restrictions . ") ";
        }
        $query_restrictions .= $meta_query_restrictions;
    }
    if (!$post_type && get_option('relevanssi_respect_exclude') == 'on') {
        if (function_exists('get_post_types')) {
            $pt_1 = get_post_types(array('exclude_from_search' => '0'));
            $pt_2 = get_post_types(array('exclude_from_search' => false));
            $post_type = implode(',', array_merge($pt_1, $pt_2));
        }
    }
    if ($post_type) {
        if ($post_type == -1) {
            $post_type = null;
        }
        // Facetious sets post_type to -1 if not selected
        if (!is_array($post_type)) {
            $post_types = explode(',', $post_type);
        } else {
            $post_types = $post_type;
        }
        $post_type = count($post_types) ? implode(',', array_fill(1, count($post_types), "'%s'")) : 'NULL';
    }
    //Added by OdditY:
    //Exclude Post_IDs (Pages) for non-admin search ->
    $postex = '';
    if ($expost) {
        if ($expost != "") {
            $aexpids = explode(",", $expost);
            foreach ($aexpids as $exid) {
                $exid = esc_sql(trim($exid, ' -'));
                $postex .= " AND relevanssi.doc !='{$exid}'";
            }
        }
    }
    // <- OdditY End
    $remove_stopwords = true;
    $phrases = relevanssi_recognize_phrases($q);
    if (function_exists('relevanssi_recognize_negatives')) {
        $negative_terms = relevanssi_recognize_negatives($q);
    } else {
        $negative_terms = false;
    }
    if (function_exists('relevanssi_recognize_positives')) {
        $positive_terms = relevanssi_recognize_positives($q);
    } else {
        $positive_terms = false;
    }
    $terms = relevanssi_tokenize($q, $remove_stopwords);
    if (count($terms) < 1) {
        // Tokenizer killed all the search terms.
        return $hits;
    }
    $terms = array_keys($terms);
    // don't care about tf in query
    if ($negative_terms) {
        $terms = array_diff($terms, $negative_terms);
        if (count($terms) < 1) {
            return $hits;
        }
    }
    $D = $wpdb->get_var("SELECT COUNT(DISTINCT(relevanssi.doc)) FROM {$relevanssi_table} AS relevanssi");
    $total_hits = 0;
    $title_matches = array();
    $tag_matches = array();
    $comment_matches = array();
    $link_matches = array();
    $body_matches = array();
    $scores = array();
    $term_hits = array();
    $fuzzy = get_option('relevanssi_fuzzy');
    if ($expost) {
        //added by OdditY
        $query_restrictions .= $postex;
    }
    if (function_exists('relevanssi_negatives_positives')) {
        $query_restrictions .= relevanssi_negatives_positives($negative_terms, $positive_terms, $relevanssi_table);
    }
    if (!empty($author)) {
        $author_in = array();
        $author_not_in = array();
        foreach ($author as $id) {
            if ($id > 0) {
                $author_in[] = $id;
            } else {
                $author_not_in[] = abs($id);
            }
        }
        if (count($author_in) > 0) {
            $authors = implode(',', $author_in);
            $query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\t    WHERE posts.post_author IN ({$authors}))";
        }
        if (count($author_not_in) > 0) {
            $authors = implode(',', $author_not_in);
            $query_restrictions .= " AND relevanssi.doc NOT IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\t    WHERE posts.post_author IN ({$authors}))";
        }
    }
    if ($post_type) {
        // the -1 is there to get user profiles and category pages
        $query_restrictions .= $wpdb->prepare(" AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\tWHERE posts.post_type IN ({$post_type}))) OR (doc = -1))", $post_types);
    }
    if ($phrases) {
        $query_restrictions .= " AND relevanssi.doc IN ({$phrases})";
    }
    if (isset($_REQUEST['by_date'])) {
        $n = $_REQUEST['by_date'];
        $u = substr($n, -1, 1);
        switch ($u) {
            case 'h':
                $unit = "HOUR";
                break;
            case 'd':
                $unit = "DAY";
                break;
            case 'm':
                $unit = "MONTH";
                break;
            case 'y':
                $unit = "YEAR";
                break;
            case 'w':
                $unit = "WEEK";
                break;
            default:
                $unit = "DAY";
        }
        $n = preg_replace('/[hdmyw]/', '', $n);
        if (is_numeric($n)) {
            $query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\t\tWHERE posts.post_date > DATE_SUB(NOW(), INTERVAL {$n} {$unit}))";
        }
    }
    $query_restrictions = apply_filters('relevanssi_where', $query_restrictions);
    // Charles St-Pierre
    $query_join = apply_filters('relevanssi_join', '');
    $no_matches = true;
    if ("always" == $fuzzy) {
        $o_term_cond = apply_filters('relevanssi_fuzzy_query', "(relevanssi.term LIKE '#term#%' OR relevanssi.term_reverse LIKE CONCAT(REVERSE('#term#'), '%')) ");
    } else {
        $o_term_cond = " relevanssi.term = '#term#' ";
    }
    $post_type_weights = get_option('relevanssi_post_type_weights');
    if (function_exists('relevanssi_get_recency_bonus')) {
        list($recency_bonus, $recency_cutoff_date) = relevanssi_get_recency_bonus();
    } else {
        $recency_bonus = false;
        $recency_cutoff_date = false;
    }
    $min_length = get_option('relevanssi_min_word_length');
    $search_again = false;
    $title_boost = floatval(get_option('relevanssi_title_boost'));
    $link_boost = floatval(get_option('relevanssi_link_boost'));
    $comment_boost = floatval(get_option('relevanssi_comment_boost'));
    $include_these_posts = array();
    do {
        foreach ($terms as $term) {
            $term = trim($term);
            // numeric search terms will start with a space
            if (strlen($term) < $min_length) {
                continue;
            }
            $term = esc_sql(like_escape($term));
            $term_cond = str_replace('#term#', $term, $o_term_cond);
            !empty($post_type_weights['post_tag']) ? $tag = $post_type_weights['post_tag'] : ($tag = $relevanssi_variables['post_type_weight_defaults']['post_tag']);
            !empty($post_type_weights['category']) ? $cat = $post_type_weights['category'] : ($cat = $relevanssi_variables['post_type_weight_defaults']['category']);
            $query = "SELECT relevanssi.*, relevanssi.title * {$title_boost} + relevanssi.content + relevanssi.comment * {$comment_boost} + relevanssi.tag * {$tag} + relevanssi.link * {$link_boost} + relevanssi.author + relevanssi.category * {$cat} + relevanssi.excerpt + relevanssi.taxonomy + relevanssi.customfield + relevanssi.mysqlcolumn AS tf \n\t\t\t\t\t  FROM {$relevanssi_table} AS relevanssi {$query_join} WHERE {$term_cond} {$query_restrictions}";
            $query = apply_filters('relevanssi_query_filter', $query);
            $matches = $wpdb->get_results($query);
            if (count($matches) < 1) {
                continue;
            } else {
                $no_matches = false;
                if (count($include_these_posts) > 0) {
                    $post_ids_to_add = implode(',', array_keys($include_these_posts));
                    $query = "SELECT relevanssi.*, relevanssi.title * {$title_boost} + relevanssi.content + relevanssi.comment * {$comment_boost} + relevanssi.tag * {$tag} + relevanssi.link * {$link_boost} + relevanssi.author + relevanssi.category * {$cat} + relevanssi.excerpt + relevanssi.taxonomy + relevanssi.customfield + relevanssi.mysqlcolumn AS tf \n\t\t\t\t\t\t  FROM {$relevanssi_table} AS relevanssi WHERE relevanssi.doc IN ({$post_ids_to_add}) AND {$term_cond}";
                    $matches_to_add = $wpdb->get_results($query);
                    $matches = array_merge($matches, $matches_to_add);
                }
            }
            relevanssi_populate_array($matches);
            global $relevanssi_post_types;
            $total_hits += count($matches);
            $query = "SELECT COUNT(DISTINCT(relevanssi.doc)) FROM {$relevanssi_table} AS relevanssi {$query_join} WHERE {$term_cond} {$query_restrictions}";
            $query = apply_filters('relevanssi_df_query_filter', $query);
            $df = $wpdb->get_var($query);
            if ($df < 1 && "sometimes" == $fuzzy) {
                $query = "SELECT COUNT(DISTINCT(relevanssi.doc)) FROM {$relevanssi_table} AS relevanssi {$query_join}\n\t\t\t\t\tWHERE (relevanssi.term LIKE '{$term}%' OR relevanssi.term_reverse LIKE CONCAT(REVERSE('{$term}), %')) {$query_restrictions}";
                $query = apply_filters('relevanssi_df_query_filter', $query);
                $df = $wpdb->get_var($query);
            }
            $idf = log($D + 1 / (1 + $df));
            $idf = $idf * $idf;
            foreach ($matches as $match) {
                if ('user' == $match->type) {
                    $match->doc = 'u_' . $match->item;
                }
                if ('taxonomy' == $match->type) {
                    $match->doc = 't_' . $match->item;
                }
                if (isset($match->taxonomy_detail)) {
                    $match->taxonomy_score = 0;
                    $match->taxonomy_detail = unserialize($match->taxonomy_detail);
                    if (is_array($match->taxonomy_detail)) {
                        foreach ($match->taxonomy_detail as $tax => $count) {
                            if ($tax == 'post_tag') {
                                $match->tag = $count;
                            }
                            if (empty($post_type_weights[$tax])) {
                                $match->taxonomy_score += $count * 1;
                            } else {
                                $match->taxonomy_score += $count * $post_type_weights[$tax];
                            }
                        }
                    }
                }
                $match->tf = $match->title * $title_boost + $match->content + $match->comment * $comment_boost + $match->link * $link_boost + $match->author + $match->excerpt + $match->taxonomy_score + $match->customfield + $match->mysqlcolumn;
                $term_hits[$match->doc][$term] = $match->title + $match->content + $match->comment + $match->tag + $match->link + $match->author + $match->category + $match->excerpt + $match->taxonomy + $match->customfield + $match->mysqlcolumn;
                $match->weight = $match->tf * $idf;
                if ($recency_bonus) {
                    $post = relevanssi_get_post($match->doc);
                    if (strtotime($post->post_date) > $recency_cutoff_date) {
                        $match->weight = $match->weight * $recency_bonus['bonus'];
                    }
                }
                $body_matches[$match->doc] = $match->content;
                $title_matches[$match->doc] = $match->title;
                $link_matches[$match->doc] = $match->link;
                $tag_matches[$match->doc] = $match->tag;
                $comment_matches[$match->doc] = $match->comment;
                isset($relevanssi_post_types[$match->doc]) ? $type = $relevanssi_post_types[$match->doc] : ($type = null);
                if (!empty($post_type_weights[$type])) {
                    $match->weight = $match->weight * $post_type_weights[$type];
                }
                $match = apply_filters('relevanssi_match', $match, $idf);
                if ($match->weight == 0) {
                    continue;
                }
                // the filters killed the match
                $post_ok = true;
                $post_ok = apply_filters('relevanssi_post_ok', $post_ok, $match->doc);
                if ($post_ok) {
                    $doc_terms[$match->doc][$term] = true;
                    // count how many terms are matched to a doc
                    isset($doc_weight[$match->doc]) ? $doc_weight[$match->doc] += $match->weight : ($doc_weight[$match->doc] = $match->weight);
                    isset($scores[$match->doc]) ? $scores[$match->doc] += $match->weight : ($scores[$match->doc] = $match->weight);
                    if (is_numeric($match->doc)) {
                        // this is to weed out taxonomies and users (t_XXX, u_XXX)
                        $include_these_posts[$match->doc] = true;
                    }
                }
            }
        }
        if (!isset($doc_weight)) {
            $no_matches = true;
        }
        if ($no_matches) {
            if ($search_again) {
                // no hits even with fuzzy search!
                $search_again = false;
            } else {
                if ("sometimes" == $fuzzy) {
                    $search_again = true;
                    $o_term_cond = "(term LIKE '%#term#' OR term LIKE '#term#%') ";
                }
            }
        } else {
            $search_again = false;
        }
    } while ($search_again);
    $strip_stops = true;
    $temp_terms_without_stops = array_keys(relevanssi_tokenize(implode(' ', $terms), $strip_stops));
    $terms_without_stops = array();
    foreach ($temp_terms_without_stops as $temp_term) {
        if (strlen($temp_term) >= $min_length) {
            array_push($terms_without_stops, $temp_term);
        }
    }
    $total_terms = count($terms_without_stops);
    if (isset($doc_weight)) {
        $doc_weight = apply_filters('relevanssi_results', $doc_weight);
    }
    if (isset($doc_weight) && count($doc_weight) > 0) {
        arsort($doc_weight);
        $i = 0;
        foreach ($doc_weight as $doc => $weight) {
            if (count($doc_terms[$doc]) < $total_terms && $operator == "AND") {
                // AND operator in action:
                // doc didn't match all terms, so it's discarded
                continue;
            }
            $hits[intval($i)] = relevanssi_get_post($doc);
            $hits[intval($i)]->relevance_score = round($weight, 2);
            $i++;
        }
    }
    if (count($hits) < 1) {
        if ($operator == "AND" and get_option('relevanssi_disable_or_fallback') != 'on') {
            $return = relevanssi_search($q, $o_tax_query, $o_relation, $o_post_query, $o_meta_query, $o_expost, $o_post_type, "OR", $o_search_blogs, $o_author);
            extract($return);
        }
    }
    global $wp;
    $default_order = get_option('relevanssi_default_orderby', 'relevance');
    if (empty($orderby)) {
        $orderby = $default_order;
    }
    // the sorting function checks for non-existing keys, cannot whitelist here
    if (empty($order)) {
        $order = 'desc';
    }
    $order = strtolower($order);
    $order_accepted_values = array('asc', 'desc');
    if (!in_array($order, $order_accepted_values)) {
        $order = 'desc';
    }
    if ($orderby != 'relevance') {
        relevanssi_object_sort($hits, $orderby, $order);
    }
    $return = array('hits' => $hits, 'body_matches' => $body_matches, 'title_matches' => $title_matches, 'tag_matches' => $tag_matches, 'comment_matches' => $comment_matches, 'scores' => $scores, 'term_hits' => $term_hits, 'query' => $q, 'link_matches' => $link_matches);
    return $return;
}
Example #2
0
function relevanssi_search($args)
{
    global $wpdb, $relevanssi_variables;
    $relevanssi_table = $relevanssi_variables['relevanssi_table'];
    $filtered_args = apply_filters('relevanssi_search_filters', $args);
    extract($filtered_args);
    $hits = array();
    $query_restrictions = "";
    if (!isset($tax_query_relation)) {
        $tax_query_relation = "or";
    }
    $tax_query_relation = strtolower($tax_query_relation);
    $term_tax_id = array();
    $term_tax_ids = array();
    $not_term_tax_ids = array();
    $and_term_tax_ids = array();
    if (is_array($tax_query)) {
        foreach ($tax_query as $row) {
            if ($row['field'] == 'slug') {
                $slug = $row['terms'];
                $numeric_slugs = array();
                $slug_in = null;
                if (is_array($slug)) {
                    $slugs = array();
                    $term_id = array();
                    foreach ($slug as $t_slug) {
                        $term = get_term_by('slug', $t_slug, $row['taxonomy']);
                        if (!$term && is_numeric($t_slug)) {
                            $numeric_slugs[] = "'{$t_slug}'";
                        } else {
                            $t_slug = sanitize_title($t_slug);
                            $term_id[] = $term->term_id;
                            $slugs[] = "'{$t_slug}'";
                        }
                    }
                    if (!empty($slugs)) {
                        $slug_in = implode(',', $slugs);
                    }
                } else {
                    $term = get_term_by('slug', $slug, $row['taxonomy']);
                    if (!$term && is_numeric($slug)) {
                        $numeric_slugs[] = $slug;
                    } else {
                        $term_id = $term->term_id;
                        $slug_in = "'{$slug}'";
                    }
                }
                if (!empty($slug_in)) {
                    $row_taxonomy = sanitize_text_field($row['taxonomy']);
                    $tt_q = "SELECT tt.term_taxonomy_id\n\t\t\t\t\t\t  \tFROM {$wpdb->term_taxonomy} AS tt\n\t\t\t\t\t\t  \tLEFT JOIN {$wpdb->terms} AS t ON (tt.term_id=t.term_id)\n\t\t\t\t\t\t  \tWHERE tt.taxonomy = '{$row_taxonomy}' AND t.slug IN ({$slug_in})";
                    // Clean: $row_taxonomy is sanitized, each slug in $slug_in is sanitized
                    $term_tax_id = $wpdb->get_col($tt_q);
                }
                if (!empty($numeric_slugs)) {
                    $row['field'] = 'id';
                }
            }
            if ($row['field'] == 'id' || $row['field'] == 'term_id') {
                $id = $row['terms'];
                $term_id = $id;
                if (is_array($id)) {
                    $numeric_values = array();
                    foreach ($id as $t_id) {
                        if (is_numeric($t_id)) {
                            $numeric_values[] = $t_id;
                        }
                    }
                    $id = implode(',', $numeric_values);
                }
                $row_taxonomy = sanitize_text_field($row['taxonomy']);
                $tt_q = "SELECT tt.term_taxonomy_id\n\t\t\t\t  \tFROM {$wpdb->term_taxonomy} AS tt\n\t\t\t\t  \tLEFT JOIN {$wpdb->terms} AS t ON (tt.term_id=t.term_id)\n\t\t\t\t  \tWHERE tt.taxonomy = '{$row_taxonomy}' AND t.term_id IN ({$id})";
                // Clean: $row_taxonomy is sanitized, $id is checked to be numeric
                $id_term_tax_id = $wpdb->get_col($tt_q);
                if (!empty($term_tax_id) && is_array($term_tax_id)) {
                    $term_tax_id = array_unique(array_merge($term_tax_id, $id_term_tax_id));
                } else {
                    $term_tax_id = $id_term_tax_id;
                }
            }
            if (!isset($row['include_children']) || $row['include_children'] == true) {
                if (!is_array($term_id)) {
                    $term_id = array($term_id);
                }
                foreach ($term_id as $t_id) {
                    $kids = get_term_children($t_id, $row['taxonomy']);
                    foreach ($kids as $kid) {
                        $term = get_term_by('id', $kid, $row['taxonomy']);
                        $term_tax_id[] = relevanssi_get_term_tax_id('id', $kid, $row['taxonomy']);
                    }
                }
            }
            $term_tax_id = array_unique($term_tax_id);
            if (!empty($term_tax_id)) {
                $n = count($term_tax_id);
                $term_tax_id = implode(',', $term_tax_id);
                $tq_operator = 'IN';
                if (isset($row['operator'])) {
                    $tq_operator = strtoupper($row['operator']);
                }
                if ($tq_operator != 'IN' && $tq_operator != 'NOT IN' && $tq_operator != 'AND') {
                    $tq_operator = 'IN';
                }
                if ($tax_query_relation == 'and') {
                    if ($tq_operator == 'AND') {
                        $query_restrictions .= " AND relevanssi.doc IN (\n\t\t\t\t\t\t\tSELECT ID FROM {$wpdb->posts} WHERE 1=1 \n\t\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\t\tSELECT COUNT(1) \n\t\t\t\t\t\t\t\tFROM {$wpdb->term_relationships} AS tr\n\t\t\t\t\t\t\t\tWHERE tr.term_taxonomy_id IN ({$term_tax_id}) \n\t\t\t\t\t\t\t\tAND tr.object_id = {$wpdb->posts}.ID ) = {$n}\n\t\t\t\t\t\t\t)";
                        // Clean: $term_tax_id and $n are Relevanssi-generated
                    } else {
                        $query_restrictions .= " AND relevanssi.doc {$tq_operator} (SELECT DISTINCT(tr.object_id) FROM {$wpdb->term_relationships} AS tr\n\t\t\t\t\t\tWHERE tr.term_taxonomy_id IN ({$term_tax_id}))";
                        // Clean: all variables are Relevanssi-generated
                    }
                } else {
                    if ($tq_operator == 'IN') {
                        $term_tax_ids[] = $term_tax_id;
                    }
                    if ($tq_operator == 'NOT IN') {
                        $not_term_tax_ids[] = $term_tax_id;
                    }
                    if ($tq_operator == 'AND') {
                        $and_term_tax_ids[] = $term_tax_id;
                    }
                }
            } else {
                global $wp_query;
                $wp_query->is_category = false;
            }
        }
        if ($tax_query_relation == 'or') {
            $term_tax_ids = array_unique($term_tax_ids);
            if (count($term_tax_ids) > 0) {
                $term_tax_ids = implode(',', $term_tax_ids);
                $query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(tr.object_id) FROM {$wpdb->term_relationships} AS tr\n\t\t\t    \tWHERE tr.term_taxonomy_id IN ({$term_tax_ids}))";
                // Clean: all variables are Relevanssi-generated
            }
            if (count($not_term_tax_ids) > 0) {
                $not_term_tax_ids = implode(',', $not_term_tax_ids);
                $query_restrictions .= " AND relevanssi.doc NOT IN (SELECT DISTINCT(tr.object_id) FROM {$wpdb->term_relationships} AS tr\n\t\t\t    \tWHERE tr.term_taxonomy_id IN ({$not_term_tax_ids}))";
                // Clean: all variables are Relevanssi-generated
            }
            if (count($and_term_tax_ids) > 0) {
                $and_term_tax_ids = implode(',', $and_term_tax_ids);
                $n = count(explode(',', $and_term_tax_ids));
                $query_restrictions .= " AND relevanssi.doc IN (\n\t\t\t\t\tSELECT ID FROM {$wpdb->posts} WHERE 1=1 \n\t\t\t\t\tAND (\n\t\t\t\t\t\tSELECT COUNT(1) \n\t\t\t\t\t\tFROM {$wpdb->term_relationships} AS tr\n\t\t\t\t\t\tWHERE tr.term_taxonomy_id IN ({$and_term_tax_ids}) \n\t\t\t\t\t\tAND tr.object_id = {$wpdb->posts}.ID ) = {$n}\n\t\t\t\t\t)";
                // Clean: all variables are Relevanssi-generated
            }
        }
    }
    if (is_array($post_query)) {
        if (!empty($post_query['in'])) {
            $valid_values = array();
            foreach ($post_query['in'] as $post_in_id) {
                if (is_numeric($post_in_id)) {
                    $valid_values[] = $post_in_id;
                }
            }
            $posts = implode(',', $valid_values);
            if (!empty($posts)) {
                $query_restrictions .= " AND relevanssi.doc IN ({$posts})";
            }
            // Clean: $posts is checked to be integers
        }
        if (!empty($post_query['not in'])) {
            $valid_values = array();
            foreach ($post_query['not in'] as $post_not_in_id) {
                if (is_numeric($post_not_in_id)) {
                    $valid_values[] = $post_not_in_id;
                }
            }
            $posts = implode(',', $valid_values);
            if (!empty($posts)) {
                $query_restrictions .= " AND relevanssi.doc NOT IN ({$posts})";
            }
            // Clean: $posts is checked to be integers
        }
    }
    if (is_array($parent_query)) {
        if (!empty($parent_query['parent in'])) {
            $valid_values = array();
            foreach ($parent_query['parent in'] as $post_in_id) {
                if (is_numeric($post_in_id)) {
                    $valid_values[] = $post_in_id;
                }
            }
            $posts = implode(',', $valid_values);
            if (!empty($posts)) {
                $query_restrictions .= " AND relevanssi.doc IN (SELECT ID FROM {$wpdb->posts} WHERE post_parent IN ({$posts}))";
            }
            // Clean: $posts is checked to be integers
        }
        if (!empty($parent_query['parent not in'])) {
            $valid_values = array();
            foreach ($parent_query['parent not in'] as $post_not_in_id) {
                if (is_numeric($post_not_in_id)) {
                    $valid_values[] = $post_not_in_id;
                }
            }
            $posts = implode(',', $valid_values);
            if (!empty($posts)) {
                $query_restrictions .= " AND relevanssi.doc NOT IN (SELECT ID FROM {$wpdb->posts} WHERE post_parent IN ({$posts}))";
            }
            // Clean: $posts is checked to be integers
        }
    }
    if (is_array($meta_query)) {
        $meta_query_restrictions = "";
        $mq_vars = array('meta_query' => $meta_query);
        $mq = new WP_Meta_Query();
        $mq->parse_query_vars($mq_vars);
        $meta_sql = $mq->get_sql('post', 'relevanssi', 'doc');
        $meta_join = "";
        $meta_where = "";
        if ($meta_sql) {
            $meta_join = $meta_sql['join'];
            $meta_where = $meta_sql['where'];
        }
        $query_restrictions .= $meta_where;
    }
    if (!empty($date_query)) {
        if (is_object($date_query) && method_exists($date_query, 'get_sql')) {
            $sql = $date_query->get_sql();
            // AND ( the query itself )
            $query_restrictions .= " AND relevanssi.doc IN ( SELECT DISTINCT(ID) FROM {$wpdb->posts} WHERE 1 {$sql} )";
            // Clean: $sql generated by $date_query->get_sql() query
        }
    }
    if (!$post_type && get_option('relevanssi_respect_exclude') == 'on') {
        if (function_exists('get_post_types')) {
            $pt_1 = get_post_types(array('exclude_from_search' => '0'));
            $pt_2 = get_post_types(array('exclude_from_search' => false));
            $post_type = implode(',', array_merge($pt_1, $pt_2));
        }
    }
    if ($post_type) {
        if ($post_type == -1) {
            $post_type = null;
        }
        // Facetious sets post_type to -1 if not selected
        if (!is_array($post_type)) {
            $post_types = esc_sql(explode(',', $post_type));
        } else {
            $post_types = esc_sql($post_type);
        }
        $post_type = count($post_types) ? "'" . implode("', '", $post_types) . "'" : 'NULL';
    }
    if ($post_status) {
        if (!is_array($post_status)) {
            $post_statuses = esc_sql(explode(',', $post_status));
        } else {
            $post_statuses = esc_sql($post_status);
        }
        $post_status = count($post_statuses) ? "'" . implode("', '", $post_statuses) . "'" : 'NULL';
    }
    //Added by OdditY:
    //Exclude Post_IDs (Pages) for non-admin search ->
    $postex = '';
    if (!empty($expost)) {
        if ($expost != "") {
            $aexpids = explode(",", $expost);
            foreach ($aexpids as $exid) {
                $exid = esc_sql(trim($exid, ' -'));
                $postex .= " AND relevanssi.doc != '{$exid}'";
                // Clean: escaped
            }
        }
    }
    // <- OdditY End
    if ($expost) {
        //added by OdditY
        $query_restrictions .= $postex;
    }
    $remove_stopwords = true;
    if (function_exists('wp_encode_emoji')) {
        $q = wp_encode_emoji($q);
    }
    $phrases = relevanssi_recognize_phrases($q);
    if (function_exists('relevanssi_recognize_negatives')) {
        $negative_terms = relevanssi_recognize_negatives($q);
    } else {
        $negative_terms = false;
    }
    if (function_exists('relevanssi_recognize_positives')) {
        $positive_terms = relevanssi_recognize_positives($q);
    } else {
        $positive_terms = false;
    }
    $terms = relevanssi_tokenize($q, $remove_stopwords);
    if (count($terms) < 1) {
        // Tokenizer killed all the search terms.
        return $hits;
    }
    $terms = array_keys($terms);
    // don't care about tf in query
    if ($negative_terms) {
        $terms = array_diff($terms, $negative_terms);
        if (count($terms) < 1) {
            return $hits;
        }
    }
    // Go get the count from the options table, but keep running the full query if it's not available
    $D = get_option('relevanssi_doc_count');
    if (!$D || $D < 1) {
        $D = $wpdb->get_var("SELECT COUNT(DISTINCT(relevanssi.doc)) FROM {$relevanssi_table} AS relevanssi");
        // Clean: no external inputs
        update_option('relevanssi_doc_count', $D);
    }
    $total_hits = 0;
    $title_matches = array();
    $tag_matches = array();
    $comment_matches = array();
    $link_matches = array();
    $body_matches = array();
    $category_matches = array();
    $taxonomy_matches = array();
    $scores = array();
    $term_hits = array();
    $fuzzy = get_option('relevanssi_fuzzy');
    if (function_exists('relevanssi_negatives_positives')) {
        $query_restrictions .= relevanssi_negatives_positives($negative_terms, $positive_terms, $relevanssi_table);
        // Clean: escaped in the function
    }
    if (!empty($author)) {
        $author_in = array();
        $author_not_in = array();
        foreach ($author as $id) {
            if (!is_numeric($id)) {
                continue;
            }
            if ($id > 0) {
                $author_in[] = $id;
            } else {
                $author_not_in[] = abs($id);
            }
        }
        if (count($author_in) > 0) {
            $authors = implode(',', $author_in);
            $query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\t    WHERE posts.post_author IN ({$authors}))";
            // Clean: $authors is always just numbers
        }
        if (count($author_not_in) > 0) {
            $authors = implode(',', $author_not_in);
            $query_restrictions .= " AND relevanssi.doc NOT IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\t    WHERE posts.post_author IN ({$authors}))";
            // Clean: $authors is always just numbers
        }
    }
    if ($post_type) {
        // the -1 is there to get user profiles and category pages
        $query_restrictions .= " AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\tWHERE posts.post_type IN ({$post_type}))) OR (doc = -1))";
        // Clean: $post_type is escaped
    }
    if ($post_status) {
        // the -1 is there to get user profiles and category pages
        $query_restrictions .= " AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\tWHERE posts.post_status IN ({$post_status}))) OR (doc = -1))";
        // Clean: $post_status is escaped
    }
    if ($phrases) {
        $query_restrictions .= " {$phrases}";
        // Clean: $phrases is escaped earlier
    }
    if (isset($_REQUEST['by_date'])) {
        $n = $_REQUEST['by_date'];
        $u = substr($n, -1, 1);
        switch ($u) {
            case 'h':
                $unit = "HOUR";
                break;
            case 'd':
                $unit = "DAY";
                break;
            case 'm':
                $unit = "MONTH";
                break;
            case 'y':
                $unit = "YEAR";
                break;
            case 'w':
                $unit = "WEEK";
                break;
            default:
                $unit = "DAY";
        }
        $n = preg_replace('/[hdmyw]/', '', $n);
        if (is_numeric($n)) {
            $query_restrictions .= " AND relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM {$wpdb->posts} AS posts\n\t\t\t\tWHERE posts.post_date > DATE_SUB(NOW(), INTERVAL {$n} {$unit}))";
            // Clean: $n is always numeric, $unit is Relevanssi-generated
        }
    }
    $query_restrictions = apply_filters('relevanssi_where', $query_restrictions);
    // Charles St-Pierre
    $query_join = "";
    if (!empty($meta_join)) {
        $query_join = $meta_join;
    }
    $query_join = apply_filters('relevanssi_join', $query_join);
    $no_matches = true;
    if ("always" == $fuzzy) {
        $o_term_cond = apply_filters('relevanssi_fuzzy_query', "(relevanssi.term LIKE '#term#%' OR relevanssi.term_reverse LIKE CONCAT(REVERSE('#term#'), '%')) ");
    } else {
        $o_term_cond = " relevanssi.term = '#term#' ";
    }
    $post_type_weights = get_option('relevanssi_post_type_weights');
    if (function_exists('relevanssi_get_recency_bonus')) {
        list($recency_bonus, $recency_cutoff_date) = relevanssi_get_recency_bonus();
    } else {
        $recency_bonus = false;
        $recency_cutoff_date = false;
    }
    $min_length = get_option('relevanssi_min_word_length');
    $search_again = false;
    $title_boost = floatval(get_option('relevanssi_title_boost'));
    $link_boost = floatval(get_option('relevanssi_link_boost'));
    $comment_boost = floatval(get_option('relevanssi_comment_boost'));
    $include_these_posts = array();
    do {
        foreach ($terms as $term) {
            $term = trim($term);
            // numeric search terms will start with a space
            if (strlen($term) < $min_length) {
                continue;
            }
            $term = esc_sql($term);
            if (strpos($o_term_cond, 'LIKE') !== false) {
                // only like_escape() if necessary, otherwise _ in search terms will not work
                if (method_exists($wpdb, 'esc_like')) {
                    $term = $wpdb->esc_like($term);
                } else {
                    // Compatibility for pre-4.0 WordPress
                    $term = like_escape($term);
                }
            }
            $term_cond = str_replace('#term#', $term, $o_term_cond);
            !empty($post_type_weights['post_tag']) ? $tag = $post_type_weights['post_tag'] : ($tag = $relevanssi_variables['post_type_weight_defaults']['post_tag']);
            !empty($post_type_weights['category']) ? $cat = $post_type_weights['category'] : ($cat = $relevanssi_variables['post_type_weight_defaults']['category']);
            $query = "SELECT relevanssi.*, relevanssi.title * {$title_boost} + relevanssi.content + relevanssi.comment * {$comment_boost} + relevanssi.tag * {$tag} + relevanssi.link * {$link_boost} + relevanssi.author + relevanssi.category * {$cat} + relevanssi.excerpt + relevanssi.taxonomy + relevanssi.customfield + relevanssi.mysqlcolumn AS tf \n\t\t\t\t\t  FROM {$relevanssi_table} AS relevanssi {$query_join} WHERE {$term_cond} {$query_restrictions}";
            // Clean: $query_restrictions is escaped, $term_cond is escaped
            $query = apply_filters('relevanssi_query_filter', $query);
            $matches = $wpdb->get_results($query);
            if (count($matches) < 1) {
                continue;
            } else {
                $no_matches = false;
                if (count($include_these_posts) > 0) {
                    $post_ids_to_add = implode(',', array_keys($include_these_posts));
                    $existing_ids = array();
                    foreach ($matches as $match) {
                        $existing_ids[] = $match->doc;
                    }
                    $existing_ids = implode(',', $existing_ids);
                    $query = "SELECT relevanssi.*, relevanssi.title * {$title_boost} + relevanssi.content + relevanssi.comment * {$comment_boost} + relevanssi.tag * {$tag} + relevanssi.link * {$link_boost} + relevanssi.author + relevanssi.category * {$cat} + relevanssi.excerpt + relevanssi.taxonomy + relevanssi.customfield + relevanssi.mysqlcolumn AS tf \n\t\t\t\t\t\t  FROM {$relevanssi_table} AS relevanssi WHERE relevanssi.doc IN ({$post_ids_to_add}) AND relevanssi.doc NOT IN ({$existing_ids}) AND {$term_cond}";
                    // Clean: no unescaped user inputs
                    $matches_to_add = $wpdb->get_results($query);
                    $matches = array_merge($matches, $matches_to_add);
                }
            }
            relevanssi_populate_array($matches);
            global $relevanssi_post_types;
            $total_hits += count($matches);
            $query = "SELECT COUNT(DISTINCT(relevanssi.doc)) FROM {$relevanssi_table} AS relevanssi {$query_join} WHERE {$term_cond} {$query_restrictions}";
            // Clean: $query_restrictions is escaped, $term_cond is escaped
            $query = apply_filters('relevanssi_df_query_filter', $query);
            $df = $wpdb->get_var($query);
            if ($df < 1 && "sometimes" == $fuzzy) {
                $query = "SELECT COUNT(DISTINCT(relevanssi.doc)) FROM {$relevanssi_table} AS relevanssi {$query_join}\n\t\t\t\t\tWHERE (relevanssi.term LIKE '{$term}%' OR relevanssi.term_reverse LIKE CONCAT(REVERSE('{$term}), %')) {$query_restrictions}";
                // Clean: $query_restrictions is escaped, $term is escaped
                $query = apply_filters('relevanssi_df_query_filter', $query);
                $df = $wpdb->get_var($query);
            }
            $idf = log($D + 1 / (1 + $df));
            $idf = $idf * $idf;
            foreach ($matches as $match) {
                if ('user' == $match->type) {
                    $match->doc = 'u_' . $match->item;
                } else {
                    if (!in_array($match->type, array('post', 'attachment'))) {
                        $match->doc = '**' . $match->type . '**' . $match->item;
                    }
                }
                if (isset($match->taxonomy_detail)) {
                    $match->taxonomy_score = 0;
                    $match->taxonomy_detail = unserialize($match->taxonomy_detail);
                    if (is_array($match->taxonomy_detail)) {
                        foreach ($match->taxonomy_detail as $tax => $count) {
                            if ($tax == 'post_tag') {
                                $match->tag = $count;
                            }
                            if (empty($post_type_weights[$tax])) {
                                $match->taxonomy_score += $count * 1;
                            } else {
                                $match->taxonomy_score += $count * $post_type_weights[$tax];
                            }
                        }
                    }
                }
                $match->tf = $match->title * $title_boost + $match->content + $match->comment * $comment_boost + $match->link * $link_boost + $match->author + $match->excerpt + $match->taxonomy_score + $match->customfield + $match->mysqlcolumn;
                $term_hits[$match->doc][$term] = $match->title + $match->content + $match->comment + $match->tag + $match->link + $match->author + $match->category + $match->excerpt + $match->taxonomy + $match->customfield + $match->mysqlcolumn;
                $match->weight = $match->tf * $idf;
                if ($recency_bonus) {
                    $post = relevanssi_get_post($match->doc);
                    if (strtotime($post->post_date) > $recency_cutoff_date) {
                        $match->weight = $match->weight * $recency_bonus['bonus'];
                    }
                }
                isset($body_matches[$match->doc]) ? $body_matches[$match->doc] += $match->content : ($body_matches[$match->doc] = $match->content);
                isset($title_matches[$match->doc]) ? $title_matches[$match->doc] += $match->title : ($title_matches[$match->doc] = $match->title);
                isset($link_matches[$match->doc]) ? $link_matches[$match->doc] += $match->link : ($link_matches[$match->doc] = $match->link);
                isset($tag_matches[$match->doc]) ? $tag_matches[$match->doc] += $match->tag : ($tag_matches[$match->doc] = $match->tag);
                isset($category_matches[$match->doc]) ? $category_matches[$match->doc] += $match->category : ($category_matches[$match->doc] = $match->category);
                isset($taxonomy_matches[$match->doc]) ? $taxonomy_matches[$match->doc] += $match->taxonomy : ($taxonomy_matches[$match->doc] = $match->taxonomy);
                isset($comment_matches[$match->doc]) ? $comment_matches[$match->doc] += $match->comment : ($comment_matches[$match->doc] = $match->comment);
                isset($relevanssi_post_types[$match->doc]) ? $type = $relevanssi_post_types[$match->doc] : ($type = null);
                if (!empty($post_type_weights[$type])) {
                    $match->weight = $match->weight * $post_type_weights[$type];
                }
                $match = apply_filters('relevanssi_match', $match, $idf);
                if ($match->weight == 0) {
                    continue;
                }
                // the filters killed the match
                $post_ok = true;
                $post_ok = apply_filters('relevanssi_post_ok', $post_ok, $match->doc);
                if ($post_ok) {
                    $doc_terms[$match->doc][$term] = true;
                    // count how many terms are matched to a doc
                    isset($doc_weight[$match->doc]) ? $doc_weight[$match->doc] += $match->weight : ($doc_weight[$match->doc] = $match->weight);
                    isset($scores[$match->doc]) ? $scores[$match->doc] += $match->weight : ($scores[$match->doc] = $match->weight);
                    if (is_numeric($match->doc)) {
                        // this is to weed out taxonomies and users (t_XXX, u_XXX)
                        $include_these_posts[$match->doc] = true;
                    }
                }
            }
        }
        if (!isset($doc_weight)) {
            $no_matches = true;
        }
        if ($no_matches) {
            if ($search_again) {
                // no hits even with fuzzy search!
                $search_again = false;
            } else {
                if ("sometimes" == $fuzzy) {
                    $search_again = true;
                    $o_term_cond = "(term LIKE '%#term#' OR term LIKE '#term#%') ";
                }
            }
        } else {
            $search_again = false;
        }
    } while ($search_again);
    $strip_stops = true;
    $temp_terms_without_stops = array_keys(relevanssi_tokenize(implode(' ', $terms), $strip_stops));
    $terms_without_stops = array();
    foreach ($temp_terms_without_stops as $temp_term) {
        if (strlen($temp_term) >= $min_length) {
            array_push($terms_without_stops, $temp_term);
        }
    }
    $total_terms = count($terms_without_stops);
    if (isset($doc_weight)) {
        $doc_weight = apply_filters('relevanssi_results', $doc_weight);
    }
    if (isset($doc_weight) && count($doc_weight) > 0) {
        arsort($doc_weight);
        $i = 0;
        foreach ($doc_weight as $doc => $weight) {
            if (count($doc_terms[$doc]) < $total_terms && $operator == "AND") {
                // AND operator in action:
                // doc didn't match all terms, so it's discarded
                continue;
            }
            if (!empty($fields)) {
                if ($fields == 'ids') {
                    $hits[intval($i)] = $doc;
                }
                if ($fields == 'id=>parent') {
                    $object = new StdClass();
                    $object->ID = $doc;
                    $object->post_parent = wp_get_post_parent_id($doc);
                    $hits[intval($i)] = $object;
                }
            } else {
                $hits[intval($i)] = relevanssi_get_post($doc);
                $hits[intval($i)]->relevance_score = round($weight, 2);
            }
            $i++;
        }
    }
    if (count($hits) < 1) {
        if ($operator == "AND" and get_option('relevanssi_disable_or_fallback') != 'on') {
            $or_args = $args;
            $or_args['operator'] = "OR";
            $or_args['q'] = relevanssi_add_synonyms($q);
            $return = relevanssi_search($or_args);
            extract($return);
        }
    }
    global $wp;
    $default_order = get_option('relevanssi_default_orderby', 'relevance');
    if (empty($orderby)) {
        $orderby = $default_order;
    }
    // the sorting function checks for non-existing keys, cannot whitelist here
    if (empty($order)) {
        $order = 'desc';
    }
    $order = strtolower($order);
    $order_accepted_values = array('asc', 'desc');
    if (!in_array($order, $order_accepted_values)) {
        $order = 'desc';
    }
    $orderby = apply_filters('relevanssi_orderby', $orderby);
    $order = apply_filters('relevanssi_order', $order);
    if ($orderby != 'relevance') {
        relevanssi_object_sort($hits, $orderby, $order);
    }
    $return = array('hits' => $hits, 'body_matches' => $body_matches, 'title_matches' => $title_matches, 'tag_matches' => $tag_matches, 'category_matches' => $category_matches, 'taxonomy_matches' => $taxonomy_matches, 'comment_matches' => $comment_matches, 'scores' => $scores, 'term_hits' => $term_hits, 'query' => $q, 'link_matches' => $link_matches);
    return $return;
}