Ticket #8048: 8048.2.patch
| File 8048.2.patch, 89.3 KB (added by , 6 years ago) |
|---|
-
.gitignore
diff --git .gitignore .gitignore index 769dc445e..f26f47fbd 100644
1 1 .DS_Store 2 2 phpunit.xml 3 3 .idea 4 .cache 4 5 5 6 lib-cov 6 7 *.seed -
.jshintignore
diff --git .jshintignore .jshintignore index c7593c293..b94772ae8 100644
1 1 // 3rd party libraries 2 2 src/bp-core/js/vendor/**/* 3 3 src/bp-messages/js/autocomplete/* 4 5 // Blocks Scripts 6 src/**/js/blocks/*.js 7 src/**/js/block-components/*.js 8 src/**/js/block-components/**/*.js 9 src/bp-core/js/block-components.js -
Gruntfile.js
diff --git Gruntfile.js Gruntfile.js index 590b38872..a2d97b06d 100644
module.exports = function( grunt ) { 17 17 '**/*.js' 18 18 ], 19 19 20 BP_EXCLUDED_JS = [ 21 '!**/js/blocks/*.js', 22 '!**/js/block-components/*.js', 23 '!**/js/block-components/**/*.js', 24 '!**/js/block-components.js' 25 ], 26 20 27 BP_EXCLUDED_MISC = [ 21 28 ], 22 29 … … module.exports = function( grunt ) { 164 171 expand: true 165 172 } 166 173 }, 167 makepot: {168 target: {169 options: {170 cwd: BUILD_DIR,171 domainPath: '.',172 mainFile: 'bp-loader.php',173 potFilename: 'buddypress.pot',174 processPot: function( pot ) {175 pot.headers['report-msgid-bugs-to'] = 'https://buddypress.trac.wordpress.org';176 pot.headers['last-translator'] = 'JOHN JAMES JACOBY <jjj@buddypress.org>';177 pot.headers['language-team'] = 'ENGLISH <jjj@buddypress.org>';178 return pot;179 },180 type: 'wp-plugin'181 }182 }183 },184 174 imagemin: { 185 175 core: { 186 176 expand: true, … … module.exports = function( grunt ) { 201 191 dest: BUILD_DIR, 202 192 dot: true, 203 193 expand: true, 204 src: ['**', '!**/.{svn,git }/**'].concat( BP_EXCLUDED_MISC )194 src: ['**', '!**/.{svn,git,cache}/**', '!js/**'].concat( BP_EXCLUDED_MISC ) 205 195 }, 206 196 { 207 197 dest: BUILD_DIR, … … module.exports = function( grunt ) { 245 235 extDot: 'last', 246 236 expand: true, 247 237 ext: '.min.js', 248 src: BP_JS 238 src: BP_JS.concat( BP_EXCLUDED_JS, BP_EXCLUDED_MISC ) 249 239 } 250 240 }, 251 241 stylelint: { … … module.exports = function( grunt ) { 332 322 command: 'svn export --force https://github.com/buddypress/BP-REST.git/trunk bp-rest', 333 323 cwd: BUILD_DIR, 334 324 stdout: false 325 }, 326 makepot: { 327 command: 'wp i18n make-pot build build/buddypress.pot --headers=\'{"Project-Id-Version": "BuddyPress", "Report-Msgid-Bugs-To": "https://buddypress.trac.wordpress.org", "Last-Translator": "JOHN JAMES JACOBY <jjj@buddypress.org>", "Language-Team": "ENGLISH <jjj@buddypress.org>"}\'', 328 stdout: true 329 }, 330 blocks_src: { 331 command: 'npm run dev', 332 cwd: SOURCE_DIR, 333 stdout: true 334 }, 335 blocks_build: { 336 command: 'npm run build', 337 cwd: SOURCE_DIR, 338 stdout: true 335 339 } 336 340 }, 337 341 jsvalidate:{ … … module.exports = function( grunt ) { 342 346 }, 343 347 build: { 344 348 files: { 345 src: [BUILD_DIR + '/**/*.js'] 349 src: [BUILD_DIR + '/**/*.js'].concat( BP_EXCLUDED_JS, BP_EXCLUDED_MISC ) 346 350 } 347 351 }, 348 352 src: { 349 353 files: { 350 src: [SOURCE_DIR + '/**/*.js'].concat( BP_EXCLUDED_ MISC )354 src: [SOURCE_DIR + '/**/*.js'].concat( BP_EXCLUDED_JS, BP_EXCLUDED_MISC ) 351 355 } 352 356 } 353 357 }, … … module.exports = function( grunt ) { 367 371 * Register tasks. 368 372 */ 369 373 grunt.registerTask( 'src', ['checkDependencies', 'jsvalidate:src', 'jshint', 'stylelint', 'sass', 'postcss', 'rtlcss'] ); 374 grunt.registerTask( 'makepot', ['exec:makepot'] ); 370 375 grunt.registerTask( 'commit', ['src', 'checktextdomain', 'imagemin', 'phplint', 'exec:phpcompat'] ); 371 376 grunt.registerTask( 'bp_rest', [ 'exec:rest_api', 'copy:bp_rest_components', 'copy:bp_rest_core', 'clean:bp_rest' ] ); 372 grunt.registerTask( 'build', ['commit', 'clean:all', 'copy:files', 'uglify ', 'jsvalidate:build', 'cssmin', 'bp_rest', 'makepot', 'exec:bpdefault', 'exec:cli'] );377 grunt.registerTask( 'build', ['commit', 'clean:all', 'copy:files', 'uglify:core', 'jsvalidate:build', 'exec:blocks_src', 'cssmin', 'bp_rest', 'makepot', 'exec:blocks_build', 'exec:bpdefault', 'exec:cli'] ); 373 378 grunt.registerTask( 'release', ['build'] ); 374 379 375 380 // Testing tasks. -
composer.json
diff --git composer.json composer.json index df0c4dbdd..216b1d8a6 100644
31 31 "php": ">=5.3.0" 32 32 }, 33 33 "require-dev": { 34 "phpcompatibility/phpcompatibility-wp": "*",34 "phpcompatibility/phpcompatibility-wp": "*", 35 35 "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3" 36 36 } 37 37 } -
package.json
diff --git package.json package.json index 5e26d7be7..9ed9a4a44 100644
5 5 }, 6 6 "description": "BuddyPress adds community features to WordPress. Member Profiles, Activity Streams, Direct Messaging, Notifications, and more!", 7 7 "devDependencies": { 8 "@babel/core": "~7.8.7", 9 "@wordpress/babel-preset-default": "~4.10.0", 8 10 "@wordpress/browserslist-config": "~2.1.4", 9 11 "autoprefixer": "~8.5.2", 10 12 "grunt": "~1.0.3", … … 26 28 "grunt-rtlcss": "~2.0.1", 27 29 "grunt-sass": "~2.0.0", 28 30 "grunt-stylelint": "~0.8.0", 29 "grunt-wp-i18n": "~1.0.2",30 31 "matchdep": "~1.0.1", 32 "parcel-bundler": "~1.12.4", 31 33 "postcss-scss": "~1.0.6", 32 34 "stylelint": "~7.10.1", 33 35 "stylelint-config-wordpress": "~11.0.0" … … 35 37 "engines": { 36 38 "node": ">=6.9.1" 37 39 }, 40 "scripts": { 41 "start": "npm run dev:components && parcel watch src/js/bp-*/*s/blocks/*.js --out-dir src --no-source-maps", 42 "dev": "npm run dev:components && parcel build src/js/bp-*/*s/blocks/*.js --out-dir src --no-source-maps --no-minify", 43 "build": "npm run build:components && parcel build src/js/bp-*/*s/blocks/*.js --out-dir build --no-source-maps", 44 "watch:components": "parcel watch src/js/bp-core/js/block-components/block-components.js --out-dir src/bp-core/js --out-file block-components.js --no-source-maps --global bp", 45 "dev:components": "parcel build src/js/bp-core/js/block-components/block-components.js --out-dir src/bp-core/js --out-file block-components.js --no-source-maps --no-minify --global bp", 46 "build:components": "parcel build src/js/bp-core/js/block-components/block-components.js --out-dir build/bp-core/js --out-file block-components.js --no-source-maps --global bp" 47 }, 38 48 "keywords": [ 39 49 "activity", 40 50 "community", … … 53 63 "url": "https://buddypress.svn.wordpress.org/trunk/" 54 64 }, 55 65 "version": "6.0.0-alpha", 56 "dependencies": {},57 66 "browserslist": [ 58 67 "extends @wordpress/browserslist-config" 59 68 ] -
src/bp-core/bp-core-actions.php
diff --git src/bp-core/bp-core-actions.php src/bp-core/bp-core-actions.php index fe50c8a58..89296dd79 100644
add_action( 'bp_init', 'bp_setup_globals', 4 ); 75 75 add_action( 'bp_init', 'bp_setup_canonical_stack', 5 ); 76 76 add_action( 'bp_init', 'bp_setup_nav', 6 ); 77 77 add_action( 'bp_init', 'bp_setup_title', 8 ); 78 add_action( 'bp_init', 'bp_blocks_init', 10 ); 78 79 add_action( 'bp_init', 'bp_core_load_admin_bar_css', 12 ); 79 80 add_action( 'bp_init', 'bp_add_rewrite_tags', 20 ); 80 81 add_action( 'bp_init', 'bp_add_rewrite_rules', 30 ); -
new file src/bp-core/bp-core-blocks.php
diff --git src/bp-core/bp-core-blocks.php src/bp-core/bp-core-blocks.php new file mode 100644 index 000000000..7045c1d30
- + 1 <?php 2 /** 3 * Core BP Blocks functions. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @since 6.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * Registers the BP Block components. 15 * 16 * @since 6.0.0 17 */ 18 function bp_register_block_components() { 19 wp_register_script( 20 'bp-block-components', 21 plugins_url( 'js/block-components.js', __FILE__ ), 22 array( 23 'wp-element', 24 'wp-components', 25 'wp-i18n', 26 'wp-api-fetch', 27 ), 28 bp_get_version() 29 ); 30 } 31 add_action( 'bp_blocks_init', 'bp_register_block_components', 1 ); 32 33 /** 34 * Filters the Block Editor settings to gather BuddyPress ones into a `bp` key. 35 * 36 * @since 6.0.0 37 * 38 * @param array $editor_settings Default editor settings. 39 * @return array The editor settings including BP blocks specific ones. 40 */ 41 function bp_blocks_editor_settings( $editor_settings = array() ) { 42 /** 43 * Filter here to include your BP Blocks specific settings. 44 * 45 * @since 6.0.0 46 * 47 * @param array $bp_editor_settings BP blocks specific editor settings. 48 */ 49 $bp_editor_settings = (array) apply_filters( 'bp_blocks_editor_settings', array() ); 50 51 if ( $bp_editor_settings ) { 52 $editor_settings['bp'] = $bp_editor_settings; 53 } 54 55 return $editor_settings; 56 } 57 add_filter( 'block_editor_settings', 'bp_blocks_editor_settings' ); 58 59 /** 60 * Register a BuddyPress block type. 61 * 62 * @since 6.0.0 63 * 64 * @param array $args The registration arguments for the block type. 65 * @return BP_Block The BuddyPress block type object. 66 */ 67 function bp_register_block( $args = array() ) { 68 return new BP_Block( $args ); 69 } -
src/bp-core/bp-core-dependency.php
diff --git src/bp-core/bp-core-dependency.php src/bp-core/bp-core-dependency.php index 6ea67ed85..cb3a3f4f5 100644
function bp_rest_api_init() { 267 267 do_action( 'bp_rest_api_init' ); 268 268 } 269 269 270 /** 271 * BP Blocks Init hook. 272 * 273 * @since 6.0.0 274 */ 275 function bp_blocks_init() { 276 /** 277 * Hook here to register your BuddyPress blocks. 278 * 279 * @since 6.0.0 280 */ 281 do_action( 'bp_blocks_init' ); 282 } 283 270 284 /** 271 285 * Fire the 'bp_customize_register' action when the Customizer has loaded, 272 286 * allowing scripts and styles to be initialized. -
new file src/bp-core/classes/class-bp-block.php
diff --git src/bp-core/classes/class-bp-block.php src/bp-core/classes/class-bp-block.php new file mode 100644 index 000000000..3f75a3644
- + 1 <?php 2 /** 3 * BP Block class. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @since 6.0.0 8 */ 9 10 // Exit if accessed directly. 11 if ( ! defined( 'ABSPATH' ) ) { 12 exit; 13 } 14 15 /** 16 * BP Block Class. 17 * 18 * @since 6.0.0 19 */ 20 class BP_Block { 21 /** 22 * WP Block Type object. 23 * 24 * @since 6.0.0 25 * @var WP_Block_Type|WP_Error 26 */ 27 public $block; 28 29 /** 30 * The script types registered. 31 * 32 * @since 6.0.0 33 * @var array 34 */ 35 private $registered_scripts; 36 37 /** 38 * The style types registered. 39 * 40 * @since 6.0.0 41 * @var array 42 */ 43 private $registered_styles; 44 45 /** 46 * Construct the BuddyPress Block. 47 * 48 * @since 6.0.0 49 * 50 * @param array $args The registration arguments for the BP Block. 51 */ 52 public function __construct( $args ) { 53 if ( ! did_action( 'bp_blocks_init' ) ) { 54 _doing_it_wrong( __METHOD__, esc_html__( 'BP Blocks needs to be registered hooking `bp_blocks_init`', 'buddypress' ), '6.0.0' ); 55 } 56 57 $min = bp_core_get_minified_asset_suffix(); 58 $wp_args = array_intersect_key( 59 $args, 60 array( 61 'name' => '', 62 'render_callback' => '', 63 'attributes' => '', 64 'editor_script' => '', 65 'script' => '', 66 'editor_style' => '', 67 'style' => '', 68 ) 69 ); 70 71 if ( ! isset( $wp_args['name'] ) || ! $wp_args['name'] || ! isset( $wp_args['editor_script'] ) || ! $wp_args['editor_script'] ) { 72 $this->block = new WP_Error( 'missing_parameters', __( 'The `name` or `editor_script` required keys are missing.', 'buddypress' ) ); 73 } else { 74 // Get specific BP Blocks arguments. 75 $bp_args = array_intersect_key( 76 $args, 77 array( 78 'editor_script_url' => '', 79 'editor_script_deps' => array(), 80 'script_url' => '', 81 'script_deps' => array(), 82 'editor_style_url' => '', 83 'editor_style_deps' => array(), 84 'style_url' => '', 85 'style_deps' => array(), 86 ) 87 ); 88 89 // Register the scripts. 90 $version = bp_get_version(); 91 $this->registered_scripts = array(); 92 93 foreach ( array( 'editor_script', 'script' ) as $script_handle_key ) { 94 if ( ! isset( $wp_args[ $script_handle_key ] ) || ! $wp_args[ $script_handle_key ] ) { 95 continue; 96 } 97 98 if ( ! isset( $bp_args[ $script_handle_key . '_url' ] ) || ! $bp_args[ $script_handle_key . '_url' ] ) { 99 continue; 100 } 101 102 $deps = array(); 103 if ( isset( $bp_args[ $script_handle_key . '_deps' ] ) && is_array( $bp_args[ $script_handle_key . '_deps' ] ) ) { 104 $deps = $bp_args[ $script_handle_key . '_deps' ]; 105 } 106 107 $this->registered_scripts[ $script_handle_key ] = wp_register_script( 108 $wp_args[ $script_handle_key ], 109 $bp_args[ $script_handle_key . '_url' ], 110 $deps, 111 $version, 112 true 113 ); 114 } 115 116 if ( ! isset( $this->registered_scripts['editor_script'] ) || ! $this->registered_scripts['editor_script'] ) { 117 $this->block = new WP_Error( 'script_registration_error', __( 'The required `editor_script` could not be registered.', 'buddypress' ) ); 118 } else { 119 // Register the styles. 120 $registered_styles = array(); 121 122 foreach ( array( 'editor_style', 'style' ) as $style_handle_key ) { 123 if ( ! isset( $wp_args[ $style_handle_key ] ) || ! $wp_args[ $style_handle_key ] ) { 124 continue; 125 } 126 127 if ( ! isset( $bp_args[ $style_handle_key . '_url' ] ) || ! $bp_args[ $style_handle_key . '_url' ] ) { 128 continue; 129 } 130 131 if ( $min ) { 132 $minified_css = str_replace( '.css', $min . '.css', $bp_args[ $style_handle_key . '_url' ] ); 133 $css_file_path = str_replace( content_url(), WP_CONTENT_DIR, $minified_css ); 134 135 if ( file_exists( $css_file_path ) ) { 136 $bp_args[ $style_handle_key . '_url' ] = $minified_css; 137 } 138 } 139 140 $deps = array(); 141 if ( isset( $bp_args[ $style_handle_key . '_deps' ] ) && is_array( $bp_args[ $style_handle_key . '_deps' ] ) ) { 142 $deps = $bp_args[ $style_handle_key . '_deps' ]; 143 } 144 145 $this->registered_styles[ $style_handle_key ] = wp_register_style( 146 $wp_args[ $style_handle_key ], 147 $bp_args[ $style_handle_key . '_url' ], 148 $deps, 149 $version 150 ); 151 152 wp_style_add_data( $wp_args[ $style_handle_key ], 'rtl', 'replace' ); 153 if ( $min ) { 154 wp_style_add_data( $wp_args[ $style_handle_key ], 'suffix', $min ); 155 } 156 } 157 158 $name = $wp_args['name']; 159 unset( $wp_args['name'] ); 160 161 // Set the Block Type. 162 $this->block = new WP_Block_Type( $name, $wp_args ); 163 164 // Register the Block Type. 165 register_block_type( $this->block ); 166 167 // Load Block translations if found. 168 if ( $this->block->editor_script ) { 169 /** 170 * Filter here to use a custom directory to look for the JSON translation file into. 171 * 172 * @since 6.0.0 173 * 174 * @param string $value Absolute path to the directory to look for the JSON translation file into. 175 * @param string $editor_script The editor's script handle. 176 * @param string $name The block's name. 177 */ 178 $translation_dir = apply_filters( 'bp_block_translation_dir', null, $this->block->editor_script, $name ); 179 180 /** 181 * Filter here to use a custom domain for the JSON translation file. 182 * 183 * @since 6.0.0 184 * 185 * @param string $value The custom domain for the JSON translation file. 186 * @param string $editor_script The editor's script handle. 187 * @param string $name The block's name. 188 */ 189 $domain = apply_filters( 'bp_block_translation_dir', 'buddypress', $this->block->editor_script, $name ); 190 191 // Try to load the translation. 192 $translated = wp_set_script_translations( $this->block->editor_script, $domain, $translation_dir ); 193 } 194 } 195 } 196 } 197 } -
src/bp-core/classes/class-bp-component.php
diff --git src/bp-core/classes/class-bp-component.php src/bp-core/classes/class-bp-component.php index 6aaffc0a6..1e0d3478e 100644
class BP_Component { 466 466 add_action( 'bp_rest_api_init', array( $this, 'rest_api_init' ), 10 ); 467 467 } 468 468 469 // Register BP Blocks. 470 if ( bp_rest_api_is_available() ) { 471 add_action( 'bp_blocks_init', array( $this, 'blocks_init' ), 10 ); 472 } 473 469 474 /** 470 475 * Fires at the end of the setup_actions method inside BP_Component. 471 476 * … … class BP_Component { 906 911 */ 907 912 do_action( 'bp_' . $this->id . '_rest_api_init' ); 908 913 } 914 915 /** 916 * Register the BP Blocks. 917 * 918 * @since 6.0.0 919 * 920 * @param array $blocks The list of BP Blocks to register. 921 */ 922 public function blocks_init( $blocks = array() ) { 923 if ( is_array( $blocks ) && $blocks ) { 924 /** 925 * Filter here to disable all or some BP Blocks for a component. 926 * 927 * This is a dynamic hook that is based on the component string ID. 928 * 929 * @since 6.0.0 930 * 931 * @param array $blocks The list of BP Blocks for the component. 932 */ 933 $blocks = (array) apply_filters( 'bp_' . $this->id . '_register_blocks', $blocks ); 934 935 foreach ( $blocks as $block ) { 936 bp_register_block( $block ); 937 } 938 } 939 940 /** 941 * Fires in the blocks_init method inside BP_Component. 942 * 943 * This is a dynamic hook that is based on the component string ID. 944 * 945 * @since 6.0.0 946 */ 947 do_action( 'bp_' . $this->id . '_blocks_init' ); 948 } 909 949 } 910 950 endif; // BP_Component. -
new file src/bp-core/js/block-components.js
diff --git src/bp-core/js/block-components.js src/bp-core/js/block-components.js new file mode 100644 index 000000000..c27c7828b
- + 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 8 parcelRequire = (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 })({"IC7x":[function(require,module,exports) { 121 function _classCallCheck(instance, Constructor) { 122 if (!(instance instanceof Constructor)) { 123 throw new TypeError("Cannot call a class as a function"); 124 } 125 } 126 127 module.exports = _classCallCheck; 128 },{}],"WiqS":[function(require,module,exports) { 129 function _defineProperties(target, props) { 130 for (var i = 0; i < props.length; i++) { 131 var descriptor = props[i]; 132 descriptor.enumerable = descriptor.enumerable || false; 133 descriptor.configurable = true; 134 if ("value" in descriptor) descriptor.writable = true; 135 Object.defineProperty(target, descriptor.key, descriptor); 136 } 137 } 138 139 function _createClass(Constructor, protoProps, staticProps) { 140 if (protoProps) _defineProperties(Constructor.prototype, protoProps); 141 if (staticProps) _defineProperties(Constructor, staticProps); 142 return Constructor; 143 } 144 145 module.exports = _createClass; 146 },{}],"xOn8":[function(require,module,exports) { 147 function _typeof(obj) { 148 "@babel/helpers - typeof"; 149 150 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 151 module.exports = _typeof = function _typeof(obj) { 152 return typeof obj; 153 }; 154 } else { 155 module.exports = _typeof = function _typeof(obj) { 156 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 157 }; 158 } 159 160 return _typeof(obj); 161 } 162 163 module.exports = _typeof; 164 },{}],"NS7G":[function(require,module,exports) { 165 function _assertThisInitialized(self) { 166 if (self === void 0) { 167 throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 168 } 169 170 return self; 171 } 172 173 module.exports = _assertThisInitialized; 174 },{}],"oXYo":[function(require,module,exports) { 175 var _typeof = require("../helpers/typeof"); 176 177 var assertThisInitialized = require("./assertThisInitialized"); 178 179 function _possibleConstructorReturn(self, call) { 180 if (call && (_typeof(call) === "object" || typeof call === "function")) { 181 return call; 182 } 183 184 return assertThisInitialized(self); 185 } 186 187 module.exports = _possibleConstructorReturn; 188 },{"../helpers/typeof":"xOn8","./assertThisInitialized":"NS7G"}],"goD2":[function(require,module,exports) { 189 function _getPrototypeOf(o) { 190 module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 191 return o.__proto__ || Object.getPrototypeOf(o); 192 }; 193 return _getPrototypeOf(o); 194 } 195 196 module.exports = _getPrototypeOf; 197 },{}],"zqo5":[function(require,module,exports) { 198 function _setPrototypeOf(o, p) { 199 module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 200 o.__proto__ = p; 201 return o; 202 }; 203 204 return _setPrototypeOf(o, p); 205 } 206 207 module.exports = _setPrototypeOf; 208 },{}],"RISo":[function(require,module,exports) { 209 var setPrototypeOf = require("./setPrototypeOf"); 210 211 function _inherits(subClass, superClass) { 212 if (typeof superClass !== "function" && superClass !== null) { 213 throw new TypeError("Super expression must either be null or a function"); 214 } 215 216 subClass.prototype = Object.create(superClass && superClass.prototype, { 217 constructor: { 218 value: subClass, 219 writable: true, 220 configurable: true 221 } 222 }); 223 if (superClass) setPrototypeOf(subClass, superClass); 224 } 225 226 module.exports = _inherits; 227 },{"./setPrototypeOf":"zqo5"}],"W80x":[function(require,module,exports) { 228 "use strict"; 229 230 Object.defineProperty(exports, "__esModule", { 231 value: true 232 }); 233 exports.default = void 0; 234 235 var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); 236 237 var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); 238 239 var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); 240 241 var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); 242 243 var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); 244 245 var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); 246 247 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 248 249 /** 250 * WordPress dependencies. 251 */ 252 var _wp$element = wp.element, 253 Component = _wp$element.Component, 254 Fragment = _wp$element.Fragment, 255 createElement = _wp$element.createElement; 256 var Popover = wp.components.Popover; 257 var _wp = wp, 258 apiFetch = _wp.apiFetch; 259 var __ = wp.i18n.__; 260 261 var AutoCompleter = /*#__PURE__*/function (_Component) { 262 (0, _inherits2.default)(AutoCompleter, _Component); 263 264 function AutoCompleter() { 265 var _this; 266 267 (0, _classCallCheck2.default)(this, AutoCompleter); 268 _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(AutoCompleter).apply(this, arguments)); 269 _this.state = { 270 search: '', 271 items: [], 272 error: '' 273 }; 274 _this.searchItemName = _this.searchItemName.bind((0, _assertThisInitialized2.default)(_this)); 275 _this.selectItemName = _this.selectItemName.bind((0, _assertThisInitialized2.default)(_this)); 276 return _this; 277 } 278 279 (0, _createClass2.default)(AutoCompleter, [{ 280 key: "searchItemName", 281 value: function searchItemName(value) { 282 var _this2 = this; 283 284 var search = this.state.search; 285 var _this$props = this.props, 286 component = _this$props.component, 287 objectStatus = _this$props.objectStatus; 288 this.setState({ 289 search: value 290 }); 291 292 if (value.length < search.length) { 293 this.setState({ 294 items: [] 295 }); 296 } 297 298 var path = '/buddypress/v1/' + component; 299 300 if (value) { 301 path += '?search=' + encodeURIComponent(value); 302 } 303 304 if (objectStatus) { 305 path += '&status=' + objectStatus; 306 } 307 308 apiFetch({ 309 path: path 310 }).then(function (items) { 311 _this2.setState({ 312 items: items 313 }); 314 }, function (error) { 315 _this2.setState({ 316 error: error.message 317 }); 318 }); 319 } 320 }, { 321 key: "selectItemName", 322 value: function selectItemName(event, itemID) { 323 var onSelectItem = this.props.onSelectItem; 324 event.preventDefault(); 325 this.setState({ 326 search: '', 327 items: [], 328 error: '' 329 }); 330 return onSelectItem({ 331 itemID: itemID 332 }); 333 } 334 }, { 335 key: "render", 336 value: function render() { 337 var _this3 = this; 338 339 var _this$state = this.state, 340 search = _this$state.search, 341 items = _this$state.items; 342 var _this$props2 = this.props, 343 ariaLabel = _this$props2.ariaLabel, 344 placeholder = _this$props2.placeholder, 345 useAvatar = _this$props2.useAvatar; 346 var itemsList; 347 348 if (!ariaLabel) { 349 ariaLabel = __('Item\'s name', 'buddypress'); 350 } 351 352 if (!placeholder) { 353 placeholder = __('Enter Item\'s name here…', 'buddypress'); 354 } 355 356 if (items.length) { 357 itemsList = items.map(function (item) { 358 return createElement("button", { 359 type: "button", 360 key: 'editor-autocompleters__item-item-' + item.id, 361 role: "option", 362 "aria-selected": "true", 363 className: "components-button components-autocomplete__result editor-autocompleters__user", 364 onClick: function onClick(event) { 365 return _this3.selectItemName(event, item.id); 366 } 367 }, useAvatar && createElement("img", { 368 key: "avatar", 369 className: "editor-autocompleters__user-avatar", 370 alt: "", 371 src: item.avatar_urls.thumb 372 }), createElement("span", { 373 key: "name", 374 className: "editor-autocompleters__user-name" 375 }, item.name), item.mention_name && createElement("span", { 376 key: "slug", 377 className: "editor-autocompleters__user-slug" 378 }, item.mention_name)); 379 }); 380 } 381 382 return createElement(Fragment, null, createElement("input", { 383 type: "text", 384 value: search, 385 className: "components-placeholder__input", 386 "aria-label": ariaLabel, 387 placeholder: placeholder, 388 onChange: function onChange(event) { 389 return _this3.searchItemName(event.target.value); 390 } 391 }), 0 !== items.length && createElement(Popover, { 392 className: "components-autocomplete__popover", 393 focusOnMount: false, 394 position: "bottom left" 395 }, createElement("div", { 396 className: "components-autocomplete__results" 397 }, itemsList))); 398 } 399 }]); 400 return AutoCompleter; 401 }(Component); 402 403 var _default = AutoCompleter; 404 exports.default = _default; 405 },{"@babel/runtime/helpers/classCallCheck":"IC7x","@babel/runtime/helpers/createClass":"WiqS","@babel/runtime/helpers/possibleConstructorReturn":"oXYo","@babel/runtime/helpers/getPrototypeOf":"goD2","@babel/runtime/helpers/assertThisInitialized":"NS7G","@babel/runtime/helpers/inherits":"RISo"}],"iA92":[function(require,module,exports) { 406 "use strict"; 407 408 Object.defineProperty(exports, "__esModule", { 409 value: true 410 }); 411 exports.default = void 0; 412 413 var _autocompleter = _interopRequireDefault(require("./autocompleter")); 414 415 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 416 417 // Components 418 var _default = { 419 AutoCompleter: _autocompleter.default 420 }; 421 exports.default = _default; 422 },{"./autocompleter":"W80x"}],"Ee8M":[function(require,module,exports) { 423 "use strict"; 424 425 Object.defineProperty(exports, "__esModule", { 426 value: true 427 }); 428 Object.defineProperty(exports, "blockComponents", { 429 enumerable: true, 430 get: function () { 431 return _components.default; 432 } 433 }); 434 435 var _components = _interopRequireDefault(require("./components")); 436 437 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 438 },{"./components":"iA92"}]},{},["Ee8M"], "bp") 439 No newline at end of file -
new file src/bp-groups/bp-groups-blocks.php
diff --git src/bp-groups/bp-groups-blocks.php src/bp-groups/bp-groups-blocks.php new file mode 100644 index 000000000..cd9e41993
- + 1 <?php 2 /** 3 * BP Groups Blocks Functions. 4 * 5 * @package BuddyPress 6 * @subpackage GroupsBlocks 7 * @since 6.0.0 8 */ 9 10 // Exit if accessed directly. 11 if ( ! defined( 'ABSPATH' ) ) { 12 exit; 13 } 14 15 /** 16 * Add BP Groups blocks specific settings to the BP Blocks Editor ones. 17 * 18 * @since 6.0.0 19 * 20 * @param array $bp_editor_settings BP blocks editor settings. 21 * @return array BP Groups blocks editor settings. 22 */ 23 function bp_groups_editor_settings( $bp_editor_settings = array() ) { 24 $bp = buddypress(); 25 26 return array_merge( 27 $bp_editor_settings, 28 array( 29 'groups' => array( 30 'isAvatarEnabled' => $bp->avatar && $bp->avatar->show_avatars && ! bp_disable_group_avatar_uploads(), 31 'isCoverImageEnabled' => bp_is_active( 'groups', 'cover_image' ), 32 ), 33 ) 34 ); 35 } 36 add_filter( 'bp_blocks_editor_settings', 'bp_groups_editor_settings' ); 37 38 /** 39 * Callback function to render the BP Group Block. 40 * 41 * @since 6.0.0 42 * 43 * @param array $attributes The block attributes. 44 * @return string HTML output. 45 */ 46 function bp_groups_render_group_block( $attributes = array() ) { 47 $bp = buddypress(); 48 49 $block_args = wp_parse_args( 50 $attributes, 51 array( 52 'itemID' => 0, 53 'avatarSize' => 'full', 54 'displayDescription' => true, 55 'displayActionButton' => true, 56 'displayCoverImage' => true, 57 ) 58 ); 59 60 if ( ! $block_args['itemID'] ) { 61 return; 62 } 63 64 // Set the group ID and container classes. 65 $group_id = (int) $block_args['itemID']; 66 $container_classes = array( 'bp-block-group' ); 67 68 // Group object. 69 $group = groups_get_group( $group_id ); 70 71 if ( ! $group->id ) { 72 return; 73 } 74 75 // Avatar variables. 76 $avatar = ''; 77 $avatar_container = ''; 78 79 // Cover image variable. 80 $cover_image = ''; 81 $cover_style = ''; 82 $cover_container = ''; 83 84 // Group name/link/description variables. 85 $group_name = bp_get_group_name( $group ); 86 $group_link = bp_get_group_permalink( $group ); 87 $group_description = ''; 88 $group_content = ''; 89 90 // Group action button. 91 $action_button = ''; 92 $display_action_button = (bool) $block_args['displayActionButton']; 93 94 if ( $bp->avatar && $bp->avatar->show_avatars && ! bp_disable_group_avatar_uploads() && in_array( $block_args['avatarSize'], array( 'thumb', 'full' ), true ) ) { 95 $avatar = bp_core_fetch_avatar( 96 array( 97 'item_id' => $group->id, 98 'object' => 'group', 99 'type' => $block_args['avatarSize'], 100 'html' => false, 101 ) 102 ); 103 104 $container_classes[] = 'avatar-' . $block_args['avatarSize']; 105 } else { 106 $container_classes[] = 'avatar-none'; 107 } 108 109 if ( $avatar ) { 110 $avatar_container = sprintf( 111 '<div class="item-header-avatar"> 112 <a href="%1$s"> 113 <img src="%2$s" alt="%3$s" class="avatar"> 114 </a> 115 </div>', 116 esc_url( $group_link ), 117 esc_url( $avatar ), 118 // Translators: %s is the group's name. 119 sprintf( esc_html__( 'Group Profile photo of %s', 'buddypress' ), $group_name ) 120 ); 121 } 122 123 $display_cover_image = (bool) $block_args['displayCoverImage']; 124 if ( bp_is_active( 'groups', 'cover_image' ) && $display_cover_image ) { 125 $cover_image = bp_attachments_get_attachment( 126 'url', 127 array( 128 'item_id' => $group->id, 129 'object_dir' => 'groups', 130 ) 131 ); 132 133 if ( $cover_image ) { 134 $cover_style = sprintf( 135 ' style="background-image: url( %s );"', 136 esc_url( $cover_image ) 137 ); 138 } 139 140 $cover_container = sprintf( 141 '<div class="bp-group-cover-image"%s></div>', 142 $cover_style 143 ); 144 145 $container_classes[] = 'has-cover'; 146 } 147 148 $display_description = (bool) $block_args['displayDescription']; 149 if ( $display_description ) { 150 $group_description = bp_get_group_description( $group ); 151 $group_content = sprintf( 152 '<div class="group-description-content">%s</div>', 153 $group_description 154 ); 155 156 $container_classes[] = 'has-description'; 157 } 158 159 if ( $display_action_button ) { 160 $action_button = sprintf( 161 '<div class="bp-profile-button"> 162 <a href="%1$s" class="button large primary button-primary" role="button">%2$s</a> 163 </div>', 164 esc_url( $group_link ), 165 esc_html__( 'Visit Group', 'buddypress' ) 166 ); 167 } 168 169 $output = sprintf( 170 '<div class="%1$s"> 171 %2$s 172 <div class="group-content"> 173 %3$s 174 <div class="group-description"> 175 <strong><a href="%4$s">%5$s</a></strong> 176 %6$s 177 %7$s 178 </div> 179 </div> 180 </div>', 181 implode( ' ', array_map( 'sanitize_html_class', $container_classes ) ), 182 $cover_container, 183 $avatar_container, 184 esc_url( $group_link ), 185 esc_html( $group_name ), 186 $group_content, 187 $action_button 188 ); 189 190 // Compact all interesting parameters. 191 $params = array_merge( $block_args, compact( 'group_name', 'group_link', 'group_description', 'avatar', 'cover_image' ) ); 192 193 /** 194 * Filter here to edit the output of the single group block. 195 * 196 * @since 6.0.0 197 * 198 * @param string $output The HTML output of the block. 199 * @param BP_Groups_Group $group The group object. 200 * @param array $params The block extended parameters. 201 */ 202 return apply_filters( 'bp_groups_render_group_block_output', $output, $group, $params ); 203 } -
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 b53835ea0..2f07fceae 100644
class BP_Groups_Component extends BP_Component { 130 130 'functions', 131 131 'notifications', 132 132 'cssjs', 133 'blocks', 133 134 ); 134 135 135 136 // Conditional includes. … … class BP_Groups_Component extends BP_Component { 940 941 'BP_REST_Attachments_Group_Avatar_Endpoint', 941 942 ) ); 942 943 } 944 945 /** 946 * Register the BP Groups Blocks. 947 * 948 * @since 6.0.0 949 * 950 * @param array $blocks Optional. See BP_Component::blocks_init() for 951 * description. 952 */ 953 public function blocks_init( $blocks = array() ) { 954 parent::blocks_init( 955 array( 956 'bp/group' => array( 957 'name' => 'bp/group', 958 'editor_script' => 'bp-group-block', 959 'editor_script_url' => plugins_url( 'js/blocks/group.js', dirname( __FILE__ ) ), 960 'editor_script_deps' => array( 961 'wp-blocks', 962 'wp-element', 963 'wp-components', 964 'wp-i18n', 965 'wp-editor', 966 'wp-compose', 967 'wp-data', 968 'wp-block-editor', 969 'bp-block-components', 970 ), 971 'style' => 'bp-group-block', 972 'style_url' => plugins_url( 'css/blocks/group.css', dirname( __FILE__ ) ), 973 'render_callback' => 'bp_groups_render_group_block', 974 'attributes' => array( 975 'itemID' => array( 976 'type' => 'integer', 977 'default' => 0, 978 ), 979 'avatarSize' => array( 980 'type' => 'string', 981 'default' => 'full', 982 ), 983 'displayDescription' => array( 984 'type' => 'boolean', 985 'default' => true, 986 ), 987 'displayActionButton' => array( 988 'type' => 'boolean', 989 'default' => true, 990 ), 991 'displayCoverImage' => array( 992 'type' => 'boolean', 993 'default' => true, 994 ), 995 ), 996 ), 997 ) 998 ); 999 } 943 1000 } -
new file src/bp-groups/css/blocks/group-rtl.css
diff --git src/bp-groups/css/blocks/group-rtl.css src/bp-groups/css/blocks/group-rtl.css new file mode 100644 index 000000000..dce932ac8
- + 1 /* CSS for the bp/group block */ 2 .bp-block-group { 3 position: relative; 4 } 5 6 .bp-block-group .group-content { 7 display: flex; 8 } 9 10 .bp-block-group.has-cover .group-content, 11 .bp-block-group.has-cover .item-header-avatar, 12 .bp-block-group.has-cover .group-description { 13 z-index: 2; 14 } 15 16 .bp-block-group .group-description { 17 width: 100%; 18 } 19 20 .bp-block-group.has-cover .group-description { 21 padding-top: 75px; 22 } 23 24 .bp-block-group.avatar-full .group-description { 25 padding-right: 35px; 26 } 27 28 .bp-block-group.has-cover .bp-group-cover-image { 29 background-color: #c5c5c5; 30 background-position: center top; 31 background-repeat: no-repeat; 32 background-size: cover; 33 border: 0; 34 display: block; 35 right: 0; 36 margin: 0; 37 padding: 0; 38 position: absolute; 39 top: 0; 40 width: 100%; 41 z-index: 1; 42 height: 150px; 43 } 44 45 .bp-block-group img.avatar { 46 width: auto; 47 height: auto; 48 } 49 50 .bp-block-group.avatar-none .item-header-avatar { 51 display: none; 52 } 53 54 .bp-block-group.avatar-none.has-cover { 55 min-height: 200px; 56 } 57 58 .bp-block-group.avatar-full { 59 min-height: 150px; 60 } 61 62 .bp-block-group.avatar-full.has-cover { 63 min-height: 300px; 64 } 65 66 .bp-block-group.avatar-full .item-header-avatar { 67 width: 180px; 68 } 69 70 .bp-block-group.has-cover.avatar-full .item-header-avatar { 71 width: 200px; 72 } 73 74 .bp-block-group.has-cover.avatar-full img.avatar { 75 border: solid 2px #fff; 76 background: rgba(255, 255, 255, 0.8); 77 margin-right: 20px; 78 } 79 80 .bp-block-group.has-cover .group-content { 81 padding-top: 75px; 82 } 83 84 .bp-block-group.avatar-thumb .item-header-avatar img.avatar { 85 margin-top: 15px; 86 } 87 88 .bp-block-group.avatar-thumb:not(.has-description) .group-content { 89 min-height: 50px; 90 align-items: center; 91 } 92 93 .bp-block-group .group-description-content { 94 width: 100%; 95 margin-bottom: 18px; 96 } 97 98 .bp-block-group.avatar-thumb .item-header-avatar { 99 width: 70px; 100 } 101 102 .bp-block-group.avatar-thumb.has-cover .item-header-avatar { 103 padding-top: 75px; 104 } 105 106 .bp-block-group .bp-profile-button { 107 width: 100%; 108 overflow: hidden; 109 } 110 111 .bp-block-group .bp-profile-button a.button { 112 margin: 18px 0 0; 113 } 114 115 .bp-block-group.has-description .bp-profile-button a.button { 116 display: block; 117 float: left; 118 } -
new file src/bp-groups/css/blocks/group.css
diff --git src/bp-groups/css/blocks/group.css src/bp-groups/css/blocks/group.css new file mode 100644 index 000000000..502b70b69
- + 1 /* CSS for the bp/group block */ 2 .bp-block-group { 3 position: relative; 4 } 5 6 .bp-block-group .group-content { 7 display: flex; 8 } 9 10 .bp-block-group.has-cover .group-content, 11 .bp-block-group.has-cover .item-header-avatar, 12 .bp-block-group.has-cover .group-description { 13 z-index: 2; 14 } 15 16 .bp-block-group .group-description { 17 width: 100%; 18 } 19 20 .bp-block-group.has-cover .group-description { 21 padding-top: 75px; 22 } 23 24 .bp-block-group.avatar-full .group-description { 25 padding-left: 35px; 26 } 27 28 .bp-block-group.has-cover .bp-group-cover-image { 29 background-color: #c5c5c5; 30 background-position: center top; 31 background-repeat: no-repeat; 32 background-size: cover; 33 border: 0; 34 display: block; 35 left: 0; 36 margin: 0; 37 padding: 0; 38 position: absolute; 39 top: 0; 40 width: 100%; 41 z-index: 1; 42 height: 150px; 43 } 44 45 .bp-block-group img.avatar { 46 width: auto; 47 height: auto; 48 } 49 50 .bp-block-group.avatar-none .item-header-avatar { 51 display: none; 52 } 53 54 .bp-block-group.avatar-none.has-cover { 55 min-height: 200px; 56 } 57 58 .bp-block-group.avatar-full { 59 min-height: 150px; 60 } 61 62 .bp-block-group.avatar-full.has-cover { 63 min-height: 300px; 64 } 65 66 .bp-block-group.avatar-full .item-header-avatar { 67 width: 180px; 68 } 69 70 .bp-block-group.has-cover.avatar-full .item-header-avatar { 71 width: 200px; 72 } 73 74 .bp-block-group.has-cover.avatar-full img.avatar { 75 border: solid 2px #fff; 76 background: rgba(255, 255, 255, 0.8); 77 margin-left: 20px; 78 } 79 80 .bp-block-group.has-cover .group-content { 81 padding-top: 75px; 82 } 83 84 .bp-block-group.avatar-thumb .item-header-avatar img.avatar { 85 margin-top: 15px; 86 } 87 88 .bp-block-group.avatar-thumb:not(.has-description) .group-content { 89 min-height: 50px; 90 align-items: center; 91 } 92 93 .bp-block-group .group-description-content { 94 width: 100%; 95 margin-bottom: 18px; 96 } 97 98 .bp-block-group.avatar-thumb .item-header-avatar { 99 width: 70px; 100 } 101 102 .bp-block-group.avatar-thumb.has-cover .item-header-avatar { 103 padding-top: 75px; 104 } 105 106 .bp-block-group .bp-profile-button { 107 width: 100%; 108 overflow: hidden; 109 } 110 111 .bp-block-group .bp-profile-button a.button { 112 margin: 18px 0 0; 113 } 114 115 .bp-block-group.has-description .bp-profile-button a.button { 116 display: block; 117 float: right; 118 } -
new file src/bp-groups/js/blocks/group.js
diff --git src/bp-groups/js/blocks/group.js src/bp-groups/js/blocks/group.js new file mode 100644 index 000000000..c10b7e6bd
- + 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 8 parcelRequire = (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 })({"pvse":[function(require,module,exports) { 121 /** 122 * WordPress dependencies. 123 */ 124 var registerBlockType = wp.blocks.registerBlockType; 125 var _wp$element = wp.element, 126 createElement = _wp$element.createElement, 127 Fragment = _wp$element.Fragment; 128 var _wp$components = wp.components, 129 Placeholder = _wp$components.Placeholder, 130 Disabled = _wp$components.Disabled, 131 PanelBody = _wp$components.PanelBody, 132 SelectControl = _wp$components.SelectControl, 133 ToggleControl = _wp$components.ToggleControl, 134 Toolbar = _wp$components.Toolbar, 135 ToolbarButton = _wp$components.ToolbarButton; 136 var _wp$blockEditor = wp.blockEditor, 137 InspectorControls = _wp$blockEditor.InspectorControls, 138 BlockControls = _wp$blockEditor.BlockControls; 139 var withSelect = wp.data.withSelect; 140 var compose = wp.compose.compose; 141 var ServerSideRender = wp.editor.ServerSideRender; 142 var __ = wp.i18n.__; 143 /** 144 * BuddyPress dependencies. 145 */ 146 147 var AutoCompleter = bp.blockComponents.AutoCompleter; 148 var AVATAR_SIZES = [{ 149 label: __('None', 'buddypress'), 150 value: 'none' 151 }, { 152 label: __('Thumb', 'buddypress'), 153 value: 'thumb' 154 }, { 155 label: __('Full', 'buddypress'), 156 value: 'full' 157 }]; 158 159 var editGroup = function editGroup(_ref) { 160 var attributes = _ref.attributes, 161 setAttributes = _ref.setAttributes, 162 bpSettings = _ref.bpSettings; 163 var isAvatarEnabled = bpSettings.isAvatarEnabled, 164 isCoverImageEnabled = bpSettings.isCoverImageEnabled; 165 var avatarSize = attributes.avatarSize, 166 displayDescription = attributes.displayDescription, 167 displayActionButton = attributes.displayActionButton, 168 displayCoverImage = attributes.displayCoverImage; 169 170 if (!attributes.itemID) { 171 return createElement(Placeholder, { 172 icon: "buddicons-groups", 173 label: __('BuddyPress Group', 'buddypress'), 174 instructions: __('Start typing the name of the group you want to feature into this post.', 'buddypress') 175 }, createElement(AutoCompleter, { 176 component: "groups", 177 objectStatus: "public", 178 ariaLabel: __('Group\'s name', 'buddypress'), 179 placeholder: __('Enter Group\'s name here…', 'buddypress'), 180 onSelectItem: setAttributes, 181 useAvatar: isAvatarEnabled 182 })); 183 } 184 185 return createElement(Fragment, null, createElement(BlockControls, null, createElement(Toolbar, null, createElement(ToolbarButton, { 186 icon: "edit", 187 title: __('Select another group', 'buddypress'), 188 onClick: function onClick() { 189 setAttributes({ 190 itemID: 0 191 }); 192 } 193 }))), createElement(InspectorControls, null, createElement(PanelBody, { 194 title: __('Group\'s home button settings', 'buddypress'), 195 initialOpen: true 196 }, createElement(ToggleControl, { 197 label: __('Display Group\'s home button', 'buddypress'), 198 checked: !!displayActionButton, 199 onChange: function onChange() { 200 setAttributes({ 201 displayActionButton: !displayActionButton 202 }); 203 }, 204 help: displayActionButton ? __('Include a link to the group\'s home page under their name.', 'buddypress') : __('Toggle to display a link to the group\'s home page under their name.', 'buddypress') 205 })), createElement(PanelBody, { 206 title: __('Description settings', 'buddypress'), 207 initialOpen: false 208 }, createElement(ToggleControl, { 209 label: __('Display group\'s description', 'buddypress'), 210 checked: !!displayDescription, 211 onChange: function onChange() { 212 setAttributes({ 213 displayDescription: !displayDescription 214 }); 215 }, 216 help: displayDescription ? __('Include the group\'s description under their name.', 'buddypress') : __('Toggle to display the group\'s description under their name.', 'buddypress') 217 })), isAvatarEnabled && createElement(PanelBody, { 218 title: __('Avatar settings', 'buddypress'), 219 initialOpen: false 220 }, createElement(SelectControl, { 221 label: __('Size', 'buddypress'), 222 value: avatarSize, 223 options: AVATAR_SIZES, 224 onChange: function onChange(option) { 225 setAttributes({ 226 avatarSize: option 227 }); 228 } 229 })), isCoverImageEnabled && createElement(PanelBody, { 230 title: __('Cover image settings', 'buddypress'), 231 initialOpen: false 232 }, createElement(ToggleControl, { 233 label: __('Display Cover Image', 'buddypress'), 234 checked: !!displayCoverImage, 235 onChange: function onChange() { 236 setAttributes({ 237 displayCoverImage: !displayCoverImage 238 }); 239 }, 240 help: displayCoverImage ? __('Include the group\'s cover image over their name.', 'buddypress') : __('Toggle to display the group\'s cover image over their name.', 'buddypress') 241 }))), createElement(Disabled, null, createElement(ServerSideRender, { 242 block: "bp/group", 243 attributes: attributes 244 }))); 245 }; 246 247 var editGroupBlock = compose([withSelect(function (select) { 248 var editorSettings = select('core/editor').getEditorSettings(); 249 return { 250 bpSettings: editorSettings.bp.groups || {} 251 }; 252 })])(editGroup); 253 registerBlockType('bp/group', { 254 title: __('Group', 'buddypress'), 255 description: __('BuddyPress Group.', 'buddypress'), 256 icon: 'buddicons-groups', 257 category: 'buddypress', 258 attributes: { 259 itemID: { 260 type: 'integer', 261 default: 0 262 }, 263 avatarSize: { 264 type: 'string', 265 default: 'full' 266 }, 267 displayDescription: { 268 type: 'boolean', 269 default: true 270 }, 271 displayActionButton: { 272 type: 'boolean', 273 default: true 274 }, 275 displayCoverImage: { 276 type: 'boolean', 277 default: true 278 } 279 }, 280 edit: editGroupBlock 281 }); 282 },{}]},{},["pvse"], null) 283 No newline at end of file -
new file src/bp-members/bp-members-blocks.php
diff --git src/bp-members/bp-members-blocks.php src/bp-members/bp-members-blocks.php new file mode 100644 index 000000000..8835625ef
- + 1 <?php 2 /** 3 * BP Members Blocks Functions. 4 * 5 * @package BuddyPress 6 * @subpackage MembersBlocks 7 * @since 6.0.0 8 */ 9 10 // Exit if accessed directly. 11 if ( ! defined( 'ABSPATH' ) ) { 12 exit; 13 } 14 15 /** 16 * Add BP Members blocks specific settings to the BP Blocks Editor ones. 17 * 18 * @since 6.0.0 19 * 20 * @param array $bp_editor_settings BP blocks editor settings. 21 * @return array BP Members blocks editor settings. 22 */ 23 function bp_members_editor_settings( $bp_editor_settings = array() ) { 24 $bp = buddypress(); 25 26 return array_merge( 27 $bp_editor_settings, 28 array( 29 'members' => array( 30 'isMentionEnabled' => bp_is_active( 'activity' ) && bp_activity_do_mentions(), 31 'isAvatarEnabled' => $bp->avatar && $bp->avatar->show_avatars, 32 'isCoverImageEnabled' => bp_is_active( 'members', 'cover_image' ), 33 ), 34 ) 35 ); 36 } 37 add_filter( 'bp_blocks_editor_settings', 'bp_members_editor_settings' ); 38 39 /** 40 * Callback function to render the BP Member Block. 41 * 42 * @since 6.0.0 43 * 44 * @param array $attributes The block attributes. 45 * @return string HTML output. 46 */ 47 function bp_members_render_member_block( $attributes = array() ) { 48 $bp = buddypress(); 49 50 $block_args = wp_parse_args( 51 $attributes, 52 array( 53 'itemID' => 0, 54 'avatarSize' => 'full', 55 'displayMentionSlug' => true, 56 'displayActionButton' => true, 57 'displayCoverImage' => true, 58 ) 59 ); 60 61 if ( ! $block_args['itemID'] ) { 62 return; 63 } 64 65 // Set the member ID and container classes. 66 $member_id = (int) $block_args['itemID']; 67 $container_classes = array( 'bp-block-member' ); 68 69 // Mention variables. 70 $username = bp_core_get_username( $member_id ); 71 $at_mention = ''; 72 73 // Avatar variables. 74 $avatar = ''; 75 $avatar_container = ''; 76 77 // Cover image variable. 78 $cover_image = ''; 79 $cover_style = ''; 80 $cover_container = ''; 81 82 // Member name variables. 83 $display_name = bp_core_get_user_displayname( $member_id ); 84 $member_link = bp_core_get_user_domain( $member_id ); 85 86 // Member action button. 87 $action_button = ''; 88 $display_action_button = (bool) $block_args['displayActionButton']; 89 90 if ( $bp->avatar && $bp->avatar->show_avatars && in_array( $block_args['avatarSize'], array( 'thumb', 'full' ), true ) ) { 91 $avatar = bp_core_fetch_avatar( 92 array( 93 'item_id' => $member_id, 94 'object' => 'user', 95 'type' => $block_args['avatarSize'], 96 'html' => false, 97 ) 98 ); 99 100 $container_classes[] = 'avatar-' . $block_args['avatarSize']; 101 } else { 102 $container_classes[] = 'avatar-none'; 103 } 104 105 if ( $avatar ) { 106 $avatar_container = sprintf( 107 '<div class="item-header-avatar"> 108 <a href="%1$s"> 109 <img src="%2$s" alt="%3$s" class="avatar"> 110 </a> 111 </div>', 112 esc_url( $member_link ), 113 esc_url( $avatar ), 114 // Translators: %s is the member's display name. 115 sprintf( esc_html__( 'Profile photo of %s', 'buddypress' ), $display_name ) 116 ); 117 } 118 119 $display_cover_image = (bool) $block_args['displayCoverImage']; 120 if ( bp_is_active( 'members', 'cover_image' ) && $display_cover_image ) { 121 $cover_image = bp_attachments_get_attachment( 122 'url', 123 array( 124 'item_id' => $member_id, 125 ) 126 ); 127 128 if ( $cover_image ) { 129 $cover_style = sprintf( 130 ' style="background-image: url( %s );"', 131 esc_url( $cover_image ) 132 ); 133 } 134 135 $cover_container = sprintf( 136 '<div class="bp-member-cover-image"%s></div>', 137 $cover_style 138 ); 139 140 $container_classes[] = 'has-cover'; 141 } 142 143 $display_mention_slug = (bool) $block_args['displayMentionSlug']; 144 if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() && $display_mention_slug ) { 145 $at_mention = sprintf( 146 '<span class="user-nicename">@%s</span>', 147 esc_html( $username ) 148 ); 149 } 150 151 if ( $display_action_button ) { 152 $action_button = sprintf( 153 '<div class="bp-profile-button"> 154 <a href="%1$s" class="button large primary button-primary" role="button">%2$s</a> 155 </div>', 156 esc_url( $member_link ), 157 esc_html__( 'View Profile', 'buddypress' ) 158 ); 159 } 160 161 $output = sprintf( 162 '<div class="%1$s"> 163 %2$s 164 <div class="member-content"> 165 %3$s 166 <div class="member-description"> 167 <strong><a href="%4$s">%5$s</a></strong> 168 %6$s 169 %7$s 170 </div> 171 </div> 172 </div>', 173 implode( ' ', array_map( 'sanitize_html_class', $container_classes ) ), 174 $cover_container, 175 $avatar_container, 176 esc_url( $member_link ), 177 esc_html( $display_name ), 178 $at_mention, 179 $action_button 180 ); 181 182 // Compact all interesting parameters. 183 $params = array_merge( $block_args, compact( 'username', 'display_name', 'member_link', 'avatar', 'cover_image' ) ); 184 185 /** 186 * Filter here to edit the output of the single member block. 187 * 188 * @since 6.0.0 189 * 190 * @param string $output The HTML output of the block. 191 * @param array $params The block extended parameters. 192 */ 193 return apply_filters( 'bp_members_render_member_block_output', $output, $params ); 194 } -
src/bp-members/classes/class-bp-members-component.php
diff --git src/bp-members/classes/class-bp-members-component.php src/bp-members/classes/class-bp-members-component.php index 29576b52f..25818244e 100644
class BP_Members_Component extends BP_Component { 61 61 'template', 62 62 'adminbar', 63 63 'functions', 64 'blocks', 64 65 'widgets', 65 66 'cache', 66 67 ); … … class BP_Members_Component extends BP_Component { 668 669 'BP_REST_Attachments_Member_Avatar_Endpoint', 669 670 ) ); 670 671 } 672 673 /** 674 * Register the BP Members Blocks. 675 * 676 * @since 6.0.0 677 * 678 * @param array $blocks Optional. See BP_Component::blocks_init() for 679 * description. 680 */ 681 public function blocks_init( $blocks = array() ) { 682 parent::blocks_init( 683 array( 684 'bp/member' => array( 685 'name' => 'bp/member', 686 'editor_script' => 'bp-member-block', 687 'editor_script_url' => plugins_url( 'js/blocks/member.js', dirname( __FILE__ ) ), 688 'editor_script_deps' => array( 689 'wp-blocks', 690 'wp-element', 691 'wp-components', 692 'wp-i18n', 693 'wp-editor', 694 'wp-compose', 695 'wp-data', 696 'wp-block-editor', 697 'bp-block-components', 698 ), 699 'style' => 'bp-member-block', 700 'style_url' => plugins_url( 'css/blocks/member.css', dirname( __FILE__ ) ), 701 'render_callback' => 'bp_members_render_member_block', 702 'attributes' => array( 703 'itemID' => array( 704 'type' => 'integer', 705 'default' => 0, 706 ), 707 'avatarSize' => array( 708 'type' => 'string', 709 'default' => 'full', 710 ), 711 'displayMentionSlug' => array( 712 'type' => 'boolean', 713 'default' => true, 714 ), 715 'displayActionButton' => array( 716 'type' => 'boolean', 717 'default' => true, 718 ), 719 'displayCoverImage' => array( 720 'type' => 'boolean', 721 'default' => true, 722 ), 723 ), 724 ), 725 ) 726 ); 727 } 671 728 } -
new file src/bp-members/css/blocks/member-rtl.css
diff --git src/bp-members/css/blocks/member-rtl.css src/bp-members/css/blocks/member-rtl.css new file mode 100644 index 000000000..ff9de024c
- + 1 /* CSS for the bp/member block */ 2 .bp-block-member { 3 position: relative; 4 } 5 6 .bp-block-member .member-content { 7 display: flex; 8 } 9 10 .bp-block-member.has-cover .member-content, 11 .bp-block-member.has-cover .item-header-avatar, 12 .bp-block-member.has-cover .member-description { 13 z-index: 2; 14 } 15 16 .bp-block-member.has-cover .member-description { 17 padding-top: 75px; 18 } 19 20 .bp-block-member.has-cover .bp-member-cover-image { 21 background-color: #c5c5c5; 22 background-position: center top; 23 background-repeat: no-repeat; 24 background-size: cover; 25 border: 0; 26 display: block; 27 right: 0; 28 margin: 0; 29 padding: 0; 30 position: absolute; 31 top: 0; 32 width: 100%; 33 z-index: 1; 34 height: 150px; 35 } 36 37 .bp-block-member img.avatar { 38 width: auto; 39 height: auto; 40 } 41 42 .bp-block-member.avatar-none .item-header-avatar { 43 display: none; 44 } 45 46 .bp-block-member.avatar-none.has-cover { 47 min-height: 200px; 48 } 49 50 .bp-block-member.avatar-full { 51 min-height: 150px; 52 } 53 54 .bp-block-member.avatar-full.has-cover { 55 min-height: 300px; 56 } 57 58 .bp-block-member.avatar-full .item-header-avatar { 59 width: 180px; 60 } 61 62 .bp-block-member.has-cover.avatar-full .item-header-avatar { 63 width: 200px; 64 } 65 66 .bp-block-member.has-cover.avatar-full img.avatar { 67 border: solid 2px #fff; 68 background: rgba(255, 255, 255, 0.8); 69 margin-right: 20px; 70 } 71 72 .bp-block-member.has-cover .member-content { 73 padding-top: 75px; 74 } 75 76 .bp-block-member.avatar-thumb .member-content { 77 min-height: 50px; 78 align-items: center; 79 } 80 81 .bp-block-member.avatar-thumb .item-header-avatar { 82 width: 70px; 83 } 84 85 .bp-block-member.avatar-thumb.has-cover .item-header-avatar { 86 padding-top: 75px; 87 } 88 89 .bp-block-member .user-nicename { 90 display: block; 91 } 92 93 .bp-block-member .user-nicename a, 94 .entry .entry-content .bp-block-member .user-nicename a { 95 color: currentColor; 96 text-decoration: none; 97 border: none; 98 } 99 100 .bp-block-member .bp-profile-button { 101 width: 100%; 102 } 103 104 .bp-block-member .bp-profile-button a.button { 105 position: absolute; 106 bottom: 10px; 107 left: 0; 108 display: inline-block; 109 margin: 18px 0 0; 110 } -
new file src/bp-members/css/blocks/member.css
diff --git src/bp-members/css/blocks/member.css src/bp-members/css/blocks/member.css new file mode 100644 index 000000000..b03ea8687
- + 1 /* CSS for the bp/member block */ 2 .bp-block-member { 3 position: relative; 4 } 5 6 .bp-block-member .member-content { 7 display: flex; 8 } 9 10 .bp-block-member.has-cover .member-content, 11 .bp-block-member.has-cover .item-header-avatar, 12 .bp-block-member.has-cover .member-description { 13 z-index: 2; 14 } 15 16 .bp-block-member.has-cover .member-description { 17 padding-top: 75px; 18 } 19 20 .bp-block-member.has-cover .bp-member-cover-image { 21 background-color: #c5c5c5; 22 background-position: center top; 23 background-repeat: no-repeat; 24 background-size: cover; 25 border: 0; 26 display: block; 27 left: 0; 28 margin: 0; 29 padding: 0; 30 position: absolute; 31 top: 0; 32 width: 100%; 33 z-index: 1; 34 height: 150px; 35 } 36 37 .bp-block-member img.avatar { 38 width: auto; 39 height: auto; 40 } 41 42 .bp-block-member.avatar-none .item-header-avatar { 43 display: none; 44 } 45 46 .bp-block-member.avatar-none.has-cover { 47 min-height: 200px; 48 } 49 50 .bp-block-member.avatar-full { 51 min-height: 150px; 52 } 53 54 .bp-block-member.avatar-full.has-cover { 55 min-height: 300px; 56 } 57 58 .bp-block-member.avatar-full .item-header-avatar { 59 width: 180px; 60 } 61 62 .bp-block-member.has-cover.avatar-full .item-header-avatar { 63 width: 200px; 64 } 65 66 .bp-block-member.has-cover.avatar-full img.avatar { 67 border: solid 2px #fff; 68 background: rgba(255, 255, 255, 0.8); 69 margin-left: 20px; 70 } 71 72 .bp-block-member.has-cover .member-content { 73 padding-top: 75px; 74 } 75 76 .bp-block-member.avatar-thumb .member-content { 77 min-height: 50px; 78 align-items: center; 79 } 80 81 .bp-block-member.avatar-thumb .item-header-avatar { 82 width: 70px; 83 } 84 85 .bp-block-member.avatar-thumb.has-cover .item-header-avatar { 86 padding-top: 75px; 87 } 88 89 .bp-block-member .user-nicename { 90 display: block; 91 } 92 93 .bp-block-member .user-nicename a, 94 .entry .entry-content .bp-block-member .user-nicename a { 95 color: currentColor; 96 text-decoration: none; 97 border: none; 98 } 99 100 .bp-block-member .bp-profile-button { 101 width: 100%; 102 } 103 104 .bp-block-member .bp-profile-button a.button { 105 position: absolute; 106 bottom: 10px; 107 right: 0; 108 display: inline-block; 109 margin: 18px 0 0; 110 } -
new file src/bp-members/js/blocks/member.js
diff --git src/bp-members/js/blocks/member.js src/bp-members/js/blocks/member.js new file mode 100644 index 000000000..4e7f56941
- + 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 8 parcelRequire = (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 })({"TmUL":[function(require,module,exports) { 121 /** 122 * WordPress dependencies. 123 */ 124 var registerBlockType = wp.blocks.registerBlockType; 125 var _wp$element = wp.element, 126 createElement = _wp$element.createElement, 127 Fragment = _wp$element.Fragment; 128 var _wp$components = wp.components, 129 Placeholder = _wp$components.Placeholder, 130 Disabled = _wp$components.Disabled, 131 PanelBody = _wp$components.PanelBody, 132 SelectControl = _wp$components.SelectControl, 133 ToggleControl = _wp$components.ToggleControl, 134 Toolbar = _wp$components.Toolbar, 135 ToolbarButton = _wp$components.ToolbarButton; 136 var _wp$blockEditor = wp.blockEditor, 137 InspectorControls = _wp$blockEditor.InspectorControls, 138 BlockControls = _wp$blockEditor.BlockControls; 139 var withSelect = wp.data.withSelect; 140 var compose = wp.compose.compose; 141 var ServerSideRender = wp.editor.ServerSideRender; 142 var __ = wp.i18n.__; 143 /** 144 * BuddyPress dependencies. 145 */ 146 147 var AutoCompleter = bp.blockComponents.AutoCompleter; 148 var AVATAR_SIZES = [{ 149 label: __('None', 'buddypress'), 150 value: 'none' 151 }, { 152 label: __('Thumb', 'buddypress'), 153 value: 'thumb' 154 }, { 155 label: __('Full', 'buddypress'), 156 value: 'full' 157 }]; 158 159 var editMember = function editMember(_ref) { 160 var attributes = _ref.attributes, 161 setAttributes = _ref.setAttributes, 162 bpSettings = _ref.bpSettings; 163 var isAvatarEnabled = bpSettings.isAvatarEnabled, 164 isMentionEnabled = bpSettings.isMentionEnabled, 165 isCoverImageEnabled = bpSettings.isCoverImageEnabled; 166 var avatarSize = attributes.avatarSize, 167 displayMentionSlug = attributes.displayMentionSlug, 168 displayActionButton = attributes.displayActionButton, 169 displayCoverImage = attributes.displayCoverImage; 170 171 if (!attributes.itemID) { 172 return createElement(Placeholder, { 173 icon: "admin-users", 174 label: __('BuddyPress Member', 'buddypress'), 175 instructions: __('Start typing the name of the member you want to feature into this post.', 'buddypress') 176 }, createElement(AutoCompleter, { 177 component: "members", 178 ariaLabel: __('Member\'s username', 'buddypress'), 179 placeholder: __('Enter Member\'s username here…', 'buddypress'), 180 onSelectItem: setAttributes, 181 useAvatar: isAvatarEnabled 182 })); 183 } 184 185 return createElement(Fragment, null, createElement(BlockControls, null, createElement(Toolbar, null, createElement(ToolbarButton, { 186 icon: "edit", 187 title: __('Select another member', 'buddypress'), 188 onClick: function onClick() { 189 setAttributes({ 190 itemID: 0 191 }); 192 } 193 }))), createElement(InspectorControls, null, createElement(PanelBody, { 194 title: __('Profile button settings', 'buddypress'), 195 initialOpen: true 196 }, createElement(ToggleControl, { 197 label: __('Display Profile button', 'buddypress'), 198 checked: !!displayActionButton, 199 onChange: function onChange() { 200 setAttributes({ 201 displayActionButton: !displayActionButton 202 }); 203 }, 204 help: displayActionButton ? __('Include a link to the user\'s profile page under their display name.', 'buddypress') : __('Toggle to display a link to the user\'s profile page under their display name.', 'buddypress') 205 })), isAvatarEnabled && createElement(PanelBody, { 206 title: __('Avatar settings', 'buddypress'), 207 initialOpen: false 208 }, createElement(SelectControl, { 209 label: __('Size', 'buddypress'), 210 value: avatarSize, 211 options: AVATAR_SIZES, 212 onChange: function onChange(option) { 213 setAttributes({ 214 avatarSize: option 215 }); 216 } 217 })), isCoverImageEnabled && createElement(PanelBody, { 218 title: __('Cover image settings', 'buddypress'), 219 initialOpen: false 220 }, createElement(ToggleControl, { 221 label: __('Display Cover Image', 'buddypress'), 222 checked: !!displayCoverImage, 223 onChange: function onChange() { 224 setAttributes({ 225 displayCoverImage: !displayCoverImage 226 }); 227 }, 228 help: displayCoverImage ? __('Include the user\'s cover image over their display name.', 'buddypress') : __('Toggle to display the user\'s cover image over their display name.', 'buddypress') 229 })), isMentionEnabled && createElement(PanelBody, { 230 title: __('Mention settings', 'buddypress'), 231 initialOpen: false 232 }, createElement(ToggleControl, { 233 label: __('Display Mention slug', 'buddypress'), 234 checked: !!displayMentionSlug, 235 onChange: function onChange() { 236 setAttributes({ 237 displayMentionSlug: !displayMentionSlug 238 }); 239 }, 240 help: displayMentionSlug ? __('Include the user\'s mention name under their display name.', 'buddypress') : __('Toggle to display the user\'s mention name under their display name.', 'buddypress') 241 }))), createElement(Disabled, null, createElement(ServerSideRender, { 242 block: "bp/member", 243 attributes: attributes 244 }))); 245 }; 246 247 var editMemberBlock = compose([withSelect(function (select) { 248 var editorSettings = select('core/editor').getEditorSettings(); 249 return { 250 bpSettings: editorSettings.bp.members || {} 251 }; 252 })])(editMember); 253 registerBlockType('bp/member', { 254 title: __('Member', 'buddypress'), 255 description: __('BuddyPress Member.', 'buddypress'), 256 icon: 'admin-users', 257 category: 'buddypress', 258 attributes: { 259 itemID: { 260 type: 'integer', 261 default: 0 262 }, 263 avatarSize: { 264 type: 'string', 265 default: 'full' 266 }, 267 displayMentionSlug: { 268 type: 'boolean', 269 default: true 270 }, 271 displayActionButton: { 272 type: 'boolean', 273 default: true 274 }, 275 displayCoverImage: { 276 type: 'boolean', 277 default: true 278 } 279 }, 280 edit: editMemberBlock 281 }); 282 },{}]},{},["TmUL"], null) 283 No newline at end of file -
src/class-buddypress.php
diff --git src/class-buddypress.php src/class-buddypress.php index a5d449ebd..e4e559eae 100644
class BuddyPress { 488 488 require( $this->plugin_dir . 'bp-core/bp-core-loader.php' ); 489 489 require( $this->plugin_dir . 'bp-core/bp-core-customizer-email.php' ); 490 490 require( $this->plugin_dir . 'bp-core/bp-core-rest-api.php' ); 491 require( $this->plugin_dir . 'bp-core/bp-core-blocks.php' ); 491 492 492 493 // Maybe load deprecated functionality (this double negative is proof positive!). 493 494 if ( ! bp_get_option( '_bp_ignore_deprecated_code', ! $this->load_deprecated ) ) { … … class BuddyPress { 554 555 'BP_Attachment_Cover_Image' => 'core', 555 556 'BP_Attachment' => 'core', 556 557 'BP_Button' => 'core', 558 'BP_Block' => 'core', 557 559 'BP_Component' => 'core', 558 560 'BP_Customizer_Control_Range' => 'core', 559 561 'BP_Date_Query' => 'core', -
new file src/js/bp-core/js/block-components/.babelrc
diff --git src/js/bp-core/js/block-components/.babelrc src/js/bp-core/js/block-components/.babelrc new file mode 100644 index 000000000..ab258a69c
- + 1 { 2 "presets": ["@wordpress/default"] 3 } -
new file src/js/bp-core/js/block-components/block-components.js
diff --git src/js/bp-core/js/block-components/block-components.js src/js/bp-core/js/block-components/block-components.js new file mode 100644 index 000000000..32c0026cd
- + 1 export { default as blockComponents } from './components'; -
new file src/js/bp-core/js/block-components/components/autocompleter.js
diff --git src/js/bp-core/js/block-components/components/autocompleter.js src/js/bp-core/js/block-components/components/autocompleter.js new file mode 100644 index 000000000..30d0c7c2d
- + 1 /** 2 * WordPress dependencies. 3 */ 4 const { Component, Fragment, createElement } = wp.element; 5 const { Popover } = wp.components; 6 const { apiFetch } = wp; 7 const { __ } = wp.i18n; 8 9 class AutoCompleter extends Component { 10 constructor() { 11 super( ...arguments ); 12 13 this.state = { 14 search: '', 15 items: [], 16 error: '', 17 }; 18 19 this.searchItemName = this.searchItemName.bind( this ); 20 this.selectItemName = this.selectItemName.bind( this ); 21 } 22 23 searchItemName( value ) { 24 const { search } = this.state; 25 const { component, objectStatus } = this.props; 26 this.setState( { search: value } ); 27 28 if ( value.length < search.length ) { 29 this.setState( { items: [] } ); 30 } 31 32 let path= '/buddypress/v1/' + component; 33 34 if ( value ) { 35 path += '?search=' + encodeURIComponent( value ); 36 } 37 38 if ( objectStatus ) { 39 path += '&status=' + objectStatus; 40 } 41 42 apiFetch( { path: path } ).then( items => { 43 this.setState( { items: items } ); 44 }, error => { 45 this.setState( { error: error.message } ); 46 } ); 47 } 48 49 selectItemName( event, itemID ) { 50 const { onSelectItem } = this.props; 51 event.preventDefault(); 52 53 this.setState( { 54 search: '', 55 items: [], 56 error: '', 57 } ); 58 59 return onSelectItem( { itemID: itemID } ); 60 } 61 62 render() { 63 const { search, items } = this.state; 64 let { ariaLabel, placeholder, useAvatar } = this.props; 65 let itemsList; 66 67 if ( ! ariaLabel ) { 68 ariaLabel = __( 'Item\'s name', 'buddypress' ); 69 } 70 71 if ( ! placeholder ) { 72 placeholder = __( 'Enter Item\'s name here…', 'buddypress' ); 73 } 74 75 if ( items.length ) { 76 itemsList = items.map( ( item ) => { 77 return ( 78 <button 79 type="button" key={ 'editor-autocompleters__item-item-' + item.id } 80 role="option" 81 aria-selected="true" 82 className="components-button components-autocomplete__result editor-autocompleters__user" 83 onClick={ ( event ) => this.selectItemName( event, item.id ) } 84 > 85 { useAvatar && ( 86 <img key="avatar" className="editor-autocompleters__user-avatar" alt="" src={ item.avatar_urls.thumb } /> 87 ) } 88 <span key="name" className="editor-autocompleters__user-name">{ item.name }</span> 89 90 { item.mention_name && ( 91 <span key="slug" className="editor-autocompleters__user-slug">{ item.mention_name }</span> 92 ) } 93 </button> 94 ); 95 } ); 96 } 97 98 return ( 99 <Fragment> 100 <input 101 type="text" 102 value={ search } 103 className="components-placeholder__input" 104 aria-label={ ariaLabel } 105 placeholder={ placeholder } 106 onChange={ ( event ) => this.searchItemName( event.target.value ) } 107 /> 108 { 0 !== items.length && 109 <Popover 110 className="components-autocomplete__popover" 111 focusOnMount={ false } 112 position="bottom left" 113 > 114 <div className="components-autocomplete__results"> 115 { itemsList } 116 </div> 117 </Popover> 118 } 119 </Fragment> 120 ); 121 } 122 } 123 124 export default AutoCompleter; -
new file src/js/bp-core/js/block-components/components/index.js
diff --git src/js/bp-core/js/block-components/components/index.js src/js/bp-core/js/block-components/components/index.js new file mode 100644 index 000000000..e255e9376
- + 1 // Components 2 import AutoCompleter from './autocompleter' 3 4 export default { 5 AutoCompleter 6 }; -
new file src/js/bp-groups/js/blocks/.babelrc
diff --git src/js/bp-groups/js/blocks/.babelrc src/js/bp-groups/js/blocks/.babelrc new file mode 100644 index 000000000..ab258a69c
- + 1 { 2 "presets": ["@wordpress/default"] 3 } -
new file src/js/bp-groups/js/blocks/group.js
diff --git src/js/bp-groups/js/blocks/group.js src/js/bp-groups/js/blocks/group.js new file mode 100644 index 000000000..6a1c4c869
- + 1 /** 2 * WordPress dependencies. 3 */ 4 const { registerBlockType } = wp.blocks; 5 const { createElement, Fragment } = wp.element; 6 const { Placeholder, Disabled, PanelBody, SelectControl, ToggleControl, Toolbar, ToolbarButton } = wp.components; 7 const { InspectorControls, BlockControls } = wp.blockEditor; 8 const { withSelect } = wp.data; 9 const { compose } = wp.compose; 10 const { ServerSideRender } = wp.editor; 11 const { __ } = wp.i18n; 12 13 /** 14 * BuddyPress dependencies. 15 */ 16 const { AutoCompleter } = bp.blockComponents; 17 18 const AVATAR_SIZES = [ 19 { 20 label: __( 'None', 'buddypress' ), 21 value: 'none', 22 }, 23 { 24 label: __( 'Thumb', 'buddypress' ), 25 value: 'thumb', 26 }, 27 { 28 label: __( 'Full', 'buddypress' ), 29 value: 'full', 30 }, 31 ]; 32 33 const editGroup = ( { attributes, setAttributes, bpSettings } ) => { 34 const { isAvatarEnabled, isCoverImageEnabled } = bpSettings; 35 const { avatarSize, displayDescription, displayActionButton, displayCoverImage } = attributes; 36 37 if ( ! attributes.itemID ) { 38 return ( 39 <Placeholder 40 icon="buddicons-groups" 41 label={ __( 'BuddyPress Group', 'buddypress' ) } 42 instructions={ __( 'Start typing the name of the group you want to feature into this post.', 'buddypress' ) } 43 > 44 <AutoCompleter 45 component="groups" 46 objectStatus="public" 47 ariaLabel={ __( 'Group\'s name', 'buddypress' ) } 48 placeholder={ __( 'Enter Group\'s name here…', 'buddypress' ) } 49 onSelectItem={ setAttributes } 50 useAvatar={ isAvatarEnabled } 51 /> 52 </Placeholder> 53 ); 54 } 55 56 return ( 57 <Fragment> 58 <BlockControls> 59 <Toolbar> 60 <ToolbarButton 61 icon="edit" 62 title={ __( 'Select another group', 'buddypress' ) } 63 onClick={ () =>{ 64 setAttributes( { itemID: 0 } ); 65 } } 66 /> 67 </Toolbar> 68 </BlockControls> 69 <InspectorControls> 70 <PanelBody title={ __( 'Group\'s home button settings', 'buddypress' ) } initialOpen={ true }> 71 <ToggleControl 72 label={ __( 'Display Group\'s home button', 'buddypress' ) } 73 checked={ !! displayActionButton } 74 onChange={ () => { 75 setAttributes( { displayActionButton: ! displayActionButton } ); 76 } } 77 help={ 78 displayActionButton 79 ? __( 'Include a link to the group\'s home page under their name.', 'buddypress' ) 80 : __( 'Toggle to display a link to the group\'s home page under their name.', 'buddypress' ) 81 } 82 /> 83 </PanelBody> 84 <PanelBody title={ __( 'Description settings', 'buddypress' ) } initialOpen={ false }> 85 <ToggleControl 86 label={ __( 'Display group\'s description', 'buddypress' ) } 87 checked={ !! displayDescription } 88 onChange={ () => { 89 setAttributes( { displayDescription: ! displayDescription } ); 90 } } 91 help={ 92 displayDescription 93 ? __( 'Include the group\'s description under their name.', 'buddypress' ) 94 : __( 'Toggle to display the group\'s description under their name.', 'buddypress' ) 95 } 96 /> 97 </PanelBody> 98 { isAvatarEnabled && ( 99 <PanelBody title={ __( 'Avatar settings', 'buddypress' ) } initialOpen={ false }> 100 <SelectControl 101 label={ __( 'Size', 'buddypress' ) } 102 value={ avatarSize } 103 options={ AVATAR_SIZES } 104 onChange={ ( option ) => { 105 setAttributes( { avatarSize: option } ); 106 } } 107 /> 108 </PanelBody> 109 ) } 110 { isCoverImageEnabled && ( 111 <PanelBody title={ __( 'Cover image settings', 'buddypress' ) } initialOpen={ false }> 112 <ToggleControl 113 label={ __( 'Display Cover Image', 'buddypress' ) } 114 checked={ !! displayCoverImage } 115 onChange={ () => { 116 setAttributes( { displayCoverImage: ! displayCoverImage } ); 117 } } 118 help={ 119 displayCoverImage 120 ? __( 'Include the group\'s cover image over their name.', 'buddypress' ) 121 : __( 'Toggle to display the group\'s cover image over their name.', 'buddypress' ) 122 } 123 /> 124 </PanelBody> 125 ) } 126 </InspectorControls> 127 <Disabled> 128 <ServerSideRender block="bp/group" attributes={ attributes } /> 129 </Disabled> 130 </Fragment> 131 ); 132 }; 133 134 const editGroupBlock = compose( [ 135 withSelect( ( select ) => { 136 const editorSettings = select( 'core/editor' ).getEditorSettings(); 137 return { 138 bpSettings: editorSettings.bp.groups || {}, 139 }; 140 } ), 141 ] )( editGroup ); 142 143 registerBlockType( 'bp/group', { 144 title: __( 'Group', 'buddypress' ), 145 146 description: __( 'BuddyPress Group.', 'buddypress' ), 147 148 icon: 'buddicons-groups', 149 150 category: 'buddypress', 151 152 attributes: { 153 itemID: { 154 type: 'integer', 155 default: 0, 156 }, 157 avatarSize: { 158 type: 'string', 159 default: 'full', 160 }, 161 displayDescription: { 162 type: 'boolean', 163 default: true, 164 }, 165 displayActionButton: { 166 type: 'boolean', 167 default: true, 168 }, 169 displayCoverImage: { 170 type: 'boolean', 171 default: true, 172 }, 173 }, 174 175 edit: editGroupBlock, 176 } ); -
new file src/js/bp-members/js/blocks/.babelrc
diff --git src/js/bp-members/js/blocks/.babelrc src/js/bp-members/js/blocks/.babelrc new file mode 100644 index 000000000..ab258a69c
- + 1 { 2 "presets": ["@wordpress/default"] 3 } -
new file src/js/bp-members/js/blocks/member.js
diff --git src/js/bp-members/js/blocks/member.js src/js/bp-members/js/blocks/member.js new file mode 100644 index 000000000..1d0e650ec
- + 1 /** 2 * WordPress dependencies. 3 */ 4 const { registerBlockType } = wp.blocks; 5 const { createElement, Fragment } = wp.element; 6 const { Placeholder, Disabled, PanelBody, SelectControl, ToggleControl, Toolbar, ToolbarButton } = wp.components; 7 const { InspectorControls, BlockControls } = wp.blockEditor; 8 const { withSelect } = wp.data; 9 const { compose } = wp.compose; 10 const { ServerSideRender } = wp.editor; 11 const { __ } = wp.i18n; 12 13 /** 14 * BuddyPress dependencies. 15 */ 16 const { AutoCompleter } = bp.blockComponents; 17 18 const AVATAR_SIZES = [ 19 { 20 label: __( 'None', 'buddypress' ), 21 value: 'none', 22 }, 23 { 24 label: __( 'Thumb', 'buddypress' ), 25 value: 'thumb', 26 }, 27 { 28 label: __( 'Full', 'buddypress' ), 29 value: 'full', 30 }, 31 ]; 32 33 const editMember = ( { attributes, setAttributes, bpSettings } ) => { 34 const { isAvatarEnabled, isMentionEnabled, isCoverImageEnabled } = bpSettings; 35 const { avatarSize, displayMentionSlug, displayActionButton, displayCoverImage } = attributes; 36 37 if ( ! attributes.itemID ) { 38 return ( 39 <Placeholder 40 icon="admin-users" 41 label={ __( 'BuddyPress Member', 'buddypress' ) } 42 instructions={ __( 'Start typing the name of the member you want to feature into this post.', 'buddypress' ) } 43 > 44 <AutoCompleter 45 component="members" 46 ariaLabel={ __( 'Member\'s username', 'buddypress' ) } 47 placeholder={ __( 'Enter Member\'s username here…', 'buddypress' ) } 48 onSelectItem={ setAttributes } 49 useAvatar={ isAvatarEnabled } 50 /> 51 </Placeholder> 52 ); 53 } 54 55 return ( 56 <Fragment> 57 <BlockControls> 58 <Toolbar> 59 <ToolbarButton 60 icon="edit" 61 title={ __( 'Select another member', 'buddypress' ) } 62 onClick={ () =>{ 63 setAttributes( { itemID: 0 } ); 64 } } 65 /> 66 </Toolbar> 67 </BlockControls> 68 <InspectorControls> 69 <PanelBody title={ __( 'Profile button settings', 'buddypress' ) } initialOpen={ true }> 70 <ToggleControl 71 label={ __( 'Display Profile button', 'buddypress' ) } 72 checked={ !! displayActionButton } 73 onChange={ () => { 74 setAttributes( { displayActionButton: ! displayActionButton } ); 75 } } 76 help={ 77 displayActionButton 78 ? __( 'Include a link to the user\'s profile page under their display name.', 'buddypress' ) 79 : __( 'Toggle to display a link to the user\'s profile page under their display name.', 'buddypress' ) 80 } 81 /> 82 </PanelBody> 83 { isAvatarEnabled && ( 84 <PanelBody title={ __( 'Avatar settings', 'buddypress' ) } initialOpen={ false }> 85 <SelectControl 86 label={ __( 'Size', 'buddypress' ) } 87 value={ avatarSize } 88 options={ AVATAR_SIZES } 89 onChange={ ( option ) => { 90 setAttributes( { avatarSize: option } ); 91 } } 92 /> 93 </PanelBody> 94 ) } 95 { isCoverImageEnabled && ( 96 <PanelBody title={ __( 'Cover image settings', 'buddypress' ) } initialOpen={ false }> 97 <ToggleControl 98 label={ __( 'Display Cover Image', 'buddypress' ) } 99 checked={ !! displayCoverImage } 100 onChange={ () => { 101 setAttributes( { displayCoverImage: ! displayCoverImage } ); 102 } } 103 help={ 104 displayCoverImage 105 ? __( 'Include the user\'s cover image over their display name.', 'buddypress' ) 106 : __( 'Toggle to display the user\'s cover image over their display name.', 'buddypress' ) 107 } 108 /> 109 </PanelBody> 110 ) } 111 { isMentionEnabled && ( 112 <PanelBody title={ __( 'Mention settings', 'buddypress' ) } initialOpen={ false }> 113 <ToggleControl 114 label={ __( 'Display Mention slug', 'buddypress' ) } 115 checked={ !! displayMentionSlug } 116 onChange={ () => { 117 setAttributes( { displayMentionSlug: ! displayMentionSlug } ); 118 } } 119 help={ 120 displayMentionSlug 121 ? __( 'Include the user\'s mention name under their display name.', 'buddypress' ) 122 : __( 'Toggle to display the user\'s mention name under their display name.', 'buddypress' ) 123 } 124 /> 125 </PanelBody> 126 ) } 127 </InspectorControls> 128 <Disabled> 129 <ServerSideRender block="bp/member" attributes={ attributes } /> 130 </Disabled> 131 </Fragment> 132 ); 133 }; 134 135 const editMemberBlock = compose( [ 136 withSelect( ( select ) => { 137 const editorSettings = select( 'core/editor' ).getEditorSettings(); 138 return { 139 bpSettings: editorSettings.bp.members || {}, 140 }; 141 } ), 142 ] )( editMember ); 143 144 registerBlockType( 'bp/member', { 145 title: __( 'Member', 'buddypress' ), 146 147 description: __( 'BuddyPress Member.', 'buddypress' ), 148 149 icon: 'admin-users', 150 151 category: 'buddypress', 152 153 attributes: { 154 itemID: { 155 type: 'integer', 156 default: 0, 157 }, 158 avatarSize: { 159 type: 'string', 160 default: 'full', 161 }, 162 displayMentionSlug: { 163 type: 'boolean', 164 default: true, 165 }, 166 displayActionButton: { 167 type: 'boolean', 168 default: true, 169 }, 170 displayCoverImage: { 171 type: 'boolean', 172 default: true, 173 }, 174 }, 175 176 edit: editMemberBlock, 177 } );