In this tutorial, you will learn how to create your own Gutenberg blocks to be used in App Pages and the App Editor. For more information about how app blocks and the App Editor work, it is explained and demoed in the Blog Posts tutorial (you can fast forward to 2:15 in the video).
We are supporting a number of blocks designed to work natively in the BuddyBoss App, but you may want to create your own blocks for your custom functionality.
Once a block is registered, you’ll need to follow the instructions in our Adding Custom Gutenberg Blocks into your App tutorial to configure how it will render in your app.
You can optionally skip to the “Example Plugin” section at the end of the article, for an example plugin you can quickly test with.
Note: This tutorial requires BuddyBoss App Plugin v1.0.4 or higher.
1. Create one class file and extend ‘BuddyBossApp\Admin\GutenbergBlockAbstract’
<?php
namespace BuddyBossApp\Custom;
use BuddyBossApp\Admin\GutenbergBlockAbstract;
class <ClassName> extends GutenbergBlockAbstract {
private static $instance;
public $default_args;
public static function instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
public function __construct() {
$this->initialize_default_args();
$this->setup_block_configuration();
$this->init();
}
}
2. Once the class is created, set a block argument using the Setter method.
blockNamespace : Block namespace, eg. bbapp/books
blockTitle : Block title.
blockDescription : Block description.
blockIcon : Block Icon. Use Dashicons.
blockKeywords : Block keyword.
attributes : Block attribute, including block setting fields.
preview : Preview HTML for the web when the block is added in the editor or page content.
private function initialize_default_args() {
$this->default_args = array(
'title' => __( 'Books', 'buddyboss-app' ),
'description' => __( 'Display a list of books', 'buddyboss-app' ),
'icon' => 'dashicons-book',
'per_page' => 5,
'route' => '/wp/v2/books', // Create a CPT and enable the REST API support.
'namespace' => 'bbapp/books',
'keywords' => array( 'book', 'books', 'library' ),
'icon_url' => '',
);
}
private function setup_block_configuration() {
$args = $this->default_args;
$this->set_namespace( $args['namespace'] );
$this->set_title( $args['title'] );
$this->set_description( $args['description'] );
$this->set_icon( $args['icon'] );
$this->set_keywords( $args['keywords'] );
$this->set_attributes( $this->get_attributes() );
$this->set_preview( $this->get_preview() );
}
3. Once the attribute is set, execute the parent class init method, which will add hooks to the registered block.
public function init() {
parent::init();
add_filter( 'bbapp_custom_block_data', array( $this, 'update_block_data' ), 10, 2 );
}
4. To send block data with the same app page endpoint, use the get_results method.
public function get_results( $attrs ) {
// This method can be extended to return actual book data.
return array();
}
5. In other cases, you can send a data_source argument with the app page endpoint, and the app will know that it will need to fetch data before rendering your block.
App_page_data : Block rest response
block_data : Block details.
In data_source you need to pass two values:
type : Value should be`fetch`
Request_params : Request argument to fetch data
Note: This Request_params argument is prepared from the WordPress side because doing this in the app would require a new app build every time you change the argument or its value.
public function update_block_data( $app_page_data, $block_data ) {
$attrs = isset( $block_data['attrs'] ) && is_array( $block_data['attrs'] ) ? $block_data['attrs'] : array();
$per_page = ! empty( $attrs['per_page'] ) && is_numeric( $attrs['per_page'] ) ? absint( $attrs['per_page'] ) : $this->default_args['per_page'];
$title = ! empty( $attrs['title'] ) ? sanitize_text_field( $attrs['title'] ) : $this->default_args['title'];
$data_source = array(
'type' => 'fetch',
'request_params' => array(
'per_page' => $per_page,
),
'route' => $this->default_args['route'],
);
$app_page_data['data']['data_source'] = $data_source;
$app_page_data['content'] = isset( $app_page_data['render'] ) ? $app_page_data['render'] : '';
$app_page_data['data']['icon_url'] = '';
$app_page_data['data']['title'] = $title;
return $app_page_data;
}
Now, the block should be available when editing content on an App Page. Once a block is used in an App Page, you will get block data similar to the one below, in the endpoint to be handled in the app.

