Widget update function not saving values

This took a bit to sort out. 🙂

You are trying to use $instance['post_types'] in your update() function but are not setting that value at all in the form. I altered a couple of things so that the two match up.

Leaving your form (mostly) as it is, your update() needs to be…

// save the widget settings
function update( $new_instance, $old_instance ) {
    $instance = $old_instance;
    $instance['num_posts'] = strip_tags( $new_instance['num_posts'] );
    // start of the change
    foreach (get_post_types() as $post_type) {
      $instance[$post_type] = $new_instance[$post_type];
    }
    // end of the change
    return $instance;
}

Now, that will get things to save but it won’t look like it because your checked() is a little off, so your form() needs to be altered just a little bit. Change the code for the list items to…

<input name="<?php echo $this->get_field_name( $post_type ); ?>" type="checkbox" <?php echo checked( $instance[$post_type] ,'on' ); ?> />
<label for="<?php echo $this->get_field_name( $post_type ); ?>" /><?php echo $post_type; ?></label>

Notice that the checked() function went from checked( $this->get_field_name( $post_type ) ); to checked( $instance[$post_type] ,'on' ); ‘on’ is the ‘true’ value.

You were trying to use a ‘post_types’ array but that didn’t match what was in the form, so I altered the update function to match the form. You could do it the other way around and alter the form to create an array. I think my way is easier though.

Some bits of the code you really don’t need, like…

foreach ( get_post_types() as $post_type ) {
   $instance['post_types'][$post_type] = '';
} 

And that will cause trouble if you try to use the ‘post_types’ array. It will overwrite that variable every time.