Magento:禁用任何特定商店的模块

发布于 2024-11-06 05:57:22 字数 382 浏览 0 评论 0原文

假设,我有 3 家商店。

我想禁用商店 2 中的模块。我只希望在商店 1 和商店 3 中启用它。

我发现我可以通过以下方式做到这一点:-

  • 转到系统 ->配置->高级

  • 当前配置范围下拉列表中选择所需的商店。

但这并不能完全发挥作用。

而且,我也不想检查模块代码本身中的存储或为模块创建系统配置字段以检查/取消选中存储以启用/禁用。

我期望的是在 app/etc/modules/MyNamespace_MyModule.xml 中添加一些代码。我们可以这样做吗?

Suppose, I have 3 stores.

I want to disable a module in Store 2. I only want it to be enabled in Store 1 and Store 3.

I see that I can do it by:-

  • Going to System -> Configuration -> Advanced

  • Selecting desired store from Current Configuration Scope dropdown list.

But this does not work fully.

And, I also don't want to check store in the module code itself or create system configuration field for the module to check/uncheck store to enable/disable.

What I am expecting is by adding some code in app/etc/modules/MyNamespace_MyModule.xml. Can we do it this way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

剩一世无双 2024-11-13 05:57:22

要禁用商店范围内的模块,我发现可以这样做:

将 app/code/core/Mage/Core/Model/Config.php 移动到 app/code/local/Mage/Core/Model/ Config.php

在 Config.php 里面找到方法“loadModulesConfiguration”,不要改变任何东西,但是添加以下代码,使该方法看起来像这样。

