Skip to:
Content

BuddyPress.org

Ticket #8522: 8522.patch

File 8522.patch, 45.5 KB (added by imath, 4 years ago)
  • .jshintignore

    diff --git .jshintignore .jshintignore
    index 06a8e1509..185586a70 100644
    src/**/js/block-*/*.js 
    99src/**/js/block-*/**/*.js
    1010src/**/js/block-*.js
    1111src/**/js/friends.js
     12src/**/js/dynamic-members.js
    1213src/**/js/dynamic-widget-block.js
  • Gruntfile.js

    diff --git Gruntfile.js Gruntfile.js
    index 3417b09fd..5951547f2 100644
    module.exports = function( grunt ) { 
    2424                        '!**/js/block-*/**/*.js',
    2525                        '!**/js/block-*.js',
    2626                        '!**/js/friends.js',
     27                        '!**/js/dynamic-members.js',
    2728                        '!**/js/dynamic-widget-block.js'
    2829                ],
    2930
    module.exports = function( grunt ) { 
    4344                        '!bp-groups/css/blocks/groups.css',
    4445                        '!bp-core/css/blocks/login-form.css',
    4546                        '!bp-activity/css/blocks/latest-activities.css',
    46                         '!bp-friends/css/blocks/friends.css'
     47                        '!bp-friends/css/blocks/friends.css',
     48                        '!bp-members/css/blocks/dynamic-members.css'
    4749                ],
    4850
    4951                autoprefixer = require('autoprefixer');
  • src/bp-members/bp-members-blocks.php

    diff --git src/bp-members/bp-members-blocks.php src/bp-members/bp-members-blocks.php
    index 50b49bc55..06310ecf0 100644
    function bp_members_render_members_block( $attributes = array() ) { 
    331331         */
    332332        return apply_filters( 'bp_members_render_members_block_output', $output, $block_args, $members );
    333333}
     334
     335/**
     336 * Adds specific script data for the BP Members blocks.
     337 *
     338 * Only used for the BP Dynamic Members block.
     339 *
     340 * @since 9.0.0
     341 */
     342function bp_members_blocks_add_script_data() {
     343        $dynamic_members_blocks = array_filter( buddypress()->members->block_globals['bp/dynamic-members']->items );
     344
     345        if ( ! $dynamic_members_blocks ) {
     346                return;
     347        }
     348
     349        // Include the common JS template.
     350        echo bp_get_dynamic_template_part( 'assets/widgets/dynamic-members.php' );
     351
     352        // List the block specific props.
     353        wp_add_inline_script(
     354                'bp-dynamic-members-script',
     355                sprintf( 'var bpDynamicMembersBlocks = %s;', wp_json_encode( array_values( $dynamic_members_blocks ) ) ),
     356                'before'
     357        );
     358}
     359
     360/**
     361 * Callback function to render the Dynamic Members Block.
     362 *
     363 * @since 9.0.0
     364 *
     365 * @param array $attributes The block attributes.
     366 * @return string           HTML output.
     367 */
     368function bp_members_render_dynamic_members_block( $attributes = array() ) {
     369        $block_args = wp_parse_args(
     370                $attributes,
     371                array(
     372                        'title'         => __( 'Members', 'buddypress' ),
     373                        'maxMembers'    => 5,
     374                        'memberDefault' => 'active',
     375                        'linkTitle'     => false,
     376                )
     377        );
     378
     379        $classnames         = 'widget_bp_core_members_widget buddypress widget';
     380        $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classnames ) );
     381
     382        $max_members = (int) $block_args['maxMembers'];
     383        $no_members  = __( 'No members found.', 'buddypress' );
     384
     385        /** This filter is documented in buddypress/src/bp-members/classes/class-bp-core-members-widget.php */
     386        $separator = apply_filters( 'bp_members_widget_separator', '|' );
     387
     388        // Make sure the widget ID is unique.
     389        $widget_id              = uniqid( 'members-list-' );
     390        $members_directory_link = bp_get_members_directory_permalink();
     391
     392        // Set the Block's title.
     393        if ( true === $block_args['linkTitle'] ) {
     394                $widget_content = sprintf(
     395                        '<h2 class="widget-title"><a href="%1$s">%2$s</a></h2>',
     396                        esc_url( $members_directory_link ),
     397                        esc_html( $block_args['title'] )
     398                );
     399        } else {
     400                $widget_content = sprintf( '<h2 class="widget-title">%s</h2>', esc_html( $block_args['title'] ) );
     401        }
     402
     403        $item_options = array(
     404                'newest' => array(
     405                        'class' => '',
     406                        'label' => __( 'Newest', 'buddypress' ),
     407                ),
     408                'active' => array(
     409                        'class' => '',
     410                        'label' => __( 'Active', 'buddypress' ),
     411                ),
     412        );
     413
     414        if ( bp_is_active( 'friends' ) ) {
     415                $item_options['popular'] = array(
     416                        'class' => '',
     417                        'label' => __( 'Popular', 'buddypress' ),
     418                );
     419        }
     420
     421        $item_options_output = array();
     422        $separator_output    = sprintf( ' <span class="bp-separator" role="separator">%s</span> ', esc_html( $separator ) );
     423
     424        foreach ( $item_options as $item_type => $item_attr ) {
     425                if ( $block_args['memberDefault'] === $item_type ) {
     426                        $item_attr['class'] = ' class="selected"';
     427                }
     428
     429                $item_options_output[] = sprintf(
     430                        '<a href="%1$s" data-bp-sort="%2$s"%3$s>%4$s</a>',
     431                        esc_url( $members_directory_link ),
     432                        esc_attr( $item_type ),
     433                        $item_attr['class'],
     434                        esc_html( $item_attr['label'] )
     435                );
     436        }
     437
     438        $preview      = '';
     439        $default_args = array(
     440                'type'            => $block_args['memberDefault'],
     441                'per_page'        => $max_members,
     442                'populate_extras' => true,
     443        );
     444
     445        // Previewing the Block inside the editor.
     446        if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
     447                $bp_query = bp_core_get_users( $default_args );
     448                $preview  = sprintf( '<div class="widget-error">%s</div>', $no_members );
     449
     450                if ( is_array( $bp_query['users'] ) && 0 < count( $bp_query['users'] ) ) {
     451                        $preview = '';
     452                        foreach ( $bp_query['users'] as $user ) {
     453                                if ( 'newest' === $block_args['memberDefault'] ) {
     454                                        /* translators: %s is time elapsed since the registration date happened */
     455                                        $extra = sprintf( _x( 'Registered %s', 'The timestamp when the user registered', 'buddypress' ), bp_core_time_since( $user->user_registered ) );
     456                                } elseif ( 'popular' === $block_args['memberDefault'] && isset( $item_options['popular'] ) && isset( $user->total_friend_count ) ) {
     457                                        /* translators: %s: total friend count */
     458                                        $extra = sprintf( _n( '%s friend', '%s friends', $user->total_friend_count, 'buddypress' ), number_format_i18n( $user->total_friend_count ) );
     459                                } else {
     460                                        /* translators: %s: a human time diff. */
     461                                        $extra = sprintf( __( 'Active %s', 'buddypress' ), bp_core_time_since( $user->last_activity ) );
     462                                }
     463
     464                                $preview .= bp_get_dynamic_template_part(
     465                                        'assets/widgets/dynamic-members.php',
     466                                        'php',
     467                                        array(
     468                                                'data.link'              => bp_core_get_user_domain( $user->ID, $user->user_nicename, $user->user_login ),
     469                                                'data.name'              => $user->display_name,
     470                                                'data.avatar_urls.thumb' => bp_core_fetch_avatar(
     471                                                        array(
     472                                                                'item_id' => $user->ID,
     473                                                                'html'    => false,
     474                                                        )
     475                                                ),
     476                                                'data.avatar_alt'        => esc_html(
     477                                                        sprintf(
     478                                                                /* translators: %s: member name */
     479                                                                __( 'Profile picture of %s', 'buddypress' ),
     480                                                                $user->display_name
     481                                                        )
     482                                                ),
     483                                                'data.id'                => $user->ID,
     484                                                'data.extra'             => $extra,
     485                                        )
     486                                );
     487                        }
     488                }
     489        } else {
     490                // Get corresponding members.
     491                $path = sprintf(
     492                        '/%1$s/%2$s/%3$s',
     493                        bp_rest_namespace(),
     494                        bp_rest_version(),
     495                        buddypress()->members->id
     496                );
     497
     498                $default_path = add_query_arg(
     499                        $default_args,
     500                        $path
     501                );
     502
     503                $preloaded_members = array();
     504                if ( bp_is_running_wp( '5.0.0' ) ) {
     505                        $preloaded_members = rest_preload_api_request( '', $default_path );
     506                }
     507
     508                buddypress()->members->block_globals['bp/dynamic-members']->items[ $widget_id ] = (object) array(
     509                        'selector'   => $widget_id,
     510                        'query_args' => $default_args,
     511                        'preloaded'  => reset( $preloaded_members ),
     512                );
     513
     514                // Only enqueue common/specific scripts and data once per page load.
     515                if ( ! has_action( 'wp_footer', 'bp_members_blocks_add_script_data', 1 ) ) {
     516                        wp_set_script_translations( 'bp-dynamic-members-script', 'buddypress' );
     517                        wp_enqueue_script( 'bp-dynamic-members-script' );
     518                        wp_localize_script(
     519                                'bp-dynamic-members-script',
     520                                'bpDynamicMembersSettings',
     521                                array(
     522                                        'path'  => ltrim( $path, '/' ),
     523                                        'root'  => esc_url_raw( get_rest_url() ),
     524                                        'nonce' => wp_create_nonce( 'wp_rest' ),
     525                                )
     526                        );
     527
     528                        add_action( 'wp_footer', 'bp_members_blocks_add_script_data', 1 );
     529                }
     530        }
     531
     532        $widget_content .= sprintf(
     533                '<div class="item-options">
     534                        %1$s
     535                </div>
     536                <ul id="%2$s" class="item-list" aria-live="polite" aria-relevant="all" aria-atomic="true">
     537                        %3$s
     538                </ul>',
     539                implode( $separator_output, $item_options_output ),
     540                esc_attr( $widget_id ),
     541                $preview
     542        );
     543
     544        // Adds a container to make sure the block is styled even when used into the Columns parent block.
     545        $widget_content = sprintf( '<div class="bp-dynamic-block-container">%s</div>', "\n" . $widget_content . "\n" );
     546
     547        // Only add a block wrapper if not loaded into a Widgets sidebar.
     548        if ( ! did_action( 'dynamic_sidebar_before' ) ) {
     549                return sprintf(
     550                        '<div %1$s>%2$s</div>',
     551                        $wrapper_attributes,
     552                        $widget_content
     553                );
     554        }
     555
     556        return $widget_content;
     557}
  • new file src/bp-members/bp-members-cssjs.php

    diff --git src/bp-members/bp-members-cssjs.php src/bp-members/bp-members-cssjs.php
    new file mode 100644
    index 000000000..61bb70b81
    - +  
     1<?php
     2/**
     3 * BP Members component CSS/JS.
     4 *
     5 * @package BuddyPress
     6 * @subpackage MembersScripts
     7 * @since 9.0.0
     8 */
     9
     10// Exit if accessed directly.
     11if ( ! defined( 'ABSPATH' ) ) {
     12        exit;
     13}
     14
     15/**
     16 * Registers the script to manage the dynamic part of the Dynamic Members widget/block.
     17 *
     18 * @since 9.0.0
     19 *
     20 * @param array $scripts Data about the scripts to register.
     21 * @return array Data about the scripts to register.
     22 */
     23function bp_members_register_scripts( $scripts = array() ) {
     24        $scripts['bp-dynamic-members-script'] = array(
     25                'file'         => plugins_url( 'js/dynamic-members.js', __FILE__ ),
     26                'dependencies' => array(
     27                        'bp-dynamic-widget-block-script',
     28                        'wp-i18n',
     29                ),
     30                'footer'       => true,
     31        );
     32
     33        return $scripts;
     34}
     35add_filter( 'bp_core_register_common_scripts', 'bp_members_register_scripts', 9, 1 );
  • src/bp-members/classes/class-bp-members-component.php

    diff --git src/bp-members/classes/class-bp-members-component.php src/bp-members/classes/class-bp-members-component.php
    index 280485e33..efa93300f 100644
    class BP_Members_Component extends BP_Component { 
    5858
    5959                // Always include these files.
    6060                $includes = array(
     61                        'cssjs',
    6162                        'filters',
    6263                        'template',
    6364                        'adminbar',
    class BP_Members_Component extends BP_Component { 
    196197                                'table_name_signups'       => $wpdb->base_prefix . 'signups', // Signups is a global WordPress table.
    197198                        ),
    198199                        'notification_callback' => 'members_format_notifications',
     200                        'block_globals'         => array(
     201                                'bp/dynamic-members' => array(
     202                                        'widget_classnames' => array( 'widget_bp_core_members_widget', 'buddypress' ),
     203                                )
     204                        ),
    199205                );
    200206
    201207                parent::setup_globals( $args );
    class BP_Members_Component extends BP_Component { 
    821827                                        ),
    822828                                        'render_callback'    => 'bp_members_render_members_block',
    823829                                ),
     830                                'bp/dynamic-members' => array(
     831                                        'name'               => 'bp/dynamic-members',
     832                                        'editor_script'      => 'bp-dynamic-members-block',
     833                                        'editor_script_url'  => plugins_url( 'js/blocks/dynamic-members.js', dirname( __FILE__ ) ),
     834                                        'editor_script_deps' => array(
     835                                                'wp-blocks',
     836                                                'wp-element',
     837                                                'wp-components',
     838                                                'wp-i18n',
     839                                                'wp-block-editor',
     840                                                'bp-block-data',
     841                                                'bp-block-components',
     842                                        ),
     843                                        'style'              => 'bp-dynamic-members-block',
     844                                        'style_url'          => plugins_url( 'css/blocks/dynamic-members.css', dirname( __FILE__ ) ),
     845                                        'attributes'         => array(
     846                                                'title'         => array(
     847                                                        'type'    => 'string',
     848                                                        'default' => __( 'Members', 'buddypress' ),
     849                                                ),
     850                                                'maxMembers'    => array(
     851                                                        'type'    => 'number',
     852                                                        'default' => 5,
     853                                                ),
     854                                                'memberDefault' => array(
     855                                                        'type'    => 'string',
     856                                                        'default' => 'active',
     857                                                ),
     858                                                'linkTitle'     => array(
     859                                                        'type'    => 'boolean',
     860                                                        'default' => false,
     861                                                ),
     862                                        ),
     863                                        'render_callback'    => 'bp_members_render_dynamic_members_block',
     864                                ),
    824865                        )
    825866                );
    826867        }
  • new file src/bp-members/css/blocks/dynamic-members-rtl.css

    diff --git src/bp-members/css/blocks/dynamic-members-rtl.css src/bp-members/css/blocks/dynamic-members-rtl.css
    new file mode 100644
    index 000000000..8aff30506
    - +  
     1.bp-dynamic-block-container .item-options {
     2        font-size: 0.5em;
     3        margin: 0 0 1em;
     4        padding: 1em 0;
     5}
     6
     7.bp-dynamic-block-container .item-options a.selected {
     8        font-weight: 600;
     9}
     10
     11.bp-dynamic-block-container ul.item-list {
     12        list-style: none;
     13        margin: 1em 0;
     14}
     15
     16.bp-dynamic-block-container ul.item-list li {
     17        margin-bottom: 1em;
     18}
     19
     20.bp-dynamic-block-container ul.item-list li:before, .bp-dynamic-block-container ul.item-list li:after {
     21        content: " ";
     22        display: table;
     23}
     24
     25.bp-dynamic-block-container ul.item-list li:after {
     26        clear: both;
     27}
     28
     29.bp-dynamic-block-container ul.item-list li .item-avatar {
     30        float: right;
     31        width: 60px;
     32}
     33
     34.bp-dynamic-block-container ul.item-list li .item {
     35        margin-right: 70px;
     36}
  • new file src/bp-members/css/blocks/dynamic-members.css

    diff --git src/bp-members/css/blocks/dynamic-members.css src/bp-members/css/blocks/dynamic-members.css
    new file mode 100644
    index 000000000..110c8aaa5
    - +  
     1.bp-dynamic-block-container .item-options {
     2        font-size: 0.5em;
     3        margin: 0 0 1em;
     4        padding: 1em 0;
     5}
     6
     7.bp-dynamic-block-container .item-options a.selected {
     8        font-weight: 600;
     9}
     10
     11.bp-dynamic-block-container ul.item-list {
     12        list-style: none;
     13        margin: 1em 0;
     14}
     15
     16.bp-dynamic-block-container ul.item-list li {
     17        margin-bottom: 1em;
     18}
     19
     20.bp-dynamic-block-container ul.item-list li:before, .bp-dynamic-block-container ul.item-list li:after {
     21        content: " ";
     22        display: table;
     23}
     24
     25.bp-dynamic-block-container ul.item-list li:after {
     26        clear: both;
     27}
     28
     29.bp-dynamic-block-container ul.item-list li .item-avatar {
     30        float: left;
     31        width: 60px;
     32}
     33
     34.bp-dynamic-block-container ul.item-list li .item {
     35        margin-left: 70px;
     36}
  • new file src/bp-members/js/blocks/dynamic-members.js

    diff --git src/bp-members/js/blocks/dynamic-members.js src/bp-members/js/blocks/dynamic-members.js
    new file mode 100644
    index 000000000..6f55a264e
    - +  
     1// modules are defined as an array
     2// [ module function, map of requires ]
     3//
     4// map of requires is short require name -> numeric require
     5//
     6// anything defined in a previous bundle is accessed via the
     7// orig method which is the require for previous bundles
     8parcelRequire = (function (modules, cache, entry, globalName) {
     9  // Save the require from previous bundle to this closure if any
     10  var previousRequire = typeof parcelRequire === 'function' && parcelRequire;
     11  var nodeRequire = typeof require === 'function' && require;
     12
     13  function newRequire(name, jumped) {
     14    if (!cache[name]) {
     15      if (!modules[name]) {
     16        // if we cannot find the module within our internal map or
     17        // cache jump to the current global require ie. the last bundle
     18        // that was added to the page.
     19        var currentRequire = typeof parcelRequire === 'function' && parcelRequire;
     20        if (!jumped && currentRequire) {
     21          return currentRequire(name, true);
     22        }
     23
     24        // If there are other bundles on this page the require from the
     25        // previous one is saved to 'previousRequire'. Repeat this as
     26        // many times as there are bundles until the module is found or
     27        // we exhaust the require chain.
     28        if (previousRequire) {
     29          return previousRequire(name, true);
     30        }
     31
     32        // Try the node require function if it exists.
     33        if (nodeRequire && typeof name === 'string') {
     34          return nodeRequire(name);
     35        }
     36
     37        var err = new Error('Cannot find module \'' + name + '\'');
     38        err.code = 'MODULE_NOT_FOUND';
     39        throw err;
     40      }
     41
     42      localRequire.resolve = resolve;
     43      localRequire.cache = {};
     44
     45      var module = cache[name] = new newRequire.Module(name);
     46
     47      modules[name][0].call(module.exports, localRequire, module, module.exports, this);
     48    }
     49
     50    return cache[name].exports;
     51
     52    function localRequire(x){
     53      return newRequire(localRequire.resolve(x));
     54    }
     55
     56    function resolve(x){
     57      return modules[name][1][x] || x;
     58    }
     59  }
     60
     61  function Module(moduleName) {
     62    this.id = moduleName;
     63    this.bundle = newRequire;
     64    this.exports = {};
     65  }
     66
     67  newRequire.isParcelRequire = true;
     68  newRequire.Module = Module;
     69  newRequire.modules = modules;
     70  newRequire.cache = cache;
     71  newRequire.parent = previousRequire;
     72  newRequire.register = function (id, exports) {
     73    modules[id] = [function (require, module) {
     74      module.exports = exports;
     75    }, {}];
     76  };
     77
     78  var error;
     79  for (var i = 0; i < entry.length; i++) {
     80    try {
     81      newRequire(entry[i]);
     82    } catch (e) {
     83      // Save first error but execute all entries
     84      if (!error) {
     85        error = e;
     86      }
     87    }
     88  }
     89
     90  if (entry.length) {
     91    // Expose entry point to Node, AMD or browser globals
     92    // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
     93    var mainExports = newRequire(entry[entry.length - 1]);
     94
     95    // CommonJS
     96    if (typeof exports === "object" && typeof module !== "undefined") {
     97      module.exports = mainExports;
     98
     99    // RequireJS
     100    } else if (typeof define === "function" && define.amd) {
     101     define(function () {
     102       return mainExports;
     103     });
     104
     105    // <script>
     106    } else if (globalName) {
     107      this[globalName] = mainExports;
     108    }
     109  }
     110
     111  // Override the current require with this new one
     112  parcelRequire = newRequire;
     113
     114  if (error) {
     115    // throw error from earlier, _after updating parcelRequire_
     116    throw error;
     117  }
     118
     119  return newRequire;
     120})({"gOka":[function(require,module,exports) {
     121"use strict";
     122
     123Object.defineProperty(exports, "__esModule", {
     124  value: true
     125});
     126exports.TYPES = void 0;
     127
     128/**
     129 * WordPress dependencies.
     130 */
     131var _wp = wp,
     132    __ = _wp.i18n.__;
     133/**
     134 * Members ordering types.
     135 *
     136 * @type {Array}
     137 */
     138
     139var TYPES = [{
     140  label: __('Newest', 'buddypress'),
     141  value: 'newest'
     142}, {
     143  label: __('Active', 'buddypress'),
     144  value: 'active'
     145}, {
     146  label: __('Popular', 'buddypress'),
     147  value: 'popular'
     148}];
     149exports.TYPES = TYPES;
     150},{}],"z0p7":[function(require,module,exports) {
     151"use strict";
     152
     153Object.defineProperty(exports, "__esModule", {
     154  value: true
     155});
     156exports.default = void 0;
     157
     158var _constants = require("./constants");
     159
     160/**
     161 * WordPress dependencies.
     162 */
     163var _wp = wp,
     164    InspectorControls = _wp.blockEditor.InspectorControls,
     165    _wp$components = _wp.components,
     166    Disabled = _wp$components.Disabled,
     167    PanelBody = _wp$components.PanelBody,
     168    RangeControl = _wp$components.RangeControl,
     169    SelectControl = _wp$components.SelectControl,
     170    TextControl = _wp$components.TextControl,
     171    ToggleControl = _wp$components.ToggleControl,
     172    _wp$element = _wp.element,
     173    Fragment = _wp$element.Fragment,
     174    createElement = _wp$element.createElement,
     175    __ = _wp.i18n.__;
     176/**
     177 * BuddyPress dependencies.
     178 */
     179
     180var _bp = bp,
     181    ServerSideRender = _bp.blockComponents.ServerSideRender,
     182    isActive = _bp.blockData.isActive;
     183/**
     184 * Internal dependencies.
     185 */
     186
     187var editDynamicMembersBlock = function editDynamicMembersBlock(_ref) {
     188  var attributes = _ref.attributes,
     189      setAttributes = _ref.setAttributes;
     190  var title = attributes.title,
     191      maxMembers = attributes.maxMembers,
     192      memberDefault = attributes.memberDefault,
     193      linkTitle = attributes.linkTitle;
     194  var sortTypes = !!isActive('friends') ? _constants.TYPES : _constants.TYPES.filter(function (type) {
     195    return 'popular' !== type.value;
     196  });
     197  return createElement(Fragment, null, createElement(InspectorControls, null, createElement(PanelBody, {
     198    title: __('Settings', 'buddypress'),
     199    initialOpen: true
     200  }, createElement(TextControl, {
     201    label: __('Title', 'buddypress'),
     202    value: title,
     203    onChange: function onChange(text) {
     204      setAttributes({
     205        title: text
     206      });
     207    }
     208  }), createElement(RangeControl, {
     209    label: __('Max members to show', 'buddypress'),
     210    value: maxMembers,
     211    onChange: function onChange(value) {
     212      return setAttributes({
     213        maxMembers: value
     214      });
     215    },
     216    min: 1,
     217    max: 10,
     218    required: true
     219  }), createElement(SelectControl, {
     220    label: __('Default members to show', 'buddypress'),
     221    value: memberDefault,
     222    options: sortTypes,
     223    onChange: function onChange(option) {
     224      setAttributes({
     225        memberDefault: option
     226      });
     227    }
     228  }), createElement(ToggleControl, {
     229    label: __('Link block title to Members directory', 'buddypress'),
     230    checked: !!linkTitle,
     231    onChange: function onChange() {
     232      setAttributes({
     233        linkTitle: !linkTitle
     234      });
     235    }
     236  }))), createElement(Disabled, null, createElement(ServerSideRender, {
     237    block: "bp/dynamic-members",
     238    attributes: attributes
     239  })));
     240};
     241
     242var _default = editDynamicMembersBlock;
     243exports.default = _default;
     244},{"./constants":"gOka"}],"qfGr":[function(require,module,exports) {
     245"use strict";
     246
     247Object.defineProperty(exports, "__esModule", {
     248  value: true
     249});
     250exports.default = void 0;
     251
     252/**
     253 * WordPress dependencies.
     254 */
     255var _wp = wp,
     256    createBlock = _wp.blocks.createBlock;
     257/**
     258 * Transforms Legacy Widget to Dynamic Members Block.
     259 *
     260 * @type {Object}
     261 */
     262
     263var transforms = {
     264  from: [{
     265    type: 'block',
     266    blocks: ['core/legacy-widget'],
     267    isMatch: function isMatch(_ref) {
     268      var idBase = _ref.idBase,
     269          instance = _ref.instance;
     270
     271      if (!(instance !== null && instance !== void 0 && instance.raw)) {
     272        return false;
     273      }
     274
     275      return idBase === 'bp_core_members_widget';
     276    },
     277    transform: function transform(_ref2) {
     278      var instance = _ref2.instance;
     279      return createBlock('bp/dynamic-members', {
     280        title: instance.raw.title,
     281        maxMembers: instance.raw.max_members,
     282        memberDefault: instance.raw.member_default,
     283        linkTitle: instance.raw.link_title
     284      });
     285    }
     286  }]
     287};
     288var _default = transforms;
     289exports.default = _default;
     290},{}],"Znbi":[function(require,module,exports) {
     291"use strict";
     292
     293var _edit = _interopRequireDefault(require("./dynamic-members/edit"));
     294
     295var _transforms = _interopRequireDefault(require("./dynamic-members/transforms"));
     296
     297function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
     298
     299/**
     300 * WordPress dependencies.
     301 */
     302var _wp = wp,
     303    registerBlockType = _wp.blocks.registerBlockType,
     304    __ = _wp.i18n.__;
     305/**
     306 * Internal dependencies.
     307 */
     308
     309registerBlockType('bp/dynamic-members', {
     310  title: __('Dynamic Members List', 'buddypress'),
     311  description: __('A dynamic list of recently active, popular, and newest members.', 'buddypress'),
     312  icon: {
     313    background: '#fff',
     314    foreground: '#d84800',
     315    src: 'groups'
     316  },
     317  category: 'buddypress',
     318  attributes: {
     319    title: {
     320      type: 'string',
     321      default: __('Members', 'buddypress')
     322    },
     323    maxMembers: {
     324      type: 'number',
     325      default: 5
     326    },
     327    memberDefault: {
     328      type: 'string',
     329      default: 'active'
     330    },
     331    linkTitle: {
     332      type: 'boolean',
     333      default: false
     334    }
     335  },
     336  edit: _edit.default,
     337  transforms: _transforms.default
     338});
     339},{"./dynamic-members/edit":"z0p7","./dynamic-members/transforms":"qfGr"}]},{},["Znbi"], null)
     340 No newline at end of file
  • new file src/bp-members/js/dynamic-members.js

    diff --git src/bp-members/js/dynamic-members.js src/bp-members/js/dynamic-members.js
    new file mode 100644
    index 000000000..827f914c5
    - +  
     1// modules are defined as an array
     2// [ module function, map of requires ]
     3//
     4// map of requires is short require name -> numeric require
     5//
     6// anything defined in a previous bundle is accessed via the
     7// orig method which is the require for previous bundles
     8parcelRequire = (function (modules, cache, entry, globalName) {
     9  // Save the require from previous bundle to this closure if any
     10  var previousRequire = typeof parcelRequire === 'function' && parcelRequire;
     11  var nodeRequire = typeof require === 'function' && require;
     12
     13  function newRequire(name, jumped) {
     14    if (!cache[name]) {
     15      if (!modules[name]) {
     16        // if we cannot find the module within our internal map or
     17        // cache jump to the current global require ie. the last bundle
     18        // that was added to the page.
     19        var currentRequire = typeof parcelRequire === 'function' && parcelRequire;
     20        if (!jumped && currentRequire) {
     21          return currentRequire(name, true);
     22        }
     23
     24        // If there are other bundles on this page the require from the
     25        // previous one is saved to 'previousRequire'. Repeat this as
     26        // many times as there are bundles until the module is found or
     27        // we exhaust the require chain.
     28        if (previousRequire) {
     29          return previousRequire(name, true);
     30        }
     31
     32        // Try the node require function if it exists.
     33        if (nodeRequire && typeof name === 'string') {
     34          return nodeRequire(name);
     35        }
     36
     37        var err = new Error('Cannot find module \'' + name + '\'');
     38        err.code = 'MODULE_NOT_FOUND';
     39        throw err;
     40      }
     41
     42      localRequire.resolve = resolve;
     43      localRequire.cache = {};
     44
     45      var module = cache[name] = new newRequire.Module(name);
     46
     47      modules[name][0].call(module.exports, localRequire, module, module.exports, this);
     48    }
     49
     50    return cache[name].exports;
     51
     52    function localRequire(x){
     53      return newRequire(localRequire.resolve(x));
     54    }
     55
     56    function resolve(x){
     57      return modules[name][1][x] || x;
     58    }
     59  }
     60
     61  function Module(moduleName) {
     62    this.id = moduleName;
     63    this.bundle = newRequire;
     64    this.exports = {};
     65  }
     66
     67  newRequire.isParcelRequire = true;
     68  newRequire.Module = Module;
     69  newRequire.modules = modules;
     70  newRequire.cache = cache;
     71  newRequire.parent = previousRequire;
     72  newRequire.register = function (id, exports) {
     73    modules[id] = [function (require, module) {
     74      module.exports = exports;
     75    }, {}];
     76  };
     77
     78  var error;
     79  for (var i = 0; i < entry.length; i++) {
     80    try {
     81      newRequire(entry[i]);
     82    } catch (e) {
     83      // Save first error but execute all entries
     84      if (!error) {
     85        error = e;
     86      }
     87    }
     88  }
     89
     90  if (entry.length) {
     91    // Expose entry point to Node, AMD or browser globals
     92    // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
     93    var mainExports = newRequire(entry[entry.length - 1]);
     94
     95    // CommonJS
     96    if (typeof exports === "object" && typeof module !== "undefined") {
     97      module.exports = mainExports;
     98
     99    // RequireJS
     100    } else if (typeof define === "function" && define.amd) {
     101     define(function () {
     102       return mainExports;
     103     });
     104
     105    // <script>
     106    } else if (globalName) {
     107      this[globalName] = mainExports;
     108    }
     109  }
     110
     111  // Override the current require with this new one
     112  parcelRequire = newRequire;
     113
     114  if (error) {
     115    // throw error from earlier, _after updating parcelRequire_
     116    throw error;
     117  }
     118
     119  return newRequire;
     120})({"k5We":[function(require,module,exports) {
     121function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
     122
     123function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
     124
     125function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
     126
     127function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
     128
     129function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }
     130
     131function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
     132
     133function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
     134
     135function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
     136
     137function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
     138
     139function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
     140
     141function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
     142
     143function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
     144
     145function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
     146
     147/**
     148 * WordPress dependencies.
     149 */
     150var _wp = wp,
     151    _wp$i18n = _wp.i18n,
     152    __ = _wp$i18n.__,
     153    sprintf = _wp$i18n.sprintf;
     154/**
     155 * BuddyPress dependencies.
     156 */
     157
     158var _bp = bp,
     159    dynamicWidgetBlock = _bp.dynamicWidgetBlock;
     160/**
     161 * Front-end Dynamic Members Widget Block class.
     162 *
     163 * @since 9.0.0
     164 */
     165
     166var bpMembersWidgetBlock = /*#__PURE__*/function (_dynamicWidgetBlock) {
     167  _inherits(bpMembersWidgetBlock, _dynamicWidgetBlock);
     168
     169  var _super = _createSuper(bpMembersWidgetBlock);
     170
     171  function bpMembersWidgetBlock() {
     172    _classCallCheck(this, bpMembersWidgetBlock);
     173
     174    return _super.apply(this, arguments);
     175  }
     176
     177  _createClass(bpMembersWidgetBlock, [{
     178    key: "loop",
     179    value: function loop() {
     180      var members = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
     181      var container = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
     182      var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'active';
     183
     184      var tmpl = _get(_getPrototypeOf(bpMembersWidgetBlock.prototype), "useTemplate", this).call(this, 'bp-dynamic-members-item');
     185
     186      var selector = document.querySelector('#' + container);
     187      var output = '';
     188
     189      if (members && members.length) {
     190        members.forEach(function (member) {
     191          if ('active' === type && member.last_activity) {
     192            /* translators: %s: a human time diff. */
     193            member.extra = sprintf(__('Active %s', 'buddypress'), member.last_activity.timediff);
     194          } else if ('popular' === type && member.total_friend_count) {
     195            var friendsCount = parseInt(member.total_friend_count, 10);
     196
     197            if (0 === friendsCount) {
     198              member.extra = __('No friends', 'buddypress');
     199            } else if (1 === friendsCount) {
     200              member.extra = __('1 friend', 'buddypress');
     201            } else {
     202              /* translators: %s: total friend count (more than 1). */
     203              member.extra = sprintf(__('%s friends', 'buddypress'), member.total_friend_count);
     204            }
     205          } else if ('newest' === type && member.registered_since) {
     206            /* translators: %s is time elapsed since the registration date happened */
     207            member.extra = sprintf(__('Registered %s', 'buddypress'), member.registered_since);
     208          }
     209          /* translators: %s: member name */
     210
     211
     212          member.avatar_alt = sprintf(__('Profile picture of %s', 'buddypress'), member.name);
     213          output += tmpl(member);
     214        });
     215      } else {
     216        output = '<div class="widget-error">' + __('No members found.', 'buddypress') + '</div>';
     217      }
     218
     219      selector.innerHTML = output;
     220    }
     221  }, {
     222    key: "start",
     223    value: function start() {
     224      var _this = this;
     225
     226      this.blocks.forEach(function (block, i) {
     227        var selector = block.selector;
     228        var type = block.query_args.type;
     229        var list = document.querySelector('#' + selector).closest('.bp-dynamic-block-container'); // Get default Block's type members.
     230
     231        _get(_getPrototypeOf(bpMembersWidgetBlock.prototype), "getItems", _this).call(_this, type, i); // Listen to Block's Nav item clics
     232
     233
     234        list.querySelectorAll('.item-options a').forEach(function (navItem) {
     235          navItem.addEventListener('click', function (event) {
     236            event.preventDefault(); // Changes the displayed filter.
     237
     238            event.target.closest('.item-options').querySelector('.selected').classList.remove('selected');
     239            event.target.classList.add('selected');
     240            var newType = event.target.getAttribute('data-bp-sort');
     241
     242            if (newType !== _this.blocks[i].query_args.type) {
     243              _get(_getPrototypeOf(bpMembersWidgetBlock.prototype), "getItems", _this).call(_this, newType, i);
     244            }
     245          });
     246        });
     247      });
     248    }
     249  }]);
     250
     251  return bpMembersWidgetBlock;
     252}(dynamicWidgetBlock);
     253
     254var settings = window.bpDynamicMembersSettings || {};
     255var blocks = window.bpDynamicMembersBlocks || {};
     256var bpDynamicMembers = new bpMembersWidgetBlock(settings, blocks);
     257
     258if ('loading' === document.readyState) {
     259  document.addEventListener('DOMContentLoaded', bpDynamicMembers.start());
     260} else {
     261  bpDynamicMembers.start();
     262}
     263},{}]},{},["k5We"], null)
     264 No newline at end of file
  • new file src/bp-members/sass/blocks/dynamic-members.scss

    diff --git src/bp-members/sass/blocks/dynamic-members.scss src/bp-members/sass/blocks/dynamic-members.scss
    new file mode 100644
    index 000000000..35104d10d
    - +  
     1.bp-dynamic-block-container {
     2
     3        .item-options {
     4                font-size: 0.5em;
     5                margin: 0 0 1em;
     6                padding: 1em 0;
     7
     8                a.selected {
     9                        font-weight: 600;
     10                }
     11        }
     12
     13        ul.item-list {
     14                list-style: none;
     15                margin: 1em 0;
     16
     17                li {
     18                        margin-bottom: 1em;
     19
     20                        &:before,
     21                        &:after {
     22                                content: " ";
     23                                display: table;
     24                        }
     25
     26                        &:after {
     27                                clear: both;
     28                        }
     29
     30                        .item-avatar {
     31                                float: left;
     32                                width: 60px;
     33                        }
     34
     35                        .item {
     36                                margin-left: 70px;
     37                        }
     38                }
     39        }
     40}
  • new file src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-members.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-members.php src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-members.php
    new file mode 100644
    index 000000000..52bf4a0f8
    - +  
     1<?php
     2/**
     3 * Dynamic Members Widget Block template.
     4 *
     5 * @since 9.0.0
     6 *
     7 * @package BuddyPress
     8 * @subpackage bp-legacy
     9 * @version 9.0.0
     10 */
     11?>
     12<script type="html/template" id="tmpl-bp-dynamic-members-item">
     13        <li class="vcard">
     14                <div class="item-avatar">
     15                        <a href="{{{data.link}}}" class="bp-tooltip" data-bp-tooltip="{{data.name}}">
     16                                <img loading="lazy" src="{{{data.avatar_urls.thumb}}}" class="avatar user-{{data.id}}-avatar avatar-50 photo" width="50" height="50" alt="{{{data.avatar_alt}}}">
     17                        </a>
     18                </div>
     19
     20                <div class="item">
     21                        <div class="item-title fn"><a href="{{{data.link}}}">{{data.name}}</a></div>
     22                        <div class="item-meta">
     23                                <span class="activity">{{data.extra}}</span>
     24                        </div>
     25                </div>
     26        </li>
     27</script>
  • new file src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-members.php

    diff --git src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-members.php src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-members.php
    new file mode 100644
    index 000000000..9ca4bdd45
    - +  
     1<?php
     2/**
     3 * Dynamic Members Widget Block template.
     4 *
     5 * @since 9.0.0
     6 *
     7 * @package BuddyPress
     8 * @subpackage bp-nouveau
     9 * @version 9.0.0
     10 */
     11?>
     12<script type="html/template" id="tmpl-bp-dynamic-members-item">
     13        <li class="vcard">
     14                <div class="item-avatar">
     15                        <a href="{{{data.link}}}" class="bp-tooltip" data-bp-tooltip="{{data.name}}">
     16                                <img loading="lazy" src="{{{data.avatar_urls.thumb}}}" class="avatar user-{{data.id}}-avatar avatar-50 photo" width="50" height="50" alt="{{{data.avatar_alt}}}">
     17                        </a>
     18                </div>
     19
     20                <div class="item">
     21                        <div class="item-title fn"><a href="{{{data.link}}}">{{data.name}}</a></div>
     22                        <div class="item-meta">
     23                                <span class="activity">{{data.extra}}</span>
     24                        </div>
     25                </div>
     26        </li>
     27</script>
  • new file src/js/bp-members/js/blocks/dynamic-members.js

    diff --git src/js/bp-members/js/blocks/dynamic-members.js src/js/bp-members/js/blocks/dynamic-members.js
    new file mode 100644
    index 000000000..bddb04dc7
    - +  
     1/**
     2 * WordPress dependencies.
     3 */
     4const {
     5        blocks: {
     6                registerBlockType,
     7        },
     8        i18n: {
     9                __,
     10        },
     11} = wp;
     12
     13/**
     14 * Internal dependencies.
     15 */
     16import editDynamicMembersBlock from './dynamic-members/edit';
     17import transforms from './dynamic-members/transforms';
     18
     19registerBlockType( 'bp/dynamic-members', {
     20        title: __( 'Dynamic Members List', 'buddypress' ),
     21        description: __( 'A dynamic list of recently active, popular, and newest members.', 'buddypress' ),
     22        icon: {
     23                background: '#fff',
     24                foreground: '#d84800',
     25                src: 'groups',
     26        },
     27        category: 'buddypress',
     28        attributes: {
     29                title: {
     30                        type: 'string',
     31                        default: __( 'Members', 'buddypress' ),
     32                },
     33                maxMembers: {
     34                        type: 'number',
     35                        default: 5
     36                },
     37                memberDefault: {
     38                        type: 'string',
     39                        default: 'active',
     40                },
     41                linkTitle: {
     42                        type: 'boolean',
     43                        default: false,
     44                },
     45        },
     46        edit: editDynamicMembersBlock,
     47        transforms: transforms,
     48} );
  • new file src/js/bp-members/js/blocks/dynamic-members/constants.js

    diff --git src/js/bp-members/js/blocks/dynamic-members/constants.js src/js/bp-members/js/blocks/dynamic-members/constants.js
    new file mode 100644
    index 000000000..0f8930622
    - +  
     1/**
     2 * WordPress dependencies.
     3 */
     4const {
     5        i18n: {
     6                __,
     7        },
     8} = wp;
     9
     10/**
     11 * Members ordering types.
     12 *
     13 * @type {Array}
     14 */
     15export const TYPES = [
     16        {
     17                label: __( 'Newest', 'buddypress' ),
     18                value: 'newest',
     19        },
     20        {
     21                label: __( 'Active', 'buddypress' ),
     22                value: 'active',
     23        },
     24        {
     25                label: __( 'Popular', 'buddypress' ),
     26                value: 'popular',
     27        },
     28];
  • new file src/js/bp-members/js/blocks/dynamic-members/edit.js

    diff --git src/js/bp-members/js/blocks/dynamic-members/edit.js src/js/bp-members/js/blocks/dynamic-members/edit.js
    new file mode 100644
    index 000000000..88b5ee297
    - +  
     1/**
     2 * WordPress dependencies.
     3 */
     4const {
     5        blockEditor: {
     6                InspectorControls,
     7        },
     8        components: {
     9                Disabled,
     10                PanelBody,
     11                RangeControl,
     12                SelectControl,
     13                TextControl,
     14                ToggleControl,
     15        },
     16        element: {
     17                Fragment,
     18                createElement,
     19        },
     20        i18n: {
     21                __,
     22        },
     23} = wp;
     24
     25/**
     26 * BuddyPress dependencies.
     27 */
     28const {
     29        blockComponents: {
     30                ServerSideRender,
     31        },
     32        blockData: {
     33                isActive,
     34        }
     35} = bp;
     36
     37/**
     38 * Internal dependencies.
     39 */
     40import { TYPES } from './constants';
     41
     42const editDynamicMembersBlock = ( { attributes, setAttributes } ) => {
     43        const { title, maxMembers, memberDefault, linkTitle } = attributes;
     44        const sortTypes = !! isActive( 'friends' ) ? TYPES : TYPES.filter( ( type ) => 'popular' !== type.value );
     45
     46        return (
     47                <Fragment>
     48                        <InspectorControls>
     49                                <PanelBody title={ __( 'Settings', 'buddypress' ) } initialOpen={ true }>
     50                                        <TextControl
     51                                                label={ __( 'Title', 'buddypress' ) }
     52                                                value={ title }
     53                                                onChange={ ( text ) => {
     54                                                        setAttributes( { title: text } );
     55                                                } }
     56                                        />
     57                                        <RangeControl
     58                                                label={ __( 'Max members to show', 'buddypress' ) }
     59                                                value={ maxMembers }
     60                                                onChange={ ( value ) =>
     61                                                        setAttributes( { maxMembers: value } )
     62                                                }
     63                                                min={ 1 }
     64                                                max={ 10 }
     65                                                required
     66                                        />
     67                                        <SelectControl
     68                                                label={ __( 'Default members to show', 'buddypress' ) }
     69                                                value={ memberDefault }
     70                                                options={ sortTypes }
     71                                                onChange={ ( option ) => {
     72                                                        setAttributes( { memberDefault: option } );
     73                                                } }
     74                                        />
     75                                        <ToggleControl
     76                                                label={ __( 'Link block title to Members directory', 'buddypress' ) }
     77                                                checked={ !! linkTitle }
     78                                                onChange={ () => {
     79                                                        setAttributes( { linkTitle: ! linkTitle } );
     80                                                } }
     81                                        />
     82                                </PanelBody>
     83                        </InspectorControls>
     84                        <Disabled>
     85                                <ServerSideRender block="bp/dynamic-members" attributes={ attributes } />
     86                        </Disabled>
     87                </Fragment>
     88        );
     89};
     90
     91export default editDynamicMembersBlock;
  • new file src/js/bp-members/js/blocks/dynamic-members/transforms.js

    diff --git src/js/bp-members/js/blocks/dynamic-members/transforms.js src/js/bp-members/js/blocks/dynamic-members/transforms.js
    new file mode 100644
    index 000000000..d5090aee8
    - +  
     1/**
     2 * WordPress dependencies.
     3 */
     4const {
     5        blocks: {
     6                createBlock,
     7        },
     8} = wp;
     9
     10/**
     11 * Transforms Legacy Widget to Dynamic Members Block.
     12 *
     13 * @type {Object}
     14 */
     15const transforms = {
     16        from: [
     17                {
     18                        type: 'block',
     19                        blocks: [ 'core/legacy-widget' ],
     20                        isMatch: ( { idBase, instance } ) => {
     21                                if ( ! instance?.raw ) {
     22                                        return false;
     23                                }
     24
     25                                return idBase === 'bp_core_members_widget';
     26                        },
     27                        transform: ( { instance } ) => {
     28                                return createBlock( 'bp/dynamic-members', {
     29                                        title: instance.raw.title,
     30                                        maxMembers: instance.raw.max_members,
     31                                        memberDefault: instance.raw.member_default,
     32                                        linkTitle: instance.raw.link_title,
     33                                } );
     34                        },
     35                },
     36        ],
     37};
     38
     39export default transforms;
  • new file src/js/bp-members/js/dynamic-members.js

    diff --git src/js/bp-members/js/dynamic-members.js src/js/bp-members/js/dynamic-members.js
    new file mode 100644
    index 000000000..c1f340a60
    - +  
     1/**
     2 * WordPress dependencies.
     3 */
     4const {
     5        i18n: {
     6                __,
     7                sprintf,
     8        },
     9} = wp;
     10
     11/**
     12 * BuddyPress dependencies.
     13 */
     14const {
     15        dynamicWidgetBlock,
     16} = bp;
     17
     18/**
     19 * Front-end Dynamic Members Widget Block class.
     20 *
     21 * @since 9.0.0
     22 */
     23class bpMembersWidgetBlock extends dynamicWidgetBlock {
     24        loop( members = [], container = '', type = 'active' ) {
     25                const tmpl = super.useTemplate( 'bp-dynamic-members-item' );
     26                const selector = document.querySelector( '#' + container );
     27                let output = '';
     28
     29                if ( members && members.length ) {
     30                        members.forEach( ( member ) => {
     31                                if ( 'active' === type && member.last_activity ) {
     32                                        /* translators: %s: a human time diff. */
     33                                        member.extra = sprintf( __( 'Active %s', 'buddypress' ), member.last_activity.timediff );
     34                                } else if ( 'popular' === type && member.total_friend_count ) {
     35                                        const friendsCount = parseInt( member.total_friend_count, 10 );
     36
     37                                        if ( 0 === friendsCount ) {
     38                                                member.extra = __( 'No friends', 'buddypress' );
     39                                        } else if ( 1 === friendsCount ) {
     40                                                member.extra = __( '1 friend', 'buddypress' );
     41                                        } else {
     42                                                /* translators: %s: total friend count (more than 1). */
     43                                                member.extra = sprintf( __( '%s friends', 'buddypress' ), member.total_friend_count );
     44                                        }
     45                                } else if ( 'newest' === type && member.registered_since ) {
     46                                        /* translators: %s is time elapsed since the registration date happened */
     47                                        member.extra = sprintf( __( 'Registered %s', 'buddypress' ), member.registered_since );
     48                                }
     49
     50                                /* translators: %s: member name */
     51                                member.avatar_alt = sprintf( __( 'Profile picture of %s', 'buddypress' ), member.name );
     52
     53                                output += tmpl( member );
     54                        } );
     55                } else {
     56                        output = '<div class="widget-error">' + __( 'No members found.', 'buddypress' ) + '</div>';
     57                }
     58
     59                selector.innerHTML = output;
     60        }
     61
     62        start() {
     63                this.blocks.forEach( ( block, i ) => {
     64                        const { selector } = block;
     65                        const { type } = block.query_args;
     66                        const list = document.querySelector( '#' + selector ).closest( '.bp-dynamic-block-container' );
     67
     68                        // Get default Block's type members.
     69                        super.getItems( type, i );
     70
     71                        // Listen to Block's Nav item clics
     72                        list.querySelectorAll( '.item-options a' ).forEach( ( navItem ) => {
     73                                navItem.addEventListener( 'click', ( event ) => {
     74                                        event.preventDefault();
     75
     76                                        // Changes the displayed filter.
     77                                        event.target.closest( '.item-options' ).querySelector( '.selected' ).classList.remove( 'selected' );
     78                                        event.target.classList.add( 'selected' );
     79
     80                                        const newType = event.target.getAttribute( 'data-bp-sort' );
     81
     82                                        if ( newType !== this.blocks[ i ].query_args.type ) {
     83                                                super.getItems( newType, i );
     84                                        }
     85                                } );
     86                        } );
     87                } );
     88        }
     89}
     90
     91const settings = window.bpDynamicMembersSettings || {};
     92const blocks = window.bpDynamicMembersBlocks || {};
     93const bpDynamicMembers = new bpMembersWidgetBlock( settings, blocks );
     94
     95if ( 'loading' === document.readyState ) {
     96        document.addEventListener( 'DOMContentLoaded', bpDynamicMembers.start() );
     97} else {
     98        bpDynamicMembers.start();
     99}