Relevanssi – A Better Search - Version 4.3.2

Version Description

  • New feature: SEOPress support, posts marked "noindex" in SEOPress are no longer indexed by Relevanssi by default.
  • Changed behaviour: Membership plugin compatibility is removed from relevanssi_default_post_ok function and has been moved to individual compatibility functions for each supported membership plugin. This makes it much easier to for example disable the membership plugin features if required.
  • Minor fix: The searchform shortcode now works better with different kinds of search forms.
  • Minor fix: Yoast SEO compatibility won't block indexing of posts with explicitly allowed indexing.
  • Minor fix: The relevanssi_the_tags() function printed out plain text, not HTML code like it should. The function now also accepts the post ID as a parameter.
  • Minor fix: Excerpt creation and highlighting have been improved a little.
Download this release

Release Info

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

Code changes from version 4.3.1.1 to 4.3.2

changelog.txt CHANGED
@@ -1,3 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.
1
+ = 4.2.0 =
2
+ * 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"]`.
3
+ * New feature: Relevanssi can now use the contents of the PDF files indexed with WP File Download.
4
+ * New filter: `relevanssi_indexing_tokens` can be used to filter the tokens (individual words) before they are indexed.
5
+ * Removed filter: `relevanssi_default_meta_query_relation` did not have any effect anymore.
6
+ * Changed behaviour: The default taxonomy relation was set to AND in 4.1.4, but wasn't properly applied before. Now it is really switched.
7
+ * Changed behaviour: New post types have been added to list of forbidden post types Relevanssi won't show as indexing options (ACF, TablePress and WooCommerce).
8
+ * Major fix: Tax query processing has been completely refactored, eliminating all sorts of bugs, especially with various edge cases.
9
+ * Major fix: Gutenberg block indexing only worked with the Gutenberg plugin enabled. It now works with WP 5.0 built-in Gutenberg as well. If you use Gutenberg blocks, reindex to get all the block content in the index.
10
+ * Major fix: Excerpt-building and highlighting did not respect the "Keyword matching" setting. They do now, and the excerpts should be better now.
11
+ * Major fix: AND searches needed queries that could get too long for the database to handle. This has been fixed and optimized.
12
+ * Major fix: Taxonomy term subquery relations didn't work; now they are applied.
13
+ * Minor fix: iOS uses curly quotes by default, and that didn't work as a phrase operator. Now phrase operator works with curly quotes and straight quotes.
14
+ * Minor fix: The Did you mean broke with search terms longer than 255 characters.
15
+ * Minor fix: Phrases with numbers and one word like "team 17" didn't work, because numbers weren't counted as words.
16
+
17
  = 4.1.4 =
18
  * `EXISTS` and `NOT EXISTS` didn’t work for taxonomy terms in searches.
19
  * WPML post type handling has been improved. If post type allows fallback for default language, Relevanssi will support that.
lib/common.php CHANGED
@@ -175,62 +175,24 @@ function relevanssi_default_post_ok( $post_ok, $post_id ) {
175
  $post_ok = true;
176
  }
177
  }
178
- if ( function_exists( 'members_content_permissions_enabled' ) && function_exists( 'members_can_current_user_view_post' ) ) {
179
- // Members. Only use if 'content permissions' feature is enabled.
180
- if ( members_content_permissions_enabled() ) {
181
- $post_ok = members_can_current_user_view_post( $post_id );
182
- }
183
- }
184
- }
185
- if ( defined( 'GROUPS_CORE_VERSION' ) && 'publish' === $status ) {
186
- // Groups. Only apply to published posts, don't apply to drafts.
187
- $current_user = wp_get_current_user();
188
- $post_ok = Groups_Post_Access::user_can_read_post( $post_id, $current_user->ID );
189
- }
190
- if ( class_exists( 'MeprUpdateCtrl', false ) && MeprUpdateCtrl::is_activated() ) { // False, because class_exists() can be really slow sometimes otherwise.
191
- // Memberpress.
192
- $post = get_post( $post_id );
193
- if ( MeprRule::is_locked( $post ) ) {
194
- $post_ok = false;
195
- }
196
- }
197
- if ( defined( 'SIMPLE_WP_MEMBERSHIP_VER' ) ) {
198
- // Simple Membership.
199
- $access_ctrl = SwpmAccessControl::get_instance();
200
- $post = get_post( $post_id );
201
- $post_ok = $access_ctrl->can_i_read_post( $post );
202
- }
203
- if ( function_exists( 'wp_jv_prg_user_can_see_a_post' ) ) {
204
- // WP JV Post Reading Groups.
205
- $post_ok = wp_jv_prg_user_can_see_a_post( get_current_user_id(), $post_id );
206
- }
207
- if ( function_exists( 'rcp_user_can_access' ) ) {
208
- // Restrict Content Pro.
209
- $post_ok = rcp_user_can_access( get_current_user_id(), $post_id );
210
- }
211
- // User Access Manager.
212
- global $userAccessManager; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
213
- if ( isset( $userAccessManager ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName
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.
225
- *
226
- * By default, admin searches may show posts that have 'draft', 'pending' and
227
- * 'future' status (in addition to 'publish' and 'private'). If you use custom
228
- * statuses and want them included in the admin search, you can add the statuses
229
- * using this filter.
230
- *
231
- * @param array $statuses Array of statuses to accept.
232
- */
233
- if ( in_array( $status, apply_filters( 'relevanssi_valid_admin_status', array( 'draft', 'pending', 'future' ) ), true ) && is_admin() ) {
 
 
 
 
 
234
  // Only show drafts, pending and future posts in admin search.
235
  $post_ok = true;
236
  }
@@ -922,13 +884,29 @@ function relevanssi_get_post_type( $post_id ) {
922
  * @param string $separator The separator between items, default ', '.
923
  * @param string $after What is printed after the tags, default ''.
924
  * @param boolean $echo If true, echo, otherwise return the result. Default true.
 
925
  */
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
  }
933
  }
934
 
@@ -941,9 +919,10 @@ function relevanssi_the_tags( $before = null, $separator = ', ', $after = '', $e
941
  * @param string $before What is printed before the tags, default null.
942
  * @param string $separator The separator between items, default ', '.
943
  * @param string $after What is printed after the tags, default ''.
 
944
  */
945
- function relevanssi_get_the_tags( $before = null, $separator = ', ', $after = '' ) {
946
- return relevanssi_the_tags( $before, $separator, $after, false );
947
  }
948
 
949
  /**
175
  $post_ok = true;
176
  }
177
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  }
179
 
180
+ if ( in_array(
181
+ $status,
182
+ /**
183
+ * Filters statuses allowed in admin searches.
184
+ *
185
+ * By default, admin searches may show posts that have 'draft',
186
+ * 'pending' and 'future' status (in addition to 'publish' and
187
+ * 'private'). If you use custom statuses and want them included in the
188
+ * admin search, you can add the statuses using this filter.
189
+ *
190
+ * @param array $statuses Array of statuses to accept.
191
+ */
192
+ apply_filters( 'relevanssi_valid_admin_status', array( 'draft', 'pending', 'future' ) ),
193
+ true
194
+ )
195
+ && is_admin() ) {
196
  // Only show drafts, pending and future posts in admin search.
197
  $post_ok = true;
198
  }
884
  * @param string $separator The separator between items, default ', '.
885
  * @param string $after What is printed after the tags, default ''.
886
  * @param boolean $echo If true, echo, otherwise return the result. Default true.
887
+ * @param int $post_id The post ID. Default current post ID (in the Loop).
888
  */
889
+ function relevanssi_the_tags( $before = null, $separator = ', ', $after = '', $echo = true, $post_id = null ) {
890
+ $tag_list = get_the_tag_list( $before, $separator, $after, $post_id );
891
+ $found = preg_match_all( '~<a href=".*?" rel="tag">(.*?)</a>~', $tag_list, $matches );
892
+ if ( $found ) {
893
+ $originals = $matches[0];
894
+ $tag_names = $matches[1];
895
+ $highlighted = array();
896
+
897
+ $count = count( $matches[0] );
898
+ for ( $i = 0; $i < $count; $i++ ) {
899
+ $highlighted_tag_name = relevanssi_highlight_terms( $tag_names[ $i ], get_search_query() );
900
+ $highlighted[ $i ] = str_replace( '>' . $tag_names[ $i ] . '<', '>' . $highlighted_tag_name . '<', $originals[ $i ] );
901
+ }
902
+
903
+ $tag_list = str_replace( $originals, $highlighted, $tag_list );
904
+ }
905
+
906
  if ( $echo ) {
907
+ echo $tag_list; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
908
  } else {
909
+ return $tag_list;
910
  }
911
  }
912
 
919
  * @param string $before What is printed before the tags, default null.
920
  * @param string $separator The separator between items, default ', '.
921
  * @param string $after What is printed after the tags, default ''.
922
+ * @param int $post_id The post ID. Default current post ID (in the Loop).
923
  */
924
+ function relevanssi_get_the_tags( $before = null, $separator = ', ', $after = '', $post_id = null ) {
925
+ return relevanssi_the_tags( $before, $separator, $after, false, $post_id );
926
  }
927
 
