Shopware 6.7 introduces significant enhancements to its commerce platform, particularly in the realm of storefront customization and content management. One of the most powerful features available to developers is the ability to create custom CMS blocks that extend the functionality of the Shopware storefront. This blog post will guide you through the technical implementation of creating a custom CMS block from scratch.
Understanding CMS Blocks in Shopware 6.7
CMS blocks in Shopware 6.7 are the building blocks of content management within the platform. They provide a flexible way to create reusable content components that can be added to product pages, category pages, and landing pages. The new version introduces improved developer APIs and better integration with the existing storefront architecture.
A CMS block consists of three main components:
- Block definition - Defines the structure and configuration options
- Frontend template - Handles the presentation layer
- Backend configuration - Manages the admin interface
Setting Up the Custom Module Structure
To create a custom CMS block, we first need to establish our module structure. The recommended approach is to create a custom plugin that extends Shopware's functionality.
<?php declare(strict_types=1);
namespace YourPluginName;
use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\ActivateContext;
use Shopware\Core\Framework\Plugin\Context\DeactivateContext;
use Shopware\Core\Framework\Plugin\Context\InstallContext;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;
class YourPluginName extends Plugin
{
public function install(InstallContext $context): void
{
parent::install($context);
}
public function activate(ActivateContext $context): void
{
parent::activate($context);
}
public function deactivate(DeactivateContext $context): void
{
parent::deactivate($context);
}
public function uninstall(UninstallContext $context): void
{
parent::uninstall($context);
}
}
Creating the CMS Block Definition
The heart of any custom CMS block lies in its definition file. This file describes the block's properties, available configuration options, and how it should be rendered.
{
"name": "custom-product-slider",
"label": "Custom Product Slider",
"component": "sw-cms-block-custom-product-slider",
"previewComponent": "sw-cms-preview-custom-product-slider",
"defaultConfig": {
"title": {
"value": "Featured Products",
"source": "static"
},
"productCount": {
"value": 4,
"source": "static"
}
},
"config": {
"title": {
"type": "text",
"label": "Title",
"source": "static"
},
"productCount": {
"type": "number",
"label": "Number of Products",
"source": "static"
}
},
"slots": {
"products": {
"type": "product-listing",
"default": {
"entity": "product",
"criteria": {
"limit": 4
}
}
}
}
}
Implementing the Frontend Component
The frontend component is written in Vue.js and handles the rendering of our custom CMS block. In Shopware 6.7, the component structure has been enhanced to provide better performance and easier integration.
<template>
<div class="custom-product-slider">
<h2>{{ config.title }}</h2>
<div class="product-grid">
<div
v-for="product in products"
:key="product.id"
class="product-card"
>
<img
:src="product.cover.url"
:alt="product.name"
class="product-image"
/>
<h3>{{ product.name }}</h3>
<p class="price">{{ product.price.totalPrice }}</p>
</div>
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'CustomProductSlider',
props: {
config: {
type: Object,
required: true
},
products: {
type: Array,
required: true
}
}
});
</script>
<style scoped>
.custom-product-slider {
padding: 20px;
}
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-top: 20px;
}
.product-card {
border: 1px solid #ddd;
padding: 15px;
border-radius: 8px;
text-align: center;
}
.product-image {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 4px;
}
</style>
Backend Configuration and Admin Interface
The backend configuration allows content editors to customize the block through the Shopware administration panel. In version 6.7, this interface has been significantly improved with better component integration.
// src/Administration/Resources/app/administration/src/module/sw-cms/elements/custom-product-slider/component.js
import { Component } from 'vue';
Component.register('sw-cms-block-custom-product-slider', {
template: `
<div class="sw-cms-block-custom-product-slider">
<h2>{{ config.title }}</h2>
<div class="product-grid">
<div v-for="product in products" :key="product.id" class="product-card">
<img :src="product.cover.url" :alt="product.name" />
<h3>{{ product.name }}</h3>
<p>{{ product.price.totalPrice }}</p>
</div>
</div>
</div>
`,
props: {
config: {
type: Object,
required: true
},
products: {
type: Array,
default: () => []
}
}
});
Data Fetching and Integration
In Shopware 6.7, the data fetching mechanism has been optimized to provide better performance and more reliable integration with existing systems.
<?php declare(strict_types=1);
namespace YourPluginName\Cms;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
class ProductSliderService
{
public function getFeaturedProducts(int $limit, SalesChannelContext $context): array
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('product.isFeatured', true));
$criteria->setLimit($limit);
$criteria->addSorting(new FieldSorting('product.createdAt', FieldSorting::DESCENDING));
// Implementation for fetching products based on criteria
return [];
}
}
Performance Optimization Considerations
When implementing custom CMS blocks, performance optimization becomes crucial. Shopware 6.7 introduces several mechanisms to help with this:
- Caching strategies: Implement proper cache keys and invalidation patterns
- Lazy loading: Load components only when needed
- Resource management: Efficiently handle image loading and resource usage
// Optimized component with caching and lazy loading
export default defineComponent({
name: 'OptimizedProductSlider',
props: {
config: {
type: Object,
required: true
},
products: {
type: Array,
required: true
}
},
data() {
return {
cachedProducts: null,
isLoading: false
};
},
watch: {
'config.productCount'() {
this.fetchProducts();
}
},
async mounted() {
if (!this.cachedProducts) {
await this.fetchProducts();
}
},
methods: {
async fetchProducts() {
this.isLoading = true;
try {
// Fetch logic here
this.cachedProducts = await this.fetchFromAPI();
} finally {
this.isLoading = false;
}
}
}
});
Integration with Existing Storefront Architecture
The custom CMS block must seamlessly integrate with Shopware's existing storefront architecture. This includes proper routing, context handling, and integration with existing components.
// Route configuration for the CMS block
const routes = [
{
name: 'cms.block.custom-product-slider',
path: '/cms/block/custom-product-slider',
component: 'CustomProductSliderComponent'
}
];
Testing and Validation
Proper testing is essential for custom CMS blocks. Shopware 6.7 provides enhanced testing capabilities including:
- Unit tests for component logic
- Integration tests for data fetching
- End-to-end tests for admin interface interactions
// Example test case
describe('CustomProductSlider Component', () => {
it('should render products correctly', () => {
const wrapper = mount(CustomProductSlider, {
props: {
config: { title: 'Test Slider' },
products: [
{ id: 1, name: 'Product 1', price: { totalPrice: '$100' } }
]
}
});
expect(wrapper.find('h2').text()).toBe('Test Slider');
});
});
Deployment and Maintenance
Once developed, the custom CMS block should be properly deployed and maintained. Shopware 6.7's plugin system makes this straightforward with clear upgrade paths and version management.
The implementation of custom CMS blocks in Shopware 6.7 represents a significant advancement in platform flexibility and developer capabilities. By following these technical guidelines, developers can create robust, performant, and maintainable custom content components that enhance the shopping experience while maintaining compatibility with the broader Shopware ecosystem.
This approach not only leverages the latest improvements in Shopware 6.7 but also ensures that custom implementations are future-proof and adhere to best practices for modern e-commerce development.