• Resolved cfoster

    (@cfoster)


    I’m writing a routine that extracts certain posts and their related categories/tags from the database every time a post is saved but have noticed what may be a bug.

    If saving a post where only the categories or tags are changing, the term_relationships table (and/or other term-related tables) are not updated until after save_post is triggered. If the post is being saved with any changes in addition to the category or tag (e.g., the title or content), then the term_relationships are updated before save_post is called.

    e.g., If I change only the category and click “update” my save_post callback-function’s query to the database doesn’t see the new category assigned to this post (it looks like it did before the change since the category was the only update). If I then make a 2nd change to only the category in that post, the query retrieves the previous change, but doesn’t see the latest change. If I then change the title of the post only (no category change), the query retrieves the final change in category (and the change in title). If I change the title and the category together, I see the category and title change right away.

    I’m using PDO to query the database directly not wp_query().

    If anyone has any ideas of how to get the updated values right away, that would be great.

    • This topic was modified 12 months ago by cfoster.
    • This topic was modified 12 months ago by cfoster.
Viewing 3 replies - 1 through 3 (of 3 total)
  • Moderator bcworkz

    (@bcworkz)

    If you look at the insert post source code, you can see the function to update terms assigned to a post is called before the “save_post” action triggers. So why can you not get the updated terms? It’s due to a race condition. It takes time to write data in the DB. In the mean time, PHP continues to run, triggering the action before writing has completed. It’s not a bug per se, it’s more of a quirk of multi-threaded environments.

    It used to be we could always get the data we’re after from the data in $_POST. But with the block editor, not all data is available from $_POST anymore. Some data gets saved through the API. Still, trying to get the data from $_POST is the first thing to try. If that doesn’t work, then the next thing to try depends on what you’re trying to do with the data. You might need to identify an API hook related to what is being saved.

    Thread Starter cfoster

    (@cfoster)

    At first I thought of just delaying my execution with usleep() but this didn’t help. As such something on *my* thread must be responsible (not a race with another thread) because if it was on another thread it would have executed while mine was asleep.

    So, I got off my lazy butt and traced through the call. ??

    When one is saving a post with only Term (category / tag) changes, the post is saved through wp_insert_post() which, yes, does save Terms before triggering the save_post action but the Term data it passes to (ultimately) wp_set_object_terms() is the OLD terms for the post. (Why resave the old data? Dunno.)

    After save_post is triggered here (and my routine has retrieved the post with the old terms still in place), there’s one more call to wp_set_object_terms() (from WP_REST_Posts_Controller) that has a the new terms data in it. So it really is storing this data after the save_post has been triggered (but my lazy has now returned and I can’t be bothered to figure out why the controller is doing it this way).

    SOLUTION
    Regardless, tracing through it all I stumbled on rest_after_insert_post which fires only when ALL the data is saved. Yay!

    • This reply was modified 12 months ago by cfoster.
    Moderator bcworkz

    (@bcworkz)

    Good discovery! Thanks for sharing.

Viewing 3 replies - 1 through 3 (of 3 total)
  • The topic ‘`save_post` action is triggered before term_relationships is updated’ is closed to new replies.