public function loadModulesConfiguration($fileName, $mergeToObject = null, $mergeModel=null)
{
    $disableLocalModules = !$this->_canUseLocalModules();

    if ($mergeToObject === null) {
        $mergeToObject = clone $this->_prototype;
        $mergeToObject->loadString('<config/>');
    }
    if ($mergeModel === null) {
        $mergeModel = clone $this->_prototype;
    }
    $modules = $this->getNode('modules')->children();
    foreach ($modules as $modName=>$module) {
        if ($module->is('active')) {
            // Begin additional code
            if((bool)$module->restricted) {
                $restricted = explode(',', (string)$module->restricted);
                $runCode = (isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default');
                if(in_array($runCode, $restricted)) {
                    continue;
                }
            }
            // End additional code
            if ($disableLocalModules && ('local' === (string)$module->codePool)) {
                continue;
            }
            if (!is_array($fileName)) {
                $fileName = array($fileName);
            }

            foreach ($fileName as $configFile) {
                $configFile = $this->getModuleDir('etc', $modName).DS.$configFile;
                if ($mergeModel->loadFile($configFile)) {
                    $mergeToObject->extend($mergeModel, true);
                }
            }
        }
    }
    return $mergeToObject;
}

新代码将导致该方法还检查模块 xml 文件中的新节点。如果该节点存在,则该值将是您不希望加载模块的商店代码的逗号分隔列表。如果您有多个商店,则应使用当前商店代码设置 $_SERVER 变量“MAGE_RUN_CODE”。如果未设置,脚本将回退到假设商店代码为“默认”,这就是默认情况,除非出于某种奇怪的原因您决定在后端更改它。

模块 xml 文件可能如下所示:

<?xml version="1.0"?>
<config>
    <modules>
        <MyPackage_MyModule>
            <active>false</active>
            <restricted>mystore1,mystore4,mystore5</restricted>
            <codePool>local</codePool>
        </MyPackage_MyModule>
    </modules>
</config>

这样,模块在商店代码为 mystore1、mystore4 或 mystore5 的商店中甚至不会加载。 <限制>标签完全是可选的,如果省略它,模块将像平常一样加载。

To disable a module on the store scope, I've found it's possible to do it like this:

Move app/code/core/Mage/Core/Model/Config.php to app/code/local/Mage/Core/Model/Config.php

Inside Config.php find the method "loadModulesConfiguration" Don't change anything, but add the following code to make the method look like this.

public function loadModulesConfiguration($fileName, $mergeToObject = null, $mergeModel=null)
{
    $disableLocalModules = !$this->_canUseLocalModules();

    if ($mergeToObject === null) {
        $mergeToObject = clone $this->_prototype;
        $mergeToObject->loadString('<config/>');
    }
    if ($mergeModel === null) {
        $mergeModel = clone $this->_prototype;
    }
    $modules = $this->getNode('modules')->children();
    foreach ($modules as $modName=>$module) {
        if ($module->is('active')) {
            // Begin additional code
            if((bool)$module->restricted) {
                $restricted = explode(',', (string)$module->restricted);
                $runCode = (isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default');
                if(in_array($runCode, $restricted)) {
                    continue;
                }
            }
            // End additional code
            if ($disableLocalModules && ('local' === (string)$module->codePool)) {
                continue;
            }
            if (!is_array($fileName)) {
                $fileName = array($fileName);
            }

            foreach ($fileName as $configFile) {
                $configFile = $this->getModuleDir('etc', $modName).DS.$configFile;
                if ($mergeModel->loadFile($configFile)) {
                    $mergeToObject->extend($mergeModel, true);
                }
            }
        }
    }
    return $mergeToObject;
}

The new code will cause the method to also check for a new node in the module xml file, <restricted>. If the node exists, the value would be a comma separated list of store codes that you do NOT want the module to load on. If you have multiple stores, the $_SERVER variable "MAGE_RUN_CODE" should be set with the current store code. If it's not set, the script will fallback to assuming the store code is "default" which is what it is by default unless for some bizarre reason you decide to change that in the backend.

A modules xml file could then look like this:

<?xml version="1.0"?>
<config>
    <modules>
        <MyPackage_MyModule>
            <active>false</active>
            <restricted>mystore1,mystore4,mystore5</restricted>
            <codePool>local</codePool>
        </MyPackage_MyModule>
    </modules>
</config>

With this, the module will not even load while on the stores with a store code of mystore1, mystore4, or mystore5. The <restricted> tag is entirely optional, if you omit it the module will load as it normally would.

宁愿没拥抱 2024-11-13 05:57:22

此配置只是禁用前端布局中的模块输出,但模块控制器、事件观察器、管理页面等仍然工作。

另外,不要忘记在布局文件定义中指定模块名称,否则将为特定商店加载所有布局文件内容:

<config>
   <layout>
       <module_alias module="Module_Name">
           <file>yourlayoutfile.xml</file>
       </module_alias>
   </layout>
</config>

如果您正在开发模块并希望在特定商店的前端禁用其全部功能,那么您应该创建一个“是/否”类型的配置字段,并通过模块代码中的 Mage::getStoreConfigFlag('config/field/path') 检查其值。

This configuration just disables module output in layout for frontend, but module controllers, event observers, admin pages, etc still working.

Also don't forget to specify your module name in layout files definition, otherwise all the layout file content will be loaded for a particular store:

<config>
   <layout>
       <module_alias module="Module_Name">
           <file>yourlayoutfile.xml</file>
       </module_alias>
   </layout>
</config>

If you are developing a module and want to disable full its functionality on the frontent for a particular store, then you should create a configuration field of "Yes/No" type and check its value via Mage::getStoreConfigFlag('config/field/path') in your module code.

药祭#氼 2024-11-13 05:57:22

我使用 Eric 解决方案有一段时间了。就我而言,我在我的一家商店中禁用了负责分层导航的某些模块 - 从而返回到默认的分层导航行为。

它看起来正常,但过了一会儿我注意到分层导航选项不再出现在它们应该出现的地方。很快我就注意到,实际上不应该在这家商店上工作的模块仍然可以工作。然后我意识到,当我禁用配置缓存时,埃里克的解决方案可以工作,但再次启用它后,它就会停止。

一段时间后,我意识到它必须以这种方式工作,并启用配置缓存,因为 Eric 的解决方案仅在生成此 xml 时才在全局 xml 中包含(或不包含)指定的配置文件。然后它被缓存并仅从缓存中调用。因此,当它是从应该使用某些模块的站点生成时,它被包含在内,然后也在不应该使用它的站点上使用。

无论如何,我根据 Eric 的代码制定了另一个解决方案(在模块配置中使用 restricted )。我认为 Magento 应该决定在请求类时加载什么。然后它可以检查当前的MAGE_RUN_CODE并动态使用它。

Mage_Core_Model_Config 中有一个方法负责获取类名:getGroupedClassName

这是我在那里使用的代码:

if (strpos($className, 'Pneumatig_') !== false) {
    $var = substr($className, 0, strpos($className, '_', strpos($className, '_') + 1));
    if (isset($this->_xml->modules->$var)) { 
        if ((bool)$this->_xml->modules->$var->restricted === true) {
            $code = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default';
            if (strpos((string)$this->_xml->modules->$var->restricted, $code) !== false) {
                $className = '';
            }
        }
    }
}

这个 Pneumatig 条件是因为我的所有模块都从公司名称开始,所以我想避免不必要的处理,但它是可选的,代码应该在没有它的情况下工作,或者您可以将其更改为其他任何内容。

然后我得到实际的模块名称​​[Company]_[Module],然后检查它是否在_xml(这是当前配置对象)中启用。如果它受到限制,我会清除 $className ,以便强制 Magento 在下一行加载默认值。

这段代码是在空条件之前添加的:

    // Second - if entity is not rewritten then use class prefix to form class name
    if (empty($className)) {
        if (!empty($config)) {
            $className = $config->getClassName();
        }
        if (empty($className)) {
            $className = 'mage_'.$group.'_'.$groupType;
        }
        if (!empty($class)) {
            $className .= '_'.$class;
        }
        $className = uc_words($className);
    }

    $this->_classNameCache[$groupRootNode][$group][$class] = $className;
    return $className;

为了您的方便,我粘贴整个 getGroupedClassName 代码:

public function getGroupedClassName($groupType, $classId, $groupRootNode=null)
{
    if (empty($groupRootNode)) {
        $groupRootNode = 'global/'.$groupType.'s';
    }

    $classArr = explode('/', trim($classId));
    $group = $classArr[0];
    $class = !empty($classArr[1]) ? $classArr[1] : null;

    if (isset($this->_classNameCache[$groupRootNode][$group][$class])) {
        return $this->_classNameCache[$groupRootNode][$group][$class];
    }

    $config = $this->_xml->global->{$groupType.'s'}->{$group};

    // First - check maybe the entity class was rewritten
    $className = null;
    if (isset($config->rewrite->$class)) {
        $className = (string)$config->rewrite->$class;
    } else {
        /**
         * Backwards compatibility for pre-MMDB extensions.
         * In MMDB release resource nodes <..._mysql4> were renamed to <..._resource>. So <deprecatedNode> is left
         * to keep name of previously used nodes, that still may be used by non-updated extensions.
         */
        if (isset($config->deprecatedNode)) {
            $deprecatedNode = $config->deprecatedNode;
            $configOld = $this->_xml->global->{$groupType.'s'}->$deprecatedNode;
            if (isset($configOld->rewrite->$class)) {
                $className = (string) $configOld->rewrite->$class;
            }
        }
    }

    //START CHECKING IF CLASS MODULE IS ENABLED
    if (strpos($className, 'Pneumatig_') !== false) {
        $var = substr($className, 0, strpos($className, '_', strpos($className, '_') + 1));
        if (isset($this->_xml->modules->$var)) { 
            if ((bool)$this->_xml->modules->$var->restricted === true) {
                $code = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default';
                if (strpos((string)$this->_xml->modules->$var->restricted, $code) !== false) {
                    $className = '';
                }
            }
        }
    }
    //END CHECKING IF CLASS MODULE IS ENABLED

    // Second - if entity is not rewritten then use class prefix to form class name
    if (empty($className)) {
        if (!empty($config)) {
            $className = $config->getClassName();
        }
        if (empty($className)) {
            $className = 'mage_'.$group.'_'.$groupType;
        }
        if (!empty($class)) {
            $className .= '_'.$class;
        }
        $className = uc_words($className);
    }

    $this->_classNameCache[$groupRootNode][$group][$class] = $className;
    return $className;
}

I was using Eric solution for a while. In my case I disabled certain module responsible for Layered Navigation in one of my shops - thus returning to default Layered Navigation behaviour.

And it looked like its working, but after a while I've noticed that layered navigation options stopped to appear where they should. Soon I've noticed that in fact the module that should not work on this shop continued to work. Then I realized that when I disable configuration cache Eric's solution works, but after enabling it again it stops.

After a while I realized it had to work that way, with configuration cache enabled, because Eric's solution includes (or not) specified config files in global xml only while this xml is being generated. Then its cached and called from cache only. So when it was generated from site which should use some module it was included, and then used also on site which wasn't suppose to use it.

Anyway I worked out another solution, based on Eric's code (using restricted in modules config). I thought Magento should decide what to load when class is being requested. Then it could check what is current MAGE_RUN_CODE and use it dynamically.

There is a method in Mage_Core_Model_Config which is responsible for getting class name: getGroupedClassName.

Here is the code I used there:

if (strpos($className, 'Pneumatig_') !== false) {
    $var = substr($className, 0, strpos($className, '_', strpos($className, '_') + 1));
    if (isset($this->_xml->modules->$var)) { 
        if ((bool)$this->_xml->modules->$var->restricted === true) {
            $code = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default';
            if (strpos((string)$this->_xml->modules->$var->restricted, $code) !== false) {
                $className = '';
            }
        }
    }
}

This Pneumatig condition is because all my modules start from Company name, so i wanted to avoid not necessary processing, but its optional, code should work without it, or you can change it to anything else.

Then I get actual module name [Company]_[Module], and then check if its enabled in _xml (which is current configuration object). If it is restricted I clear $className so it force Magento to load the default in next line.

And this code is added just before is empty condition:

    // Second - if entity is not rewritten then use class prefix to form class name
    if (empty($className)) {
        if (!empty($config)) {
            $className = $config->getClassName();
        }
        if (empty($className)) {
            $className = 'mage_'.$group.'_'.$groupType;
        }
        if (!empty($class)) {
            $className .= '_'.$class;
        }
        $className = uc_words($className);
    }

    $this->_classNameCache[$groupRootNode][$group][$class] = $className;
    return $className;

And for your convenience i paste whole getGroupedClassName code:

public function getGroupedClassName($groupType, $classId, $groupRootNode=null)
{
    if (empty($groupRootNode)) {
        $groupRootNode = 'global/'.$groupType.'s';
    }

    $classArr = explode('/', trim($classId));
    $group = $classArr[0];
    $class = !empty($classArr[1]) ? $classArr[1] : null;

    if (isset($this->_classNameCache[$groupRootNode][$group][$class])) {
        return $this->_classNameCache[$groupRootNode][$group][$class];
    }

    $config = $this->_xml->global->{$groupType.'s'}->{$group};

    // First - check maybe the entity class was rewritten
    $className = null;
    if (isset($config->rewrite->$class)) {
        $className = (string)$config->rewrite->$class;
    } else {
        /**
         * Backwards compatibility for pre-MMDB extensions.
         * In MMDB release resource nodes <..._mysql4> were renamed to <..._resource>. So <deprecatedNode> is left
         * to keep name of previously used nodes, that still may be used by non-updated extensions.
         */
        if (isset($config->deprecatedNode)) {
            $deprecatedNode = $config->deprecatedNode;
            $configOld = $this->_xml->global->{$groupType.'s'}->$deprecatedNode;
            if (isset($configOld->rewrite->$class)) {
                $className = (string) $configOld->rewrite->$class;
            }
        }
    }

    //START CHECKING IF CLASS MODULE IS ENABLED
    if (strpos($className, 'Pneumatig_') !== false) {
        $var = substr($className, 0, strpos($className, '_', strpos($className, '_') + 1));
        if (isset($this->_xml->modules->$var)) { 
            if ((bool)$this->_xml->modules->$var->restricted === true) {
                $code = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default';
                if (strpos((string)$this->_xml->modules->$var->restricted, $code) !== false) {
                    $className = '';
                }
            }
        }
    }
    //END CHECKING IF CLASS MODULE IS ENABLED

    // Second - if entity is not rewritten then use class prefix to form class name
    if (empty($className)) {
        if (!empty($config)) {
            $className = $config->getClassName();
        }
        if (empty($className)) {
            $className = 'mage_'.$group.'_'.$groupType;
        }
        if (!empty($class)) {
            $className .= '_'.$class;
        }
        $className = uc_words($className);
    }

    $this->_classNameCache[$groupRootNode][$group][$class] = $className;
    return $className;
}
天涯离梦残月幽梦 2024-11-13 05:57:22

我的客户安装的 Magento 1.8.1.0 有一个有问题的模块,该模块会破坏多商店设置中另一个站点的菜单。 Eric Hainer 发布的上述解决方案不适用于此安装,因此我稍微修改了它:

我使用 $_SERVER['SERVER_NAME' 而不是使用 $_SERVER['MAGE_RUN_CODE'] ]。工作起来就像一个魅力。 :)

因此,而不是:

$runCode = (isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default');

使用:

$runCode = (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'www.site1.com');

并代替:

<restricted>mystore1,mystore4,mystore5</restricted>

使用:

<restricted>www.site2.com,www.site3.com</restricted>

显然用您自己的位置更改“www.site1.com”、“www.site2.com”和“www.site3.com”。

感谢埃里克的想法:)

My clients install of Magento 1.8.1.0 has a problematic module that breaks another site's menu on a multi-store setup. The solution above posted by Eric Hainer didn't work for this install, so I altered it slightly:

Instead of using $_SERVER['MAGE_RUN_CODE'], I used $_SERVER['SERVER_NAME']. Worked like a charm. :)

So instead of:

$runCode = (isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default');

use:

$runCode = (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'www.site1.com');

and instead of:

<restricted>mystore1,mystore4,mystore5</restricted>

use:

<restricted>www.site2.com,www.site3.com</restricted>

obviously changing "www.site1.com", "www.site2.com", and "www.site3.com" with your own locations.

Thanks for the idea Eric :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文