Code blocks
Code blocks start with three backticks and the language. Each block has a copy button in the top right corner.
Languages
<?php declare(strict_types=1);
namespace Gambit24\DarstellungsBeispiel\Subscriber;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class ProductPageSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [ProductPageLoadedEvent::class => 'onProductPageLoaded'];
}
public function onProductPageLoaded(ProductPageLoadedEvent $event): void
{
// Load the notice and attach it to the page
}
}
// Administration: override a component
Shopware.Component.override('sw-product-detail-base', {
template,
computed: {
noticeRepository() {
return this.repositoryFactory.create('gb_notice');
},
},
});
export interface Notice {
id: string;
text: string;
validFrom: string | null;
validUntil: string | null;
}
{% sw_extends '@Storefront/storefront/page/product-detail/buy-widget.html.twig' %}
{% block page_product_detail_buy_container %}
{{ parent() }}
{% block gb_notice %}
<div class="gb-notice">{{ page.extensions.gbNotice.text }}</div>
{% endblock %}
{% endblock %}
.gb-notice {
padding: $spacer-sm;
border-left: 4px solid $sw-color-brand-primary;
}
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services">
<services>
<service id="Gambit24\DarstellungsBeispiel\Subscriber\ProductPageSubscriber">
<tag name="kernel.event_subscriber"/>
</service>
</services>
</container>
{
"id": "0190a1b2c3d4e5f6a7b8c9d0e1f2a3b4",
"text": "Versand nur innerhalb Deutschlands.",
"validFrom": null
}
gb_notice:
default_position: below_price
cache_ttl: 3600
SELECT LOWER(HEX(id)) AS id, text
FROM gb_notice
WHERE valid_from IS NULL OR valid_from <= NOW();
bin/console plugin:install --activate GbmsDarstellungsBeispiel
bin/console cache:clear
- $notice = $this->repository->search($criteria, $context)->first();
+ $notice = $this->noticeLoader->load($productId, $context);
Plain text without highlighting, e.g. for log output:
[2026-10-24 12:00:00] app.ERROR: Notice not found {"productId":"..."}
Twig is currently shown without colours, but the code stays readable and copyable.
Title
src/Resources/config/services.php
return static function (ContainerConfigurator $container): void {
$container->services()->defaults()->autowire()->autoconfigure();
};
Highlighting lines
Using line numbers in curly brackets:
public function onProductPageLoaded(ProductPageLoadedEvent $event): void
{
$notice = $this->noticeLoader->load($event->getPage()->getProduct()->getId(), $event->getSalesChannelContext());
$event->getPage()->addExtension('gbNotice', $notice);
}
Or with comments directly in the code:
const position = config.position ?? 'below_price';
const notice = await loadNotice(productId);
if (!notice) {
return null;
}
render(notice, position);
Line numbers
public function load(string $productId, SalesChannelContext $context): ?NoticeStruct
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('productId', $productId));
return $this->repository->search($criteria, $context->getContext())->first();
}
Title, highlighting and line numbers can be combined:
NoticeLoader.php
public function load(string $productId): ?NoticeStruct
{
return $this->cache->get($productId);
}
Inline-Code
The NoticeLoader service is available under the ID Gambit24\DarstellungsBeispiel\Service\NoticeLoader. Configuration values live under GbmsDarstellungsBeispiel.config.position.
Long lines
Long lines are not wrapped but scroll horizontally:
$criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [new EqualsFilter('validFrom', null), new RangeFilter('validFrom', [RangeFilter::LTE => (new \DateTimeImmutable())->format(Defaults::STORAGE_DATE_TIME_FORMAT)])]));