acf-post2post icon indicating copy to clipboard operation
acf-post2post copied to clipboard

Update relationship after post delete

Open FloLech opened this issue 4 years ago • 3 comments

I encountered an issue when deleting a post by the method wp_delete_post(POST_ID). The related posts do not get updated. In other words: once a post is deleted the relationship field does not get updated until a manual save action is triggered in the WP Admin area.

Context: I have two post types (products and productBundles). A productBundle is linked to multiple Products. A Product might be linked to multiple productBundles. When a product is deleted by using wp_delete_post(productID) the productBundle still keeps a reference to the deleted product. When saving the productBundle in the WP backend the reference is updated.

How can I trigger an automated update of the related productBundle?

Hint: already tried triggering wp_save_post_revision(relatedProductBundleId), did not work :(

FloLech avatar Dec 09 '20 11:12 FloLech

I did not build this in because there usually is not a need do to so. When you get the field on the front end ACF should only return valid posts and skip posts that no longer exist. In the admin when editing the post any invalid posts should automatically be remove from the selected posts.

The only case I can see that you'd get deleted posts is if you get an unformulated value from ACF, for example using get_field(relationship_field, false, false)` in this case ACF only returns a list of post IDs and may include the deleted posts. If you do this then in your loop when displaying anything for a post you would first need to check that the post ID is associated with an active post.

Can you give my an example where not updating when a post is deleted is causing an issue.

Hube2 avatar Dec 09 '20 12:12 Hube2

Thanks for your answer! I use exactly the second case: I get a list of ids from the relationship field and populate data with the get_field("key", $id) function.

In the meantime I figured out a solution to this problem: when deleting a product I loop over the related prodcutBundels and splice out the deleted product id from the relationship field.

In general I think it might be hard to implement an abstract delete method for your plugin due to the complex use cases that might appear (delete related post, delete relationship, etc).

Keep up the great work, really appropriate your plugin and like using it!

FloLech avatar Dec 09 '20 12:12 FloLech

I have done this with other things, but it was more specific and requires hooking into the WP trash/delete before the post is actually trashed or deleted. But since only the post ID is passed in these cases it would require reading through every field associated with a post to find the relationship fields and then check each relationship field to see if it is a bidirectional field and then go through the process of removing the relationships on the other end. It would be a time consuming process.

I will have to think about this, it might be possible to add a way to allow specifying field names or keys where this should be done when a post is deleted using a filter and that could reduce the resources and time required.

A filter on the WP pre delete post action (sorry, I forget what this hook is) custom made for your fields that checks for specific post types would speed it up. You could then simply update the relationship field on that post update_field('relationship_field', array(), $post_id) this would, or should, trigger this plugin to do the updates.... I think. The value updated would just need to be the empty value that ACF is expecting based on if it is a relationship or post object field and its associated settings.

Hube2 avatar Dec 09 '20 14:12 Hube2

Similar (or same) issue.

  • I have Store and Promotion post types
  • Each has an ACF Relationship field (associated_store_promotion)
  • Elsewhere on the site I'm trying to run a wp_query to get Stores that have Promotions
  • Using a meta_query to see if the associated_store_promotion meta key has a value is inaccurate because if a Promotion has been deleted the meta_value for the Store still has a value until the Store is manually re-saved

Ideally when a Promotion is deleted in Admin any associated Store would be updated at the same time (or vice-versa).

Anyway I will attempt the idea of looping through Stores (and updating as necessary) when a Promotion is deleted.

davidallenlewis avatar May 25 '23 13:05 davidallenlewis

As I said above, most of the time this is not needed. It is also not something that ACF does either. If you create a relationship field without using this plugin and you delete a post that is selected in that relationship field ACF will not update the relationship field.

Like I said 2+ years ago, this would take searching every post (doing a reverse relationship query) on a specific field for the post ID during the trash/delete process and then updating the values for any posts returned.

If you think you need this then it is something that you'll need to code yourself. It's not something that I'm doing to add to this plugin.

Hube2 avatar May 26 '23 11:05 Hube2

I understand. I already wrote my own solution. Thanks for the pointers and for the amazing plugin. Maybe a filter would be nice(?) but whatever. All good. Thx again!

If anyone with the same issue comes upon this here's my solution. Perhaps this could be better / more efficient (don't know) but it works. Watches for the deletion of three different custom post types that are related to a Store. I could also watch for Store deletion (the other side of the relationship) but Promos, Jobs, and Events are short lived… Stores will always outlive them.

` add_action('trashed_post', 'update_associated_stores_after_delete', 10, 3); function update_associated_stores_after_delete( $post_id ) {

// The post types we will be acting upon when deleted
$post_types = array('event','job','promotion');

// Bail early if it's not one of the targeted post types
if( ! in_array(get_post_type( $post_id ), $post_types ) )
	return;

foreach ( $post_types as $post_type ) {
	
	// Get any Stores which had this Promotion, Job, or Event associated with it
	$args = array(
		'post_type'      => 'store',
		'posts_per_page' => -1,
		'post_status'    => 'publish',
		'meta_query'     => array(
			array(
				'key'     => 'associated_store_' . $post_type, // ACF Relationship Field Key
				'value'   => $post_id,
				'compare' => 'LIKE',
		    ),
		)
	);
	$custom_query = new WP_Query($args);
	
	// Loop through Stores and update ACF Field
	if( $custom_query->have_posts() ) : while ( $custom_query->have_posts() ) : $custom_query->the_post();
		$relationship_field = get_field( 'associated_store_' . $post_type, get_the_ID() );
		update_field('associated_store_' . $post_type, $relationship_field, get_the_ID() );
	endwhile; endif;
}

} `

davidallenlewis avatar May 26 '23 11:05 davidallenlewis