PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.1-beta5
Secure Custom Fields v6.4.1-beta5
6.9.5 6.9.4 6.9.3 6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / fields / class-acf-field-user.php
secure-custom-fields / includes / fields Last commit date
class-acf-field-accordion.php 1 year ago class-acf-field-button-group.php 1 year ago class-acf-field-checkbox.php 1 year ago class-acf-field-clone.php 1 year ago class-acf-field-color_picker.php 1 year ago class-acf-field-date_picker.php 1 year ago class-acf-field-date_time_picker.php 1 year ago class-acf-field-email.php 1 year ago class-acf-field-file.php 1 year ago class-acf-field-flexible-content.php 1 year ago class-acf-field-gallery.php 1 year ago class-acf-field-google-map.php 1 year ago class-acf-field-group.php 1 year ago class-acf-field-icon_picker.php 1 year ago class-acf-field-image.php 1 year ago class-acf-field-link.php 1 year ago class-acf-field-message.php 1 year ago class-acf-field-number.php 1 year ago class-acf-field-oembed.php 1 year ago class-acf-field-output.php 1 year ago class-acf-field-page_link.php 1 year ago class-acf-field-password.php 1 year ago class-acf-field-post_object.php 1 year ago class-acf-field-radio.php 1 year ago class-acf-field-range.php 1 year ago class-acf-field-relationship.php 1 year ago class-acf-field-repeater.php 1 year ago class-acf-field-select.php 1 year ago class-acf-field-separator.php 1 year ago class-acf-field-tab.php 1 year ago class-acf-field-taxonomy.php 1 year ago class-acf-field-text.php 1 year ago class-acf-field-textarea.php 1 year ago class-acf-field-time_picker.php 1 year ago class-acf-field-true_false.php 1 year ago class-acf-field-url.php 1 year ago class-acf-field-user.php 1 year ago class-acf-field-wysiwyg.php 1 year ago class-acf-field.php 1 year ago class-acf-repeater-table.php 1 year ago index.php 1 year ago
class-acf-field-user.php
664 lines
1 <?php
2
3 if ( ! class_exists( 'ACF_Field_User' ) ) :
4
5 class ACF_Field_User extends ACF_Field {
6
7
8 /**
9 * Initializes the field type.
10 *
11 * @date 5/03/2014
12 * @since ACF 5.0.0
13 */
14 function initialize() {
15 $this->name = 'user';
16 $this->label = __( 'User', 'secure-custom-fields' );
17 $this->category = 'relational';
18 $this->description = __( 'Allows the selection of one or more users which can be used to create relationships between data objects.', 'secure-custom-fields' );
19 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-user.png';
20 $this->doc_url = 'https://www.advancedcustomfields.com/resources/user/';
21 $this->defaults = array(
22 'role' => '',
23 'multiple' => 0,
24 'allow_null' => 0,
25 'return_format' => 'array',
26 'bidirectional_target' => array(),
27 );
28
29 // Register filter variations.
30 acf_add_filter_variations( 'acf/fields/user/query', array( 'name', 'key' ), 1 );
31 acf_add_filter_variations( 'acf/fields/user/result', array( 'name', 'key' ), 2 );
32 acf_add_filter_variations( 'acf/fields/user/search_columns', array( 'name', 'key' ), 3 );
33 add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_user_conditional_choices' ), 10, 3 );
34
35 // Add AJAX query.
36 add_action( 'wp_ajax_acf/fields/user/query', array( $this, 'ajax_query' ) );
37 add_action( 'wp_ajax_nopriv_acf/fields/user/query', array( $this, 'ajax_query' ) );
38 }
39
40 /**
41 * Filters choices in user conditions.
42 *
43 * @since ACF 6.3
44 *
45 * @param array $choices The selected choice.
46 * @param array $conditional_field The conditional field settings object.
47 * @param string $rule_value The rule value.
48 * @return array
49 */
50 public function render_field_user_conditional_choices( $choices, $conditional_field, $rule_value ) {
51 if ( ! is_array( $conditional_field ) || $conditional_field['type'] !== 'user' ) {
52 return $choices;
53 }
54 if ( ! empty( $rule_value ) ) {
55 $user = acf_get_users(
56 array(
57 'include' => array( $rule_value ),
58 )
59 );
60
61 $user_result = acf_get_user_result( $user[0] );
62 $choices = array( $user_result['id'] => $user_result['text'] );
63 }
64
65 return $choices;
66 }
67
68 /**
69 * Renders the field settings HTML.
70 *
71 * @date 23/01/13
72 * @since ACF 3.6.0
73 *
74 * @param array $field The ACF field.
75 * @return void
76 */
77 function render_field_settings( $field ) {
78 acf_render_field_setting(
79 $field,
80 array(
81 'label' => __( 'Filter by Role', 'secure-custom-fields' ),
82 'instructions' => '',
83 'type' => 'select',
84 'name' => 'role',
85 'choices' => acf_get_user_role_labels(),
86 'multiple' => 1,
87 'ui' => 1,
88 'allow_null' => 1,
89 'placeholder' => __( 'All user roles', 'secure-custom-fields' ),
90 )
91 );
92
93 acf_render_field_setting(
94 $field,
95 array(
96 'label' => __( 'Return Format', 'secure-custom-fields' ),
97 'instructions' => '',
98 'type' => 'radio',
99 'name' => 'return_format',
100 'choices' => array(
101 'array' => __( 'User Array', 'secure-custom-fields' ),
102 'object' => __( 'User Object', 'secure-custom-fields' ),
103 'id' => __( 'User ID', 'secure-custom-fields' ),
104 ),
105 'layout' => 'horizontal',
106 )
107 );
108
109 acf_render_field_setting(
110 $field,
111 array(
112 'label' => __( 'Select Multiple', 'secure-custom-fields' ),
113 'instructions' => 'Allow content editors to select multiple values',
114 'name' => 'multiple',
115 'type' => 'true_false',
116 'ui' => 1,
117 )
118 );
119 }
120
121 /**
122 * Renders the field settings used in the "Validation" tab.
123 *
124 * @since ACF 6.0
125 *
126 * @param array $field The field settings array.
127 * @return void
128 */
129 function render_field_validation_settings( $field ) {
130 acf_render_field_setting(
131 $field,
132 array(
133 'label' => __( 'Allow Null', 'secure-custom-fields' ),
134 'instructions' => '',
135 'name' => 'allow_null',
136 'type' => 'true_false',
137 'ui' => 1,
138 )
139 );
140 }
141
142 /**
143 * Renders the field settings used in the "Advanced" tab.
144 *
145 * @since ACF 6.2
146 *
147 * @param array $field The field settings array.
148 * @return void
149 */
150 public function render_field_advanced_settings( $field ) {
151 acf_render_bidirectional_field_settings( $field );
152 }
153
154 /**
155 * Renders the field input HTML.
156 *
157 * @since ACF 3.6.0
158 *
159 * @param array $field The ACF field.
160 * @return void
161 */
162 public function render_field( $field ) {
163 // Change Field into a select.
164 $field['type'] = 'select';
165 $field['ui'] = 1;
166 $field['ajax'] = 1;
167 $field['choices'] = array();
168 $field['nonce'] = wp_create_nonce( $field['key'] );
169
170 // Populate choices.
171 if ( $field['value'] ) {
172
173 // Clean value into an array of IDs.
174 $user_ids = array_map( 'intval', acf_array( $field['value'] ) );
175
176 // Find users in database (ensures all results are real).
177 $users = acf_get_users(
178 array(
179 'include' => $user_ids,
180 )
181 );
182
183 // Append.
184 if ( $users ) {
185 foreach ( $users as $user ) {
186 $field['choices'][ $user->ID ] = $this->get_result( $user, $field );
187 }
188 }
189 }
190
191 // Render.
192 acf_render_field( $field );
193 }
194
195 /**
196 * Returns the result text for a given WP_User object.
197 *
198 * @date 1/11/2013
199 * @since ACF 5.0.0
200 *
201 * @param WP_User $user The WP_User object.
202 * @param array $field The ACF field related to this query.
203 * @param (int|string) $post_id The post_id being edited.
204 * @return string
205 */
206 function get_result( $user, $field, $post_id = 0 ) {
207
208 // Get user result item.
209 $item = acf_get_user_result( $user );
210
211 // Default $post_id to current post being edited.
212 $post_id = $post_id ? $post_id : acf_get_form_data( 'post_id' );
213
214 /**
215 * Filters the result text.
216 *
217 * @date 21/5/19
218 * @since ACF 5.8.1
219 *
220 * @param array $args The query args.
221 * @param array $field The ACF field related to this query.
222 * @param (int|string) $post_id The post_id being edited.
223 */
224 return apply_filters( 'acf/fields/user/result', $item['text'], $user, $field, $post_id );
225 }
226
227 /**
228 * Filters the field value after it is loaded from the database.
229 *
230 * @date 23/01/13
231 * @since ACF 3.6.0
232 *
233 * @param mixed $value The field value.
234 * @param mixed $post_id The post ID where the value is saved.
235 * @param array $field The field array containing all settings.
236 * @return mixed
237 */
238 function load_value( $value, $post_id, $field ) {
239
240 // Add compatibility for version 4.
241 if ( $value === 'null' ) {
242 return false;
243 }
244 return $value;
245 }
246
247 /**
248 * Filters the field value after it is loaded from the database but before it is returned to the front-end API.
249 *
250 * @date 23/01/13
251 * @since ACF 3.6.0
252 *
253 * @param mixed $value The field value.
254 * @param mixed $post_id The post ID where the value is saved.
255 * @param array $field The field array containing all settings.
256 * @return mixed
257 */
258 function format_value( $value, $post_id, $field ) {
259
260 // Bail early if no value.
261 if ( ! $value ) {
262 return false;
263 }
264
265 // Clean value into an array of IDs.
266 $user_ids = array_map( 'intval', acf_array( $value ) );
267
268 // Find users in database (ensures all results are real).
269 $users = acf_get_users(
270 array(
271 'include' => $user_ids,
272 )
273 );
274
275 // Bail early if no users found.
276 if ( ! $users ) {
277 return false;
278 }
279
280 // Format values using field settings.
281 $value = array();
282 foreach ( $users as $user ) {
283
284 // Return object.
285 if ( $field['return_format'] == 'object' ) {
286 $item = $user;
287
288 // Return array.
289 } elseif ( $field['return_format'] == 'array' ) {
290 $item = array(
291 'ID' => $user->ID,
292 'user_firstname' => $user->user_firstname,
293 'user_lastname' => $user->user_lastname,
294 'nickname' => $user->nickname,
295 'user_nicename' => $user->user_nicename,
296 'display_name' => $user->display_name,
297 'user_email' => $user->user_email,
298 'user_url' => $user->user_url,
299 'user_registered' => $user->user_registered,
300 'user_description' => $user->user_description,
301 'user_avatar' => get_avatar( $user->ID ),
302 );
303
304 // Return ID.
305 } else {
306 $item = $user->ID;
307 }
308
309 // Append item
310 $value[] = $item;
311 }
312
313 // Convert to single.
314 if ( ! $field['multiple'] ) {
315 $value = array_shift( $value );
316 }
317
318 // Return.
319 return $value;
320 }
321
322 /**
323 * Filters the field value before it is saved into the database.
324 *
325 * @since ACF 3.6.0
326 *
327 * @param mixed $value The field value.
328 * @param mixed $post_id The post ID where the value is saved.
329 * @param array $field The field array containing all settings.
330 * @return mixed $value The modified value.
331 */
332 public function update_value( $value, $post_id, $field ) {
333
334 // Bail early if no value.
335 if ( empty( $value ) ) {
336 acf_update_bidirectional_values( array(), $post_id, $field, 'user' );
337 return $value;
338 }
339
340 // Format array of values.
341 // - ensure each value is an id.
342 // - Parse each id as string for SQL LIKE queries.
343 if ( acf_is_sequential_array( $value ) ) {
344 $value = array_map( 'acf_idval', $value );
345 $value = array_map( 'strval', $value );
346
347 // Parse single value for id.
348 } else {
349 $value = acf_idval( $value );
350 }
351
352 acf_update_bidirectional_values( acf_get_array( $value ), $post_id, $field, 'user' );
353
354 // Return value.
355 return $value;
356 }
357
358 /**
359 * Callback for the AJAX query request.
360 *
361 * @date 24/10/13
362 * @since ACF 5.0.0
363 *
364 * @return void
365 */
366 function ajax_query() {
367
368 // phpcs:disable WordPress.Security.NonceVerification.Recommended
369 // Modify Request args.
370 if ( isset( $_REQUEST['s'] ) ) {
371 $_REQUEST['search'] = sanitize_text_field( $_REQUEST['s'] );
372 }
373 if ( isset( $_REQUEST['paged'] ) ) {
374 $_REQUEST['page'] = absint( $_REQUEST['paged'] );
375 }
376 // phpcs:enable WordPress.Security.NonceVerification.Recommended
377
378 // Add query hooks.
379 add_action( 'acf/ajax/query_users/init', array( $this, 'ajax_query_init' ), 10, 2 );
380 add_filter( 'acf/ajax/query_users/args', array( $this, 'ajax_query_args' ), 10, 3 );
381 add_filter( 'acf/ajax/query_users/result', array( $this, 'ajax_query_result' ), 10, 3 );
382 add_filter( 'acf/ajax/query_users/search_columns', array( $this, 'ajax_query_search_columns' ), 10, 4 );
383 // Simulate AJAX request.
384 acf_get_instance( 'ACF_Ajax_Query_Users' )->request();
385 }
386
387 /**
388 * Runs during the AJAX query initialization.
389 *
390 * @date 9/3/20
391 * @since ACF 5.8.8
392 *
393 * @param array $request The query request.
394 * @param ACF_Ajax_Query $query The query object.
395 * @return void
396 */
397 function ajax_query_init( $request, $query ) {
398 // Require field and make sure it's a user field.
399 if ( ! $query->field || $query->field['type'] !== $this->name ) {
400 $query->send( new WP_Error( 'acf_missing_field', __( 'Error loading field.', 'secure-custom-fields' ), array( 'status' => 404 ) ) );
401 }
402
403 // Verify that this is a legitimate request using a separate nonce from the main AJAX nonce.
404 $nonce = acf_request_arg( 'nonce', '' );
405 $key = acf_request_arg( 'field_key', '' );
406
407 if ( ! acf_verify_ajax( $nonce, $key ) ) {
408 $query->send( new WP_Error( 'acf_invalid_request', __( 'Invalid request.', 'secure-custom-fields' ), array( 'status' => 404 ) ) );
409 }
410 }
411
412 /**
413 * Filters the AJAX query args.
414 *
415 * @date 9/3/20
416 * @since ACF 5.8.8
417 *
418 * @param array $args The query args.
419 * @param array $request The query request.
420 * @param ACF_Ajax_Query $query The query object.
421 * @return array
422 */
423 function ajax_query_args( $args, $request, $query ) {
424
425 // Add specific roles.
426 if ( $query->field['role'] ) {
427 $args['role__in'] = acf_array( $query->field['role'] );
428 }
429
430 /**
431 * Filters the query args.
432 *
433 * @date 21/5/19
434 * @since ACF 5.8.1
435 *
436 * @param array $args The query args.
437 * @param array $field The ACF field related to this query.
438 * @param (int|string) $post_id The post_id being edited.
439 */
440 return apply_filters( 'acf/fields/user/query', $args, $query->field, $query->post_id );
441 }
442
443 /**
444 * Filters the WP_User_Query search columns.
445 *
446 * @date 9/3/20
447 * @since ACF 5.8.8
448 *
449 * @param array $columns An array of column names to be searched.
450 * @param string $search The search term.
451 * @param WP_User_Query $WP_User_Query The WP_User_Query instance.
452 * @return array
453 */
454 function ajax_query_search_columns( $columns, $search, $WP_User_Query, $query ) {
455
456 /**
457 * Filters the column names to be searched.
458 *
459 * @date 21/5/19
460 * @since ACF 5.8.1
461 *
462 * @param array $columns An array of column names to be searched.
463 * @param string $search The search term.
464 * @param WP_User_Query $WP_User_Query The WP_User_Query instance.
465 * @param array $field The ACF field related to this query.
466 */
467 return apply_filters( 'acf/fields/user/search_columns', $columns, $search, $WP_User_Query, $query->field );
468 }
469
470 /**
471 * Filters the AJAX Query result.
472 *
473 * @date 9/3/20
474 * @since ACF 5.8.8
475 *
476 * @param array $item The choice id and text.
477 * @param WP_User $user The user object.
478 * @param ACF_Ajax_Query $query The query object.
479 * @return array
480 */
481 function ajax_query_result( $item, $user, $query ) {
482
483 /**
484 * Filters the result text.
485 *
486 * @date 21/5/19
487 * @since ACF 5.8.1
488 *
489 * @param string The result text.
490 * @param WP_User $user The user object.
491 * @param array $field The ACF field related to this query.
492 * @param (int|string) $post_id The post_id being edited.
493 */
494 $item['text'] = apply_filters( 'acf/fields/user/result', $item['text'], $user, $query->field, $query->post_id );
495 return $item;
496 }
497
498 /**
499 * Return an array of data formatted for use in a select2 AJAX response.
500 *
501 * @date 15/10/2014
502 * @since ACF 5.0.9
503 * @deprecated 5.8.9
504 *
505 * @param array $args An array of query args.
506 * @return array
507 */
508 function get_ajax_query( $options = array() ) {
509 _deprecated_function( __FUNCTION__, '5.8.9' );
510 return array();
511 }
512
513 /**
514 * Filters the WP_User_Query search columns.
515 *
516 * @date 15/10/2014
517 * @since ACF 5.0.9
518 * @deprecated 5.8.9
519 *
520 * @param array $columns An array of column names to be searched.
521 * @param string $search The search term.
522 * @param WP_User_Query $WP_User_Query The WP_User_Query instance.
523 * @return array
524 */
525 function user_search_columns( $columns, $search, $WP_User_Query ) {
526 _deprecated_function( __FUNCTION__, '5.8.9' );
527 return $columns;
528 }
529
530 /**
531 * Validates user fields updated via the REST API.
532 *
533 * @param boolean $valid The current validity booleean
534 * @param integer $value The value of the field
535 * @param array $field The field array
536 * @return boolean|WP_Error
537 */
538 public function validate_rest_value( $valid, $value, $field ) {
539 if ( is_null( $value ) ) {
540 return $valid;
541 }
542
543 $param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
544 $data = array( 'param' => $param );
545 $value = is_array( $value ) ? $value : array( $value );
546
547 $invalid_users = array();
548 $insufficient_roles = array();
549
550 foreach ( $value as $user_id ) {
551 $user_data = get_userdata( $user_id );
552 if ( ! $user_data ) {
553 $invalid_users[] = $user_id;
554 continue;
555 }
556
557 if ( empty( $field['role'] ) ) {
558 continue;
559 }
560
561 $has_roles = count( array_intersect( $field['role'], $user_data->roles ) );
562 if ( ! $has_roles ) {
563 $insufficient_roles[] = $user_id;
564 }
565 }
566
567 if ( count( $invalid_users ) ) {
568 $error = sprintf(
569 /* translators: %s: field value */
570 __( '%1$s must have a valid user ID.', 'secure-custom-fields' ),
571 $param
572 );
573 $data['value'] = $invalid_users;
574 return new WP_Error( 'rest_invalid_param', $error, $data );
575 }
576
577 if ( count( $insufficient_roles ) ) {
578 $error = sprintf(
579 /* translators: 1: field name, 2: role name */
580 _n(
581 '%1$s must have a user with the %2$s role.',
582 '%1$s must have a user with one of the following roles: %2$s',
583 count( $field['role'] ),
584 'secure-custom-fields'
585 ),
586 $param,
587 count( $field['role'] ) > 1 ? implode( ', ', $field['role'] ) : $field['role'][0]
588 );
589 $data['value'] = $insufficient_roles;
590 return new WP_Error( 'rest_invalid_param', $error, $data );
591 }
592
593 return $valid;
594 }
595
596 /**
597 * Return the schema array for the REST API.
598 *
599 * @param array $field
600 * @return array
601 */
602 public function get_rest_schema( array $field ) {
603 $schema = array(
604 'type' => array( 'integer', 'array', 'null' ),
605 'required' => ! empty( $field['required'] ),
606 'items' => array(
607 'type' => 'integer',
608 ),
609 );
610
611 if ( empty( $field['allow_null'] ) ) {
612 $schema['minItems'] = 1;
613 }
614
615 if ( empty( $field['multiple'] ) ) {
616 $schema['maxItems'] = 1;
617 }
618
619 return $schema;
620 }
621
622 /**
623 * @see \acf_field::get_rest_links()
624 * @param mixed $value The raw (unformatted) field value.
625 * @param integer|string $post_id
626 * @param array $field
627 * @return array
628 */
629 public function get_rest_links( $value, $post_id, array $field ) {
630 $links = array();
631
632 if ( empty( $value ) ) {
633 return $links;
634 }
635
636 foreach ( (array) $value as $object_id ) {
637 $links[] = array(
638 'rel' => 'acf:user',
639 'href' => rest_url( '/wp/v2/users/' . $object_id ),
640 'embeddable' => true,
641 );
642 }
643
644 return $links;
645 }
646
647 /**
648 * Apply basic formatting to prepare the value for default REST output.
649 *
650 * @param mixed $value
651 * @param string|integer $post_id
652 * @param array $field
653 * @return mixed
654 */
655 public function format_value_for_rest( $value, $post_id, array $field ) {
656 return acf_format_numerics( $value );
657 }
658 }
659
660
661 // initialize
662 acf_register_field_type( 'ACF_Field_User' );
663 endif; // class_exists check
664