Skip to:
Content

BuddyPress.org

Changeset 12868


Ignore:
Timestamp:
03/21/2021 02:17:21 PM (5 years ago)
Author:
imath
Message:

Field Types can now declare supported features & field visibility

  • Edit the JavaScript file used by the xProfile Create field Administration screen to handle Field types requirements by showing/hiding screen metaboxes according to feature supports and to get ride of some jQuery deprecated methods.
  • Improve the xProfile Field API to take in account xProfile Field Types declared feature supports by adding two new methods to get (BP_XProfile_Field->get_field_type_supports()) & check (BP_XProfile_Field->field_type_supports( $feature_name )) the field type supported features.
  • The xProfile Create field Administration Screen Metaboxes displayed to set the field properties can now be disabled by the Field Type using the static variable $supported_features. See tests/phpunit/assets/bptest-xprofile-field-type.php for an example of use.
  • Improve the xProfile Field API to take in account the xProfile Field Types visibility property to use as default field visibility. NB: setting this Field Type visibility and its allow_custom_visibility feature support to false, a Field Type can now enforce the visibility to use for a field.
  • Introduce a new xProfile Fields loop argument $hide_field_types to avoid displaying fields according to an array of Field types. To customize this new argument you can use the bp_before_has_profile_parse_args filter for existing xProfile loop. For instance you can avoid to list xProfile fields according to their type from the WP-Admin/Extended profile screen checking the corresponding Administration Screen ID.
  • Add PHP unit tests to verify these improvements are working the right way.

Props DJPaul, Offereins, needle, netweb, vapvarun

See #7162

