Creating a Settings Form in your Extension.¶
In quite a few cases, you will need some settings for your extension. In this example, we will create settings for a URL, a Client ID, a Client Secret and which financial type to use.
This guide will show you how to
- add some settings to your extension
- have a form for those settings
- add the form to the navigation menu
- make some settings in the form mandatory
- validate a setting when the form is submitted.
Add Settings to your Extension¶
First thing is to add a settings folder to your extension and add a file yourextensionname.settings.php in the folder, as you can see in the example below.

In the myextension.settings.php file, you will define the settings. More information can be found in the Settings part of this Developer Guide.
return [
'ehvoorbeeld_url' => [
'name' => 'ehvoorbeeld_url',
'title' => 'URL to connect to My Wonderful Site',
'type' => 'String',
'html_type' => 'text',
'html_attributes' => [
'class' => 'huge',
],
'add' => '6.7',
'is_domain' => 1,
'is_contact' => 0,
'help_text' => 'URL to connect to My Wonderful Site',
'settings_pages' => ['ehvoorbeeld' => ['weight' => 10]],
],
'ehvoorbeeld_client_id' => [
'name' => 'ehvoorbeeld_client_id',
'title' => 'Client ID to connect to My Wonderful Site',
'type' => 'String',
'html_type' => 'text',
'html_attributes' => [
'class' => 'huge',
],
'add' => '6.7',
'is_domain' => 1,
'is_contact' => 0,
'help_text' => 'Client ID to connect to My Wonderful Site',
'settings_pages' => ['ehvoorbeeld' => ['weight' => 15]],
],
'ehvoorbeeld_client_secret' => [
'name' => 'ehvoorbeeld_client_secret',
'title' => 'Client Secret to connect to My Wonderful Site',
'type' => 'String',
'html_type' => 'text',
'html_attributes' => [
'class' => 'huge',
],
'add' => '6.7',
'is_domain' => 1,
'is_contact' => 0,
'help_text' => 'Client Secret to connect to My Wonderful Site',
'settings_pages' => ['ehvoorbeeld' => ['weight' => 20]],
],
];
As you can see, the name of the extension is included for each setting.
You will also have to make sure that your info.xml file contains the relevant mixin for settings. If you have used civix to generate your extension it probably already is. But check :-)
For example, this would be the required definition if it was just one mixin. You probably already have a mixins element in your info.xml but if not, you can just add the settings mixin.
<mixins>
<mixin>setting-php@1.0.0</mixin>
</mixins>
Create a Form for your Settings¶
Next we will see how we can now add a form to CiviCRM to manage these settings.
The actual form will be autogenerated by CiviCRM (and updated once you clear your caches), but CiviCRM needs to know where to find it. For that, you need to:
- create a folder called Menu within the xml folder of your extension
- add a file called yourextensionname.xml

As you can see, there is a file called ehvoorbeeld.xml within my xml/Menu folder and it will contain this:
<?xml version="1.0"?>
<menu>
<item>
<path>civicrm/admin/setting/ehvoorbeeld</path>
<title>Settings for the Developer Documentation Settings How To</title>
<page_callback>CRM_Admin_Form_Generic</page_callback>
</item>
</menu>
If you now clear your caches (from the UI or with cv flush) you can now load the form if you use the URL:

