Relevanssi – A Better Search - Version 3.6.2

Version Description

  • Simple Membership plugin is now supported automatically to restrict access to posts.
  • Relevanssi can now handle orderby parameter in array format.
  • Relevanssi now blocks Easy Digital Downloads shortcodes when indexing to improve compatibility with EDD.
  • When using fields to only fetch post IDs, Relevanssi doesn't try to highlight post titles.
  • New action: relevanssi_update_options lets you adjust Relevanssi options immediately after the defaults are set.
  • Remove notices about duplicated database columns when installing the plugin.
Download this release

Release Info

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

Code changes from version 3.6.1 to 3.6.2

Files changed (5) hide show
  1. lib/common.php +183 -60
  2. lib/indexing.php +11 -4
  3. lib/search.php +18 -9
  4. readme.txt +9 -1
  5. relevanssi.php +4 -14
lib/common.php CHANGED
@@ -23,20 +23,6 @@ function relevanssi_wpml_filter($data) {
23
  $filtered_hits[] = $hit;
24
  }
25
  }
26
- elseif (function_exists('icl_object_id') && function_exists('pll_is_translated_post_type')) {
27
- if (pll_is_translated_post_type($hit->post_type)) {
28
- if (PLL()->model->post->get_language($hit->ID)->slug == ICL_LANGUAGE_CODE) {
29
- $filtered_hits[] = $hit;
30
- }
31
- else if ($hit->ID == icl_object_id($hit->ID, $hit->post_type, false, ICL_LANGUAGE_CODE)) {
32
- $filtered_hits[] = $hit;
33
- }
34
- }
35
- else {
36
- $filtered_hits[] = $hit;
37
- }
38
- }
39
-
40
  // if there is no WPML but the target blog has identical language with current blog,
41
  // we use the hits. Note en-US is not identical to en-GB!
