Skip to:
Content

BuddyPress.org


Ignore:
Timestamp:
07/21/2015 02:00:38 PM (10 years ago)
Author:
boonebgorges
Message:

Allow xProfile fields to be restricted to users belonging to one or more member types.

A new metabox on the profile field edit panel allows the administrator to
select the member types to which the field is applicable. Admins can also
choose to have a field apply to users who do not belong to any member type.
Information about a field's member type associations is displayed on the
Users > Profile Fields page, alongside each field name.

During registration, the only fields that are displayed are those that are
unrestricted - that is, those available to all users, regardless of member type
(or lack thereof).

This changeset introduces a number of new methods on BP_XProfile_Field that
developers should use to manipulate member type information:
get_member_types(), set_member_types(), and the static
get_fields_for_member_type(). In addition to member types that have been
explicitly registered, 'null' is a pseudo-type representing users who do not
belong to a member type.

This changeset introduces a blacklist of illegal member type names. By default,
the blacklist includes 'any', 'null', and '_none'. Use the
'bp_member_type_illegal_names' filter to add names to the blacklist.

Props Offereins, boonebgorges, tanner m, imath.
See #5192.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-xprofile/classes/class-bp-xprofile-field.php

    r9986 r10022  
    123123     */
    124124    public $data;
     125
     126    /**
     127     * Member types to which the profile field should be applied.
     128     *
     129     * @since BuddyPress (2.4.0)
     130     * @access protected
     131     * @var array Array of member types.
     132     */
     133    protected $member_types;
    125134
    126135    /**
     
    458467    }
    459468
     469    /**
     470     * Gets the member types to which this field should be available.
     471     *
     472     * Will not return inactive member types, even if associated metadata is found.
     473     *
     474     * 'null' is a special pseudo-type, which represents users that do not have a member type.
     475     *
     476     * @since BuddyPress (2.4.0)
     477     *
     478     * @return array Array of member type names.
     479     */
     480    public function get_member_types() {
     481        if ( ! is_null( $this->member_types ) ) {
     482            return $this->member_types;
     483        }
     484
     485        $raw_types = bp_xprofile_get_meta( $this->id, 'field', 'member_type', false );
     486
     487        // If `$raw_types` is not an array, it probably means this is a new field (id=0).
     488        if ( ! is_array( $raw_types ) ) {
     489            $raw_types = array();
     490        }
     491
     492        // If '_none' is found in the array, it overrides all types.
     493        $types = array();
     494        if ( ! in_array( '_none', $raw_types ) ) {
     495            $registered_types = bp_get_member_types();
     496
     497            // Eliminate invalid member types saved in the database.
     498            foreach ( $raw_types as $raw_type ) {
     499                // 'null' is a special case - it represents users without a type.
     500                if ( 'null' === $raw_type || isset( $registered_types[ $raw_type ] ) ) {
     501                    $types[] = $raw_type;
     502                }
     503            }
     504
     505            // If no member types have been saved, intepret as *all* member types.
     506            if ( empty( $types ) ) {
     507                $types = array_values( $registered_types );
     508
     509                // + the "null" type, ie users without a type.
     510                $types[] = 'null';
     511            }
     512        }
     513
     514        /**
     515         * Filters the member types to which an XProfile object should be applied.
     516         *
     517         * @since BuddyPress (2.4.0)
     518         *
     519         * @param array             $types Member types.
     520         * @param BP_XProfile_Field $field Field object.
     521         */
     522        $this->member_types = apply_filters( 'bp_xprofile_field_member_types', $types, $this );
     523
     524        return $this->member_types;
     525    }
     526
     527    /**
     528     * Sets the member types for this field.
     529     *
     530     * @since BuddyPress (2.4.0)
     531     *
     532     * @param array $member_types Array of member types. Can include 'null' (users with no type) in addition to any
     533     *                            registered types.
     534     * @param bool  $append       Whether to append to existing member types. If false, all existing member type
     535     *                            associations will be deleted before adding your `$member_types`. Default false.
     536     * @return array Member types for the current field, after being saved.
     537     */
     538    public function set_member_types( $member_types, $append = false ) {
     539        // Unset invalid member types.
     540        $types = array();
     541        foreach ( $member_types as $member_type ) {
     542            // 'null' is a special case - it represents users without a type.
     543            if ( 'null' === $member_type || bp_get_member_type_object( $member_type ) ) {
     544                $types[] = $member_type;
     545            }
     546        }
     547
     548        // When `$append` is false, delete all existing types before adding new ones.
     549        if ( ! $append ) {
     550            bp_xprofile_delete_meta( $this->id, 'field', 'member_type' );
     551
     552            /*
     553             * We interpret an empty array as disassociating the field from all types. This is
     554             * represented internally with the '_none' flag.
     555             */
     556            if ( empty( $types ) ) {
     557                bp_xprofile_add_meta( $this->id, 'field', 'member_type', '_none' );
     558            }
     559        }
     560
     561        /*
     562         * Unrestricted fields are represented in the database as having no 'member_type'.
     563         * We detect whether a field is being set to unrestricted by checking whether the
     564         * list of types passed to the method is the same as the list of registered types,
     565         * plus the 'null' pseudo-type.
     566         */
     567        $_rtypes  = bp_get_member_types();
     568        $rtypes   = array_values( $_rtypes );
     569        $rtypes[] = 'null';
     570
     571        sort( $types );
     572        sort( $rtypes );
     573
     574        // Only save if this is a restricted field.
     575        if ( $types !== $rtypes ) {
     576            // Save new types.
     577            foreach ( $types as $type ) {
     578                bp_xprofile_add_meta( $this->id, 'field', 'member_type', $type );
     579            }
     580        }
     581
     582        // Reset internal cache of member types.
     583        $this->member_types = null;
     584
     585        /**
     586         * Fires after a field's member types have been updated.
     587         *
     588         * @since BuddyPress (2.4.0)
     589         *
     590         * @param BP_XProfile_Field $field Field object.
     591         */
     592        do_action( 'bp_xprofile_field_set_member_type', $this );
     593
     594        // Refetch fresh items from the database.
     595        return $this->get_member_types();
     596    }
     597
     598    /**
     599     * Gets a label representing the field's member types.
     600     *
     601     * This label is displayed alongside the field's name on the Profile Fields Dashboard panel.
     602     *
     603     * @since BuddyPress (2.4.0)
     604     *
     605     * @return string
     606     */
     607    public function get_member_type_label() {
     608        // Field 1 is always displayed to everyone, so never gets a label.
     609        if ( 1 == $this->id ) {
     610            return '';
     611        }
     612
     613        // Return an empty string if no member types are registered.
     614        $all_types = bp_get_member_types();
     615        if ( empty( $all_types ) ) {
     616            return '';
     617        }
     618
     619        $member_types = $this->get_member_types();
     620
     621        // If the field applies to all member types, show no message.
     622        $all_types[] = 'null';
     623        if ( array_values( $all_types ) == $member_types ) {
     624            return '';
     625        }
     626
     627        $label = '';
     628        if ( ! empty( $member_types ) ) {
     629            $has_null = false;
     630            $member_type_labels = array();
     631            foreach ( $member_types as $member_type ) {
     632                if ( 'null' === $member_type ) {
     633                    $has_null = true;
     634                    continue;
     635                } else {
     636                    $mt_obj = bp_get_member_type_object( $member_type );
     637                    $member_type_labels[] = $mt_obj->labels['name'];
     638                }
     639            }
     640
     641            // Alphabetical sort.
     642            natcasesort( $member_type_labels );
     643            $member_type_labels = array_values( $member_type_labels );
     644
     645            // Add the 'null' option to the end of the list.
     646            if ( $has_null ) {
     647                $member_type_labels[] = __( 'Users with no member type', 'buddypress' );
     648            }
     649
     650            $label = sprintf( __( '(Member types: %s)', 'buddypress' ), implode( ', ', array_map( 'esc_html', $member_type_labels ) ) );
     651        } else {
     652            $label = '<span class="member-type-none-notice">' . __( '(Unavailable to all members)', 'buddypress' ) . '</span>';
     653        }
     654
     655        return $label;
     656    }
     657
    460658    /** Static Methods ********************************************************/
    461659
     
    572770
    573771        return false;
     772    }
     773
     774    /**
     775     * Gets the IDs of fields applicable for a given member type or array of member types.
     776     *
     777     * @since BuddyPress (2.4.0)
     778     *
     779     * @param string|array $member_types Member type or array of member types. Use 'any' to return unrestricted
     780     *                                   fields (those available for anyone, regardless of member type).
     781     * @return array Multi-dimensional array, with field IDs as top-level keys, and arrays of member types
     782     *               associated with each field as values.
     783     */
     784    public static function get_fields_for_member_type( $member_types ) {
     785        global $wpdb;
     786
     787        $fields = array();
     788
     789        if ( empty( $member_types ) ) {
     790            $member_types = array( 'any' );
     791        } elseif ( ! is_array( $member_types ) ) {
     792            $member_types = array( $member_types );
     793        }
     794
     795        $bp = buddypress();
     796
     797        // Pull up all recorded field member type data.
     798        $mt_meta = wp_cache_get( 'field_member_types', 'bp_xprofile' );
     799        if ( false === $mt_meta ) {
     800            $mt_meta = $wpdb->get_results( "SELECT object_id, meta_value FROM {$bp->profile->table_name_meta} WHERE meta_key = 'member_type' AND object_type = 'field'" );
     801            wp_cache_set( 'field_member_types', $mt_meta, 'bp_xprofile' );
     802        }
     803
     804        // Keep track of all fields with recorded member_type metadata.
     805        $all_recorded_field_ids = wp_list_pluck( $mt_meta, 'object_id' );
     806
     807        // Sort member_type matches in arrays, keyed by field_id.
     808        foreach ( $mt_meta as $_mt_meta ) {
     809            if ( ! isset( $fields[ $_mt_meta->object_id ] ) ) {
     810                $fields[ $_mt_meta->object_id ] = array();
     811            }
     812
     813            $fields[ $_mt_meta->object_id ][] = $_mt_meta->meta_value;
     814        }
     815
     816        /*
     817         * Filter out fields that don't match any passed types, or those marked '_none'.
     818         * The 'any' type is implicitly handled here: it will match no types.
     819         */
     820        foreach ( $fields as $field_id => $field_types ) {
     821            if ( ! array_intersect( $field_types, $member_types ) ) {
     822                unset( $fields[ $field_id ] );
     823            }
     824        }
     825
     826        // Any fields with no member_type metadata are available to all member types.
     827        if ( ! in_array( '_none', $member_types ) ) {
     828            if ( ! empty( $all_recorded_field_ids ) ) {
     829                $all_recorded_field_ids_sql = implode( ',', array_map( 'absint', $all_recorded_field_ids ) );
     830                $unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields} WHERE id NOT IN ({$all_recorded_field_ids_sql})" );
     831            } else {
     832                $unrestricted_field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields}" );
     833            }
     834
     835            // Append the 'null' pseudo-type.
     836            $all_member_types   = bp_get_member_types();
     837            $all_member_types   = array_values( $all_member_types );
     838            $all_member_types[] = 'null';
     839
     840            foreach ( $unrestricted_field_ids as $unrestricted_field_id ) {
     841                $fields[ $unrestricted_field_id ] = $all_member_types;
     842            }
     843        }
     844
     845        return $fields;
    574846    }
    575847
     
    718990                            // Output the required metabox
    719991                            $this->required_metabox();
     992
     993                            // Output the Member Types metabox.
     994                            $this->member_type_metabox();
    720995
    721996                            // Output the field visibility metaboxes
     
    8621137
    8631138    <?php
     1139    }
     1140
     1141    /**
     1142     * Private method used to output field Member Type metabox.
     1143     *
     1144     * @since BuddyPress (2.4.0)
     1145     */
     1146    private function member_type_metabox() {
     1147
     1148        // The primary field is for all, so bail.
     1149        if ( 1 === (int) $this->id ) {
     1150            return;
     1151        }
     1152
     1153        // Bail when no member types are registered.
     1154        if ( ! $member_types = bp_get_member_types( array(), 'objects' ) ) {
     1155            return;
     1156        }
     1157
     1158        $field_member_types = $this->get_member_types();
     1159
     1160        ?>
     1161
     1162        <div id="member-types-div" class="postbox">
     1163            <h3><?php _e( 'Member Types', 'buddypress' ); ?></h3>
     1164            <div class="inside">
     1165                <p class="description"><?php _e( 'This field should be available to:', 'buddypress' ); ?></p>
     1166
     1167                <ul>
     1168                    <?php foreach ( $member_types as $member_type ) : ?>
     1169                    <li>
     1170                        <label>
     1171                            <input name="member-types[]" class="member-type-selector" type="checkbox" value="<?php echo $member_type->name; ?>" <?php checked( in_array( $member_type->name, $field_member_types ) ); ?>/>
     1172                            <?php echo $member_type->labels['name']; ?>
     1173                        </label>
     1174                    </li>
     1175                    <?php endforeach; ?>
     1176
     1177                    <li>
     1178                        <label>
     1179                            <input name="member-types[]" class="member-type-selector" type="checkbox" value="null" <?php checked( in_array( 'null', $field_member_types ) ); ?>/>
     1180                            <?php _e( 'Users with no member type', 'buddypress' ); ?>
     1181                        </label>
     1182                    </li>
     1183
     1184                </ul>
     1185                <p class="description member-type-none-notice<?php if ( ! empty( $field_member_types ) ) : ?> hide<?php endif; ?>"><?php _e( 'Unavailable to all members.', 'buddypress' ) ?></p>
     1186            </div>
     1187
     1188            <input type="hidden" name="has-member-types" value="1" />
     1189        </div>
     1190
     1191        <?php
    8641192    }
    8651193
Note: See TracChangeset for help on using the changeset viewer.