Relevanssi – A Better Search - Version 4.3.1

Version Description

  • Adding a missing file.
Download this release

Release Info

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

Code changes from version 4.2.0 to 4.3.1

changelog.txt CHANGED
@@ -1,3 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 4.0.11 =
2
  * Home page links were getting the highlight parameter even though they shouldn't. This has been fixed.
3
  * Added support for WP JV Post Reading Groups.
1
+ = 4.1.4 =
2
+ * `EXISTS` and `NOT EXISTS` didn’t work for taxonomy terms in searches.
3
+ * WPML post type handling has been improved. If post type allows fallback for default language, Relevanssi will support that.
4
+ * 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.
5
+ * The Groups posts filter is only applied to public posts to avoid drafts being shown to people who shouldn’t see them.
6
+ * The `posts_per_page` query variable didn’t work; it’s now added to the introduced query variables so that it works.
7
+ * Relevanssi won’t log empty queries anymore.
8
+ * The default tax query relation was switched from `OR` to `AND` to match the WP_Query default behaviour.
9
+ * When used with WP 5.1, Relevanssi will now use `wp_insert_site` instead of the now-deprecated `wpmu_new_blog`.
10
+ * Multisite blog creation is handled better in WP 5.1+.
11
+ * Relevanssi now supports Restrict Content Pro permissions.
12
+
13
+ = 4.1.3 =
14
+ * Improvements to meta key sorting.
15
+ * Relevanssi settings page won't let you exclude categories you have restricted the search to.
16
+ * Members plugin compatibility has been improved: it's only used if the 'content permissions' feature has been enabled.
17
+ * The excerpt settings page was a bit buggy.
18
+ * Slimstat analytics is now added to the blocked shortcodes list.
19
+ * New filter: `relevanssi_search_form` works exactly like `get_search_form`, but only applies to the Relevanssi shortcode search forms.
20
+ * New JetPack taxonomies and post types have been added to the block list so they won't appear in Relevanssi settings.
21
+
22
+ = 4.1.2 =
23
+ * Choosing "CSS Style" for highlighting was not possible. That is now fixed.
24
+ * Gutenberg reusable block indexing was fatally broken with the latest Gutenberg version. That has been updated.
25
+ * Relevanssi now by default respects the WooCommerce "exclude from search" setting.
26
+ * `post__not_in` still didn't work properly, it does now.
27
+ * New filter: `relevanssi_comparison_order` can be used to define the sorting order when sorting the results by post type.
28
+ * "Did you mean" process included a very slow query. It is now cached, leading in some cases to massive performance improvements (we're talking about several seconds here).
29
+ * Highlights inside `code` and similar blocks are handled better now.
30
+
31
+ = 4.1.1.2 =
32
+ * Fixes the broken User searches page.
33
+
34
+ = 4.1.1.1 =
35
+ * Adding the missing Gutenberg compatibility file.
36
+
37
+ = 4.1.1 =
38
+ * Relevanssi can now index Gutenberg reusable blocks. (This functionality broke once already before release, so that can happen, since Gutenberg is still in very active development.)
39
+ * The `post__in` and `post__not_in` parameters didn't work, and are now fixed. `post_parent__in` and `post_parent__not_in` are also improved.
40
+ * You can use named meta queries for sorting posts. Meta query sorting is improved in other ways as well.
41
+ * Log export didn't work properly.
42
+ * Adding stopwords from the common word list has been fixed.
43
+ * The `relevanssi_get_words_having` filter hook is now also applied to the free version Did you mean queries.
44
+ * New filters: `relevanssi_1day` and `relevanssi_7days` can be used to adjust the number of days for log displays, so instead of 1, 7 and 30 days you can have anything you want.
45
+
46
+ = 4.1.0.1 =
47
+ * Actually working admin search.
48
+
49
+ = 4.1 =
50
+ * New feature: You can now export the search log as a CSV file.
51
+ * New feature: Admin Search page allows you to perform searches in WP admin using Relevanssi.
52
+ * New filter: `relevanssi_admin_search_capability` can be used to adjust who sees the admin search page.
53
+ * New filter: `relevanssi_entities_inside_pre` and `relevanssi_entities_inside_code` adjust how HTML entities are handled inside `pre` and `code` tags.
54
+ * Numeric meta values (`meta_value_num`) are now sorted as numbers and not strings.
55
+ * Pinned posts have `$post->relevanssi_pinned` set to 1 for debugging purposes, but you can also use this for styling the posts in the search results templates.
56
+ * The Did you mean feature has been toned down a bit, to make the suggestions slightly less weird in some cases.
57
+ * Post parent parameters now accept 0 as a value, making it easier to search for children of any post or posts without a parent.
58
+ * Polylang compatibility has been improved.
59
+ * Phrases with apostrophes inside work better.
60
+ * The `relevanssi_excerpt` filter hook got a second parameter that holds the post ID.
61
+ * Custom field sorting actually works now.
62
+ * WP Search Suggest compatibility added.
63
+
64
  = 4.0.11 =
65
  * Home page links were getting the highlight parameter even though they shouldn't. This has been fixed.
66
  * Added support for WP JV Post Reading Groups.
lib/admin-ajax.php CHANGED
@@ -85,10 +85,16 @@ function relevanssi_index_posts_ajax_wrapper() {
85
 
86
  $response['feedback'] = sprintf(
87
  // translators: Number of posts indexed on this go, total number of posts indexed so far, number of posts processed on this go, total number of posts to process.
88
- _n( 'Indexed %1$d post (total %2$d), processed %3$d / %4$d.', 'Indexed %1$d posts (total %2$d), processed %3$d / %4$d.',
89
- $indexing_response['indexed'], 'relevanssi'
 
 
 
90
  ),
91
- $indexing_response['indexed'], $completed, $processed, $total
 
 
 
92
  ) . "\n";
93
  $response['offset'] = $offset;
94
 
@@ -124,10 +130,12 @@ function relevanssi_count_missing_posts_ajax_wrapper() {
124
  * AJAX wrapper for get_categories().
125
  */
126
  function relevanssi_list_categories() {
127
- $categories = get_categories( array(
128
- 'taxonomy' => 'category',
129
- 'hide_empty' => false,
130
- ) );
 
 
131
  echo wp_json_encode( $categories );
132
  wp_die();
133
  }
@@ -152,6 +160,10 @@ function relevanssi_admin_search() {
152
  $args['posts_per_page'] = $posts_per_page;
153
  }
154
  }
 
 
 
 
155
  if ( isset( $_POST['offset'] ) ) {
156
  $offset = intval( $_POST['offset'] );
157
  if ( $offset > 0 ) {
@@ -165,6 +177,7 @@ function relevanssi_admin_search() {
165
  $query = new WP_Query();
166
  $query->parse_query( $args );
167
  $query->set( 'relevanssi_admin_search', true );
 
168
  relevanssi_do_query( $query );
169
 
170
  $results = relevanssi_admin_search_debugging_info( $query );
@@ -197,15 +210,17 @@ function relevanssi_admin_search() {
197
  */
198
  function relevanssi_admin_search_format_posts( $posts, $total, $offset, $query ) {
199
  $result = '<h3>' . __( 'Results', 'relevanssi' ) . '</h3>';
 
 
200
  // Translators: %1$d is the total number of posts found, %2$d is the current search result count, %3$d is the offset.
201
- $result .= '<p>' . sprintf( __( 'Found a total of %1$d posts, showing %2$d posts from offset %3$s.', 'relevanssi' ), $total, count( $posts ), '<span id="offset">' . $offset . '</span>' ) . '</p>';
202
  if ( $offset > 0 ) {
203
  $result .= sprintf( '<button type="button" id="prev_page">%s</button>', __( 'Previous page', 'relevanssi' ) );
204
  }
205
  if ( count( $posts ) + $offset < $total ) {
206
  $result .= sprintf( '<button type="button" id="next_page">%s</button>', __( 'Next page', 'relevanssi' ) );
207
  }
208
- $result .= '<ol>';
209
 
210
  $score_label = __( 'Score:', 'relevanssi' );
211
 
@@ -229,8 +244,12 @@ function relevanssi_admin_search_format_posts( $posts, $total, $offset, $query )
229
  $edit_url = get_edit_term_link( $post->term_id, $post->post_type );
230
  }
231
  }
232
- $view_link = sprintf( '<a href="%1$s">%2$s %3$s</a>', $permalink, __( 'View', 'relevanssi' ), $post_type );
233
- $edit_link = sprintf( '<a href="%1$s">%2$s %3$s</a>', $edit_url, __( 'Edit', 'relevanssi' ), $post_type );
 
 
 
 
234
  $pinning_buttons = '';
235
  $pinned = '';
236
 
@@ -240,7 +259,7 @@ function relevanssi_admin_search_format_posts( $posts, $total, $offset, $query )
240
  }
241
 
242
  $post_element = <<<EOH
243
- <li>$blog_name <strong>$post->post_title</strong> ($view_link) ($edit_link) $pinning_buttons <br />
244
  $post->post_excerpt<br />
245
  $score_label $post->relevance_score $pinned</li>
246
  EOH;
@@ -273,20 +292,44 @@ EOH;
273
  * @since 2.2.0
274
  */
275
  function relevanssi_admin_search_debugging_info( $query ) {
276
- $result = '<h3>' . __( 'Query variables', 'relevanssi' ) . '</h3>';
 
277
  $result .= '<ul style="list-style: disc; margin-left: 1.5em">';
278
  foreach ( $query->query_vars as $key => $value ) {
279
- if ( is_array( $value ) ) {
280
- $value = relevanssi_flatten_array( $value );
281
- }
282
- if ( empty( $value ) ) {
283
- continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  }
285
- $result .= "<li>$key: $value</li>";
286
  }
287
  if ( ! empty( $query->tax_query ) ) {
288
- $result .= '<li><strong>tax_query</strong>:<ul style="list-style: disc; margin-left: 1.5em">';
289
  foreach ( $query->tax_query as $tax_query ) {
 
 
 
290
  foreach ( $tax_query as $key => $value ) {
291
  if ( is_array( $value ) ) {
292
  $value = relevanssi_flatten_array( $value );
@@ -336,6 +379,7 @@ function relevanssi_admin_search_debugging_info( $query ) {
336
  }
337
  }
338
  $result .= '</div>';
 
339
 
340
  return $result;
341
  }
85
 
86
  $response['feedback'] = sprintf(
87
  // translators: Number of posts indexed on this go, total number of posts indexed so far, number of posts processed on this go, total number of posts to process.
88
+ _n(
89
+ 'Indexed %1$d post (total %2$d), processed %3$d / %4$d.',
90
+ 'Indexed %1$d posts (total %2$d), processed %3$d / %4$d.',
91
+ $indexing_response['indexed'],
92
+ 'relevanssi'
93
  ),
94
+ $indexing_response['indexed'],
95
+ $completed,
96
+ $processed,
97
+ $total
98
  ) . "\n";
99
  $response['offset'] = $offset;
100
 
130
  * AJAX wrapper for get_categories().
131
  */
132
  function relevanssi_list_categories() {
133
+ $categories = get_categories(
134
+ array(
135
+ 'taxonomy' => 'category',
136
+ 'hide_empty' => false,
137
+ )
138
+ );
139
  echo wp_json_encode( $categories );
140
  wp_die();
141
  }
160
  $args['posts_per_page'] = $posts_per_page;
161
  }
162
  }
163
+ if ( isset( $_POST['post_types'] ) ) {
164
+ $post_type = $_POST['post_types'];
165
+ $args['post_types'] = $post_type;
166
+ }
167
  if ( isset( $_POST['offset'] ) ) {
168
  $offset = intval( $_POST['offset'] );
169
  if ( $offset > 0 ) {
177
  $query = new WP_Query();
178
  $query->parse_query( $args );
179
  $query->set( 'relevanssi_admin_search', true );
180
+ $query = apply_filters( 'relevanssi_modify_wp_query', $query );
181
  relevanssi_do_query( $query );
182
 
183
  $results = relevanssi_admin_search_debugging_info( $query );
210
  */
211
  function relevanssi_admin_search_format_posts( $posts, $total, $offset, $query ) {
212
  $result = '<h3>' . __( 'Results', 'relevanssi' ) . '</h3>';
213
+ $start = $offset + 1;
214
+ $end = $offset + count( $posts );
215
  // Translators: %1$d is the total number of posts found, %2$d is the current search result count, %3$d is the offset.
216
+ $result .= '<p>' . sprintf( __( 'Found a total of %1$d posts, showing posts %2$d–%3$s.', 'relevanssi' ), $total, $start, '<span id="offset">' . $end . '</span>' ) . '</p>';
217
  if ( $offset > 0 ) {
218
  $result .= sprintf( '<button type="button" id="prev_page">%s</button>', __( 'Previous page', 'relevanssi' ) );
219
  }
220
  if ( count( $posts ) + $offset < $total ) {
221
  $result .= sprintf( '<button type="button" id="next_page">%s</button>', __( 'Next page', 'relevanssi' ) );
222
  }
223
+ $result .= '<ol start="' . $start . '">';
224
 
225
  $score_label = __( 'Score:', 'relevanssi' );
226
 
244
  $edit_url = get_edit_term_link( $post->term_id, $post->post_type );
245
  }
246
  }
247
+ $title = sprintf( '<a href="%1$s">%2$s %3$s</a>', $permalink, $post->post_title, $post_type );
248
+ $edit_link = '';
249
+ if ( current_user_can( 'edit_post', $post->ID ) ) {
250
+ $edit_link = sprintf( '(<a href="%1$s">%2$s %3$s</a>)', $edit_url, __( 'Edit', 'relevanssi' ), $post_type );
251
+ }
252
+
253
  $pinning_buttons = '';
254
  $pinned = '';
255
 
259
  }
260
 
261
  $post_element = <<<EOH
262
+ <li>$blog_name <strong>$title</strong> $edit_link $pinning_buttons <br />
263
  $post->post_excerpt<br />
264
  $score_label $post->relevance_score $pinned</li>
265
  EOH;
292
  * @since 2.2.0
293
  */
294
  function relevanssi_admin_search_debugging_info( $query ) {
295
+ $result = '<div id="debugging">';
296
+ $result .= '<h3>' . __( 'Query variables', 'relevanssi' ) . '</h3>';
297
  $result .= '<ul style="list-style: disc; margin-left: 1.5em">';
298
  foreach ( $query->query_vars as $key => $value ) {
299
+ if ( 'tax_query' === $key ) {
300
+ $result .= '<li>tax_query:<ul style="list-style: disc; margin-left: 1.5em">';
301
+ $result .= implode(
302
+ '',
303
+ array_map(
304
+ function ( $row ) {
305
+ $result = '';
306
+ if ( is_array( $row ) ) {
307
+ foreach ( $row as $row_key => $row_value ) {
308
+ $result .= "<li>$row_key: $row_value</li>";
309
+ }
310
+ }
311
+ return $result;
312
+ },
313
+ $value
314
+ )
315
+ );
316
+ $result .= '</ul></li>';
317
+ } else {
318
+ if ( is_array( $value ) ) {
319
+ $value = relevanssi_flatten_array( $value );
320
+ }
321
+ if ( empty( $value ) ) {
322
+ continue;
323
+ }
324
+ $result .= "<li>$key: $value</li>";
325
  }
 
326
  }
327
  if ( ! empty( $query->tax_query ) ) {
328
+ $result .= '<li>tax_query:<ul style="list-style: disc; margin-left: 1.5em">';
329
  foreach ( $query->tax_query as $tax_query ) {
330
+ if ( ! is_array( $tax_query ) ) {
331
+ continue;
332
+ }
333
  foreach ( $tax_query as $key => $value ) {
334
  if ( is_array( $value ) ) {
335
  $value = relevanssi_flatten_array( $value );
379
  }
380
  }
381
  $result .= '</div>';
382
+ $result .= '</div>';
383
 
384
  return $result;
385
  }
lib/admin_scripts.js CHANGED
@@ -171,14 +171,13 @@ jQuery(document).ready(function($) {
171
  count_response = JSON.parse(response)
172
  console.log("Counted " + count_response + " posts.")
173
  results.value += count_response + " " + relevanssi.posts_found + "\n"
174
-
175
  if (count_response > 0) {
176
  var args = {
177
  completed: 0,
178
  total: count_response,
179
  offset: 0,
180
  total_seconds: 0,
181
- limit: 10,
182
  extend: true,
183
  security: nonce.indexing_nonce
184
  }
@@ -351,6 +350,7 @@ jQuery(document).ready(function($) {
351
  action: "relevanssi_admin_search",
352
  args: document.getElementById("args").value,
353
  posts_per_page: document.getElementById("posts_per_page").value,
 
354
  s: document.getElementById("s").value,
355
  security: nonce.searching_nonce
356
  },
@@ -376,11 +376,10 @@ jQuery(document).ready(function($) {
376
  })
377
 
378
  $(document).on("click", "#next_page", function(e) {
379
- var results = document.getElementById("results")
380
  e.preventDefault()
 
381
  var offset = parseInt(document.getElementById("offset").innerHTML)
382
  var posts = parseInt(document.getElementById("posts_per_page").value)
383
- offset = offset + posts
384
  results.innerHTML = "Searching..."
385
  jQuery.ajax({
386
  type: "POST",
@@ -388,7 +387,7 @@ jQuery(document).ready(function($) {
388
  data: {
389
  action: "relevanssi_admin_search",
390
  args: document.getElementById("args").value,
391
- posts_per_page: document.getElementById("posts_per_page").value,
392
  s: document.getElementById("s").value,
393
  offset: offset,
394
  security: nonce.searching_nonce
@@ -401,11 +400,11 @@ jQuery(document).ready(function($) {
401
  })
402
 
403
  $(document).on("click", "#prev_page", function(e) {
404
- var results = document.getElementById("results")
405
  e.preventDefault()
 
406
  var offset = parseInt(document.getElementById("offset").innerHTML)
407
  var posts = parseInt(document.getElementById("posts_per_page").value)
408
- offset = offset - posts
409
  if (offset < 0) offset = 0
410
  results.innerHTML = "Searching..."
411
  jQuery.ajax({
171
  count_response = JSON.parse(response)
172
  console.log("Counted " + count_response + " posts.")
173
  results.value += count_response + " " + relevanssi.posts_found + "\n"
 
174
  if (count_response > 0) {
175
  var args = {
176
  completed: 0,
177
  total: count_response,
178
  offset: 0,
179
  total_seconds: 0,
180
+ limit: relevanssi_params.indexing_limit,
181
  extend: true,
182
  security: nonce.indexing_nonce
183
  }
350
  action: "relevanssi_admin_search",
351
  args: document.getElementById("args").value,
352
  posts_per_page: document.getElementById("posts_per_page").value,
353
+ post_types: document.getElementById("post_types").value,
354
  s: document.getElementById("s").value,
355
  security: nonce.searching_nonce
356
  },
376
  })
377
 
378
  $(document).on("click", "#next_page", function(e) {
 
379
  e.preventDefault()
380
+ var results = document.getElementById("results")
381
  var offset = parseInt(document.getElementById("offset").innerHTML)
382
  var posts = parseInt(document.getElementById("posts_per_page").value)
 
383
  results.innerHTML = "Searching..."
384
  jQuery.ajax({
385
  type: "POST",
387
  data: {
388
  action: "relevanssi_admin_search",
389
  args: document.getElementById("args").value,
390
+ posts_per_page: posts,
391
  s: document.getElementById("s").value,
392
  offset: offset,
393
  security: nonce.searching_nonce
400
  })
401
 
402
  $(document).on("click", "#prev_page", function(e) {
 
403
  e.preventDefault()
404
+ var results = document.getElementById("results")
405
  var offset = parseInt(document.getElementById("offset").innerHTML)
406
  var posts = parseInt(document.getElementById("posts_per_page").value)
407
+ offset = offset - posts - posts
408
  if (offset < 0) offset = 0
409
  results.innerHTML = "Searching..."
410
  jQuery.ajax({
lib/admin_scripts_free.js CHANGED
@@ -40,7 +40,7 @@ jQuery(document).ready(function($) {
40
  total: post_total,
41
  offset: 0,
42
  total_seconds: 0,
43
- limit: 10,
44
  extend: false,
45
  security: nonce.indexing_nonce
46
  }
40
  total: post_total,
41
  offset: 0,
42
  total_seconds: 0,
43
+ limit: relevanssi_params.indexing_limit,
44
  extend: false,
45
  security: nonce.indexing_nonce
46
  }
lib/common.php CHANGED
@@ -214,6 +214,11 @@ function relevanssi_default_post_ok( $post_ok, $post_id ) {
214
  $type = relevanssi_get_post_type( $post_id );
215
  $post_ok = $userAccessManager->getAccessHandler()->checkObjectAccess( $type, $post_id ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName
216
  }
 
 
 
 
 
217
 
218
  /**
219
  * Filters statuses allowed in admin searches.
@@ -259,8 +264,8 @@ function relevanssi_populate_array( $matches ) {
259
  }
260
 
261
  $ids = array_keys( array_flip( $ids ) ); // Remove duplicate IDs.
262
- $ids = implode( ',', $ids );
263
- $posts = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE id IN ($ids)" ); // WPCS: unprepared SQL ok, no user-generated inputs.
264
 
265
  foreach ( $posts as $post ) {
266
  $relevanssi_post_array[ $post->ID ] = $post;
@@ -277,14 +282,14 @@ function relevanssi_populate_array( $matches ) {
277
  * Fetches the taxonomy from wp_term_taxonomy based on term_id.
278
  *
279
  * @global object $wpdb The WordPress database interface.
280
- *
281
  * @param int $term_id The term ID.
282
- *
283
  * @return string $taxonomy The term taxonomy.
284
  */
285
  function relevanssi_get_term_taxonomy( $term_id ) {
286
  global $wpdb;
287
- $taxonomy = $wpdb->get_var( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); // WPCS: Unprepared SQL ok, database table name.
 
288
  return $taxonomy;
289
  }
290
 
@@ -345,14 +350,16 @@ function relevanssi_extract_phrases( $query ) {
345
  * @global object $wpdb The WordPress database interface.
346
  *
347
  * @param string $search_query The search query.
 
348
  *
349
  * @return string $queries If not phrase hits are found, an empty string; otherwise
350
  * MySQL queries to restrict the search.
351
  */
352
- function relevanssi_recognize_phrases( $search_query ) {
353
  global $wpdb;
354
 
355
  $phrases = relevanssi_extract_phrases( $search_query );
 
356
 
357
  $all_queries = array();
358
  if ( count( $phrases ) > 0 ) {
@@ -375,13 +382,13 @@ function relevanssi_recognize_phrases( $search_query ) {
375
 
376
  $query = "(SELECT ID FROM $wpdb->posts
377
  WHERE (post_content LIKE '%$phrase%' OR post_title LIKE '%$phrase%' $excerpt)
378
- AND post_status IN ('publish', 'draft', 'private', 'pending', 'future', 'inherit'))";
379
 
380
  $queries[] = $query;
381
 
382
  $query = "(SELECT ID FROM $wpdb->posts as p, $wpdb->term_relationships as r, $wpdb->term_taxonomy as s, $wpdb->terms as t
383
  WHERE r.term_taxonomy_id = s.term_taxonomy_id AND s.term_id = t.term_id AND p.ID = r.object_id
384
- AND t.name LIKE '%$phrase%' AND p.post_status IN ('publish', 'draft', 'private', 'pending', 'future', 'inherit'))";
385
 
386
  $queries[] = $query;
387
 
@@ -389,19 +396,26 @@ function relevanssi_recognize_phrases( $search_query ) {
389
  FROM $wpdb->posts AS p, $wpdb->postmeta AS m
390
  WHERE p.ID = m.post_id
391
  AND m.meta_value LIKE '%$phrase%'
392
- AND p.post_status IN ('publish', 'draft', 'private', 'pending', 'future', 'inherit'))";
393
 
394
  $queries[] = $query;
395
 
396
  $queries = implode( ' OR relevanssi.doc IN ', $queries );
397
- $queries = "AND (relevanssi.doc IN $queries)";
398
  $all_queries[] = $queries;
399
  }
400
  } else {
401
  $phrases = '';
402
  }
403
 
404
- $all_queries = implode( ' ', $all_queries );
 
 
 
 
 
 
 
405
 
406
  return $all_queries;
407
  }
@@ -429,7 +443,9 @@ function relevanssi_strip_invisibles( $text ) {
429
  '@<iframe[^>]*?.*?</iframe>@siu',
430
  '@<del[^>]*?.*?</del>@siu',
431
  ),
432
- ' ', $text );
 
 
433
  return $text;
434
  }
435
 
@@ -655,7 +671,7 @@ function relevanssi_prevent_default_request( $request, $query ) {
655
  }
656
  }
657
 
658
- if ( isset( $_REQUEST['action'] ) && 'acf' === substr( $_REQUEST['action'], 0, 3 ) ) { // WPCS: CSRF ok.
659
  // ACF stuff, do not touch (eg. a relationship field search).
660
  return $request;
661
  }
@@ -910,7 +926,7 @@ function relevanssi_get_post_type( $post_id ) {
910
  function relevanssi_the_tags( $before = null, $separator = ', ', $after = '', $echo = true ) {
911
  $tags = relevanssi_highlight_terms( get_the_tag_list( $before, $separator, $after ), get_search_query() );
912
  if ( $echo ) {
913
- echo $tags; // WPCS: XSS ok. All content is already escaped by WP.
914
  } else {
915
  return $tags;
916
  }
@@ -970,7 +986,13 @@ function relevanssi_add_synonyms( $query ) {
970
  // Skip empty rows.
971
  continue;
972
  }
 
973
  $parts = explode( '=', $pair );
 
 
 
 
 
974
  $key = strval( trim( $parts[0] ) );
975
  $value = trim( $parts[1] );
976
 
@@ -1093,7 +1115,7 @@ function relevanssi_the_title( $echo = true ) {
1093
  $post->post_highlighted_title = $post->post_title;
1094
  }
1095
  if ( $echo ) {
1096
- echo $post->post_highlighted_title; // WPCS: XSS ok, $post->post_highlighted_title is generated by Relevanssi.
1097
  }
1098
  return $post->post_highlighted_title;
1099
  }
@@ -1131,7 +1153,7 @@ function relevanssi_get_the_title( $post_id ) {
1131
  */
1132
  function relevanssi_update_doc_count() {
1133
  global $wpdb, $relevanssi_variables;
1134
- $doc_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT(doc)) FROM ' . $relevanssi_variables['relevanssi_table'] ); // WPCS: unprepared SQL ok, Relevanssi table name.
1135
  update_option( 'relevanssi_doc_count', $doc_count );
1136
  return $doc_count;
1137
  }
@@ -1335,7 +1357,7 @@ function relevanssi_didyoumean( $query, $pre, $post, $n = 5, $echo = true ) {
1335
  }
1336
 
1337
  if ( $echo ) {
1338
- echo $result; // WPCS: XSS ok, already escaped.
1339
  }
1340
 
1341
  return $result;
@@ -1434,7 +1456,7 @@ function relevanssi_simple_generate_suggestion( $query ) {
1434
 
1435
  $data = get_transient( 'relevanssi_didyoumean_query' );
1436
  if ( empty( $data ) ) {
1437
- $data = $wpdb->get_results( $q ); // WPCS: unprepared SQL ok. No user-generated input involved.
1438
  set_transient( 'relevanssi_didyoumean_query', $data, 60 * 60 * 24 * 7 );
1439
  }
1440
 
@@ -1522,9 +1544,11 @@ function relevanssi_get_post( $post_id, $blog_id = -1 ) {
1522
 
1523
  global $relevanssi_post_array;
1524
 
 
1525
  if ( isset( $relevanssi_post_array[ $post_id ] ) ) {
1526
  $post = $relevanssi_post_array[ $post_id ];
1527
- } else {
 
1528
  $post = get_post( $post_id );
1529
 
1530
  $relevanssi_post_array[ $post_id ] = $post;
@@ -1592,36 +1616,35 @@ function relevanssi_common_words( $limit = 25, $wp_cli = false ) {
1592
  $limit = 25;
1593
  }
1594
 
1595
- $words = $wpdb->get_results( 'SELECT COUNT(*) as cnt, term FROM ' . $relevanssi_variables['relevanssi_table'] . " GROUP BY term ORDER BY cnt DESC LIMIT $limit" ); // WPCS: unprepared sql ok, Relevanssi table name and $limit is numeric.
1596
 
1597
  if ( ! $wp_cli ) {
1598
  printf( '<h2>%s</h2>', esc_html__( '25 most common words in the index', 'relevanssi' ) );
1599
  printf( '<p>%s</p>', esc_html__( "These words are excellent stopword material. A word that appears in most of the posts in the database is quite pointless when searching. This is also an easy way to create a completely new stopword list, if one isn't available in your language. Click the word to add the word to the stopword list. The word will also be removed from the index, so rebuilding the index is not necessary.", 'relevanssi' ) );
1600
 
1601
- ?>
1602
  <input type="hidden" name="dowhat" value="add_stopword" />
1603
  <table class="form-table">
1604
  <tr>
1605
  <th scope="row"><?php esc_html_e( 'Stopword Candidates', 'relevanssi' ); ?></th>
1606
  <td>
1607
  <ul>
1608
- <?php
1609
- foreach ( $words as $word ) {
1610
- $stop = __( 'Add to stopwords', 'relevanssi' );
1611
- printf( '<li>%1$s (%2$d) <button name="term" value="%1$s" />%3$s</button>', esc_attr( $word->term ), esc_html( $word->cnt ), esc_html( $stop ) );
1612
- if ( RELEVANSSI_PREMIUM ) {
1613
- $body = __( 'Add to content stopwords', 'relevanssi' );
1614
- printf( ' <button name="body_term" value="%1$s" />%3$s</button>', esc_attr( $word->term ), esc_html( $word->cnt ), esc_html( $body ) );
 
 
1615
  }
1616
- echo '</li>';
1617
- }
1618
- ?>
1619
  </ul>
1620
  </td>
1621
  </tr>
1622
  </table>
1623
- <?php
1624
-
1625
  }
1626
 
1627
  return $words;
@@ -1649,6 +1672,7 @@ function relevanssi_get_forbidden_post_types() {
1649
  'amp_validated_url', // AMP.
1650
  'jp_pay_order', // Jetpack.
1651
  'jp_pay_product', // Jetpack.
 
1652
  'tablepress_table', // TablePress.
1653
  'shop_order', // WooCommerce.
1654
  'shop_order_refund', // WooCommerce.
214
  $type = relevanssi_get_post_type( $post_id );
215
  $post_ok = $userAccessManager->getAccessHandler()->checkObjectAccess( $type, $post_id ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName
216
  }
217
+ if ( function_exists( 'pmpro_has_membership_access' ) ) {
218
+ // Paid Membership Pro.
219
+ $current_user = wp_get_current_user();
220
+ $post_ok = pmpro_has_membership_access( $post_id, $current_user->ID );
221
+ }
222
 
223
  /**
224
  * Filters statuses allowed in admin searches.
264
  }
265
 
266
  $ids = array_keys( array_flip( $ids ) ); // Remove duplicate IDs.
267
+ $ids = implode( ', ', $ids );
268
+ $posts = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE id IN ( $ids )", OBJECT ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
269
 
270
  foreach ( $posts as $post ) {
271
  $relevanssi_post_array[ $post->ID ] = $post;
282
  * Fetches the taxonomy from wp_term_taxonomy based on term_id.
283
  *
284
  * @global object $wpdb The WordPress database interface.
 
285
  * @param int $term_id The term ID.
286
+ * @deprecated Will be removed in future versions.
287
  * @return string $taxonomy The term taxonomy.
288
  */
289
  function relevanssi_get_term_taxonomy( $term_id ) {
290
  global $wpdb;
291
+
292
+ $taxonomy = $wpdb->get_var( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
293
  return $taxonomy;
294
  }
295
 
350
  * @global object $wpdb The WordPress database interface.
351
  *
352
  * @param string $search_query The search query.
353
+ * @param string $operator The search operator (AND or OR).
354
  *
355
  * @return string $queries If not phrase hits are found, an empty string; otherwise
356
  * MySQL queries to restrict the search.
357
  */
358
+ function relevanssi_recognize_phrases( $search_query, $operator = 'AND' ) {
359
  global $wpdb;
360
 
361
  $phrases = relevanssi_extract_phrases( $search_query );
362
+ $status = relevanssi_valid_status_array();
363
 
364
  $all_queries = array();
365
  if ( count( $phrases ) > 0 ) {
382
 
383
  $query = "(SELECT ID FROM $wpdb->posts
384
  WHERE (post_content LIKE '%$phrase%' OR post_title LIKE '%$phrase%' $excerpt)
385
+ AND post_status IN ($status))";
386
 
387
  $queries[] = $query;
388
 
389
  $query = "(SELECT ID FROM $wpdb->posts as p, $wpdb->term_relationships as r, $wpdb->term_taxonomy as s, $wpdb->terms as t
390
  WHERE r.term_taxonomy_id = s.term_taxonomy_id AND s.term_id = t.term_id AND p.ID = r.object_id
391
+ AND t.name LIKE '%$phrase%' AND p.post_status IN ($status))";
392
 
393
  $queries[] = $query;
394
 
396
  FROM $wpdb->posts AS p, $wpdb->postmeta AS m
397
  WHERE p.ID = m.post_id
398
  AND m.meta_value LIKE '%$phrase%'
399
+ AND p.post_status IN ($status))";
400
 
401
  $queries[] = $query;
402
 
403
  $queries = implode( ' OR relevanssi.doc IN ', $queries );
404
+ $queries = "(relevanssi.doc IN $queries)";
405
  $all_queries[] = $queries;
406
  }
407
  } else {
408
  $phrases = '';
409
  }
410
 
411
+ $operator = strtoupper( $operator );
412
+ if ( 'AND' !== $operator && 'OR' !== $operator ) {
413
+ $operator = 'AND';
414
+ }
415
+
416
+ if ( ! empty( $all_queries ) ) {
417
+ $all_queries = ' AND ( ' . implode( ' ' . $operator . ' ', $all_queries ) . ' ) ';
418
+ }
419
 
420
  return $all_queries;
421
  }
443
  '@<iframe[^>]*?.*?</iframe>@siu',
444
  '@<del[^>]*?.*?</del>@siu',
445
  ),
446
+ ' ',
447
+ $text
448
+ );
449
  return $text;
450
  }
451
 
671
  }
672
  }
673
 
674
+ if ( isset( $_REQUEST['action'] ) && 'acf' === substr( $_REQUEST['action'], 0, 3 ) ) { // phpcs:ignore WordPress.Security.NonceVerification
675
  // ACF stuff, do not touch (eg. a relationship field search).
676
  return $request;
677
  }
926
  function relevanssi_the_tags( $before = null, $separator = ', ', $after = '', $echo = true ) {
927
  $tags = relevanssi_highlight_terms( get_the_tag_list( $before, $separator, $after ), get_search_query() );
928
  if ( $echo ) {
929
+ echo $tags; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
930
  } else {
931
  return $tags;
932
  }
986
  // Skip empty rows.
987
  continue;
988
  }
989
+
990
  $parts = explode( '=', $pair );
991
+
992
+ if ( count( $parts ) < 2 ) {
993
+ continue;
994
+ }
995
+
996
  $key = strval( trim( $parts[0] ) );
997
  $value = trim( $parts[1] );
998
 
1115
  $post->post_highlighted_title = $post->post_title;
1116
  }
1117
  if ( $echo ) {
1118
+ echo $post->post_highlighted_title; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1119
  }
1120
  return $post->post_highlighted_title;
1121
  }
1153
  */
1154
  function relevanssi_update_doc_count() {
1155
  global $wpdb, $relevanssi_variables;
1156
+ $doc_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT(doc)) FROM ' . $relevanssi_variables['relevanssi_table'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1157
  update_option( 'relevanssi_doc_count', $doc_count );
1158
  return $doc_count;
1159
  }
1357
  }
1358
 
1359
  if ( $echo ) {
1360
+ echo $result; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1361
  }
1362
 
1363
  return $result;
1456
 
1457
  $data = get_transient( 'relevanssi_didyoumean_query' );
1458
  if ( empty( $data ) ) {
1459
+ $data = $wpdb->get_results( $q ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1460
  set_transient( 'relevanssi_didyoumean_query', $data, 60 * 60 * 24 * 7 );
1461
  }
1462
 
1544
 
1545
  global $relevanssi_post_array;
1546
 
1547
+ $post = null;
1548
  if ( isset( $relevanssi_post_array[ $post_id ] ) ) {
1549
  $post = $relevanssi_post_array[ $post_id ];
1550
+ }
1551
+ if ( ! $post ) {
1552
  $post = get_post( $post_id );
1553
 
1554
  $relevanssi_post_array[ $post_id ] = $post;
1616
  $limit = 25;
1617
  }
1618
 
1619
+ $words = $wpdb->get_results( 'SELECT COUNT(*) as cnt, term FROM ' . $relevanssi_variables['relevanssi_table'] . " GROUP BY term ORDER BY cnt DESC LIMIT $limit" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
1620
 
1621
  if ( ! $wp_cli ) {
1622
  printf( '<h2>%s</h2>', esc_html__( '25 most common words in the index', 'relevanssi' ) );
1623
  printf( '<p>%s</p>', esc_html__( "These words are excellent stopword material. A word that appears in most of the posts in the database is quite pointless when searching. This is also an easy way to create a completely new stopword list, if one isn't available in your language. Click the word to add the word to the stopword list. The word will also be removed from the index, so rebuilding the index is not necessary.", 'relevanssi' ) );
1624
 
1625
+ ?>
1626
  <input type="hidden" name="dowhat" value="add_stopword" />
1627
  <table class="form-table">
1628
  <tr>
1629
  <th scope="row"><?php esc_html_e( 'Stopword Candidates', 'relevanssi' ); ?></th>
1630
  <td>
1631
  <ul>
1632
+ <?php
1633
+ foreach ( $words as $word ) {
1634
+ $stop = __( 'Add to stopwords', 'relevanssi' );
1635
+ printf( '<li>%1$s (%2$d) <button name="term" value="%1$s" />%3$s</button>', esc_attr( $word->term ), esc_html( $word->cnt ), esc_html( $stop ) );
1636
+ if ( RELEVANSSI_PREMIUM ) {
1637
+ $body = __( 'Add to content stopwords', 'relevanssi' );
1638
+ printf( ' <button name="body_term" value="%1$s" />%3$s</button>', esc_attr( $word->term ), esc_html( $word->cnt ), esc_html( $body ) );
1639
+ }
1640
+ echo '</li>';
1641
  }
1642
+ ?>
 
 
1643
  </ul>
1644
  </td>
1645
  </tr>
1646
  </table>
1647
+ <?php
 
1648
  }
1649
 
1650
  return $words;
1672
  'amp_validated_url', // AMP.
1673
  'jp_pay_order', // Jetpack.
1674
  'jp_pay_product', // Jetpack.
1675
+ 'jp_mem_plan', // Jetpack.
1676
  'tablepress_table', // TablePress.
1677
  'shop_order', // WooCommerce.
1678
  'shop_order_refund', // WooCommerce.
lib/compatibility/acf.php CHANGED
@@ -24,7 +24,7 @@ add_filter( 'relevanssi_search_ok', 'relevanssi_acf_relationship_fields' );
24
  * parameter unchanged otherwise.
25
  */
26
  function relevanssi_acf_relationship_fields( $search_ok ) {
27
- if ( isset( $_REQUEST['action'] ) && 'acf' === substr( $_REQUEST['action'], 0, 3 ) ) { // WPCS: CSRF ok.
28
  $search_ok = false;
29
  }
30
  return $search_ok;
24
  * parameter unchanged otherwise.
25
  */
26
  function relevanssi_acf_relationship_fields( $search_ok ) {
27
+ if ( isset( $_REQUEST['action'] ) && 'acf' === substr( $_REQUEST['action'], 0, 3 ) ) { // phpcs:ignore WordPress.Security.NonceVerification
28
  $search_ok = false;
29
  }
30
  return $search_ok;
lib/compatibility/polylang.php CHANGED
@@ -50,7 +50,12 @@ function relevanssi_polylang_filter( $query ) {
50
  // Tax queries can be here as well, so let's sweep this one too.
51
  $ok_queries = array();
52
  foreach ( $query->query_vars['tax_query'] as $tax_query ) {
53
- if ( 'language' !== $tax_query['taxonomy'] ) {
 
 
 
 
 
54
  $ok_queries[] = $tax_query;
55
  }
56
  }
50
  // Tax queries can be here as well, so let's sweep this one too.
51
  $ok_queries = array();
52
  foreach ( $query->query_vars['tax_query'] as $tax_query ) {
53
+ if ( isset( $tax_query['taxonomy'] ) ) {
54
+ if ( 'language' !== $tax_query['taxonomy'] ) {
55
+ $ok_queries[] = $tax_query;
56
+ }
57
+ } else {
58
+ // Relation parameter most likely.
59
  $ok_queries[] = $tax_query;
60
  }
61
  }
lib/compatibility/wp-file-download.php CHANGED
@@ -31,12 +31,14 @@ function relevanssi_wpfd_content( $content, $post ) {
31
  if ( 'wpfd_file' === $post->post_type ) {
32
  if ( $wpfd_search_config && isset( $wpfd_search_config['plain_text_search'] ) && $wpfd_search_config['plain_text_search'] ) {
33
  global $wpdb;
34
- $words = $wpdb->get_col("SELECT word
35
- FROM {$wpdb->prefix}wpfd_words, {$wpdb->prefix}wpfd_docs, {$wpdb->prefix}wpfd_index, {$wpdb->prefix}wpfd_vectors
36
- WHERE {$wpdb->prefix}wpfd_index.tid = {$post->ID}
37
- AND {$wpdb->prefix}wpfd_docs.index_id = {$wpdb->prefix}wpfd_index.id
 
38
  AND {$wpdb->prefix}wpfd_docs.id = {$wpdb->prefix}wpfd_vectors.did
39
- AND {$wpdb->prefix}wpfd_vectors.wid = {$wpdb->prefix}wpfd_words.id"); // WPCS: unprepared SQL ok, no user-generated inputs.
 
40
  $content .= implode( ' ', $words );
41
  }
42
  }
31
  if ( 'wpfd_file' === $post->post_type ) {
32
  if ( $wpfd_search_config && isset( $wpfd_search_config['plain_text_search'] ) && $wpfd_search_config['plain_text_search'] ) {
33
  global $wpdb;
34
+ $words = $wpdb->get_col(
35
+ "SELECT word
36
+ FROM {$wpdb->prefix}wpfd_words, {$wpdb->prefix}wpfd_docs, {$wpdb->prefix}wpfd_index, {$wpdb->prefix}wpfd_vectors " .
37
+ "WHERE {$wpdb->prefix}wpfd_index.tid = {$post->ID} " . // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
38
+ " AND {$wpdb->prefix}wpfd_docs.index_id = {$wpdb->prefix}wpfd_index.id
39
  AND {$wpdb->prefix}wpfd_docs.id = {$wpdb->prefix}wpfd_vectors.did
40
+ AND {$wpdb->prefix}wpfd_vectors.wid = {$wpdb->prefix}wpfd_words.id"
41
+ );
42
  $content .= implode( ' ', $words );
43
  }
44
  }
lib/compatibility/yoast-seo.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/yoast-seo.php
4
+ *
5
+ * Yoast SEO noindex filtering function.
6
+ *
7
+ * @package Relevanssi
8
+ * @author Mikko Saari
9
+ * @license https://wordpress.org/about/gpl/ GNU General Public License
10
+ * @see https://www.relevanssi.com/
11
+ */
12
+
13
+ add_filter( 'relevanssi_do_not_index', 'relevanssi_yoast_noindex', 10, 2 );
14
+
15
+ /**
16
+ * Blocks indexing of posts marked "noindex" in the Yoast SEO settings.
17
+ *
18
+ * Attaches to the 'relevanssi_do_not_index' filter hook.
19
+ *
20
+ * @param boolean $do_not_index True, if the post shouldn't be indexed.
21
+ * @param integer $post_id The post ID number.
22
+ *
23
+ * @return boolean True, if the post shouldn't be indexed.
24
+ */
25
+ function relevanssi_yoast_noindex( $do_not_index, $post_id ) {
26
+ $noindex = get_post_meta( $post_id, '_yoast_wpseo_meta-robots-noindex', true );
27
+ if ( $noindex ) {
28
+ $do_not_index = true;
29
+ }
30
+ return $do_not_index;
31
+ }
lib/contextual-help.php CHANGED
@@ -19,144 +19,164 @@ function relevanssi_admin_help() {
19
  global $wpdb;
20
 
21
  $screen = get_current_screen();
22
- $screen->add_help_tab( array(
23
- 'id' => 'relevanssi-searching',
24
- 'title' => __( 'Searching', 'relevanssi' ),
25
- 'content' => '<ul>' .
26
- // Translators: %1$s is 'orderby', %2$s is the Codex page URL.
27
- '<li>' . sprintf( __( "To adjust the post order, you can use the %1\$s query parameter. With %1\$s, you can use multiple layers of different sorting methods. See <a href='%2\$s'>WordPress Codex</a> for more details on using arrays for orderby.", 'relevanssi' ), '<code>orderby</code>', 'https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters' ) . '</li>' .
28
- '<li>' . __( "Inside-word matching is disabled by default, because it increases garbage results that don't really match the search term. If you want to enable it, add the following function to your theme functions.php:", 'relevanssi' ) .
29
- '<pre>add_filter( \'relevanssi_fuzzy_query\', \'rlv_partial_inside_words\' );
30
- function rlv_partial_inside_words( $query ) {
31
- return "(term LIKE \'%#term#%\')";
32
- }</pre></li>' .
33
- // Translators: %s is 'Uncheck this if you use non-ASCII characters' option name.
34
- '<li>' . sprintf( __( 'To get inside-word highlights, uncheck the "%s" option. That has a side-effect of enabling the inside-word highlights.', 'relevanssi' ), __( 'Uncheck this if you use non-ASCII characters', 'relevanssi' ) ) . '</li>' .
35
- // Translators: %s is 'relevanssi_throttle_limit'.
36
- '<li>' . sprintf( __( 'In order to adjust the throttle limit, you can use the %s filter hook.', 'relevanssi' ), '<code>pre_option_relevanssi_throttle_limit</code>' ) .
37
- '<pre>add_filter( \'pre_option_relevanssi_throttle_limit\', function( $limit ) { return 200; } );</pre></li>' .
38
- '<li>' . __( "It's not usually necessary to adjust the limit from 500, but in some cases performance gains can be achieved by setting a lower limit. We don't suggest going under 200, as low values will make the results worse.", 'relevanssi' ) . '</li>' .
39
- '</ul>',
40
- ));
41
- $screen->add_help_tab( array(
42
- 'id' => 'relevanssi-search-restrictions',
43
- 'title' => __( 'Restrictions', 'relevanssi' ),
44
- 'content' => '<ul>' .
45
- '<li>' . __( 'If you want the general search to target all posts, but have a single search form target only certain posts, you can add a hidden input variable to the search form. ', 'relevanssi' ) . '</li>' .
46
- '<li>' . __( 'For example in order to restrict the search to categories 10, 14 and 17, you could add this to the search form:', 'relevanssi' ) .
47
- '<pre>&lt;input type="hidden" name="cats" value="10,14,17" /&gt;</pre></li>' .
48
- '<li>' . __( 'To restrict the search to posts tagged with alfa AND beta, you could add this to the search form:', 'relevanssi' ) .
49
- '<pre>&lt;input type="hidden" name="tag" value="alfa+beta" /&gt;</pre></li>' .
50
- // Translators: %s is the link to the Codex page.
51
- '<li>' . sprintf( __( 'For all the possible options, see the Codex documentation for %s.', 'relevanssi' ), '<a href="https://codex.wordpress.org/Class_Reference/WP_Query">WP_Query</a>' ) . '</li>' .
52
- '</ul>',
53
- ));
54
- $screen->add_help_tab( array(
55
- 'id' => 'relevanssi-search-exclusions',
56
- 'title' => __( 'Exclusions', 'relevanssi' ),
57
- 'content' => '<ul>' .
58
- // Translators: %s is the link to the Codex page.
59
- '<li>' . sprintf( __( 'For more exclusion options, see the Codex documentation for %s. For example, to exclude tag ID 10, use', 'relevanssi' ), '<a href="https://codex.wordpress.org/Class_Reference/WP_Query">WP_Query</a>' ) .
60
- '<pre>&lt;input type="hidden" name="tag__not_in" value="10" /&gt;</pre></li>' .
61
- // Translators: %s is 'relevanssi_do_not_index'.
62
- '<li>' . sprintf( __( 'To exclude posts from the index and not just from the search, you can use the %s filter hook. This would not index posts that have a certain taxonomy term:', 'relevanssi' ), '<code>relevanssi_do_not_index</code>' ) .
63
- '<pre>add_filter( \'relevanssi_do_not_index\', \'rlv_index_filter\', 10, 2 );
64
- function rlv_index_filter( $block, $post_id ) {
65
- if ( has_term( \'jazz\', \'genre\', $post_id ) ) {
66
- $block = true;
 
 
 
 
 
 
 
67
  }
68
- return $block;
69
- }
70
- </pre></li>' .
71
- // Translators: %s is a link to the Relevanssi knowledge base.
72
- '<li>' . sprintf( __( "For more examples, see <a href='%s'>the related knowledge base posts</a>.", 'relevanssi' ), 'https://www.relevanssi.com/tag/relevanssi_do_not_index/' ) . '</li>' .
73
- '</ul>',
74
- ));
75
- $screen->add_help_tab( array(
76
- 'id' => 'relevanssi-logging',
77
- 'title' => __( 'Logs', 'relevanssi' ),
78
- 'content' => '<ul>' .
79
- // Translators: %s is 'relevanssi_user_searches_limit'.
80
- '<li>' . sprintf( __( 'By default, the User searches page shows 20 most common keywords. In order to see more, you can adjust the value with the %s filter hook, like this:', 'relevanssi' ), '<code>relevanssi_user_searches_limit</code>' ) .
81
- "<pre>add_filter( 'relevanssi_user_searches_limit', function() { return 50; } );</pre></li>" .
82
- // Translators: %s is the name of the database table.
83
- '<li>' . sprintf( __( 'The complete logs are stored in the %s database table, where you can access them if you need more information than what the User searches page provides.', 'relevanssi' ), '<code>' . $wpdb->prefix . 'relevanssi_log</code>' ) . '</li>' .
84
- '</ul>',
85
- ));
86
- $screen->add_help_tab( array(
87
- 'id' => 'relevanssi-excerpts',
88
- 'title' => __( 'Excerpts', 'relevanssi' ),
89
- 'content' => '<ul>' .
90
- '<li>' . __( 'Building custom excerpts can be slow. If you are not actually using the excerpts, make sure you disable the option.', 'relevanssi' ) . '</li>' .
91
- // Translators: %s is 'the_excerpt()'.
92
- '<li>' . sprintf( __( 'Custom snippets require that the search results template uses %s to print out the excerpts.', 'relevanssi' ), '<code>the_excerpt()</code>' ) . '</li>' .
93
- '<li>' . __( 'Generally, Relevanssi generates the excerpts from post content. If you want to include custom field content in the excerpt-building, this can be done with a simple setting from the excerpt settings.', 'relevanssi' ) . '</li>' .
94
- // Translators: %1$s is 'relevanssi_pre_excerpt_content', %2$s is 'relevanssi_excerpt_content'.
95
- '<li>' . sprintf( __( 'If you want more control over what content Relevanssi uses to create the excerpts, you can use the %1$s and %2$s filter hooks to adjust the content.', 'relevanssi' ), '<code>relevanssi_pre_excerpt_content</code>', '<code>relevanssi_excerpt_content</code>' ) . '</li>' .
96
- // Translators: %s is 'relevanssi_disable_shortcodes_excerpt'.
97
- '<li>' . sprintf( __( 'Some shortcode do not work well with Relevanssi excerpt-generation. Relevanssi disables some shortcodes automatically to prevent problems. This can be adjusted with the %s filter hook.', 'relevanssi' ), '<code>relevanssi_disable_shortcodes_excerpt</code>' ) . '</li>' .
98
- // Translators: %s is 'relevanssi_optimize_excerpts'.
99
- '<li>' . sprintf( __( "If you want Relevanssi to build excerpts faster and don't mind that they may be less than perfect in quality, add a filter that returns true on hook %s.", 'relevanssi' ), '<code>relevanssi_optimize_excerpts</code>' ) .
100
- "<pre>add_filter( 'relevanssi_optimize_excerpts', '__return_true' );</pre></li>" .
101
- '</ul>',
102
- ));
103
- $screen->add_help_tab( array(
104
- 'id' => 'relevanssi-highlights',
105
- 'title' => __( 'Highlights', 'relevanssi' ),
106
- 'content' => '<ul>' .
107
- '<li>' . __( "Title highlights don't appear automatically, because that led to problems with highlights appearing in wrong places and messing up navigation menus, for example.", 'relevanssi' ) . '</li>' .
108
- // Translators: %1$s is 'the_title()', %2$s is 'relevanssi_the_title()'.
109
- '<li>' . sprintf( __( 'In order to see title highlights from Relevanssi, replace %1$s in the search results template with %2$s. It does the same thing, but supports Relevanssi title highlights.', 'relevanssi' ), '<code>the_title()</code>', '<code>relevanssi_the_title()</code>' ) . '</li>' .
110
- '</ul>',
111
- ));
112
- $screen->add_help_tab( array(
113
- 'id' => 'relevanssi-punctuation',
114
- 'title' => __( 'Punctuation', 'relevanssi' ),
115
- 'content' => '<ul>' .
116
- '<li>' . __( 'Relevanssi removes punctuation. Some punctuation is removed, some replaced with spaces. Advanced indexing settings include some of the more common settings people want to change.', 'relevanssi' ) . '</li>' .
117
- // Translators: %1$s is 'relevanssi_punctuation_filter', %2$s is 'relevanssi_remove_punctuation'.
118
- '<li>' . sprintf( __( 'For more fine-tuned changes, you can use %1$s filter hook to adjust what is replaced with what, and %2$s filter hook to completely override the default punctuation control.', 'relevanssi' ), '<code>relevanssi_punctuation_filter</code>', '<code>relevanssi_remove_punctuation</code>' ) . '</li>' .
119
- // Translators: %s is the URL to the Knowledge Base entry.
120
- '<li>' . sprintf( __( "For more examples, see <a href='%s'>the related knowledge base posts</a>.", 'relevanssi' ), 'https://www.relevanssi.com/tag/relevanssi_remove_punct/' ) . '</li>' .
121
- '</ul>',
122
- ));
123
- $screen->add_help_tab( array(
124
- 'id' => 'relevanssi-helpful-shortcodes',
125
- 'title' => __( 'Helpful shortcodes', 'relevanssi' ),
126
- 'content' => '<ul>' .
127
- // Translators: %s is '[noindex]'.
128
- '<li>' . sprintf( __( "If you have content that you don't want indexed, you can wrap that content in a %s shortcode.", 'relevanssi' ), '<code>[noindex]</code>' ) . '</li>' .
129
- // Translators: %s is '[searchform]'.
130
- '<li>' . sprintf( __( 'If you need a search form on some page on your site, you can use the %s shortcode to print out a basic search form.', 'relevanssi' ), '<code>[searchform]</code>' ) . '</li>' .
131
- // Translators: %1$s is '[searchform post_types="page"]', %2$s is '[searchform cats="10,14,17"]'.
132
- '<li>' . sprintf( __( 'If you need to add query variables to the search form, the shortcode takes parameters, which are then printed out as hidden input fields. To get a search form with a post type restriction, you can use %1$s. To restrict the search to categories 10, 14 and 17, you can use %2$s and so on.', 'relevanssi' ), '<code>[searchform post_types="page"]</code>', '<code>[searchform cats="10,14,17"]</code>' ) . '</li>' .
133
- // Translators: %1$s is 'dropdown', %2$s is '[searchform dropdown="category"]'.
134
- '<li>' . sprintf( __( 'You can use the %1$s parameter to add a taxonomy dropdown to the search form. Just use the name of the taxonomy, like %2$s. This works best with hierarchical taxonomies like categories with relatively few options available.', 'relevanssi' ), '<code>dropdown</code>', '<code>[searchform dropdown="category"]</code>' ) . '</li>' .
135
- '</ul>',
136
- ));
137
- $screen->add_help_tab( array(
138
- 'id' => 'relevanssi-title-woocommerce',
139
- 'title' => __( 'WooCommerce', 'relevanssi' ),
140
- 'content' => '<ul>' .
141
- '<li>' . __( "If your SKUs include hyphens or other punctuation, do note that Relevanssi replaces most punctuation with spaces. That's going to cause issues with SKU searches.", 'relevanssi' ) . '</li>' .
142
- // Translators: %s is the Knowledge Base URL.
143
- '<li>' . sprintf( __( "For more details how to fix that issue, see <a href='%s'>WooCommerce tips in Relevanssi user manual</a>.", 'relevanssi' ), 'https://www.relevanssi.com/user-manual/woocommerce/' ) . '</li>' .
144
- '<li>' . __( "If you don't want to index products that are out of stock, excluded from the catalog or excluded from the search, there's a product visibility filtering method that is described in the user manual (see link above).", 'relevanssi' ) . '</li>' .
145
- '</ul>',
146
- ));
147
- $screen->add_help_tab( array(
148
- 'id' => 'relevanssi-exact-match',
149
- 'title' => __( 'Exact match bonus', 'relevanssi' ),
150
- 'content' => '<ul>' .
151
- // Translators: %s is the name of the filter hook.
152
- '<li>' . sprintf( __( 'To adjust the amount of the exact match bonus, you can use the %s filter hook. It works like this:', 'relevanssi' ), '<code>relevanssi_exact_match_bonus</code>' ) .
153
- "<pre>add_filter( 'relevanssi_exact_match_bonus', 'rlv_adjust_bonus' );
154
- function rlv_adjust_bonus( \$bonus ) {
155
- return array( 'title' => 10, 'content' => 5 );
156
- }</li>" .
157
- // Translators: %1$s is the title weight and %2$s is the content weight.
158
- '<li>' . sprintf( esc_html__( 'The default values are %1$s for titles and %2$s for content.', 'relevanssi' ), '<code>5</code>', '<code>2</code>' ) . '</ul>',
159
- ));
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  $screen->set_help_sidebar(
161
  '<p><strong>' . __( 'For more information:', 'relevanssi' ) . '</strong></p>' .
162
  '<p><a href="https://www.relevanssi.com/knowledge-base/" target="_blank">' . __( 'Plugin knowledge base', 'relevanssi' ) . '</a></p>' .
19
  global $wpdb;
20
 
21
  $screen = get_current_screen();
22
+ $screen->add_help_tab(
23
+ array(
24
+ 'id' => 'relevanssi-searching',
25
+ 'title' => __( 'Searching', 'relevanssi' ),
26
+ 'content' => '<ul>' .
27
+ // Translators: %1$s is 'orderby', %2$s is the Codex page URL.
28
+ '<li>' . sprintf( __( "To adjust the post order, you can use the %1\$s query parameter. With %1\$s, you can use multiple layers of different sorting methods. See <a href='%2\$s'>WordPress Codex</a> for more details on using arrays for orderby.", 'relevanssi' ), '<code>orderby</code>', 'https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters' ) . '</li>' .
29
+ '<li>' . __( "Inside-word matching is disabled by default, because it increases garbage results that don't really match the search term. If you want to enable it, add the following function to your theme functions.php:", 'relevanssi' ) .
30
+ '<pre>add_filter( \'relevanssi_fuzzy_query\', \'rlv_partial_inside_words\' );
31
+ function rlv_partial_inside_words( $query ) {
32
+ return "(term LIKE \'%#term#%\')";
33
+ }</pre></li>' .
34
+ // Translators: %s is 'Uncheck this if you use non-ASCII characters' option name.
35
+ '<li>' . sprintf( __( 'To get inside-word highlights, uncheck the "%s" option. That has a side-effect of enabling the inside-word highlights.', 'relevanssi' ), __( 'Uncheck this if you use non-ASCII characters', 'relevanssi' ) ) . '</li>' .
36
+ // Translators: %s is 'relevanssi_throttle_limit'.
37
+ '<li>' . sprintf( __( 'In order to adjust the throttle limit, you can use the %s filter hook.', 'relevanssi' ), '<code>pre_option_relevanssi_throttle_limit</code>' ) .
38
+ '<pre>add_filter( \'pre_option_relevanssi_throttle_limit\', function( $limit ) { return 200; } );</pre></li>' .
39
+ '<li>' . __( "It's not usually necessary to adjust the limit from 500, but in some cases performance gains can be achieved by setting a lower limit. We don't suggest going under 200, as low values will make the results worse.", 'relevanssi' ) . '</li>' .
40
+ '</ul>',
41
+ )
42
+ );
43
+ $screen->add_help_tab(
44
+ array(
45
+ 'id' => 'relevanssi-search-restrictions',
46
+ 'title' => __( 'Restrictions', 'relevanssi' ),
47
+ 'content' => '<ul>' .
48
+ '<li>' . __( 'If you want the general search to target all posts, but have a single search form target only certain posts, you can add a hidden input variable to the search form. ', 'relevanssi' ) . '</li>' .
49
+ '<li>' . __( 'For example in order to restrict the search to categories 10, 14 and 17, you could add this to the search form:', 'relevanssi' ) .
50
+ '<pre>&lt;input type="hidden" name="cats" value="10,14,17" /&gt;</pre></li>' .
51
+ '<li>' . __( 'To restrict the search to posts tagged with alfa AND beta, you could add this to the search form:', 'relevanssi' ) .
52
+ '<pre>&lt;input type="hidden" name="tag" value="alfa+beta" /&gt;</pre></li>' .
53
+ // Translators: %s is the link to the Codex page.
54
+ '<li>' . sprintf( __( 'For all the possible options, see the Codex documentation for %s.', 'relevanssi' ), '<a href="https://codex.wordpress.org/Class_Reference/WP_Query">WP_Query</a>' ) . '</li>' .
55
+ '</ul>',
56
+ )
57
+ );
58
+ $screen->add_help_tab(
59
+ array(
60
+ 'id' => 'relevanssi-search-exclusions',
61
+ 'title' => __( 'Exclusions', 'relevanssi' ),
62
+ 'content' => '<ul>' .
63
+ // Translators: %s is the link to the Codex page.
64
+ '<li>' . sprintf( __( 'For more exclusion options, see the Codex documentation for %s. For example, to exclude tag ID 10, use', 'relevanssi' ), '<a href="https://codex.wordpress.org/Class_Reference/WP_Query">WP_Query</a>' ) .
65
+ '<pre>&lt;input type="hidden" name="tag__not_in" value="10" /&gt;</pre></li>' .
66
+ // Translators: %s is 'relevanssi_do_not_index'.
67
+ '<li>' . sprintf( __( 'To exclude posts from the index and not just from the search, you can use the %s filter hook. This would not index posts that have a certain taxonomy term:', 'relevanssi' ), '<code>relevanssi_do_not_index</code>' ) .
68
+ '<pre>add_filter( \'relevanssi_do_not_index\', \'rlv_index_filter\', 10, 2 );
69
+ function rlv_index_filter( $block, $post_id ) {
70
+ if ( has_term( \'jazz\', \'genre\', $post_id ) ) {
71
+ $block = true;
72
+ }
73
+ return $block;
74
  }
75
+ </pre></li>' .
76
+ // Translators: %s is a link to the Relevanssi knowledge base.
77
+ '<li>' . sprintf( __( "For more examples, see <a href='%s'>the related knowledge base posts</a>.", 'relevanssi' ), 'https://www.relevanssi.com/tag/relevanssi_do_not_index/' ) . '</li>' .
78
+ '</ul>',
79
+ )
80
+ );
81
+ $screen->add_help_tab(
82
+ array(
83
+ 'id' => 'relevanssi-logging',
84
+ 'title' => __( 'Logs', 'relevanssi' ),
85
+ 'content' => '<ul>' .
86
+ // Translators: %s is 'relevanssi_user_searches_limit'.
87
+ '<li>' . sprintf( __( 'By default, the User searches page shows 20 most common keywords. In order to see more, you can adjust the value with the %s filter hook, like this:', 'relevanssi' ), '<code>relevanssi_user_searches_limit</code>' ) .
88
+ "<pre>add_filter( 'relevanssi_user_searches_limit', function() { return 50; } );</pre></li>" .
89
+ // Translators: %s is the name of the database table.
90
+ '<li>' . sprintf( __( 'The complete logs are stored in the %s database table, where you can access them if you need more information than what the User searches page provides.', 'relevanssi' ), '<code>' . $wpdb->prefix . 'relevanssi_log</code>' ) . '</li>' .
91
+ '</ul>',
92
+ )
93
+ );
94
+ $screen->add_help_tab(
95
+ array(
96
+ 'id' => 'relevanssi-excerpts',
97
+ 'title' => __( 'Excerpts', 'relevanssi' ),
98
+ 'content' => '<ul>' .
99
+ '<li>' . __( 'Building custom excerpts can be slow. If you are not actually using the excerpts, make sure you disable the option.', 'relevanssi' ) . '</li>' .
100
+ // Translators: %s is 'the_excerpt()'.
101
+ '<li>' . sprintf( __( 'Custom snippets require that the search results template uses %s to print out the excerpts.', 'relevanssi' ), '<code>the_excerpt()</code>' ) . '</li>' .
102
+ '<li>' . __( 'Generally, Relevanssi generates the excerpts from post content. If you want to include custom field content in the excerpt-building, this can be done with a simple setting from the excerpt settings.', 'relevanssi' ) . '</li>' .
103
+ // Translators: %1$s is 'relevanssi_pre_excerpt_content', %2$s is 'relevanssi_excerpt_content'.
104
+ '<li>' . sprintf( __( 'If you want more control over what content Relevanssi uses to create the excerpts, you can use the %1$s and %2$s filter hooks to adjust the content.', 'relevanssi' ), '<code>relevanssi_pre_excerpt_content</code>', '<code>relevanssi_excerpt_content</code>' ) . '</li>' .
105
+ // Translators: %s is 'relevanssi_disable_shortcodes_excerpt'.
106
+ '<li>' . sprintf( __( 'Some shortcode do not work well with Relevanssi excerpt-generation. Relevanssi disables some shortcodes automatically to prevent problems. This can be adjusted with the %s filter hook.', 'relevanssi' ), '<code>relevanssi_disable_shortcodes_excerpt</code>' ) . '</li>' .
107
+ // Translators: %s is 'relevanssi_optimize_excerpts'.
108
+ '<li>' . sprintf( __( "If you want Relevanssi to build excerpts faster and don't mind that they may be less than perfect in quality, add a filter that returns true on hook %s.", 'relevanssi' ), '<code>relevanssi_optimize_excerpts</code>' ) .
109
+ "<pre>add_filter( 'relevanssi_optimize_excerpts', '__return_true' );</pre></li>" .
110
+ '</ul>',
111
+ )
112
+ );
113
+ $screen->add_help_tab(
114
+ array(
115
+ 'id' => 'relevanssi-highlights',
116
+ 'title' => __( 'Highlights', 'relevanssi' ),
117
+ 'content' => '<ul>' .
118
+ '<li>' . __( "Title highlights don't appear automatically, because that led to problems with highlights appearing in wrong places and messing up navigation menus, for example.", 'relevanssi' ) . '</li>' .
119
+ // Translators: %1$s is 'the_title()', %2$s is 'relevanssi_the_title()'.
120
+ '<li>' . sprintf( __( 'In order to see title highlights from Relevanssi, replace %1$s in the search results template with %2$s. It does the same thing, but supports Relevanssi title highlights.', 'relevanssi' ), '<code>the_title()</code>', '<code>relevanssi_the_title()</code>' ) . '</li>' .
121
+ '</ul>',
122
+ )
123
+ );
124
+ $screen->add_help_tab(
125
+ array(
126
+ 'id' => 'relevanssi-punctuation',
127
+ 'title' => __( 'Punctuation', 'relevanssi' ),
128
+ 'content' => '<ul>' .
129
+ '<li>' . __( 'Relevanssi removes punctuation. Some punctuation is removed, some replaced with spaces. Advanced indexing settings include some of the more common settings people want to change.', 'relevanssi' ) . '</li>' .
130
+ // Translators: %1$s is 'relevanssi_punctuation_filter', %2$s is 'relevanssi_remove_punctuation'.
131
+ '<li>' . sprintf( __( 'For more fine-tuned changes, you can use %1$s filter hook to adjust what is replaced with what, and %2$s filter hook to completely override the default punctuation control.', 'relevanssi' ), '<code>relevanssi_punctuation_filter</code>', '<code>relevanssi_remove_punctuation</code>' ) . '</li>' .
132
+ // Translators: %s is the URL to the Knowledge Base entry.
133
+ '<li>' . sprintf( __( "For more examples, see <a href='%s'>the related knowledge base posts</a>.", 'relevanssi' ), 'https://www.relevanssi.com/tag/relevanssi_remove_punct/' ) . '</li>' .
134
+ '</ul>',
135
+ )
136
+ );
137
+ $screen->add_help_tab(
138
+ array(
139
+ 'id' => 'relevanssi-helpful-shortcodes',
140
+ 'title' => __( 'Helpful shortcodes', 'relevanssi' ),
141
+ 'content' => '<ul>' .
142
+ // Translators: %s is '[noindex]'.
143
+ '<li>' . sprintf( __( "If you have content that you don't want indexed, you can wrap that content in a %s shortcode.", 'relevanssi' ), '<code>[noindex]</code>' ) . '</li>' .
144
+ // Translators: %s is '[searchform]'.
145
+ '<li>' . sprintf( __( 'If you need a search form on some page on your site, you can use the %s shortcode to print out a basic search form.', 'relevanssi' ), '<code>[searchform]</code>' ) . '</li>' .
146
+ // Translators: %1$s is '[searchform post_types="page"]', %2$s is '[searchform cats="10,14,17"]'.
147
+ '<li>' . sprintf( __( 'If you need to add query variables to the search form, the shortcode takes parameters, which are then printed out as hidden input fields. To get a search form with a post type restriction, you can use %1$s. To restrict the search to categories 10, 14 and 17, you can use %2$s and so on.', 'relevanssi' ), '<code>[searchform post_types="page"]</code>', '<code>[searchform cats="10,14,17"]</code>' ) . '</li>' .
148
+ // Translators: %1$s is 'dropdown', %2$s is '[searchform dropdown="category"]'.
149
+ '<li>' . sprintf( __( 'You can use the %1$s parameter to add a taxonomy dropdown to the search form. Just use the name of the taxonomy, like %2$s. This works best with hierarchical taxonomies like categories with relatively few options available.', 'relevanssi' ), '<code>dropdown</code>', '<code>[searchform dropdown="category"]</code>' ) . '</li>' .
150
+ '</ul>',
151
+ )
152
+ );
153
+ $screen->add_help_tab(
154
+ array(
155
+ 'id' => 'relevanssi-title-woocommerce',
156
+ 'title' => __( 'WooCommerce', 'relevanssi' ),
157
+ 'content' => '<ul>' .
158
+ '<li>' . __( "If your SKUs include hyphens or other punctuation, do note that Relevanssi replaces most punctuation with spaces. That's going to cause issues with SKU searches.", 'relevanssi' ) . '</li>' .
159
+ // Translators: %s is the Knowledge Base URL.
160
+ '<li>' . sprintf( __( "For more details how to fix that issue, see <a href='%s'>WooCommerce tips in Relevanssi user manual</a>.", 'relevanssi' ), 'https://www.relevanssi.com/user-manual/woocommerce/' ) . '</li>' .
161
+ '<li>' . __( "If you don't want to index products that are out of stock, excluded from the catalog or excluded from the search, there's a product visibility filtering method that is described in the user manual (see link above).", 'relevanssi' ) . '</li>' .
162
+ '</ul>',
163
+ )
164
+ );
165
+ $screen->add_help_tab(
166
+ array(
167
+ 'id' => 'relevanssi-exact-match',
168
+ 'title' => __( 'Exact match bonus', 'relevanssi' ),
169
+ 'content' => '<ul>' .
170
+ // Translators: %s is the name of the filter hook.
171
+ '<li>' . sprintf( __( 'To adjust the amount of the exact match bonus, you can use the %s filter hook. It works like this:', 'relevanssi' ), '<code>relevanssi_exact_match_bonus</code>' ) .
172
+ "<pre>add_filter( 'relevanssi_exact_match_bonus', 'rlv_adjust_bonus' );
173
+ function rlv_adjust_bonus( \$bonus ) {
174
+ return array( 'title' => 10, 'content' => 5 );
175
+ }</li>" .
176
+ // Translators: %1$s is the title weight and %2$s is the content weight.
177
+ '<li>' . sprintf( esc_html__( 'The default values are %1$s for titles and %2$s for content.', 'relevanssi' ), '<code>5</code>', '<code>2</code>' ) . '</ul>',
178
+ )
179
+ );
180
  $screen->set_help_sidebar(
181
  '<p><strong>' . __( 'For more information:', 'relevanssi' ) . '</strong></p>' .
182
  '<p><a href="https://www.relevanssi.com/knowledge-base/" target="_blank">' . __( 'Plugin knowledge base', 'relevanssi' ) . '</a></p>' .
lib/excerpts-highlights.php CHANGED
@@ -19,7 +19,7 @@
19
  function relevanssi_the_excerpt() {
20
  global $post;
21
  if ( ! post_password_required( $post ) ) {
22
- echo '<p>' . $post->post_excerpt . '</p>'; // WPCS: XSS ok.
23
  } else {
24
  esc_html_e( 'There is no excerpt because this is a protected post.', 'relevanssi' );
25
  }
@@ -43,7 +43,7 @@ function relevanssi_do_excerpt( $t_post, $query ) {
43
  if ( null !== $post ) {
44
  $old_global_post = $post;
45
  }
46
- $post = $t_post; // WPCS: override ok, must do because shortcodes etc. expect it.
47
 
48
  $remove_stopwords = true;
49
 
@@ -213,7 +213,7 @@ function relevanssi_do_excerpt( $t_post, $query ) {
213
  }
214
 
215
  if ( null !== $old_global_post ) {
216
- $post = $old_global_post; // WPCS: override ok, returning the overridden value.
217
  }
218
 
219
  return $excerpt;
@@ -586,7 +586,7 @@ function relevanssi_highlight_terms( $content, $query, $in_docs = false ) {
586
  */
587
  function relevanssi_fix_entities( $excerpt, $in_docs ) {
588
  if ( ! $in_docs ) {
589
- // For excerpts, use htmlentities().
590
  $excerpt = htmlentities( $excerpt, ENT_NOQUOTES, 'UTF-8' );
591
 
592
  // Except for allowed tags, which are turned back into tags.
@@ -619,7 +619,7 @@ function relevanssi_fix_entities( $excerpt, $in_docs ) {
619
 
620
  $closing_tags_entitied_regexped = array();
621
  foreach ( $closing_tags_entitied as $tag ) {
622
- $pattern = '~' . preg_quote( $tag ) . '~';
623
 
624
  $closing_tags_entitied_regexped[] = $pattern;
625
  }
@@ -824,7 +824,15 @@ function relevanssi_count_matches( $words, $complete_text ) {
824
 
825
  $count_words = count( $words );
826
  for ( $t = 0; $t < $count_words; $t++ ) {
827
- $word_slice = relevanssi_strtolower( relevanssi_add_accent_variations( $words[ $t ] ), 'UTF-8' );
 
 
 
 
 
 
 
 
828
  if ( $word_boundaries_available ) {
829
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
830
  $regex = "/\b$word_slice|$word_slice\b/";
@@ -982,10 +990,13 @@ function relevanssi_add_accent_variations( $word ) {
982
  *
983
  * @param array Array of replacements. 'from' has the source characters, 'to' the replacements.
984
  */
985
- $replacement_arrays = apply_filters('relevanssi_accents_replacement_arrays', array(
986
- 'from' => array( 'a', 'c', 'e', 'i', 'o', 'u', 'n', 'ss' ),
987
- 'to' => array( '(a|á|à|â)', '(c|ç)', '(e|é|è|ê|ë)', '(i|í|ì|î|ï)', '(o|ó|ò|ô|õ)', '(u|ú|ù|ü|û)', '(n|ñ)', '(ss|ß)' ),
988
- ));
 
 
 
989
 
990
  $len = mb_strlen( $word );
991
  $word_array = array();
@@ -1000,6 +1011,8 @@ function relevanssi_add_accent_variations( $word ) {
1000
  $word = preg_replace( '/s$/', "(s|'s|’s)", $word );
1001
  $word = preg_replace( '/^o/', "(o|o'|o’)", $word );
1002
 
 
 
1003
  return $word;
1004
  }
1005
 
@@ -1032,7 +1045,6 @@ function relevanssi_get_custom_field_content( $post_id ) {
1032
  if ( is_array( $custom_fields ) ) {
1033
  $custom_fields = array_unique( $custom_fields ); // No reason to index duplicates.
1034
 
1035
- $repeater_fields = array();
1036
  if ( function_exists( 'relevanssi_add_repeater_fields' ) ) {
1037
  relevanssi_add_repeater_fields( $custom_fields, $post_id );
1038
  }
@@ -1086,27 +1098,30 @@ function relevanssi_remove_page_builder_shortcodes( $content ) {
1086
  *
1087
  * @param array An array of page builder shortcode regexes.
1088
  */
1089
- $search_array = apply_filters('relevanssi_page_builder_shortcodes', array(
1090
- // Remove content.
1091
- '/\[et_pb_code.*?\].*\[\/et_pb_code\]/',
1092
- '/\[et_pb_sidebar.*?\].*\[\/et_pb_sidebar\]/',
1093
- '/\[et_pb_fullwidth_slider.*?\].*\[\/et_pb_fullwidth_slider\]/',
1094
- '/\[vc_raw_html.*?\].*\[\/vc_raw_html\]/',
1095
- // Remove only the tags.
1096
- '/\[\/?et_pb.*?\]/',
1097
- '/\[\/?vc.*?\]/',
1098
- '/\[\/?mk.*?\]/',
1099
- '/\[\/?cs_.*?\]/',
1100
- '/\[\/?av_.*?\]/',
1101
- '/\[\/?fusion_.*?\]/',
1102
- // Max Mega Menu doesn't work in excerpts.
1103
- '/\[maxmegamenu.*?\]/',
1104
- // All-in-one Events Calendar shortcode doesn't look good.
1105
- '/\[ai1ec.*?\]/',
1106
- // Events Made Easy Calendar shortcodes should be removed.
1107
- '/\[eme_.*?\]/',
1108
- ));
1109
- $content = preg_replace( $search_array, '', $content );
 
 
 
1110
  return $content;
1111
  }
1112
 
19
  function relevanssi_the_excerpt() {
20
  global $post;
21
  if ( ! post_password_required( $post ) ) {
22
+ echo '<p>' . $post->post_excerpt . '</p>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
23
  } else {
24
  esc_html_e( 'There is no excerpt because this is a protected post.', 'relevanssi' );
25
  }
43
  if ( null !== $post ) {
44
  $old_global_post = $post;
45
  }
46
+ $post = $t_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
47
 
48
  $remove_stopwords = true;
49
 
213
  }
214
 
215
  if ( null !== $old_global_post ) {
216
+ $post = $old_global_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
217
  }
218
 
219
  return $excerpt;
586
  */
587
  function relevanssi_fix_entities( $excerpt, $in_docs ) {
588
  if ( ! $in_docs ) {
589
+ // For excerpts, use htmlentities() to convert.
590
  $excerpt = htmlentities( $excerpt, ENT_NOQUOTES, 'UTF-8' );
591
 
592
  // Except for allowed tags, which are turned back into tags.
619
 
620
  $closing_tags_entitied_regexped = array();
621
  foreach ( $closing_tags_entitied as $tag ) {
622
+ $pattern = '~' . preg_quote( $tag, '~' ) . '~';
623
 
624
  $closing_tags_entitied_regexped[] = $pattern;
625
  }
824
 
825
  $count_words = count( $words );
826
  for ( $t = 0; $t < $count_words; $t++ ) {
827
+ $word_slice = relevanssi_strtolower(
828
+ relevanssi_add_accent_variations(
829
+ preg_quote(
830
+ $words[ $t ],
831
+ '/'
832
+ )
833
+ ),
834
+ 'UTF-8'
835
+ );
836
  if ( $word_boundaries_available ) {
837
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
838
  $regex = "/\b$word_slice|$word_slice\b/";
990
  *
991
  * @param array Array of replacements. 'from' has the source characters, 'to' the replacements.
992
  */
993
+ $replacement_arrays = apply_filters(
994
+ 'relevanssi_accents_replacement_arrays',
995
+ array(
996
+ 'from' => array( 'a', 'c', 'e', 'i', 'o', 'u', 'n', 'ss' ),
997
+ 'to' => array( '(a|á|à|â)', '(c|ç)', '(e|é|è|ê|ë)', '(i|í|ì|î|ï)', '(o|ó|ò|ô|õ)', '(u|ú|ù|ü|û)', '(n|ñ)', '(ss|ß)' ),
998
+ )
999
+ );
1000
 
1001
  $len = mb_strlen( $word );
1002
  $word_array = array();
1011
  $word = preg_replace( '/s$/', "(s|'s|’s)", $word );
1012
  $word = preg_replace( '/^o/', "(o|o'|o’)", $word );
1013
 
1014
+ $word = str_replace( '\-?/', '\/', $word );
1015
+
1016
  return $word;
1017
  }
1018
 
1045
  if ( is_array( $custom_fields ) ) {
1046
  $custom_fields = array_unique( $custom_fields ); // No reason to index duplicates.
1047
 
 
1048
  if ( function_exists( 'relevanssi_add_repeater_fields' ) ) {
1049
  relevanssi_add_repeater_fields( $custom_fields, $post_id );
1050
  }
1098
  *
1099
  * @param array An array of page builder shortcode regexes.
1100
  */
1101
+ $search_array = apply_filters(
1102
+ 'relevanssi_page_builder_shortcodes',
1103
+ array(
1104
+ // Remove content.
1105
+ '/\[et_pb_code.*?\].*\[\/et_pb_code\]/ims',
1106
+ '/\[et_pb_sidebar.*?\].*\[\/et_pb_sidebar\]/ims',
1107
+ '/\[et_pb_fullwidth_slider.*?\].*\[\/et_pb_fullwidth_slider\]/ims',
1108
+ '/\[vc_raw_html.*?\].*\[\/vc_raw_html\]/ims',
1109
+ // Remove only the tags.
1110
+ '/\[\/?et_pb.*?\]/ims',
1111
+ '/\[\/?vc.*?\]/ims',
1112
+ '/\[\/?mk.*?\]/ims',
1113
+ '/\[\/?cs_.*?\]/ims',
1114
+ '/\[\/?av_.*?\]/ims',
1115
+ '/\[\/?fusion_.*?\]/ims',
1116
+ // Max Mega Menu doesn't work in excerpts.
1117
+ '/\[maxmegamenu.*?\]/ims',
1118
+ // All-in-one Events Calendar shortcode doesn't look good.
1119
+ '/\[ai1ec.*?\]/ims',
1120
+ // Events Made Easy Calendar shortcodes should be removed.
1121
+ '/\[eme_.*?\]/ims',
1122
+ )
1123
+ );
1124
+ $content = preg_replace( $search_array, '', $content );
1125
  return $content;
1126
  }
1127
 
lib/indexing.php CHANGED
@@ -40,9 +40,7 @@ function relevanssi_count_missing_posts() {
40
  * Counts the total number of posts to index, considering post type restrictions and
41
  * the valid statuses.
42
  *
43
- * @global object $wpdb The WordPress database interface.
44
- * @global array $relevanssi_variables The Relevanssi global variables array, used
45
- * for table names.
46
  *
47
  * @param boolean $extend If true, count only missing posts. If false, count all
48
  * posts. Default false.
@@ -50,11 +48,10 @@ function relevanssi_count_missing_posts() {
50
  * @return int The number of posts to index.
51
  */
52
  function relevanssi_indexing_post_counter( $extend = false ) {
53
- global $wpdb, $relevanssi_variables;
54
- $relevanssi_table = $relevanssi_variables['relevanssi_table'];
55
- $restriction = relevanssi_post_type_restriction();
56
- $valid_status = relevanssi_valid_status_array();
57
- $limit = '';
58
 
59
  $query = relevanssi_generate_indexing_query( $valid_status, $extend, $restriction, $limit );
60
  $query = str_replace( 'SELECT post.ID', 'SELECT COUNT(post.ID)', $query );
@@ -66,7 +63,7 @@ function relevanssi_indexing_post_counter( $extend = false ) {
66
  * those missing from the index, depending on the case).
67
  */
68
  do_action( 'relevanssi_pre_indexing_query' );
69
- $count = $wpdb->get_var( $query ); // WPCS: unprepared SQL ok.
70
 
71
  if ( empty( $count ) ) {
72
  $count = 0;
@@ -197,7 +194,7 @@ function relevanssi_post_type_restriction() {
197
  * a custom post status, you can use the 'relevanssi_valid_status' filter hook to add
198
  * your own post status to the list of valid statuses.
199
  *
200
- * @return string A comma-separated list of valid post statuses.
201
  */
202
  function relevanssi_valid_status_array() {
203
  /**
@@ -276,6 +273,13 @@ function relevanssi_build_index( $extend_offset = false, $verbose = true, $post_
276
  }
277
  }
278
 
 
 
 
 
 
 
 
279
  // If $post_limit parameter is present, numeric and > 0, use that.
280
  $limit = '';
281
  if ( isset( $post_limit ) && is_numeric( $post_limit ) && $post_limit > 0 ) {
@@ -329,7 +333,7 @@ function relevanssi_build_index( $extend_offset = false, $verbose = true, $post_
329
 
330
  /* This action documented earlier in lib/indexing.php. */
331
  do_action( 'relevanssi_pre_indexing_query' );
332
- $content = $wpdb->get_results( $query ); // WPCS: unprepared SQL ok.
333
 
334
  if ( defined( 'WP_CLI' ) && WP_CLI && function_exists( 'relevanssi_generate_progress_bar' ) ) {
335
  $progress = relevanssi_generate_progress_bar( 'Indexing posts', count( $content ) );
@@ -353,7 +357,7 @@ function relevanssi_build_index( $extend_offset = false, $verbose = true, $post_
353
  }
354
 
355
  // To prevent empty indices.
356
- $wpdb->query( "ANALYZE TABLE $relevanssi_table" ); // WPCS: unprepared SQL ok, just Relevanssi table name.
357
 
358
  $complete = false;
359
  if ( ( 0 === $size ) || ( count( $content ) < $size ) ) {
@@ -421,7 +425,7 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
421
  $previous_post = null;
422
 
423
  // Check if this is a Jetpack Contact Form entry.
424
- if ( isset( $_REQUEST['contact-form-id'] ) ) { // WPCS: CSRF ok.
425
  return;
426
  }
427
 
@@ -435,24 +439,24 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
435
  }
436
 
437
  if ( is_object( $index_post ) ) {
438
- $post = $index_post; // WPCS: override ok.
439
  } else {
440
- $post = get_post( $index_post ); // WPCS: override ok.
441
  }
442
  } else {
443
  // Quick edit has an array in the global $post, so fetch the post ID for the
444
  // post to edit.
445
  if ( is_array( $post ) ) {
446
- $post = get_post( $post['ID'] ); // WPCS: override ok.
447
  }
448
 
449
  if ( empty( $post ) ) {
450
  // No $post set, so we need to use $indexpost, if it's a post object.
451
  $post_was_null = true;
452
  if ( is_object( $index_post ) ) {
453
- $post = $index_post; // WPCS: override ok.
454
  } else {
455
- $post = get_post( $index_post ); // WPCS: override ok.
456
  }
457
  } else {
458
  // $post was set, let's grab the previous value in case we need it
@@ -463,17 +467,21 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
463
  if ( null === $post ) {
464
  // At this point we should have something in $post; if not, quit.
465
  if ( $post_was_null ) {
466
- $post = null; // WPCS: override ok.
467
  }
468
  if ( $previous_post ) {
469
- $post = $previous_post; // WPCS: override ok.
470
  }
471
  return -1;
472
  }
473
 
474
  // Finally fetch the post again by ID. Complicated, yes, but unless we do this,
475
  // we might end up indexing the post before the updates come in.
476
- $post = get_post( $post->ID ); // WPCS: override ok.
 
 
 
 
477
 
478
  // Post exclusion feature from Relevanssi Premium.
479
  if ( function_exists( 'relevanssi_hide_post' ) ) {
@@ -482,10 +490,10 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
482
  relevanssi_debug_echo( 'relevanssi_hide_post() returned true.' );
483
  }
484
  if ( $post_was_null ) {
485
- $post = null; // WPCS: override ok.
486
  }
487
  if ( $previous_post ) {
488
- $post = $previous_post; // WPCS: override ok.
489
  }
490
  return 'hide';
491
  }
@@ -533,10 +541,10 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
533
  // otherwise a post that's in the index but shouldn't be there won't get removed.
534
  if ( ! $index_this_post ) {
535
  if ( $post_was_null ) {
536
- $post = null; // WPCS: override ok.
537
  }
538
  if ( $previous_post ) {
539
- $post = $previous_post; // WPCS: override ok.
540
  }
541
  return 'donotindex';
542
  }
@@ -550,7 +558,7 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
550
  * @param object $post The post object again (in other uses for this filter, the
551
  * second parameter actually makes sense).
552
  */
553
- $post = apply_filters( 'relevanssi_post_to_index', $post, $post ); // WPCS: override ok.
554
 
555
  $min_word_length = get_option( 'relevanssi_min_word_length', 3 );
556
  $insert_data = array();
@@ -563,7 +571,7 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
563
  if ( ! empty( $post_comments ) ) {
564
  $post_comments = relevanssi_strip_invisibles( $post_comments );
565
  $post_comments = preg_replace( '/<[a-zA-Z\/][^>]*>/', ' ', $post_comments );
566
- $post_comments = strip_tags( $post_comments );
567
  if ( $debug ) {
568
  relevanssi_debug_echo( "Comment content: $post_comments" );
569
  }
@@ -892,7 +900,7 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
892
 
893
  $post_before_shortcode = $post;
894
  $contents = do_shortcode( $contents );
895
- $post = $post_before_shortcode; // WPCS: override ok.
896
 
897
  if ( defined( 'TABLEPRESS_ABSPATH' ) ) {
898
  unset( $my_tablepress_controller );
@@ -916,7 +924,7 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
916
  }
917
 
918
  $contents = preg_replace( '/<[a-zA-Z\/][^>]*>/', ' ', $contents );
919
- $contents = strip_tags( $contents );
920
  if ( function_exists( 'wp_encode_emoji' ) ) {
921
  $contents = wp_encode_emoji( $contents );
922
  }
@@ -987,8 +995,26 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
987
 
988
  $term = trim( $term );
989
 
990
- $value = $wpdb->prepare('(%d, %s, REVERSE(%s), %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %d)',
991
- $post->ID, $term, $term, $content, $title, $comment, $tag, $link, $author, $category, $excerpt, $taxonomy, $customfield, $type, $taxonomy_detail, $customfield_detail, $mysqlcolumn);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
992
 
993
  array_push( $values, $value );
994
  }
@@ -1007,14 +1033,14 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
1007
  if ( $debug ) {
1008
  relevanssi_debug_echo( "Final indexing query:\n\t$query" );
1009
  }
1010
- $wpdb->query( $query ); // WPCS: unprepared sql ok. The values are Relevanssi-generated and safe.
1011
  }
1012
 
1013
  if ( $post_was_null ) {
1014
- $post = null; // WPCS: override ok.
1015
  }
1016
  if ( $previous_post ) {
1017
- $post = $previous_post; // WPCS: override ok.
1018
  }
1019
 
1020
  return $n;
@@ -1190,7 +1216,7 @@ function relevanssi_insert_edit( $post_id ) {
1190
  if ( ! empty( $restriction ) ) {
1191
  // Check the indexing restriction filter: if the post passes the filter, this
1192
  // should return the post ID.
1193
- $is_unrestricted = $wpdb->get_var( "SELECT ID FROM $wpdb->posts AS post WHERE ID = $post_id $restriction" ); // WPCS: unprepared SQL ok.
1194
  if ( ! $is_unrestricted ) {
1195
  $index_this_post = false;
1196
  }
@@ -1385,7 +1411,7 @@ function relevanssi_get_comments( $post_id ) {
1385
  function relevanssi_truncate_index() {
1386
  global $wpdb, $relevanssi_variables;
1387
  $relevanssi_table = $relevanssi_variables['relevanssi_table'];
1388
- return $wpdb->query( "TRUNCATE TABLE $relevanssi_table" ); // WPCS: unprepared SQL ok, Relevanssi table name.
1389
  }
1390
 
1391
  /**
@@ -1415,7 +1441,12 @@ function relevanssi_remove_doc( $post_id, $keep_internal_links = false ) {
1415
 
1416
  $doc_count = get_option( 'relevanssi_doc_count' );
1417
 
1418
- $rows_updated = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc=%d', $post_id ) ); // WPCS: unprepared SQL ok, Relevanssi table name.
 
 
 
 
 
1419
 
1420
  if ( $rows_updated && $rows_updated > 0 ) {
1421
  update_option( 'relevanssi_doc_count', $doc_count - $rows_updated );
40
  * Counts the total number of posts to index, considering post type restrictions and
41
  * the valid statuses.
42
  *
43
+ * @global object $wpdb The WordPress database interface.
 
 
44
  *
45
  * @param boolean $extend If true, count only missing posts. If false, count all
46
  * posts. Default false.
48
  * @return int The number of posts to index.
49
  */
50
  function relevanssi_indexing_post_counter( $extend = false ) {
51
+ global $wpdb;
52
+ $restriction = relevanssi_post_type_restriction();
53
+ $valid_status = relevanssi_valid_status_array();
54
+ $limit = '';
 
55
 
56
  $query = relevanssi_generate_indexing_query( $valid_status, $extend, $restriction, $limit );
57
  $query = str_replace( 'SELECT post.ID', 'SELECT COUNT(post.ID)', $query );
63
  * those missing from the index, depending on the case).
64
  */
65
  do_action( 'relevanssi_pre_indexing_query' );
66
+ $count = $wpdb->get_var( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
67
 
68
  if ( empty( $count ) ) {
69
  $count = 0;
194
  * a custom post status, you can use the 'relevanssi_valid_status' filter hook to add
195
  * your own post status to the list of valid statuses.
196
  *
197
+ * @return string A comma-separated list of valid post statuses ready for MySQL.
198
  */
199
  function relevanssi_valid_status_array() {
200
  /**
273
  }
274
  }
275
 
276
+ // Premium feature: index post type archives.
277
+ if ( function_exists( 'relevanssi_index_post_type_archives' ) ) {
278
+ if ( 'on' === get_option( 'relevanssi_index_post_type_archives' ) ) {
279
+ relevanssi_index_post_type_archives();
280
+ }
281
+ }
282
+
283
  // If $post_limit parameter is present, numeric and > 0, use that.
284
  $limit = '';
285
  if ( isset( $post_limit ) && is_numeric( $post_limit ) && $post_limit > 0 ) {
333
 
334
  /* This action documented earlier in lib/indexing.php. */
335
  do_action( 'relevanssi_pre_indexing_query' );
336
+ $content = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
337
 
338
  if ( defined( 'WP_CLI' ) && WP_CLI && function_exists( 'relevanssi_generate_progress_bar' ) ) {
339
  $progress = relevanssi_generate_progress_bar( 'Indexing posts', count( $content ) );
357
  }
358
 
359
  // To prevent empty indices.
360
+ $wpdb->query( "ANALYZE TABLE $relevanssi_table" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
361
 
362
  $complete = false;
363
  if ( ( 0 === $size ) || ( count( $content ) < $size ) ) {
425
  $previous_post = null;
426
 
427
  // Check if this is a Jetpack Contact Form entry.
428
+ if ( isset( $_REQUEST['contact-form-id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
429
  return;
430
  }
431
 
439
  }
440
 
441
  if ( is_object( $index_post ) ) {
442
+ $post = $index_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
443
  } else {
444
+ $post = get_post( $index_post ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
445
  }
446
  } else {
447
  // Quick edit has an array in the global $post, so fetch the post ID for the
448
  // post to edit.
449
  if ( is_array( $post ) ) {
450
+ $post = get_post( $post['ID'] ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
451
  }
452
 
453
  if ( empty( $post ) ) {
454
  // No $post set, so we need to use $indexpost, if it's a post object.
455
  $post_was_null = true;
456
  if ( is_object( $index_post ) ) {
457
+ $post = $index_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
458
  } else {
459
+ $post = get_post( $index_post ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
460
  }
461
  } else {
462
  // $post was set, let's grab the previous value in case we need it
467
  if ( null === $post ) {
468
  // At this point we should have something in $post; if not, quit.
469
  if ( $post_was_null ) {
470
+ $post = null; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
471
  }
472
  if ( $previous_post ) {
473
+ $post = $previous_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
474
  }
475
  return -1;
476
  }
477
 
478
  // Finally fetch the post again by ID. Complicated, yes, but unless we do this,
479
  // we might end up indexing the post before the updates come in.
480
+ $post = get_post( $post->ID ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
481
+
482
+ if ( null === $post ) {
483
+ return -1;
484
+ }
485
 
486
  // Post exclusion feature from Relevanssi Premium.
487
  if ( function_exists( 'relevanssi_hide_post' ) ) {
490
  relevanssi_debug_echo( 'relevanssi_hide_post() returned true.' );
491
  }
492
  if ( $post_was_null ) {
493
+ $post = null; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
494
  }
495
  if ( $previous_post ) {
496
+ $post = $previous_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
497
  }
498
  return 'hide';
499
  }
541
  // otherwise a post that's in the index but shouldn't be there won't get removed.
542
  if ( ! $index_this_post ) {
543
  if ( $post_was_null ) {
544
+ $post = null; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
545
  }
546
  if ( $previous_post ) {
547
+ $post = $previous_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
548
  }
549
  return 'donotindex';
550
  }
558
  * @param object $post The post object again (in other uses for this filter, the
559
  * second parameter actually makes sense).
560
  */
561
+ $post = apply_filters( 'relevanssi_post_to_index', $post, $post ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
562
 
563
  $min_word_length = get_option( 'relevanssi_min_word_length', 3 );
564
  $insert_data = array();
571
  if ( ! empty( $post_comments ) ) {
572
  $post_comments = relevanssi_strip_invisibles( $post_comments );
573
  $post_comments = preg_replace( '/<[a-zA-Z\/][^>]*>/', ' ', $post_comments );
574
+ $post_comments = wp_strip_all_tags( $post_comments );
575
  if ( $debug ) {
576
  relevanssi_debug_echo( "Comment content: $post_comments" );
577
  }
900
 
901
  $post_before_shortcode = $post;
902
  $contents = do_shortcode( $contents );
903
+ $post = $post_before_shortcode; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
904
 
905
  if ( defined( 'TABLEPRESS_ABSPATH' ) ) {
906
  unset( $my_tablepress_controller );
924
  }
925
 
926
  $contents = preg_replace( '/<[a-zA-Z\/][^>]*>/', ' ', $contents );
927
+ $contents = wp_strip_all_tags( $contents );
928
  if ( function_exists( 'wp_encode_emoji' ) ) {
929
  $contents = wp_encode_emoji( $contents );
930
  }
995
 
996
  $term = trim( $term );
997
 
998
+ $value = $wpdb->prepare(
999
+ '(%d, %s, REVERSE(%s), %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %d)',
1000
+ $post->ID,
1001
+ $term,
1002
+ $term,
1003
+ $content,
1004
+ $title,
1005
+ $comment,
1006
+ $tag,
1007
+ $link,
1008
+ $author,
1009
+ $category,
1010
+ $excerpt,
1011
+ $taxonomy,
1012
+ $customfield,
1013
+ $type,
1014
+ $taxonomy_detail,
1015
+ $customfield_detail,
1016
+ $mysqlcolumn
1017
+ );
1018
 
1019
  array_push( $values, $value );
1020
  }
1033
  if ( $debug ) {
1034
  relevanssi_debug_echo( "Final indexing query:\n\t$query" );
1035
  }
1036
+ $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1037
  }
1038
 
1039
  if ( $post_was_null ) {
1040
+ $post = null; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1041
  }
1042
  if ( $previous_post ) {
1043
+ $post = $previous_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1044
  }
1045
 
1046
  return $n;
1216
  if ( ! empty( $restriction ) ) {
1217
  // Check the indexing restriction filter: if the post passes the filter, this
1218
  // should return the post ID.
1219
+ $is_unrestricted = $wpdb->get_var( "SELECT ID FROM $wpdb->posts AS post WHERE ID = $post_id $restriction" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1220
  if ( ! $is_unrestricted ) {
1221
  $index_this_post = false;
1222
  }
1411
  function relevanssi_truncate_index() {
1412
  global $wpdb, $relevanssi_variables;
1413
  $relevanssi_table = $relevanssi_variables['relevanssi_table'];
1414
+ return $wpdb->query( "TRUNCATE TABLE $relevanssi_table" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1415
  }
1416
 
1417
  /**
1441
 
1442
  $doc_count = get_option( 'relevanssi_doc_count' );
1443
 
1444
+ $rows_updated = $wpdb->query(
1445
+ $wpdb->prepare(
1446
+ 'DELETE FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc=%d', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1447
+ $post_id
1448
+ )
1449
+ );
1450
 
1451
  if ( $rows_updated && $rows_updated > 0 ) {
1452
  update_option( 'relevanssi_doc_count', $doc_count - $rows_updated );
lib/init.php CHANGED
@@ -70,9 +70,12 @@ function relevanssi_init() {
70
 
71
  $plugin_dir = dirname( plugin_basename( $relevanssi_variables['file'] ) );
72
  load_plugin_textdomain( 'relevanssi', false, $plugin_dir . '/languages' );
73
- $page = '';
74
- if ( isset( $_GET['page'] ) ) {
75
- $page = $_GET['page']; // WPCS: CSRF ok; this value is read-only.
 
 
 
76
  }
77
 
78
  if ( 'done' !== get_option( 'relevanssi_indexed' ) ) {
@@ -86,7 +89,7 @@ function relevanssi_init() {
86
  }
87
  printf( "<div id='relevanssi-warning' class='update-nag'><p><strong>%s</strong></p></div>", esc_html__( 'You do not have an index! Remember to build the index (click the "Build the index" button), otherwise searching won\'t work.', 'relevanssi' ) );
88
  }
89
- if ( 'options-general.php' === $pagenow && plugin_basename( $relevanssi_variables['file'] ) === $page ) {
90
  add_action( 'admin_notices', 'relevanssi_warning' );
91
  }
92
  }
@@ -98,7 +101,7 @@ function relevanssi_init() {
98
  function relevanssi_mb_warning() {
99
  printf( "<div id='relevanssi-warning' class='error'><p><strong>%s</strong></p></div>", esc_html__( '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' ) );
100
  }
101
- if ( 'options-general.php' === $pagenow && plugin_basename( $relevanssi_variables['file'] ) === $page ) {
102
  add_action( 'admin_notices', 'relevanssi_mb_warning' );
103
  }
104
  }
@@ -147,6 +150,10 @@ function relevanssi_init() {
147
  if ( defined( 'WPFD_VERSION' ) ) {
148
  require_once 'compatibility/wp-file-download.php';
149
  }
 
 
 
 
150
  }
151
 
152
  /**
@@ -160,7 +167,7 @@ function relevanssi_admin_init() {
160
  require_once $relevanssi_variables['plugin_dir'] . 'lib/admin-ajax.php';
161
 
162
  add_action( 'admin_enqueue_scripts', 'relevanssi_add_admin_scripts' );
163
- add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'relevanssi_action_links' );
164
  }
165
 
166
  /**
@@ -297,45 +304,45 @@ function relevanssi_create_database_tables( $relevanssi_db_version ) {
297
  dbDelta( $sql );
298
 
299
  $sql = "SHOW INDEX FROM $relevanssi_table";
300
- $indices = $wpdb->get_results( $sql ); // WPCS: unprepared SQL ok.
301
 
302
  $terms_exists = false;
303
  $relevanssi_term_reverse_idx_exists = false;
304
  $docs_exists = false;
305
  $typeitem_exists = false;
306
  foreach ( $indices as $index ) {
307
- if ( 'terms' === $index->Key_name ) {
308
  $terms_exists = true;
309
  }
310
- if ( 'relevanssi_term_reverse_idx' === $index->Key_name ) {
311
  $relevanssi_term_reverse_idx_exists = true;
312
  }
313
- if ( 'docs' === $index->Key_name ) {
314
  $docs_exists = true;
315
  }
316
- if ( 'typeitem' === $index->Key_name ) {
317
  $typeitem_exists = true;
318
  }
319
  }
320
 
321
  if ( ! $terms_exists ) {
322
  $sql = "CREATE INDEX terms ON $relevanssi_table (term(20))";
323
- $wpdb->query( $sql ); // WPCS: unprepared SQL ok.
324
  }
325
 
326
  if ( ! $relevanssi_term_reverse_idx_exists ) {
327
  $sql = "CREATE INDEX relevanssi_term_reverse_idx ON $relevanssi_table (term_reverse(10))";
328
- $wpdb->query( $sql ); // WPCS: unprepared SQL ok.
329
  }
330
 
331
  if ( ! $docs_exists ) {
332
  $sql = "CREATE INDEX docs ON $relevanssi_table (doc)";
333
- $wpdb->query( $sql ); // WPCS: unprepared SQL ok.
334
  }
335
 
336
  if ( ! $typeitem_exists ) {
337
  $sql = "CREATE INDEX typeitem ON $relevanssi_table (type(190), item)";
338
- $wpdb->query( $sql ); // WPCS: unprepared SQL ok.
339
  }
340
 
341
  $sql = 'CREATE TABLE ' . $relevanssi_stopword_table . " (stopword varchar(50) $charset_collate_bin_column NOT NULL,
@@ -354,24 +361,24 @@ function relevanssi_create_database_tables( $relevanssi_db_version ) {
354
  dbDelta( $sql );
355
 
356
  $sql = "SHOW INDEX FROM $relevanssi_log_table";
357
- $indices = $wpdb->get_results( $sql ); // WPCS: unprepared SQL ok.
358
 
359
  $query_exists = false;
360
  foreach ( $indices as $index ) {
361
- if ( 'query' === $index->Key_name ) {
362
  $query_exists = true;
363
  }
364
  }
365
 
366
  if ( ! $query_exists ) {
367
  $sql = "CREATE INDEX query ON $relevanssi_log_table (query(190))";
368
- $wpdb->query( $sql ); // WPCS: unprepared SQL ok.
369
  }
370
 
371
  update_option( 'relevanssi_db_version', $relevanssi_db_version );
372
  }
373
 
374
- if ( $wpdb->get_var( "SELECT COUNT(*) FROM $relevanssi_stopword_table WHERE 1" ) < 1 ) { // WPCS: unprepared SQL ok.
375
  relevanssi_populate_stopwords();
376
  }
377
  }
@@ -396,7 +403,7 @@ function relevanssi_action_links( $links ) {
396
  if ( ! RELEVANSSI_PREMIUM ) {
397
  $relevanssi_links[] = '<a href="https://www.relevanssi.com/buy-premium/">' . __( 'Go Premium!', 'relevanssi' ) . '</a>';
398
  }
399
- return array_merge( $links, $relevanssi_links );
400
  }
401
 
402
  /**
@@ -419,7 +426,7 @@ function relevanssi_rest_api_disable() {
419
  * @see relevanssi_export_log
420
  */
421
  function relevanssi_export_log_check() {
422
- if ( isset( $_REQUEST['relevanssi_export'] ) ) { // WPCS: CSRF ok, just checking the parameter exists.
423
  relevanssi_export_log();
424
  }
425
  }
70
 
71
  $plugin_dir = dirname( plugin_basename( $relevanssi_variables['file'] ) );
72
  load_plugin_textdomain( 'relevanssi', false, $plugin_dir . '/languages' );
73
+ $on_relevanssi_page = false;
74
+ if ( isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
75
+ $page = sanitize_file_name( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
76
+ if ( plugin_basename( $relevanssi_variables['file'] ) === $page ) {
77
+ $on_relevanssi_page = true;
78
+ }
79
  }
80
 
81
  if ( 'done' !== get_option( 'relevanssi_indexed' ) ) {
89
  }
90
  printf( "<div id='relevanssi-warning' class='update-nag'><p><strong>%s</strong></p></div>", esc_html__( 'You do not have an index! Remember to build the index (click the "Build the index" button), otherwise searching won\'t work.', 'relevanssi' ) );
91
  }
92
+ if ( 'options-general.php' === $pagenow && $on_relevanssi_page ) {
93
  add_action( 'admin_notices', 'relevanssi_warning' );
94
  }
95
  }
101
  function relevanssi_mb_warning() {
102
  printf( "<div id='relevanssi-warning' class='error'><p><strong>%s</strong></p></div>", esc_html__( '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' ) );
103
  }
104
+ if ( 'options-general.php' === $pagenow && $on_relevanssi_page ) {
105
  add_action( 'admin_notices', 'relevanssi_mb_warning' );
106
  }
107
  }
150
  if ( defined( 'WPFD_VERSION' ) ) {
151
  require_once 'compatibility/wp-file-download.php';
152
  }
153
+
154
+ if ( defined( 'WPSEO_FILE' ) ) {
155
+ require_once 'compatibility/yoast-seo.php';
156
+ }
157
  }
158
 
159
  /**
167
  require_once $relevanssi_variables['plugin_dir'] . 'lib/admin-ajax.php';
168
 
169
  add_action( 'admin_enqueue_scripts', 'relevanssi_add_admin_scripts' );
170
+ add_filter( 'plugin_action_links_' . $relevanssi_variables['plugin_basename'], 'relevanssi_action_links' );
171
  }
172
 
173
  /**
304
  dbDelta( $sql );
305
 
306
  $sql = "SHOW INDEX FROM $relevanssi_table";
307
+ $indices = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery
308
 
309
  $terms_exists = false;
310
  $relevanssi_term_reverse_idx_exists = false;
311
  $docs_exists = false;
312
  $typeitem_exists = false;
313
  foreach ( $indices as $index ) {
314
+ if ( 'terms' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
315
  $terms_exists = true;
316
  }
317
+ if ( 'relevanssi_term_reverse_idx' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
318
  $relevanssi_term_reverse_idx_exists = true;
319
  }
320
+ if ( 'docs' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
321
  $docs_exists = true;
322
  }
323
+ if ( 'typeitem' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
324
  $typeitem_exists = true;
325
  }
326
  }
327
 
328
  if ( ! $terms_exists ) {
329
  $sql = "CREATE INDEX terms ON $relevanssi_table (term(20))";
330
+ $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
331
  }
332
 
333
  if ( ! $relevanssi_term_reverse_idx_exists ) {
334
  $sql = "CREATE INDEX relevanssi_term_reverse_idx ON $relevanssi_table (term_reverse(10))";
335
+ $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
336
  }
337
 
338
  if ( ! $docs_exists ) {
339
  $sql = "CREATE INDEX docs ON $relevanssi_table (doc)";
340
+ $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
341
  }
342
 
343
  if ( ! $typeitem_exists ) {
344
  $sql = "CREATE INDEX typeitem ON $relevanssi_table (type(190), item)";
345
+ $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery
346
  }
347
 
348
  $sql = 'CREATE TABLE ' . $relevanssi_stopword_table . " (stopword varchar(50) $charset_collate_bin_column NOT NULL,
361
  dbDelta( $sql );
362
 
363
  $sql = "SHOW INDEX FROM $relevanssi_log_table";
364
+ $indices = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
365
 
366
  $query_exists = false;
367
  foreach ( $indices as $index ) {
368
+ if ( 'query' === $index->Key_name ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
369
  $query_exists = true;
370
  }
371
  }
372
 
373
  if ( ! $query_exists ) {
374
  $sql = "CREATE INDEX query ON $relevanssi_log_table (query(190))";
375
+ $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
376
  }
377
 
378
  update_option( 'relevanssi_db_version', $relevanssi_db_version );
379
  }
380
 
381
+ if ( $wpdb->get_var( "SELECT COUNT(*) FROM $relevanssi_stopword_table WHERE 1" ) < 1 ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
382
  relevanssi_populate_stopwords();
383
  }
384
  }
403
  if ( ! RELEVANSSI_PREMIUM ) {
404
  $relevanssi_links[] = '<a href="https://www.relevanssi.com/buy-premium/">' . __( 'Go Premium!', 'relevanssi' ) . '</a>';
405
  }
406
+ return array_merge( $relevanssi_links, $links );
407
  }
408
 
409
  /**
426
  * @see relevanssi_export_log
427
  */
428
  function relevanssi_export_log_check() {
429
+ if ( isset( $_REQUEST['relevanssi_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification, just checking the parameter exists.
430
  relevanssi_export_log();
431
  }
432
  }
lib/install.php CHANGED
@@ -109,11 +109,14 @@ function _relevanssi_install() {
109
  add_option( 'relevanssi_min_word_length', '3' );
110
  add_option( 'relevanssi_omit_from_logs', '' );
111
  add_option( 'relevanssi_polylang_all_languages', 'off' );
112
- add_option( 'relevanssi_punctuation', array(
113
- 'quotes' => 'replace',
114
- 'hyphens' => 'replace',
115
- 'ampersands' => 'replace',
116
- ));
 
 
 
117
  add_option( 'relevanssi_respect_exclude', 'on' );
118
  add_option( 'relevanssi_show_matches', '' );
119
  add_option( 'relevanssi_show_matches_text', '(Search hits: %body% in body, %title% in title, %categories% in categories, %tags% in tags, %taxonomies% in other taxonomies, %comments% in comments. Score: %score%)' );
109
  add_option( 'relevanssi_min_word_length', '3' );
110
  add_option( 'relevanssi_omit_from_logs', '' );
111
  add_option( 'relevanssi_polylang_all_languages', 'off' );
112
+ add_option(
113
+ 'relevanssi_punctuation',
114
+ array(
115
+ 'quotes' => 'replace',
116
+ 'hyphens' => 'replace',
117
+ 'ampersands' => 'replace',
118
+ )
119
+ );
120
  add_option( 'relevanssi_respect_exclude', 'on' );
121
  add_option( 'relevanssi_show_matches', '' );
122
  add_option( 'relevanssi_show_matches_text', '(Search hits: %body% in body, %title% in title, %categories% in categories, %tags% in tags, %taxonomies% in other taxonomies, %comments% in comments. Score: %score%)' );
lib/interface.php CHANGED
@@ -95,7 +95,7 @@ function relevanssi_options() {
95
  * check_admin_referer() is done immediately before this function is called.
96
  */
97
  function update_relevanssi_options() {
98
- // phpcs:disable WordPress.CSRF.NonceVerification
99
  if ( isset( $_REQUEST['relevanssi_content_boost'] ) ) {
100
  $boost = floatval( $_REQUEST['relevanssi_content_boost'] );
101
  update_option( 'relevanssi_content_boost', $boost );
@@ -532,7 +532,7 @@ function relevanssi_admin_search_page() {
532
  function relevanssi_truncate_logs( $verbose = true ) {
533
  global $wpdb, $relevanssi_variables;
534
 
535
- $result = $wpdb->query( 'TRUNCATE ' . $relevanssi_variables['log_table'] ); // WPCS: unprepared SQL ok.
536
 
537
  if ( $verbose ) {
538
  if ( false !== $result ) {
@@ -574,7 +574,7 @@ function relevanssi_query_log() {
574
 
575
  printf( '<h3>%s</h3>', esc_html__( 'Total Searches', 'relevanssi' ) );
576
 
577
- printf( "<div style='width: 50%%; overflow: auto'>%s</div>", relevanssi_total_queries( __( 'Totals', 'relevanssi' ) ) ); // WPCS: XSS ok, already escaped by relevanssi_total_queries().
578
 
579
  echo '<div style="clear: both"></div>';
580
 
@@ -632,9 +632,18 @@ function relevanssi_query_log() {
632
  printf( '<h3>%s</h3>', esc_html__( 'Reset Logs', 'relevanssi' ) );
633
  print( "<form method='post'>" );
634
  wp_nonce_field( 'relevanssi_reset_logs', '_relresnonce', true, true );
635
- // Translators: %1$s is the input field, %2$s is the submit button.
636
- printf( '<p>%s</p></form>', sprintf( __( 'To reset the logs, type "reset" into the box here %1$s and click %2$s', 'relevanssi' ), ' <input type="text" name="relevanssi_reset_code" />', ' <input type="submit" name="relevanssi_reset" value="Reset" class="button" />' ) ); // WPCS: XSS ok.
637
-
 
 
 
 
 
 
 
 
 
638
  }
639
 
640
  echo '</div>';
@@ -660,13 +669,17 @@ function relevanssi_total_queries( $title ) {
660
  $titles[2] = __( 'Last 30 days', 'relevanssi' );
661
  $titles[3] = __( 'Forever', 'relevanssi' );
662
 
663
- $count[0] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= 1;" ); // WPCS: unprepared SQL ok, Relevanssi table name.
664
- $count[1] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= 7;" ); // WPCS: unprepared SQL ok, Relevanssi table name.
665
- $count[2] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= 30;" ); // WPCS: unprepared SQL ok, Relevanssi table name.
666
- $count[3] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table;" ); // WPCS: unprepared SQL ok, Relevanssi table name.
667
 
668
- printf( '<table class="widefat"><thead><tr><th colspan="2">%1$s</th></tr></thead><tbody><tr><th>%2$s</th><th style="text-align: center">%3$s</th></tr>',
669
- esc_html( $title ), esc_html__( 'When', 'relevanssi' ), esc_html__( 'Searches', 'relevanssi' ) );
 
 
 
 
670
 
671
  foreach ( $count as $key => $searches ) {
672
  $when = $titles[ $key ];
@@ -696,40 +709,51 @@ function relevanssi_date_queries( $days, $title, $version = 'good' ) {
696
  if ( 'good' === $version ) {
697
  $queries = $wpdb->get_results(
698
  $wpdb->prepare(
699
- "SELECT COUNT(DISTINCT(id)) as cnt, query, hits
700
- FROM $log_table
701
- WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= %d
702
  GROUP BY query
703
  ORDER BY cnt DESC
704
- LIMIT %d",
705
- $days, $limit
 
706
  )
707
- ); // WPCS: unprepared SQL ok, Relevanssi table name.
708
  }
709
 
710
  if ( 'bad' === $version ) {
711
  $queries = $wpdb->get_results(
712
  $wpdb->prepare(
713
- "SELECT COUNT(DISTINCT(id)) as cnt, query, hits
714
- FROM $log_table
715
- WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= %d AND hits = 0
716
  GROUP BY query
717
  ORDER BY cnt DESC
718
- LIMIT %d",
719
- $days, $limit
 
720
  )
721
- ); // WPCS: unprepared SQL ok, Relevanssi table name.
722
  }
723
 
724
  if ( count( $queries ) > 0 ) {
725
- printf( "<table class='widefat'><thead><tr><th colspan='3'>%s</th></tr></thead><tbody><tr><th>%s</th><th style='text-align: center'>#</th><th style='text-align: center'>%s</th></tr>",
726
- esc_html( $title ), esc_html__( 'Query', 'relevanssi' ), esc_html__( 'Hits', 'relevanssi' ) );
 
 
 
 
727
  $url = get_bloginfo( 'url' );
728
  foreach ( $queries as $query ) {
729
  $search_parameter = rawurlencode( $query->query );
730
  $query_url = $url . '/?s=' . $search_parameter;
731
- printf( "<tr><td><a href='%s'>%s</a></td><td style='padding: 3px 5px; text-align: center'>%d</td><td style='padding: 3px 5px; text-align: center'>%d</td></tr>",
732
- esc_attr( $query_url ), esc_attr( $query->query ), intval( $query->cnt ), intval( $query->hits ) );
 
 
 
 
 
733
  }
734
  echo '</tbody></table>';
735
  }
@@ -790,8 +814,8 @@ function relevanssi_options_form() {
790
  $display_save_button = true;
791
 
792
  $active_tab = 'overview';
793
- if ( isset( $_REQUEST['tab'] ) ) { // WPCS: CSRF ok.
794
- $active_tab = $_REQUEST['tab']; // WPCS: CSRF ok. The value is printed once, but there it is escaped.
795
  }
796
 
797
  if ( 'stopwords' === $active_tab ) {
@@ -801,7 +825,7 @@ function relevanssi_options_form() {
801
  printf( "<input type='hidden' name='tab' value='%s' />", esc_attr( $active_tab ) );
802
 
803
  $this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
804
- ?>
805
 
806
  <h2 class="nav-tab-wrapper">
807
  <a href="<?php echo esc_attr( $this_page ); ?>&amp;tab=overview" class="nav-tab <?php echo 'overview' === $active_tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Overview', 'relevanssi' ); ?></a>
@@ -885,7 +909,7 @@ function relevanssi_options_form() {
885
  }
886
 
887
  if ( $display_save_button ) :
888
- ?>
889
 
890
  <input type='submit' name='submit' value='<?php esc_attr_e( 'Save the options', 'relevanssi' ); ?>' class='button button-primary' />
891
 
@@ -924,14 +948,14 @@ function relevanssi_add_admin_scripts( $hook ) {
924
  }
925
 
926
  wp_enqueue_style( 'wp-color-picker' );
927
- wp_enqueue_script( 'relevanssi_admin_js', $plugin_dir_url . 'lib/admin_scripts.js', array( 'wp-color-picker' ) );
928
  if ( ! RELEVANSSI_PREMIUM ) {
929
- wp_enqueue_script( 'relevanssi_admin_js_free', $plugin_dir_url . 'lib/admin_scripts_free.js', array( 'relevanssi_admin_js' ) );
930
  }
931
  if ( RELEVANSSI_PREMIUM ) {
932
- wp_enqueue_script( 'relevanssi_admin_js_premium', $plugin_dir_url . 'premium/admin_scripts_premium.js', array( 'relevanssi_admin_js' ) );
933
  }
934
- wp_enqueue_style( 'relevanssi_admin_css', $plugin_dir_url . 'lib/admin_styles.css' );
935
 
936
  $localizations = array(
937
  'confirm' => __( 'Click OK to copy Relevanssi options to all subsites', 'relevanssi' ),
@@ -978,6 +1002,9 @@ function relevanssi_add_admin_scripts( $hook ) {
978
  if ( ! RELEVANSSI_PREMIUM ) {
979
  wp_localize_script( 'relevanssi_admin_js', 'nonce', $nonce );
980
  }
 
 
 
981
  }
982
 
983
  /**
@@ -994,7 +1021,7 @@ function relevanssi_form_tag_weight() {
994
  if ( isset( $taxonomy_weights['category'] ) ) {
995
  $category_value = $taxonomy_weights['category'];
996
  }
997
- ?>
998
  <tr>
999
  <td>
1000
  <?php esc_html_e( 'Tag weight', 'relevanssi' ); ?>
@@ -1011,5 +1038,5 @@ function relevanssi_form_tag_weight() {
1011
  <input type='text' id='relevanssi_weight_category' name='relevanssi_weight_category' size='4' value='<?php echo esc_attr( $category_value ); ?>' />
1012
  </td>
1013
  </tr>
1014
- <?php
1015
  }
95
  * check_admin_referer() is done immediately before this function is called.
96
  */
97
  function update_relevanssi_options() {
98
+ // phpcs:disable WordPress.Security.NonceVerification
99
  if ( isset( $_REQUEST['relevanssi_content_boost'] ) ) {
100
  $boost = floatval( $_REQUEST['relevanssi_content_boost'] );
101
  update_option( 'relevanssi_content_boost', $boost );
532
  function relevanssi_truncate_logs( $verbose = true ) {
533
  global $wpdb, $relevanssi_variables;
534
 
535
+ $result = $wpdb->query( 'TRUNCATE ' . $relevanssi_variables['log_table'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
536
 
537
  if ( $verbose ) {
538
  if ( false !== $result ) {
574
 
575
  printf( '<h3>%s</h3>', esc_html__( 'Total Searches', 'relevanssi' ) );
576
 
577
+ printf( "<div style='width: 50%%; overflow: auto'>%s</div>", relevanssi_total_queries( __( 'Totals', 'relevanssi' ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
578
 
579
  echo '<div style="clear: both"></div>';
580
 
632
  printf( '<h3>%s</h3>', esc_html__( 'Reset Logs', 'relevanssi' ) );
633
  print( "<form method='post'>" );
634
  wp_nonce_field( 'relevanssi_reset_logs', '_relresnonce', true, true );
635
+ printf(
636
+ '<p><label for="relevanssi_reset_code">%s</label></p></form>',
637
+ sprintf(
638
+ // Translators: %1$s is the input field, %2$s is the submit button.
639
+ __( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
640
+ 'To reset the logs, type "reset" into the box here %1$s and click %2$s',
641
+ 'relevanssi'
642
+ ),
643
+ ' <input type="text" id="relevanssi_reset_code" name="relevanssi_reset_code" />',
644
+ ' <input type="submit" name="relevanssi_reset" value="Reset" class="button" />'
645
+ )
646
+ );
647
  }
648
 
649
  echo '</div>';
669
  $titles[2] = __( 'Last 30 days', 'relevanssi' );
670
  $titles[3] = __( 'Forever', 'relevanssi' );
671
 
672
+ $count[0] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= 1;" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
673
+ $count[1] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= 7;" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
674
+ $count[2] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= 30;" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
675
+ $count[3] = $wpdb->get_var( "SELECT COUNT(id) FROM $log_table;" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
676
 
677
+ printf(
678
+ '<table class="widefat"><thead><tr><th colspan="2">%1$s</th></tr></thead><tbody><tr><th>%2$s</th><th style="text-align: center">%3$s</th></tr>',
679
+ esc_html( $title ),
680
+ esc_html__( 'When', 'relevanssi' ),
681
+ esc_html__( 'Searches', 'relevanssi' )
682
+ );
683
 
684
  foreach ( $count as $key => $searches ) {
685
  $when = $titles[ $key ];
709
  if ( 'good' === $version ) {
710
  $queries = $wpdb->get_results(
711
  $wpdb->prepare(
712
+ 'SELECT COUNT(DISTINCT(id)) as cnt, query, hits ' .
713
+ "FROM $log_table " . // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
714
+ 'WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= %d
715
  GROUP BY query
716
  ORDER BY cnt DESC
717
+ LIMIT %d',
718
+ $days,
719
+ $limit
720
  )
721
+ );
722
  }
723
 
724
  if ( 'bad' === $version ) {
725
  $queries = $wpdb->get_results(
726
  $wpdb->prepare(
727
+ 'SELECT COUNT(DISTINCT(id)) as cnt, query, hits ' .
728
+ "FROM $log_table " . // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
729
+ 'WHERE TIMESTAMPDIFF(DAY, time, NOW()) <= %d AND hits = 0
730
  GROUP BY query
731
  ORDER BY cnt DESC
732
+ LIMIT %d',
733
+ $days,
734
+ $limit
735
  )
736
+ ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
737
  }
738
 
739
  if ( count( $queries ) > 0 ) {
740
+ printf(
741
+ "<table class='widefat'><thead><tr><th colspan='3'>%s</th></tr></thead><tbody><tr><th>%s</th><th style='text-align: center'>#</th><th style='text-align: center'>%s</th></tr>",
742
+ esc_html( $title ),
743
+ esc_html__( 'Query', 'relevanssi' ),
744
+ esc_html__( 'Hits', 'relevanssi' )
745
+ );
746
  $url = get_bloginfo( 'url' );
747
  foreach ( $queries as $query ) {
748
  $search_parameter = rawurlencode( $query->query );
749
  $query_url = $url . '/?s=' . $search_parameter;
750
+ printf(
751
+ "<tr><td><a href='%s'>%s</a></td><td style='padding: 3px 5px; text-align: center'>%d</td><td style='padding: 3px 5px; text-align: center'>%d</td></tr>",
752
+ esc_attr( $query_url ),
753
+ esc_attr( $query->query ),
754
+ intval( $query->cnt ),
755
+ intval( $query->hits )
756
+ );
757
  }
758
  echo '</tbody></table>';
759
  }
814
  $display_save_button = true;
815
 
816
  $active_tab = 'overview';
817
+ if ( isset( $_REQUEST['tab'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
818
+ $active_tab = $_REQUEST['tab']; // phpcs:ignore WordPress.Security.NonceVerification
819
  }
820
 
821
  if ( 'stopwords' === $active_tab ) {
825
  printf( "<input type='hidden' name='tab' value='%s' />", esc_attr( $active_tab ) );
826
 
827
  $this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
828
+ ?>
829
 
830
  <h2 class="nav-tab-wrapper">
831
  <a href="<?php echo esc_attr( $this_page ); ?>&amp;tab=overview" class="nav-tab <?php echo 'overview' === $active_tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Overview', 'relevanssi' ); ?></a>
909
  }
910
 
911
  if ( $display_save_button ) :
912
+ ?>
913
 
914
  <input type='submit' name='submit' value='<?php esc_attr_e( 'Save the options', 'relevanssi' ); ?>' class='button button-primary' />
915
 
948
  }
949
 
950
  wp_enqueue_style( 'wp-color-picker' );
951
+ wp_enqueue_script( 'relevanssi_admin_js', $plugin_dir_url . 'lib/admin_scripts.js', array( 'wp-color-picker' ), $relevanssi_variables['plugin_version'], true );
952
  if ( ! RELEVANSSI_PREMIUM ) {
953
+ wp_enqueue_script( 'relevanssi_admin_js_free', $plugin_dir_url . 'lib/admin_scripts_free.js', array( 'relevanssi_admin_js' ), $relevanssi_variables['plugin_version'], true );
954
  }
955
  if ( RELEVANSSI_PREMIUM ) {
956
+ wp_enqueue_script( 'relevanssi_admin_js_premium', $plugin_dir_url . 'premium/admin_scripts_premium.js', array( 'relevanssi_admin_js' ), $relevanssi_variables['plugin_version'], true );
957
  }
958
+ wp_enqueue_style( 'relevanssi_admin_css', $plugin_dir_url . 'lib/admin_styles.css', array(), $relevanssi_variables['plugin_version'] );
959
 
960
  $localizations = array(
961
  'confirm' => __( 'Click OK to copy Relevanssi options to all subsites', 'relevanssi' ),
1002
  if ( ! RELEVANSSI_PREMIUM ) {
1003
  wp_localize_script( 'relevanssi_admin_js', 'nonce', $nonce );
1004
  }
1005
+
1006
+ $indexing_limit = apply_filters( 'relevanssi_indexing_limit', 10 );
1007
+ wp_localize_script( 'relevanssi_admin_js', 'relevanssi_params', array( 'indexing_limit' => $indexing_limit ) );
1008
  }
1009
 
1010
  /**
1021
  if ( isset( $taxonomy_weights['category'] ) ) {
1022
  $category_value = $taxonomy_weights['category'];
1023
  }
1024
+ ?>
1025
  <tr>
1026
  <td>
1027
  <?php esc_html_e( 'Tag weight', 'relevanssi' ); ?>
1038
  <input type='text' id='relevanssi_weight_category' name='relevanssi_weight_category' size='4' value='<?php echo esc_attr( $category_value ); ?>' />
1039
  </td>
1040
  </tr>
1041
+ <?php
1042
  }
lib/log.php CHANGED
@@ -98,9 +98,14 @@ function relevanssi_update_log( $query, $hits ) {
98
  global $wpdb, $relevanssi_variables;
99
 
100
  $wpdb->query(
101
- $wpdb->prepare( 'INSERT INTO ' . $relevanssi_variables['log_table'] . ' (query, hits, user_id, ip, time) VALUES (%s, %d, %d, %s, NOW())',
102
- $query, intval( $hits ), $user->ID, $ip )
103
- ); // WPCS: unprepared SQL ok, Relevanssi database table name.
 
 
 
 
 
104
  }
105
  }
106
 
@@ -116,9 +121,11 @@ function relevanssi_trim_logs() {
116
  global $wpdb, $relevanssi_variables;
117
  $interval = intval( get_option( 'relevanssi_trim_logs' ) );
118
  $wpdb->query(
119
- $wpdb->prepare( 'DELETE FROM ' . $relevanssi_variables['log_table'] . ' WHERE time < TIMESTAMP(DATE_SUB(NOW(), INTERVAL %d DAY))',
120
- $interval )
121
- ); // WPCS: unprepared SQL ok, Relevanssi database table name.
 
 
122
  }
123
 
124
  /**
@@ -142,9 +149,13 @@ function relevanssi_export_log_data( $user_id, $page ) {
142
  $limit = 500;
143
  $offset = $limit * ( $page - 1 );
144
  $log_data = $wpdb->get_results(
145
- $wpdb->prepare( 'SELECT * FROM ' . $relevanssi_variables['log_table'] . ' WHERE user_id = %d LIMIT %d OFFSET %d',
146
- $user_id, $limit, $offset )
147
- ); // WPCS: unprepared SQL ok, Relevanssi database table name.
 
 
 
 
148
 
149
  $export_items = array();
150
 
@@ -217,9 +228,12 @@ function relevanssi_erase_log_data( $user_id, $page ) {
217
  }
218
  $limit = 500;
219
  $rows_removed = $wpdb->query(
220
- $wpdb->prepare( 'DELETE FROM ' . $relevanssi_variables['log_table'] . ' WHERE user_id = %d LIMIT %d',
221
- $user_id, $limit )
222
- ); // WPCS: unprepared SQL ok, Relevanssi database table name.
 
 
 
223
 
224
  $done = false;
225
  if ( $rows_removed < $limit ) {
@@ -260,7 +274,7 @@ function relevanssi_export_log() {
260
  header( "Content-Disposition: attachment;filename={$filename}" );
261
  header( 'Content-Transfer-Encoding: binary' );
262
 
263
- $data = $wpdb->get_results( 'SELECT * FROM ' . $relevanssi_variables['log_table'], ARRAY_A ); // WPCS: unprepared SQL ok. Relevanssi table name.
264
  ob_start();
265
  $df = fopen( 'php://output', 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions
266
  fputcsv( $df, array_keys( reset( $data ) ) );
@@ -268,6 +282,6 @@ function relevanssi_export_log() {
268
  fputcsv( $df, $row );
269
  }
270
  fclose( $df ); // phpcs:ignore WordPress.WP.AlternativeFunctions
271
- echo ob_get_clean(); // WPCS XSS ok.
272
  die();
273
  }
98
  global $wpdb, $relevanssi_variables;
99
 
100
  $wpdb->query(
101
+ $wpdb->prepare(
102
+ 'INSERT INTO ' . $relevanssi_variables['log_table'] . ' (query, hits, user_id, ip, time) VALUES (%s, %d, %d, %s, NOW())', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
103
+ $query,
104
+ intval( $hits ),
105
+ $user->ID,
106
+ $ip
107
+ )
108
+ );
109
  }
110
  }
111
 
121
  global $wpdb, $relevanssi_variables;
122
  $interval = intval( get_option( 'relevanssi_trim_logs' ) );
123
  $wpdb->query(
124
+ $wpdb->prepare(
125
+ 'DELETE FROM ' . $relevanssi_variables['log_table'] . ' WHERE time < TIMESTAMP(DATE_SUB(NOW(), INTERVAL %d DAY))', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
126
+ $interval
127
+ )
128
+ );
129
  }
130
 
131
  /**
149
  $limit = 500;
150
  $offset = $limit * ( $page - 1 );
151
  $log_data = $wpdb->get_results(
152
+ $wpdb->prepare(
153
+ 'SELECT * FROM ' . $relevanssi_variables['log_table'] . ' WHERE user_id = %d LIMIT %d OFFSET %d', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
154
+ $user_id,
155
+ $limit,
156
+ $offset
157
+ )
158
+ );
159
 
160
  $export_items = array();
161
 
228
  }
229
  $limit = 500;
230
  $rows_removed = $wpdb->query(
231
+ $wpdb->prepare(
232
+ 'DELETE FROM ' . $relevanssi_variables['log_table'] . ' WHERE user_id = %d LIMIT %d', // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
233
+ $user_id,
234
+ $limit
235
+ )
236
+ );
237
 
238
  $done = false;
239
  if ( $rows_removed < $limit ) {
274
  header( "Content-Disposition: attachment;filename={$filename}" );
275
  header( 'Content-Transfer-Encoding: binary' );
276
 
277
+ $data = $wpdb->get_results( 'SELECT * FROM ' . $relevanssi_variables['log_table'], ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
278
  ob_start();
279
  $df = fopen( 'php://output', 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions
280
  fputcsv( $df, array_keys( reset( $data ) ) );
282
  fputcsv( $df, $row );
283
  }
284
  fclose( $df ); // phpcs:ignore WordPress.WP.AlternativeFunctions
285
+ echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
286
  die();
287
  }
lib/search-query-restrictions.php CHANGED
@@ -67,15 +67,18 @@ function relevanssi_process_query_args( $args ) {
67
  $query_restrictions .= relevanssi_process_by_date( $args['by_date'] );
68
  }
69
 
70
- $phrases = relevanssi_recognize_phrases( $query );
71
  if ( $phrases ) {
72
  $query_restrictions .= " $phrases";
73
  // Clean: $phrases is escaped earlier.
74
  }
75
 
76
  if ( $args['post_type'] || $args['include_attachments'] ) {
77
- $query_restrictions .= relevanssi_process_post_type( $args['post_type'],
78
- $args['admin_search'], $args['include_attachments'] );
 
 
 
79
  }
80
 
81
  if ( $args['post_status'] ) {
67
  $query_restrictions .= relevanssi_process_by_date( $args['by_date'] );
68
  }
69
 
70
+ $phrases = relevanssi_recognize_phrases( $query, $args['operator'] );
71
  if ( $phrases ) {
72
  $query_restrictions .= " $phrases";
73
  // Clean: $phrases is escaped earlier.
74
  }
75
 
76
  if ( $args['post_type'] || $args['include_attachments'] ) {
77
+ $query_restrictions .= relevanssi_process_post_type(
78
+ $args['post_type'],
79
+ $args['admin_search'],
80
+ $args['include_attachments']
81
+ );
82
  }
83
 
84
  if ( $args['post_status'] ) {
lib/search-tax-query.php CHANGED
@@ -17,18 +17,13 @@
17
  *
18
  * @uses relevanssi_process_tax_query_row()
19
  *
20
- * @global object $wpdb The WP database interface.
21
- *
22
  * @param string $tax_query_relation The base tax query relation. Default 'and'.
23
  * @param array $tax_query The tax query array.
24
  *
25
  * @return string The query restrictions for the MySQL query.
26
  */
27
  function relevanssi_process_tax_query( $tax_query_relation, $tax_query ) {
28
- global $wpdb;
29
-
30
  $query_restrictions = '';
31
-
32
  if ( ! isset( $tax_query_relation ) ) {
33
  $tax_query_relation = 'and';
34
  }
@@ -36,12 +31,13 @@ function relevanssi_process_tax_query( $tax_query_relation, $tax_query ) {
36
  $term_tax_ids = array();
37
  $not_term_tax_ids = array();
38
  $and_term_tax_ids = array();
 
39
 
40
  $is_sub_row = false;
41
  foreach ( $tax_query as $row ) {
42
  if ( isset( $row['terms'] ) || ( isset( $row['operator'] ) && ( 'not exists' === strtolower( $row['operator'] ) || 'exists' === strtolower( $row['operator'] ) ) ) ) {
43
- list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids ) =
44
- 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 );
45
  } else {
46
  $row_tax_query_relation = $tax_query_relation;
47
  if ( isset( $row['relation'] ) ) {
@@ -51,15 +47,16 @@ function relevanssi_process_tax_query( $tax_query_relation, $tax_query ) {
51
  foreach ( $row as $subrow ) {
52
  $is_sub_row = true;
53
  if ( isset( $subrow['terms'] ) ) {
54
- list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids ) =
55
- relevanssi_process_tax_query_row( $subrow, $is_sub_row, $tax_query_relation, $query_restrictions, $row_tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids );
56
  }
57
  }
58
  if ( 'or' === $row_tax_query_relation ) {
59
  $query_restrictions .= relevanssi_process_term_tax_ids(
60
  $term_tax_ids,
61
  $not_term_tax_ids,
62
- $and_term_tax_ids
 
63
  );
64
  }
65
  }
@@ -70,7 +67,8 @@ function relevanssi_process_tax_query( $tax_query_relation, $tax_query ) {
70
  $query_restrictions .= relevanssi_process_term_tax_ids(
71
  $term_tax_ids,
72
  $not_term_tax_ids,
73
- $and_term_tax_ids
 
74
  );
75
  }
76
 
@@ -92,11 +90,13 @@ function relevanssi_process_tax_query( $tax_query_relation, $tax_query ) {
92
  * @param array $term_tax_ids Array of term taxonomy IDs.
93
  * @param array $not_term_tax_ids Array of excluded term taxonomy IDs.
94
  * @param array $and_term_tax_ids Array of AND term taxonomy IDs.
 
95
  *
96
  * @return array Returns an array where the first item is the updated
97
- * $query_restrictions, then $term_tax_ids, $not_term_tax_ids, and $and_term_tax_ids.
 
98
  */
99
- function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation, $query_restrictions, $tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids ) {
100
  global $wpdb;
101
 
102
  $local_term_tax_ids = array();
@@ -209,15 +209,18 @@ function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation,
209
  if ( 'not exists' === strtolower( $row['operator'] ) ) {
210
  $operator = 'NOT IN';
211
  }
212
- $query_restrictions .= " AND relevanssi.doc $operator (
213
  SELECT DISTINCT(tr.object_id)
214
  FROM $wpdb->term_relationships AS tr, $wpdb->term_taxonomy AS tt
215
  WHERE tr.term_taxonomy_id = tt.term_taxonomy_id
216
- AND tt.taxonomy = '$taxonomy'
217
- )";
 
 
 
218
  }
219
 
220
- return array( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids );
221
  }
222
 
223
  /**
@@ -231,10 +234,11 @@ function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation,
231
  * @param array $term_tax_ids The regular terms.
232
  * @param array $not_term_tax_ids The NOT terms.
233
  * @param array $and_term_tax_ids The AND terms.
 
234
  *
235
  * @return string The MySQL query restrictions.
236
  */
237
- function relevanssi_process_term_tax_ids( $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids ) {
238
  global $wpdb;
239
 
240
  $query_restriction_parts = array();
@@ -272,7 +276,11 @@ function relevanssi_process_term_tax_ids( $term_tax_ids, $not_term_tax_ids, $and
272
  )";
273
  // Clean: all variables are Relevanssi-generated.
274
  }
275
- $query_restrictions .= ' AND ';
 
 
 
 
276
  if ( count( $query_restriction_parts ) > 1 ) {
277
  $query_restrictions .= '(';
278
  }
@@ -281,6 +289,10 @@ function relevanssi_process_term_tax_ids( $term_tax_ids, $not_term_tax_ids, $and
281
  $query_restrictions .= ')';
282
  }
283
 
 
 
 
 
284
  return $query_restrictions;
285
  }
286
 
@@ -292,11 +304,12 @@ function relevanssi_process_term_tax_ids( $term_tax_ids, $not_term_tax_ids, $and
292
  *
293
  * @param string $terms_parameter The 'terms' field from the tax_query row.
294
  * @param string $taxonomy The taxonomy name.
 
295
  *
296
  * @return array An array containing numeric terms and the list of sanitized term
297
  * names.
298
  */
299
- function relevanssi_get_term_in( $terms_parameter, $taxonomy ) {
300
  $numeric_terms = array();
301
  $names = array();
302
 
@@ -304,13 +317,14 @@ function relevanssi_get_term_in( $terms_parameter, $taxonomy ) {
304
  $terms_parameter = array( $terms_parameter );
305
  }
306
  foreach ( $terms_parameter as $name ) {
307
- $term = get_term_by( 'name', $name, $taxonomy );
308
- if ( ! $term && is_numeric( $name ) ) {
309
  $numeric_terms[] = $name;
310
  } else {
311
- if ( isset( $term->term_id ) ) {
312
- $name = sanitize_title( $name );
313
- $names[] = "'$name'";
 
314
  }
315
  }
316
  }
@@ -334,12 +348,13 @@ function relevanssi_get_term_in( $terms_parameter, $taxonomy ) {
334
  function relevanssi_term_tax_id_from_row( $row ) {
335
  global $wpdb;
336
 
337
- $term_in_results = relevanssi_get_term_in( $row['terms'], $row['taxonomy'] );
 
 
338
  $numeric_terms = $term_in_results['numeric_terms'];
339
  $term_in = $term_in_results['term_in'];
340
  $term_tax_id = array();
341
 
342
- $type = $row['field'];
343
  if ( ! empty( $numeric_terms ) ) {
344
  $type = 'term_id';
345
  $term_in = $numeric_terms;
@@ -353,7 +368,7 @@ function relevanssi_term_tax_id_from_row( $row ) {
353
  LEFT JOIN $wpdb->terms AS t ON (tt.term_id=t.term_id)
354
  WHERE tt.taxonomy = '$row_taxonomy' AND t.$type IN ($term_in)";
355
  // Clean: $row_taxonomy is sanitized, each term in $term_in is sanitized.
356
- $term_tax_id = $wpdb->get_col( $tt_q ); // WPCS: unprepared SQL ok.
357
  }
358
 
359
  return $term_tax_id;
17
  *
18
  * @uses relevanssi_process_tax_query_row()
19
  *
 
 
20
  * @param string $tax_query_relation The base tax query relation. Default 'and'.
21
  * @param array $tax_query The tax query array.
22
  *
23
  * @return string The query restrictions for the MySQL query.
24
  */
25
  function relevanssi_process_tax_query( $tax_query_relation, $tax_query ) {
 
 
26
  $query_restrictions = '';
 
27
  if ( ! isset( $tax_query_relation ) ) {
28
  $tax_query_relation = 'and';
29
  }
31
  $term_tax_ids = array();
32
  $not_term_tax_ids = array();
33
  $and_term_tax_ids = array();
34
+ $exist_queries = array();
35
 
36
  $is_sub_row = false;
37
  foreach ( $tax_query as $row ) {
38
  if ( isset( $row['terms'] ) || ( isset( $row['operator'] ) && ( 'not exists' === strtolower( $row['operator'] ) || 'exists' === strtolower( $row['operator'] ) ) ) ) {
39
+ list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries ) =
40
+ 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, $exist_queries );
41
  } else {
42
  $row_tax_query_relation = $tax_query_relation;
43
  if ( isset( $row['relation'] ) ) {
47
  foreach ( $row as $subrow ) {
48
  $is_sub_row = true;
49
  if ( isset( $subrow['terms'] ) ) {
50
+ list( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries ) =
51
+ relevanssi_process_tax_query_row( $subrow, $is_sub_row, $tax_query_relation, $query_restrictions, $row_tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries );
52
  }
53
  }
54
  if ( 'or' === $row_tax_query_relation ) {
55
  $query_restrictions .= relevanssi_process_term_tax_ids(
56
  $term_tax_ids,
57
  $not_term_tax_ids,
58
+ $and_term_tax_ids,
59
+ $exist_queries
60
  );
61
  }
62
  }
67
  $query_restrictions .= relevanssi_process_term_tax_ids(
68
  $term_tax_ids,
69
  $not_term_tax_ids,
70
+ $and_term_tax_ids,
71
+ $exist_queries
72
  );
73
  }
74
 
90
  * @param array $term_tax_ids Array of term taxonomy IDs.
91
  * @param array $not_term_tax_ids Array of excluded term taxonomy IDs.
92
  * @param array $and_term_tax_ids Array of AND term taxonomy IDs.
93
+ * @param array $exist_queries MySQL queries for EXIST subqueries.
94
  *
95
  * @return array Returns an array where the first item is the updated
96
+ * $query_restrictions, then $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids
97
+ * and $exist_queries.
98
  */
99
+ function relevanssi_process_tax_query_row( $row, $is_sub_row, $global_relation, $query_restrictions, $tax_query_relation, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries ) {
100
  global $wpdb;
101
 
102
  $local_term_tax_ids = array();
209
  if ( 'not exists' === strtolower( $row['operator'] ) ) {
210
  $operator = 'NOT IN';
211
  }
212
+ $exist_query_sql = " relevanssi.doc $operator (
213
  SELECT DISTINCT(tr.object_id)
214
  FROM $wpdb->term_relationships AS tr, $wpdb->term_taxonomy AS tt
215
  WHERE tr.term_taxonomy_id = tt.term_taxonomy_id
216
+ AND tt.taxonomy = '$taxonomy' )";
217
+ $exist_queries[] = $exist_query_sql;
218
+ if ( 'and' === $tax_query_relation ) {
219
+ $query_restrictions .= ' AND ' . $exist_query_sql;
220
+ }
221
  }
222
 
223
+ return array( $query_restrictions, $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries );
224
  }
225
 
226
  /**
234
  * @param array $term_tax_ids The regular terms.
235
  * @param array $not_term_tax_ids The NOT terms.
236
  * @param array $and_term_tax_ids The AND terms.
237
+ * @param array $exist_queries The EXIST queries.
238
  *
239
  * @return string The MySQL query restrictions.
240
  */
241
+ function relevanssi_process_term_tax_ids( $term_tax_ids, $not_term_tax_ids, $and_term_tax_ids, $exist_queries ) {
242
  global $wpdb;
243
 
244
  $query_restriction_parts = array();
276
  )";
277
  // Clean: all variables are Relevanssi-generated.
278
  }
279
+
280
+ if ( $exist_queries ) {
281
+ $query_restriction_parts = array_merge( $query_restriction_parts, $exist_queries );
282
+ }
283
+
284
  if ( count( $query_restriction_parts ) > 1 ) {
285
  $query_restrictions .= '(';
286
  }
289
  $query_restrictions .= ')';
290
  }
291
 
292
+ if ( $query_restrictions ) {
293
+ $query_restrictions = ' AND ' . $query_restrictions;
294
+ }
295
+
296
  return $query_restrictions;
297
  }
298
 
304
  *
305
  * @param string $terms_parameter The 'terms' field from the tax_query row.
306
  * @param string $taxonomy The taxonomy name.
307
+ * @param string $field_name The field name ('slug', 'name').
308
  *
309
  * @return array An array containing numeric terms and the list of sanitized term
310
  * names.
311
  */
312
+ function relevanssi_get_term_in( $terms_parameter, $taxonomy, $field_name ) {
313
  $numeric_terms = array();
314
  $names = array();
315
 
317
  $terms_parameter = array( $terms_parameter );
318
  }
319
  foreach ( $terms_parameter as $name ) {
320
+ $term = get_term_by( $field_name, $name, $taxonomy );
321
+ if ( ! $term && ctype_digit( strval( $name ) ) ) {
322
  $numeric_terms[] = $name;
323
  } else {
324
+ if ( isset( $term->term_id ) && in_array( $field_name, array( 'slug', 'name' ), true ) ) {
325
+ $names[] = "'" . esc_sql( $name ) . "'";
326
+ } else {
327
+ $numeric_terms[] = $name;
328
  }
329
  }
330
  }
348
  function relevanssi_term_tax_id_from_row( $row ) {
349
  global $wpdb;
350
 
351
+ $type = $row['field'];
352
+
353
+ $term_in_results = relevanssi_get_term_in( $row['terms'], $row['taxonomy'], $type );
354
  $numeric_terms = $term_in_results['numeric_terms'];
355
  $term_in = $term_in_results['term_in'];
356
  $term_tax_id = array();
357
 
 
358
  if ( ! empty( $numeric_terms ) ) {
359
  $type = 'term_id';
360
  $term_in = $numeric_terms;
368
  LEFT JOIN $wpdb->terms AS t ON (tt.term_id=t.term_id)
369
  WHERE tt.taxonomy = '$row_taxonomy' AND t.$type IN ($term_in)";
370
  // Clean: $row_taxonomy is sanitized, each term in $term_in is sanitized.
371
+ $term_tax_id = $wpdb->get_col( $tt_q ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
372
  }
373
 
374
  return $term_tax_id;
lib/search.php CHANGED
@@ -122,7 +122,6 @@ function relevanssi_search( $args ) {
122
  $orderby = $filtered_args['orderby'];
123
  $order = $filtered_args['order'];
124
  $fields = $filtered_args['fields'];
125
- $meta_query = $filtered_args['meta_query'];
126
 
127
  $hits = array();
128
 
@@ -139,10 +138,6 @@ function relevanssi_search( $args ) {
139
  $remove_stopwords = apply_filters( 'relevanssi_remove_stopwords_in_titles', true );
140
 
141
  $terms = relevanssi_tokenize( $q, $remove_stopwords );
142
- if ( count( $terms ) < 1 ) {
143
- // Tokenizer killed all the search terms.
144
- return $hits;
145
- }
146
  $terms = array_keys( $terms ); // Don't care about tf in query.
147
 
148
  if ( function_exists( 'relevanssi_process_terms' ) ) {
@@ -151,6 +146,12 @@ function relevanssi_search( $args ) {
151
  $terms = $process_terms_results['terms'];
152
  }
153
 
 
 
 
 
 
 
154
  /**
155
  * Filters the query restrictions for the Relevanssi query.
156
  *
@@ -192,25 +193,6 @@ function relevanssi_search( $args ) {
192
  $fuzzy = get_option( 'relevanssi_fuzzy' );
193
 
194
  $no_matches = true;
195
- if ( 'always' === $fuzzy ) {
196
- /**
197
- * Filters the partial matching search query.
198
- *
199
- * By default partial matching matches the beginnings and the ends of the
200
- * words. If you want it to match inside words, add a function to this
201
- * hook that returns '(relevanssi.term LIKE '%#term#%')'.
202
- *
203
- * @param string The partial matching query.
204
- */
205
- $o_term_cond = apply_filters( 'relevanssi_fuzzy_query', "(relevanssi.term LIKE '#term#%' OR relevanssi.term_reverse LIKE CONCAT(REVERSE('#term#'), '%')) " );
206
- } else {
207
- $o_term_cond = " relevanssi.term = '#term#' ";
208
- }
209
-
210
- if ( count( $terms ) < 1 ) {
211
- $o_term_cond = ' relevanssi.term = relevanssi.term ';
212
- $terms[] = 'term';
213
- }
214
 
215
  $post_type_weights = get_option( 'relevanssi_post_type_weights' );
216
 
@@ -231,10 +213,13 @@ function relevanssi_search( $args ) {
231
  * @param array The title bonus under 'title' (default 5) and the content
232
  * bonus under 'content' (default 2).
233
  */
234
- $exact_match_boost = apply_filters( 'relevanssi_exact_match_bonus', array(
235
- 'title' => 5,
236
- 'content' => 2,
237
- ));
 
 
 
238
 
239
  }
240
 
@@ -257,13 +242,16 @@ function relevanssi_search( $args ) {
257
  $cat = $post_type_weights['post_tagged_with_category'];
258
  }
259
 
260
- /* Legacy code, improvement introduced in 2.1.8, remove at some point. */
 
 
261
  if ( ! empty( $post_type_weights['post_tag'] ) ) {
262
  $tag = $post_type_weights['post_tag'];
263
  }
264
  if ( ! empty( $post_type_weights['category'] ) ) {
265
  $cat = $post_type_weights['category'];
266
  }
 
267
  /* End legacy code. */
268
 
269
  $include_these_posts = array();
@@ -273,7 +261,7 @@ function relevanssi_search( $args ) {
273
 
274
  do {
275
  foreach ( $terms as $term ) {
276
- $term_cond = relevanssi_generate_term_cond( $term, $o_term_cond );
277
  if ( null === $term_cond ) {
278
  continue;
279
  }
@@ -289,16 +277,18 @@ function relevanssi_search( $args ) {
289
  */
290
  $query = apply_filters( 'relevanssi_df_query_filter', $query );
291
 
292
- $df = $wpdb->get_var( $query ); // WPCS: unprepared SQL ok.
293
 
294
  if ( $df < 1 && 'sometimes' === $fuzzy ) {
295
- $query = "SELECT COUNT(DISTINCT(relevanssi.doc)) FROM $relevanssi_table AS relevanssi
296
- $query_join WHERE (relevanssi.term LIKE '$term%'
297
- OR relevanssi.term_reverse LIKE CONCAT(REVERSE('$term'), '%')) $query_restrictions";
 
 
298
  // Clean: $query_restrictions is escaped, $term is escaped.
299
  /** Documented in lib/search.php. */
300
  $query = apply_filters( 'relevanssi_df_query_filter', $query );
301
- $df = $wpdb->get_var( $query ); // WPCS: unprepared SQL ok.
302
  }
303
 
304
  $df_counts[ $term ] = $df;
@@ -310,10 +300,7 @@ function relevanssi_search( $args ) {
310
  asort( $df_counts );
311
 
312
  foreach ( $df_counts as $term => $df ) {
313
- $term_cond = relevanssi_generate_term_cond( $term, $o_term_cond );
314
- if ( null === $term_cond ) {
315
- continue;
316
- }
317
 
318
  $query = "SELECT DISTINCT(relevanssi.doc), relevanssi.*, relevanssi.title * $title_boost +
319
  relevanssi.content * $content_boost + relevanssi.comment * $comment_boost +
@@ -331,7 +318,7 @@ function relevanssi_search( $args ) {
331
  * @param string MySQL query for the Relevanssi search.
332
  */
333
  $query = apply_filters( 'relevanssi_query_filter', $query );
334
- $matches = $wpdb->get_results( $query ); // WPCS: unprepared SQL ok, the query is thoroughly escaped.
335
  if ( count( $matches ) < 1 ) {
336
  continue;
337
  } else {
@@ -360,7 +347,7 @@ function relevanssi_search( $args ) {
360
  AND $term_cond";
361
 
362
  // Clean: no unescaped user inputs.
363
- $matches_to_add = $wpdb->get_results( $query ); // WPCS: unprepared SQL ok.
364
  $matches = array_merge( $matches, $matches_to_add );
365
  }
366
  $offset += $slice_length;
@@ -387,7 +374,7 @@ function relevanssi_search( $args ) {
387
  AND $term_cond";
388
 
389
  // Clean: no unescaped user inputs.
390
- $matches_to_add = $wpdb->get_results( $query ); // WPCS: unprepared SQL ok.
391
  $matches = array_merge( $matches, $matches_to_add );
392
  }
393
  }
@@ -426,7 +413,9 @@ function relevanssi_search( $args ) {
426
  $category_weight = $post_type_weights['post_tagged_with_category'];
427
  }
428
 
429
- /* Legacy code from 2.1.8. Remove at some point. */
 
 
430
  if ( isset( $post_type_weights['post_tag'] ) && is_numeric( $post_type_weights['post_tag'] ) ) {
431
  $tag_weight = $post_type_weights['post_tag'];
432
  }
@@ -435,6 +424,7 @@ function relevanssi_search( $args ) {
435
  if ( isset( $post_type_weights['category'] ) && is_numeric( $post_type_weights['category'] ) ) {
436
  $category_weight = $post_type_weights['category'];
437
  }
 
438
  /* End legacy code. */
439
 
440
  $taxonomy_weight = 1;
@@ -480,12 +470,14 @@ function relevanssi_search( $args ) {
480
 
481
  if ( $exact_match_bonus ) {
482
  $post = relevanssi_get_post( $match->doc );
483
- $clean_q = str_replace( '"', '', $q );
484
- if ( stristr( $post->post_title, $clean_q ) !== false ) {
485
- $match->weight *= $exact_match_boost['title'];
486
- }
487
- if ( stristr( $post->post_content, $clean_q ) !== false ) {
488
- $match->weight *= $exact_match_boost['content'];
 
 
489
  }
490
  }
491
 
@@ -584,10 +576,6 @@ function relevanssi_search( $args ) {
584
  }
585
  }
586
 
587
- if ( ! isset( $doc_weight ) ) {
588
- $doc_weight = array();
589
- $no_matches = true;
590
- }
591
  if ( $no_matches ) {
592
  if ( $search_again ) {
593
  // No hits even with fuzzy search!
@@ -595,7 +583,6 @@ function relevanssi_search( $args ) {
595
  } else {
596
  if ( 'sometimes' === $fuzzy ) {
597
  $search_again = true;
598
- $o_term_cond = "(term LIKE '%#term#' OR term LIKE '#term#%') ";
599
  }
600
  }
601
  } else {
@@ -605,7 +592,6 @@ function relevanssi_search( $args ) {
605
  'no_matches' => $no_matches,
606
  'doc_weight' => $doc_weight,
607
  'terms' => $terms,
608
- 'o_term_cond' => $o_term_cond,
609
  'search_again' => $search_again,
610
  );
611
  /**
@@ -620,7 +606,6 @@ function relevanssi_search( $args ) {
620
  $params = apply_filters( 'relevanssi_search_again', $params );
621
  $search_again = $params['search_again'];
622
  $terms = $params['terms'];
623
- $o_term_cond = $params['o_term_cond'];
624
  $doc_weight = $params['doc_weight'];
625
  $no_matches = $params['no_matches'];
626
  } while ( $search_again );
@@ -693,7 +678,6 @@ function relevanssi_search( $args ) {
693
  $category_matches = $return['category_matches'];
694
  $taxonomy_matches = $return['taxonomy_matches'];
695
  $comment_matches = $return['comment_matches'];
696
- $body_matches = $return['body_matches'];
697
  $link_matches = $return['link_matches'];
698
  $term_hits = $return['term_hits'];
699
  $q = $return['query'];
@@ -1234,6 +1218,42 @@ function relevanssi_do_query( &$query ) {
1234
  $date_query = new WP_Date_Query( $query->query_vars['date_query'] );
1235
  }
1236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1237
  $search_blogs = false;
1238
  if ( isset( $query->query_vars['search_blogs'] ) ) {
1239
  $search_blogs = $query->query_vars['search_blogs'];
@@ -1430,12 +1450,8 @@ function relevanssi_do_query( &$query ) {
1430
  }
1431
 
1432
  if ( 'on' === get_option( 'relevanssi_hilite_title' ) && empty( $fields ) ) {
1433
- if ( function_exists( 'qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage' ) ) {
1434
- $post->post_highlighted_title = strip_tags( qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage( $post->post_title ) );
1435
- } else {
1436
- $post->post_highlighted_title = strip_tags( $post->post_title );
1437
- }
1438
- $highlight = get_option( 'relevanssi_highlight' );
1439
  if ( 'none' !== $highlight ) {
1440
  if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
1441
  $post->post_highlighted_title = relevanssi_highlight_terms( $post->post_highlighted_title, $q );
@@ -1562,34 +1578,74 @@ function relevanssi_get_negative_post_type( $include_attachments ) {
1562
  *
1563
  * Tested.
1564
  *
1565
- * @param string $term The search term.
1566
- * @param string $o_term_cond The search condition template.
 
 
 
 
1567
  *
1568
  * @return string The template with the term in place.
1569
  */
1570
- function relevanssi_generate_term_cond( $term, $o_term_cond ) {
1571
  global $wpdb;
1572
 
1573
- $term = trim( $term ); // Numeric search terms will start with a space.
 
 
 
 
 
1574
  /**
1575
- * Allows the use of one letter search terms.
1576
  *
1577
- * Return false to allow one letter searches.
 
 
1578
  *
1579
- * @param boolean True, if search term is one letter long and will be blocked.
1580
  */
1581
- if ( apply_filters( 'relevanssi_block_one_letter_searches', relevanssi_strlen( $term ) < 2 ) ) {
1582
- return null;
 
 
 
 
 
 
 
 
1583
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1584
  $term = esc_sql( $term );
1585
 
1586
- if ( false !== strpos( $o_term_cond, 'LIKE' ) ) {
1587
  $term = $wpdb->esc_like( $term );
1588
  }
1589
 
1590
- $term_cond = str_replace( '#term#', $term, $o_term_cond );
1591
 
1592
- return $term_cond;
1593
  }
1594
 
1595
  /**
@@ -1613,7 +1669,10 @@ function relevanssi_taxonomy_score( &$match, $post_type_weights ) {
1613
  foreach ( $match->taxonomy_detail as $tax => $count ) {
1614
  if ( empty( $post_type_weights[ 'post_tagged_with_' . $tax ] ) ) {
1615
  if ( ! empty( $post_type_weights[ $tax ] ) ) { // Legacy code, needed for 2.1.8, remove later.
 
 
1616
  $match->taxonomy_score += $count * $post_type_weights[ $tax ];
 
1617
  } else {
1618
  $match->taxonomy_score += $count * 1;
1619
  }
122
  $orderby = $filtered_args['orderby'];
123
  $order = $filtered_args['order'];
124
  $fields = $filtered_args['fields'];
 
125
 
126
  $hits = array();
127
 
138
  $remove_stopwords = apply_filters( 'relevanssi_remove_stopwords_in_titles', true );
139
 
140
  $terms = relevanssi_tokenize( $q, $remove_stopwords );
 
 
 
 
141
  $terms = array_keys( $terms ); // Don't care about tf in query.
142
 
143
  if ( function_exists( 'relevanssi_process_terms' ) ) {
146
  $terms = $process_terms_results['terms'];
147
  }
148
 
149
+ $no_terms = false;
150
+ if ( count( $terms ) < 1 && empty( $q ) ) {
151
+ $no_terms = true;
152
+ $terms[] = 'term';
153
+ }
154
+
155
  /**
156
  * Filters the query restrictions for the Relevanssi query.
157
  *
193
  $fuzzy = get_option( 'relevanssi_fuzzy' );
194
 
195
  $no_matches = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
  $post_type_weights = get_option( 'relevanssi_post_type_weights' );
198
 
213
  * @param array The title bonus under 'title' (default 5) and the content
214
  * bonus under 'content' (default 2).
215
  */
216
+ $exact_match_boost = apply_filters(
217
+ 'relevanssi_exact_match_bonus',
218
+ array(
219
+ 'title' => 5,
220
+ 'content' => 2,
221
+ )
222
+ );
223
 
224
  }
225
 
242
  $cat = $post_type_weights['post_tagged_with_category'];
243
  }
244
 
245
+ // Legacy code, improvement introduced in 2.1.8, remove at some point.
246
+ // phpcs:ignore Squiz.Commenting.InlineComment
247
+ // @codeCoverageIgnoreStart
248
  if ( ! empty( $post_type_weights['post_tag'] ) ) {
249
  $tag = $post_type_weights['post_tag'];
250
  }
251
  if ( ! empty( $post_type_weights['category'] ) ) {
252
  $cat = $post_type_weights['category'];
253
  }
254
+ // @codeCoverageIgnoreEnd
255
  /* End legacy code. */
256
 
257
  $include_these_posts = array();
261
 
262
  do {
263
  foreach ( $terms as $term ) {
264
+ $term_cond = relevanssi_generate_term_where( $term, $search_again, $no_terms );
265
  if ( null === $term_cond ) {
266
  continue;
267
  }
277
  */
278
  $query = apply_filters( 'relevanssi_df_query_filter', $query );
279
 
280
+ $df = $wpdb->get_var( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
281
 
282
  if ( $df < 1 && 'sometimes' === $fuzzy ) {
283
+ $term_cond = relevanssi_generate_term_where( $term, true, $no_terms );
284
+ $query = "
285
+ SELECT COUNT(DISTINCT(relevanssi.doc))
286
+ FROM $relevanssi_table AS relevanssi
287
+ $query_join WHERE $term_cond $query_restrictions";
288
  // Clean: $query_restrictions is escaped, $term is escaped.
289
  /** Documented in lib/search.php. */
290
  $query = apply_filters( 'relevanssi_df_query_filter', $query );
291
+ $df = $wpdb->get_var( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
292
  }
293
 
294
  $df_counts[ $term ] = $df;
300
  asort( $df_counts );
301
 
302
  foreach ( $df_counts as $term => $df ) {
303
+ $term_cond = relevanssi_generate_term_where( $term, $search_again, $no_terms );
 
 
 
304
 
305
  $query = "SELECT DISTINCT(relevanssi.doc), relevanssi.*, relevanssi.title * $title_boost +
306
  relevanssi.content * $content_boost + relevanssi.comment * $comment_boost +
318
  * @param string MySQL query for the Relevanssi search.
319
  */
320
  $query = apply_filters( 'relevanssi_query_filter', $query );
321
+ $matches = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
322
  if ( count( $matches ) < 1 ) {
323
  continue;
324
  } else {
347
  AND $term_cond";
348
 
349
  // Clean: no unescaped user inputs.
350
+ $matches_to_add = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
351
  $matches = array_merge( $matches, $matches_to_add );
352
  }
353
  $offset += $slice_length;
374
  AND $term_cond";
375
 
376
  // Clean: no unescaped user inputs.
377
+ $matches_to_add = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
378
  $matches = array_merge( $matches, $matches_to_add );
379
  }
380
  }
413
  $category_weight = $post_type_weights['post_tagged_with_category'];
414
  }
415
 
416
+ // Legacy code from 2.1.8. Remove at some point.
417
+ // phpcs:ignore Squiz.Commenting.InlineComment
418
+ // @codeCoverageIgnoreStart
419
  if ( isset( $post_type_weights['post_tag'] ) && is_numeric( $post_type_weights['post_tag'] ) ) {
420
  $tag_weight = $post_type_weights['post_tag'];
421
  }
424
  if ( isset( $post_type_weights['category'] ) && is_numeric( $post_type_weights['category'] ) ) {
425
  $category_weight = $post_type_weights['category'];
426
  }
427
+ // @codeCoverageIgnoreEnd
428
  /* End legacy code. */
429
 
430
  $taxonomy_weight = 1;
470
 
471
  if ( $exact_match_bonus ) {
472
  $post = relevanssi_get_post( $match->doc );
473
+ $clean_q = str_replace( array( '"', '', '“' ), '', $q );
474
+ if ( $post && $clean_q ) {
475
+ if ( stristr( $post->post_title, $clean_q ) !== false ) {
476
+ $match->weight *= $exact_match_boost['title'];
477
+ }
478
+ if ( stristr( $post->post_content, $clean_q ) !== false ) {
479
+ $match->weight *= $exact_match_boost['content'];
480
+ }
481
  }
482
  }
483
 
576
  }
577
  }
578
 
 
 
 
 
579
  if ( $no_matches ) {
580
  if ( $search_again ) {
581
  // No hits even with fuzzy search!
583
  } else {
584
  if ( 'sometimes' === $fuzzy ) {
585
  $search_again = true;
 
586
  }
587
  }
588
  } else {
592
  'no_matches' => $no_matches,
593
  'doc_weight' => $doc_weight,
594
  'terms' => $terms,
 
595
  'search_again' => $search_again,
596
  );
597
  /**
606
  $params = apply_filters( 'relevanssi_search_again', $params );
607
  $search_again = $params['search_again'];
608
  $terms = $params['terms'];
 
609
  $doc_weight = $params['doc_weight'];
610
  $no_matches = $params['no_matches'];
611
  } while ( $search_again );
678
  $category_matches = $return['category_matches'];
679
  $taxonomy_matches = $return['taxonomy_matches'];
680
  $comment_matches = $return['comment_matches'];
 
681
  $link_matches = $return['link_matches'];
682
  $term_hits = $return['term_hits'];
683
  $q = $return['query'];
1218
  $date_query = new WP_Date_Query( $query->query_vars['date_query'] );
1219
  }
1220
 
1221
+ if ( ! $date_query ) {
1222
+ $date_query = array();
1223
+ if ( ! empty( $query->query_vars['year'] ) ) {
1224
+ $date_query['year'] = intval( $query->query_vars['year'] );
1225
+ }
1226
+ if ( ! empty( $query->query_vars['monthnum'] ) ) {
1227
+ $date_query['month'] = intval( $query->query_vars['monthnum'] );
1228
+ }
1229
+ if ( ! empty( $query->query_vars['w'] ) ) {
1230
+ $date_query['week'] = intval( $query->query_vars['w'] );
1231
+ }
1232
+ if ( ! empty( $query->query_vars['day'] ) ) {
1233
+ $date_query['day'] = intval( $query->query_vars['day'] );
1234
+ }
1235
+ if ( ! empty( $query->query_vars['hour'] ) ) {
1236
+ $date_query['hour'] = intval( $query->query_vars['hour'] );
1237
+ }
1238
+ if ( ! empty( $query->query_vars['minute'] ) ) {
1239
+ $date_query['minute'] = intval( $query->query_vars['minute'] );
1240
+ }
1241
+ if ( ! empty( $query->query_vars['second'] ) ) {
1242
+ $date_query['second'] = intval( $query->query_vars['second'] );
1243
+ }
1244
+ if ( ! empty( $query->query_vars['m'] ) ) {
1245
+ if ( 6 === strlen( $query->query_vars['m'] ) ) {
1246
+ $date_query['year'] = intval( substr( $query->query_vars['m'], 0, 4 ) );
1247
+ $date_query['month'] = intval( substr( $query->query_vars['m'], -2, 2 ) );
1248
+ }
1249
+ }
1250
+ if ( ! empty( $date_query ) ) {
1251
+ $date_query = new WP_Date_Query( $date_query );
1252
+ } else {
1253
+ $date_query = false;
1254
+ }
1255
+ }
1256
+
1257
  $search_blogs = false;
1258
  if ( isset( $query->query_vars['search_blogs'] ) ) {
1259
  $search_blogs = $query->query_vars['search_blogs'];
1450
  }
1451
 
1452
  if ( 'on' === get_option( 'relevanssi_hilite_title' ) && empty( $fields ) ) {
1453
+ $post->post_highlighted_title = wp_strip_all_tags( $post->post_title );
1454
+ $highlight = get_option( 'relevanssi_highlight' );
 
 
 
 
1455
  if ( 'none' !== $highlight ) {
1456
  if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
1457
  $post->post_highlighted_title = relevanssi_highlight_terms( $post->post_highlighted_title, $q );
1578
  *
1579
  * Tested.
1580
  *
1581
+ * @param string $term The search term.
1582
+ * @param boolean $force_fuzzy If true, force fuzzy search. Default false.
1583
+ * @param boolean $no_terms If true, no search term is used. Default false.
1584
+ * @param string $option_override If set, won't read the value from the
1585
+ * 'relevanssi_fuzzy' option but will use this instead. Used in multisite searching.
1586
+ * Default null.
1587
  *
1588
  * @return string The template with the term in place.
1589
  */
1590
+ function relevanssi_generate_term_where( $term, $force_fuzzy = false, $no_terms = false, $option_override = null ) {
1591
  global $wpdb;
1592
 
1593
+ $fuzzy = get_option( 'relevanssi_fuzzy' );
1594
+ if ( $option_override &&
1595
+ in_array( $option_override, array( 'always', 'sometimes', 'never' ), true ) ) {
1596
+ $fuzzy = $option_override;
1597
+ }
1598
+
1599
  /**
1600
+ * Filters the partial matching search query.
1601
  *
1602
+ * By default partial matching matches the beginnings and the ends of the
1603
+ * words. If you want it to match inside words, add a function to this
1604
+ * hook that returns '(relevanssi.term LIKE '%#term#%')'.
1605
  *
1606
+ * @param string The partial matching query.
1607
  */
1608
+ $fuzzy_query = apply_filters(
1609
+ 'relevanssi_fuzzy_query',
1610
+ "(relevanssi.term LIKE '#term#%' OR relevanssi.term_reverse LIKE CONCAT(REVERSE('#term#'), '%')) "
1611
+ );
1612
+ $basic_query = " relevanssi.term = '#term#' ";
1613
+
1614
+ if ( 'always' === $fuzzy || $force_fuzzy ) {
1615
+ $term_where_template = $fuzzy_query;
1616
+ } else {
1617
+ $term_where_template = $basic_query;
1618
  }
1619
+ if ( $no_terms ) {
1620
+ $term_where_template = ' relevanssi.term = relevanssi.term ';
1621
+ }
1622
+
1623
+ $term = trim( $term ); // Numeric search terms will start with a space.
1624
+
1625
+ if ( relevanssi_strlen( $term ) < 2 ) {
1626
+ /**
1627
+ * Allows the use of one letter search terms.
1628
+ *
1629
+ * Return false to allow one letter searches.
1630
+ *
1631
+ * @param boolean True, if search term is one letter long and will be blocked.
1632
+ */
1633
+ if ( apply_filters( 'relevanssi_block_one_letter_searches', true ) ) {
1634
+ return null;
1635
+ }
1636
+ // No fuzzy matching for one-letter search terms.
1637
+ $term_where_template = $basic_query;
1638
+ }
1639
+
1640
  $term = esc_sql( $term );
1641
 
1642
+ if ( false !== strpos( $term_where_template, 'LIKE' ) ) {
1643
  $term = $wpdb->esc_like( $term );
1644
  }
1645
 
1646
+ $term_where = str_replace( '#term#', $term, $term_where_template );
1647
 
1648
+ return $term_where;
1649
  }
1650
 
1651
  /**
1669
  foreach ( $match->taxonomy_detail as $tax => $count ) {
1670
  if ( empty( $post_type_weights[ 'post_tagged_with_' . $tax ] ) ) {
1671
  if ( ! empty( $post_type_weights[ $tax ] ) ) { // Legacy code, needed for 2.1.8, remove later.
1672
+ // phpcs:ignore Squiz.Commenting.InlineComment
1673
+ // @codeCoverageIgnoreStart
1674
  $match->taxonomy_score += $count * $post_type_weights[ $tax ];
1675
+ // @codeCoverageIgnoreEnd
1676
  } else {
1677
  $match->taxonomy_score += $count * 1;
1678
  }
lib/shortcodes.php CHANGED
@@ -34,10 +34,13 @@ add_shortcode( 'searchform', 'relevanssi_search_form' );
34
  function relevanssi_shortcode( $atts, $content ) {
35
  global $wpdb;
36
 
37
- $attributes = shortcode_atts( array(
38
- 'term' => false,
39
- 'phrase' => 'not',
40
- ), $atts);
 
 
 
41
 
42
  $term = $attributes['term'];
43
  $phrase = $attributes['phrase'];
@@ -45,7 +48,7 @@ function relevanssi_shortcode( $atts, $content ) {
45
  if ( false !== $term ) {
46
  $term = rawurlencode( relevanssi_strtolower( $term ) );
47
  } else {
48
- $term = rawurlencode( strip_tags( relevanssi_strtolower( $content ) ) );
49
  }
50
 
51
  if ( 'not' !== $phrase ) {
34
  function relevanssi_shortcode( $atts, $content ) {
35
  global $wpdb;
36
 
37
+ $attributes = shortcode_atts(
38
+ array(
39
+ 'term' => false,
40
+ 'phrase' => 'not',
41
+ ),
42
+ $atts
43
+ );
44
 
45
  $term = $attributes['term'];
46
  $phrase = $attributes['phrase'];
48
  if ( false !== $term ) {
49
  $term = rawurlencode( relevanssi_strtolower( $term ) );
50
  } else {
51
+ $term = rawurlencode( wp_strip_all_tags( relevanssi_strtolower( $content ) ) );
52
  }
53
 
54
  if ( 'not' !== $phrase ) {
lib/sorting.php CHANGED
@@ -106,7 +106,7 @@ function relevanssi_get_next_key( &$orderby ) {
106
  if ( 'rand' === $key ) {
107
  if ( is_numeric( $dir ) ) {
108
  // A specific random seed is requested.
109
- mt_srand( $dir );
110
  }
111
  } else {
112
  $dir = strtolower( $dir );
@@ -140,8 +140,8 @@ function relevanssi_get_next_key( &$orderby ) {
140
  function relevanssi_get_compare_values( $key, $item_1, $item_2 ) {
141
  if ( 'rand' === $key ) {
142
  do {
143
- $key1 = rand();
144
- $key2 = rand();
145
  } while ( $key1 === $key2 );
146
  $keys = array(
147
  'key1' => $key1,
@@ -399,7 +399,6 @@ function relevanssi_object_sort( &$data, $orderby, $meta_query ) {
399
  $relevanssi_compares[] = $values['compare'];
400
  }
401
  } while ( ! empty( $values['key'] ) );
402
- $primary_key = $relevanssi_keys[0];
403
 
404
  usort( $data, 'relevanssi_cmp_function' );
405
  }
106
  if ( 'rand' === $key ) {
107
  if ( is_numeric( $dir ) ) {
108
  // A specific random seed is requested.
109
+ mt_srand( $dir ); // phpcs:ignore WordPress.WP.AlternativeFunctions
110
  }
111
  } else {
112
  $dir = strtolower( $dir );
140
  function relevanssi_get_compare_values( $key, $item_1, $item_2 ) {
141
  if ( 'rand' === $key ) {
142
  do {
143
+ $key1 = wp_rand();
144
+ $key2 = wp_rand();
145
  } while ( $key1 === $key2 );
146
  $keys = array(
147
  'key1' => $key1,
399
  $relevanssi_compares[] = $values['compare'];
400
  }
401
  } while ( ! empty( $values['key'] ) );
 
402
 
403
  usort( $data, 'relevanssi_cmp_function' );
404
  }
lib/tabs/excerpts-tab.php CHANGED
@@ -86,7 +86,7 @@ function relevanssi_excerpts_tab() {
86
  <table class="form-table">
87
  <tr>
88
  <th scope="row">
89
- <label for='relevanssi_excerpts'><?php esc_html_e( 'Custom search result snippets', 'relevanssi' ); ?></label>
90
  </th>
91
  <td>
92
  <fieldset>
@@ -101,7 +101,7 @@ function relevanssi_excerpts_tab() {
101
  $theme = wp_get_theme();
102
  $template = $theme->get( 'Template' );
103
  if ( 'divi' === strtolower( $template ) ) :
104
- ?>
105
  <?php // Translators: %1$s opens the link, %2$s closes it. ?>
106
  <p class="important"><?php printf( esc_html__( 'Looks like you are using Divi. In order to use custom excerpts with Divi, you need to make some changes to your templates. %1$sSee instructions here%2$s.', 'relevanssi' ), '<a href="https://www.relevanssi.com/knowledge-base/divi-page-builder-and-cleaner-excerpts/">', '</a>' ); ?></p>
107
  <?php endif; ?>
@@ -125,6 +125,7 @@ function relevanssi_excerpts_tab() {
125
  }
126
  ?>
127
  />
 
128
  <select name='relevanssi_excerpt_type' id='relevanssi_excerpt_type'
129
  <?php
130
  if ( empty( $excerpts ) ) {
@@ -149,7 +150,7 @@ function relevanssi_excerpts_tab() {
149
  <label for='relevanssi_excerpt_allowable_tags'><?php esc_html_e( 'Allowable tags in excerpts', 'relevanssi' ); ?></label>
150
  </th>
151
  <td>
152
- <input type='text' name='relevanssi_excerpt_allowable_tags' id='relevanssi_excerpt_allowable_tags' size='60' value='<?php echo esc_attr( $excerpt_allowable_tags ); ?>'
153
  <?php
154
  if ( empty( $excerpts ) ) {
155
  echo "disabled='disabled'";
@@ -167,7 +168,7 @@ function relevanssi_excerpts_tab() {
167
  ?>
168
  >
169
  <th scope="row">
170
- <label for='relevanssi_excerpt_custom_fields'><?php esc_html_e( 'Use custom fields for excerpts', 'relevanssi' ); ?></label>
171
  </th>
172
  <td>
173
  <fieldset>
@@ -191,7 +192,7 @@ function relevanssi_excerpts_tab() {
191
  ?>
192
  </p>
193
 
194
- <p class="description"><?php esc_html_e( 'Current custom field setting', 'relevanssi' ); ?>:
195
  <?php
196
  if ( 'visible' === $index_fields ) {
197
  esc_html_e( 'all visible custom fields', 'relevanssi' );
@@ -245,7 +246,7 @@ function relevanssi_excerpts_tab() {
245
  </tr>
246
  <tr id="tr_relevanssi_txt_col" class='<?php echo esc_attr( $txt_col_display ); ?>'>
247
  <th scope="row">
248
- <label for="relevanssi_txt_col"><?php esc_html_e( 'Text color', 'relevanssi' ); ?></label>
249
  </th>
250
  <td>
251
  <input type='text' name='relevanssi_txt_col' id='relevanssi_txt_col' size='7' class="color-field" data-default-color="#ff0000" value='<?php echo esc_attr( $txt_col ); ?>'
@@ -259,7 +260,7 @@ function relevanssi_excerpts_tab() {
259
  </tr>
260
  <tr id="tr_relevanssi_bg_col" class=' <?php echo esc_attr( $bg_col_display ); ?>'>
261
  <th scope="row">
262
- <label for="relevanssi_bg_col"><?php esc_html_e( 'Background color', 'relevanssi' ); ?></label>
263
  </th>
264
  <td>
265
  <input type='text' name='relevanssi_bg_col' id='relevanssi_bg_col' size='7' class="color-field" data-default-color="#ffaf75" value='<?php echo esc_attr( $bg_col ); ?>'
@@ -305,7 +306,7 @@ function relevanssi_excerpts_tab() {
305
  </tr>
306
  <tr>
307
  <th scope="row">
308
- <label for='relevanssi_hilite_title'><?php esc_html_e( 'Highlight in titles', 'relevanssi' ); ?></label>
309
  </th>
310
  <td>
311
  <fieldset>
@@ -327,7 +328,7 @@ function relevanssi_excerpts_tab() {
327
  </tr>
328
  <tr>
329
  <th scope="row">
330
- <label for='relevanssi_highlight_docs'><?php esc_html_e( 'Highlight in documents', 'relevanssi' ); ?></label>
331
  </th>
332
  <td>
333
  <fieldset>
@@ -349,7 +350,7 @@ function relevanssi_excerpts_tab() {
349
  </tr>
350
  <tr>
351
  <th scope="row">
352
- <label for='relevanssi_highlight_comments'><?php esc_html_e( 'Highlight in comments', 'relevanssi' ); ?></label>
353
  </th>
354
  <td>
355
  <fieldset>
@@ -365,12 +366,12 @@ function relevanssi_excerpts_tab() {
365
  <?php esc_html_e( 'Highlight query terms in comments', 'relevanssi' ); ?>
366
  </label>
367
  </fieldset>
368
- <p class="description"><?php esc_html_e( 'Highlights hits in comments when user opens the post from search results.', 'relevanssi' ); ?></p>
369
  </td>
370
  </tr>
371
  <tr>
372
  <th scope="row">
373
- <label for='relevanssi_word_boundaries'><?php esc_html_e( 'Highlighting problems with non-ASCII alphabet?', 'relevanssi' ); ?></label>
374
  </th>
375
  <td>
376
  <fieldset>
@@ -386,7 +387,7 @@ function relevanssi_excerpts_tab() {
386
  <?php esc_html_e( 'Uncheck this if you use non-ASCII characters', 'relevanssi' ); ?>
387
  </label>
388
  </fieldset>
389
- <p class="description"><?php esc_html_e( "If you use non-ASCII characters (like Cyrillic alphabet) and the highlights don't work, unchecking this option may make the highlights work.", 'relevanssi' ); ?></p>
390
  </td>
391
  </tr>
392
  </table>
@@ -402,7 +403,7 @@ function relevanssi_excerpts_tab() {
402
  ">
403
  <tr>
404
  <th scope="row">
405
- <label for='relevanssi_show_matches'><?php esc_html_e( 'Breakdown of search hits in excerpts', 'relevanssi' ); ?></label>
406
  </th>
407
  <td>
408
  <fieldset>
86
  <table class="form-table">
87
  <tr>
88
  <th scope="row">
89
+ <?php esc_html_e( 'Custom search result snippets', 'relevanssi' ); ?>
90
  </th>
91
  <td>
92
  <fieldset>
101
  $theme = wp_get_theme();
102
  $template = $theme->get( 'Template' );
103
  if ( 'divi' === strtolower( $template ) ) :
104
+ ?>
105
  <?php // Translators: %1$s opens the link, %2$s closes it. ?>
106
  <p class="important"><?php printf( esc_html__( 'Looks like you are using Divi. In order to use custom excerpts with Divi, you need to make some changes to your templates. %1$sSee instructions here%2$s.', 'relevanssi' ), '<a href="https://www.relevanssi.com/knowledge-base/divi-page-builder-and-cleaner-excerpts/">', '</a>' ); ?></p>
107
  <?php endif; ?>
125
  }
126
  ?>
127
  />
128
+ <label for="relevanssi_excerpt_type" class="screen-reader-text"><?php esc_html_e( 'Excerpt length type', 'relevanssi' ); ?></label>
129
  <select name='relevanssi_excerpt_type' id='relevanssi_excerpt_type'
130
  <?php
131
  if ( empty( $excerpts ) ) {
150
  <label for='relevanssi_excerpt_allowable_tags'><?php esc_html_e( 'Allowable tags in excerpts', 'relevanssi' ); ?></label>
151
  </th>
152
  <td>
153
+ <input type='text' name='relevanssi_excerpt_allowable_tags' id='relevanssi_excerpt_allowable_tags' size='60' value='<?php echo esc_attr( $excerpt_allowable_tags ); ?>'
154
  <?php
155
  if ( empty( $excerpts ) ) {
156
  echo "disabled='disabled'";
168
  ?>
169
  >
170
  <th scope="row">
171
+ <?php esc_html_e( 'Use custom fields for excerpts', 'relevanssi' ); ?>
172
  </th>
173
  <td>
174
  <fieldset>
192
  ?>
193
  </p>
194
 
195
+ <p class="description"><?php esc_html_e( 'Current custom field setting', 'relevanssi' ); ?>:
196
  <?php
197
  if ( 'visible' === $index_fields ) {
198
  esc_html_e( 'all visible custom fields', 'relevanssi' );
246
  </tr>
247
  <tr id="tr_relevanssi_txt_col" class='<?php echo esc_attr( $txt_col_display ); ?>'>
248
  <th scope="row">
249
+ <?php esc_html_e( 'Text color', 'relevanssi' ); ?>
250
  </th>
251
  <td>
252
  <input type='text' name='relevanssi_txt_col' id='relevanssi_txt_col' size='7' class="color-field" data-default-color="#ff0000" value='<?php echo esc_attr( $txt_col ); ?>'
260
  </tr>
261
  <tr id="tr_relevanssi_bg_col" class=' <?php echo esc_attr( $bg_col_display ); ?>'>
262
  <th scope="row">
263
+ <?php esc_html_e( 'Background color', 'relevanssi' ); ?>
264
  </th>
265
  <td>
266
  <input type='text' name='relevanssi_bg_col' id='relevanssi_bg_col' size='7' class="color-field" data-default-color="#ffaf75" value='<?php echo esc_attr( $bg_col ); ?>'
306
  </tr>
307
  <tr>
308
  <th scope="row">
309
+ <?php esc_html_e( 'Highlight in titles', 'relevanssi' ); ?>
310
  </th>
311
  <td>
312
  <fieldset>
328
  </tr>
329
  <tr>
330
  <th scope="row">
331
+ <?php esc_html_e( 'Highlight in documents', 'relevanssi' ); ?>
332
  </th>
333
  <td>
334
  <fieldset>
350
  </tr>
351
  <tr>
352
  <th scope="row">
353
+ <?php esc_html_e( 'Highlight in comments', 'relevanssi' ); ?>
354
  </th>
355
  <td>
356
  <fieldset>
366
  <?php esc_html_e( 'Highlight query terms in comments', 'relevanssi' ); ?>
367
  </label>
368
  </fieldset>
369
+ <p class="description"><?php esc_html_e( 'Highlights hits in comments when user opens the post from search results.', 'relevanssi' ); ?></p>
370
  </td>
371
  </tr>
372
  <tr>
373
  <th scope="row">
374
+ <?php esc_html_e( 'Highlighting problems with non-ASCII alphabet?', 'relevanssi' ); ?>
375
  </th>
376
  <td>
377
  <fieldset>
387
  <?php esc_html_e( 'Uncheck this if you use non-ASCII characters', 'relevanssi' ); ?>
388
  </label>
389
  </fieldset>
390
+ <p class="description"><?php esc_html_e( "If you use non-ASCII characters (like Cyrillic alphabet) and the highlights don't work, unchecking this option may make the highlights work.", 'relevanssi' ); ?></p>
391
  </td>
392
  </tr>
393
  </table>
403
  ">
404
  <tr>
405
  <th scope="row">
406
+ <?php esc_html_e( 'Breakdown of search hits in excerpts', 'relevanssi' ); ?>
407
  </th>
408
  <td>
409
  <fieldset>
lib/tabs/indexing-tab.php CHANGED
@@ -47,7 +47,6 @@ function relevanssi_indexing_tab() {
47
  $fields_select_none = '';
48
  $fields_select_some = 'selected';
49
  $fields_select_visible = '';
50
- $original_index_fields = $index_fields;
51
 
52
  if ( empty( $index_fields ) ) {
53
  $fields_select_none = 'selected';
@@ -88,13 +87,13 @@ function relevanssi_indexing_tab() {
88
  $punct_hyphens_remove = relevanssi_select( $punctuation['hyphens'], 'remove' );
89
  $punct_hyphens_keep = relevanssi_select( $punctuation['hyphens'], 'keep' );
90
 
91
- $docs_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT doc) FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc != -1' ); // WPCS: unprepared SQL ok, Relevanssi table name.
92
- $terms_count = $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $relevanssi_variables['relevanssi_table'] ); // WPCS: unprepared SQL ok, Relevanssi table name.
93
- $lowest_doc = $wpdb->get_var( 'SELECT doc FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc > 0 ORDER BY doc ASC LIMIT 1' ); // WPCS: unprepared SQL ok, Relevanssi table name.
94
 
95
  if ( RELEVANSSI_PREMIUM ) {
96
- $user_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT item) FROM ' . $relevanssi_variables['relevanssi_table'] . " WHERE type = 'user'" ); // WPCS: unprepared SQL ok, Relevanssi table name.
97
- $taxterm_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT item) FROM ' . $relevanssi_variables['relevanssi_table'] . " WHERE (type != 'post' AND type != 'attachment' AND type != 'user')" ); // WPCS: unprepared SQL ok, Relevanssi table name.
98
  }
99
 
100
  ?>
@@ -102,11 +101,11 @@ function relevanssi_indexing_tab() {
102
 
103
  <table class="form-table">
104
  <tr>
105
- <th scope="row">
106
  <input type='submit' name='submit' value='<?php esc_attr_e( 'Save the options', 'relevanssi' ); ?>' class='button button-primary' /><br /><br />
107
  <input type="button" id="build_index" name="index" value="<?php esc_attr_e( 'Build the index', 'relevanssi' ); ?>" class='button-primary' /><br /><br />
108
  <input type="button" id="continue_indexing" name="continue" value="<?php esc_attr_e( 'Index unindexed posts', 'relevanssi' ); ?>" class='button-primary' />
109
- </th>
110
  <td>
111
  <div id='indexing_button_instructions'>
112
  <?php // Translators: %s is "Build the index". ?>
@@ -123,7 +122,7 @@ function relevanssi_indexing_tab() {
123
  <div id='relevanssi-note' style='display: none'></div>
124
  <div id='relevanssi-progress' class='rpi-progress'><div class="rpi-indicator"></div></div>
125
  <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>
126
- <textarea id='results' rows='10' cols='80'></textarea>
127
  <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>
128
  </td>
129
  </tr>
@@ -133,7 +132,7 @@ function relevanssi_indexing_tab() {
133
  <?php if ( RELEVANSSI_PREMIUM ) : ?>
134
  <br /><?php echo esc_html( $user_count ); ?> <?php echo esc_html( _n( 'user in the index.', 'users in the index.', $user_count, 'relevanssi' ) ); ?><br />
135
  <?php echo esc_html( $taxterm_count ); ?> <?php echo esc_html( _n( 'taxonomy term in the index.', 'taxonomy terms in the index.', $taxterm_count, 'relevanssi' ) ); ?>
136
- <?php endif; ?>
137
  </p>
138
  <p><?php echo esc_html( $terms_count ); ?> <?php echo esc_html( _n( 'term in the index.', 'terms in the index.', $terms_count, 'relevanssi' ) ); ?><br />
139
  <?php echo esc_html( $lowest_doc ); ?> <?php esc_html_e( 'is the lowest post ID indexed.', 'relevanssi' ); ?></p>
@@ -187,13 +186,18 @@ function relevanssi_indexing_tab() {
187
  $excluded_from_search = __( 'no', 'relevanssi' );
188
  }
189
  $name_id = 'relevanssi_index_type_' . $type;
190
- printf( '<tr><td>%1$s</td><td><input type="checkbox" name="%2$s" id="%2$s" %3$s /></td><td>%4$s</td></tr>',
191
- esc_html( $label ), esc_attr( $name_id ), esc_html( $checked ), esc_html( $excluded_from_search ) );
 
 
 
 
 
192
  }
193
  ?>
194
  <tr style="display:none">
195
  <td>
196
- Helpful little control field
197
  </td>
198
  <td>
199
  <input type='checkbox' name='relevanssi_index_type_bogus' id='relevanssi_index_type_bogus' checked="checked" />
@@ -205,6 +209,7 @@ function relevanssi_indexing_tab() {
205
  </table>
206
  <?php // Translators: %1$s is 'attachment', %2$s opens the link, %3$s closes it. ?>
207
  <p class="description"><?php printf( esc_html__( '%1$s includes all attachment types. If you want to index only some attachments, see %2$sControlling attachment types in the Knowledge base%3$s.', 'relevanssi' ), '<code>attachment</code>', '<a href="https://www.relevanssi.com/knowledge-base/controlling-attachment-types-index/">', '</a>' ); ?></p>
 
208
  </td>
209
  </tr>
210
 
@@ -239,8 +244,13 @@ function relevanssi_indexing_tab() {
239
  $public = __( 'yes', 'relevanssi' );
240
  }
241
  $name_id = 'relevanssi_index_taxonomy_' . $taxonomy->name;
242
- printf( '<tr><td>%1$s</td><td><input type="checkbox" name="%2$s" id="%2$s" %3$s /></td><td>%4$s</td></tr>',
243
- esc_html( $label ), esc_attr( $name_id ), esc_html( $checked ), esc_html( $public ) );
 
 
 
 
 
244
  }
245
  ?>
246
  </table>
@@ -252,7 +262,7 @@ function relevanssi_indexing_tab() {
252
 
253
  <tr>
254
  <th scope="row">
255
- <label for='relevanssi_index_comments'><?php esc_html_e( 'Comments', 'relevanssi' ); ?></label>
256
  </th>
257
  <td>
258
  <select name='relevanssi_index_comments' id='relevanssi_index_comments'>
@@ -266,7 +276,7 @@ function relevanssi_indexing_tab() {
266
 
267
  <tr>
268
  <th scope="row">
269
- <label for='relevanssi_index_fields'><?php esc_html_e( 'Custom fields', 'relevanssi' ); ?></label>
270
  </th>
271
  <td>
272
  <select name='relevanssi_index_fields_select' id='relevanssi_index_fields_select'>
@@ -298,12 +308,13 @@ function relevanssi_indexing_tab() {
298
  }
299
  ?>
300
  >
 
301
  <input type='text' name='relevanssi_index_fields' id='relevanssi_index_fields' size='60' value='<?php echo esc_attr( $index_fields ); ?>' />
302
  <p class="description"><?php esc_html_e( "Enter a comma-separated list of custom fields to include in the index. With Relevanssi Premium, you can also use 'fieldname_%_subfieldname' notation for ACF repeater fields.", 'relevanssi' ); ?></p>
303
  <p class="description"><?php esc_html_e( "You can use 'relevanssi_index_custom_fields' filter hook to adjust which custom fields are indexed.", 'relevanssi' ); ?></p>
304
  </div>
305
  <?php if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) : ?>
306
- <?php // Translators: %1$s is the 'some' option and %2$s is '_sku'. ?>
307
  <p class="description"><?php printf( esc_html__( 'If you want the SKU included, choose %1$s and enter %2$s. Also see the contextual help for more details.', 'relevanssi' ), esc_html( "'" . __( 'some', 'relevanssi' ) . "'" ), '<code>_sku</code>' ); ?></p>
308
  <?php endif; ?>
309
  </td>
@@ -311,7 +322,7 @@ function relevanssi_indexing_tab() {
311
 
312
  <tr>
313
  <th scope="row">
314
- <label for='relevanssi_index_author'><?php esc_html_e( 'Author display names', 'relevanssi' ); ?></label>
315
  </th>
316
  <td>
317
  <fieldset>
@@ -327,7 +338,7 @@ function relevanssi_indexing_tab() {
327
 
328
  <tr>
329
  <th scope="row">
330
- <label for='relevanssi_index_excerpt'><?php esc_html_e( 'Excerpts', 'relevanssi' ); ?></label>
331
  </th>
332
  <td>
333
  <fieldset>
@@ -351,7 +362,7 @@ function relevanssi_indexing_tab() {
351
  <table class="form-table">
352
  <tr>
353
  <th scope="row">
354
- <label for='relevanssi_expand_shortcodes'><?php esc_html_e( 'Expand shortcodes', 'relevanssi' ); ?></label>
355
  </th>
356
  <td>
357
  <fieldset>
@@ -487,5 +498,5 @@ function relevanssi_indexing_tab() {
487
  <p><button type="button" style="display: none" id="hide_advanced_indexing"><?php esc_html_e( 'Hide advanced settings', 'relevanssi' ); ?></button></p>
488
 
489
  </div>
490
- <?php
491
  }
47
  $fields_select_none = '';
48
  $fields_select_some = 'selected';
49
  $fields_select_visible = '';
 
50
 
51
  if ( empty( $index_fields ) ) {
52
  $fields_select_none = 'selected';
87
  $punct_hyphens_remove = relevanssi_select( $punctuation['hyphens'], 'remove' );
88
  $punct_hyphens_keep = relevanssi_select( $punctuation['hyphens'], 'keep' );
89
 
90
+ $docs_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT doc) FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc != -1' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
91
+ $terms_count = $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $relevanssi_variables['relevanssi_table'] ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
92
+ $lowest_doc = $wpdb->get_var( 'SELECT doc FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc > 0 ORDER BY doc ASC LIMIT 1' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
93
 
94
  if ( RELEVANSSI_PREMIUM ) {
95
+ $user_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT item) FROM ' . $relevanssi_variables['relevanssi_table'] . " WHERE type = 'user'" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
96
+ $taxterm_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT item) FROM ' . $relevanssi_variables['relevanssi_table'] . " WHERE (type != 'post' AND type != 'attachment' AND type != 'user')" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
97
  }
98
 
99
  ?>
101
 
102
  <table class="form-table">
103
  <tr>
104
+ <td scope="row">
105
  <input type='submit' name='submit' value='<?php esc_attr_e( 'Save the options', 'relevanssi' ); ?>' class='button button-primary' /><br /><br />
106
  <input type="button" id="build_index" name="index" value="<?php esc_attr_e( 'Build the index', 'relevanssi' ); ?>" class='button-primary' /><br /><br />
107
  <input type="button" id="continue_indexing" name="continue" value="<?php esc_attr_e( 'Index unindexed posts', 'relevanssi' ); ?>" class='button-primary' />
108
+ </td>
109
  <td>
110
  <div id='indexing_button_instructions'>
111
  <?php // Translators: %s is "Build the index". ?>
122
  <div id='relevanssi-note' style='display: none'></div>
123
  <div id='relevanssi-progress' class='rpi-progress'><div class="rpi-indicator"></div></div>
124
  <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>
125
+ <label for="results" class="screen-reader-text"><?php esc_html_e( 'Results', 'relevanssi' ); ?></label><textarea id='results' rows='10' cols='80'></textarea>
126
  <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>
127
  </td>
128
  </tr>
132
  <?php if ( RELEVANSSI_PREMIUM ) : ?>
133
  <br /><?php echo esc_html( $user_count ); ?> <?php echo esc_html( _n( 'user in the index.', 'users in the index.', $user_count, 'relevanssi' ) ); ?><br />
134
  <?php echo esc_html( $taxterm_count ); ?> <?php echo esc_html( _n( 'taxonomy term in the index.', 'taxonomy terms in the index.', $taxterm_count, 'relevanssi' ) ); ?>
135
+ <?php endif; ?>
136
  </p>
137
  <p><?php echo esc_html( $terms_count ); ?> <?php echo esc_html( _n( 'term in the index.', 'terms in the index.', $terms_count, 'relevanssi' ) ); ?><br />
138
  <?php echo esc_html( $lowest_doc ); ?> <?php esc_html_e( 'is the lowest post ID indexed.', 'relevanssi' ); ?></p>
186
  $excluded_from_search = __( 'no', 'relevanssi' );
187
  }
188
  $name_id = 'relevanssi_index_type_' . $type;
189
+ printf(
190
+ '<tr><td><label for="%2$s">%1$s</label></td><td><input type="checkbox" name="%2$s" id="%2$s" %3$s /></td><td>%4$s</td></tr>',
191
+ esc_html( $label ),
192
+ esc_attr( $name_id ),
193
+ esc_html( $checked ),
194
+ esc_html( $excluded_from_search )
195
+ );
196
  }
197
  ?>
198
  <tr style="display:none">
199
  <td>
200
+ <label for="relevanssi_index_type_bogus">Helper control field to make sure settings are saved if no post types are selected.</label>
201
  </td>
202
  <td>
203
  <input type='checkbox' name='relevanssi_index_type_bogus' id='relevanssi_index_type_bogus' checked="checked" />
209
  </table>
210
  <?php // Translators: %1$s is 'attachment', %2$s opens the link, %3$s closes it. ?>
211
  <p class="description"><?php printf( esc_html__( '%1$s includes all attachment types. If you want to index only some attachments, see %2$sControlling attachment types in the Knowledge base%3$s.', 'relevanssi' ), '<code>attachment</code>', '<a href="https://www.relevanssi.com/knowledge-base/controlling-attachment-types-index/">', '</a>' ); ?></p>
212
+ <p class="description"><?php esc_html_e( "If you want to index a post type that's marked 'Excluded from search', you can do that without worrying about it – but you need to uncheck the 'Respect exclude_from_search' setting from the Searching tab.", 'relevanssi' ); ?></p>
213
  </td>
214
  </tr>
215
 
244
  $public = __( 'yes', 'relevanssi' );
245
  }
246
  $name_id = 'relevanssi_index_taxonomy_' . $taxonomy->name;
247
+ printf(
248
+ '<tr><td><label for="%2$s">%1$s</label></td><td><input type="checkbox" name="%2$s" id="%2$s" %3$s /></td><td>%4$s</td></tr>',
249
+ esc_html( $label ),
250
+ esc_attr( $name_id ),
251
+ esc_html( $checked ),
252
+ esc_html( $public )
253
+ );
254
  }
255
  ?>
256
  </table>
262
 
263
  <tr>
264
  <th scope="row">
265
+ <label for='relevanssi_index_comments'><?php esc_html_e( 'Comments', 'relevanssi' ); ?></label>
266
  </th>
267
  <td>
268
  <select name='relevanssi_index_comments' id='relevanssi_index_comments'>
276
 
277
  <tr>
278
  <th scope="row">
279
+ <label for='relevanssi_index_fields_select'><?php esc_html_e( 'Custom fields', 'relevanssi' ); ?></label>
280
  </th>
281
  <td>
282
  <select name='relevanssi_index_fields_select' id='relevanssi_index_fields_select'>
308
  }
309
  ?>
310
  >
311
+ <label for="relevanssi_index_fields" class="screen-reader-text"><?php esc_html__( 'Custom fields to index', 'relevanssi' ); ?></label>
312
  <input type='text' name='relevanssi_index_fields' id='relevanssi_index_fields' size='60' value='<?php echo esc_attr( $index_fields ); ?>' />
313
  <p class="description"><?php esc_html_e( "Enter a comma-separated list of custom fields to include in the index. With Relevanssi Premium, you can also use 'fieldname_%_subfieldname' notation for ACF repeater fields.", 'relevanssi' ); ?></p>
314
  <p class="description"><?php esc_html_e( "You can use 'relevanssi_index_custom_fields' filter hook to adjust which custom fields are indexed.", 'relevanssi' ); ?></p>
315
  </div>
316
  <?php if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) : ?>
317
+ <?php // Translators: %1$s is the 'some' option and %2$s is '_sku'. ?>
318
  <p class="description"><?php printf( esc_html__( 'If you want the SKU included, choose %1$s and enter %2$s. Also see the contextual help for more details.', 'relevanssi' ), esc_html( "'" . __( 'some', 'relevanssi' ) . "'" ), '<code>_sku</code>' ); ?></p>
319
  <?php endif; ?>
320
  </td>
322
 
323
  <tr>
324
  <th scope="row">
325
+ <?php esc_html_e( 'Author display names', 'relevanssi' ); ?>
326
  </th>
327
  <td>
328
  <fieldset>
338
 
339
  <tr>
340
  <th scope="row">
341
+ <?php esc_html_e( 'Excerpts', 'relevanssi' ); ?>
342
  </th>
343
  <td>
344
  <fieldset>
362
  <table class="form-table">
363
  <tr>
364
  <th scope="row">
365
+ <?php esc_html_e( 'Expand shortcodes', 'relevanssi' ); ?>
366
  </th>
367
  <td>
368
  <fieldset>
498
  <p><button type="button" style="display: none" id="hide_advanced_indexing"><?php esc_html_e( 'Hide advanced settings', 'relevanssi' ); ?></button></p>
499
 
500
  </div>
501
+ <?php
502
  }
lib/tabs/logging-tab.php CHANGED
@@ -26,11 +26,11 @@ function relevanssi_logging_tab() {
26
  $omit_from_logs = get_option( 'relevanssi_omit_from_logs' );
27
  $trim_logs = get_option( 'relevanssi_trim_logs' );
28
 
29
- ?>
30
  <table class="form-table">
31
  <tr>
32
  <th scope="row">
33
- <label for='relevanssi_log_queries'><?php esc_html_e( 'Enable logs', 'relevanssi' ); ?></label>
34
  </th>
35
  <td>
36
  <fieldset>
@@ -43,15 +43,18 @@ function relevanssi_logging_tab() {
43
  <p class="description">
44
  <?php
45
  // Translators: %1$s is the name of the "User searches" page, %2$s is the name of the database table.
46
- printf( esc_html__( "If enabled, Relevanssi will log user queries. The logs can be examined under '%1\$s' on the Dashboard admin menu and are stored in the %2\$s database table.", 'relevanssi' ),
47
- esc_html__( 'User searches', 'relevanssi' ), esc_html( $wpdb->prefix . 'relevanssi_log' ) );
 
 
 
48
  ?>
49
  </p>
50
  </td>
51
  </tr>
52
  <tr>
53
  <th scope="row">
54
- <label for='relevanssi_log_queries_with_ip'><?php esc_html_e( 'Log user IP', 'relevanssi' ); ?></label>
55
  </th>
56
  <td>
57
  <fieldset>
@@ -63,7 +66,7 @@ function relevanssi_logging_tab() {
63
  </fieldset>
64
  <p class="description"><?php esc_html_e( "If enabled, Relevanssi will log user's IP adress with the queries. Note that this may be illegal where you live, and in EU will create a person registry that falls under the GDPR.", 'relevanssi' ); ?></p>
65
  </td>
66
- </tr>
67
  <tr>
68
  <th scope="row">
69
  <label for='relevanssi_omit_from_logs'><?php esc_html_e( 'Exclude users', 'relevanssi' ); ?></label>
@@ -102,7 +105,7 @@ function relevanssi_logging_tab() {
102
 
103
  <tr>
104
  <th scope="row">
105
- <label for='relevanssi_export_logs'><?php esc_html_e( 'Export logs', 'relevanssi' ); ?></label>
106
  </th>
107
  <td>
108
  <?php submit_button( __( 'Export the log as a CSV file', 'relevanssi' ), 'secondary', 'relevanssi_export' ); ?>
26
  $omit_from_logs = get_option( 'relevanssi_omit_from_logs' );
27
  $trim_logs = get_option( 'relevanssi_trim_logs' );
28
 
29
+ ?>
30
  <table class="form-table">
31
  <tr>
32
  <th scope="row">
33
+ <?php esc_html_e( 'Enable logs', 'relevanssi' ); ?>
34
  </th>
35
  <td>
36
  <fieldset>
43
  <p class="description">
44
  <?php
45
  // Translators: %1$s is the name of the "User searches" page, %2$s is the name of the database table.
46
+ printf(
47
+ esc_html__( "If enabled, Relevanssi will log user queries. The logs can be examined under '%1\$s' on the Dashboard admin menu and are stored in the %2\$s database table.", 'relevanssi' ),
48
+ esc_html__( 'User searches', 'relevanssi' ),
49
+ esc_html( $wpdb->prefix . 'relevanssi_log' )
50
+ );
51
  ?>
52
  </p>
53
  </td>
54
  </tr>
55
  <tr>
56
  <th scope="row">
57
+ <?php esc_html_e( 'Log user IP', 'relevanssi' ); ?>
58
  </th>
59
  <td>
60
  <fieldset>
66
  </fieldset>
67
  <p class="description"><?php esc_html_e( "If enabled, Relevanssi will log user's IP adress with the queries. Note that this may be illegal where you live, and in EU will create a person registry that falls under the GDPR.", 'relevanssi' ); ?></p>
68
  </td>
69
+ </tr>
70
  <tr>
71
  <th scope="row">
72
  <label for='relevanssi_omit_from_logs'><?php esc_html_e( 'Exclude users', 'relevanssi' ); ?></label>
105
 
106
  <tr>
107
  <th scope="row">
108
+ <?php esc_html_e( 'Export logs', 'relevanssi' ); ?>
109
  </th>
110
  <td>
111
  <?php submit_button( __( 'Export the log as a CSV file', 'relevanssi' ), 'secondary', 'relevanssi_export' ); ?>
lib/tabs/overview-tab.php CHANGED
@@ -18,7 +18,7 @@
18
  function relevanssi_overview_tab() {
19
  global $relevanssi_variables;
20
  $this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
21
- ?>
22
  <h2><?php esc_html_e( 'Welcome to Relevanssi!', 'relevanssi' ); ?></h2>
23
 
24
  <table class="form-table">
@@ -40,11 +40,11 @@ function relevanssi_overview_tab() {
40
  <p><?php esc_html_e( "You've already installed Relevanssi. That's a great first step towards good search experience!", 'relevanssi' ); ?></p>
41
  <ol>
42
  <?php if ( 'done' !== get_option( 'relevanssi_indexed' ) ) : ?>
43
- <?php // Translators: %1$s opens the link, %2$s is the anchor text, %3$s closes the link. ?>
44
  <li><p><?php printf( esc_html__( 'Now, you need an index. Head over to the %1$s%2$s%3$s tab to set up the basic indexing options and to build the index.', 'relevanssi' ), "<a href='" . esc_attr( $this_page ) . "&amp;tab=indexing'>", esc_html__( 'Indexing', 'relevanssi' ), '</a>' ); ?></p>
45
  <p><?php esc_html_e( 'You need to check at least the following options:', 'relevanssi' ); ?><br />
46
  – <?php esc_html_e( 'Make sure the post types you want to include in the index are indexed.', 'relevanssi' ); ?><br />
47
- <?php // Translators: %s is '_sku'. ?>
48
  – <?php printf( esc_html__( 'Do you use custom fields to store content you want included? If so, add those too. WooCommerce user? You probably want to include %s.', 'relevanssi' ), '<code>_sku</code>' ); ?></p>
49
  <p><?php esc_html_e( "Then just save the options and build the index. First time you have to do it manually, but after that, it's fully automatic: all changes are reflected in the index without reindexing. (That said, it's a good idea to rebuild the index once a year.)", 'relevanssi' ); ?></p>
50
  </li>
18
  function relevanssi_overview_tab() {
19
  global $relevanssi_variables;
20
  $this_page = '?page=' . plugin_basename( $relevanssi_variables['file'] );
21
+ ?>
22
  <h2><?php esc_html_e( 'Welcome to Relevanssi!', 'relevanssi' ); ?></h2>
23
 
24
  <table class="form-table">
40
  <p><?php esc_html_e( "You've already installed Relevanssi. That's a great first step towards good search experience!", 'relevanssi' ); ?></p>
41
  <ol>
42
  <?php if ( 'done' !== get_option( 'relevanssi_indexed' ) ) : ?>
43
+ <?php // Translators: %1$s opens the link, %2$s is the anchor text, %3$s closes the link. ?>
44
  <li><p><?php printf( esc_html__( 'Now, you need an index. Head over to the %1$s%2$s%3$s tab to set up the basic indexing options and to build the index.', 'relevanssi' ), "<a href='" . esc_attr( $this_page ) . "&amp;tab=indexing'>", esc_html__( 'Indexing', 'relevanssi' ), '</a>' ); ?></p>
45
  <p><?php esc_html_e( 'You need to check at least the following options:', 'relevanssi' ); ?><br />
46
  – <?php esc_html_e( 'Make sure the post types you want to include in the index are indexed.', 'relevanssi' ); ?><br />
47
+ <?php // Translators: %s is '_sku'. ?>
48
  – <?php printf( esc_html__( 'Do you use custom fields to store content you want included? If so, add those too. WooCommerce user? You probably want to include %s.', 'relevanssi' ), '<code>_sku</code>' ); ?></p>
49
  <p><?php esc_html_e( "Then just save the options and build the index. First time you have to do it manually, but after that, it's fully automatic: all changes are reflected in the index without reindexing. (That said, it's a good idea to rebuild the index once a year.)", 'relevanssi' ); ?></p>
50
  </li>
lib/tabs/search-page.php CHANGED
@@ -1,22 +1,23 @@
1
  <?php
2
  /**
3
- * /premium/tabs/search-tab.php
4
  *
5
- * Prints out the Premium search tab in Relevanssi settings.
6
  *
7
- * @package Relevanssi_Premium
8
  * @author Mikko Saari
9
  * @license https://wordpress.org/about/gpl/ GNU General Public License
10
  * @see https://www.relevanssi.com/
11
  */
12
 
13
  /**
14
- * Prints out the Premium search tab in Relevanssi settings.
15
  */
16
  function relevanssi_search_tab() {
17
- ?>
18
  <p><?php esc_html_e( 'You can use this search to perform Relevanssi searches without any restrictions from WordPress. You can search all post types here.', 'relevanssi' ); ?></p>
19
 
 
20
  <table class="form-table">
21
  <tr>
22
  <th scope="row">
@@ -26,6 +27,33 @@ function relevanssi_search_tab() {
26
  <input type='text' name='s' id='s' size='60' />
27
  </td>
28
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  <tr>
30
  <th scope="row">
31
  <label for='posts_per_page'><?php esc_html_e( 'Posts per page', 'relevanssi' ); ?></label>
@@ -50,14 +78,15 @@ function relevanssi_search_tab() {
50
  </td>
51
  </tr>
52
  <tr>
53
- <th scope="row">
54
- </th>
55
  <td>
56
  <input type='submit' name='search' id='search' value='<?php echo esc_html_x( 'Search', 'button action', 'relevanssi' ); ?>' class='button' />
57
  </td>
58
  </tr>
59
  </table>
 
60
 
61
  <div id='results'></div>
62
- <?php
63
  }
1
  <?php
2
  /**
3
+ * /lib/tabs/search-tab.php
4
  *
5
+ * Prints out the search tab in Relevanssi settings.
6
  *
7
+ * @package Relevanssi
8
  * @author Mikko Saari
9
  * @license https://wordpress.org/about/gpl/ GNU General Public License
10
  * @see https://www.relevanssi.com/
11
  */
12
 
13
  /**
14
+ * Prints out the search tab in Relevanssi settings.
15
  */
16
  function relevanssi_search_tab() {
17
+ ?>
18
  <p><?php esc_html_e( 'You can use this search to perform Relevanssi searches without any restrictions from WordPress. You can search all post types here.', 'relevanssi' ); ?></p>
19
 
20
+ <form action="" method="get">
21
  <table class="form-table">
22
  <tr>
23
  <th scope="row">
27
  <input type='text' name='s' id='s' size='60' />
28
  </td>
29
  </tr>
30
+ <tr>
31
+ <th scope="row">
32
+ <label for='post_types'><?php esc_html_e( 'Post type', 'relevanssi' ); ?></label>
33
+ </th>
34
+ <td>
35
+ <select name='post_types' id='post_types'>
36
+ <option value="any"><?php esc_html_e( 'Any', 'relevanssi' ); ?></option>
37
+ <?php
38
+ echo implode(
39
+ ' ',
40
+ array_map( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
41
+ function ( $post_type ) {
42
+ $pt = get_post_type_object( $post_type );
43
+ if ( $pt ) {
44
+ $post_type_value = esc_attr( $post_type );
45
+ $post_type_name = esc_html( $pt->labels->singular_name );
46
+ return "<option value='{$post_type_value}'>{$post_type_name}</option>";
47
+ }
48
+ return null;
49
+ },
50
+ get_option( 'relevanssi_index_post_types' )
51
+ )
52
+ );
53
+ ?>
54
+ </select>
55
+ </td>
56
+ </tr>
57
  <tr>
58
  <th scope="row">
59
  <label for='posts_per_page'><?php esc_html_e( 'Posts per page', 'relevanssi' ); ?></label>
78
  </td>
79
  </tr>
80
  <tr>
81
+ <td>
82
+ </td>
83
  <td>
84
  <input type='submit' name='search' id='search' value='<?php echo esc_html_x( 'Search', 'button action', 'relevanssi' ); ?>' class='button' />
85
  </td>
86
  </tr>
87
  </table>
88
+ </form>
89
 
90
  <div id='results'></div>
91
+ <?php
92
  }
lib/tabs/searching-tab.php CHANGED
@@ -57,7 +57,7 @@ function relevanssi_searching_tab() {
57
  $orfallback_visibility = '';
58
  }
59
 
60
- $docs_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT doc) FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc != -1' ); // WPCS: unprepared SQL ok, Relevanssi table name.
61
  ?>
62
 
63
  <table class="form-table">
@@ -78,7 +78,7 @@ function relevanssi_searching_tab() {
78
  }
79
  ?>
80
  </td>
81
- </tr>
82
  <tr id="orfallback" class='<?php echo esc_attr( $orfallback_visibility ); ?>'>
83
  <th scope="row">
84
  <label for='relevanssi_disable_or_fallback'><?php esc_html_e( 'Fallback to OR', 'relevanssi' ); ?></label>
@@ -143,7 +143,7 @@ function relevanssi_searching_tab() {
143
  </thead>
144
  <tr>
145
  <td>
146
- <?php esc_html_e( 'Content', 'relevanssi' ); ?>
147
  </td>
148
  <td class="col-2">
149
  <input type='text' name='relevanssi_content_boost' id='relevanssi_content_boost' size='4' value='<?php echo esc_attr( $content_boost ); ?>' />
@@ -151,7 +151,7 @@ function relevanssi_searching_tab() {
151
  </tr>
152
  <tr>
153
  <td>
154
- <?php esc_html_e( 'Titles', 'relevanssi' ); ?>
155
  </td>
156
  <td class="col-2">
157
  <input type='text' name='relevanssi_title_boost' id='relevanssi_title_boost' size='4' value='<?php echo esc_attr( $title_boost ); ?>' />
@@ -164,7 +164,7 @@ function relevanssi_searching_tab() {
164
  ?>
165
  <tr>
166
  <td>
167
- <?php esc_html_e( 'Comment text', 'relevanssi' ); ?>
168
  </td>
169
  <td class="col-2">
170
  <input type='text' name='relevanssi_comment_boost' id='relevanssi_comment_boost' size='4' value='<?php echo esc_attr( $comment_boost ); ?>' />
@@ -185,7 +185,7 @@ function relevanssi_searching_tab() {
185
  ?>
186
  </table>
187
  </td>
188
- </tr>
189
  <?php
190
  if ( function_exists( 'relevanssi_form_recency_cutoff' ) ) {
191
  relevanssi_form_recency_cutoff();
@@ -193,7 +193,7 @@ function relevanssi_searching_tab() {
193
  ?>
194
  <tr>
195
  <th scope="row">
196
- <label for='relevanssi_exact_match_bonus'><?php esc_html_e( 'Boost exact matches', 'relevanssi' ); ?></label>
197
  </th>
198
  <td>
199
  <fieldset>
@@ -209,10 +209,10 @@ function relevanssi_searching_tab() {
209
  </tr>
210
  <?php
211
  if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_get_post' ) ) {
212
- ?>
213
  <tr>
214
  <th scope="row">
215
- <label for='relevanssi_wpml_only_current'><?php esc_html_e( 'WPML', 'relevanssi' ); ?></label>
216
  </th>
217
  <td>
218
  <fieldset>
@@ -229,7 +229,7 @@ function relevanssi_searching_tab() {
229
  <?php if ( function_exists( 'pll_get_post' ) ) { ?>
230
  <tr>
231
  <th scope="row">
232
- <label for='relevanssi_polylang_all_languages'><?php esc_html_e( 'Polylang', 'relevanssi' ); ?></label>
233
  </th>
234
  <td>
235
  <fieldset>
@@ -245,7 +245,7 @@ function relevanssi_searching_tab() {
245
  <?php } // Polylang. ?>
246
  <tr>
247
  <th scope="row">
248
- <label for='relevanssi_admin_search'><?php esc_html_e( 'Admin search', 'relevanssi' ); ?></label>
249
  </th>
250
  <td>
251
  <fieldset>
@@ -261,7 +261,7 @@ function relevanssi_searching_tab() {
261
  <tr>
262
  <th scope="row">
263
  <?php // Translators: %s is 'exclude_from_search'. ?>
264
- <label for='relevanssi_respect_exclude'><?php printf( esc_html__( 'Respect %s', 'relevanssi' ), 'exclude_from_search' ); ?></label>
265
  </th>
266
  <td>
267
  <fieldset>
@@ -280,14 +280,14 @@ function relevanssi_searching_tab() {
280
  $private_types = array_merge( $pt_1, $pt_2 );
281
  $problem_post_types = array_intersect( $index_post_types, $private_types );
282
  if ( ! empty( $problem_post_types ) ) {
283
- ?>
284
  <p class="description important">
285
  <?php
286
  esc_html_e( "You probably should uncheck this option, because you've set Relevanssi to index the following non-public post types:", 'relevanssi' );
287
  echo ' ' . esc_html( implode( ', ', $problem_post_types ) );
288
  ?>
289
  </p>
290
- <?php
291
  }
292
  }
293
  ?>
@@ -296,7 +296,7 @@ function relevanssi_searching_tab() {
296
  </tr>
297
  <tr>
298
  <th scope="row">
299
- <label for='relevanssi_throttle'><?php esc_html_e( 'Throttle searches', 'relevanssi' ); ?></label>
300
  </th>
301
  <td id="throttlesearches">
302
  <div id="throttle_disabled"
@@ -328,26 +328,32 @@ function relevanssi_searching_tab() {
328
  <p class="description"><?php esc_html_e( 'If this option is checked, Relevanssi will limit search results to at most 500 results per term. This will improve performance, but may cause some relevant documents to go unfound. See Help for more details.', 'relevanssi' ); ?></p>
329
  </div>
330
  </td>
331
- </tr>
332
  <tr>
333
  <th scope="row">
334
- <label for='relevanssi_cat'><?php esc_html_e( 'Category restriction', 'relevanssi' ); ?></label>
335
  </th>
336
  <td>
337
  <div class="categorydiv" style="max-width: 400px">
338
  <div class="tabs-panel">
 
 
339
  <ul id="category_inclusion_checklist">
340
  <?php
341
  $selected_cats = explode( ',', $cat );
342
  $walker = get_relevanssi_taxonomy_walker();
343
  $walker->name = 'relevanssi_cat';
344
- wp_terms_checklist( 0, array(
345
- 'taxonomy' => 'category',
346
- 'selected_cats' => $selected_cats,
347
- 'walker' => $walker,
348
- ));
 
 
 
349
  ?>
350
  </ul>
 
351
  <input type="hidden" name="relevanssi_cat_active" value="1" />
352
  </div>
353
  </div>
@@ -356,24 +362,30 @@ function relevanssi_searching_tab() {
356
  </tr>
357
  <tr>
358
  <th scope="row">
359
- <label for='relevanssi_excat'><?php esc_html_e( 'Category exclusion', 'relevanssi' ); ?></label>
360
  </th>
361
  <td>
362
  <div class="categorydiv" style="max-width: 400px">
363
  <div class="tabs-panel">
 
 
364
  <ul id="category_exclusion_checklist">
365
  <?php
366
  $selected_cats = explode( ',', $excat );
367
  $walker = get_relevanssi_taxonomy_walker();
368
  $walker->name = 'relevanssi_excat';
369
- wp_terms_checklist( 0, array(
370
- 'taxonomy' => 'category',
371
- 'selected_cats' => $selected_cats,
372
- 'walker' => $walker,
373
- ));
 
 
 
374
  ?>
375
  </ul>
376
  <input type="hidden" name="relevanssi_excat_active" value="1" />
 
377
  </div>
378
  </div>
379
  <p class="description"><?php esc_html_e( 'Posts in these categories are not included in search results. To exclude the posts completely from the index, see Help.', 'relevanssi' ); ?></p>
57
  $orfallback_visibility = '';
58
  }
59
 
60
+ $docs_count = $wpdb->get_var( 'SELECT COUNT(DISTINCT doc) FROM ' . $relevanssi_variables['relevanssi_table'] . ' WHERE doc != -1' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
61
  ?>
62
 
63
  <table class="form-table">
78
  }
79
  ?>
80
  </td>
81
+ </tr>
82
  <tr id="orfallback" class='<?php echo esc_attr( $orfallback_visibility ); ?>'>
83
  <th scope="row">
84
  <label for='relevanssi_disable_or_fallback'><?php esc_html_e( 'Fallback to OR', 'relevanssi' ); ?></label>
143
  </thead>
144
  <tr>
145
  <td>
146
+ <label for="relevanssi_content_boost"><?php esc_html_e( 'Content', 'relevanssi' ); ?></label>
147
  </td>
148
  <td class="col-2">
149
  <input type='text' name='relevanssi_content_boost' id='relevanssi_content_boost' size='4' value='<?php echo esc_attr( $content_boost ); ?>' />
151
  </tr>
152
  <tr>
153
  <td>
154
+ <label for="relevanssi_title_boost"><?php esc_html_e( 'Titles', 'relevanssi' ); ?></label>
155
  </td>
156
  <td class="col-2">
157
  <input type='text' name='relevanssi_title_boost' id='relevanssi_title_boost' size='4' value='<?php echo esc_attr( $title_boost ); ?>' />
164
  ?>
165
  <tr>
166
  <td>
167
+ <label for="relevanssi_comment_boost"><?php esc_html_e( 'Comment text', 'relevanssi' ); ?></label>
168
  </td>
169
  <td class="col-2">
170
  <input type='text' name='relevanssi_comment_boost' id='relevanssi_comment_boost' size='4' value='<?php echo esc_attr( $comment_boost ); ?>' />
185
  ?>
186
  </table>
187
  </td>
188
+ </tr>
189
  <?php
190
  if ( function_exists( 'relevanssi_form_recency_cutoff' ) ) {
191
  relevanssi_form_recency_cutoff();
193
  ?>
194
  <tr>
195
  <th scope="row">
196
+ <?php esc_html_e( 'Boost exact matches', 'relevanssi' ); ?>
197
  </th>
198
  <td>
199
  <fieldset>
209
  </tr>
210
  <?php
211
  if ( function_exists( 'icl_object_id' ) && ! function_exists( 'pll_get_post' ) ) {
212
+ ?>
213
  <tr>
214
  <th scope="row">
215
+ <?php esc_html_e( 'WPML', 'relevanssi' ); ?>
216
  </th>
217
  <td>
218
  <fieldset>
229
  <?php if ( function_exists( 'pll_get_post' ) ) { ?>
230
  <tr>
231
  <th scope="row">
232
+ <?php esc_html_e( 'Polylang', 'relevanssi' ); ?>
233
  </th>
234
  <td>
235
  <fieldset>
245
  <?php } // Polylang. ?>
246
  <tr>
247
  <th scope="row">
248
+ <?php esc_html_e( 'Admin search', 'relevanssi' ); ?>
249
  </th>
250
  <td>
251
  <fieldset>
261
  <tr>
262
  <th scope="row">
263
  <?php // Translators: %s is 'exclude_from_search'. ?>
264
+ <?php printf( esc_html__( 'Respect %s', 'relevanssi' ), 'exclude_from_search' ); ?>
265
  </th>
266
  <td>
267
  <fieldset>
280
  $private_types = array_merge( $pt_1, $pt_2 );
281
  $problem_post_types = array_intersect( $index_post_types, $private_types );
282
  if ( ! empty( $problem_post_types ) ) {
283
+ ?>
284
  <p class="description important">
285
  <?php
286
  esc_html_e( "You probably should uncheck this option, because you've set Relevanssi to index the following non-public post types:", 'relevanssi' );
287
  echo ' ' . esc_html( implode( ', ', $problem_post_types ) );
288
  ?>
289
  </p>
290
+ <?php
291
  }
292
  }
293
  ?>
296
  </tr>
297
  <tr>
298
  <th scope="row">
299
+ <?php esc_html_e( 'Throttle searches', 'relevanssi' ); ?>
300
  </th>
301
  <td id="throttlesearches">
302
  <div id="throttle_disabled"
328
  <p class="description"><?php esc_html_e( 'If this option is checked, Relevanssi will limit search results to at most 500 results per term. This will improve performance, but may cause some relevant documents to go unfound. See Help for more details.', 'relevanssi' ); ?></p>
329
  </div>
330
  </td>
331
+ </tr>
332
  <tr>
333
  <th scope="row">
334
+ <?php esc_html_e( 'Category restriction', 'relevanssi' ); ?>
335
  </th>
336
  <td>
337
  <div class="categorydiv" style="max-width: 400px">
338
  <div class="tabs-panel">
339
+ <fieldset>
340
+ <legend class="screen-reader-text"><?php esc_html_e( 'Category restriction', 'relevanssi' ); ?></legend>
341
  <ul id="category_inclusion_checklist">
342
  <?php
343
  $selected_cats = explode( ',', $cat );
344
  $walker = get_relevanssi_taxonomy_walker();
345
  $walker->name = 'relevanssi_cat';
346
+ wp_terms_checklist(
347
+ 0,
348
+ array(
349
+ 'taxonomy' => 'category',
350
+ 'selected_cats' => $selected_cats,
351
+ 'walker' => $walker,
352
+ )
353
+ );
354
  ?>
355
  </ul>
356
+ </fieldset>
357
  <input type="hidden" name="relevanssi_cat_active" value="1" />
358
  </div>
359
  </div>
362
  </tr>
363
  <tr>
364
  <th scope="row">
365
+ <?php esc_html_e( 'Category exclusion', 'relevanssi' ); ?>
366
  </th>
367
  <td>
368
  <div class="categorydiv" style="max-width: 400px">
369
  <div class="tabs-panel">
370
+ <fieldset>
371
+ <legend class="screen-reader-text"><?php esc_html_e( 'Category exclusion', 'relevanssi' ); ?></legend>
372
  <ul id="category_exclusion_checklist">
373
  <?php
374
  $selected_cats = explode( ',', $excat );
375
  $walker = get_relevanssi_taxonomy_walker();
376
  $walker->name = 'relevanssi_excat';
377
+ wp_terms_checklist(
378
+ 0,
379
+ array(
380
+ 'taxonomy' => 'category',
381
+ 'selected_cats' => $selected_cats,
382
+ 'walker' => $walker,
383
+ )
384
+ );
385
  ?>
386
  </ul>
387
  <input type="hidden" name="relevanssi_excat_active" value="1" />
388
+ </fieldset>
389
  </div>
390
  </div>
391
  <p class="description"><?php esc_html_e( 'Posts in these categories are not included in search results. To exclude the posts completely from the index, see Help.', 'relevanssi' ); ?></p>
lib/tabs/stopwords-tab.php CHANGED
@@ -57,7 +57,7 @@ function relevanssi_show_stopwords() {
57
  global $wpdb, $relevanssi_variables;
58
 
59
  printf( '<p>%s</p>', esc_html__( '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.', 'relevanssi' ) );
60
- ?>
61
  <table class="form-table">
62
  <tr>
63
  <th scope="row">
@@ -79,7 +79,7 @@ function relevanssi_show_stopwords() {
79
  <td>
80
  <?php
81
  echo '<ul>';
82
- $results = $wpdb->get_results( 'SELECT * FROM ' . $relevanssi_variables['stopword_table'] ); // WPCS: unprepared SQL ok, Relevanssi table name.
83
  $exportlist = array();
84
  foreach ( $results as $stopword ) {
85
  $sw = stripslashes( $stopword->stopword );
@@ -89,7 +89,7 @@ function relevanssi_show_stopwords() {
89
  echo '</ul>';
90
 
91
  $exportlist = htmlspecialchars( implode( ', ', $exportlist ) );
92
- ?>
93
  <p><input type="submit" id="removeallstopwords" name="removeallstopwords" value="<?php esc_attr_e( 'Remove all stopwords', 'relevanssi' ); ?>" class='button' /></p>
94
  </td>
95
  </tr>
@@ -98,11 +98,12 @@ function relevanssi_show_stopwords() {
98
  <?php esc_html_e( 'Exportable list of stopwords', 'relevanssi' ); ?>
99
  </th>
100
  <td>
 
101
  <textarea name="stopwords" id="stopwords" rows="2" cols="80"><?php echo esc_textarea( $exportlist ); ?></textarea>
102
  <p class="description"><?php esc_html_e( 'You can copy the list of stopwords here if you want to back up the list, copy it to a different blog or otherwise need the list.', 'relevanssi' ); ?></p>
103
  </td>
104
  </tr>
105
  </table>
106
 
107
- <?php
108
  }
57
  global $wpdb, $relevanssi_variables;
58
 
59
  printf( '<p>%s</p>', esc_html__( '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.', 'relevanssi' ) );
60
+ ?>
61
  <table class="form-table">
62
  <tr>
63
  <th scope="row">
79
  <td>
80
  <?php
81
  echo '<ul>';
82
+ $results = $wpdb->get_results( 'SELECT * FROM ' . $relevanssi_variables['stopword_table'] ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared
83
  $exportlist = array();
84
  foreach ( $results as $stopword ) {
85
  $sw = stripslashes( $stopword->stopword );
89
  echo '</ul>';
90
 
91
  $exportlist = htmlspecialchars( implode( ', ', $exportlist ) );
92
+ ?>
93
  <p><input type="submit" id="removeallstopwords" name="removeallstopwords" value="<?php esc_attr_e( 'Remove all stopwords', 'relevanssi' ); ?>" class='button' /></p>
94
  </td>
95
  </tr>
98
  <?php esc_html_e( 'Exportable list of stopwords', 'relevanssi' ); ?>
99
  </th>
100
  <td>
101
+ <label for="stopwords" class="screen-reader-text"><?php esc_html_e( 'Exportable list of stopwords', 'relevanssi' ); ?></label>
102
  <textarea name="stopwords" id="stopwords" rows="2" cols="80"><?php echo esc_textarea( $exportlist ); ?></textarea>
103
  <p class="description"><?php esc_html_e( 'You can copy the list of stopwords here if you want to back up the list, copy it to a different blog or otherwise need the list.', 'relevanssi' ); ?></p>
104
  </td>
105
  </tr>
106
  </table>
107
 
108
+ <?php
109
  }
lib/tabs/synonyms-tab.php CHANGED
@@ -21,13 +21,13 @@ function relevanssi_synonyms_tab() {
21
  } else {
22
  $synonyms = '';
23
  }
24
- ?>
25
  <h3 id="synonyms"><?php esc_html_e( 'Synonyms', 'relevanssi' ); ?></h3>
26
 
27
  <table class="form-table">
28
  <tr>
29
  <th scope="row">
30
- <?php esc_html_e( 'Synonyms', 'relevanssi' ); ?>
31
  </th>
32
  <td>
33
  <p class="description"><?php esc_html_e( 'Add synonyms here to make the searches find better results. If you notice your users frequently misspelling a product name, or for other reasons use many names for one thing, adding synonyms will make the results better.', 'relevanssi' ); ?></p>
@@ -36,11 +36,11 @@ function relevanssi_synonyms_tab() {
36
  <br />
37
  <textarea name='relevanssi_synonyms' id='relevanssi_synonyms' rows='9' cols='60'><?php echo esc_textarea( $synonyms ); ?></textarea>
38
 
39
- <p class="description"><?php _e( 'The format here is <code>key = value</code>. If you add <code>dog = hound</code> to the list of synonyms, searches for <code>dog</code> automatically become a search for <code>dog hound</code> and will thus match to posts that include either <code>dog</code> or <code>hound</code>. This only works in OR searches: in AND searches the synonyms only restrict the search, as now the search only finds posts that contain <strong>both</strong> <code>dog</code> and <code>hound</code>.', 'relevanssi' ); // WPCS: XSS ok. ?></p>
40
 
41
- <p class="description"><?php _e( 'The synonyms are one direction only. If you want both directions, add the synonym again, reversed: <code>hound = dog</code>.', 'relevanssi' ); // WPCS: XSS ok. ?></p>
42
 
43
- <p class="description"><?php _e( "It's possible to use phrases for the value, but not for the key. <code>dog = \"great dane\"</code> works, but <code>\"great dane\" = dog</code> doesn't.", 'relevanssi' ); // WPCS: XSS ok. ?></p>
44
 
45
  <?php if ( RELEVANSSI_PREMIUM ) : ?>
46
  <p class="description"><?php esc_html_e( 'If you want to use synonyms in AND searches, enable synonym indexing on the Indexing tab.', 'relevanssi' ); ?></p>
@@ -48,5 +48,5 @@ function relevanssi_synonyms_tab() {
48
  </td>
49
  </tr>
50
  </table>
51
- <?php
52
  }
21
  } else {
22
  $synonyms = '';
23
  }
24
+ ?>
25
  <h3 id="synonyms"><?php esc_html_e( 'Synonyms', 'relevanssi' ); ?></h3>
26
 
27
  <table class="form-table">
28
  <tr>
29
  <th scope="row">
30
+ <label for="relevanssi_synonyms"><?php esc_html_e( 'Synonyms', 'relevanssi' ); ?></label>
31
  </th>
32
  <td>
33
  <p class="description"><?php esc_html_e( 'Add synonyms here to make the searches find better results. If you notice your users frequently misspelling a product name, or for other reasons use many names for one thing, adding synonyms will make the results better.', 'relevanssi' ); ?></p>
36
  <br />
37
  <textarea name='relevanssi_synonyms' id='relevanssi_synonyms' rows='9' cols='60'><?php echo esc_textarea( $synonyms ); ?></textarea>
38
 
39
+ <p class="description"><?php _e( 'The format here is <code>key = value</code>. If you add <code>dog = hound</code> to the list of synonyms, searches for <code>dog</code> automatically become a search for <code>dog hound</code> and will thus match to posts that include either <code>dog</code> or <code>hound</code>. This only works in OR searches: in AND searches the synonyms only restrict the search, as now the search only finds posts that contain <strong>both</strong> <code>dog</code> and <code>hound</code>.', 'relevanssi' ); // phpcs:ignore WordPress.Security.EscapeOutput.UnsafePrintingFunction ?></p>
40
 
41
+ <p class="description"><?php _e( 'The synonyms are one direction only. If you want both directions, add the synonym again, reversed: <code>hound = dog</code>.', 'relevanssi' ); // phpcs:ignore WordPress.Security.EscapeOutput.UnsafePrintingFunction ?></p>
42
 
43
+ <p class="description"><?php _e( "It's possible to use phrases for the value, but not for the key. <code>dog = \"great dane\"</code> works, but <code>\"great dane\" = dog</code> doesn't.", 'relevanssi' ); // phpcs:ignore WordPress.Security.EscapeOutput.UnsafePrintingFunction ?></p>
44
 
45
  <?php if ( RELEVANSSI_PREMIUM ) : ?>
46
  <p class="description"><?php esc_html_e( 'If you want to use synonyms in AND searches, enable synonym indexing on the Indexing tab.', 'relevanssi' ); ?></p>
48
  </td>
49
  </tr>
50
  </table>
51
+ <?php
52
  }
readme.txt CHANGED
@@ -3,9 +3,9 @@ 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.1
7
  Requires PHP: 5.6
8
- Stable tag: 4.2.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -129,6 +129,25 @@ Each document database is full of useless words. All the little words that appea
129
  * John Calahan for extensive 4.0 beta testing.
130
 
131
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  = 4.2.0 =
133
  * New feature: The search form shortcode has a new parameter `dropdown` which can be used to add a category dropdown, like this: `[searchform dropdown="category"]`.
134
  * New feature: Relevanssi can now use the contents of the PDF files indexed with WP File Download.
@@ -145,90 +164,12 @@ Each document database is full of useless words. All the little words that appea
145
  * Minor fix: The Did you mean broke with search terms longer than 255 characters.
146
  * Minor fix: Phrases with numbers and one word like "team 17" didn't work, because numbers weren't counted as words.
147
 
148
- = 4.1.4 =
149
- * `EXISTS` and `NOT EXISTS` didn’t work for taxonomy terms in searches.
150
- * WPML post type handling has been improved. If post type allows fallback for default language, Relevanssi will support that.
151
- * 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.
152
- * The Groups posts filter is only applied to public posts to avoid drafts being shown to people who shouldn’t see them.
153
- * The `posts_per_page` query variable didn’t work; it’s now added to the introduced query variables so that it works.
154
- * Relevanssi won’t log empty queries anymore.
155
- * The default tax query relation was switched from `OR` to `AND` to match the WP_Query default behaviour.
156
- * When used with WP 5.1, Relevanssi will now use `wp_insert_site` instead of the now-deprecated `wpmu_new_blog`.
157
- * Multisite blog creation is handled better in WP 5.1+.
158
- * Relevanssi now supports Restrict Content Pro permissions.
159
-
160
- = 4.1.3 =
161
- * Improvements to meta key sorting.
162
- * Relevanssi settings page won't let you exclude categories you have restricted the search to.
163
- * Members plugin compatibility has been improved: it's only used if the 'content permissions' feature has been enabled.
164
- * The excerpt settings page was a bit buggy.
165
- * Slimstat analytics is now added to the blocked shortcodes list.
166
- * New filter: `relevanssi_search_form` works exactly like `get_search_form`, but only applies to the Relevanssi shortcode search forms.
167
- * New JetPack taxonomies and post types have been added to the block list so they won't appear in Relevanssi settings.
168
-
169
- = 4.1.2 =
170
- * Choosing "CSS Style" for highlighting was not possible. That is now fixed.
171
- * Gutenberg reusable block indexing was fatally broken with the latest Gutenberg version. That has been updated.
172
- * Relevanssi now by default respects the WooCommerce "exclude from search" setting.
173
- * `post__not_in` still didn't work properly, it does now.
174
- * New filter: `relevanssi_comparison_order` can be used to define the sorting order when sorting the results by post type.
175
- * "Did you mean" process included a very slow query. It is now cached, leading in some cases to massive performance improvements (we're talking about several seconds here).
176
- * Highlights inside `code` and similar blocks are handled better now.
177
-
178
- = 4.1.1.2 =
179
- * Fixes the broken User searches page.
180
-
181
- = 4.1.1.1 =
182
- * Adding the missing Gutenberg compatibility file.
183
-
184
- = 4.1.1 =
185
- * Relevanssi can now index Gutenberg reusable blocks. (This functionality broke once already before release, so that can happen, since Gutenberg is still in very active development.)
186
- * The `post__in` and `post__not_in` parameters didn't work, and are now fixed. `post_parent__in` and `post_parent__not_in` are also improved.
187
- * You can use named meta queries for sorting posts. Meta query sorting is improved in other ways as well.
188
- * Log export didn't work properly.
189
- * Adding stopwords from the common word list has been fixed.
190
- * The `relevanssi_get_words_having` filter hook is now also applied to the free version Did you mean queries.
191
- * New filters: `relevanssi_1day` and `relevanssi_7days` can be used to adjust the number of days for log displays, so instead of 1, 7 and 30 days you can have anything you want.
192
-
193
- = 4.1.0.1 =
194
- * Actually working admin search.
195
-
196
- = 4.1 =
197
- * New feature: You can now export the search log as a CSV file.
198
- * New feature: Admin Search page allows you to perform searches in WP admin using Relevanssi.
199
- * New filter: `relevanssi_admin_search_capability` can be used to adjust who sees the admin search page.
200
- * New filter: `relevanssi_entities_inside_pre` and `relevanssi_entities_inside_code` adjust how HTML entities are handled inside `pre` and `code` tags.
201
- * Numeric meta values (`meta_value_num`) are now sorted as numbers and not strings.
202
- * Pinned posts have `$post->relevanssi_pinned` set to 1 for debugging purposes, but you can also use this for styling the posts in the search results templates.
203
- * The Did you mean feature has been toned down a bit, to make the suggestions slightly less weird in some cases.
204
- * Post parent parameters now accept 0 as a value, making it easier to search for children of any post or posts without a parent.
205
- * Polylang compatibility has been improved.
206
- * Phrases with apostrophes inside work better.
207
- * The `relevanssi_excerpt` filter hook got a second parameter that holds the post ID.
208
- * Custom field sorting actually works now.
209
- * WP Search Suggest compatibility added.
210
-
211
  == Upgrade notice ==
212
- = 4.2.0 =
213
- * New features, bug fixes, smaller improvements.
214
-
215
- = 4.1.4 =
216
- * Restrict Content Pro support, bug fixes and small improvements.
217
-
218
- = 4.1.3 =
219
- * Small improvements here and there.
220
 
221
- = 4.1.2 =
222
- * Better compatibility with Gutenberg, new features.
223
 
224
- = 4.1.1.2 =
225
- * Fixes the broken User searches page.
226
-
227
- = 4.1.1.1 =
228
- * Adding the missing Gutenberg compatibility file.
229
-
230
- = 4.1.1 =
231
- * Minor improvements here and there, particularly in custom field sorting.
232
-
233
- = 4.1 =
234
- * New features and plenty of small fixes.
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.2
7
  Requires PHP: 5.6
8
+ Stable tag: 4.3.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
129
  * John Calahan for extensive 4.0 beta testing.
130
 
131
  == Changelog ==
132
+ = 4.3.1 =
133
+ * Adding a missing file.
134
+
135
+ = 4.3.0 =
136
+ * New feature: Multi-phrase searches now respect AND and OR operators. If multiple phrases are included in an OR search, any posts with at least one phrase will be included. In AND search, all phrases must be included.
137
+ * New feature: Admin search has been improved: there's a post type dropdown and the search is triggered when you press enter. The debug information has a `div` tag around it with the id `debugging`, so you can hide them with CSS if you want to. The numbering of results also makes more sense.
138
+ * New feature: The date parameters (`year`, `monthnum`, `w`, `day`, `hour`, `minute`, `second`, `m`) are now supported.
139
+ * New feature: New filter hook `relevanssi_indexing_limit` filters the default number of posts to index (10). If you have issues with indexing timing out, you can try adjusting this to a smaller number like 5 or 1.
140
+ * New feature: Support for Paid Membership Pro added.
141
+ * New feature: WordPress SEO support, posts marked "noindex" in WordPress SEO are no longer indexed by Relevanssi by default.
142
+ * Removed feature: qTranslate is no longer supported.
143
+ * Major fix: Tax query searching had some bugs in it, manifesting especially into Polylang not limiting the languages correctly. Some problems with the test suites were found and fixed, and similar problems won't happen again.
144
+ * Minor fix: Admin search only shows editing options to users with enough capabilities to use them.
145
+ * Minor fix: Phrase searching now uses filterable post statuses instead of a hard-coded set of post statuses.
146
+ * Minor fix: The plugin action links were missing on the Plugins page list, they're back now.
147
+ * Minor fix: Search terms with slashes won't cause errors anymore.
148
+ * Minor fix: Relevanssi admin pages have been examined for accessibility and form labels have been improved in many places.
149
+ * Deprecated: `relevanssi_get_term_taxonomy()` function is deprecated and will be removed at some point in the future.
150
+
151
  = 4.2.0 =
152
  * New feature: The search form shortcode has a new parameter `dropdown` which can be used to add a category dropdown, like this: `[searchform dropdown="category"]`.
153
  * New feature: Relevanssi can now use the contents of the PDF files indexed with WP File Download.
164
  * Minor fix: The Did you mean broke with search terms longer than 255 characters.
165
  * Minor fix: Phrases with numbers and one word like "team 17" didn't work, because numbers weren't counted as words.
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  == Upgrade notice ==
168
+ = 4.3.1 =
169
+ * Fixes the broken 4.3.0 release.
 
 
 
 
 
 
170
 
171
+ = 4.3.0 =
172
+ * Major bug fixes for taxonomy queries, new features and smaller improvements.
173
 
174
+ = 4.2.0 =
175
+ * New features, bug fixes, smaller improvements.
 
 
 
 
 
 
 
 
 
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.2.0
17
  * Author: Mikko Saari
18
  * Author URI: http://www.mikkosaari.fi/
19
  * Text Domain: relevanssi
@@ -57,6 +57,7 @@ $relevanssi_variables['post_type_index_defaults'] = array( 'post',
57
  $relevanssi_variables['database_version'] = 5;
58
  $relevanssi_variables['file'] = __FILE__;
59
  $relevanssi_variables['plugin_dir'] = plugin_dir_path( __FILE__ );
 
60
 
61
  require_once 'lib/admin-ajax.php';
62
  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.3.1
17
  * Author: Mikko Saari
18
  * Author URI: http://www.mikkosaari.fi/
19
  * Text Domain: relevanssi
57
  $relevanssi_variables['database_version'] = 5;
58
  $relevanssi_variables['file'] = __FILE__;
59
  $relevanssi_variables['plugin_dir'] = plugin_dir_path( __FILE__ );
60
+ $relevanssi_variables['plugin_basename'] = plugin_basename( __FILE__ );
61
 
62
  require_once 'lib/admin-ajax.php';
63
  require_once 'lib/common.php';