Index: /trunk/.jshintignore
===================================================================
--- /trunk/.jshintignore	(revision 13002)
+++ /trunk/.jshintignore	(revision 13003)
@@ -10,3 +10,4 @@
 src/**/js/block-*.js
 src/**/js/friends.js
+src/**/js/dynamic-members.js
 src/**/js/dynamic-widget-block.js
Index: /trunk/Gruntfile.js
===================================================================
--- /trunk/Gruntfile.js	(revision 13002)
+++ /trunk/Gruntfile.js	(revision 13003)
@@ -25,4 +25,5 @@
 			'!**/js/block-*.js',
 			'!**/js/friends.js',
+			'!**/js/dynamic-members.js',
 			'!**/js/dynamic-widget-block.js'
 		],
@@ -44,5 +45,6 @@
 			'!bp-core/css/blocks/login-form.css',
 			'!bp-activity/css/blocks/latest-activities.css',
-			'!bp-friends/css/blocks/friends.css'
+			'!bp-friends/css/blocks/friends.css',
+			'!bp-members/css/blocks/dynamic-members.css'
 		],
 
Index: /trunk/src/bp-members/bp-members-blocks.php
===================================================================
--- /trunk/src/bp-members/bp-members-blocks.php	(revision 13002)
+++ /trunk/src/bp-members/bp-members-blocks.php	(revision 13003)
@@ -332,2 +332,226 @@
 	return apply_filters( 'bp_members_render_members_block_output', $output, $block_args, $members );
 }
