WordPress Multi-Site: Get Featured Image from Another Blog

Yesterday, David Bisset posted a tweet asking the following question:

Is there a function similar to get_the_post_thumbnail for multi-site (to grab a featured image from a post of a particular blog id)?

At the time, it seemed that the best way to do so was to use the Sitewide Tags plugin for WordPress, which, I believe, does offer some functionality similar to this (I haven’t used the plugin, yet, so I can’t say for sure).

However, I took the liberty of using some code I posted here on HTMLCenter a few weeks ago as a starting point, then writing up some functions to pull featured images from other blogs in the network. The functions below are similar to the get_the_post_thumbnail(), the_post_thumbnail() and has_post_thumbnail() functions found in the WordPress core, except that they each take one additional parameter: the ID of the blog from which you want to pull the thumbnail.

The code below has only been minimally tested, so there may be issues or bugs in it. If you find any issues or bugs, please let me know.

Note: Please ignore the code immediately below. An update has been added to the bottom of this post.

if( !function_exists( 'get_the_post_thumbnail_by_blog' ) ) {
	function get_the_post_thumbnail_by_blog($blog_id=NULL,$post_id=NULL,$size='post-thumbnail',$attrs=NULL) {
		global $current_blog;
		$sameblog = false;

		if( empty( $blog_id ) ) {
			$blog_id = $current_blog->ID;
			$sameblog = true;
		}
		if( empty( $post_id ) ) {
			global $post;
			$post_id = $post->ID;
		}
		if( $sameblog )
			return get_the_post_thumbnail( $post_id, $size, $attrs );

		if( !has_post_thumbnail_by_blog($blog_id,$post_id) )
			return false;

		global $wpdb;
		$wpdbobj = clone $wpdb;
		$wpdb->flush();
		$wpdb->blogid = $blog_id;
		$wpdb->set_prefix( $wpdb->base_prefix );

		$blogdetails = get_blog_details( $blog_id );
		return str_replace( $current_blog->domain . $current_blog->path, $blogdetails->domain . $blogdetails->path, get_the_post_thumbnail( $post_id, $size, $attrs ) );

	}

	function has_post_thumbnail_by_blog($blog_id=NULL,$post_id=NULL) {
		if( empty( $blog_id ) ) {
			global $current_blog;
			$blog_id = $current_blog;
		}
		if( empty( $post_id ) ) {
			global $post;
			$post_id = $post->ID;
		}

		global $wpdb;
		$wpdbobj = clone $wpdb;
		$wpdb->flush();
		$wpdb->blogid = $blog_id;
		$wpdb->set_prefix( $wpdb->base_prefix );

		$thumbid = get_post_meta( $post_id, '_thumbnail_id', true );
		$wpdb = clone $wpdbobj;
		return ($thumbid !== false) ? true : false;
	}

	function the_post_thumbnail_by_blog($blog_id=NULL,$post_id=NULL,$size='post-thumbnail',$attrs=NULL) {
		echo get_the_post_thumbnail_by_blog($blog_id,$post_id,$size,$attrs);
	}
}

Update

After speaking with Andrea_R on Twitter about this, I found that there is a much better way to perform these actions. She first recommended simply querying the database directly. That’s still entirely possible (especially if we find that the code below doesn’t scale very well for some reason), but the main reason I am using the native get_post_thumbnail() function rather than rewriting the <img> code for the thumbnail within my function is that it will (hopefully) be somewhat future-proof. If the WordPress devs decide to update or change the HTML code that the get_post_thumbnail() function outputs, the functions below will be automatically updated by proxy.

Regardless, she pointed out a method of the WPDB class of which I was previously unaware. The method is called get_blog_prefix, and, while my code below doesn’t call that function itself, it did turn me onto the “set_blog_id” method within the WPDB class.

Therefore, rather than having to clone the WPDB object, make changes to it, then restore it, the modified code simply calls the set_blog_id() method to make the necessary changes. Hopefully this code will scale, but I’ll really only know that once we do some major testing with it.

