Combining content from multiple blogs

I have written earlier about the multiblog structure of Taffel.se. We actually use WP blogs in two ways: as blogs (such as Kort om gott, Matälskaren and this blog) of course, but also as content databases for recipes and kitchen tips, among other things. The latter blogs are separate blogs on the back end, but for the reader they appear to be integrated with the main website. In this and some future posts, I will explain how this integration is achieved with remarkable ease.

Database access in WordPress is all handled by the $wpdb global, an instance of the wpdb class. $wpdb is actually the only object that knows what the table prefix is (it is set from wp-config.php) and all queries go through it, so if you change the prefix (using $wpdb->set_prefix()), you’ve effectively switched blogs and subsequent queries will use the new tables.

There’s just one catch, and that’s caching of options. If you want to be able to switch blogs and still use nice convenience functions like get_permalink(), you need to somehow be able to override the cache. It is easy to bypass by simply flushing it, but then you sacrifice the advantages of caching. So what I do is create a new cache object for each prefix that I switch to and just switch the object in the global $wp_object_cache every time I change databases. It is very easy and works amazingly well. Here’s my code:

function switch_db($pre='') {
	global $wpdb, $wp_object_cache;
	static $tfl_cache, $tfl_prefix;
	if (empty($pre)) {
		if(empty($tfl_prefix)) return;
		$pre = $tfl_prefix;
	}
	if (!isset($tfl_cache)) $tfl_cache=array();
	if (!isset($tfl_prefix[$wpdb->prefix])) $tfl_prefix = $wpdb->prefix;
	if (!isset($tfl_cache[$wpdb->prefix])) $tfl_cache[$wpdb->prefix] = $wp_object_cache;
	$wpdb->set_prefix($pre);
	if (!isset($tfl_cache[$pre])) $tfl_cache[$pre]=new WP_Object_Cache();
	$wp_object_cache = $tfl_cache[$pre];
}
 
function end_switch() {
	switch_db();
}

I call switch_db with the table prefix as an argument whenever I want to change the active blog. It swaps the cache object and changes the table prefix. end_switch() restores the original prefix and cache.

A very simple usage example: I want to have a list of recent recipes on the first page. The recipes are stored in a separate blog with table prefix ‘wp_recept’. Yes, I know this can be done with RSS, but this is even easier (and I also use it for much more complicated cases).

function nytt_recept() {
	global $wpdb;
	switch_db('wp_recept_');
	$posts = get_posts();
	$links=array();
	foreach ($posts as $post) {
		$links[] = '<a href="'.get_permalink($post).'">'.$post->post_title.'</a>';
	}
	end_switch();
	nytt_section('Senaste recept', $links);
}

I do it this way because the list fits into a larger widget, but I could have simply created a loop with my own WP_Query object and it would have worked just as well. In this example, no custom SQL is necessary and everything just works, even get_permalink(). I love WordPress!

5 Responses to “Combining content from multiple blogs”

  1. konsty says:

    Your posts are really useful!
    Thanks for sharing :)

  2. heynow says:

    Hmm. I am wondering if I could create something similar to combine tags from two different WordPress blogs that are in the same database. What would you suggest? Sounds like it would be similar, right?

  3. Johan says:

    @heynow: I don’t know what you plan to do with the tags. Probably it will be a bit more complicated than just switching databases. Suppose for instance that you wanted to list all posts with a given tag from several wp installations (in the same db). If you are content with sorting them by blog (so first all of the posts from one blog, then all of the posts from the other) then yeah, you can just cycle through the blogs using the above technique. If you want some fancier sorting (for instance by sort date), you’ll have to write some custom SQL code. I’ve written a custom search engine for taffel.se which indexes all of the blogs in the site and provides pretty decent relevance ranking (it’s based on the mysql fulltext engine). It uses some pretty complicated SQL to do the query (in a subclass of WP_Query, but with the above method I can display the results in the loop using all of the standard loop functions (despite the posts coming from different wp installations).

  4. heynow says:

    Hey now, that’s cool! Sounds like a great search function. Is that something I would be able to adapt to my sites? I am new to PHP, so I don’t intend to be writing a whole lot. Seems like SQL queries would be the way to go with the tag issue too, wouldn’t it? I just don’t know how easy it would be to then display such results in WP.

  5. Johan says:

    @heynow: Displaying the results is easy if you know what you’re doing. Otherwise not. Read about how the loop works at the WP codex. But if you want to do things that you can’t find a ready-made plugin for you’ll have to get more ambitious about php.

    My search module is not at this stage something that a beginner could easily get to work on another site. I do plan to blog more about what I did to make it work.