District Core Developer DocsDistrict Core Developer Docs
Developers
Boilerplate
Modules
Bitbucket
Developers
Boilerplate
Modules
Bitbucket
  • Modules

    • ABN
    • ActivityLog
    • AnalyticsApi
    • ApiConnector
    • BlockApi
    • CategoryApi
    • CloneApi
    • CommentApi
    • ContentApi
    • Core
    • Documents
    • EmbedApi
    • Event
    • ExportApi
    • FeatureApi
    • FormApi
    • GTM
    • GalleryApi
    • HelpApi
    • Hotspot
    • IdeaSurvey
    • ImportApi
    • InteractionsApi
    • Intercom
    • MailApi
    • MapApi
    • MapSurvey
    • MediaApi
    • MenuApi
    • MetaTagApi
    • NlpApi
    • NotificationApi
    • Page
    • ParentableContent
    • PaymentApi
    • PermissionsApi
    • Postcode
    • ReCaptcha
    • Redirects
    • Renderer
    • ReportApi
    • RestrictionApi
    • RevisionApi
    • SearchApi
    • Settings
    • ShareableApi
    • Slack
    • SlugApi
    • SubscribableApi
    • Survey
    • Team
    • TenantApi
    • TestApi
    • ThemeApi
    • Timeline
    • TranslationApi
    • Update
    • Users
    • VisualisationApi
    • WorkflowApi
    • Wysiwyg

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

  1. Defining the plugin (type/name/description)
  2. Defining the default settings
  3. Defining the form schema for editing schema
  4. Defining how it will be rendered (via parseSettingsToRender()). The output of parseSettingsToRender() should return an array with
    • component - The vue component used to render
    • props - The props passed to the vue component
    • title - 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:

  • Adding links to other content
  • Adding links to document downloads

ContentApi based relationship

This is the easiest relationship to add as you only need to add two things

  1. 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 name
    • optionsUrl() - A url that returns ContentBlockBuilderResource.php
  2. A Route that returns DashboardContentController::blockBuilderIndex(), the url should be the same as what optionsUrl() 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.

  1. 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
  2. A controller method that returns a list of models available to the controller via a resource that extends BaseBlockBuilderRelationshipResource example. 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());
     }
    
  3. A Route that returns above controller method, the url should be the same as what optionsUrl() returns. NOTE: Ensure protected with permissions!
  4. Frontend components for rendering the block. As per $component above, 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.js file to Modules/MyModule/Resources/assets/js example

Edit this page
Prev
ApiConnector
Next
CategoryApi