| [ Web Proxy ] |
| Viewing: https://rudrastyh.com/wordpress-multisite/move-posts-between-blogs.html | [Back] [Original] |
Let me show you an easy way to duplicate WordPress pages between any of your sites within a multisite network.
Or to be more specific, I am about to show you two ways how you can do that:
Either way, by the end of this tutorial, we will have brand-new bulk actions on the “All Pages” admin page. However, each page can also be copied individually to a specific sub-site in case you decide to go for the plugin approach.
[Copy Pages between Sites within WordPress Multisite network]As you can see, in this screenshot, it says “Move to…” instead of “Copy to…”. You can choose what suits you best, but if you want to move a page to another multisite site and remove the original one, it can be achieved with just one extra line of code.
By the way, if you’re not using a WordPress Multisite network, check out this article.
Let’s start with the programmatic approach. For your convenience, I decided to split this chapter into three parts.
In this part, we’re just going to create bulk actions for every site in a multisite network. To achieve that, I am going to use the get_sites() WordPress function. By the way, don’t forget to check out my other in-depth tutorial about bulk actions in WordPress.
// add bulk actions
add_filter( 'bulk_actions-edit-page', 'rudr_my_bulk_multisite_actions' );
function rudr_my_bulk_multisite_actions( $bulk_array ) {
$sites = get_sites(
array(
// 'site__in' => array( 1, 2, 3 )
'site__not_in' => get_current_blog_id(), // exclude the current blog
'number' => 50,
)
);
if( $sites ) {
foreach( $sites as $site ) {
$bulk_array[ "move_to_{$site->blog_id}" ] = "Move to {$site->blogname}";
}
}
return $bulk_array;
}What is actually important to keep in mind here:
add_filter( 'bulk_actions-edit-{POST TYPE}' ...site__not_in parameter. We don’t want to duplicate pages on the same subsite here, right?get_sites() function. The thing is that WordPress Multisite networks support an unlimited number of sites, so if you have 1000+ sites in your Network, youd better think about another implementation of this step. I can give you two hints, though maybe you do not even need all the sites. In that case, the site_in parameter will help you, or, if you need all of them, you could try to replace the default bulk action element with Select2 with AJAX search.In this part, we’re going to make our brand-new bulk action to do the thing. I mean, actually, to copy pages between sites in our multisite network.
For your convenience, I decided to create a separate PHP function rudr_copy_page_to_site():
/**
* WordPress Multisite: Copy or Move Pages between Sites
*
* @author Misha Rudrastyh
* @link https://rudrastyh.com/wordpress-multisite/copy-pages-between-sites.html
*/
function rudr_copy_page_to_site( $post_id, $blog_id ) {
// first of all we need to get some page information from the current site
// get the original WP_Post object as an array
$post = get_post( $post_id, ARRAY_A );
if( ! $post ) {
return;
}
// get all the page meta
$post_meta = get_post_custom( $post_id );
// empty ID field, to tell WordPress to create a new post, not update an existing one
$post[ 'ID' ] = '';
// once we collected all the page information, we are ready to switch to another blog and create a page copy there
switch_to_blog( $blog_id );
// insert the page
$inserted_post_id = wp_insert_post( $post ); // insert the post
// add page meta
foreach( $post_meta as $key => $values) {
// if you do not want weird redirects
if( '_wp_old_slug' === $key ) {
continue;
}
foreach( $values as $value ) {
add_post_meta( $inserted_post_id, $key, $value );
}
}
restore_current_blog();
// if you want just to copy pages, comment this line
wp_delete_post( $post_id );
}In this function:
get_page_by_path() function for that purpose, for example._wp_old_slug meta key when copying page custom fields, but consider that there could be more system custom fields worth excluding, for example _edit_lock.Also, we need to connect this PHP function to a bulk action trigger.
add_filter( 'handle_bulk_actions-edit-page', 'rudr_bulk_action_multisite_handler', 10, 3 );
function rudr_bulk_action_multisite_handler( $redirect, $doaction, $object_ids ) {
// we need query args to display correct admin notices
$redirect = remove_query_arg( array( 'misha_posts_moved', 'misha_blogid' ), $redirect );
// our actions begin with "move_to_", so let's check if it is a target action
if( strpos( $doaction, 'move_to_' ) === 0 ) {
$blog_id = str_replace( 'move_to_', '', $doaction ); // get blog ID from action name
foreach ( $object_ids as $post_id ) {
// that's our custom function
rudr_copy_page_to_site( $post_id, $blog_id );
}
$redirect = add_query_arg( array(
'misha_posts_moved' => count( $object_ids ),
'misha_blogid' => $blog_id
), $redirect );
}
return $redirect;
}Last but not least, once pages are copied between sites, an appropriate admin notice should be displayed. We can do it with the admin_notices action hook. There is also another one, which is network_admin_notice, but we don’t need it because it is actually intended for network admin pages like “Sites”, “Users”, etc.
// show an appropriate notice
add_action( 'admin_notices', 'rudr_bulk_multisite_notices' );
function rudr_bulk_multisite_notices() {
if( ! empty( $_REQUEST[ 'misha_posts_moved' ] ) ) {
// because I want to add blog names to notices
$blog = get_blog_details( $_REQUEST[ 'misha_blogid' ] );
// depending on ho much posts were changed, make the message different
echo '<div class="updated notice is-dismissible"><p>';
printf(
_n(
'%d post has been moved to "%s".',
'%d posts have been moved to "%s".',
$_REQUEST[ 'misha_posts_moved' ]
),
$_REQUEST[ 'misha_posts_moved' ],
$blog->blogname
);
echo '</p></div>';
}
}In this part, we’ll talk about my Simple Multisite Crossposting plugin.
Let’s say you tried to use the code mentioned above, but what if:
Well, that’s when my plugin comes in It allows you to implement everything mentioned above and much more, actually.
You can still use bulk actions:
[WordPress Multisite: Copy pages between sites using bulk actions]
Or you can select specific sites directly when editing a page in a classic or block editor:
[WordPress Multisite - copying pages between sites using the block editor]You can select specific subsites with checkboxes.
If you have any questions, guys, either about the plugin or about the code, please let me know in the comments section below.
Hey guys and welcome to my website. For more than 15 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
| Web Proxy Viewer | New URL | Original Page |
Hi Misha, excellent work, thank you so much for sharing!
Hi Jakub,
Always welcome!
Hi Misha again,
could you help me include a post thumbnail, please? I added a snippet
$thumbnail = get_post_thumbnail_id($post_id);and then
set_post_thumbnail($inserted_post_id, $thumbnail);but the thumbnail wouldn’t copy.
thanks in advance!
The thing is here is that when you’re using
set_post_thumbnail()you need to provide an attachment ID which exists on that specific website.So, you need to either copy an attachment there manually, or, for example, use a network media library plugin.
Hi, well done, thanks for sharing.
Just a question, i only need to show on the “main blog” a preview of the posts written on the “satellite blogs”, something like title, excerpt, thumb and href to the original post; i don’t need to get all the post.
It’s possible?
Thanks
Enrico
Hello,
This method only moves the post to the other site.
How to copy/duplicate a post?
Thank you.
Hello Selvi,
Just remove/comment line 39 in the code
Hello,
When copying a post, all custom fields are also copied. Is it possible to ignore e.g. fields such as “music_post”, “video_post” (this is meta key)?
Hello Arthur,
Just add more conditions:
Hi Misha,
Thanks for the wonderful code! Is it possible to configure it to work for pages as well as posts?
Anthony
Hi Anthony,
Yes, it is possible. I decided to update my code for Pages.
How to include its featured image?
You might check this tutorial for the ready code for copying attachments. Once you do that, you can use a new attachment ID as
_thumbnail_idkey of the post.Or as an option you can use my plugin that covers this by default.
Hi Misha,
Great work.
I have a question:
Is it possible to ignore comments once the post has been duplicated?
Please let me know
Thanks
Hi Tommaso,
The comments should be ignored by default. By I think you’re talking about comment count, in this case just add the line
$post[ 'comment_count' ] = 0;This was a great script – thanks for sharing. However – it totally broke all my pages that was created in Elementor. But for everything else it was awesome.
For Elementor we need to additionally regenerate its CSS files created for this page. Plus, there are custom fields like
_elementor_datawhich may require some replacements during the copying process.Hey, this script is exactly the sort of thing I was looking for and seems to work well. I was wondering how it could be edited to add to all blogs except the current one, rather than adding to one blog each time.
Thanks!
Hey, amazing!
Easy enough
get_sites()andforeach()(I have added it to the code).