The Themosis framework is bundled with an API to build custom fields. This API is leveraged by the framework to help you build WordPress metabox custom fields, page settings, ... and form fields.
The Field
class is a generic class that you should use to build any type of custom fields within your application. This class is used for:
The Field
class has been fully refactored and no longer returns just a HTML tag. Each time a field is created, it returns a FieldTypeInterface
instance. Depending on the context, the field API has methods to return each instance either as a string for HTML output, as an array of properties or as a JSON object.
Each field method signature follow the same structure, the first argument is the name
and the second argument is an array of options
like so:
Field::text('name', [
'label' => 'Full name',
...
]);
Before going into each field and their specific options, let's first list all the shared options you can use on all instances.
The attributes
option allows you to define an array of HTML attributes for your field. The key is the attribute name and its value the attribute value. For some attributes, it is also possible to omit the value and only pass the key name.
Field::text('demo', [
'attributes' => [
'id' => 'demo-id',
'class' => 'custom-demo',
'required'
]
]);
The data
option lets you define a default value for your field. You can either set a string or an array default value depending on the field type.
Field::text('demo', [
'data' => 'Initial value'
]);
The data_type
option is mainly used for fields combined with WordPress elements like metabox, settings, ... The data_type
value is used by the WordPress RestAPI and let you define the type of the data stored by the field: string
, boolean
, array
, ... and that is going to be exposed by the RestAPI schema.
Field::text('demo', [
'data_type' => 'string'
]);
The errors
option lets you display or not the field errors messages. The option only accepts a boolean value. Default value is true
.
The
errors
option is not handled by the field when used with a metabox.
Field::text('demo', [
'errors' => false
]);
The flush
option defines if the value of the field should be flushed after a successful validation. By default, it is set to false
.
Note that if the field is used from the context of a form, by default it is set to
true
.
Field::text('demo', [
'flush' => true
]);
The group
option lets you organize your fields by groups. Mainly used by the default form API where you can specify a group name for your field. The parent container is then using that information to group fields and wrap them in a HTML container at output.
Here is an example of its usage with a form:
return $factory->make()
->add($fields->text('firstname', [
'group' => 'personal'
]))
->add($fields->text('lastname', [
'group' => 'personal'
]))
->add($fields->email())
->get();
In the above example, the fields firstname
and lastname
will be grouped together at render time.
The info
option lets you specify an extra information text or content generally displayed right under the field.
Field::text('demo', [
'info' => 'This is a short description displayed below the field.'
]);
The l10n
option lets you store translations texts for your field. You can pass an array of key/value pairs where the key is the translation ID and the value, the translation text. This option is helpful when you need to provide translated text on fields rendered through a JavaScript component.
Field::text('demo', [
'l10n' => [
'hello' => 'World',
'say' => __('something', 'textdomain')
]
]);
The label
option lets you specify the label HTML element text rendered beside the field.
Field::text('demo', [
'label' => 'Demonstration'
]);
The label_attr
option lets you define the HTML attributes of the field label element. You can pass an array of key/value pairs where the key is the attribute name and the value, the attribute value.
Field::text('demo', [
'label_attr' => [
'class' => 'form-label'
]
]);
The mapped
option is used by the form API in order to know if the field should be mapped or not to a data object property. By default, its value is set to true
.
Here is an example on a form context:
return $factory->make($dto)
->add($fields->password('password'))
->add($fields->password('password_confirmation', [
'mapped' => false
]))
->get();
In the above example, the field password_confirmation
is not mapped to the given data object.
The messages
option lets you define a list of validation messages by rule. You can pass an array of key/value pairs where the key is the validation rule name and the value, the validation message text.
Field::text('demo', [
'rules' => 'required|min:6',
'messages' => [
'required' => 'The :attribute field is a required and very important field.',
'min' => 'The :attribute field must be at least :min characters long.'
]
]);
The placeholder
option is used by the validation. You can specify a custom text value for the : attribute
placeholder in a validation message. By default it takes the field name as a value.
Field::text('demo', [
'placeholder' => 'demonstration'
]);
The rules
option lets you define a list of validation rules for the field. Validation is handled by the illuminate/validation
package. Click here to view a full list of available validation rules.
Field::text('demo', [
'rules' => 'required|min:6|max:191'
]);
The show_in_rest
option is used by WordPress. The option accepts a boolean value and lets you specify if your field (post meta, ...) should be shown in the WordPress Rest API. This option mainly works within the context of a metabox, a page setting, a term meta, ... Its default value is set to false
Here is an example in the context of a metabox custom field:
Metabox::make('properties', 'post')
->add(Field::text('show_me', [
'show_in_rest' => true
]))
->set();
The theme
option lets you choose the output style of your field. This option only works within the context of a form. You can choose between the default themosis
theme or the bootstrap
theme.
Generally, it is not necessary to define a theme value on a per field basis. The form API also provide a theme option in order to apply it to all its children elements (fields).
Field::text('demo', [
'theme' => 'bootstrap'
]);
Here is the list of fields bundled with the framework. Please note that some fields from the list below are not available on some contexts.
The button field can only be used within a form context in order to add a submit/button field.
Field::button($name, $options = []);
The checkbox field only handles a single checkbox input. In order to build a field with multiple checkbox inputs, please use the new choice field.
Field::checkbox($name, $options = []);
The choice field allows you to create 4 different types of field:
The choice field accept as a first parameter a name and in order to attach a list of options to your field, you need to pass a choices
option to it like so:
Field::choice('color', [
'choices' => ['red', 'green', 'blue']
]);
The above example renders a single select input element.
The choice field is by default configured to output a single select input element. You can pass a list of options by using the choices
property.
The choices
field option accepts an array as a value and the structure of your array also defines its output.
If you pass a numeric array as a value for your field choices
option, each array item is considered as the option value.
For example:
// Select field with numeric array:
Field::choice('color', [
'choices' => [
'red',
'green',
'blue'
]
]);
// Output the following HTML:
<select name="th_color">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
The array value is always used as the option element value.
If you pass an associative array as a value for your field choices
option, the key is option element text and the value its value attribute.
For example:
// Select field with associative array
Field::choice('color', [
'choices' => [
'Red Color' => 'red',
'Green Color' => 'green',
'Blue Color' => 'blue'
]
]);
// Output the following HTML:
<select name="th_color">
<option value="red">Red Color</option>
<option value="green">Green Color</option>
<option value="blue">Blue Color</option>
</select>
If you pass an array of array as a value for your field choices
option, you can output a select field with optgroup HTML elements.
For example:
// Select field with optgroup elements
Field::choice('color', [
'choices' => [
'Light Colors' => [
'red',
'green',
'blue'
],
'Dark Colors' => [
'Dark purple' => 'purple',
'Dark brown' => 'brown',
'Deep black' => 'black'
]
]
]);
// Output the following HTML
<select name="th_color">
<optgroup label="Light Colors">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</optgroup>
<optgroup label="Dark Colors">
<option value="purple">Dark purple</option>
<option value="brown">Dark brown</option>
<option value="black">Deep black</option>
</optgroup>
</select>
The choice field can also be used to build a select field with multiple options. In order to let a user select multiple values, set the field multiple
option to true
like so:
Field::choice('color', [
'choices' => [
'red',
'green',
'blue'
],
'multiple' => true
]);
The choice field can generate a radio input field by setting the field expanded
option to true
:
Field::choice('direction', [
'choices' => [
'left',
'right'
],
'expanded' => true
]);
You can create a multiple checkbox field by setting the expanded
and multiple
option of the choice field to true
:
Field::choice('languages', [
'choices' => [
'css',
'html',
'javascript,'
'php'
],
'expanded' => true,
'multiple' => true
]);
The collection field is only available within a metabox context and allows a user to insert multiple WordPress media items. The field only stores the WordPress attachment ID.
The collection field UI allows an end-user to add, order, delete or bulk delete attachments. Useful for galleries or specifying a list of files to download,...
The collection field is only available within a metabox context.
Field::collection($name, $options = []);
The collection field also accepts a limit
option which allows you to limit the number of media a user can add to the collection.
You can also specify the type
of media attachment to insert into the collection by passing a type
option to the field. The type
option accepts a string or an array of those values: image
, application
, video
, audio
, text
. By default, the type
options has the following value ['application', 'image']
// The default collection field allows you to manage images and files
Field::collection('gallery');
// Same but only for files.
Field::collection('papers', [
'type' => 'application'
]);
Field::collection('files', [
'type' => 'image'
]);
Using the limit
option, you can limit the number of media files a user can add to the collection field:
// Limit the number of media to add to a collection.
Field::collection('pictures', [
'limit' => 5
]);
Build a color field and display a color picker widget so end-users can easily pick a color.
Note that the color field is only available within a metabox context.
Field::color($name, $options = []);
You can specify a set of default colors for the field by passing a list of colors to the colors
field option like so:
Field::color('brand', [
'colors' => [
[
'name' => 'Primary Color',
'color' => '#f78da7'
],
[
'name' => 'Secondary Color',
'color' => '#cf2e2e'
]
]
]);
Note how the list of colors is formatted, you must pass an array of array with the keys
name
andcolor
.
The above example will output a color field with 2 default colors and a color picker.
The color field provides a color picker by default to let the end-user choose a custom color. You can disable this feature and in that case limit the user to use only the pre-defined color palette.
In order to disable the color picker, set the disableCustomColors
option to true
:
Field::color('brand', [
'disableCustomColors' => true
]);
Create a WordPress Editor TinyMCE field.
Field::editor($name, $options = []);
You can control the behavior of the TinyMCE editor by passing a settings
option to the editor field. The settings
option accepts an array of parameters. Use this codex guide to define the field settings
option.
If you're using the editor field within the context of a metabox, use the settings_js
option instead.
Create an email input field.
Field::email($name, $options = []);
Create a hidden input field. In the context of a page setting, the hidden field displays a disabled input, the value is then visible to end-users.
The hidden field is not supported on term fields and user fields.
Field::hidden($name, $options = []);
In order to specify the default value for a hidden field, use the data
option like so:
Field::hidden('apikey', [
'data' => 'XYZ123456789'
]);
Create a number input field where its value is always formatted to an integer numeric value. The field helps reinforce the value so an end-user cannot enter a float number.
Field::integer($name, $options = []);
Build a WordPress media field. This field allows you to upload or attach any file by using the WordPress Media API.
The media field is only available within a metabox context.
Field::media($name, $options = []);
By default, the media field allows you to attach images only.
Field::media('profile');
In order to allow the media field to attach other files except images, you need to specify the type
feature like so:
Field::media('report', [
'label' => 'Attach report',
'type' => 'application'
]);
In some scenario, you might need to define multiple types, like having the ability to let users choose a PDF file or an image. In order to define multiple types, simply pass an array:
Field::media('attachments', [
'label' => 'Share a file',
'type' => ['image', 'application']
]);
The
type
option accepts the following values:image
,text
,application
,video
andaudio
.
Create a number input field where float values are accepted.
Field::number($name, $options = []);
Build a password input field.
Field::password($name, $options = []);
The submit field can only be used within a form context in order to add a submit input. Similar to the button field.
Field::submit($name, $options = []);
The text field output an input tag with a type of text
.
Field::text($name, $options = []);
Build a textarea field: <textarea></textarea>
Field::textarea($name, $options = []);
As mentioned in the introduction, the new Field API is no longer just returning a string of HTML but each time you create a field you get back a FieldTypeInterface
instance.
The new API allows you to use it outside of the default core contexts and gives you several methods to control the behavior of your field as well as render it or transform it in a JSON object.
It is recommended to use the Field
facade to create new field instances. The facade is referencing a field factory class. Each time you call a factory method, it sets up the field main dependencies and sets its options.
In order to create a new field instance, simply use the Field
facade like so:
$title = Field::text('title');
The $title
variable is now a FieldTypeInterface
instance.
By default, all field instances generate a field name value that is prefixed by th_
. If you were to render the above field, its input name will be th_title
.
As mentioned above, by default, all field names are prefixed by th_
. This is done on purpose in order to avoid conflict with WordPress query vars. You can retrieve the composed name by using the getName
method on a field instance like so:
$title = Field::text('title');
// Output: th_title
var_dump($title->getName());
It is also possible to retrieve the field base name, without its prefix by calling the getBaseName
method on a field instance:
$title = Field::text('title');
// Output: title
var_dump($title->getBaseName());
You can modify the default prefix of a field by using the setPrefix
method. In the case where you no longer want to use a prefix, you can pass an empty string as a parameter:
$title = Field::text('title');
$title->setPrefix('wp_');
// or remove the prefix
$title->setPrefix('');
The FieldTypeInterface
also provides a method in order to return the field instance prefix. Use the getPrefix
method to retrieve its value:
$title = Field::text('title');
$prefix = $title->getPrefix();
// Output: th_
var_dump($prefix);
The Field
facade allows you to pass field options as a second parameter when creating a new instance. Just note that the field factory is calling the setOptions
method on a field instance for you as well as setting the field locale and view factory dependencies.
Some fields have specific and shared options. Pass field options using the second parameter of the factory method like so:
Field::text($name, $options);
You can retrieve all field options by calling the getOptions
method. The method returns an array of key/value pairs where the key is the option name and the value, the option value.
$title = Field::text('title');
$options = $title->getOptions();
It is also possible to retrieve a single option value by using the getOption
method like so:
$title = Field::text('title');
$attributes = $title->getOption('attributes');
If the option is not yet set on the field instance and you're calling the getOption
method, you can also define a default value to return as a second parameter:
$title = Field::text('title');
$group = $title->getOption('group', 'general');
A field instance implements the ArrayAccess interface. It is also possible to get or set field options using the array syntax.
The field instance must handle its data. Each field instance contains a data transformer class. The data transformer class must implement the DataTransformerInterface
and provides two methods: transform
and reverseTransform
. The transform
method is responsible to convert raw data to an expected data type and the reverseTransform
method to convert it back to its raw value.
For example, the Integer field has a data transformer to reinforce the value transformation as an integer. A date field might implement a transformer that takes a date string and transform it as a DateTimeImmutable object, ...
In order to set the field value, you may use the setValue
method like so:
$title = Field::text('title');
$title->setValue($request->get($title->getName()));
The setValue
method calls the field transform
method and store the transformed value within the instance.
You can retrieve a field value by using the getValue
method:
$title = Field::text('title');
$value = $title->getValue();
The getValue
method returns the currently stored value of the instance. This means that it is always the transformed value that is returned.
You can retrieve the raw value of your field by calling the getRawValue
method. The getRawValue
is calling the reverseTransform
field method in order to return the initial raw value:
$title = Field::text('title');
$rawValue = $title->getRawValue();
When used outside of a core context, a field does not have a view file attached to it in order to be rendered. In order to customize the output of your field, you may use the setView
method like so:
$text = Field::text('title');
$text->setView('fields.text');
By default, a field instance will try to use the defined view without prefixing its path with a theme
. The above example will try to render the field using the fields/text.blade.php
view file.
<!-- resources/views/fields/text.blade.php -->
<input type="text" name="{{ $__field->getName() }}"/>
All field views received their field instance which is accessible under the $__field
variable:
Here is an example of a custom text view using field methods:
<label {!! $__field->attributes($__field->getOption('label_attr')) !!}>{!! $__field->getOption('label') !!}</label>
<input type="text" name="{{ $__field->getName() }}" {!! $__field->attributes($__field->getAttributes()) !!} value="{{ $__field->getRawValue() }}">
Note the use of the attributes
method that accepts an array of HTML attributes.
You can also pass custom data to your field view by using the with
method:
// Pass single data
Field::text('note')
->setView('fields.custom')
->with('title', 'Some content for the title');
// Pass multiple data
Field::text('note')
->setView('fields.custom')
->with([
'title' => 'The title value',
'two' => 'Another value'
]);
The use of the with
method is only relevant when building custom field views. Core views will ignore passed custom data.
If you want to use framework existing views, you need to define at least a theme to your field. Two themes are defined by the framework, you can use the themosis
or the bootstrap
theme and call the setTheme
method:
$title = Field::text('title');
$title->setTheme('themosis');
A theme is mainly a directory name that stores field views. By setting a theme, we basically prepend the theme name in front of the field default view path. On the above example, the field view path will be: themosis.types.text
and is looking after a themosis/types/text.blade.php
view file for output.
In order to render a field, you may call the render
method on a field instance. For example, from a controller you might define your field and pass it to a view like so:
public function index()
{
$title = Field::text('title');
$title->setTheme('themosis');
return view('page', [
'field' => $title
]);
}
And then render the field instance by using its render
method:
{!! $field->render() !!}
The FieldTypeInterface
provides methods to transform a field instance into a resource.
The field transformation uses the PHP League Fractal package. You must add a fractal Manager
instance to your field as well as a transformer class in order to modify the field as a resource. Use the Themosis\Forms\Resources\Factory
class to set the transformer class for your field. The factory will try to load the appropriate transformer for you.
Each field must have an instance of a fractal Manager
and a transformer instance:
use League\Fractal\Manager;
use Themosis\Forms\Resources\Factory;
$title = Field::text('title');
// Set the fractal manager instance.
$title->setManager(new Manager());
// Set the transformer using core resource factory.
$title->setResourceTransformerFactory(new Factory());
You can define your own transformer class by passing the fully qualified name of your transformer to the resources factory constructor like so:
$title->setResourceTransformerFactory(new Factory('\\App\\Transformers\\TitleTransfomer'));
You can transform your field as an associative array by using the toArray
method like so:
use League\Fractal\Manager;
use Themosis\Forms\Resources\Factory;
$title = Field::text('title');
$title->setManager(new Manager());
$title->setResourceTransformerFactory(new Factory());
var_dump($title->toArray());
// Output the following resource
[
"attributes" => [
"id" => "th_title_field"
]
"basename" => "title"
"component" => "themosis.fields.text"
"data_type" => ""
"default" => ""
"name" => "th_title"
"options" => [
"group" => "default"
"info" => ""
"l10n" => []
]
"label" => [
"inner" => "Title"
"attributes" => [
"for" => "th_title_field"
]
]
"theme" => ""
"type" => "text"
"validation" => [
"errors" => true
"messages" => []
"placeholder" => "title"
"rules" => ""
]
"value" => ""
]
You can transform your field as a JSON object by using the toJson
method like so:
use League\Fractal\Manager;
use Themosis\Forms\Resources\Factory;
$title = Field::text('title');
$title->setManager(new Manager());
$title->setResourceTransformerFactory(new Factory());
var_dump($title->toJson());
Check those guide to implement your custom fields:
Made in Belgium