Relevanssi – A Better Search - Version 3.5

Version Description

  • Tokenizer was using strlen() and not mb_strlen(), so word lengths were not calculated properly. If your site uses non-ASCII alphabet, rebuilding the index is a good idea.
  • Small improvement to WPML multilanguage filtering.
  • relevanssi_the_title() got a new parameter: if you don't want to echo the title, you can use it like relevanssi_the_title(false) to make it return the title.
  • Relevanssi had the_title filter hook calls that were missing the second parameter; that's now fixed.
  • The excerpt-building algorithm is completely rewritten based on work by Ben Boyter (http://www.boyter.org/).
  • The [watupro] shortcode didn't work with Relevanssi, so Relevanssi will now bypass it.
  • The plugin i18n features have been improved slightly.
  • New filter: relevanssi_didyoumean_suggestion lets you modify the Did you mean? suggestion before it's displayed.
  • relevanssi_didyoumean() has a new parameter: you can now choose whether the result is echoed out (the default value) or just returned.
  • In the search results breakdown, you can now use %categories% and %taxonomies% to show the number of matches in categories and taxonomies other than tags and cats, respectively.
  • Relevanssi supports fields parameter (both ids and id=>parent) to return only post IDs or post IDs and post parents.
Download this release

Release Info

Developer msaari
Plugin Icon 128x128 Relevanssi – A Better Search
Version 3.5
Comparing to
See all releases

Code changes from version 3.4.2 to 3.5

lib/common.php CHANGED
@@ -15,7 +15,7 @@ function relevanssi_wpml_filter($data) {
15
 
16
  if (function_exists('icl_object_id') && !function_exists('pll_is_translated_post_type')) {
17
  if ($sitepress->is_translated_post_type($hit->post_type)) {
18
- if ($hit->ID == icl_object_id($hit->ID, $hit->post_type, false, ICL_LANGUAGE_CODE)) $filtered_hits[] = $hit;
19
  }
20
  else {
21
  $filtered_hits[] = $hit;
@@ -355,7 +355,7 @@ function relevanssi_strip_invisibles($text) {
355
  }
356
 
357
  function relevanssi_strlen_sort($a, $b) {
358
- return strlen($b) - strlen($a);
359
  }
360
 
361
  function relevanssi_get_custom_fields() {
@@ -387,7 +387,12 @@ function relevanssi_mb_trim($string) {
387
  }
388
 
389
  function relevanssi_remove_punct($a) {
390
- $a = strip_tags($a);
 
 
 
 
 
391
  $a = stripslashes($a);
392
 
393
  $a = str_replace('ß', 'ss', $a);
@@ -493,7 +498,8 @@ function relevanssi_tokenize($str, $remove_stops = true, $min_word_length = -1)
493
  while ($t !== false) {
494
  $t = strval($t);
495
  $accept = true;
496
- if (strlen($t) < $min_word_length) {
 
497
  $t = strtok("\n\t ");
498
  continue;
499
  }
@@ -638,13 +644,9 @@ function relevanssi_add_synonyms($q) {
638
  /* Helper function that does mb_stripos, falls back to mb_strpos and mb_strtoupper
639
  * if that cannot be found, and falls back to just strpos if even that is not possible.
640
  */
641
- function relevanssi_stripos($content, $term, $offset) {
642
- if (function_exists('mb_strlen')) {
643
- if ($offset > mb_strlen($content)) return false;
644
- }
645
- else {
646
- if ($offset > strlen($content)) return false;
647
- }
648
  if (function_exists('mb_stripos')) {
649
  $pos = ("" == $content) ? false : mb_stripos($content, $term, $offset);
650
  }
@@ -682,16 +684,17 @@ function relevanssi_close_tags($html) {
682
 
683
  /* Prints out post title with highlighting.
684
  */
685
- function relevanssi_the_title() {
686
  global $post;
687
  if (empty($post->post_highlighted_title)) $post->post_highlighted_title = $post->post_title;
688
- echo $post->post_highlighted_title;
 
689
  }
690
 
691
  /* Returns the post title with highlighting.
692
  */
693
  function relevanssi_get_the_title($post_id) {
694
- $post = get_post($post_id);
695
  if (empty($post->post_highlighted_title)) $post->post_highlighted_title = $post->post_title;
696
  return $post->post_highlighted_title;
697
  }
@@ -704,4 +707,12 @@ function relevanssi_update_doc_count( $values, $post ) {
704
  }
705
  return $values;
706
  }
 
 
 
 
 
 
 
 
707
  ?>
15
 
16
  if (function_exists('icl_object_id') && !function_exists('pll_is_translated_post_type')) {
17
  if ($sitepress->is_translated_post_type($hit->post_type)) {
18
+ if ($hit->ID == icl_object_id($hit->ID, $hit->post_type, false, $sitepress->get_current_language())) $filtered_hits[] = $hit;
19
  }
20
  else {
21
  $filtered_hits[] = $hit;
355
  }
356
 
357
  function relevanssi_strlen_sort($a, $b) {
358
+ return relevanssi_strlen($b) - relevanssi_strlen($a);
359
  }
360
 
361
  function relevanssi_get_custom_fields() {
387
  }
388
 
389
  function relevanssi_remove_punct($a) {
390
+ $a = preg_replace ('/<[^>]*>/', ' ', $a);
391
+
392
+ $a = str_replace("\r", '', $a); // --- replace with empty space
393
+ $a = str_replace("\n", ' ', $a); // --- replace with space
394
+ $a = str_replace("\t", ' ', $a); // --- replace with space
395
+
396
  $a = stripslashes($a);
397
 
398
  $a = str_replace('ß', 'ss', $a);
498
  while ($t !== false) {
499
  $t = strval($t);
500
  $accept = true;
501
+
502
+ if (relevanssi_strlen($t) < $min_word_length) {
503
  $t = strtok("\n\t ");
504
  continue;
505
  }
644
  /* Helper function that does mb_stripos, falls back to mb_strpos and mb_strtoupper
645
  * if that cannot be found, and falls back to just strpos if even that is not possible.
646
  */
647
+ function relevanssi_stripos($content, $term, $offset = 0) {
648
+ if ($offset > relevanssi_strlen($content)) return false;
649
+
 
 
 
 
650
  if (function_exists('mb_stripos')) {
651
  $pos = ("" == $content) ? false : mb_stripos($content, $term, $offset);
652
  }
684
 
685
  /* Prints out post title with highlighting.
686
  */
687
+ function relevanssi_the_title($echo = true) {
688
  global $post;
689
  if (empty($post->post_highlighted_title)) $post->post_highlighted_title = $post->post_title;
690
+ if ($echo) echo $post->post_highlighted_title;
691
+ return $post->post_highlighted_title;
692
  }
693
 
694
  /* Returns the post title with highlighting.
695
  */
696
  function relevanssi_get_the_title($post_id) {
697
+ $post = relevanssi_get_post($post_id);
698
  if (empty($post->post_highlighted_title)) $post->post_highlighted_title = $post->post_title;
699
  return $post->post_highlighted_title;
700
  }
707
  }
708
  return $values;
709
  }
710
+
711
+ /* Uses mb_strlen() if available, otherwise falls back to strlen().
712
+ */
713
+ function relevanssi_strlen($s) {
714
+ if ( function_exists( 'mb_strlen' ) ) return mb_strlen( $s );
715
+ return strlen( $s );
716
+ }
717
+
718
  ?>
lib/excerpts-highlights.php CHANGED
@@ -18,7 +18,7 @@ function relevanssi_do_excerpt($t_post, $query) {
18
  if ($post != NULL) $old_global_post = $post;
19
  $post = $t_post;
20
 
21
- $remove_stopwords = false;
22
  $terms = relevanssi_tokenize($query, $remove_stopwords, -1);
23
 
24
  // These shortcodes cause problems with Relevanssi excerpts
@@ -60,7 +60,7 @@ function relevanssi_do_excerpt($t_post, $query) {
60
  }
61
  }
62
  }
63
-
64
  $start = $excerpt_data[2];
65
 
66
  $excerpt = $excerpt_data[0];
@@ -113,7 +113,7 @@ function relevanssi_create_excerpt($content, $terms, $query) {
113
  $best_excerpt_term_hits = -1;
114
  $excerpt = "";
115
 
116
- $content = preg_replace('/\s+/', ' ', $content);
117
  $content = " $content";
118
 
119
  $phrases = relevanssi_extract_phrases(stripslashes($query));
@@ -131,89 +131,13 @@ function relevanssi_create_excerpt($content, $terms, $query) {
131
  $terms[$phrase] = 1;
132
  }
133
 
 
134
  uksort($terms, 'relevanssi_strlen_sort');
135
 
136
  $start = false;
137
  if ("chars" == $type) {
138
- $term_positions = array();
139
- foreach (array_keys($terms) as $term) {
140
- $term = trim($term);
141
- $term_key = $term;
142
- get_option('relevanssi_fuzzy') != 'none' ? $term = "$term" : $term = " $term";
143
-
144
- $pos = 0;
145
- $n = 0;
146
- while (false !== $pos) {
147
- $pos = relevanssi_stripos($content, $term, $pos);
148
- if (false !== $pos) {
149
- $term_positions[$pos] = $term_key;
150
- function_exists('mb_strlen') ? $pos = $pos + mb_strlen($term) : $pos = $pos + strlen(utf8_decode($term));
151
- }
152
- }
153
- }
154
- ksort($term_positions);
155
- $positions = array_keys($term_positions);
156
- $best_position = 0;
157
- $best_position_hits = 0;
158
- $quarter = floor($excerpt_length/4); // adjustment, so the excerpt doesn't start with the search term
159
- for ($i = 0; $i < count($positions); $i++) {
160
- $key = $positions[$i];
161
- $orig_key = $key;
162
- $key = $key - $quarter;
163
- if ($key < 0) $key = 0;
164
-
165
- $j = $i + 1;
166
-
167
- $this_excerpt_terms = array();
168
-
169
- if (isset($term_positions[$orig_key])) $this_excerpt_terms[$term_positions[$orig_key]] = true;
170
-
171
- while (isset($positions[$j])) {
172
- if (isset($positions[$j])) {
173
- $next_key = $positions[$j];
174
- }
175
-
176
- if ($key + $excerpt_length > $next_key) {
177
- $this_excerpt_terms[$term_positions[$next_key]] = true;
178
- }
179
- else {
180
- break; // farther than the excerpt length
181
- }
182
- $j++;
183
- }
184
-
185
- if (count($this_excerpt_terms) > $best_position_hits) {
186
- $best_position_hits = count($this_excerpt_terms);
187
- $best_position = $key;
188
- }
189
- }
190
-
191
- if ($best_position + $excerpt_length < strlen($content)) {
192
- if (function_exists('mb_substr'))
193
- $excerpt = mb_substr($content, $best_position, $excerpt_length);
194
- else
195
- $excerpt = substr($content, $best_position, $excerpt_length);
196
- }
197
- else {
198
- $fixed_position = strlen($content) - $excerpt_length;
199
- if ($fixed_position > 0) {
200
- if (function_exists('mb_substr'))
201
- $excerpt = mb_substr($content, $fixed_position, $excerpt_length);
202
- else
203
- $excerpt = substr($content, $fixed_position, $excerpt_length);
204
- }
205
- }
206
-
207
- if ($best_position == 0) $start = true;
208
-
209
-
210
- if ("" == $excerpt) {
211
- if (function_exists('mb_substr'))
212
- $excerpt = mb_substr($content, 0, $excerpt_length);
213
- else
214
- $excerpt = substr($content, 0, $excerpt_length);
215
- $start = true;
216
- }
217
  }
218
  else {
219
  $words = explode(' ', $content);
@@ -230,51 +154,11 @@ function relevanssi_create_excerpt($content, $terms, $query) {
230
 
231
  $excerpt_slice = " $excerpt_slice";
232
  $term_hits = 0;
233
- foreach (array_keys($terms) as $term) {
234
- $term = " $term";
235
- if (function_exists('mb_stripos')) {
236
- $pos = ("" == $excerpt_slice) ? false : mb_stripos($excerpt_slice, $term);
237
- // To avoid "empty haystack" warnings
238
- }
239
- else if (function_exists('mb_strpos')) {
240
- $pos = mb_strpos($excerpt_slice, $term);
241
- if (false === $pos) {
242
- if (function_exists('mb_strtoupper') && function_exists('mb_strpos') && function_exists('mb_substr')) {
243
- $titlecased = mb_strtoupper(mb_substr($term, 0, 1)) . mb_substr($term, 1);
244
- $pos = mb_strpos($excerpt_slice, $titlecased);
245
- if (false === $pos) {
246
- $pos = mb_strpos($excerpt_slice, mb_strtoupper($term));
247
- }
248
- }
249
- else {
250
- $titlecased = strtoupper(substr($term, 0, 1)) . substr($term, 1);
251
- $pos = strpos($excerpt_slice, $titlecased);
252
- if (false === $pos) {
253
- $pos = strpos($excerpt_slice, strtoupper($term));
254
- }
255
- }
256
- }
257
- }
258
- else {
259
- $pos = strpos($excerpt_slice, $term);
260
- if (false === $pos) {
261
- $titlecased = strtoupper(substr($term, 0, 1)) . substr($term, 1);
262
- $pos = strpos($excerpt_slice, $titlecased);
263
- if (false === $pos) {
264
- $pos = strpos($excerpt_slice, strtoupper($term));
265
- }
266
- }
267
- }
268
 
269
- if (false !== $pos) {
270
- $term_hits++;
271
- if (0 == $i) $start = true;
272
-
273
- if ($term_hits > $best_excerpt_term_hits) {
274
- $best_excerpt_term_hits = $term_hits;
275
- $excerpt = $excerpt_slice;
276
- }
277
- }
278
  }
279
 
280
  $i += $excerpt_length;
@@ -374,7 +258,8 @@ function relevanssi_highlight_terms($excerpt, $query) {
374
 
375
  if ( function_exists('mb_internal_encoding') )
376
  mb_internal_encoding("UTF-8");
377
-
 
378
  $terms = array_keys(relevanssi_tokenize($query, $remove_stopwords = true, $min_word_length = -1));
379
 
380
  if (is_array($query)) $query = implode(' ', $query); // just in case
@@ -403,7 +288,9 @@ function relevanssi_highlight_terms($excerpt, $query) {
403
  $excerpt = html_entity_decode($excerpt);
404
 
405
  if ($word_boundaries) {
406
- get_option('relevanssi_fuzzy') != 'none' ? $regex = "/($pr_term)(?!(^&+)?(;))/iu" : $regex = "/(\b$pr_term|$pr_term\b)(?!(^&+)?(;))/iu";
 
 
407
  $excerpt = preg_replace($regex, $start_emp_token . '\\1' . $end_emp_token, $excerpt);
408
  if (empty($excerpt)) $excerpt = preg_replace($regex, $start_emp_token . '\\1' . $end_emp_token, $undecoded_excerpt);
409
  }
@@ -493,4 +380,118 @@ function relevanssi_remove_nested_highlights($s, $a, $b) {
493
  return $whole;
494
  }
495
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
  ?>
18
  if ($post != NULL) $old_global_post = $post;
19
  $post = $t_post;
20
 
21
+ $remove_stopwords = true;
22
  $terms = relevanssi_tokenize($query, $remove_stopwords, -1);
23
 
24
  // These shortcodes cause problems with Relevanssi excerpts
60
  }
61
  }
62
  }
63
+
64
  $start = $excerpt_data[2];
65
 
66
  $excerpt = $excerpt_data[0];
113
  $best_excerpt_term_hits = -1;
114
  $excerpt = "";
115
 
116
+ $content = preg_replace('/\s+/u', ' ', $content);
117
  $content = " $content";
118
 
119
  $phrases = relevanssi_extract_phrases(stripslashes($query));
131
  $terms[$phrase] = 1;
132
  }
133
 
134
+ // longest search terms first, because those are generally more significant
135
  uksort($terms, 'relevanssi_strlen_sort');
136
 
137
  $start = false;
138
  if ("chars" == $type) {
139
+ $prev_count = floor($excerpt_length / 2);
140
+ list($excerpt, $best_excerpt_term_hits, $start) = relevanssi_extract_relevant(array_keys($terms), $content, $excerpt_length, $prev_count);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
142
  else {
143
  $words = explode(' ', $content);
154
 
155
  $excerpt_slice = " $excerpt_slice";
156
  $term_hits = 0;
157
+ $count = relevanssi_count_matches(array_keys($terms), $excerpt_slice);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
+ if ($count > 0 && $count > $best_excerpt_term_hits) {
160
+ $best_excerpt_term_hits = $count;
161
+ $excerpt = $excerpt_slice;
 
 
 
 
 
 
162
  }
163
 
164
  $i += $excerpt_length;
258
 
259
  if ( function_exists('mb_internal_encoding') )
260
  mb_internal_encoding("UTF-8");
261
+
262
+ do_action('relevanssi_highlight_tokenize');
263
  $terms = array_keys(relevanssi_tokenize($query, $remove_stopwords = true, $min_word_length = -1));
264
 
265
  if (is_array($query)) $query = implode(' ', $query); // just in case
288
  $excerpt = html_entity_decode($excerpt);
289
 
290
  if ($word_boundaries) {
291
+ // get_option('relevanssi_fuzzy') != 'none' ? $regex = "/($pr_term)(?!(^&+)?(;))/iu" : $regex = "/(\b$pr_term|$pr_term\b)(?!(^&+)?(;))/iu";
292
+ get_option('relevanssi_fuzzy') != 'none' ? $regex = "/(\b$pr_term|$pr_term\b)(?!(^&+)?(;))/iu" : $regex = "/(\b$pr_term\b)(?!(^&+)?(;))/iu";
293
+
294
  $excerpt = preg_replace($regex, $start_emp_token . '\\1' . $end_emp_token, $excerpt);
295
  if (empty($excerpt)) $excerpt = preg_replace($regex, $start_emp_token . '\\1' . $end_emp_token, $undecoded_excerpt);
296
  }
380
  return $whole;
381
  }
382
 
383
+ /******
384
+ * This code originally written by Ben Boyter
385
+ * http://www.boyter.org/2013/04/building-a-search-result-extract-generator-in-php/
386
+ */
387
+
388
+ // find the locations of each of the words
389
+ // Nothing exciting here. The array_unique is required
390
+ // unless you decide to make the words unique before passing in
391
+ function relevanssi_extract_locations($words, $fulltext) {
392
+ $locations = array();
393
+ foreach($words as $word) {
394
+ $wordlen = relevanssi_strlen($word);
395
+ $loc = relevanssi_stripos($fulltext, $word);
396
+ while($loc !== FALSE) {
397
+ $locations[] = $loc;
398
+ $loc = relevanssi_stripos($fulltext, $word, $loc + $wordlen);
399
+ }
400
+ }
401
+ $locations = array_unique($locations);
402
+ sort($locations);
403
+
404
+ return $locations;
405
+ }
406
+
407
+ function relevanssi_count_matches($words, $fulltext) {
408
+ $count = 0;
409
+ foreach( $words as $word ) {
410
+ if (get_option('relevanssi_fuzzy') == 'never') {
411
+ $pattern = '/([\s,\.:;]'.$word.'[\s,\.:;])/i';
412
+ if (preg_match($pattern, $fulltext, $matches, PREG_OFFSET_CAPTURE)) {
413
+ $count += count($matches) - 1;
414
+ }
415
+ }
416
+ else {
417
+ $pattern = '/([\s,\.:;]'.$word.')/i';
418
+ if (preg_match($pattern, $fulltext, $matches, PREG_OFFSET_CAPTURE)) {
419
+ $count += count($matches) - 1;
420
+ }
421
+ $pattern = '/('.$word.'[\s,\.:;])/i';
422
+ if (preg_match($pattern, $fulltext, $matches, PREG_OFFSET_CAPTURE)) {
423
+ $count += count($matches) - 1;
424
+ }
425
+ }
426
+ }
427
+
428
+ return $count;
429
+ }
430
+
431
+ // Work out which is the most relevant portion to display
432
+ // This is done by looping over each match and finding the smallest distance between two found
433
+ // strings. The idea being that the closer the terms are the better match the snippet would be.
434
+ // When checking for matches we only change the location if there is a better match.
435
+ // The only exception is where we have only two matches in which case we just take the
436
+ // first as will be equally distant.
437
+ function relevanssi_determine_snip_location($locations, $prevcount) {
438
+ // If we only have 1 match we dont actually do the for loop so set to the first
439
+ $startpos = $locations[0];
440
+ $loccount = count($locations);
441
+ $smallestdiff = PHP_INT_MAX;
442
+
443
+ // If we only have 2 skip as its probably equally relevant
444
+ if(count($locations) > 2) {
445
+ // skip the first as we check 1 behind
446
+ for($i=1; $i < $loccount; $i++) {
447
+ if($i == $loccount-1) { // at the end
448
+ $diff = $locations[$i] - $locations[$i-1];
449
+ }
450
+ else {
451
+ $diff = $locations[$i+1] - $locations[$i];
452
+ }
453
+
454
+ if($smallestdiff > $diff) {
455
+ $smallestdiff = $diff;
456
+ $startpos = $locations[$i];
457
+ }
458
+ }
459
+ }
460
+
461
+ $startpos = $startpos > $prevcount ? $startpos - $prevcount : 0;
462
+ return $startpos;
463
+ }
464
+
465
+ // 1/6 ratio on prevcount tends to work pretty well and puts the terms
466
+ // in the middle of the extract
467
+ function relevanssi_extract_relevant($words, $fulltext, $rellength=300, $prevcount=50) {
468
+
469
+ $textlength = mb_strlen($fulltext);
470
+ if($textlength <= $rellength) {
471
+ return $fulltext;
472
+ }
473
+
474
+ $locations = relevanssi_extract_locations($words, $fulltext);
475
+ $startpos = relevanssi_determine_snip_location($locations,$prevcount);
476
+
477
+ // if we are going to snip too much...
478
+ if($textlength-$startpos < $rellength) {
479
+ $startpos = $startpos - ($textlength-$startpos)/2;
480
+ }
481
+
482
+ $reltext = mb_substr($fulltext, $startpos, $rellength);
483
+
484
+ // check to ensure we dont snip the last word if thats the match
485
+ if( $startpos + $rellength < $textlength) {
486
+ $reltext = mb_substr($reltext, 0, mb_strrpos($reltext, " ")); // remove last word
487
+ }
488
+
489
+ $start = false;
490
+ if($startpos == 0) $start = true;
491
+
492
+ $besthits = count(relevanssi_extract_locations($words, $reltext));
493
+
494
+ return array($reltext, $besthits, $start);
495
+ }
496
+
497
  ?>
lib/indexing.php CHANGED
@@ -313,7 +313,7 @@ function relevanssi_index_doc($indexpost, $remove_first = false, $custom_fields
313
  $index_titles = true;
314
  if (apply_filters('relevanssi_index_titles', $index_titles)) {
315
  $filtered_title = apply_filters('relevanssi_post_title_before_tokenize', $post->post_title, $post);
316
- $titles = relevanssi_tokenize(apply_filters('the_title', $filtered_title));
317
 
318
  if (count($titles) > 0) {
319
  foreach ($titles as $title => $count) {
@@ -361,6 +361,7 @@ function relevanssi_index_doc($indexpost, $remove_first = false, $custom_fields
361
  remove_shortcode('product_categories'); // A problematic WooCommerce shortcode
362
  remove_shortcode('recent_products'); // A problematic WooCommerce shortcode
363
  remove_shortcode('php'); // PHP Code for Posts
 
364
 
365
  $post_before_shortcode = $post;
366
  $contents = do_shortcode($contents);
@@ -530,6 +531,7 @@ function relevanssi_update_child_posts($new_status, $old_status, $post) {
530
  || (in_array($post->post_type, array('attachment', 'revision')))) {
531
  return;
532
  }
 
533
  $q = "SELECT * FROM $wpdb->posts WHERE post_parent=$post->ID AND post_type!='revision'";
534
  $child_posts = $wpdb->get_results($q);
535
  if ($child_posts) {
313
  $index_titles = true;
314
  if (apply_filters('relevanssi_index_titles', $index_titles)) {
315
  $filtered_title = apply_filters('relevanssi_post_title_before_tokenize', $post->post_title, $post);
316
+ $titles = relevanssi_tokenize(apply_filters('the_title', $filtered_title, $post->ID));
317
 
318
  if (count($titles) > 0) {
319
  foreach ($titles as $title => $count) {
361
  remove_shortcode('product_categories'); // A problematic WooCommerce shortcode
362
  remove_shortcode('recent_products'); // A problematic WooCommerce shortcode
363
  remove_shortcode('php'); // PHP Code for Posts
364
+ remove_shortcode('watupro'); // Watu PRO doesn't co-operate
365
 
366
  $post_before_shortcode = $post;
367
  $contents = do_shortcode($contents);
531
  || (in_array($post->post_type, array('attachment', 'revision')))) {
532
  return;
533
  }
534
+
535
  $q = "SELECT * FROM $wpdb->posts WHERE post_parent=$post->ID AND post_type!='revision'";
536
  $child_posts = $wpdb->get_results($q);
537
  if ($child_posts) {
lib/init.php CHANGED
@@ -38,7 +38,7 @@ function relevanssi_init() {
38
  function relevanssi_warning() {
39
  RELEVANSSI_PREMIUM ? $plugin = 'relevanssi-premium' : $plugin = 'relevanssi';
40
  echo "<div id='relevanssi-warning' class='update-nag'><p><strong>"
41
- . __('You do not have an index! Remember to build the index (click the "Build the index" button), otherwise searching won\'t work.')
42
  . "</strong></p></div>";
43
  }
44
  if ( 'options-general.php' == $pagenow and isset( $_GET['page'] ) and plugin_basename($relevanssi_variables['file']) == $_GET['page'] ) {
@@ -54,8 +54,7 @@ function relevanssi_init() {
54
  if (!function_exists('mb_internal_encoding')) {
55
  function relevanssi_mb_warning() {
56
  echo "<div id='relevanssi-warning' class='error'><p><strong>"
57
- . "Multibyte string functions are not available. Relevanssi may not work well without them. "
58
- . "Please install (or ask your host to install) the mbstring extension."
59
  . "</strong></p></div>";
60
  }
61
  if ( 'options-general.php' == $pagenow and isset( $_GET['page'] ) and plugin_basename($relevanssi_variables['file']) == $_GET['page'] )
38
  function relevanssi_warning() {
39
  RELEVANSSI_PREMIUM ? $plugin = 'relevanssi-premium' : $plugin = 'relevanssi';
40
  echo "<div id='relevanssi-warning' class='update-nag'><p><strong>"
41
+ . __('You do not have an index! Remember to build the index (click the "Build the index" button), otherwise searching won\'t work.', 'relevanssi')
42
  . "</strong></p></div>";
43
  }
44
  if ( 'options-general.php' == $pagenow and isset( $_GET['page'] ) and plugin_basename($relevanssi_variables['file']) == $_GET['page'] ) {
54
  if (!function_exists('mb_internal_encoding')) {
55
  function relevanssi_mb_warning() {
56
  echo "<div id='relevanssi-warning' class='error'><p><strong>"
57
+ . __("Multibyte string functions are not available. Relevanssi may not work well without them. Please install (or ask your host to install) the mbstring extension.", 'relevanssi')
 
58
  . "</strong></p></div>";
59
  }
60
  if ( 'options-general.php' == $pagenow and isset( $_GET['page'] ) and plugin_basename($relevanssi_variables['file']) == $_GET['page'] )
lib/interface.php CHANGED
@@ -108,7 +108,7 @@ function relevanssi_search_stats() {
108
  relevanssi_query_log();
109
  }
110
  else {
111
- echo "<p>Enable query logging to see stats here.</p>";
112
  }
113
 
114
  echo "</div>";
@@ -123,7 +123,7 @@ function relevanssi_truncate_logs() {
123
  $query = "TRUNCATE " . $relevanssi_variables['log_table'];
124
  $wpdb->query($query);
125
 
126
- echo "<div id='relevanssi-warning' class='updated fade'>Logs clear!</div>";
127
  }
128
 
129
  function update_relevanssi_options() {
@@ -856,9 +856,9 @@ function relevanssi_options_form() {
856
 
857
  <h3><?php _e('Quick tools', 'relevanssi') ?></h3>
858
  <p>
859
- <input type='submit' name='submit' value='<?php esc_attr(_e('Save options', 'relevanssi')); ?>' class='button-primary' />
860
- <input type="submit" name="index" value="<?php esc_attr(_e('Build the index', 'relevanssi')); ?>" class='button-primary' />
861
- <input type="submit" name="index_extend" value="<?php esc_attr(_e('Continue indexing', 'relevanssi')); ?>" class='button-secondary' />, <?php _e('add', 'relevanssi'); ?> <input type="text" size="4" name="relevanssi_index_limit" value="<?php echo $index_limit ?>" /> <?php _e('documents.', 'relevanssi'); ?></p>
862
 
863
  <?php
864
  if (empty($index_post_types)) {
@@ -1175,7 +1175,7 @@ function relevanssi_options_form() {
1175
  <br />
1176
  <br />
1177
 
1178
- <input type='submit' name='submit' value='<?php esc_attr(_e('Save the options', 'relevanssi')); ?>' class='button button-primary' />
1179
 
1180
  <h3 id="indexing"><?php _e('Indexing options', 'relevanssi'); ?></h3>
1181
 
@@ -1321,9 +1321,9 @@ EOH;
1321
 
1322
  <?php if (function_exists('relevanssi_form_index_taxonomies')) relevanssi_form_index_taxonomies($index_taxonomies, $index_terms); ?>
1323
 
1324
- <input type='submit' name='index' value='<?php esc_attr(_e("Save indexing options, erase index and rebuild the index", 'relevanssi')); ?>' class='button button-primary' />
1325
 
1326
- <input type='submit' name='index_extend' value='<?php esc_attr(_e("Continue indexing", 'relevanssi')); ?>' class='button' />
1327
 
1328
  <h3 id="synonyms"><?php _e("Synonyms", "relevanssi"); ?></h3>
1329
 
@@ -1333,7 +1333,7 @@ EOH;
1333
 
1334
  <?php if (function_exists('relevanssi_form_index_synonyms')) relevanssi_form_index_synonyms($index_synonyms); ?>
1335
 
1336
- <input type='submit' name='submit' value='<?php esc_attr(_e('Save the options', 'relevanssi')); ?>' class='button' />
1337
 
1338
  <h3 id="stopwords"><?php _e("Stopwords", "relevanssi"); ?></h3>
1339
 
@@ -1357,7 +1357,7 @@ function relevanssi_show_stopwords() {
1357
  _e("<p>Enter a word here to add it to the list of stopwords. The word will automatically be removed from the index, so re-indexing is not necessary. You can enter many words at the same time, separate words with commas.</p>", 'relevanssi');
1358
 
1359
  ?><label for="addstopword"><p><?php _e("Stopword(s) to add: ", 'relevanssi'); ?><textarea name="addstopword" id="addstopword" rows="2" cols="40"></textarea>
1360
- <input type="submit" value="<?php esc_attr(_e("Add", 'relevanssi')); ?>" class='button' /></p></label>
1361
  <?php
1362
 
1363
  _e("<p>Here's a list of stopwords in the database. Click a word to remove it from stopwords. Removing stopwords won't automatically return them to index, so you need to re-index all posts after removing stopwords to get those words back to index.", 'relevanssi');
@@ -1386,7 +1386,7 @@ function relevanssi_show_stopwords() {
1386
  echo "</ul>";
1387
 
1388
  ?>
1389
- <p><input type="submit" name="removeallstopwords" value="<?php esc_attr(_e('Remove all stopwords', 'relevanssi')); ?>" class='button' /></p>
1390
  <?php
1391
 
1392
  $exportlist = htmlspecialchars(implode(", ", $exportlist));
108
  relevanssi_query_log();
109
  }
110
  else {
111
+ echo "<p>" . __('Enable query logging to see stats here.', 'relevanssi') . "</p>";
112
  }
113
 
114
  echo "</div>";
123
  $query = "TRUNCATE " . $relevanssi_variables['log_table'];
124
  $wpdb->query($query);
125
 
126
+ echo "<div id='relevanssi-warning' class='updated fade'>" . __('Logs clear!', 'relevanssi') . "</div>";
127
  }
128
 
129
  function update_relevanssi_options() {
856
 
857
  <h3><?php _e('Quick tools', 'relevanssi') ?></h3>
858
  <p>
859
+ <input type='submit' name='submit' value='<?php esc_attr_e('Save options', 'relevanssi'); ?>' class='button-primary' />
860
+ <input type="submit" name="index" value="<?php esc_attr_e('Build the index', 'relevanssi'); ?>" class='button-primary' />
861
+ <input type="submit" name="index_extend" value="<?php esc_attr_e('Continue indexing', 'relevanssi'); ?>" class='button-secondary' />, <?php _e('add', 'relevanssi'); ?> <input type="text" size="4" name="relevanssi_index_limit" value="<?php echo $index_limit ?>" /> <?php _e('documents.', 'relevanssi'); ?></p>
862
 
863
  <?php
864
  if (empty($index_post_types)) {
1175
  <br />
1176
  <br />
1177
 
1178
+ <input type='submit' name='submit' value='<?php esc_attr_e('Save the options', 'relevanssi'); ?>' class='button button-primary' />
1179
 
1180
  <h3 id="indexing"><?php _e('Indexing options', 'relevanssi'); ?></h3>
1181
 
1321
 
1322
  <?php if (function_exists('relevanssi_form_index_taxonomies')) relevanssi_form_index_taxonomies($index_taxonomies, $index_terms); ?>
1323
 
1324
+ <input type='submit' name='index' value='<?php esc_attr_e("Save indexing options, erase index and rebuild the index", 'relevanssi'); ?>' class='button button-primary' />
1325
 
1326
+ <input type='submit' name='index_extend' value='<?php esc_attr_e("Continue indexing", 'relevanssi'); ?>' class='button' />
1327
 
1328
  <h3 id="synonyms"><?php _e("Synonyms", "relevanssi"); ?></h3>
1329
 
1333
 
1334
  <?php if (function_exists('relevanssi_form_index_synonyms')) relevanssi_form_index_synonyms($index_synonyms); ?>
1335
 
1336
+ <input type='submit' name='submit' value='<?php esc_attr_e('Save the options', 'relevanssi'); ?>' class='button' />
1337
 
1338
  <h3 id="stopwords"><?php _e("Stopwords", "relevanssi"); ?></h3>
1339
 
1357
  _e("<p>Enter a word here to add it to the list of stopwords. The word will automatically be removed from the index, so re-indexing is not necessary. You can enter many words at the same time, separate words with commas.</p>", 'relevanssi');
1358
 
1359
  ?><label for="addstopword"><p><?php _e("Stopword(s) to add: ", 'relevanssi'); ?><textarea name="addstopword" id="addstopword" rows="2" cols="40"></textarea>
1360
+ <input type="submit" value="<?php esc_attr_e("Add", 'relevanssi'); ?>" class='button' /></p></label>
1361
  <?php
1362
 
1363
  _e("<p>Here's a list of stopwords in the database. Click a word to remove it from stopwords. Removing stopwords won't automatically return them to index, so you need to re-index all posts after removing stopwords to get those words back to index.", 'relevanssi');
1386
  echo "</ul>";
1387
 
1388
  ?>
1389
+ <p><input type="submit" name="removeallstopwords" value="<?php esc_attr_e('Remove all stopwords', 'relevanssi'); ?>" class='button' /></p>
1390
  <?php
1391
 
1392
  $exportlist = htmlspecialchars(implode(", ", $exportlist));
lib/search.php CHANGED
@@ -376,6 +376,8 @@ function relevanssi_search($args) {
376
  $comment_matches = array();
377
  $link_matches = array();
378
  $body_matches = array();
 
 
379
  $scores = array();
380
  $term_hits = array();
381
 
@@ -627,6 +629,8 @@ function relevanssi_search($args) {
627
  isset($title_matches[$match->doc]) ? $title_matches[$match->doc] += $match->title : $title_matches[$match->doc] = $match->title;
628
  isset($link_matches[$match->doc]) ? $link_matches[$match->doc] += $match->link : $link_matches[$match->doc] = $match->link;
629
  isset($tag_matches[$match->doc]) ? $tag_matches[$match->doc] += $match->tag : $tag_matches[$match->doc] = $match->tag;
 
 
630
  isset($comment_matches[$match->doc]) ? $comment_matches[$match->doc] += $match->comment : $comment_matches[$match->doc] = $match->comment;
631
 
632
  isset($relevanssi_post_types[$match->doc]) ? $type = $relevanssi_post_types[$match->doc] : $type = null;
@@ -693,9 +697,23 @@ function relevanssi_search($args) {
693
  // doc didn't match all terms, so it's discarded
694
  continue;
695
  }
696
-
697
- $hits[intval($i)] = relevanssi_get_post($doc);
698
- $hits[intval($i)]->relevance_score = round($weight, 2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
699
  $i++;
700
  }
701
  }
@@ -727,7 +745,8 @@ function relevanssi_search($args) {
727
  relevanssi_object_sort($hits, $orderby, $order);
728
 
729
  $return = array('hits' => $hits, 'body_matches' => $body_matches, 'title_matches' => $title_matches,
730
- 'tag_matches' => $tag_matches, 'comment_matches' => $comment_matches, 'scores' => $scores,
 
731
  'term_hits' => $term_hits, 'query' => $q, 'link_matches' => $link_matches);
732
 
733
  return $return;
@@ -978,8 +997,8 @@ function relevanssi_do_query(&$query) {
978
 
979
  $expost = get_option("relevanssi_exclude_posts");
980
 
981
- if (is_admin()) {
982
- // in admin search, search everything
983
  $excat = null;
984
  $extag = null;
985
  $expost = null;
@@ -994,6 +1013,16 @@ function relevanssi_do_query(&$query) {
994
 
995
  isset($query->query_vars['orderby']) ? $orderby = $query->query_vars['orderby'] : $orderby = null;
996
  isset($query->query_vars['order']) ? $order = $query->query_vars['order'] : $order = null;
 
 
 
 
 
 
 
 
 
 
997
 
998
  // Add synonyms
999
  // This is done here so the new terms will get highlighting
@@ -1017,7 +1046,8 @@ function relevanssi_do_query(&$query) {
1017
  'search_blogs' => $search_blogs,
1018
  'author' => $author,
1019
  'orderby' => $orderby,
1020
- 'order' => $order);
 
1021
 
1022
  $return = relevanssi_search($search_params);
1023
  }
@@ -1100,16 +1130,23 @@ function relevanssi_do_query(&$query) {
1100
  }
1101
  // OdditY end <-
1102
 
1103
- if ('on' == $make_excerpts) {
1104
  $post->original_excerpt = $post->post_excerpt;
1105
  $post->post_excerpt = relevanssi_do_excerpt($post, $q);
1106
  }
1107
 
1108
- if ('on' == get_option('relevanssi_show_matches')) {
1109
- $post->post_excerpt .= relevanssi_show_matches($return, $post->ID);
 
 
 
 
 
 
 
1110
  }
1111
 
1112
- if (isset($return['scores'][$post->ID])) $post->relevance_score = round($return['scores'][$post->ID], 2);
1113
 
1114
  $posts[] = $post;
1115
  }
376
  $comment_matches = array();
377
  $link_matches = array();
378
  $body_matches = array();
379
+ $category_matches = array();
380
+ $taxonomy_matches = array();
381
  $scores = array();
382
  $term_hits = array();
383
 
629
  isset($title_matches[$match->doc]) ? $title_matches[$match->doc] += $match->title : $title_matches[$match->doc] = $match->title;
630
  isset($link_matches[$match->doc]) ? $link_matches[$match->doc] += $match->link : $link_matches[$match->doc] = $match->link;
631
  isset($tag_matches[$match->doc]) ? $tag_matches[$match->doc] += $match->tag : $tag_matches[$match->doc] = $match->tag;
632
+ isset($category_matches[$match->doc]) ? $category_matches[$match->doc] += $match->category : $category_matches[$match->doc] = $match->category;
633
+ isset($taxonomy_matches[$match->doc]) ? $taxonomy_matches[$match->doc] += $match->taxonomy : $taxonomy_matches[$match->doc] = $match->taxonomy;
634
  isset($comment_matches[$match->doc]) ? $comment_matches[$match->doc] += $match->comment : $comment_matches[$match->doc] = $match->comment;
635
 
636
  isset($relevanssi_post_types[$match->doc]) ? $type = $relevanssi_post_types[$match->doc] : $type = null;
697
  // doc didn't match all terms, so it's discarded
698
  continue;
699
  }
700
+
701
+ if (!empty($fields)) {
702
+ if ($fields == 'ids') {
703
+ $hits[intval($i)] = $doc;
704
+ }
705
+ if ($fields == 'id=>parent') {
706
+ $object = new StdClass();
707
+ $object->ID = $doc;
708
+ $object->post_parent = wp_get_post_parent_id($doc);
709
+
710
+ $hits[intval($i)] = $object;
711
+ }
712
+ }
713
+ else {
714
+ $hits[intval($i)] = relevanssi_get_post($doc);
715
+ $hits[intval($i)]->relevance_score = round($weight, 2);
716
+ }
717
  $i++;
718
  }
719
  }
745
  relevanssi_object_sort($hits, $orderby, $order);
746
 
747
  $return = array('hits' => $hits, 'body_matches' => $body_matches, 'title_matches' => $title_matches,
748
+ 'tag_matches' => $tag_matches, 'category_matches' => $category_matches, 'taxonomy_matches' => $taxonomy_matches,
749
+ 'comment_matches' => $comment_matches, 'scores' => $scores,
750
  'term_hits' => $term_hits, 'query' => $q, 'link_matches' => $link_matches);
751
 
752
  return $return;
997
 
998
  $expost = get_option("relevanssi_exclude_posts");
999
 
1000
+ // In admin (and when not AJAX), search everything
1001
+ if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) {
1002
  $excat = null;
1003
  $extag = null;
1004
  $expost = null;
1013
 
1014
  isset($query->query_vars['orderby']) ? $orderby = $query->query_vars['orderby'] : $orderby = null;
1015
  isset($query->query_vars['order']) ? $order = $query->query_vars['order'] : $order = null;
1016
+
1017
+ $fields = "";
1018
+ if (!empty($query->query_vars['fields'])) {
1019
+ if ($query->query_vars['fields'] == 'ids') {
1020
+ $fields = 'ids';
1021
+ }
1022
+ if ($query->query_vars['fields'] == 'id=>parent') {
1023
+ $fields = 'id=>parent';
1024
+ }
1025
+ }
1026
 
1027
  // Add synonyms
1028
  // This is done here so the new terms will get highlighting
1046
  'search_blogs' => $search_blogs,
1047
  'author' => $author,
1048
  'orderby' => $orderby,
1049
+ 'order' => $order,
1050
+ 'fields' => $fields);
1051
 
1052
  $return = relevanssi_search($search_params);
1053
  }
1130
  }
1131
  // OdditY end <-
1132
 
1133
+ if ('on' == $make_excerpts && empty($fields)) {
1134
  $post->original_excerpt = $post->post_excerpt;
1135
  $post->post_excerpt = relevanssi_do_excerpt($post, $q);
1136
  }
1137
 
1138
+ if ('on' == get_option('relevanssi_show_matches') && empty($fields)) {
1139
+ $post_id = $post->ID;
1140
+ if ($post->post_type == 'user') {
1141
+ $post_id = "u_" . $post->user_id;
1142
+ }
1143
+ else if (isset($post->term_id)) {
1144
+ $post_id = '**' . $post->post_type . '**' . $post->term_id;
1145
+ }
1146
+ $post->post_excerpt .= relevanssi_show_matches($return, $post_id);
1147
  }
1148
 
1149
+ if (empty($fields) && isset($return['scores'][$post->ID])) $post->relevance_score = round($return['scores'][$post->ID], 2);
1150
 
1151
  $posts[] = $post;
1152
  }
lib/shortcodes.php CHANGED
@@ -29,7 +29,7 @@ function relevanssi_shortcode($atts, $content, $name) {
29
 
30
  function relevanssi_noindex_shortcode($atts, $content) {
31
  // When in general use, make the shortcode disappear.
32
- return $content;
33
  }
34
 
35
  function relevanssi_noindex_shortcode_indexing($atts, $content) {
29
 
30
  function relevanssi_noindex_shortcode($atts, $content) {
31
  // When in general use, make the shortcode disappear.
32
+ return do_shortcode($content);
33
  }
34
 
35
  function relevanssi_noindex_shortcode_indexing($atts, $content) {
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: msaari
3
  Donate link: http://www.relevanssi.com/buy-premium/
4
  Tags: search, relevance, better search
5
  Requires at least: 3.3
6
- Tested up to: 4.2
7
- Stable tag: 3.4.2
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -386,6 +386,19 @@ removing those words helps to make the index smaller and searching faster.
386
 
387
  == Changelog ==
388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  = 3.4.2 =
390
  * Empty lines on synonym settings caused problems. Fixed that.
391
  * In WordPress 4.2 installations, emoji in will be handled better. Emoji in posts may cause problems with WordPress versions below 4.2, so please update!
@@ -1078,6 +1091,9 @@ removing those words helps to make the index smaller and searching faster.
1078
 
1079
  == Upgrade notice ==
1080
 
 
 
 
1081
  = 3.4.2 =
1082
  * Better emoji support in WP 4.2, fixed issues with synonyms.
1083
 
3
  Donate link: http://www.relevanssi.com/buy-premium/
4
  Tags: search, relevance, better search
5
  Requires at least: 3.3
6
+ Tested up to: 4.4
7
+ Stable tag: 3.5
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
386
 
387
  == Changelog ==
388
 
389
+ = 3.5 =
390
+ * Tokenizer was using `strlen()` and not `mb_strlen()`, so word lengths were not calculated properly. If your site uses non-ASCII alphabet, rebuilding the index is a good idea.
391
+ * Small improvement to WPML multilanguage filtering.
392
+ * `relevanssi_the_title()` got a new parameter: if you don't want to echo the title, you can use it like `relevanssi_the_title(false)` to make it return the title.
393
+ * Relevanssi had `the_title` filter hook calls that were missing the second parameter; that's now fixed.
394
+ * The excerpt-building algorithm is completely rewritten based on work by Ben Boyter (http://www.boyter.org/).
395
+ * The `[watupro]` shortcode didn't work with Relevanssi, so Relevanssi will now bypass it.
396
+ * The plugin i18n features have been improved slightly.
397
+ * New filter: `relevanssi_didyoumean_suggestion` lets you modify the Did you mean? suggestion before it's displayed.
398
+ * `relevanssi_didyoumean()` has a new parameter: you can now choose whether the result is echoed out (the default value) or just returned.
399
+ * In the search results breakdown, you can now use %categories% and %taxonomies% to show the number of matches in categories and taxonomies other than tags and cats, respectively.
400
+ * Relevanssi supports `fields` parameter (both `ids` and `id=>parent`) to return only post IDs or post IDs and post parents.
401
+
402
  = 3.4.2 =
403
  * Empty lines on synonym settings caused problems. Fixed that.
404
  * In WordPress 4.2 installations, emoji in will be handled better. Emoji in posts may cause problems with WordPress versions below 4.2, so please update!
1091
 
1092
  == Upgrade notice ==
1093
 
1094
+ = 3.5 =
1095
+ * Improved excerpt-building, several bug fixes, couple of small updates.
1096
+
1097
  = 3.4.2 =
1098
  * Better emoji support in WP 4.2, fixed issues with synonyms.
1099
 
relevanssi.php CHANGED
@@ -3,10 +3,9 @@
3
  Plugin Name: Relevanssi
4
  Plugin URI: http://www.relevanssi.com/
5
  Description: This plugin replaces WordPress search with a relevance-sorting search.
6
- Version: 3.4.2
7
  Author: Mikko Saari
8
  Author URI: http://www.mikkosaari.fi/
9
- Text Domain: relevanssi
10
  */
11
 
12
  /* Copyright 2015 Mikko Saari (email: mikko@mikkosaari.fi)
@@ -59,7 +58,7 @@ require_once('lib/excerpts-highlights.php');
59
  require_once('lib/shortcodes.php');
60
  require_once('lib/common.php');
61
 
62
- function relevanssi_didyoumean($query, $pre, $post, $n = 5) {
63
  global $wpdb, $relevanssi_variables, $wp_query;
64
 
65
  $total_results = $wp_query->found_posts;
@@ -88,14 +87,14 @@ function relevanssi_didyoumean($query, $pre, $post, $n = 5) {
88
  }
89
 
90
  if ($distance > 0) {
91
-
92
  $url = get_bloginfo('url');
93
  $url = esc_attr(add_query_arg(array(
94
  's' => urlencode($closest)
95
 
96
  ), $url ));
97
  $url = apply_filters('relevanssi_didyoumean_url', $url);
98
- echo "$pre<a href='$url'>$closest</a>$post";
 
99
  }
100
 
101
 
@@ -251,7 +250,7 @@ function _relevanssi_install() {
251
  add_option('relevanssi_highlight_comments', 'off');
252
  add_option('relevanssi_index_comments', 'none'); //added by OdditY
253
  add_option('relevanssi_show_matches', '');
254
- add_option('relevanssi_show_matches_text', '(Search hits: %body% in body, %title% in title, %tags% in tags, %comments% in comments. Score: %score%)');
255
  add_option('relevanssi_fuzzy', 'sometimes');
256
  add_option('relevanssi_indexed', '');
257
  add_option('relevanssi_expand_shortcodes', 'on');
3
  Plugin Name: Relevanssi
4
  Plugin URI: http://www.relevanssi.com/
5
  Description: This plugin replaces WordPress search with a relevance-sorting search.
6
+ Version: 3.5
7
  Author: Mikko Saari
8
  Author URI: http://www.mikkosaari.fi/
 
9
  */
10
 
11
  /* Copyright 2015 Mikko Saari (email: mikko@mikkosaari.fi)
58
  require_once('lib/shortcodes.php');
59
  require_once('lib/common.php');
60
 
61
+ function relevanssi_didyoumean($query, $pre, $post, $n = 5, $echo = true) {
62
  global $wpdb, $relevanssi_variables, $wp_query;
63
 
64
  $total_results = $wp_query->found_posts;
87
  }
88
 
89
  if ($distance > 0) {
 
90
  $url = get_bloginfo('url');
91
  $url = esc_attr(add_query_arg(array(
92
  's' => urlencode($closest)
93
 
94
  ), $url ));
95
  $url = apply_filters('relevanssi_didyoumean_url', $url);
96
+ $result = apply_filters('relevanssi_didyoumean_suggestion', "$pre<a href='$url'>$suggestion</a>$post");
97
+ if ($echo) echo $result;
98
  }
99
 
100
 
250
  add_option('relevanssi_highlight_comments', 'off');
251
  add_option('relevanssi_index_comments', 'none'); //added by OdditY
252
  add_option('relevanssi_show_matches', '');
253
+ add_option('relevanssi_show_matches_text', '(Search hits: %body% in body, %title% in title, %category% in categories, %tags% in tags, %taxonomy% in other taxonomies, %comments% in comments. Score: %score%)');
254
  add_option('relevanssi_fuzzy', 'sometimes');
255
  add_option('relevanssi_indexed', '');
256
  add_option('relevanssi_expand_shortcodes', 'on');