Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm making a plugin administration page with the settings API. I'd like to know a way to display a warning message when the user submits an invalid value.

For example, with the below code, if the user sends an empty value for Option A, the first input field, I'd like to show a message that says it's invalid and please fill the form. And the other submitted option values should not be saved to the database but remain in the input fields with the message on the page.

<?php
/*
Plugin Name: Demo Verification Notice with Settings API
Description: Learning how to warn invalid values when submitting the form and take back the user to the setting page without saving the options.
Author: Teno
*/

add_action('admin_init', 'settingsapi_init');
function settingsapi_init(){
    register_setting( 'settingsapi_optiongroupname', 'settingsapi_optionname');
    add_settings_section('plugin_main', 'Section 1', 'settingsapi_sectiondescription', 'settingsapi_pageslug');
    add_settings_field('plugin_text_string_a', 'Option A', 'settingsapi_setting_string_a', 'settingsapi_pageslug', 'plugin_main');
    add_settings_field('plugin_text_string_b', 'Option B', 'settingsapi_setting_string_b', 'settingsapi_pageslug', 'plugin_main');
}

function settingsapi_sectiondescription() {
    echo '<p>This is a section description.</p>';
}
function settingsapi_setting_string_a() {
    $options = get_option('settingsapi_optionname');
    echo "<input id='plugin_text_string' name='settingsapi_optionname[option_a]' size='40' type='text' value='{$options['option_a']}' />"; 
} 
function settingsapi_setting_string_b() {
    $options = get_option('settingsapi_optionname');
    echo "<input id='plugin_text_string' name='settingsapi_optionname[option_b]' size='40' type='text' value='{$options['option_b']}' />"; 
}
// admin menu
add_action('admin_menu', 'plugin_admin_add_page');
function plugin_admin_add_page() {
    add_options_page('Custom Plugin Page', 'Demo Settings API Menu for Verification', 'manage_options', 'settingsapi_pageslug', 'settingsapi_adminpage');
}

function settingsapi_adminpage() {
    ?>
    <div class="wrap">
        <?php screen_icon(); ?> <h2>Demo Plugin for Settings API</h2>
        <form action="options.php" method="post">
            <?php settings_fields('settingsapi_optiongroupname'); ?>
            <?php do_settings_sections('settingsapi_pageslug'); ?>
            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}
?>

Is that possible with the settings API?

The register_setting() function accepts the third parameter as validation function call. However, it can be used to just fix the passed value but it accepts the form submission and saves the options. That is not what I'm looking for.

[Edit]

Okey, I'm almost there. This validates the submitted value with the callback function set in the register_setting() function. And if the value is invalid it leaves a flag, invalid, in the option array and displays a warning message.

However, there is one remaining issue. Otherwise, it is almost done.

  1. Once an empty value is set to the first input option, it shows the warning message. It is what we've achieved so far. And if the user leaves the page showing the warning, somehow the empty value is saved to the option. It should revert the previous value.

The code below is ready to use as a plugin. If you run it, you'll see what I'm talking about.

<?php
/*
Plugin Name: Demo Verification Notice with Settings API
Description: Learning how to warn invalid values when submitting the form and take back the user to the setting page without saving the options.
Author: Teno
*/

add_action('admin_init', 'settingsapi_init');
function settingsapi_init(){
    register_setting( 'settingsapi_optiongroupname', 'settingsapi_optionname','validation_callback');

    add_settings_section('plugin_main', 'Section 1', 'settingsapi_sectiondescription', 'settingsapi_pageslug');
    add_settings_field('plugin_text_string_a', 'Option A', 'settingsapi_setting_string_a', 'settingsapi_pageslug', 'plugin_main');
    add_settings_field('plugin_text_string_b', 'Option B', 'settingsapi_setting_string_b', 'settingsapi_pageslug', 'plugin_main');
}

