First off let me just clearly say that I am not talking about just activating/deactivating a module output per a website level. Module output merely disables toHtml() method that certain module block class implements. In this article I am talking about fully deactivating the module like when we open the modules config xml file and place <active>true</active>.
When we place <active>true</active> it means is that our module is fully turned off. In such case, if some external module calls our models (classes) we will get error or some sort of exception. Reason for this is that class autoloader does not load anything trough “Mage::getModel(‘something/something’);” if this “something” is defined as model in config file from module that is turned off by <active>true</active>.
So, when would we like to turn off a module per a website level?! Imagine you are running a Magento that server as your own personal private hosted shop solution. On website A and C you want to have a cool JavaScript zoom module that shows awesome zoom feature on product photos. On site B you wish to have a different zoomer coded entirely by different JS framework etc. Something like this can easily be done just by modifying the theme files or setting up a partially different theme for this website where only difference would be in one or two layout xml files that would load up different JavaScript etc.
Besides doing a special theme/layout changes would it not be nice if you can simply say: Turn the Zoomer1 on website A and C and Zoomer2 on website B?! Maybe theme changes are not best fit to describe the possible convenience of having ModuleX turned on on websites A and C and ModuleY on website B. However, for those interested in such possibilities (scenario), here is a possible way of doing it.
First thing we need to do is to modify the appcodecoreMageCoreModelConfig.php file. Given that we do not modify the core file in order to avoid upgrade overwrite, we will make a copy of this file in appcodelocalMageCoreModelConfig.php.
In this file I will add the method with the content of code as show below.
/** Start: Per website module on/off */
public function handleModulesPerWebsite($moduleFiles)
{
if($options = $this->getOptions()) {
$websiteCode = 'website';
$mageRunCode = $options->getData('mageRunCode');
$mageRunType = $options->getData('mageRunType');
//Check if we are running a valid website
//if($mageRunType == $websiteCode) {
$xml = simplexml_load_file('S:Serverappsshopsrv_stagingmodules.xml');
$modules = array_keys((array)$xml);
$moduleFilesX = $moduleFiles;
foreach($moduleFilesX as $k => $moduleFile) {
$s = explode('\', $moduleFile);
$moduleName = str_replace('.xml', '', end($s));
//Turn off all the other modules that are not listed in modules.php file
if(!in_array($moduleName, $modules)) {
unset($moduleFiles[$k]);
}
}
unset($moduleFilesX);
//}
//Zend_Debug::dump($moduleFiles);
}
return $moduleFiles;
}
/** End: Per website module on/off */
Highly important thing to note here. As you can see I have hard-coded the “S:Serverappsshopsrv_stagingmodules.xml” path to one specific website folder. If you choose to play with this code, please modify it to do some current website path check and include only the modules.xml file from the currently viewed website on frontend.
And I will modify the existing “protected function _getDeclaredModuleFiles()” method to include a call towards my new method like shown below in code.
/**
* Start: Custom addded, calls the new Non-Magento method,
coded to do turn-off of modules per website.
* Place right below the $collectModuleFiles['custom'] variable definition.
*/
$collectModuleFiles['custom'] = $this->handleModulesPerWebsite($collectModuleFiles['custom']);
/**
* End: Custom addded, calls the new Non-Magento method,
coded to do turn-off of modules per website.
* Place right below the $collectModuleFiles['custom'] variable definition.
*/
Here is the full view of the modified “protected function _getDeclaredModuleFiles()” method.
protected function _getDeclaredModuleFiles()
{
$etcDir = $this->getOptions()->getEtcDir();
$moduleFiles = glob($etcDir . DS . 'modules' . DS . '*.xml');
if (!$moduleFiles) {
return false;
}
$collectModuleFiles = array(
'base' => array(),
'mage' => array(),
'custom' => array()
);
foreach ($moduleFiles as $v) {
$name = explode(DIRECTORY_SEPARATOR, $v);
$name = substr($name[count($name) - 1], 0, -4);
if ($name == 'Mage_All') {
$collectModuleFiles['base'][] = $v;
}
elseif (substr($name, 0, 5) == 'Mage_') {
$collectModuleFiles['mage'][] = $v;
}
else {
$collectModuleFiles['custom'][] = $v;
}
}
/**
* Start: Custom addded, calls the new Non-Magento method,
coded to do turn-off of modules per website.
* Place right below the $collectModuleFiles['custom'] variable definition.
*/
$collectModuleFiles['custom'] = $this->handleModulesPerWebsite($collectModuleFiles['custom']);
/**
* End: Custom addded, calls the new Non-Magento method,
coded to do turn-off of modules per website.
* Place right below the $collectModuleFiles['custom'] variable definition.
*/
return array_merge(
$collectModuleFiles['base'],
$collectModuleFiles['mage'],
$collectModuleFiles['custom']
);
}
With the above changes in place we now have a basic mechanism of removing unwanted custom modules from globally merged config file.
Next, we will create a new website in Magento under the “System > Manage Stores” admin section. Lets say we give this site a code name “staging” and we create a folder called “srv_staging” in our root Magento installation folder. For instance if my Magento is installed under the “S:Serverappsshop” then I will place my new website in the “S:Serverappsshopsrv_staging” folder. Keep in mind that when you are doing a multiple websites setup in Magento it is not necessary to set your other websites in a subfolder of root Magento. If you are not on top of the “How To Setup Multiple Magento Stores” topic then please skip this article.
Moving on, now we have a “S:Serverappsshopsrv_staging” folder from which we will run our second website. Reason why I place my second website in the sub-folder of root Magento is simply to avoid playing around with virtual hosts in this example. That way I can do http://shop.local/srv_staging/ and go to my “staging” website given that http://shop.local/ points to my default base website.
In order for our “Aactivate/Deactivate Magento module per a website level” mechanism to work we will need a partially different call for “Mage:.run” in our “S:Serverappsshopsrv_stagingindex.php” file.
Here is how it should look (at least for my example and the code above):
Mage::run($mageRunCode, $mageRunType, $options = array('mageRunCode'=>$mageRunCode, 'mageRunType'=>$mageRunType));
And for the grand finale, here is the new additional file you can place in the S:Serverappsshopsrv_stagingmodules.xml file, with a sample content like shown below.
<?xml version="1.0" encoding="UTF-8"?>
<ActiveModules>
<Ajzele_Resourcer />
<Ajzele_Qrcode />
</ActiveModules>
All the module names declared within ActiveModules tag in this XML file are the names of the custom (community/local) modules we wish to turn on for this website. In my case I said: Turn on the Ajzele_Resourcer and Ajzele_Qrcode modules for the “staging” website.
That’s it. These little modifications and additions should enable you to have “Aactivate/Deactivate Magento module per a website level” mechanism.
Please note that this code and approach entirely are highly experimental. Thus, try not to use them in any live sites. My intention was merely to give you something to think about in case you need something like this.
Also, additional info, this experiment was done on Magento 1.4.0.1.
Cheers.