0
I'm working on a WordPress plugin and facing an issue with the Settings API. I have a settings page with two forms. The first form uses do_settings_sections() to call fields from a public function (callback). The second form renders the fields directly in the HTML.
When I submit the form that calls fields directly, it works fine. However, the form that uses do_settings_sections() and callbacks results in a "400 Bad Request" error when submitted.
Why isn't the do_settings_sections form submitting correctly?
Here's a simplified version of my code:
function snap_save_settings() {
error_log('triggered snap_save_settings, Success!');
}
add_action('admin_post_snap_save_settings', 'snap_save_settings');
class Snap_Settings extends Snap_Settings_Page {
protected function initialize_settings() {
// General Settings Section
$this->add_section('snap_main_settings', '', [$this, 'main_settings_section_callback'], 'snap-main-settings');
$this->add_field('snap_main_settings', 'snap_linking_mode', '', [$this, 'linking_mode_callback'], 'snap-main-settings');
}
//callback
public function main_settings_section_callback() {
}
public function linking_mode_callback() {
// Output a basic text input form field for testing
echo '<label for="snap_test_input">Test Input:</label>';
echo '<input type="text" id="snap_test_input" name="snap_test_input" value="">';
}
// Display Settings
public function display_settings_page() {
?>
<div class="wrap">
<!-- Form using do_settings_sections() -->
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<label>This form is rendered using do_settings_sections and does not work</label>
<input type="hidden" name="action" value="snap_save_settings">
<?php
settings_fields('snap_settings_group');
do_settings_sections('snap-main-settings');
submit_button();
?>
</form>
<br>
<br>
<!-- Form with fields rendered directly -->
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<label>This form is rendered directly and it works</label>
<input type="hidden" name="action" value="snap_save_settings">
<input type="text" name="snap_test_input" value="Test Value">
<input type="submit" value="Save Changes">
</form>
</div>
<?php
}
}
new Snap_Settings();
Here is the settings base:
abstract class Snap_Settings_Page {
private $sections = [];
abstract protected function initialize_settings();
public function __construct() {
add_action('admin_menu', [$this, 'add_menu_page']);
add_action('admin_init', [$this, 'register_settings']);
}
public function add_menu_page() {
add_options_page(
'Snap Settings', // Page title
'Snap', // Menu title
'manage_options', // Capability
'snap-settings', // Menu slug
[$this, 'display_settings_page'] // Callback function
);
}
public function register_settings() {
$this->initialize_settings();
foreach ($this->sections as $section_id => $section) {
add_settings_section(
$section_id,
$section['title'],
$section['callback'],
$section['page_slug']
);
foreach ($section['fields'] as $field_id => $field) {
add_settings_field(
$field_id,
$field['title'],
$field['callback'],
$field['page_slug'], // Use the page_slug from the field
$section_id
);
register_setting('snap_settings_group', $field_id);
}
}
}
protected function add_section($id, $title, $callback, $page_slug = 'snap-settings') {
$this->sections[$id] = [
'title' => $title,
'callback' => $callback,
'fields' => [],
'page_slug' => $page_slug // Store the page_slug with the section
];
}
protected function add_field($section_id, $field_id, $title, $callback, $page_slug = 'snap-settings') {
if (!isset($this->sections[$section_id])) {
// Optionally handle the error if the section does not exist
return;
}
$this->sections[$section_id]['fields'][$field_id] = [
'title' => $title,
'callback' => $callback,
'page_slug' => $page_slug
];
}
abstract public function display_settings_page();
}
new Snap_Settings();
, this means the object is never assigned to a variable and it's impossible to get a reference to it afterwards to unhook or do extra work, making debugging and extending this from other files super difficultregister_setting('snap_settings_group', $field_id);
You're right, I should've a variable assigned Snap_Settings() which I have now. How can I troubleshoot further? The callback inside the form stops the form action from triggering for some reason.