As I mentioned above, if you have any further suggestions for improvement or optimization, please feel free to share them.

if( !function_exists( 'get_the_post_thumbnail_by_blog' ) ) {
	function get_the_post_thumbnail_by_blog($blog_id=NULL,$post_id=NULL,$size='post-thumbnail',$attrs=NULL) {
		global $current_blog;
		$sameblog = false;

		if( empty( $blog_id ) || $blog_id == $current_blog->ID ) {
			$blog_id = $current_blog->ID;
			$sameblog = true;
		}
		if( empty( $post_id ) ) {
			global $post;
			$post_id = $post->ID;
		}
		if( $sameblog )
			return get_the_post_thumbnail( $post_id, $size, $attrs );

		if( !has_post_thumbnail_by_blog($blog_id,$post_id) )
			return false;

		global $wpdb;
		$oldblog = $wpdb->set_blog_id( $blog_id );

		$blogdetails = get_blog_details( $blog_id );
		$thumbcode = str_replace( $current_blog->domain . $current_blog->path, $blogdetails->domain . $blogdetails->path, get_the_post_thumbnail( $post_id, $size, $attrs ) );

		$wpdb->set_blog_id( $oldblog );
		return $thumbcode;
	}

	function has_post_thumbnail_by_blog($blog_id=NULL,$post_id=NULL) {
		if( empty( $blog_id ) ) {
			global $current_blog;
			$blog_id = $current_blog;
		}
		if( empty( $post_id ) ) {
			global $post;
			$post_id = $post->ID;
		}

		global $wpdb;
		$oldblog = $wpdb->set_blog_id( $blog_id );

		$thumbid = has_post_thumbnail( $post_id );
		$wpdb->set_blog_id( $oldblog );
		return ($thumbid !== false) ? true : false;
	}

	function the_post_thumbnail_by_blog($blog_id=NULL,$post_id=NULL,$size='post-thumbnail',$attrs=NULL) {
		echo get_the_post_thumbnail_by_blog($blog_id,$post_id,$size,$attrs);
	}
}

Also, I thought it might be a good idea to mention; if you decide to try querying the database directly rather than using the native WordPress functions for retrieving a thumbnail, the place you’ll want to start is within the postmeta table, and the meta key for the item is _thumbnail_id. Once you retrieve that _thumbnail_id from the database, you should be able to retrieve the necessary information about that thumbnail from the posts and postmeta tables in the database.

