Problem with saving checkbox values with WordPress Widget API

(Update #2)

Here‘s the full widget class that I previously shared via my comment. =)

In that class, the checkbox1 field is default to not checked, while the rest of the checkbox fields are checked by default.


(Update #1. Note that this update does not use your example code, but hopefully this answer would be of more help than the previous answer.)

First off, checkbox fields (i.e. <input type="checkbox">), as you may already know, normally would be of two values — a “on” value (set if the checkbox field is checked), and a “off” value (set if the field is not checked).

So let’s say you have a widget with the following default options, which are all checkbox fields:

$defaults = array(
  'cb1' => 'yes',
  'cb2' => 'no',
);

And for both of the fields, the “on” value is yes, while the “off” value is no.

Then in your widget options form, you display the checkbox fields using the following markup: (other attributes such as id and name are intentionally not included)

<input type="checkbox" value="{A}"<?php checked( '{B}', '{C}' ); ?>>

Where {A} and {B} are always the “on” value, whereas {C} is the value as it is currently in the database or in the $defaults array if the widget options have not yet been changed — e.g. the widget has just been added to a sidebar.

So if you look at the (above) sample $defaults array:

  1. The cb1 field would be checked by default, because the default value is the “on” value — $defaults['cb1'] is yes.

  2. The cb2 field would be not checked by default, because the default value is the “off” value — $defaults['cb2'] is no.

Sample widget class for testing the checkbox fields: “My Widget”

<?php
class MY_Widget extends WP_Widget {

    public function __construct() {
        parent::__construct( 'my_widget', 'My Widget', array(
            'classname'   => 'my-widget',
            'description' => 'Testing checkbox fields.',
        ) );
    }

    public function widget( $args, $instance ) {
        echo $args['before_widget'];
            echo '<pre>'; var_dump( $instance ); echo '</pre>';
        echo $args['after_widget'];
    }

    public function update( $new_instance, $old_instance ) {
        $instance = $old_instance;

        $instance['cb1'] = isset( $new_instance['cb1'] ) ? 'yes' : 'no';
        $instance['cb2'] = isset( $new_instance['cb2'] ) ? 'yes' : 'no';

        return $instance;
    }

    public function form( $instance ) {
        $instance = wp_parse_args(
            (array) $instance,
            // The default options.
            array(
                'cb1' => 'yes', // checked by default
                'cb2' => 'no',  // not checked by default
            )
        );
        ?>
            <p>
                <input type="checkbox" id="<?php echo $this->get_field_id( 'cb1' ); ?>" name="<?php echo $this->get_field_name( 'cb1' ); ?>" value="yes"<?php checked( 'yes', $instance['cb1'] ); ?>>
                <label for="<?php echo $this->get_field_id( 'cb1' ); ?>">Checkbox #1</label><br>

                <input type="checkbox" id="<?php echo $this->get_field_id( 'cb2' ); ?>" name="<?php echo $this->get_field_name( 'cb2' ); ?>" value="yes"<?php checked( 'yes', $instance['cb2'] ); ?>>
                <label for="<?php echo $this->get_field_id( 'cb2' ); ?>">Checkbox #2</label>
            </p>
        <?php
    }
}