在Magento 2中更新主题父级的正确方法


14

在Magento 2中,您可以在主题theme.xml文件中指定父主题。

<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
    <title>Theme Title</title>
    <parent>Package/base-theme</parent>
    <media>
        <preview_image>media/preview.jpg</preview_image>
    </media>
</theme>

Magento第一次看到主题时,它将使用此值parent_idtheme表中设置a 。这是主题父级所在位置的真相来源。

但是,如果您在将主题添加到系统后尝试更改此值,则Magento无法更新该parent_id列,并且实例化的Magento\Theme\Model\Theme对象仍将具有原始父主题。(即使您清除了缓存。)

我可以通过手动更改parent_id值来解决此问题-好像是hack。parent_idMagento的核心代码通常在哪里设置,哪些用户操作会触发此操作?即有没有办法告诉Magento“请重新加载这个主题”


2
是的,我也注意到了这一点,在注册主题之后,发现修改此内容的唯一方法是直接修改数据库。可能是错误?
Gareth Daine

Answers:


2

于20160310更新

结论

updateTheme()如果您的计算机始终通过或从集合(通过DB)中进行设置,appState->getMode() == AppState::MODE_PRODUCTION

回答

为了回答这个问题,让Magento重新加载theme.xml文件的方法是什么:

将应用程序状态设置为developerusing SetEnv MAGE_MODE developerin .htaccess(或等效于nginx),然后登录到管理区域(或刷新任何管理路径)以进行触发Magento\Theme\Model\Theme\Plugin\Registration::beforeDispatch()

由于以下原因,数据库中的主题表已更新

