Расширяем фильтрацию в категории товаров админ панели

Как это по итогу должно выглядеть.


Привожу простейший пример фильтрации товаров по наличию изображения.
ВАЖНО!
Мы не лезем в исходники самого компонента.


По данному примеру можно фильтровать по любому полю товара.

1) Создаем плагин на событие msOnManagerCustomCssJs

<?php
switch ($modx->event->name) {
    case 'msOnManagerCustomCssJs': 
         
        $modx->controller->addLastJavascript(MODX_ASSETS_URL.'components/customAssets/category/filter/script.js);
  
    break;
}

2) Подключаем туда наш файлик,

например, из папки assets/components/customAssets/category/filter/
Содержимое файла

if(Ext.ComponentMgr.types['minishop2-grid-products']) {
    
    miniShop2.grid.ProductsCustom = function (config) {
        
        Ext.applyIf(config, { 
            baseParams: {
                action: 'mgr/product/getlist_custom',
            },
        });
        miniShop2.grid.ProductsCustom.superclass.constructor.call(this, config);
    };
    
    Ext.extend(miniShop2.grid.ProductsCustom, Ext.ComponentMgr.types['minishop2-grid-products'], {
        
        getTopBar: function () { 
            return [{
                text: (MODx.config.mgr_tree_icon_msproduct ? String.format('<i class="{0}"></i> ', Ext.util.Format.htmlEncode(MODx.config.mgr_tree_icon_msproduct)) : '') + _('ms2_product_create'),
                handler: this.createProduct,
                scope: this
            }, '-', {
                text: (MODx.config.mgr_tree_icon_mscategory ? String.format('<i class="{0}"></i> ', Ext.util.Format.htmlEncode(MODx.config.mgr_tree_icon_mscategory)) : '') + _('ms2_category_create'),
                handler: this.createCategory,
                scope: this
            }, '-', {
                text: '<i class="icon icon-trash-o action-red"></i>',
                handler: this._emptyRecycleBin,
                scope: this,
            }, '->', {
                xtype: 'xcheckbox',
                name: 'with_photo',
                width: 170,
                boxLabel: 'Только с фото',
                ctCls: 'tbar-checkbox',
                checked: MODx.config['ms2_category_show_only_with_photo'] == 1,
                listeners: {
                    check: {fn: this.photoFilter, scope: this}
                }
            },{
                xtype: 'xcheckbox',
                name: 'nested',
                width: 200,
                boxLabel: _('ms2_category_show_nested'),
                ctCls: 'tbar-checkbox',
                checked: MODx.config['ms2_category_show_nested_products'] == 1,
                listeners: {
                    check: {fn: this.nestedFilter, scope: this}
                }
            }, '-', this.getSearchField()];
        },
        
        
        photoFilter: function (checkbox, checked) {
            var s = this.getStore();
            s.baseParams.with_photo = checked ? 1 : 0;
            this.getBottomToolbar().changePage(1);
        },
        
        
    });
    Ext.reg('minishop2-grid-products', miniShop2.grid.ProductsCustom);
}

За отображение фильтра отвечает вот этот вот кусочек

{
        xtype: 'xcheckbox',
        name: 'with_photo',
        width: 170,
        boxLabel: 'Только с фото',
        ctCls: 'tbar-checkbox',
        checked: MODx.config['ms2_category_show_only_with_photo'] == 1,
        listeners: {
            check: {fn: this.photoFilter, scope: this}
        }
}

А за обработку нажатия вот это

photoFilter: function (checkbox, checked) {
        var s = this.getStore();
        s.baseParams.with_photo = checked ? 1 : 0;
        this.getBottomToolbar().changePage(1);
    },

Также стоит обратить внимание на то, что был переопределен процессор по умолчанию на
'mgr/product/getlist_custom'

Пример кастомного процессора.
Создаем файл в папке
core/components/minishop2/processors/mgr/product/getlist_custom.class.php
В нем переопределяем один из методов

<?php 

require_once(dirname(__FILE__) . '/getlist.class.php');

class msProductGetListProcessorCustom extends msProductGetListProcessor
{
    
