Where is the submitted $_POST array stored after an option page submission?

What happens, when I click Save Changes on a option page, which was created by add_menu_page()? Where is the submitted data stored before the database transmission?

A print_r($_REQUEST) returns only the two $_GET parameters page and settings-updated.

Read More

I’ve checked the manual for add_settings_field and there is only the following hint:

… the saving will be done behind the scenes.

Background

I’d like to optimize my process of creating a plugin settings page. I’ve already jumped on the WP Settings API with add_settings_section and add_settings_field long time ago, but it feels a bit uncomfortable to create a new callback function every time. So instead of creating the specific field/section code inside a callback, I’d like to create the complete settings page with Zend_View. All input fields would be created with Zend_Form and also attached to the view. In the end, the callback of add_menu_page() will return the rendered View-Object instead of the normal HTML output.

The HTML is stored inside a View-Template, located in views/pages/admin/ (e.g. default.phtml).

The basic principle is already working I’m very happy with the result. Due to the use of Zend_View, I’ve to do the saving on my own. But WordPress seems to delete the submitted $_POST array. If I debug the output after a successfull form submission, only the two $_GET params above are set.

I’ve also attached the output of the function settings_fields() to the view, which generates the required hidden fields (option_page, action, _wp_nonce).

Any ideas?

Related posts

Leave a Reply

2 comments

  1. You only need one callback function, as defined in your call to register_setting() (Codex ref.):

    register_setting( $option_group, $option_name, $sanitize_callback );
    

    Thus, all options are contained in an array, in a single database entry, $option_name.

    Then, the callback function is passed the $input variable that holds all of the form-submitted data, the function manipulates/sanitizes those data, and returns the sanitized output:

    function mytheme_sanitize_callback( $input ) {
        // sanitization functions go here
        return $sanitized_output;
    }
    

    So: one database entry, as an array of options; and one sanitization callback for form-submitted user data.

    For more help, you might reference this tutorial.

  2. I’ve finally found my fault.

    The “problem” with Zend_View and Zend_Form is, that you have to check and save the submitted settings by yourself. But if you register a sanitize hook with register_setting(), WordPress will indeed not return any $_POST array and will immediatly submit the data to the defined option in the database.

    The solution was to remove the call to register_setting() completely. I’ve also removed the call to settings_field() and set the hidden fields manually in the Zend_Form object.

    $form = new Zend_Form();
    $form->setAction('options.php?page=' . $this->getMenuSlug())
         ->setMethod('post');
    
    $wpnonce = $form->createElement('hidden', '_wp_nonce');
    $wpnonce->setValue(wp_create_nonce($this->getMenuSlug()));
    

    The method $this->getMenuSlug() will return the id of the current generate admin page used in add_page_menu().

    The last part was to do the form validation before echoing the Zend_View object. This is done in the renderView() method, which will be called as callback in add_menu_page().

    public function renderView() {
        try {
            if($_POST['submit']) {
                // Check wp nonce
                if(!wp_verify_nonce($_POST['_wp_nonce'], $this->getMenuSlug())) {
                    wp_die(__('Nonce incorrect!'));
                } else {
                    if($this->_form->isValid($_POST)) {
                        echo '<div id="message" class="updated fade"><p><strong>' . __('Settings saved.') . '</strong></p></div>';
                        foreach ($this->_form->getElements() as $element) {
                            if(in_array($element->getName(), $this->_skipElements)) {
                                continue;
                            }
    
                            Webeo_Option::getInstance()->setValue($element->getName(), $element->getValue());
                        }
    
                        Webeo_Option::getInstance()->commit();
                    } else {
                        echo '<div id="message" class="error fade"><p><strong>' . __('Errors occured.') . '</strong></p></div>';
                    }
                }
            }
    
            echo $this->_form->render($this->_view);
            //echo $this->_view->render($this->getViewTemplate());
        } catch (Zend_View_Exception $e) {
            echo $e->getMessage();
        }
    }
    

    The Webeo_Option is just an object storage and could be replaced with update_option().