Hello, I’m hoping for some insights into an issue I’m having. For a variety of reasons I need to prune leftover data from ACF fields when a post is saved. I’ve already read over similar topics (this one being very informative: https://support.advancedcustomfields.com/forums/topic/flush-unused-custom-fields/) and I’m fine with wiping out all ACF data attached to a page before saving it (all I care about is a single flex-field and its contents, so all my fields are effectively prefixed by the flex field, which itself has a unique name).
The issue I’m having is that bizarrely, the deletion process seems to continue to occur even as the post is being saved, leading to some of the new data being deleted as well (some of the data from the first flex row). I’m not sure how or why this would happen – if I run the SQL directly, then save the page, everything works perfectly – but if I tie it into acf/save_posts I always get a partial deletion (tossing in a sleep(X) seems to adjust how much is deleted, making me think that PHP execution is continuing while the SQL runs, but I’ve not seen this happen before and I’m not sure how to stop it – also I would have thought the table would be write locked).
Here’s an example of the SQL I’m running:
DELETE FROM wp_postmeta
WHERE wp_postmeta.post_id = 15543
AND (
meta_key LIKE 'page_builder_%'
OR meta_key LIKE '_page_builder_%'
)
Anyone have any ideas that would make sense of this behavior for me?
What is the priority of your acf/save_post action?
Also, I can’t be sure without seeing your action filter. The DB query to delete should be done before ACF inserts new data, so I can’t see why the deletion would continue while the update is being done.
Also, you may need to clear the meta cache for the post after you do the query. Here is what happens when a field is updated, what WP does.
First it does a query to see if the value is already in the DB. However, if the value is the the cache then it does not to the query and instead uses the value from the cache. If the new value and the old value are different then it does an update query, but if they are the same it may or may not do the update query (I have never been able to sort out why it sometimes does the update and other times does not).
There may also be a case where all of the data will be deleted but nothing new will be saved. This could happen if you update a post without making any changes to ACF fields. There is a hidden field for ACF that is a flag indicating if anything was updated. If this flag is not set then ACF will not update values but and your acf/save_post action might not be called.
Thanks John, that is very helpful.
Here’s the entirety of the function, its set to priority 0:
public static function remove_orphans($post_id) {
global $wpdb;
$result = $wpdb->query($wpdb->prepare("
DELETE FROM {$wpdb->postmeta}
WHERE {$wpdb->postmeta}.post_id = %d
AND (
meta_key LIKE '".static::PAGE_BUILDER_ACF_FIELD."_%'
OR meta_key LIKE '_".static::PAGE_BUILDER_ACF_FIELD."_%'
)",
$post_id
));
}
It’s very straightforward, hence my confusion.
The cache is interesting, I will give that a shot in a little bit and let you know if it works… Based on your description that does seem like it could be the source of some odd behavior.
I don’t think it will be an issue in normal operation if this process gets skipped when no changes are made, but I would like to be able to force it so that I don’t have to go through everything and make arbitrary changes to trigger an update – do you know of an easy way to do so and/or what’s the name of the field ACF uses to track that?
Thanks!
I should clarify
an acf/save_post action with a priority of < 10 will always be called
The ACF built in acf/save_post action which runs at priority 10 will be called but may not update anything if it detects no changes have been made.
I need to do some additional testing (due to how destructive this operation can be), but initial testing seems to indicate that running wp_cache_flush() immediately after the deletion does indeed fix the problem.
Thanks a bunch, hopefully that’s all it needed!
@kmdg would you be willing to share you final solution for this filter.
Just saw this, here’s what I ended up with – it’s nearly identical to the above:
public static function remove_orphans($post_id) {
global $wpdb;
$wpdb->query($wpdb->prepare("
DELETE FROM {$wpdb->postmeta}
WHERE {$wpdb->postmeta}.post_id = %d
AND (
meta_key LIKE '".static::PAGE_BUILDER_ACF_FIELD."_%'
OR meta_key LIKE '_".static::PAGE_BUILDER_ACF_FIELD."_%'
)",
$post_id
));
wp_cache_flush();
}
I’ve now tested this pretty extensively, having re-saved all the pages on a nearly 100 page site with no issues. This shaved a little over 60mb out of the postmeta table on this site.
Its worth noting that this does also clear out any saved data that is hidden behind conditional logic. I consider this a feature personally, as I find the default behavior of conditional fields in ACF a bit weird and error prone. This prevents situations where a field that is hidden by logic can still have a value even if its not visible.
Hello, please how to display active events first then the expired events , i need code!
am using ACF 5.7.10
Screenshot :
https://imagehost.imageupload.net/2020/04/23/FireShot-Capture-024—Evenements—mesloisirs—www.creativejobgroup.com.jpg
please please help me , am beginner on ACF
The topic ‘Pruning Orphaned Flex-field Data’ is closed to new replies.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.