Reputation: 130
I have a plugin page where I added some custom fields in order to create a form made with dynamic fields.
On my plugin page, I have an option group with the field_name and the type_of_field.
If the user selects 'select' as type of field, i would like to add dynamically another set of text fields to constitute the select options.
//definition of the fields
public function setSettings()
{
$args = array(
array(
'option_group' => 'nsp_form_option_group',
'option_name' => 'nps_form_option',
'callback' => array( $this->form_callbacks, 'formSanitize' )
)
);
$this->settings->setSettings( $args );
}
public function setSections()
{
$args = array(
array(
'id' => 'nsp_form_section',
'title' => 'Form Manager',
'callback' => array( $this->form_callbacks, 'formSectionManager' ),
'page' => 'nsp_form_manager'
)
);
$this->settings->setSections( $args );
}
// define the fields for creating a form field
// name
// type
// required
public function setFields()
{
$args = array(
array(
'id' => 'field_name',
'title' => 'Field Name',
'callback' => array( $this->form_callbacks, 'textField' ),
'page' => 'nsp_form_manager',
'section' => 'nsp_form_section',
'args' => array(
'option_name' => 'nsp_form_option',
'label_for' => 'field_name',
'placeholder' => 'eg. Profession'
)
),
array(
'id' => 'type_of_field',
'title' => 'Type of Field',
'callback' => array( $this->form_callbacks, 'selectField' ),
'page' => 'nsp_form_manager',
'section' => 'nsp_form_section',
'args' => array(
'option_name' => 'nsp_form_option',
'label_for' => 'type_of_field',
'options' => array(
'textfield' => 'Text',
'checkbox' => 'Checkbox',
'radio' => 'Radio buttons',
'select' => 'Select',
'textarea' => 'Textarea'
)
)
),
array(
'id' => 'required',
'title' => 'Required',
'callback' => array( $this->form_callbacks, 'checkboxField' ),
'page' => 'nsp_form_manager',
'section' => 'nsp_form_section',
'args' => array(
'option_name' => 'nsp_form_option',
'label_for' => 'required',
'class' => 'ui-toggle'
)
)
);
$this->settings->setFields( $args );
}
//creation of fields
public function registerCustomFields()
{
// register setting
foreach ( $this->settings as $setting ) {
register_setting( $setting["option_group"], $setting["option_name"], ( isset( $setting["callback"] ) ? $setting["callback"] : '' ) );
}
// add settings section
foreach ( $this->sections as $section ) {
add_settings_section( $section["id"], $section["title"], ( isset( $section["callback"] ) ? $section["callback"] : '' ), $section["page"] );
}
// add settings field
foreach ( $this->fields as $field ) {
add_settings_field( $field["id"], $field["title"], ( isset( $field["callback"] ) ? $field["callback"] : '' ), $field["page"], $field["section"], ( isset( $field["args"] ) ? $field["args"] : '' ) );
}
}
// template
<div class="wrap">
<h1>Form Fields Manager</h1>
<?php settings_errors(); ?>
<form method="post" action="options.php">
<?php
settings_fields( 'nsp_form_option_group' );
do_settings_sections( 'nsp_form_manager' );
submit_button();
?>
</form>
</div>
I was thinking doing an ajax request 'onchange' and create new fields in php, but then how would I update the template to display / hide the fields ?
Or another approach ?
Upvotes: 0
Views: 1577
Reputation: 130
Ok so first I would edit the title of the question by
How to add dynamic fields in a form in a plugin page using settings API
I kind of found a solution, not sure it's the best approach but it works
// ajax function
const select_field = document.getElementById('type_of_field');
const form_field_id = document.getElementById('form_field_id');
select_field.addEventListener('change', (event) => {
if(!event.target.value) {
alert('Please Select One');
return;
}
const count = select_field.options.length;
if(event.target.value == 'select') {
fetch(ajaxurl , {
credentials: 'same-origin',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cache-Control': 'no-cache',
},
method: "POST",
body: 'action=update_form'
}).then(res => {
return res.text();
})
.then(data => {
form_field_id.innerHTML = data;
});
}
})
and then I replace all the content of the form (not just the field added)
public function update_form()
{
$field = array(
'id' => 'option',
'title' => 'Option',
'callback' => array( $this->form_callbacks, 'textField' ),
'page' => 'nsp_form_manager',
'section' => 'nsp_form_section',
'args' => array(
'option_name' => 'nsp_form_option',
'label_for' => 'option',
)
);
add_settings_field( $field["id"], $field["title"], ( isset( $field["callback"] ) ? $field["callback"] : '' ), $field["page"], $field["section"], ( isset( $field["args"] ) ? $field["args"] : '' ) );
$res = settings_fields( 'nsp_form_option_group' ) . do_settings_sections( 'nsp_form_manager' ) . submit_button();
echo $res;
wp_die();
}
// form.php (where the form is displayed)
<div class="wrap">
<h1>Form Fields Manager</h1>
<?php settings_errors(); ?>
<form method="post" action="options.php" id="form_field_id">
<?php
settings_fields( 'nsp_form_option_group' );
do_settings_sections( 'nsp_form_manager' );
submit_button();
?>
</form>
</div>
Upvotes: 0
Reputation: 78
Ajax is possible, but it is also possible (and easier) to do what you want in JavaScript only, without php. I actually did something very similar to what you want to do in my wordpress backend:
Decide where you want the new fields to be displayed when you select the corresponding select option. In the HTML of that place, insert an (empty) HTML table with a unique ID.
Store the HTML code of new fields supposed to be added / to be shwon when you select the corresponding trigger option in your select menu inside a variable, let's say
let newRow = "<td>cell 1</td><td>cell 2</td>";
,if your table for example contains two columns.
a) get the (previously empty) HTML table via
let table = document.getElementById('unique-id)
;
b) In that table, you then insert a new last row (with insertRow(-1)
).
c) Then you get the last row of the table with let lastRow = table.rows[-1];
of the "new" HTML table, now containing one more row
d) And then, insert the corresponding new field into it, via lastRow.innerHTML = newRow;
.
UPDATE: (In case you want to dynamically use settings fields created in php code)
Create a javascript file, for example update_fields.js. In this file, you define a JavaScript function which does what's written above (or whatever else you want to make happen with your settings field, once the corresponding select option gets selected). Don't type any php code into this javascript file. Simply refer to your settings field in whichever way you want (as when you define a variable). For illustrative purpose, let's use let settingsField = php_variable.field;
(read until the end and you'll understand this).
Use wp_enqueue_script()
to register and enqueue your javascript file created above onto the settings page. In other words, this will import the javascript functionality created in the file mentioned in step 1. onto your settings page. To do this properly, check https://developer.wordpress.org/reference/functions/wp_enqueue_script/.
Define your settings field you wish to use dynamically if the specific select option is chosen (if not already done) in php code. Store it as a php variable, let's say $settings_field
.
Now you use wp_localize_script()
. Don't get confused by the name, "localize" here has nothing to do with places or paths, it rather refers to the translation of terms (which is the original purpose of the function; to translate terms in scripts; because the built-in translation of terms is not possible in javascript via WordPress). Anyway, you use the function to get the settings field created as php variable in step 3. and pass it to the javascript file created in step 1. After that, you will be able to use the settings field created in php as a simple javascript variable. To do this properly, check https://developer.wordpress.org/reference/functions/wp_localize_script/. Make sure to use the same $handler as used for wp_enqueue_script() in wp_localize_script().
According to the variable definition of the let settingsField
in step 1., for this example to work, you would need to use "php_variable"
as the $object name
used in the wp_localize_script()
function, and "field" => $settings_field
to assign the php_variable
object's property accessed via .field
to your settings field, originally stored as $settings_field
. This is what will allow you to use your settings field, originally created in php code, dynamically via javascript only, without any need of ajax. Clear?
Upvotes: 1