Stop the form of beign submitted on “Save changes” custom option page

How to stop the form data from being saved on error

Actually, the “Settings saved.” message does not necessarily mean that the options/value in the database was actually updated — because if the old and new values were the same, means there were no changes, then the old value will not be re-saved or overwritten in the database. However, you’d still see the “Settings saved.” message which indicates that the form (data) was successfully submitted and processed without errors.

Hence, when the form data contains empty or invalid values, you should return the old options and not an empty array. Please see below, which is your code, but it’s slightly modified so that you could hopefully understand what I mean:

function input_validation( $input ){

//settings_errors('custom_options'); // <- this should NOT be here..

$options = get_option( 'custom_options' ); // <- here's the OLD VALUE

// Create our array for storing the validated options
$output = array();

// Loop through each of the incoming options
foreach( $input as $key => $value ) {

        ... your code here ...

        //check if its not empty
            if(empty($value)){

                add_settings_error(
                    'custom_options',
                    'Missing value error',
                    __('On or more fields can\'t be empty.', 'custom'),
                    'error'
                );

                //return array(); // <- here don't return empty array
                return $options; // <- instead, return the old value
            } // end if


    } // end foreach

    // Return the array processing any additional functions filtered by this action
    return $output; // <- even if all form data are VALID, this/$output
                    // could still be the same as $options (i.e. there
                    // were no changes made)
}

//settings_errors('custom_options'); // <- this should NOT be here.. — Why not?

That’s because the settings_errors() function is automatically called on your custom options page (provided it was created using the WordPress Settings API), therefore there’s no need to manually call the function — just add settings errors and they’ll be displayed automatically.

This is called automatically after a settings page based on the
Settings API is submitted
. Errors should be added during the
validation callback function for a setting defined in
register_setting().

— See https://developer.wordpress.org/reference/functions/settings_errors/

How to stop the form from being submitted on error

  1. If you just want to make sure the form fields are all filled in, add
    (the HTML5 attribute of) required to the field’s HTML. For examples:

    <input name="custom_options[option_1]" type="text" required>
    <select name="custom_options[option_2]" required></select>
    <textarea name="custom_options[option_3]" required></textarea>
    
  2. Use JavaScript validation. Here’s a very simple example:
    (using jQuery)

    <form method="post" action="options.php" id="my-form">
      <input name="custom_options[option_1]" type="text" id="option-1">
      <select name="custom_options[option_2]" id="option-2">
        <option value="">Select</option>
        <option value="1">One</option>
      </select>
      <textarea name="custom_options[option_3]" id="option-3"></textarea>
      <input type="submit">
    </form>
    
    <script>
    $('#my-form').on('submit', function(){
      if ( // check if all fields are filled
        $('#option-1', this).val().length < 1 ||
        $('#option-2', this).val().length < 1 ||
        $('#option-3', this).val().length < 1
      ) {
        alert('Please fill in all fields.');
        return false; // cancels the submit
      }
    });
    </script>
    

Try a demo here.


So basically, in the input_validation() function, the form has already been submitted. To prevent that, you can use client-side validation like I mentioned above — the HTML5 and jQuery validation.