1

How can we assign a theme in Magento 2.1 to a store using setup scripts?

Thank you

6

Create a new InstallData (or UpgradeData) script in either a new module or a fitting pre-existing module.

Here is a simple example for a complete InstallData script. Simply replace the THEME_NAME constant found at the top of the class with your own theme name. For example, if you wanted to assign the default Magento 2 luma theme, you would write:

const THEME_NAME = 'Magento/luma';

(Make sure the Vendor starts with an uppercase and the theme with a lower case letter!)

You can find your theme name by simply looking at the registration.php in the directory of your theme (found in app/design/frontend/), it's probably easiest to copy paste it from here to prevent any typos:

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::THEME,
    'frontend/Vendor/theme',
    __DIR__
);

The full InstallData.php script looks like this, alternatively you can add it to an UpgradeData.php as well, you mainly need the assignTheme() method from the bottom and inject all the required classes into the constructor:

<?php
namespace Medline\Theme\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\Store;

/**
 * @codeCoverageIgnore
 * @SuppressWarnings(PHPMD)
 */
class InstallData implements InstallDataInterface
{
    const THEME_NAME = 'Vendor/theme';

    /**
     * @var \Magento\Theme\Model\Config
     */
    private $config;

    /**
     * @var \Magento\Theme\Model\ResourceModel\Theme\CollectionFactory
     */
    private $collectionFactory;

    /**
     * InstallData constructor.
     * @param \Magento\Theme\Model\ResourceModel\Theme\CollectionFactory $collectionFactory
     * @param \Magento\Theme\Model\Config $config
     */
    public function __construct(
        \Magento\Theme\Model\ResourceModel\Theme\CollectionFactory $collectionFactory,
        \Magento\Theme\Model\Config $config
    ) {
        $this->collectionFactory = $collectionFactory;
        $this->config = $config;
    }


    /**
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();

        $this->assignTheme();

        $setup->endSetup();
    }

    /**
     * Assign Theme
     *
     * @return void
     */
    protected function assignTheme()
    {
        $themes = $this->collectionFactory->create()->loadRegisteredThemes();
        /**
         * @var \Magento\Theme\Model\Theme $theme
         */
        foreach ($themes as $theme) {
            if ($theme->getCode() == self::THEME_NAME) {
                $this->config->assignToStore(
                    $theme,
                    [Store::DEFAULT_STORE_ID],
                    ScopeConfigInterface::SCOPE_TYPE_DEFAULT
                );
            }
        }
    }
}
  • I'd just like to add, that I had to reindex the desing grid in order for it to work – Philipp Sander Oct 20 '17 at 9:26
  • instead of DEFAULT_STORE_ID how can i give my custom store id to this ? – Manthan Dave Feb 16 '18 at 13:22
5

On Magento 2.1 and later (2.2 and 2.3 coming out) it is recommended to use service contract so I tried doing this without calling method in the model directly.

Unfortunately at this point there is no straight forward way in the core Magento_Theme module service contract so we still have to make do with using some factory class.

First we need to inject the following classes to the setup script contructor:

use Magento\Theme\Api\DesignConfigRepositoryInterface;
use Magento\Theme\Model\Data\Design\ConfigFactory;
use Magento\Theme\Model\ResourceModel\Theme\CollectionFactory;

public function __construct(
        DesignConfigRepositoryInterface $designConfigRepository,
        CollectionFactory $themeCollectionFactory,
        ConfigFactory $themeConfigFactory) {...}

Next we will try to load the theme ID from it's path. Then we create a Design Config object by using factory class (hopefully Magento core will provide a service contract to do this in the future). Finally we use the ConfigRepository to save the value.

In this example my theme is for the frontend area, and has path MyVendorName/MyThemeName.

if (version_compare($context->getVersion(), '1.0.0', '<')) {
    $themeCollection = $this->themeCollectionFactory->create();
    $theme = $themeCollection->getThemeByFullPath('frontend/MyVendorName/MyThemeName');
    $themeId = $theme->getId();

    $designConfigData = $this->themeConfigFactory->create('default', 0, ['theme_theme_id' => $themeId]);

    $this->designConfigRepository->save($designConfigData);
}

Notes: the designConfigRepository should take care of reindexing the grid.

Using this approach you can also change other theme configuration, for example:

$designConfigData = $this->themeConfigFactory->create('default', 0, [
'theme_theme_id' => $themeId,
'head_default_title' => 'My Default Title',
'head_demonotice' => 1 // Display demo store notice
]);

Obviously you can replace 'default' and '0' with relevant store scope. Hope this helps.

  • Hai, i am used in Controller to Change Default Store Theme shown: Exception #0 (UnexpectedValueException): Email template '' is not defined . Use another Store itz shown Exception #0 (Magento\Framework\Exception\LocalizedException): Invalid scope or scope id. How can i find my scope and scope id in core_config_data table . core_config table have scope : Default, Stores . Scope_Id: 0,1,2 @William Tran – kamal May 17 '18 at 5:09
1

Above solutions work but have one shortcoming. They assume that magento has already registered the theme, before setup script execution. This is not always the case. If you revert entries in setup_module table, you discover that error is "magically fixed".

To avoid it, make sure that themes are registered before setup script execution. One way to do it is

\Magento\Theme\Model\Theme\Registration::register()
0

Better to use \Magento\Framework\View\Design\Theme\ListInterface instead of \Magento\Theme\Model\ResourceModel\Theme\CollectionFactory. ListInterface have method getThemeByFullPath, so your code would be:

<?php
namespace Vendor\Module\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\Store;

/**
 * Class InstallData
 */
class InstallData implements InstallDataInterface
{
    const THEME_FULL_PATH = 'frontend/Vendor/theme';

    /**
     * @var \Magento\Theme\Model\Config
     */
    private $config;

    /**
     * @var \Magento\Framework\View\Design\Theme\ListInterface $themeList
     */
    private $themeList;

    /**
     * InstallData constructor.
     *
     * @param \Magento\Framework\View\Design\Theme\ListInterface $themeList
     * @param \Magento\Theme\Model\Config $config
     */
    public function __construct(
        \Magento\Framework\View\Design\Theme\ListInterface $themeList,
        \Magento\Theme\Model\Config $config
    ) {
        $this->themeList = $themeList;
        $this->config = $config;
    }


    /**
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     * @return void
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();

        $this->assignTheme();

        $setup->endSetup();
    }

    /**
     * Assign Theme
     *
     * @return void
     */
    protected function assignTheme()
    {
        /** @var \Magento\Framework\View\Design\ThemeInterface $theme */
        $theme = $this->themeList->getThemeByFullPath(self::THEME_FULL_PATH);

        if ($theme->getId()) {
            $this->config->assignToStore($theme, [Store::DEFAULT_STORE_ID], ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
        }
    }
}

And you should add di.xml to your module

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Vendor\Module\Setup\InstallData">
        <arguments>
            <argument name="themeList" xsi:type="object">Magento\Theme\Model\ResourceModel\Theme\Collection</argument>
        </arguments>
    </type>
</config> 
  • /** @var \Magento\Framework\View\Design\ListInterface $theme */ $theme = $this->themeList->getThemeByFullPath(self::THEME_FULL_PATH); var_dump($theme->getId()); Getting NUll Value Let me know how can i use getId() . I am use getCode() then save config my cache management only affect . Not any changes in my default store – kamal May 16 '18 at 10:54
  • Did you add di.xml to your module? – Oleksii Mukhin May 17 '18 at 12:12
  • Ya im added @Oleksii Mukhin – kamal May 17 '18 at 12:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.