Skip to content
  1. Extras
  2. mSearch2
  3. Extension
  4. Items filtration example

Items filtration example

miniShop2 can work with any column of product properties table, whereas mSearch2 can receive any columns from tables and generate filters on the base of them.

Let us combine these 2 abilities and write a filter by product availability. We will also learn to add our own fields to product and build a special filter for it.

Product properties extension: new availability field

First of all we read about product extension miniShop2.

Then we create new column availability INT(10) in table msProductData.

We add the new field in product model on the path: /core/components/minishop2/plugins/availability/model/

php
<?php

return array(
  'fields' => array(
    'availability' => 0
  ),
  'fieldMeta' => array(
    'availability' => array(
      'dbtype' => 'integer',
      'precision' => '10',
      'phptype' => 'integer',
      'null' => true,
      'default' => 0
    )
  )
);

We add widgets ExtJS for this field to the admin space on the path: /assets/components/minishop2/plugins/availability/

js
miniShop2.plugin.pluginname = {
  getFields: function (config) {
    return {
      availability: { xtype: 'numberfield', description: _('ms2_product_availability_help') }
    }
  },
  getColumns: function () {
    return {
      availability: {width:50, sortable:true, editor: {xtype:'numberfield'}}
    }
  }
};

We join all this with an index file which will turn on the plugin on the path: /core/components/minishop2/plugins/availability/

php
<?php
//
return array(
  'xpdo_meta_map' => array(
    'msProductData' => require_once dirname(__FILE__) .'/model/msproductdata.map.inc.php'
  ),
  'manager' => array(
    'msProductData' => MODX_ASSETS_URL . 'components/minishop2/plugins/availability/msproductdata.js'
  )
);

We add record to lexicon:

Then we clear the cache properly and try to turn on the new field in settings.

If it does not work, we will have to do all this for a second time. It worked for me at once, though:

Adding filter by the new field

availability field is now as native a field of product as price, weight and all other fields msProductData.

This means that we can turn it on very easily:

modx
[[!mFilter?
  &filters=`ms|availability:availability`
]]

Only this will show us checkboxes where different variants of product availability will be indicated by figures. 0, 5, 10, etc. Evidently, a slider with a range of prices will not suit here. It is a radio button that we need.

modx
[[!mFilter?
  &filters=`ms|availability:availability`
  &suggestionsRadio=`ms|availability`
  &tplFilter.row.ms|availability=`tpl.mFilter2.filter.radio`
]]

Упс! Добавляем запись в словари mSearch2, чистим кэш и обновляем:

We write availability into products, clear the cache and see something quite expectable - a column of values:

We have to write our own method of filtration which will show whether a product is available or not.

Extending filtration class

All standard filters mSearch2 are situated in file /core/components/msearch2/model/msearch2/filters.class.php. We have to inherit it, extend it and indicate new class in system settings.

We create a new file in /core/components/msearch2/custom/filters/custom.class.php write in it:

php
<?php

class myCustomFilter extends mse2FiltersHandler {}

Then we indicate it in system setting mse2_filters_handler_class.

From this moment on mSearch2 uses for work your filtration class, in which you can write new methods or redefine standard ones.

For getting data methods getMethodNameValues() are used, for preparing filter — buildMethodNameFilter(), for filtration - filterMethodName. How these 3 types of methods work can be seen in filters.class.php.

Adding new availability filter

We need to write our own methods of data preparation and filtration in order to divide all products into 2 arrays:

  • Field availability <= 0
  • Field availability > 0

This means that all products are divided into groups 'available' or 'unavailable'.

We write methods buildAvailabilityFilter and filterAvailability:

php
<?php
class myCustomFilter extends mse2FiltersHandler {

  // We take standard buildBooleanFilter as a sample and change it a little
  public function buildAvailabilityFilter(array $values) {
    if (count($values) < 2 && empty($this->config['showEmptyFilters'])) {
      return array();
    }

    $results = array();
    foreach ($values as $value => $ids) {
      $title = ($value <= 0)
        ? $this->modx->lexicon('mse2_filter_availability_no')
        : $this->modx->lexicon('mse2_filter_availability_yes');

      $value = $value <= 0 ? '0' : '1';

      if (!isset($results[$value])) {
        $results[$value] = array(
          'title' => $title
          ,'value' => $value
          ,'type' => 'availability'
          ,'resource' => array()
        );
      }

      foreach ($ids as $id) {
        $results[$value]['resources'][] = $id;
      }
    }

    ksort($results);
    return $results;
  }


  // When it comes to proper filtration, we take filterNumber as a basis
  public function filterAvailability(array $requested, array $values, array $ids) {
    $matched = array();

    $value = $requested[0];
    $tmp = array_flip($ids);
    foreach ($values as $number => $resources) {
      if ($value && $number > 0) {
        foreach ($resources as $id) {
          if (isset($tmp[$id])) {
            $matched[] = $id;
          }
        }
      }
      elseif (!$value && $number <= 0) {
        foreach ($resources as $id) {
          if (isset($tmp[$id])) {
            $matched[] = $id;
          }
        }
      }
    }

    return $matched;
  }
}

We add records mse2_filter_availability_no and mse2_filter_availability_yes into lexicon and get the filter needed:

Obviously, this can be supported by checkboxes, texts in dictionaries can be changed, etc. The principle remains as it is.