remove_filter( string $hook_name, callable|string|array $callback, int $priority = 10 ): bool
- Since
- 1.2.0
- Source
wp-includes/plugin.php:318
Detaches a previously registered callback from a filter hook, using the hook name, callback, and priority to identify it. The $priority argument must match the value used when the callback was originally added via add_filter(), or the removal silently fails and the callback keeps running. Pair it with has_filter() first if you need to know whether a callback is even attached before trying to remove it.
Description
This can be used to remove default functions attached to a specific filter hook and possibly replace them with a substitute.
To remove a hook, the $callback and $priority arguments must match when the hook was added. This goes for both filters and actions. No warning will be given on removal failure.
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
$hook_namestring- The filter hook to which the function to be removed is hooked.
$callbackcallable|string|array- The callback to be removed from running when the filter is applied.
This function can be called unconditionally to speculatively remove a callback that may or may not exist. $priorityintoptional- The exact priority used when adding the original filter callback. Default 10.Default:
10
Return value
bool- Whether the function existed before it was removed.
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.
Strip wpautop from post content before displaying it
Compare the_content output with and without the core wpautop filter attached.
$post = get_post( 1 );
$before = apply_filters( 'the_content', $post->post_content );
remove_filter( 'the_content', 'wpautop' );
$after = apply_filters( 'the_content', $post->post_content );
echo 'With wpautop: ' . esc_html( $before );
echo '<br>';
echo 'Without wpautop: ' . esc_html( $after );wpautop is normally attached to the_content at priority 10, which is why no explicit $priority argument is needed here.
Show that removal fails silently when the priority doesn't match
Attach a title filter at priority 20, then attempt to remove it with the wrong priority before removing it correctly.
function wpp_shout_title( $title ) {
return strtoupper( $title );
}
add_filter( 'the_title', 'wpp_shout_title', 20 );
$post = get_post( 1 );
echo 'Before removal: ' . esc_html( apply_filters( 'the_title', $post->post_title, $post->ID ) );
echo '<br>';
$wrong = remove_filter( 'the_title', 'wpp_shout_title', 10 );
echo 'remove_filter() with priority 10 returned: ' . ( $wrong ? 'true' : 'false' );
echo '<br>';
echo 'Still shouting: ' . esc_html( apply_filters( 'the_title', $post->post_title, $post->ID ) );
echo '<br>';
$right = remove_filter( 'the_title', 'wpp_shout_title', 20 );
echo 'remove_filter() with priority 20 returned: ' . ( $right ? 'true' : 'false' );
echo '<br>';
echo 'After correct removal: ' . esc_html( apply_filters( 'the_title', $post->post_title, $post->ID ) );Common problems and fixes · 3
- Why does remove_filter() return false even though I definitely added the callback?
- Why doesn't removing a filter from inside a callback on that same hook change the current output?
- Why can't I remove a filter that was added with an anonymous function?
Why does remove_filter() return false even though I definitely added the callback?
Why doesn't removing a filter from inside a callback on that same hook change the current output?
Why can't I remove a filter that was added with an anonymous function?
Alternatives and related functions
remove_action- When the hook was registered with add_action() and fired with do_action() rather than apply_filters(), since actions and filters share the same underlying hook storage but have their own paired functions.
has_filter- When you only need to check whether a callback is currently attached to a hook, optionally at a specific priority, without removing it.
remove_all_filters- When you want to strip every callback (or every callback at a given priority) from a hook instead of removing one specific callback.
add_filter- When you need to reattach a replacement callback to the same hook right after removing the original one.
Performance profile
How much work a call to remove_filter() 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
- Trivial
- Scaling
- Constant
- Instructions
- 8–19
- Plugin surface
- None
- Called by
- 50
Touches nothing outside its own arguments.
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 19.
Nothing here hands control to plugin code.
50 places in core call this, so the cost is paid more often than your own code shows.
What one call costs · 2 distinct outcomes
One number would be a lie: the work depends on which branch runs. These are every distinct cost remove_filter() can have, taken from its control-flow graph on PHP 8.5.
| When | Instructions | Calls it makes |
|---|---|---|
!isset($wp_filter[$hook_name]) | 8 | none |
isset($wp_filter[$hook_name]) | 18–19 | ->remove_filter() |
Across PHP versions
Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 19 instructions, 8–19 executed per call, 2 branches. The work does not change between versions.
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.
Used by · 50
- Language_Pack_Upgrader::bulk_upgrade()Upgrades several language packs at once.
- Plugin_Upgrader::bulk_upgrade()Upgrades several plugins at once.
- Plugin_Upgrader::install()Install a plugin package.
- Plugin_Upgrader::upgrade()Upgrades a plugin.
- Theme_Upgrader::bulk_upgrade()Upgrades several themes at once.
- Theme_Upgrader::check_parent_theme_filter()Checks if a child theme is being installed and its parent also needs to be installed.
- Theme_Upgrader::install()Install a theme package.
- Theme_Upgrader::upgrade()Upgrades a theme.
- WP_Customize_Manager::save_changeset_post()Saves the post for the loaded changeset.
- WP_Customize_Manager::stop_previewing_theme()Stops previewing the selected theme.
- WP_Customize_Nav_Menus::customize_register()Adds the customizer settings and controls.
- WP_Customize_Nav_Menus::insert_auto_draft_post()Adds a new `auto-draft` post.
Show all 50
- WP_Customize_Widgets::render_widget_partial()Renders a specific widget using the supplied sidebar arguments.
- WP_Customize_Widgets::stop_capturing_option_updates()Undoes any changes to the options since options capture began.
- WP_Metadata_Lazyloader::reset_queue()Resets lazy-load queue for a given object type.
- WP_REST_Attachments_Controller::prepare_item_for_response()Prepares a single attachment output for response.
- WP_REST_Comments_Controller::check_read_post_permission()Checks if the post can be read.
- WP_REST_Font_Faces_Controller::handle_font_file_upload()Handles the upload of a font file using wp_handle_upload().
- WP_REST_Global_Styles_Controller::prepare_item_for_response()Prepare a global styles config output for response.
- WP_REST_Menu_Items_Controller::prepare_item_for_response()Prepares a single nav menu item output for response.
- WP_REST_Post_Search_Handler::prepare_item()Prepares the search result for a given post ID.
- WP_REST_Posts_Controller::get_items()Retrieves a collection of posts.
- WP_REST_Posts_Controller::prepare_item_for_response()Prepares a single post output for response.
- WP_Taxonomy::remove_hooks()Removes the ajax callback for the meta box.
- WP_Widget_Custom_HTML::widget()Outputs the content for the current Custom HTML widget instance.
- WP_Widget_Media_Video::render_media()Render the media on the frontend.
- WP_Widget_Text::form()Outputs the Text widget settings form.
- WP_Widget_Text::widget()Outputs the content for the current Text widget instance.
- Walker_Comment::start_el()Starts the element output.
- _WP_Editors::editor()Outputs the HTML for a single instance of the editor.
- _default_wp_die_handler()Kills WordPress execution and displays HTML page with an error message.
- _filter_query_attachment_filenames()Filter the SQL clauses of an attachment query to include filenames.
- _resolve_template_for_new_post()Sets the current WP_Query to return auto-draft posts.
- _restore_wpautop_hook()If do_blocks() needs to remove wpautop() from the `the_content` filter, this re-adds it afterwards, for subsequent `the_content` usage.
- _wp_footnotes_remove_filters()Removes the filters for footnotes meta field.
- _wp_get_iframed_editor_assets()Collect the block editor assets that need to be loaded into the editor's iframe.
- _wp_post_thumbnail_class_filter_remove()Removes the '_wp_post_thumbnail_class_filter' callback from the 'wp_get_attachment_image_attributes' filter hook. Internal use only.
- _wp_post_thumbnail_context_filter_remove()Removes the '_wp_post_thumbnail_context_filter' callback from the 'wp_get_attachment_image_context' filter hook. Internal use only.
- apply_block_hooks_to_content()Runs the hooked blocks algorithm on the given content.
- apply_block_hooks_to_content_from_post_object()Run the Block Hooks algorithm on a post object's content.
- block_core_comment_template_render_comments()Function that recursively renders a list of nested comments.
- block_core_query_disable_enhanced_pagination()Traverse the tree of blocks looking for any plugin block (i.e., a block from an installed plugin) inside a Query block with the enhanced pagination enabled. If at least one is found, the enhanced pagination is effectively disabled to prevent any potential incompatibilities.
- do_blocks()Parses dynamic blocks out of `post_content` and re-renders them.
- do_shortcode()Searches content for shortcodes and filter shortcodes through their hooks.
- insert_hooked_blocks_into_rest_response()Hooks into the REST API response for the Posts endpoint and adds the first and last inner blocks.
- kses_remove_filters()Removes all KSES input form content filters.
- remove_action()Removes a callback function from an action hook.
- render_block_core_comments()Renders the `core/comments` block on the server.
- render_block_core_comments_pagination_next()Renders the `core/comments-pagination-next` block on the server.
- render_block_core_comments_pagination_previous()Renders the `core/comments-pagination-previous` block on the server.
Source code
function remove_filter( $hook_name, $callback, $priority = 10 ) { global $wp_filter; $r = false; if ( isset( $wp_filter[ $hook_name ] ) ) { $r = $wp_filter[ $hook_name ]->remove_filter( $hook_name, $callback, $priority ); if ( ! $wp_filter[ $hook_name ]->callbacks ) { unset( $wp_filter[ $hook_name ] ); } } return $r;}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.0.4 tag, from
src/wp-includes/plugin.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.