function settingsapi_sectiondescription() {
    echo '<p>This is a section description.</p>';
}
function settingsapi_setting_string_a() {
    $options = get_option('settingsapi_optionname');
    ?>
    <input type="hidden" name="settingsapi_optionname[submitted]" value="1" />
<? print_r($options); ?><br />
    <input id="plugin_text_string" name="settingsapi_optionname[preview][option_a]" size="40" type="text" value="<?php echo $options['submitted']  ? $options['preview']['option_a'] : $options['valid']['option_a']; ?>" />
    <?php echo ($options['invalid'] && $options['submitted'] ) ? '<font color="red">* cannot be blank.</font>' :'' ?>
    <?php
} 
function settingsapi_setting_string_b() {
    $options = get_option('settingsapi_optionname');
    ?>
<? print_r($options); ?><br />  
    <input id="plugin_text_string" name="settingsapi_optionname[preview][option_b]" size="40" type="text" value="<?php echo $options['submitted'] ? $options['preview']['option_b'] : $options['valid']['option_b']; ?>" />
    <?php
}
// admin menu
add_action('admin_menu', 'plugin_admin_add_page');
function plugin_admin_add_page() {
    add_options_page('Custom Plugin Page', 'Demo Settings API Menu for Verification', 'manage_options', 'settingsapi_pageslug', 'settingsapi_adminpage');
}

function settingsapi_adminpage() {
    ?>
    <div class="wrap">
        <?php screen_icon(); ?> <h2>Demo Plugin for Validation Message with Settings API</h2>

        <?php
        $options = get_option('settingsapi_optionname');
        print_r($options);      // for debugging purpose
        if (!($options['invalid'] && $options['submitted'])) {

            // update the correct option values
            $options['valid'] = is_array($options['valid']) ? $options['valid'] : array();  // if the options['valid'] is called for the first time, make it an array
            $options['valid'] = array_merge($options['valid'], $options['preview']);
            // $options['preview'] = '';    // initialize the preview option data. //<-- this seems to cause a problem
            update_option('settingsapi_optionname', $options);
        }
        ?>

        <form action="options.php" method="post">
            <?php 
            settings_fields('settingsapi_optiongroupname');
            do_settings_sections('settingsapi_pageslug'); 

            // after displaying the form content, set the invalid flag and the subbmited flag to false
            $options['invalid'] = False;
            $options['submitted'] = False;      
            update_option('settingsapi_optionname', $options);  

            submit_button();
            ?>          
        </form>

    </div>
        <?php 
            print_r($options);
        ?>  
    <?php
}

function validation_callback($input){
    if (strlen(trim($input['preview']['option_a'])) == 0 && $input['submitted']) {
        // $input['preview']['option_a'] = '';
        unset($input['preview']['option_a']);
        $input['invalid'] = True;   // <-- this one is the problem. It seems to be called multiple times and setting the invalid flag to true when it's not necessary.
        add_settings_error('unique_identifyer',esc_attr('settings_updated'),__('Settings NOT saved.'),'error');
        add_action('admin_notices', 'print_errors');
    } else {
        $input['invalid'] = False;
    }
    return $input;
}

function print_errors(){
    settings_errors( 'unique_identifyer' );
}

?>

[Edit]

It might be easier to do it without the Settings API. Here is a working example.

<?php
/*
Plugin Name: Demo Verification Warning without Settings API
Description: Demo plugin demonstrating how to display a warning message when the user tries to save an invalid value in the option page.
Author: Teno
*/

// define constants
define("DEMOVERIFICATIONKEY", "demo_verification_option");

// create an option array
$arrOption = get_option(DEMOVERIFICATIONKEY);
if (!(is_array($arrOption))) {
    $arrOption = array(
        "tab1" => array(),
        "tab2" => array(),
        "tab3" => array()
    );
    update_option(DEMOVERIFICATIONKEY, $arrOption);
}

