I'm trying to wrap my head around the Settings and Options APIs as I'm writing a simple plugin.
One thing that has really stomped me is the possibility to add a default
value to an option when calling the register_setting()
function. This does not work the way I expected and I don't get how it's supposed to work.
Here is a simplified example:
<?php
/**
* Plugin name: Options test
*/
define( 'MY_PAGE', 'my_test_page' );
define( 'MY_SECTION', 'my_test_section' );
define( 'MY_OPTION', 'my_test_option' );
add_action( 'admin_menu', function () {
add_options_page( 'Options test', 'Options test', 'manage_options', MY_PAGE, function () {
echo '<div class="wrap"><h1>Options test</h1>';
echo '<form action="options.php" method="post">';
settings_fields( MY_PAGE );
do_settings_sections( MY_PAGE );
submit_button();
echo '</form>';
echo '<p>The option value: <code>' . get_option( MY_OPTION ) . '</code></p>';
echo '</div>';
} );
} );
add_action( 'admin_init', function () {
register_setting( MY_PAGE, MY_OPTION, [ 'default' => 'My default value' ] );
add_settings_section( MY_SECTION, '', null, MY_PAGE );
add_settings_field( MY_OPTION, 'The option', function () {
echo '<input name="' . MY_OPTION . '" value="' . get_option( MY_OPTION ) . '">';
}, MY_PAGE, MY_SECTION );
} );
add_shortcode( 'my-test-option', function ( $atts, $content = '' ) {
return get_option( MY_OPTION );
} );
This results in a setings page that looks like this:
You can see that the <input>
has a default value and that the separate call to get_option()
returns the default value - on this page. When accessing the option on the front end using the shortcode [my-test-option]
it is blank. This is expected when I haven't visited the settings page, as nothing has been saved to the database. There is no 'my_test_option' in the wp_options database table.
But...
Even when I press the [Save Changes] button, the default value is NOT saved to the database. I've traced the code and found that in the update_option()
function (/wp-includes/option.php) there is a test to check if the new value is the same as the old, and if so the new value isn't stored.
So in order to actually save the default value to the database using this custom settings page, I would have to change the value to something other than the default, save it, change it back to the default and save it again. Very unintuitive.
I've already understood that I need to fix this by using register_activation_hook()
in my plugin and add the default options to the database there. Then remove the default from the register_setting()
calls.
What I don't understand is how the default
parameter to the register_setting()
function is meant to be used. When and how is it useful? As it stands, it has only lead to confusion and wasted hours.
get_option()
is called.register_setting()
outside of the function hooked toadmin_init
that builds the settings form by callingadd_settings_field()
etc.