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 +331 -43 4.4.15.3.5 View file →
@@ -51,8 +51,83 @@
51 51 return $credentials;
52 52 }
53 53
54 54 /**
55 + * Get WP capability needed for a user to interact with ElasticPress in the admin
56 + *
57 + * @since 4.5.0, 5.1.0 added $context
58 + * @param string $context Context for the capability. Defaults to empty string.
59 + * @return string
60 + */
61 +function get_capability( string $context = '' ): string {
62 + /**
63 + * Filter the WP capability needed to interact with ElasticPress in the admin
64 + *
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
80 + * @hook ep_capability
81 + * @param {string} $capability Capability name. Defaults to `'manage_elasticpress'`
82 + * @param {string} $context Additional context
83 + * @return {string} New capability value
84 + */
85 + return apply_filters( 'ep_capability', 'manage_elasticpress', $context );
86 +}
87 +
88 +/**
89 + * Get WP capability needed for a user to interact with ElasticPress in the network admin
90 + *
91 + * @since 4.5.0, 5.1.0 added $context
92 + * @param string $context Context for the capability. Defaults to empty string.
93 + * @return string
94 + */
95 +function get_network_capability( string $context = '' ): string {
96 + /**
97 + * Filter the WP capability needed to interact with ElasticPress in the network admin
98 + *
99 + * @since 4.5.0, 5.1.0 added $context
100 + * @hook ep_network_capability
101 + * @param {string} $capability Capability name. Defaults to `'manage_network_elasticpress'`
102 + * @param {string} $context Additional context
103 + * @return {string} New capability value
104 + */
105 + return apply_filters( 'ep_network_capability', 'manage_network_elasticpress', $context );
106 +}
107 +
108 +/**
109 + * Get mapped capabilities for post types
110 + *
111 + * @since 4.5.0, 5.1.0 added $context
112 + * @param string $context Context for the capability. Defaults to empty string.
113 + * @return array
114 + */
115 +function get_post_map_capabilities( string $context = '' ): array {
116 + $capability = get_capability( $context );
117 +
118 + return [
119 + 'edit_post' => $capability,
120 + 'edit_posts' => $capability,
121 + 'edit_others_posts' => $capability,
122 + 'publish_posts' => $capability,
123 + 'read_post' => $capability,
124 + 'read_private_posts' => $capability,
125 + 'delete_post' => $capability,
126 + ];
127 +}
128 +
129 +/**
55 130 * Get shield credentials
56 131 *
57 132 * @since 3.0
58 133 * @return string|bool
@@ -109,9 +184,11 @@
109 184 * @since 2.6
110 185 * @return bool
111 186 */
112 187 function is_epio() {
113 - 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;
114 191 }
115 192
116 193 /**
117 194 * Determine if we should index a blog/site
@@ -120,19 +197,21 @@
120 197 * @since 3.2
121 198 * @return boolean
122 199 */
123 200 function is_site_indexable( $blog_id = null ) {
124 - if ( is_multisite() ) {
125 - $site = get_site( $blog_id );
201 + if ( ! is_multisite() ) {
202 + return true;
203 + }
126 204
127 - $is_indexable = get_blog_option( (int) $blog_id, 'ep_indexable', 'yes' );
205 + $site = get_site( $blog_id );
128 206
129 - if ( 'no' === $is_indexable || $site['deleted'] || $site['archived'] || $site['spam'] ) {
130 - return false;
131 - }
207 + if ( empty( $site ) ) {
208 + return false;
132 209 }
133 210
134 - 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'];
135 214 }
136 215
137 216 /**
138 217 * Sanitize EPIO credentials prior to storing them.
@@ -227,8 +306,12 @@
227 306 */
228 307 function get_site( $site_id ) {
229 308 $site = \get_site( $site_id );
230 309
310 + if ( ! $site instanceof \WP_Site ) {
311 + return [];
312 + }
313 +
231 314 return [
232 315 'blog_id' => $site->blog_id,
233 316 'domain' => $site->domain,
234 317 'path' => $site->path,
@@ -241,18 +324,46 @@
241 324
242 325 /**
243 326 * Wrapper function for get_sites - allows us to have one central place for the `ep_indexable_sites` filter
244 327 *
245 - * @param int $limit The maximum amount of sites retrieved, Use 0 to return all sites.
246 - * @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`
247 331 * @return array
248 332 */
249 -function get_sites( $limit = 0 ) {
250 -
333 +function get_sites( $limit = 0, $only_indexable = false ) {
251 334 if ( ! is_multisite() ) {
252 335 return [];
253 336 }
254 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 +
255 366 /**
256 367 * Filter arguments to use to query for sites on network
257 368 *
258 369 * @since 2.1
@@ -259,15 +370,9 @@
259 370 * @hook ep_indexable_sites_args
260 371 * @param {array} $args Array of args to query sites with. See WP_Site_Query
261 372 * @return {array} New arguments
262 373 */
263 - $args = apply_filters(
264 - 'ep_indexable_sites_args',
265 - array(
266 - 'limit' => $limit,
267 - 'number' => $limit,
268 - )
269 - );
374 + $args = apply_filters( 'ep_indexable_sites_args', $args );
270 375
271 376 $site_objects = \get_sites( $args );
272 377 $sites = [];
273 378
@@ -341,9 +446,9 @@
341 446 break;
342 447 }
343 448
344 449 foreach ( $all_terms as $key => $term ) {
345 - $iteration_id++;
450 + ++$iteration_id;
346 451
347 452 if ( ! isset( $term->children ) ) {
348 453 $term->children = [];
349 454 }
@@ -368,18 +473,17 @@
368 473 $terms_tree[ strtolower( $term->name ) ] = $term;
369 474 }
370 475
371 476 unset( $all_terms[ $key ] );
372 - } else {
373 - 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 ) ) {
374 478
375 - if ( empty( $orderby ) ) {
376 - $terms_map[ $term->parent ]->children[] = $term;
377 - } elseif ( 'count' === $orderby ) {
378 - $terms_map[ $term->parent ]->children[ ( ( $term->count * 10000000 ) + $iteration_id ) ] = $term;
379 - } elseif ( 'name' === $orderby ) {
380 - $terms_map[ $term->parent ]->children[ $term->name ] = $term;
381 - }
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 + }
382 486
383 487 $parent_level = ( $terms_map[ $term->parent ]->level ) ? $terms_map[ $term->parent ]->level : 0;
384 488
385 489 $term->level = $parent_level + 1;
@@ -385,9 +489,8 @@
385 489 $term->level = $parent_level + 1;
386 490 $term->parent_term = $terms_map[ $term->parent ];
387 491
388 492 unset( $all_terms[ $key ] );
389 - }
390 493 }
391 494 }
392 495 }
393 496
@@ -433,21 +536,16 @@
433 536 return $terms_tree;
434 537 }
435 538
436 539 /**
437 - * Returns the defaiult language for ES mapping.
540 + * Returns the default language for ES mapping.
438 541 *
439 542 * @return string Default EP language.
440 543 */
441 544 function get_language() {
442 - if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
443 - $ep_language = get_site_option( 'ep_language' );
444 - } else {
445 - $ep_language = get_option( 'ep_language' );
446 - }
545 + $ep_language = get_option( 'ep_language' );
546 + $ep_language = ! empty( $ep_language ) ? $ep_language : 'site-default';
447 547
448 - $ep_language = ! empty( $ep_language ) ? $ep_language : get_locale();
449 -
450 548 /**
451 549 * Filter the default language to use at index time
452 550 *
453 551 * @since 3.1
@@ -505,9 +603,8 @@
505 603 }
506 604 }
507 605
508 606 return $index_status;
509 -
510 607 }
511 608
512 609 /**
513 610 * Use the correct update option function depending on the context (multisite or not)
@@ -530,9 +627,9 @@
530 627 *
531 628 * @since 3.6.0
532 629 * @param string $option Name of the option to get.
533 630 * @param mixed $default_value Default value.
534 - * @return bool
631 + * @return mixed
535 632 */
536 633 function get_option( $option, $default_value = false ) {
537 634 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
538 635 return \get_site_option( $option, $default_value );
@@ -584,9 +681,9 @@
584 681 $types = [ 'admin', 'ajax', 'public', 'rest' ];
585 682 }
586 683
587 684 $is_admin_request = is_admin();
588 - $is_ajax_request = defined( 'DOING_AJAX' ) && DOING_AJAX;
685 + $is_ajax_request = wp_doing_ajax();
589 686 $is_rest_request = defined( 'REST_REQUEST' ) && REST_REQUEST;
590 687 $is_integrated_admin_request = false;
591 688 $is_integrated_ajax_request = false;
592 689 $is_integrated_public_request = false;
@@ -676,16 +773,207 @@
676 773 /**
677 774 * Return the Sync Page URL.
678 775 *
679 776 * @since 4.4.0
680 - * @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.
681 778 * @return string
682 779 */
683 -function get_sync_url( bool $do_sync = false ) : string {
780 +function get_sync_url( $do_sync = false ): string {
684 781 $page = 'admin.php?page=elasticpress-sync';
685 782 if ( $do_sync ) {
686 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' );
687 788 }
688 789 return ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) ?
689 790 network_admin_url( $page ) :
690 791 admin_url( $page );
792 +}
793 +
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 +/**
805 + * Generate a common prefix to be used while generating a request ID.
806 + *
807 + * Uses the return of `get_index_prefix()` by default.
808 + *
809 + * @since 4.5.0
810 + * @return string
811 + */
812 +function get_request_id_base() {
813 + /**
814 + * Filter the base of requests IDs. Uses the return of `get_index_prefix()` by default.
815 + *
816 + * @hook ep_request_id_base
817 + * @since 4.5.0
818 + * @param {string} $request_id_base Request ID base
819 + * @return {string} New Request ID base
820 + */
821 + return apply_filters( 'ep_request_id_base', str_replace( '-', '', get_index_prefix() ) );
822 +}
823 +
824 +/**
825 + * Generate a Request ID.
826 + *
827 + * The function concatenates the indices prefix to a random UUID4.
828 + *
829 + * @since 4.5.0
830 + * @return string
831 + */
832 +function generate_request_id(): string {
833 + $uuid = str_replace( '-', '', wp_generate_uuid4() );
834 +
835 + /**
836 + * Filter the ID generated to identify a request.
837 + *
838 + * @hook ep_request_id
839 + * @since 4.5.0
840 + * @param {string} $request_id Request ID. By default formed by the indices prefix and a random UUID4.
841 + * @return {string} New Request ID
842 + */
843 + return apply_filters( 'ep_request_id', get_request_id_base() . $uuid );
844 +}
845 +
846 +/**
847 + * Given an Elasticsearch response, try to find an error message.
848 + *
849 + * @since 4.6.0
850 + * @param mixed $response The Elasticsearch response
851 + * @return string
852 + */
853 +function get_elasticsearch_error_reason( $response ): string {
854 + if ( is_string( $response ) ) {
855 + return $response;
856 + }
857 +
858 + if ( ! is_array( $response ) ) {
859 + return var_export( $response, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
860 + }
861 +
862 + if ( ! empty( $response['reason'] ) ) {
863 + return (string) $response['reason'];
864 + }
865 +
866 + if ( ! empty( $response['result']['error'] ) && ! empty( $response['result']['error']['root_cause'][0]['reason'] ) ) {
867 + return (string) $response['result']['error']['root_cause'][0]['reason'];
868 + }
869 +
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;
879 + }
880 +
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' ) );
691 979 }