do_action( string $hook_name, mixed $arg )
- Since
- 1.2.0, 5.3.0
- Source
wp-includes/plugin.php:482
Fire an action hook with do_action() so every callback registered via add_action() runs, receiving any extra arguments you pass. Calling it with a new hook name creates the hook, which is how plugins and themes expose their own extension points; there is no return value.
Description
This function invokes all functions attached to action hook $hook_name.
It is possible to create new action hooks by simply calling this function, specifying the name of the new hook using the $hook_name parameter.
You can pass extra arguments to the hooks, much like you can with apply_filters().
Example usage:
// The action callback function.
function example_callback( $arg1, $arg2 ) {
// (maybe) do something with the args.
}
add_action( 'example_action', 'example_callback', 10, 2 );
/*
* Trigger the actions by calling the 'example_callback()' function
* that's hooked onto example_action above.
*
* - 'example_action' is the action hook.
* - $arg1 and $arg2 are the additional arguments passed to the callback.
do_action( 'example_action', $arg1, $arg2 );Compatibility
- WordPress
- since 5.3.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 name of the action to be executed.
$argmixed- Additional arguments which are passed on to the functions hooked to the action. Default empty.
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.
Create a custom extension point
Fire your own action so other code can react, exactly the way core actions work.
// Anything can hook this, exactly like a core action.
add_action( 'wppaste_order_processed', function ( $order_id ) {
echo "listener: order {$order_id} was processed\n";
}, 10, 1 );
function wppaste_process_order( $order_id ) {
update_post_meta( $order_id, '_processed_at', time() );
do_action( 'wppaste_order_processed', $order_id );
}
wppaste_process_order( 2 );
echo 'the action has run ', did_action( 'wppaste_order_processed' ), ' time(s)';Callbacks must be added before do_action() runs; anything registered later never fires.
Fire a hook with multiple arguments
Pass several values after the hook name and have listeners opt in to them with $accepted_args.
$imported_count = 12;
$skipped_count = 3;
do_action( 'myplugin_import_finished', $imported_count, $skipped_count );
// Elsewhere, another plugin listens for it.
add_action(
'myplugin_import_finished',
function ( $imported, $skipped ) {
error_log( "Import done: {$imported} imported, {$skipped} skipped." );
},
10,
2
);Listeners only receive the extra arguments when their add_action() call sets $accepted_args to match; with the default of 1 the second value never arrives.
Performance profile
How much work a call to do_action() 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
- 16–52
- 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 63.
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 it touches
- hookthird-party callbacks
do_action()this function does it
What one call costs · 6 distinct outcomes
One number would be a lie: the work depends on which branch runs. These are every distinct cost do_action() can have, taken from its control-flow graph on PHP 8.5.
| When | Instructions | Calls it makes |
|---|---|---|
!isset($wp_filter) && !isset($wp_filter[$hook_name]) | 16–17 | none |
!isset($wp_filter[$hook_name]) | 19–20 | array_pop() |
!isset($wp_filter[$hook_name]) | 22–23 | _wp_call_all_hook() |
isset($wp_filter) && !isset($wp_filter[$hook_name]) | 25–26 | _wp_call_all_hook(), array_pop() |
!isset($wp_filter) && isset($wp_filter[$hook_name]) | 28–46 | ->do_action(), array_pop() |
isset($wp_filter) && isset($wp_filter[$hook_name]) | 34–52 | _wp_call_all_hook(), ->do_action(), array_pop() |
Across PHP versions
Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 63 instructions, 16–52 executed per call, 10 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.
Uses · 1
- _wp_call_all_hook()Calls the 'all' hook, which will process the functions hooked into it.
Used by · 50
- Core_Upgrader::upgrade()Upgrades WordPress core.
- Custom_Image_Header::step_1()Displays first step of custom header image page.
- 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.
- Theme_Upgrader::bulk_upgrade()Upgrades several themes at once.
- Theme_Upgrader::install()Install a theme package.
- WP_Admin_Bar::add_menus()Adds menus to the admin bar.
- WP_Admin_Bar::initialize()Initializes the admin bar.
- WP_Application_Passwords::create_new_application_password()Creates a new application password.
- WP_Application_Passwords::delete_all_application_passwords()Deletes all application passwords for the given user.
- WP_Application_Passwords::delete_application_password()Deletes an application password.
Show all 50
- WP_Application_Passwords::update_application_password()Updates an application password.
- WP_Application_Passwords_List_Table::column_default()Generates content for a single row of the table
- WP_Application_Passwords_List_Table::print_js_template_row()Prints the JavaScript template for the new row item.
- WP_Automatic_Updater::run()Kicks off the background update process, looping through all pending updates.
- WP_Automatic_Updater::update()Updates an item, if appropriate.
- WP_Comments_List_Table::column_default()
- WP_Comments_List_Table::extra_tablenav()
- WP_Customize_Control::maybe_render()Checks capabilities and render the control.
- WP_Customize_Manager::_publish_changeset_values()Publishes the values of a changeset.
- WP_Customize_Manager::customize_preview_init()Prints JavaScript settings.
- WP_Customize_Manager::save_changeset_post()Saves the post for the loaded changeset.
- WP_Customize_Manager::set_post_value()Overrides a setting's value in the current customized state.
- WP_Customize_Manager::start_previewing_theme()If the theme to be previewed isn't the active theme, add filter callbacks to swap it out at runtime.
- WP_Customize_Manager::stop_previewing_theme()Stops previewing the selected theme.
- WP_Customize_Manager::trash_changeset_post()Trashes or deletes a changeset post.
- WP_Customize_Manager::wp_loaded()Registers styles/scripts and initialize the preview of each setting
- WP_Customize_Nav_Menu_Item_Control::content_template()JS/Underscore template for the control UI.
- WP_Customize_Panel::maybe_render()Check capabilities and render the panel.
- WP_Customize_Section::maybe_render()Check capabilities and render the section.
- WP_Customize_Selective_Refresh::handle_render_partials_request()Handles the Ajax request to return the rendered partials for the requested placements.
- WP_Customize_Setting::preview()Add filters to supply the setting's value when accessed.
- WP_Customize_Setting::save()Checks user capabilities and theme supports, and then saves the value of the setting.
- WP_Customize_Setting::update()Save the value of the setting, using the related API.
- WP_Customize_Widgets::customize_controls_init()Ensures all widgets get loaded into the Customizer.
- WP_Customize_Widgets::enqueue_scripts()Enqueues scripts and styles for Customizer panel and export data to JavaScript.
- WP_Customize_Widgets::print_footer_scripts()Calls admin_print_footer_scripts and admin_print_scripts hooks to allow custom scripts from plugins.
- WP_Customize_Widgets::print_scripts()Calls admin_print_scripts-widgets.php and admin_print_scripts hooks to allow custom scripts from plugins.
- WP_Customize_Widgets::print_styles()Calls admin_print_styles-widgets.php and admin_print_styles hooks to allow custom styles from plugins.
- WP_Customize_Widgets::wp_ajax_update_widget()Updates widget settings asynchronously.
- WP_Error::add()Adds an error or appends an additional message to an existing error.
- WP_Http::_dispatch_request()Dispatches a HTTP request to a supporting transport.
- WP_Http::request()Send an HTTP request to a URI.
- WP_Links_List_Table::column_default()Handles the default column output.
- WP_Locale_Switcher::change_locale()Changes the site's locale to the given one.
- WP_Locale_Switcher::restore_previous_locale()Restores the translations according to the previous locale.
- WP_Locale_Switcher::switch_to_locale()Switches the translations according to the given locale.
- WP_MS_Sites_List_Table::column_default()Handles output for the default column.
- WP_MS_Sites_List_Table::column_plugins()Handles the plugins column output.
Source code
function do_action( $hook_name, ...$arg ) { global $wp_filter, $wp_actions, $wp_current_filter; if ( ! isset( $wp_actions[ $hook_name ] ) ) { $wp_actions[ $hook_name ] = 1; } else { ++$wp_actions[ $hook_name ]; } // Do 'all' actions first. if ( isset( $wp_filter['all'] ) ) { $wp_current_filter[] = $hook_name; $all_args = func_get_args(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection _wp_call_all_hook( $all_args ); } if ( ! isset( $wp_filter[ $hook_name ] ) ) { if ( isset( $wp_filter['all'] ) ) { array_pop( $wp_current_filter ); } return; } if ( ! isset( $wp_filter['all'] ) ) { $wp_current_filter[] = $hook_name; } if ( empty( $arg ) ) { $arg[] = ''; } elseif ( is_array( $arg[0] ) && 1 === count( $arg[0] ) && isset( $arg[0][0] ) && is_object( $arg[0][0] ) ) { // Backward compatibility for PHP4-style passing of `array( &$this )` as action `$arg`. $arg[0] = $arg[0][0]; } $wp_filter[ $hook_name ]->do_action( $arg ); array_pop( $wp_current_filter );}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.
...$arg parameter by adding it to the function signature.from the docblockAbout this page
- Parsed data
- Generated from the wordpress-develop 6.8.8 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.