在我们之前的一篇博客中我们学习了如何创建一个小部件。现在我们将看到如何创建一个自定义的甚至更好的,如何扩展核心的。在本篇博客中,我选择了默认的产品列表小部件,我将使用排序字段对其进行扩展,以便更好地自定义此小部件。

 

模块设置

首先,我们需要创建一个新模块。新模块要求的名称和模块文件夹是模块文件夹内的registration.phpetc/module.xml对于此示例,我将使用Magease作为名称,使用CatalogWidget作为模块名称

registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Magease_CatalogWidget',
    __DIR__
);

etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magease_CatalogWidget" setup_version="1.0.0" >
        <sequence>
            <module name="Magento_CatalogWidget"/>
        </sequence>
    </module>
</config>

 

自定义代码

首先,我们将创建与扩展小部件中使用的工具几乎相同的小部件配置。我们通过在etc文件夹中创建widget.xml文件来实现这一点除了标签和描述的变化,有两个额外的参数collection_sort_bycollection_sort_order,稍后我们将使用这两个参数对产品集合进行排序。参数类型是select,它们使用我们将在下面步骤中创建的自定义源模型。其他区别是容器节点(我将在后面解释)和模板参数选项我添加了自己的模板选项和名称top_products这将是我们自己的自定义模板,以便按照我们想要的方式呈现产品列表。最后但并非最不重要的是自定义小部件占位符图像。我们将把它放在view/adminhtml/web/images/magease_widget_block.png。

etc/widget.xml

<?xml version="1.0" encoding="UTF-8"?>
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
    <widget id="magease_products_list" class="Magease\CatalogWidget\Block\Product\ProductsList"
            placeholder_image="Magease_CatalogWidget::images/magease_widget_block.png">
        <label translate="true">Magease Catalog Products List</label>
        <description>Magease - Extended Catalog Products List</description>
        <parameters>
            <parameter name="title" xsi:type="text" required="false" visible="true">
                <label translate="true">Title</label>
            </parameter>
            <parameter name="collection_sort_by" xsi:type="select" visible="true"
                       source_model="Magease\CatalogWidget\Model\Config\Source\SortBy">
                <label translate="true">Sort Collection By</label>
            </parameter>
            <parameter name="collection_sort_order" xsi:type="select" visible="true"
                       source_model="Magease\CatalogWidget\Model\Config\Source\SortOrder">
                <label translate="true">Sort Collection Order</label></parameter>
            <parameter name="show_pager" xsi:type="select" visible="true"
                       source_model="Magento\Config\Model\Config\Source\Yesno">
                <label translate="true">Display Page Control</label>
            </parameter>
            <parameter name="products_per_page" xsi:type="text" required="true" visible="true">
                <label translate="true">Number of Products per Page</label>
                <depends>
                    <parameter name="show_pager" value="1" />
                </depends>
                <value>5</value>
            </parameter>
            <parameter name="products_count" xsi:type="text" required="true" visible="true">
                <label translate="true">Number of Products to Display</label>
                <value>10</value>
            </parameter>
            <parameter name="template" xsi:type="select" required="true" visible="true">
                <label translate="true">Template</label>
                <options>
                    <option name="default" value="Magento_CatalogWidget::product/widget/content/grid.phtml" selected="true">
                        <label translate="true">Products Grid Template</label>
                    </option>
                    <option name="top_products" value="Magease_CatalogWidget::product/widget/content/top_products.phtml">
                        <label translate="true">Top Products Template</label>
                    </option>
                </options>
            </parameter>
            <parameter name="cache_lifetime" xsi:type="text" visible="true">
                <label translate="true">Cache Lifetime (Seconds)</label>
                <description translate="true">86400 by default, if not set. To refresh instantly, clear the Blocks HTML Output cache.</description>
            </parameter>
            <parameter name="condition" xsi:type="conditions" visible="true" required="true" sort_order="10"
                       class="Magento\CatalogWidget\Block\Product\Widget\Conditions">
                <label translate="true">Conditions</label>
            </parameter>
        </parameters>
        <containers>
            <container name="content">
                <template name="grid" value="default" />
                <template name="top-products" value="top_products" />
            </container>
            <container name="content.top">
                <template name="grid" value="default" />
            </container>
        </containers>
    </widget>
