BlockAPI Module
A Block defines pieces of content or components that can be used to build pages.
Where is it used
Blocks are used on multiple model types. Anywhere an author needs to build a page piecing together content or lists from elsewhere in the platform.
Schema and structure
Blocks use a json DB field and contain an array of blocks to display. Add a migration that looks something like this:
return new class extends Migration
{
public function up()
{
Schema::table('my_model', function (Blueprint $table) {
$table->json('blocks')->nullable();
});
}
};
Adding to a model
Add the interface, trait and update casts
use Modules\BlockApi\Models\Concerns\HasBlocksTrait;
use Modules\BlockApi\Models\Contracts\HasBlocks;
class MyModel extends Model implements HasBlocks
{
use HasBlocksTrait;
protected $casts = [
'blocks' => NullableArrayValues::class,
];
}
Example of a block settings on a model
eg dd(json_encode($model->blocks));
[
{
"type": "BLOCK_PLUGIN_CLASS_NAME",
"uuid": "UNIQUE_ID_FOR_BLOCK",
"id": "UNIQUE_ID_USED_IN_BUILDER_UI",
"title": "TITLE_OF_THE_BLOCK",
"setting1": "SETTING1_VALUE",
"setting2": "SETTING1_VALUE",
},
{
... another block
}
]
Also see Config/blockapi_test_settings.php
The above should be fairly self-explanatory, what will be different for each block, type, uuid, id and title will be present on almost all blocks. Any other settings keys are defined by the block plugin.
Autonomy of a block plugin
A block plugin is responsible for
- Defining the plugin (type/name/description)
- Defining the default settings
- Defining the form schema for editing schema
- Defining how it will be rendered (via
parseSettingsToRender()). The output ofparseSettingsToRender()should return an array withcomponent- The vue component used to renderprops- The props passed to the vue componenttitle- The block title (empty for no title)display- Should the block display (set to false if block settings return empty)
The easiest way to understand this is via example, check out \Modules\BlockApi\Plugins\Blocks\Plugins\Html for the Html block plugin
Rendering a block
All block rendering gets handled by Modules/BlockApi/Resources/js/Render/Show.vue.
Block rendering only supports global components!
To render a block plugin component it must be registered globally. This can be done by the module adding a Resources/js/GlobalImports.js file and in that importing and registering the components.
Eg.
import Vue from "vue";
import MyModuleBlockComponent from "./Path/To/MyModuleBlockComponent";
Vue.component('my-module-block-component', MyModuleBlockComponent)
Then in your plugin:
protected string $component = 'my-module-block-component';
Adding a relationship block to your module
If you want to expose models from your module to the block builder, you can do this with a few additions to your module.
Examples:
ContentApi based relationship
This is the easiest relationship to add as you only need to add two things
- A block plugin that extends
BaseContentRelationshipBlock. This should define a few things$label- Generally the model name, shown in block builder$description- Description to complement label$machine_name- Machine representation of the block (usually the label, lowercase and no spaces)$contentBundle- The content bundle class nameoptionsUrl()- A url that returns ContentBlockBuilderResource.php
- A
Routethat returnsDashboardContentController::blockBuilderIndex(), the url should be the same as whatoptionsUrl()returns. NOTE: Ensure protected with permissions!
That's it, see The page module for a working example.
NOTE: There a plenty of additional overrides available all the way down to the component used to render the final model.
Non-ContentApi based relationship
Got some relationship that is a bit more complex? You just need a bit more code.
- A block plugin that extends
BaseRelationshipBlock, You require the same definitions as above (sans contentBundle). You will also need to define$modelType- The class name for your model$modelResource- A JsonResource responsible for data provided to frontend render$component- A component that handles rendering the list of models- Example
- A controller method that returns a list of models available to the controller via a resource that extends
BaseBlockBuilderRelationshipResourceexample. Most the work is done for you, just define the$modelType. Example of controller method:public function blockBuilderIndex(): JsonResource { return MyModuleBlockBuilderResource::collection(MyModel::orderBy('title')->paginate()); } - A
Routethat returns above controller method, the url should be the same as whatoptionsUrl()returns. NOTE: Ensure protected with permissions! - Frontend components for rendering the block. As per
$componentabove, example- NOTE: Your components MUST be global as the block renderer cannot import (this happens during build). To import your components globally, add a
GlobalImports.jsfile toModules/MyModule/Resources/assets/jsexample
- NOTE: Your components MUST be global as the block renderer cannot import (this happens during build). To import your components globally, add a