My multisite setup has one sort-of-admin site, where users can insert/edit posts and specify on which site they want ’em published. This is a contract requirement and cannot be changed.
EDIT: Check the accepted answer for a much simpler approach to this.
The basic steps in inserting content are done and properly working with the full power of switch_to_blog()
but we’re facing a little discomfort with file uploads. We’ve decided to use the WP Uploader and as such, make the admin media library a mere sandbox for the files being uploaded.
So the process goes like this:
-
Client inserts new post and images on a form.
-
WP Uploader handles uploads, crunching, and places the files temporarily on the Admin Site Media Library with custom values representing his User ID and Session ID (we still don’t have a Post ID at this time).
-
User clicks to save the post.
-
System fires
wp_insert_post()
at the correct site and gets the returned Post ID and:<?php // functions.php inside the function triggered upon post save foreach ($files as $f) { restore_current_blog(); /* * 5. System copies the files from the Admin Site Uploads Dir to the Selected Site Uploads Dir. */ $filename = get_attached_file($f); $arq = get_post($f, ARRAY_A); $filedest = str_replace('blogs.dir/22/', 'blogs.dir/' . $marca . '/', $filename); if (copy($filename, $filedest)) { switch_to_blog($marca); unset($arq['ID']); /* * 6. System fires `wp_insert_attachment()`, `wp_generate_attachment_metadata()` * and `wp_update_attachment_metadata()` associating the newly moved files to the * returned Post ID from step 4. * */ $att = wp_insert_attachment($arq, $filedest, $err); if ($att) { $attach_data = wp_generate_attachment_metadata( $att, $filedest ); wp_update_attachment_metadata( $att, $attach_data ); if ($f == $destaque) { update_post_meta($err, '_thumbnail_id', $att); } restore_current_blog(); /* * 7. System deletes the old images from the Admin Media Library aka Sandbox. */ $del = wp_delete_attachment( $f, true ); $msg = '8. User is (should be) happy his files are properly put in place and goes on with his life.'; } else { echo 'erro'; } } } ?>
After the files are copied to the right path and the attachments are properly managed, we find that although the main file is present and attached to the right post, and we are calling wp_generate_attachment_metadata
and wp_update_attachment_metadata
inside switch_to_blog()
the intermediate sizes defined on the target site are NOT being generated, and so aren’t the functions hooked to add_attachment
.
I suspect this has something to do with this actions being fired from the admin site functions.php and not being able to access the other site’s functions.
So, is there a more clever way to move this images as if they were native to the target site?
Who would say the solution would be this simple…
After days battling with this, somehow it struck me: “what if we
switch_to_blog()
inside the media upload iframe?” What if we require the user to save the post before uploading any images?Turns out I had no answer to why we weren’t doing this on the first place so, having required that the user saved the post before uploading any images, the solution came short and sweet:
1) Add
site_id
to the GET variables being passed to media-uploader:2) And retrieve it from inside the iframe, right after hooking the scripts and styles:
This simple trick allows you to upload media from any site to any other site inside a network, so long as you already have the destination’s
site_id
andpost_id
. No need to hand-copy files and re-generate metadata, lots of code straight to the garbage can, yay! 🙂Also, since we’re in an iframe and the only way to get out of it is to close the window, not calling
restore_current_blog()
doesn’t cause any adverse effects.