// admin menu
add_action('admin_menu', 'demo_verification_adminmenu');
function demo_verification_adminmenu() {
    add_options_page('Demo Plugin Menu for Verification without Settings API', 'Demo Plugin Menu for Verification without Settings API', 'manage_options', 'demo_verification_admin_menu', 'demo_verification_adminpage');
}
// admin page
function demo_verification_adminpage() {
    $options = get_option(DEMOVERIFICATIONKEY);
    print_r($_POST); // for debugging
    echo '<br />';
    if(isset($_POST[DEMOVERIFICATIONKEY]['tab1']['submitted']) && $_POST[DEMOVERIFICATIONKEY]['tab1']['submitted'] == 1){
        if (strlen(trim($_POST[DEMOVERIFICATIONKEY]['tab1']['option_a'])) == 0) {
            $options['tab1']['invalid'] = True;     
            echo '<div class="error settings-error"><p>Options are not saved.</p></div>';
        } else {    
            $options = array_merge($options, $_POST[DEMOVERIFICATIONKEY]);
            update_option(DEMOVERIFICATIONKEY, $options);
            echo '<div class="updated"><p>Updates are saved.</p></div>';
        }
    }   
    ?>
    <div class="wrap">
        <?php screen_icon(); ?> <h2>Demo Plugin for Validation Message without Settings API</h2>
        <form method="post" action="">  <?php // 'action=""' means to send the form post data to this page itself. ?>
            <input type="hidden" name="<?php echo DEMOVERIFICATIONKEY; ?>[tab1][submitted]" value="1" />
            <table class="form-table">
                <tbody>
                <tr valign="top">
                    <th scope="row">Option A</th>
                    <td>
                        <input name="<?php echo DEMOVERIFICATIONKEY; ?>[tab1][option_a]" size="40" type="text" value="<?php echo $options['tab1']['invalid']  ? $_POST[DEMOVERIFICATIONKEY]['tab1']['option_a'] : $options['tab1']['option_a']; ?>" />
                        <?php echo ($options['tab1']['invalid'] && $options['tab1']['invalid'] ) ? '<font color="red">* cannot be blank.</font>' :'' ?>
                    </td>
                </tr>
                <tr valign="top">
                    <th scope="row">Option B</th>
                    <td>
                        <input name="<?php echo DEMOVERIFICATIONKEY; ?>[tab1][option_b]" size="40" type="text" value="<?php echo $options['tab1']['invalid'] ? $_POST[DEMOVERIFICATIONKEY]['tab1']['option_b'] : $options['tab1']['option_b']; ?>" />
                    </td>
                </tr>
                </tbody>
            </table>
            <?php submit_button(); ?>   
        </form>     
    </div>
    <?php
}
?>

But in case if somebody can figure it out with the Settings API, please post the solution.

share|improve this question
    
revert to what previous value? –  Bainternet Aug 21 '12 at 14:03
    
I mean the saved value. The blank value shouldn't be saved as the verified value. It should be only saved as a preview value. You can confirm the problem with this step: 1. type any string value in the first field and save. 2. type an empty string in the first field and you get a warning message. 3. go to the admin dashboard. 4. come back to the plugin page. 5. you see the empty value is saved. –  Teno Aug 22 '12 at 0:22
add comment

2 Answers

First add a validation callback to your register_settings:

register_setting( 'settingsapi_optiongroupname', 'settingsapi_optionname','validation_callback');

then define validation_callback:

function validation_callback($input){
    //check if all is good
    //If so then return the wanted value to be saved
    //If Not then hook your admin notice function and return null to be saved ex:
    if ($something){
        return $input;
    }else{
        add_settings_error('unique_identifyer',esc_attr('settings_updated'),__('Settings saved.'),'updated');
        add_action('admin_notices', 'print_errors');
        return null;
    }
}

and last define print_errors something like:

function print_errors(){
    settings_errors( 'unique_identifyer' );
}

and if nothing happens then try adding include_once 'options-head.php'; in your page

Update here is a plugin to test and see that it works just fine:

<?php
/*
Plugin Name: wpse62418
Plugin URI: http://en.bainternet.info
Description: answer to http://wordpress.stackexchange.com/questions/62418/verify-submitted-form-values-and-show-warning-messages-with-setting-api/62434
Version: 1.0
Author: Bainternet
Author URI: http://en.bainternet.info
*/


