Relevanssi – A Better Search - Version 4.8.2

Version Description

  • New feature: New filter hook relevanssi_term_where lets you filter the term WHERE conditional for the search query.
  • Minor fix: Doing the document count updates asynchronously caused problems in some cases (eg. importing posts). Now the document count is only updated after a full indexing and once per week.
  • Minor fix: Phrase matching has been improved to make it possible to search for phrases that include characters like the ampersand.
Download this release

Release Info

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

Code changes from version 4.8.1 to 4.8.2

lib/common.php CHANGED
@@ -508,14 +508,8 @@ function relevanssi_generate_phrase_queries( $phrases, $taxonomies, $custom_fiel
508
  foreach ( $phrases as $phrase ) {
509
  $queries = array();
510
  $phrase = $wpdb->esc_like( $phrase );
511
- $phrase = str_replace( '‘', '_', $phrase );
512
- $phrase = str_replace( '’', '_', $phrase );
513
- $phrase = str_replace( "'", '_', $phrase );
514
- $phrase = str_replace( '"', '_', $phrase );
515
- $phrase = str_replace( '”', '_', $phrase );
516
- $phrase = str_replace( '“', '_', $phrase );
517
- $phrase = str_replace( '„', '_', $phrase );
518
- $phrase = str_replace( '´', '_', $phrase );
519
  $phrase = esc_sql( $phrase );
520
 
521
  $excerpt = '';
@@ -1307,7 +1301,43 @@ function relevanssi_stripos( $haystack, $needle, $offset = 0 ) {
1307
  return false;
1308
  }
1309
 
1310
- if ( function_exists( 'mb_stripos' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1311
  if ( '' === $haystack ) {
1312
  $pos = false;
1313
  } else {
508
  foreach ( $phrases as $phrase ) {
509
  $queries = array();
510
  $phrase = $wpdb->esc_like( $phrase );
511
+ $phrase = str_replace( array( '‘', '’', "'", '"', '”', '“', '“', '„', '´' ), '_', $phrase );
512
+ $phrase = htmlentities( $phrase );
 
 
 
 
 
 
513
  $phrase = esc_sql( $phrase );
514
 
515
  $excerpt = '';
1301
  return false;
1302
  }
1303
 
1304
+ if ( preg_match( '/[\?\*]/', $needle ) ) {
1305
+ // There's a ? or an * in the string, which means it's a wildcard search
1306
+ // query (a Premium feature) and requires some extra steps.
1307
+
1308
+ $needle_regex = str_replace(
1309
+ array( '?', '*' ),
1310
+ array( '.', '.*' ),
1311
+ $needle
1312
+ );
1313
+ $pos_found = false;
1314
+ while ( ! $pos_found ) {
1315
+ preg_match(
1316
+ "/$needle_regex/i",
1317
+ $haystack,
1318
+ $matches,
1319
+ PREG_OFFSET_CAPTURE,
1320
+ $offset
1321
+ );
1322
+ /**
1323
+ * This trickery is necessary, because PREG_OFFSET_CAPTURE gives
1324
+ * wrong offsets for multibyte strings. The mb_strlen() gives the
1325
+ * correct offset, the rest of this is because the $offset received
1326
+ * as a parameter can be before the first $position, leading to an
1327
+ * infinite loop.
1328
+ */
1329
+ $pos = isset( $matches[0][1] )
1330
+ ? mb_strlen( substr( $haystack, 0, $matches[0][1] ) )
1331
+ : false;
1332
+ if ( $pos && $pos > $offset ) {
1333
+ $pos_found = true;
1334
+ } elseif ( $pos ) {
1335
+ $offset++;
1336
+ } else {
1337
+ $pos_found = true;
1338
+ }
1339
+ }
1340
+ } elseif ( function_exists( 'mb_stripos' ) ) {
1341
  if ( '' === $haystack ) {
1342
  $pos = false;
1343
  } else {
lib/excerpts-highlights.php CHANGED
@@ -524,6 +524,13 @@ function relevanssi_highlight_terms( $content, $query, $in_docs = false ) {
524
  $pr_term = preg_quote( $term, '/' );
525
  $pr_term = relevanssi_add_accent_variations( $pr_term );
526
 
 
 
 
 
 
 
 
527
  if ( $word_boundaries_available ) {
528
  $regex = "/(\b$pr_term\b)/iu";
529
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
@@ -879,6 +886,13 @@ function relevanssi_count_matches( $words, $complete_text ) {
879
  ),
880
  'UTF-8'
881
  );
 
 
 
 
 
 
 
882
  if ( $word_boundaries_available ) {
883
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
884
  $regex = "/\b$word_slice|$word_slice\b/";
524
  $pr_term = preg_quote( $term, '/' );
525
  $pr_term = relevanssi_add_accent_variations( $pr_term );
526
 
527
+ // Support for wildcard matching (a Premium feature).
528
+ $pr_term = str_replace(
529
+ array( '\*', '\?' ),
530
+ array( '\S*', '.' ),
531
+ $pr_term
532
+ );
533
+
534
  if ( $word_boundaries_available ) {
535
  $regex = "/(\b$pr_term\b)/iu";
536
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
886
  ),
887
  'UTF-8'
888
  );
889
+ // Support for wildcard matching (a Premium feature).
890
+ $word_slice = str_replace(
891
+ array( '\*', '\?' ),
892
+ array( '\S*', '.' ),
893
+ $word_slice
894
+ );
895
+
896
  if ( $word_boundaries_available ) {
897
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
898
  $regex = "/\b$word_slice|$word_slice\b/";
lib/indexing.php CHANGED
@@ -816,7 +816,6 @@ function relevanssi_publish( $post_id, $bypass_global_post = false ) {
816
  */
817
  function relevanssi_insert_edit( $post_id ) {
818
  global $wpdb;
819
-
820
  if ( 'revision' === relevanssi_get_post_type( $post_id ) ) {
821
  return 'revision';
822
  }
@@ -862,10 +861,6 @@ function relevanssi_insert_edit( $post_id ) {
862
  if ( $index_this_post ) {
863
  $bypass_global_post = true;
864
  $return_value = relevanssi_publish( $post_id, $bypass_global_post );
865
-
866
- if ( is_int( $return_value ) && $return_value > 0 ) {
867
- relevanssi_async_update_doc_count();
868
- }
869
  } else {
870
  // The post isn't supposed to be indexed anymore, remove it from index.
871
  relevanssi_remove_doc( $post_id );
@@ -1046,10 +1041,6 @@ function relevanssi_remove_doc( $post_id, $keep_internal_links = false ) {
1046
  $post_id
1047
  )
1048
  );
1049
-
1050
- if ( $rows_updated && $rows_updated > 0 ) {
1051
- relevanssi_async_update_doc_count();
1052
- }
1053
  }
1054
  }
1055
 
816
  */
817
  function relevanssi_insert_edit( $post_id ) {
818
  global $wpdb;
 
819
  if ( 'revision' === relevanssi_get_post_type( $post_id ) ) {
820
  return 'revision';
821
  }
861
  if ( $index_this_post ) {
862
  $bypass_global_post = true;
863
  $return_value = relevanssi_publish( $post_id, $bypass_global_post );
 
 
 
 
864
  } else {
865
  // The post isn't supposed to be indexed anymore, remove it from index.
866
  relevanssi_remove_doc( $post_id );
1041
  $post_id
1042
  )
1043
  );
 
 
 
 
1044
  }
1045
  }
1046
 
lib/init.php CHANGED
@@ -141,6 +141,10 @@ function relevanssi_init() {
141
  }
142
  }
143
 
 
 
 
 
144
  if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) ) {
145
  require_once 'compatibility/wpml.php';
146
  }
141
  }
142
  }
143
 
144
+ if ( ! wp_next_scheduled( 'relevanssi_update_counts' ) ) {
145
+ wp_schedule_event( time(), 'weekly', 'relevanssi_update_counts' );
146
+ }
147
+
148
  if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) ) {
149
  require_once 'compatibility/wpml.php';
150
  }
lib/interface.php CHANGED
@@ -87,6 +87,11 @@ function relevanssi_options() {
87
  check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
88
  relevanssi_remove_all_body_stopwords();
89
  }
 
 
 
 
 
90
  }