+
+/**
+ * Adds specific script data for the BP Members blocks.
+ *
+ * Only used for the BP Dynamic Members block.
+ *
+ * @since 9.0.0
+ */
+function bp_members_blocks_add_script_data() {
+	$dynamic_members_blocks = array_filter( buddypress()->members->block_globals['bp/dynamic-members']->items );
+
+	if ( ! $dynamic_members_blocks ) {
+		return;
+	}
+
+	// Include the common JS template.
+	echo bp_get_dynamic_template_part( 'assets/widgets/dynamic-members.php' );
+
+	// List the block specific props.
+	wp_add_inline_script(
+		'bp-dynamic-members-script',
+		sprintf( 'var bpDynamicMembersBlocks = %s;', wp_json_encode( array_values( $dynamic_members_blocks ) ) ),
+		'before'
+	);
+}
+
+/**
+ * Callback function to render the Dynamic Members Block.
+ *
+ * @since 9.0.0
+ *
+ * @param array $attributes The block attributes.
+ * @return string           HTML output.
+ */
+function bp_members_render_dynamic_members_block( $attributes = array() ) {
+	$block_args = wp_parse_args(
+		$attributes,
+		array(
+			'title'         => __( 'Members', 'buddypress' ),
+			'maxMembers'    => 5,
+			'memberDefault' => 'active',
+			'linkTitle'     => false,
+		)
+	);
+
+	$classnames         = 'widget_bp_core_members_widget buddypress widget';
+	$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classnames ) );
+
+	$max_members = (int) $block_args['maxMembers'];
+	$no_members  = __( 'No members found.', 'buddypress' );
+
+	/** This filter is documented in buddypress/src/bp-members/classes/class-bp-core-members-widget.php */
+	$separator = apply_filters( 'bp_members_widget_separator', '|' );
+
+	// Make sure the widget ID is unique.
+	$widget_id              = uniqid( 'members-list-' );
+	$members_directory_link = bp_get_members_directory_permalink();
+
+	// Set the Block's title.
+	if ( true === $block_args['linkTitle'] ) {
+		$widget_content = sprintf(
+			'<h2 class="widget-title"><a href="%1$s">%2$s</a></h2>',
+			esc_url( $members_directory_link ),
+			esc_html( $block_args['title'] )
+		);
+	} else {
+		$widget_content = sprintf( '<h2 class="widget-title">%s</h2>', esc_html( $block_args['title'] ) );
+	}
+
+	$item_options = array(
+		'newest' => array(
+			'class' => '',
+			'label' => __( 'Newest', 'buddypress' ),
+		),
+		'active' => array(
+			'class' => '',
+			'label' => __( 'Active', 'buddypress' ),
+		),
+	);
+
+	if ( bp_is_active( 'friends' ) ) {
+		$item_options['popular'] = array(
+			'class' => '',
+			'label' => __( 'Popular', 'buddypress' ),
+		);
+	}
+
+	$item_options_output = array();
+	$separator_output    = sprintf( ' <span class="bp-separator" role="separator">%s</span> ', esc_html( $separator ) );
+
+	foreach ( $item_options as $item_type => $item_attr ) {
+		if ( $block_args['memberDefault'] === $item_type ) {
+			$item_attr['class'] = ' class="selected"';
+		}
+
+		$item_options_output[] = sprintf(
+			'<a href="%1$s" data-bp-sort="%2$s"%3$s>%4$s</a>',
+			esc_url( $members_directory_link ),
+			esc_attr( $item_type ),
+			$item_attr['class'],
+			esc_html( $item_attr['label'] )
+		);
+	}
+
+	$preview      = '';
+	$default_args = array(
+		'type'            => $block_args['memberDefault'],
+		'per_page'        => $max_members,
+		'populate_extras' => true,
+	);
+
+	// Previewing the Block inside the editor.
+	if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+		$bp_query = bp_core_get_users( $default_args );
+		$preview  = sprintf( '<div class="widget-error">%s</div>', $no_members );
+
+		if ( is_array( $bp_query['users'] ) && 0 < count( $bp_query['users'] ) ) {
+			$preview = '';
+			foreach ( $bp_query['users'] as $user ) {
+				if ( 'newest' === $block_args['memberDefault'] ) {
+					/* translators: %s is time elapsed since the registration date happened */
+					$extra = sprintf( _x( 'Registered %s', 'The timestamp when the user registered', 'buddypress' ), bp_core_time_since( $user->user_registered ) );
+				} elseif ( 'popular' === $block_args['memberDefault'] && isset( $item_options['popular'] ) && isset( $user->total_friend_count ) ) {
+					/* translators: %s: total friend count */
+					$extra = sprintf( _n( '%s friend', '%s friends', $user->total_friend_count, 'buddypress' ), number_format_i18n( $user->total_friend_count ) );
+				} else {
+					/* translators: %s: a human time diff. */
+					$extra = sprintf( __( 'Active %s', 'buddypress' ), bp_core_time_since( $user->last_activity ) );
+				}
+
+				$preview .= bp_get_dynamic_template_part(
+					'assets/widgets/dynamic-members.php',
+					'php',
+					array(
+						'data.link'              => bp_core_get_user_domain( $user->ID, $user->user_nicename, $user->user_login ),
+						'data.name'              => $user->display_name,
+						'data.avatar_urls.thumb' => bp_core_fetch_avatar(
+							array(
+								'item_id' => $user->ID,
+								'html'    => false,
+							)
+						),
+						'data.avatar_alt'        => esc_html(
+							sprintf(
+								/* translators: %s: member name */
+								__( 'Profile picture of %s', 'buddypress' ),
+								$user->display_name
+							)
+						),
+						'data.id'                => $user->ID,
+						'data.extra'             => $extra,
+					)
+				);
+			}
+		}
+	} else {
+		// Get corresponding members.
+		$path = sprintf(
+			'/%1$s/%2$s/%3$s',
+			bp_rest_namespace(),
+			bp_rest_version(),
+			buddypress()->members->id
+		);
+
+		$default_path = add_query_arg(
+			$default_args,
+			$path
+		);
+
+		$preloaded_members = array();
+		if ( bp_is_running_wp( '5.0.0' ) ) {
+			$preloaded_members = rest_preload_api_request( '', $default_path );
+		}
+
+		buddypress()->members->block_globals['bp/dynamic-members']->items[ $widget_id ] = (object) array(
+			'selector'   => $widget_id,
+			'query_args' => $default_args,
+			'preloaded'  => reset( $preloaded_members ),
+		);
+
+		// Only enqueue common/specific scripts and data once per page load.
+		if ( ! has_action( 'wp_footer', 'bp_members_blocks_add_script_data', 1 ) ) {
+			wp_set_script_translations( 'bp-dynamic-members-script', 'buddypress' );
+			wp_enqueue_script( 'bp-dynamic-members-script' );
+			wp_localize_script(
+				'bp-dynamic-members-script',
+				'bpDynamicMembersSettings',
+				array(
+					'path'  => ltrim( $path, '/' ),
+					'root'  => esc_url_raw( get_rest_url() ),
+					'nonce' => wp_create_nonce( 'wp_rest' ),
+				)
+			);
+
+			add_action( 'wp_footer', 'bp_members_blocks_add_script_data', 1 );
+		}
+	}
+
+	$widget_content .= sprintf(
+		'<div class="item-options">
+			%1$s
+		</div>
+		<ul id="%2$s" class="item-list" aria-live="polite" aria-relevant="all" aria-atomic="true">
+			%3$s
+		</ul>',
+		implode( $separator_output, $item_options_output ),
+		esc_attr( $widget_id ),
+		$preview
+	);
+
+	// Adds a container to make sure the block is styled even when used into the Columns parent block.
+	$widget_content = sprintf( '<div class="bp-dynamic-block-container">%s</div>', "\n" . $widget_content . "\n" );
+
+	// Only add a block wrapper if not loaded into a Widgets sidebar.
+	if ( ! did_action( 'dynamic_sidebar_before' ) ) {
+		return sprintf(
+			'<div %1$s>%2$s</div>',
+			$wrapper_attributes,
+			$widget_content
+		);
+	}
+
+	return $widget_content;
+}
Index: /trunk/src/bp-members/bp-members-cssjs.php
===================================================================
--- /trunk/src/bp-members/bp-members-cssjs.php	(revision 13003)
+++ /trunk/src/bp-members/bp-members-cssjs.php	(revision 13003)
@@ -0,0 +1,35 @@
+<?php
+/**
+ * BP Members component CSS/JS.
+ *
+ * @package BuddyPress
+ * @subpackage MembersScripts
+ * @since 9.0.0
+ */
+
+// Exit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Registers the script to manage the dynamic part of the Dynamic Members widget/block.
+ *
+ * @since 9.0.0
+ *
+ * @param array $scripts Data about the scripts to register.
+ * @return array Data about the scripts to register.
+ */
+function bp_members_register_scripts( $scripts = array() ) {
+	$scripts['bp-dynamic-members-script'] = array(
+		'file'         => plugins_url( 'js/dynamic-members.js', __FILE__ ),
+		'dependencies' => array(
+			'bp-dynamic-widget-block-script',
+			'wp-i18n',
+		),
+		'footer'       => true,
+	);
+
+	return $scripts;
+}
+add_filter( 'bp_core_register_common_scripts', 'bp_members_register_scripts', 9, 1 );
Index: /trunk/src/bp-members/classes/class-bp-members-component.php
===================================================================
--- /trunk/src/bp-members/classes/class-bp-members-component.php	(revision 13002)
+++ /trunk/src/bp-members/classes/class-bp-members-component.php	(revision 13003)
@@ -59,4 +59,5 @@
 		// Always include these files.
 		$includes = array(
+			'cssjs',
 			'filters',
 			'template',
@@ -197,4 +198,9 @@
 			),
 			'notification_callback' => 'members_format_notifications',
+			'block_globals'         => array(
+				'bp/dynamic-members' => array(
+					'widget_classnames' => array( 'widget_bp_core_members_widget', 'buddypress' ),
+				)
+			),
 		);
 
