#60434 closed enhancement (invalid)
Implementing a core solution for the infinite loop issue on `save_post` and `save_post_{$post->post_type}` action hooks.
Reported by: | gerardreches | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | minor | Version: | |
Component: | Posts, Post Types | Keywords: | dev-feedback |
Focuses: | Cc: |
Description
We all find ourselves having to use a manual fix when using wp_update_post()
in a save_post
or save_post_{$post->post_type}
callback to avoid an infinite loop.
https://developer.wordpress.org/reference/hooks/save_post/
https://developer.wordpress.org/reference/hooks/save_post_post-post_type/
The fix consists on removing the current action before updating the post, and then adding it again. But this only solves the problem for the current callback, as other actions that may have been added to the same hook may be firing twice.
I thought of a way to prevent this. This code would be contained in your save_post
action callback.
<?php /** * Prevent infinite loop and repeated actions. */ global $wp_actions, $wp_filters, $wp_filter; $actions = $wp_actions; $filters = $wp_filters; $filter = $wp_filter; remove_all_actions( 'save_post' ); remove_all_actions( "save_post_{$post->post_type}" ); wp_update_post( $post ); $wp_actions = $actions; $wp_filters = $filters; $wp_filter = $filter;
And then I was thinking that the core could include a wrapper function for this:
<?php function wp_update_post_silent( array|object $postarr = array(), bool $wp_error = false, bool $fire_after_hooks = true ): int|WP_Error { /** * Prevent infinite loop and repeating actions. */ global $wp_actions, $wp_filters, $wp_filter; $actions = $wp_actions; $filters = $wp_filters; $filter = $wp_filter; remove_all_actions( 'save_post' ); if ( is_object( $postarr ) ) { remove_all_actions( "save_post_{$postarr->post_type}" ); } elseif ( is_array( $postarr ) ) { remove_all_actions( "save_post_{$postarr['post_type']}" ); } $result = wp_update_post( $postarr, $wp_error, $fire_after_hooks ); $wp_actions = $actions; $wp_filters = $filters; $wp_filter = $filter; return $result; }
Or another option would be to add an optional 4th parameter to wp_update_post()
, similar to its third $fire_after_hooks = true
parameter. Something like $fire_save_hooks = true
.