Skip to content
  1. Extras
  2. MiniShop3
  3. Snippets
  4. msProducts

msProducts

Snippet for outputting a list of products. It is based on pdoTools and supports all its filtering, sorting, and pagination capabilities.

Parameters

Main

ParameterDefaultDescription
tpltpl.msProducts.rowChunk for outputting each product
limit10Number of products per page
offset0Number of products to skip from the start
depth10Search depth in child categories
parentscurrent resourceComma-separated parent category IDs
resourcesComma-separated specific product IDs

Sorting

ParameterDefaultDescription
sortbyidSort field
sortdirASCDirection: ASC or DESC
sortbyOptionsSort by product option (see below)
ParameterDefaultDescription
linkLink type ID (from ms3_links)
masterMaster product ID (products linked to it)
slaveSlave product ID (products it is linked to)

parents=0

When using link for related products, set parents => 0 to disable category filtering. Otherwise only related products from the same category are returned.

Filtering

ParameterDefaultDescription
whereJSON extra conditions
optionFiltersJSON filters by product options
showZeroPricetrueShow zero-price products
showUnpublishedfalseShow unpublished
showDeletedfalseShow deleted
showHiddentrueShow hidden in menu

Extra data

ParameterDefaultDescription
includeContentfalseInclude content
includeTVsComma-separated TV list
includeThumbsComma-separated thumbnail sizes
includeVendorFields*Vendor fields (* = all)
includeOptionsComma-separated options to include
formatPricesfalseFormat prices via $ms3->format->price()
withCurrencyfalseAdd currency symbol (with formatPrices)
usePackagesComma-separated external packages (see Integration)

Output

ParameterDefaultDescription
returndataFormat: data, json, ids, sql
returnIdsfalseReturn only IDs
toPlaceholderSave to placeholder
toSeparatePlaceholdersPrefix for separate placeholders
outputSeparator\nSeparator between products
tplWrapperWrapper chunk
wrapIfEmptytrueUse wrapper when empty
showLogfalseShow execution log

Table aliases

The msProducts snippet automatically joins related product tables. Fields of the main table (msProduct) are available without a prefix; for joined tables you need the alias.

Tables and their fields

TableAliasFields
msProductid, pagetitle, longtitle, alias, uri, parent, createdon, publishedon, template...
msProductDataDataprice, old_price, article, weight, vendor_id, new, popular, favorite, color, size, tags...
msVendorVendorname, country, logo, address, phone, email (when includeVendorFields is set)

Dynamic aliases

AliasWhen usedDescription
LinkWith link + master or slaveProduct links table
{size}With includeThumbsThumbnails; alias is the size name (small, medium, …)
{option}With optionFilters or sortbyOptionsProduct option; alias is the option key (color, size, …)

Внимание

Product fields (price, article, new, popular, etc.) are in table Data. Without the alias the query will fail: use 'Data.price:>' => 1000, not 'price:>' => 1000.

Examples

Basic output

fenom
{'msProducts' | snippet: [
    'parents' => 5,
    'limit' => 12,
    'tpl' => 'tpl.msProducts.row'
]}

Sort by price

fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'sortby' => 'Data.price',
    'sortdir' => 'ASC'
]}

New products (sort by date)

fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'sortby' => 'createdon',
    'sortdir' => 'DESC',
    'limit' => 8,
    'where' => ['Data.new' => 1]
]}
fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'where' => ['Data.popular' => 1],
    'limit' => 4
]}

Filter by options

fenom
{* Products that are red and size M *}
{'msProducts' | snippet: [
    'parents' => 0,
    'optionFilters' => ['color' => 'red', 'size' => 'M']
]}

OR in options

fenom
{* Red OR blue products *}
{'msProducts' | snippet: [
    'parents' => 0,
    'optionFilters' => ['color' => 'red', 'OR:color' => 'blue']
]}

Vendor products

fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'where' => ['Data.vendor_id' => 5]
]}

Product links let you output accessories, related products, alternatives, etc.

fenom
{* Accessories for the current product *}
{'msProducts' | snippet: [
    'link' => 2,
    'master' => $_modx->resource.id,
    'parents' => 0,
    'limit' => 4,
    'tpl' => 'tpl.msProducts.related'
]}

Parameter master is the product for which linked products are searched. The link id (link) corresponds to the link type in MiniShop3 settings.

fenom
{'msProducts' | snippet: [
    'link' => 2,
    'slave' => $_modx->resource.id,
    'parents' => 0,
    'limit' => 4
]}

Default link types in MiniShop3:

IDName
1Similar (Related)
2Accessories
3Alternatives

Add types in Settings → Link types.

Sort by option

fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'sortby' => 'weight',
    'sortbyOptions' => 'weight:number',
    'sortdir' => 'ASC'
]}

Supported types for sortbyOptions:

TypeExampleUse when
number / decimalweight:numberDecimals: price, weight, volume
int / integerquantity:intIntegers: quantity, rating, age
date / datetimerelease_date:dateDates: release date, arrival date
(no type)colorText: alphabetical sort

With image thumbnails

fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'includeThumbs' => 'small,medium'
]}

In the chunk you get {$small}, {$medium} — URL of the first image of each size.