42
  elseif (get_bloginfo('language') == $lang) {
@@ -51,52 +37,186 @@ function relevanssi_wpml_filter($data) {
51
  return $data;
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  /**
55
  * Function by Matthew Hood http://my.php.net/manual/en/function.sort.php#75036
56
  */
57
- function relevanssi_object_sort(&$data, $key, $dir = 'desc') {
58
- if ('title' == $key) $key = 'post_title';
59
- if ('date' == $key) $key = 'post_date';
60
- if (!isset($data[0]->$key)) return; // trying to sort by a non-existent key
61
- $dir = strtolower($dir);
62
- function_exists('mb_strtolower') ? $strtolower = 'mb_strtolower' : $strtolower = 'strtolower';
63
- for ($i = count($data) - 1; $i >= 0; $i--) {
64
- $swapped = false;
65
- for ($j = 0; $j < $i; $j++) {
66
- $key1 = "";
67
- $key2 = "";
68
- if (isset($data[$j]->$key)) {
69
- $key1 = call_user_func($strtolower, $data[$j]->$key);
70
- }
71
- else {
72
- $key1 = apply_filters('relevanssi_missing_sort_key', $key1, $key);
73
- }
74
- if (isset($data[$j + 1]->$key)) {
75
- $key2 = call_user_func($strtolower, $data[$j + 1]->$key);
76
- }
77
- else {
78
- $key2 = apply_filters('relevanssi_missing_sort_key', $key2, $key);
79
- }
80
- if ('asc' == $dir) {
81
- if ($key1 > $key2) {
82
- $tmp = $data[$j];
83
- $data[$j] = $data[$j + 1];
84
- $data[$j + 1] = $tmp;
85
- $swapped = true;
86
- }
87
- }
88
- else {
89
- if ($key1 < $key2) {
90
- $tmp = $data[$j];
91
- $data[$j] = $data[$j + 1];
92
- $data[$j + 1] = $tmp;
93
- $swapped = true;
94
- }
95
- }
96
- }
97
- if (!$swapped) return;
98
- }
99
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  function relevanssi_show_matches($data, $hit) {
102
  isset($data['body_matches'][$hit]) ? $body = $data['body_matches'][$hit] : $body = 0;
@@ -115,7 +235,7 @@ function relevanssi_show_matches($data, $hit) {
115
  $total_hits += $hits;
116
  }
117
 
118
- $text = get_option('relevanssi_show_matches_text');
119
  $replace_these = array("%body%", "%title%", "%tags%", "%categories%", "%taxonomies%", "%comments%", "%score%", "%terms%", "%total%");
120
  $replacements = array($body, $title, $tag, $category, $taxonomy, $comment, $score, $term_hits, $total_hits);
121
 
@@ -188,6 +308,11 @@ function relevanssi_default_post_ok($post_ok, $doc) {
188
  $current_user = wp_get_current_user();
189
  $access = Groups_Post_Access::user_can_read_post($doc, $current_user->ID);
190
  }
 
 
 
 
 
191
  else {
192
  // Basic WordPress version
193
  $type = relevanssi_get_post_type($doc);
@@ -756,5 +881,3 @@ function relevanssi_debug_echo($s) {
756
  echo $s . "\n";
757
  }
758
  }
759
-
760
- ?>
23
  $filtered_hits[] = $hit;
24
  }
25
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  // if there is no WPML but the target blog has identical language with current blog,
27
  // we use the hits. Note en-US is not identical to en-GB!
28
  elseif (get_bloginfo('language') == $lang) {
37
  return $data;
38
  }
39
 
40
+ /*
41
+ * Fetches a key-direction pair from the orderby array. Converts key names to match the post object parameters
42
+ * when necessary and seeds the random generator, if required.
43
+ */
44
+ function relevanssi_get_next_key(&$orderby) {
45
+ if (!is_array($orderby) || count($orderby) < 1) return array(null, null);
46
+
47
+ list($key) = array_keys($orderby);
48
+ $dir = $orderby[$key];
49
+ unset($orderby[$key]);
50
+
51
+ $compare = "string";
52
+
53
+ if (strtolower($dir) == "rand") $key = "rand";
54
+
55
+ if ('title' == $key) $key = 'post_title';
56
+ if ('date' == $key) $key = 'post_date';
57
+ if ('modified' == $key) $key = 'post_modified';
58
+ if ('parent' == $key) $key = 'post_parent';
59
+ if ('type' == $key) $key = 'post_type';
60
+ if ('name' == $key) $key = 'post_name';
61
+ if ('author' == $key) $key = 'post_author';
62
+ if ('relevance' == $key) $key = 'relevance_score';
63
+
64
+ $numeric_keys = array('menu_order', 'ID', 'post_parent', 'post_author', 'comment_count', 'relevance_score');
65
+ $date_keys = array('post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt');
66
+
67
+ if (in_array($key, $numeric_keys)) $compare = "number";
68
+ if (in_array($key, $date_keys)) $compare = "date";
69
+
70
+ if ('rand' == $key) {
71
+ if (is_numeric($dir)) srand($dir);
72
+ }
73
+ else {
74
+ $dir = strtolower($dir);
75
+ if ($dir != "asc") $dir = "desc";
76
+ }
77
+
78
+ return array($key, $dir, $compare);
79
+ }
80
+
81
+ /*
82
+ * Fetches the key values for the item pair. If random order is required, will randomize the order.
83
+ */
84
+ function relevanssi_get_compare_keys($key, $item_1, $item_2) {
85
+ function_exists('mb_strtolower') ? $strtolower = 'mb_strtolower' : $strtolower = 'strtolower';
86
+
87
+ if ($key == "rand") {
88
+ do {
89
+ $key1 = rand();
90
+ $key2 = rand();
91
+ } while ($key1 == $key2);
92
+ return array($key1, $key2);
93
+ }
94
+
95
+ $key1 = "";
96
+ $key2 = "";
97
+
98
+ if ($key == "meta_value" || $key == "meta_value_num") {
99
+ global $wp_query;
100
+ $key = $wp_query->query_vars['meta_key'];
101
+ if (!isset($key)) return array("", "");
102
+
103
+ $key1 = get_post_meta($item_1->ID, $key, true);
104
+ if (empty($key1)) $key1 = apply_filters('relevanssi_missing_sort_key', $key1, $key);
105
+
106
+ $key2 = get_post_meta($item_2->ID, $key, true);
107
+ if (empty($key2)) $key2 = apply_filters('relevanssi_missing_sort_key', $key2, $key);
108
+ }
109
+ else {
110
+ if (isset($item_1->$key)) {
111
+ $key1 = call_user_func($strtolower, $item_1->$key);
112
+ }
113
+ else {
114
+ $key1 = apply_filters('relevanssi_missing_sort_key', $key1, $key);
115
+ }
116
+ if (isset($item_2->$key)) {
117
+ $key2 = call_user_func($strtolower, $item_2->$key);
118
+ }
119
+ else {
120
+ $key2 = apply_filters('relevanssi_missing_sort_key', $key2, $key);
121
+ }
122
+ }
123
+ return array($key1, $key2);
124
+ }
125
+
126
+ function relevanssi_compare_keys($key1, $key2, $compare) {
127
+ $val = 0;
128
+ if ($compare == "date") {
129
+ if (strtotime($key1) > strtotime($key2)) {
130
+ $val = 1;
131
+ }
132
+ else if (strtotime($key1) < strtome($key2)) {
133
+ $val = -1;
134
+ }
135
+ }
136
+ else if ($compare == "string") {
137
+ $val = relevanssi_mb_strcasecmp($key1, $key2);
138
+ }
139
+ else {
140
+ if ($key1 > $key2) {
141
+ $val = 1;
142
+ }
143
+ else if ($key1 < $key2) {
144
+ $val = -1;
145
+ }
146
+ }
147
+ return $val;
148
+ }
149
+
150
+ function relevanssi_mb_strcasecmp($str1, $str2, $encoding = null) {
151
+ if (!function_exists('mb_internal_encoding')) {
152
+ return strcasecmp($str1, $str2);
153
+ }
154
+ else {
155
+ if (null === $encoding) $encoding = mb_internal_encoding();
156
+ return strcmp(mb_strtoupper($str1, $encoding), mb_strtoupper($str2, $encoding));
157
+ }
158
+ }
159
+
160
  /**
161
  * Function by Matthew Hood http://my.php.net/manual/en/function.sort.php#75036
162
  */
163
+ function relevanssi_object_sort(&$data, $orderby) {
164
+ $keys = array();
165
+ $dirs = array();
166
+ $compares = array();
167
+ do {
168
+ list($key, $dir, $compare) = relevanssi_get_next_key($orderby);
169
+ if ($key != null) {
170
+ $keys[] = $key;
171
+ $dirs[] = $dir;
172
+ $compares[] = $compare;
173
+ }
174
+ } while ($key != null);
175
+
176
+ $primary_key = $keys[0];
177
+ if (!isset($data[0]->$primary_key)) return; // trying to sort by a non-existent key
178
+
179
+ for ($i = count($data) - 1; $i >= 0; $i--) {
180
+ $swapped = false;
181
+ for ($j = 0; $j < $i; $j++) {
182
+ $key1 = "";
183
+ $key2 = "";
184
+
185
+ $level = -1;
186
+
187
+ $compare = $compares[$level];
188
+ $val = relevanssi_compare_keys($key1, $key2, $compare);
189
+
190
+ while ($val == 0) {
191
+ $level++;
192
+ if (!isset($keys[$level])) {
193
+ $level--;
194
+ break; // give up – we can't sort these two
195
+ }
196
+ list($key1, $key2) = relevanssi_get_compare_keys($keys[$level], $data[$j], $data[$j + 1]);
197
+ $val = relevanssi_compare_keys($key1, $key2, $compare);
198
+ }
199
+
200
+ if ('asc' == $dirs[$level]) {
201
+ if ($val == 1) {
202
+ $tmp = $data[$j];
203
+ $data[$j] = $data[$j + 1];
204
+ $data[$j + 1] = $tmp;
205
+ $swapped = true;
206
+ }
207
+ }
208
+ else {
209
+ if ($val == -1) {
210
+ $tmp = $data[$j];
211
+ $data[$j] = $data[$j + 1];
212
+ $data[$j + 1] = $tmp;
213
+ $swapped = true;
214
+ }
215
+ }
216
+ }
217
+ if (!$swapped) return;
218
+ }
219
+ }
220
 
221
  function relevanssi_show_matches($data, $hit) {
222
  isset($data['body_matches'][$hit]) ? $body = $data['body_matches'][$hit] : $body = 0;
235
  $total_hits += $hits;
236
  }
237
 
238
+ $text = stripslashes(get_option('relevanssi_show_matches_text'));
239
  $replace_these = array("%body%", "%title%", "%tags%", "%categories%", "%taxonomies%", "%comments%", "%score%", "%terms%", "%total%");
240
  $replacements = array($body, $title, $tag, $category, $taxonomy, $comment, $score, $term_hits, $total_hits);
241
 
308
  $current_user = wp_get_current_user();
309
  $access = Groups_Post_Access::user_can_read_post($doc, $current_user->ID);
310
  }
311
+ else if (defined('SIMPLE_WP_MEMBERSHIP_VER')) {
312
+ // Simple Membership
313
+ $access_ctrl = SwpmAccessControl::get_instance();
314
+ $access = $access_ctrl->can_i_read_post($post);
315
+ }
316
  else {
317
  // Basic WordPress version
318
  $type = relevanssi_get_post_type($doc);
881
  echo $s . "\n";
882
  }
883
  }
 
 
lib/indexing.php CHANGED
@@ -448,6 +448,16 @@ function relevanssi_index_doc($indexpost, $remove_first = false, $custom_fields
448
  remove_shortcode('tc_process_payment');
449
  remove_shortcode('maxmegamenu'); // Max Mega Menu
450
  remove_shortcode('searchandfilter'); // Search and Filter
 
 
 
 
 
 
 
 
 
 
451
 
452
  $post_before_shortcode = $post;
453
  $contents = do_shortcode($contents);
@@ -462,10 +472,7 @@ function relevanssi_index_doc($indexpost, $remove_first = false, $custom_fields
462
  }
463
  }
464
  else {
465
- if (function_exists("strip_shortcodes")) {
466
- // WP 2.5 doesn't have the function
467
- $contents = strip_shortcodes($contents);
468
- }
469
  }
470
 
471
  remove_shortcode('noindex');
448
  remove_shortcode('tc_process_payment');
449
  remove_shortcode('maxmegamenu'); // Max Mega Menu
450
  remove_shortcode('searchandfilter'); // Search and Filter
451
+ remove_shortcode('downloads'); // Easy Digital Downloads
452
+ remove_shortcode('download_history');
453
+ remove_shortcode('purchase_history');
454
+ remove_shortcode('download_checkout');
455
+ remove_shortcode('purchase_link');
456
+ remove_shortcode('download_cart');
457
+ remove_shortcode('edd_profile_editor');
458
+ remove_shortcode('edd_login');
459
+ remove_shortcode('edd_register');
460
+ remove_shortcode('swpm_protected'); // Simple Membership Partially Protected content
461
 
462
  $post_before_shortcode = $post;
463
  $contents = do_shortcode($contents);
472
  }
