Relevanssi – A Better Search - Version 4.1.4

Version Description

  • EXISTS and NOT EXISTS didnt work for taxonomy terms in searches.
  • WPML post type handling has been improved. If post type allows fallback for default language, Relevanssi will support that.
  • Relevanssi now reminds you to set up automatic trimming for the logs. Its a really good idea, otherwise the logs will become bloated, which will hurt search performance.
  • The Groups posts filter is only applied to public posts to avoid drafts being shown to people who shouldnt see them.
  • The posts_per_page query variable didnt work; its now added to the introduced query variables so that it works.
  • Relevanssi wont log empty queries anymore.
  • The default tax query relation was switched from OR to AND to match the WP_Query default behaviour.
  • When used with WP 5.1, Relevanssi will now use wp_insert_site instead of the now-deprecated wpmu_new_blog.
  • Multisite blog creation is handled better in WP 5.1+.
  • Relevanssi now supports Restrict Content Pro permissions.
Download this release

Release Info

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

Code changes from version 4.1.3 to 4.1.4

lib/common.php CHANGED
@@ -175,8 +175,8 @@ function relevanssi_default_post_ok( $post_ok, $post_id ) {
175
  }
176
  }
177
  }
178
- if ( defined( 'GROUPS_CORE_VERSION' ) ) {
179
- // Groups.
180
  $current_user = wp_get_current_user();
181
  $post_ok = Groups_Post_Access::user_can_read_post( $post_id, $current_user->ID );
182
  }
@@ -197,6 +197,10 @@ function relevanssi_default_post_ok( $post_ok, $post_id ) {
197
  // WP JV Post Reading Groups.
198
  $post_ok = wp_jv_prg_user_can_see_a_post( get_current_user_id(), $post_id );
199
  }
 
 
 
 
200
  /**
201
  * Filters statuses allowed in admin searches.
202
  *
@@ -894,7 +898,7 @@ function relevanssi_the_tags( $before = null, $separator = ', ', $after = '', $e
894
  * @param string $after What is printed after the tags, default ''.
895
  */
896
  function relevanssi_get_the_tags( $before = null, $separator = ', ', $after = '' ) {
897
- return relevanssi_the_tags( $before, $sep, $after, false );
898
  }
899
 
900
  /**
175
  }
176
  }
177
  }
178
+ if ( defined( 'GROUPS_CORE_VERSION' ) && 'publish' === $status ) {
179
+ // Groups. Only apply to published posts, don't apply to drafts.
180
  $current_user = wp_get_current_user();
181
  $post_ok = Groups_Post_Access::user_can_read_post( $post_id, $current_user->ID );
182
  }
197
  // WP JV Post Reading Groups.
198
  $post_ok = wp_jv_prg_user_can_see_a_post( get_current_user_id(), $post_id );
199
  }
200
+ if ( function_exists( 'rcp_user_can_access' ) ) {
201
+ // Restrict Content Pro.
202
+ $post_ok = rcp_user_can_access( get_current_user_id(), $post_id );
203
+ }
204
  /**
205
  * Filters statuses allowed in admin searches.
206
  *
898
  * @param string $after What is printed after the tags, default ''.
899
  */
900
  function relevanssi_get_the_tags( $before = null, $separator = ', ', $after = '' ) {
901
+ return relevanssi_the_tags( $before, $separator, $after, false );
902
  }
903
 
904
  /**
lib/compatibility/gutenberg.php CHANGED
@@ -10,6 +10,12 @@
10
  * @see https://www.relevanssi.com/
11
  */
12
 
 
 
 
 
 
 
13
  add_filter( 'relevanssi_post_content', 'relevanssi_gutenberg_block_rendering', 10, 2 );
14
 
15
  /**
10
  * @see https://www.relevanssi.com/
11
  */
12
 