</widgets>

我们有两个自定义参数和两个自定义源模型。我喜欢按照magento核心模块一样组织我的模块,所以我将创建模型Model/Config/Source

Model/Config/Source/SortBy.php

<?php
namespace Magease\CatalogWidget\Model\Config\Source;
 
class SortBy implements \Magento\Framework\Option\ArrayInterface
{
    public function toOptionArray()
    {
        return [
            ['value' => 'name', 'label' => __('Product Name')],
            ['value' => 'price', 'label' => __('Price')]
        ];
    }
}

Model/Config/Source/SortOrder.php

<?php
namespace Magease\CatalogWidget\Model\Config\Source;
 
class SortOrder implements \Magento\Framework\Option\ArrayInterface
{
    public function toOptionArray()
    {
        return [
            ['value' => 'asc', 'label' => __('Ascending')],
            ['value' => 'desc', 'label' => __('Descending')]
        ];
    }
}

下一步是创建我们的小部件将使用的自定义块。为了简单,我们将扩展Magento_CatalogWidget中的ProductList。这将为我们提供产品列表小部件的所有Magento现有功能
我们从ProductList中重写createCollection方法,在集合上添加排序。我添加了“collection_sort_by”和“collection_sort_order”属性getter,并在类的开头定义了默认值。此自定义参数在widget.xml配置中定义

Block/Product/ProductsList.php

<?php
namespace Magease\CatalogWidget\Block\Product;
 
class ProductsList extends \Magento\CatalogWidget\Block\Product\ProductsList
{
    const DEFAULT_COLLECTION_SORT_BY = 'name';
    const DEFAULT_COLLECTION_ORDER = 'asc';
 
    public function createCollection()
    {
        /** @var $collection \Magento\Catalog\Model\ResourceModel\Product\Collection */
        $collection = $this->productCollectionFactory->create();
        $collection->setVisibility($this->catalogProductVisibility->getVisibleInCatalogIds());
 
        $collection = $this->_addProductAttributesAndPrices($collection)
            ->addStoreFilter()
            ->setPageSize($this->getPageSize())
            ->setCurPage($this->getRequest()->getParam($this->getData('page_var_name'), 1))
            ->setOrder($this->getSortBy(), $this->getSortOrder());
 
        $conditions = $this->getConditions();
        $conditions->collectValidatedAttributes($collection);
        $this->sqlBuilder->attachConditionToCollection($collection, $conditions);
 
        return $collection;
    }
 
    public function getSortBy()
    {
        if (!$this->hasData('collection_sort_by')) {
            $this->setData('collection_sort_by', self::DEFAULT_COLLECTION_SORT_BY);
        }
        return $this->getData('collection_sort_by');
    }
 
    public function getSortOrder()
    {
        if (!$this->hasData('collection_sort_order')) {
            $this->setData('collection_sort_order', self::DEFAULT_COLLECTION_ORDER);
        }
        return $this->getData('collection_sort_order');
    }
}

现在可以开始测试了。

 

Containers

在创建小部件时,我们有布局更新选项,可以指定在哪个页面以及在哪个容器中展示我们的小部件。为了充分展示其能力,我将创建自定义模板文件。在这个示例中,我复制了默认产品列表模板。同样,为了保持一致性,我模仿了view/frontend/templates/product/widget/content/top_products.phtml的模版路径在我们的小部件配置中,我们指定了两个容器,一个名为content,另一个名为content.top。在第一个中,我定义了两个模板grid top-products这个节点的值将显示具有相同名称的模板选项,能使特定的自定义模板只在特定的容器中显示。

<container name="content">
    <template name="grid" value="default" />
    <template name="top-products" value="top_products" />
</container>
<container name="content.top">
    <template name="grid" value="default" />
</container>

主要内容区域 - name="content",模板选择可用。

主要内容顶部 - name="content.top,模板选择不可用。