3

I need to display entries by searching a custom field like so:

{exp:channel:entries channel="my_channel" search:my_field="#{segment_2}\W" limit="20"}

Note the # sign. I'm specifically searching for hashtags.

If I leave off the \W it works just fine. But it does not always return the exact words – (eg. #cat also returns #catnap) – exactly as you'd expect.

So I really need that whole word feature to work.

I believe I've traced the breaking point down to the code below (approx. line 1145-1155 in mod.channel.php):

elseif (strpos($term, '\W') !== FALSE) // full word only, no partial matches
    {
    // Note: MySQL's nutty POSIX regex word boundary is [[:>:]]
    $term = '([[:<:]]|^)'.preg_quote(str_replace('\W', '', $term)).'([[:>:]]|$)';

    $fields_sql .= ' (wd.site_id=' . $site_id 
    . ' AND wd.field_id_' . $this->cfields[$site_id][$field_name] . ' ' . $not 
    . ' REGEXP "' . $this->EE->db->escape_str($term).'") '
    . $andor;
}

Someone correct me if I'm wrong, but I think that REGEXP escape_str($term) bit is breaking it.

So I'm looking for a workaround. It would be best not to hack the code directly (of course), but this is the only time that function is being used on the site... So I'm not totally opposed to hacking a fix right there.

Any ideas?

1
  • two comments. (1) check output profiler for the query. Test it in phpmyadmin or sequelpro to refine etc. and check if your data might be escaped maybe. (2) if you want to change part of core, a cleaner way (albeit with a bit of overhead) is to add only a hook yourself. After updating EE, you only have to add the hook again, no difficult re-insert code/hacks. (see: ellislab.com/forums/viewthread/232776/#1047806 )
    – GDmac
    Mar 22, 2013 at 8:50

2 Answers 2

2

The problem stems from the opening pattern in the regex, ([[:<:]]|^). That will return a match for either the start of a string or a word boundary. Here's the definition of a word boundary:

[:<:] These markers stand for word boundaries. They match the beginning and end of words, respectively. A word is a sequence of word characters that is not preceded by or followed by word characters. A word character is an alphanumeric character in the alnum class or an underscore (_).

As such searches will only perform reliably if your search terms begins with an alphanumeric character or an underscore. You can change this behaviour by switching the opening pattern to a specific character class. For example, instead of searching for strings starting with a word boundary you could search for strings preceded by a [:space:]. Here's the definition of a space:

Space, tab, newline, and carriage return

To make this change replace this line of code:

$term = '([[:<:]]|^)'.preg_quote(str_replace('\W', '', $term)).'([[:>:]]|$)';

With this:

$term = '([[:space:]]|^)'.preg_quote(str_replace('\W', '', $term)).'([[:>:]]|$)';

For your usage that should work nicely, but it wouldn't necessarily be a better default behaviour. Unfortunately there's no hook for rewriting channel entry queries, so this would need to be a core hack.

2
  • Awesome. Awesome. Awesome. So simple, and it works perfectly for my scenario. I appreciate that you took the time to explain the WHYs and HOWs of it all. While some might argue that this doesn't adhere to "Best Practices" I'm completely satisfied with the simplicity. It will be super easy to migrate this change/edit into future EE updates as necessary. Thank you.
    – JJ.
    Mar 22, 2013 at 18:15
  • No worries, I'm glad to hear it's working nicely.
    – Dom Stubbs
    Mar 24, 2013 at 16:32
2

If you want to search for whole words only, (exact matching) you can use
search:my_field="=#{segment_2}" (note the extra = inside the quotes)

http://ellislab.com/expressionengine/user-guide/modules/channel/channel_entries.html#search-field-name

3
  • This would only work if there is a single hash tag in the field, not if there are multiple.
    – Low
    Mar 22, 2013 at 8:43
  • would searching with the extra space be an option.
    – GDmac
    Mar 22, 2013 at 8:54
  • Indeed. Generally there are multiple tags, so this method doesn't work. But kudos for the idea, because it was the second thing I tried while attempting to troubleshoot this.
    – JJ.
    Mar 22, 2013 at 17:55

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.