Skip to:
Content

BuddyPress.org


Ignore:
Timestamp:
03/27/2014 07:34:02 PM (10 years ago)
Author:
djpaul
Message:

xProfile: re-architecture profile field types and de-duplicate the templating and validation logic to make it easier for core and plugins to add new profile field types.

Until now, it's been pretty hard to add new types of profile field to BuddyPress. There are a couple of plugins that do a good job, but BuddyPress makes it much harder than it should be because, historically, we've hardcoded values and checks in templates throughout the project. For example, profile field templating was duplicated in the registration template, the member/profile/edit template, in parts of the wp-admin xProfile screens, and in the new wp-admin extended profile editor.

This change implements a new approach that creates a class for each profile field type; selectbox, textbox, textarea, and so on. They all share an abstract base class BP_XProfile_Field_Type which consolidates a lot of special behaviour that had been added to BuddyPress over the years (e.g. some fields accept null values, some accept multiple default values), and adds true field value validation. Unit tests are included.

We've also implemented a new "Numbers" field type with these changes. It behaves much the same as a regular textbox field does, but it only accepts numbers.

Fixes #5220 and #4694

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/bp-xprofile/bp-xprofile-admin.php

    r8028 r8178  
    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 ); ?>
    446 
    447             <?php endswitch; ?>
     385            <?php
     386            $field_type = bp_xprofile_create_field_type( $field->type );
     387            $field_type->admin_field_html();
     388
     389            do_action( 'xprofile_admin_field', $field, 1 );
     390            ?>
    448391
    449392            <?php if ( $field->description ) : ?>
     
    466409
    467410<?php
     411}
     412
     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    }
    468462}
    469463
     
    643637                $errors = false;
    644638
    645                 // Now we've checked for required fields, lets save the values.
     639                // Now we've checked for required fields, let's save the values.
    646640                foreach ( (array) $posted_field_ids as $field_id ) {
    647641
    648642                    // 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.
    649                     if ( empty( $_POST['field_' . $field_id] ) ) {
    650                         $value = array();
    651                     } else {
    652                         $value = $_POST['field_' . $field_id];
    653                     }
     643                    $value = isset( $_POST['field_' . $field_id] ) ? $_POST['field_' . $field_id] : '';
    654644
    655645                    if ( ! xprofile_set_field_data( $field_id, $user_id, $value, $is_required[ $field_id ] ) ) {
     
    703693
    704694        if ( bp_has_profile( $r ) ) :
    705 
    706695            while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
    707 
    708                 <p class="description"><?php bp_the_profile_group_description(); ?></p>
    709 
    710                 <table class="form-table">
    711                     <tbody>
    712 
    713                     <?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
    714 
    715                         <tr>
    716 
    717                             <?php if ( 'textbox' === bp_get_the_profile_field_type() ) : ?>
    718 
    719                                 <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>
    720                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    721                                     <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; ?>/>
    722                                     <span class="description"><?php bp_the_profile_field_description(); ?></span>
    723                                 </td>
    724 
     696                <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() ); ?>" />
     697
     698                <?php if ( bp_get_the_profile_group_description() ) : ?>
     699                    <p class="description"><?php bp_the_profile_group_description(); ?></p>
     700                <?php
     701                endif;
     702
     703                while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
     704
     705                    <div<?php bp_field_css_class( 'bp-profile-field' ); ?>>
     706                        <?php
     707                        $field_type = bp_xprofile_create_field_type( bp_get_the_profile_field_type() );
     708                        $field_type->edit_field_html( array( 'user_id' => $r['user_id'] ) );
     709
     710                        if ( bp_get_the_profile_field_description() ) : ?>
     711                            <p class="description"><?php bp_the_profile_field_description(); ?></p>
     712                        <?php endif;
     713
     714                        do_action( 'bp_custom_profile_edit_fields_pre_visibility' );
     715                        $can_change_visibility = bp_current_user_can( 'bp_xprofile_change_field_visibility' );
     716                        ?>
     717
     718                        <p class="field-visibility-settings-<?php echo $can_change_visibility ? 'toggle' : 'notoggle'; ?>" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id(); ?>">
     719                            <?php
     720                            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() );
     721
     722                            if ( $can_change_visibility ) : ?>
     723                                 <a href="#" class="button visibility-toggle-link"><?php _e( 'Change', 'buddypress' ); ?></a>
    725724                            <?php endif; ?>
    726 
    727                             <?php if ( 'textarea' === bp_get_the_profile_field_type() ) : ?>
    728 
    729                                 <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>
    730                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    731                                     <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>
    732                                     <p class="description"><?php bp_the_profile_field_description(); ?></p>
    733                                 </td>
    734 
    735                             <?php endif; ?>
    736 
    737                             <?php if ( 'selectbox' === bp_get_the_profile_field_type() ) : ?>
    738 
    739                                 <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>
    740                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    741                                     <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; ?>>
    742                                         <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    743                                     </select>
    744                                     <span class="description"><?php bp_the_profile_field_description(); ?></span>
    745                                 </td>
    746 
    747                             <?php endif; ?>
    748 
    749                             <?php if ( 'multiselectbox' === bp_get_the_profile_field_type() ) : ?>
    750 
    751                                 <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>
    752                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    753                                     <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; ?>>
    754 
    755                                         <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    756 
    757                                     </select>
    758 
    759 
    760                                     <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    761 
    762                                         <p><a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a></p>
    763 
    764                                     <?php endif; ?>
    765                                     <p class="description"><?php bp_the_profile_field_description(); ?></p>
    766                                 </td>
    767 
    768                             <?php endif; ?>
    769 
    770                             <?php if ( 'radio' === bp_get_the_profile_field_type() ) : ?>
    771 
    772                                 <th>
    773                                     <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>
    774                                 </th>
    775                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    776                                     <fieldset>
    777                                         <legend class="screen-reader-text"><span><?php bp_the_profile_field_name(); ?></span></legend>
    778                                         <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    779                                     </fieldset>
    780 
    781                                     <?php if ( !bp_get_the_profile_field_is_required() ) : ?>
    782 
    783                                         <p><a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a></p>
    784 
    785                                     <?php endif; ?>
    786                                     <p class="description"><?php bp_the_profile_field_description(); ?></p>
    787                                 </td>
    788 
    789                             <?php endif; ?>
    790 
    791                             <?php if ( 'checkbox' === bp_get_the_profile_field_type() ) : ?>
    792 
    793                                 <th>
    794                                     <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>
    795                                 </th>
    796                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    797                                     <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], ) ); ?>
    798                                     <p class="description"><?php bp_the_profile_field_description(); ?></p>
    799                                 </td>
    800 
    801                             <?php endif; ?>
    802 
    803                             <?php if ( 'datebox' === bp_get_the_profile_field_type() ) : ?>
    804 
    805                                 <th>
    806                                     <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>
    807                                 </th>
    808                                 <td class="admin-field-<?php bp_the_profile_field_type();?>">
    809                                     <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; ?>>
    810 
    811                                         <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], 'type' => 'day', ) ); ?>
    812 
    813                                     </select>
    814 
    815                                     <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; ?>>
    816 
    817                                         <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], 'type' => 'month', ) ); ?>
    818 
    819                                     </select>
    820 
    821                                     <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; ?>>
    822 
    823                                         <?php bp_the_profile_field_options( array( 'user_id' => $r['user_id'], 'type' => 'year', ) ); ?>
    824 
    825                                     </select>
    826                                     <p class="description"><?php bp_the_profile_field_description(); ?></p>
    827                                 </td>
    828 
    829                             <?php endif; ?>
    830 
    831                         </tr>
    832 
    833                         <tr class="admin-field-visibility-tr">
    834                             <td class="admin-field-visibility-td">&nbsp;</td>
    835                             <td class="admin-field-visibility-td">
    836 
    837                                 <?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
    838 
    839                                 <?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
    840                                     <p class="description field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
    841                                         <?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>
    842                                     </p>
    843 
    844                                     <div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
    845                                         <fieldset>
    846                                             <legend><?php esc_html_e( 'Who can see this field?', 'buddypress' ) ?></legend>
    847 
    848                                             <?php bp_profile_visibility_radio_buttons() ?>
    849 
    850                                         </fieldset>
    851                                         <a class="field-visibility-settings-close" href="#"><?php esc_html_e( 'Close', 'buddypress' ) ?></a>
    852                                     </div>
    853                                 <?php else : ?>
    854                                     <div class="field-visibility-settings-notoggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
    855                                         <?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?>
    856                                     </div>
    857                                 <?php endif ?>
    858 
    859                             </td>
    860                         </tr>
    861 
    862                     <?php endwhile; ?>
    863                     </tbody>
    864 
    865                 </table>
    866                 <input type="hidden" name="field_ids[]" id="field_ids_<?php bp_the_profile_group_slug(); ?>" value="<?php bp_the_profile_group_field_ids(); ?>" />
    867             <?php endwhile;
     725                        </p>
     726
     727                        <?php if ( $can_change_visibility ) : ?>
     728                            <div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
     729                                <fieldset>
     730                                    <legend><?php _e( 'Who can see this field?', 'buddypress' ); ?></legend>
     731                                    <?php bp_profile_visibility_radio_buttons(); ?>
     732                                </fieldset>
     733                                <a class="button field-visibility-settings-close" href="#"><?php _e( 'Close', 'buddypress' ); ?></a>
     734                            </div>
     735                        <?php endif;
     736
     737                        do_action( 'bp_custom_profile_edit_fields' ); ?>
     738                    </div>
     739
     740                <?php
     741                endwhile; // bp_profile_fields()
     742
     743            endwhile; // bp_profile_groups()
    868744        endif;
    869745    }
Note: See TracChangeset for help on using the changeset viewer.