Building a Craft CMS Dropdown Field Type with Static Data

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 drop­down that allows us to cre­ate a drop­down of world languages.

We won’t pop­u­late the drop­down with remote data but instead, just store it in an array right in the mod­ule source code. I showed in the first video of the course how it worked.

Cre­at­ing the Field Type Class File

The first step in cre­at­ing the field type is to cre­ate the class file. We name the class file based on the name of the field type. We will call our field type World Lan­guages, and the class file name will be WorldLanguages.php. So, let’s cre­ate 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 cre­ate. Since our field type is rel­a­tive­ly sim­ple, we don’t need much code to make it hap­pen. The idea here is that we’re learn­ing the frame­work for cre­at­ing the field type, and then you can use that frame­work to build your imple­men­ta­tions as they are needed.

Field types in Craft can extend the base Field class in Craft. This gives every­thing we need to get start­ed. How­ev­er, we can also extend one of the in-built fields that come with Craft and lay­er our cus­tomiza­tion over top of them. 

In the case of a drop­down field, this is a good option because we don’t need to do a lot of heavy lift­ing. There will be very lit­tle code for us to write.

Look­ing at the includ­ed field types, I think we can just extend the Dropdown class and build on top of it.

Let’s pop­u­late the class file with the base code we need to get started. 

Our name­space for this field will be craftquest\fields since our name­space for the con­tain­ing mod­ule is craftquest.

<?php

namespace craftquest\fields;

We want to import the Drop­down 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. Reload­ing our site shouldn’t result in any errors since we have valid class code, albeit use­less at this point.

Now let’s focus on the class meth­ods that we need to cre­ate to get things working. 

First, we’ll cre­ate the init method that ini­tial­izes 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 par­ent class init method, too, since we’re extend­ing it. Lat­er on we’ll come back and call our class method to set the options for our drop­down field.

Next, let’s give our field type a name, so Craft can dis­play some­thing human-read­able in the UI. We do this with a sta­t­ic 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 Com­pos­er autoload files to get the class picked up. 

composer dump-autoload

Reg­is­ter­ing a Field Type

Before we can see our new field type in the Craft CMS con­trol pan­el as an option to choose when cre­at­ing a new field, we need to reg­is­ter it with Craft via an Event. 

We do that in the mod­ule class file. I like to cre­ate a pri­vate method for reg­is­ter­ing dif­fer­ent com­po­nents in a mod­ule. For this, we’ll cre­ate one called _registerCustomFieldTypes() and then call it in the init() method of the mod­ule 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 final­ly, 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 cre­ate our pri­vate class method to reg­is­ter 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 pri­vate method from the module’s init() method:

$this->_registerCustomFieldTypes();

Now when we cre­ate a new field, we can see our field type appear as an option!

How­ev­er, it looks just like a stan­dard Drop­down field since that’s the one we’re extend­ing. The only dif­fer­ence right now is the name!

Let make it our own by pop­u­lat­ing it with the world lan­guages data.

Cre­at­ing the Lan­guages List

We are going to store our lan­guages in an array right in our code. It might make sense to have this attached to a ser­vice of some type, but we’ll keep it sim­ple for now.

When we extend the Drop­down class from Craft, we get access to the $options prop­er­ty. We need to add to that prop­er­ty the options for each lan­guage when we want to make available. 

Let’s start with our lan­guages array. This array is avail­able as a Github Gist and you can copy and paste into your code.

Let’s cre­ate a pro­tect­ed class method where we’ll process the lan­guages in the array and add them to the options for our dropdown. 

protected function setLanguages(): void
{
	
}

We set the return type as void, mean­ing that we don’t have any­thing at all to return. We are inter­cept­ing and updat­ing the options array via the event in Craft for reg­is­ter­ing ad adding a new field type.

The first thing we’ll do is drop in our array. Now, to be clear, hav­ing this array like this in the method isn’t ide­al, but we want to focus on build­ing our field type, and then we can always come back around and refac­tor 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 avail­able as options for the drop­down, let’s first clear the drop­down 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 for­mat that the $options prop­er­ty in Craft expects, so it’ll pop­u­late a drop­down for us. We’ll iter­ate over the array and place the keys and val­ues 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 over­ride yet anoth­er base class method to con­trol how our World Lan­guages field type func­tions. By default, the Drop­down field type has a set­tings area in the bot­tom of the field set­tings. With a drop­down field this is where you would add your drop­down field data. Since we’re pop­u­lat­ing this data from the array in the class method, then we don’t need (or want) the data to be updat­ed. Plus, with the way the set­tings field works, it would dou­ble our data if we saved the HTML fields data, and then our cus­tom field code would load that data again from the array. 

We want to avoid both sit­u­a­tions, so we’ll just over­ride the set­tings method and return noth­ing 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. Usu­al­ly, we want to call our own meth­ods in the init() method before we call our own. That way we’re get­ting the base code we extend and then over­ride it with our own. How­ev­er, 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 cus­tom field type and see how it works!

Transcript

Premium

Follow along with the full transcript

Search every word, click any line to jump to that moment, and read along as you watch — a CraftQuest Premium feature.

Sign up for Premium
Craft Version
Craft 4
Instructor
Level
Intermediate
Date Published
May 12, 2021