First, we create a controller in our custom plugin:
There are two ways to use repository in controller:
- 1. Using container of current controller
- 2. By sending the repository from services.xml file.
/custom/plugins/PluginName/src/Controller
<?php declare(strict_types=1); namespace PluginName\Controller; use Shopware\Core\Content\Cms\Exception\PageNotFoundException; use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageLoaderInterface; use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Shopware\Core\Framework\Routing\Annotation\RouteScope; use Shopware\Core\System\SalesChannel\SalesChannelContext; use Shopware\Storefront\Controller\StorefrontController; use Shopware\Storefront\Framework\Cache\Annotation\HttpCache; use Shopware\Storefront\Page\Navigation\NavigationPage; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter; /** * @RouteScope(scopes={"storefront"}) */ class ProductController extends StorefrontController { private $productCategoryRepository; /** * @var EntityRepositoryInterface */ private $productRepository; public function __construct(EntityRepositoryInterface $productRepository) { $this->productRepository= $productRepository; } /** * @HttpCache() * @Route("/products", name="frontend.products.detail", methods={"GET"}) */ public function detailAction(Request $request, SalesChannelContext $context, Context $con): Response { $criteria1 = new Criteria(); $criteria1->addAssociations(['media', 'properties', 'properties.group', 'unit', 'tax']); // using reference of repository sent from services.xml $products = $this->productRepository->search($criteria1, $con)->getEntities(); $productIds; foreach($products as $key => $p){ foreach($p as $k => $pr){ $productIds[] = $pr; } } // using current class reference controller $this->productPriceRepository = $this->container->get('product_price.repository'); $criteria2 = new Criteria(); $productPrice = $this->productPriceRepository->search($criteria2, $con); return $this->renderStorefront('@Storefront/storefront/page/content/index.html.twig', [ 'products' => $products, 'productPrice' => $productPrice, ]); } }
Then you need to create routes.xml file:
/custom/plugins/PluginName/src/Resources/config/routes.xml
<?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="../../Controller" type="annotation" /> </routes>
Then Next you need to create services.xml
/custom/plugins/PluginName/src/Resources/config/services.xml
<?xml version="1.0" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="PluginName\Controller\ProductController" public="true"> <argument type="service" id="product.repository"/> <call method="setContainer"> <argument type="service" id="service_container"/> </call> </service> </services> </container>
Here I am creating two pages to show the product data on html.twig file
custom/plugins/PluginName/src/Resources/views/storefront/page/content/index.html.twig
{% sw_extends '@Storefront/storefront/page/content/index.html.twig' %} {% block base_main_inner %} <div class="container-main"> {% block page_content %} {% block cms_content %} <div class="cms-page"> {% block page_content_blocks %} {% sw_include "@Storefront/storefront/page/content/product_detail.html.twig" %} {% endblock %} </div> {% endblock %} {% endblock %} </div> {% endblock %}
custom/plugins/PluginName/src/Resources/views/storefront/page/content/product_detail.html.twig
This code will show the Product detail on the page I have only 3 products you can show more products according to your need:
<div class="cms-block product-listing-part pos-1 cms-block-product-three-column section-products" style=""> <div class="cms-block-container" style="padding: 20px 20px 20px 20px;"> <div class="cms-block-container-row row cms-row "> {% set i = 0 %} {% for product in products %} {% if i <= 2 %} {% set i = (i+1) %} <div class="col-md-4 card-col" data-cms-element-id="d3c7873569b844239e5756f6a89c1f7f"> <div class="cms-element-product-box"> <div class="card product-box box-minimal"> <div class="card-body"> <div class="product-badges"></div> <meta content=""> <meta content="SW10011"> <div class="product-image-wrapper"> <a href="{{ seoUrl('frontend.detail.page', {'productId': product.id}) }}" title="AIX Rosé Copy" class="product-image-link is-standard" "=""> {% for element in product.media.elements %} {% if element.id == product.coverId %} <img src="{{element.media.url}}" class="product-image is-standard" alt="{{product.translated.name}}" title="{{product.translated.name}}"> {%endif%} {% endfor %} </a> </div> <div class="product-info"> <span class="product-subtext"> {% set comma = null %}{% for element in product.properties.elements %}{{(comma ~ ' ' ~ element.translated.name)|trim|trans}}{% set comma=','%}{% endfor %} </span> <a href="{{ seoUrl('frontend.detail.page', {'productId': product.id}) }}" class="product-name" title="{{product.translated.name}}">{{product.translated.name}}</a> <div class="product-price-info"> <div class="product-price-wrapper"> <span class="product-price"> {% set listPrice = 0 %} {% for element in product.cheapestPrice.price.elements %} {% if element.listPrice != null %} {{element.listPrice.net|currency}}{{ "general.star"|trans|sw_sanitize }} {% set listPrice = element.listPrice.net %} {%endif%} {% endfor %} </span> </div> <br> <p class="product-price-unit"> <span class="price-unit-content"> {{product.purchaseUnit}} {{product.unit.translated.name}} {# for element in product.cheapestPriceContainer.value #} {#element.default.purchase_unit#} {# endfor #} </span> <span class="price-unit-reference"> {% set pricePerUnit = (((listPrice/product.purchaseUnit)*product.referenceUnit)|number_format(2))*1 %} ({{pricePerUnit|currency }} {{ "general.star"|trans|sw_sanitize }} / {{product.referenceUnit}} {{product.unit.translated.name}}) </span> <br> {% set taxText = "general.grossTaxInformation"|trans|sw_sanitize %} {% if taxText == null or taxText == ''%} {% set taxText = "general.netTaxInformation"|trans|sw_sanitize %} {% endif %} <span class="product-detail-tax"> {{taxText}} </span> </p> </div> <input type="hidden" name="product-name" value="{{product.translated.name}}"> <input type="hidden" name="product-id" value="{{product.id}}"> </div> </div> </div> </div> </div> {% endif %} {% endfor %} </div> </div> </div>