1

We are heavily marking up our pages/posts so there is a lot of html and pictures being used. The problem is that our search results are hitting image names and class names (maybe I have a few other examples but these are the two worst offenders).

Anyway to only search on the text showing on the page?

2 Answers 2

0

One possibility would be to try and alter the search SQL query. There's a filter for that.

$search = apply_filters_ref_array( 'posts_search', array( $search, &$this ) );

and (sidenote) a filter to influence the ORDER BY clause as well

$search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );

I haven't taken a look at search for quite some time, but when I look at WP_Query::parse_search, I could find something that might be of interest and worth giving a try.

  1. Look at

    protected function parse_search( &$q ) {
    

    which has the full stack of Query variables in it, so everything added actually lands inside that function. And in there is the following line:

    $n = ! empty( $q['exact'] ) ? '' : '%';
    

    If $q['exact'] is emtpy, then $n will be empty as well. This is what happens next:

    if ( $n )
        $q['search_orderby_title'][] = "$wpdb->posts.post_title LIKE '%$term%'";
    

    and

    $search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";
    

    So if you have a query var(?) named exact which needs to be TRUE, you should be able to just run exact matches instead of the default LIKE clause followed by every match that is in the middle of anything.

  2. And as it's protected, it may get overridden by an extending class. So you could just go and create class My_Search_Query extends WP_Query and define your own internals to generate the needed SQL statement.

0

Wordpress uses a simple MySQL LIKE search for the Core search feature. You can see that by running a simple test case like this:

$q = new WP_Query(array('s' => 'test'));
var_dump($q->request);
die;

You should see something like (Formatted courtesy of http://sqlformat.org/):

SELECT SQL_CALC_FOUND_ROWS dev_posts.ID
FROM dev_posts
WHERE 1=1
  AND (((dev_posts.post_title LIKE '%test%')
        OR (dev_posts.post_content LIKE '%test%')))
  AND (dev_posts.post_password = '')
  AND dev_posts.post_type IN ('post',
                              'page',
                              'attachment',
                              'book')
  AND (dev_posts.post_status = 'publish')
ORDER BY dev_posts.post_title LIKE '%test%' DESC, dev_posts.post_date DESC LIMIT 0,10

You could filter the WHERE clause with the posts_search filter but MySQL's REGEX is very limited. I doubt you will be able to get it to ignore markup.

If I were facing this problem, I would parse the post on save-- save_post or draft_to_publish for example-- and store a keyword list to the database, then use the posts_search filter, and/or other filters, to alter the search so that it searches the keyword list. Implementation can be more or less complicated depending on how you do it, but I think that is about the only way you are going to get the results you want without having to depend on MySQL extensions or external search engines like Sphinx.

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.