Skip Navigation

[Resolved] Automatically delete connections when a child is trashed

This thread is resolved. Here is a description of the problem and solution.

Problem:

The customer created a many-to-many relationship between posts and products using Toolset and WooCommerce. When a connected product is "trashed," the connection is not automatically deleted, resulting in empty product cells in the grid view. The customer wanted a way to either filter out intermediary posts with trashed children or automatically delete the connections when a product is trashed.

Solution:

We provided a custom function using the wp_trash_post hook to automatically disconnect any intermediary posts associated with a product when it is trashed. The function also initially moved the intermediary posts to the trash, but this behavior was corrected to ensure only the connections were deleted without affecting the original post status. The code was updated to handle multiple relationships and ensure the associated posts remain published even after a product is trashed.

Final code:

The function disconnects intermediary posts while ensuring that the associated posts remain published.
The customer confirmed that the final solution worked correctly after adding an additional check to maintain the post's published status:

add_action('wp_trash_post', 'delete_relationships_on_trashed_product', 101, 2);
function delete_relationships_on_trashed_product($post_id, $previous_status) {
    // Get the post object based on the post ID
    $post = get_post($post_id);
  
    // Ensure we have a valid post object and that it is of type 'product'
    if ($post && $post->post_type === 'product') {
        // Define the relationship slugs to check
        $relationship_slugs = ['post-product', 'post-product-2', 'post-product-3'];
  
        // Loop through each relationship slug and handle the disconnection
        foreach ($relationship_slugs as $relationship_slug) {
            // Get all intermediary posts related to this product for the current relationship slug
            $related_intermediary_posts = toolset_get_related_posts(
                $post_id, // ID of the post to get relationships from
                $relationship_slug, // Relationship slug
                'child', // Role of $post_id in this relationship
                -1, // Limit to get all related posts
                0, // Offset
                [], // Additional arguments
                'post_id', // Return type, we want the post IDs
                'parent' // We want to get the parent posts related to this child
            );
  
            // Loop through each intermediary post and delete the relationship
            if (!empty($related_intermediary_posts)) {
                foreach ($related_intermediary_posts as $intermediary_post_id) {
                    // Disconnect the intermediary post
                    $disconnect_result = toolset_disconnect_posts($relationship_slug, $intermediary_post_id, $post_id);
 
                    // After disconnecting, ensure the parent post remains published
                    // Get the parent post object
                    $parent_post = get_post($intermediary_post_id);
                     
                    // Check if the post status is not 'publish' and update it to 'publish'
                    if ($parent_post && $parent_post->post_status !== 'publish') {
                        wp_update_post([
                            'ID' => $parent_post->ID,
                            'post_status' => 'publish'
                        ]);
                    }
                }
            }
        }
    }
}

Relevant Documentation:
https://developer.wordpress.org/reference/hooks/wp_trash_post/
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_disconnect_posts

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
- 9:00 – 12:00 9:00 – 12:00 9:00 – 12:00 9:00 – 12:00 9:00 – 12:00 -
- 13:00 – 18:00 13:00 – 18:00 13:00 – 18:00 13:00 – 18:00 13:00 – 18:00 -

Supporter timezone: America/Sao_Paulo (GMT-03:00)

This topic contains 6 replies, has 2 voices.

Last updated by Mateus Getulio 3 months, 1 week ago.

Assisted by: Mateus Getulio.

Author
Posts
#2739961

Hi, I've Toolset and WooCommerce installed. I've created the many-to-many relatioship Posts-Products.

I've built a view that loops intermediary posts, ordered by the custom field related-order. The view output displays the children products in the Post template.

When some of the connected product is "trashed", the connection is not deleted, so in my loop I get intermediary posts but empty product cells in my grid.

Is there a way to filter the intermediary posts with trashed children? Or, is it possible to automatically delete connections when a product is trashed?

thanks

#2740288

Mateus Getulio
Supporter

Languages: English (English )

Timezone: America/Sao_Paulo (GMT-03:00)

Hi,

Thank you for contacting us and I'd be happy to assist.

When you trash a post/product, are you doing it on the front end using a form or in the back end?

