I've used the settings API to create a very simple page for plugin settings. This is my first time using the API, and through various tutorials online and answers here, I think I've figured it out. This is backed up by the fact that the page even works!!

However, something weird is happening:

two notices regarding the saving of settings

As you can see above, there are two div.update messages being displayed on the screen. I've checked and there's only one call to the settings_errors() function so and that function isn't called in a loop or anything that I can find, but I'm still getting two notices.

Here's the code:

public function __construct() {
    /* more stuff */

    add_action("admin_menu", array($this, "plugin_settings_menu_add");
    if($pagenow == "options.php" || $pagenow == "options-general.php") {
        add_action("admin_init", array($this, "plugin_settings_initialize");

public function plugin_settings_menu_add() {
    add_options_page("Gallery Settings", "Galleries", "manage_options", "galleries-settings-page", array($this, "plugin_settings_menu_display"));

public function plugin_settings_menu_display() {
    require(plugin_dir_path(__FILE__) . "views/plugin-settings.php");

public function plugin_settings_permissions_to_use_default() {
    return apply_filters(
            "galleries-settings-permission-to-use-url" => ""

public function plugin_settings_initialize() {
    if(get_option("galleries-settings-permission-to-use") == false) {
        add_option("galleries-settings-permission-to-use", $this->plugin_settings_permissions_to_use_default());

        "galleries-settings-permission-to-use-section",                    // DOM ID for the section
        "Permission to Use Gallery Items",                                        // on-screen title for it
        array($this, "plugin_settings_permissions_to_use_header_display"),        // callback to display its header
        "galleries-settings-page"                                            // the menu page on which to show it

        '<label for="galleries-settings-permission-to-use-url">Webtools Form (required)</label>',
        array($this, "plugin_settings_permissions_to_use_url_display"),

        array($this, "plugin_settings_permissions_to_use_sanitize")

public function plugin_settings_permissions_to_use_header_display() {
    echo "<p>......</p>";

public function plugin_settings_permissions_to_use_url_display() {
    $settings = get_option("galleries-settings-permission-to-use");
    $value = isset($settings["galleries-settings-permission-to-use-url"])
        ? $settings["galleries-settings-permission-to-use-url"]
        : ""; ?>

    <input type="url" id="galleries-settings-permission-to-use-url"
        value="<?=esc_url($value)?>" class="regular-text" required aria-required="true"><br>

    <em>Enter the full URL but without any query string parameters.</em>    
<? }

public function plugin_settings_permissions_to_use_sanitize($input) {
    $output = array();
    foreach($input as $key => $value) {
        // even though we have only one field here at the moment, we'll use a loop and a switch
        // to santize.  that way we're ready to go with respect to additional data that might one
        // day be sent here.  

        switch($key) {
        case "galleries-settings-permission-to-use-url":
            if(empty($value) || !filter_var($value, FILTER_VALIDATE_URL)) {
                    "You must enter a valid web address."
            } elseif(($qloc = strpos($value, "?"))!==false) $value = substr($value, 0, $qloc);

        $output[$key] = $value;

    return apply_filters("galleries_plugin_settings_permissions_to_use_sanitize", $output, $input);

The following is the contents of the plugin-settings.php page that's included in the code above:

<div class="wrap">
    <div id="icon-options-general" class="icon32"></div>
    <h2>Gallery Settings</h2>

    <? settings_errors(); ?>

    <form method="post" action="options.php">
            <? settings_fields("galleries-settings-page"); ?>
            <? do_settings_sections("galleries-settings-page"); ?>
            <? submit_button(); ?>

And, yes, as you can probably tell, this is Yet Another Image Gallery Plugin. I did do a search and replace to hide some of the information about for whom I'm doing the plugin. Hopefully doing so didn't introduce any errors.

  • Note: you have syntax errors in the posted code. (Check strings.) Also: can you isolate the code to the part that is outputtting the admin notice? Commented Nov 6, 2013 at 16:31
  • I have no idea what part is printing the admin notices; if I knew that, I woudldn't need to ask for help ;) According to the docs, it's the single call to settings_errors() in the plugin-settings.php file. I'll look into the syntax problems, but as I said, I had to remove identifying information from the code via global search are replace. I'll do my best to find them.
    – David Kees
    Commented Nov 6, 2013 at 16:53
  • Side note: please use full PHP tags - <?php rather than <?. You'll save yourself some headaches. Commented Nov 6, 2013 at 16:56
  • If you remove the call to settings_errors(), do you get one or no admin notices generated? Commented Nov 6, 2013 at 16:57
  • I get one. But, if there's an error in the sanitization, it doesn't show that either (logically).
    – David Kees
    Commented Nov 6, 2013 at 17:01

2 Answers 2


The issue, as determined by Chip Bennett in our conversation above, was related to the settings_errors() call. The problem was that I didn't specify a setting for which I wanted to display either errors or update notices mostly because the tutorial from which I was working didn't either. By specifying that setting, I see one single notice and the errors if necessary.

Thanks, Chip, for the help!


We can easily solve this by using the options page slug in it, like, settings_errors('page_slug'); I'm not sure is it right or wrong way but worked for me well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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