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