91
 
92
  relevanssi_options_form();
87
  check_admin_referer( plugin_basename( $relevanssi_variables['file'] ), 'relevanssi_options' );
88
  relevanssi_remove_all_body_stopwords();
89
  }
90
+
91
+ if ( isset( $_REQUEST['update_counts'] ) ) {
92
+ check_admin_referer( 'update_counts' );
93
+ relevanssi_update_counts();
94
+ }
95
  }
96
 
97
  relevanssi_options_form();
lib/search.php CHANGED
@@ -182,8 +182,11 @@ function relevanssi_search( $args ) {
182
  // Get the count from the options.
183
  $doc_count = get_option( 'relevanssi_doc_count', 0 );
184
  if ( ! $doc_count || $doc_count < 1 ) {
185
- // Doc count is 0, update async in case there's some problem.
186
- relevanssi_async_update_doc_count();
 
 
 
187
  }
188
 
189
  $total_hits = 0;
@@ -1147,7 +1150,12 @@ function relevanssi_generate_term_where( $term, $force_fuzzy = false, $no_terms
1147
 
1148
  $term_where = str_replace( '#term#', $term, $term_where_template );
1149
 
1150
- return $term_where;
 
 
 
 
 
1151
  }
1152
 
1153
  /**
182
  // Get the count from the options.
183
  $doc_count = get_option( 'relevanssi_doc_count', 0 );
184
  if ( ! $doc_count || $doc_count < 1 ) {
185
+ $doc_count = relevanssi_update_doc_count();
186
+ if ( ! $doc_count || $doc_count < 1 ) {
187
+ // No value available for some reason, use a random value.
188
+ $doc_count = 100;
189
+ }
190
  }
191
 
192
  $total_hits = 0;
1150
 
1151
  $term_where = str_replace( '#term#', $term, $term_where_template );
1152
 
1153
+ /**
1154
+ * Filters the term WHERE condition for the Relevanssi MySQL query.
1155
+ *
1156
+ * @param string $term_where The WHERE condition for the terms.
1157
+ */
1158
+ return apply_filters( 'relevanssi_term_where', $term_where );
1159
  }