Template File:
namespace BuddyBossApp\Custom;
use BuddyBossApp\Admin\GutenbergBlockAbstract;
/**
* Class Gutenberg Block
*/
class ClasName extends GutenbergBlockAbstract {
private static $instance;
/**
* Default block arguments.
*
* @var array $default_args
*/
public $default_args;
/**
* Get the instance of the class.
*
* @return $instance
*/
public static function instance() {
if ( ! isset( self::$instance ) ) {
$class = __CLASS__;
self::$instance = new $class;
}
return self::$instance;
}
public function __construct() {
$this->initialize_default_args();
$this->setup_block_configuration();
$this->init();
}
/**
* Initialize block details. Modify this method to change the block details.
*
* @return void
*/
private function initialize_default_args() {
$this->default_args = array(
'title' => "<blockTItle>",
'description' => "<blockDescription>",
'icon' => '<blockIcon>',
'per_page' => 5,
'route' => '<blocKRestRoute>',
'namespace' => 'bbapp/<blockName>',
'keywords' => '<blocKkeyword>',
'icon_url' => '',
);
}
/**
* Set up the block configuration.
*
* @return void
*/
private function setup_block_configuration() {
$args = $this->default_args;
$this->set_namespace( $args['namespace'] );
$this->set_title( $args['title'] );
$this->set_description( $args['description'] );
$this->set_icon( $args['icon'] );
$this->set_keywords( $args['keywords'] );
$this->set_attributes( $this->get_attributes() );
$this->set_preview( $this->get_preview() );
}
public function init() {
parent::init();
add_filter( 'bbapp_custom_block_data', array( $this, 'update_block_data' ), 10, 2 );
}
function get_attributes() {
return array();
}
function get_preview( ) {
return "<div>" . esc_html_e('Preview', 'text-domain') . "</div>";
}
function get_results( $attributes ) {
// TODO: Implement get_results() method.
}
function update_block_data( $app_page_data, $block_data ) {
$data_source = array(
'type' => 'fetch',
'request_params' => array(
'per_page' => 5,
),
'route' => $this->default_args['route'],
);
$app_page_data['data']['data_source'] = $data_source;
return $app_page_data;
}
}
Example Plugin
You can assemble the two PHP template files below into a folder, to create a plugin that will add a new “Books” block, which can be viewed when editing an App Page or using the App Editor.
Note: For this to actually work in your app or website, we are assuming you have also already registered a “book” custom post type in WordPress. Alternatively, you can adjust this code to use your own custom post type.