    /**
     * @param xPDOQuery $c
     *
     * @return xPDOQuery
     */
    public function prepareQueryBeforeCount(xPDOQuery $c)
    {
        $c->where(['class_key' => 'msProduct']);
        $c->leftJoin('msProductData', 'Data', 'msProduct.id = Data.id');
        $c->leftJoin('msCategoryMember', 'Member', 'msProduct.id = Member.product_id');
        $c->leftJoin('msVendor', 'Vendor', 'Data.vendor = Vendor.id');
        $c->leftJoin('msCategory', 'Category', 'Category.id = msProduct.parent');
        if ($this->getProperty('combo')) {
            $c->select('msProduct.id,msProduct.pagetitle,msProduct.context_key');
        } else {
            $c->select($this->modx->getSelectColumns('msProduct', 'msProduct'));
            $c->select($this->modx->getSelectColumns('msProductData', 'Data', '', ['id'], true));
            $c->select($this->modx->getSelectColumns('msVendor', 'Vendor', 'vendor_', ['name']));
            $c->select($this->modx->getSelectColumns('msCategory', 'Category', 'category_', ['pagetitle']));
        }
        
       
        if ($this->item_id) {
            $c->where(['msProduct.id' => $this->item_id]);
            if ($parent = (int)$this->getProperty('parent')) {
                $this->parent = $parent;
            }
        } else {
            $query = trim($this->getProperty('query'));
            if (!empty($query)) {
                if (is_numeric($query)) {
                    $c->where([
                        'msProduct.id' => $query,
                        'OR:Data.article:=' => $query,
                    ]);
                } else {
                    $c->where([
                        'msProduct.pagetitle:LIKE' => "%{$query}%",
                        'OR:msProduct.longtitle:LIKE' => "%{$query}%",
                        'OR:msProduct.description:LIKE' => "%{$query}%",
                        'OR:msProduct.introtext:LIKE' => "%{$query}%",
                        'OR:Data.article:LIKE' => "%{$query}%",
                        'OR:Data.made_in:LIKE' => "%{$query}%",
                        'OR:Vendor.name:LIKE' => "%{$query}%",
                        'OR:Category.pagetitle:LIKE' => "%{$query}%",
                    ]);
                }
            }
            
             
            ///////////////////////////////

            $queryPhoto = $this->getProperty('with_photo', null);
            $queryPhoto = ($queryPhoto === null) || (bool)$queryPhoto;

            
            if (!empty($queryPhoto)) {
                
                $c->query['where'][] = [
                    [
                        new xPDOQueryCondition(['sql' => 'Data.thumb IS NOT null', 'conjunction' => 'AND'])
                    ]
                ];

            } else { 
              
                $c->query['where'][] = [
                    [
                        new xPDOQueryCondition(['sql' => 'Data.thumb IS null', 'conjunction' => 'AND'])
                    ]
                ];
            }
            
            ///////////////////////////////
           

            $parent = (int)$this->getProperty('parent');
            if (!empty($parent)) {
                $category = $this->modx->getObject('modResource', $parent);
                $this->parent = $parent;
                $parents = [$parent];

                $nested = $this->getProperty('nested', null);
                $nested = ($nested === null) && $this->modx->getOption(
                    'ms2_category_show_nested_products',
                    null,
                    true
                ) || (bool)$nested;
                if ($nested) {
                    $tmp = $this->modx->getChildIds($parent, 10, ['context' => $category->get('context_key')]);
                    foreach ($tmp as $v) {
                        $parents[] = $v;
                    }
                }
                $parents = '(' . implode(',', $parents) . ')';
                $c->query['where'][] = [
                    [
                        new xPDOQueryCondition(['sql' => 'msProduct.parent IN ' . $parents, 'conjunction' => 'OR']),
                        new xPDOQueryCondition(['sql' => 'Member.category_id IN ' . $parents, 'conjunction' => 'OR'])
                    ]
                ];
            }
          
            
        }

        $c->groupby($this->classKey . '.id');

        return $c;
    }
   
    
}

return 'msProductGetListProcessorCustom';

Также один из кейсов: показать товары, созданные текущим пользователем (авторизован в админ панели)
Шаги те же самые, только переменная в extJs называется по другому (onlyMy) и в процессоре проще условие дописанное

$onlyMy = $this->getProperty('onlyMy', null);
        $onlyMy = ($onlyMy === null) || (bool)$onlyMy;

        if (!empty($onlyMy)) {
            $c->where([
                'msProduct.createdby' => $this->modx->user->get('id'),
            ]);
        }
Евгений Webinmd
20 января 2025, 22:35
modx.pro
2
218
+9

Комментарии: 0

Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
0