1160
 
1161
  /**
lib/tabs/indexing-tab.php CHANGED
@@ -98,6 +98,9 @@ function relevanssi_indexing_tab() {
98
  $taxterm_count = get_option( 'relevanssi_taxterm_count', 0 );
99
  }
100
 
 
 
 
101
  ?>
102
  <div id="indexing_tab">
103
 
@@ -123,7 +126,7 @@ function relevanssi_indexing_tab() {
123
  </div>
124
  <div id='relevanssi-note' style='display: none'></div>
125
  <div id='relevanssi-progress' class='rpi-progress'><div class="rpi-indicator"></div></div>
126
- <div id='relevanssi-timer'><?php esc_html_e( 'Time elapsed', 'relevanssi' ); ?>: <span id="relevanssi_elapsed">0:00:00</span> | <?php esc_html_e( 'Time remaining', 'relevanssi' ); ?>: <span id="relevanssi_estimated"><?php esc_html_e( 'some time', 'relevanssi' ); ?></span></div>
127
  <label for="results" class="screen-reader-text"><?php esc_html_e( 'Results', 'relevanssi' ); ?></label><textarea id='results' rows='10' cols='80'></textarea>
128
  <div id='relevanssi-indexing-instructions' style='display: none'><?php esc_html_e( "Indexing should respond quickly. If nothing happens in couple of minutes, it's probably stuck. The most common reasons for indexing issues are incompatible shortcodes, so try disabling the shortcode expansion setting and try again. Also, if you've just updated Relevanssi, doing a hard refresh in your browser will make sure your browser is not trying to use an outdated version of the Relevanssi scripts.", 'relevanssi' ); ?></div>
129
  </td>
@@ -138,6 +141,8 @@ function relevanssi_indexing_tab() {
138
  </p>
139
  <p><?php echo esc_html( $terms_count ); ?> <?php echo esc_html( _n( 'term in the index.', 'terms in the index.', $terms_count, 'relevanssi' ) ); ?><br />
140
  <?php echo esc_html( $lowest_doc ); ?> <?php esc_html_e( 'is the lowest post ID indexed.', 'relevanssi' ); ?></p>
 
 
141
  </td>
142
  </tr>
143
  </table>
98
  $taxterm_count = get_option( 'relevanssi_taxterm_count', 0 );
99
  }
100
 
101
+ $this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
102
+ $update_url = wp_nonce_url( $this_page . '&tab=indexing&update_counts=1', 'update_counts' );
103
+
104
  ?>
105
  <div id="indexing_tab">
106
 
126
  </div>
127
  <div id='relevanssi-note' style='display: none'></div>
128
  <div id='relevanssi-progress' class='rpi-progress'><div class="rpi-indicator"></div></div>
129
+ <div id='relevanssi-timer'><?php esc_html_e( 'Time elapsed', 'relevanssi' ); ?>: <span id="relevanssi_elapsed">0:00:00</span> | <?php esc_html_e( 'Time remaining', 'relevanssi' ); ?>: <span id="relevanssi_estimated"><?php esc_html_e( 'some time', 'relevanssi' ); ?></span></div>
130
  <label for="results" class="screen-reader-text"><?php esc_html_e( 'Results', 'relevanssi' ); ?></label><textarea id='results' rows='10' cols='80'></textarea>
131
  <div id='relevanssi-indexing-instructions' style='display: none'><?php esc_html_e( "Indexing should respond quickly. If nothing happens in couple of minutes, it's probably stuck. The most common reasons for indexing issues are incompatible shortcodes, so try disabling the shortcode expansion setting and try again. Also, if you've just updated Relevanssi, doing a hard refresh in your browser will make sure your browser is not trying to use an outdated version of the Relevanssi scripts.", 'relevanssi' ); ?></div>
132
  </td>
141
  </p>
142
  <p><?php echo esc_html( $terms_count ); ?> <?php echo esc_html( _n( 'term in the index.', 'terms in the index.', $terms_count, 'relevanssi' ) ); ?><br />
143
  <?php echo esc_html( $lowest_doc ); ?> <?php esc_html_e( 'is the lowest post ID indexed.', 'relevanssi' ); ?></p>
144
+ <?php /** Translators: %1$s opens the a tag, %2$s closes it. */ ?>
145
+ <p class="description">(<?php printf( esc_html__( 'These values may be inaccurate. If you need exact values, %1$supdate the counts%2$s' ), '<a href="' . esc_attr( $update_url ) . '">', '</a>' ); ?>.)</p>
146
  </td>
