Skip to:
Content

BuddyPress.org

Changeset 12868


Ignore:
Timestamp:
03/21/2021 02:17:21 PM (7 months 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.