Also, to suggest the best way to achieve this, I'll need to see how this view is set up in the admin area.

Can you please share temporary admin login details along with a link to a page where this view can be seen?

Note: Your next reply will be private and please make a complete backup copy, before sharing the access details.

regards,
Mateus

#2741122

Mateus Getulio
Supporter

Languages: English (English )

Timezone: America/Sao_Paulo (GMT-03:00)

Hi Umberto,

Thank you for providing the details.

To address your requirement, I've created a function that will automatically disconnect any intermediary posts associated with a product when it is trashed. Additionally, it will also move the intermediary posts to the trash if needed.

Solution
Please add the following code snippet to your theme's functions.php file:

add_action('wp_trash_post', 'delete_relationship_on_trashed_product', 101, 2);
function delete_relationship_on_trashed_product($post_id, $previous_status) {
    // Get the post object based on the post ID
    $post = get_post($post_id);

    // Ensure we have a valid post object and that it is of type 'product'
    if ($post && $post->post_type === 'product') {
        // Get all intermediary posts related to this product
        $related_intermediary_posts = toolset_get_related_posts(
            $post_id, // ID of the post to get relationships from
            'post-product', // Relationship slug
            'child', // Role of $post_id in this relationship
            -1, // Limit to get all related posts
            0, // Offset
            [], // Additional arguments
            'post_id', // Return type, we want the post IDs
            'parent' // We want to get the parent posts related to this child
        );

        // Loop through each intermediary post and delete the relationship
        if (!empty($related_intermediary_posts)) {
            foreach ($related_intermediary_posts as $intermediary_post_id) {
                // Disconnect the intermediary post
                $disconnect_result = toolset_disconnect_posts('post-product', $intermediary_post_id, $post_id);

                // If the disconnection is successful, move the intermediary post to the trash
                if ($disconnect_result) {
                    wp_trash_post($intermediary_post_id);
                }
            }
        }
    }
}

This function will automatically disconnect any related intermediary posts when a product is trashed. After disconnection, the intermediary post will also be moved to the trash.

I used the WordPress hook wp_trash_post to target the trash acrion and the API call toolset_disconnect_posts to perform the 'unlink':
https://developer.wordpress.org/reference/hooks/wp_trash_post/
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_disconnect_posts

It is targeting the relationship between posts and products with the slug: 'post-product'.

Can you please review it and confirm it is working as expected?

#2741516

Hi Mateus, thanks for the hook. There is a problem. When I trash a connected product, the custom code trashes also the Post, not only the intermediary connections. The result is that Th eproduct and also the connected post are moved to trash.

I've restored the Test Post and Test Procuct, and I also connected them again so you can test it.

There are also post-product-2 and post-product-3 Relationships. I would like the same hook delete the intermediary posts of these connections too.

cheers

#2742348

Mateus Getulio
Supporter

Languages: English (English )

Timezone: America/Sao_Paulo (GMT-03:00)

Hi Umberto,

Thank you for the update and additional information.

I've adjusted the code to ensure that only the intermediary posts are trashed and not the original post. Additionally, the code now handles multiple relationships, including post-product, post-product-2, and post-product-3.

Please check the updated code below:

add_action('wp_trash_post', 'delete_relationships_on_trashed_product', 101, 2);
function delete_relationships_on_trashed_product($post_id, $previous_status) {
    // Get the post object based on the post ID
    $post = get_post($post_id);

    // Ensure we have a valid post object and that it is of type 'product'
    if ($post && $post->post_type === 'product') {
        // Define the relationship slugs to check
        $relationship_slugs = ['post-product', 'post-product-2', 'post-product-3'];

        // Loop through each relationship slug and handle the disconnection and trashing
        foreach ($relationship_slugs as $relationship_slug) {
            // Get all intermediary posts related to this product for the current relationship slug
            $related_intermediary_posts = toolset_get_related_posts(
                $post_id, // ID of the post to get relationships from
                $relationship_slug, // Relationship slug
                'child', // Role of $post_id in this relationship
                -1, // Limit to get all related posts
                0, // Offset
                [], // Additional arguments
                'post_id', // Return type, we want the post IDs
                'parent' // We want to get the parent posts related to this child
            );

            // Loop through each intermediary post and delete the relationship
            if (!empty($related_intermediary_posts)) {
                foreach ($related_intermediary_posts as $intermediary_post_id) {
                    // Disconnect the intermediary post
                    $disconnect_result = toolset_disconnect_posts($relationship_slug, $intermediary_post_id, $post_id);

                    // If the disconnection is successful, move the intermediary post to the trash
                    if ($disconnect_result) {
                        wp_trash_post($intermediary_post_id);
                    }
                }
            }
        }
    }
}