13 Responses

  • dains

    Hi, I’m trying this code out on a multiblog installation with 4 test blogs, but I’m getting this error right off:

    Undefined property: stdClass::$ID on line 15

    and no output is shown.
    That’s the
    $blog_id = $current_blog->ID;
    line, so I echoed the variables out and found that they’re both empty, while $sameblog echoed 1, so the if statement is being processed.

    Can you help troubleshoot this, or give me some more information on what we’re trying to do with this line?

  • That line is supposed to set the function’s $blog_id var in case it’s sent to the function as an empty value.

    Try replacing $current_blog->ID with $current_blog->blog_id wherever it occurs in the code.

    Also, the line in the has_post_thumbnail_by_blog() function that currently looks like $blog_id = $current_blog; should probably say $blog_id = $current_blog->blog_id; instead.

  • Hello Curtiss thanks for posting this, your function allowed me to easily add the thumbnails’ functionality to my plugin called “Network Latest Posts”. However someone found a bug in my code and was related to your thumbnail functions, as you can see your code changes the blog ID using the $wpdb->set_blog_id each time you want to grab the thumbnail for a post inside a different blog ID and then you try to restore the current’s blog ID using $wpdb->set_blog_id which shamefully fails to restore the original ID.

    I solved this problem replacing the $oldblog = $wpdb->set_blog_id($blog_id) by switch_to_blog($blog_id) and $wpdb->set_blog_id($oldblog) by restore_current_blog() in both functions get_the_post_thumbnail_by_blog & has_post_thumbnail_by_blog, just letting you know.

    Cheers.

  • Nick

    Can you help me understand how can I use your function?

    I added the code in functions.php of my child theme and in the template-blog.php replaced the the_post_thumbnail with the_post_thumbnail_by_blog.

    How and where do I add the blog_id?

    Here is my template-blog.php: http://pastebin.com/uDvcKTyj

    Thank you
    Nick

  • Mpa4Hu

    http://pastebin.com/aJnpBLxV
    I have this code which confusies me,

    $wpdb->set_blog_id( $oldblog );

    How does this return $wpdb to default blog? I just don’t see it
    In my opinion it sets it to blog_ID alerted (in this case ‘2’)

  • Catherine

    So this is interesting: if I’m logged in, this works fine. If I’m logged out, the first time–and only the first time–I call either get_the_post_thumbnail_by_blog() or the_post_thumbnail_by_blog(), it silently fails. No image appears. If I’m logged in, it works fine, and if I’m logged out, only the second image onwards appears. Is this a problem with set_blog_id as mentioned above?

  • Qutek

    Thanks Mpa4Hu,
    your explanation, works well..

  • sebastian_pi

    I have one more fix for you code, which is great by the way. There are situation when you’re not in blog context, like when i use Global Search plugin. Code fires notice that $current_blog->ID is not initiated. So I had modified line:

    if( empty( $blog_id ) || $blog_id == $current_blog->ID) {

    into

    if( isset($current_blog->ID) && (empty( $blog_id ) || $blog_id == $current_blog->ID)) {

    • Please where I can edit this code?

  • sebastian_pi

    Also I had to replace this line:

    $thumbcode = str_replace( $current_blog->domain . $current_blog->path, $blogdetails->domain . $blogdetails->path, get_the_post_thumbnail( $post_id, $size, $attrs ) );

    Into this:

    $wpdb->set_blog_id( $blog_id );
    $thumbcode = str_replace(
    $current_blog->domain . $current_blog->path . “wp-content/uploads”,
    $blogdetails->domain . $blogdetails->path . “wp-content/uploads/sites/” . $blog_id,
    get_the_post_thumbnail( $post_id, $size, $attrs )
    );

    It looks like get_blog_details(); bring back old blogid into $wpdb.

  • Лосяра

    function multisite_thumb_url($pid, $bid){
    if(isset($pid) && $pid>0){
    if(isset($bid) && $bid>0){
    global $wpdb;
    $curr_blog_id=get_current_blog_id();
    $wpdb->set_blog_id( $bid );
    $post_thumbnail_id = $wpdb->get_var( “SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = ‘_thumbnail_id’ AND post_id = {$pid}” );
    $post_thumbnail_metadata = $post_thumbnail_id ? maybe_unserialize( $wpdb->get_var( “SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = ‘_wp_attachment_metadata’ AND post_id = {$post_thumbnail_id}” ) ) : NULL;
    if ( ! $post_thumbnail_metadata ){
    return false;
    }else{
    if($bid==1){
    $default_post_thumbnail_url = get_blog_option( $bid, ‘siteurl’ ).’/wp-content/uploads/’.$post_thumbnail_metadata[ ‘file’ ];
    }else{
    $default_post_thumbnail_url = get_blog_option( $bid, ‘siteurl’ ).’/wp-content/uploads/sites/’.$bid.’/’.$post_thumbnail_metadata[ ‘file’ ];
    }
    return $default_post_thumbnail_url;
    }
    $wpdb->set_blog_id( $curr_blog_id );
    }else{
    return wp_get_attachment_url( get_post_thumbnail_id($pid) );
    }
    }else{
    return wp_get_attachment_url( get_post_thumbnail_id() );
    }
    }

    BEST VARIANT

    Get post thumbnail url with multisite http://regid.biz/kak-poluchit-adres-kartinki-s-uchetom-multisajta-v-wordpress/

  • Igor Benić

    I have developed a plugin for something similar. It could be used to share the same featured image across sites if used with Network Shared Media. Ty for this functions that could be used in custom solutions.

    My plugin url is: https://wordpress.org/plugins/multisite-featured-image/