I have a multisite network of sites which should display blog content from each other if the blog post has a tag with the site name.

To gather all posts within the network I use the SWT (Sitewide Tags) plugin as it seems most efficient. I store all posts in the main site (blog id 1) and from my other sites I want to query the main sites posts table for posts containing a tag with the querying site's domain name.

I have working code in a page template (home.php) - see below - but I understand the action pre_get_posts are the way to go, but I can't seem to figure out how to change the table to query. Should I perhaps do a JOIN in the action posts_join?

If my solution seems to be way more complicated than it should be, feel free to bash me with other suggestions :)

This is my current template code:

$tags = array(
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$wp_query = new WP_Query(array(
    'post_status' => 'publish',
    'paged' => $paged,
    'orderby' => 'date',
    'order' => 'desc',
    'tag' => implode(",", $tags)

while (have_posts()) : the_post();

How can I rewrite this in pre_get_posts?

Note; as you see the tag I'm searching for is static at the moment, this will change to match the domain name + ccTLD of the querying site or something similar later on.

Note 2; I'd rather not use switch_to_blog() since I read it's expensive but haven't found a best practice for querying other blogs inside a network. Should I set the table name to query manually instead?

I have read most posts both here, in blogs and in the Codex (WP_Query, pre_get_posts etc.) touching multisite querying but almost all talks of using switch_to_blog and restore_current_blog.

  • This might be helpful: wordpress.stackexchange.com/questions/70129/… Oct 28, 2013 at 12:06
  • @ialocin thanks I have already checked out that post and he seems to be a bit off, he allocated a $test_obj but never uses it and pre_get_posts doesn't return anything, it gets $query by reference and from what I can see he never attaches $test_obj to $query->something. Also, he's using switch_to_blog which I'd rather avoid if possible :). Oct 28, 2013 at 12:26
  • Did you ever get this working? I'm coming up against exactly the same situation now
    – josh
    Mar 7, 2014 at 12:14
  • 1
    @josh no, after checking the source code I found no way to do this with the action pre_get_posts so I resorted to switch_to_blog() and restore_current_blog(). Note: I found advice saying I should skip restore_current_blog() but analyzing the code for those two functions I could see that it builds up a huge array taking up lots of memory if I do not "pop" each switch_to_blog() with a restore_current_blog(). Mar 7, 2014 at 16:17
  • 1
    @JohanNordström You've saved me some time investigating the same there. I'll do something similar and fallback on switch_to_blog with some cacheing to avoid too many queries. Thanks for getting back with that so swiftly!
    – josh
    Mar 10, 2014 at 16:51

3 Answers 3


OK so for reference I ended up actually using switch_to_blog() and restore_current_blog(). I found no references whatever for querying multiple tables (except writing my own JOIN-statements) when followed the source code for the action pre_get_posts.

A lot of advice was given to skip restore_current_blog() to save CPU-cycles but when I checked the source code for this I saw that it would cause a huge memory problem since the main thing restore_current_blog() does is to pop the latest inserted object in a global array and this array would grow hugely with each switch_to_blog() that one does not do a restore_current_blog() on.

Please feel free to check the source code and also see @user42826's answer regarding this at https://wordpress.stackexchange.com/a/123516/14820.

For those who are interested, I ended up with transients both for the site-list and for the result to save both CPU-cycles and DB performance. I only needed data to be updated if it were stale (15 minutes or more of age). Only relevant bit of function included below:

$site_transient = get_site_transient( 'multisite_site_list');
if ($site_transient == false || LL_USE_TRANSIENTS == false) {
    $using_site_transient = false;

    // no cache available
    global $wpdb;

    // TODO: get prefix for wp tables
    $site_list = $wpdb->get_results($wpdb->prepare('SELECT * FROM nw_blogs WHERE public = %d AND deleted = %d ORDER BY blog_id', 1, 0));

    // set transient
    set_site_transient('multisite_site_list', $site_list, LL_TRANSIENT_EXPIRES);

} else {
    //log_msg("SITELIST - Transient found, using cached query..");
    $site_list = $site_transient;
    $using_site_transient = true;

//log_msg("$id - get_posts_from_network | tags: " . implode(",", $tags) . " | tag_slug__and: $lang_full");

$start = microtime(true);

// get blogpost transient, if existing
$post_transient = get_site_transient( 'limelight_recent_posts_' . $hash);

// if not, do query and save result as a transient
if ($post_transient == false || LL_USE_TRANSIENTS == false) {
    $using_post_transient = false;
    $blogposts = array();

    foreach ($site_list as $site) {
        $posts = get_posts(array(
            'post_status' => 'publish',
            'orderby' => 'date',
            'order' => 'desc',
            'tag' => implode(",", $tags),
            'tag_slug__and' => array($lang_full)

        //log_msg("$id - get_posts_form_network | at site: $site->blog_id");

        foreach ($posts as $post) {

            //log_msg("$id - get_posts_form_network | at site: $site->blog_id | got post!");

            $post->human_post_date = human_time_diff(get_post_time('U', false, $post->ID), current_time('timestamp')) . ' ' . __('ago', 'limelight');

            if (isset($tagline_metabox)) {
                $meta = get_post_meta($post->ID, $tagline_metabox->get_the_id(), TRUE);
                $post->tagline = $meta['tagline_text'];

            if (!isset($post->tagline) || $post->tagline == '')
                $post->tagline = substr($post->post_title, 0, 20) . '..';

            $post->post_date_timestamp = strtotime($post->post_date);           

            //$post->blog_id = $site->blog_id;
            $post->blog_name = get_bloginfo('name');
            $post->blog_url = get_bloginfo('wpurl');
            $post->permalink = get_permalink($post->ID);
            $post->author_name = get_userdata($post->post_author)->display_name;
            //$data = get_userdata($post->post_author);

            $blogposts[] = $post;

    // sort blogposts by post_date_timestamp, descending
    array_sort_by_obj($blogposts, 'post_date_timestamp', SORT_DESC);

    // pick five latest posts
    if (sizeof($blogposts) > 5) {
        $posts = array();
        for ($i = 0; $i <= 4; $i++) {
            $posts[$i] = $blogposts[$i];
        $blogposts = $posts;

    // set transient
        set_site_transient('limelight_recent_posts_' . $hash, $blogposts, LL_TRANSIENT_EXPIRES);

Try the following:

add_filter( 'pre_get_posts', 'get_post_from_main_blog' );
function get_post_from_main_blog($query) {
    global $wpdb;
    $wpdb->posts = 'wp_posts';
    return $query;

You may need to change wp_posts to your main blog's post table name.

  • 2
    That does not explain how to query other sites within the same Wordpress network, which was my question. Mar 20, 2014 at 8:23

Afaik there is no built in way to query posts of different Multisite instances, so you can only build a custom query, use "switch_to_blog" in a loop with all blogs, or use a custom WP_Query Class like this one: https://github.com/miguelpeixe/WP_Query_Multisite/

The last option just overrides WP_Query, so you can use it like this:

$query = new WP_Query(['multisite' => 1]);

Of course you would add other query params too. In this case, the WP_Query will search for the relevant items in the whole Multisite.

Btw, this only seems to work with regular posts, not with other post types.

Another option that works with other post types: https://github.com/ericandrewlewis/WP_Query_Multisite

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.