@@ -822,4 +828,39 @@
 					'render_callback'    => 'bp_members_render_members_block',
 				),
+				'bp/dynamic-members' => array(
+					'name'               => 'bp/dynamic-members',
+					'editor_script'      => 'bp-dynamic-members-block',
+					'editor_script_url'  => plugins_url( 'js/blocks/dynamic-members.js', dirname( __FILE__ ) ),
+					'editor_script_deps' => array(
+						'wp-blocks',
+						'wp-element',
+						'wp-components',
+						'wp-i18n',
+						'wp-block-editor',
+						'bp-block-data',
+						'bp-block-components',
+					),
+					'style'              => 'bp-dynamic-members-block',
+					'style_url'          => plugins_url( 'css/blocks/dynamic-members.css', dirname( __FILE__ ) ),
+					'attributes'         => array(
+						'title'         => array(
+							'type'    => 'string',
+							'default' => __( 'Members', 'buddypress' ),
+						),
+						'maxMembers'    => array(
+							'type'    => 'number',
+							'default' => 5,
+						),
+						'memberDefault' => array(
+							'type'    => 'string',
+							'default' => 'active',
+						),
+						'linkTitle'     => array(
+							'type'    => 'boolean',
+							'default' => false,
+						),
+					),
+					'render_callback'    => 'bp_members_render_dynamic_members_block',
+				),
 			)
 		);