buddyboss-app-custom.php
This is the loader file. Create a plugin folder and add this file into it.
<?php
/*
Plugin Name: BuddyBoss App Custom Block Example
Plugin URI: {add your own}
Description: {add your own}
Version: 1.0.0
Author: {add your own}
Author URI: {add your own}
*/
if ( ! defined( 'ABSPATH' ) ) {
exit();
}
/**
* Load Custom Block Functions
*/
function bbapp_custom_work_init() {
if ( class_exists( 'bbapp' ) ) {
include 'buddyboss-app-custom-block.php';
BuddyBossApp\Custom\BookBlock::instance();
}
}
add_action( 'plugins_loaded', 'bbapp_custom_work_init' );
buddyboss-app-custom-block.php
This file also goes into your plugin folder. This contains most of the functional code to register the new app block.
<?php
/**
* BuddyBoss App Custom Books Block
*
* This file contains the BookBlock class that creates a Gutenberg block
* for displaying books post type in the BuddyBoss App.
*
* @package BuddyBossApp\Custom
* @since 1.0.0
*/
namespace BuddyBossApp\Custom;
use BuddyBossApp\Admin\GutenbergBlockAbstract;
// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* BookBlock class for creating a custom books Gutenberg block.
*
* @package BuddyBossApp\Custom
* @since 1.0.0
*/
class BookBlock extends GutenbergBlockAbstract {
/**
* Single instance of the class.
*
* @var BookBlock $instance
*/
private static $instance;
/**
* Default block arguments.
*
* @var array $default_args
*/
public $default_args;
/**
* Get the single instance of the class.
*
* @return BookBlock Single instance of the class.
*/
public static function instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*
* Sets up the block configuration and initializes the block.
*/
public function __construct() {
$this->initialize_default_args();
$this->setup_block_configuration();
$this->init();
}
/**
* Initialize block details. Modify this method to change the block details.
*
* @return void
*/
private function initialize_default_args() {
$this->default_args = array(
'title' => __( 'Books', 'buddyboss-app' ),
'description' => __( 'Display a list of books', 'buddyboss-app' ),
'icon' => 'dashicons-book',
'per_page' => 5,
'route' => '/wp/v2/books',
'namespace' => 'bbapp/books',
'keywords' => array( 'book', 'books', 'library' ),
'icon_url' => '',
);
}
/**
* Set up the block configuration.
*
* @return void
*/
private function setup_block_configuration() {
$args = $this->default_args;
$this->set_namespace( $args['namespace'] );
$this->set_title( $args['title'] );
$this->set_description( $args['description'] );
$this->set_icon( $args['icon'] );
$this->set_keywords( $args['keywords'] );
$this->set_attributes( $this->get_attributes() );
$this->set_preview( $this->get_preview() );
}
/**
* Initialize the block.
*
* @return void
*/
public function init() {
parent::init();
add_filter( 'bbapp_custom_block_data', array( $this, 'update_block_data' ), 10, 2 );
}
/**
* Get block attributes configuration.
*
* @return array Block attributes configuration.
*/
public function get_attributes() {
return array(
array(
'name' => 'title',
'fieldtype' => 'text',
'default' => $this->default_args['title'],
'label' => __( 'Enter Block Title', 'buddyboss-app' ),
),
array(
'name' => 'per_page',
'fieldtype' => 'number',
'default' => $this->default_args['per_page'],
'label' => __( 'Number of items to show', 'buddyboss-app' ),
),
);
}
/**
* Get block preview HTML.
*
* @return string Preview HTML.
*/
public function get_preview() {
return "<div>
<h3>" . $this->default_args['title'] . "</h3>
<ul>
<li id='li_one'><div className='appboss_div'>" . esc_html__( 'Book One', 'buddyboss-app' ) . "</div></li>
<li id='li_two'><div className='appboss_div' >" . esc_html__( 'Book Two', 'buddyboss-app' ) . "</div></li>
<li id='li_three'><div className='appboss_div' >" . esc_html__( 'Book Three', 'buddyboss-app' ) . "</div></li>
<li id='li_four'><div className='appboss_div' >" . esc_html__( 'Book Four', 'buddyboss-app' ) . "</div></li>
<li id='li_five'><div className='appboss_div' >" . esc_html__( 'Book Five', 'buddyboss-app' ) . "</div></li>
</ul>
</div>";
}
/**
* Get results for the block.
*
* This method can be extended to return actual book data.
*
* @param array $attrs Block attributes.
* @return array Empty array for now, can be extended.
*/
public function get_results( $attrs ) {
// This method can be extended to return actual book data.
return array();
}
/**
* Update block data for the Books block.
*
* @param array $app_page_data The current app page data.
* @param array $block_data The block data including attributes.
*
* @return array Modified app page data.
*/
public function update_block_data( $app_page_data, $block_data ) {
$attrs = isset( $block_data['attrs'] ) && is_array( $block_data['attrs'] ) ? $block_data['attrs'] : array();
$per_page = ! empty( $attrs['per_page'] ) && is_numeric( $attrs['per_page'] ) ? absint( $attrs['per_page'] ) : $this->default_args['per_page'];
$title = ! empty( $attrs['title'] ) ? sanitize_text_field( $attrs['title'] ) : $this->default_args['title'];
$data_source = array(
'type' => 'fetch',
'request_params' => array(
'per_page' => $per_page,
),
'route' => $this->default_args['route'],
);
$app_page_data['data']['data_source'] = $data_source;
$app_page_data['content'] = isset( $app_page_data['render'] ) ? $app_page_data['render'] : '';
$app_page_data['data']['icon_url'] = '';
$app_page_data['data']['title'] = $title;
return $app_page_data;
}
}