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