Location:
trunk
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-xprofile/admin/js/admin.js

    r12833 r12868  
    9696        }
    9797
     98        // Show/hides metaboxes according to selected field type supports.
     99        jQuery( '#field-type-visibiliy-metabox, #field-type-required-metabox, #field-type-autolink-metabox, #field-type-member-types' ).show();
     100        if ( -1 !== XProfileAdmin.hide_required_metabox.indexOf( forWhat ) ) {
     101                jQuery( '#field-type-required-metabox' ).hide();
     102        }
     103
     104        if ( -1 !== XProfileAdmin.hide_allow_custom_visibility_metabox.indexOf( forWhat ) ) {
     105                jQuery( '#field-type-visibiliy-metabox' ).hide();
     106        }
     107
     108        if ( -1 !== XProfileAdmin.hide_do_autolink_metabox.indexOf( forWhat ) ) {
     109                jQuery( '#field-type-autolink-metabox' ).hide();
     110        }
     111
     112        if ( -1 !== XProfileAdmin.hide_member_types_metabox.indexOf( forWhat ) ) {
     113                jQuery( '#field-type-member-types' ).hide();
     114        }
     115
    98116        jQuery( document ).trigger( 'bp-xprofile-show-options', forWhat );
    99117}
     
    174192        titleprompt.on( 'click', function(){
    175193                jQuery(this).addClass('screen-reader-text');
    176                 title.focus();
     194                title.trigger( 'focus' );
    177195        });
    178196
     
    185203        }).on( 'keydown', function(e){
    186204                titleprompt.addClass('screen-reader-text');
    187                 jQuery(this).unbind(e);
     205                jQuery(this).off( e );
    188206        });
    189207}
    190208
    191 jQuery( document ).ready( function() {
     209jQuery( function() {
    192210
    193211        // Set focus in Field Title, if we're on the right page.
  • trunk/src/bp-xprofile/bp-xprofile-admin.php

    r12768 r12868  
    494494                        $field->name        = $_POST['title'];
    495495
     496                        /*
     497                         * By default a Textbox field is created. To run field type's feature
     498                         * checks we need to set it to what it really is early.
     499                         */
     500                        if ( is_null( $field_id ) ) {
     501                                $field_type = bp_xprofile_create_field_type( $field->type );
     502
     503                                // If it's a placeholder, then the field type is not registered.
     504                                if ( ! $field_type instanceof BP_XProfile_Field_Type_Placeholder ) {
     505                                        $field->type_obj = $field_type;
     506                                }
     507                        }
     508
     509                        if ( ! $field->field_type_supports( 'required' ) ) {
     510                                $field->is_required = "0";
     511                        }
     512
    496513                        if ( ! empty( $_POST['description'] ) ) {
    497514                                $field->description = $_POST['description'];
     
    538555                                // Validate default visibility.
    539556                                if ( ! empty( $_POST['default-visibility'] ) && in_array( $_POST['default-visibility'], wp_list_pluck( bp_xprofile_get_visibility_levels(), 'id' ) ) ) {
    540                                         bp_xprofile_update_field_meta( $field_id, 'default_visibility', $_POST['default-visibility'] );
     557                                        $default_visibility = $_POST['default-visibility'];
     558
     559                                        if ( ! $field->field_type_supports( 'allow_custom_visibility' ) ) {
     560                                                $default_visibility = 'public';
     561                                        }
     562
     563                                        bp_xprofile_update_field_meta( $field_id, 'default_visibility', $default_visibility );
    541564                                }
    542565
    543566                                // Validate custom visibility.
    544567                                if ( ! empty( $_POST['allow-custom-visibility'] ) && in_array( $_POST['allow-custom-visibility'], array( 'allowed', 'disabled' ) ) ) {
    545                                         bp_xprofile_update_field_meta( $field_id, 'allow_custom_visibility', $_POST['allow-custom-visibility'] );
     568                                        $allow_custom_visibility = $_POST['allow-custom-visibility'];
     569
     570                                        if ( ! $field->field_type_supports( 'allow_custom_visibility' ) ) {
     571                                                $allow_custom_visibility = 'disabled';
     572                                        }
     573
     574                                        bp_xprofile_update_field_meta( $field_id, 'allow_custom_visibility', $allow_custom_visibility );
    546575                                }
    547576
     
    553582                                }
    554583
     584                                $do_autolink = '';
     585                                if ( $field->field_type_supports( 'do_autolink' ) && isset( $_POST['do_autolink'] ) && $_POST['do_autolink'] ) {
     586                                        $do_autolink = wp_unslash( $_POST['do_autolink'] );
     587                                }
     588
    555589                                // Save autolink settings.
    556                                 if ( isset( $_POST['do_autolink'] ) && 'on' === wp_unslash( $_POST['do_autolink'] ) ) {
     590                                if ( 'on' === $do_autolink ) {
    557591                                        bp_xprofile_update_field_meta( $field_id, 'do_autolink', 'on' );
    558592                                } else {
  • trunk/src/bp-xprofile/bp-xprofile-cssjs.php

    r12829 r12868  
    5252                // "please enter options for this field" section.
    5353                $strings = array(
    54                         'do_settings_section_field_types' => array(),
    55                         'do_autolink'                     => '',
    56                         'text'                            => array(
     54                        'do_settings_section_field_types'      => array(),
     55                        'do_autolink'                          => '',
     56                        'hide_do_autolink_metabox'             => array(),
     57                        'hide_allow_custom_visibility_metabox' => array(),
     58                        'hide_required_metabox'                => array(),
     59                        'hide_member_types_metabox'            => array(),
     60                        'text'                                 => array(
    5761                                'defaultValue' => __( 'Default Value', 'buddypress' ),
    5862                                'deleteLabel'  => __( 'Delete', 'buddypress' ),
     
    6468                        if ( $field->do_settings_section() ) {
    6569                                $strings['do_settings_section_field_types'][] = $field_type;
     70                        }
     71
     72                        if ( isset( $field::$supported_features ) && is_array( $field::$supported_features ) ) {
     73                                foreach ( $field::$supported_features as $feature => $support ) {
     74                                        if ( isset( $strings['hide_' . $feature . '_metabox'] ) && ! $support ) {
     75                                                $strings['hide_' . $feature . '_metabox'][] = $field_type;
     76                                        }
     77                                }
    6678                        }
    6779                }
  • trunk/src/bp-xprofile/bp-xprofile-template.php

    r12768 r12868  
    1515 *
    1616 * @since 1.0.0
     17 * @since 2.4.0 Introduced `$member_type` argument.
     18 * @since 8.0.0 Introduced `$hide_field_types` argument.
    1719 *
    1820 * @global object $profile_template
     
    3234 *     @type bool         $fetch_visibility_level Defaults to true when an admin is viewing a profile, or when a user is
    3335 *                                                viewing her own profile, or during registration. Otherwise false.
    34  *     @type int|bool     $exclude_groups         Default: false.
    35  *     @type int|bool     $exclude_fields         Default: false
     36 *     @type int[]|bool   $exclude_groups         Default: false.
     37 *     @type int[]|bool   $exclude_fields         Default: false.
     38 *     @type string[]     $hide_field_types       Default: empty array.
    3639 *     @type bool         $update_meta_cache      Default: true.
    3740 * }
     
    6568                'exclude_groups'         => false, // Comma-separated list of profile field group IDs to exclude.
    6669                'exclude_fields'         => false, // Comma-separated list of profile field IDs to exclude.
     70                'hide_field_types'       => array(), // List of field types to hide from profile fields loop.
    6771                'update_meta_cache'      => true,
    6872        ), 'has_profile' );
  • trunk/src/bp-xprofile/classes/class-bp-xprofile-data-template.php

    r12426 r12868  
    106106         * @since 1.5.0
    107107         * @since 2.4.0 Introduced `$member_type` argument.
     108         * @since 8.0.0 Introduced `$hide_field_types` argument.
    108109         *
    109110         * @param array|string $args {
     
    121122         *     @type int|bool     $fetch_visibility_level  Fetch visibility levels.
    122123         *     @type int|bool     $update_meta_cache       Should metadata cache be updated.
     124         *     @type string[]     $hide_field_types        List of field types to hide form loop. Default: empty array.
    123125         * }
    124126         */
     
    157159                        'exclude_groups'         => false,
    158160                        'exclude_fields'         => false,
     161                        'hide_field_types'       => array(),
    159162                        'update_meta_cache'      => true
    160163                ) );
  • trunk/src/bp-xprofile/classes/class-bp-xprofile-field.php

    r12725 r12868  
    183183                        $this->type_obj->field_obj = $this;
    184184                }
     185
     186                /**
     187                 * Fires when the xProfile field object has been constructed.
     188                 *
     189                 * @since 8.0.0
     190                 *
     191                 * @param BP_XProfile_Field $this The xProfile field object.
     192                 */
     193                do_action( 'bp_xprofile_field', $this );
    185194        }
    186195
     
    807816        public function get_default_visibility() {
    808817                if ( ! isset( $this->default_visibility ) ) {
    809                         $this->default_visibility = bp_xprofile_get_meta( $this->id, 'field', 'default_visibility' );
    810 
    811                         if ( ! $this->default_visibility ) {
    812                                 $this->default_visibility = 'public';
     818                        $this->default_visibility = 'public';
     819                        $this->visibility         = '';
     820
     821                        if ( isset( $this->type_obj->visibility ) && $this->type_obj->visibility ) {
     822                                $this->visibility = $this->type_obj->visibility;
     823                        }
     824
     825                        if ( $this->field_type_supports( 'allow_custom_visibility' ) ) {
     826                                $this->visibility = bp_xprofile_get_meta( $this->id, 'field', 'default_visibility' );
     827                        }
     828
     829                        if ( $this->visibility ) {
     830                                $this->default_visibility = $this->visibility;
    813831                        }
    814832                }
     
    13191337
    13201338        /**
     1339         * Gets field type supports.
     1340         *
     1341         * @since 8.0.0
     1342         *
     1343         * @return bool[] Supported features.
     1344         */
     1345        public function get_field_type_supports() {
     1346                $supports = array(
     1347                        'switch_fieldtype'        => true,
     1348                        'allow_required'          => true,
     1349                        'allow_autolink'          => true,
     1350                        'allow_custom_visibility' => true,
     1351                        'member_types'            => true,
     1352                );
     1353
     1354                if ( isset( $this->type_obj ) && $this->type_obj ) {
     1355                        $field_type = $this->type_obj;
     1356
     1357                        if ( isset( $field_type::$supported_features ) ) {
     1358                                $supports = array_merge( $supports, $field_type::$supported_features );
     1359                        }
     1360                }
     1361
     1362                return $supports;
     1363        }
     1364
     1365        /**
     1366         * Checks whether the field type supports the requested feature.
     1367         *
     1368         * @since 8.0.0
     1369         *
     1370         * @param string $support The name of the feature.
     1371         * @return boolean True if the field type supports the feature. False otherwise.
     1372         */
     1373        public function field_type_supports( $support = '' ) {
     1374                $retval   = true;
     1375                $features = $this->get_field_type_supports();
     1376
     1377                if ( isset( $features[ $support ] ) ) {
     1378                        $retval = $features[ $support ];
     1379                }
     1380
     1381                return $retval;
     1382        }
     1383
     1384        /**
    13211385         * Private method used to display the submit metabox.
    13221386         *
     
    14431507
    14441508                // The primary field is for all, so bail.
    1445                 if ( 1 === (int) $this->id ) {
     1509                if ( 1 === (int) $this->id || ! $this->field_type_supports( 'member_types' ) ) {
    14461510                        return;
    14471511                }
     
    14561520                ?>
    14571521
    1458                 <div id="member-types-div" class="postbox">
     1522                <div id="field-type-member-types" class="postbox">
    14591523                        <h2><?php _e( 'Member Types', 'buddypress' ); ?></h2>
    14601524                        <div class="inside">
     
    14971561        private function visibility_metabox() {
    14981562
    1499                 // Default field cannot have custom visibility.
    1500                 if ( true === $this->is_default_field() ) {
     1563                // Default field and field types not supporting the feature cannot have custom visibility.
     1564                if ( true === $this->is_default_field() || ! $this->field_type_supports( 'allow_custom_visibility' ) ) {
    15011565                        return;
    15021566                } ?>
    15031567
    1504                 <div class="postbox">
     1568                <div class="postbox" id="field-type-visibiliy-metabox">
    15051569                        <h2><label for="default-visibility"><?php esc_html_e( 'Visibility', 'buddypress' ); ?></label></h2>
    15061570                        <div class="inside">
     
    15461610        private function required_metabox() {
    15471611
    1548                 // Default field is always required.
    1549                 if ( true === $this->is_default_field() ) {
     1612                // Default field and field types not supporting the feature cannot be required.
     1613                if ( true === $this->is_default_field() || ! $this->field_type_supports( 'required' ) ) {
    15501614                        return;
    15511615                } ?>
    15521616
    1553                 <div class="postbox">
     1617                <div class="postbox" id="field-type-required-metabox">
    15541618                        <h2><label for="required"><?php esc_html_e( 'Requirement', 'buddypress' ); ?></label></h2>
    15551619                        <div class="inside">
     
    15721636         */
    15731637        private function autolink_metabox() {
    1574                 ?>
    1575 
    1576                 <div class="postbox">
     1638
     1639                // Field types not supporting the feature cannot use autolink.
     1640                if ( ! $this->field_type_supports( 'do_autolink' ) ) {
     1641                        return;
     1642                } ?>
     1643
     1644                <div class="postbox" id="field-type-autolink-metabox">
    15771645                        <h2><?php esc_html_e( 'Autolink', 'buddypress' ); ?></h2>
    15781646                        <div class="inside">
     
    16071675                if ( true === $this->is_default_field() ) {
    16081676                        return;
    1609                 } ?>
     1677                }
     1678                ?>
    16101679
    16111680                <div class="postbox">
    16121681                        <h2><label for="fieldtype"><?php esc_html_e( 'Type', 'buddypress'); ?></label></h2>
    16131682                        <div class="inside" aria-live="polite" aria-atomic="true" aria-relevant="all">
    1614                                 <select name="fieldtype" id="fieldtype" onchange="show_options(this.value)">
    1615 
    1616                                         <?php bp_xprofile_admin_form_field_types( $this->type ); ?>
    1617 
    1618                                 </select>
     1683                                <?php if ( ! $this->field_type_supports( 'switch_fieldtype' ) ) : ?>
     1684                                        <input type="text" disabled="true" value="<?php echo esc_attr( $this->type_obj->name ); ?>">
     1685                                        <input type="hidden" name="fieldtype" id="fieldtype" value="<?php echo esc_attr( $this->type ); ?>">
     1686
     1687                                <?php else : ?>
     1688                                        <select name="fieldtype" id="fieldtype" onchange="show_options(this.value)">
     1689
     1690                                                <?php bp_xprofile_admin_form_field_types( $this->type ); ?>
     1691
     1692                                        </select>
     1693                                <?php endif; ?>
    16191694
    16201695                                <?php
     
    16431718                wp_nonce_field( 'bp_xprofile_admin_field', 'bp_xprofile_admin_field' );
    16441719
    1645                 // Field 1 is the fullname field, which cannot have custom visibility.
    1646                 if ( false === $this->is_default_field() ) {
     1720                // Init default field hidden inputs.
     1721                $default_field_hidden_inputs = array();
     1722                $hidden_fields = array(
     1723                        'required' => array(
     1724                                'name'  => 'required',
     1725                                'id'    => 'required',
     1726                                'value' => '0',
     1727                        ),
     1728                        'default_visibility' => array(
     1729                                'name'  => 'default-visibility',
     1730                                'id'    => 'default-visibility',
     1731                                'value' => $this->get_default_visibility(),
     1732                        ),
     1733                        'allow_custom_visibility' => array(
     1734                                'name'  => 'allow-custom-visibility',
     1735                                'id'    => 'allow-custom-visibility',
     1736                                'value' => 'disabled',
     1737                        ),
     1738                        'do_autolink' => array(
     1739                                'name'  => 'do_autolink',
     1740                                'id'    => 'do-autolink',
     1741                                'value' => '',
     1742                        ),
     1743                );
     1744
     1745                // Field 1 is the fullname field, which is required.
     1746                if ( true === $this->is_default_field() ) {
     1747                        $default_field_required          = $hidden_fields['required'];
     1748                        $default_field_required['value'] = '1';
     1749
     1750                        $default_field_hidden_inputs = array(
     1751                                $default_field_required,
     1752                                array(
     1753                                        'name'  => 'fieldtype',
     1754                                        'id'    => 'fieldtype',
     1755                                        'value' => 'textbox',
     1756                                ),
     1757                        );
     1758                }
     1759
     1760                $supports = $this->get_field_type_supports();
     1761                if ( $supports ) {
     1762                        foreach ( $supports as $feature => $support ) {
     1763                                if ( true === $support || in_array( $feature, array( 'switch_fieldtype', 'member_types' ), true ) ) {
     1764                                        continue;
     1765                                }
     1766
     1767                                $default_field_hidden_inputs[] = $hidden_fields[ $feature ];
     1768
     1769                                if ( 'allow_custom_visibility' === $feature ) {
     1770                                        $default_field_hidden_inputs[] = $hidden_fields['default_visibility'];
     1771                                }
     1772                        }
     1773                }
     1774
     1775                if ( ! $default_field_hidden_inputs ) {
    16471776                        return;
    1648                 } ?>
    1649 
    1650                 <input type="hidden" name="required"  id="required"  value="1"       />
    1651                 <input type="hidden" name="fieldtype" id="fieldtype" value="textbox" />
    1652 
    1653                 <?php
     1777                }
     1778
     1779                foreach ( $default_field_hidden_inputs as $default_field_hidden_input ) {
     1780                        printf(
     1781                                '<input type="hidden" name="%1$s" id="%2$s" value="%3$s"/>',
     1782                                esc_attr( $default_field_hidden_input['name'] ),
     1783                                esc_attr( $default_field_hidden_input['id'] ),
     1784                                esc_attr( $default_field_hidden_input['value'] )
     1785                        );
     1786                }
    16541787        }
    16551788
  • trunk/src/bp-xprofile/classes/class-bp-xprofile-group.php

    r12725 r12868  
    238238         *
    239239         * @since 1.2.0
     240         * @since 2.4.0 Introduced `$member_type` argument.
     241         * @since 8.0.0 Introduced `$hide_field_types` argument.
    240242         *
    241243         * @global object $wpdb WordPress DB access object.
     
    257259         *      @type bool         $fetch_field_data  Whether to fetch data for each field. Requires a $user_id.
    258260         *                                            Default: false.
    259          *      @type array        $exclude_groups    Comma-separated list or array of group IDs to exclude.
    260          *      @type array        $exclude_fields    Comma-separated list or array of field IDs to exclude.
     261         *      @type int[]|bool   $exclude_groups    Comma-separated list or array of group IDs to exclude.
     262         *      @type int[]|bool   $exclude_fields    Comma-separated list or array of field IDs to exclude.
     263         *      @type string[]     $hide_field_types  List of field types to hide form loop. Default: empty array.
    261264         *      @type bool         $update_meta_cache Whether to pre-fetch xprofilemeta for all retrieved groups, fields,
    262265         *                                            and data. Default: true.
     
    279282                        'exclude_groups'         => false,
    280283                        'exclude_fields'         => false,
     284                        'hide_field_types'       => array(),
    281285                        'update_meta_cache'      => true,
    282286                ) );
     
    339343                $fields = array();
    340344                foreach ( $field_ids as $field_id ) {
    341                         $fields[] = xprofile_get_field( $field_id, null, false );
     345                        $_field = xprofile_get_field( $field_id, null, false );
     346
     347                        if ( in_array( $_field->type, $r['hide_field_types'], true ) ) {
     348                                continue;
     349                        }
     350
     351                        $fields[] = $_field;
    342352                }
    343353
     
    347357                // Maybe fetch field data.
    348358                if ( ! empty( $r['fetch_field_data'] ) ) {
     359                        $field_type_objects = wp_list_pluck( $fields, 'type_obj', 'id' );
    349360
    350361                        // Get field data for user ID.
    351362                        if ( ! empty( $field_ids ) && ! empty( $r['user_id'] ) ) {
    352                                 $field_data = BP_XProfile_ProfileData::get_data_for_user( $r['user_id'], $field_ids );
     363                                $field_data = BP_XProfile_ProfileData::get_data_for_user( $r['user_id'], $field_ids, $field_type_objects );
    353364                        }
    354365
  • trunk/tests/phpunit/testcases/xprofile/class-bp-xprofile-field-type.php

    r12697 r12868  
    11<?php
     2// Include the xProfile Test Type
     3include_once BP_TESTS_DIR . 'assets/bptest-xprofile-field-type.php';
     4
    25/**
    36 * @group xprofile
     
    58 */
    69class BP_Tests_XProfile_Field_Type extends BP_UnitTestCase {
     10
     11        public function setUp() {
     12                parent::setUp();
     13
     14                add_filter( 'bp_xprofile_get_field_types', array( $this, 'get_field_types' ) );
     15        }
     16
     17        public function tearDown() {
     18                parent::tearDown();
     19
     20                remove_filter( 'bp_xprofile_get_field_types', array( $this, 'get_field_types' ) );
     21        }
     22
    723        public function test_unregistered_field_type_returns_textbox() {
    824                $field = bp_xprofile_create_field_type( 'fakeyfield' );
     
    184200                $this->assertTrue( $field->is_valid( '(212) 664-7665' ) );
    185201        }
     202
     203        /**
     204         * @ticket BP7162
     205         */
     206        public function test_xprofile_field_type_test_supports() {
     207                $group_id = self::factory()->xprofile_group->create();
     208                $field_id = self::factory()->xprofile_field->create(
     209                        array(
     210                                'field_group_id' => $group_id,
     211                                'type'           => 'test-field-type',
     212                                'name'           => 'Test Supports',
     213                        )
     214                );
     215
     216                $field = xprofile_get_field( $field_id, null, false );
     217
     218                $this->assertTrue( $field->field_type_supports( 'switch_fieldtype' ) );
     219                $this->assertFalse( $field->field_type_supports( 'do_autolink' ) );
     220                $this->assertFalse( $field->field_type_supports( 'allow_custom_visibility' ) );
     221                $this->assertTrue( $field->field_type_supports( 'required' ) );
     222                $this->assertTrue( $field->field_type_supports( 'member_types' ) );
     223                $this->assertEquals( 'adminsonly', $field->get_default_visibility() );
     224        }
     225
     226        public function get_field_types( $types ) {
     227                $types['test-field-type'] = 'BPTest_XProfile_Field_Type';
     228                return $types;
     229        }
    186230}
Note: See TracChangeset for help on using the changeset viewer.