Introduction #
The goal of this article is to help you become familiar with easily creating custom input fields using fluentforms.. We will create new input field using the BaseFieldManager class. In this example we will see how we can leverage other prebuilt classes available in fluent forms and how to create custom UI settings for a input. This field will work as a confirmation field such as password, email or other text confirmation field. User will set target input and the input will validate according to the target input value.
ConfirmField Class #
First let us create a class ConfirmField which will be an extended class of BaseFieldManager class. All input field are extended form this class so this is like a skeleton class of fluentforms input fields BaseFieldManager is an abstract Class which is extended by BaseComponent class. So, It will look like this :
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly.
}
class ConfirmField extends \FluentForm\App\Services\FormBuilder\BaseFieldManager
{
We extended our ConfirmField class by including BaseFieldManager with its namespace. Now We have to call the parent class construct method from ConfirmField classes construct method .
__construct() #
In this method we will call the Parent classes’s __construct method. It needs 4 parameters
- $key : Unique key identifier
- $title : Input tile in form editor
- $tag : Search tags for this input
- $position : Position of the input in the form editor (general | advanced | payments )
Here is the code :
public function __construct()
{
parent::__construct(
'confirm_field',
'Confirm Input',
['confirm', 'check'],
'general'
);
}
getComponent() #
Next we will create getComponent() method which will return the configuration array of the input. This is the most important part. The array includes four core property, index, element, attributes, settings, editor_options. First property index represents the serial number this field will appear in the form editor. element is the key, attributes data will be used when rendering in frontend.
public function getComponent()
{
return [
'index' => 16,
'element' => $this->key,
'attributes' => [
'name' => $this->key,
'class' => '',
'value' => '',
'type' => 'text',
'placeholder' => __('Confirm Input', 'text-domain')
],
'settings' => [
'container_class' => '',
'placeholder' => '',
'auto_select_country' => 'no',
'label' => $this->title,
'label_placement' => '',
'help_message' => '',
'validate_on_change' => false,
'target_input' => '',
'error_message' => __('Confirm value does not match', 'text-domain'),
'validation_rules' => [
'required' => [
'value' => false,
'message' => __('This field is required', 'text-domain'),
]
],
'conditional_logics' => []
],
' ' => [
'title' => $this->title . ' Field',
'icon_class' => 'el-icon-phone-outline',
'template' => 'inputText'
],
];
}
The settings property includes the fields settings which is stored in editor and can be accessed needed. Each of these property inside settings represents a setting input template and its initial value. For example , container_class represents text input which store container class. For the ConfirmField input we will need the settings ‘label’, ‘placeholder’, ‘value’, ‘label placement’, ‘validation rules’. These are already available, so we just have to define those in the settings array with the initial value.
There has 69 UI components available for making any type of settings ui for your element. You can even implement your own by implementing generalEditorElement and advancedEditorElement method. We will get into the details of creating new settings ui later. Please check the BaseFieldManager class for details.
Where to find the fluentforms built-in UI components: Please check this Github source file.
getGeneralEditorElements() #
Here we will declare what settings should appear in the general section of the input customization. These are the settings that we just defined in getComponent() method settings array. If you check the code in parent class method you will see that it returns an array of keys. We can override this method in our class if we need new settings or default settings key will be returned. As we have already mentioned these keys represents the fluentforms input settings ui template, defined in getComponent() methods settings array, now we are just placing it in general section. As you know all inputs have two section of settings general & advanced. Now if you are developer you may think what if you need a new type of settings input to store user values, it is very simple. We will do that next.
generalEditorElement() #
This is an optional method. We can define our own ui setting inputs here for the general section of the editor. For our ConfirmField we need to store target input name , error message ,and an option whether to validate when user starts typing. So let’s create those. We will use a text and a checkbox ui component to store these settings. Check the following code.
public function generalEditorElement()
{
return [
'target_input' => [
'template' => 'inputText',
'label' => 'Target Field Name',
'help_text' => 'The input value will be matched with target input and show error if not matched',
],
'error_message' => [
'template' => 'inputText',
'label' => 'Error Message',
],
'validate_on_change' => [
'template' => 'inputCheckbox',
'label' => 'Validate on Change',
'options' => array(
array(
'value' => true,
'label' => 'Yes',
),
)
],
];
}
- target_input : The key of the settings is target_input it will store the target input name for example a password or email field name. The ‘template’ of the UI will inputText as it is a text input. ‘label’ represents the settings label and ‘help_text’ will show a tooltip message info ,it is optional. Here is the output of the this Ui settings.
- error_message : This will store the error message which will be shown when the Confirmation input does not match the target input. Setting key is error_message and other option is same as the target_input ui.
- validate_on_change : We will use a checkbox ui component for this settings , to determine whether to validate when user starts typing in the input. For checkbox we will use inputCheckbox template.
render() #
This method is self explanatory. The input html will be rendered in the form from this method. We will have access to full input config with values saved from editor and we can render it exactly as we need. As this is a text input we can leverage already built text input to compile it and then we will apply our validation on it. So here is how the code looks like :
public function render($data, $form)
{
$data['attributes']['id'] = $this->makeElementId($data, $form);
$this->pushScripts($data, $form);
return (new FluentForm\App\Services\FormBuilder\Components\Text())->compile($data, $form);
}
There are some useful method available here like extractValueFromAttributes, extractDynamicValues, makeElementId, check the parent class for more. We have called another method here pushScripts , this will add our required scripts.
pushScripts() #
You can see we called this method from the render() method, to add our required JS scripts here. Here we wrote a script that will compare the current field with the target input. It will show the saved error message if the value does not match. First it will check if the validate on change settings is enabled. ArrayHelper is a helper class to access array elements easily.
private function pushScripts($data, $form)
{
add_action('wp_footer', function () use ($data, $form) {
if (!ArrayHelper::isTrue($data, 'settings.validate_on_change')) {
return;
}
?>
<script type="text/javascript">
jQuery(document).ready(function ($) {
function confirmValidate() {
let confirmInput = jQuery('.<?php echo $form->instance_css_class; ?>').find("#<?php echo $data['attributes']['id']; ?>");
let targetName = '<?php echo ArrayHelper::get($data, 'settings.target_input') ?>';
let message = '<?php echo ArrayHelper::get($data, 'settings.error_message') ?>';
let targetInput = jQuery("input[name='" + targetName + "']")
let timeout = null;
confirmInput.on("keyup", function () {
clearTimeout(timeout);
timeout = setTimeout(() => {
validate()
}, 1500);
});
function validate() {
if (confirmInput.val() !== targetInput.val()) {
let div = $('<div/>', {class: 'error text-danger'});
confirmInput.closest('.ff-el-group').addClass('ff-el-is-error');
confirmInput.closest('.ff-el-input--content').find('div.error').remove();
confirmInput.closest('.ff-el-input--content').append(div.text(message));
} else {
confirmInput.closest('.ff-el-group').removeClass('ff-el-is-error');
confirmInput.closest('.ff-el-input--content').find('div.error').remove();
}
}
}
confirmValidate();
});
</script>
<?php
}, 999);
}
validate() #
This is the final method, here we will validate the input data after submission and show error message if validation fails. It checks the target field value and current field value. This method should be called from __construct() method. Like this
add_filter("fluentform/validate_input_item_{$this->key}", [$this, 'validate'], 10, 5);
This filter is available for all input. We can use this do our validation check and show error message if required.
public function validate($errorMessage, $field, $formData, $fields, $form)
{
$ConfirmInputName = ArrayHelper::get($field, 'raw.attributes.name');
$targetInputName = ArrayHelper::get($field, 'raw.settings.target_input');
$message = ArrayHelper::get($field, 'raw.settings.error_message');
if (ArrayHelper::get($formData, $ConfirmInputName) != ArrayHelper::get($formData, $targetInputName)) {
$errorMessage = [$message];
}
return $errorMessage;
}
After we initialize this class we have our brand new custom field. We can go to the form editor a see if our new field is ready to be inserted into a form. It can be initialized like this.
add_action('fluentform/loaded',function (){
new ConfirmField();
});
You can find the complete code here.
Final Note #
It’s highly recommended to explore our source files and try to understand the design. Once you get it it’s very easy to implement your own custom input elements.
If you have any questions please feel free to reach our awesome facebook community group