WordPress Options API: add_option, get_option, update_option explained

The WordPress Options API is the built-in key-value store for saving plugin and theme configuration data to the database. It is simpler than custom database tables for small amounts of structured data, automatically handles serialisation of arrays and objects, and integrates with WordPress’s caching layer so repeated get_option() calls within the same request do not hit the database twice. The four core functions are: add_option() (insert a value if the key does not already exist), get_option() (retrieve a value with an optional default), update_option() (create or overwrite a value), and delete_option() (remove a value). All values are stored in the wp_options table as serialised PHP. Options with the autoload flag set to yes (the default) are loaded into memory on every page load — this is efficient for small values you always need, but a performance killer for large arrays you only occasionally use. For large or rarely-needed data, always pass ‘no’ as the fourth argument to add_option() or use a transient instead. Grouping related settings into a single serialised array (e.g. update_option( ‘myplugin_settings’, $array )) is much better than storing dozens of individual option keys. The settings page integration via the WordPress Settings API is covered in a separate guide; this article focuses purely on the storage functions and their correct usage patterns. Pair the Options API with input sanitisation and with the object cache for a complete data management strategy.

Problem: You need to save plugin or theme configuration data to the WordPress database and retrieve it reliably on every page load without writing raw SQL.

Solution: Add the following patterns to your functions.php or plugin file:

// Store a simple string
update_option( 'helloadmin_api_key', sanitize_text_field( $api_key ) );
$api_key = get_option( 'helloadmin_api_key', '' ); // '' is the default

// Store an array of settings (autoload=no for rarely-used data)
$settings = [
    'enable_feature'   => true,
    'items_per_page'   => 10,
    'allowed_roles'    => [ 'editor', 'administrator' ],
];
add_option( 'helloadmin_settings', $settings, '', 'no' ); // add once (e.g. on activation)
update_option( 'helloadmin_settings', $settings );         // update any time after

$settings = get_option( 'helloadmin_settings', [] );
$per_page  = absint( $settings['items_per_page'] ?? 10 );

// Delete an option
delete_option( 'helloadmin_settings' );

// On plugin activation: set defaults
register_activation_hook( __FILE__, 'helloadmin_activate' );
function helloadmin_activate() {
    add_option( 'helloadmin_version', '1.0.0', '', 'no' );
    add_option( 'helloadmin_settings', [
        'enable_feature' => false,
        'items_per_page' => 10,
    ], '', 'no' );
}

// On plugin deactivation: optionally clean up
register_deactivation_hook( __FILE__, 'helloadmin_deactivate' );
function helloadmin_deactivate() {
    // Uncomment to remove data on deactivation (use uninstall.php for full removal)
    // delete_option( 'helloadmin_settings' );
}

// Check for DB upgrades using a version option
add_action( 'plugins_loaded', 'helloadmin_run_upgrades' );
function helloadmin_run_upgrades() {
    $installed = get_option( 'helloadmin_version', '0.0.0' );
    if ( version_compare( $installed, '1.1.0', '<' ) ) {
        // run migration...
        update_option( 'helloadmin_version', '1.1.0' );
    }
}

NOTE: Autoloaded options are loaded in a single query on every WordPress page load, so the total size of all autoloaded options directly impacts your time-to-first-byte. Run SELECT option_name, LENGTH(option_value) FROM wp_options WHERE autoload=’yes’ ORDER BY LENGTH(option_value) DESC LIMIT 20; to see your heaviest autoloaded options and decide which ones should be set to autoload=’no’. Many plugins (especially page builders and SEO plugins) add large autoloaded options — this is a common source of slow WordPress admin dashboards.