13
+ if ( RELEVANSSI_PREMIUM ) {
14
+ // Gutenberg causes duplicate postmeta to appear in posts. This will remove the
15
+ // extras when a post is saved.
16
+ add_action( 'save_post', 'relevanssi_remove_duplicate_postmeta', 100 );
17
+ }
18
+
19
  add_filter( 'relevanssi_post_content', 'relevanssi_gutenberg_block_rendering', 10, 2 );
20
 
21
  /**
lib/compatibility/wpml.php CHANGED
@@ -28,6 +28,8 @@ add_filter( 'relevanssi_hits_filter', 'relevanssi_wpml_filter' );
28
  function relevanssi_wpml_filter( $data ) {
29
  $filter_enabled = get_option( 'relevanssi_wpml_only_current' );
30
  if ( 'on' === $filter_enabled ) {
 
 
31
  $current_blog_language = get_bloginfo( 'language' );
32
  $filtered_hits = array();
33
  foreach ( $data[0] as $hit ) {
@@ -52,9 +54,14 @@ function relevanssi_wpml_filter( $data ) {
52
  // Check if WPML is used.
53
  if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) ) {
54
  if ( $sitepress->is_translated_post_type( $hit->post_type ) ) {
55
- $id = apply_filters( 'wpml_object_id', $hit->ID, $hit->post_type, false );
 
 
 
 
 
56
  // This is a post in a translated post type.
57
- if ( intval( $hit->ID ) === $id ) {
58
  // The post exists in the current language, and can be included.
59
  $filtered_hits[] = $hit;
60
  }
@@ -83,22 +90,3 @@ function relevanssi_wpml_filter( $data ) {
83
 
84
  return $data;
85
  }
86
-
87
- add_action( 'wp_ajax_relevanssi_index_posts', 'relevanssi_wpml_remove_filters', 5 );
88
- add_action( 'wp_ajax_relevanssi_index_taxonomies', 'relevanssi_wpml_remove_filters', 5 );
89
-
90
- /**
91
- * Removes WPML filters from get_term().
92
- *
93
- * Relevanssi indexes WooCommerce terms in current language. Indexed term should
94
- * have translated entry. Term title is filtered by WPML and value in current
95
- * language is always returned. Removing this filter fixes the problem.
96
- *
97
- * @author Srdjan Jocić
98
- */
99
- function relevanssi_wpml_remove_filters() {
100
- if ( did_action( 'wpml_loaded' ) ) {
101
- global $sitepress;
102
- remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
103
- }
104
- }
28
  function relevanssi_wpml_filter( $data ) {
29
  $filter_enabled = get_option( 'relevanssi_wpml_only_current' );
30
  if ( 'on' === $filter_enabled ) {
31
+ $wpml_post_type_setting = apply_filters( 'wpml_setting', false, 'custom_posts_sync_option' );
32
+
33
  $current_blog_language = get_bloginfo( 'language' );
34
  $filtered_hits = array();
35
  foreach ( $data[0] as $hit ) {
54
  // Check if WPML is used.
55
  if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_is_translated_post_type' ) ) {
56
  if ( $sitepress->is_translated_post_type( $hit->post_type ) ) {
57
+
58
+ $fallback_to_default = false;
59
+ if ( isset( $wpml_post_type_setting[ $hit->post_type ] ) && '2' === $wpml_post_type_setting[ $hit->post_type ] ) {
60
+ $fallback_to_default = true;
61
+ }
62
+ $id = apply_filters( 'wpml_object_id', $hit->ID, $hit->post_type, $fallback_to_default );
63
  // This is a post in a translated post type.
64
+ if ( intval( $hit->ID ) === intval( $id ) ) {
65
  // The post exists in the current language, and can be included.
66
  $filtered_hits[] = $hit;
67
  }
90
 
91
  return $data;
92
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/excerpts-highlights.php CHANGED
@@ -379,9 +379,10 @@ function relevanssi_highlight_in_docs( $content ) {
379
  * want to override the settings, 'pre_option_relevanssi_highlight' filter hook
380
  * is your friend).
381
  *
382
- * @param string $content The content to highlight.
383
- * @param string $query The search query.
384
- * @param boolean $in_docs Are we highlighting post content? Default false.
 
385
  *
386
  * @return string The $content with highlighting.
387
  */
379
  * want to override the settings, 'pre_option_relevanssi_highlight' filter hook
380
  * is your friend).
381
  *
382
+ * @param string $content The content to highlight.
383
+ * @param string|array $query The search query (should be a string, can sometimes
384
+ * be an array).
385
+ * @param boolean $in_docs Are we highlighting post content? Default false.
386
  *
387
  * @return string The $content with highlighting.
388
  */
lib/init.php CHANGED
@@ -230,6 +230,7 @@ function relevanssi_query_vars( $qv ) {
230
  $qv[] = 'post_types';
231
  $qv[] = 'by_date';
232
  $qv[] = 'highlight';
 
233
 
234
  return $qv;
235
  }
230
  $qv[] = 'post_types';
231
  $qv[] = 'by_date';
232
  $qv[] = 'highlight';
233
+ $qv[] = 'posts_per_page';
234
 
235
  return $qv;
236
  }
lib/install.php CHANGED
@@ -11,13 +11,18 @@
11
  /**
12
  * Installs Relevanssi on a new plugin if Relevanssi is network active.
13
  *
14
- * Hooks on to 'wpmu_new_blog' action hook and runs '_relevanssi_install' on the
15
- * new blog.
16
  *
17
- * @param int $blog_id The blog ID.
 
18
  */
19
- function relevanssi_new_blog( $blog_id ) {
20
- global $wpdb;
 
 
 
 
21
 
22
  if ( is_plugin_active_for_network( 'relevanssi-premium/relevanssi.php' ) || is_plugin_active_for_network( 'relevanssi/relevanssi.php' ) ) {
23
  switch_to_blog( $blog_id );
11
  /**
12
  * Installs Relevanssi on a new plugin if Relevanssi is network active.
13
  *
14
+ * Hooks on to 'wpmu_new_blog' and 'wp_insert_site' action hooks and runs
15
+ * '_relevanssi_install' on the new blog.
16
  *
17
+ * @param int|object $blog Either the blog ID (if 'wpmu_new_blog') or new site
18
+ * object (if 'wp_insert_site').
19
  */
20
+ function relevanssi_new_blog( $blog ) {
21
+ if ( is_int( $blog ) ) {
22
+ $blog_id = $blog;
23
+ } else {
24
+ $blog_id = $blog->id;
25
+ }
26
 
27
  if ( is_plugin_active_for_network( 'relevanssi-premium/relevanssi.php' ) || is_plugin_active_for_network( 'relevanssi/relevanssi.php' ) ) {
28
  switch_to_blog( $blog_id );
lib/log.php CHANGED
@@ -20,6 +20,10 @@
20
  * @param int $hits The number of hits found.
21
  */
22
  function relevanssi_update_log( $query, $hits ) {
 
 
 
 
23
  // Bot filter, by Justin_K.
24
  // See: http://wordpress.org/support/topic/bot-logging-problem-w-tested-solution.
25
  $user_agent = '';
20
  * @param int $hits The number of hits found.
21
  */
22
  function relevanssi_update_log( $query, $hits ) {
23
+ if ( empty( $query ) ) {
24
+ return;
25
+ }
26
+
27
  // Bot filter, by Justin_K.
28
  // See: http://wordpress.org/support/topic/bot-logging-problem-w-tested-solution.
29
  $user_agent = '';
lib/search.php CHANGED
@@ -143,7 +143,7 @@ function relevanssi_search( $args ) {
143
  $query_restrictions = '';
144
 
145
  if ( ! isset( $tax_query_relation ) ) {
146
- $tax_query_relation = 'or';
147
  }
148
  $tax_query_relation = relevanssi_strtolower( $tax_query_relation );
149
  $term_tax_id = array();
@@ -154,7 +154,7 @@ function relevanssi_search( $args ) {
154
  if ( is_array( $tax_query ) ) {
155
  $is_sub_row = false;
156
  foreach ( $tax_query as $row ) {
157
- if ( isset( $row['terms'] ) ) {
158
  list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids ) =
159
  relevanssi_process_tax_query_row( $row, $is_sub_row, $tax_query_relation, $query_restrictions, $tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids );
160
  } else {
@@ -630,6 +630,7 @@ function relevanssi_search( $args ) {
630
  $include_these_posts = array();
631
  $include_these_items = array();
632
  $df_counts = array();
 
633
 
634
  do {
635
  foreach ( $terms as $term ) {
@@ -1925,8 +1926,17 @@ function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation,
1925
  $local_term_tax_ids = array();
1926
  $local_not_term_tax_ids = array();
1927
  $local_and_term_tax_ids = array();
 
 
 
 
 
 
1928
 
1929
  $using_term_tax_id = false;
 
 
 
1930
  if ( ! isset( $row['field'] ) ) {
1931
  $row['field'] = 'term_id'; // In case 'field' is not set, go with the WP default of 'term_id'.
1932
  }
@@ -1988,7 +1998,7 @@ function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation,
1988
  $term_id = array();
1989
  foreach ( $name as $t_name ) {
1990
  $term = get_term_by( 'name', $t_name, $row['taxonomy'] );
1991
- if ( ! $term && is_numeric( $t_names ) ) {
1992
  $numeric_names[] = "'$t_name'";
1993
  } else {
1994
  if ( isset( $term->term_id ) ) {
@@ -2070,7 +2080,7 @@ function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation,
2070
  }
2071
  }
2072
 
2073
- if ( ! isset( $row['include_children'] ) || true === $row['include_children'] ) {
2074
  if ( ! $using_term_tax_id && isset( $term_id ) ) {
2075
  if ( ! is_array( $term_id ) ) {
2076
  $term_id = array( $term_id );
@@ -2194,6 +2204,16 @@ function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation,
2194
  $and_term_tax_ids = array_merge( $and_term_tax_ids, $local_and_term_tax_ids );
2195
  }
2196
 
 
 
 
 
 
 
 
 
 
 
2197
  return array( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids );
2198
  }
2199
 
143
  $query_restrictions = '';
144
 
145
  if ( ! isset( $tax_query_relation ) ) {
146
+ $tax_query_relation = 'and';
147
  }
148
  $tax_query_relation = relevanssi_strtolower( $tax_query_relation );
149
  $term_tax_id = array();
154
  if ( is_array( $tax_query ) ) {
155
  $is_sub_row = false;
156
  foreach ( $tax_query as $row ) {
157
+ if ( isset( $row['terms'] ) || ( isset( $row['operator'] ) && ( 'not exists' === strtolower( $row['operator'] ) || 'exists' === strtolower( $row['operator'] ) ) ) ) {
158
  list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids ) =
159
  relevanssi_process_tax_query_row( $row, $is_sub_row, $tax_query_relation, $query_restrictions, $tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids );
160
  } else {
630
  $include_these_posts = array();
631
  $include_these_items = array();
632
  $df_counts = array();
633
+ $doc_weight = array();
634
 
635
  do {
636
  foreach ( $terms as $term ) {
1926
  $local_term_tax_ids = array();
1927
  $local_not_term_tax_ids = array();
1928
  $local_and_term_tax_ids = array();
1929
+ $term_tax_id = array();
1930
+
1931
+ $exists_query = false;
1932
+ if ( isset( $row['operator'] ) && ( 'exists' === strtolower( $row['operator'] ) || 'not exists' === strtolower( $row['operator'] ) ) ) {
1933
+ $exists_query = true;
1934
+ }
1935
 
1936
  $using_term_tax_id = false;
1937
+ if ( $exists_query ) {
1938
+ $row['field'] = 'exists';
1939
+ }
1940
  if ( ! isset( $row['field'] ) ) {
1941
  $row['field'] = 'term_id'; // In case 'field' is not set, go with the WP default of 'term_id'.
1942
  }
1998
  $term_id = array();
1999
  foreach ( $name as $t_name ) {
2000
  $term = get_term_by( 'name', $t_name, $row['taxonomy'] );
2001
+ if ( ! $term && is_numeric( $t_name ) ) {
2002
  $numeric_names[] = "'$t_name'";
2003
  } else {
2004
  if ( isset( $term->term_id ) ) {
2080
  }
2081
  }
2082
 
2083
+ if ( ! $exists_query && ( ! isset( $row['include_children'] ) || true === $row['include_children'] ) ) {
2084
  if ( ! $using_term_tax_id && isset( $term_id ) ) {
2085
  if ( ! is_array( $term_id ) ) {
2086
  $term_id = array( $term_id );
2204
  $and_term_tax_ids = array_merge( $and_term_tax_ids, $local_and_term_tax_ids );
2205
  }
2206
 
2207
+ if ( $exists_query ) {
2208
+ $taxonomy = $row['taxonomy'];
2209
+ $operator = 'IN';
2210
+ if ( 'not exists' === strtolower( $row['operator'] ) ) {
2211
+ $operator = 'NOT IN';
2212
+ }
2213
+ $query_restrictions .= " AND relevanssi.doc $operator (SELECT DISTINCT(tr.object_id) FROM $wpdb->term_relationships AS tr,
2214
+ $wpdb->term_taxonomy AS tt WHERE tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = '$taxonomy')";
2215
+ }
2216
+
2217
  return array( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids );
2218
  }
2219
 
lib/tabs/logging-tab.php CHANGED
@@ -85,8 +85,18 @@ function relevanssi_logging_tab() {
85
  <td>
86
  <input type='number' name='relevanssi_trim_logs' id='relevanssi_trim_logs' value='<?php echo esc_attr( $trim_logs ); ?>' />
87
  <?php esc_html_e( 'How many days of logs to keep in the database.', 'relevanssi' ); ?>
88
- <?php // Translators: %d is the setting for no trim (probably 0). ?>
89
- <p class="description"><?php printf( esc_html__( ' Set to %d for no trimming.', 'relevanssi' ), 0 ); ?></p>
 
 
 
 
 
 
 
 
 
 
90
  </td>
91
  </tr>
92
 
85
  <td>
86
  <input type='number' name='relevanssi_trim_logs' id='relevanssi_trim_logs' value='<?php echo esc_attr( $trim_logs ); ?>' />
87
  <?php esc_html_e( 'How many days of logs to keep in the database.', 'relevanssi' ); ?>
88
+ <?php
89
+ if ( '0' === $trim_logs ) {
90
+ echo '<p class="description">';
91
+ esc_html_e( "Big log database table will eventually start to slow down the search, so it's a good idea to use some level of automatic log trimming.", 'relevanssi' );
92
+ echo '</p>';
93
+ } else {
94
+ echo '<p class="description">';
95
+ // Translators: %d is the setting for no trim (probably 0).
96
+ printf( esc_html__( ' Set to %d for no trimming.', 'relevanssi' ), 0 );
97
+ echo '</p>';
98
+ }
99
+ ?>
100
  </td>
101
  </tr>
102
 
readme.txt CHANGED
@@ -2,10 +2,10 @@
2
  Contributors: msaari
3
  Donate link: https://www.relevanssi.com/buy-premium/
4
  Tags: search, relevance, better search
5
- Requires at least: 4.0
6
- Tested up to: 5.0.3
7
  Requires PHP: 5.6
8
- Stable tag: 4.1.3
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -53,7 +53,6 @@ Do note that using Relevanssi may require large amounts (hundreds of megabytes)
53
  * Assign weights to any post types and taxonomies.
54
  * Assign extra weight to new posts.
55
  * Let the user choose between AND and OR searches, use + and - operator (AND and NOT).
56
- * Highlighting search terms for visitors from external search engines.
57
  * Export and import settings.
58
  * [WP CLI commands](https://www.relevanssi.com/user-manual/wp-cli/).
59
  * Related posts.
@@ -130,6 +129,18 @@ Each document database is full of useless words. All the little words that appea
130
  * John Calahan for extensive 4.0 beta testing.
131
 
132
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
133
  = 4.1.3 =
134
  * Improvements to meta key sorting.
135
  * Relevanssi settings page won't let you exclude categories you have restricted the search to.
@@ -182,6 +193,9 @@ Each document database is full of useless words. All the little words that appea
182
  * WP Search Suggest compatibility added.
183
 
184
  == Upgrade notice ==
 
 
 
185
  = 4.1.3 =
186
  * Small improvements here and there.
187
 
2
  Contributors: msaari
3
  Donate link: https://www.relevanssi.com/buy-premium/
4
  Tags: search, relevance, better search
5
+ Requires at least: 4.8.3
6
+ Tested up to: 5.2
7
  Requires PHP: 5.6
8
+ Stable tag: 4.1.4
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
53
  * Assign weights to any post types and taxonomies.
54
  * Assign extra weight to new posts.
55
  * Let the user choose between AND and OR searches, use + and - operator (AND and NOT).
 
56
  * Export and import settings.
57
  * [WP CLI commands](https://www.relevanssi.com/user-manual/wp-cli/).
58
  * Related posts.
129
  * John Calahan for extensive 4.0 beta testing.
130
 
131
  == Changelog ==
132
+ = 4.1.4 =
133
+ * `EXISTS` and `NOT EXISTS` didn’t work for taxonomy terms in searches.
134
+ * WPML post type handling has been improved. If post type allows fallback for default language, Relevanssi will support that.
135
+ * Relevanssi now reminds you to set up automatic trimming for the logs. It’s a really good idea, otherwise the logs will become bloated, which will hurt search performance.
136
+ * The Groups posts filter is only applied to public posts to avoid drafts being shown to people who shouldn’t see them.
137
+ * The `posts_per_page` query variable didn’t work; it’s now added to the introduced query variables so that it works.
138
+ * Relevanssi won’t log empty queries anymore.
139
+ * The default tax query relation was switched from `OR` to `AND` to match the WP_Query default behaviour.
140
+ * When used with WP 5.1, Relevanssi will now use `wp_insert_site` instead of the now-deprecated `wpmu_new_blog`.
141
+ * Multisite blog creation is handled better in WP 5.1+.
142
+ * Relevanssi now supports Restrict Content Pro permissions.
143
+
144
  = 4.1.3 =
145
  * Improvements to meta key sorting.
146
  * Relevanssi settings page won't let you exclude categories you have restricted the search to.
193
  * WP Search Suggest compatibility added.
194
 
195
  == Upgrade notice ==
196
+ = 4.1.4 =
197
+ * Restrict Content Pro support, bug fixes and small improvements.
198
+
199
  = 4.1.3 =
200
  * Small improvements here and there.
201
 
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.1.3
17
  * Author: Mikko Saari
18
  * Author URI: http://www.mikkosaari.fi/
19
  * Text Domain: relevanssi
@@ -69,4 +69,4 @@ require_once 'lib/search.php';
69
  require_once 'lib/excerpts-highlights.php';
70
  require_once 'lib/shortcodes.php';
71
  require_once 'lib/common.php';
72
- require_once 'lib/admin-ajax.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.1.4
17
  * Author: Mikko Saari
18
  * Author URI: http://www.mikkosaari.fi/
19
  * Text Domain: relevanssi
69
  require_once 'lib/excerpts-highlights.php';
70
  require_once 'lib/shortcodes.php';
71
  require_once 'lib/common.php';
72
+ require_once 'lib/admin-ajax.php';