[+] Include related posts and repeatable field groups when duplicating posts using Yoast Duplicate Post plugin

Use the following code with care, it makes direct queries of the relationship tables because of some omissions in the official API.

If cloning a post which has RFGs or child posts in a one-to-many relationship, the child posts/RFGs will be duplicated and then assigned to the newly cloned parent post. If a child post is cloned, the newly cloned post will be assigned to the same existing parent. No action is taken with many-to-many relationships as everyone’s requirements may differ.

/**
 * Handle related posts (incl. RFGs) when duplicating post with Yoast Duplicate Post plugin
 * 
 * @param int $new_post_id The newly created post's ID.
 * @param WP_Post $post The original post's object.
 *
 * CASES
 * 
 * 1. When cloning a post with RFGs, duplicate the RFGs and assign to the cloned post
 * 2. When cloning a parent post, duplicate the child posts and assign to the cloned post
 * 3. When cloning a child post, assign to the same parent as the original post
 * 4. No action with M2M relationships, no clear use case
 */
add_action( 'dp_duplicate_post', 'ts_clone_posts', 10, 3 );
function ts_clone_posts( $new_post_id, $post, $status ) {

    /**
     * First, what relationships—if any—is the cloned post type involved in?
     * (No API function available, query DB directly)
     */
    global $wpdb;

    $query = $wpdb->prepare(
        "
        SELECT set_id 
        FROM {$wpdb->prefix}toolset_type_sets
        WHERE type LIKE '%s'
        ",
        $post->post_type
    );

    $set_ids_array = $wpdb->get_results(
        $query,
        ARRAY_A
    );

    // If not part of any relationships then quit
    if ( !( isset( $set_ids_array ) && is_array( $set_ids_array ) ) )
        return;

    /**
     * CASES 1 and 2 
     * Where the cloned post is a parent (O2M) or has RFGs
     * Can't just use toolset_get_related_post_types because it doesn't include RFGs, so direct query again
     */

    $set_ids = array_column( $set_ids_array, 'set_id' );
    $set_ids_list = implode(",", $set_ids);

    $relationships = $wpdb->get_results(
        "
        SELECT slug
        FROM {$wpdb->prefix}toolset_relationships
        WHERE parent_types IN ({$set_ids_list})
        ",
        ARRAY_A
    );

    if ( isset( $relationships ) && is_array( $relationships ) )
    {

        $relationship_slugs = array_column( $relationships, 'slug' );
        // This is an array of the relationships where $post->post_type is a parent
    
        foreach ($relationship_slugs as $relationship_slug) 
        {
            $relationship_definition = toolset_get_relationship( $relationship_slug );
    
            $child_type = $relationship_definition['roles']['child']['types'][0];
    
            // Ignore is this is a 'parent' in a M2M relationship
            if ( isset( $relationship_definition ) && is_array( $relationship_definition ) && $relationship_definition['cardinality']['type'] != 'many-to-many' )
            {
                $children = toolset_get_related_posts( $post, $relationship_slug, array(
                    'query_by_role'     => 'parent',
                    'role_to_return'    => 'child',
                    'return'            => 'post_object'
                    ) 
                );
            
                // Update on the fly duplicate post plugin option for allowed post types to be sure we can duplicate the children
                add_filter( 'option_duplicate_post_types_enabled', static function( $values ) use ( $child_type ){
                    if ( is_array( $values ) ){
                        $values[] = $child_type;
                    }    
                    return $values;
                } );
        
                // Unhook our code first to avoid recursion (optional)
                remove_action( 'dp_duplicate_post', 'ts_clone_posts' );
                // Duplicate the child posts (using the Yoast Duplicate Plugin API)
                foreach ($children as $key => $child) 
                {
                    $new_child_id = duplicate_post_create_duplicate( $child );
                    if ( isset( $new_child_id ) )
                    {
                        toolset_connect_posts( $relationship_slug, $new_post_id, $new_child_id );
                    }
                }
                // add back our hook callback
                add_action( 'dp_duplicate_post', 'ts_clone_posts', 10, 3 );
            }
        }

    }

    /**
     * CASE 3: Where the cloned post is a child post
     */
    $parent_types = toolset_get_related_post_types( 'parent', $post->post_type );

    if ( isset( $parent_types ) && is_array( $parent_types ) ){
        foreach ($parent_types as $parent_type => $relationship) {
            // But are these relationships O2M relationships?
            $relationship_definition = toolset_get_relationship( $relationship[0] );
            if ( isset( $relationship_definition ) && is_array( $relationship_definition ) && $relationship_definition['cardinality']['type'] == 'one-to-many' )
            {
                // In this relationship this post type is a child, and can have only one parent
                $parent_id = toolset_get_related_post( $post, $relationship[0], 'parent' );
                if ( isset( $parent_id ) && $parent_id != 0 ){
                    // Update the cloned post with the same parent
                    toolset_connect_posts( $relationship[0], $parent_id, $new_post_id );
                }
            }
        }
    }
}

Let us know if this snippet is not working for you:

This snippet doesn’t work
0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments