Skip to:
Content

BuddyPress.org

Ticket #8523: 8523.patch

File 8523.patch, 45.8 KB (added by imath, 4 years ago)
  • .jshintignore

    diff --git .jshintignore .jshintignore
    index 185586a70..eeeb21557 100644
    src/**/js/block-*/**/*.js 
    1010src/**/js/block-*.js
    1111src/**/js/friends.js
    1212src/**/js/dynamic-members.js
     13src/**/js/dynamic-groups.js
    1314src/**/js/dynamic-widget-block.js
  • Gruntfile.js

    diff --git Gruntfile.js Gruntfile.js
    index 5951547f2..7e4ecdae2 100644
    module.exports = function( grunt ) { 
    2525                        '!**/js/block-*.js',
    2626                        '!**/js/friends.js',
    2727                        '!**/js/dynamic-members.js',
     28                        '!**/js/dynamic-groups.js',
    2829                        '!**/js/dynamic-widget-block.js'
    2930                ],
    3031
    module.exports = function( grunt ) { 
    4546                        '!bp-core/css/blocks/login-form.css',
    4647                        '!bp-activity/css/blocks/latest-activities.css',
    4748                        '!bp-friends/css/blocks/friends.css',
    48                         '!bp-members/css/blocks/dynamic-members.css'
     49                        '!bp-members/css/blocks/dynamic-members.css',
     50                        '!bp-groups/css/blocks/dynamic-groups.css'
    4951                ],
    5052
    5153                autoprefixer = require('autoprefixer');
  • src/bp-friends/bp-friends-blocks.php

    diff --git src/bp-friends/bp-friends-blocks.php src/bp-friends/bp-friends-blocks.php
    index 876bc46d3..3d3b99f07 100644
    function bp_friends_render_friends_block( $attributes = array() ) { 
    182182                                                                'html'    => false,
    183183                                                        )
    184184                                                ),
    185                                                 'data.avatar_alt'        => esc_html(
     185                                                'data.avatar_alt'        => esc_attr(
    186186                                                        sprintf(
    187187                                                                /* translators: %s: member name */
    188188                                                                __( 'Profile picture of %s', 'buddypress' ),
  • src/bp-groups/bp-groups-blocks.php

    diff --git src/bp-groups/bp-groups-blocks.php src/bp-groups/bp-groups-blocks.php
    index c3c08fb39..8eed69b46 100644
    function bp_groups_render_groups_block( $attributes = array() ) { 
    310310         */
    311311        return apply_filters( 'bp_groups_render_groups_block_output', $output, $block_args, $groups );
    312312}
     313
     314/**
     315 * Adds specific script data for the BP Groups blocks.
     316 *
     317 * Only used for the BP Dynamic Groups block.
     318 *
     319 * @since 9.0.0
     320 */
     321function bp_groups_blocks_add_script_data() {
     322        $dynamic_groups_blocks = array_filter( buddypress()->groups->block_globals['bp/dynamic-groups']->items );
     323
     324        if ( ! $dynamic_groups_blocks ) {
     325                return;
     326        }
     327
     328        // Include the common JS template.
     329        echo bp_get_dynamic_template_part( 'assets/widgets/dynamic-groups.php' );
     330
     331        // List the block specific props.
     332        wp_add_inline_script(
     333                'bp-dynamic-groups-script',
     334                sprintf( 'var bpDynamicGroupsBlocks = %s;', wp_json_encode( array_values( $dynamic_groups_blocks ) ) ),
     335                'before'
     336        );
     337}
     338
     339/**
     340 * Callback function to render the Dynamic Groups Block.
     341 *
     342 * @since 9.0.0
     343 *
     344 * @param array $attributes The block attributes.
     345 * @return string           HTML output.
     346 */
     347function bp_groups_render_dynamic_groups_block( $attributes = array() ) {
     348        $block_args = wp_parse_args(
     349                $attributes,
     350                array(
     351                        'title'        => __( 'Groups', 'buddypress' ),
     352                        'maxGroups'    => 5,
     353                        'groupDefault' => 'active',
     354                        'linkTitle'    => false,
     355                )
     356        );
     357
     358        $classnames         = 'widget_bp_groups_widget buddypress widget';
     359        $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classnames ) );
     360
     361        $max_groups = (int) $block_args['maxGroups'];
     362        $no_groups  = __( 'There are no groups to display.', 'buddypress' );
     363
     364        /** This filter is documented in buddypress/src/bp-groups/classes/class-bp-groups-widget.php */
     365        $separator = apply_filters( 'bp_groups_widget_separator', '|' );
     366
     367        // Make sure the widget ID is unique.
     368        $widget_id             = uniqid( 'groups-list-' );
     369        $groups_directory_link = bp_get_groups_directory_permalink();
     370
     371        // Set the Block's title.
     372        if ( true === $block_args['linkTitle'] ) {
     373                $widget_content = sprintf(
     374                        '<h2 class="widget-title"><a href="%1$s">%2$s</a></h2>',
     375                        esc_url( $groups_directory_link ),
     376                        esc_html( $block_args['title'] )
     377                );
     378        } else {
     379                $widget_content = sprintf( '<h2 class="widget-title">%s</h2>', esc_html( $block_args['title'] ) );
     380        }
     381
     382        $item_options = array(
     383                'newest'       => array(
     384                        'class' => '',
     385                        'label' => __( 'Newest', 'buddypress' ),
     386                ),
     387                'active'       => array(
     388                        'class' => '',
     389                        'label' => __( 'Active', 'buddypress' ),
     390                ),
     391                'popular'      => array(
     392                        'class' => '',
     393                        'label' => __( 'Popular', 'buddypress' ),
     394                ),
     395                'alphabetical' => array(
     396                        'class' => '',
     397                        'label' => __( 'Alphabetical', 'buddypress' ),
     398                ),
     399        );
     400
     401        $item_options_output = array();
     402        $separator_output    = sprintf( ' <span class="bp-separator" role="separator">%s</span> ', esc_html( $separator ) );
     403
     404        foreach ( $item_options as $item_type => $item_attr ) {
     405                if ( $block_args['groupDefault'] === $item_type ) {
     406                        $item_attr['class'] = ' class="selected"';
     407                }
     408
     409                $item_options_output[] = sprintf(
     410                        '<a href="%1$s" data-bp-sort="%2$s"%3$s>%4$s</a>',
     411                        esc_url( $groups_directory_link ),
     412                        esc_attr( $item_type ),
     413                        $item_attr['class'],
     414                        esc_html( $item_attr['label'] )
     415                );
     416        }
     417
     418        $preview      = '';
     419        $default_args = array(
     420                'type'            => $block_args['groupDefault'],
     421                'per_page'        => $max_groups,
     422                'populate_extras' => true,
     423        );
     424
     425        // Previewing the Block inside the editor.
     426        if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
     427                $bp_query = groups_get_groups( $default_args );
     428                $preview  = sprintf( '<div class="widget-error">%s</div>', $no_groups );
     429
     430                if ( is_array( $bp_query['groups'] ) && 0 < count( $bp_query['groups'] ) ) {
     431                        $preview = '';
     432                        foreach ( $bp_query['groups'] as $group ) {
     433                                if ( 'newest' === $block_args['groupDefault'] ) {
     434                                        /* translators: %s is time elapsed since the group was created */
     435                                        $extra = sprintf( __( 'Created %s', 'buddypress' ), bp_get_group_date_created( $group ) );
     436                                } elseif ( 'popular' === $block_args['groupDefault'] ) {
     437                                        $count = (int) $group->total_member_count;
     438
     439                                        /* translators: %s is the number of Group members */
     440                                        $extra = sprintf( _n( '%s member', '%s members', $count, 'buddypress' ), bp_core_number_format( $count ) );
     441                                } else {
     442                                        /* translators: %s: a human time diff. */
     443                                        $extra = sprintf( __( 'Active %s', 'buddypress' ), bp_get_group_last_active( $group ) );
     444                                }
     445
     446                                $preview .= bp_get_dynamic_template_part(
     447                                        'assets/widgets/dynamic-groups.php',
     448                                        'php',
     449                                        array(
     450                                                'data.link'              => bp_get_group_permalink( $group ),
     451                                                'data.name'              => bp_get_group_name( $group ),
     452                                                'data.avatar_urls.thumb' => bp_core_fetch_avatar(
     453                                                        array(
     454                                                                'item_id' => $group->id,
     455                                                                'html'    => false,
     456                                                                'object'  => 'group',
     457                                                        )
     458                                                ),
     459                                                'data.avatar_alt'        => esc_attr(
     460                                                        sprintf(
     461                                                                /* Translators: %s is the group's name. */
     462                                                                __( 'Group Profile photo of %s', 'buddypress' ),
     463                                                                $group->name
     464                                                        )
     465                                                ),
     466                                                'data.id'                => $group->id,
     467                                                'data.extra'             => $extra,
     468                                        )
     469                                );
     470                        }
     471                }
     472        } else {
     473                // Get corresponding members.
     474                $path = sprintf(
     475                        '/%1$s/%2$s/%3$s',
     476                        bp_rest_namespace(),
     477                        bp_rest_version(),
     478                        buddypress()->groups->id
     479                );
     480
     481                $default_path = add_query_arg(
     482                        $default_args,
     483                        $path
     484                );
     485
     486                $preloaded_groups = array();
     487                if ( bp_is_running_wp( '5.0.0' ) ) {
     488                        $preloaded_groups = rest_preload_api_request( '', $default_path );
     489                }
     490
     491                buddypress()->groups->block_globals['bp/dynamic-groups']->items[ $widget_id ] = (object) array(
     492                        'selector'   => $widget_id,
     493                        'query_args' => $default_args,
     494                        'preloaded'  => reset( $preloaded_groups ),
     495                );
     496
     497                // Only enqueue common/specific scripts and data once per page load.
     498                if ( ! has_action( 'wp_footer', 'bp_groups_blocks_add_script_data', 1 ) ) {
     499                        wp_set_script_translations( 'bp-dynamic-groups-script', 'buddypress' );
     500                        wp_enqueue_script( 'bp-dynamic-groups-script' );
     501                        wp_localize_script(
     502                                'bp-dynamic-groups-script',
     503                                'bpDynamicGroupsSettings',
     504                                array(
     505                                        'path'  => ltrim( $path, '/' ),
     506                                        'root'  => esc_url_raw( get_rest_url() ),
     507                                        'nonce' => wp_create_nonce( 'wp_rest' ),
     508                                )
     509                        );
     510
     511                        add_action( 'wp_footer', 'bp_groups_blocks_add_script_data', 1 );
     512                }
     513        }
     514
     515        $widget_content .= sprintf(
     516                '<div class="item-options">
     517                        %1$s
     518                </div>
     519                <ul id="%2$s" class="item-list" aria-live="polite" aria-relevant="all" aria-atomic="true">
     520                        %3$s
     521                </ul>',
     522                implode( $separator_output, $item_options_output ),
     523                esc_attr( $widget_id ),
     524                $preview
     525        );
     526
     527        // Adds a container to make sure the block is styled even when used into the Columns parent block.
     528        $widget_content = sprintf( '<div class="bp-dynamic-block-container">%s</div>', "\n" . $widget_content . "\n" );
     529
     530        // Only add a block wrapper if not loaded into a Widgets sidebar.
     531        if ( ! did_action( 'dynamic_sidebar_before' ) ) {
     532                return sprintf(
     533                        '<div %1$s>%2$s</div>',
     534                        $wrapper_attributes,
     535                        $widget_content
     536                );
     537        }
     538
     539        return $widget_content;
     540}
  • src/bp-groups/bp-groups-cssjs.php

    diff --git src/bp-groups/bp-groups-cssjs.php src/bp-groups/bp-groups-cssjs.php
    index 4a2221486..99aab5bb6 100644
    function bp_groups_get_group_manage_members_script_data( $group_id = 0 ) { 
    6363                ),
    6464        );
    6565}
     66
     67/**
     68 * Registers a new script to manage the dynamic part of the Dynamic groups widget/block.
     69 *
     70 * @since 9.0.0
     71 *
     72 * @param array $scripts Data about the scripts to register.
     73 * @return array Data about the scripts to register.
     74 */
     75function bp_groups_register_widget_block_scripts( $scripts = array() ) {
     76        $scripts['bp-dynamic-groups-script'] = array(
     77                'file'         => plugins_url( 'js/dynamic-groups.js', __FILE__ ),
     78                'dependencies' => array(
     79                        'bp-dynamic-widget-block-script',
     80                        'wp-i18n',
     81                ),
     82                'footer'       => true,
     83        );
     84
     85        return $scripts;
     86}
     87add_filter( 'bp_core_register_common_scripts', 'bp_groups_register_widget_block_scripts', 9, 1 );
  • 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 d40a5c7b7..554ebdc94 100644
    class BP_Groups_Component extends BP_Component { 
    261261                        'search_string'         => _x( 'Search Groups...', 'Component directory search', 'buddypress' ),
    262262                        'global_tables'         => $global_tables,
    263263                        'meta_tables'           => $meta_tables,
     264                        'block_globals'         => array(
     265                                'bp/dynamic-groups' => array(
     266                                        'widget_classnames' => array( 'widget_bp_groups_widget', 'buddypress' ),
     267                                ),
     268                        ),
    264269                );
    265270
    266271                parent::setup_globals( $args );
    class BP_Groups_Component extends BP_Component { 
    10581063                                        ),
    10591064                                        'render_callback'    => 'bp_groups_render_groups_block',
    10601065                                ),
     1066                                'bp/dynamic-groups' => array(
     1067                                        'name'               => 'bp/dynamic-groups',
     1068                                        'editor_script'      => 'bp-dynamic-groups-block',
     1069                                        'editor_script_url'  => plugins_url( 'js/blocks/dynamic-groups.js', dirname( __FILE__ ) ),
     1070                                        'editor_script_deps' => array(
     1071                                                'wp-blocks',
     1072                                                'wp-element',
     1073                                                'wp-components',
     1074                                                'wp-i18n',
     1075                                                'wp-block-editor',
     1076                                                'bp-block-components',
     1077                                        ),
     1078                                        'style'              => 'bp-dynamic-groups-block',
     1079                                        'style_url'          => plugins_url( 'css/blocks/dynamic-groups.css', dirname( __FILE__ ) ),
     1080                                        'attributes'         => array(
     1081                                                'title'        => array(
     1082                                                        'type'    => 'string',
     1083                                                        'default' => __( 'Groups', 'buddypress' ),
     1084                                                ),
     1085                                                'maxGroups'    => array(
     1086                                                        'type'    => 'number',
     1087                                                        'default' => 5,
     1088                                                ),
     1089                                                'groupDefault' => array(
     1090                                                        'type'    => 'string',
     1091                                                        'default' => 'active',
     1092                                                ),
     1093                                                'linkTitle'    => array(
     1094                                                        'type'    => 'boolean',
     1095                                                        'default' => false,
     1096                                                ),
     1097                                        ),
     1098                                        'render_callback'    => 'bp_groups_render_dynamic_groups_block',
     1099                                ),
    10611100                        )
    10621101                );
    10631102        }
  • new file src/bp-groups/css/blocks/dynamic-groups-rtl.css

    diff --git src/bp-groups/css/blocks/dynamic-groups-rtl.css src/bp-groups/css/blocks/dynamic-groups-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-groups/css/blocks/dynamic-groups.css

    diff --git src/bp-groups/css/blocks/dynamic-groups.css src/bp-groups/css/blocks/dynamic-groups.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-groups/js/blocks/dynamic-groups.js

    diff --git src/bp-groups/js/blocks/dynamic-groups.js src/bp-groups/js/blocks/dynamic-groups.js
    new file mode 100644
    index 000000000..ed9e2a31e
    - +  
     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})({"Ra3s":[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 * Groups 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}, {
     149  label: __('Alphabetical', 'buddypress'),
     150  value: 'alphabetical'
     151}];
     152exports.TYPES = TYPES;
     153},{}],"l8fw":[function(require,module,exports) {
     154"use strict";
     155
     156Object.defineProperty(exports, "__esModule", {
     157  value: true
     158});
     159exports.default = void 0;
     160
     161var _constants = require("./constants");
     162
     163/**
     164 * WordPress dependencies.
     165 */
     166var _wp = wp,
     167    InspectorControls = _wp.blockEditor.InspectorControls,
     168    _wp$components = _wp.components,
     169    Disabled = _wp$components.Disabled,
     170    PanelBody = _wp$components.PanelBody,
     171    RangeControl = _wp$components.RangeControl,
     172    SelectControl = _wp$components.SelectControl,
     173    TextControl = _wp$components.TextControl,
     174    ToggleControl = _wp$components.ToggleControl,
     175    _wp$element = _wp.element,
     176    Fragment = _wp$element.Fragment,
     177    createElement = _wp$element.createElement,
     178    __ = _wp.i18n.__;
     179/**
     180 * BuddyPress dependencies.
     181 */
     182
     183var _bp = bp,
     184    ServerSideRender = _bp.blockComponents.ServerSideRender;
     185/**
     186 * Internal dependencies.
     187 */
     188
     189var editDynamicGroupsBlock = function editDynamicGroupsBlock(_ref) {
     190  var attributes = _ref.attributes,
     191      setAttributes = _ref.setAttributes;
     192  var title = attributes.title,
     193      maxGroups = attributes.maxGroups,
     194      groupDefault = attributes.groupDefault,
     195      linkTitle = attributes.linkTitle;
     196  return createElement(Fragment, null, createElement(InspectorControls, null, createElement(PanelBody, {
     197    title: __('Settings', 'buddypress'),
     198    initialOpen: true
     199  }, createElement(TextControl, {
     200    label: __('Title', 'buddypress'),
     201    value: title,
     202    onChange: function onChange(text) {
     203      setAttributes({
     204        title: text
     205      });
     206    }
     207  }), createElement(RangeControl, {
     208    label: __('Max groups to show', 'buddypress'),
     209    value: maxGroups,
     210    onChange: function onChange(value) {
     211      return setAttributes({
     212        maxGroups: value
     213      });
     214    },
     215    min: 1,
     216    max: 10,
     217    required: true
     218  }), createElement(SelectControl, {
     219    label: __('Default groups to show', 'buddypress'),
     220    value: groupDefault,
     221    options: _constants.TYPES,
     222    onChange: function onChange(option) {
     223      setAttributes({
     224        groupDefault: option
     225      });
     226    }
     227  }), createElement(ToggleControl, {
     228    label: __('Link block title to Groups directory', 'buddypress'),
     229    checked: !!linkTitle,
     230    onChange: function onChange() {
     231      setAttributes({
     232        linkTitle: !linkTitle
     233      });
     234    }
     235  }))), createElement(Disabled, null, createElement(ServerSideRender, {
     236    block: "bp/dynamic-groups",
     237    attributes: attributes
     238  })));
     239};
     240
     241var _default = editDynamicGroupsBlock;
     242exports.default = _default;
     243},{"./constants":"Ra3s"}],"SJlW":[function(require,module,exports) {
     244"use strict";
     245
     246Object.defineProperty(exports, "__esModule", {
     247  value: true
     248});
     249exports.default = void 0;
     250
     251/**
     252 * WordPress dependencies.
     253 */
     254var _wp = wp,
     255    createBlock = _wp.blocks.createBlock;
     256/**
     257 * Transforms Legacy Widget to Dynamic Groups Block.
     258 *
     259 * @type {Object}
     260 */
     261
     262var transforms = {
     263  from: [{
     264    type: 'block',
     265    blocks: ['core/legacy-widget'],
     266    isMatch: function isMatch(_ref) {
     267      var idBase = _ref.idBase,
     268          instance = _ref.instance;
     269
     270      if (!(instance !== null && instance !== void 0 && instance.raw)) {
     271        return false;
     272      }
     273
     274      return idBase === 'bp_groups_widget';
     275    },
     276    transform: function transform(_ref2) {
     277      var instance = _ref2.instance;
     278      return createBlock('bp/dynamic-groups', {
     279        title: instance.raw.title,
     280        maxGroups: instance.raw.max_groups,
     281        groupDefault: instance.raw.group_default,
     282        linkTitle: instance.raw.link_title
     283      });
     284    }
     285  }]
     286};
     287var _default = transforms;
     288exports.default = _default;
     289},{}],"lVvR":[function(require,module,exports) {
     290"use strict";
     291
     292var _edit = _interopRequireDefault(require("./dynamic-groups/edit"));
     293
     294var _transforms = _interopRequireDefault(require("./dynamic-groups/transforms"));
     295
     296function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
     297
     298/**
     299 * WordPress dependencies.
     300 */
     301var _wp = wp,
     302    registerBlockType = _wp.blocks.registerBlockType,
     303    __ = _wp.i18n.__;
     304/**
     305 * Internal dependencies.
     306 */
     307
     308registerBlockType('bp/dynamic-groups', {
     309  title: __('Dynamic Groups List', 'buddypress'),
     310  description: __('A dynamic list of recently active, popular, newest, or alphabetical groups.', 'buddypress'),
     311  icon: {
     312    background: '#fff',
     313    foreground: '#d84800',
     314    src: 'buddicons-groups'
     315  },
     316  category: 'buddypress',
     317  attributes: {
     318    title: {
     319      type: 'string',
     320      default: __('Groups', 'buddypress')
     321    },
     322    maxGroups: {
     323      type: 'number',
     324      default: 5
     325    },
     326    groupDefault: {
     327      type: 'string',
     328      default: 'active'
     329    },
     330    linkTitle: {
     331      type: 'boolean',
     332      default: false
     333    }
     334  },
     335  edit: _edit.default,
     336  transforms: _transforms.default
     337});
     338},{"./dynamic-groups/edit":"l8fw","./dynamic-groups/transforms":"SJlW"}]},{},["lVvR"], null)
     339 No newline at end of file
  • new file src/bp-groups/js/dynamic-groups.js

    diff --git src/bp-groups/js/dynamic-groups.js src/bp-groups/js/dynamic-groups.js
    new file mode 100644
    index 000000000..4a0839982
    - +  
     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})({"UOvc":[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 Groups Widget Block class.
     162 *
     163 * @since 9.0.0
     164 */
     165
     166var bpGroupsWidgetBlock = /*#__PURE__*/function (_dynamicWidgetBlock) {
     167  _inherits(bpGroupsWidgetBlock, _dynamicWidgetBlock);
     168
     169  var _super = _createSuper(bpGroupsWidgetBlock);
     170
     171  function bpGroupsWidgetBlock() {
     172    _classCallCheck(this, bpGroupsWidgetBlock);
     173
     174    return _super.apply(this, arguments);
     175  }
     176
     177  _createClass(bpGroupsWidgetBlock, [{
     178    key: "loop",
     179    value: function loop() {
     180      var groups = 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(bpGroupsWidgetBlock.prototype), "useTemplate", this).call(this, 'bp-dynamic-groups-item');
     185
     186      var selector = document.querySelector('#' + container);
     187      var output = '';
     188
     189      if (groups && groups.length) {
     190        groups.forEach(function (group) {
     191          if ('newest' === type && group.created_since) {
     192            /* translators: %s is time elapsed since the group was created */
     193            group.extra = sprintf(__('Created %s', 'buddypress'), group.created_since);
     194          } else if ('popular' === type && group.total_member_count) {
     195            var membersCount = parseInt(group.total_member_count, 10);
     196
     197            if (0 === membersCount) {
     198              group.extra = __('No members', 'buddypress');
     199            } else if (1 === membersCount) {
     200              group.extra = __('1 member', 'buddypress');
     201            } else {
     202              /* translators: %s is the number of Group members (more than 1). */
     203              group.extra = sprintf(__('%s members', 'buddypress'), group.total_member_count);
     204            }
     205          } else {
     206            /* translators: %s: a human time diff. */
     207            group.extra = sprintf(__('Active %s', 'buddypress'), group.last_activity_diff);
     208          }
     209          /* Translators: %s is the group's name. */
     210
     211
     212          group.avatar_alt = sprintf(__('Group Profile photo of %s', 'buddypress'), group.name);
     213          output += tmpl(group);
     214        });
     215      } else {
     216        output = '<div class="widget-error">' + __('There are no groups to display.', '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 groups.
     230
     231        _get(_getPrototypeOf(bpGroupsWidgetBlock.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(bpGroupsWidgetBlock.prototype), "getItems", _this).call(_this, newType, i);
     244            }
     245          });
     246        });
     247      });
     248    }
     249  }]);
     250
     251  return bpGroupsWidgetBlock;
     252}(dynamicWidgetBlock);
     253
     254var settings = window.bpDynamicGroupsSettings || {};
     255var blocks = window.bpDynamicGroupsBlocks || [];
     256var bpDynamicGroups = new bpGroupsWidgetBlock(settings, blocks);
     257
     258if ('loading' === document.readyState) {
     259  document.addEventListener('DOMContentLoaded', bpDynamicGroups.start());
     260} else {
     261  bpDynamicGroups.start();
     262}
     263},{}]},{},["UOvc"], null)
     264 No newline at end of file
  • new file src/bp-groups/sass/blocks/dynamic-groups.scss

    diff --git src/bp-groups/sass/blocks/dynamic-groups.scss src/bp-groups/sass/blocks/dynamic-groups.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}
  • src/bp-members/bp-members-blocks.php

    diff --git src/bp-members/bp-members-blocks.php src/bp-members/bp-members-blocks.php
    index 06310ecf0..467c51ff9 100644
    function bp_members_render_dynamic_members_block( $attributes = array() ) { 
    473473                                                                'html'    => false,
    474474                                                        )
    475475                                                ),
    476                                                 'data.avatar_alt'        => esc_html(
     476                                                'data.avatar_alt'        => esc_attr(
    477477                                                        sprintf(
    478478                                                                /* translators: %s: member name */
    479479                                                                __( 'Profile picture of %s', 'buddypress' ),
  • new file src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-groups.php

    diff --git src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-groups.php src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-groups.php
    new file mode 100644
    index 000000000..0fa900c52
    - +  
     1<?php
     2/**
     3 * Dynamic Groups 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-groups-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 group-{{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-groups.php

    diff --git src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-groups.php src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-groups.php
    new file mode 100644
    index 000000000..4047d8a2d
    - +  
     1<?php
     2/**
     3 * Dynamic Groups 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-groups-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 group-{{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-groups/js/blocks/dynamic-groups.js

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

    diff --git src/js/bp-groups/js/blocks/dynamic-groups/constants.js src/js/bp-groups/js/blocks/dynamic-groups/constants.js
    new file mode 100644
    index 000000000..e3e5ebe3e
    - +  
     1/**
     2 * WordPress dependencies.
     3 */
     4const {
     5        i18n: {
     6                __,
     7        },
     8} = wp;
     9
     10/**
     11 * Groups 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        {
     29                label: __('Alphabetical', 'buddypress' ),
     30                value: 'alphabetical',
     31        },
     32];
  • new file src/js/bp-groups/js/blocks/dynamic-groups/edit.js

    diff --git src/js/bp-groups/js/blocks/dynamic-groups/edit.js src/js/bp-groups/js/blocks/dynamic-groups/edit.js
    new file mode 100644
    index 000000000..b1be4d5b5
    - +  
     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} = bp;
     33
     34/**
     35 * Internal dependencies.
     36 */
     37import { TYPES } from './constants';
     38
     39const editDynamicGroupsBlock = ( { attributes, setAttributes } ) => {
     40        const { title, maxGroups, groupDefault, linkTitle } = attributes;
     41
     42        return (
     43                <Fragment>
     44                        <InspectorControls>
     45                                <PanelBody title={ __( 'Settings', 'buddypress' ) } initialOpen={ true }>
     46                                        <TextControl
     47                                                label={ __( 'Title', 'buddypress' ) }
     48                                                value={ title }
     49                                                onChange={ ( text ) => {
     50                                                        setAttributes( { title: text } );
     51                                                } }
     52                                        />
     53                                        <RangeControl
     54                                                label={ __( 'Max groups to show', 'buddypress' ) }
     55                                                value={ maxGroups }
     56                                                onChange={ ( value ) =>
     57                                                        setAttributes( { maxGroups: value } )
     58                                                }
     59                                                min={ 1 }
     60                                                max={ 10 }
     61                                                required
     62                                        />
     63                                        <SelectControl
     64                                                label={ __( 'Default groups to show', 'buddypress' ) }
     65                                                value={ groupDefault }
     66                                                options={ TYPES }
     67                                                onChange={ ( option ) => {
     68                                                        setAttributes( { groupDefault: option } );
     69                                                } }
     70                                        />
     71                                        <ToggleControl
     72                                                label={ __( 'Link block title to Groups directory', 'buddypress' ) }
     73                                                checked={ !! linkTitle }
     74                                                onChange={ () => {
     75                                                        setAttributes( { linkTitle: ! linkTitle } );
     76                                                } }
     77                                        />
     78                                </PanelBody>
     79                        </InspectorControls>
     80                        <Disabled>
     81                                <ServerSideRender block="bp/dynamic-groups" attributes={ attributes } />
     82                        </Disabled>
     83                </Fragment>
     84        );
     85};
     86
     87export default editDynamicGroupsBlock;
  • new file src/js/bp-groups/js/blocks/dynamic-groups/transforms.js

    diff --git src/js/bp-groups/js/blocks/dynamic-groups/transforms.js src/js/bp-groups/js/blocks/dynamic-groups/transforms.js
    new file mode 100644
    index 000000000..b4ced716a
    - +  
     1/**
     2 * WordPress dependencies.
     3 */
     4const {
     5        blocks: {
     6                createBlock,
     7        },
     8} = wp;
     9
     10/**
     11 * Transforms Legacy Widget to Dynamic Groups 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_groups_widget';
     26                        },
     27                        transform: ( { instance } ) => {
     28                                return createBlock( 'bp/dynamic-groups', {
     29                                        title: instance.raw.title,
     30                                        maxGroups: instance.raw.max_groups,
     31                                        groupDefault: instance.raw.group_default,
     32                                        linkTitle: instance.raw.link_title,
     33                                } );
     34                        },
     35                },
     36        ],
     37};
     38
     39export default transforms;
  • new file src/js/bp-groups/js/dynamic-groups.js

    diff --git src/js/bp-groups/js/dynamic-groups.js src/js/bp-groups/js/dynamic-groups.js
    new file mode 100644
    index 000000000..17a732113
    - +  
     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 Groups Widget Block class.
     20 *
     21 * @since 9.0.0
     22 */
     23class bpGroupsWidgetBlock extends dynamicWidgetBlock {
     24        loop( groups = [], container = '', type = 'active' ) {
     25                const tmpl = super.useTemplate( 'bp-dynamic-groups-item' );
     26                const selector = document.querySelector( '#' + container );
     27                let output = '';
     28
     29                if ( groups && groups.length ) {
     30                        groups.forEach( ( group ) => {
     31                                if ( 'newest' === type && group.created_since ) {
     32                                        /* translators: %s is time elapsed since the group was created */
     33                                        group.extra = sprintf( __( 'Created %s', 'buddypress' ), group.created_since );
     34                                } else if ( 'popular' === type && group.total_member_count ) {
     35                                        const membersCount = parseInt( group.total_member_count, 10 );
     36
     37                                        if ( 0 === membersCount ) {
     38                                                group.extra = __( 'No members', 'buddypress' );
     39                                        } else if ( 1 === membersCount ) {
     40                                                group.extra = __( '1 member', 'buddypress' );
     41                                        } else {
     42                                                /* translators: %s is the number of Group members (more than 1). */
     43                                                group.extra = sprintf( __( '%s members', 'buddypress' ), group.total_member_count );
     44                                        }
     45                                } else {
     46                                        /* translators: %s: a human time diff. */
     47                                        group.extra = sprintf( __( 'Active %s', 'buddypress' ), group.last_activity_diff );
     48                                }
     49
     50                                /* Translators: %s is the group's name. */
     51                                group.avatar_alt = sprintf( __( 'Group Profile photo of %s', 'buddypress' ), group.name );
     52
     53                                output += tmpl( group );
     54                        } );
     55                } else {
     56                        output = '<div class="widget-error">' + __( 'There are no groups to display.', '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 groups.
     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.bpDynamicGroupsSettings || {};
     92const blocks = window.bpDynamicGroupsBlocks || [];
     93const bpDynamicGroups = new bpGroupsWidgetBlock( settings, blocks );
     94
     95if ( 'loading' === document.readyState ) {
     96        document.addEventListener( 'DOMContentLoaded', bpDynamicGroups.start() );
     97} else {
     98        bpDynamicGroups.start();
     99}