147
  </tr>
148
  </table>
lib/uninstall.php CHANGED
@@ -23,8 +23,6 @@ function relevanssi_drop_database_tables() {
23
  return;
24
  }
25
 
26
- wp_clear_scheduled_hook( 'relevanssi_truncate_cache' );
27
-
28
  $relevanssi_table = $wpdb->prefix . 'relevanssi';
29
  $stopword_table = $wpdb->prefix . 'relevanssi_stopwords';
30
  $log_table = $wpdb->prefix . 'relevanssi_log';
@@ -136,5 +134,7 @@ function relevanssi_uninstall_free() {
136
  global $wpdb;
137
  $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_relevanssi_noindex_reason'" );
138
 
 
 
139
  relevanssi_drop_database_tables();
140
  }
23
  return;
24
  }
25
 
 
 
26
  $relevanssi_table = $wpdb->prefix . 'relevanssi';
27
  $stopword_table = $wpdb->prefix . 'relevanssi_stopwords';
28
  $log_table = $wpdb->prefix . 'relevanssi_log';
134
  global $wpdb;
135
  $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_relevanssi_noindex_reason'" );
136
 
137
+ wp_clear_scheduled_hook( 'relevanssi_update_counts' );
138
+
139
  relevanssi_drop_database_tables();
140
  }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: search, relevance, better search, product search, woocommerce search