add_action('admin_init', 'settingsapi_init');
function settingsapi_init(){
    register_setting( 'settingsapi_optiongroupname', 'settingsapi_optionname','validation_callback');       //

    add_settings_section('plugin_main', 'Section 1', 'settingsapi_sectiondescription', 'settingsapi_pageslug');
    add_settings_field('plugin_text_string_a', 'Option A', 'settingsapi_setting_string_a', 'settingsapi_pageslug', 'plugin_main');
}

function settingsapi_sectiondescription() {
    echo '<p>This is a section description.</p>';
}
function settingsapi_setting_string_a() {
    $options = get_option('settingsapi_optionname');
    ?>
    <input type="hidden" name="settingsapi_optionname[submitted]" value="1" />
    <input id="plugin_text_string" name="settingsapi_optionname[preview][option_a]" size="40" type="text" value="<?php echo isset( $options['preview']['option_a']) ? $options['preview']['option_a'] : ''; ?>" />
    <?php
} 
// admin menu
add_action('admin_menu', 'plugin_admin_add_page');
function plugin_admin_add_page() {
    add_options_page('Custom Plugin Page', 'Demo Settings API Menu for Verification', 'manage_options', 'settingsapi_pageslug', 'settingsapi_adminpage');
}

function settingsapi_adminpage() {
    ?>
    <div class="wrap">
        <?php screen_icon(); ?> <h2>Demo Plugin for Validation Message with Settings API</h2>

        <?php
        $options = get_option('settingsapi_optionname');
        print_r($options);      // for debugging purpose
        ?>

        <form action="options.php" method="post">
            <?php 
            settings_fields('settingsapi_optiongroupname');
            do_settings_sections('settingsapi_pageslug'); 

            // after displaying the form content, set the invalid flag and the subbmited flag to false

            submit_button(); 
            ?>
        </form>

    </div>
        <?php 
            print_r($options);
        ?>  
    <?php
}

function validation_callback($input){
    add_settings_error('unique_identifyer',esc_attr('settings_updated'),__('Settings NOT saved.'),'error');
    add_action('admin_notices', 'print_errors');
    return $input;
}

function print_errors(){
    settings_errors( 'unique_identifyer' );
}
share|improve this answer
    
The validation callback function does not seem to be able to interact with the admin page. add_action('admin_notices', 'print_errors'); does not do anything in my environment. I'm using v3.4.1. –  Teno Aug 21 '12 at 2:59
    
updated my code to use the settings API add_settings_error() –  Bainternet Aug 21 '12 at 6:38
    
Still nothing happens. Including 'option-head.php' in the setting page didn't help. For testing, I removed the lines of if-clauses, if ($something) { return $input; } else {} int the validation_callback() function, but nothing happens. It just shows a yellow box saying options are updated as normal. –  Teno Aug 21 '12 at 7:04
    
here is a demo tested plugin that works. –  Bainternet Aug 21 '12 at 8:25
    
Thanks indeed your updated code shows the custom warning message. I also updated the initial post and it has one last issue. –  Teno Aug 21 '12 at 10:00
add comment

Once the validation callback is invoked, you're too late in the process to do form validation, because the form has already been submitted. You're likely going to have to look at a javascript form-validation solution that happens on-page, and before the form is submitted.

share|improve this answer
    
Some users disable javascript in their browser. So it is not the ideal solution. –  Teno Aug 21 '12 at 2:48
    
One idea I have is that if the submitted values are invalid, save them as review values with a hidden option value indicating 'do not process.' And then show the warning message to the user. If the submitted values are all okey, save them separately to another group of hidden option fields. But how can I show the warning message without javascript? –  Teno Aug 21 '12 at 3:03
    
"Some users disable javascript in their browser. So it is not the ideal solution." Those users are going to have issues in the WordPress admin area regardless, then, as the entire admin is heavily dependent on scripts. –  Chip Bennett Aug 21 '12 at 5:36
    
The default administration page allows the user to operate the minimum functionality without javascript regardless it is efficient or not. So as plugins. –  Teno Aug 21 '12 at 5:52
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.