It’s because you’re always outputting the default value into the input, regardless of what the saved value is:
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $defaults['title'] ); ?>" />
Specifically:
value="<?php echo esc_attr( $defaults['title'] ); ?>"
$defaults['title']
is always going to be an empty string. The saved title is inside $instance['title']
, and, because of this line:
extract( wp_parse_args( array( $instance, $defaults ) ) );
It is also inside a variable called $title
. This isn’t immediately obvious, which is why using extract()
like this is bad practice.
I suggest either setting the variables explicitly:
$title = isset( $instance['title'] ) ? $instance['title'] : $defaults['title'];
In which case the value should be output like so:
value="<?php echo esc_attr( $title ); ?>"
Or putting the result of wp_parse_args()
back into $instance
:
public function form( $instance ) {
$defaults = array(
'title' => '',
);
$instance = wp_parse_args( array( $instance, $defaults ) );
// ...etc.
}
In which case the value should be output like so:
value="<?php echo esc_attr( $instance['title'] ); ?>"