Updating a WordPress Post in the Save Post Action

For those who have worked with WordPress long enough, you’re likely familiar and comfortable with how hooks works – that is, you’re familiar and comfortable with the event-driven design pattern.

Sure, it’s a bit different than many other frameworks and foundations that use MVC, MVVM, and some other remix of the model-view paradigm, but I don’t think that’s really here nor there in terms of which is better. This is what WordPress uses and it’s easy enough – and powerful enough – to work with once you’ve got it.

But that’s not to say it’s not without it’s nuances.

For example, one of the challenges of working with event-driven design is understanding how hooks work throughout the page lifecycle, how it’s possible to actually get stuck in an infinite loop if you’re not careful, and how to work with the various hooks to prevent this from happening.

Unhook and Hook the Save Post Action

To give a clear example as to how you can create an infinite loop within the context of event-driven design, take a look at the following code.

Though this is a simple example, here’s exactly what the class is doing:

  • The class defines a callback on the save_post action.
  • Then save_post is fired, the modify_post_content function is fired.
  • modify_post_content updates the post given the new array which empties the post content.

But there’s a problem in this code: Specifically, wp_update_post calls save_post, and when save_post is called, it triggers the modify_post_content function which sets the whole process into motion again.

So there’s our infinite loop.

Fixing the issue isn’t terribly difficult – simply put, you need to temporarily unhook modify_post_content from the save_post action to make sure that the update function fires without continually calling our custom.

To do this, we need to adjust the code to do the following:

  • Create the array that will be used to update the post
  • Unhook the modify_post_content action from the save_post hook
  • Update the post
  • Re-hook attach the save_post action

See the following code.

That will end the endless loop.

But Wait, There’s a Gotcha

What’s a piece of sample code without something that could go wrong?

Depending on your use case, un-hooking and re-hooking the action may still result in a loop depending on the priority of the hook that you’ve defined or based on any number of conditions based on the hook that you’re using.

Obviously, the code is above is meant to demonstrate how to handle the case of working with hooks to prevent an endless loop, but it’s not a mini-pattern or prescription for how to handle all cases like this.

Additionally, Helen points out an interesting point in that, in the code above, a better option would be to use wp_insert_post_data so if you’re looking for a copy-and-paste solution (which I’m no fan of), then the above code isn’t ideal. Instead, the point of the code above is to demonstrate how callbacks and trigger loops in event-driven programming.

If you’re looking to update a post’s data without falling into that trap, don’t copy and code above. Modify it to use the wp_insert_post_data function as shared by Helen.

Ultimately, the point is that you need to be careful in how you un-hook an action, perform an action, then re-hook an action. You may need to introduce some type of control variable to make sure that it doesn’t get called again after the hook is reattached, or reconsider your flow of control if performing the above action doesn’t work.

4 Comments

Hey Tom,
Why remove the hook and deal with the subsequent issues when you could just using a local static variable instead? This approach is rock solid. For example:
https://gist.github.com/mikeschinkel/d0ade8a26fe4934bb0be
-Mike

    Frankly, the thought just didn’t cross my mind :).

    Recursions one of those topics that, although powerful, I tend to stay away from unless absolutely needed. I dunno what that says about my proficiency as a programmer, but your suggestion makes perfect sense here.

    Thanks Mike!

      Avoiding recursion, eh? I’d say it’s one of the best and more powerful tools in my programming toolbelt, but you are correct it can be daunting at first. Recursion is a lot like Regular Expressions; before you become comfortable with them they seem like more trouble than they are worth. But once they “click” for you, you’ll wonder how you got along without them.

      That said, I realize my comment took away from your point about removing (or even adding) hooks while inside of the same hook and that’s actually a topic that probably needs more attention and not let less. That said, this particular use-case is easier to handle with a static to avoid recursion. As you acknowledged! :)

        Avoiding recursion, eh? I’d say it’s one of the best and more powerful tools in my programming toolbelt, but you are correct it can be daunting at first. Recursion is a lot like Regular Expressions; before you become comfortable with them they seem like more trouble than they are worth. But once they “click” for you, you’ll wonder how you got along without them.

        I should’ve clarified in that I don’t use recursion [as much as I probably should] for the sake of code readability. I think that’s a weak argument, but it’s true.

        The thing about recursion that I remember from my undergrad days is how it’s almost formulaic in terms of checking for the base case, recurse until the final condition is met, then set a flag to stop it. Generalized a bit, but you get the point, I’m sure :).

        That said, I realize my comment took away from your point about removing (or even adding) hooks while inside of the same hook and that’s actually a topic that probably needs more attention and not let less

        Yes – and its one of those topics that slightly more experienced programmers will be able to get whereas those who are just entering the space may have a hard time visualizing the event-driven pattern, the call stack moving up and down (with recursion), and so on.

        That said, it’s something I think that’s definitely worth covering at some point if for no other reason than to help bring a new perspective to how the lifecycle works.

Leave a Reply

Name and email address are required. Your email address will not be published.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>