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.
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:
- the current site_name
- 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?
Have your say...