Skip to:
Content

BuddyPress.org

Ticket #8045: 8045.3.patch

File 8045.3.patch, 31.6 KB (added by imath, 6 years ago)
  • src/bp-core/bp-core-rest-api.php

    diff --git src/bp-core/bp-core-rest-api.php src/bp-core/bp-core-rest-api.php
    index e69de29bb..0aec5c0c0 100644
     
     1<?php
     2/**
     3 * Core REST API functions.
     4 *
     5 * @package BuddyPress
     6 * @subpackage Core
     7 * @since 5.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * Check the availability of the BP REST API.
     15 *
     16 * @since 5.0.0
     17 *
     18 * @return boolean True if the BP REST API is available. False otherwise.
     19 */
     20function bp_rest_api_is_available() {
     21    /**
     22     * Filter here to disable the BP REST API.
     23     *
     24     * The BP REST API requires at least WordPress 4.7.0
     25     *
     26     * @since 5.0.0
     27     *
     28     * @param boolean $value True if the BP REST API is available. False otherwise.
     29     */
     30    return apply_filters( 'bp_rest_api_is_available', function_exists( 'create_initial_rest_routes' ) );
     31}
     32
     33/**
     34 * Register the jQuery.ajax wrapper for BP REST API requests.
     35 *
     36 * @since 5.0.0
     37 */
     38function bp_rest_api_register_request_script() {
     39    if ( ! bp_rest_api_is_available() ) {
     40        return;
     41    }
     42
     43    $dependencies = array( 'jquery' );
     44
     45    // The wrapper for WP REST API requests was introduced in WordPress 4.9.0
     46    if ( wp_script_is( 'wp-api-request', 'registered' ) ) {
     47        $dependencies = array( 'wp-api-request' );
     48    }
     49
     50    wp_register_script(
     51        'bp-api-request',
     52        sprintf( '%1$sbp-core/js/bp-api-request%2$s.js', buddypress()->plugin_url, bp_core_get_minified_asset_suffix() ),
     53        $dependencies,
     54        bp_get_version(),
     55        true
     56    );
     57    wp_localize_script(
     58        'bp-api-request',
     59        'bpApiSettings',
     60        array(
     61            'root'  => esc_url_raw( get_rest_url() ),
     62            'nonce' => wp_create_nonce( 'wp_rest' ),
     63        )
     64    );
     65}
     66add_action( 'bp_init', 'bp_rest_api_register_request_script' );
  • src/bp-core/js/bp-api-request.js

    diff --git src/bp-core/js/bp-api-request.js src/bp-core/js/bp-api-request.js
    index e69de29bb..d301b5482 100644
     
     1/**
     2 * jQuery.ajax wrapper for BP REST API requests.
     3 *
     4 * @since  5.0.0
     5 * @output bp-core/js/bp-api-request.js
     6 */
     7/* global bpApiSettings */
     8window.bp = window.bp || {};
     9
     10( function( wp, bp, $ ) {
     11    // Bail if not set
     12    if ( typeof bpApiSettings === 'undefined' ) {
     13        return;
     14    }
     15
     16    bp.isRestEnabled = true;
     17
     18    // Polyfill wp.apiRequest if WordPress < 4.9
     19        bp.apiRequest = wp.apiRequest || function( options ) {
     20                var url = bpApiSettings.root;
     21
     22                if ( options.path ) {
     23                        url = url + options.path.replace( /^\//, '' );
     24                }
     25
     26                options.url = url;
     27                options.beforeSend = function( xhr ) {
     28                        xhr.setRequestHeader( 'X-WP-Nonce', bpApiSettings.nonce );
     29                };
     30
     31                return $.ajax( options );
     32        };
     33
     34} )( window.wp || {}, window.bp, jQuery );
  • src/bp-groups/admin/css/admin.css

    diff --git src/bp-groups/admin/css/admin.css src/bp-groups/admin/css/admin.css
    index 0a7887a10..a87b9aabb 100644
    table.bp-group-members .urole-column { 
    140140        padding-right: 20px;
    141141}
    142142
     143#group-manage-members-ui .subnav-filters .filter.last {
     144        float: right;
     145}
     146
     147#group-manage-members-ui .uname-column .profile-photo {
     148        margin-right: 1em;
     149}
     150
    143151@media screen and (max-width: 782px) {
    144152
    145153        .bp-groups-settings-section label {
  • src/bp-groups/bp-groups-admin.php

    diff --git src/bp-groups/bp-groups-admin.php src/bp-groups/bp-groups-admin.php
    index 94ef62829..71718e02d 100644
    function bp_groups_admin_edit_metabox_add_new_members( $item ) { 
    891891 * @param BP_Groups_Group $item The BP_Groups_Group object for the current group.
    892892 */
    893893function bp_groups_admin_edit_metabox_members( $item ) {
     894        // Use the BP REST API if it supported.
     895        if ( bp_rest_api_is_available() && bp_groups_has_manage_group_members_templates() ) {
     896                wp_enqueue_script( 'bp-group-manage-members' );
     897                wp_localize_script(
     898                        'bp-group-manage-members',
     899                        'bpGroupManageMembersSettings',
     900                        bp_groups_get_group_manage_members_script_data( $item->id )
     901                );
     902
     903                bp_get_template_part( 'common/js-templates/group-members/index' );
     904
     905                /**
     906                 * Echo out the JavaScript variable.
     907                 * This seems to be required by the autocompleter, leaving this here for now...
     908                 */
     909                echo '<script type="text/javascript">var group_id = "' . esc_js( $item->id ) . '";</script>';
     910                return;
     911        }
    894912
    895913        // Pull up a list of group members, so we can separate out the types
    896914        // We'll also keep track of group members here to place them into a
  • src/bp-groups/bp-groups-cssjs.php

    diff --git src/bp-groups/bp-groups-cssjs.php src/bp-groups/bp-groups-cssjs.php
    index e69de29bb..61368a56a 100644
     
     1<?php
     2/**
     3 * Groups component CSS/JS
     4 *
     5 * @package BuddyPress
     6 * @subpackage GroupsScripts
     7 * @since 5.0.0
     8 */
     9
     10// Exit if accessed directly.
     11defined( 'ABSPATH' ) || exit;
     12
     13/**
     14 * Register Groups JavaScripts.
     15 *
     16 * @since 5.0.0
     17 */
     18function bp_groups_register_scripts() {
     19    wp_register_script(
     20        'bp-group-manage-members',
     21        sprintf( '%1$sbp-groups/js/manage-members%2$s.js', buddypress()->plugin_url, bp_core_get_minified_asset_suffix() ),
     22        array( 'json2', 'wp-backbone', 'bp-api-request' ),
     23        bp_get_version(),
     24        true
     25    );
     26}
     27add_action( 'bp_enqueue_scripts',       'bp_groups_register_scripts', 1 );
     28add_action( 'bp_admin_enqueue_scripts', 'bp_groups_register_scripts', 1 );
     29
     30/**
     31 * Get JavaScript data for the Manage Group Members UI.
     32 *
     33 * @since 5.0.0
     34 *
     35 * @param  integer $group_id Required. The Group ID whose members has to be managed.
     36 * @return array   The JavaScript data.
     37 */
     38function bp_groups_get_group_manage_members_script_data( $group_id = 0 ) {
     39        if ( ! $group_id ) {
     40                return array();
     41        } else {
     42                $group_id = (int) $group_id;
     43        }
     44
     45        $path = sprintf( '/%1$s/%2$s/%3$s/%4$s/members?exclude_admins=false',
     46                bp_rest_namespace(),
     47                bp_rest_version(),
     48                buddypress()->groups->id,
     49                $group_id
     50        );
     51
     52        $preloaded_members = array();
     53        if ( function_exists( 'rest_preload_api_request' ) ) {
     54                $preloaded_members = rest_preload_api_request( '', $path );
     55        }
     56
     57        return array(
     58                'path'      => remove_query_arg( 'exclude_admins', $path ),
     59                'preloaded' => reset( $preloaded_members ),
     60                'roles'     => bp_groups_get_group_roles(),
     61        );
     62}
  • src/bp-groups/bp-groups-functions.php

    diff --git src/bp-groups/bp-groups-functions.php src/bp-groups/bp-groups-functions.php
    index 43240122a..ab0199090 100644
    function groups_avatar_upload_dir( $group_id = 0 ) { 
    11111111
    11121112/** Group Member Status Checks ************************************************/
    11131113
     1114/**
     1115 * Get the Group roles.
     1116 *
     1117 * @since 5.0.0
     1118 *
     1119 * @return array The list of Group role objects.
     1120 */
     1121function bp_groups_get_group_roles() {
     1122        return array(
     1123                'admin' => (object) array(
     1124                        'id'           => 'admin',
     1125                        'name'         => __( 'Administrator', 'buddypress' ),
     1126                        'is_admin'     => true,
     1127                        'is_banned'    => false,
     1128                        'is_confirmed' => true,
     1129                        'is_mod'       => false,
     1130                ),
     1131                'mod' => (object) array(
     1132                        'id'           => 'mod',
     1133                        'name'         => __( 'Moderator', 'buddypress' ),
     1134                        'is_admin'     => false,
     1135                        'is_banned'    => false,
     1136                        'is_confirmed' => true,
     1137                        'is_mod'       => true,
     1138                ),
     1139                'member' => (object) array(
     1140                        'id'           => 'member',
     1141                        'name'         => __( 'Member', 'buddypress' ),
     1142                        'is_admin'     => false,
     1143                        'is_banned'    => false,
     1144                        'is_confirmed' => true,
     1145                        'is_mod'       => false,
     1146                ),
     1147                'banned' => (object) array(
     1148                        'id'           => 'banned',
     1149                        'name'         => __( 'Banned', 'buddypress' ),
     1150                        'is_admin'     => false,
     1151                        'is_banned'    => true,
     1152                        'is_confirmed' => true,
     1153                        'is_mod'       => false,
     1154                ),
     1155        );
     1156}
     1157
    11141158/**
    11151159 * Check whether a user is an admin of a given group.
    11161160 *
  • src/bp-groups/bp-groups-template.php

    diff --git src/bp-groups/bp-groups-template.php src/bp-groups/bp-groups-template.php
    index c5c5a0465..cc855dd63 100644
    function bp_groups_get_profile_stats( $args = '' ) { 
    61616161         */
    61626162        return apply_filters( 'bp_groups_get_profile_stats', $r['output'], $r );
    61636163}
     6164
     6165/**
     6166 * Check if the active template pack includes the Group Membership management UI templates.
     6167 *
     6168 * @since 5.0.0
     6169 *
     6170 * @return boolean True if the active template pack includes the Group Membership management UI templates.
     6171 *                 False otherwise.
     6172 */
     6173function bp_groups_has_manage_group_members_templates() {
     6174        return file_exists( bp_locate_template( 'common/js-templates/group-members/index.php' ) );
     6175}
  • src/bp-groups/classes/class-bp-groups-component.php

    diff --git src/bp-groups/classes/class-bp-groups-component.php src/bp-groups/classes/class-bp-groups-component.php
    index f7d45658d..99c5a7f31 100644
    class BP_Groups_Component extends BP_Component { 
    128128                        'template',
    129129                        'adminbar',
    130130                        'functions',
    131                         'notifications'
     131                        'notifications',
     132                        'cssjs',
    132133                );
    133134
    134135                // Conditional includes.
  • src/bp-groups/js/manage-members.js

    diff --git src/bp-groups/js/manage-members.js src/bp-groups/js/manage-members.js
    index e69de29bb..039f23502 100644
     
     1/* global wp, bp, bpGroupManageMembersSettings, _, Backbone */
     2/* @version 5.0.0 */
     3
     4( function( wp, bp, $ ) {
     5
     6        // Bail if not set
     7        if ( typeof bpGroupManageMembersSettings === 'undefined' || ! bp.isRestEnabled ) {
     8                return;
     9        }
     10
     11        // Copy useful WP Objects into BP.
     12        _.extend( bp, _.pick( wp, 'Backbone', 'template' ) );
     13
     14        bp.Models      = bp.Models || {};
     15        bp.Collections = bp.Collections || {};
     16        bp.Views       = bp.Views || {};
     17
     18        /**
     19         * Model for the Member of the displayed group.
     20         */
     21        bp.Models.groupMember = Backbone.Model.extend( {
     22                defaults: {
     23                        id: 0,
     24                        name: '',
     25                        avatar_urls : {},
     26                        is_admin: false,
     27                        is_banned: false,
     28                        is_confirmed: false,
     29                        is_mod: false,
     30                        link: ''
     31                },
     32                options : {
     33                        path: bpGroupManageMembersSettings.path,
     34                        type: 'POST',
     35                        data: {},
     36                        dataType: 'json'
     37                },
     38
     39                initialize: function() {
     40                        // Make sure to reset data & path on model's sync.
     41                        this.on( 'sync', this.resetRequestOptions, this );
     42                },
     43
     44                resetRequestOptions: function() {
     45                        this.options.data = {};
     46                        this.options.path = bpGroupManageMembersSettings.path;
     47                },
     48
     49                sync: function( method, model, options ) {
     50                        options  = options || {};
     51                        options.context = this;
     52                        var data = options.data || {};
     53                        this.options.path = this.options.path.concat( '/' + model.get( 'id' ) );
     54
     55                        _.extend( options, this.options );
     56                        _.extend( options.data, data );
     57
     58                        if ( 'delete' === method || 'update' === method ) {
     59                                if ( 'delete' === method ) {
     60                                        options.headers = { 'X-HTTP-Method-Override': 'DELETE' };
     61                                } else {
     62                                        options.headers = { 'X-HTTP-Method-Override': 'PUT' };
     63                                }
     64
     65                                return bp.apiRequest( options );
     66                        }
     67                },
     68
     69                parse: function( response ) {
     70                        if ( _.isArray( response ) ) {
     71                                response = _.first( response );
     72                        }
     73
     74                        return response;
     75                }
     76        } );
     77
     78        /**
     79         * Collection for the Members of the displayed group.
     80         */
     81        bp.Collections.groupMembers = Backbone.Collection.extend( {
     82                model: bp.Models.groupMember,
     83                options : {
     84                        path: bpGroupManageMembersSettings.path,
     85                        type: 'GET',
     86                        data: {},
     87                        dataType: 'json'
     88                },
     89
     90                initialize: function() {
     91                        // Make sure to reset data on collection's reset.
     92                        this.on( 'reset', function() {
     93                                this.options.data = {};
     94                        }, this );
     95                },
     96
     97                sync: function( method, collection, options ) {
     98                        options  = options || {};
     99                        options.context = this;
     100                        var data = options.data || {};
     101
     102                        _.extend( options, this.options );
     103                        _.extend( options.data, data );
     104
     105                        if ( 'read' === method ) {
     106                                var self = this, success = options.success;
     107                                options.success = function( data, textStatus, request ) {
     108                                        if ( ! _.isUndefined( request ) ) {
     109                                                self.totalPages        = parseInt( request.getResponseHeader( 'X-WP-TotalPages' ), 10 );
     110                                                self.totalGroupMembers = parseInt( request.getResponseHeader( 'X-WP-Total' ), 10 );
     111                                        }
     112
     113                                        self.currentPage = options.data.page || 1;
     114
     115                                        if ( success ) {
     116                                                return success.apply( this, arguments );
     117                                        }
     118                                };
     119
     120                                return bp.apiRequest( options );
     121                        }
     122                }
     123        } );
     124
     125        // Extend wp.Backbone.View with .prepare().
     126        bp.View = bp.View || bp.Backbone.View.extend( {
     127                prepare: function() {
     128                        if ( ! _.isUndefined( this.model ) && _.isFunction( this.model.toJSON ) ) {
     129                                return this.model.toJSON();
     130                        } else {
     131                                return {};
     132                        }
     133                }
     134        } );
     135
     136        bp.Views.GroupMemberUpdatingInfo = bp.View.extend( {
     137                tagName: 'p',
     138                template : bp.template( 'bp-manage-members-updating' ),
     139
     140                initialize: function() {
     141                        this.model = new Backbone.Model( {
     142                                type: this.options.value
     143                        } );
     144                }
     145        } );
     146
     147        bp.Views.GroupMemberErrorInfo = bp.View.extend( {
     148                tagName: 'p',
     149                template : bp.template( 'bp-manage-members-error' ),
     150
     151                initialize: function() {
     152                        this.model = new Backbone.Model( {
     153                                message: this.options.value
     154                        } );
     155                }
     156        } );
     157
     158        bp.Views.GroupsMembersLabel = bp.Views.GroupMemberUpdatingInfo.extend( {
     159                tagName: 'label',
     160                template:  bp.template( 'bp-manage-members-label' )
     161        } );
     162
     163        bp.Views.GroupRolesDropDown = bp.View.extend( {
     164                tagName: 'select',
     165                filters: _.extend( { all: { name: 'All members' } }, bpGroupManageMembersSettings.roles ),
     166
     167                events: {
     168                        change: 'change'
     169                },
     170
     171                initialize: function() {
     172                        if ( this.options.omits ) {
     173                                this.filters = _.omit( this.filters, this.options.omits );
     174                        }
     175
     176                        if ( this.options.extends ) {
     177                                this.filters = _.extend( this.filters, this.options.extends );
     178                        }
     179
     180                        // Build `<option>` elements.
     181                        this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
     182                                var optionOutput = $( '<option></option>' ).val( value ).html( filter.name )[0];
     183
     184                                if ( this.options.currentRole && value === this.options.currentRole ) {
     185                                        return {
     186                                                el: $( optionOutput ).prop( 'selected', true )
     187                                        };
     188                                } else {
     189                                        return {
     190                                                el: optionOutput
     191                                        };
     192                                }
     193                        }, this ).pluck( 'el' ).value() );
     194                },
     195
     196                change: function( event ) {
     197                        var role =  $( event.target ).val(), queryArgs = { roles: [ role ] };
     198
     199                        if ( ! this.collection ) {
     200                                return;
     201                        }
     202
     203                        if ( 'all' === role ) {
     204                                // Unset the current role.
     205                                this.collection.currentRole = '';
     206
     207                                queryArgs = { 'exclude_admins': false };
     208                        } else {
     209                                // Set the current role.
     210                                this.collection.currentRole = role;
     211                        }
     212
     213                        queryArgs.page = 1;
     214
     215                        this.collection.fetch( {
     216                                data: queryArgs,
     217                                reset: true
     218                        } );
     219                }
     220        } );
     221
     222        bp.Views.GroupsMembersPagination = bp.View.extend( {
     223                className: 'bp-pagination',
     224                template:  bp.template( 'bp-manage-members-paginate' ),
     225
     226                events: {
     227                        'click .group-members-paginate-link' : 'queryPage',
     228                },
     229
     230                initialize: function() {
     231                        this.collection.on( 'reset', this.setPagination, this );
     232                },
     233
     234                setPagination: function( collection ) {
     235                        var attributes = _.pick( collection, [ 'currentPage', 'totalGroupMembers', 'totalPages' ] );
     236
     237                        if ( attributes.totalPages > 1 ) {
     238                                attributes.nextPage = attributes.currentPage + 1;
     239                                attributes.prevPage = attributes.currentPage - 1;
     240                        }
     241
     242                        this.model = new Backbone.Model( attributes );
     243                        this.render();
     244                },
     245
     246                queryPage: function( event ) {
     247                        event.preventDefault();
     248
     249                        var page = $( event.target ).data( 'page' ),
     250                                queryArgs = _.extend( this.collection.options.data, { page: page } );
     251
     252                        if ( ! this.collection.currentRole ) {
     253                                queryArgs[ 'exclude_admins' ] = false;
     254                        } else {
     255                                queryArgs.roles = [ this.collection.currentRole ];
     256                        }
     257
     258                        this.collection.fetch( {
     259                                data: queryArgs,
     260                                reset: true
     261                        } );
     262                }
     263        } );
     264
     265        bp.Views.GroupMembersListRow = bp.View.extend( {
     266                tagName: 'tr',
     267                template : bp.template( 'bp-manage-members-row' ),
     268
     269                events: {
     270                        'click .group-member-actions a' : 'doMemberAction',
     271                        'change .group-member-edit select' : 'editMemberRole'
     272                },
     273
     274                initialize: function() {
     275                        var roleProps = [ 'is_admin', 'is_banned', 'is_confirmed', 'is_mod' ],
     276                                self = this;
     277
     278                        _.each( bpGroupManageMembersSettings.roles, function( props ) {
     279                                if ( _.isMatch( self.model.attributes,  _.pick( props, roleProps ) ) ) {
     280                                        self.model.set( 'role', _.pick( props, ['id', 'name'] ), { silent: true } );
     281                                }
     282                        } );
     283
     284                        this.model.collection.on( 'reset', this.clearRow, this );
     285                },
     286
     287                clearRow: function() {
     288                        this.views.view.remove();
     289                },
     290
     291                renderEditForm: function() {
     292                        var userId = this.model.get( 'id' );
     293
     294                        this.render();
     295
     296                        this.views.set( '#edit-group-member-' + userId, [
     297                                new bp.Views.GroupsMembersLabel( { value: userId, attributes: { for: 'group-member' + userId + '-role' } } ),
     298                                new bp.Views.GroupRolesDropDown( { id: 'group-member' + userId + '-role', omits: [ 'all', 'banned' ], currentRole: this.model.get( 'role' ).id } ).render()
     299                        ] );
     300                },
     301
     302                resetRow: function() {
     303                        this.model.set( 'editing', false );
     304
     305                        return this.render();
     306                },
     307
     308                getRoleObject: function( roleId ) {
     309                        var roles = bpGroupManageMembersSettings.roles;
     310
     311                        if ( _.isUndefined( roles[ roleId ] ) ) {
     312                                return {};
     313                        }
     314
     315                        return _.extend(
     316                                { role: _.pick( roles[ roleId ], ['id', 'name'] ) },
     317                                _.pick( roles[ roleId ], [ 'is_admin', 'is_banned', 'is_confirmed', 'is_mod' ] )
     318                        );
     319                },
     320
     321                doMemberAction: function( event ) {
     322                        event.preventDefault();
     323
     324                        var action = $( event.target ).data( 'action' ), self = this;
     325
     326                        if ( 'edit' === action ) {
     327                                this.model.set( 'editing', true );
     328                                return this.renderEditForm();
     329
     330                        } else if ( 'abort' === action ) {
     331                                return this.resetRow();
     332
     333                        } else if ( 'ban' === action || 'unban' === action ) {
     334                                var newRole = ( 'ban' === action ) ? 'banned' : 'member', roleObject = this.getRoleObject( newRole );
     335
     336                                if ( ! roleObject ) {
     337                                        return this.resetRow();
     338                                } else {
     339                                        this.model.set( 'managingBan', true );
     340                                        this.render();
     341                                }
     342
     343                                // Display user feedback.
     344                                this.views.set( '#edit-group-member-' + this.model.get( 'id' ), new bp.Views.GroupMemberUpdatingInfo( { value: action } ).render() );
     345
     346                                // Update Group member's role.
     347                                this.model.save( roleObject, {
     348                                        wait: true,
     349                                        data: { action: action },
     350                                        success: function( model, response ) {
     351                                                self.model.collection.remove( model );
     352                                                return self.clearRow();
     353                                        },
     354                                        error: function( model, response ) {
     355                                                self.views.set( '#edit-group-member-' + model.get( 'id' ), new bp.Views.GroupMemberErrorInfo( { value: response.responseJSON.message } ).render() );
     356
     357                                                // Make sure to reset request options.
     358                                                model.resetRequestOptions();
     359                                                model.set( 'managingBan', false );
     360                                        }
     361                                } );
     362                        } else if ( 'remove' === action ) {
     363                                this.model.set( 'removing', true );
     364                                this.render();
     365
     366                                // Display user feedback.
     367                                this.views.set( '#edit-group-member-' + this.model.get( 'id' ), new bp.Views.GroupMemberUpdatingInfo( { value: action } ).render() );
     368
     369                                // Destroy the membership model.
     370                                this.model.destroy( {
     371                                        wait: true,
     372                                        data: {},
     373                                        success: function( model, response ) {
     374                                                return self.clearRow();
     375                                        },
     376                                        error: function( model, response ) {
     377                                                self.views.set( '#edit-group-member-' + model.get( 'id' ), new bp.Views.GroupMemberErrorInfo( { value: response.responseJSON.message } ).render() );
     378
     379                                                // Make sure to reset request options.
     380                                                model.resetRequestOptions();
     381                                                model.set( 'removing', false );
     382                                        }
     383                                } );
     384                        }
     385                },
     386
     387                editMemberRole: function( event ) {
     388                        var newRole = $( event.target ).val(), roleObject = this.getRoleObject( newRole ),
     389                            currentRole = this.model.get( 'role').id, roleAction = 'promote', self = this;
     390
     391                        if ( newRole === this.model.get( 'role' ).id || ! roleObject ) {
     392                                return this.resetRow();
     393                        }
     394
     395                        this.views.set( '#edit-group-member-' + this.model.get( 'id' ), new bp.Views.GroupMemberUpdatingInfo().render() );
     396
     397                        if ( 'admin' === currentRole || ( 'mod' === currentRole && 'member' === newRole ) ) {
     398                                roleAction = 'demote';
     399                        }
     400
     401                        // Update Group member's role
     402                        this.model.save( roleObject, {
     403                                wait: true,
     404                                data: {
     405                                        action: roleAction,
     406                                        role: newRole
     407                                },
     408                                success: function( model, response ) {
     409                                        if ( self.model.collection.currentRole && newRole !== self.model.collection.currentRole ) {
     410                                                self.model.collection.remove( model );
     411                                                return self.clearRow();
     412                                        } else {
     413                                                return self.resetRow();
     414                                        }
     415                                },
     416                                error: function( model, response ) {
     417                                        self.views.set( '#edit-group-member-' + model.get( 'id' ), new bp.Views.GroupMemberErrorInfo( { value: response.responseJSON.message } ).render() );
     418
     419                                        // Make sure to reset request options.
     420                                        model.resetRequestOptions();
     421                                        model.set( 'editing', false );
     422                                }
     423                        } );
     424                }
     425        } );
     426
     427        bp.Views.GroupMembersListHeader = bp.View.extend( {
     428                tagName: 'thead',
     429                template : bp.template( 'bp-manage-members-header' )
     430        } );
     431
     432        bp.Views.GroupMembersListTable = bp.View.extend( {
     433                tagName: 'tbody',
     434
     435                initialize: function() {
     436                        var preloaded = bpGroupManageMembersSettings.preloaded || {},
     437                            models = [];
     438
     439                        this.collection.on( 'reset', this.addListTableRows, this );
     440
     441                        if ( preloaded.body && preloaded.body.length > 0 ) {
     442                                _.each( preloaded.body, function( member ) {
     443                                        models.push( new bp.Models.groupMember( member ) )
     444                                } );
     445
     446                                this.collection.currentPage = 1;
     447                                if ( preloaded.headers && preloaded.headers[ 'X-WP-TotalPages' ] ) {
     448                                        this.collection.totalPages = parseInt( preloaded.headers[ 'X-WP-TotalPages' ], 10 );
     449                                }
     450
     451                                if ( preloaded.headers && preloaded.headers[ 'X-WP-Total' ] ) {
     452                                        this.collection.totalGroupMembers = parseInt( preloaded.headers[ 'X-WP-Total' ], 10 );
     453                                }
     454
     455                                this.collection.reset( models );
     456                        } else {
     457                                this.collection.fetch( {
     458                                        data: { 'exclude_admins': false },
     459                                        reset: true
     460                                } );
     461                        }
     462                },
     463
     464                addListTableRows: function( collection ) {
     465                        _.each( collection.models, function( member ) {
     466                                this.views.add( new bp.Views.GroupMembersListRow( { model: member } ) );
     467                        }, this );
     468                }
     469        } );
     470
     471        bp.Views.GroupMembersUI = bp.View.extend( {
     472                className: 'group-members',
     473
     474                initialize: function() {
     475                        var groupMembers = new bp.Collections.groupMembers();
     476
     477                        // Set filters.
     478                        this.views.set( '#group-roles-filter', [
     479                                new bp.Views.GroupsMembersLabel( { attributes: { for: 'group-members-role-filter' } } ),
     480                                new bp.Views.GroupRolesDropDown( { id: 'group-members-role-filter', collection: groupMembers } )
     481                        ] );
     482
     483                        // Set Paginate links.
     484                        this.views.set( '#group-members-pagination', new bp.Views.GroupsMembersPagination( { collection: groupMembers } ) );
     485
     486                        // Set Group members list header and body.
     487                        this.views.set( '#group-members-list-table', [
     488                                new bp.Views.GroupMembersListHeader(),
     489                                new bp.Views.GroupMembersListTable( { collection: groupMembers } )
     490                        ] );
     491                }
     492        } );
     493
     494        // Inject the UI to manage Group Members into the DOM.
     495        var manageGroupMembersUI = new bp.Views.GroupMembersUI( { el:'#group-manage-members-ui' } ).render();
     496
     497} )( window.wp || {}, window.bp || {}, jQuery );
  • src/bp-templates/bp-nouveau/buddypress/common/js-templates/group-members/index.php

    diff --git src/bp-templates/bp-nouveau/buddypress/common/js-templates/group-members/index.php src/bp-templates/bp-nouveau/buddypress/common/js-templates/group-members/index.php
    index e69de29bb..1c9dd7649 100644
     
     1<?php
     2/**
     3 * BP Nouveau single group's membership management main template.
     4 *
     5 * This template is used to inject the BuddyPress Backbone views
     6 * dealing with a group's membership management.
     7 *
     8 * @since 5.0.0
     9 * @version 5.0.0
     10 */
     11?>
     12
     13<?php
     14/**
     15 * Placeholder to inject elements of the UI
     16 * to manage Group members.
     17 */
     18?>
     19<div id="group-manage-members-ui" class="standard-form">
     20    <ul class="subnav-filters">
     21        <li id="group-roles-filter" class="last filter"><?php // Placeholder for the Group Role Tabs ?></li>
     22        <li id="group-members-search-form"><?php // Placeholder for search form ?></li>
     23        <li id="group-members-pagination" class="left-menu"><?php // Placeholder for paginate links ?></li>
     24    </ul>
     25    <table id="group-members-list-table" class="<?php echo is_admin() ? 'widefat bp-group-members' : 'bp-list'; ?>"><?php // Placeholder to list members ?></table>
     26</div>
     27
     28<script type="text/html" id="tmpl-bp-manage-members-updating">
     29    <# if ( ! data.type ) { #>
     30        <small><?php echo esc_html_x( 'Updating role... Please wait.', 'group manage members update feedback', 'buddypress' ); ?></small>
     31    <# } else if ( 'ban' === data.type ) { #>
     32        <small><?php echo esc_html_x( 'Banning member... Please wait.', 'group manage members ban feedback', 'buddypress' ); ?></small>
     33    <# } else if ( 'unban' === data.type ) { #>
     34        <small><?php echo esc_html_x( 'Unbanning member... Please wait.', 'group manage members unban feedback', 'buddypress' ); ?></small>
     35    <# } else if ( 'remove' === data.type ) { #>
     36        <small><?php echo esc_html_x( 'Removing member... Please wait.', 'group manage members remove feedback', 'buddypress' ); ?></small>
     37    <# } #>
     38</script>
     39
     40<script type="text/html" id="tmpl-bp-manage-members-error">
     41   <small>{{data.message}}</small>
     42</script>
     43
     44<script type="text/html" id="tmpl-bp-manage-members-header">
     45    <tr>
     46        <th><?php echo esc_html_x( 'Group Members', 'group manage members table header', 'buddypress' ); ?></th>
     47        <th><?php echo esc_html_x( 'Roles', 'group manage members table header', 'buddypress' ); ?></th>
     48    </tr>
     49</script>
     50
     51<script type="text/html" id="tmpl-bp-manage-members-label">
     52    <# if ( data.type && 'filter' !== data.type ) { #>
     53        <?php echo esc_html_x( 'Change role for:', 'group manage members row edit', 'buddypress' ); ?>
     54    <# } else { #>
     55        <?php echo esc_html_x( 'Filter:', 'group manage members roles filter', 'buddypress' ); ?></small>
     56    <# } #>
     57</script>
     58
     59<script type="text/html" id="tmpl-bp-manage-members-row">
     60        <td class="uname-column">
     61        <div class="group-member">
     62            <a href="{{{data.link}}}">
     63                <img src="{{{data.avatar_urls.thumb}}}" alt="{{data.name}}" class="avatar profile-photo alignleft"/>
     64                {{data.name}}
     65            </a>
     66        </div>
     67        <div class="group-member-actions row-actions">
     68            <# if ( ! data.editing && ! data.is_banned ) { #>
     69                <span class="edit"><a href="#edit-role" data-action="edit"><?php echo esc_html_x( 'Edit', 'group member edit role link', 'buddypress' ); ?></a> | </span>
     70            <# } #>
     71            <# if ( data.editing ) { #>
     72                <span><a href="#edit-role-abort" data-action="abort"><?php echo esc_html_x( 'Stop editing', 'group member edit role abort link', 'buddypress' ); ?></a> | </span>
     73            <# } #>
     74            <# if ( ! data.is_banned ) { #>
     75                <span class="spam"><a href="#ban" class="submitdelete" data-action="ban"><?php echo esc_html_x( 'Ban', 'group member ban link', 'buddypress' ); ?></a> | </span>
     76            <# } else { #>
     77                <span class="ham"><a href="#unban" data-action="unban"><?php echo esc_html_x( 'Unban', 'group member unban link', 'buddypress' ); ?></a> | </span>
     78            <# } #>
     79            <span class="delete"><a href="#remove" class="submitdelete" data-action="remove"><?php echo esc_html_x( 'Remove', 'group member ban link', 'buddypress' ); ?></a></span>
     80        </div>
     81    </td>
     82    <td class="urole-column">
     83        <# if ( ! data.editing  && ! data.managingBan && ! data.removing ) { #>
     84            {{data.role.name}}
     85        <# } else { #>
     86            <div id="edit-group-member-{{data.id}}" class="group-member-edit"><?php // Placeholder for the Edit Role Dropdown. ;?></div>
     87        <# } #>
     88    </td>
     89</script>
     90
     91<script type="text/html" id="tmpl-bp-manage-members-paginate">
     92    <# if ( 1 !== data.currentPage && data.totalPages ) { #>
     93        <a class="group-members-paginate-link bp-pagination-links" href="#prev-page" data-page="{{data.prevPage}}">
     94            <?php echo esc_html_x( 'Prev.', 'link', 'buddypress' ); ?>
     95        </a>
     96        <# } #>
     97
     98    <# if ( data.totalPages !== data.currentPage ) { #>
     99        <a class="group-members-paginate-link bp-pagination-links" href="#next-page" data-page="{{data.nextPage}}">
     100            <?php echo esc_html_x( 'Next', 'link', 'buddypress' ); ?>
     101        </a>
     102        <# } #>
     103</script>
  • src/bp-templates/bp-nouveau/buddypress/groups/single/admin/manage-members.php

    diff --git src/bp-templates/bp-nouveau/buddypress/groups/single/admin/manage-members.php src/bp-templates/bp-nouveau/buddypress/groups/single/admin/manage-members.php
    index f29e351db..6aa50ec19 100644
     
    33 * BP Nouveau Group's manage members template.
    44 *
    55 * @since 3.0.0
    6  * @version 3.1.0
     6 * @version 5.0.0
    77 */
    88?>
    99
     
    1111        <?php esc_html_e( 'Manage Group Members', 'buddypress' ); ?>
    1212</h2>
    1313
    14         <p class="bp-help-text"><?php esc_html_e( 'Manage your group members; promote to moderators, admins or demote or ban.', 'buddypress' ); ?></p>
     14<p class="bp-help-text"><?php esc_html_e( 'Manage your group members; promote to moderators, admins or demote or ban.', 'buddypress' ); ?></p>
     15
     16<?php if ( bp_rest_api_is_available() ) :
     17        /**
     18         * Get the templates to manage Group Members using the BP REST API.
     19         *
     20         * @since 5.0.0
     21         */
     22        bp_get_template_part( 'common/js-templates/group-members/index' );
     23
     24else : ?>
    1525
    1626        <dl class="groups-manage-members-list">
    1727
     
    119129
    120130                bp_nouveau_user_feedback( 'group-manage-members-none' );
    121131
    122         endif; ?>
     132        endif;
    123133
     134endif;
  • src/bp-templates/bp-nouveau/includes/groups/functions.php

    diff --git src/bp-templates/bp-nouveau/includes/groups/functions.php src/bp-templates/bp-nouveau/includes/groups/functions.php
    index d02a1be49..5db92a1d5 100644
     
    33 * Groups functions
    44 *
    55 * @since 3.0.0
    6  * @version 3.1.0
     6 * @version 5.0.0
    77 */
    88
    99// Exit if accessed directly.
    function bp_nouveau_groups_enqueue_scripts() { 
    6868                ' );
    6969        }
    7070
    71         if ( ! bp_is_group_invites() && ! ( bp_is_group_create() && bp_is_group_creation_step( 'group-invites' ) ) ) {
    72                 return;
     71        if ( bp_is_group_invites() || ( bp_is_group_create() && bp_is_group_creation_step( 'group-invites' ) ) ) {
     72                wp_enqueue_script( 'bp-nouveau-group-invites' );
    7373        }
    7474
    75         wp_enqueue_script( 'bp-nouveau-group-invites' );
     75        if ( bp_is_group_admin_page() && bp_is_group_admin_screen( 'manage-members' ) ) {
     76                wp_enqueue_script( 'bp-group-manage-members' );
     77                wp_localize_script(
     78                        'bp-group-manage-members',
     79                        'bpGroupManageMembersSettings',
     80                        bp_groups_get_group_manage_members_script_data( bp_get_current_group_id() )
     81                );
     82        }
    7683}
    7784
    7885/**
  • src/class-buddypress.php

    diff --git src/class-buddypress.php src/class-buddypress.php
    index 0789be65c..b3348007b 100644
    class BuddyPress { 
    487487                require( $this->plugin_dir . 'bp-core/bp-core-moderation.php'       );
    488488                require( $this->plugin_dir . 'bp-core/bp-core-loader.php'           );
    489489                require( $this->plugin_dir . 'bp-core/bp-core-customizer-email.php' );
     490                require( $this->plugin_dir . 'bp-core/bp-core-rest-api.php'         );
    490491
    491492                // Maybe load deprecated functionality (this double negative is proof positive!)
    492493                if ( ! bp_get_option( '_bp_ignore_deprecated_code', ! $this->load_deprecated ) ) {