This is a pretty heavy-handed ‘solution’ but, for what it’s worth, what I’m doing at the moment to remove unused ACF post_meta data is this…
I name all my ACF fields with a unique prefix (eg. my_prefix_first_name, my_prefix_last_name, etc…) making sure that my_prefix is unlikely to conflict with any default WordPress post_meta keys or any of the post_meta keys created by plugins that I might use.
Then, every time I update a post, I simply delete ALL post_meta containing my_prefix using the acf/save_post action below:
function acf_delete_all_post_meta($post_id) {
global $wpdb;
$result = $wpdb->query($wpdb->prepare("
DELETE FROM wp_postmeta
WHERE meta_key
LIKE '%my_prefix%'
AND wp_postmeta.post_id = %s",
$post_id
));
}
add_action('acf/save_post', 'acf_delete_all_post_meta', 1);
With a priority of less than 10, this action will fire BEFORE the actual post data is saved. Thus, when the post data IS saved, it’s saved to a clean slate and only saves post_meta for fields that are currently being used in the post.
Obviously, this technique will not flush your entire site of unwanted post_meta in one go – it only acts upon one post at a time and only when you update the post. However, if used during development (which is probably the only time I would use it) it will help tidy-things-up as you go along.