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.

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.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 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);

Method 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.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x