How to get the data from PHP to the Twig template
Shopware 6 uses Twig template engine to render the pages. It is surprisingly simple and flexible, once you get the hang of it. Programmers like me, who usually work with the PHP part of Shopware 6, will mostly need one thing: to make variables from PHP available to the Twig templates. This article will describe exactly that.
Dumping the variables in Twig
First of all, we need to have a way to detect, if our PHP variable was passed to the Twig template. This is super easy, we just need to put the ‘dump’ command somewhere in out template like this:
1 2 3 4 |
{% block base_content %} <p>Dump the variables!</p> {{ dump() }} {% endblock %} |
And this is the result:
You can browse through the dump by clicking on the triangles, which will reveal the deeper structure. You can also press Ctrl + F to search through the dump and the searched term will be highlighted. Neat!
If you want to dump just one variable, you can use the same syntax, that the Twig template engine uses for accessing the variables. For example, if you want to display juste the value of the variable ‘currencyFactor’, you can do it like this:
1 2 3 4 |
{% block base_content %} <p>Dump the variables!</p> {{ dump( context.context.currencyFactor ) }} {% endblock %} |
And the result looks like this then:
Now, that we know, how to display the variables, available to Twig, we can pass it our own custom variables.
Passing variables from a storefront controller to a Twig template
Storefront controllers are the usual way, how to create our own custom pages on our own custom URLs. The following example demonstrates a storefront page on a URL address {your-store}/test, that gets rendered by TestController, using a Twig template index.html.twig.
The controller (path – custom/plugins/TestPlugin/src/Controller/TestController.php):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?php namespace TestPlugin\Storefront\Controller; use Shopware\Core\Framework\Routing\Annotation\RouteScope; use Shopware\Core\System\SalesChannel\SalesChannelContext; use Shopware\Storefront\Controller\StorefrontController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; /** * @RouteScope(scopes={"storefront"}) */ class TestController extends StorefrontController { /** * @Route("/test", name="frontend.testplugin.test", methods={"GET"}) */ public function showPage(Request $request, SalesChannelContext $context): Response { return $this->renderStorefront('@TestPlugin/storefront/page/test/index.html.twig', [ 'customString' => 'Custom string value', 'customArray' => [ 'key1' => 'Value 1', 'key2' => 'Value 2' ] ]); } } |
The Twig template (path – custom/plugins/TestPlugin/src/Resources/views/storefront/page/test/index.html.twig):
1 2 3 4 5 6 7 8 9 10 11 12 |
{% sw_extends '@Storefront/storefront/base.html.twig' %} {% block base_content %} <p>Dump the string!</p> {{ dump( customString ) }} <p>Dump the array!</p> {{ dump( customArray ) }} <p>Dump the value of key1 of the array!</p> {{ dump( customArray.key1 ) }} {% endblock %} |
The routes.xml file (path – custom/plugins/TestPlugin/src/Resources/config/routes.xml):
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> <import resource="../../Storefront/Controller/**/*Controller.php" type="annotation" /> </routes> |
The result of this, shown on the URL address {your-store}/test, looks like this:
As you can see in the example above, you can pass multiple variables from your PHP controller to your Twig template very easily. You can inject any PHP class to your storefront controllers, including repositories, so you can probably imagine, that you could pass basically anything from the Shopware 6 universe to your custom frontend page like this.
Passing variables to a Twig template using the extensions
Your own custom frontend pages probably will not be the only place, where you will want to use some custom variables. For instance, you might want to add some custom information to the product detail page. That actually looks like a good use case. So let us see, how can we pass the variables from PHP to Twig from a subscriber, hooked up to the ProductPageLoadedEvent. As the name suggests, this event is triggered, when the product detail page is loaded and allows us to prepare some stuff, before it gets displayed to the customer. Here is the code for our subscriber:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<?php namespace TestPlugin\Subscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Shopware\Storefront\Page\Product\ProductPageLoadedEvent; use Shopware\Core\Framework\Struct\ArrayEntity; class Subscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ ProductPageLoadedEvent::class => 'onProductPageLoaded' ]; } public function onProductPageLoaded (ProductPageLoadedEvent $event) { //declare an array $array = ['key1' => 'Value 1', 'key2' => [ 'subKey1' => 'subValue 1'] ]; //assign the array to the page $event->getPage()->assign($array); //add the array to the page as an extension $event->getPage()->addExtension('testPageExtension', new ArrayEntity($array)); //assign the array to the context $event->getContext()->assign($array); //add the array to the context as an extension $event->getContext()->addExtension('testContextExtension', new ArrayEntity($array)); } } |
In the code above, I have declared an array and then used multiple ways of passing it to the Twig template on your Shopware 6 store. Now let us see, how can we retrieve those values in the template, using the ‘dump’ method. For this, we will need the template file, that is responsible for displaying the product detail page. Most likely, it will be located in custom/plugins/{your-theme}/src/Resources/views/storefront/page/product-detail/index.html.twig directory and extending the core product-base.html.twig template.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{% sw_extends '@Storefront/storefront/product-base.html.twig' %} {% block base_head %} {% sw_include '@Storefront/storefront/page/product-detail/meta.html.twig' %} {% endblock %} {% block base_content %} {% block page_product_detail %} {{ dump( page ) }} {{ dump( page.extensions.testPageExtension['key1'] ) }} {{ dump( context.context ) }} {{ dump( context.context.extensions.testContextExtension['key2'] ) }} ... |
And this is how the result looks on the product detail page:
The methods, that I have shown in the example above, are all valid and work well in Shopware 6. In the end, it depends on your personal preference, which one will you use. In simpler cases, it should be just fine to use ‘assign’. Personally, I use the ‘extension’ method on the context most of the time. Mainly because it can hold more complex structures than the ‘assign’ method. The addExtension method expects an object, based on the core class Shopware\Core\Framework\Struct\Struct. It may seem overcomplicated at first, when most of the time, you just need a string or an array anyway. But as you could see in the example, you can pass an array very easily, using the ArrayEntity, which extends the Struct. If you want, you could create a new class youself, extending the core Struct and containing multiple values, like this:
1 2 3 4 |
class StructForTwig extends \Shopware\Core\Framework\Struct\Struct { public $content = []; public $additionalContent = []; } |
So these were the methods, that I use, when I need to pass variables from PHP classes to the Twig templates in Shopware 6. I hope this will help some people, who are struggling with this topic. Do you know of other methods, how to pass the variables? If yes, then please describe them here in the comments or send them to me and I will update the article. In any case, have fun with PHP and Twig in Shopware 6! 🙂
Hello nice works
If you have time replace the wrong path and file name
from
{% sw_extends ‘@Storefront/storefront/product-base.html.twig’ %}
to
{% sw_extends ‘@Storefront/storefront/page/product-detail/index.html.twig’ %}
Cheers
Hi, the path and file name in the example is not really wrong in my opinion, because it works like that (tested on Shopware 6.3.5). So for demonstration purposes, it is good enough. But you are right, usually it is best to extend the most ‘deep’ template, which would be the one you mentioned.