did_action( string $hook_name ): int
- Since
- 2.1.0
- Source
wp-includes/plugin.php:685
Returns how many times a given action hook has already fired during the current request, based on the global $wp_actions counter. Use it to guard code that should only run once a hook has completed, or to confirm a hook actually fired during a bulk operation. It does not tell you whether a callback is currently attached; for that use has_action() instead.
Compatibility
- WordPress
- since 2.1.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 hook.
Return value
int- The number of times the action hook has been fired.
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.
Check whether the init hook has already fired
Guard logic that should behave differently depending on whether WordPress has finished the init phase.
$times = did_action( 'init' );
if ( $times > 0 ) {
echo esc_html( sprintf( 'The init action has fired %d time(s) so far.', $times ) );
} else {
echo esc_html( 'The init action has not fired yet in this request.' );
}Confirm save_post fired once per post during a bulk update
Programmatically touch posts 1 through 5 and then check how many times save_post ran.
foreach ( range( 1, 5 ) as $post_id ) {
wp_update_post(
array(
'ID' => $post_id,
'post_title' => get_the_title( $post_id ) . ' (touched)',
)
);
}
echo esc_html( sprintf( 'save_post fired %d time(s) during this request.', did_action( 'save_post' ) ) );wp_update_post() fires save_post once per successful update, so the count reflects only updates made in this request, not any prior ones.
Common problems and fixes · 4
- Why does did_action always return 0 for a hook I know runs on every page?
- What's the difference between did_action and has_action?
- Does did_action tell me if I'm currently inside that action right now?
- Will did_action remember counts from an earlier page load?
Why does did_action always return 0 for a hook I know runs on every page?
What's the difference between did_action and has_action?
Does did_action tell me if I'm currently inside that action right now?
Will did_action remember counts from an earlier page load?
Alternatives and related functions
has_action- When you need to know whether a specific callback is registered on a hook, regardless of whether that hook has fired yet.
doing_action- When you need to know if you are currently inside the execution of that hook's callbacks, not just whether it fired in the past.
current_action- When you need the name of whichever hook is presently executing, rather than a fire count for one specific hook.
did_filter- When you need the same fire count but for a filter hook instead of an action hook.
Performance profile
How much work a call to did_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
- 5–6
- Plugin surface
- None
- Called by
- 49
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 7.
Nothing here hands control to plugin code.
49 places in core call this, so the cost is paid more often than your own code shows.
What one call costs · 1 distinct outcome
One number would be a lie: the work depends on which branch runs. These are every distinct cost did_action() can have, taken from its control-flow graph on PHP 8.5.
| When | Instructions | Calls it makes |
|---|---|---|
| always | 5–6 | none |
Across PHP versions
Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 7 instructions, 5–6 executed per call, 1 branch. 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 · 49
- WP_Abilities_Registry::get_instance()Utility method to retrieve the main instance of the registry class.
- WP_Ability_Categories_Registry::get_instance()Utility method to retrieve the main instance of the registry class.
- WP_Admin_Bar::_render()
- WP_Block::render()Generates the render output for the block.
- WP_Customize_Manager::_publish_changeset_values()Publishes the values of a changeset.
- WP_Customize_Manager::import_theme_starter_content()Imports theme starter content into the customized state.
- WP_Customize_Widgets::call_widget_update()Finds and invokes the widget update and control callbacks.
- WP_Privacy_Policy_Content::text_change_check()Performs a quick check to determine whether any privacy info has changed.
- WP_Rewrite::flush_rules()Removes rewrite rules and then recreate rewrite rules.
- WP_Rewrite::refresh_rewrite_rules()Refreshes the rewrite rules, saving the fresh value to the database.
- WP_Site::__get()Getter.
- WP_Site::__isset()Isset-er.
Show all 49
- WP_User_Query::query()Executes the query, with the current variables.
- _WP_Editors::enqueue_default_editor()Enqueue all editor scripts.
- _default_wp_die_handler()Kills WordPress execution and displays HTML page with an error message.
- _load_textdomain_just_in_time()Loads plugin and theme text domains just-in-time.
- _register_widget_form_callback()Registers the form callback for a widget.
- _remove_theme_support()Do not use. Removes theme support internally without knowledge of those not used by themes directly.
- _wp_customize_publish_changeset()Publishes a snapshot's changes.
- _wp_scripts_maybe_doing_it_wrong()Helper function to output a _doing_it_wrong message when applicable.
- add_theme_support()Registers theme support for a given feature.
- create_initial_taxonomies()Creates the initial taxonomies.
- get_the_content()Retrieves the post content.
- print_emoji_detection_script()Prints the inline Emoji detection script if it is not already printed.
- print_head_scripts()Prints the script queue in the HTML head on admin pages.
- register_rest_route()Registers a REST API route.
- script_concat_settings()Determines the concatenation and compression settings for scripts and styles.
- wp_add_privacy_policy_content()Declares a helper function for adding content to the Privacy Policy Guide.
- wp_admin_css()Enqueues or directly prints a stylesheet link to the specified CSS file.
- wp_allowed_protocols()Retrieves a list of protocols to allow in HTML attributes.
- wp_audio_shortcode()Builds the Audio shortcode output.
- wp_cron()Registers _wp_cron() to run on the {@see 'shutdown'} action.
- wp_default_packages()Registers all the WordPress packages scripts.
- wp_default_packages_vendor()Registers all the WordPress vendor scripts that are in the standardized `js/dist/vendor/` location.
- wp_default_scripts()Registers all WordPress scripts.
- wp_enqueue_block_style()Enqueues a stylesheet for a specific block.
- wp_enqueue_media()Enqueues all scripts, styles, settings, and templates necessary to use all media JS APIs.
- wp_get_loading_attr_default()Gets the default value to use for a `loading` attribute on an element.
- wp_get_loading_optimization_attributes()Gets loading optimization attributes.
- wp_load_translations_early()Attempts an early load of translations.
- wp_oembed_add_provider()Adds a URL format and oEmbed provider URL pair.
- wp_oembed_remove_provider()Removes an oEmbed provider.
- wp_print_head_scripts()Prints the script queue in the HTML head on the front end.
- wp_register_sidebar_widget()Registers an instance of a widget.
- wp_register_widget_control()Registers widget control callback for customizing options.
- wp_switch_roles_and_user()Switches the initialized roles and current user capabilities to another site.
- wp_video_shortcode()Builds the Video shortcode output.
- wpdb::check_connection()Checks that the connection to the database is still up. If not, try to reconnect.
- wpdb::select()Selects a database using the current or provided database connection.
Source code
function did_action( $hook_name ) { global $wp_actions; if ( ! isset( $wp_actions[ $hook_name ] ) ) { return 0; } return $wp_actions[ $hook_name ];}Changelog
Introduced in 2.1.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 6.9.7 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.