delete_option( string $option ): bool
- Since
- 1.2.0
- Source
wp-includes/option.php:1201
Deletes a single row from the wp_options table by option name, returning true only when a matching row existed and was removed. Internal options guarded by wp_protect_special_option() cannot be deleted this way. Pair it with add_option() or update_option() when you need to reset a setting rather than remove it outright.
Compatibility
- WordPress
- since 1.2.0
- PHP
- 7.4–8.6-dev
- 6.7.7
- 6.8.8
- 6.9.7
- 7.0.4
- 7.1.0
Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.
Parameters
$optionstring- Name of the option to delete. Expected to not be SQL-escaped.
Return value
bool- True if the option was deleted, false otherwise.
Code examples
Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.
Delete a custom plugin setting and confirm it's gone
A plugin stores a settings array under its own option name and needs to remove it during cleanup, for example on uninstall.
add_option( 'my_plugin_settings', array( 'enabled' => true, 'threshold' => 10 ) );
$deleted = delete_option( 'my_plugin_settings' );
printf( 'delete_option() returned: %s' . "\n", $deleted ? 'true' : 'false' );
$value = get_option( 'my_plugin_settings', 'default (not found)' );
printf( 'get_option() now returns: %s', esc_html( is_array( $value ) ? print_r( $value, true ) : $value ) );add_option() is used here purely to have something to remove; in real plugin code the option would already exist from earlier use.
Run cleanup code when a specific option is deleted
Hook into the dynamic delete_option_{$option} action to react whenever one particular option name is removed.
add_option( 'my_feature_flag', '1' );
add_action( 'delete_option_my_feature_flag', function ( $option ) {
printf( 'Fired delete_option_%s just before removal.' . "\n", esc_html( $option ) );
} );
$result = delete_option( 'my_feature_flag' );
printf( 'Deletion result: %s', $result ? 'true' : 'false' );The dynamic hook only fires when a matching row is found and the deletion query runs, not when the option was already missing.
Common problems and fixes · 4
- Why does delete_option keep returning false even though I'm sure the option exists?
- Why did my code die with a 'protected WP option' message when I called delete_option?
- Does delete_option clear the object cache right away or just the database row?
- Why doesn't my delete_option_{$option} callback fire during install?
Why does delete_option keep returning false even though I'm sure the option exists?
Why did my code die with a 'protected WP option' message when I called delete_option?
Does delete_option clear the object cache right away or just the database row?
Why doesn't my delete_option_{$option} callback fire during install?
Alternatives and related functions
update_option- When you want to change an option's value without ever removing the row, since update_option() will create it if it doesn't exist yet.
add_option- When you only want to set a value the first time and leave an existing option untouched.
delete_site_option- When the setting is a network-wide option in a multisite install rather than a single site's option.
delete_transient- When the value you're removing was stored as a transient rather than a permanent option, since transients use a separate storage and expiration mechanism.
Performance profile
How much work a call to delete_option() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.
- Cost class
- Heavy
- Scaling
- Constant
- Instructions
- 7–87
- Plugin surface
- 3 hooks
- Called by
- 34
Reaches the database via ->get_row().
No loop in the body: the same number of instructions runs whatever you pass in.
Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 94.
Third-party callbacks on 'delete_option', 'delete_option_{$option}', 'deleted_option' run inside this call, and their cost is not bounded by anything here.
34 places in core call this, so the cost is paid more often than your own code shows.
What it touches
- optionoption read or write
delete_option()this function does it - hookthird-party callbacks
do_action()called directly - cacheobject cache
wp_cache_set()called directly - sqldatabase query
->get_row()called directly
Further down the call graph this can also reach serialize, query and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.
What one call costs · 10 distinct outcomes
One number would be a lie: the work depends on which branch runs. These are every distinct cost delete_option() can have, taken from its control-flow graph on PHP 8.5.
| When | Instructions | Calls it makes |
|---|---|---|
empty($option) | 7–9 | none |
!empty($option) && $row === null | 24–26 | wp_protect_special_option(), ->prepare(), ->get_row() |
!empty($option) && $row !== null && wp_installing() | 40–42 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing() |
!empty($option) && $row !== null && wp_installing() | 49–51 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing(), do_action(), do_action() |
!empty($option) && $row !== null && !wp_installing() | 64–67 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing(), wp_autoload_values_to_autoload(), wp_cache_delete(), wp_cache_get(), wp_cache_set() |
!empty($option) && $row !== null && !wp_installing() | 66–71 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing(), wp_autoload_values_to_autoload(), wp_load_alloptions(), wp_cache_get(), wp_cache_set() |
!empty($option) && $row !== null && !wp_installing() | 73–76 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing(), wp_autoload_values_to_autoload(), wp_cache_delete(), wp_cache_get(), wp_cache_set(), do_action(), do_action() |
!empty($option) && $row !== null && !wp_installing() && is_array($alloptions) && isset($alloptions[$option]) | 75–78 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing(), wp_autoload_values_to_autoload(), wp_load_alloptions(), wp_cache_set(), wp_cache_get(), wp_cache_set() |
!empty($option) && $row !== null && !wp_installing() | 75–80 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing(), wp_autoload_values_to_autoload(), wp_load_alloptions(), wp_cache_get(), wp_cache_set(), do_action(), do_action() |
!empty($option) && $row !== null && !wp_installing() && is_array($alloptions) && isset($alloptions[$option]) | 84–87 | wp_protect_special_option(), ->prepare(), ->get_row(), do_action(), option_name(), wp_installing(), wp_autoload_values_to_autoload(), wp_load_alloptions(), wp_cache_set(), wp_cache_get(), wp_cache_set(), do_action(), do_action() |
Across PHP versions
| PHP | Compiled | Executed | Branches | Notes |
|---|---|---|---|---|
| 8.6-dev | 94 | 7–87 | 9 | |
| 8.5 | 94 | 7–87 | 9 | |
| 8.4 | 94 | 7–87 | 9 | 5 fewer instructions than PHP 8.3 |
| 8.3 | 99 | 7–92 | 9 | |
| 8.2 | 99 | 7–92 | 9 | |
| 8.1 | 99 | 7–92 | 9 | 2 fewer instructions than PHP 7.4 |
| 7.4 | 101 | 9–94 | 9 |
An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.
Hooks and filters fired · 3
3 hooks fire while delete_option() runs, in this order:
- do_action( delete_option )actionline 1227 (+26 into the body)
Fires immediately before an option is deleted.
- do_action( delete_option_{$option} )actionline 1264 (+63 into the body)
Fires after a specific option has been deleted.
- do_action( deleted_option )actionline 1273 (+72 into the body)
Fires after an option has been deleted.
Uses · 8
- wp_protect_special_option()Protects WordPress special option from being modified.
- do_action()Calls the callback functions that have been added to an action hook.
- wp_installing()Checks or sets whether WordPress is in "installation" mode.
- wp_autoload_values_to_autoload()Returns the values that trigger autoloading from the options table.
- wp_load_alloptions()Loads and caches all autoloaded options, if available or all options.
- wp_cache_set()Saves the data to the cache.
- wp_cache_delete()Removes the cache contents matching key and group.
- wp_cache_get()Retrieves the cache contents from the cache by key and group.
Used by · 34
- Twenty_Eleven_Ephemera_Widget::update()Updates widget settings.
- WP_Paused_Extensions_Storage::delete()Forgets a previously recorded extension error.
- WP_Paused_Extensions_Storage::delete_all()Remove all paused extensions.
- WP_REST_Settings_Controller::update_item()Updates settings for the settings object.
- WP_Recovery_Mode_Email_Service::clear_rate_limit()Clears the rate limit, allowing a new recovery mode email to be sent immediately.
- WP_Site_Icon::delete_attachment_data()Deletes the Site Icon when the image file is deleted.
- WP_Theme::get_allowed_on_site()Returns array of stylesheet names of themes allowed on the site.
- WP_Upgrader::release_lock()Releases an upgrader lock.
- WP_Widget::get_settings()Retrieves the settings for all instances of the widget class.
- _delete_attachment_theme_mod()Checks an attachment being deleted to see if it's a header or background image.
- _delete_site_logo_on_remove_custom_logo()Deletes the site_logo when the custom_logo theme mod is removed.
- _delete_site_logo_on_remove_theme_mods()Deletes the site logo when all theme mods are being removed.
Show all 34
- _sync_custom_logo_to_site_logo()Updates the site_logo option when the custom_logo theme-mod gets updated.
- _wp_batch_split_terms()Splits a batch of shared taxonomy terms.
- _wp_batch_update_comment_type()Updates the comment type for a batch of comments.
- _wp_menus_changed()Handles menu config after theme change.
- _wp_upgrade_revisions_of_post()Upgrades the revisions author, adds the current post as a revision and sets the revisions version to 1.
- clean_taxonomy_cache()Cleans the caches for a taxonomy.
- delete_blog_option()Removes an option by name for a given blog ID. Prevents removal of protected WordPress options.
- delete_network_option()Removes a network option by name.
- delete_transient()Deletes a transient.
- get_theme_mods()Retrieves all theme modifications.
- get_transient()Retrieves the value of a transient.
- maybe_add_existing_user_to_blog()Adds a new user to a blog by visiting /newbloguser/{key}/.
- populate_options()Create WordPress options and set the default values.
- remove_theme_mods()Removes theme modifications option for the active theme.
- set_transient()Sets/updates the value of a transient.
- switch_theme()Switches the theme.
- update_core()Upgrades the core of WordPress.
- update_home_siteurl()Flushes rewrite rules if `siteurl`, `home` or `page_on_front` changed.
- upgrade_340()Execute changes made in WordPress 3.4.
- upgrade_550()Executes changes made in WordPress 5.5.0.
- upgrade_630()Executes changes made in WordPress 6.3.0.
- wp_update_https_migration_required()Updates the 'https_migration_required' option if needed when the given URL has been updated from HTTP to HTTPS.
Source code
function delete_option( $option ) { global $wpdb; if ( is_scalar( $option ) ) { $option = trim( $option ); } if ( empty( $option ) ) { return false; } wp_protect_special_option( $option ); // Get the ID, if no ID then return. $row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) ); if ( is_null( $row ) ) { return false; } /** * Fires immediately before an option is deleted. * * @since 2.9.0 * * @param string $option Name of the option to delete. */ do_action( 'delete_option', $option ); $result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) ); if ( ! wp_installing() ) { if ( in_array( $row->autoload, wp_autoload_values_to_autoload(), true ) ) { $alloptions = wp_load_alloptions( true ); if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) { unset( $alloptions[ $option ] ); wp_cache_set( 'alloptions', $alloptions, 'options' ); } } else { wp_cache_delete( $option, 'options' ); } $notoptions = wp_cache_get( 'notoptions', 'options' ); if ( ! is_array( $notoptions ) ) { $notoptions = array(); } $notoptions[ $option ] = true; wp_cache_set( 'notoptions', $notoptions, 'options' ); } if ( $result ) { /** * Fires after a specific option has been deleted. * * The dynamic portion of the hook name, `$option`, refers to the option name. * * @since 3.0.0 * * @param string $option Name of the deleted option. */ do_action( "delete_option_{$option}", $option ); /** * Fires after an option has been deleted. * * @since 2.9.0 * * @param string $option Name of the deleted option. */ do_action( 'deleted_option', $option ); return true; } return false;}Changelog
Introduced in 1.2.0. Unchanged from 6.7.7 through 7.1.0.
Signature, return type and hooks compared across 5 parsed releases.
About this page
- Parsed data
- Generated from the wordpress-develop 7.1.0 tag, from
src/wp-includes/option.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it. - Corrections
- Something wrong on this page? Report it and it gets fixed in the next regeneration.