PluginProbe
ElasticPress / 4.7.1
ElasticPress v4.7.1
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
elasticpress / includes / classes / Indexable / User / User.php

User.php in ElasticPress 4.7.1, at includes/classes/Indexable/User/User.php

916 lines 22.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * User indexable
4 *
5 * @since 3.0
6 * @package elasticpress
7 */
8
9 namespace ElasticPress\Indexable\User;
10
11 use ElasticPress\Indexable as Indexable;
12 use ElasticPress\Elasticsearch as Elasticsearch;
13 use \WP_User_Query as WP_User_Query;
14 use ElasticPress\Utils as Utils;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly.
18 }
19
20 /**
21 * User indexable class
22 */
23 class User extends Indexable {
24
25 /**
26 * We only need one user index
27 *
28 * @var boolean
29 * @since 3.0
30 */
31 public $global = true;
32
33 /**
34 * Indexable slug
35 *
36 * @var string
37 * @since 3.0
38 */
39 public $slug = 'user';
40
41 /**
42 * Create indexable and setup dependencies
43 *
44 * @since 3.0
45 */
46 public function __construct() {
47 $this->labels = [
48 'plural' => esc_html__( 'Users', 'elasticpress' ),
49 'singular' => esc_html__( 'User', 'elasticpress' ),
50 ];
51 }
52
53 /**
54 * Instantiate the indexable SyncManager and QueryIntegration, the main responsibles for the WP integration.
55 *
56 * @since 4.5.0
57 * @return void
58 */
59 public function setup() {
60 $this->sync_manager = new SyncManager( $this->slug );
61 $this->query_integration = new QueryIntegration( $this->slug );
62 }
63
64 /**
65 * Format query vars into ES query
66 *
67 * @param array $query_vars WP_User_Query args.
68 * @param WP_User_Query $query User query object
69 * @since 3.0
70 * @return array
71 */
72 public function format_args( $query_vars, $query ) {
73 global $wpdb;
74
75 /**
76 * Handle `number` query var
77 */
78 if ( ! empty( $query_vars['number'] ) ) {
79 $number = (int) $query_vars['number'];
80
81 // ES have a maximum size allowed so we have to convert "-1" to a maximum size.
82 if ( -1 === $number ) {
83 /**
84 * Set the maximum results window size.
85 *
86 * The request will return a HTTP 500 Internal Error if the size of the
87 * request is larger than the [index.max_result_window] parameter in ES.
88 * See the scroll api for a more efficient way to request large data sets.
89 *
90 * @return int The max results window size.
91 *
92 * @since 2.3.0
93 */
94
95 /**
96 * Filter max result size if set to -1
97 *
98 * @hook ep_max_results_window
99 * @param {int} $window Max result window
100 * @return {int} New window
101 */
102 $number = apply_filters( 'ep_max_results_window', 10000 );
103 }
104 } else {
105 /**
106 * Filter max result size if set to -1
107 *
108 * @hook ep_max_results_window
109 * @param {int} $window Max result window
110 * @return {int} New window
111 */
112 $number = apply_filters( 'ep_max_results_window', 10000 );
113 }
114
115 $formatted_args = [
116 'from' => 0,
117 'size' => $number,
118 ];
119
120 $filter = [
121 'bool' => [
122 'must' => [],
123 ],
124 ];
125
126 $use_filters = false;
127
128 /**
129 * Support `blog_id` query arg
130 */
131 $blog_id = false;
132 if ( isset( $query_vars['blog_id'] ) ) {
133 $blog_id = (int) $query_vars['blog_id'];
134 }
135
136 /**
137 * Support `role` query arg
138 */
139 if ( ! empty( $blog_id ) ) {
140 // If a blog id is set, we will apply at least one filter for roles.
141 $use_filters = true;
142
143 // If there are no specific roles named, make sure the user is a member of the site.
144 if ( empty( $query_vars['role'] ) && empty( $query_vars['role__in'] ) && empty( $query_vars['role__not_in'] ) ) {
145 $filter['bool']['must'][] = array(
146 'exists' => array(
147 'field' => 'capabilities.' . $blog_id . '.roles',
148 ),
149 );
150 /**
151 * EP versions prior to 4.1.0 set non-existent roles as `0`.
152 */
153 $filter['bool']['must_not'][] = array(
154 'term' => array(
155 'capabilities.' . $blog_id . '.roles' => 0,
156 ),
157 );
158 } elseif ( ! empty( $query_vars['role'] ) ) {
159 $roles = (array) $query_vars['role'];
160
161 foreach ( $roles as $role ) {
162 $filter['bool']['must'][] = array(
163 'terms' => array(
164 'capabilities.' . $blog_id . '.roles' => [
165 strtolower( $role ),
166 ],
167 ),
168 );
169 }
170 } else {
171 if ( ! empty( $query_vars['role__in'] ) ) {
172 $roles_in = (array) $query_vars['role__in'];
173
174 $roles_in = array_map( 'strtolower', $roles_in );
175
176 $filter['bool']['must'][] = array(
177 'terms' => array(
178 'capabilities.' . $blog_id . '.roles' => $roles_in,
179 ),
180 );
181 }
182
183 if ( ! empty( $query_vars['role__not_in'] ) ) {
184 $roles_not_in = (array) $query_vars['role__not_in'];
185
186 foreach ( $roles_not_in as $role ) {
187 $filter['bool']['must_not'][] = array(
188 'terms' => array(
189 'capabilities.' . $blog_id . '.roles' => [
190 strtolower( $role ),
191 ],
192 ),
193 );
194 }
195 }
196 }
197 }
198
199 $meta_queries = [];
200
201 /**
202 * Support `meta_key`, `meta_value`, and `meta_compare`
203 */
204 if ( ! empty( $query_vars['meta_key'] ) ) {
205 $meta_query_array = [
206 'key' => $query_vars['meta_key'],
207 ];
208
209 if ( isset( $query_vars['meta_value'] ) ) {
210 $meta_query_array['value'] = $query_vars['meta_value'];
211 }
212
213 if ( isset( $query_vars['meta_compare'] ) ) {
214 $meta_query_array['compare'] = $query_vars['meta_compare'];
215 }
216
217 $meta_queries[] = $meta_query_array;
218 }
219
220 /**
221 * 'meta_query' arg support.
222 */
223 if ( ! empty( $query_vars['meta_query'] ) ) {
224 $meta_queries = array_merge( $meta_queries, $query_vars['meta_query'] );
225 }
226
227 if ( ! empty( $meta_queries ) ) {
228 $filter['bool']['must'][] = $this->build_meta_query( $meta_queries );
229
230 $use_filters = true;
231 }
232
233 /**
234 * Support `fields` query var.
235 */
236 if ( isset( $query_vars['fields'] ) && 'all' !== $query_vars['fields'] && 'all_with_meta' !== $query_vars['fields'] ) {
237 $fields = (array) $query_vars['fields'];
238 $id_position = array_search( 'id', $fields, true );
239 if ( false !== $id_position ) {
240 $fields[ $id_position ] = 'ID';
241 }
242 $formatted_args['_source'] = [
243 'includes' => $fields,
244 ];
245 }
246
247 /**
248 * Support `nicename` query var
249 */
250 if ( ! empty( $query_vars['nicename'] ) ) {
251 $filter['bool']['must'][] = array(
252 'terms' => array(
253 'user_nicename' => [
254 $query_vars['nicename'],
255 ],
256 ),
257 );
258
259 $use_filters = true;
260 }
261
262 /**
263 * Support `nicename` query var
264 */
265 if ( ! empty( $query_vars['nicename__not_in'] ) ) {
266 $filter['bool']['must'][] = [
267 'bool' => [
268 'must_not' => [
269 [
270 'terms' => [
271 'user_nicename' => (array) $query_vars['nicename__not_in'],
272 ],
273 ],
274 ],
275 ],
276 ];
277
278 $use_filters = true;
279 }
280
281 /**
282 * Support `nicename__in` query var
283 */
284 if ( ! empty( $query_vars['nicename__in'] ) ) {
285 $filter['bool']['must'][] = array(
286 'terms' => array(
287 'user_nicename' => (array) $query_vars['nicename__in'],
288 ),
289 );
290
291 $use_filters = true;
292 }
293
294 /**
295 * Support `login` query var
296 */
297 if ( ! empty( $query_vars['login'] ) ) {
298 $filter['bool']['must'][] = array(
299 'terms' => array(
300 'user_login' => [
301 $query_vars['login'],
302 ],
303 ),
304 );
305
306 $use_filters = true;
307 }
308
309 /**
310 * Support `login__in` query var
311 */
312 if ( ! empty( $query_vars['login__in'] ) ) {
313 $filter['bool']['must'][] = array(
314 'terms' => array(
315 'user_login' => (array) $query_vars['login__in'],
316 ),
317 );
318
319 $use_filters = true;
320 }
321
322 /**
323 * Support `login__not_in` query var
324 */
325 if ( ! empty( $query_vars['login__not_in'] ) ) {
326 $filter['bool']['must'][] = [
327 'bool' => [
328 'must_not' => [
329 [
330 'terms' => [
331 'user_login' => (array) $query_vars['login__not_in'],
332 ],
333 ],
334 ],
335 ],
336 ];
337
338 $use_filters = true;
339 }
340
341 /**
342 * Handle `offset` and `paged` query vars. Paged takes priority if both are set.
343 */
344 if ( isset( $query_vars['offset'] ) ) {
345 $formatted_args['from'] = (int) $query_vars['offset'];
346 }
347
348 if ( isset( $query_vars['paged'] ) && $query_vars['paged'] > 1 ) {
349 $formatted_args['from'] = $number * ( $query_vars['paged'] - 1 );
350 }
351
352 /**
353 * Support `include` parameter
354 */
355 if ( ! empty( $query_vars['include'] ) ) {
356 $filter['bool']['must'][] = [
357 'bool' => [
358 'must' => [
359 'terms' => [
360 'ID' => array_values( (array) $query_vars['include'] ),
361 ],
362 ],
363 ],
364 ];
365
366 $use_filters = true;
367 }
368
369 /**
370 * Support `exclude` parameter
371 */
372 if ( ! empty( $query_vars['exclude'] ) ) {
373 $filter['bool']['must'][] = [
374 'bool' => [
375 'must_not' => [
376 'terms' => [
377 'ID' => array_values( (array) $query_vars['exclude'] ),
378 ],
379 ],
380 ],
381 ];
382
383 $use_filters = true;
384 }
385
386 /**
387 * Need to support a few more params
388 *
389 * @todo Support the following parameters:
390 *
391 * $who
392 * $has_published_posts
393 */
394
395 /**
396 * Handle `search` query_var
397 */
398 if ( ! empty( $query_vars['search'] ) ) {
399
400 /**
401 * Remove *'s from beginning and end of user search string'
402 *
403 * @hook ep_user_search_remove_wildcards
404 * @param {boolean} $remove True to remove
405 * @param {array} $query Current query
406 * @param {array} $query_vars Query variables
407 * @since 3.4
408 * @return {boolean}
409 */
410 if ( apply_filters( 'ep_user_search_remove_wildcards', true, $query, $query_vars ) ) {
411 $query_vars['search'] = trim( $query_vars['search'], '*' );
412 }
413
414 $search_fields = ( ! empty( $query_vars['search_columns'] ) ) ? $query_vars['search_columns'] : [];
415
416 if ( ! empty( $query_vars['search_fields'] ) ) {
417 $search_fields = array_merge( $search_fields, $query_vars['search_fields'] );
418 }
419
420 /**
421 * Handle `search_fields` query var and `search_columns`. search_columns is a bit too
422 * simplistic for our needs since we want to be able to search meta too. We just merge
423 * search columns into search_fields. search_fields overwrites search_columns.
424 */
425 if ( ! empty( $search_fields ) ) {
426 $prepared_search_fields = [];
427
428 // WP_User_Query uses shortened column names so we need to expand those.
429 if ( ! empty( $search_fields['login'] ) ) {
430 $prepared_search_fields['user_login'] = $search_fields['login'];
431
432 unset( $search_fields['login'] );
433 }
434
435 if ( ! empty( $search_fields['url'] ) ) {
436 $prepared_search_fields['user_url'] = $search_fields['url'];
437
438 unset( $search_fields['url'] );
439 }
440
441 if ( ! empty( $search_fields['nicename'] ) ) {
442 $prepared_search_fields['user_nicename'] = $search_fields['nicename'];
443
444 unset( $search_fields['nicename'] );
445 }
446
447 if ( ! empty( $search_fields['email'] ) ) {
448 $prepared_search_fields['user_email'] = $search_fields['email'];
449
450 unset( $search_fields['email'] );
451 }
452
453 if ( ! empty( $search_fields['meta'] ) ) {
454 $metas = (array) $search_fields['meta'];
455
456 foreach ( $metas as $meta ) {
457 $prepared_search_fields[] = 'meta.' . $meta . '.value';
458 }
459
460 unset( $search_fields['meta'] );
461 }
462
463 $prepared_search_fields = array_merge( $search_fields, $prepared_search_fields );
464 } else {
465 $prepared_search_fields = [
466 'user_login',
467 'user_nicename',
468 'display_name',
469 'user_url',
470 'user_email',
471 'meta.first_name',
472 'meta.last_name',
473 'meta.nickname',
474 ];
475 }
476
477 /**
478 * Filter search fields in user query
479 *
480 * @hook ep_user_search_fields
481 * @param {array} $prepared_search_fields Prepared search fields
482 * @param {array} $query_vars Query variables
483 * @since 3.0
484 * @return {array} Search fields
485 */
486 $prepared_search_fields = apply_filters( 'ep_user_search_fields', $prepared_search_fields, $query_vars );
487
488 $search_algorithm = $this->get_search_algorithm( $query_vars['search'], $prepared_search_fields, $query_vars );
489 $formatted_args['query'] = $search_algorithm->get_query( 'user', $query_vars['search'], $prepared_search_fields, $query_vars );
490 } else {
491 $formatted_args['query']['match_all'] = [
492 'boost' => 1,
493 ];
494 }
495
496 if ( $use_filters ) {
497 $formatted_args['post_filter'] = $filter;
498 }
499
500 /**
501 * Handle order and orderby
502 */
503 if ( ! empty( $query_vars['order'] ) ) {
504 $order = trim( strtolower( $query_vars['order'] ) );
505 } else {
506 $order = 'desc';
507 }
508
509 if ( empty( $query_vars['orderby'] ) && ( ! isset( $query_vars['search'] ) || '' === $query_vars['search'] ) ) {
510 $query_vars['orderby'] = 'user_login';
511 }
512
513 // Set sort type.
514 if ( ! empty( $query_vars['orderby'] ) ) {
515 $formatted_args['sort'] = $this->parse_orderby( $query_vars['orderby'], $order, $query_vars );
516 } else {
517 // Default sort is to use the score (based on relevance).
518 $formatted_args['sort'] = array(
519 array(
520 '_score' => array(
521 'order' => $order,
522 ),
523 ),
524 );
525 }
526
527 /**
528 * Filter formatted Elasticsearch user query (entire query)
529 *
530 * @hook ep_user_formatted_args_query
531 * @param {array} $formatted_args Formatted Elasticsearch query
532 * @param {array} $query_vars Query variables
533 * @param {array} $query Query part
534 * @since 3.0
535 * @return {array} New query
536 */
537 return apply_filters( 'ep_user_formatted_args', $formatted_args, $query_vars, $query );
538 }
539
540 /**
541 * Convert the alias to a properly-prefixed sort value.
542 *
543 * @since 3.0
544 * @param string $orderby Orderby query var
545 * @param string $default_order Order direction
546 * @param array $query_vars Query vars
547 * @return array
548 */
549 public function parse_orderby( $orderby, $default_order, $query_vars ) {
550 /**
551 * More params to support
552 *
553 * @todo Need to support:
554 *
555 * include
556 * login__in
557 * nicename__in
558 * post_count
559 */
560
561 if ( ! is_array( $orderby ) ) {
562 $orderby = explode( ' ', $orderby );
563 }
564
565 $from_to = [
566 'relevance' => '_score',
567 'user_login' => 'user_login.raw',
568 'login' => 'user_login.raw',
569 'id' => 'ID',
570 'display_name' => 'display_name.sortable',
571 'name' => 'display_name.sortable',
572 'nicename' => 'user_nicename.raw',
573 'user_nicename' => 'user_nicename.raw',
574 'user_email' => 'user_email.raw',
575 'email' => 'user_email.raw',
576 'user_url' => 'user_url.raw',
577 'url' => 'user_url.raw',
578 'registered' => 'user_registered',
579 ];
580
581 $sort = [];
582
583 if ( empty( $orderby ) ) {
584 return $sort;
585 }
586
587 $unsupported_clauses = [ 'rand', 'include', 'login__in', 'nicename__in', 'post_count' ];
588
589 foreach ( $orderby as $key => $value ) {
590 if ( is_string( $key ) ) {
591 $orderby_clause = $key;
592 $order = $value;
593 } else {
594 $orderby_clause = $value;
595 $order = $default_order;
596 }
597
598 if ( empty( $orderby_clause ) || in_array( $orderby_clause, $unsupported_clauses, true ) ) {
599 continue;
600 }
601
602 if ( in_array( $orderby_clause, [ 'meta_value', 'meta_value_num' ], true ) ) {
603 if ( empty( $args['meta_key'] ) ) {
604 continue;
605 } else {
606 $from_to['meta_value'] = 'meta.' . $args['meta_key'] . '.raw';
607 $from_to['meta_value_num'] = 'meta.' . $args['meta_key'] . '.long';
608 }
609 }
610
611 $orderby_clause = $from_to[ $orderby_clause ] ?? $orderby_clause;
612
613 $sort[] = array(
614 $orderby_clause => array(
615 'order' => $order,
616 ),
617 );
618 }
619
620 return $sort;
621 }
622
623 /**
624 * Query DB for users
625 *
626 * @param array $args Query arguments
627 * @since 3.0
628 * @return array
629 */
630 public function query_db( $args ) {
631 global $wpdb;
632
633 $defaults = [
634 'number' => 350,
635 'offset' => 0,
636 'orderby' => 'ID',
637 'order' => 'desc',
638 ];
639
640 if ( isset( $args['per_page'] ) ) {
641 $args['number'] = $args['per_page'];
642 }
643
644 /**
645 * Filter query database arguments for user indexable
646 *
647 * @hook ep_user_query_db_args
648 * @param {array} $args Database query arguments
649 * @since 3.0
650 * @return {array} New arguments
651 */
652 $args = apply_filters( 'ep_user_query_db_args', wp_parse_args( $args, $defaults ) );
653
654 $args['order'] = trim( strtolower( $args['order'] ) );
655
656 if ( ! in_array( $args['order'], [ 'asc', 'desc' ], true ) ) {
657 $args['order'] = 'desc';
658 }
659
660 $orderby_args = sanitize_sql_orderby( "{$args['orderby']} {$args['order']}" );
661 $orderby = $orderby_args ? sprintf( 'ORDER BY %s', $orderby_args ) : '';
662
663 /**
664 * WP_User_Query doesn't let us get users across all blogs easily. This is the best
665 * way to do that.
666 */
667 // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery
668 $objects = $wpdb->get_results(
669 $wpdb->prepare(
670 "SELECT SQL_CALC_FOUND_ROWS ID FROM {$wpdb->users} {$orderby} LIMIT %d, %d",
671 (int) $args['offset'],
672 (int) $args['number']
673 )
674 );
675
676 return [
677 'objects' => $objects,
678 'total_objects' => ( 0 === count( $objects ) ) ? 0 : (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' ),
679 ];
680 // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery
681 }
682
683 /**
684 * Generate the mapping array
685 *
686 * @since 3.6.0
687 * @return array
688 */
689 public function generate_mapping() {
690 $es_version = Elasticsearch::factory()->get_elasticsearch_version();
691 if ( empty( $es_version ) ) {
692 /**
693 * Filter fallback Elasticsearch version
694 *
695 * @hook ep_fallback_elasticsearch_version
696 * @param {string} $version Fall back Elasticsearch version
697 * @return {string} New version
698 */
699 $es_version = apply_filters( 'ep_fallback_elasticsearch_version', '2.0' );
700 }
701 $es_version = (string) $es_version;
702
703 $mapping_file = 'initial.php';
704
705 if ( version_compare( $es_version, '5.0', '<' ) ) {
706 $mapping_file = 'pre-5-0.php';
707 } elseif ( version_compare( $es_version, '7.0', '>=' ) ) {
708 $mapping_file = '7-0.php';
709 }
710
711 /**
712 * Filter user indexable mapping file
713 *
714 * @hook ep_user_mapping_file
715 * @param {string} $file Path to file
716 * @since 3.0
717 * @return {string} New file path
718 */
719 $mapping = require apply_filters( 'ep_user_mapping_file', __DIR__ . '/../../../mappings/user/' . $mapping_file );
720
721 /**
722 * Filter user indexable mapping
723 *
724 * @hook ep_user_mapping
725 * @param {array} $mapping Mapping
726 * @since 3.0
727 * @return {array} New mapping
728 */
729 $mapping = apply_filters( 'ep_user_mapping', $mapping );
730
731 return $mapping;
732 }
733
734 /**
735 * Prepare a user document for indexing
736 *
737 * @param int $user_id User id
738 * @since 3.0
739 * @return array
740 */
741 public function prepare_document( $user_id ) {
742 $user = get_user_by( 'ID', $user_id );
743
744 if ( empty( $user ) ) {
745 return false;
746 }
747
748 $user_args = [
749 'ID' => $user_id,
750 'user_login' => $user->user_login,
751 'user_email' => $user->user_email,
752 'user_nicename' => $user->user_nicename,
753 'spam' => $user->spam,
754 'deleted' => $user->spam,
755 'user_status' => $user->user_status,
756 'display_name' => $user->display_name,
757 'user_registered' => $user->user_registered,
758 'user_url' => $user->user_url,
759 'capabilities' => $this->prepare_capabilities( $user_id ),
760 'meta' => $this->prepare_meta_types( $this->prepare_meta( $user_id ) ),
761 ];
762
763 /**
764 * Filter prepared user document before index
765 *
766 * @hook ep_user_sync_args
767 * @param {array} $user_args Document
768 * @param {int} $user_id User ID
769 * @since 3.0
770 * @return {array} New document
771 */
772 $user_args = apply_filters( 'ep_user_sync_args', $user_args, $user_id );
773
774 return $user_args;
775 }
776
777 /**
778 * Prepare capabilities for indexing
779 *
780 * @param int $user_id User ID
781 * @since 3.0
782 * @return array
783 */
784 public function prepare_capabilities( $user_id ) {
785 global $wpdb;
786
787 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
788 $sites = Utils\get_sites();
789 } else {
790 $sites = [
791 [
792 'blog_id' => (int) get_current_blog_id(),
793 ],
794 ];
795 }
796
797 $prepared_roles = [];
798
799 foreach ( $sites as $site ) {
800 $roles = (array) get_user_meta( $user_id, $wpdb->get_blog_prefix( $site['blog_id'] ) . 'capabilities', true );
801
802 if ( ! empty( $roles ) ) {
803 $prepared_roles[ (int) $site['blog_id'] ] = [
804 'roles' => array_keys( (array) $roles ),
805 ];
806 }
807 }
808
809 return $prepared_roles;
810 }
811
812 /**
813 * Prepare meta to send to ES
814 *
815 * @param int $user_id User id
816 * @since 3.0
817 * @return array
818 */
819 public function prepare_meta( $user_id ) {
820 /**
821 * Filter pre-prepare meta for a user
822 *
823 * @hook ep_prepare_user_meta_data
824 * @param {array} $meta Meta data
825 * @param {int} $user_id User ID
826 * @return {array} New meta
827 */
828 $meta = apply_filters( 'ep_prepare_user_meta_data', (array) get_user_meta( $user_id ), $user_id );
829
830 if ( empty( $meta ) ) {
831 /**
832 * Filter final list of prepared user meta.
833 *
834 * @hook ep_prepared_user_meta
835 * @param {array} $prepared_meta Prepared meta
836 * @param {integer} $user_id User ID
837 * @since 3.4
838 * @return {array} Prepared meta
839 */
840 return apply_filters( 'ep_prepared_user_meta', [], $user_id );
841 }
842
843 $prepared_meta = [];
844
845 /**
846 * Filter indexable private meta for users
847 *
848 * @hook ep_prepare_user_meta_allowed_protected_keys
849 * @param {array} $meta Meta keys
850 * @param {int} $user_id User ID
851 * @since 3.0
852 * @return {array} New meta array
853 */
854 $allowed_protected_keys = apply_filters( 'ep_prepare_user_meta_allowed_protected_keys', [], $user_id );
855
856 /**
857 * Filter out excluded indexable public meta keys for users
858 *
859 * @hook ep_prepare_user_meta_excluded_public_keys
860 * @param {array} $meta Meta keys
861 * @param {int} $user_id User ID
862 * @since 3.0
863 * @return {array} New meta array
864 */
865 $excluded_public_keys = apply_filters(
866 'ep_prepare_user_meta_excluded_public_keys',
867 [
868 'session_tokens',
869 ],
870 $user_id
871 );
872
873 foreach ( $meta as $key => $value ) {
874
875 $allow_index = false;
876
877 if ( is_protected_meta( $key ) ) {
878
879 if ( true === $allowed_protected_keys || in_array( $key, $allowed_protected_keys, true ) ) {
880 $allow_index = true;
881 }
882 } else {
883
884 if ( true !== $excluded_public_keys && ! in_array( $key, $excluded_public_keys, true ) ) {
885 $allow_index = true;
886 }
887 }
888
889 /**
890 * Filter whether to whitelist a specific user meta key
891 *
892 * @hookep_prepare_user_meta_whitelist_key
893 * @param {bool} $index True to force index
894 * @param {string} $key User meta key
895 * @param {int} $user_id User ID
896 * @since 3.0
897 * @return {bool} New index value
898 */
899 if ( true === $allow_index || apply_filters( 'ep_prepare_user_meta_whitelist_key', false, $key, $user_id ) ) {
900 $prepared_meta[ $key ] = maybe_unserialize( $value );
901 }
902 }
903
904 /**
905 * Filter final list of prepared user meta.
906 *
907 * @hook ep_prepared_user_meta
908 * @param {array} $prepared_meta Prepared meta
909 * @param {integer} $user_id User ID
910 * @since 3.4
911 * @return {array} Prepared meta
912 */
913 return apply_filters( 'ep_prepared_user_meta', $prepared_meta, $user_id );
914 }
915 }
916