Add the Settings Form to the CiviCRM Menu¶
That is all very fine but you probably also want to add the settings form you just created to the CiviCRM menu rather than the user typing the URL :-)
We use the navigationMenu hook (see Navigation Menu Hook for this hook or Hooks for a more generic explanation of hooks).
Go to the yourextensionname.php file (so in this case ehvoorbeeld.php) in the extension folder and add the following code:
/**
* Implements hook_civicrm_navigationMenu().
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_navigationMenu/
*/
function ehvoorbeeld_civicrm_navigationMenu(&$menu) {
_ehvoorbeeld_civix_insert_navigation_menu($menu, 'Administer/System Settings', [
'label' => 'Settings for the Developer Documentation Settings How To',
'name' => 'ehvoorbeeld_settings',
'url' => CRM_Utils_System::url('civicrm/admin/setting/ehvoorbeeld', ['reset' => TRUE]),
'permission' => 'administer CiviCRM',
'operator' => 'OR',
'separator' => 0,
]);
}
If you now clear your caches (or do a cv flush), you should see the new menu item for your settings form in the menu.
Make Settings Mandatory on Form¶
Some settings on the form might need to be required. At the moment, you can not use the settings definitions to achieve that but you can do this with the buildForm hook.
First of all, create a Civi folder and then within that folder, create a Yourextensionname folder, so in this case a folder called Ehvoorbeeld.

Next we add a listener to the yourextensionname.php file to define what to do when listening for the buildForm hook.
This is done in the ehvoorbeeld_civicrm_config function like so:
/**
* Implements hook_civicrm_config().
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config/
*/
function ehvoorbeeld_civicrm_config(&$config): void {
Civi::dispatcher()->addListener('hook_civicrm_buildForm', ['Civi\Ehvoorbeeld\HookHandler', 'setRequiredSettings']);
_ehvoorbeeld_civix_civicrm_config($config);
}
When you generate your extension with civix, the function ehvoorbeeld_civicrm_config will already be in your myextensionname.php file.
In the code above, this says that within the class Civi\Ehvoorbeeld\HookHandler, we will have a function setRequiredSettings.
Next, we add a php file to define the class. In this case, the filename is HookHandler.php

Below, you can see the code in this php file which will be processed when the listened for buildForm hook occurs.
namespace Civi\Ehvoorbeeld;
use \Civi\Core\Event\GenericHookEvent;
use CRM_Ehvoorbeeld_ExtensionUtil as E;
/**
* Class to handle the hooks listeners within this extension
*
* @author Erik Hommel (CiviCooP) <erik.hommel@civicoop.org>
* @license AGPL-3.0
*/
class HookHandler {
public static function setRequiredSettings(GenericHookEvent $event): void{
if ($event->formName === "CRM_Admin_Form_Generic") {
$requiredSettings = ['ehvoorbeeld_url', 'ehvoorbeeld_client_id', 'ehvoorbeeld_client_secret'];
foreach ($requiredSettings as $setting) {
if (isset($event->form->_elementIndex[$setting])) {
$event->form->addRule($setting, E::ts("This field is required"), 'required');
}
}
}
}
}
In this code above, we check for 3 elements on the settings form and add the required rule to each of them so now these fields on the form are required:

Validate a Setting when the Form is Submitted¶
On this settings form, we have asked the user to enter a URL and it would be a good idea to check if the URL that was entered is actually a valid URL.
We can do this with the Validate Form hook.
First we add a listener for the validateForm hook to our myextensionname.php file (as we have done in the section above for the buildForm hook):
/**
* Implements hook_civicrm_config().
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config/
*/
function ehvoorbeeld_civicrm_config(&$config): void {
Civi::dispatcher()->addListener('hook_civicrm_buildForm', ['Civi\Ehvoorbeeld\HookHandler', 'setRequiredSettings']);
Civi::dispatcher()->addListener('hook_civicrm_validateForm', ['Civi\Ehvoorbeeld\HookHandler', 'validateUrl']);
_ehvoorbeeld_civix_civicrm_config($config);
}
And then we add the validateUrl function to the HookHandler class in the HookHandler.php file we created in the section above for the required fields:
*
* @param GenericHookEvent $event
* @return void
*/
public static function validateUrl(GenericHookEvent $event): void {
if ($event->formName === "CRM_Admin_Form_Generic") {
if (isset($event->fields['ehvoorbeeld_url'])) {
if (!filter_var($event->fields['ehvoorbeeld_url'], FILTER_VALIDATE_URL)) {
$event->errors['ehvoorbeeld_url'] = E::ts("This URL is not valid.");
}
}
}
}
And done!