\\Magento\Theme\Model\Theme\Plugin\Registration::updateThemeData()
\\...
$themeData->setParentId($parentTheme->getId());`.
\\...

有关详细信息,请参见下面的分析。

分析

哇,Magento 2代码对我来说似乎真的很复杂。您是否研究过此函数beforeDispatch()updateThemeData()但仅if ($this->appState->getMode() != AppState::MODE_PRODUCTION)

//namespace: namespace Magento\Theme\Model\Theme\Plugin;
//class: Registration
//file: app/code/Magento/Theme/Model/Theme/Plugin/Registration.php 

     /**
     * Add new theme from filesystem and update existing
     *
     * @param AbstractAction $subject
     * @param RequestInterface $request
     *
     * @return void
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function beforeDispatch(
        AbstractAction $subject,
        RequestInterface $request
    ) {
        try {
            if ($this->appState->getMode() != AppState::MODE_PRODUCTION) {
                $this->themeRegistration->register();
                $this->updateThemeData();
            }
        } catch (LocalizedException $e) {
            $this->logger->critical($e);
        }
    }

可能您已经看过这段代码。

beforeDispatch()仅通过管理路由而不是在前端路由上调用。这是痕迹:

#0 [internal function]: Magento\Theme\Model\Theme\Plugin\Registration->beforeDispatch(Object(Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor), Object(Magento\Framework\App\Request\Http))
#1 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(122): call_user_func_array(Array, Array)
#2 \magento2\var\generation\Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor.php(39): Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor->___callPlugins('dispatch', Array, Array)
#3 \magento2\lib\internal\Magento\Framework\App\FrontController.php(55): Magento\Backend\Controller\Adminhtml\Dashboard\Index\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#4 [internal function]: Magento\Framework\App\FrontController->dispatch(Object(Magento\Framework\App\Request\Http))
#5 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(74): call_user_func_array(Array, Array)
#6 \magento2\lib\internal\Magento\Framework\Interception\Chain\Chain.php(70): Magento\Framework\App\FrontController\Interceptor->___callParent('dispatch', Array)
#7 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(136): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Framewo...', 'dispatch', Object(Magento\Framework\App\FrontController\Interceptor), Array, 'install')
#8 \magento2\lib\internal\Magento\Framework\Module\Plugin\DbStatusValidator.php(69): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#9 [internal function]: Magento\Framework\Module\Plugin\DbStatusValidator->aroundDispatch(Object(Magento\Framework\App\FrontController\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#10 \magento2\lib\internal\Magento\Framework\Interception\Interceptor.php(141): call_user_func_array(Array, Array)
#11 \magento2\var\generation\Magento\Framework\App\FrontController\Interceptor.php(26): Magento\Framework\App\FrontController\Interceptor->___callPlugins('dispatch', Array, Array)
#12 \magento2\lib\internal\Magento\Framework\App\Http.php(115): Magento\Framework\App\FrontController\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#13 \magento2\lib\internal\Magento\Framework\App\Bootstrap.php(258): Magento\Framework\App\Http->launch()
#14 \magento2\index.php(39): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http))

实际上,我看到包含此块的beforeDispatch()呼叫updateThemeData()

//namespace: namespace Magento\Theme\Model\Theme\Plugin;
//class: Registration
//file: app/code/Magento/Theme/Model/Theme/Plugin/Registration.php 
//function: updateThemeData()

//...
            if ($themeData->getParentTheme()) {
                $parentTheme = $this->themeLoader->getThemeByFullPath(
                    $themeData->getParentTheme()->getFullPath()
                );
                $themeData->setParentId($parentTheme->getId());
            }
//...

似乎实际上(最终)引用了配置XML路径,$themeData->getParentTheme()->getFullPath()但该功能仍在使用$themeData->getParentTheme()。哦,我认为逻辑是“ 如果我要更新一个在集合中具有parentId的注册主题(通过DB),然后在配置中查找父路径并更新集合 ”。也许就是这样。

否则,我完全不知道如何Magento\Theme\Model\Theme::getParentTheme()实现getParentId()主题界面中声明的内容。当然,这不是魔术。正如您所说,它需要来自数据库,也可以来自集合,也可以来自主题的config XML路径(如果它已更改或尚未定义),但是我找不到的定义getParentId()。也许总是通过updateTheme()集合中的OR(通过DB)进行设置,如果您使用,那就太糟糕了appState->getMode() == AppState::MODE_PRODUCTION

我发现updateThemeData()通过添加一些日志输出从内部收集信息很有用:

//namespace: namespace Magento\Theme\Model\Theme\Plugin;
//class: Registration
//file: app/code/Magento/Theme/Model/Theme/Plugin/Registration.php 
//function: updateThemeData()

//...
            if ($themeData->getParentTheme()) {
                $parentTheme = $this->themeLoader->getThemeByFullPath(
                    $themeData->getParentTheme()->getFullPath()
                );
            $this->logger->addDebug("Theme parent full path ".$themeData->getParentTheme()->getFullPath());
            $this->logger->addDebug("Theme parent new ID ".$parentTheme->getId());                    $themeData->setParentId($parentTheme->getId());
            }
//...

哪个将登录到/var/log/debug.log。在将应用程序状态设置为的情况下,developer无论是否进行了更改,我都能看到始终在每次管理页面刷新时都设置父ID theme.xml。对于应用程序状态,production该功能永远不会运行,因此我得出结论:

它总是通过updateTheme()集合中的OR 设置(通过DB),如果您的appState->getMode() == AppState::MODE_PRODUCTION

我认为您可能都处于developer应用程序状态。default应用程序状态updateThemeData()当然也会触发。在进一步的调试中,我记录了Luma父主题为的主题完整路径frontend/Magento/blank。首都M使我感到惊讶,所以也许需要提防。


0

上面的代码似乎不适用于我,所以我选择了hack。

希望它可以帮助某人。

using the command line

 mysql

 SHOW databases;

 use magento; (or whatever your DB's name is)

 SHOW tables

 SELECT * FROM theme; 

(Check the **parent_id** of theme in question, it should be the same number as **theme_id** of theme you want as the parent)

如果不是,请进行更改。

 UPDATE theme SET parent_id  = '[value]' WHERE theme_title = '[Theme name]';

then quit mysql;

 bin/magento setup:static-content:deploy 

要么

grunt clean:[theme] (For example:  grunt clean:blank)

grunt exec:[theme]

grunt less:[theme]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.