Create Pages
Creating a module often requires creating a section where how the module works can be configured. NexoPOS comes with a settings API that aims to ease the creation of the settings for developers. Before proceeding with this guide, we believe you already know how to :
The settings API interacts with the Options API and validates, stores, and fetches your settings for you.
Creating A Settings Page Class
Every settings page must extend `App\Services\SettingsPage`. Within your module, you'll store your settings page in a folder named "Settings", "Forms" or any folder name that makes sense for you, as no convention has been decided for that. Typically, here is how the class must look.
<?php
namespace Modules\MyFooBarModule\Settings;
use App\Services\SettingsPage;
use App\Classes\SettingForm;
class MyFooBarSettings extends SettingsPage
{
const IDENTIFIER = 'your-settings-identifier';
const AUTOLOAD = true;
public function __construct()
{
// do not perform any data load here
// as during the registration and the built, the settings are intantiated twice
}
public function getForm(): array
{
return SettingForm::form(
title: 'My Settings Page',
description: 'description page',
tabs: SettingForm::tabs(
SettingForm::tab(
identifier: 'general',
label: __( 'General' ),
fields: SettingForm::fields(
// fields goes here
)
)
)
);
}
}
Here, we define the method "getForm", which defines the shape of the form.
A settings page usually consists of tabs and fields, but not only. From NexoPOS >= 5.3, you can also assign a custom Vue component to tabs and fields.
<?php
namespace Modules\MyFooBarModule\Settings;
use App\Services\SettingsPage;
use App\Classes\SettingForm;
class MyFooBarSettings extends SettingsPage
{
const IDENTIIER = 'my-foo-bar-settings';
const AUTOLOAD = true;
public function getForm()
{
return SettingForm::form(
title: __( 'My Settings Page' ),
description: __( 'a sort settings description' ),
tabs: SettingForm::tabs(
// your tabs go there.
)
);
}
}
Structure of a field
Most fields have a common way of being defined. Usually, a field looks like this.
[
'type' => 'text',
'label' => __( 'My Field Name' ),
'description' => __( 'My field description' ),
'validation' => 'required',
'name' => 'my_field_name'
]
These are however not all the parameters that can be used for a field. So some field such as "select" requires more attributes that are explained on this list of supported attributes.
type
Every field definition must have a "type" that defines the type of the field. Supported types are :
- text
- textarea
- number
- select
- media
- switch
- multiselect
- checkbox
- ckeditor
- datetimepicker
- password
- tel
- date
label
The label is what the user will see as the field name. This should be descriptive of what the field is about.
description
The description provides more hints on the field. This can be useful to explain how the field will be used.
validation
This is used to enforce validation for a field. All Laravel's validation strings a supported (on the backend). Validations based on an object are ignored on the front end as well as validation that performs a check on the database.
name
This is the name of the field but also the name of the option. In case you create a settings page for your module, you should prefix all of your fields' names. For example, NexoPOS uses "ns_" as a prefix for all the settings created for the system, so it's a reserved prefix. However, you should note that your name value should never use a dot as a separator. For example "my.custom.field.name", is not allowed.
value
This is the desired value that needs to be displayed on the field. Usually, you'll need to use the options here to fetch the option from the database using "ns()->option->get( '[your field name]' )", where [your field name] must be replaced by the field name as you have defined above.
options
This is only used for "switch", "select" and "multiselect" field types. It consists of an array having an array as an option. Typically, it is designed like this.
[
[
'label' => __( 'Choose Me' ),
'value' => 'choose_me'
], [
'label' => __( 'No choose me' ),
'value' => 'no_choose_me'
]
]
This can be shortened using an array helpers :
Using kvTojsOptions
<?php
use App\Services\Helper;
Helper::kvToJsOptions([
'choose_me' => __( 'Choose Me' ),
'no_choose_me' => __( 'No choose me' ),
]);
// will convert into
/**
* [
* [
* 'label' => __( 'Choose me' ),
* 'value' => 'choose_me',
* ], [
* 'label' => __( 'No choose me' ),
* 'value' => 'no_choose_me'
* ]
* ]
*
**/
Using toJsOptions
This should be used while converting a collection into options for a field. This function accepts as first parameter the collection, and as second an array whose first index should be the "value" and second index should be the "label".
<?php
use App\Services\Helper;
use App\Models\User;
Helper::kvToJsOptions( User::get(), [ 'id', 'username' ]);
// will convert into
/**
* [
* [
* 'label' => 'blair_jersyer',
* 'value' => 10,
* ],
* // ...
* ]
*
**/
If you would like to have a look at a complete settings page, you can check this file from the source code of NexoPOS.
Render A Vue Component
If you would like to completely change the layout of the settings and create a custom settings page that is actually a Vue component, it's also possible. To get started, you'll have to inject your Vue component. Once it's done, while defining your form, instead of providing a "fields" attribute, you'll provide the "component" attribute.
Let's suppose you've injected your view component as follows :
<script>
nsExtraComponents.myCustomComponent = Vue.component( 'my-extra-component', {
// your component here
});
</script>
You can see that our component registered name is "myCustomComponent". That is the name we'll use on the "component" attribute like this.
[
'tabs' => [
'general' => [
'component' => 'myCustomComponent', // here
'label' => __( 'My FooBar General Settings' )
],
]
]
When the page will be rendered, NexoPOS will try to resolve the dynamic component and replace the body of the settings with that.
Registering Settings Page
From NexoPOS 5.3, you no longer need to register the settings page. If you want a setting page to be an autoloader, you should define a constant in your setting class as AUTOLOAD = true.
<?php
namespace Modules\MyFooBarModule\Settings;
use App\Services\SettingsPage;
use App\Classes\SettingForm;
class MyFooBarSettings extends SettingsPage
{
const IDENTIIER = 'my-foo-bar-settings';
const AUTOLOAD = true; // autoload here
public function getForm()
{
return SettingForm::form(
title: __( 'My Settings Page' ),
description: __( 'a sort settings description' ),
tabs: SettingForm::tabs(
// your tabs go there.
)
);
}
}
How To Render Settings Page
Now it's time to render a settings page. What you'll need is to create a route that points to a controller method where we'll use the class we have created so far.
<?php
namespace Modules\MyFooBarModule\Http\Controllers;
use Modules\MyFooBarModule\Settings\MyFooBarSettings;
use App\Http\Controllers\DashboardController;
class MyFooBarController extends DashboardController
{
public function showSettingsPage()
{
return MyFooBarSettings::renderForm();
}
}