John D Wells

I build websites with HTML, CSS, jQuery, PHP, ExpressionEngine & CodeIgniter.

Proud co-founder of the kick-ass, London-based creative agency One Darnley Road.

© johndwells

Custom plugin: How to switch MSM sites while mid-rendering of template

More often than not, EE add-ons assume that you are only interested in the current site being loaded. But, well, you know what they say about ass-u-mptions. Read on to learn how you can switch MSM sites while mid-rendering of a template.

Published:
Feb 04, 2011
Filed under:
EECMS
Comments:
7 - add yours

I'm smack in the middle of a monumental MSM build. It's my second MSM site, and I am once again reminded how I am not in Kansas anymore.  It's still EE, and it's still awesome, but "gotchas" seem a frustratingly common occurrence.

One such "gotcha" is this: as much as EE's docs claim it's easy to mix content across sites, this is in fact much easier said than done. In particular, many 3rd party add-ons, while claiming to be MSM-compatible, are "hard-coded" to use the current site being visited.

Take for example, the glorious Structure addon. It's very MSM-capable, allowing you to build tree structures for each of your sites. However none of its tags allow for you to specify which site you'd like to pull navigation from; it always assumes you want to pull navigation from the currently loaded site.

For this particular MSM project, that's exactly the roadblock I encountered last week, and needed to find a workaround. So I set about digging. Here's what I came up with.

Step 1: Set up your plugin

This article falls under my "Build Your Own Plugin" mantra that I, and others, have written about before. EE plugins are awesomely fun and simple to write, and put you on the fast track to becoming an EE guru.

We're going to build ourselves a simple plugin that :

  • saves site-specific config settings for the current site into EE's session object;
  • accepts site_name as a parameter, and replaces our site-specific config settings with this requested site;
  • when prompted, reverts back to the current site-specific config settings

To start off with we need to set up our plugin. In our __construct() method, let's get an instance of EE, and then set up a session cache array to use later:

<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');

$plugin_info = array(
	'pi_name'			=> 'MSM Switch Site,
	'pi_version'			=> '1.0.0',
	'pi_author'			=> 'Your Name Here',
	'pi_author_url'		=> 'http://yournamehere.com',
	'pi_description'		=> 'Switch MSM sites mid-rendering of template'
);

class Msm_switch_site {

	var $EE;
	var $cache;

	function __construct()
	{
		$this->EE =& get_instance();

		// set up sess cache if not yet exist
		if( ! array_key_exists('msm_switch_site', $this->EE->session->cache))
		{
			$this->EE->session->cache['msm_switch_site'] = array();
		}
		
		// pass cache object as reference
		$this->cache =& $this->EE->session->cache['msm_switch_site'];
	}
}

Step 2: making the switch()

And here's where the magic happens: first, our switch() method places our current site's config array into our session.  It needs to remember two things:

  1. the current site_name
  2. the current site's config object

Next, we check for a provided site_name parameter; if passed, then we need to tell EE to load the site's prefs into the config object (check out lines 27-28). If no site_name is passed, then we will switch back to the current site.

function switch()
{
	// capture the orig site config info
	if( ! array_key_exists('msm_switch_site', $this->cache))
	{
		$this->cache['msm_switch_site_orig_short_name'] = $this->EE->config->item('site_short_name');
		$this->cache['msm_switch_site'] = array(
			$this->cache['msm_switch_site_orig_short_name'] => $this->EE->config->config
		);
	}
	
	// if no site_name param was passed, assume we'd like to switch back to orig site
	if( ! $site_name = $this->EE->TMPL->fetch_param('site_name'))
	{
		$this->EE->config->config = $this->cache['msm_switch_site'][$this->cache['msm_switch_site_orig_short_name']];
	}
	else
	{
		// do we already have it in the cache?
		if(array_key_exists($site_name, $this->cache['msm_switch_site']))
		{
			$this->EE->config->config = $this->cache['msm_switch_site'][$site_name];
		}
		else
		{
			// here's the single magical line that switches our site config
			$this->EE->config->site_prefs($site_name);
			$this->cache['msm_switch_site'][$site_name] = $this->EE->config->config;
		}
	}
}

Check out those last couple lines of code again: All we need to do is call $this->EE->config->site_prefs($site_name); to have EE look up our settings, and re-set all the necessary config items.  Then we just have to set this new config object into our cache (in case we need to switch to this site again and again, we can avoid subsequent DB calls).

Step 3: How to use

Let's again use Structure as an example.  Say we want to be guaranteed to show the main navigation of our default site, no matter what site is currently being displayed.  It will look like this:

{exp:msm_switch_site:switch site_name='default_site'}
	{exp:structure:nav_main}
{exp:msm_switch_site:switch}

Line 1 tells EE to switch to the default_site; line 2 calls Structure's nav_main as usual; line 3 tells EE to switch back to whichever site was currently being displayed.

Groovy, eh?

Published:
Feb 04, 2011
Filed under:
EECMS
Comments:
7 - add yours
 

Have your say...

That’s pretty slick. My last MSM site I had to hard code site name’s and entry id’s to build out navigation.

Is this EE1 compatible? If so, I may go back and rework the templates with this plugin.

Thanks for sharing!

  • #2
  • On 03:54 PM, 04/02/11
  • From London, UK
  • John D Wells said:

Funny you mention that - my first MSM site was on EE1, and same as you I had to hard-code the “mother” nav in.

At a glance, you should be able to refactor to work with EE1, something like:

global $PREFS;
$PREFS->site_prefs($site_name);
  • #3
  • On 08:08 AM, 21/02/11
  • From San Diego, CA
  • Natetronn said:

Love how you just pull out a can of 1-2-3 and go to town. I am glad I at least understand what to put for “Your Name Here” :)

Anyway, off to read the docs some more.

  • #4
  • On 03:13 AM, 09/03/11
  • Graham H said:

Hi John,

I love what you’ve done here!

However, I’m having a little trouble getting it to work… I’m getting an error that says the PI has a syntax error. I’m sure it’s a minor thing, but I can’t figure it out.

Can you post or email me a working copy of this plugin?

Thank you so much!

Graham

  • #5
  • On 03:24 AM, 09/03/11
  • Graham H said:

lol, I had my PI file named “msm_site_switch”, not “msm_switch_site”.

Watch out for dyslexia, people. It breaks plugins.

Works now!

You’re amazing!

  • #6
  • On 04:51 AM, 11/08/11
  • From United States
  • Steve James said:

John, your blog is incredibly helpful. I’m constantly seeking DRY techniques to speed up development, and you seem to have all my answers! Thanks for sharing your knowledge!

  • #7
  • On 07:50 AM, 11/08/11
  • From London, UK
  • John D Wells said:

Thanks Steve, I appreciate the kind words.  Always happy to share what I learn…

John