2

I have registered a setting, added a section in my plugin. Inside that section, multiple inputs (checkboxes) fields have been added using the add_settings_field method. This method has a callback function which I am using to return true for checkboxes which are checked and return false which are unchecked in an array.

Now the problem is this function works as expected except the plugin is activated for the first time. For first time activation, the callback function is being called twice. Once the option is stored in the database then it doesn't called for the second time which it shouldn't be. But if I deletes the option value from database then again same problem occures.

Here is my code

Register Setting

public function setSettings()
    {
        $args = array();
        $args[] = array(
            'option_group' => 'fahad_plugin_settings',
            'option_name' => 'fahad_plugin',
            'callback' => array($this->callbacks_mngr, 'checkboxSanitize')
        );

        $this->settings->setSettings($args);
    }

Adding Section

public function setSections()
    {
        $args = array(
            array(
                'id' => 'fahad_admin_index',
                'title' => 'Settings Manager',
                'callback' => array($this->callbacks_mngr, 'adminSectionManager'),
                'page' => 'fahad_plugin'
            )
        );

        $this->settings->setSections($args);
    }

Added Fields

public function setFields()
    {
        $args = array();
        foreach ($this->managers as $key => $value)
        {
            $args[] = array(
                'id' => $key,
                'title' => $value,
                'callback' => array($this->callbacks_mngr, 'checkboxField'),
                'page' => 'fahad_plugin',
                'section' => 'fahad_admin_index',
                'args' => array(
                    'option_name' => 'fahad_plugin',
                    'label_for' => $key,
                    'class' => 'ui-toggle',
                )
            );
        }

        $this->settings->setFields($args);
    }

Form Submitting The Fields

<form method="post" action="options.php">
                <?php
                settings_fields('fahad_plugin_settings');
                do_settings_sections('fahad_plugin');
                submit_button();
                ?>
            </form>

Wordpress FunctionS To Register Setting

//register setting
        foreach ($this->settings as $setting) {
            register_setting($setting["option_group"], $setting["option_name"], (isset($setting["callback"]) ? $setting["callback"] : ''));
        }

        //add settings section
        foreach ($this->sections as $section) {
            add_settings_section($section["id"], $section["title"], (isset($section["callback"]) ? $section["callback"] : ''), $section["page"]);
        }

        //add settings field
        foreach ($this->fields as $field) {
            add_settings_field($field["id"], $field["title"], (isset($field["callback"]) ? $field["callback"] : ''), $field["page"], $field["section"], (isset($field["args"]) ? $field["args"] : ''));
        }

Callback function Which is being called twice

 public function checkboxSanitize($input)
    {
        $output = array();
        foreach ($this->managers as $key => $value)
        {
            $output[$key] = isset($input[$key]) ? true : false;
        }
        return $output;
    }

1 Answer 1

0

The issue is not with your code. It is due to how WordPress works internally. This has been reported as bug in 2012 (almost 10 years ago at this point).

You can see the bug report here: https://core.trac.wordpress.org/ticket/21989

The thing is that update_option is called, which when the option does not exist, will call add_option first. Now this makes this weird 2-time-pass.

To "live with it" you can do several different things. The best might be to check your option as well as the input.

In the way how I make my options, for me it is as simple as checking for one of the keys I know will be present. It ends up being either available or within an array.

public function checkboxSanitize($input) {

    if(!isset($input['known_key']) && isset($input[0],$input[0]['known_key'])) {
        $input = $input[0];
    }
    //...
}

Another, also simple way to check is to define some constant and then check it up if defined. In most cases it would not fire.

public function checkboxSanitize($input) {

    if(defined('CHECKBOXES_SANITIZED')) {
        // handle differently
        // For example, do not call any APIs again, just build and save option
    }

    define('CHECKBOXES_SANITIZED', true);

    //...
}

I do want to point out anyone new to WP that finds this. Please make note that on second pass, you do not necessarily have anything saved, so if you just exist the function at that time, you might end up with no value saved.

Instead you are likely going to want to handle it (again). Also skipping first time is not ideal, since it might only fire once in some cases. In which case you would again end up without any value saved.

PS: I know this has been asked a bit back, however as I myself end up from time to time with a search to remember why exactly this is happening and this question has no answer, wanted to add it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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