5
  Requires at least: 4.9
6
  Tested up to: 5.5
7
  Requires PHP: 7.0
8
- Stable tag: 4.8.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -133,6 +133,11 @@ Each document database is full of useless words. All the little words that appea
133
  * John Calahan for extensive 4.0 beta testing.
134
 
135
  == Changelog ==
 
 
 
 
 
136
  = 4.8.1 =
137
  * Major fix: Changes in WooCommerce 4.4.0 broke the Relevanssi searches. This makes the WooCommerce search work again.
138
  * Minor fix: Excluding from logs didn't work if user IDs had spaces between them ('user_a, user_b'). Now the extra spaces don't matter.
@@ -175,6 +180,9 @@ Each document database is full of useless words. All the little words that appea
175
  * Minor fix: User Access Manager showed drafts in search results for all users. This is now fixed.
176
 
177
  == Upgrade notice ==
 
 
 
178
  = 4.8.1 =
179
  * WooCommerce 4.4 compatibility, other minor fixes.
180
 
5
  Requires at least: 4.9
6
  Tested up to: 5.5
7
  Requires PHP: 7.0
8
+ Stable tag: 4.8.2
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
133
  * John Calahan for extensive 4.0 beta testing.
134
 
135
  == Changelog ==
136
+ = 4.8.2 =
137
+ * New feature: New filter hook `relevanssi_term_where` lets you filter the term WHERE conditional for the search query.
138
+ * Minor fix: Doing the document count updates asynchronously caused problems in some cases (eg. importing posts). Now the document count is only updated after a full indexing and once per week.
139
+ * Minor fix: Phrase matching has been improved to make it possible to search for phrases that include characters like the ampersand.
140
+
141
  = 4.8.1 =
142
  * Major fix: Changes in WooCommerce 4.4.0 broke the Relevanssi searches. This makes the WooCommerce search work again.
143
  * Minor fix: Excluding from logs didn't work if user IDs had spaces between them ('user_a, user_b'). Now the extra spaces don't matter.
180
  * Minor fix: User Access Manager showed drafts in search results for all users. This is now fixed.
181
 
182
  == Upgrade notice ==
183
+ = 4.8.2 =
184
+ * Performance and phrase search improvements.
185
+
186
  = 4.8.1 =
187
  * WooCommerce 4.4 compatibility, other minor fixes.
188
 
relevanssi.php CHANGED
@@ -13,7 +13,7 @@
13
  * Plugin Name: Relevanssi
14
  * Plugin URI: https://www.relevanssi.com/
15
  * Description: This plugin replaces WordPress search with a relevance-sorting search.
16
- * Version: 4.8.1
17
  * Author: Mikko Saari
18
  * Author URI: http://www.mikkosaari.fi/
19
  * Text Domain: relevanssi
@@ -67,7 +67,7 @@ $relevanssi_variables['database_version'] = 5;
67
  $relevanssi_variables['file'] = __FILE__;
68
  $relevanssi_variables['plugin_dir'] = plugin_dir_path( __FILE__ );
69
  $relevanssi_variables['plugin_basename'] = plugin_basename( __FILE__ );
70
- $relevanssi_variables['plugin_version'] = '4.8.1';
71
 
72
  require_once 'lib/admin-ajax.php';
73
  require_once 'lib/common.php';
13
  * Plugin Name: Relevanssi
14
  * Plugin URI: https://www.relevanssi.com/
15
  * Description: This plugin replaces WordPress search with a relevance-sorting search.
16
+ * Version: 4.8.2
17
  * Author: Mikko Saari
18
  * Author URI: http://www.mikkosaari.fi/
19
  * Text Domain: relevanssi
67
  $relevanssi_variables['file'] = __FILE__;
68
  $relevanssi_variables['plugin_dir'] = plugin_dir_path( __FILE__ );
69
  $relevanssi_variables['plugin_basename'] = plugin_basename( __FILE__ );
70
+ $relevanssi_variables['plugin_version'] = '4.8.2';
71
 
72
  require_once 'lib/admin-ajax.php';
73
  require_once 'lib/common.php';