| @@ -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 |
| @@ -182,8 +203,12 @@ | ||
| 182 | 203 | } |
| 183 | 204 | |
| 184 | 205 | $site = get_site( $blog_id ); |
| 185 | 206 | |
| 207 | + if ( empty( $site ) ) { | |
| 208 | + return false; | |
| 209 | + } | |
| 210 | + | |
| 186 | 211 | $is_indexable = get_site_meta( $site['blog_id'], 'ep_indexable', true ); |
| 187 | 212 | |
| 188 | 213 | return 'no' !== $is_indexable && ! $site['deleted'] && ! $site['archived'] && ! $site['spam']; |
| 189 | 214 | } |
| @@ -281,8 +306,12 @@ | ||
| 281 | 306 | */ |
| 282 | 307 | function get_site( $site_id ) { |
| 283 | 308 | $site = \get_site( $site_id ); |
| 284 | 309 | |
| 310 | + if ( ! $site instanceof \WP_Site ) { | |
| 311 | + return []; | |
| 312 | + } | |
| 313 | + | |
| 285 | 314 | return [ |
| 286 | 315 | 'blog_id' => $site->blog_id, |
| 287 | 316 | 'domain' => $site->domain, |
| 288 | 317 | 'path' => $site->path, |
| @@ -417,9 +446,9 @@ | ||
| 417 | 446 | break; |
| 418 | 447 | } |
| 419 | 448 | |
| 420 | 449 | foreach ( $all_terms as $key => $term ) { |
| 421 | - $iteration_id++; | |
| 450 | + ++$iteration_id; | |
| 422 | 451 | |
| 423 | 452 | if ( ! isset( $term->children ) ) { |
| 424 | 453 | $term->children = []; |
| 425 | 454 | } |
| @@ -444,18 +473,17 @@ | ||
| 444 | 473 | $terms_tree[ strtolower( $term->name ) ] = $term; |
| 445 | 474 | } |
| 446 | 475 | |
| 447 | 476 | unset( $all_terms[ $key ] ); |
| 448 | - } else { | |
| 449 | - 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 ) ) { | |
| 450 | 478 | |
| 451 | - if ( empty( $orderby ) ) { | |
| 452 | - $terms_map[ $term->parent ]->children[] = $term; | |
| 453 | - } elseif ( 'count' === $orderby ) { | |
| 454 | - $terms_map[ $term->parent ]->children[ ( ( $term->count * 10000000 ) + $iteration_id ) ] = $term; | |
| 455 | - } elseif ( 'name' === $orderby ) { | |
| 456 | - $terms_map[ $term->parent ]->children[ $term->name ] = $term; | |
| 457 | - } | |
| 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 | + } | |
| 458 | 486 | |
| 459 | 487 | $parent_level = ( $terms_map[ $term->parent ]->level ) ? $terms_map[ $term->parent ]->level : 0; |
| 460 | 488 | |
| 461 | 489 | $term->level = $parent_level + 1; |
| @@ -461,9 +489,8 @@ | ||
| 461 | 489 | $term->level = $parent_level + 1; |
| 462 | 490 | $term->parent_term = $terms_map[ $term->parent ]; |
| 463 | 491 | |
| 464 | 492 | unset( $all_terms[ $key ] ); |
| 465 | - } | |
| 466 | 493 | } |
| 467 | 494 | } |
| 468 | 495 | } |
| 469 | 496 | |
| @@ -576,9 +603,8 @@ | ||
| 576 | 603 | } |
| 577 | 604 | } |
| 578 | 605 | |
| 579 | 606 | return $index_status; |
| 580 | - | |
| 581 | 607 | } |
| 582 | 608 | |
| 583 | 609 | /** |
| 584 | 610 | * Use the correct update option function depending on the context (multisite or not) |
| @@ -601,9 +627,9 @@ | ||
| 601 | 627 | * |
| 602 | 628 | * @since 3.6.0 |
| 603 | 629 | * @param string $option Name of the option to get. |
| 604 | 630 | * @param mixed $default_value Default value. |
| 605 | - * @return bool | |
| 631 | + * @return mixed | |
| 606 | 632 | */ |
| 607 | 633 | function get_option( $option, $default_value = false ) { |
| 608 | 634 | if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { |
| 609 | 635 | return \get_site_option( $option, $default_value ); |
| @@ -655,9 +681,9 @@ | ||
| 655 | 681 | $types = [ 'admin', 'ajax', 'public', 'rest' ]; |
| 656 | 682 | } |
| 657 | 683 | |
| 658 | 684 | $is_admin_request = is_admin(); |
| 659 | - $is_ajax_request = defined( 'DOING_AJAX' ) && DOING_AJAX; | |
| 685 | + $is_ajax_request = wp_doing_ajax(); | |
| 660 | 686 | $is_rest_request = defined( 'REST_REQUEST' ) && REST_REQUEST; |
| 661 | 687 | $is_integrated_admin_request = false; |
| 662 | 688 | $is_integrated_ajax_request = false; |
| 663 | 689 | $is_integrated_public_request = false; |
| @@ -747,15 +773,19 @@ | ||
| 747 | 773 | /** |
| 748 | 774 | * Return the Sync Page URL. |
| 749 | 775 | * |
| 750 | 776 | * @since 4.4.0 |
| 751 | - * @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. | |
| 752 | 778 | * @return string |
| 753 | 779 | */ |
| 754 | -function get_sync_url( bool $do_sync = false ) : string { | |
| 780 | +function get_sync_url( $do_sync = false ): string { | |
| 755 | 781 | $page = 'admin.php?page=elasticpress-sync'; |
| 756 | 782 | if ( $do_sync ) { |
| 757 | 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' ); | |
| 758 | 788 | } |
| 759 | 789 | return ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) ? |
| 760 | 790 | network_admin_url( $page ) : |
| 761 | 791 | admin_url( $page ); |
| @@ -761,8 +791,18 @@ | ||
| 761 | 791 | admin_url( $page ); |
| 762 | 792 | } |
| 763 | 793 | |
| 764 | 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 | +/** | |
| 765 | 805 | * Generate a common prefix to be used while generating a request ID. |
| 766 | 806 | * |
| 767 | 807 | * Uses the return of `get_index_prefix()` by default. |
| 768 | 808 | * |
| @@ -788,9 +828,9 @@ | ||
| 788 | 828 | * |
| 789 | 829 | * @since 4.5.0 |
| 790 | 830 | * @return string |
| 791 | 831 | */ |
| 792 | -function generate_request_id() : string { | |
| 832 | +function generate_request_id(): string { | |
| 793 | 833 | $uuid = str_replace( '-', '', wp_generate_uuid4() ); |
| 794 | 834 | |
| 795 | 835 | /** |
| 796 | 836 | * Filter the ID generated to identify a request. |
| @@ -809,9 +849,9 @@ | ||
| 809 | 849 | * @since 4.6.0 |
| 810 | 850 | * @param mixed $response The Elasticsearch response |
| 811 | 851 | * @return string |
| 812 | 852 | */ |
| 813 | -function get_elasticsearch_error_reason( $response ) : string { | |
| 853 | +function get_elasticsearch_error_reason( $response ): string { | |
| 814 | 854 | if ( is_string( $response ) ) { |
| 815 | 855 | return $response; |
| 816 | 856 | } |
| 817 | 857 | |
| @@ -826,10 +866,17 @@ | ||
| 826 | 866 | if ( ! empty( $response['result']['error'] ) && ! empty( $response['result']['error']['root_cause'][0]['reason'] ) ) { |
| 827 | 867 | return (string) $response['result']['error']['root_cause'][0]['reason']; |
| 828 | 868 | } |
| 829 | 869 | |
| 830 | - if ( ! empty( $response['result']['errors'] ) && ! empty( $response['result']['items'] ) && ! empty( $response['result']['items'][0]['index']['error']['reason'] ) ) { | |
| 831 | - 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; | |
| 832 | 879 | } |
| 833 | 880 | |
| 834 | 881 | return ''; |
| 835 | 882 | } |
| @@ -877,5 +924,56 @@ | ||
| 877 | 924 | if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { |
| 878 | 925 | return \delete_site_transient( $transient ); |
| 879 | 926 | } |
| 880 | 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' ) ); | |
| 881 | 979 | } |