Multiple product images

Parameter includeThumbs returns only the first image (position = 0). To get 2–3 images for a carousel or gallery, use leftJoin and select:

fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'leftJoin' => [
        'Img1' => [
            'class' => 'MiniShop3\\Model\\msProductFile',
            'on' => 'Img1.product_id = msProduct.id AND Img1.position = 0 AND Img1.path LIKE "%/small/%"'
        ],
        'Img2' => [
            'class' => 'MiniShop3\\Model\\msProductFile',
            'on' => 'Img2.product_id = msProduct.id AND Img2.position = 1 AND Img2.path LIKE "%/small/%"'
        ],
        'Img3' => [
            'class' => 'MiniShop3\\Model\\msProductFile',
            'on' => 'Img3.product_id = msProduct.id AND Img3.position = 2 AND Img3.path LIKE "%/small/%"'
        ]
    ],
    'select' => [
        'Img1' => 'Img1.url as img1',
        'Img2' => 'Img2.url as img2',
        'Img3' => 'Img3.url as img3'
    ]
]}

In the chunk you get {$img1}, {$img2}, {$img3} — image URLs in gallery order.

Image position

position = 0 is the first image, position = 1 the second, etc. Order is defined by the product gallery sort.

Return only IDs

fenom
{set $productIds = 'msProducts' | snippet: [
    'parents' => 5,
    'returnIds' => 1
]}

{* $productIds = "1,2,3,4,5" *}

JSON output (for AJAX)

fenom
{'msProducts' | snippet: [
    'parents' => 0,
    'return' => 'json',
    'limit' => 20
]}

With pagination (pdoPage)

fenom
{'pdoPage' | snippet: [
    'element' => 'msProducts',
    'parents' => 0,
    'limit' => 12,
    'tpl' => 'tpl.msProducts.row'
]}

{$_modx->getPlaceholder('page.nav')}

Placeholders in the chunk

In the tpl chunk all product fields are available:

Resource fields

  • {$id} — product ID
  • {$pagetitle} — title
  • {$longtitle} — long title
  • {$description} — description
  • {$introtext} — summary
  • {$content} — content (if includeContent)
  • {$alias} — URL alias
  • {$uri} — full URI
  • {$parent} — parent ID
  • {$template} — template ID
  • {$published} — published
  • {$createdon} — created date
  • {$editedon} — edited date

Product fields (Data)

  • {$article} — article/sku
  • {$price} — price
  • {$old_price} — previous price
  • {$weight} — weight
  • {$image} — main image
  • {$thumb} — thumbnail
  • {$vendor_id} — vendor ID
  • {$made_in} — country of origin
  • {$new} — "new" flag
  • {$popular} — "popular" flag
  • {$favorite} — "favorite" flag
  • {$color} — color (JSON)
  • {$size} — size (JSON)
  • {$tags} — tags (JSON)
  • {$discount} — discount percent (computed)

Vendor fields

With includeVendorFields:

  • {$vendor_position} — position
  • {$vendor_name} — name
  • {$vendor_resource_id} — resource ID
  • {$vendor_country} — country
  • {$vendor_logo} — logo
  • {$vendor_address} — address
  • {$vendor_phone} — phone
  • {$vendor_email} — email
  • {$vendor_description} — description
  • {$vendor_properties} — properties

Other

  • {$idx} — index in the result set

Integration with external packages

The msProducts snippet supports integration with third-party packages (ms3Variants, msBrands, etc.) via the event system. This lets you extend product data without modifying MiniShop3 core.

usePackages parameter

To load data from an external package, pass its name in the usePackages parameter:

fenom
{* Load product variants *}
{'msProducts' | snippet : [
    'parents' => 0,
    'usePackages' => 'ms3Variants'
]}

{* Load variants and brands *}
{'msProducts' | snippet : [
    'parents' => 0,
    'usePackages' => 'ms3Variants,msBrands'
]}

Without usePackages, external package data is not loaded — which saves resources on pages that do not need it.

Available placeholders

Each package adds its own placeholders. For example, ms3Variants adds:

PlaceholderTypeDescription
{$has_variants}boolWhether the product has variants
{$variants_count}intNumber of variants
{$variants_json}stringJSON array for JavaScript
{$variants}arrayArray of variants for Fenom

Example with variants

fenom
{'msProducts' | snippet : [
    'parents' => 0,
    'usePackages' => 'ms3Variants',
    'tpl' => 'tpl.msProducts.variants'
]}

Chunk tpl.msProducts.variants:

fenom
<div class="product-card" data-product-id="{$id}">
    <h3>{$pagetitle}</h3>
    <div class="price">{$price}</div>

    {if $has_variants}
        <div class="variants-selector" data-variants='{$variants_json}'>
            {* JavaScript initializes selectors from JSON *}
        </div>
    {/if}

    <form method="post" class="ms-product-form">
        <input type="hidden" name="id" value="{$id}">
        <input type="hidden" name="variant_id" value="">
        <button type="submit">Add to cart</button>
    </form>
</div>

Events for developers

Third-party packages use the msOnProductsLoad and msOnProductPrepare events for integration. See Events.