This code should work as expected to handle multiple relationships and avoid moving the original post to the trash, only the intermediary ones.

The issue is that while I was putting the code in place in the staging site, something broke, likely an extra '}' or something similar when I pasted it.

I'm afraid I don't have FTP access to revert it, can you please test the code above to make sure it is working as expected?

If you have issues with getting the staging site back to work, I'm enabling private fields for you to share the FTP credentials with me so I can fix it and implement the new code.

Thank you for your understanding and I apologize for the inconvenience.

#2743478

Hi Mateus, the problem was that I've moved your custom code to Toolset>Settings>Custom Code>custom2.php

You can work there, now I removed the code from functions.php

I tested the new code and it still trashes the Post on Product trashing. Please check it again.

cheers

#2743851

Mateus Getulio
Supporter

Languages: English (English )

Timezone: America/Sao_Paulo (GMT-03:00)

Hello Umberto, thank you for restoring it.

I removed this part from the code:

if ($disconnect_result) {
  wp_trash_post($intermediary_post_id);
}

Now the code is no longer trashing the post.

I sent the 'test product' to trash and checked that the 'test post' remain in there but there was no connection with the test product any longer.

I believe this is the behavior you need, right?

Can you please test it and confirm it is working as expected now?

Best,

#2744224

Hi Mateus, with your final code the Post is not trashed but it is set to Draft.

I've added this to the code to ensure that even after the product is trashed, the associated post remains published:

// After disconnecting, ensure the parent post remains published
// Get the parent post object
$parent_post = get_post($intermediary_post_id);

// Check if the post status is not 'publish' and update it to 'publish'
if ($parent_post && $parent_post->post_status !== 'publish') {
wp_update_post([
'ID' => $parent_post->ID,
'post_status' => 'publish'
]);
}

Now it works fine.

This is the complete code:

add_action('wp_trash_post', 'delete_relationships_on_trashed_product', 101, 2);
function delete_relationships_on_trashed_product($post_id, $previous_status) {
    // Get the post object based on the post ID
    $post = get_post($post_id);
 
    // Ensure we have a valid post object and that it is of type 'product'
    if ($post && $post->post_type === 'product') {
        // Define the relationship slugs to check
        $relationship_slugs = ['post-product', 'post-product-2', 'post-product-3'];
 
        // Loop through each relationship slug and handle the disconnection
        foreach ($relationship_slugs as $relationship_slug) {
            // Get all intermediary posts related to this product for the current relationship slug
            $related_intermediary_posts = toolset_get_related_posts(
                $post_id, // ID of the post to get relationships from
                $relationship_slug, // Relationship slug
                'child', // Role of $post_id in this relationship
                -1, // Limit to get all related posts
                0, // Offset
                [], // Additional arguments
                'post_id', // Return type, we want the post IDs
                'parent' // We want to get the parent posts related to this child
            );
 
            // Loop through each intermediary post and delete the relationship
            if (!empty($related_intermediary_posts)) {
                foreach ($related_intermediary_posts as $intermediary_post_id) {
                    // Disconnect the intermediary post
                    $disconnect_result = toolset_disconnect_posts($relationship_slug, $intermediary_post_id, $post_id);

                    // After disconnecting, ensure the parent post remains published
                    // Get the parent post object
                    $parent_post = get_post($intermediary_post_id);
                    
                    // Check if the post status is not 'publish' and update it to 'publish'
                    if ($parent_post && $parent_post->post_status !== 'publish') {
                        wp_update_post([
                            'ID' => $parent_post->ID,
                            'post_status' => 'publish'
                        ]);
                    }
                }
            }
        }
    }
}

cheers