Skip to:
Content

BuddyPress.org

source: trunk/src/bp-xprofile/classes/class-bp-xprofile-field.php @ 11079

Last change on this file since 11079 was 11079, checked in by boonebgorges, 6 years ago

XProfile: Improvements to responsive styling and accessibilty on date format admin panel.

Props mercime.
Fixes #5500.

File size: 43.4 KB
Line 
1<?php
2/**
3 * BuddyPress XProfile Classes.
4 *
5 * @package BuddyPress
6 * @subpackage XProfileClasses
7 * @since 1.0.0
8 */
9
10// Exit if accessed directly.
11defined( 'ABSPATH' ) || exit;
12
13/**
14 * Class to help set up XProfile fields.
15 *
16 * @since 1.0.0
17 */
18class BP_XProfile_Field {
19
20        /**
21         * Field ID.
22         *
23         * @since 1.0.0
24         * @var int ID of field.
25         */
26        public $id;
27
28        /**
29         * Field group ID.
30         *
31         * @since 1.0.0
32         * @var int Field group ID for field.
33         */
34        public $group_id;
35
36        /**
37         * Field parent ID.
38         *
39         * @since 1.0.0
40         * @var int Parent ID of field.
41         */
42        public $parent_id;
43
44        /**
45         * Field type.
46         *
47         * @since 1.0.0
48         * @var string Field type.
49         */
50        public $type;
51
52        /**
53         * Field name.
54         *
55         * @since 1.0.0
56         * @var string Field name.
57         */
58        public $name;
59
60        /**
61         * Field description.
62         *
63         * @since 1.0.0
64         * @var string Field description.
65         */
66        public $description;
67
68        /**
69         * Required field?
70         *
71         * @since 1.0.0
72         * @var bool Is field required to be filled out?
73         */
74        public $is_required;
75
76        /**
77         * Deletable field?
78         *
79         * @since 1.0.0
80         * @var int Can field be deleted?
81         */
82        public $can_delete = '1';
83
84        /**
85         * Field position.
86         *
87         * @since 1.0.0
88         * @var int Field position.
89         */
90        public $field_order;
91
92        /**
93         * Option order.
94         *
95         * @since 1.0.0
96         * @var int Option order.
97         */
98        public $option_order;
99
100        /**
101         * Order child fields.
102         *
103         * @since 1.0.0
104         * @var string Order child fields by.
105         */
106        public $order_by;
107
108        /**
109         * Is this the default option?
110         *
111         * @since 1.0.0
112         * @var bool Is this the default option for this field?
113         */
114        public $is_default_option;
115
116        /**
117         * Field data visibility.
118         *
119         * @since 1.9.0
120         * @since 2.4.0 Property marked protected. Now accessible by magic method or by `get_default_visibility()`.
121         * @var string Default field data visibility.
122         */
123        protected $default_visibility;
124
125        /**
126         * Is the visibility able to be modified?
127         *
128         * @since 2.3.0
129         * @since 2.4.0 Property marked protected. Now accessible by magic method or by `get_allow_custom_visibility()`.
130         * @var string Members are allowed/disallowed to modify data visibility.
131         */
132        protected $allow_custom_visibility;
133
134        /**
135         * Whether values from this field are autolinked to directory searches.
136         *
137         * @since 2.5.0
138         * @var bool
139         */
140        public $do_autolink;
141
142        /**
143         * Field type option.
144         *
145         * @since 2.0.0
146         * @var BP_XProfile_Field_Type Field type object used for validation.
147         */
148        public $type_obj = null;
149
150        /**
151         * Field data for user ID.
152         *
153         * @since 2.0.0
154         * @var BP_XProfile_ProfileData Field data for user ID.
155         */
156        public $data;
157
158        /**
159         * Member types to which the profile field should be applied.
160         *
161         * @since 2.4.0
162         * @var array Array of member types.
163         */
164        protected $member_types;
165
166        /**
167         * Initialize and/or populate profile field.
168         *
169         * @since 1.1.0
170         *
171         * @param int|null $id Field ID.
172         * @param int|null $user_id User ID.
173         * @param bool     $get_data Get data.
174         */
175        public function __construct( $id = null, $user_id = null, $get_data = true ) {
176
177                if ( ! empty( $id ) ) {
178                        $this->populate( $id, $user_id, $get_data );
179
180                // Initialise the type obj to prevent fatals when creating new profile fields.
181                } else {
182                        $this->type_obj            = bp_xprofile_create_field_type( 'textbox' );
183                        $this->type_obj->field_obj = $this;
184                }
185        }
186
187        /**
188         * Populate a profile field object.
189         *
190         * @since 1.1.0
191         *
192         * @global object $wpdb
193         * @global object $userdata
194         *
195         * @param int      $id Field ID.
196         * @param int|null $user_id User ID.
197         * @param bool     $get_data Get data.
198         */
199        public function populate( $id, $user_id = null, $get_data = true ) {
200                global $wpdb, $userdata;
201
202                if ( empty( $user_id ) ) {
203                        $user_id = isset( $userdata->ID ) ? $userdata->ID : 0;
204                }
205
206                $field = wp_cache_get( $id, 'bp_xprofile_fields' );
207                if ( false === $field ) {
208                        $bp = buddypress();
209
210                        $field = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id = %d", $id ) );
211
212                        if ( ! $field ) {
213                                return false;
214                        }
215
216                        wp_cache_add( $id, $field, 'bp_xprofile_fields' );
217                }
218
219                $this->fill_data( $field );
220
221                if ( ! empty( $get_data ) && ! empty( $user_id ) ) {
222                        $this->data = $this->get_field_data( $user_id );
223                }
224        }
225
226        /**
227         * Retrieve a `BP_XProfile_Field` instance.
228         *
229         * @since 2.4.0
230         *
231         * @static
232         *
233         * @param int $field_id ID of the field.
234         * @return BP_XProfile_Field|false Field object if found, otherwise false.
235         */
236        public static function get_instance( $field_id ) {
237                global $wpdb;
238
239                $field_id = (int) $field_id;
240                if ( ! $field_id ) {
241                        return false;
242                }
243
244                return new self( $field_id );
245        }
246
247        /**
248         * Fill object vars based on data passed to the method.
249         *
250         * @since 2.4.0
251         *
252         * @param array|object $args Array or object representing the `BP_XProfile_Field` properties.
253         *                           Generally, this is a row from the fields database table.
254         */
255        public function fill_data( $args ) {
256                if ( is_object( $args ) ) {
257                        $args = (array) $args;
258                }
259
260                $int_fields = array(
261                        'id', 'is_required', 'group_id', 'parent_id', 'is_default_option',
262                        'field_order', 'option_order', 'can_delete'
263                );
264
265                foreach ( $args as $k => $v ) {
266                        if ( 'name' === $k || 'description' === $k ) {
267                                $v = stripslashes( $v );
268                        }
269
270                        // Cast numeric strings as integers.
271                        if ( true === in_array( $k, $int_fields ) ) {
272                                $v = (int) $v;
273                        }
274
275                        $this->{$k} = $v;
276                }
277
278                // Create the field type and store a reference back to this object.
279                $this->type_obj            = bp_xprofile_create_field_type( $this->type );
280                $this->type_obj->field_obj = $this;
281        }
282
283        /**
284         * Magic getter.
285         *
286         * @since 2.4.0
287         *
288         * @param string $key Property name.
289         * @return mixed
290         */
291        public function __get( $key ) {
292                switch ( $key ) {
293                        case 'default_visibility' :
294                                return $this->get_default_visibility();
295                                break;
296
297                        case 'allow_custom_visibility' :
298                                return $this->get_allow_custom_visibility();
299                                break;
300                }
301        }
302
303        /**
304         * Magic issetter.
305         *
306         * @since 2.4.0
307         *
308         * @param string $key Property name.
309         * @return bool
310         */
311        public function __isset( $key ) {
312                switch ( $key ) {
313                        // Backward compatibility for when these were public methods.
314                        case 'allow_custom_visibility' :
315                        case 'default_visibility' :
316                                return true;
317                                break;
318                }
319        }
320
321        /**
322         * Delete a profile field.
323         *
324         * @since 1.1.0
325         *
326         * @global object $wpdb
327         *
328         * @param boolean $delete_data Whether or not to delete data.
329         * @return boolean
330         */
331        public function delete( $delete_data = false ) {
332                global $wpdb;
333
334                // Prevent deletion if no ID is present.
335                // Prevent deletion by url when can_delete is false.
336                // Prevent deletion of option 1 since this invalidates fields with options.
337                if ( empty( $this->id ) || empty( $this->can_delete ) || ( $this->parent_id && $this->option_order == 1 ) ) {
338                        return false;
339                }
340
341                $bp  = buddypress();
342                $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE id = %d OR parent_id = %d", $this->id, $this->id );
343
344                if ( ! $wpdb->query( $sql ) ) {
345                        return false;
346                }
347
348                // Delete the data in the DB for this field.
349                if ( true === $delete_data ) {
350                        BP_XProfile_ProfileData::delete_for_field( $this->id );
351                }
352
353                return true;
354        }
355
356        /**
357         * Save a profile field.
358         *
359         * @since 1.1.0
360         *
361         * @global object $wpdb
362         *
363         * @return boolean
364         */
365        public function save() {
366                global $wpdb;
367
368                $bp = buddypress();
369
370                $this->group_id     = apply_filters( 'xprofile_field_group_id_before_save',     $this->group_id,     $this->id );
371                $this->parent_id    = apply_filters( 'xprofile_field_parent_id_before_save',    $this->parent_id,    $this->id );
372                $this->type         = apply_filters( 'xprofile_field_type_before_save',         $this->type,         $this->id );
373                $this->name         = apply_filters( 'xprofile_field_name_before_save',         $this->name,         $this->id );
374                $this->description  = apply_filters( 'xprofile_field_description_before_save',  $this->description,  $this->id );
375                $this->is_required  = apply_filters( 'xprofile_field_is_required_before_save',  $this->is_required,  $this->id );
376                $this->order_by     = apply_filters( 'xprofile_field_order_by_before_save',     $this->order_by,     $this->id );
377                $this->field_order  = apply_filters( 'xprofile_field_field_order_before_save',  $this->field_order,  $this->id );
378                $this->option_order = apply_filters( 'xprofile_field_option_order_before_save', $this->option_order, $this->id );
379                $this->can_delete   = apply_filters( 'xprofile_field_can_delete_before_save',   $this->can_delete,   $this->id );
380                $this->type_obj     = bp_xprofile_create_field_type( $this->type );
381
382                /**
383                 * Fires before the current field instance gets saved.
384                 *
385                 * Please use this hook to filter the properties above. Each part will be passed in.
386                 *
387                 * @since 1.0.0
388                 *
389                 * @param BP_XProfile_Field $this Current instance of the field being saved.
390                 */
391                do_action_ref_array( 'xprofile_field_before_save', array( $this ) );
392
393                $is_new_field = is_null( $this->id );
394
395                if ( ! $is_new_field ) {
396                        $sql = $wpdb->prepare( "UPDATE {$bp->profile->table_name_fields} SET group_id = %d, parent_id = 0, type = %s, name = %s, description = %s, is_required = %d, order_by = %s, field_order = %d, option_order = %d, can_delete = %d, is_default_option = %d WHERE id = %d", $this->group_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->option_order, $this->can_delete, $this->is_default_option, $this->id );
397                } else {
398                        $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, order_by, field_order, option_order, can_delete, is_default_option ) VALUES ( %d, %d, %s, %s, %s, %d, %s, %d, %d, %d, %d )", $this->group_id, $this->parent_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->option_order, $this->can_delete, $this->is_default_option );
399                }
400
401                /**
402                 * Check for null so field options can be changed without changing any
403                 * other part of the field. The described situation will return 0 here.
404                 */
405                if ( $wpdb->query( $sql ) !== null ) {
406
407                        if ( $is_new_field ) {
408                                $this->id = $wpdb->insert_id;
409                        }
410
411                        // Only do this if we are editing an existing field.
412                        if ( ! $is_new_field ) {
413
414                                /**
415                                 * Remove any radio or dropdown options for this
416                                 * field. They will be re-added if needed.
417                                 * This stops orphan options if the user changes a
418                                 * field from a radio button field to a text box.
419                                 */
420                                $this->delete_children();
421                        }
422
423                        /**
424                         * Check to see if this is a field with child options.
425                         * We need to add the options to the db, if it is.
426                         */
427                        if ( $this->type_obj->supports_options ) {
428
429                                $parent_id = $this->id;
430
431                                // Allow plugins to filter the field's child options (i.e. the items in a selectbox).
432                                $post_option  = ! empty( $_POST["{$this->type}_option"]           ) ? $_POST["{$this->type}_option"]           : '';
433                                $post_default = ! empty( $_POST["isDefault_{$this->type}_option"] ) ? $_POST["isDefault_{$this->type}_option"] : '';
434
435                                /**
436                                 * Filters the submitted field option value before saved.
437                                 *
438                                 * @since 1.5.0
439                                 *
440                                 * @param string            $post_option Submitted option value.
441                                 * @param BP_XProfile_Field $type        Current field type being saved for.
442                                 */
443                                $options      = apply_filters( 'xprofile_field_options_before_save', $post_option,  $this->type );
444
445                                /**
446                                 * Filters the default field option value before saved.
447                                 *
448                                 * @since 1.5.0
449                                 *
450                                 * @param string            $post_default Default option value.
451                                 * @param BP_XProfile_Field $type         Current field type being saved for.
452                                 */
453                                $defaults     = apply_filters( 'xprofile_field_default_before_save', $post_default, $this->type );
454
455                                $counter = 1;
456                                if ( !empty( $options ) ) {
457                                        foreach ( (array) $options as $option_key => $option_value ) {
458                                                $is_default = 0;
459
460                                                if ( is_array( $defaults ) ) {
461                                                        if ( isset( $defaults[ $option_key ] ) ) {
462                                                                $is_default = 1;
463                                                        }
464                                                } else {
465                                                        if ( (int) $defaults == $option_key ) {
466                                                                $is_default = 1;
467                                                        }
468                                                }
469
470                                                if ( '' != $option_value ) {
471                                                        $sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, option_order, is_default_option) VALUES (%d, %d, 'option', %s, '', 0, %d, %d)", $this->group_id, $parent_id, $option_value, $counter, $is_default );
472                                                        if ( ! $wpdb->query( $sql ) ) {
473                                                                return false;
474                                                        }
475                                                }
476
477                                                $counter++;
478                                        }
479                                }
480                        }
481
482                        /**
483                         * Fires after the current field instance gets saved.
484                         *
485                         * @since 1.0.0
486                         *
487                         * @param BP_XProfile_Field $this Current instance of the field being saved.
488                         */
489                        do_action_ref_array( 'xprofile_field_after_save', array( $this ) );
490
491                        // Recreate type_obj in case someone changed $this->type via a filter.
492                        $this->type_obj            = bp_xprofile_create_field_type( $this->type );
493                        $this->type_obj->field_obj = $this;
494
495                        return $this->id;
496                } else {
497                        return false;
498                }
499        }
500
501        /**
502         * Get field data for a user ID.
503         *
504         * @since 1.2.0
505         *
506         * @param int $user_id ID of the user to get field data for.
507         * @return BP_XProfile_ProfileData
508         */
509        public function get_field_data( $user_id = 0 ) {
510                return new BP_XProfile_ProfileData( $this->id, $user_id );
511        }
512
513        /**
514         * Get all child fields for this field ID.
515         *
516         * @since 1.2.0
517         *
518         * @global object $wpdb
519         *
520         * @param bool $for_editing Whether or not the field is for editing.
521         * @return array
522         */
523        public function get_children( $for_editing = false ) {
524                global $wpdb;
525
526                // This is done here so we don't have problems with sql injection.
527                if ( empty( $for_editing ) && ( 'asc' === $this->order_by ) ) {
528                        $sort_sql = 'ORDER BY name ASC';
529                } elseif ( empty( $for_editing ) && ( 'desc' === $this->order_by ) ) {
530                        $sort_sql = 'ORDER BY name DESC';
531                } else {
532                        $sort_sql = 'ORDER BY option_order ASC';
533                }
534
535                // This eliminates a problem with getting all fields when there is no
536                // id for the object.
537                if ( empty( $this->id ) ) {
538                        $parent_id = -1;
539                } else {
540                        $parent_id = $this->id;
541                }
542
543                $bp  = buddypress();
544                $sql = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE parent_id = %d AND group_id = %d {$sort_sql}", $parent_id, $this->group_id );
545
546                $children = $wpdb->get_results( $sql );
547
548                /**
549                 * Filters the found children for a field.
550                 *
551                 * @since 1.2.5
552                 *
553                 * @param object $children    Found children for a field.
554                 * @param bool   $for_editing Whether or not the field is for editing.
555                 */
556                return apply_filters( 'bp_xprofile_field_get_children', $children, $for_editing );
557        }
558
559        /**
560         * Delete all field children for this field.
561         *
562         * @since 1.2.0
563         *
564         * @global object $wpdb
565         */
566        public function delete_children() {
567                global $wpdb;
568
569                $bp  = buddypress();
570                $sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE parent_id = %d", $this->id );
571
572                $wpdb->query( $sql );
573        }
574
575        /**
576         * Gets the member types to which this field should be available.
577         *
578         * Will not return inactive member types, even if associated metadata is found.
579         *
580         * 'null' is a special pseudo-type, which represents users that do not have a member type.
581         *
582         * @since 2.4.0
583         *
584         * @return array Array of member type names.
585         */
586        public function get_member_types() {
587                if ( ! is_null( $this->member_types ) ) {
588                        return $this->member_types;
589                }
590
591                $raw_types = bp_xprofile_get_meta( $this->id, 'field', 'member_type', false );
592
593                // If `$raw_types` is not an array, it probably means this is a new field (id=0).
594                if ( ! is_array( $raw_types ) ) {
595                        $raw_types = array();
596                }
597
598                // If '_none' is found in the array, it overrides all types.
599                $types = array();
600                if ( ! in_array( '_none', $raw_types ) ) {
601                        $registered_types = bp_get_member_types();
602
603                        // Eliminate invalid member types saved in the database.
604                        foreach ( $raw_types as $raw_type ) {
605                                // 'null' is a special case - it represents users without a type.
606                                if ( 'null' === $raw_type || isset( $registered_types[ $raw_type ] ) ) {
607                                        $types[] = $raw_type;
608                                }
609                        }
610
611                        // If no member types have been saved, intepret as *all* member types.
612                        if ( empty( $types ) ) {
613                                $types = array_values( $registered_types );
614
615                                // + the "null" type, ie users without a type.
616                                $types[] = 'null';
617                        }
618                }
619
620                /**
621                 * Filters the member types to which an XProfile object should be applied.
622                 *
623                 * @since 2.4.0
624                 *
625                 * @param array             $types Member types.
626                 * @param BP_XProfile_Field $field Field object.
627                 */
628                $this->member_types = apply_filters( 'bp_xprofile_field_member_types', $types, $this );
629
630                return $this->member_types;
631        }
632
633        /**
634         * Sets the member types for this field.
635         *
636         * @since 2.4.0
637         *
638         * @param array $member_types Array of member types. Can include 'null' (users with no type) in addition to any
639         *                            registered types.
640         * @param bool  $append       Whether to append to existing member types. If false, all existing member type
641         *                            associations will be deleted before adding your `$member_types`. Default false.
642         * @return array Member types for the current field, after being saved.
643         */
644        public function set_member_types( $member_types, $append = false ) {
645                // Unset invalid member types.
646                $types = array();
647                foreach ( $member_types as $member_type ) {
648                        // 'null' is a special case - it represents users without a type.
649                        if ( 'null' === $member_type || bp_get_member_type_object( $member_type ) ) {
650                                $types[] = $member_type;
651                        }
652                }
653
654                // When `$append` is false, delete all existing types before adding new ones.
655                if ( ! $append ) {
656                        bp_xprofile_delete_meta( $this->id, 'field', 'member_type' );
657
658                        /*
659                         * We interpret an empty array as disassociating the field from all types. This is
660                         * represented internally with the '_none' flag.
661                         */
662                        if ( empty( $types ) ) {
663                                bp_xprofile_add_meta( $this->id, 'field', 'member_type', '_none' );
664                        }
665                }
666
667                /*
668                 * Unrestricted fields are represented in the database as having no 'member_type'.
669                 * We detect whether a field is being set to unrestricted by checking whether the
670                 * list of types passed to the method is the same as the list of registered types,
671                 * plus the 'null' pseudo-type.
672                 */
673                $_rtypes  = bp_get_member_types();
674                $rtypes   = array_values( $_rtypes );
675                $rtypes[] = 'null';
676
677                sort( $types );
678                sort( $rtypes );
679
680                // Only save if this is a restricted field.
681                if ( $types !== $rtypes ) {
682                        // Save new types.
683                        foreach ( $types as $type ) {
684                                bp_xprofile_add_meta( $this->id, 'field', 'member_type', $type );
685                        }
686                }
687
688                // Reset internal cache of member types.
689                $this->member_types = null;
690
691                /**
692                 * Fires after a field's member types have been updated.
693                 *
694                 * @since 2.4.0
695                 *
696                 * @param BP_XProfile_Field $this Field object.
697                 */
698                do_action( 'bp_xprofile_field_set_member_type', $this );
699
700                // Refetch fresh items from the database.
701                return $this->get_member_types();
702        }
703
704        /**
705         * Gets a label representing the field's member types.
706         *
707         * This label is displayed alongside the field's name on the Profile Fields Dashboard panel.
708         *
709         * @since 2.4.0
710         *
711         * @return string
712         */
713        public function get_member_type_label() {
714                // Field 1 is always displayed to everyone, so never gets a label.
715                if ( 1 == $this->id ) {
716                        return '';
717                }
718
719                // Return an empty string if no member types are registered.
720                $all_types = bp_get_member_types();
721                if ( empty( $all_types ) ) {
722                        return '';
723                }
724
725                $member_types = $this->get_member_types();
726
727                // If the field applies to all member types, show no message.
728                $all_types[] = 'null';
729                if ( array_values( $all_types ) == $member_types ) {
730                        return '';
731                }
732
733                $label = '';
734                if ( ! empty( $member_types ) ) {
735                        $has_null = false;
736                        $member_type_labels = array();
737                        foreach ( $member_types as $member_type ) {
738                                if ( 'null' === $member_type ) {
739                                        $has_null = true;
740                                        continue;
741                                } else {
742                                        $mt_obj = bp_get_member_type_object( $member_type );
743                                        $member_type_labels[] = $mt_obj->labels['name'];
744                                }
745                        }
746
747                        // Alphabetical sort.
748                        natcasesort( $member_type_labels );
749                        $member_type_labels = array_values( $member_type_labels );
750
751                        // Add the 'null' option to the end of the list.
752                        if ( $has_null ) {
753                                $member_type_labels[] = __( 'Users with no member type', 'buddypress' );
754                        }
755
756                        $label = sprintf( __( '(Member types: %s)', 'buddypress' ), implode( ', ', array_map( 'esc_html', $member_type_labels ) ) );
757                } else {
758                        $label = '<span class="member-type-none-notice">' . __( '(Unavailable to all members)', 'buddypress' ) . '</span>';
759                }
760
761                return $label;
762        }
763
764        /**
765         * Get the field's default visibility setting.
766         *
767         * Lazy-loaded to reduce overhead.
768         *
769         * Defaults to 'public' if no visibility setting is found in the database.
770         *
771         * @since 2.4.0
772         *
773         * @return string
774         */
775        public function get_default_visibility() {
776                if ( ! isset( $this->default_visibility ) ) {
777                        $this->default_visibility = bp_xprofile_get_meta( $this->id, 'field', 'default_visibility' );
778
779                        if ( ! $this->default_visibility ) {
780                                $this->default_visibility = 'public';
781                        }
782                }
783
784                return $this->default_visibility;
785        }
786
787        /**
788         * Get whether the field's default visibility can be overridden by users.
789         *
790         * Lazy-loaded to reduce overhead.
791         *
792         * Defaults to 'allowed'.
793         *
794         * @since 4.4.0
795         *
796         * @return string 'disabled' or 'allowed'.
797         */
798        public function get_allow_custom_visibility() {
799                if ( ! isset( $this->allow_custom_visibility ) ) {
800                        $allow_custom_visibility = bp_xprofile_get_meta( $this->id, 'field', 'allow_custom_visibility' );
801
802                        if ( 'disabled' === $allow_custom_visibility ) {
803                                $this->allow_custom_visibility = 'disabled';
804                        } else {
805                                $this->allow_custom_visibility = 'allowed';
806                        }
807                }
808
809                return $this->allow_custom_visibility;
810        }
811
812        /**
813         * Get whether the field values should be auto-linked to a directory search.
814         *
815         * Lazy-loaded to reduce overhead.
816         *
817         * Defaults to true for multi and default fields, false for single fields.
818         *
819         * @since 2.5.0
820         *
821         * @return bool
822         */
823        public function get_do_autolink() {
824                if ( ! isset( $this->do_autolink ) ) {
825                        $do_autolink = bp_xprofile_get_meta( $this->id, 'field', 'do_autolink' );
826
827                        if ( '' === $do_autolink ) {
828                                $this->do_autolink = $this->type_obj->supports_options;
829                        } else {
830                                $this->do_autolink = 'on' === $do_autolink;
831                        }
832                }
833
834                return $this->do_autolink;
835        }
836
837        /* Static Methods ********************************************************/
838
839        /**
840         * Get the type for provided field ID.
841         *
842         * @param int $field_id Field ID to get type of.
843         * @return bool|null|string
844         */
845        public static function get_type( $field_id = 0 ) {
846                global $wpdb;
847
848                // Bail if no field ID.
849                if ( empty( $field_id ) ) {
850                        return false;
851                }
852
853                $bp   = buddypress();
854                $sql  = $wpdb->prepare( "SELECT type FROM {$bp->profile->table_name_fields} WHERE id = %d", $field_id );
855                $type = $wpdb->get_var( $sql );
856
857                // Return field type.
858                if ( ! empty( $type ) ) {
859                        return $type;
860                }
861
862                return false;
863        }
864
865        /**
866         * Delete all fields in a field group.
867         *
868         * @since 1.2.0
869         *
870         * @global object $wpdb
871         *
872         * @param int $group_id ID of the field group to delete fields from.
873         * @return boolean
874         */
875        public static function delete_for_group( $group_id = 0 ) {
876                global $wpdb;
877
878                // Bail if no group ID.
879                if ( empty( $group_id ) ) {
880                        return false;
881                }
882
883                $bp      = buddypress();
884                $sql     = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE group_id = %d", $group_id );
885                $deleted = $wpdb->get_var( $sql );
886
887                // Return true if fields were deleted.
888                if ( false !== $deleted ) {
889                        return true;
890                }
891
892                return false;
893        }
894
895        /**
896         * Get field ID from field name.
897         *
898         * @since 1.5.0
899         *
900         * @global object $wpdb
901         *
902         * @param string $field_name Name of the field to query the ID for.
903         * @return int|null Field ID on success; null on failure.
904         */
905        public static function get_id_from_name( $field_name = '' ) {
906                global $wpdb;
907
908                $bp = buddypress();
909
910                if ( empty( $bp->profile->table_name_fields ) || empty( $field_name ) ) {
911                        return false;
912                }
913
914                $sql = $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s AND parent_id = 0", $field_name );
915
916                $query = $wpdb->get_var( $sql );
917
918                return is_numeric( $query ) ? (int) $query : $query;
919        }
920
921        /**
922         * Update field position and/or field group when relocating.
923         *
924         * @since 1.5.0
925         *
926         * @global object $wpdb
927         *
928         * @param int      $field_id       ID of the field to update.
929         * @param int|null $position       Field position to update.
930         * @param int|null $field_group_id ID of the field group.
931         * @return boolean
932         */
933        public static function update_position( $field_id, $position = null, $field_group_id = null ) {
934                global $wpdb;
935
936                // Bail if invalid position or field group.
937                if ( ! is_numeric( $position ) || ! is_numeric( $field_group_id ) ) {
938                        return false;
939                }
940
941                // Get table name and field parent.
942                $table_name = buddypress()->profile->table_name_fields;
943                $sql        = $wpdb->prepare( "UPDATE {$table_name} SET field_order = %d, group_id = %d WHERE id = %d", $position, $field_group_id, $field_id );
944                $parent     = $wpdb->query( $sql );
945
946                // Update $field_id with new $position and $field_group_id.
947                if ( ! empty( $parent ) && ! is_wp_error( $parent ) ) {
948
949                        // Update any children of this $field_id.
950                        $sql = $wpdb->prepare( "UPDATE {$table_name} SET group_id = %d WHERE parent_id = %d", $field_group_id, $field_id );
951                        $wpdb->query( $sql );
952
953                        // Invalidate profile field cache.
954                        wp_cache_delete( $field_id, 'bp_xprofile_fields' );
955
956                        return $parent;
957                }
958
959                return false;
960        }
961
962        /**
963         * Gets the IDs of fields applicable for a given member type or array of member types.
964         *
965         * @since 2.4.0
966         *
967         * @param string|array $member_types Member type or array of member types. Use 'any' to return unrestricted
968         *                                   fields (those available for anyone, regardless of member type).
969         * @return array Multi-dimensional array, with field IDs as top-level keys, and arrays of member types
970         *               associated with each field as values.
971         */
972        public static function get_fields_for_member_type( $member_types ) {
973                global $wpdb;
974
975                $fields = array();
976
977                if ( empty( $member_types ) ) {
978                        $member_types = array( 'any' );
979                } elseif ( ! is_array( $member_types ) ) {
980                        $member_types = array( $member_types );
981                }
982
983                $bp = buddypress();
984
985                // Pull up all recorded field member type data.
986                $mt_meta = wp_cache_get( 'field_member_types', 'bp_xprofile' );
987                if ( false === $mt_meta ) {
988                        $mt_meta = $wpdb->get_results( "SELECT object_id, meta_value FROM {$bp->profile->table_name_meta} WHERE meta_key = 'member_type' AND object_type = 'field'" );
989                        wp_cache_set( 'field_member_types', $mt_meta, 'bp_xprofile' );
990                }
991
992                // Keep track of all fields with recorded member_type metadata.
993                $all_recorded_field_ids = wp_list_pluck( $mt_meta, 'object_id' );
994
995                // Sort member_type matches in arrays, keyed by field_id.
996                foreach ( $mt_meta as $_mt_meta ) {
997                        if ( ! isset( $fields[ $_mt_meta->object_id ] ) ) {
998                                $fields[ $_mt_meta->object_id ] = array();
999                        }
1000
1001                        $fields[ $_mt_meta->object_id ][] = $_mt_meta->meta_value;
1002                }
1003
1004                /*
1005                 * Filter out fields that don't match any passed types, or those marked '_none'.
1006                 * The 'any' type is implicitly handled here: it will match no types.
1007                 */
1008                foreach ( $fields as $field_id => $field_types ) {
1009                        if ( ! array_intersect( $field_types, $member_types ) ) {
1010                                unset( $fields[ $field_id ] );
1011                        }
1012                }
1013
1014                // Any fields with no member_type metadata are available to all member types.
1015                if ( ! in_array( '_none', $member_types ) ) {
1016                        if ( ! empty( $all_recorded_field_ids ) ) {
1017                                $all_recorded_field_ids_sql = implode( ',', array_map( 'absint', $all_recorded_field_ids ) );
1018                                $unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields} WHERE id NOT IN ({$all_recorded_field_ids_sql})" );
1019                        } else {
1020                                $unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields}" );
1021                        }
1022
1023                        // Append the 'null' pseudo-type.
1024                        $all_member_types   = bp_get_member_types();
1025                        $all_member_types   = array_values( $all_member_types );
1026                        $all_member_types[] = 'null';
1027
1028                        foreach ( $unrestricted_field_ids as $unrestricted_field_id ) {
1029                                $fields[ $unrestricted_field_id ] = $all_member_types;
1030                        }
1031                }
1032
1033                return $fields;
1034        }
1035
1036        /**
1037         * Validate form field data on sumbission.
1038         *
1039         * @since 2.2.0
1040         *
1041         * @global $message
1042         *
1043         * @return boolean
1044         */
1045        public static function admin_validate() {
1046                global $message;
1047
1048                // Check field name.
1049                if ( ! isset( $_POST['title'] ) || ( '' === $_POST['title'] ) ) {
1050                        $message = esc_html__( 'Profile fields must have a name.', 'buddypress' );
1051                        return false;
1052                }
1053
1054                // Check field requirement.
1055                if ( ! isset( $_POST['required'] ) ) {
1056                        $message = esc_html__( 'Profile field requirement is missing.', 'buddypress' );
1057                        return false;
1058                }
1059
1060                // Check field type.
1061                if ( empty( $_POST['fieldtype'] ) ) {
1062                        $message = esc_html__( 'Profile field type is missing.', 'buddypress' );
1063                        return false;
1064                }
1065
1066                // Check that field is of valid type.
1067                if ( ! in_array( $_POST['fieldtype'], array_keys( bp_xprofile_get_field_types() ), true ) ) {
1068                        $message = sprintf( esc_html__( 'The profile field type %s is not registered.', 'buddypress' ), '<code>' . esc_attr( $_POST['fieldtype'] ) . '</code>' );
1069                        return false;
1070                }
1071
1072                // Get field type so we can check for and lavidate any field options.
1073                $field_type = bp_xprofile_create_field_type( $_POST['fieldtype'] );
1074
1075                // Field type requires options.
1076                if ( true === $field_type->supports_options ) {
1077
1078                        // Build the field option key.
1079                        $option_name = sanitize_key( $_POST['fieldtype'] ) . '_option';
1080
1081                        // Check for missing or malformed options.
1082                        if ( empty( $_POST[ $option_name ] ) || ! is_array( $_POST[ $option_name ] ) ) {
1083                                $message = esc_html__( 'These field options are invalid.', 'buddypress' );
1084                                return false;
1085                        }
1086
1087                        // Trim out empty field options.
1088                        $field_values  = array_values( $_POST[ $option_name ] );
1089                        $field_options = array_map( 'sanitize_text_field', $field_values );
1090                        $field_count   = count( $field_options );
1091
1092                        // Check for missing or malformed options.
1093                        if ( 0 === $field_count ) {
1094                                $message = sprintf( esc_html__( '%s require at least one option.', 'buddypress' ), $field_type->name );
1095                                return false;
1096                        }
1097
1098                        // If only one option exists, it cannot be an empty string.
1099                        if ( ( 1 === $field_count ) && ( '' === $field_options[0] ) ) {
1100                                $message = sprintf( esc_html__( '%s require at least one option.', 'buddypress' ), $field_type->name );
1101                                return false;
1102                        }
1103                }
1104
1105                return true;
1106        }
1107
1108        /**
1109         * Save miscellaneous settings for this field.
1110         *
1111         * Some field types have type-specific settings, which are saved here.
1112         *
1113         * @since 2.7.0
1114         *
1115         * @param array $settings Array of settings.
1116         */
1117        public function admin_save_settings( $settings ) {
1118                return $this->type_obj->admin_save_settings( $this->id, $settings );
1119        }
1120
1121        /**
1122         * Populates the items for radio buttons, checkboxes, and dropdown boxes.
1123         */
1124        public function render_admin_form_children() {
1125                foreach ( array_keys( bp_xprofile_get_field_types() ) as $field_type ) {
1126                        $type_obj = bp_xprofile_create_field_type( $field_type );
1127                        $type_obj->admin_new_field_html( $this );
1128                }
1129        }
1130
1131        /**
1132         * Oupput the admin form for this field.
1133         *
1134         * @since 1.9.0
1135         *
1136         * @param string $message Message to display.
1137         */
1138        public function render_admin_form( $message = '' ) {
1139                if ( empty( $this->id ) ) {
1140                        $title  = __( 'Add New Field', 'buddypress' );
1141                        $action = "users.php?page=bp-profile-setup&amp;group_id=" . $this->group_id . "&amp;mode=add_field#tabs-" . $this->group_id;
1142                        $button = __( 'Save', 'buddypress' );
1143
1144                        if ( !empty( $_POST['saveField'] ) ) {
1145                                $this->name        = $_POST['title'];
1146                                $this->description = $_POST['description'];
1147                                $this->is_required = $_POST['required'];
1148                                $this->type        = $_POST['fieldtype'];
1149                                $this->field_order = $_POST['field_order'];
1150
1151                                if ( ! empty( $_POST["sort_order_{$this->type}"] ) ) {
1152                                        $this->order_by = $_POST["sort_order_{$this->type}"];
1153                                }
1154                        }
1155                } else {
1156                        $title  = __( 'Edit Field', 'buddypress' );
1157                        $action = "users.php?page=bp-profile-setup&amp;mode=edit_field&amp;group_id=" . $this->group_id . "&amp;field_id=" . $this->id . "#tabs-" . $this->group_id;
1158                        $button = __( 'Update', 'buddypress' );
1159                } ?>
1160
1161                <div class="wrap">
1162
1163                        <h1><?php echo esc_html( $title ); ?></h1>
1164
1165                        <?php if ( !empty( $message ) ) : ?>
1166
1167                                <div id="message" class="error fade">
1168                                        <p><?php echo esc_html( $message ); ?></p>
1169                                </div>
1170
1171                        <?php endif; ?>
1172
1173                        <form id="bp-xprofile-add-field" action="<?php echo esc_url( $action ); ?>" method="post">
1174                                <div id="poststuff">
1175                                        <div id="post-body" class="metabox-holder columns-<?php echo ( 1 == get_current_screen()->get_columns() ) ? '1' : '2'; ?>">
1176                                                <div id="post-body-content">
1177
1178                                                        <?php
1179
1180                                                        // Output the name & description fields.
1181                                                        $this->name_and_description(); ?>
1182
1183                                                </div><!-- #post-body-content -->
1184
1185                                                <div id="postbox-container-1" class="postbox-container">
1186
1187                                                        <?php
1188
1189                                                        // Output the sumbit metabox.
1190                                                        $this->submit_metabox( $button );
1191
1192                                                        // Output the required metabox.
1193                                                        $this->required_metabox();
1194
1195                                                        // Output the Member Types metabox.
1196                                                        $this->member_type_metabox();
1197
1198                                                        // Output the field visibility metaboxes.
1199                                                        $this->visibility_metabox();
1200
1201                                                        // Output the autolink metabox.
1202                                                        $this->autolink_metabox();
1203
1204
1205                                                        /**
1206                                                         * Fires after XProfile Field sidebar metabox.
1207                                                         *
1208                                                         * @since 2.2.0
1209                                                         *
1210                                                         * @param BP_XProfile_Field $this Current XProfile field.
1211                                                         */
1212                                                        do_action( 'xprofile_field_after_sidebarbox', $this ); ?>
1213
1214                                                </div>
1215
1216                                                <div id="postbox-container-2" class="postbox-container">
1217
1218                                                        <?php
1219
1220                                                        /**
1221                                                         * Fires before XProfile Field content metabox.
1222                                                         *
1223                                                         * @since 2.3.0
1224                                                         *
1225                                                         * @param BP_XProfile_Field $this Current XProfile field.
1226                                                         */
1227                                                        do_action( 'xprofile_field_before_contentbox', $this );
1228
1229                                                        // Output the field attributes metabox.
1230                                                        $this->type_metabox();
1231
1232                                                        // Output hidden inputs for default field.
1233                                                        $this->default_field_hidden_inputs();
1234
1235                                                        /**
1236                                                         * Fires after XProfile Field content metabox.
1237                                                         *
1238                                                         * @since 2.2.0
1239                                                         *
1240                                                         * @param BP_XProfile_Field $this Current XProfile field.
1241                                                         */
1242                                                        do_action( 'xprofile_field_after_contentbox', $this ); ?>
1243
1244                                                </div>
1245                                        </div><!-- #post-body -->
1246                                </div><!-- #poststuff -->
1247                        </form>
1248                </div>
1249
1250        <?php
1251        }
1252
1253        /**
1254         * Private method used to display the submit metabox.
1255         *
1256         * @since 2.3.0
1257         *
1258         * @param string $button_text Text to put on button.
1259         */
1260        private function submit_metabox( $button_text = '' ) {
1261
1262                /**
1263                 * Fires before XProfile Field submit metabox.
1264                 *
1265                 * @since 2.1.0
1266                 *
1267                 * @param BP_XProfile_Field $this Current XProfile field.
1268                 */
1269                do_action( 'xprofile_field_before_submitbox', $this ); ?>
1270
1271                <div id="submitdiv" class="postbox">
1272                        <h2><?php esc_html_e( 'Submit', 'buddypress' ); ?></h2>
1273                        <div class="inside">
1274                                <div id="submitcomment" class="submitbox">
1275                                        <div id="major-publishing-actions">
1276
1277                                                <?php
1278
1279                                                /**
1280                                                 * Fires at the beginning of the XProfile Field publishing actions section.
1281                                                 *
1282                                                 * @since 2.1.0
1283                                                 *
1284                                                 * @param BP_XProfile_Field $this Current XProfile field.
1285                                                 */
1286                                                do_action( 'xprofile_field_submitbox_start', $this ); ?>
1287
1288                                                <input type="hidden" name="field_order" id="field_order" value="<?php echo esc_attr( $this->field_order ); ?>" />
1289
1290                                                <?php if ( ! empty( $button_text ) ) : ?>
1291
1292                                                        <div id="publishing-action">
1293                                                                <input type="submit" name="saveField" value="<?php echo esc_attr( $button_text ); ?>" class="button-primary" />
1294                                                        </div>
1295
1296                                                <?php endif; ?>
1297
1298                                                <div id="delete-action">
1299                                                        <a href="users.php?page=bp-profile-setup" class="deletion"><?php esc_html_e( 'Cancel', 'buddypress' ); ?></a>
1300                                                </div>
1301
1302                                                <?php wp_nonce_field( 'xprofile_delete_option' ); ?>
1303
1304                                                <div class="clear"></div>
1305                                        </div>
1306                                </div>
1307                        </div>
1308                </div>
1309
1310                <?php
1311
1312                /**
1313                 * Fires after XProfile Field submit metabox.
1314                 *
1315                 * @since 2.1.0
1316                 *
1317                 * @param BP_XProfile_Field $this Current XProfile field.
1318                 */
1319                do_action( 'xprofile_field_after_submitbox', $this );
1320        }
1321
1322        /**
1323         * Private method used to output field name and description fields.
1324         *
1325         * @since 2.3.0
1326         */
1327        private function name_and_description() {
1328        ?>
1329
1330                <div id="titlediv">
1331                        <div class="titlewrap">
1332                                <label id="title-prompt-text" for="title"><?php echo esc_html_x( 'Name', 'XProfile admin edit field', 'buddypress' ); ?></label>
1333                                <input type="text" name="title" id="title" value="<?php echo esc_attr( $this->name ); ?>" autocomplete="off" />
1334                        </div>
1335                </div>
1336
1337                <div class="postbox">
1338                        <h2><?php echo esc_html_x( 'Description', 'XProfile admin edit field', 'buddypress' ); ?></h2>
1339                        <div class="inside">
1340                                <label for="description" class="screen-reader-text"><?php
1341                                        /* translators: accessibility text */
1342                                        esc_html_e( 'Add description', 'buddypress' );
1343                                ?></label>
1344                                <textarea name="description" id="description" rows="8" cols="60"><?php echo esc_textarea( $this->description ); ?></textarea>
1345                        </div>
1346                </div>
1347
1348        <?php
1349        }
1350
1351        /**
1352         * Private method used to output field Member Type metabox.
1353         *
1354         * @since 2.4.0
1355         */
1356        private function member_type_metabox() {
1357
1358                // The primary field is for all, so bail.
1359                if ( 1 === (int) $this->id ) {
1360                        return;
1361                }
1362
1363                // Bail when no member types are registered.
1364                if ( ! $member_types = bp_get_member_types( array(), 'objects' ) ) {
1365                        return;
1366                }
1367
1368                $field_member_types = $this->get_member_types();
1369
1370                ?>
1371
1372                <div id="member-types-div" class="postbox">
1373                        <h2><?php _e( 'Member Types', 'buddypress' ); ?></h2>
1374                        <div class="inside">
1375                                <p class="description"><?php _e( 'This field should be available to:', 'buddypress' ); ?></p>
1376
1377                                <ul>
1378                                        <?php foreach ( $member_types as $member_type ) : ?>
1379                                        <li>
1380                                                <label for="member-type-<?php echo $member_type->labels['name']; ?>">
1381                                                        <input name="member-types[]" id="member-type-<?php echo $member_type->labels['name']; ?>" class="member-type-selector" type="checkbox" value="<?php echo $member_type->name; ?>" <?php checked( in_array( $member_type->name, $field_member_types ) ); ?>/>
1382                                                        <?php echo $member_type->labels['name']; ?>
1383                                                </label>
1384                                        </li>
1385                                        <?php endforeach; ?>
1386
1387                                        <li>
1388                                                <label for="member-type-none">
1389                                                        <input name="member-types[]" id="member-type-none" class="member-type-selector" type="checkbox" value="null" <?php checked( in_array( 'null', $field_member_types ) ); ?>/>
1390                                                        <?php _e( 'Users with no member type', 'buddypress' ); ?>
1391                                                </label>
1392                                        </li>
1393
1394                                </ul>
1395                                <p class="description member-type-none-notice<?php if ( ! empty( $field_member_types ) ) : ?> hide<?php endif; ?>"><?php _e( 'Unavailable to all members.', 'buddypress' ) ?></p>
1396                        </div>
1397
1398                        <input type="hidden" name="has-member-types" value="1" />
1399                </div>
1400
1401                <?php
1402        }
1403
1404        /**
1405         * Private method used to output field visibility metaboxes.
1406         *
1407         * @since 2.3.0
1408         *
1409         * @return void If default field id 1.
1410         */
1411        private function visibility_metabox() {
1412
1413                // Default field cannot have custom visibility.
1414                if ( true === $this->is_default_field() ) {
1415                        return;
1416                } ?>
1417
1418                <div class="postbox">
1419                        <h2><label for="default-visibility"><?php esc_html_e( 'Visibility', 'buddypress' ); ?></label></h2>
1420                        <div class="inside">
1421                                <div>
1422                                        <select name="default-visibility" id="default-visibility">
1423
1424                                                <?php foreach( bp_xprofile_get_visibility_levels() as $level ) : ?>
1425
1426                                                        <option value="<?php echo esc_attr( $level['id'] ); ?>" <?php selected( $this->get_default_visibility(), $level['id'] ); ?>>
1427                                                                <?php echo esc_html( $level['label'] ); ?>
1428                                                        </option>
1429
1430                                                <?php endforeach ?>
1431
1432                                        </select>
1433                                </div>
1434
1435                                <div>
1436                                        <ul>
1437                                                <li>
1438                                                        <input type="radio" id="allow-custom-visibility-allowed" name="allow-custom-visibility" value="allowed" <?php checked( $this->get_allow_custom_visibility(), 'allowed' ); ?> />
1439                                                        <label for="allow-custom-visibility-allowed"><?php esc_html_e( 'Allow members to override', 'buddypress' ); ?></label>
1440                                                </li>
1441                                                <li>
1442                                                        <input type="radio" id="allow-custom-visibility-disabled" name="allow-custom-visibility" value="disabled" <?php checked( $this->get_allow_custom_visibility(), 'disabled' ); ?> />
1443                                                        <label for="allow-custom-visibility-disabled"><?php esc_html_e( 'Enforce field visibility', 'buddypress' ); ?></label>
1444                                                </li>
1445                                        </ul>
1446                                </div>
1447                        </div>
1448                </div>
1449
1450                <?php
1451        }
1452
1453        /**
1454         * Output the metabox for setting if field is required or not.
1455         *
1456         * @since 2.3.0
1457         *
1458         * @return void If default field.
1459         */
1460        private function required_metabox() {
1461
1462                // Default field is always required.
1463                if ( true === $this->is_default_field() ) {
1464                        return;
1465                } ?>
1466
1467                <div class="postbox">
1468                        <h2><label for="required"><?php esc_html_e( 'Requirement', 'buddypress' ); ?></label></h2>
1469                        <div class="inside">
1470                                <select name="required" id="required">
1471                                        <option value="0"<?php selected( $this->is_required, '0' ); ?>><?php esc_html_e( 'Not Required', 'buddypress' ); ?></option>
1472                                        <option value="1"<?php selected( $this->is_required, '1' ); ?>><?php esc_html_e( 'Required',     'buddypress' ); ?></option>
1473                                </select>
1474                        </div>
1475                </div>
1476
1477        <?php
1478        }
1479
1480        /**
1481         * Private method used to output autolink metabox.
1482         *
1483         * @since 2.5.0
1484         *
1485         * @return void If default field id 1.
1486         */
1487        private function autolink_metabox() {
1488                ?>
1489
1490                <div class="postbox">
1491                        <h2><?php esc_html_e( 'Autolink', 'buddypress' ); ?></h2>
1492                        <div class="inside">
1493                                <p class="description"><?php esc_html_e( 'On user profiles, link this field to a search of the Members directory, using the field value as a search term.', 'buddypress' ); ?></p>
1494
1495                                <p>
1496                                        <label for="do-autolink" class="screen-reader-text"><?php
1497                                                /* translators: accessibility text */
1498                                                esc_html_e( 'Autolink status for this field', 'buddypress' );
1499                                        ?></label>
1500                                        <select name="do_autolink" id="do-autolink">
1501                                                <option value="on" <?php selected( $this->get_do_autolink() ); ?>><?php esc_html_e( 'Enabled', 'buddypress' ); ?></option>
1502                                                <option value="" <?php selected( $this->get_do_autolink(), false ); ?>><?php esc_html_e( 'Disabled', 'buddypress' ); ?></option>
1503                                        </select>
1504                                </p>
1505                        </div>
1506                </div>
1507
1508                <?php
1509        }
1510
1511        /**
1512         * Output the metabox for setting what type of field this is.
1513         *
1514         * @since 2.3.0
1515         *
1516         * @return void If default field.
1517         */
1518        private function type_metabox() {
1519
1520                // Default field cannot change type.
1521                if ( true === $this->is_default_field() ) {
1522                        return;
1523                } ?>
1524
1525                <div class="postbox">
1526                        <h2><label for="fieldtype"><?php esc_html_e( 'Type', 'buddypress'); ?></label></h2>
1527                        <div class="inside">
1528                                <select name="fieldtype" id="fieldtype" onchange="show_options(this.value)">
1529
1530                                        <?php bp_xprofile_admin_form_field_types( $this->type ); ?>
1531
1532                                </select>
1533
1534                                <?php
1535
1536                                // Deprecated filter, don't use. Go look at {@link BP_XProfile_Field_Type::admin_new_field_html()}.
1537                                do_action( 'xprofile_field_additional_options', $this );
1538
1539                                $this->render_admin_form_children(); ?>
1540
1541                        </div>
1542                </div>
1543
1544        <?php
1545        }
1546
1547        /**
1548         * Output hidden fields used by default field.
1549         *
1550         * @since 2.3.0
1551         *
1552         * @return void If not default field.
1553         */
1554        private function default_field_hidden_inputs() {
1555
1556                // Field 1 is the fullname field, which cannot have custom visibility.
1557                if ( false === $this->is_default_field() ) {
1558                        return;
1559                } ?>
1560
1561                <input type="hidden" name="required"  id="required"  value="1"       />
1562                <input type="hidden" name="fieldtype" id="fieldtype" value="textbox" />
1563
1564                <?php
1565        }
1566
1567        /**
1568         * Return if a field ID is the default field.
1569         *
1570         * @since 2.3.0
1571         *
1572         * @param int $field_id ID of field to check.
1573         * @return bool
1574         */
1575        private function is_default_field( $field_id = 0 ) {
1576
1577                // Fallback to current field ID if none passed.
1578                if ( empty( $field_id ) ) {
1579                        $field_id = $this->id;
1580                }
1581
1582                // Compare & return.
1583                return (bool) ( 1 === (int) $field_id );
1584        }
1585}
Note: See TracBrowser for help on using the repository browser.