• ClintonLee83

    (@clintonlee83)


    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();
       
    }
Viewing 2 replies - 1 through 2 (of 2 total)
  • Moderator bcworkz

    (@bcworkz)

    Settings API forms are not intended to be submitted to admin-post.php (there’s no action value or associated submitted form handler). Settings forms should submit to options.php.

    Thread Starter ClintonLee83

    (@clintonlee83)

    That’s the right answer. Thank you bcworkz!

    The settings api forms have a hidden input with the update action. I was adding an additional action on top of that. I removed my action and changed admin-post.php to options.php and everything is gravy.

    Thank You!

Viewing 2 replies - 1 through 2 (of 2 total)
  • The topic ‘Form Submits When Fields Called Directly, Fails When Using Callbacks’ is closed to new replies.