928
  /**
lib/compatibility/groups.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/groups.php
4
+ *
5
+ * Groups compatibility features.
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_post_ok', 'relevanssi_groups_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * Only applies to published posts.
19
+ *
20
+ * @param boolean $post_ok Can the post be shown to the user.
21
+ * @param int $post_id The post ID.
22
+ *
23
+ * @return boolean $post_ok True if the user is allowed to see the post,
24
+ * otherwise false.
25
+ */
26
+ function relevanssi_groups_compatibility( $post_ok, $post_id ) {
27
+ $status = relevanssi_get_post_status( $post_id );
28
+
29
+ if ( 'publish' === $status ) {
30
+ // Only apply to published posts, don't apply to drafts.
31
+ $current_user = wp_get_current_user();
32
+ $post_ok = Groups_Post_Access::user_can_read_post( $post_id, $current_user->ID );
33
+ }
34
+
35
+ return $post_ok;
36
+ }
lib/compatibility/memberpress.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/memberpress.php
4
+ *
5
+ * Memberpress compatibility features.
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_post_ok', 'relevanssi_memberpress_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * @param boolean $post_ok Can the post be shown to the user.
19
+ * @param int $post_id The post ID.
20
+ *
21
+ * @return boolean $post_ok True if the user is allowed to see the post,
22
+ * otherwise false.
23
+ */
24
+ function relevanssi_memberpress_compatibility( $post_ok, $post_id ) {
25
+ $post = get_post( $post_id );
26
+ if ( MeprRule::is_locked( $post ) ) {
27
+ $post_ok = false;
28
+ }
29
+
30
+ return $post_ok;
31
+ }
lib/compatibility/members.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/members.php
4
+ *
5
+ * Members compatibility features.
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_post_ok', 'relevanssi_members_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * Only applies to private posts and only if the "content permissions" feature
19
+ * is enabled.
20
+ *
21
+ * @param boolean $post_ok Can the post be shown to the user.
22
+ * @param int $post_id The post ID.
23
+ *
24
+ * @return boolean $post_ok True if the user is allowed to see the post,
25
+ * otherwise false.
26
+ */
27
+ function relevanssi_members_compatibility( $post_ok, $post_id ) {
28
+ $status = relevanssi_get_post_status( $post_id );
29
+
30
+ if ( 'private' === $status ) {
31
+ if ( members_content_permissions_enabled() ) {
32
+ $post_ok = members_can_current_user_view_post( $post_id );
33
+ }
34
+ }
35
+
36
+ return $post_ok;
37
+ }
lib/compatibility/paidmembershippro.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/paidmembershippro.php
4
+ *
5
+ * Paid Membership Pro compatibility features.
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_post_ok', 'relevanssi_paidmembershippro_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * @param boolean $post_ok Can the post be shown to the user.
19
+ * @param int $post_id The post ID.
20
+ *
21
+ * @return boolean $post_ok True if the user is allowed to see the post,
22
+ * otherwise false.
23
+ */
24
+ function relevanssi_paidmembershippro_compatibility( $post_ok, $post_id ) {
25
+ $current_user = wp_get_current_user();
26
+ $post_ok = pmpro_has_membership_access( $post_id, $current_user->ID );
27
+
28
+ return $post_ok;
29
+ }
lib/compatibility/restrictcontentpro.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/restrictcontentpro.php
4
+ *
5
+ * Restrict Content Pro compatibility features.
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_post_ok', 'relevanssi_restrictcontentpro_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * @param boolean $post_ok Can the post be shown to the user.
19
+ * @param int $post_id The post ID.
20
+ *
21
+ * @return boolean $post_ok True if the user is allowed to see the post,
22
+ * otherwise false.
23
+ */
24
+ function relevanssi_restrictcontentpro_compatibility( $post_ok, $post_id ) {
25
+ $post_ok = rcp_user_can_access( get_current_user_id(), $post_id );
26
+
27
+ return $post_ok;
28
+ }
lib/compatibility/seopress.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/seopress.php
4
+ *
5
+ * SEOPress noindex filtering function.
6
+ *
7
+ * @package Relevanssi
8
+ * @author Benjamin Denis
9
+ * @source ./yoast-seo.php (Mikko Saari)
10
+ * @license https://wordpress.org/about/gpl/ GNU General Public License
11
+ * @see https://www.relevanssi.com/
12
+ */
13
+
14
+ add_filter( 'relevanssi_do_not_index', 'relevanssi_seopress_noindex', 10, 2 );
15
+
16
+ /**
17
+ * Blocks indexing of posts marked "noindex" in the SEOPress settings.
18
+ *
19
+ * Attaches to the 'relevanssi_do_not_index' filter hook.
20
+ *
21
+ * @param boolean $do_not_index True, if the post shouldn't be indexed.
22
+ * @param integer $post_id The post ID number.
23
+ *
24
+ * @return boolean True, if the post shouldn't be indexed.
25
+ */
26
+ function relevanssi_seopress_noindex( $do_not_index, $post_id ) {
27
+ $noindex = get_post_meta( $post_id, '_seopress_robots_index', true );
28
+ if ( 'yes' === $noindex ) {
29
+ $do_not_index = true;
30
+ }
31
+ return $do_not_index;
32
+ }
lib/compatibility/simplemembership.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/simplemembership.php
4
+ *
5
+ * Simple Membership compatibility features.
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_post_ok', 'relevanssi_simplemembership_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * @param boolean $post_ok Can the post be shown to the user.
19
+ * @param int $post_id The post ID.
20
+ *
21
+ * @return boolean $post_ok True if the user is allowed to see the post,
22
+ * otherwise false.
23
+ */
24
+ function relevanssi_simplemembership_compatibility( $post_ok, $post_id ) {
25
+ $access_ctrl = SwpmAccessControl::get_instance();
26
+ $post = get_post( $post_id );
27
+ $post_ok = $access_ctrl->can_i_read_post( $post );
28
+
29
+ return $post_ok;
30
+ }
lib/compatibility/useraccessmanager.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/useraccessmanager.php
4
+ *
5
+ * User Access Manager compatibility features.
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_post_ok', 'relevanssi_useraccessmanager_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * @param boolean $post_ok Can the post be shown to the user.
19
+ * @param int $post_id The post ID.
20
+ *
21
+ * @return boolean $post_ok True if the user is allowed to see the post,
22
+ * otherwise false.
23
+ */
24
+ function relevanssi_useraccessmanager_compatibility( $post_ok, $post_id ) {
25
+ // phpcs:disable WordPress.NamingConventions.ValidVariableName
26
+ global $userAccessManager;
27
+ $type = relevanssi_get_post_type( $post_id );
28
+ $post_ok = $userAccessManager->getAccessHandler()->checkObjectAccess( $type, $post_id );
29
+ // phpcs:enable WordPress.NamingConventions.ValidVariableName
30
+
31
+ return $post_ok;
32
+ }
lib/compatibility/wpjvpostreadinggroups.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * /lib/compatibility/wpjvpostreadinggroups.php
4
+ *
5
+ * WP JV Post Reading Groups compatibility features.
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_post_ok', 'relevanssi_wpjvpostreadinggroups_compatibility', 10, 2 );
14
+
15
+ /**
16
+ * Checks whether the user is allowed to see the post.
17
+ *
18
+ * @param boolean $post_ok Can the post be shown to the user.
19
+ * @param int $post_id The post ID.
20
+ *
21
+ * @return boolean $post_ok True if the user is allowed to see the post,
22
+ * otherwise false.
23
+ */
24
+ function relevanssi_wpjvpostreadinggroups_compatibility( $post_ok, $post_id ) {
25
+ $post_ok = wp_jv_prg_user_can_see_a_post( get_current_user_id(), $post_id );
26
+
27
+ return $post_ok;
28
+ }
lib/compatibility/yoast-seo.php CHANGED
@@ -24,7 +24,7 @@ add_filter( 'relevanssi_do_not_index', 'relevanssi_yoast_noindex', 10, 2 );
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;
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 ( '1' === $noindex ) {
28
  $do_not_index = true;
29
  }
30
  return $do_not_index;
lib/excerpts-highlights.php CHANGED
@@ -180,11 +180,6 @@ function relevanssi_do_excerpt( $t_post, $query ) {
180
  $whole_post_excerpted = true;
181
  }
182
 
183
- if ( empty( $excerpt ) && ! empty( $post->post_excerpt ) ) {
184
- $excerpt = $post->post_excerpt;
185
- $excerpt = strip_tags( $excerpt, get_option( 'relevanssi_excerpt_allowable_tags', '' ) );
186
- }
187
-
188
  /**
189
  * Filters the ellipsis Relevanssi uses in excerpts.
190
  *
@@ -266,71 +261,22 @@ function relevanssi_create_excerpt( $content, $terms, $query ) {
266
 
267
  $start = false;
268
  if ( 'chars' === $type ) {
269
- /**
270
- * Character-based excerpts use the relevanssi_extract_relevant() to figure out
271
- * the best part of the post to use.
272
- */
273
- $prev_count = floor( $excerpt_length / 2 );
274
-
275
- list( $excerpt, $best_excerpt_term_hits, $start ) = relevanssi_extract_relevant( array_keys( $terms ), $content, $excerpt_length, $prev_count );
 
 
276
  } else {
277
- /**
278
- * Word-based excerpts split the content in an array of individual words and
279
- * takes slices.
280
- */
281
- $words = array_filter( explode( ' ', $content ) );
282
- $offset = 0;
283
- $tries = 0;
284
- $count_words = count( $words );
285
- while ( $offset < $count_words ) {
286
- if ( $offset + $excerpt_length > $count_words ) {
287
- $offset = $count_words - $excerpt_length;
288
- if ( $offset < 0 ) {
289
- $offset = 0;
290
- }
291
- }
292
-
293
- $excerpt_slice = array_slice( $words, $offset, $excerpt_length );
294
- $excerpt_slice = ' ' . implode( ' ', $excerpt_slice );
295
-
296
- $count_matches = relevanssi_count_matches( array_keys( $terms ), $excerpt_slice );
297
- if ( $count_matches > 0 && $count_matches > $best_excerpt_term_hits ) {
298
- $best_excerpt_term_hits = $count_matches;
299
- $excerpt = $excerpt_slice;
300
- if ( 0 === $offset ) {
301
- $start = true;
302
- }
303
- }
304
- if ( $count_matches > 0 ) {
305
- $tries++;
306
- }
307
-
308
- /**
309
- * Enables the excerpt optimization.
310
- *
311
- * If your posts are very long, building excerpts can be really slow.
312
- * To speed up the process, you can enable optimization, which means
313
- * Relevanssi only creates 50 excerpt candidates.
314
- *
315
- * @param boolean Return true to enable optimization, default false.
316
- */
317
- if ( apply_filters( 'relevanssi_optimize_excerpts', false ) ) {
318
- if ( $tries > 50 ) {
319
- // An optimization trick: try only 50 times.
320
- break;
321
- }
322
- }
323
-
324
- $offset += $excerpt_length;
325
- }
326
-
327
- if ( '' === $excerpt ) {
328
- // Nothing found, take the beginning of the post.
329
- $excerpt = explode( ' ', $content, $excerpt_length );
330
- array_pop( $excerpt );
331
- $excerpt = implode( ' ', $excerpt );
332
- $start = true;
333
- }
334
  }
335
 
336
  return array( $excerpt, $best_excerpt_term_hits, $start );
