[wp-trac] [WordPress Trac] #60434: Implementing a core solution for the infinite loop issue on `save_post` and `save_post_{$post->post_type}` action hooks.

WordPress Trac noreply at wordpress.org
Sun Feb 4 17:01:12 UTC 2024


#60434: Implementing a core solution for the infinite loop issue on `save_post` and
`save_post_{$post->post_type}` action hooks.
-------------------------------+-----------------------------
 Reporter:  gerardreches       |      Owner:  (none)
     Type:  enhancement        |     Status:  new
 Priority:  normal             |  Milestone:  Awaiting Review
Component:  Posts, Post Types  |    Version:
 Severity:  minor              |   Keywords:  dev-feedback
  Focuses:                     |
-------------------------------+-----------------------------
 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
 <?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
 <?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`.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/60434>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list