Skip to:
Content

BuddyPress.org

Ticket #5220: 5220.01.patch

File 5220.01.patch, 120.9 KB (added by DJPaul, 6 years ago)
  • bp-members/admin/css/admin.css

    diff --git bp-members/admin/css/admin.css bp-members/admin/css/admin.css
    index 5473fe5..5d295da 100644
    div#profile-page.wrap form#your-profile ul#profile-nav { 
    1515        width:100%;
    1616}
    1717
    18 div#community-profile-page h2:first-of-type {
    19         margin-bottom:1em;
    20 }
    21 
    22 div#community-profile-page  h2.profile-section {
    23         border-bottom:dotted 1px #ccc;
    24 }
    25 
    2618div#community-profile-page ul#profile-nav {
    2719        border-bottom:solid 1px #ccc;
    2820        width:100%;
    div#community-profile-page p.not-activated { 
    10496        color:red;
    10597}
    10698
    107 div#community-profile-page .form-table td.admin-field-visibility-td {
    108         padding:5px 5px 15px 5px;
     99.alt {
     100        background: none;
    109101}
    110 
    111 div#community-profile-page .form-table tr.admin-field-visibility-tr {
    112         border-bottom:dotted 1px #ccc;
     102.bp-profile-field {
     103        border-bottom: dotted 1px #ccc;
     104        font-size: 14px;
     105        margin: 15px 0;
    113106}
    114 
    115 div#community-profile-page .form-table tr.admin-field-visibility-tr:last-child{
    116         border:none;
     107.bp-profile-field:last-child {
     108        border-bottom: 0;
    117109}
    118 
    119 div#community-profile-page .field-visibility-settings legend,
    120 div#community-profile-page .field-visibility-settings-notoggle {
     110.bp-profile-field p {
    121111        font-size: 14px;
    122         font-style: italic;
    123         color:#666;
    124112}
    125 
    126 div#community-profile-page .field-visibility-settings ul {
    127         margin:0;
    128         font-size: 13px;
     113.bp-profile-field .datebox > label,
     114.bp-profile-field .radio > label,
     115.bp-profile-field > label {  /* label takes on left side 200px */
     116        display: inline-block;
     117        font-weight: 600;
     118        text-align: left;
     119        vertical-align: middle;
     120        width: 200px;
    129121}
    130122
    131 div#community-profile-page .field-visibility-settings ul li {
    132         display:inline-block;
    133         margin-right:1em;
     123.field_type_textarea > label,
     124.field_type_multiselectbox > label,
     125.field_type_radio .radio > label,
     126.field_type_checkbox .checkbox > label {  /* these fields are usually pretty tall, so align the label for better consistency */
     127        vertical-align: top;
    134128}
    135 
    136 div#community-profile-page .form-table td.admin-field-radio label,
    137 div#community-profile-page .form-table td.admin-field-checkbox label {
    138         display:block;
     129.bp-profile-field .description {  /* description also sits in the right side column */
     130        margin: 10px 0 10px 200px;
     131        text-align: left;
    139132}
    140 
    141 .field-visibility-settings {
     133.clear-value {  /* 'clear value' option also sits in the right side column */
     134        display: block;
     135        font-size: 12px;
     136        margin-left: 200px;
     137}
     138.field_type_checkbox .checkbox > label + label {  /* force checkboxes to new lines, in the right side column */
     139        display: block;
     140        margin-left: 200px;
     141        width: auto;
     142}
     143.field_type_radio .radio div:not(.field-visibility-settings) label {  /* force radio buttons to new lines */
     144        display: block;
     145}
     146.field_type_radio .radio div:not(.field-visibility-settings) {  /* make the radio buttons sit in the right side column */
     147        display: inline-block;
     148}
     149.field-visibility-settings-notoggle,
     150.field-visibility-settings-toggle {  /* visibility settings go in the left column */
     151        margin: 10px 0 10px 200px;
     152        text-align: left;
     153}
     154.field-visibility-settings {  /* visibility settings go in the left column */
    142155        display: none;
    143 }
    144  No newline at end of file
     156        margin-left: 200px;
     157}
     158.field-visibility-settings .button {  /* visibility setting close button */
     159        margin-bottom: 15px;
     160}
     161#normal-sortables .field-visibility-settings legend {  /* id required for css selector weight */
     162        font-size: 16px;
     163        margin-bottom: 10px;
     164}
  • bp-templates/bp-legacy/buddypress/members/register.php

    diff --git bp-templates/bp-legacy/buddypress/members/register.php bp-templates/bp-legacy/buddypress/members/register.php
    index 8679dc2..6624817 100644
     
    6868
    6969                                                <div class="editfield">
    7070
    71                                                         <?php if ( 'textbox' == bp_get_the_profile_field_type() ) : ?>
     71                                                        <?php
     72                                                        $field_type = bp_xprofile_create_field_type( bp_get_the_profile_field_type() );
     73                                                        $field_type->edit_field_html();
    7274
    73                                                                 <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    74                                                                 <?php do_action( bp_get_the_profile_field_errors_action() ); ?>
    75                                                                 <input type="text" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" value="<?php bp_the_profile_field_edit_value(); ?>" />
     75                                                        do_action( 'bp_custom_profile_edit_fields_pre_visibility' );
    7676
    77                                                         <?php endif; ?>
    78 
    79                                                         <?php if ( 'textarea' == bp_get_the_profile_field_type() ) : ?>
    80 
    81                                                                 <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    82                                                                 <?php do_action( bp_get_the_profile_field_errors_action() ); ?>
    83                                                                 <textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_edit_value(); ?></textarea>
    84 
    85                                                         <?php endif; ?>
    86 
    87                                                         <?php if ( 'selectbox' == bp_get_the_profile_field_type() ) : ?>
    88 
    89                                                                 <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    90                                                                 <?php do_action( bp_get_the_profile_field_errors_action() ); ?>
    91                                                                 <select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>">
    92                                                                         <?php bp_the_profile_field_options(); ?>
    93                                                                 </select>
    94 
    95                                                         <?php endif; ?>
    96 
    97                                                         <?php if ( 'multiselectbox' == bp_get_the_profile_field_type() ) : ?>
    98 
    99                                                                 <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    100                                                                 <?php do_action( bp_get_the_profile_field_errors_action() ); ?>
    101                                                                 <select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" multiple="multiple">
    102                                                                         <?php bp_the_profile_field_options(); ?>
    103                                                                 </select>
    104 
    105                                                         <?php endif; ?>
    106 
    107                                                         <?php if ( 'radio' == bp_get_the_profile_field_type() ) : ?>
    108 
    109                                                                 <div class="radio">
    110                                                                         <span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
    111 
    112                                                                         <?php do_action( bp_get_the_profile_field_errors_action() ); ?>
    113                                                                         <?php bp_the_profile_field_options(); ?>
    114 
    115                                                                         <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    116                                                                                 <a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
    117                                                                         <?php endif; ?>
    118                                                                 </div>
    119 
    120                                                         <?php endif; ?>
    121 
    122                                                         <?php if ( 'checkbox' == bp_get_the_profile_field_type() ) : ?>
    123 
    124                                                                 <div class="checkbox">
    125                                                                         <span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
    126 
    127                                                                         <?php do_action( bp_get_the_profile_field_errors_action() ); ?>
    128                                                                         <?php bp_the_profile_field_options(); ?>
    129                                                                 </div>
    130 
    131                                                         <?php endif; ?>
    132 
    133                                                         <?php if ( 'datebox' == bp_get_the_profile_field_type() ) : ?>
    134 
    135                                                                 <div class="datebox">
    136                                                                         <label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    137                                                                         <?php do_action( bp_get_the_profile_field_errors_action() ); ?>
    138 
    139                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day">
    140                                                                                 <?php bp_the_profile_field_options( 'type=day' ); ?>
    141                                                                         </select>
    142 
    143                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month">
    144                                                                                 <?php bp_the_profile_field_options( 'type=month' ); ?>
    145                                                                         </select>
    146 
    147                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year">
    148                                                                                 <?php bp_the_profile_field_options( 'type=year' ); ?>
    149                                                                         </select>
    150                                                                 </div>
    151 
    152                                                         <?php endif; ?>
    153 
    154                                                         <?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
    155 
    156                                                         <?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
     77                                                        if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
    15778                                                                <p class="field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
    15879                                                                        <?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?> <a href="#" class="visibility-toggle-link"><?php _ex( 'Change', 'Change profile field visibility level', 'buddypress' ); ?></a>
    15980                                                                </p>
  • bp-templates/bp-legacy/buddypress/members/single/profile/edit.php

    diff --git bp-templates/bp-legacy/buddypress/members/single/profile/edit.php bp-templates/bp-legacy/buddypress/members/single/profile/edit.php
    index b7b6cc5..a20c079 100644
    if ( bp_has_profile( 'profile_group_id=' . bp_get_current_profile_group_id() ) ) 
    2121
    2222                        <div<?php bp_field_css_class( 'editfield' ); ?>>
    2323
    24                                 <?php if ( 'textbox' == bp_get_the_profile_field_type() ) : ?>
     24                                <?php
     25                                $field_type = bp_xprofile_create_field_type( bp_get_the_profile_field_type() );
     26                                $field_type->edit_field_html();
    2527
    26                                         <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    27                                         <input type="text" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" value="<?php bp_the_profile_field_edit_value(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>/>
    28 
    29                                 <?php endif; ?>
    30 
    31                                 <?php if ( 'textarea' == bp_get_the_profile_field_type() ) : ?>
    32 
    33                                         <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    34                                         <textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>><?php bp_the_profile_field_edit_value(); ?></textarea>
    35 
    36                                 <?php endif; ?>
    37 
    38                                 <?php if ( 'selectbox' == bp_get_the_profile_field_type() ) : ?>
    39 
    40                                         <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    41                                         <select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    42                                                 <?php bp_the_profile_field_options(); ?>
    43                                         </select>
    44 
    45                                 <?php endif; ?>
    46 
    47                                 <?php if ( 'multiselectbox' == bp_get_the_profile_field_type() ) : ?>
    48 
    49                                         <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    50                                         <select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" multiple="multiple" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    51 
    52                                                 <?php bp_the_profile_field_options(); ?>
    53 
    54                                         </select>
    55 
    56                                         <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    57 
    58                                                 <a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
    59 
    60                                         <?php endif; ?>
    61 
    62                                 <?php endif; ?>
    63 
    64                                 <?php if ( 'radio' == bp_get_the_profile_field_type() ) : ?>
    65 
    66                                         <div class="radio">
    67                                                 <span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
    68 
    69                                                 <?php bp_the_profile_field_options(); ?>
    70 
    71                                                 <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    72 
    73                                                         <a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
    74 
    75                                                 <?php endif; ?>
    76                                         </div>
    77 
    78                                 <?php endif; ?>
    79 
    80                                 <?php if ( 'checkbox' == bp_get_the_profile_field_type() ) : ?>
    81 
    82                                         <div class="checkbox">
    83                                                 <span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
    84 
    85                                                 <?php bp_the_profile_field_options(); ?>
    86                                         </div>
    87 
    88                                 <?php endif; ?>
    89 
    90                                 <?php if ( 'datebox' == bp_get_the_profile_field_type() ) : ?>
    91 
    92                                         <div class="datebox">
    93                                                 <label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    94 
    95                                                 <select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    96 
    97                                                         <?php bp_the_profile_field_options( 'type=day' ); ?>
    98 
    99                                                 </select>
    100 
    101                                                 <select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    102 
    103                                                         <?php bp_the_profile_field_options( 'type=month' ); ?>
    104 
    105                                                 </select>
    106 
    107                                                 <select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    108 
    109                                                         <?php bp_the_profile_field_options( 'type=year' ); ?>
    110 
    111                                                 </select>
    112                                         </div>
    113 
    114                                 <?php endif; ?>
    115 
    116                                 <?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
     28                                do_action( 'bp_custom_profile_edit_fields_pre_visibility' );
     29                                ?>
    11730
    11831                                <?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
    11932                                        <p class="field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
  • bp-templates/bp-legacy/css/buddypress.css

    diff --git bp-templates/bp-legacy/css/buddypress.css bp-templates/bp-legacy/css/buddypress.css
    index 6c13c70..b16f39b 100644
    body.activity-permalink #buddypress div.activity-comments div.acomment-content { 
    607607        font-weight: bold;
    608608        margin: 15px 0 5px 0;
    609609}
    610 #buddypress .standard-form div.checkbox label,
    611 #buddypress .standard-form div.radio label {
     610#buddypress .standard-form div.checkbox label:nth-child(n+2),
     611#buddypress .standard-form div.radio div label {
    612612        color: #888;
    613613        font-size: 100%;
    614614        font-weight: normal;
  • bp-xprofile/bp-xprofile-admin.php

    diff --git bp-xprofile/bp-xprofile-admin.php bp-xprofile/bp-xprofile-admin.php
    index 99dcfd8..10681ab 100644
    function xprofile_admin_field( $admin_field, $admin_group, $class = '' ) { 
    382382                <legend><span><?php bp_the_profile_field_name(); ?> <?php if( !$field->can_delete ) : ?> <?php _e( '(Primary)', 'buddypress' ); endif; ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(Required)', 'buddypress' ) ?><?php endif; ?></span></legend>
    383383                <div class="field-wrapper">
    384384
    385                         <?php switch ( $field->type ) : case 'textbox' : ?>
    386 
    387                                 <input type="text" name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>" value="" />
    388 
    389                         <?php break; case 'textarea' : ?>
    390 
    391                                 <textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>"></textarea>
    392 
    393                         <?php break; case 'selectbox' : ?>
    394 
    395                                 <select name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>">
    396 
    397                                         <?php bp_the_profile_field_options() ?>
    398 
    399                                 </select>
    400 
    401                         <?php break; case 'multiselectbox' : ?>
    402 
    403                                 <select name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>" multiple="multiple">
    404 
    405                                         <?php bp_the_profile_field_options() ?>
    406 
    407                                 </select>
    408 
    409                         <?php break; case 'radio' : ?>
    410 
    411                                 <?php bp_the_profile_field_options() ?>
    412 
    413                                 <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    414 
    415                                         <a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name() ?>' );"><?php _e( 'Clear', 'buddypress' ) ?></a>
    416 
    417                                 <?php endif; ?>
    418 
    419                         <?php break; case 'checkbox' : ?>
    420 
    421                                 <?php bp_the_profile_field_options(); ?>
    422 
    423                         <?php break; case 'datebox' : ?>
    424 
    425                                 <select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day">
    426 
    427                                         <?php bp_the_profile_field_options( 'type=day' ); ?>
    428 
    429                                 </select>
    430 
    431                                 <select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month">
    432 
    433                                         <?php bp_the_profile_field_options( 'type=month' ); ?>
    434 
    435                                 </select>
    436 
    437                                 <select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year">
    438 
    439                                         <?php bp_the_profile_field_options( 'type=year' ); ?>
    440 
    441                                 </select>
    442 
    443                         <?php break; default : ?>
    444 
    445                         <?php do_action( 'xprofile_admin_field', $field, 1 ); ?>
     385                        <?php
     386                        $field_type = bp_xprofile_create_field_type( $field->type );
     387                        $field_type->admin_field_html();
    446388
    447                         <?php endswitch; ?>
     389                        do_action( 'xprofile_admin_field', $field, 1 );
     390                        ?>
    448391
    449392                        <?php if ( $field->description ) : ?>
    450393
    function xprofile_admin_field( $admin_field, $admin_group, $class = '' ) { 
    467410<?php
    468411}
    469412
     413/**
     414 * Print <option> elements containing the xprofile field types.
     415 *
     416 * @param string $select_field_type The name of the field type that should be selected. Will defaults to "textbox" if NULL is passed.
     417 * @since BuddyPress (2.0.0)
     418 */
     419function bp_xprofile_admin_form_field_types( $select_field_type ) {
     420        $categories = array();
     421
     422        if ( is_null( $select_field_type ) ) {
     423                $select_field_type = 'textbox';
     424        }
     425
     426        // Sort each field type into its category
     427        foreach ( bp_xprofile_get_field_types() as $field_name => $field_class ) {
     428                $field_type_obj = new $field_class;
     429                $the_category   = $field_type_obj->category;
     430
     431                // Fallback to a catch-all if category not set
     432                if ( ! $the_category ) {
     433                        $the_category = _x( 'Other', 'xprofile field type category', 'buddypress' );
     434                }
     435
     436                if ( isset( $categories[$the_category] ) ) {
     437                        $categories[$the_category][] = array( $field_name, $field_type_obj );
     438                } else {
     439                        $categories[$the_category] = array( array( $field_name, $field_type_obj ) );
     440                }
     441        }
     442
     443        // Sort the categories alphabetically. ksort()'s SORT_NATURAL is only in PHP >= 5.4 :((
     444        uksort( $categories, 'strnatcmp' );
     445
     446        // Loop through each category and output form <options>
     447        foreach ( $categories as $category => $fields ) {
     448                printf( '<optgroup label="%1$s">', esc_attr( $category ) );  // Already i18n'd in each profile type class
     449
     450                // Sort these fields types alphabetically
     451                uasort( $fields, create_function( '$a, $b', 'return strnatcmp( $a[1]->name, $b[1]->name );' ) );
     452
     453                foreach ( $fields as $field_type_obj ) {
     454                        $field_name     = $field_type_obj[0];
     455                        $field_type_obj = $field_type_obj[1];
     456
     457                        printf( '<option value="%1$s" %2$s>%3$s</option>', esc_attr( $field_name ), selected( $select_field_type, $field_name, false ), esc_html( $field_type_obj->name ) );
     458                }
     459
     460                printf( '</optgroup>' );
     461        }
     462}
     463
    470464if ( ! class_exists( 'BP_XProfile_User_Admin' ) ) :
    471465/**
    472466 * Load xProfile Profile admin area.
    class BP_XProfile_User_Admin { 
    633627                                // Set the errors var
    634628                                $errors = false;
    635629
    636                                 // Now we've checked for required fields, lets save the values.
     630                                // Now we've checked for required fields, let's save the values.
    637631                                foreach ( (array) $posted_field_ids as $field_id ) {
    638632
    639633                                        // Certain types of fields (checkboxes, multiselects) may come through empty. Save them as an empty array so that they don't get overwritten by the default on the next edit.
    class BP_XProfile_User_Admin { 
    693687                }
    694688
    695689                if ( bp_has_profile( $r ) ) :
    696 
    697690                        while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
     691                                <input type="hidden" name="field_ids" id="<?php echo esc_attr( 'field_ids_' . bp_get_the_profile_group_slug() ); ?>" value="<?php echo esc_attr( bp_get_the_profile_group_field_ids() ); ?>" />
    698692
    699                                 <p class="description"><?php bp_the_profile_group_description(); ?></p>
    700 
    701                                 <table class="form-table">
    702                                         <tbody>
    703 
    704                                         <?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
    705 
    706                                                 <tr>
    707 
    708                                                         <?php if ( 'textbox' === bp_get_the_profile_field_type() ) : ?>
     693                                <?php if ( bp_get_the_profile_group_description() ) : ?>
     694                                        <p class="description"><?php bp_the_profile_group_description(); ?></p>
     695                                <?php
     696                                endif;
    709697
    710                                                                 <th><label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label></th>
    711                                                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    712                                                                         <input type="text" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" value="<?php bp_the_profile_field_edit_value(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>/>
    713                                                                         <span class="description"><?php bp_the_profile_field_description(); ?></span>
    714                                                                 </td>
     698                                while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
    715699
    716                                                         <?php endif; ?>
    717 
    718                                                         <?php if ( 'textarea' === bp_get_the_profile_field_type() ) : ?>
     700                                        <div<?php bp_field_css_class( 'bp-profile-field' ); ?>>
     701                                                <?php
     702                                                $field_type = bp_xprofile_create_field_type( bp_get_the_profile_field_type() );
     703                                                $field_type->edit_field_html( array( 'user_id' => $r['user_id'] ) );
    719704
    720                                                                 <th><label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label></th>
    721                                                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    722                                                                         <textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>><?php bp_the_profile_field_edit_value(); ?></textarea>
    723                                                                         <p class="description"><?php bp_the_profile_field_description(); ?></p>
    724                                                                 </td>
    725 
    726                                                         <?php endif; ?>
     705                                                if ( bp_get_the_profile_field_description() ) : ?>
     706                                                        <p class="description"><?php bp_the_profile_field_description(); ?></p>
     707                                                <?php endif;
    727708
    728                                                         <?php if ( 'selectbox' === bp_get_the_profile_field_type() ) : ?>
     709                                                do_action( 'bp_custom_profile_edit_fields_pre_visibility' );
     710                                                $can_change_visibility = bp_current_user_can( 'bp_xprofile_change_field_visibility' );
     711                                                ?>
    729712
    730                                                                 <th><label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label></th>
    731                                                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    732                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    733                                                                                 <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    734                                                                         </select>
    735                                                                         <span class="description"><?php bp_the_profile_field_description(); ?></span>
    736                                                                 </td>
     713                                                <p class="field-visibility-settings-<?php echo $can_change_visibility ? 'toggle' : 'notoggle'; ?>" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id(); ?>">
     714                                                        <?php
     715                                                        printf( __( 'This field can be seen by: <span class="%s">%s</span>', 'buddypress' ), esc_attr( 'current-visibility-level' ), bp_get_the_profile_field_visibility_level_label() );
    737716
     717                                                        if ( $can_change_visibility ) : ?>
     718                                                                 <a href="#" class="button visibility-toggle-link"><?php _e( 'Change', 'buddypress' ); ?></a>
    738719                                                        <?php endif; ?>
     720                                                </p>
     721
     722                                                <?php if ( $can_change_visibility ) : ?>
     723                                                        <div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
     724                                                                <fieldset>
     725                                                                        <legend><?php _e( 'Who can see this field?', 'buddypress' ); ?></legend>
     726                                                                        <?php bp_profile_visibility_radio_buttons(); ?>
     727                                                                </fieldset>
     728                                                                <a class="button field-visibility-settings-close" href="#"><?php _e( 'Close', 'buddypress' ); ?></a>
     729                                                        </div>
     730                                                <?php endif;
    739731
    740                                                         <?php if ( 'multiselectbox' === bp_get_the_profile_field_type() ) : ?>
    741 
    742                                                                 <th><label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label></th>
    743                                                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    744                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" multiple="multiple" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    745 
    746                                                                                 <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    747 
    748                                                                         </select>
    749 
    750 
    751                                                                         <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    752 
    753                                                                                 <p><a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a></p>
    754 
    755                                                                         <?php endif; ?>
    756                                                                         <p class="description"><?php bp_the_profile_field_description(); ?></p>
    757                                                                 </td>
    758 
    759                                                         <?php endif; ?>
    760 
    761                                                         <?php if ( 'radio' === bp_get_the_profile_field_type() ) : ?>
    762 
    763                                                                 <th>
    764                                                                         <span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
    765                                                                 </th>
    766                                                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    767                                                                         <fieldset>
    768                                                                                 <legend class="screen-reader-text"><span><?php bp_the_profile_field_name(); ?></span></legend>
    769                                                                                 <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    770                                                                         </fieldset>
    771 
    772                                                                         <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    773 
    774                                                                                 <p><a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a></p>
    775 
    776                                                                         <?php endif; ?>
    777                                                                         <p class="description"><?php bp_the_profile_field_description(); ?></p>
    778                                                                 </td>
    779 
    780                                                         <?php endif; ?>
    781 
    782                                                         <?php if ( 'checkbox' === bp_get_the_profile_field_type() ) : ?>
    783 
    784                                                                 <th>
    785                                                                         <span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
    786                                                                 </th>
    787                                                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    788                                                                         <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    789                                                                         <p class="description"><?php bp_the_profile_field_description(); ?></p>
    790                                                                 </td>
    791 
    792                                                         <?php endif; ?>
    793 
    794                                                         <?php if ( 'datebox' === bp_get_the_profile_field_type() ) : ?>
    795 
    796                                                                 <th>
    797                                                                         <label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
    798                                                                 </th>
    799                                                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    800                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    801 
    802                                                                                 <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], 'type' => 'day', ) ); ?>
    803 
    804                                                                         </select>
    805 
    806                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    807 
    808                                                                                 <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], 'type' => 'month', ) ); ?>
    809 
    810                                                                         </select>
    811 
    812                                                                         <select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
    813 
    814                                                                                 <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], 'type' => 'year', ) ); ?>
    815 
    816                                                                         </select>
    817                                                                         <p class="description"><?php bp_the_profile_field_description(); ?></p>
    818                                                                 </td>
    819 
    820                                                         <?php endif; ?>
    821 
    822                                                 </tr>
    823 
    824                                                 <tr class="admin-field-visibility-tr">
    825                                                         <td class="admin-field-visibility-td">&nbsp;</td>
    826                                                         <td class="admin-field-visibility-td">
    827 
    828                                                                 <?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
    829 
    830                                                                 <?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
    831                                                                         <p class="description field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
    832                                                                                 <?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?> <a href="#" class="visibility-toggle-link"><?php _e( 'Change', 'buddypress' ); ?></a>
    833                                                                         </p>
    834 
    835                                                                         <div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
    836                                                                                 <fieldset>
    837                                                                                         <legend><?php esc_html_e( 'Who can see this field?', 'buddypress' ) ?></legend>
    838 
    839                                                                                         <?php bp_profile_visibility_radio_buttons() ?>
    840 
    841                                                                                 </fieldset>
    842                                                                                 <a class="field-visibility-settings-close" href="#"><?php esc_html_e( 'Close', 'buddypress' ) ?></a>
    843                                                                         </div>
    844                                                                 <?php else : ?>
    845                                                                         <div class="field-visibility-settings-notoggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
    846                                                                                 <?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?>
    847                                                                         </div>
    848                                                                 <?php endif ?>
    849 
    850                                                         </td>
    851                                                 </tr>
     732                                                do_action( 'bp_custom_profile_edit_fields' ); ?>
     733                                        </div>
    852734
    853                                         <?php endwhile; ?>
    854                                         </tbody>
     735                                <?php
     736                                endwhile; // bp_profile_fields()
    855737
    856                                 </table>
    857                                 <input type="hidden" name="field_ids[]" id="field_ids_<?php bp_the_profile_group_slug(); ?>" value="<?php bp_the_profile_group_field_ids(); ?>" />
    858                         <?php endwhile;
     738                        endwhile; // bp_profile_groups()
    859739                endif;
    860740        }
    861741
  • bp-xprofile/bp-xprofile-classes.php

    diff --git bp-xprofile/bp-xprofile-classes.php bp-xprofile/bp-xprofile-classes.php
    index 84fb54a..8699316 100644
    class BP_XProfile_Field { 
    541541        public $default_visibility = 'public';
    542542        public $allow_custom_visibility = 'allowed';
    543543
     544        /**
     545         * @since BuddyPress (2.0.0)
     546         * @var BP_XProfile_Field_Type Field type object used for validation
     547         */
     548        public $type_obj = null;
     549
    544550        public $data;
    545551        public $message = null;
    546552        public $message_type = 'err';
    547553
    548554        public function __construct( $id = null, $user_id = null, $get_data = true ) {
    549                 if ( !empty( $id ) )
     555                if ( !empty( $id ) ) {
    550556                        $this->populate( $id, $user_id, $get_data );
     557
     558                // Initialise the type obj to prevent fatals when creating new profile fields
     559                } else {
     560                        $this->type_obj            = bp_xprofile_create_field_type( 'textbox' );
     561                        $this->type_obj->field_obj = $this;
     562                }
    551563        }
    552564
    553565        public function populate( $id, $user_id, $get_data ) {
    class BP_XProfile_Field { 
    573585                        $this->order_by          = $field->order_by;
    574586                        $this->is_default_option = $field->is_default_option;
    575587
     588                        // Create the field type and store a reference back to this object.
     589                        $this->type_obj            = bp_xprofile_create_field_type( $field->type );
     590                        $this->type_obj->field_obj = $this;
     591
    576592                        if ( $get_data && $user_id ) {
    577593                                $this->data          = $this->get_field_data( $user_id );
    578594                        }
    class BP_XProfile_Field { 
    618634                $this->order_by    = apply_filters( 'xprofile_field_order_by_before_save',    $this->order_by,    $this->id );
    619635                $this->field_order = apply_filters( 'xprofile_field_field_order_before_save', $this->field_order, $this->id );
    620636                $this->can_delete  = apply_filters( 'xprofile_field_can_delete_before_save',  $this->can_delete,  $this->id );
     637                $this->type_obj    = bp_xprofile_create_field_type( $this->type );
    621638
    622639                do_action_ref_array( 'xprofile_field_before_save', array( $this ) );
    623640
    class BP_XProfile_Field { 
    655672                         * Check to see if this is a field with child options.
    656673                         * We need to add the options to the db, if it is.
    657674                         */
    658                         if ( 'radio' == $this->type || 'selectbox' == $this->type || 'checkbox' == $this->type || 'multiselectbox' == $this->type ) {
     675                        if ( $this->type_obj->supports_options ) {
    659676
    660677                                if ( !empty( $this->id ) ) {
    661678                                        $parent_id = $this->id;
    class BP_XProfile_Field { 
    663680                                        $parent_id = $wpdb->insert_id;
    664681                                }
    665682
    666                                 if ( 'radio' == $this->type ) {
    667                                         $post_option  = !empty( $_POST['radio_option']           ) ? $_POST['radio_option']           : '';
    668                                         $post_default = !empty( $_POST['isDefault_radio_option'] ) ? $_POST['isDefault_radio_option'] : '';
    669 
    670                                         $options        = apply_filters( 'xprofile_field_options_before_save', $post_option,  'radio' );
    671                                         $defaults       = apply_filters( 'xprofile_field_default_before_save', $post_default, 'radio' );
    672 
    673                                 } elseif ( 'selectbox' == $this->type ) {
    674                                         $post_option  = !empty( $_POST['selectbox_option']           ) ? $_POST['selectbox_option']           : '';
    675                                         $post_default = !empty( $_POST['isDefault_selectbox_option'] ) ? $_POST['isDefault_selectbox_option'] : '';
    676 
    677                                         $options        = apply_filters( 'xprofile_field_options_before_save', $post_option, 'selectbox' );
    678                                         $defaults       = apply_filters( 'xprofile_field_default_before_save', $post_default, 'selectbox' );
    679 
    680                                 } elseif ( 'multiselectbox' == $this->type ) {
    681                                         $post_option  = !empty( $_POST['multiselectbox_option']           ) ? $_POST['multiselectbox_option']           : '';
    682                                         $post_default = !empty( $_POST['isDefault_multiselectbox_option'] ) ? $_POST['isDefault_multiselectbox_option'] : '';
    683 
    684                                         $options        = apply_filters( 'xprofile_field_options_before_save', $post_option, 'multiselectbox' );
    685                                         $defaults       = apply_filters( 'xprofile_field_default_before_save', $post_default, 'multiselectbox' );
    686 
    687                                 } elseif ( 'checkbox' == $this->type ) {
    688                                         $post_option  = !empty( $_POST['checkbox_option']           ) ? $_POST['checkbox_option']           : '';
    689                                         $post_default = !empty( $_POST['isDefault_checkbox_option'] ) ? $_POST['isDefault_checkbox_option'] : '';
    690 
    691                                         $options        = apply_filters( 'xprofile_field_options_before_save', $post_option, 'checkbox' );
    692                                         $defaults       = apply_filters( 'xprofile_field_default_before_save', $post_default, 'checkbox' );
    693                                 }
     683                                // Allow plugins to filter the field's child options (i.e. the items in a selectbox).
     684                                $post_option  = ! empty( $_POST["{$this->type}_option"] ) ? $_POST["{$this->type}_option"] : '';
     685                                $post_default = ! empty( $_POST["isDefault_{$this->type}_option"] ) ? $_POST["isDefault_{$this->type}_option"] : '';
     686                                $options      = apply_filters( 'xprofile_field_options_before_save', $post_option,  $this->type );
     687                                $defaults     = apply_filters( 'xprofile_field_default_before_save', $post_default, $this->type );
    694688
    695689                                $counter = 1;
    696690                                if ( !empty( $options ) ) {
    class BP_XProfile_Field { 
    718712
    719713                        do_action_ref_array( 'xprofile_field_after_save', array( $this ) );
    720714
     715                        // Recreate type_obj in case someone changed $this->type via a filter
     716                        $this->type_obj            = bp_xprofile_create_field_type( $this->type );
     717                        $this->type_obj->field_obj = $this;
     718
    721719                        return $field_id;
    722720                } else {
    723721                        return false;
    class BP_XProfile_Field { 
    824822                return false;
    825823        }
    826824
    827         /* ADMIN AREA HTML.
    828         * TODO: Get this out of here and replace with standard template loops
    829         */
    830 
    831         /* This function populates the items for radio buttons checkboxes and drop down boxes */
     825        /**
     826         * This function populates the items for radio buttons checkboxes and drop down boxes
     827         */
    832828        public function render_admin_form_children() {
    833                 $input_types = array( 'checkbox', 'selectbox', 'multiselectbox', 'radio' );
    834 
    835                 foreach ( $input_types as $type ) {
    836                         $default_name = '';
    837 
    838                         if ( ( 'multiselectbox' == $type ) || ( 'checkbox' == $type ) ) {
    839                                 $default_input = 'checkbox';
    840                         } else {
    841                                 $default_input = 'radio';
    842                         }
    843 
    844                         $class = $this->type != $type ? 'display: none;' : '';
    845 
    846                         if ( empty( $this->default_visibility ) ) {
    847                                 $this->default_visibility = 'public';
    848                         }
    849 
    850                         ?>
    851 
    852                         <div id="<?php echo esc_attr( $type ); ?>" class="postbox bp-options-box" style="<?php echo esc_attr( $class ); ?> margin-top: 15px;">
    853                                 <h3><?php _e( 'Please enter options for this Field:', 'buddypress' ); ?></h3>
    854                                 <div class="inside">
    855                                         <p>
    856                                                 <label for="sort_order_<?php echo esc_attr( $type ); ?>"><?php _e( 'Sort Order:', 'buddypress' ); ?></label>
    857                                                 <select name="sort_order_<?php echo esc_attr( $type ); ?>" id="sort_order_<?php echo esc_attr( $type ); ?>" >
    858                                                         <option value="custom" <?php selected( 'custom', $this->order_by ); ?>><?php _e( 'Custom',     'buddypress' ); ?></option>
    859                                                         <option value="asc"    <?php selected( 'asc',    $this->order_by ); ?>><?php _e( 'Ascending',  'buddypress' ); ?></option>
    860                                                         <option value="desc"   <?php selected( 'desc',   $this->order_by ); ?>><?php _e( 'Descending', 'buddypress' ); ?></option>
    861                                                 </select>
    862                                         </p>
    863 
    864                                         <?php if ( !$options = $this->get_children( true ) ) {
    865 
    866                                                 $i = 1;
    867                                                 while ( isset( $_POST[$type . '_option'][$i] ) ) {
    868                                                         (array) $options[] = (object) array(
    869                                                                 'id'                => -1,
    870                                                                 'name'              => $_POST[$type . '_option'][$i],
    871                                                                 'is_default_option' => ( ( 'multiselectbox' != $type ) && ( 'checkbox' != $type ) && ( $_POST["isDefault_{$type}_option"] == $i ) ) ? 1 : $_POST["isDefault_{$type}_option"][$i]
    872                                                         );
    873 
    874                                                         ++$i;
    875                                                 }
    876                                         }
    877 
    878                                         if ( !empty( $options ) ) {
    879                                                 for ( $i = 0, $count = count( $options ); $i < $count; ++$i ) {
    880                                                         $j = $i + 1;
    881 
    882                                                         if ( 'multiselectbox' == $type || 'checkbox' == $type )
    883                                                                 $default_name = '[' . $j . ']'; ?>
    884 
    885                                                         <p class="sortable">
    886                                                                 <span>&nbsp;&Xi;&nbsp;</span>
    887                                                                 <input type="text" name="<?php echo esc_attr( $type ); ?>_option[<?php echo esc_attr( $j ); ?>]" id="<?php echo esc_attr( $type ); ?>_option<?php echo esc_attr( $j ); ?>" value="<?php echo stripslashes( esc_attr( $options[$i]->name ) ); ?>" />
    888                                                                 <input type="<?php echo $default_input; ?>" name="isDefault_<?php echo esc_attr( $type ); ?>_option<?php echo esc_attr( $default_name ); ?>" <?php checked( (int) $options[$i]->is_default_option, true ); ?> value="<?php echo esc_attr( $j ); ?>" />
    889                                                                 <span><?php _e( 'Default Value', 'buddypress' ); ?></span>
    890                                                                 <a href="<?php echo esc_url( 'users.php?page=bp-profile-setup&amp;mode=delete_option&amp;option_id=' . $options[$i]->id ); ?>" class="ajax-option-delete" id="delete-<?php echo esc_attr( $options[$i]->id ); ?>">[x]</a>
    891                                                         </p>
    892 
    893                                                 <?php } /* end for */ ?>
    894 
    895                                                 <input type="hidden" name="<?php echo esc_attr( $type ); ?>_option_number" id="<?php echo esc_attr( $type ); ?>_option_number" value="<?php echo esc_attr( (int) $j + 1 ); ?>" />
    896 
    897                                         <?php } else {
    898 
    899                                                 if ( 'multiselectbox' == $type || 'checkbox' == $type )
    900                                                         $default_name = '[1]'; ?>
    901 
    902                                                 <p class="sortable">
    903                                                         <span>&nbsp;&Xi;&nbsp;</span>
    904                                                         <input type="text" name="<?php echo esc_attr( $type ); ?>_option[1]" id="<?php echo esc_attr( $type ); ?>_option1" />
    905                                                         <input type="<?php echo esc_attr( $default_input ); ?>" name="isDefault_<?php echo esc_attr( $type ); ?>_option<?php echo esc_attr( $default_name ); ?>" id="isDefault_<?php echo esc_attr( $type ); ?>_option" value="1" />
    906                                                         <span><?php _e( 'Default Value', 'buddypress' ); ?></span>
    907                                                         <input type="hidden" name="<?php echo esc_attr( $type ); ?>_option_number" id="<?php echo esc_attr( $type ); ?>_option_number" value="2" />
    908                                                 </p>
    909 
    910                                         <?php } /* end if */ ?>
    911 
    912                                         <div id="<?php echo esc_attr( $type ); ?>_more"></div>
    913                                         <p><a href="javascript:add_option('<?php echo esc_attr( $type ); ?>')"><?php _e( 'Add Another Option', 'buddypress' ); ?></a></p>
    914                                 </div>
    915                         </div>
    916 
    917                 <?php }
     829                foreach ( array_keys( bp_xprofile_get_field_types() ) as $field_type ) {
     830                        $type_obj = bp_xprofile_create_field_type( $field_type );
     831                        $type_obj->admin_new_field_html( $this );
     832                }
    918833        }
    919834
    920835        public function render_admin_form( $message = '' ) {
    class BP_XProfile_Field { 
    1041956                                                                        <h3><label for="fieldtype"><?php _e( 'Field Type', 'buddypress'); ?></label></h3>
    1042957                                                                        <div class="inside">
    1043958                                                                                <select name="fieldtype" id="fieldtype" onchange="show_options(this.value)" style="width: 30%">
    1044                                                                                         <optgroup label="<?php esc_attr_e( 'Single Fields', 'buddypress' ); ?>">
    1045                                                                                                 <option value="textbox"        <?php selected( $this->type, 'textbox'        ); ?>><?php _e( 'Text Box',             'buddypress' ); ?></option>
    1046                                                                                                 <option value="textarea"       <?php selected( $this->type, 'textarea'       ); ?>><?php _e( 'Multi-line Text Area', 'buddypress' ); ?></option>
    1047                                                                                                 <option value="datebox"        <?php selected( $this->type, 'datebox'        ); ?>><?php _e( 'Date Selector',        'buddypress' ); ?></option>
    1048                                                                                         </optgroup>
    1049                                                                                         <optgroup label="<?php esc_attr_e( 'Multi Fields', 'buddypress' ); ?>">
    1050                                                                                                 <option value="radio"          <?php selected( $this->type, 'radio'          ); ?>><?php _e( 'Radio Buttons',        'buddypress' ); ?></option>
    1051                                                                                                 <option value="selectbox"      <?php selected( $this->type, 'selectbox'      ); ?>><?php _e( 'Drop Down Select Box', 'buddypress' ); ?></option>
    1052                                                                                                 <option value="multiselectbox" <?php selected( $this->type, 'multiselectbox' ); ?>><?php _e( 'Multi Select Box',     'buddypress' ); ?></option>
    1053                                                                                                 <option value="checkbox"       <?php selected( $this->type, 'checkbox'       ); ?>><?php _e( 'Checkboxes',           'buddypress' ); ?></option>
    1054                                                                                         </optgroup>
     959                                                                                        <?php bp_xprofile_admin_form_field_types( $this->type ); ?>
    1055960                                                                                </select>
    1056961
    1057                                                                                 <?php do_action_ref_array( 'xprofile_field_additional_options', array( $this ) ); ?>
    1058 
    1059                                                                                 <?php $this->render_admin_form_children(); ?>
     962                                                                                <?php
     963                                                                                // Deprecated filter, don't use. Go look at {@link BP_XProfile_Field_Type::admin_new_field_html()}.
     964                                                                                do_action( 'xprofile_field_additional_options', $this );
    1060965
     966                                                                                $this->render_admin_form_children();
     967                                                                                ?>
    1061968                                                                        </div>
    1062969                                                                </div>
    1063970
    class BP_XProfile_Field { 
    1086993                if ( '' == $_POST['title'] || '' == $_POST['required'] || '' == $_POST['fieldtype'] ) {
    1087994                        $message = __( 'Please make sure you fill out all required fields.', 'buddypress' );
    1088995                        return false;
    1089                 } else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'radio' && empty( $_POST['radio_option'][1] ) ) {
    1090                         $message = __( 'Radio button field types require at least one option. Please add options below.', 'buddypress' );
    1091                         return false;
    1092                 } else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'selectbox' && empty( $_POST['selectbox_option'][1] ) ) {
    1093                         $message = __( 'Select box field types require at least one option. Please add options below.', 'buddypress' );
    1094                         return false;
    1095                 } else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'multiselectbox' && empty( $_POST['multiselectbox_option'][1] ) ) {
    1096                         $message = __( 'Select box field types require at least one option. Please add options below.', 'buddypress' );
    1097                         return false;
    1098                 } else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'checkbox' && empty( $_POST['checkbox_option'][1] ) ) {
    1099                         $message = __( 'Checkbox field types require at least one option. Please add options below.', 'buddypress' );
    1100                         return false;
    1101                 } else {
    1102                         return true;
     996
     997                } elseif ( empty( $_POST['field_file'] ) ) {
     998                        $field_type  = bp_xprofile_create_field_type( $_POST['fieldtype'] );
     999                        $option_name = "{$_POST['fieldtype']}_option";
     1000
     1001                        if ( $field_type->supports_options && isset( $_POST[$option_name] ) && empty( $_POST[$option_name][1] ) ) {
     1002                                $message = __( 'This field type require at least one option. Please add options below.', 'buddypress' );
     1003                                return false;
     1004                        }
    11031005                }
     1006
     1007                return true;
    11041008        }
    11051009}
    11061010
    1107 
    11081011class BP_XProfile_ProfileData {
    11091012        public $id;
    11101013        public $user_id;
    class BP_XProfile_ProfileData { 
    15401443                return $data[$field_name];
    15411444        }
    15421445}
     1446
     1447/**
     1448 * Datebox xprofile field type.
     1449 *
     1450 * @since BuddyPress (2.0.0)
     1451 */
     1452class BP_XProfile_Field_Type_Datebox extends BP_XProfile_Field_Type {
     1453
     1454        /**
     1455         * Constructor for the datebox field type
     1456         *
     1457         * @since BuddyPress (2.0.0)
     1458         */
     1459        public function __construct() {
     1460                parent::__construct();
     1461
     1462                $this->category = _x( 'Single Fields', 'xprofile field type category', 'buddypress' );
     1463                $this->name     = _x( 'Date Selector', 'xprofile field type', 'buddypress' );
     1464
     1465                $this->set_format( '/^\d{4}-\d{1,2}-\d{1,2} 00:00:00$/', 'replace' );  // "Y-m-d 00:00:00"
     1466                do_action( 'bp_xprofile_field_type_datebox', $this );
     1467        }
     1468
     1469        /**
     1470         * Output the edit field HTML for this field type.
     1471         *
     1472         * Must be used inside the {@link bp_profile_fields()} template loop.
     1473         *
     1474         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/input.html permitted attributes} that you want to add.
     1475         * @since BuddyPress (2.0.0)
     1476         */
     1477        public function edit_field_html( array $raw_properties = array() ) {
     1478                $user_id = bp_displayed_user_id();
     1479
     1480                // user_id is a special optional parameter that we pass to {@link bp_the_profile_field_options()}.
     1481                if ( isset( $raw_properties['user_id'] ) ) {
     1482                        $user_id = (int) $raw_properties['user_id'];
     1483                        unset( $raw_properties['user_id'] );
     1484                }
     1485
     1486                $day_html = $this->get_edit_field_html_elements( array_merge(
     1487                        array(
     1488                                'id'   => bp_get_the_profile_field_input_name() . '_day',
     1489                                'name' => bp_get_the_profile_field_input_name() . '_day',
     1490                        ),
     1491                        $raw_properties
     1492                ) );
     1493
     1494                $month_html = $this->get_edit_field_html_elements( array_merge(
     1495                        array(
     1496                                'id'   => bp_get_the_profile_field_input_name() . '_month',
     1497                                'name' => bp_get_the_profile_field_input_name() . '_month',
     1498                        ),
     1499                        $raw_properties
     1500                ) );
     1501
     1502                $year_html = $this->get_edit_field_html_elements( array_merge(
     1503                        array(
     1504                                'id'   => bp_get_the_profile_field_input_name() . '_year',
     1505                                'name' => bp_get_the_profile_field_input_name() . '_year',
     1506                        ),
     1507                        $raw_properties
     1508                ) );
     1509        ?>
     1510                <div class="datebox">
     1511
     1512                        <label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     1513
     1514                        <select <?php echo $day_html; ?>>
     1515                                <?php bp_the_profile_field_options( array( 'type' => 'day', 'user_id' => $user_id ) ); ?>
     1516                        </select>
     1517
     1518                        <select <?php echo $month_html; ?>>
     1519                                <?php bp_the_profile_field_options( array( 'type' => 'month', 'user_id' => $user_id ) ); ?>
     1520                        </select>
     1521
     1522                        <select <?php echo $year_html; ?>>
     1523                                <?php bp_the_profile_field_options( array( 'type' => 'year', 'user_id' => $user_id ) ); ?>
     1524                        </select>
     1525
     1526                </div>
     1527        <?php
     1528        }
     1529
     1530        /**
     1531         * Output the edit field options HTML for this field type.
     1532         *
     1533         * BuddyPress considers a field's "options" to be, for example, the items in a selectbox.
     1534         * These are stored seperately in the database, and their templating is handled seperately.
     1535         *
     1536         * This templating is seperate from {@link BP_XProfile_Field_Type::edit_field_html()} because
     1537         * it's also used in the wp-admin screens when creating new fields, and for backwards compatibility.
     1538         *
     1539         * Must be used inside the {@link bp_profile_fields()} template loop.
     1540         *
     1541         * @param array $args Optional. The arguments passed to {@link bp_the_profile_field_options()}.
     1542         * @since BuddyPress (2.0.0)
     1543         */
     1544        public function edit_field_options_html( array $args = array() ) {
     1545                $options = $this->field_obj->get_children();
     1546                $date    = BP_XProfile_ProfileData::get_value_byid( $this->field_obj->id, $args['user_id'] );
     1547
     1548                $day   = 0;
     1549                $month = 0;
     1550                $year  = 0;
     1551                $html  = '';
     1552
     1553                // Set day, month, year defaults
     1554                if ( ! empty( $date ) ) {
     1555
     1556                        // If Unix timestamp
     1557                        if ( is_numeric( $date ) ) {
     1558                                $day   = date( 'j', $date );
     1559                                $month = date( 'F', $date );
     1560                                $year  = date( 'Y', $date );
     1561
     1562                        // If MySQL timestamp
     1563                        } else {
     1564                                $day   = mysql2date( 'j', $date );
     1565                                $month = mysql2date( 'F', $date, false ); // Not localized, so that selected() works below
     1566                                $year  = mysql2date( 'Y', $date );
     1567                        }
     1568                }
     1569
     1570                // Check for updated posted values, and errors preventing them from being saved first time.
     1571                if ( ! empty( $_POST['field_' . $this->field_obj->id . '_day'] ) ) {
     1572                        $new_day = (int) $_POST['field_' . $this->field_obj->id . '_day'];
     1573                        $day     = ( $day != $new_day ) ? $new_day : $day;
     1574                }
     1575
     1576                if ( ! empty( $_POST['field_' . $this->field_obj->id . '_month'] ) ) {
     1577                        $new_month = (int) $_POST['field_' . $this->field_obj->id . '_month'];
     1578                        $month     = ( $month != $new_month ) ? $new_month : $month;
     1579                }
     1580
     1581                if ( ! empty( $_POST['field_' . $this->field_obj->id . '_year'] ) ) {
     1582                        $new_year = date( 'j', (int) $_POST['field_' . $this->field_obj->id . '_year'] );
     1583                        $year     = ( $year != $new_year ) ? $new_year : $year;
     1584                }
     1585
     1586                // $type will be passed by calling function when needed
     1587                switch ( $args['type'] ) {
     1588                        case 'day':
     1589                                $html = sprintf( '<option value="" %1$s>%2$s</option>', selected( $day, 0, false ), /* translators: no option picked in select box */ __( '----', 'buddypress' ) );
     1590
     1591                                for ( $i = 1; $i < 32; ++$i ) {
     1592                                        $html .= sprintf( '<option value="%1$s" %2$s>%3$s</option>', (int) $i, selected( $day, $i, false ), (int) $i );
     1593                                }
     1594                        break;
     1595
     1596                        case 'month':
     1597                                $eng_months = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );
     1598
     1599                                $months = array(
     1600                                        __( 'January', 'buddypress' ),
     1601                                        __( 'February', 'buddypress' ),
     1602                                        __( 'March', 'buddypress' ),
     1603                                        __( 'April', 'buddypress' ),
     1604                                        __( 'May', 'buddypress' ),
     1605                                        __( 'June', 'buddypress' ),
     1606                                        __( 'July', 'buddypress' ),
     1607                                        __( 'August', 'buddypress' ),
     1608                                        __( 'September', 'buddypress' ),
     1609                                        __( 'October', 'buddypress' ),
     1610                                        __( 'November', 'buddypress' ),
     1611                                        __( 'December', 'buddypress' )
     1612                                );
     1613
     1614                                $html = sprintf( '<option value="" %1$s>%2$s</option>', selected( $month, 0, false ), /* translators: no option picked in select box */ __( '----', 'buddypress' ) );
     1615
     1616                                for ( $i = 0; $i < 12; ++$i ) {
     1617                                        $html .= sprintf( '<option value="%1$s" %2$s>%3$s</option>', esc_attr( $eng_months[$i] ), selected( $month, $eng_months[$i], false ), $months[$i] );
     1618                                }
     1619                        break;
     1620
     1621                        case 'year':
     1622                                $html = sprintf( '<option value="" %1$s>%2$s</option>', selected( $year, 0, false ), /* translators: no option picked in select box */ __( '----', 'buddypress' ) );
     1623
     1624                                for ( $i = 2037; $i > 1901; $i-- ) {
     1625                                        $html .= sprintf( '<option value="%1$s" %2$s>%3$s</option>', (int) $i, selected( $year, $i, false ), (int) $i );
     1626                                }
     1627                        break;
     1628                }
     1629
     1630                echo apply_filters( 'bp_get_the_profile_field_datebox', $html, $args['type'], $day, $month, $year, $this->field_obj->id, $date );
     1631        }
     1632
     1633        /**
     1634         * Output HTML for this field type on the wp-admin Profile Fields screen.
     1635         *
     1636         * Must be used inside the {@link bp_profile_fields()} template loop.
     1637         *
     1638         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     1639         * @since BuddyPress (2.0.0)
     1640         */
     1641        public function admin_field_html( array $raw_properties = array() ) {
     1642                $day_html = $this->get_edit_field_html_elements( array_merge(
     1643                        array(
     1644                                'id'   => bp_get_the_profile_field_input_name() . '_day',
     1645                                'name' => bp_get_the_profile_field_input_name() . '_day',
     1646                        ),
     1647                        $raw_properties
     1648                ) );
     1649
     1650                $month_html = $this->get_edit_field_html_elements( array_merge(
     1651                        array(
     1652                                'id'   => bp_get_the_profile_field_input_name() . '_month',
     1653                                'name' => bp_get_the_profile_field_input_name() . '_month',
     1654                        ),
     1655                        $raw_properties
     1656                ) );
     1657
     1658                $year_html = $this->get_edit_field_html_elements( array_merge(
     1659                        array(
     1660                                'id'   => bp_get_the_profile_field_input_name() . '_year',
     1661                                'name' => bp_get_the_profile_field_input_name() . '_year',
     1662                        ),
     1663                        $raw_properties
     1664                ) );
     1665        ?>
     1666                <select <?php echo $day_html; ?>>
     1667                        <?php bp_the_profile_field_options( 'type=day' ); ?>
     1668                </select>
     1669
     1670                <select <?php echo $month_html; ?>>
     1671                        <?php bp_the_profile_field_options( 'type=month' ); ?>
     1672                </select>
     1673
     1674                <select <?php echo $year_html; ?>>
     1675                        <?php bp_the_profile_field_options( 'type=year' ); ?>
     1676                </select>
     1677        <?php
     1678        }
     1679
     1680        /**
     1681         * This method usually outputs HTML for this field type's children options on the wp-admin Profile Fields
     1682         * "Add Field" and "Edit Field" screens, but for this field type, we don't want it, so it's stubbed out.
     1683         *
     1684         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     1685         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     1686         * @since BuddyPress (2.0.0)
     1687         */
     1688        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {}
     1689}
     1690
     1691/**
     1692 * Checkbox xprofile field type.
     1693 *
     1694 * @since BuddyPress (2.0.0)
     1695 */
     1696class BP_XProfile_Field_Type_Checkbox extends BP_XProfile_Field_Type {
     1697
     1698        /**
     1699         * Constructor for the checkbox field type
     1700         *
     1701         * @since BuddyPress (2.0.0)
     1702         */
     1703        public function __construct() {
     1704                parent::__construct();
     1705
     1706                $this->category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
     1707                $this->name     = _x( 'Checkboxes', 'xprofile field type', 'buddypress' );
     1708
     1709                $this->supports_multiple_defaults = true;
     1710                $this->accepts_null_value         = true;
     1711                $this->supports_options           = true;
     1712
     1713                $this->set_format( '/^.+$/', 'replace' );
     1714                do_action( 'bp_xprofile_field_type_checkbox', $this );
     1715        }
     1716
     1717        /**
     1718         * Output the edit field HTML for this field type.
     1719         *
     1720         * Must be used inside the {@link bp_profile_fields()} template loop.
     1721         *
     1722         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/input.checkbox.html permitted attributes} that you want to add.
     1723         * @since BuddyPress (2.0.0)
     1724         */
     1725        public function edit_field_html( array $raw_properties = array() ) {
     1726                $user_id = bp_displayed_user_id();
     1727
     1728                // user_id is a special optional parameter that we pass to {@link bp_the_profile_field_options()}.
     1729                if ( isset( $raw_properties['user_id'] ) ) {
     1730                        $user_id = (int) $raw_properties['user_id'];
     1731                        unset( $raw_properties['user_id'] );
     1732                }
     1733        ?>
     1734                <div class="checkbox">
     1735
     1736                        <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     1737                        <?php bp_the_profile_field_options( "user_id={$user_id}" ); ?>
     1738
     1739                </div>
     1740                <?php
     1741        }
     1742
     1743        /**
     1744         * Output the edit field options HTML for this field type.
     1745         *
     1746         * BuddyPress considers a field's "options" to be, for example, the items in a selectbox.
     1747         * These are stored seperately in the database, and their templating is handled seperately.
     1748         *
     1749         * This templating is seperate from {@link BP_XProfile_Field_Type::edit_field_html()} because
     1750         * it's also used in the wp-admin screens when creating new fields, and for backwards compatibility.
     1751         *
     1752         * Must be used inside the {@link bp_profile_fields()} template loop.
     1753         *
     1754         * @param array $args Optional. The arguments passed to {@link bp_the_profile_field_options()}.
     1755         * @since BuddyPress (2.0.0)
     1756         */
     1757        public function edit_field_options_html( array $args = array() ) {
     1758                $options       = $this->field_obj->get_children();
     1759                $option_values = BP_XProfile_ProfileData::get_value_byid( $this->field_obj->id, $args['user_id'] );
     1760                $option_values = (array) maybe_unserialize( $option_values );
     1761
     1762                $html = '';
     1763
     1764                // Check for updated posted values, but errors preventing them from being saved first time
     1765                if ( isset( $_POST['field_' . $this->field_obj->id] ) && $option_values != maybe_serialize( $_POST['field_' . $this->field_obj->id] ) ) {
     1766                        if ( ! empty( $_POST['field_' . $this->field_obj->id] ) ) {
     1767                                $option_values = array_map( 'sanitize_text_field', $_POST['field_' . $this->field_obj->id] );
     1768                        }
     1769                }
     1770
     1771                for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
     1772                        $selected = '';
     1773
     1774                        // First, check to see whether the user's saved values match the option
     1775                        for ( $j = 0, $count_values = count( $option_values ); $j < $count_values; ++$j ) {
     1776
     1777                                // Run the allowed option name through the before_save filter, so we'll be sure to get a match
     1778                                $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
     1779
     1780                                if ( $option_values[$j] === $allowed_options || in_array( $allowed_options, $option_values ) ) {
     1781                                        $selected = ' checked="checked"';
     1782                                        break;
     1783                                }
     1784                        }
     1785
     1786                        // If the user has not yet supplied a value for this field, check to see whether there is a default value available
     1787                        if ( ! is_array( $option_values ) && empty( $option_values ) && empty( $selected ) && ! empty( $options[$k]->is_default_option ) ) {
     1788                                $selected = ' checked="checked"';
     1789                        }
     1790
     1791                        $new_html = sprintf( '<label><input %1$s type="checkbox" name="%2$s" id="%3$s" value="%4$s">%5$s</label>',
     1792                                $selected,
     1793                                esc_attr( "field_{$this->field_obj->id}[]" ),
     1794                                esc_attr( "field_{$options[$k]->id}_{$k}" ),
     1795                                esc_attr( stripslashes( $options[$k]->name ) ),
     1796                                esc_html( stripslashes( $options[$k]->name ) )
     1797                        );
     1798                        $html .= apply_filters( 'bp_get_the_profile_field_options_checkbox', $new_html, $options[$k], $this->field_obj->id, $selected, $k );
     1799                }
     1800
     1801                echo $html;
     1802        }
     1803
     1804        /**
     1805         * Output HTML for this field type on the wp-admin Profile Fields screen.
     1806         *
     1807         * Must be used inside the {@link bp_profile_fields()} template loop.
     1808         *
     1809         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     1810         * @since BuddyPress (2.0.0)
     1811         */
     1812        public function admin_field_html( array $raw_properties = array() ) {
     1813                bp_the_profile_field_options();
     1814        }
     1815
     1816        /**
     1817         * Output HTML for this field type's children options on the wp-admin Profile Fields "Add Field" and "Edit Field" screens.
     1818         *
     1819         * Must be used inside the {@link bp_profile_fields()} template loop.
     1820         *
     1821         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     1822         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     1823         * @since BuddyPress (2.0.0)
     1824         */
     1825        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {
     1826                parent::admin_new_field_html( $current_field, 'checkbox' );
     1827        }
     1828}
     1829
     1830/**
     1831 * Radio button xprofile field type.
     1832 *
     1833 * @since BuddyPress (2.0.0)
     1834 */
     1835class BP_XProfile_Field_Type_Radiobutton extends BP_XProfile_Field_Type {
     1836
     1837        /**
     1838         * Constructor for the radio button field type
     1839         *
     1840         * @since BuddyPress (2.0.0)
     1841         */
     1842        public function __construct() {
     1843                parent::__construct();
     1844
     1845                $this->category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
     1846                $this->name     = _x( 'Radio Buttons', 'xprofile field type', 'buddypress' );
     1847
     1848                $this->supports_options = true;
     1849
     1850                $this->set_format( '/^.+$/', 'replace' );
     1851                do_action( 'bp_xprofile_field_type_radiobutton', $this );
     1852        }
     1853
     1854        /**
     1855         * Output the edit field HTML for this field type.
     1856         *
     1857         * Must be used inside the {@link bp_profile_fields()} template loop.
     1858         *
     1859         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/input.radio.html permitted attributes} that you want to add.
     1860         * @since BuddyPress (2.0.0)
     1861         */
     1862        public function edit_field_html( array $raw_properties = array() ) {
     1863                $user_id = bp_displayed_user_id();
     1864
     1865                // user_id is a special optional parameter that we pass to {@link bp_the_profile_field_options()}.
     1866                if ( isset( $raw_properties['user_id'] ) ) {
     1867                        $user_id = (int) $raw_properties['user_id'];
     1868                        unset( $raw_properties['user_id'] );
     1869                }
     1870        ?>
     1871                <div class="radio">
     1872
     1873                        <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     1874                        <?php bp_the_profile_field_options( "user_id={$user_id}" );
     1875
     1876                        if ( ! bp_get_the_profile_field_is_required() ) : ?>
     1877                                <a class="clear-value" href="javascript:clear( '<?php echo esc_js( bp_get_the_profile_field_input_name() ); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
     1878                        <?php endif; ?>
     1879
     1880                </div>
     1881                <?php
     1882        }
     1883
     1884        /**
     1885         * Output the edit field options HTML for this field type.
     1886         *
     1887         * BuddyPress considers a field's "options" to be, for example, the items in a selectbox.
     1888         * These are stored seperately in the database, and their templating is handled seperately.
     1889         *
     1890         * This templating is seperate from {@link BP_XProfile_Field_Type::edit_field_html()} because
     1891         * it's also used in the wp-admin screens when creating new fields, and for backwards compatibility.
     1892         *
     1893         * Must be used inside the {@link bp_profile_fields()} template loop.
     1894         *
     1895         * @param array $args Optional. The arguments passed to {@link bp_the_profile_field_options()}.
     1896         * @since BuddyPress (2.0.0)
     1897         */
     1898        public function edit_field_options_html( array $args = array() ) {
     1899                $option_value = BP_XProfile_ProfileData::get_value_byid( $this->field_obj->id, $args['user_id'] );
     1900                $options      = $this->field_obj->get_children();
     1901
     1902                $html = sprintf( '<div id="%s">', esc_attr( 'field_' . $this->field_obj->id ) );
     1903
     1904                for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
     1905
     1906                        // Check for updated posted values, but errors preventing them from being saved first time
     1907                        if ( isset( $_POST['field_' . $this->field_obj->id] ) && $option_value != $_POST['field_' . $this->field_obj->id] ) {
     1908                                if ( ! empty( $_POST['field_' . $this->field_obj->id] ) ) {
     1909                                        $option_value = sanitize_text_field( $_POST['field_' . $this->field_obj->id] );
     1910                                }
     1911                        }
     1912
     1913                        // Run the allowed option name through the before_save filter, so we'll be sure to get a match
     1914                        $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
     1915                        $selected        = '';
     1916
     1917                        if ( $option_value === $allowed_options || ( empty( $option_value ) && ! empty( $options[$k]->is_default_option ) ) ) {
     1918                                $selected = ' checked="checked"';
     1919                        }
     1920
     1921                        $new_html = sprintf( '<label><input %1$s type="radio" name="%2$s" id="%3$s" value="%4$s">%5$s</label>',
     1922                                $selected,
     1923                                esc_attr( "field_{$this->field_obj->id}" ),
     1924                                esc_attr( "option_{$options[$k]->id}" ),
     1925                                esc_attr( stripslashes( $options[$k]->name ) ),
     1926                                esc_html( stripslashes( $options[$k]->name ) )
     1927                        );
     1928                        $html .= apply_filters( 'bp_get_the_profile_field_options_radio', $new_html, $options[$k], $this->field_obj->id, $selected, $k );
     1929                }
     1930
     1931                echo $html . '</div>';
     1932        }
     1933
     1934        /**
     1935         * Output HTML for this field type on the wp-admin Profile Fields screen.
     1936         *
     1937         * Must be used inside the {@link bp_profile_fields()} template loop.
     1938         *
     1939         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     1940         * @since BuddyPress (2.0.0)
     1941         */
     1942        public function admin_field_html( array $raw_properties = array() ) {
     1943                bp_the_profile_field_options();
     1944
     1945                if ( ! bp_get_the_profile_field_is_required() ) : ?>
     1946                        <a class="clear-value" href="javascript:clear( '<?php echo esc_js( bp_get_the_profile_field_input_name() ); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
     1947                <?php endif; ?>
     1948        <?php
     1949        }
     1950
     1951        /**
     1952         * Output HTML for this field type's children options on the wp-admin Profile Fields "Add Field" and "Edit Field" screens.
     1953         *
     1954         * Must be used inside the {@link bp_profile_fields()} template loop.
     1955         *
     1956         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     1957         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     1958         * @since BuddyPress (2.0.0)
     1959         */
     1960        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {
     1961                parent::admin_new_field_html( $current_field, 'radio' );
     1962        }
     1963}
     1964
     1965/**
     1966 * Multi-selectbox xprofile field type.
     1967 *
     1968 * @since BuddyPress (2.0.0)
     1969 */
     1970class BP_XProfile_Field_Type_Multiselectbox extends BP_XProfile_Field_Type {
     1971
     1972        /**
     1973         * Constructor for the multi-selectbox field type
     1974         *
     1975         * @since BuddyPress (2.0.0)
     1976         */
     1977        public function __construct() {
     1978                parent::__construct();
     1979
     1980                $this->category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
     1981                $this->name     = _x( 'Multi Select Box', 'xprofile field type', 'buddypress' );
     1982
     1983                $this->supports_multiple_defaults = true;
     1984                $this->accepts_null_value         = true;
     1985                $this->supports_options           = true;
     1986
     1987                $this->set_format( '/^.+$/', 'replace' );
     1988                do_action( 'bp_xprofile_field_type_multiselectbox', $this );
     1989        }
     1990
     1991        /**
     1992         * Output the edit field HTML for this field type.
     1993         *
     1994         * Must be used inside the {@link bp_profile_fields()} template loop.
     1995         *
     1996         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/select.html permitted attributes} that you want to add.
     1997         * @since BuddyPress (2.0.0)
     1998         */
     1999        public function edit_field_html( array $raw_properties = array() ) {
     2000                $user_id = bp_displayed_user_id();
     2001
     2002                // user_id is a special optional parameter that we pass to {@link bp_the_profile_field_options()}.
     2003                if ( isset( $raw_properties['user_id'] ) ) {
     2004                        $user_id = (int) $raw_properties['user_id'];
     2005                        unset( $raw_properties['user_id'] );
     2006                }
     2007
     2008                $html = $this->get_edit_field_html_elements( array_merge(
     2009                        array( 'multiple' => 'multiple' ),
     2010                        $raw_properties
     2011                ) );
     2012        ?>
     2013                <label for="<?php bp_the_profile_field_input_name(); ?>[]"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     2014                <select <?php echo $html; ?>>
     2015                        <?php bp_the_profile_field_options( "user_id={$user_id}" ); ?>
     2016                </select>
     2017
     2018                <?php if ( ! bp_get_the_profile_field_is_required() ) : ?>
     2019                        <a class="clear-value" href="javascript:clear( '<?php echo esc_js( bp_get_the_profile_field_input_name() ); ?>[]' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
     2020                <?php endif; ?>
     2021        <?php
     2022        }
     2023
     2024        /**
     2025         * Output the edit field options HTML for this field type.
     2026         *
     2027         * BuddyPress considers a field's "options" to be, for example, the items in a selectbox.
     2028         * These are stored seperately in the database, and their templating is handled seperately.
     2029         *
     2030         * This templating is seperate from {@link BP_XProfile_Field_Type::edit_field_html()} because
     2031         * it's also used in the wp-admin screens when creating new fields, and for backwards compatibility.
     2032         *
     2033         * Must be used inside the {@link bp_profile_fields()} template loop.
     2034         *
     2035         * @param array $args Optional. The arguments passed to {@link bp_the_profile_field_options()}.
     2036         * @since BuddyPress (2.0.0)
     2037         */
     2038        public function edit_field_options_html( array $args = array() ) {
     2039                $original_option_values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $this->field_obj->id, $args['user_id'] ) );
     2040
     2041                $options = $this->field_obj->get_children();
     2042                $html    = '';
     2043
     2044                if ( empty( $original_option_values ) && ! empty( $_POST['field_' . $this->field_obj->id] ) ) {
     2045                        $original_option_values = sanitize_text_field( $_POST['field_' . $this->field_obj->id] );
     2046                }
     2047
     2048                $option_values = (array) $original_option_values;
     2049                for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
     2050                        $selected = '';
     2051
     2052                        // Check for updated posted values, but errors preventing them from being saved first time
     2053                        foreach( $option_values as $i => $option_value ) {
     2054                                if ( isset( $_POST['field_' . $this->field_obj->id] ) && $_POST['field_' . $this->field_obj->id][$i] != $option_value ) {
     2055                                        if ( ! empty( $_POST['field_' . $this->field_obj->id][$i] ) ) {
     2056                                                $option_values[] = sanitize_text_field( $_POST['field_' . $this->field_obj->id][$i] );
     2057                                        }
     2058                                }
     2059                        }
     2060
     2061                        // Run the allowed option name through the before_save filter, so we'll be sure to get a match
     2062                        $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
     2063
     2064                        // First, check to see whether the user-entered value matches
     2065                        if ( in_array( $allowed_options, $option_values ) ) {
     2066                                $selected = ' selected="selected"';
     2067                        }
     2068
     2069                        // Then, if the user has not provided a value, check for defaults
     2070                        if ( ! is_array( $original_option_values ) && empty( $option_values ) && ! empty( $options[$k]->is_default_option ) ) {
     2071                                $selected = ' selected="selected"';
     2072                        }
     2073
     2074                        $html .= apply_filters( 'bp_get_the_profile_field_options_multiselect', '<option' . $selected . ' value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '">' . esc_html( stripslashes( $options[$k]->name ) ) . '</option>', $options[$k], $this->field_obj->id, $selected, $k );
     2075                }
     2076
     2077                echo $html;
     2078        }
     2079
     2080        /**
     2081         * Output HTML for this field type on the wp-admin Profile Fields screen.
     2082         *
     2083         * Must be used inside the {@link bp_profile_fields()} template loop.
     2084         *
     2085         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     2086         * @since BuddyPress (2.0.0)
     2087         */
     2088        public function admin_field_html( array $raw_properties = array() ) {
     2089                $html = $this->get_edit_field_html_elements( array_merge(
     2090                        array( 'multiple' => 'multiple' ),
     2091                        $raw_properties
     2092                ) );
     2093        ?>
     2094                <select <?php echo $html; ?>>
     2095                        <?php bp_the_profile_field_options(); ?>
     2096                </select>
     2097        <?php
     2098        }
     2099
     2100        /**
     2101         * Output HTML for this field type's children options on the wp-admin Profile Fields "Add Field" and "Edit Field" screens.
     2102         *
     2103         * Must be used inside the {@link bp_profile_fields()} template loop.
     2104         *
     2105         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     2106         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     2107         * @since BuddyPress (2.0.0)
     2108         */
     2109        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {
     2110                parent::admin_new_field_html( $current_field, 'checkbox' );
     2111        }
     2112}
     2113
     2114/**
     2115 * Selectbox xprofile field type.
     2116 *
     2117 * @since BuddyPress (2.0.0)
     2118 */
     2119class BP_XProfile_Field_Type_Selectbox extends BP_XProfile_Field_Type {
     2120
     2121        /**
     2122         * Constructor for the selectbox field type
     2123         *
     2124         * @since BuddyPress (2.0.0)
     2125         */
     2126        public function __construct() {
     2127                parent::__construct();
     2128
     2129                $this->category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
     2130                $this->name     = _x( 'Drop Down Select Box', 'xprofile field type', 'buddypress' );
     2131
     2132                $this->supports_options = true;
     2133
     2134                $this->set_format( '/^.+$/', 'replace' );
     2135                do_action( 'bp_xprofile_field_type_selectbox', $this );
     2136        }
     2137
     2138        /**
     2139         * Output the edit field HTML for this field type.
     2140         *
     2141         * Must be used inside the {@link bp_profile_fields()} template loop.
     2142         *
     2143         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/select.html permitted attributes} that you want to add.
     2144         * @since BuddyPress (2.0.0)
     2145         */
     2146        public function edit_field_html( array $raw_properties = array() ) {
     2147                $user_id = bp_displayed_user_id();
     2148
     2149                // user_id is a special optional parameter that we pass to {@link bp_the_profile_field_options()}.
     2150                if ( isset( $raw_properties['user_id'] ) ) {
     2151                        $user_id = (int) $raw_properties['user_id'];
     2152                        unset( $raw_properties['user_id'] );
     2153                }
     2154
     2155                $html = $this->get_edit_field_html_elements( $raw_properties );
     2156        ?>
     2157                <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     2158                <select <?php echo $html; ?>>
     2159                        <?php bp_the_profile_field_options( "user_id={$user_id}" ); ?>
     2160                </select>
     2161        <?php
     2162        }
     2163
     2164        /**
     2165         * Output the edit field options HTML for this field type.
     2166         *
     2167         * BuddyPress considers a field's "options" to be, for example, the items in a selectbox.
     2168         * These are stored seperately in the database, and their templating is handled seperately.
     2169         *
     2170         * This templating is seperate from {@link BP_XProfile_Field_Type::edit_field_html()} because
     2171         * it's also used in the wp-admin screens when creating new fields, and for backwards compatibility.
     2172         *
     2173         * Must be used inside the {@link bp_profile_fields()} template loop.
     2174         *
     2175         * @param array $args Optional. The arguments passed to {@link bp_the_profile_field_options()}.
     2176         * @since BuddyPress (2.0.0)
     2177         */
     2178        public function edit_field_options_html( array $args = array() ) {
     2179                $original_option_values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $this->field_obj->id, $args['user_id'] ) );
     2180
     2181                $options = $this->field_obj->get_children();
     2182                $html     = '<option value="">' . /* translators: no option picked in select box */ __( '----', 'buddypress' ) . '</option>';
     2183
     2184                if ( empty( $original_option_values ) && !empty( $_POST['field_' . $this->field_obj->id] ) ) {
     2185                        $original_option_values = sanitize_text_field(  $_POST['field_' . $this->field_obj->id] );
     2186                }
     2187
     2188                $option_values = (array) $original_option_values;
     2189                for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
     2190                        $selected = '';
     2191
     2192                        // Check for updated posted values, but errors preventing them from being saved first time
     2193                        foreach( $option_values as $i => $option_value ) {
     2194                                if ( isset( $_POST['field_' . $this->field_obj->id] ) && $_POST['field_' . $this->field_obj->id] != $option_value ) {
     2195                                        if ( ! empty( $_POST['field_' . $this->field_obj->id] ) ) {
     2196                                                $option_values[$i] = sanitize_text_field( $_POST['field_' . $this->field_obj->id] );
     2197                                        }
     2198                                }
     2199                        }
     2200
     2201                        // Run the allowed option name through the before_save filter, so we'll be sure to get a match
     2202                        $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
     2203
     2204                        // First, check to see whether the user-entered value matches
     2205                        if ( in_array( $allowed_options, $option_values ) ) {
     2206                                $selected = ' selected="selected"';
     2207                        }
     2208
     2209                        // Then, if the user has not provided a value, check for defaults
     2210                        if ( ! is_array( $original_option_values ) && empty( $option_values ) && $options[$k]->is_default_option ) {
     2211                                $selected = ' selected="selected"';
     2212                        }
     2213
     2214                        $html .= apply_filters( 'bp_get_the_profile_field_options_select', '<option' . $selected . ' value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '">' . esc_html( stripslashes( $options[$k]->name ) ) . '</option>', $options[$k], $this->field_obj->id, $selected, $k );
     2215                }
     2216
     2217                echo $html;
     2218        }
     2219
     2220        /**
     2221         * Output HTML for this field type on the wp-admin Profile Fields screen.
     2222         *
     2223         * Must be used inside the {@link bp_profile_fields()} template loop.
     2224         *
     2225         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     2226         * @since BuddyPress (2.0.0)
     2227         */
     2228        public function admin_field_html( array $raw_properties = array() ) {
     2229                $html = $this->get_edit_field_html_elements( $raw_properties );
     2230        ?>
     2231                <select <?php echo $html; ?>>
     2232                        <?php bp_the_profile_field_options(); ?>
     2233                </select>
     2234        <?php
     2235        }
     2236
     2237        /**
     2238         * Output HTML for this field type's children options on the wp-admin Profile Fields "Add Field" and "Edit Field" screens.
     2239         *
     2240         * Must be used inside the {@link bp_profile_fields()} template loop.
     2241         *
     2242         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     2243         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     2244         * @since BuddyPress (2.0.0)
     2245         */
     2246        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {
     2247                parent::admin_new_field_html( $current_field, 'radio' );
     2248        }
     2249}
     2250
     2251/**
     2252 * Textarea xprofile field type.
     2253 *
     2254 * @since BuddyPress (2.0.0)
     2255 */
     2256class BP_XProfile_Field_Type_Textarea extends BP_XProfile_Field_Type {
     2257
     2258        /**
     2259         * Constructor for the textarea field type
     2260         *
     2261         * @since BuddyPress (2.0.0)
     2262         */
     2263        public function __construct() {
     2264                parent::__construct();
     2265
     2266                $this->category = _x( 'Single Fields', 'xprofile field type category', 'buddypress' );
     2267                $this->name     = _x( 'Multi-line Text Area', 'xprofile field type', 'buddypress' );
     2268
     2269                $this->set_format( '/^.*$/m', 'replace' );
     2270                do_action( 'bp_xprofile_field_type_textarea', $this );
     2271        }
     2272
     2273        /**
     2274         * Output the edit field HTML for this field type.
     2275         *
     2276         * Must be used inside the {@link bp_profile_fields()} template loop.
     2277         *
     2278         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/textarea.html permitted attributes} that you want to add.
     2279         * @since BuddyPress (2.0.0)
     2280         */
     2281        public function edit_field_html( array $raw_properties = array() ) {
     2282
     2283                // user_id is a special optional parameter that certain other fields types pass to {@link bp_the_profile_field_options()}.
     2284                if ( isset( $raw_properties['user_id'] ) ) {
     2285                        unset( $raw_properties['user_id'] );
     2286                }
     2287
     2288                $html = $this->get_edit_field_html_elements( array_merge(
     2289                        array(
     2290                                'cols' => 40,
     2291                                'rows' => 5,
     2292                        ),
     2293                        $raw_properties
     2294                ) );
     2295        ?>
     2296                <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     2297                <textarea <?php echo $html; ?>><?php bp_the_profile_field_edit_value(); ?></textarea>
     2298        <?php
     2299        }
     2300
     2301        /**
     2302         * Output HTML for this field type on the wp-admin Profile Fields screen.
     2303         *
     2304         * Must be used inside the {@link bp_profile_fields()} template loop.
     2305         *
     2306         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     2307         * @since BuddyPress (2.0.0)
     2308         */
     2309        public function admin_field_html( array $raw_properties = array() ) {
     2310                $html = $this->get_edit_field_html_elements( array_merge(
     2311                        array(
     2312                                'cols' => 40,
     2313                                'rows' => 5,
     2314                        ),
     2315                        $raw_properties
     2316                ) );
     2317        ?>
     2318                <textarea <?php echo $html; ?>></textarea>
     2319        <?php
     2320        }
     2321
     2322        /**
     2323         * This method usually outputs HTML for this field type's children options on the wp-admin Profile Fields
     2324         * "Add Field" and "Edit Field" screens, but for this field type, we don't want it, so it's stubbed out.
     2325         *
     2326         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     2327         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     2328         * @since BuddyPress (2.0.0)
     2329         */
     2330        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {}
     2331}
     2332
     2333/**
     2334 * Textbox xprofile field type.
     2335 *
     2336 * @since BuddyPress (2.0.0)
     2337 */
     2338class BP_XProfile_Field_Type_Textbox extends BP_XProfile_Field_Type {
     2339
     2340        /**
     2341         * Constructor for the textbox field type
     2342         *
     2343         * @since BuddyPress (2.0.0)
     2344         */
     2345        public function __construct() {
     2346                parent::__construct();
     2347
     2348                $this->category = _x( 'Single Fields', 'xprofile field type category', 'buddypress' );
     2349                $this->name     = _x( 'Text Box', 'xprofile field type', 'buddypress' );
     2350
     2351                $this->set_format( '/^.*$/', 'replace' );
     2352                do_action( 'bp_xprofile_field_type_textbox', $this );
     2353        }
     2354
     2355        /**
     2356         * Output the edit field HTML for this field type.
     2357         *
     2358         * Must be used inside the {@link bp_profile_fields()} template loop.
     2359         *
     2360         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/input.text.html permitted attributes} that you want to add.
     2361         * @since BuddyPress (2.0.0)
     2362         */
     2363        public function edit_field_html( array $raw_properties = array() ) {
     2364
     2365                // user_id is a special optional parameter that certain other fields types pass to {@link bp_the_profile_field_options()}.
     2366                if ( isset( $raw_properties['user_id'] ) ) {
     2367                        unset( $raw_properties['user_id'] );
     2368                }
     2369
     2370                $html = $this->get_edit_field_html_elements( array_merge(
     2371                        array(
     2372                                'type'  => 'text',
     2373                                'value' => bp_get_the_profile_field_edit_value(),
     2374                        ),
     2375                        $raw_properties
     2376                ) );
     2377        ?>
     2378                <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     2379                <input <?php echo $html; ?>>
     2380        <?php
     2381        }
     2382
     2383        /**
     2384         * Output HTML for this field type on the wp-admin Profile Fields screen.
     2385         *
     2386         * Must be used inside the {@link bp_profile_fields()} template loop.
     2387         *
     2388         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     2389         * @since BuddyPress (2.0.0)
     2390         */
     2391        public function admin_field_html( array $raw_properties = array() ) {
     2392                $html = $this->get_edit_field_html_elements( array_merge(
     2393                        array( 'type' => 'text' ),
     2394                        $raw_properties
     2395                ) );
     2396        ?>
     2397                <input <?php echo $html; ?>>
     2398        <?php
     2399        }
     2400
     2401        /**
     2402         * This method usually outputs HTML for this field type's children options on the wp-admin Profile Fields
     2403         * "Add Field" and "Edit Field" screens, but for this field type, we don't want it, so it's stubbed out.
     2404         *
     2405         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     2406         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     2407         * @since BuddyPress (2.0.0)
     2408         */
     2409        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {}
     2410}
     2411
     2412/**
     2413 * Number xprofile field type.
     2414 *
     2415 * @since BuddyPress (2.0.0)
     2416 */
     2417class BP_XProfile_Field_Type_Number extends BP_XProfile_Field_Type {
     2418
     2419        /**
     2420         * Constructor for the number field type
     2421         *
     2422         * @since BuddyPress (2.0.0)
     2423         */
     2424        public function __construct() {
     2425                parent::__construct();
     2426
     2427                $this->category = _x( 'Single Fields', 'xprofile field type category', 'buddypress' );
     2428                $this->name     = _x( 'Number', 'xprofile field type', 'buddypress' );
     2429
     2430                $this->set_format( '/^\d+$/', 'replace' );
     2431                do_action( 'bp_xprofile_field_type_number', $this );
     2432        }
     2433
     2434        /**
     2435         * Output the edit field HTML for this field type.
     2436         *
     2437         * Must be used inside the {@link bp_profile_fields()} template loop.
     2438         *
     2439         * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/input.number.html permitted attributes} that you want to add.
     2440         * @since BuddyPress (2.0.0)
     2441         */
     2442        public function edit_field_html( array $raw_properties = array() ) {
     2443
     2444                // user_id is a special optional parameter that certain other fields types pass to {@link bp_the_profile_field_options()}.
     2445                if ( isset( $raw_properties['user_id'] ) ) {
     2446                        unset( $raw_properties['user_id'] );
     2447                }
     2448
     2449                $html = $this->get_edit_field_html_elements( array_merge(
     2450                        array(
     2451                                'type'  => 'number',
     2452                                'value' => bp_get_the_profile_field_edit_value(),
     2453                        ),
     2454                        $raw_properties
     2455                ) );
     2456        ?>
     2457                <label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
     2458                <input <?php echo $html; ?>>
     2459        <?php
     2460        }
     2461
     2462        /**
     2463         * Output HTML for this field type on the wp-admin Profile Fields screen.
     2464         *
     2465         * Must be used inside the {@link bp_profile_fields()} template loop.
     2466         *
     2467         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     2468         * @since BuddyPress (2.0.0)
     2469         */
     2470        public function admin_field_html( array $raw_properties = array() ) {
     2471                $html = $this->get_edit_field_html_elements( array_merge(
     2472                        array( 'type' => 'number' ),
     2473                        $raw_properties
     2474                ) );
     2475        ?>
     2476                <input <?php echo $html; ?>>
     2477        <?php
     2478        }
     2479
     2480        /**
     2481         * This method usually outputs HTML for this field type's children options on the wp-admin Profile Fields
     2482         * "Add Field" and "Edit Field" screens, but for this field type, we don't want it, so it's stubbed out.
     2483         *
     2484         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     2485         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     2486         * @since BuddyPress (2.0.0)
     2487         */
     2488        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {}
     2489}
     2490
     2491/**
     2492 * Represents a type of XProfile field and holds meta information about the type of value that it accepts.
     2493 *
     2494 * @since BuddyPress (2.0.0)
     2495 */
     2496abstract class BP_XProfile_Field_Type {
     2497
     2498        /**
     2499         * @since BuddyPress (2.0.0)
     2500         * @var array Field type validation regexes
     2501         */
     2502        protected $validation_regex = array();
     2503
     2504        /**
     2505         * @since BuddyPress (2.0.0)
     2506         * @var array Field type whitelisted values
     2507         */
     2508        protected $validation_whitelist = array();
     2509
     2510        /**
     2511         * @since BuddyPress (2.0.0)
     2512         * @var string The name of this field type
     2513         */
     2514        public $name = '';
     2515
     2516        /**
     2517         * The name of the category that this field type should be grouped with. Used on the [Users > Profile Fields] screen in wp-admin.
     2518         *
     2519         * @since BuddyPress (2.0.0)
     2520         * @var string
     2521         */
     2522        public $category = '';
     2523
     2524        /**
     2525         * @since BuddyPress (2.0.0)
     2526         * @var bool If this is set, allow BP to store null/empty values for this field type.
     2527         */
     2528        public $accepts_null_value = false;
     2529
     2530        /**
     2531         * If this is set, BP will set this field type's validation whitelist from the field's options (e.g checkbox, selectbox).
     2532         *
     2533         * @since BuddyPress (2.0.0)
     2534         * @var bool Does this field support options? e.g. selectbox, radio buttons, etc.
     2535         */
     2536        public $supports_options = false;
     2537
     2538        /**
     2539         * @since BuddyPress (2.0.0)
     2540         * @var bool Does this field type support multiple options being set as default values? e.g. multiselectbox, checkbox.
     2541         */
     2542        public $supports_multiple_defaults = false;
     2543
     2544        /**
     2545         * @since BuddyPress (2.0.0)
     2546         * @var BP_XProfile_Field If this object is created by instantiating a {@link BP_XProfile_Field}, this is a reference back to that object.
     2547         */
     2548        public $field_obj = null;
     2549
     2550        /**
     2551         * Constructor
     2552         *
     2553         * @since BuddyPress (2.0.0)
     2554         */
     2555        public function __construct() {
     2556                do_action( 'bp_xprofile_field_type', $this );
     2557        }
     2558
     2559        /**
     2560         * Set a regex that profile data will be asserted against.
     2561         *
     2562         * You can call this method multiple times to set multiple formats. When validation is performed,
     2563         * it's successful as long as the new value matches any one of the registered formats.
     2564         *
     2565         * @param string $format Regex string
     2566         * @param string $replace_format Optional; if 'replace', replaces the format instead of adding to it. Defaults to 'add'.
     2567         * @return BP_XProfile_Field_Type
     2568         * @since BuddyPress (2.0.0)
     2569         */
     2570        public function set_format( $format, $replace_format = 'add' ) {
     2571
     2572                $format = apply_filters( 'bp_xprofile_field_type_set_format', $format, $replace_format, $this );
     2573
     2574                if ( $replace_format === 'add' ) {
     2575                        $this->validation_regex[] = $format;
     2576                } elseif ( $replace_format === 'replace' ) {
     2577                        $this->validation_regex = array( $format );
     2578                }
     2579
     2580                return $this;
     2581        }
     2582
     2583        /**
     2584         * Add a value to this type's whitelist that that profile data will be asserted against.
     2585         *
     2586         * You can call this method multiple times to set multiple formats. When validation is performed,
     2587         * it's successful as long as the new value matches any one of the registered formats.
     2588         *
     2589         * @param string|array $values
     2590         * @return BP_XProfile_Field_Type
     2591         * @since BuddyPress (2.0.0)
     2592         */
     2593        public function set_whitelist_values( $values ) {
     2594                foreach ( (array) $values as $value ) {
     2595                        $this->validation_whitelist[] = apply_filters( 'bp_xprofile_field_type_set_whitelist_values', $value, $values, $this );
     2596                }
     2597
     2598                return $this;
     2599        }
     2600
     2601        /**
     2602         * Check the given string against the registered formats for this field type.
     2603         *
     2604         * This method doesn't support chaining.
     2605         *
     2606         * @param string|array $values Value to check against the registered formats
     2607         * @return bool True if the value validates
     2608         * @since BuddyPress (2.0.0)
     2609         */
     2610        public function is_valid( $values ) {
     2611                $validated = false;
     2612
     2613                // Some types of field (e.g. multi-selectbox) may have multiple values to check
     2614                foreach ( (array) $values as $value ) {
     2615
     2616                        // Validate the $value against the type's accepted format(s).
     2617                        foreach ( $this->validation_regex as $format ) {
     2618                                if ( 1 === preg_match( $format, $value ) ) {
     2619                                        $validated = true;
     2620                                        continue;
     2621
     2622                                } else {
     2623                                        $validated = false;
     2624                                }
     2625                        }
     2626                }
     2627
     2628                // Handle field types with accepts_null_value set if $values is an empty array
     2629                if ( ! $validated && is_array( $values ) && empty( $values ) && $this->accepts_null_value ) {
     2630                        $validated = true;
     2631                }
     2632
     2633                // If there's a whitelist set, also check the $value.
     2634                if ( $validated && ! empty( $values ) && ! empty( $this->validation_whitelist ) ) {
     2635
     2636                        foreach ( (array) $values as $value ) {
     2637                                $validated = in_array( $value, $this->validation_whitelist, true );
     2638                        }
     2639                }
     2640
     2641                return (bool) apply_filters( 'bp_xprofile_field_type_is_valid', $validated, $values, $this );
     2642        }
     2643
     2644        /**
     2645         * Output the edit field HTML for this field type.
     2646         *
     2647         * Must be used inside the {@link bp_profile_fields()} template loop.
     2648         *
     2649         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     2650         * @since BuddyPress (2.0.0)
     2651         */
     2652        abstract public function edit_field_html( array $raw_properties = array() );
     2653
     2654        /**
     2655         * Output the edit field options HTML for this field type.
     2656         *
     2657         * BuddyPress considers a field's "options" to be, for example, the items in a selectbox.
     2658         * These are stored seperately in the database, and their templating is handled seperately.
     2659         * Populate this method in a child class if it's required. Otherwise, you can leave it out.
     2660         *
     2661         * This templating is seperate from {@link BP_XProfile_Field_Type::edit_field_html()} because
     2662         * it's also used in the wp-admin screens when creating new fields, and for backwards compatibility.
     2663         *
     2664         * Must be used inside the {@link bp_profile_fields()} template loop.
     2665         *
     2666         * @param array $args Optional. The arguments passed to {@link bp_the_profile_field_options()}.
     2667         * @since BuddyPress (2.0.0)
     2668         */
     2669        public function edit_field_options_html( array $args = array() ) {}
     2670
     2671        /**
     2672         * Output HTML for this field type on the wp-admin Profile Fields screen.
     2673         *
     2674         * Must be used inside the {@link bp_profile_fields()} template loop.
     2675         *
     2676         * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
     2677         * @since BuddyPress (2.0.0)
     2678         */
     2679        abstract public function admin_field_html( array $raw_properties = array() );
     2680
     2681        /**
     2682         * Output HTML for this field type's children options on the wp-admin Profile Fields "Add Field" and "Edit Field" screens.
     2683         *
     2684         * You don't need to implement this method for all field types. It's used in core by the
     2685         * selectbox, multi selectbox, checkbox, and radio button fields, to allow the admin to
     2686         * enter the child option values (e.g. the choices in a select box).
     2687         *
     2688         * Must be used inside the {@link bp_profile_fields()} template loop.
     2689         *
     2690         * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
     2691         * @param string $control_type Optional. HTML input type used to render the current field's child options.
     2692         * @since BuddyPress (2.0.0)
     2693         */
     2694        public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {
     2695                $type = array_search( get_class( $this ), bp_xprofile_get_field_types() );
     2696                if ( $type === false ) {
     2697                        return;
     2698                }
     2699
     2700                $class            = $current_field->type != $type ? 'display: none;' : '';
     2701                $current_type_obj = bp_xprofile_create_field_type( $type );
     2702                ?>
     2703
     2704                <div id="<?php echo esc_attr( $type ); ?>" class="postbox bp-options-box" style="<?php echo esc_attr( $class ); ?> margin-top: 15px;">
     2705                        <h3><?php _e( 'Please enter options for this Field:', 'buddypress' ); ?></h3>
     2706                        <div class="inside">
     2707                                <p>
     2708                                        <label for="sort_order_<?php echo esc_attr( $type ); ?>"><?php _e( 'Sort Order:', 'buddypress' ); ?></label>
     2709                                        <select name="sort_order_<?php echo esc_attr( $type ); ?>" id="sort_order_<?php echo esc_attr( $type ); ?>" >
     2710                                                <option value="custom" <?php selected( 'custom', $current_field->order_by ); ?>><?php _e( 'Custom',     'buddypress' ); ?></option>
     2711                                                <option value="asc"    <?php selected( 'asc',    $current_field->order_by ); ?>><?php _e( 'Ascending',  'buddypress' ); ?></option>
     2712                                                <option value="desc"   <?php selected( 'desc',   $current_field->order_by ); ?>><?php _e( 'Descending', 'buddypress' ); ?></option>
     2713                                        </select>
     2714                                </p>
     2715
     2716                                <?php
     2717                                $options = $current_field->get_children( true );
     2718
     2719                                // If no children options exists for this field, check in $_POST for a submitted form (e.g. on the "new field" screen).
     2720                                if ( ! $options ) {
     2721
     2722                                        $options = array();
     2723                                        $i       = 1;
     2724
     2725                                        while ( isset( $_POST[$type . '_option'][$i] ) ) {
     2726
     2727                                                // Multiselectbox and checkboxes support MULTIPLE default options; all other core types support only ONE.
     2728                                                if ( $current_type_obj->supports_options && ! $current_type_obj->supports_multiple_defaults && isset( $_POST["isDefault_{$type}_option"][$i] ) && (int) $_POST["isDefault_{$type}_option"] === $i ) {
     2729                                                        $is_default_option = true;
     2730                                                } elseif ( isset( $_POST["isDefault_{$type}_option"][$i] ) ) {
     2731                                                        $is_default_option = (bool) $_POST["isDefault_{$type}_option"][$i];
     2732                                                } else {
     2733                                                        $is_default_option = false;
     2734                                                }
     2735
     2736                                                // Grab the values from $_POST to use as the form's options
     2737                                                $options[] = (object) array(
     2738                                                        'id'                => -1,
     2739                                                        'is_default_option' => $is_default_option,
     2740                                                        'name'              => sanitize_text_field( stripslashes( $_POST[$type . '_option'][$i] ) ),
     2741                                                );
     2742
     2743                                                ++$i;
     2744                                        }
     2745
     2746                                        // If there are still no children options set, this must be the "new field" screen, so add one new/empty option.
     2747                                        if ( ! $options ) {
     2748                                                $options[] = (object) array(
     2749                                                        'id'                => -1,
     2750                                                        'is_default_option' => false,
     2751                                                        'name'              => '',
     2752                                                );
     2753                                        }
     2754                                }
     2755
     2756                                // Render the markup for the children options
     2757                                if ( ! empty( $options ) ) {
     2758                                        $default_name = '';
     2759
     2760                                        for ( $i = 0, $count = count( $options ); $i < $count; ++$i ) :
     2761                                                $j = $i + 1;
     2762
     2763                                                // Multiselectbox and checkboxes support MULTIPLE default options; all other core types support only ONE.
     2764                                                if ( $current_type_obj->supports_options && $current_type_obj->supports_multiple_defaults ) {
     2765                                                        $default_name = '[' . $j . ']';
     2766                                                }
     2767                                                ?>
     2768
     2769                                                <p class="sortable">
     2770                                                        <span>&nbsp;&Xi;&nbsp;</span>
     2771                                                        <input type="text" name="<?php echo esc_attr( "{$type}_option[{$j}]" ); ?>" id="<?php echo esc_attr( "{$type}_option{$j}" ); ?>" value="<?php echo esc_attr( $options[$i]->name ); ?>" />
     2772                                                        <input type="<?php echo esc_attr( $control_type ); ?>" name="<?php echo esc_attr( "isDefault_{$type}_option{$default_name}" ); ?>" <?php checked( $options[$i]->is_default_option, true ); ?> value="<?php echo esc_attr( $j ); ?>" />
     2773                                                        <span><?php _e( 'Default Value', 'buddypress' ); ?></span>
     2774                                                        <a href="<?php echo esc_url( 'users.php?page=bp-profile-setup&amp;mode=delete_option&amp;option_id=' . $options[$i]->id ); ?>" class="ajax-option-delete" id="<?php echo esc_attr( "delete-{$options[$i]->id}" ); ?>">[x]</a>
     2775                                                </p>
     2776                                        <?php endfor; ?>
     2777
     2778                                        <input type="hidden" name="<?php echo esc_attr( "{$type}_option_number" ); ?>" id="<?php echo esc_attr( "{$type}_option_number" ); ?>" value="<?php echo esc_attr( $j + 1 ); ?>" />
     2779                                <?php } ?>
     2780
     2781                                <div id="<?php echo esc_attr( "{$type}_more" ); ?>"></div>
     2782                                <p><a href="javascript:add_option('<?php echo esc_js( $type ); ?>')"><?php _e( 'Add Another Option', 'buddypress' ); ?></a></p>
     2783                        </div>
     2784                </div>
     2785
     2786                <?php
     2787        }
     2788
     2789
     2790        /**
     2791         * Internal protected/private helper methods past this point.
     2792         */
     2793
     2794        /**
     2795         * Get a sanitised and escaped string of the edit field's HTML elements and attributes.
     2796         *
     2797         * Must be used inside the {@link bp_profile_fields()} template loop.
     2798         * This method was intended to be static but couldn't be because php.net/lsb/ requires PHP >= 5.3.
     2799         *
     2800         * @param array $properties Optional key/value array of attributes for this edit field.
     2801         * @return string
     2802         * @since BuddyPress (2.0.0)
     2803         */
     2804        protected function get_edit_field_html_elements( array $properties = array() ) {
     2805
     2806                $properties = array_merge( array(
     2807                        'id'   => bp_get_the_profile_field_input_name(),
     2808                        'name' => bp_get_the_profile_field_input_name(),
     2809                ), $properties );
     2810
     2811                if ( bp_get_the_profile_field_is_required() ) {
     2812                        $properties['aria-required'] = 'true';
     2813                }
     2814
     2815                $html       = '';
     2816                $properties = (array) apply_filters( 'bp_xprofile_field_edit_html_elements', $properties, get_class( $this ) );
     2817
     2818                foreach ( $properties as $name => $value ) {
     2819                        $html .= sprintf( '%s="%s" ', sanitize_key( $name ), esc_attr( $value ) );
     2820                }
     2821
     2822                return $html;
     2823        }
     2824}
  • bp-xprofile/bp-xprofile-functions.php

    diff --git bp-xprofile/bp-xprofile-functions.php bp-xprofile/bp-xprofile-functions.php
    index cd116fd..466ba30 100644
    function xprofile_update_field_group_position( $field_group_id, $position ) { 
    6060
    6161/*** Field Management *********************************************************/
    6262
     63/**
     64 * Get details of all xprofile field types.
     65 *
     66 * @return array Key/value pairs (field type => class name).
     67 * @since BuddyPress (2.0.0)
     68 */
     69function bp_xprofile_get_field_types() {
     70        $fields = array(
     71                'checkbox'       => 'BP_XProfile_Field_Type_Checkbox',
     72                'datebox'        => 'BP_XProfile_Field_Type_Datebox',
     73                'multiselectbox' => 'BP_XProfile_Field_Type_Multiselectbox',
     74                'number'         => 'BP_XProfile_Field_Type_Number',
     75                'radio'          => 'BP_XProfile_Field_Type_Radiobutton',
     76                'selectbox'      => 'BP_XProfile_Field_Type_Selectbox',
     77                'textarea'       => 'BP_XProfile_Field_Type_Textarea',
     78                'textbox'        => 'BP_XProfile_Field_Type_Textbox',
     79        );
     80
     81        // If you've added a custom field type in a plugin, register it with this filter.
     82        return apply_filters( 'bp_xprofile_get_field_types', $fields );
     83}
     84
     85/**
     86 * Creates the specified field type object; used for validation and templating.
     87 *
     88 * @param string $type Type of profile field to create. See {@link bp_xprofile_get_field_types()} for default core values.
     89 * @return object If field type unknown, returns BP_XProfile_Field_Type_Textarea. Otherwise returns an instance of the relevant child class of BP_XProfile_Field_Type.
     90 * @since BuddyPress (2.0.0)
     91 */
     92function bp_xprofile_create_field_type( $type ) {
     93
     94        $field = bp_xprofile_get_field_types();
     95        $class = isset( $field[$type] ) ? $field[$type] : '';
     96
     97        /**
     98         * For backpat and to handle (missing) field types introduced by other plugins, fallback to
     99         * textbox if a type is unknown. Textbox validation and display is intentionally low key.
     100         */
     101        if ( $class && class_exists( $class ) ) {
     102                return new $class;
     103        } else {
     104                return new BP_XProfile_Field_Type_Textbox;
     105        }
     106}
     107
    63108function xprofile_insert_field( $args = '' ) {
    64109        global $bp;
    65110
    function xprofile_set_field_data( $field, $user_id, $value, $is_required = false 
    214259        if ( $is_required && ( empty( $value ) || !is_array( $value ) && !strlen( trim( $value ) ) ) )
    215260                return false;
    216261
    217         $field = new BP_XProfile_Field( $field_id );
     262        $field          = new BP_XProfile_Field( $field_id );
     263        $field_type_obj = bp_xprofile_create_field_type( BP_XProfile_Field::get_type( $field_id ) );
    218264
    219         // If the value is empty, then delete any field data that exists, unless the field is of a
    220         // type where null values are semantically meaningful
    221         if ( empty( $value ) && 'checkbox' != $field->type && 'multiselectbox' != $field->type ) {
     265        // If the value is empty, then delete any field data that exists, unless the field is of a type where null values are semantically meaningful
     266        if ( empty( $value ) && ! $field_type_obj->accepts_null_value ) {
    222267                xprofile_delete_field_data( $field_id, $user_id );
    223268                return true;
    224269        }
    225270
    226         $possible_values = array();
    227 
    228         // Check the value is an acceptable value
    229         if ( 'checkbox' == $field->type || 'radio' == $field->type || 'selectbox' == $field->type || 'multiselectbox' == $field->type ) {
    230                 $options = $field->get_children();
    231 
    232                 foreach( $options as $option )
    233                         $possible_values[] = $option->name;
    234 
    235                 if ( is_array( $value ) ) {
    236                         foreach( $value as $i => $single ) {
    237                                 if ( !in_array( $single, $possible_values ) ) {
    238                                         unset( $value[$i] );
    239                                 }
    240                         }
     271        // For certain fields, only certain parameters are acceptable, so add them to the whitelist.
     272        if ( $field_type_obj->supports_options ) {
     273                $field_type_obj->set_whitelist_values( wp_list_pluck( $field->get_children(), 'name' ) );
     274        }
    241275
    242                         // Reset the keys by merging with an empty array
    243                         $value = array_merge( array(), $value );
    244                 } else {
    245                         if ( !in_array( $value, $possible_values ) ) {
    246                                 return false;
    247                         }
    248                 }
     276        // Check the value is in an accepted format for this form field.
     277        if ( ! $field_type_obj->is_valid( $value ) ) {
     278                return false;
    249279        }
    250280
    251281        $field           = new BP_XProfile_ProfileData();
  • bp-xprofile/bp-xprofile-loader.php

    diff --git bp-xprofile/bp-xprofile-loader.php bp-xprofile/bp-xprofile-loader.php
    index 922877c..3477fe1 100644
    class BP_XProfile_Component extends BP_Component { 
    9898                }
    9999
    100100                // Set the support field type ids
    101                 $this->field_types = apply_filters( 'xprofile_field_types', array(
    102                         'textbox',
    103                         'textarea',
    104                         'radio',
    105                         'checkbox',
    106                         'selectbox',
    107                         'multiselectbox',
    108                         'datebox'
    109                 ) );
     101                $this->field_types = apply_filters( 'xprofile_field_types', array_keys( bp_xprofile_get_field_types() ) );
    110102
    111103                // Register the visibility levels. See bp_xprofile_get_visibility_levels() to filter
    112104                $this->visibility_levels = array(
  • bp-xprofile/bp-xprofile-template.php

    diff --git bp-xprofile/bp-xprofile-template.php bp-xprofile/bp-xprofile-template.php
    index ff320d9..65e2360 100644
    function bp_field_css_class( $class = false ) { 
    221221                if ( $profile_template->current_field % 2 == 1 )
    222222                        $css_classes[] = 'alt';
    223223
     224                $css_classes[] = 'field_type_' . sanitize_title( $profile_template->field->type );
    224225                $css_classes = apply_filters_ref_array( 'bp_field_css_classes', array( &$css_classes ) );
    225226
    226227                return apply_filters( 'bp_get_field_css_class', ' class="' . implode( ' ', $css_classes ) . '"' );
    function bp_the_profile_field_input_name() { 
    386387        function bp_get_the_profile_field_input_name() {
    387388                global $field;
    388389
    389                 $array_box = false;
    390                 if ( 'multiselectbox' == $field->type )
    391                         $array_box = '[]';
    392 
    393                 return apply_filters( 'bp_get_the_profile_field_input_name', 'field_' . $field->id . $array_box );
     390                return apply_filters( 'bp_get_the_profile_field_input_name', 'field_' . $field->id );
    394391        }
    395392
    396393/**
    function bp_get_the_profile_field_errors_action() { 
    423420 *
    424421 * @param array $args Specify type for datebox. Allowed 'day', 'month', 'year'.
    425422 */
    426 function bp_the_profile_field_options( $args = '' ) {
     423function bp_the_profile_field_options( $args = array() ) {
    427424        echo bp_get_the_profile_field_options( $args );
    428425}
    429426        /**
    430427         * bp_get_the_profile_field_options()
    431428         *
    432          * Retrieves field options HTML for field types of 'selectbox', 'multiselectbox',
    433          * 'radio', 'checkbox', and 'datebox'.
     429         * Retrieves field options HTML for field types of 'selectbox', 'multiselectbox', 'radio', 'checkbox', and 'datebox'.
    434430         *
    435431         * @package BuddyPress Xprofile
    436432         * @since BuddyPress (1.1)
    function bp_the_profile_field_options( $args = '' ) { 
    446442         *           used when rendering options. Default: displayed user.
    447443         * }
    448444         */
    449         function bp_get_the_profile_field_options( $args = '' ) {
     445        function bp_get_the_profile_field_options( $args = array() ) {
    450446                global $field;
    451447
    452                 $defaults = array(
     448                $args = wp_parse_args( $args, array(
    453449                        'type'    => false,
    454450                        'user_id' => bp_displayed_user_id(),
    455                 );
    456 
    457                 $r = wp_parse_args( $args, $defaults );
    458                 extract( $r, EXTR_SKIP );
     451                ) );
    459452
    460                 // In some cases, the $field global is not an instantiation of the BP_XProfile_Field
    461                 // class. However, we have to make sure that all data originally in $field gets
    462                 // merged back in, after reinstantiation.
    463                 if ( !method_exists( $field, 'get_children' ) ) {
     453                /**
     454                 * In some cases, the $field global is not an instantiation of the BP_XProfile_Field class.
     455                 * However, we have to make sure that all data originally in $field gets merged back in, after reinstantiation.
     456                 */
     457                if ( ! method_exists( $field, 'get_children' ) ) {
    464458                        $field_obj = new BP_XProfile_Field( $field->id );
    465459
    466                         foreach( $field as $field_prop => $field_prop_value ) {
    467                                 if ( !isset( $field_obj->{$field_prop} ) ) {
     460                        foreach ( $field as $field_prop => $field_prop_value ) {
     461                                if ( ! isset( $field_obj->{$field_prop} ) )
    468462                                        $field_obj->{$field_prop} = $field_prop_value;
    469                                 }
    470463                        }
    471464
    472465                        $field = $field_obj;
    473466                }
    474467
    475                 $options = $field->get_children();
    476 
    477                 // Setup some defaults
    478                 $html     = '';
    479                 $selected = '';
    480 
    481                 switch ( $field->type ) {
    482                         case 'selectbox':
    483 
    484                                 $html .= '<option value="">' . /* translators: no option picked in select box */ __( '----', 'buddypress' ) . '</option>';
    485 
    486                                 $original_option_values = '';
    487                                 $original_option_values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $field->id, $user_id ) );
    488 
    489                                 if ( empty( $original_option_values ) && !empty( $_POST['field_' . $field->id] ) ) {
    490                                         $original_option_values = $_POST['field_' . $field->id];
    491                                 }
    492 
    493                                 $option_values = (array) $original_option_values;
    494 
    495                                 for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
    496 
    497                                         // Check for updated posted values, but errors preventing them from being saved first time
    498                                         foreach( $option_values as $i => $option_value ) {
    499                                                 if ( isset( $_POST['field_' . $field->id] ) && $_POST['field_' . $field->id] != $option_value ) {
    500                                                         if ( !empty( $_POST['field_' . $field->id] ) ) {
    501                                                                 $option_values[$i] = $_POST['field_' . $field->id];
    502                                                         }
    503                                                 }
    504                                         }
    505 
    506                                         $selected = '';
    507 
    508                                         // Run the allowed option name through the before_save filter, so we'll be sure to get a match
    509                                         $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
    510 
    511                                         // First, check to see whether the user-entered value matches
    512                                         if ( in_array( $allowed_options, (array) $option_values ) ) {
    513                                                 $selected = ' selected="selected"';
    514                                         }
    515 
    516                                         // Then, if the user has not provided a value, check for defaults
    517                                         if ( !is_array( $original_option_values ) && empty( $option_values ) && $options[$k]->is_default_option ) {
    518                                                 $selected = ' selected="selected"';
    519                                         }
    520 
    521                                         $html .= apply_filters( 'bp_get_the_profile_field_options_select', '<option' . $selected . ' value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '">' . esc_attr( stripslashes( $options[$k]->name ) ) . '</option>', $options[$k], $field->id, $selected, $k );
    522                                 }
    523                                 break;
    524 
    525                         case 'multiselectbox':
    526                                 $original_option_values = '';
    527                                 $original_option_values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $field->id, $user_id ) );
    528 
    529                                 if ( empty( $original_option_values ) && !empty( $_POST['field_' . $field->id] ) ) {
    530                                         $original_option_values = $_POST['field_' . $field->id];
    531                                 }
    532 
    533                                 $option_values = (array) $original_option_values;
    534 
    535                                 for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
    536 
    537                                         // Check for updated posted values, but errors preventing them from being saved first time
    538                                         foreach( $option_values as $i => $option_value ) {
    539                                                 if ( isset( $_POST['field_' . $field->id] ) && $_POST['field_' . $field->id][$i] != $option_value ) {
    540                                                         if ( !empty( $_POST['field_' . $field->id][$i] ) ) {
    541                                                                 $option_values[] = $_POST['field_' . $field->id][$i];
    542                                                         }
    543                                                 }
    544                                         }
    545                                         $selected = '';
    546 
    547                                         // Run the allowed option name through the before_save filter, so we'll be sure to get a match
    548                                         $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
    549 
    550                                         // First, check to see whether the user-entered value matches
    551                                         if ( in_array( $allowed_options, (array) $option_values ) ) {
    552                                                 $selected = ' selected="selected"';
    553                                         }
    554 
    555                                         // Then, if the user has not provided a value, check for defaults
    556                                         if ( !is_array( $original_option_values ) && empty( $option_values ) && !empty( $options[$k]->is_default_option ) ) {
    557                                                 $selected = ' selected="selected"';
    558                                         }
    559 
    560                                         $html .= apply_filters( 'bp_get_the_profile_field_options_multiselect', '<option' . $selected . ' value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '">' . esc_attr( stripslashes( $options[$k]->name ) ) . '</option>', $options[$k], $field->id, $selected, $k );
    561                                 }
    562                                 break;
    563 
    564                         case 'radio':
    565                                 $html .= '<div id="field_' . $field->id . '">';
    566                                 $option_value = BP_XProfile_ProfileData::get_value_byid( $field->id, $user_id );
    567 
    568                                 for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
    569 
    570                                         // Check for updated posted values, but errors preventing them from being saved first time
    571                                         if ( isset( $_POST['field_' . $field->id] ) && $option_value != $_POST['field_' . $field->id] ) {
    572                                                 if ( !empty( $_POST['field_' . $field->id] ) ) {
    573                                                         $option_value = $_POST['field_' . $field->id];
    574                                                 }
    575                                         }
    576 
    577                                         // Run the allowed option name through the before_save
    578                                         // filter, so we'll be sure to get a match
    579                                         $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
    580                                         $selected        = '';
    581 
    582                                         if ( $option_value == $allowed_options || ( empty( $option_value ) && !empty( $options[$k]->is_default_option ) ) )
    583                                                 $selected = ' checked="checked"';
    584 
    585                                         $html .= apply_filters( 'bp_get_the_profile_field_options_radio', '<label><input' . $selected . ' type="radio" name="field_' . $field->id . '" id="option_' . $options[$k]->id . '" value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '"> ' . esc_attr( stripslashes( $options[$k]->name ) ) . '</label>', $options[$k], $field->id, $selected, $k );
    586                                 }
    587 
    588                                 $html .= '</div>';
    589                                 break;
    590 
    591                         case 'checkbox':
    592                                 $option_values = BP_XProfile_ProfileData::get_value_byid( $field->id, $user_id );
    593                                 $option_values = (array) maybe_unserialize( $option_values );
    594 
    595                                 // Check for updated posted values, but errors preventing them from being saved first time
    596                                 if ( isset( $_POST['field_' . $field->id] ) && $option_values != maybe_serialize( $_POST['field_' . $field->id] ) ) {
    597                                         if ( !empty( $_POST['field_' . $field->id] ) )
    598                                                 $option_values = $_POST['field_' . $field->id];
    599                                 }
    600 
    601                                 for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
    602                                         $selected = '';
    603 
    604                                         // First, check to see whether the user's saved values
    605                                         // match the option
    606                                         for ( $j = 0, $count_values = count( $option_values ); $j < $count_values; ++$j ) {
    607 
    608                                                 // Run the allowed option name through the
    609                                                 // before_save filter, so we'll be sure to get a match
    610                                                 $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
    611 
    612                                                 if ( $option_values[$j] == $allowed_options || @in_array( $allowed_options, $option_values ) ) {
    613                                                         $selected = ' checked="checked"';
    614                                                         break;
    615                                                 }
    616                                         }
    617 
    618                                         // If the user has not yet supplied a value for this field,
    619                                         // check to see whether there is a default value available
    620                                         if ( !is_array( $option_values ) && empty( $option_values ) && empty( $selected ) && !empty( $options[$k]->is_default_option ) ) {
    621                                                 $selected = ' checked="checked"';
    622                                         }
    623 
    624                                         $html .= apply_filters( 'bp_get_the_profile_field_options_checkbox', '<label><input' . $selected . ' type="checkbox" name="field_' . $field->id . '[]" id="field_' . $options[$k]->id . '_' . $k . '" value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '"> ' . esc_attr( stripslashes( $options[$k]->name ) ) . '</label>', $options[$k], $field->id, $selected, $k );
    625                                 }
    626                                 break;
    627 
    628                         case 'datebox':
    629                                 $date = BP_XProfile_ProfileData::get_value_byid( $field->id, $user_id );
    630 
    631                                 // Set day, month, year defaults
    632                                 $day   = '';
    633                                 $month = '';
    634                                 $year  = '';
    635 
    636                                 if ( !empty( $date ) ) {
    637 
    638                                         // If Unix timestamp
    639                                         if ( is_numeric( $date ) ) {
    640                                                 $day   = date( 'j', $date );
    641                                                 $month = date( 'F', $date );
    642                                                 $year  = date( 'Y', $date );
    643 
    644                                         // If MySQL timestamp
    645                                         } else {
    646                                                 $day   = mysql2date( 'j', $date );
    647                                                 $month = mysql2date( 'F', $date, false ); // Not localized, so that selected() works below
    648                                                 $year  = mysql2date( 'Y', $date );
    649                                         }
    650                                 }
    651 
    652                                 // Check for updated posted values, and errors preventing
    653                                 // them from being saved first time.
    654                                 if ( !empty( $_POST['field_' . $field->id . '_day'] ) ) {
    655                                         if ( $day != $_POST['field_' . $field->id . '_day'] ) {
    656                                                 $day = $_POST['field_' . $field->id . '_day'];
    657                                         }
    658                                 }
    659 
    660                                 if ( !empty( $_POST['field_' . $field->id . '_month'] ) ) {
    661                                         if ( $month != $_POST['field_' . $field->id . '_month'] ) {
    662                                                 $month = $_POST['field_' . $field->id . '_month'];
    663                                         }
    664                                 }
    665 
    666                                 if ( !empty( $_POST['field_' . $field->id . '_year'] ) ) {
    667                                         if ( $year != date( "j", $_POST['field_' . $field->id . '_year'] ) ) {
    668                                                 $year = $_POST['field_' . $field->id . '_year'];
    669                                         }
    670                                 }
    671 
    672                                 // $type will be passed by calling function when needed
    673                                 switch ( $type ) {
    674                                         case 'day':
    675                                                 $html .= '<option value=""' . selected( $day, '', false ) . '>--</option>';
    676 
    677                                                 for ( $i = 1; $i < 32; ++$i ) {
    678                                                         $html .= '<option value="' . $i .'"' . selected( $day, $i, false ) . '>' . $i . '</option>';
    679                                                 }
    680                                                 break;
    681 
    682                                         case 'month':
    683                                                 $eng_months = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );
    684 
    685                                                 $months = array(
    686                                                         __( 'January', 'buddypress' ),
    687                                                         __( 'February', 'buddypress' ),
    688                                                         __( 'March', 'buddypress' ),
    689                                                         __( 'April', 'buddypress' ),
    690                                                         __( 'May', 'buddypress' ),
    691                                                         __( 'June', 'buddypress' ),
    692                                                         __( 'July', 'buddypress' ),
    693                                                         __( 'August', 'buddypress' ),
    694                                                         __( 'September', 'buddypress' ),
    695                                                         __( 'October', 'buddypress' ),
    696                                                         __( 'November', 'buddypress' ),
    697                                                         __( 'December', 'buddypress' )
    698                                                 );
    699 
    700                                                 $html .= '<option value=""' . selected( $month, '', false ) . '>------</option>';
    701 
    702                                                 for ( $i = 0; $i < 12; ++$i ) {
    703                                                         $html .= '<option value="' . $eng_months[$i] . '"' . selected( $month, $eng_months[$i], false ) . '>' . $months[$i] . '</option>';
    704                                                 }
    705                                                 break;
    706 
    707                                         case 'year':
    708                                                 $html .= '<option value=""' . selected( $year, '', false ) . '>----</option>';
    709 
    710                                                 for ( $i = 2037; $i > 1901; $i-- ) {
    711                                                         $html .= '<option value="' . $i .'"' . selected( $year, $i, false ) . '>' . $i . '</option>';
    712                                                 }
    713                                                 break;
    714                                 }
    715 
    716                                 $html = apply_filters( 'bp_get_the_profile_field_datebox', $html, $type, $day, $month, $year, $field->id, $date );
    717 
    718                                 break;
    719                 }
     468                ob_start();
     469                $field->type_obj->edit_field_options_html( $args );
     470                $html = ob_get_contents();
     471                ob_end_clean();
    720472
    721473                return $html;
    722474        }
    function bp_xprofile_settings_visibility_select( $args = '' ) { 
    1014766
    1015767                // Output the dropdown list
    1016768                return apply_filters( 'bp_xprofile_settings_visibility_select', ob_get_clean() );
    1017         }
    1018  No newline at end of file
     769        }
  • new file tests/testcases/xprofile/class-bp-xprofile-field-type.php

    diff --git tests/testcases/xprofile/class-bp-xprofile-field-type.php tests/testcases/xprofile/class-bp-xprofile-field-type.php
    new file mode 100644
    index 0000000..67138cb
    - +  
     1<?php
     2/**
     3 * @group xprofile
     4 * @group BP_XProfile_Field_Type
     5 */
     6class BP_Tests_XProfile_Field_Type extends BP_UnitTestCase {
     7        public function setUp() {
     8                parent::setUp();
     9        }
     10
     11        public function tearDown() {
     12                parent::tearDown();
     13        }
     14
     15        public function test_unregistered_field_type_returns_textbox() {
     16                $field = bp_xprofile_create_field_type( 'fakeyfield' );
     17                $this->assertEquals( get_class( $field ), 'BP_XProfile_Field_Type_Textbox' );
     18        }
     19
     20
     21        public function test_textbox_validate_string() {
     22                $field = bp_xprofile_create_field_type( 'textbox' );
     23                $this->assertTrue( $field->is_valid( 'my 117th input string!' ) );
     24        }
     25
     26        public function test_textbox_validate_integer() {
     27                $field = bp_xprofile_create_field_type( 'textbox' );
     28                $this->assertTrue( $field->is_valid( 123 ) );
     29        }
     30
     31        public function test_textbox_validate_whitelisted_string() {
     32                $field = bp_xprofile_create_field_type( 'textbox' );
     33
     34                $this->assertTrue( $field->is_valid( 'a string' ) );
     35                $this->assertFalse( $field->set_whitelist_values( 'pizza' )->is_valid( 'pasta' ) );
     36                $this->assertTrue( $field->is_valid( 'pizza' ) );
     37        }
     38
     39
     40        public function test_multiselectbox_validate_whitelisted_array() {
     41                $field = bp_xprofile_create_field_type( 'multiselectbox' );
     42                $field->set_whitelist_values( array( 'cheese', 'pepporoni' ) );
     43
     44                $this->assertTrue( $field->is_valid( array( 'cheese', 'pepporoni' ) ) );
     45                $this->assertTrue( $field->is_valid( array( 'cheese' ) ) );
     46                $this->assertFalse( $field->is_valid( array( 'cheese', 'pepporoni', 'pinapple' ) ) );
     47                $this->assertFalse( $field->is_valid( array( 'pinapple' ) ) );
     48        }
     49
     50        public function test_multiselectbox_validate_null_value() {
     51                $field = bp_xprofile_create_field_type( 'multiselectbox' );
     52                $field->set_whitelist_values( array( 'cheese', 'pepporoni' ) );
     53
     54                $this->assertFalse( $field->is_valid( array( '' ) ) );
     55                $this->assertFalse( $field->is_valid( '' ) );
     56                $this->assertTrue( $field->is_valid( array() ) );
     57        }
     58
     59
     60        public function test_datebox_do_not_validate_string() {
     61                $field = bp_xprofile_create_field_type( 'datebox' );
     62                $this->assertFalse( $field->is_valid( 'datebox fields only accept strings in: Y-m-d 00:00:00' ) );
     63        }
     64
     65        public function test_datebox_do_not_validate_integer() {
     66                $field = bp_xprofile_create_field_type( 'datebox' );
     67                $this->assertFalse( $field->is_valid( 221213 ) );
     68        }
     69
     70        public function test_datebox_validate_date() {
     71                $field = bp_xprofile_create_field_type( 'datebox' );
     72                $this->assertTrue( $field->is_valid( '2013-12-22 00:00:00' ) );
     73        }
     74
     75        public function test_datebox_do_not_validate_date_with_timestamp() {
     76                $field = bp_xprofile_create_field_type( 'datebox' );
     77                $this->assertFalse( $field->is_valid( '2013-12-22 19:11:30' ) );
     78                $this->assertFalse( $field->is_valid( '2013-12-22' ) );
     79        }
     80
     81
     82        public function test_number_do_not_validate_string() {
     83                $field = bp_xprofile_create_field_type( 'number' );
     84                $this->assertFalse( $field->is_valid( 'telephone fields only accept integers' ) );
     85        }
     86
     87        public function test_number_validate_integer() {
     88                $field = bp_xprofile_create_field_type( 'number' );
     89                $this->assertTrue( $field->is_valid( 12345678901 ) );
     90        }
     91
     92
     93        public function test_radiobutton_validate_whitelisted_array() {
     94                $field = bp_xprofile_create_field_type( 'radio' );
     95                $field->set_whitelist_values( array( 'cheese', 'pepporoni' ) );
     96
     97                $this->assertTrue( $field->is_valid( array( 'cheese', 'pepporoni' ) ) );
     98                $this->assertTrue( $field->is_valid( array( 'cheese' ) ) );
     99                $this->assertFalse( $field->is_valid( array( 'cheese', 'pepporoni', 'pinapple' ) ) );
     100                $this->assertFalse( $field->is_valid( array( 'pinapple' ) ) );
     101        }
     102
     103        public function test_radiobutton_do_not_validate_empty_items_in_whitelist() {
     104                $field = bp_xprofile_create_field_type( 'radio' );
     105                $field->set_whitelist_values( array( '' ) );
     106
     107                $this->assertFalse( $field->is_valid( array( '' ) ) );
     108        }
     109
     110
     111        public function test_checkbox_validate_whitelisted_array() {
     112                $field = bp_xprofile_create_field_type( 'checkbox' );
     113                $field->set_whitelist_values( array( 'cheese', 'pepporoni' ) );
     114
     115                $this->assertTrue( $field->is_valid( array( 'cheese', 'pepporoni' ) ) );
     116                $this->assertTrue( $field->is_valid( array( 'cheese' ) ) );
     117                $this->assertFalse( $field->is_valid( array( 'cheese', 'pepporoni', 'pinapple' ) ) );
     118                $this->assertFalse( $field->is_valid( array( 'pinapple' ) ) );
     119        }
     120
     121        public function test_checkbox_validate_null_value() {
     122                $field = bp_xprofile_create_field_type( 'checkbox' );
     123                $field->set_whitelist_values( array( 'cheese', 'pepporoni' ) );
     124
     125                $this->assertFalse( $field->is_valid( array( '' ) ) );
     126                $this->assertFalse( $field->is_valid( '' ) );
     127                $this->assertTrue( $field->is_valid( array() ) );
     128        }
     129}