spryker-demo / shop-theme-feature
Shop theme [feature]
1.0.0
2025-04-09 16:09 UTC
Requires
- php: >=8.2
- spryker-demo/shop-theme: ^1.0.0
- spryker-demo/shop-theme-data-import: ^1.0.0
- spryker-demo/shop-theme-gui: ^1.0.0
- spryker-demo/shop-theme-storage: ^1.0.0
- spryker-demo/shop-theme-widget: ^1.0.0
README
Installation
Install feature
composer require spryker-demo/shop-theme-feature
Add SprykerDemo
namespace to configuration
$config[KernelConstants::CORE_NAMESPACES] = [
'SprykerDemo',
...
];
Adjust environment config with filesystem
# config/Shared/config_default.php
$config[FileSystemConstants::FILESYSTEM_SERVICE] = [
...
'logo' => [
'sprykerAdapterClass' => Aws3v3FilesystemBuilderPlugin::class,
'root' => '',
'path' => 'sc-b2b/yves/logo/',
'key' => getenv('AWS_S3_KEY') ?? '',
'secret' => getenv('AWS_S3_SECRET') ?? '',
'bucket' => 'spryker-scb2b',
'version' => '2006-03-01',
'region' => 'eu-west-2',
],
...
];
# config/Shared/config_default.php
$config[FileSystemConstants::FILESYSTEM_SERVICE] = [
...
'logo' => [
'sprykerAdapterClass' => Aws3v3FilesystemBuilderPlugin::class,
'root' => '',
'path' => 'sc-b2b/yves/logo/',
'key' => getenv('AWS_S3_KEY') ?? '',
'secret' => getenv('AWS_S3_SECRET') ?? '',
'bucket' => 'spryker-scb2b',
'version' => '2006-03-01',
'region' => 'eu-west-2',
],
...
];
Add default theme logo path to the environment config
# config/Shared/config_default.php
$config[ShopThemeConstants::DEFAULT_LOGO_PATH] = getenv('SHOP_THEME_DEFAULT_LOGO_PATH');
Wire filesystem reader, writer and stream plugins
# src/Pyz/Service/FileSystem/FileSystemDependencyProvider.php
use Spryker\Service\FileSystem\FileSystemDependencyProvider as SprykerFileSystemDependencyProvider;
use Spryker\Service\Flysystem\Plugin\FileSystem\FileSystemReaderPlugin;
use Spryker\Service\Flysystem\Plugin\FileSystem\FileSystemStreamPlugin;
use Spryker\Service\Flysystem\Plugin\FileSystem\FileSystemWriterPlugin;
class FileSystemDependencyProvider extends SprykerFileSystemDependencyProvider
{
/**
* @return \Spryker\Service\Flysystem\Plugin\FileSystem\FileSystemReaderPlugin
*/
protected function getFileSystemReaderPlugin(): FileSystemReaderPlugin
{
return new FileSystemReaderPlugin();
}
/**
* @return \Spryker\Service\Flysystem\Plugin\FileSystem\FileSystemWriterPlugin
*/
protected function getFileSystemWriterPlugin(): FileSystemWriterPlugin
{
return new FileSystemWriterPlugin();
}
/**
* @return \Spryker\Service\Flysystem\Plugin\FileSystem\FileSystemStreamPlugin
*/
protected function getFileSystemStreamPlugin(): FileSystemStreamPlugin
{
return new FileSystemStreamPlugin();
}
}
Wire the Aws S3 plugin
# src/Pyz/Service/FlySystem/FlySystemDependencyProvider.php
use SprykerDemo\Service\FlysystemAws3v3FileSystem\Plugin\Flysystem\Aws3v3FilesystemBuilderPlugin;
...
protected function addFilesystemBuilderPluginCollection($container): Container
{
$container->set(static::PLUGIN_COLLECTION_FILESYSTEM_BUILDER, function (Container $container) {
return [
...
new Aws3v3FilesystemBuilderPlugin(),
...
];
});
return $container;
}
Wire the ShopThemeGui plugins
# src/Pyz/Zed/ShopThemeGui/ShopThemeGuiDependencyProvider.php
use Spryker\Zed\StoreGui\Communication\Plugin\Form\StoreRelationDropdownFormTypePlugin;
protected function getAclEntityConfigurationExpanderPlugins(): FormTypeInterface
{
new StoreRelationDropdownFormTypePlugin();
}
Wire the publisher plugins
# src/Pyz/Zed/Publisher/PublisherDependencyProvider.php
use SprykerDemo\Zed\ShopThemeStorage\Communication\Plugin\Publisher\ShopTheme\ShopThemeStorageDeleteByShopThemeStorePublisherPlugin;
use SprykerDemo\Zed\ShopThemeStorage\Communication\Plugin\Publisher\ShopTheme\ShopThemeStorageDeletePublisherPlugin;
use SprykerDemo\Zed\ShopThemeStorage\Communication\Plugin\Publisher\ShopTheme\ShopThemeStorageWriteByThemeStorePublisherPlugin;
use SprykerDemo\Zed\ShopThemeStorage\Communication\Plugin\Publisher\ShopTheme\ShopThemeStorageWritePublisherPlugin;
protected function getPublisherPlugins(): array
{
return array_merge(
...
$this->getShopThemeStoragePlugins(),
);
}
public function getShopThemeStoragePlugins(): array
{
return [
new ShopThemeStorageDeleteByShopThemeStorePublisherPlugin(),
new ShopThemeStorageDeletePublisherPlugin(),
new ShopThemeStorageWriteByThemeStorePublisherPlugin(),
new ShopThemeStorageWritePublisherPlugin(),
];
}
Wire the Acl plugins
# src/Pyz/Zed/AclMerchantPortal/AclMerchantPortalDependencyProvider.php
use SprykerDemo\Zed\ShopTheme\Communication\Plugin\AclMerchantPortal\ShopThemeAclEntityConfigurationExpanderPlugin;
protected function getAclEntityConfigurationExpanderPlugins(): array
{
return [
...
new ShopThemeAclEntityConfigurationExpanderPlugin(),
];
}
Wire the queue plugin
# src/Pyz/Zed/Queue/QueueDependencyProvider.php
use Spryker\Zed\Synchronization\Communication\Plugin\Queue\SynchronizationStorageQueueMessageProcessorPlugin;
use SprykerDemo\Zed\ShopThemeStorage\ShopThemeStorageConfig;
protected function getProcessorMessagePlugins(Container $container): array
{
return [
...
ShopThemeStorageConfig::SHOP_THEME_SYNC_STORAGE_QUEUE => new SynchronizationStorageQueueMessageProcessorPlugin(),
];
}
Wire the synchronization plugin
# src/Pyz/Zed/Synchronization/SynchronizationDependencyProvider.php
use SprykerDemo\Zed\ShopThemeStorage\Communication\Plugin\Synchronization\ShopThemeSynchronizationDataPlugin;
protected function getSynchronizationDataPlugins(): array
{
return [
...
new ShopThemeSynchronizationDataPlugin(),
];
}
Wire the twig extension plugin
# src/Pyz/Zed/Twig/TwigDependencyProvider.php
use SprykerDemo\Zed\ShopThemeGui\Communication\Plugin\Twig\Buttons\Form\BackofficeLogoTwigExtensionPlugin;
use SprykerDemo\Zed\ShopThemeGui\Communication\Plugin\Twig\Buttons\Form\MPLogoTwigExtensionPlugin;
protected function getTwigPlugins(): array
{
return [
...
new BackofficeLogoTwigExtensionPlugin(),
new MPLogoTwigExtensionPlugin(),
];
}
Adjust navigation configuration file
# config/Zed/navigation.xml
<?xml version="1.0"?>
<config>
<administration>
<pages>
...
<shop-theme-gui>
<label>Themes</label>
<title>Themes</title>
<bundle>shop-theme-gui</bundle>
<controller>index</controller>
<action>index</action>
</shop-theme-gui>
</pages>
</administration>
</config>
Adjust RabbitMq configuration
# src/Pyz/Client/RabbitMq/RabbitMqConfig.php
use SprykerDemo\Zed\ShopThemeStorage\ShopThemeStorageConfig;
...
protected function getPyzSynchronizationQueueConfiguration(): array
{
return [
...
ShopThemeStorageConfig::SHOP_THEME_SYNC_STORAGE_QUEUE,
];
}
Apply Twig customization
# src/Pyz/Yves/CheckoutPage/Theme/default/templates/page-layout-checkout/page-layout-checkout.twig
{% block logo %}
<div class="col col--sm-4 text-center">
{% if findWidget('ShopThemeWidget') %}
{% set shopThemeWidget = findWidget('ShopThemeWidget') %}
{% endif %}
{% include molecule('logo') with {
attributes: {
src: shopThemeWidget.data.logoUrl ?? null,
},
} only %}
</div>
{% endblock %}
#src/Pyz/Yves/ShopUi/Theme/default/components/organisms/header/header.twig
{% block logo %}
{% include molecule('logo') with {
class: 'col ' ~ config.name ~ '__logo',
modifiers: ['main'],
} only %}
{% endblock %}
#src/Pyz/Yves/ShopUi/Theme/default/templates/page-layout-main/page-layout-main.twig
{% block headStyles %}
{{ parent() }}
{% if findWidget('ShopThemeWidget') %}
{% widget 'ShopThemeWidget' only %}{% endwidget %}
{% endif %}
{% endblock %}
...
{% block body %}
{% if findWidget('ShopThemeWidget') %}
{% set shopThemeWidget = findWidget('ShopThemeWidget') %}
{% endif %}
...
{% block logo %}
{% include molecule('logo') with {
class: 'col ' ~ config.name ~ '__logo',
modifiers: ['main'],
attributes: {
src: embed.logoSrc,
}
} only %}
{% endblock %}
#src/Pyz/Zed/Gui/Presentation/Partials/menu.twig
{%- macro leaf(node, depth=0) -%}
{%- import _self as menu -%}
{%- if node is defined %}
{%- if menu_highlight is defined -%}
{%- if menu_highlight == node.uri -%}
<li class="item active">
{%- else -%}
<li class="item">
{%- endif -%}
{%- else-%}
<li class="item{{ node.is_active is defined and node.is_active ? " active" : "" }}">
{%- endif -%}
<a href="{{ node.uri }}"{% if node.shortcut is defined %} data-hotkey="{{ node.shortcut }}"{% endif %}>
{{ menu.getNodeIcon(node) }}
<span class="nav-label">{{ node.label | trans }}</span>
</a>
</li>
{% endif -%}
{%- endmacro -%}
{%- macro branch(node, depth=0) -%}
{%- import _self as menu -%}
{%- if node is defined %}
<li class="{{ node.is_active is defined and node.is_active ? " active" : "" }}">
<a href="javascript:void(0)">
{{ menu.getNodeIcon(node) }}
<span class="nav-label">{{ node.label | trans }}</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level collapse">
{{ menu.tree(node.children, (depth + 1)) }}
</ul>
</li>
{% endif -%}
{%- endmacro -%}
{%- macro tree(root) -%}
{%- import _self as menu -%}
{%- for child in root -%}
{%- if child.children is defined and child.children is not empty -%}
{{ menu.branch(child, 0) }}
{%- else -%}
{{ menu.leaf(child, 0) }}
{%- endif -%}
{%- endfor -%}
{%- endmacro -%}
{%- macro getNodeIcon(node) -%}
{%- set defaultIcon = 'fa-angle-double-right' -%}
{%- if node.icon is defined and node.icon != '' -%}
<i class="fa {{ node.icon }}"></i>
{%- else -%}
<i class="fa {{ defaultIcon }}"></i>
{%- endif -%}
{%- endmacro -%}
{%- import _self as menu -%}
<nav class="navbar-default navbar-static-side" role="navigation">
<div class="sidebar-collapse">
<ul tabindex="0" class="nav metismenu" id="side-menu">
<li class="nav-header">
<div class="dropdown profile-element">
{{ backofficeLogo() }}
<ul class="dropdown-menu animated fadeInRight m-t-xs">
<li><a href="/auth/logout">{{ 'Logout' | trans }}</a></li>
</ul>
</div>
<div class="logo-element">
SP
</div>
</li>
{{ menu.tree(navigation.menu) }}
</ul>
</div>
</nav>
#src/Pyz/Zed/SecurityGui/Presentation/Layout/layout.twig
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block head_title %}{% if title is defined %}{{ title | trans }}{% endif %}{% endblock %}</title>
{% block head_css %}
<link rel="stylesheet" href="{{ assetsPath('css/spryker-zed-gui-commons.css') }}">
<link href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700;900&family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
{% endblock %}
</head>
<body class="login">
<div class="login__wrapper">
<div class="login__container">
{{ backofficeLogo('login__logo') }}
{% include '@Messenger/Partials/flash-messages.twig' %}
<div class="login-box">
{% block login_heading %}
<div class="login-box__heading">
<h1 class="login-box__title">{{ 'Login' | trans }}</h1>
</div>
{% endblock %}
<div class="login-box__content">
{% block content %}{% endblock %}
</div>
</div>
</div>
</div>
{% block footer_js %}
<script src="{{ assetsPath('js/spryker-zed-gui-commons.js') }}"></script>
{% endblock %}
</body>
</html>
#src/Pyz/Zed/ZedUi/Presentation/Layout/merchant-layout-centered.twig
{% extends '@ZedUi/Layout/merchant-layout.twig' %}
{% block body %}
{{ mpLogo() }}
<web-mp-merchant-layout-centered cloak>
{% block content %}{% endblock %}
{% block footer %}
<span footer>Copyright Spryker Systems GmbH © {{ 'now' | date('Y') }}</span>
{% endblock %}
</web-mp-merchant-layout-centered>
{% endblock %}
#src/Pyz/Zed/ZedUi/Presentation/Layout/merchant-layout-main.twig
{% extends '@ZedUi/Layout/merchant-layout.twig' %}
{% block body %}
{{ mpLogo() }}
{% if app.twig.getFunction('navigation') != false %}
{% set navigationConfig = render_navigation_component_config(navigation('main').menu) %}
{% set userMenuNavigationItems = navigation('secondary').menu %}
{% block merchantLayoutMain %}
<web-mp-merchant-layout-main cloak navigation-config="{{ navigationConfig }}">
{% block logo %}
<web-spy-logo cloak logo></web-spy-logo>
{% endblock %}
{% block header %}
<header header>
{% block headerMenu %}
<web-mp-header-menu cloak menu>
{% block infoPrimary %}
{% if username is not empty %}
<span info-primary>{{ username }}</span>
{% endif %}
{% endblock %}
{% block infoSecondary %}
{% if userEmail is not empty %}
<span info-secondary>{{ userEmail }}</span>
{% endif %}
{% endblock %}
{% block userMenuList %}
{% for userMenuNavigationItem in userMenuNavigationItems %}
{% block userMenuLink %}
<a href="{{ userMenuNavigationItem.uri }}" class="user-menu-link">
{% block userMenuLinkInner %}
{{ userMenuNavigationItem.title }}
{% endblock %}
</a>
{% endblock %}
{% endfor %}
{% block logoutLink %}
<a href="/security-merchant-portal-gui/logout" class="user-menu-link user-menu-link--danger">
{% block logoutLinkInner %}
{{ 'Logout' | trans }}
{% endblock %}
</a>
{% endblock %}
{% endblock %}
</web-mp-header-menu>
{% endblock %}
</header>
{% endblock %}
{% block flashMessages %}
{% include '@ZedUi/Partials/FlashMessages/flash-messages.twig' %}
{% endblock %}
{% block content %}{% endblock %}
</web-mp-merchant-layout-main>
{% endblock %}
{% endif %}
{% endblock %}
Add behaviors to the database definition schemas
#src/Pyz/Zed/ShopTheme/Persistence/Propel/Schema/spy_shop_theme.schema.xml
<?xml version="1.0"?>
<database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="zed"
xsi:noNamespaceSchemaLocation="http://static.spryker.com/schema-01.xsd"
namespace="Orm\Zed\ShopTheme\Persistence"
package="src.Orm.Zed.ShopTheme.Persistence">
<table name="spy_shop_theme">
<behavior name="event">
<parameter name="spy_shop_theme_all" column="*"/>
</behavior>
</table>
<table name="spy_shop_theme_store">
<behavior name="event">
<parameter name="spy_shop_theme_store_all" column="*"/>
</behavior>
</table>
</database>