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