473
  }
474
  else {
475
+ $contents = strip_shortcodes($contents);
 
 
 
476
  }
477
 
478
  remove_shortcode('noindex');
lib/search.php CHANGED
@@ -729,16 +729,25 @@ function relevanssi_search($args) {
729
  if (empty($orderby)) $orderby = $default_order;
730
  // the sorting function checks for non-existing keys, cannot whitelist here
731
 
732
- if (empty($order)) $order = 'desc';
733
- $order = strtolower($order);
734
- $order_accepted_values = array('asc', 'desc');
735
- if (!in_array($order, $order_accepted_values)) $order = 'desc';
 
 
 
 
 
 
736
 
737
- $orderby = apply_filters('relevanssi_orderby', $orderby);
738
- $order = apply_filters('relevanssi_order', $order);
739
 
740
- if ($orderby != 'relevance')
741
- relevanssi_object_sort($hits, $orderby, $order);
 
 
 
742
 
743
  $return = array('hits' => $hits, 'body_matches' => $body_matches, 'title_matches' => $title_matches,
744
  'tag_matches' => $tag_matches, 'category_matches' => $category_matches, 'taxonomy_matches' => $taxonomy_matches,
@@ -1210,7 +1219,7 @@ function relevanssi_do_query(&$query) {
1210
  }
1211
 
1212
  //Added by OdditY - Highlight Result Title too ->
1213
- if("on" == get_option('relevanssi_hilite_title')){
1214
  if (function_exists('qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage')) {
1215
  $post->post_highlighted_title = strip_tags(qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage($post->post_title));
1216
  }
729
  if (empty($orderby)) $orderby = $default_order;
730
  // the sorting function checks for non-existing keys, cannot whitelist here
731
 
732
+ if (is_array($orderby)) {
733
+ $orderby = apply_filters('relevanssi_orderby', $orderby);
734
+
735
+ relevanssi_object_sort($hits, $orderby);
736
+ }
737
+ else {
738
+ if (empty($order)) $order = 'desc';
739
+ $order = strtolower($order);
740
+ $order_accepted_values = array('asc', 'desc');
741
+ if (!in_array($order, $order_accepted_values)) $order = 'desc';
742
 
743
+ $orderby = apply_filters('relevanssi_orderby', $orderby);
744
+ $order = apply_filters('relevanssi_order', $order);
745
 
746
+ if ($orderby != 'relevance') {
747
+ $orderby_array = array($orderby => $order);
748
+ relevanssi_object_sort($hits, $orderby_array);
749
+ }
750
+ }
751
 
752
  $return = array('hits' => $hits, 'body_matches' => $body_matches, 'title_matches' => $title_matches,
753
  'tag_matches' => $tag_matches, 'category_matches' => $category_matches, 'taxonomy_matches' => $taxonomy_matches,
1219
  }
1220
 
1221
  //Added by OdditY - Highlight Result Title too ->
1222
+ if("on" == get_option('relevanssi_hilite_title') && empty($fields)){
1223
  if (function_exists('qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage')) {
1224
  $post->post_highlighted_title = strip_tags(qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage($post->post_title));
1225
  }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: search, relevance, better search
5
  Requires at least: 4.0
6
  Tested up to: 4.9
7
  Requires PHP: 5.6
8
- Stable tag: 3.6.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -269,6 +269,14 @@ Each document database is full of useless words. All the little words that appea
269
 
270
  == Changelog ==
271
 
 
 
 
 
 
 
 
 
272
  = 3.6.1 =
273
  * SECURITY: This version fixes a SQL injection vulnerability, where a site admin could theoretically inject SQL code into Relevanssi search queries. Doing this required access to Relevanssi settings page and in my tests, I couldn't do any damage, just break the Relevanssi search, but in any case, this vulnerability is now fixed.
274
  * Search and Filter shortcode is added to the blacklist.
5
  Requires at least: 4.0
6
  Tested up to: 4.9
7
  Requires PHP: 5.6
8
+ Stable tag: 3.6.2
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
269
 
270
  == Changelog ==
271
 
272
+ = 3.6.2 =
273
+ * Simple Membership plugin is now supported automatically to restrict access to posts.
274
+ * Relevanssi can now handle orderby parameter in array format.
275
+ * Relevanssi now blocks Easy Digital Downloads shortcodes when indexing to improve compatibility with EDD.
276
+ * When using `fields` to only fetch post IDs, Relevanssi doesn't try to highlight post titles.
277
+ * New action: `relevanssi_update_options` lets you adjust Relevanssi options immediately after the defaults are set.
278
+ * Remove notices about duplicated database columns when installing the plugin.
279
+
280
  = 3.6.1 =
281
  * SECURITY: This version fixes a SQL injection vulnerability, where a site admin could theoretically inject SQL code into Relevanssi search queries. Doing this required access to Relevanssi settings page and in my tests, I couldn't do any damage, just break the Relevanssi search, but in any case, this vulnerability is now fixed.
282
  * Search and Filter shortcode is added to the blacklist.
relevanssi.php CHANGED
@@ -3,7 +3,7 @@
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.6.1
7
  Author: Mikko Saari
8
  Author URI: http://www.mikkosaari.fi/
9
  */
@@ -287,6 +287,8 @@ function _relevanssi_install() {
287
  add_option('relevanssi_index_post_types', $relevanssi_variables['post_type_index_defaults']);
288
  add_option('relevanssi_index_taxonomies_list', array());
289
 
 
 
290
  relevanssi_create_database_tables($relevanssi_variables['database_version']);
291
  }
292
 
@@ -359,19 +361,7 @@ EOH;
359
 
360
  function relevanssi_sidebar() {
361
  $tweet = 'http://twitter.com/home?status=' . urlencode("I'm using Relevanssi, a better search for WordPress. http://wordpress.org/extend/plugins/relevanssi/ #relevanssi #wordpress");
362
- if (function_exists("plugins_url")) {
363
- global $wp_version;
364
- if (version_compare($wp_version, '2.8dev', '>' )) {
365
- $facebooklogo = plugins_url('facebooklogo.jpg', __FILE__);
366
- }
367
- else {
368
- $facebooklogo = plugins_url('relevanssi/facebooklogo.jpg');
369
- }
370
- }
371
- else {
372
- // We can't check, so let's assume something sensible
373
- $facebooklogo = '/wp-content/plugins/relevanssi/facebooklogo.jpg';
374
- }
375
 
376
  echo <<<EOH
377
  <div class="postbox-container" style="width:20%; margin-top: 35px; margin-left: 15px;">
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.6.2
7
  Author: Mikko Saari
8
  Author URI: http://www.mikkosaari.fi/
9
  */
287
  add_option('relevanssi_index_post_types', $relevanssi_variables['post_type_index_defaults']);
288
  add_option('relevanssi_index_taxonomies_list', array());
289
 
290
+ do_action('relevanssi_update_options');
291
+
292
  relevanssi_create_database_tables($relevanssi_variables['database_version']);
293
  }
294
 
361
 
362
  function relevanssi_sidebar() {
363
  $tweet = 'http://twitter.com/home?status=' . urlencode("I'm using Relevanssi, a better search for WordPress. http://wordpress.org/extend/plugins/relevanssi/ #relevanssi #wordpress");
364
+ $facebooklogo = plugins_url('facebooklogo.jpg', __FILE__);
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
  echo <<<EOH
367
  <div class="postbox-container" style="width:20%; margin-top: 35px; margin-left: 15px;">