Shopware 6技术咨询:如何在自定义插件中添加并渲染产品/产品列表
Shopware 6 自定义插件传递并渲染产品/产品列表步骤
1. 通过服务层封装产品数据获取逻辑
Shopware 6 内置了产品仓库接口,我们可以通过依赖注入来复用它,先在插件的 src/Resources/config/services.xml 中定义服务:
<service id="YourPluginName\Service\ProductService"> <argument type="service" id="product.repository"/> </service>
然后创建对应的服务类 src/Service/ProductService.php,封装单个产品和列表的获取方法:
<?php namespace YourPluginName\Service; use Shopware\Core\Content\Product\ProductRepositoryInterface; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter; use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting; class ProductService { private ProductRepositoryInterface $productRepository; public function __construct(ProductRepositoryInterface $productRepository) { $this->productRepository = $productRepository; } // 获取单个产品(支持关联价格、媒体等字段) public function getSingleProduct(string $productId, Context $context) { $criteria = new Criteria([$productId]); $criteria->addAssociation('price'); $criteria->addAssociation('media'); return $this->productRepository->search($criteria, $context)->first(); } // 获取上架产品列表(可自定义数量、排序、过滤条件) public function getProductList(Context $context, int $limit = 10) { $criteria = new Criteria(); $criteria->setLimit($limit); $criteria->addFilter(new EqualsFilter('active', true)); $criteria->addSorting(new FieldSorting('createdAt', 'DESC')); return $this->productRepository->search($criteria, $context)->getEntities(); } }
2. 控制器中传递数据到模板
创建自定义控制器 src/Controller/CustomProductController.php,注入上面的服务并定义路由,将产品数据传递给模板:
<?php namespace YourPluginName\Controller; use YourPluginName\Service\ProductService; use Shopware\Core\Framework\Context; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; #[Route(defaults: ['_routeScope' => ['storefront']])] class CustomProductController extends AbstractController { private ProductService $productService; public function __construct(ProductService $productService) { $this->productService = $productService; } // 单个产品页面路由 #[Route(path: '/custom-product/{productId}', name: 'frontend.custom.single.product', methods: ['GET'])] public function singleProduct(string $productId, Context $context): Response { $product = $this->productService->getSingleProduct($productId, $context); return $this->render('@YourPluginName/storefront/page/custom-product/single.html.twig', [ 'product' => $product ]); } // 产品列表页面路由 #[Route(path: '/custom-products', name: 'frontend.custom.product.list', methods: ['GET'])] public function productList(Context $context): Response { $products = $this->productService->getProductList($context); return $this->render('@YourPluginName/storefront/page/custom-product/list.html.twig', [ 'products' => $products ]); } }
3. Twig模板渲染数据
单个产品模板 src/Resources/views/storefront/page/custom-product/single.html.twig
{% extends '@Storefront/storefront/base.html.twig' %} {% block page_content %} <div class="custom-product-container"> {% if product %} <h2 class="product-title">{{ product.translated.name }}</h2> <div class="product-description">{{ product.translated.description|raw }}</div> <div class="product-price"> {{ product.price.first.gross|currency(product.price.first.currencyId) }} </div> {% if product.media.first %} <img src="{{ product.media.first.url }}" alt="{{ product.media.first.translated.alt ?: product.translated.name }}" class="product-image" > {% endif %} {% else %} <div class="alert alert-warning">该产品不存在或已下架</div> {% endif %} </div> {% endblock %}
产品列表模板 src/Resources/views/storefront/page/custom-product/list.html.twig
{% extends '@Storefront/storefront/base.html.twig' %} {% block page_content %} <div class="custom-product-list"> <h2 class="list-title">自定义产品列表</h2> <div class="row"> {% for product in products %} <div class="col-md-4 col-sm-6 mb-4"> <div class="product-card"> {% if product.media.first %} <img src="{{ product.media.first.url }}" alt="{{ product.media.first.translated.alt ?: product.translated.name }}" class="card-img-top" > {% endif %} <div class="card-body"> <h5 class="card-title">{{ product.translated.name }}</h5> <p class="card-text">{{ product.translated.description|slice(0, 120) }}...</p> <div class="card-price"> {{ product.price.first.gross|currency(product.price.first.currencyId) }} </div> <a href="{{ path('frontend.detail.page', { productId: product.id }) }}" class="btn btn-primary" > 查看详情 </a> </div> </div> </div> {% else %} <div class="col-12"> <div class="alert alert-info">暂无上架产品</div> </div> {% endfor %} </div> </div> {% endblock %}
4. 验证测试
- 清除Shopware缓存:在项目根目录执行
bin/console cache:clear - 激活插件(若未激活):
bin/console plugin:refresh→bin/console plugin:activate YourPluginName - 访问单个产品页面:替换实际产品ID后访问
https://你的店铺域名/custom-product/xxxxxx - 访问产品列表页面:
https://你的店铺域名/custom-products
内容的提问来源于stack exchange,提问作者NewbieCoder
相关产品推荐
相关产品推荐

