Dynamic multi-select fields in Twill CMS

Twill is a really promising headless CMS built by Area17. The product was release in March 2018. Unfortunately the online docs are somewhat lacking so implementing new features can be a struggle. There is a semi-active Spectrum chat for the project .

I wanted to implement dynamic multi-select fields in the CMS and after a lot of poking about l, I succeeded. So that my time doesn’t go wasted, I’ve documented the steps to add a dynamic multi-select field here.

This example shows how to add a “Sectors” multi-select field to an Article model.

Models

You will need a new model, repository and controller for the Sectors.

php artisan twill:module Sectors

Your App/Models/Sector model should look like this:

namespace App\Models;

use A17\Twill\Models\Model;

class Sector extends Model {

   protected $fillable = [
      'published',
      'title',
      'publish_start_date',
      'publish_end_date',
   ];

   public $checkboxes = [
      'published'
   ];
}

Your Article model will need a relationship reference to the Sector model. Add this to your Article model.

public function sectors() {
return $this->belongsToMany('App\Models\Sector');
}

The ArticleRepository repository needs the addition of some logic to save the multi-select fields on saving the model.

Add the afterSave method with a call to sync the sectors.

public function afterSave($object, $fields)
{
$object->sectors()->sync($fields['sectors'] ?? []);
parent::afterSave($object, $fields);
}

Migrations

Customise the sectors migration generated by the artisan twill command

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateSectorsTables extends Migration {
   public function up() {
      Schema::create( 'sectors', function ( Blueprint $table ) {
         createDefaultTableFields( $table );
         $table->string( 'title', 200 )->nullable();
      } );
   }

   public function down() {
      Schema::dropIfExists( 'sectors' );
   }
}

You will need to create a table in your DB for the article -> sector relationship.

artisan make:migration create_sector_article_table

My migration looks like this

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateSectorsTables extends Migration {
   public function up() {
      Schema::create( 'sectors', function ( Blueprint $table ) {
         createDefaultTableFields( $table );
         $table->string( 'title', 200 )->nullable();
      } );
   }

   public function down() {
      Schema::dropIfExists( 'sectors' );
   }
}

Routes

Add a route for the sectors to the routes/admin.php file. You will probably want to add a section to the CMS to allow creation of new sectors from the CMS but this is outside of the scope of this article.

Route::module('sectors');

Form fields

And finally add the field to the CMS in articles/form.blade.php 🙂

@php
    $sectors = array();
@endphp
@foreach(\App\Models\Sector::all(['id','title']) as $sector)
    @php
        $sectors[] =
        [
        'value' => $sector->id,
        'label' => $sector->title
        ];
    @endphp
@endforeach

@formField('multi_select', [
'name' => 'sectors',
'label' => 'Sectors',
'options' => $sectors,
])
Help other people find this

Leave a Reply

Your e-mail address will not be published. Required fields are marked *