PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
← All changes | includes/utils.php +221 -62 4.6.15.3.5 View file →
@@ -53,49 +53,68 @@
53 53
54 54 /**
55 55 * Get WP capability needed for a user to interact with ElasticPress in the admin
56 56 *
57 - * @since 4.5.0
57 + * @since 4.5.0, 5.1.0 added $context
58 + * @param string $context Context for the capability. Defaults to empty string.
58 59 * @return string
59 60 */
60 -function get_capability() : string {
61 +function get_capability( string $context = '' ): string {
61 62 /**
62 63 * Filter the WP capability needed to interact with ElasticPress in the admin
63 64 *
64 - * @since 4.5.0
65 + * Example:
66 + * ```
67 + * add_filter(
68 + * 'ep_capability',
69 + * function ( $cacapability, $context ) {
70 + * return ( 'synonyms' === $context ) ?
71 + * 'manage_elasticpress_synonyms' :
72 + * $cacapability;
73 + * },
74 + * 10,
75 + * 2
76 + * );
77 + * ```
78 + *
79 + * @since 4.5.0, 5.1.0 added $context
65 80 * @hook ep_capability
66 - * @param {bool} $capability Capability name. Defaults to `'elasticpress_manage'`
67 - * @return {bool} New capability value
81 + * @param {string} $capability Capability name. Defaults to `'manage_elasticpress'`
82 + * @param {string} $context Additional context
83 + * @return {string} New capability value
68 84 */
69 - return apply_filters( 'ep_capability', 'manage_elasticpress' );
85 + return apply_filters( 'ep_capability', 'manage_elasticpress', $context );
70 86 }
71 87
72 88 /**
73 89 * Get WP capability needed for a user to interact with ElasticPress in the network admin
74 90 *
75 - * @since 4.5.0
91 + * @since 4.5.0, 5.1.0 added $context
92 + * @param string $context Context for the capability. Defaults to empty string.
76 93 * @return string
77 94 */
78 -function get_network_capability() : string {
95 +function get_network_capability( string $context = '' ): string {
79 96 /**
80 97 * Filter the WP capability needed to interact with ElasticPress in the network admin
81 98 *
82 - * @since 4.5.0
99 + * @since 4.5.0, 5.1.0 added $context
83 100 * @hook ep_network_capability
84 - * @param {bool} $capability Capability name. Defaults to `'manage_network_elasticpress'`
85 - * @return {bool} New capability value
101 + * @param {string} $capability Capability name. Defaults to `'manage_network_elasticpress'`
102 + * @param {string} $context Additional context
103 + * @return {string} New capability value
86 104 */
87 - return apply_filters( 'ep_network_capability', 'manage_network_elasticpress' );
105 + return apply_filters( 'ep_network_capability', 'manage_network_elasticpress', $context );
88 106 }
89 107
90 108 /**
91 109 * Get mapped capabilities for post types
92 110 *
93 - * @since 4.5.0
111 + * @since 4.5.0, 5.1.0 added $context
112 + * @param string $context Context for the capability. Defaults to empty string.
94 113 * @return array
95 114 */
96 -function get_post_map_capabilities() : array {
97 - $capability = get_capability();
115 +function get_post_map_capabilities( string $context = '' ): array {
116 + $capability = get_capability( $context );
98 117
99 118 return [
100 119 'edit_post' => $capability,
101 120 'edit_posts' => $capability,
@@ -165,9 +184,11 @@
165 184 * @since 2.6
166 185 * @return bool
167 186 */
168 187 function is_epio() {
169 - return filter_var( preg_match( '#elasticpress\.io#i', get_host() ), FILTER_VALIDATE_BOOLEAN );
188 + $has_url = filter_var( preg_match( '#elasticpress\.io#i', get_host() ), FILTER_VALIDATE_BOOLEAN );
189 + $has_env_var = '1' === getenv( 'IS_EPIO_ENVIRONMENT' );
190 + return $has_url || $has_env_var;
170 191 }
171 192
172 193 /**
173 194 * Determine if we should index a blog/site
@@ -176,19 +197,21 @@
176 197 * @since 3.2
177 198 * @return boolean
178 199 */
179 200 function is_site_indexable( $blog_id = null ) {
180 - if ( is_multisite() ) {
181 - $site = get_site( $blog_id );
201 + if ( ! is_multisite() ) {
202 + return true;
203 + }
182 204
183 - $is_indexable = get_blog_option( (int) $blog_id, 'ep_indexable', 'yes' );
205 + $site = get_site( $blog_id );
184 206
185 - if ( 'no' === $is_indexable || $site['deleted'] || $site['archived'] || $site['spam'] ) {
186 - return false;
187 - }
207 + if ( empty( $site ) ) {
208 + return false;
188 209 }
189 210
190 - return true;
211 + $is_indexable = get_site_meta( $site['blog_id'], 'ep_indexable', true );
212 +
213 + return 'no' !== $is_indexable && ! $site['deleted'] && ! $site['archived'] && ! $site['spam'];
191 214 }
192 215
193 216 /**
194 217 * Sanitize EPIO credentials prior to storing them.
@@ -283,8 +306,12 @@
283 306 */
284 307 function get_site( $site_id ) {
285 308 $site = \get_site( $site_id );
286 309
310 + if ( ! $site instanceof \WP_Site ) {
311 + return [];
312 + }
313 +
287 314 return [
288 315 'blog_id' => $site->blog_id,
289 316 'domain' => $site->domain,
290 317 'path' => $site->path,
@@ -297,18 +324,46 @@
297 324
298 325 /**
299 326 * Wrapper function for get_sites - allows us to have one central place for the `ep_indexable_sites` filter
300 327 *
301 - * @param int $limit The maximum amount of sites retrieved, Use 0 to return all sites.
302 - * @since 3.0
328 + * @param int $limit The maximum amount of sites retrieved, Use 0 to return all sites.
329 + * @param bool $only_indexable Whether should be returned only indexable sites or not.
330 + * @since 3.0, 4.7.0 added `$only_indexable`
303 331 * @return array
304 332 */
305 -function get_sites( $limit = 0 ) {
306 -
333 +function get_sites( $limit = 0, $only_indexable = false ) {
307 334 if ( ! is_multisite() ) {
308 335 return [];
309 336 }
310 337
338 + $args = [
339 + 'limit' => $limit,
340 + 'number' => $limit,
341 + ];
342 +
343 + if ( $only_indexable ) {
344 + $args = array_merge(
345 + $args,
346 + [
347 + 'spam' => 0,
348 + 'deleted' => 0,
349 + 'archived' => 0,
350 + 'meta_query' => [
351 + 'relation' => 'OR',
352 + [
353 + 'key' => 'ep_indexable',
354 + 'value' => 'no',
355 + 'compare' => '!=',
356 + ],
357 + [
358 + 'key' => 'ep_indexable',
359 + 'compare' => 'NOT EXISTS',
360 + ],
361 + ],
362 + ]
363 + );
364 + }
365 +
311 366 /**
312 367 * Filter arguments to use to query for sites on network
313 368 *
314 369 * @since 2.1
@@ -315,15 +370,9 @@
315 370 * @hook ep_indexable_sites_args
316 371 * @param {array} $args Array of args to query sites with. See WP_Site_Query
317 372 * @return {array} New arguments
318 373 */
319 - $args = apply_filters(
320 - 'ep_indexable_sites_args',
321 - array(
322 - 'limit' => $limit,
323 - 'number' => $limit,
324 - )
325 - );
374 + $args = apply_filters( 'ep_indexable_sites_args', $args );
326 375
327 376 $site_objects = \get_sites( $args );
328 377 $sites = [];
329 378
@@ -397,9 +446,9 @@
397 446 break;
398 447 }
399 448
400 449 foreach ( $all_terms as $key => $term ) {
401 - $iteration_id++;
450 + ++$iteration_id;
402 451
403 452 if ( ! isset( $term->children ) ) {
404 453 $term->children = [];
405 454 }
@@ -424,18 +473,17 @@
424 473 $terms_tree[ strtolower( $term->name ) ] = $term;
425 474 }
426 475
427 476 unset( $all_terms[ $key ] );
428 - } else {
429 - if ( ! empty( $terms_map[ $term->parent ] ) && isset( $terms_map[ $term->parent ]->level ) ) {
477 + } elseif ( ! empty( $terms_map[ $term->parent ] ) && isset( $terms_map[ $term->parent ]->level ) ) {
430 478
431 - if ( empty( $orderby ) ) {
432 - $terms_map[ $term->parent ]->children[] = $term;
433 - } elseif ( 'count' === $orderby ) {
434 - $terms_map[ $term->parent ]->children[ ( ( $term->count * 10000000 ) + $iteration_id ) ] = $term;
435 - } elseif ( 'name' === $orderby ) {
436 - $terms_map[ $term->parent ]->children[ $term->name ] = $term;
437 - }
479 + if ( empty( $orderby ) ) {
480 + $terms_map[ $term->parent ]->children[] = $term;
481 + } elseif ( 'count' === $orderby ) {
482 + $terms_map[ $term->parent ]->children[ ( ( $term->count * 10000000 ) + $iteration_id ) ] = $term;
483 + } elseif ( 'name' === $orderby ) {
484 + $terms_map[ $term->parent ]->children[ $term->name ] = $term;
485 + }
438 486
439 487 $parent_level = ( $terms_map[ $term->parent ]->level ) ? $terms_map[ $term->parent ]->level : 0;
440 488
441 489 $term->level = $parent_level + 1;
@@ -441,9 +489,8 @@
441 489 $term->level = $parent_level + 1;
442 490 $term->parent_term = $terms_map[ $term->parent ];
443 491
444 492 unset( $all_terms[ $key ] );
445 - }
446 493 }
447 494 }
448 495 }
449 496
@@ -489,21 +536,16 @@
489 536 return $terms_tree;
490 537 }
491 538
492 539 /**
493 - * Returns the defaiult language for ES mapping.
540 + * Returns the default language for ES mapping.
494 541 *
495 542 * @return string Default EP language.
496 543 */
497 544 function get_language() {
498 - if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
499 - $ep_language = get_site_option( 'ep_language' );
500 - } else {
501 - $ep_language = get_option( 'ep_language' );
502 - }
545 + $ep_language = get_option( 'ep_language' );
546 + $ep_language = ! empty( $ep_language ) ? $ep_language : 'site-default';
503 547
504 - $ep_language = ! empty( $ep_language ) ? $ep_language : get_locale();
505 -
506 548 /**
507 549 * Filter the default language to use at index time
508 550 *
509 551 * @since 3.1
@@ -561,9 +603,8 @@
561 603 }
562 604 }
563 605
564 606 return $index_status;
565 -
566 607 }
567 608
568 609 /**
569 610 * Use the correct update option function depending on the context (multisite or not)
@@ -586,9 +627,9 @@
586 627 *
587 628 * @since 3.6.0
588 629 * @param string $option Name of the option to get.
589 630 * @param mixed $default_value Default value.
590 - * @return bool
631 + * @return mixed
591 632 */
592 633 function get_option( $option, $default_value = false ) {
593 634 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
594 635 return \get_site_option( $option, $default_value );
@@ -640,9 +681,9 @@
640 681 $types = [ 'admin', 'ajax', 'public', 'rest' ];
641 682 }
642 683
643 684 $is_admin_request = is_admin();
644 - $is_ajax_request = defined( 'DOING_AJAX' ) && DOING_AJAX;
685 + $is_ajax_request = wp_doing_ajax();
645 686 $is_rest_request = defined( 'REST_REQUEST' ) && REST_REQUEST;
646 687 $is_integrated_admin_request = false;
647 688 $is_integrated_ajax_request = false;
648 689 $is_integrated_public_request = false;
@@ -732,15 +773,19 @@
732 773 /**
733 774 * Return the Sync Page URL.
734 775 *
735 776 * @since 4.4.0
736 - * @param boolean $do_sync Whether the link should or should not start a resync.
777 + * @param boolean|string $do_sync Whether the link should or should not start a resync. Pass a string to store the reason of the resync.
737 778 * @return string
738 779 */
739 -function get_sync_url( bool $do_sync = false ) : string {
780 +function get_sync_url( $do_sync = false ): string {
740 781 $page = 'admin.php?page=elasticpress-sync';
741 782 if ( $do_sync ) {
742 783 $page .= '&do_sync';
784 + if ( is_string( $do_sync ) ) {
785 + $page .= '=' . rawurlencode( $do_sync );
786 + }
787 + $page .= '&ep_sync_nonce=' . wp_create_nonce( 'ep_sync_nonce' );
743 788 }
744 789 return ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) ?
745 790 network_admin_url( $page ) :
746 791 admin_url( $page );
@@ -746,8 +791,18 @@
746 791 admin_url( $page );
747 792 }
748 793
749 794 /**
795 + * Check if the `do_sync` parameter is set and the nonce is valid.
796 + *
797 + * @since 5.1.2
798 + * @return boolean
799 + */
800 +function isset_do_sync_parameter(): bool {
801 + return isset( $_GET['do_sync'] ) && ! empty( $_GET['ep_sync_nonce'] ) && wp_verify_nonce( sanitize_key( $_GET['ep_sync_nonce'] ), 'ep_sync_nonce' );
802 +}
803 +
804 +/**
750 805 * Generate a common prefix to be used while generating a request ID.
751 806 *
752 807 * Uses the return of `get_index_prefix()` by default.
753 808 *
@@ -773,9 +828,9 @@
773 828 *
774 829 * @since 4.5.0
775 830 * @return string
776 831 */
777 -function generate_request_id() : string {
832 +function generate_request_id(): string {
778 833 $uuid = str_replace( '-', '', wp_generate_uuid4() );
779 834
780 835 /**
781 836 * Filter the ID generated to identify a request.
@@ -794,9 +849,9 @@
794 849 * @since 4.6.0
795 850 * @param mixed $response The Elasticsearch response
796 851 * @return string
797 852 */
798 -function get_elasticsearch_error_reason( $response ) : string {
853 +function get_elasticsearch_error_reason( $response ): string {
799 854 if ( is_string( $response ) ) {
800 855 return $response;
801 856 }
802 857
@@ -811,10 +866,114 @@
811 866 if ( ! empty( $response['result']['error'] ) && ! empty( $response['result']['error']['root_cause'][0]['reason'] ) ) {
812 867 return (string) $response['result']['error']['root_cause'][0]['reason'];
813 868 }
814 869
815 - if ( ! empty( $response['result']['errors'] ) && ! empty( $response['result']['items'] ) && ! empty( $response['result']['items'][0]['index']['error']['reason'] ) ) {
816 - return (string) $response['result']['items'][0]['index']['error']['reason'];
870 + if ( ! empty( $response['result']['errors'] ) && ! empty( $response['result']['items'] ) ) {
871 + $error = '';
872 + foreach ( $response['result']['items'] as $item ) {
873 + if ( ! empty( $item['index']['error']['reason'] ) ) {
874 + $error = $item['index']['error']['reason'];
875 + break;
876 + }
877 + }
878 + return $error;
817 879 }
818 880
819 881 return '';
882 +}
883 +
884 +/**
885 + * Use the correct set_transient option function depending on the context (multisite or not)
886 + *
887 + * @since 4.7.0
888 + * @param string $transient Transient name. Expected to not be SQL-escaped.
889 + * Must be 172 characters or fewer in length.
890 + * @param mixed $value Transient value. Must be serializable if non-scalar.
891 + * Expected to not be SQL-escaped.
892 + * @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
893 + * @return bool True if the value was set, false otherwise.
894 + */
895 +function set_transient( $transient, $value, $expiration = 0 ) {
896 + if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
897 + return \set_site_transient( $transient, $value, $expiration );
898 + }
899 + return \set_transient( $transient, $value, $expiration );
900 +}
901 +
902 +/**
903 + * Use the correct get_transient function depending on the context (multisite or not)
904 + *
905 + * @since 4.7.0
906 + * @param string $transient Transient name. Expected to not be SQL-escaped.
907 + * @return mixed Value of transient.
908 + */
909 +function get_transient( $transient ) {
910 + if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
911 + return \get_site_transient( $transient );
912 + }
913 + return \get_transient( $transient );
914 +}
915 +
916 +/**
917 + * Use the correct delete_transient function depending on the context (multisite or not)
918 + *
919 + * @since 4.7.0
920 + * @param string $transient Transient name. Expected to not be SQL-escaped.
921 + * @return bool True if the transient was deleted, false otherwise.
922 + */
923 +function delete_transient( $transient ) {
924 + if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
925 + return \delete_site_transient( $transient );
926 + }
927 + return \delete_transient( $transient );
928 +}
929 +
930 +/**
931 + * Whether we are in the top level admin context or not.
932 + *
933 + * In a single site, the top level admin context would be `is_admin()`,
934 + * in a multisite, it would be `is_network_admin()`.
935 + *
936 + * @since 5.0.0
937 + * @return boolean
938 + */
939 +function is_top_level_admin_context() {
940 + $is_network = defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK;
941 + return $is_network ? is_network_admin() : is_admin();
942 +}
943 +
944 +/**
945 + * Safely resolve the post type(s) for a taxonomy query.
946 + *
947 + * Guards against null queried objects, missing taxonomy properties,
948 + * deregistered taxonomies, and non-post-type object types that would
949 + * otherwise cause unexpected behavior when chaining
950 + * get_queried_object()->taxonomy through get_taxonomy().
951 + *
952 + * @since 5.3.3
953 + *
954 + * @param \WP_Query|null $query Optional. WP_Query instance. Defaults to the global query.
955 + * @return array Registered post type names on success, empty array otherwise.
956 + */
957 +function get_post_types_for_tax_query( ?\WP_Query $query = null ): array {
958 + global $wp_query;
959 +
960 + if ( null === $query ) {
961 + $query = $wp_query;
962 + }
963 +
964 + if ( ! $query instanceof \WP_Query || ! $query->is_tax() ) {
965 + return [];
966 + }
967 +
968 + $queried_object = $query->get_queried_object();
969 + if ( ! $queried_object || ! isset( $queried_object->taxonomy ) ) {
970 + return [];
971 + }
972 +
973 + $taxonomy_object = get_taxonomy( $queried_object->taxonomy );
974 + if ( ! $taxonomy_object || ! is_array( $taxonomy_object->object_type ) ) {
975 + return [];
976 + }
977 +
978 + return array_values( array_filter( $taxonomy_object->object_type, 'post_type_exists' ) );
820 979 }