Index: /trunk/src/bp-members/css/blocks/dynamic-members-rtl.css
===================================================================
--- /trunk/src/bp-members/css/blocks/dynamic-members-rtl.css	(revision 13003)
+++ /trunk/src/bp-members/css/blocks/dynamic-members-rtl.css	(revision 13003)
@@ -0,0 +1,36 @@
+.bp-dynamic-block-container .item-options {
+	font-size: 0.5em;
+	margin: 0 0 1em;
+	padding: 1em 0;
+}
+
+.bp-dynamic-block-container .item-options a.selected {
+	font-weight: 600;
+}
+
+.bp-dynamic-block-container ul.item-list {
+	list-style: none;
+	margin: 1em 0;
+}
+
+.bp-dynamic-block-container ul.item-list li {
+	margin-bottom: 1em;
+}
+
+.bp-dynamic-block-container ul.item-list li:before, .bp-dynamic-block-container ul.item-list li:after {
+	content: " ";
+	display: table;
+}
+
+.bp-dynamic-block-container ul.item-list li:after {
+	clear: both;
+}
+
+.bp-dynamic-block-container ul.item-list li .item-avatar {
+	float: right;
+	width: 60px;
+}
+
+.bp-dynamic-block-container ul.item-list li .item {
+	margin-right: 70px;
+}
Index: /trunk/src/bp-members/css/blocks/dynamic-members.css
===================================================================
--- /trunk/src/bp-members/css/blocks/dynamic-members.css	(revision 13003)
+++ /trunk/src/bp-members/css/blocks/dynamic-members.css	(revision 13003)
@@ -0,0 +1,36 @@
+.bp-dynamic-block-container .item-options {
+	font-size: 0.5em;
+	margin: 0 0 1em;
+	padding: 1em 0;
+}
+
+.bp-dynamic-block-container .item-options a.selected {
+	font-weight: 600;
+}
+
+.bp-dynamic-block-container ul.item-list {
+	list-style: none;
+	margin: 1em 0;
+}
+
+.bp-dynamic-block-container ul.item-list li {
+	margin-bottom: 1em;
+}
+
+.bp-dynamic-block-container ul.item-list li:before, .bp-dynamic-block-container ul.item-list li:after {
+	content: " ";
+	display: table;
+}
+
+.bp-dynamic-block-container ul.item-list li:after {
+	clear: both;
+}
+
+.bp-dynamic-block-container ul.item-list li .item-avatar {
+	float: left;
+	width: 60px;
+}
+
+.bp-dynamic-block-container ul.item-list li .item {
+	margin-left: 70px;
+}
Index: /trunk/src/bp-members/js/blocks/dynamic-members.js
===================================================================
--- /trunk/src/bp-members/js/blocks/dynamic-members.js	(revision 13003)
+++ /trunk/src/bp-members/js/blocks/dynamic-members.js	(revision 13003)
@@ -0,0 +1,339 @@
+// modules are defined as an array
+// [ module function, map of requires ]
+//
+// map of requires is short require name -> numeric require
+//
+// anything defined in a previous bundle is accessed via the
+// orig method which is the require for previous bundles
+parcelRequire = (function (modules, cache, entry, globalName) {
+  // Save the require from previous bundle to this closure if any
+  var previousRequire = typeof parcelRequire === 'function' && parcelRequire;
+  var nodeRequire = typeof require === 'function' && require;
+
+  function newRequire(name, jumped) {
+    if (!cache[name]) {
+      if (!modules[name]) {
+        // if we cannot find the module within our internal map or
+        // cache jump to the current global require ie. the last bundle
+        // that was added to the page.
+        var currentRequire = typeof parcelRequire === 'function' && parcelRequire;
+        if (!jumped && currentRequire) {
+          return currentRequire(name, true);
+        }
+
+        // If there are other bundles on this page the require from the
+        // previous one is saved to 'previousRequire'. Repeat this as
+        // many times as there are bundles until the module is found or
+        // we exhaust the require chain.
+        if (previousRequire) {
+          return previousRequire(name, true);
+        }
+
+        // Try the node require function if it exists.
+        if (nodeRequire && typeof name === 'string') {
+          return nodeRequire(name);
+        }
+
+        var err = new Error('Cannot find module \'' + name + '\'');
+        err.code = 'MODULE_NOT_FOUND';
+        throw err;
+      }
+
+      localRequire.resolve = resolve;
+      localRequire.cache = {};
+
+      var module = cache[name] = new newRequire.Module(name);
+
+      modules[name][0].call(module.exports, localRequire, module, module.exports, this);
+    }
+
+    return cache[name].exports;
+
+    function localRequire(x){
+      return newRequire(localRequire.resolve(x));
+    }
+
+    function resolve(x){
+      return modules[name][1][x] || x;
+    }
+  }
+
+  function Module(moduleName) {
+    this.id = moduleName;
+    this.bundle = newRequire;
+    this.exports = {};
+  }
+
+  newRequire.isParcelRequire = true;
+  newRequire.Module = Module;
+  newRequire.modules = modules;
+  newRequire.cache = cache;
+  newRequire.parent = previousRequire;
+  newRequire.register = function (id, exports) {
+    modules[id] = [function (require, module) {
+      module.exports = exports;
+    }, {}];
+  };
+
+  var error;
+  for (var i = 0; i < entry.length; i++) {
+    try {
+      newRequire(entry[i]);
+    } catch (e) {
+      // Save first error but execute all entries
+      if (!error) {
+        error = e;
+      }
+    }
+  }
+
+  if (entry.length) {
+    // Expose entry point to Node, AMD or browser globals
+    // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
+    var mainExports = newRequire(entry[entry.length - 1]);
+
+    // CommonJS
+    if (typeof exports === "object" && typeof module !== "undefined") {
+      module.exports = mainExports;
+
+    // RequireJS
+    } else if (typeof define === "function" && define.amd) {
+     define(function () {
+       return mainExports;
+     });
+
+    // <script>
+    } else if (globalName) {
+      this[globalName] = mainExports;
+    }
+  }
+
+  // Override the current require with this new one
+  parcelRequire = newRequire;
+
+  if (error) {
+    // throw error from earlier, _after updating parcelRequire_
+    throw error;
+  }
+
+  return newRequire;
+})({"gOka":[function(require,module,exports) {
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.TYPES = void 0;
+
+/**
+ * WordPress dependencies.
+ */
+var _wp = wp,
+    __ = _wp.i18n.__;
+/**
+ * Members ordering types.
+ *
+ * @type {Array}
+ */
+
+var TYPES = [{
+  label: __('Newest', 'buddypress'),
+  value: 'newest'
+}, {
+  label: __('Active', 'buddypress'),
+  value: 'active'
+}, {
+  label: __('Popular', 'buddypress'),
+  value: 'popular'
+}];
+exports.TYPES = TYPES;
+},{}],"z0p7":[function(require,module,exports) {
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = void 0;
+
+var _constants = require("./constants");
+
+/**
+ * WordPress dependencies.
+ */
+var _wp = wp,
+    InspectorControls = _wp.blockEditor.InspectorControls,
+    _wp$components = _wp.components,
+    Disabled = _wp$components.Disabled,
+    PanelBody = _wp$components.PanelBody,
+    RangeControl = _wp$components.RangeControl,
+    SelectControl = _wp$components.SelectControl,
+    TextControl = _wp$components.TextControl,
+    ToggleControl = _wp$components.ToggleControl,
+    _wp$element = _wp.element,
+    Fragment = _wp$element.Fragment,
+    createElement = _wp$element.createElement,
+    __ = _wp.i18n.__;
+/**
+ * BuddyPress dependencies.
+ */
+
+var _bp = bp,
+    ServerSideRender = _bp.blockComponents.ServerSideRender,
+    isActive = _bp.blockData.isActive;
+/**
+ * Internal dependencies.
+ */
+
+var editDynamicMembersBlock = function editDynamicMembersBlock(_ref) {
+  var attributes = _ref.attributes,
+      setAttributes = _ref.setAttributes;
+  var title = attributes.title,
+      maxMembers = attributes.maxMembers,
+      memberDefault = attributes.memberDefault,
+      linkTitle = attributes.linkTitle;
+  var sortTypes = !!isActive('friends') ? _constants.TYPES : _constants.TYPES.filter(function (type) {
+    return 'popular' !== type.value;
+  });
+  return createElement(Fragment, null, createElement(InspectorControls, null, createElement(PanelBody, {
+    title: __('Settings', 'buddypress'),
+    initialOpen: true
+  }, createElement(TextControl, {
+    label: __('Title', 'buddypress'),
+    value: title,
+    onChange: function onChange(text) {
+      setAttributes({
+        title: text
+      });
+    }
+  }), createElement(RangeControl, {
+    label: __('Max members to show', 'buddypress'),
+    value: maxMembers,
+    onChange: function onChange(value) {
+      return setAttributes({
+        maxMembers: value
+      });
+    },
+    min: 1,
+    max: 10,
+    required: true
+  }), createElement(SelectControl, {
+    label: __('Default members to show', 'buddypress'),
+    value: memberDefault,
+    options: sortTypes,
+    onChange: function onChange(option) {
+      setAttributes({
+        memberDefault: option
+      });
+    }
+  }), createElement(ToggleControl, {
+    label: __('Link block title to Members directory', 'buddypress'),
+    checked: !!linkTitle,
+    onChange: function onChange() {
+      setAttributes({
+        linkTitle: !linkTitle
+      });
+    }
+  }))), createElement(Disabled, null, createElement(ServerSideRender, {
+    block: "bp/dynamic-members",
+    attributes: attributes
+  })));
+};
+
+var _default = editDynamicMembersBlock;
+exports.default = _default;
+},{"./constants":"gOka"}],"qfGr":[function(require,module,exports) {
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = void 0;
+
+/**
+ * WordPress dependencies.
+ */
+var _wp = wp,
+    createBlock = _wp.blocks.createBlock;
+/**
+ * Transforms Legacy Widget to Dynamic Members Block.
+ *
+ * @type {Object}
+ */
+
+var transforms = {
+  from: [{
+    type: 'block',
+    blocks: ['core/legacy-widget'],
+    isMatch: function isMatch(_ref) {
+      var idBase = _ref.idBase,
+          instance = _ref.instance;
+
+      if (!(instance !== null && instance !== void 0 && instance.raw)) {
+        return false;
+      }
+
+      return idBase === 'bp_core_members_widget';
+    },
+    transform: function transform(_ref2) {
+      var instance = _ref2.instance;
+      return createBlock('bp/dynamic-members', {
+        title: instance.raw.title,
+        maxMembers: instance.raw.max_members,
+        memberDefault: instance.raw.member_default,
+        linkTitle: instance.raw.link_title
+      });
+    }
+  }]
+};
+var _default = transforms;
+exports.default = _default;
+},{}],"Znbi":[function(require,module,exports) {
+"use strict";
+
+var _edit = _interopRequireDefault(require("./dynamic-members/edit"));
+
+var _transforms = _interopRequireDefault(require("./dynamic-members/transforms"));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * WordPress dependencies.
+ */
+var _wp = wp,
+    registerBlockType = _wp.blocks.registerBlockType,
+    __ = _wp.i18n.__;
+/**
+ * Internal dependencies.
+ */
+
+registerBlockType('bp/dynamic-members', {
+  title: __('Dynamic Members List', 'buddypress'),
+  description: __('A dynamic list of recently active, popular, and newest members.', 'buddypress'),
+  icon: {
+    background: '#fff',
+    foreground: '#d84800',
+    src: 'groups'
+  },
+  category: 'buddypress',
+  attributes: {
+    title: {
+      type: 'string',
+      default: __('Members', 'buddypress')
+    },
+    maxMembers: {
+      type: 'number',
+      default: 5
+    },
+    memberDefault: {
+      type: 'string',
+      default: 'active'
+    },
+    linkTitle: {
+      type: 'boolean',
+      default: false
+    }
+  },
+  edit: _edit.default,
+  transforms: _transforms.default
+});
+},{"./dynamic-members/edit":"z0p7","./dynamic-members/transforms":"qfGr"}]},{},["Znbi"], null)
Index: /trunk/src/bp-members/js/dynamic-members.js
===================================================================
--- /trunk/src/bp-members/js/dynamic-members.js	(revision 13003)
+++ /trunk/src/bp-members/js/dynamic-members.js	(revision 13003)
@@ -0,0 +1,263 @@
+// modules are defined as an array
+// [ module function, map of requires ]
+//
+// map of requires is short require name -> numeric require
+//
+// anything defined in a previous bundle is accessed via the
+// orig method which is the require for previous bundles
+parcelRequire = (function (modules, cache, entry, globalName) {
+  // Save the require from previous bundle to this closure if any
+  var previousRequire = typeof parcelRequire === 'function' && parcelRequire;
+  var nodeRequire = typeof require === 'function' && require;
+
+  function newRequire(name, jumped) {
+    if (!cache[name]) {
+      if (!modules[name]) {
+        // if we cannot find the module within our internal map or
+        // cache jump to the current global require ie. the last bundle
+        // that was added to the page.
+        var currentRequire = typeof parcelRequire === 'function' && parcelRequire;
+        if (!jumped && currentRequire) {
+          return currentRequire(name, true);
+        }
+
+        // If there are other bundles on this page the require from the
+        // previous one is saved to 'previousRequire'. Repeat this as
+        // many times as there are bundles until the module is found or
+        // we exhaust the require chain.
+        if (previousRequire) {
+          return previousRequire(name, true);
+        }
+
+        // Try the node require function if it exists.
+        if (nodeRequire && typeof name === 'string') {
+          return nodeRequire(name);
+        }
+
+        var err = new Error('Cannot find module \'' + name + '\'');
+        err.code = 'MODULE_NOT_FOUND';
+        throw err;
+      }
+
+      localRequire.resolve = resolve;
+      localRequire.cache = {};
+
+      var module = cache[name] = new newRequire.Module(name);
+
+      modules[name][0].call(module.exports, localRequire, module, module.exports, this);
+    }
+
+    return cache[name].exports;
+
+    function localRequire(x){
+      return newRequire(localRequire.resolve(x));
+    }
+
+    function resolve(x){
+      return modules[name][1][x] || x;
+    }
+  }
+
+  function Module(moduleName) {
+    this.id = moduleName;
+    this.bundle = newRequire;
+    this.exports = {};
+  }
+
+  newRequire.isParcelRequire = true;
+  newRequire.Module = Module;
+  newRequire.modules = modules;
+  newRequire.cache = cache;
+  newRequire.parent = previousRequire;
+  newRequire.register = function (id, exports) {
+    modules[id] = [function (require, module) {
+      module.exports = exports;
+    }, {}];
+  };
+
+  var error;
+  for (var i = 0; i < entry.length; i++) {
+    try {
+      newRequire(entry[i]);
+    } catch (e) {
+      // Save first error but execute all entries
+      if (!error) {
+        error = e;
+      }
+    }
+  }
+
+  if (entry.length) {
+    // Expose entry point to Node, AMD or browser globals
+    // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
+    var mainExports = newRequire(entry[entry.length - 1]);
+
+    // CommonJS
+    if (typeof exports === "object" && typeof module !== "undefined") {
+      module.exports = mainExports;
+
+    // RequireJS
+    } else if (typeof define === "function" && define.amd) {
+     define(function () {
+       return mainExports;
+     });
+
+    // <script>
+    } else if (globalName) {
+      this[globalName] = mainExports;
+    }
+  }
+
+  // Override the current require with this new one
+  parcelRequire = newRequire;
+
+  if (error) {
+    // throw error from earlier, _after updating parcelRequire_
+    throw error;
+  }
+
+  return newRequire;
+})({"k5We":[function(require,module,exports) {
+function _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); }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _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); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _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); }
+
+function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
+
+function _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); }
+
+function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+
+function _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); }; }
+
+function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
+
+function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
+
+function _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; } }
+
+function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+
+/**
+ * WordPress dependencies.
+ */
+var _wp = wp,
+    _wp$i18n = _wp.i18n,
+    __ = _wp$i18n.__,
+    sprintf = _wp$i18n.sprintf;
+/**
+ * BuddyPress dependencies.
+ */
+
+var _bp = bp,
+    dynamicWidgetBlock = _bp.dynamicWidgetBlock;
+/**
+ * Front-end Dynamic Members Widget Block class.
+ *
+ * @since 9.0.0
+ */
+
+var bpMembersWidgetBlock = /*#__PURE__*/function (_dynamicWidgetBlock) {
+  _inherits(bpMembersWidgetBlock, _dynamicWidgetBlock);
+
+  var _super = _createSuper(bpMembersWidgetBlock);
+
+  function bpMembersWidgetBlock() {
+    _classCallCheck(this, bpMembersWidgetBlock);
+
+    return _super.apply(this, arguments);
+  }
+
+  _createClass(bpMembersWidgetBlock, [{
+    key: "loop",
+    value: function loop() {
+      var members = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
+      var container = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
+      var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'active';
+
+      var tmpl = _get(_getPrototypeOf(bpMembersWidgetBlock.prototype), "useTemplate", this).call(this, 'bp-dynamic-members-item');
+
+      var selector = document.querySelector('#' + container);
+      var output = '';
+
+      if (members && members.length) {
+        members.forEach(function (member) {
+          if ('active' === type && member.last_activity) {
+            /* translators: %s: a human time diff. */
+            member.extra = sprintf(__('Active %s', 'buddypress'), member.last_activity.timediff);
+          } else if ('popular' === type && member.total_friend_count) {
+            var friendsCount = parseInt(member.total_friend_count, 10);
+
+            if (0 === friendsCount) {
+              member.extra = __('No friends', 'buddypress');
+            } else if (1 === friendsCount) {
+              member.extra = __('1 friend', 'buddypress');
+            } else {
+              /* translators: %s: total friend count (more than 1). */
+              member.extra = sprintf(__('%s friends', 'buddypress'), member.total_friend_count);
+            }
+          } else if ('newest' === type && member.registered_since) {
+            /* translators: %s is time elapsed since the registration date happened */
+            member.extra = sprintf(__('Registered %s', 'buddypress'), member.registered_since);
+          }
+          /* translators: %s: member name */
+
+
+          member.avatar_alt = sprintf(__('Profile picture of %s', 'buddypress'), member.name);
+          output += tmpl(member);
+        });
+      } else {
+        output = '<div class="widget-error">' + __('No members found.', 'buddypress') + '</div>';
+      }
+
+      selector.innerHTML = output;
+    }
+  }, {
+    key: "start",
+    value: function start() {
+      var _this = this;
+
+      this.blocks.forEach(function (block, i) {
+        var selector = block.selector;
+        var type = block.query_args.type;
+        var list = document.querySelector('#' + selector).closest('.bp-dynamic-block-container'); // Get default Block's type members.
+
+        _get(_getPrototypeOf(bpMembersWidgetBlock.prototype), "getItems", _this).call(_this, type, i); // Listen to Block's Nav item clics
+
+
+        list.querySelectorAll('.item-options a').forEach(function (navItem) {
+          navItem.addEventListener('click', function (event) {
+            event.preventDefault(); // Changes the displayed filter.
+
+            event.target.closest('.item-options').querySelector('.selected').classList.remove('selected');
+            event.target.classList.add('selected');
+            var newType = event.target.getAttribute('data-bp-sort');
+
+            if (newType !== _this.blocks[i].query_args.type) {
+              _get(_getPrototypeOf(bpMembersWidgetBlock.prototype), "getItems", _this).call(_this, newType, i);
+            }
+          });
+        });
+      });
+    }
+  }]);
+
+  return bpMembersWidgetBlock;
+}(dynamicWidgetBlock);
+
+var settings = window.bpDynamicMembersSettings || {};
+var blocks = window.bpDynamicMembersBlocks || {};
+var bpDynamicMembers = new bpMembersWidgetBlock(settings, blocks);
+
+if ('loading' === document.readyState) {
+  document.addEventListener('DOMContentLoaded', bpDynamicMembers.start());
+} else {
+  bpDynamicMembers.start();
+}
+},{}]},{},["k5We"], null)
Index: /trunk/src/bp-members/sass/blocks/dynamic-members.scss
===================================================================
--- /trunk/src/bp-members/sass/blocks/dynamic-members.scss	(revision 13003)
+++ /trunk/src/bp-members/sass/blocks/dynamic-members.scss	(revision 13003)
@@ -0,0 +1,40 @@
+.bp-dynamic-block-container {
+
+	.item-options {
+		font-size: 0.5em;
+		margin: 0 0 1em;
+		padding: 1em 0;
+
+		a.selected {
+			font-weight: 600;
+		}
+	}
+
+	ul.item-list {
+		list-style: none;
+		margin: 1em 0;
+
+		li {
+			margin-bottom: 1em;
+
+			&:before,
+			&:after {
+				content: " ";
+				display: table;
+			}
+
+			&:after {
+				clear: both;
+			}
+
+			.item-avatar {
+				float: left;
+				width: 60px;
+			}
+
+			.item {
+				margin-left: 70px;
+			}
+		}
+	}
+}
Index: /trunk/src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-members.php
===================================================================
--- /trunk/src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-members.php	(revision 13003)
+++ /trunk/src/bp-templates/bp-legacy/buddypress/assets/widgets/dynamic-members.php	(revision 13003)
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Dynamic Members Widget Block template.
+ *
+ * @since 9.0.0
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ * @version 9.0.0
+ */
+?>
+<script type="html/template" id="tmpl-bp-dynamic-members-item">
+	<li class="vcard">
+		<div class="item-avatar">
+			<a href="{{{data.link}}}" class="bp-tooltip" data-bp-tooltip="{{data.name}}">
+				<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}}}">
+			</a>
+		</div>
+
+		<div class="item">
+			<div class="item-title fn"><a href="{{{data.link}}}">{{data.name}}</a></div>
+			<div class="item-meta">
+				<span class="activity">{{data.extra}}</span>
+			</div>
+		</div>
+	</li>
+</script>
Index: /trunk/src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-members.php
===================================================================
--- /trunk/src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-members.php	(revision 13003)
+++ /trunk/src/bp-templates/bp-nouveau/buddypress/assets/widgets/dynamic-members.php	(revision 13003)
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Dynamic Members Widget Block template.
+ *
+ * @since 9.0.0
+ *
+ * @package BuddyPress
+ * @subpackage bp-nouveau
+ * @version 9.0.0
+ */
+?>
+<script type="html/template" id="tmpl-bp-dynamic-members-item">
+	<li class="vcard">
+		<div class="item-avatar">
+			<a href="{{{data.link}}}" class="bp-tooltip" data-bp-tooltip="{{data.name}}">
+				<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}}}">
+			</a>
+		</div>
+
+		<div class="item">
+			<div class="item-title fn"><a href="{{{data.link}}}">{{data.name}}</a></div>
+			<div class="item-meta">
+				<span class="activity">{{data.extra}}</span>
+			</div>
+		</div>
+	</li>
+</script>
Index: /trunk/src/js/bp-members/js/blocks/dynamic-members.js
===================================================================
--- /trunk/src/js/bp-members/js/blocks/dynamic-members.js	(revision 13003)
+++ /trunk/src/js/bp-members/js/blocks/dynamic-members.js	(revision 13003)
@@ -0,0 +1,48 @@
+/**
+ * WordPress dependencies.
+ */
+const {
+	blocks: {
+		registerBlockType,
+	},
+	i18n: {
+		__,
+	},
+} = wp;
+
+/**
+ * Internal dependencies.
+ */
+import editDynamicMembersBlock from './dynamic-members/edit';
+import transforms from './dynamic-members/transforms';
+
+registerBlockType( 'bp/dynamic-members', {
+	title: __( 'Dynamic Members List', 'buddypress' ),
+	description: __( 'A dynamic list of recently active, popular, and newest members.', 'buddypress' ),
+	icon: {
+		background: '#fff',
+		foreground: '#d84800',
+		src: 'groups',
+	},
+	category: 'buddypress',
+	attributes: {
+		title: {
+			type: 'string',
+			default: __( 'Members', 'buddypress' ),
+		},
+		maxMembers: {
+			type: 'number',
+			default: 5
+		},
+		memberDefault: {
+			type: 'string',
+			default: 'active',
+		},
+		linkTitle: {
+			type: 'boolean',
+			default: false,
+		},
+	},
+	edit: editDynamicMembersBlock,
+	transforms: transforms,
+} );
Index: /trunk/src/js/bp-members/js/blocks/dynamic-members/constants.js
===================================================================
--- /trunk/src/js/bp-members/js/blocks/dynamic-members/constants.js	(revision 13003)
+++ /trunk/src/js/bp-members/js/blocks/dynamic-members/constants.js	(revision 13003)
@@ -0,0 +1,28 @@
+/**
+ * WordPress dependencies.
+ */
+const {
+	i18n: {
+		__,
+	},
+} = wp;
+
+/**
+ * Members ordering types.
+ *
+ * @type {Array}
+ */
+export const TYPES = [
+	{
+		label: __( 'Newest', 'buddypress' ),
+		value: 'newest',
+	},
+	{
+		label: __( 'Active', 'buddypress' ),
+		value: 'active',
+	},
+	{
+		label: __( 'Popular', 'buddypress' ),
+		value: 'popular',
+	},
+];
Index: /trunk/src/js/bp-members/js/blocks/dynamic-members/edit.js
===================================================================
--- /trunk/src/js/bp-members/js/blocks/dynamic-members/edit.js	(revision 13003)
+++ /trunk/src/js/bp-members/js/blocks/dynamic-members/edit.js	(revision 13003)
@@ -0,0 +1,91 @@
+/**
+ * WordPress dependencies.
+ */
+const {
+	blockEditor: {
+		InspectorControls,
+	},
+	components: {
+		Disabled,
+		PanelBody,
+		RangeControl,
+		SelectControl,
+		TextControl,
+		ToggleControl,
+	},
+	element: {
+		Fragment,
+		createElement,
+	},
+	i18n: {
+		__,
+	},
+} = wp;
+
+/**
+ * BuddyPress dependencies.
+ */
+const {
+	blockComponents: {
+		ServerSideRender,
+	},
+	blockData: {
+		isActive,
+	}
+} = bp;
+
+/**
+ * Internal dependencies.
+ */
+import { TYPES } from './constants';
+
+const editDynamicMembersBlock = ( { attributes, setAttributes } ) => {
+	const { title, maxMembers, memberDefault, linkTitle } = attributes;
+	const sortTypes = !! isActive( 'friends' ) ? TYPES : TYPES.filter( ( type ) => 'popular' !== type.value );
+
+	return (
+		<Fragment>
+			<InspectorControls>
+				<PanelBody title={ __( 'Settings', 'buddypress' ) } initialOpen={ true }>
+					<TextControl
+						label={ __( 'Title', 'buddypress' ) }
+						value={ title }
+						onChange={ ( text ) => {
+							setAttributes( { title: text } );
+						} }
+					/>
+					<RangeControl
+						label={ __( 'Max members to show', 'buddypress' ) }
+						value={ maxMembers }
+						onChange={ ( value ) =>
+							setAttributes( { maxMembers: value } )
+						}
+						min={ 1 }
+						max={ 10 }
+						required
+					/>
+					<SelectControl
+						label={ __( 'Default members to show', 'buddypress' ) }
+						value={ memberDefault }
+						options={ sortTypes }
+						onChange={ ( option ) => {
+							setAttributes( { memberDefault: option } );
+						} }
+					/>
+					<ToggleControl
+						label={ __( 'Link block title to Members directory', 'buddypress' ) }
+						checked={ !! linkTitle }
+						onChange={ () => {
+							setAttributes( { linkTitle: ! linkTitle } );
+						} }
+					/>
+				</PanelBody>
+			</InspectorControls>
+			<Disabled>
+				<ServerSideRender block="bp/dynamic-members" attributes={ attributes } />
+			</Disabled>
+		</Fragment>
+	);
+};
+
+export default editDynamicMembersBlock;
Index: /trunk/src/js/bp-members/js/blocks/dynamic-members/transforms.js
===================================================================
--- /trunk/src/js/bp-members/js/blocks/dynamic-members/transforms.js	(revision 13003)
+++ /trunk/src/js/bp-members/js/blocks/dynamic-members/transforms.js	(revision 13003)
@@ -0,0 +1,39 @@
+/**
+ * WordPress dependencies.
+ */
+const {
+	blocks: {
+		createBlock,
+	},
+} = wp;
+
+/**
+ * Transforms Legacy Widget to Dynamic Members Block.
+ *
+ * @type {Object}
+ */
+const transforms = {
+	from: [
+		{
+			type: 'block',
+			blocks: [ 'core/legacy-widget' ],
+			isMatch: ( { idBase, instance } ) => {
+				if ( ! instance?.raw ) {
+					return false;
+				}
+
+				return idBase === 'bp_core_members_widget';
+			},
+			transform: ( { instance } ) => {
+				return createBlock( 'bp/dynamic-members', {
+					title: instance.raw.title,
+					maxMembers: instance.raw.max_members,
+					memberDefault: instance.raw.member_default,
+					linkTitle: instance.raw.link_title,
+				} );
+			},
+		},
+	],
+};
+
+export default transforms;
Index: /trunk/src/js/bp-members/js/dynamic-members.js
===================================================================
--- /trunk/src/js/bp-members/js/dynamic-members.js	(revision 13003)
+++ /trunk/src/js/bp-members/js/dynamic-members.js	(revision 13003)
@@ -0,0 +1,99 @@
+/**
+ * WordPress dependencies.
+ */
+const {
+	i18n: {
+		__,
+		sprintf,
+	},
+} = wp;
+
+/**
+ * BuddyPress dependencies.
+ */
+const {
+	dynamicWidgetBlock,
+} = bp;
+
+/**
+ * Front-end Dynamic Members Widget Block class.
+ *
+ * @since 9.0.0
+ */
+class bpMembersWidgetBlock extends dynamicWidgetBlock {
+	loop( members = [], container = '', type = 'active' ) {
+		const tmpl = super.useTemplate( 'bp-dynamic-members-item' );
+		const selector = document.querySelector( '#' + container );
+		let output = '';
+
+		if ( members && members.length ) {
+			members.forEach( ( member ) => {
+				if ( 'active' === type && member.last_activity ) {
+					/* translators: %s: a human time diff. */
+					member.extra = sprintf( __( 'Active %s', 'buddypress' ), member.last_activity.timediff );
+				} else if ( 'popular' === type && member.total_friend_count ) {
+					const friendsCount = parseInt( member.total_friend_count, 10 );
+
+					if ( 0 === friendsCount ) {
+						member.extra = __( 'No friends', 'buddypress' );
+					} else if ( 1 === friendsCount ) {
+						member.extra = __( '1 friend', 'buddypress' );
+					} else {
+						/* translators: %s: total friend count (more than 1). */
+						member.extra = sprintf( __( '%s friends', 'buddypress' ), member.total_friend_count );
+					}
+				} else if ( 'newest' === type && member.registered_since ) {
+					/* translators: %s is time elapsed since the registration date happened */
+					member.extra = sprintf( __( 'Registered %s', 'buddypress' ), member.registered_since );
+				}
+
+				/* translators: %s: member name */
+				member.avatar_alt = sprintf( __( 'Profile picture of %s', 'buddypress' ), member.name );
+
+				output += tmpl( member );
+			} );
+		} else {
+			output = '<div class="widget-error">' + __( 'No members found.', 'buddypress' ) + '</div>';
+		}
+
+		selector.innerHTML = output;
+	}
+
+	start() {
+		this.blocks.forEach( ( block, i ) => {
+			const { selector } = block;
+			const { type } = block.query_args;
+			const list = document.querySelector( '#' + selector ).closest( '.bp-dynamic-block-container' );
+
+			// Get default Block's type members.
+			super.getItems( type, i );
+
+			// Listen to Block's Nav item clics
+			list.querySelectorAll( '.item-options a' ).forEach( ( navItem ) => {
+				navItem.addEventListener( 'click', ( event ) => {
+					event.preventDefault();
+
+					// Changes the displayed filter.
+					event.target.closest( '.item-options' ).querySelector( '.selected' ).classList.remove( 'selected' );
+					event.target.classList.add( 'selected' );
+
+					const newType = event.target.getAttribute( 'data-bp-sort' );
+
+					if ( newType !== this.blocks[ i ].query_args.type ) {
+						super.getItems( newType, i );
+					}
+				} );
+			} );
+		} );
+	}
+}
+
+const settings = window.bpDynamicMembersSettings || {};
+const blocks = window.bpDynamicMembersBlocks || {};
+const bpDynamicMembers = new bpMembersWidgetBlock( settings, blocks );
+
+if ( 'loading' === document.readyState ) {
+	document.addEventListener( 'DOMContentLoaded', bpDynamicMembers.start() );
+} else {
+	bpDynamicMembers.start();
+}