@@ -339,18 +285,19 @@ function relevanssi_create_excerpt( $content, $terms, $query ) {
339
  /**
340
  * Manages the highlighting in documents.
341
  *
342
- * Uses relevanssi_highlight_terms() and relevanssi_nonlocal_highlighting() to do
343
- * the highlighting. Attached to 'the_content' and 'comment_text' filter hooks.
344
  *
345
- * @global object $wp_query The global WP_Query object.
 
346
  *
347
  * @param string $content The content to highlight.
348
  *
349
  * @return string The content with highlights.
350
  */
351
  function relevanssi_highlight_in_docs( $content ) {
352
- global $wp_query;
353
- if ( is_singular() && is_main_query() ) {
354
  if ( isset( $wp_query->query_vars['highlight'] ) ) {
355
  // Local search.
356
  $query = relevanssi_add_synonyms( $wp_query->query_vars['highlight'] );
@@ -362,10 +309,6 @@ function relevanssi_highlight_in_docs( $content ) {
362
  $content = $highlighted_content;
363
  }
364
  }
365
-
366
- if ( function_exists( 'relevanssi_nonlocal_highlighting' ) ) {
367
- $content = relevanssi_nonlocal_highlighting( $content );
368
- }
369
  }
370
 
371
  return $content;
@@ -488,31 +431,32 @@ function relevanssi_highlight_terms( $content, $query, $in_docs = false ) {
488
  usort( $terms, 'relevanssi_strlen_sort' );
489
 
490
  $word_boundaries_available = true;
491
- if ( 'on' === get_option( 'relevanssi_word_boundaries', 'on' ) ) {
492
  $word_boundaries_available = false;
493
  }
494
 
 
 
495
  foreach ( $terms as $term ) {
496
  $pr_term = preg_quote( $term, '/' );
497
  $pr_term = relevanssi_add_accent_variations( $pr_term );
498
 
499
- $undecoded_content = $content;
500
- $content = html_entity_decode( $content, ENT_QUOTES, 'UTF-8' );
501
-
502
  if ( $word_boundaries_available ) {
503
  $regex = "/(\b$pr_term\b)/iu";
504
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
505
  $regex = "/(\b$pr_term|$pr_term\b)/iu";
506
  }
507
- $content = preg_replace( $regex, $start_emp_token . '\\1' . $end_emp_token, $content );
508
- if ( empty( $content ) ) {
509
- $content = preg_replace( $regex, $start_emp_token . '\\1' . $end_emp_token, $undecoded_content );
510
- }
 
511
  } else {
512
- $content = preg_replace( "/($pr_term)/iu", $start_emp_token . '\\1' . $end_emp_token, $content );
513
- if ( empty( $content ) ) {
514
- $content = preg_replace( "/($pr_term)/iu", $start_emp_token . '\\1' . $end_emp_token, $undecoded_content );
515
- }
 
516
  }
517
 
518
  if ( preg_match_all( '/<.*>/U', $content, $matches ) > 0 ) {
@@ -722,42 +666,33 @@ function relevanssi_generate_closing_tags( $tags ) {
722
  * @return string The string with nested highlights cleaned out.
723
  */
724
  function relevanssi_remove_nested_highlights( $string, $begin, $end ) {
725
- $offset = 0;
726
  $bits = explode( $begin, $string );
727
  $new_bits = array( $bits[0] );
728
  $count_bits = count( $bits );
729
- $in = false;
730
  for ( $i = 1; $i < $count_bits; $i++ ) {
731
- if ( '' === $bits[ $i ] ) {
732
- continue;
 
733
  }
734
-
735
- if ( ! $in ) {
736
- array_push( $new_bits, $begin );
737
- $in = true;
738
- }
739
- if ( substr_count( $bits[ $i ], $end ) > 0 ) {
740
- $in = false;
741
  }
742
- if ( substr_count( $bits[ $i ], $end ) > 1 ) {
743
- $more_bits = explode( $end, $bits[ $i ] );
744
- $j = 0;
745
- $k = count( $more_bits ) - 2;
746
- $whole_bit = '';
747
- foreach ( $more_bits as $bit ) {
748
- $whole_bit .= $bit;
749
- if ( $j === $k ) {
750
- $whole_bit .= $end;
751
- }
752
- $j++;
753
  }
754
- $bits[ $i ] = $whole_bit;
 
755
  }
756
- array_push( $new_bits, $bits[ $i ] );
757
  }
758
- $whole = implode( '', $new_bits );
759
-
760
- return $whole;
761
  }
762
 
763
  /**
@@ -818,7 +753,7 @@ function relevanssi_count_matches( $words, $complete_text ) {
818
  $text = '';
819
 
820
  $word_boundaries_available = true;
821
- if ( 'on' === get_option( 'relevanssi_word_boundaries', 'on' ) ) {
822
  $word_boundaries_available = false;
823
  }
824
 
@@ -857,9 +792,6 @@ function relevanssi_count_matches( $words, $complete_text ) {
857
 
858
  $lines = explode( '=***=', $text );
859
  $count = count( $lines ) - 1;
860
- if ( $count < 0 ) {
861
- $count = 0;
862
- }
863
 
864
  return $count;
865
  }
@@ -907,9 +839,10 @@ function relevanssi_determine_snip_location( $locations, $prevcount ) {
907
  }
908
  }
909
 
910
- $startpos = 0;
911
  if ( $startpos > $prevcount ) {
912
- $startpos - $prevcount;
 
 
913
  }
914
 
915
  return $startpos;
@@ -922,6 +855,8 @@ function relevanssi_determine_snip_location( $locations, $prevcount ) {
922
  * prevcount tends to work pretty well and puts the terms in the middle of the
923
  * excerpt.
924
  *
 
 
925
  * @author Ben Boyter
926
  *
927
  * @param array $words An array of relevant words.
@@ -945,25 +880,16 @@ function relevanssi_extract_relevant( $words, $fulltext, $excerpt_length = 300,
945
 
946
  // If we are going to snip too much...
947
  if ( $text_length - $startpos < $excerpt_length ) {
948
- $startpos = $startpos - ( $text_length - $startpos ) / 2;
949
  }
950
 
951
  $substr = 'substr';
952
  if ( function_exists( 'mb_substr' ) ) {
953
  $substr = 'mb_substr';
954
  }
955
- $strrpos = 'strrpos';
956
- if ( function_exists( 'mb_strrpos' ) ) {
957
- $strrpos = 'mb_strrpos';
958
- }
959
 
960
  $excerpt = call_user_func( $substr, $fulltext, $startpos, $excerpt_length );
961
 
962
- // Check to ensure we don't snip the last word if that's the match.
963
- if ( $startpos + $excerpt_length < $text_length ) {
964
- $excerpt = call_user_func( $substr, $excerpt, 0, call_user_func( $strrpos, $excerpt, ' ' ) ); // Remove last word.
965
- }
966
-
967
  $start = false;
968
  if ( 0 === $startpos ) {
969
  $start = true;
@@ -974,6 +900,82 @@ function relevanssi_extract_relevant( $words, $fulltext, $excerpt_length = 300,
974
  return array( $excerpt, $besthits, $start );
975
  }
976
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
977
  /**
978
  * Adds accented variations to letters.
979
  *
@@ -1057,7 +1059,7 @@ function relevanssi_get_custom_field_content( $post_id ) {
1057
  }
1058
  /* Documented in lib/indexing.php. */
1059
  $values = apply_filters( 'relevanssi_custom_field_value', get_post_meta( $post_id, $field, false ), $field, $post_id );
1060
- if ( '' === $values ) {
1061
  continue;
1062
  }
1063
  foreach ( $values as $value ) {
@@ -1102,23 +1104,25 @@ function relevanssi_remove_page_builder_shortcodes( $content ) {
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 );
180
  $whole_post_excerpted = true;
181
  }
182
 
 
 
 
 
 
183
  /**
184
  * Filters the ellipsis Relevanssi uses in excerpts.
185
  *
261
 
262
  $start = false;
263
  if ( 'chars' === $type ) {
264
+ $prev_count = floor( $excerpt_length / 6 );
265
+
266
+ list( $excerpt, $best_excerpt_term_hits, $start ) =
267
+ relevanssi_extract_relevant(
268
+ array_keys( $terms ),
269
+ $content,
270
+ $excerpt_length + 1,
271
+ $prev_count
272
+ );
273
  } else {
274
+ list( $excerpt, $best_excerpt_term_hits, $start ) =
275
+ relevanssi_extract_relevant_words(
276
+ array_keys( $terms ),
277
+ $content,
278
+ $excerpt_length
279
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
  }
281
 
282
  return array( $excerpt, $best_excerpt_term_hits, $start );
285
  /**
286
  * Manages the highlighting in documents.
287
  *
288
+ * Uses relevanssi_highlight_terms() to do the highlighting. Attached to
289
+ * 'the_content' and 'comment_text' filter hooks.
290
  *
291
+ * @global object $wp_query The global WP_Query object.
292
+ * @global boolean $relevanssi_test_enable If true, this is a test.
293
  *
294
  * @param string $content The content to highlight.
295
  *
296
  * @return string The content with highlights.
297
  */
298
  function relevanssi_highlight_in_docs( $content ) {
299
+ global $wp_query, $relevanssi_test_enable;
300
+ if ( ( is_singular() && is_main_query() ) || $relevanssi_test_enable ) {
301
  if ( isset( $wp_query->query_vars['highlight'] ) ) {
302
  // Local search.
303
  $query = relevanssi_add_synonyms( $wp_query->query_vars['highlight'] );
309
  $content = $highlighted_content;
310
  }
311
  }
 
 
 
 
312
  }
313
 
314
  return $content;
431
  usort( $terms, 'relevanssi_strlen_sort' );
432
 
433
  $word_boundaries_available = true;
434
+ if ( 'on' === get_option( 'relevanssi_word_boundaries', 'off' ) ) {
435
  $word_boundaries_available = false;
436
  }
437
 
438
+ $content = html_entity_decode( $content, ENT_QUOTES, 'UTF-8' );
439
+
440
  foreach ( $terms as $term ) {
441
  $pr_term = preg_quote( $term, '/' );
442
  $pr_term = relevanssi_add_accent_variations( $pr_term );
443
 
 
 
 
444
  if ( $word_boundaries_available ) {
445
  $regex = "/(\b$pr_term\b)/iu";
446
  if ( 'never' !== get_option( 'relevanssi_fuzzy' ) ) {
447
  $regex = "/(\b$pr_term|$pr_term\b)/iu";
448
  }
449
+ $content = preg_replace(
450
+ $regex,
451
+ $start_emp_token . '\\1' . $end_emp_token,
452
+ $content
453
+ );
454
  } else {
455
+ $content = preg_replace(
456
+ "/($pr_term)/iu",
457
+ $start_emp_token . '\\1' . $end_emp_token,
458
+ $content
459
+ );
460
  }
461
 
462
  if ( preg_match_all( '/<.*>/U', $content, $matches ) > 0 ) {
666
  * @return string The string with nested highlights cleaned out.
667
  */
668
  function relevanssi_remove_nested_highlights( $string, $begin, $end ) {
 
669
  $bits = explode( $begin, $string );
670
  $new_bits = array( $bits[0] );
671
  $count_bits = count( $bits );
672
+ $depth = -1;
673
  for ( $i = 1; $i < $count_bits; $i++ ) {
674
+ $depth++;
675
+ if ( 0 === $depth ) {
676
+ $new_bits[] = $begin;
677
  }
678
+ if ( empty( $bits[ $i ] ) ) {
679
+ continue;
 
 
 
 
 
680
  }
681
+ $end_count = substr_count( $bits[ $i ], $end );
682
+ if ( $end_count ) {
683
+ if ( substr_count( $bits[ $i ], $end ) < $depth ) {
684
+ $new_bits[] = str_replace( $end, '', $bits[ $i ], $count );
685
+ $depth -= $count;
686
+ } elseif ( substr_count( $bits[ $i ], $end ) >= $depth ) {
687
+ $end_p = preg_quote( $end, '#' );
688
+ $new_bits[] = preg_replace( '#' . $end_p . '#', '', $bits[ $i ], $depth );
689
+ $depth = -1;
 
 
690
  }
691
+ } else {
692
+ $new_bits[] = $bits[ $i ];
693
  }
 
694
  }
695
+ return join( '', $new_bits );
 
 
696
  }
697
 
698
  /**
753
  $text = '';
754
 
755
  $word_boundaries_available = true;
756
+ if ( 'on' === get_option( 'relevanssi_word_boundaries', 'off' ) ) {
757
  $word_boundaries_available = false;
758
  }
759
 
792
 
793
  $lines = explode( '=***=', $text );
794
  $count = count( $lines ) - 1;
 
 
 
795
 
796
  return $count;
797
  }
839
  }
840
  }
841
 
 
842
  if ( $startpos > $prevcount ) {
843
+ $startpos = $startpos - $prevcount;
844
+ } else {
845
+ $startpos = 0;
846
  }
847
 
848
  return $startpos;
855
  * prevcount tends to work pretty well and puts the terms in the middle of the
856
  * excerpt.
857
  *
858
+ * Source: https://boyter.org/2013/04/building-a-search-result-extract-generator-in-php/
859
+ *
860
  * @author Ben Boyter
861
  *
862
  * @param array $words An array of relevant words.
880
 
881
  // If we are going to snip too much...
882
  if ( $text_length - $startpos < $excerpt_length ) {
883
+ $startpos -= ( $text_length - $startpos ) / 2;
884
  }
885
 
886
  $substr = 'substr';
887
  if ( function_exists( 'mb_substr' ) ) {
888
  $substr = 'mb_substr';
889
  }
 
 
 
 
890
 
891
  $excerpt = call_user_func( $substr, $fulltext, $startpos, $excerpt_length );
892
 
 
 
 
 
 
893
  $start = false;
894
  if ( 0 === $startpos ) {
895
  $start = true;
900
  return array( $excerpt, $besthits, $start );
901
  }
902
 
903
+ /**
904
+ * Extracts relevant words of the full text.
905
+ *
906
+ * Finds the part of full text with as many relevant words as possible.
907
+ *
908
+ * @param array $terms An array of relevant words.
909
+ * @param string $content The source text.
910
+ * @param int $excerpt_length The length of the excerpt, default 30 words.
911
+ *
912
+ * @return array The excerpt, number of words in the excerpt, true if it's the start
913
+ * of the $fulltext.
914
+ */
915
+ function relevanssi_extract_relevant_words( $terms, $content, $excerpt_length = 30 ) {
916
+ $words = array_filter( explode( ' ', $content ) );
917
+ $offset = 0;
918
+ $tries = 0;
919
+ $excerpt = '';
920
+ $count_words = count( $words );
921
+ $start = false;
922
+
923
+ $best_excerpt_term_hits = -1;
924
+
925
+ while ( $offset < $count_words ) {
926
+ if ( $offset + $excerpt_length > $count_words ) {
927
+ $offset = $count_words - $excerpt_length;
928
+ if ( $offset < 0 ) {
929
+ $offset = 0;
930
+ }
931
+ }
932
+
933
+ $excerpt_slice = array_slice( $words, $offset, $excerpt_length );
934
+ $excerpt_slice = ' ' . implode( ' ', $excerpt_slice );
935
+
936
+ $count_matches = relevanssi_count_matches( $terms, $excerpt_slice );
937
+ if ( $count_matches > 0 && $count_matches > $best_excerpt_term_hits ) {
938
+ $best_excerpt_term_hits = $count_matches;
939
+ $excerpt = $excerpt_slice;
940
+ if ( 0 === $offset ) {
941
+ $start = true;
942
+ }
943
+ }
944
+ $tries++;
945
+
946
+ /**
947
+ * Enables the excerpt optimization.
948
+ *
949
+ * If your posts are very long, building excerpts can be really slow.
950
+ * To speed up the process, you can enable optimization, which means
951
+ * Relevanssi only creates 50 excerpt candidates.
952
+ *
953
+ * @param boolean Return true to enable optimization, default false.
954
+ */
955
+ if ( apply_filters( 'relevanssi_optimize_excerpts', false ) ) {
956
+ if ( $tries > 50 ) {
957
+ // An optimization trick: try only 50 times.
958
+ break;
959
+ }
960
+ }
961
+
962
+ $offset += $excerpt_length;
963
+ }
964
+
965
+ if ( '' === $excerpt ) {
966
+ /**
967
+ * Nothing found, take the beginning of the post. +2, because the first
968
+ * index is an empty space and the last index is the rest of the post.
969
+ */
970
+ $excerpt = explode( ' ', $content, $excerpt_length + 2 );
971
+ array_pop( $excerpt );
972
+ $excerpt = implode( ' ', $excerpt );
973
+ $start = true;
974
+ }
975
+
976
+ return array( $excerpt, $best_excerpt_term_hits, $start );
977
+ }
978
+
979
  /**
980
  * Adds accented variations to letters.
981
  *
1059
  }
1060
  /* Documented in lib/indexing.php. */
1061
  $values = apply_filters( 'relevanssi_custom_field_value', get_post_meta( $post_id, $field, false ), $field, $post_id );
1062
+ if ( empty( $values ) || ! is_array( $values ) ) {
1063
  continue;
1064
  }
1065
  foreach ( $values as $value ) {
1104
  'relevanssi_page_builder_shortcodes',
1105
  array(
1106
  // Remove content.
1107
+ '/\[et_pb_code.*?\].*\[\/et_pb_code\]/im',
1108
+ '/\[et_pb_sidebar.*?\].*\[\/et_pb_sidebar\]/im',
1109
+ '/\[et_pb_fullwidth_slider.*?\].*\[\/et_pb_fullwidth_slider\]/im',
1110
+ '/\[vc_raw_html.*?\].*\[\/vc_raw_html\]/im',
1111
  // Remove only the tags.
1112
+ '/\[\/?et_pb.*?\]/im',
1113
+ '/\[\/?vc.*?\]/im',
1114
+ '/\[\/?mk.*?\]/im',
1115
+ '/\[\/?cs_.*?\]/im',
1116
+ '/\[\/?av_.*?\]/im',
1117
+ '/\[\/?fusion_.*?\]/im',
1118
  // Max Mega Menu doesn't work in excerpts.
1119
+ '/\[maxmegamenu.*?\]/im',
1120
  // All-in-one Events Calendar shortcode doesn't look good.
1121
+ '/\[ai1ec.*?\]/im',
1122
  // Events Made Easy Calendar shortcodes should be removed.
1123
+ '/\[eme_.*?\]/im',
1124
+ // Layer Slider.
1125
+ '/\[layerslider.*?\]/im',
1126
  )
1127
  );
1128
  $content = preg_replace( $search_array, '', $content );
lib/indexing.php CHANGED
@@ -8,6 +8,8 @@
8
  * @see https://www.relevanssi.com/
9
  */
10
 
 
 
11
  /**
12
  * Returns the total number of posts to index.
13
  *
@@ -952,10 +954,16 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
952
  }
953
  }
954
 
955
- $type = 'post';
956
- if ( 'attachment' === $post->post_type ) {
957
- $type = 'attachment';
958
- }
 
 
 
 
 
 
959
 
960
  /**
961
  * Filters the indexing data before it is converted to INSERT queries.
@@ -1058,9 +1066,6 @@ function relevanssi_index_doc( $index_post, $remove_first = false, $custom_field
1058
  * @return array Updated insert query data array.
1059
  */
1060
  function relevanssi_index_taxonomy_terms( $post = null, $taxonomy = '', $insert_data ) {
1061
- global $wpdb, $relevanssi_variables;
1062
- $relevanssi_table = $relevanssi_variables['relevanssi_table'];
1063
-
1064
  $n = 0;
1065
 
1066
  if ( null === $post || empty( $taxonomy ) ) {
@@ -1069,41 +1074,46 @@ function relevanssi_index_taxonomy_terms( $post = null, $taxonomy = '', $insert_
1069
 
1070
  $min_word_length = get_option( 'relevanssi_min_word_length', 3 );
1071
  $post_taxonomy_terms = get_the_terms( $post->ID, $taxonomy );
1072
- if ( false !== $post_taxonomy_terms ) {
1073
- $tag_string = '';
1074
- foreach ( $post_taxonomy_terms as $post_tag ) {
1075
- if ( is_object( $post_tag ) ) {
1076
- $tag_string .= $post_tag->name . ' ';
1077
- }
 
 
 
1078
  }
1079
- $tag_string = apply_filters( 'relevanssi_tag_before_tokenize', trim( $tag_string ) );
1080
- $tag_tokens = relevanssi_tokenize( $tag_string, true, $min_word_length );
1081
- if ( count( $tag_tokens ) > 0 ) {
1082
- foreach ( $tag_tokens as $token => $count ) {
1083
- $n++;
 
1084
 
1085
- if ( 'post_tag' === $taxonomy ) {
1086
- $insert_data[ $token ]['tag'] = $count;
1087
- } elseif ( 'category' === $taxonomy ) {
1088
- $insert_data[ $token ]['category'] = $count;
1089
- } else {
1090
- if ( ! isset( $insert_data[ $token ]['taxonomy'] ) ) {
1091
- $insert_data[ $token ]['taxonomy'] = 0;
1092
- }
1093
- $insert_data[ $token ]['taxonomy'] += $count;
1094
- }
1095
- if ( isset( $insert_data[ $token ]['taxonomy_detail'] ) ) {
1096
- $tax_detail = json_decode( $insert_data[ $token ]['taxonomy_detail'], true );
1097
- } else {
1098
- $tax_detail = array();
1099
- }
1100
- if ( isset( $tax_detail[ $taxonomy ] ) ) {
1101
- $tax_detail[ $taxonomy ] += $count;
1102
- } else {
1103
- $tax_detail[ $taxonomy ] = $count;
1104
- }
1105
- $insert_data[ $token ]['taxonomy_detail'] = wp_json_encode( $tax_detail );
1106
  }
 
 
 
 
 
1107
  }
1108
  }
1109
  return $insert_data;
@@ -1112,39 +1122,66 @@ function relevanssi_index_taxonomy_terms( $post = null, $taxonomy = '', $insert_
1112
  /**
1113
  * Updates child posts when a parent post changes status.
1114
  *
1115
- * Called from 'transition_post_status' action hook when a post is edited, published,
1116
- * or deleted. Will do the appropriate indexing action on the child posts and
1117
- * attachments.
1118
- *
1119
- * @global object $wpdb The WP database interface.
1120
  *
1121
  * @author renaissancehack
1122
  *
1123
  * @param string $new_status The new status.
1124
  * @param string $old_status The old status.
1125
  * @param object $post The post object.
 
 
 
1126
  */
1127
  function relevanssi_update_child_posts( $new_status, $old_status, $post ) {
1128
- global $wpdb;
1129
-
1130
  // Safety check, for WordPress Editorial Calendar incompatibility.
1131
  if ( ! isset( $post ) || ! isset( $post->ID ) ) {
1132
  return;
1133
  }
1134
 
1135
  /** Documented in lib/indexing.php. */
1136
- $index_statuses = apply_filters( 'relevanssi_valid_status', array( 'publish', 'private', 'draft', 'pending', 'future' ) );
1137
- if ( ( $new_status === $old_status ) || ( in_array( $new_status, $index_statuses, true ) && in_array( $old_status, $index_statuses, true ) ) || ( in_array( $post->post_type, array( 'attachment', 'revision' ), true ) ) ) {
1138
- /**
1139
- * Either:
1140
- *
1141
- * 1. New status equals old status.
1142
- * 2. Both new and old status are in the list of stati to index.
1143
- * 3. The post is an attachment or a revision.
1144
- *
1145
- * In any of these cases, do nothing.
1146
- */
1147
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1148
  }
1149
 
1150
  $post_types = get_option( 'relevanssi_index_post_types' );
@@ -1152,18 +1189,27 @@ function relevanssi_update_child_posts( $new_status, $old_status, $post ) {
1152
  'post_parent' => $post->ID,
1153
  'post_type' => $post_types,
1154
  );
 
 
1155
  $child_posts = get_children( $args );
 
1156
  if ( ! empty( $child_posts ) ) {
1157
  if ( ! in_array( $new_status, $index_statuses, true ) ) {
1158
  foreach ( $child_posts as $post ) {
1159
  relevanssi_remove_doc( $post->ID );
 
1160
  }
1161
  } else {
1162
  foreach ( $child_posts as $post ) {
1163
  relevanssi_publish( $post->ID );
 
1164
  }
1165
  }
1166
  }
 
 
 
 
1167
  }
1168
 
1169
  /**
@@ -1453,3 +1499,18 @@ function relevanssi_remove_doc( $post_id, $keep_internal_links = false ) {
1453
  }
1454
  }
1455
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  * @see https://www.relevanssi.com/
9
  */
10
 
11
+ add_filter( 'relevanssi_index_get_post_type', 'relevanssi_index_get_post_type', 1, 2 );
12
+
13
  /**
14
  * Returns the total number of posts to index.
15
  *
954
  }
955
  }
956
 
957
+ /**
958
+ * Sets the indexed post 'type' column in the index.
959
+ *
960
+ * Default value is 'post', but other common values include 'attachment',
961
+ * 'user' and taxonomy name.
962
+ *
963
+ * @param string Type value.
964
+ * @param object The post object for the current post.
965
+ */
966
+ $type = apply_filters( 'relevanssi_index_get_post_type', 'post', $post );
967
 
968
  /**
969
  * Filters the indexing data before it is converted to INSERT queries.
1066
  * @return array Updated insert query data array.
1067
  */
1068
  function relevanssi_index_taxonomy_terms( $post = null, $taxonomy = '', $insert_data ) {
 
 
 
1069
  $n = 0;
1070
 
1071
  if ( null === $post || empty( $taxonomy ) ) {
1074
 
1075
  $min_word_length = get_option( 'relevanssi_min_word_length', 3 );
1076
  $post_taxonomy_terms = get_the_terms( $post->ID, $taxonomy );
1077
+
1078
+ if ( false === $post_taxonomy_terms ) {
1079
+ return $insert_data;
1080
+ }
1081
+
1082
+ $tag_string = '';
1083
+ foreach ( $post_taxonomy_terms as $post_tag ) {
1084
+ if ( is_object( $post_tag ) ) {
1085
+ $tag_string .= $post_tag->name . ' ';
1086
  }
1087
+ }
1088
+ $tag_string = apply_filters( 'relevanssi_tag_before_tokenize', trim( $tag_string ) );
1089
+ $tag_tokens = relevanssi_tokenize( $tag_string, true, $min_word_length );
1090
+ if ( count( $tag_tokens ) > 0 ) {
1091
+ foreach ( $tag_tokens as $token => $count ) {
1092
+ $n++;
1093
 
1094
+ switch ( $taxonomy ) {
1095
+ case 'post_tag':
1096
+ $type = 'tag';
1097
+ break;
1098
+ case 'category':
1099
+ $type = 'category';
1100
+ break;
1101
+ default:
1102
+ $type = 'taxonomy';
1103
+ }
1104
+
1105
+ $insert_data[ $token ][ $type ] = isset( $insert_data[ $token ][ $type ] )
1106
+ ? $insert_data[ $token ][ $type ] + $count : $count;
1107
+
1108
+ $tax_detail = array();
1109
+ if ( isset( $insert_data[ $token ]['taxonomy_detail'] ) ) {
1110
+ $tax_detail = json_decode( $insert_data[ $token ]['taxonomy_detail'], true );
 
 
 
 
1111
  }
1112
+
1113
+ $tax_detail[ $taxonomy ] = isset( $tax_detail[ $taxonomy ] )
1114
+ ? $tax_detail[ $taxonomy ] + $count : $count;
1115
+
1116
+ $insert_data[ $token ]['taxonomy_detail'] = wp_json_encode( $tax_detail );
1117
  }
1118
  }
1119
  return $insert_data;
1122
  /**
1123
  * Updates child posts when a parent post changes status.
1124
  *
1125
+ * Called from 'transition_post_status' action hook when a post is edited,
1126
+ * published, or deleted. Will do the appropriate indexing action on the child
1127
+ * posts and attachments.
 
 
1128
  *
1129
  * @author renaissancehack
1130
  *
1131
  * @param string $new_status The new status.
1132
  * @param string $old_status The old status.
1133
  * @param object $post The post object.
1134
+ *
1135
+ * @return null|array Null in problem cases, an array of 'removed' and
1136
+ * 'indexed' values that show how many posts were indexed and removed.
1137
  */
1138
  function relevanssi_update_child_posts( $new_status, $old_status, $post ) {
 
 
1139
  // Safety check, for WordPress Editorial Calendar incompatibility.
1140
  if ( ! isset( $post ) || ! isset( $post->ID ) ) {
1141
  return;
1142
  }
1143
 
1144
  /** Documented in lib/indexing.php. */
1145
+ $index_statuses = apply_filters(
1146
+ 'relevanssi_valid_status',
1147
+ array( 'publish', 'private', 'draft', 'pending', 'future' )
1148
+ );
1149
+ /**
1150
+ * Filters the attachment and revision post types.
1151
+ *
1152
+ * If you want attachment indexing to cover other post types than just
1153
+ * attachment, you need to include the new post type in the array with
1154
+ * this filter.
1155
+ *
1156
+ * @param array Array of post types, default 'attachment' and 'revision'.
1157
+ */
1158
+ $attachment_revision_types = apply_filters(
1159
+ 'relevanssi_index_attachment_revision_types',
1160
+ array( 'attachment', 'revision' )
1161
+ );
1162
+
1163
+ $did_nothing = array(
1164
+ 'removed' => 0,
1165
+ 'indexed' => 0,
1166
+ );
1167
+
1168
+ /**
1169
+ * Either:
1170
+ *
1171
+ * 1. New status equals old status.
1172
+ * 2. Both new and old status are in the list of stati to index.
1173
+ * 3. The post is an attachment or a revision.
1174
+ *
1175
+ * In any of these cases, do nothing.
1176
+ */
1177
+ if ( $new_status === $old_status ) {
1178
+ return $did_nothing;
1179
+ }
1180
+ if ( in_array( $new_status, $index_statuses, true ) && in_array( $old_status, $index_statuses, true ) ) {
1181
+ return $did_nothing;
1182
+ }
1183
+ if ( in_array( $post->post_type, $attachment_revision_types, true ) ) {
1184
+ return $did_nothing;
1185
  }
1186
 
1187
  $post_types = get_option( 'relevanssi_index_post_types' );
1189
  'post_parent' => $post->ID,
1190
  'post_type' => $post_types,
1191
  );
1192
+ $removed = 0;
1193
+ $indexed = 0;
1194
  $child_posts = get_children( $args );
1195
+
1196
  if ( ! empty( $child_posts ) ) {
1197
  if ( ! in_array( $new_status, $index_statuses, true ) ) {
1198
  foreach ( $child_posts as $post ) {
1199
  relevanssi_remove_doc( $post->ID );
1200
+ $removed++;
1201
  }
1202
  } else {
1203
  foreach ( $child_posts as $post ) {
1204
  relevanssi_publish( $post->ID );
1205
+ $indexed++;
1206
  }
1207
  }
1208
  }
1209
+ return array(
1210
+ 'removed' => $removed,
1211
+ 'indexed' => $indexed,
1212
+ );
1213
  }
1214
 
1215
  /**
1499
  }
1500
  }
1501
  }
1502
+
1503
+ /**
1504
+ * Filter that allows you to set the index type based on the post type.
1505
+ *
1506
+ * @param string $type The index 'type' column value, default 'post'.
1507
+ * @param object $post The post object containing the post being indexed.
1508
+ *
1509
+ * @return string The index 'type' column value, default 'post'.
1510
+ */
1511
+ function relevanssi_index_get_post_type( $type, $post ) {
1512
+ if ( 'attachment' === $post->post_type ) {
1513
+ $type = 'attachment';
1514
+ }
1515
+ return $type;
1516
+ }
lib/init.php CHANGED
@@ -154,6 +154,45 @@ function relevanssi_init() {
154
  if ( defined( 'WPSEO_FILE' ) ) {
155
  require_once 'compatibility/yoast-seo.php';
156
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  }
158
 
159
  /**
154
  if ( defined( 'WPSEO_FILE' ) ) {
155
  require_once 'compatibility/yoast-seo.php';
156
  }
157
+
158
+ if ( function_exists( 'seopress_get_toggle_titles_option' ) && '1' === seopress_get_toggle_titles_option() ) {
159
+ require_once 'compatibility/seopress.php';
160
+ }
161
+
162
+ if ( function_exists( 'members_content_permissions_enabled' ) ) {
163
+ require_once 'compatibility/members.php';
164
+ }
165
+
166
+ if ( defined( 'GROUPS_CORE_VERSION' ) ) {
167
+ require_once 'compatibility/groups.php';
168
+ }
169
+
170
+ if ( class_exists( 'MeprUpdateCtrl', false ) && MeprUpdateCtrl::is_activated() ) {
171
+ require_once 'compatibility/memberpress.php';
172
+ }
173
+
174
+ if ( defined( 'SIMPLE_WP_MEMBERSHIP_VER' ) ) {
175
+ require_once 'compatibility/simplemembership.php';
176
+ }
177
+
178
+ if ( function_exists( 'wp_jv_prg_user_can_see_a_post' ) ) {
179
+ require_once 'compatibility/wpjvpostreadinggroups.php';
180
+ }
181
+
182
+ if ( function_exists( 'rcp_user_can_access' ) ) {
183
+ require_once 'compatibility/restrictcontentpro.php';
184
+ }
185
+
186
+ // phpcs:disable WordPress.NamingConventions.ValidVariableName
187
+ global $userAccessManager;
188
+ if ( isset( $userAccessManager ) ) {
189
+ require_once 'compatibility/useraccessmanager.php';
190
+ }
191
+ // phpcs:enable WordPress.NamingConventions.ValidVariableName
192
+
193
+ if ( function_exists( 'pmpro_has_membership_access' ) ) {
194
+ require_once 'compatibility/paidmembershippro.php';
195
+ }
196
  }
197
 
198
  /**
lib/search-query-restrictions.php CHANGED
@@ -483,13 +483,14 @@ function relevanssi_process_post_type( $post_type, $admin_search, $include_attac
483
  *
484
  * @param string $post_status A post status string.
485
  *
486
- * @global WP_Query $wp_query The WP Query object.
487
- * @global object $wpdb The WP database interface.
 
488
  *
489
  * @return string The MySQL query restriction.
490
  */
491
  function relevanssi_process_post_status( $post_status ) {
492
- global $wp_query, $wpdb;
493
  $query_restrictions = '';
494
 
495
  if ( ! is_array( $post_status ) ) {
@@ -504,7 +505,7 @@ function relevanssi_process_post_status( $post_status ) {
504
  }
505
 
506
  if ( $escaped_post_status ) {
507
- if ( $wp_query->is_admin ) {
508
  $query_restrictions .= " AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
509
  WHERE posts.post_status IN ($escaped_post_status))))";
510
  } else {
483
  *
484
  * @param string $post_status A post status string.
485
  *
486
+ * @global WP_Query $wp_query The WP Query object.
487
+ * @global object $wpdb The WP database interface.
488
+ * @global boolean $relevanssi_admin_test If true, an admin search. for tests.
489
  *
490
  * @return string The MySQL query restriction.
491
  */
492
  function relevanssi_process_post_status( $post_status ) {
493
+ global $wp_query, $wpdb, $relevanssi_admin_test;
494
  $query_restrictions = '';
495
 
496
  if ( ! is_array( $post_status ) ) {
505
  }
506
 
507
  if ( $escaped_post_status ) {
508
+ if ( $wp_query->is_admin || $relevanssi_admin_test ) {
509
  $query_restrictions .= " AND ((relevanssi.doc IN (SELECT DISTINCT(posts.ID) FROM $wpdb->posts AS posts
510
  WHERE posts.post_status IN ($escaped_post_status))))";
511
  } else {
lib/search.php CHANGED
@@ -778,8 +778,10 @@ function relevanssi_search( $args ) {
778
  *
779
  * This function is strongly influenced by Kenny Katzgrau's wpSearch plugin.
780
  *
781
- * @global boolean $relevanssi_active If true, Relevanssi is currently doing a
782
- * search.
 
 
783
  *
784
  * @param WP_Query $query A WP_Query object, passed as a reference. Relevanssi will
785
  * put the posts found in $query->posts, and also sets $query->post_count.
@@ -787,7 +789,7 @@ function relevanssi_search( $args ) {
787
  * @return array The found posts, an array of post objects.
788
  */
789
  function relevanssi_do_query( &$query ) {
790
- global $relevanssi_active;
791
  $relevanssi_active = true;
792
 
793
  $posts = array();
@@ -796,575 +798,22 @@ function relevanssi_do_query( &$query ) {
796
 
797
  $did_multisite_search = false;
798
  if ( is_multisite() ) {
799
- $search_multisite = false;
800
- if ( isset( $query->query_vars['searchblogs'] ) && (string) get_current_blog_id() !== $query->query_vars['searchblogs'] ) {
801
- $search_multisite = true;
802
- }
803
-
804
- // Is searching all blogs enabled?
805
- $searchblogs_all = get_option( 'relevanssi_searchblogs_all', 'off' );
806
- if ( 'off' === $searchblogs_all ) {
807
- $searchblogs_all = false;
808
- }
809
- if ( ! $search_multisite && $searchblogs_all ) {
810
- $search_multisite = true;
811
- $searchblogs = 'all';
812
- }
813
-
814
- // Searchblogs is not set from the query variables, check the option.
815
- $searchblogs_setting = get_option( 'relevanssi_searchblogs' );
816
- if ( ! $search_multisite && $searchblogs_setting ) {
817
- $search_multisite = true;
818
- $searchblogs = $searchblogs_setting;
819
- }
820
-
821
- if ( $search_multisite ) {
822
- $multi_args = array();
823
- if ( isset( $query->query_vars['searchblogs'] ) ) {
824
- $multi_args['search_blogs'] = $query->query_vars['searchblogs'];
825
- } else {
826
- $multi_args['search_blogs'] = $searchblogs;
827
- }
828
- $multi_args['q'] = $q;
829
-
830
- $post_type = false;
831
- if ( isset( $query->query_vars['post_type'] ) && 'any' !== $query->query_vars['post_type'] ) {
832
- $multi_args['post_type'] = $query->query_vars['post_type'];
833
- }
834
- if ( isset( $query->query_vars['post_types'] ) && 'any' !== $query->query_vars['post_types'] ) {
835
- $multi_args['post_type'] = $query->query_vars['post_types'];
836
- }
837
-
838
- if ( isset( $query->query_vars['order'] ) ) {
839
- $multi_args['order'] = $query->query_vars['order'];
840
- }
841
- if ( isset( $query->query_vars['orderby'] ) ) {
842
- $multi_args['orderby'] = $query->query_vars['orderby'];
843
- }
844
-
845
- $operator = '';
846
- if ( function_exists( 'relevanssi_set_operator' ) ) {
847
- $operator = relevanssi_set_operator( $query );
848
- $operator = strtoupper( $operator ); // Just in case.
849
- }
850
- if ( 'OR' !== $operator && 'AND' !== $operator ) {
851
- $operator = get_option( 'relevanssi_implicit_operator' );
852
- }
853
- $multi_args['operator'] = $operator;
854
-
855
- $meta_query = array();
856
- if ( ! empty( $query->query_vars['meta_query'] ) ) {
857
- $meta_query = $query->query_vars['meta_query'];
858
- }
859
-
860
- if ( isset( $query->query_vars['customfield_key'] ) ) {
861
- $build_meta_query = array();
862
-
863
- // Use meta key.
864
- $build_meta_query['key'] = $query->query_vars['customfield_key'];
865
-
866
- /**
867
- * Check the value is not empty for ordering purpose,
868
- * Set it or not for the current meta query
869
- */
870
- if ( ! empty( $query->query_vars['customfield_value'] ) ) {
871
- $build_meta_query['value'] = $query->query_vars['customfield_value'];
872
- }
873
-
874
- // Set the compare.
875
- $build_meta_query['compare'] = '=';
876
-
877
- $meta_query[] = $build_meta_query;
878
- }
879
-
880
- if ( ! empty( $query->query_vars['meta_key'] ) || ! empty( $query->query_vars['meta_value'] ) || ! empty( $query->query_vars['meta_value_num'] ) ) {
881
- $build_meta_query = array();
882
-
883
- // Use meta key.
884
- $build_meta_query['key'] = $query->query_vars['meta_key'];
885
-
886
- $value = null;
887
- if ( ! empty( $query->query_vars['meta_value'] ) ) {
888
- $value = $query->query_vars['meta_value'];
889
- } elseif ( ! empty( $query->query_vars['meta_value_num'] ) ) {
890
- $value = $query->query_vars['meta_value_num'];
891
- }
892
-
893
- /**
894
- * Check the meta value, as it could be not set for ordering purpose
895
- * set it or not for the current meta query.
896
- */
897
- if ( ! empty( $value ) ) {
898
- $build_meta_query['value'] = $value;
899
  }
900
-
901
- // Set meta compare.
902
- $build_meta_query['compare'] = '=';
903
- if ( ! empty( $query->query_vars['meta_compare'] ) ) {
904
- $query->query_vars['meta_compare'];
905
- }
906
-
907
- $meta_query[] = $build_meta_query;
908
- }
909
-
910
- $multi_args['meta_query'] = $meta_query;
911
-
912
- if ( isset( $query->query_vars['include_attachments'] ) ) {
913
- $multi_args['include_attachments'] = $query->query_vars['include_attachments'];
914
- }
915
-
916
- if ( function_exists( 'relevanssi_search_multi' ) ) {
917
- $return = relevanssi_search_multi( $multi_args );
918
  }
919
- $did_multisite_search = true;
920
  }
921
  }
 
922
  if ( ! $did_multisite_search ) {
923
- $tax_query = array();
924
- /**
925
- * Filters the default tax_query relation.
926
- *
927
- * @param string The default relation, default 'AND'.
928
- */
929
- $tax_query_relation = apply_filters( 'relevanssi_default_tax_query_relation', 'AND' );
930
- if ( isset( $query->tax_query ) && empty( $query->tax_query->queries ) ) {
931
- // Tax query is empty, let's get rid of it.
932
- $query->tax_query = null;
933
- }
934
- if ( isset( $query->query_vars['tax_query'] ) ) {
935
- // This is user-created tax_query array as described in WP Codex.
936
- foreach ( $query->query_vars['tax_query'] as $type => $item ) {
937
- if ( is_string( $type ) && 'relation' === $type ) {
938
- $tax_query_relation = $item;
939
- } else {
940
- $tax_query[] = $item;
941
- }
942
- }
943
- } elseif ( isset( $query->tax_query ) ) {
944
- // This is the WP-created Tax_Query object, which is different from above.
945
- foreach ( $query->tax_query as $type => $item ) {
946
- if ( is_string( $type ) && 'relation' === $type ) {
947
- $tax_query_relation = $item;
948
- }
949
- if ( is_string( $type ) && 'queries' === $type ) {
950
- foreach ( $item as $tax_query_row ) {
951
- $tax_query[] = $tax_query_row;
952
- }
953
- }
954
- }
955
- } else {
956
- $cat = false;
957
- if ( isset( $query->query_vars['cats'] ) ) {
958
- $cat = $query->query_vars['cats'];
959
- }
960
- if ( empty( $cat ) ) {
961
- $cat = get_option( 'relevanssi_cat' );
962
- }
963
- if ( $cat ) {
964
- $cat = explode( ',', $cat );
965
- $tax_query[] = array(
966
- 'taxonomy' => 'category',
967
- 'field' => 'id',
968
- 'terms' => $cat,
969
- );
970
- }
971
- if ( ! empty( $query->query_vars['category_name'] ) && empty( $query->query_vars['category__in'] ) ) {
972
- $cat = explode( ',', $query->query_vars['category_name'] );
973
- $tax_query[] = array(
974
- 'taxonomy' => 'category',
975
- 'field' => 'slug',
976
- 'terms' => $cat,
977
- );
978
- }
979
- if ( ! empty( $query->query_vars['category__in'] ) ) {
980
- $tax_query[] = array(
981
- 'taxonomy' => 'category',
982
- 'field' => 'id',
983
- 'terms' => $query->query_vars['category__in'],
984
- );
985
- }
986
- if ( ! empty( $query->query_vars['category__not_in'] ) ) {
987
- $tax_query[] = array(
988
- 'taxonomy' => 'category',
989
- 'field' => 'id',
990
- 'terms' => $query->query_vars['category__not_in'],
991
- 'operator' => 'NOT IN',
992
- );
993
- }
994
- if ( ! empty( $query->query_vars['category__and'] ) ) {
995
- $tax_query[] = array(
996
- 'taxonomy' => 'category',
997
- 'field' => 'id',
998
- 'terms' => $query->query_vars['category__and'],
999
- 'operator' => 'AND',
1000
- 'include_children' => false,
1001
- );
1002
- }
1003
- $excat = get_option( 'relevanssi_excat' );
1004
- if ( ! empty( $excat ) ) {
1005
- $tax_query[] = array(
1006
- 'taxonomy' => 'category',
1007
- 'field' => 'id',
1008
- 'terms' => $excat,
1009
- 'operator' => 'NOT IN',
1010
- );
1011
- }
1012
-
1013
- $tag = false;
1014
- if ( ! empty( $query->query_vars['tags'] ) ) {
1015
- $tag = $query->query_vars['tags'];
1016
- }
1017
- if ( $tag ) {
1018
- if ( false !== strpos( $tag, '+' ) ) {
1019
- $tag = explode( '+', $tag );
1020
- $operator = 'and';
1021
- } else {
1022
- $tag = explode( ',', $tag );
1023
- $operator = 'or';
1024
- }
1025
- $tax_query[] = array(
1026
- 'taxonomy' => 'post_tag',
1027
- 'field' => 'id',
1028
- 'terms' => $tag,
1029
- 'operator' => $operator,
1030
- );
1031
- }
1032
- if ( ! empty( $query->query_vars['tag_id'] ) ) {
1033
- $tax_query[] = array(
1034
- 'taxonomy' => 'post_tag',
1035
- 'field' => 'id',
1036
- 'terms' => $query->query_vars['tag_id'],
1037
- );
1038
- }
1039
- if ( ! empty( $query->query_vars['tag_id'] ) ) {
1040
- $tax_query[] = array(
1041
- 'taxonomy' => 'post_tag',
1042
- 'field' => 'id',
1043
- 'terms' => $query->query_vars['tag_id'],
1044
- );
1045
- }
1046
- if ( ! empty( $query->query_vars['tag__in'] ) ) {
1047
- $tax_query[] = array(
1048
- 'taxonomy' => 'post_tag',
1049
- 'field' => 'id',
1050
- 'terms' => $query->query_vars['tag__in'],
1051
- );
1052
- }
1053
- if ( ! empty( $query->query_vars['tag__not_in'] ) ) {
1054
- $tax_query[] = array(
1055
- 'taxonomy' => 'post_tag',
1056
- 'field' => 'id',
1057
- 'terms' => $query->query_vars['tag__not_in'],
1058
- 'operator' => 'NOT IN',
1059
- );
1060
- }
1061
- if ( ! empty( $query->query_vars['tag__and'] ) ) {
1062
- $tax_query[] = array(
1063
- 'taxonomy' => 'post_tag',
1064
- 'field' => 'id',
1065
- 'terms' => $query->query_vars['tag__and'],
1066
- 'operator' => 'AND',
1067
- );
1068
- }
1069
- if ( ! empty( $query->query_vars['tag_slug__in'] ) ) {
1070
- $tax_query[] = array(
1071
- 'taxonomy' => 'post_tag',
1072
- 'field' => 'slug',
1073
- 'terms' => $query->query_vars['tag_slug__in'],
1074
- );
1075
- }
1076
- if ( ! empty( $query->query_vars['tag_slug__not_in'] ) ) {
1077
- $tax_query[] = array(
1078
- 'taxonomy' => 'post_tag',
1079
- 'field' => 'slug',
1080
- 'terms' => $query->query_vars['tag_slug__not_in'],
1081
- 'operator' => 'NOT IN',
1082
- );
1083
- }
1084
- if ( ! empty( $query->query_vars['tag_slug__and'] ) ) {
1085
- $tax_query[] = array(
1086
- 'taxonomy' => 'post_tag',
1087
- 'field' => 'slug',
1088
- 'terms' => $query->query_vars['tag_slug__and'],
1089
- 'operator' => 'AND',
1090
- );
1091
- }
1092
- $extag = get_option( 'relevanssi_extag' );
1093
- if ( ! empty( $extag ) && '0' !== $extag ) {
1094
- $tax_query[] = array(
1095
- 'taxonomy' => 'post_tag',
1096
- 'field' => 'id',
1097
- 'terms' => $extag,
1098
- 'operator' => 'NOT IN',
1099
- );
1100
- }
1101
-
1102
- if ( isset( $query->query_vars['taxonomy'] ) ) {
1103
- if ( function_exists( 'relevanssi_process_taxonomies' ) ) {
1104
- $tax_query = relevanssi_process_taxonomies( $query->query_vars['taxonomy'], $query->query_vars['term'], $tax_query );
1105
- } else {
1106
- if ( ! empty( $query->query_vars['term'] ) ) {
1107
- $term = $query->query_vars['term'];
1108
- }
1109
-
1110
- $tax_query[] = array(
1111
- 'taxonomy' => $query->query_vars['taxonomy'],
1112
- 'field' => 'slug',
1113
- 'terms' => $term,
1114
- );
1115
- }
1116
- }
1117
- $query->tax_query = $tax_query;
1118
- }
1119
-
1120
- $author = false;
1121
- if ( ! empty( $query->query_vars['author'] ) ) {
1122
- $author = explode( ',', $query->query_vars['author'] );
1123
- }
1124
- if ( ! empty( $query->query_vars['author_name'] ) ) {
1125
- $author_object = get_user_by( 'slug', $query->query_vars['author_name'] );
1126
- $author[] = $author_object->ID;
1127
- }
1128
-
1129
- $post_query = array();
1130
- if ( isset( $query->query_vars['p'] ) ) {
1131
- $post_query = array( 'in' => array( $query->query_vars['p'] ) );
1132
- }
1133
- if ( isset( $query->query_vars['page_id'] ) ) {
1134
- $post_query = array( 'in' => array( $query->query_vars['page_id'] ) );
1135
- }
1136
- if ( isset( $query->query_vars['post__in'] ) && is_array( $query->query_vars['post__in'] ) && ! empty( $query->query_vars['post__in'] ) ) {
1137
- $post_query = array( 'in' => $query->query_vars['post__in'] );
1138
- }
1139
- if ( isset( $query->query_vars['post__not_in'] ) && is_array( $query->query_vars['post__not_in'] ) && ! empty( $query->query_vars['post__not_in'] ) ) {
1140
- $post_query = array( 'not in' => $query->query_vars['post__not_in'] );
1141
- }
1142
-
1143
- $parent_query = array();
1144
- if ( isset( $query->query_vars['post_parent'] ) ) {
1145
- $parent_query = array( 'parent in' => array( $query->query_vars['post_parent'] ) );
1146
- }
1147
- if ( isset( $query->query_vars['post_parent__in'] ) && is_array( $query->query_vars['post_parent__in'] ) && ! empty( $query->query_vars['post_parent__in'] ) ) {
1148
- $parent_query = array( 'parent in' => $query->query_vars['post_parent__in'] );
1149
- }
1150
- if ( isset( $query->query_vars['post_parent__not_in'] ) && is_array( $query->query_vars['post_parent__not_in'] ) && ! empty( $query->query_vars['post_parent__not_in'] ) ) {
1151
- $parent_query = array( 'parent not in' => $query->query_vars['post_parent__not_in'] );
1152
- }
1153
-
1154
- $meta_query = array();
1155
- if ( ! empty( $query->query_vars['meta_query'] ) ) {
1156
- $meta_query = $query->query_vars['meta_query'];
1157
- }
1158
-
1159
- if ( isset( $query->query_vars['customfield_key'] ) ) {
1160
- $build_meta_query = array();
1161
-
1162
- // Use meta key.
1163
- $build_meta_query['key'] = $query->query_vars['customfield_key'];
1164
-
1165
- /**
1166
- * Check the value is not empty for ordering purpose,
1167
- * set it or not for the current meta query.
1168
- */
1169
- if ( ! empty( $query->query_vars['customfield_value'] ) ) {
1170
- $build_meta_query['value'] = $query->query_vars['customfield_value'];
1171
- }
1172
-
1173
- // Set the compare.
1174
- $build_meta_query['compare'] = '=';
1175
- $meta_query[] = $build_meta_query;
1176
- }
1177
-
1178
- if ( ! empty( $query->query_vars['meta_key'] ) || ! empty( $query->query_vars['meta_value'] ) || ! empty( $query->query_vars['meta_value_num'] ) ) {
1179
- $build_meta_query = array();
1180
-
1181
- // Use meta key.
1182
- $build_meta_query['key'] = $query->query_vars['meta_key'];
1183
-
1184
- $value = null;
1185
- if ( ! empty( $query->query_vars['meta_value'] ) ) {
1186
- $value = $query->query_vars['meta_value'];
1187
- } elseif ( ! empty( $query->query_vars['meta_value_num'] ) ) {
1188
- $value = $query->query_vars['meta_value_num'];
1189
- }
1190
-
1191
- /**
1192
- * Check the meta value, as it could be not set for ordering purpose.
1193
- * Set it or not for the current meta query.
1194
- */
1195
- if ( ! empty( $value ) ) {
1196
- $build_meta_query['value'] = $value;
1197
- }
1198
-
1199
- // Set meta compare.
1200
- $build_meta_query['compare'] = '=';
1201
- if ( ! empty( $query->query_vars['meta_compare'] ) ) {
1202
- $query->query_vars['meta_compare'];
1203
- }
1204
-
1205
- $meta_query[] = $build_meta_query;
1206
- }
1207
-
1208
- $date_query = false;
1209
- if ( ! empty( $query->date_query ) ) {
1210
- if ( is_object( $query->date_query ) && 'WP_Date_Query' === get_class( $query->date_query ) ) {
1211
- $date_query = $query->date_query;
1212
- } else {
1213
- $date_query = new WP_Date_Query( $query->date_query );
1214
- }
1215
- } elseif ( ! empty( $query->query_vars['date_query'] ) ) {
1216
- // The official date query is in $query->date_query, but this allows
1217
- // users to set the date query from query variables.
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'];
1260
- }
1261
-
1262
- $post_type = false;
1263
- if ( isset( $query->query_vars['post_type'] ) && 'any' !== $query->query_vars['post_type'] ) {
1264
- $post_type = $query->query_vars['post_type'];
1265
- }
1266
- if ( isset( $query->query_vars['post_types'] ) && 'any' !== $query->query_vars['post_types'] ) {
1267
- $post_type = $query->query_vars['post_types'];
1268
- }
1269
-
1270
- $post_status = false;
1271
- if ( isset( $query->query_vars['post_status'] ) && 'any' !== $query->query_vars['post_status'] ) {
1272
- $post_status = $query->query_vars['post_status'];
1273
- }
1274
-
1275
- $expost = get_option( 'relevanssi_exclude_posts' );
1276
-
1277
- // In admin (and when not AJAX), search everything.
1278
- if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) {
1279
- $excat = null;
1280
- $extag = null;
1281
- $expost = null;
1282
- }
1283
-
1284
- $sentence = false;
1285
- if ( isset( $query->query_vars['sentence'] ) && ! empty( $query->query_vars['sentence'] ) ) {
1286
- $sentence = true;
1287
- }
1288
-
1289
- $operator = '';
1290
- if ( function_exists( 'relevanssi_set_operator' ) ) {
1291
- $operator = relevanssi_set_operator( $query );
1292
- $operator = strtoupper( $operator );
1293
- }
1294
- if ( ! in_array( $operator, array( 'OR', 'AND' ), true ) ) {
1295
- $operator = get_option( 'relevanssi_implicit_operator' );
1296
- }
1297
- $query->query_vars['operator'] = $operator;
1298
-
1299
- $orderby = null;
1300
- $order = null;
1301
- if ( isset( $query->query_vars['orderby'] ) ) {
1302
- $orderby = $query->query_vars['orderby'];
1303
- }
1304
- if ( isset( $query->query_vars['order'] ) ) {
1305
- $order = $query->query_vars['order'];
1306
- }
1307
-
1308
- $fields = '';
1309
- if ( ! empty( $query->query_vars['fields'] ) ) {
1310
- if ( 'ids' === $query->query_vars['fields'] ) {
1311
- $fields = 'ids';
1312
- }
1313
- if ( 'id=>parent' === $query->query_vars['fields'] ) {
1314
- $fields = 'id=>parent';
1315
- }
1316
- }
1317
-
1318
- $by_date = '';
1319
- if ( ! empty( $query->query_vars['by_date'] ) ) {
1320
- if ( preg_match( '/\d+[hdmyw]/', $query->query_vars['by_date'] ) ) {
1321
- // Accepted format is digits followed by h, d, m, y, or w.
1322
- $by_date = $query->query_vars['by_date'];
1323
- }
1324
- }
1325
-
1326
- $admin_search = false;
1327
- if ( isset( $query->query_vars['relevanssi_admin_search'] ) ) {
1328
- $admin_search = true;
1329
- }
1330
-
1331
- $include_attachments = '';
1332
- if ( isset( $query->query_vars['include_attachments'] ) ) {
1333
- $include_attachments = $query->query_vars['include_attachments'];
1334
- }
1335
-
1336
- // Add synonyms.
1337
- // This is done here so the new terms will get highlighting.
1338
- if ( 'OR' === $operator ) {
1339
- // Synonyms are only used in OR queries.
1340
- $q = relevanssi_add_synonyms( $q );
1341
- }
1342
-
1343
- $search_params = array(
1344
- 'q' => $q,
1345
- 'tax_query' => $tax_query,
1346
- 'tax_query_relation' => $tax_query_relation,
1347
- 'post_query' => $post_query,
1348
- 'parent_query' => $parent_query,
1349
- 'meta_query' => $meta_query,
1350
- 'date_query' => $date_query,
1351
- 'expost' => $expost,
1352
- 'post_type' => $post_type,
1353
- 'post_status' => $post_status,
1354
- 'operator' => $operator,
1355
- 'search_blogs' => $search_blogs,
1356
- 'author' => $author,
1357
- 'orderby' => $orderby,
1358
- 'order' => $order,
1359
- 'fields' => $fields,
1360
- 'sentence' => $sentence,
1361
- 'by_date' => $by_date,
1362
- 'admin_search' => $admin_search,
1363
- 'include_attachments' => $include_attachments,
1364
- 'meta_query' => $meta_query,
1365
- );
1366
-
1367
- $return = relevanssi_search( $search_params );
1368
  }
1369
 
1370
  $hits = array();
@@ -1412,7 +861,7 @@ function relevanssi_do_query( &$query ) {
1412
  }
1413
 
1414
  $make_excerpts = get_option( 'relevanssi_excerpts' );
1415
- if ( $query->is_admin && ! defined( 'DOING_AJAX' ) ) {
1416
  $make_excerpts = false;
1417
  }
1418
 
@@ -1445,11 +894,13 @@ function relevanssi_do_query( &$query ) {
1445
  }
1446
 
1447
  if ( null === $post ) {
 
1448
  // Sometimes you can get a null object.
1449
  continue;
 
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 ) {
@@ -1459,7 +910,7 @@ function relevanssi_do_query( &$query ) {
1459
  }
1460
  }
1461
 
1462
- if ( 'on' === $make_excerpts && empty( $fields ) ) {
1463
  if ( isset( $post->blog_id ) ) {
1464
  switch_to_blog( $post->blog_id );
1465
  }
@@ -1469,7 +920,7 @@ function relevanssi_do_query( &$query ) {
1469
  restore_current_blog();
1470
  }
1471
  }
1472
- if ( 'on' === get_option( 'relevanssi_show_matches' ) && empty( $fields ) ) {
1473
  $post_id = $post->ID;
1474
  if ( 'user' === $post->post_type ) {
1475
  $post_id = 'u_' . $post->user_id;
@@ -1484,7 +935,7 @@ function relevanssi_do_query( &$query ) {
1484
  $post->post_excerpt .= relevanssi_show_matches( $return, $post_id );
1485
  }
1486
 
1487
- if ( empty( $fields ) ) {
1488
  $post_id = $post->ID;
1489
  if ( isset( $post->blog_id ) ) {
1490
  $post_id = $post->blog_id . '|' . $post->ID;
@@ -1682,3 +1133,358 @@ function relevanssi_taxonomy_score( &$match, $post_type_weights ) {
1682
  }
1683
  }
1684
  }