Creating a Craft CMS Field Type
The first Craft CMS field type we’ll build in this course is a dropdown that allows us to create a dropdown of world languages.
The first Craft CMS field type we’ll build in this course is a dropdown that allows us to create a dropdown of world languages.
We won’t populate the dropdown with remote data but instead, just store it in an array right in the module source code. I showed in the first video of the course how it worked.
The first step in creating the field type is to create the class file. We name the class file based on the name of the field type. We will call our field type World Languages, and the class file name will be WorldLanguages.php
. So, let’s create that file.
craft-module
├── README.md
└── src
├── CraftModule.php
└── fields
└── WorldLanguages.php
This file will be the class file for our field type, and it’s going to be the only file we need to create. Since our field type is relatively simple, we don’t need much code to make it happen. The idea here is that we’re learning the framework for creating the field type, and then you can use that framework to build your implementations as they are needed.
Field types in Craft can extend the base Field
class in Craft. This gives everything we need to get started. However, we can also extend one of the in-built fields that come with Craft and layer our customization over top of them.
In the case of a dropdown field, this is a good option because we don’t need to do a lot of heavy lifting. There will be very little code for us to write.
Looking at the included field types, I think we can just extend the Dropdown
class and build on top of it.
Let’s populate the class file with the base code we need to get started.
Our namespace for this field will be craftquest\fields
since our namespace for the containing module is craftquest
.
<?php
namespace craftquest\fields;
We want to import the Dropdown class and then extend it with our own field type class.
<?php
namespace craftquest\fields;
use craft\fields\Dropdown;
class WorldLanguages extends Dropdown
{
}
Now we have the basics of our class file. Reloading our site shouldn’t result in any errors since we have valid class code, albeit useless at this point.
Now let’s focus on the class methods that we need to create to get things working.
First, we’ll create the init
method that initializes our class file.
<?php
namespace craftquest\fields;
use craft\fields\Dropdown;
class WorldLanguages extends Dropdown
{
public function init()
{
parent::init();
}
}
Inside of the init
method we’ll run the parent class init method, too, since we’re extending it. Later on we’ll come back and call our class method to set the options for our dropdown field.
Next, let’s give our field type a name, so Craft can display something human-readable in the UI. We do this with a static method called displayName
, which returns a string.
<?php
namespace craftquest\fields;
use craft\fields\Dropdown;
class WorldLanguages extends Dropdown
{
public function init()
{
parent::init();
}
public static function displayName(): string
{
return "World Languages";
}
}
Let’s rebuild our Composer autoload files to get the class picked up.
composer dump-autoload
Before we can see our new field type in the Craft CMS control panel as an option to choose when creating a new field, we need to register it with Craft via an Event.
We do that in the module class file. I like to create a private method for registering different components in a module. For this, we’ll create one called _registerCustomFieldTypes()
and then call it in the init()
method of the module class.
First, let’s import our field type class file:
use craftquest\fields\WorldLanguages;
Our base event class:
use Yii\base\Event
And the base Fields class:
use craft\services\Fields;
And finally, we need to import the RegisterComponentTypesEvent
class as well.
use craft\events\RegisterComponentTypesEvent;
So our end result is this:
use craftquest\fields\WorldLanguages;
use Yii\base\Event;
use craft\services\Fields;
use craft\events\RegisterComponentTypesEvent;
Now we can create our private class method to register the field type via an event:
private function _registerCustomFieldTypes()
{
Event::on(
Fields::class,
Fields::EVENT_REGISTER_FIELD_TYPES,
function(RegisterComponentTypesEvent $event) {
$event->types[] = WorldLanguages::class;
}
);
}
And now we call the private method from the module’s init()
method:
$this->_registerCustomFieldTypes();
Now when we create a new field, we can see our field type appear as an option!
However, it looks just like a standard Dropdown field since that’s the one we’re extending. The only difference right now is the name!
Let make it our own by populating it with the world languages data.
We are going to store our languages in an array right in our code. It might make sense to have this attached to a service of some type, but we’ll keep it simple for now.
When we extend the Dropdown class from Craft, we get access to the $options
property. We need to add to that property the options for each language when we want to make available.
Let’s start with our languages array. This array is available as a Github Gist and you can copy and paste into your code.
Let’s create a protected class method where we’ll process the languages in the array and add them to the options for our dropdown.
protected function setLanguages(): void
{
}
We set the return type as void, meaning that we don’t have anything at all to return. We are intercepting and updating the options array via the event in Craft for registering ad adding a new field type.
The first thing we’ll do is drop in our array. Now, to be clear, having this array like this in the method isn’t ideal, but we want to focus on building our field type, and then we can always come back around and refactor this as needed.
Let’s drop our array in at the top of the method.
protected function setLanguages(): void
{
$languages = [ /*data here */ ];
}
Before we make the array data available as options for the dropdown, let’s first clear the dropdown that we get from the base class, and add our default options:
protected function setLanguages(): void
{
$languages = [ /*data here */ ];
$this->options = [
[
'label' => 'Choose a language',
'value' => '',
'disabled' => true,
]
];
}
We need to get that data into a format that the $options
property in Craft expects, so it’ll populate a dropdown for us. We’ll iterate over the array and place the keys and values as labels and values.
protected function setLanguages(): void
{
$languages = [ /*data here */ ];
$this->options = [
[
'label' => 'Choose a language',
'value' => '',
'disabled' => true,
]
];
foreach ($languages as $key => $value) {
$this->options[] = [
'label' => $plan->name,
'value' => $plan->uid
];
}
}
Next, I want to override yet another base class method to control how our World Languages field type functions. By default, the Dropdown field type has a settings area in the bottom of the field settings. With a dropdown field this is where you would add your dropdown field data. Since we’re populating this data from the array in the class method, then we don’t need (or want) the data to be updated. Plus, with the way the settings field works, it would double our data if we saved the HTML fields data, and then our custom field code would load that data again from the array.
We want to avoid both situations, so we’ll just override the settings method and return nothing or null
.
public function getSettingsHtml()
{
return;
}
The next step is to call this method is our class init()
method. We want to place it before the parent::init()
method. Usually, we want to call our own methods in the init()
method before we call our own. That way we’re getting the base code we extend and then override it with our own. However, in this case, we want to inject our code beforehand.
<?php
namespace craftquest\fields;
use craft\fields\Dropdown;
class WorldLanguages extends Dropdown
{
public function init()
{
$this->setLanguages();
parent::init();
}
}
Now we can test our new custom field type and see how it works!
Creating a Craft CMS Field Type is made up of the following videos: