How would I use pre_get_posts to query another site for posts in my multisite network?

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.

Read More

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(
    'lundalogik-se'
);
switch_to_blog(1);
$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.

Related posts

2 comments

  1. 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) {
            switch_to_blog($site->blog_id);
            $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;
            }
            restore_current_blog();
        }
    
        // 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
        if (LL_USE_TRANSIENTS)
            set_site_transient('limelight_recent_posts_' . $hash, $blogposts, LL_TRANSIENT_EXPIRES);
    
  2. 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.

Comments are closed.