MiniShop2 Show product details in product overview

Hey, I want the content / details of the product to be displayed in the product overview. At the moment i only have the page title and a picture of the product there.
Does anyone there know how to help me?

Hi @Rykoutech, next ms2 fields are also available for product page:
[[+price]],[[+old_price]],[[+article]],[[+weight]],[[+size]],[[+made_in]],[[+color]],[[+vendor.name]]
Also there are several useful snippets for work with default options(btw you can extend them and add other fields):

  1. msProductOptions - output all additional fields without selection, for debug use it next way:
    [[msProductOptions?tpl=``]]
  2. msOptions here you can choose which options you need
    [[msOptions? &options=color,size &tpl=`` ]]

Hey @antar, Thank you. But i need to display the productcontent from the product site. So i need this content in the products.row… but in this default chunk is online Pagetitle,popular, price etc…

Do you use Fenom? ContentBlocks? How about basic [[+content]] placeholder( {$content} for Fenom) if speech is about some inner chunk like products.row?

yes i use fenom. but i have no idea how i implement this command… i am a beginner xD

@Rykoutech It’s hard to say for sure, could you please share 1)your snippet call 2)your chunk code 3) the place where you’re going to output content

yes… This is The tpl.msProducts.row Chunk: `


    <h4 style="height: 30px; align: center;"><a href="{$id | url}">{$pagetitle}</a> 

   <span class="flags">
            {if $new?}
                <i class="fas fa-flag" title="{'ms2_frontend_new' | lexicon}"></i>
            
            {/if}
            {if $popular?}
                <i class="fas fa-star" title="{'ms2_frontend_popular' | lexicon}"></i>
            {/if}
        </span></h4>
     <a href="{$id | url}">  
    {if $thumb?}
        <img src="{$thumb}" alt="{$pagetitle}" title="{$pagetitle}"/>
    {else}
        <img src="{'assets_url' | option}components/minishop2/img/web/ms2_small.png"
             srcset="{'assets_url' | option}components/minishop2/img/web/ms2_small@2x.png 2x"
             alt="{$pagetitle}" title="{$pagetitle}"/>
    {/if}</a>
   <br>
      <span class="content">
         
        </span>  
       
   </span>
</div>
`

This is the msProducts snippet: `<?php
/** @var modX $modx /
/
* @var array $scriptProperties /
/
* @var miniShop2 $miniShop2 /
$miniShop2 = $modx->getService(‘miniShop2’);
$miniShop2->initialize($modx->context->key);
/
* @var pdoFetch $pdoFetch */
$fqn = $modx->getOption(‘pdoFetch.class’, null, ‘pdotools.pdofetch’, true);
$path = $modx->getOption(‘pdofetch_class_path’, null, MODX_CORE_PATH . ‘components/pdotools/model/’, true);
if ($pdoClass = $modx->loadClass($fqn, $path, false, true)) {
$pdoFetch = new $pdoClass($modx, $scriptProperties);
} else {
return false;
}
$pdoFetch->addTime(‘pdoTools loaded.’);

if (isset($parents) && $parents === ‘’) {
$scriptProperties[‘parents’] = $modx->resource->id;
}

if (!empty($returnIds)) {
$scriptProperties[‘return’] = ‘ids’;
}

if ($scriptProperties[‘return’] === ‘ids’) {
$scriptProperties[‘returnIds’] = true;
}

// Start build “where” expression
$where = array(
‘class_key’ => ‘msProduct’,
);
if (empty($showZeroPrice)) {
$where[‘Data.price:>’] = 0;
}
// Add grouping
$groupby = array(
‘msProduct.id’,
);

// Join tables
$leftJoin = array(
‘Data’ => array(‘class’ => ‘msProductData’),
‘Vendor’ => array(‘class’ => ‘msVendor’, ‘on’ => ‘Data.vendor=Vendor.id’),
);

$select = array(
‘msProduct’ => !empty($includeContent)
? $modx->getSelectColumns(‘msProduct’, ‘msProduct’)
: $modx->getSelectColumns(‘msProduct’, ‘msProduct’, ‘’, array(‘content’), true),
‘Data’ => $modx->getSelectColumns(‘msProductData’, ‘Data’, ‘’, array(‘id’), true),
‘Vendor’ => $modx->getSelectColumns(‘msVendor’, ‘Vendor’, ‘vendor.’, array(‘id’), true),
);

// Include thumbnails
if (!empty($includeThumbs)) {
$thumbs = array_map(‘trim’, explode(’,’, $includeThumbs));
foreach ($thumbs as $thumb) {
if (empty($thumb)) {
continue;
}
$leftJoin[$thumb] = array(
‘class’ => ‘msProductFile’,
‘on’ => “{$thumb}.product_id = msProduct.id AND {$thumb}.rank = 0 AND {$thumb}.path LIKE ‘%/{$thumb}/%’”,
);
$select[$thumb] = "{$thumb}.url as {$thumb}";
$groupby = “{$thumb}.url”;
}
}

// Include linked products
$innerJoin = array();
if (!empty($link) && !empty($master)) {
$innerJoin[‘Link’] = array(
‘class’ => ‘msProductLink’,
‘on’ => 'msProduct.id = Link.slave AND Link.link = ’ . $link,
);
$where[‘Link.master’] = $master;
} elseif (!empty($link) && !empty($slave)) {
$innerJoin[‘Link’] = array(
‘class’ => ‘msProductLink’,
‘on’ => 'msProduct.id = Link.master AND Link.link = ’ . $link,
);
$where[‘Link.slave’] = $slave;
}

// Add user parameters
foreach (array(‘where’, ‘leftJoin’, ‘innerJoin’, ‘select’, ‘groupby’) as $v) {
if (!empty($scriptProperties[$v])) {
$tmp = $scriptProperties[$v];
if (!is_array($tmp)) {
$tmp = json_decode($tmp, true);
}
if (is_array($tmp)) {
$$v = array_merge($$v, $tmp);
}
}
unset($scriptProperties[$v]);
}
$pdoFetch->addTime(‘Conditions prepared’);

// Add filters by options
$joinedOptions = array();
if (!empty($scriptProperties[‘optionFilters’])) {
$filters = json_decode($scriptProperties[‘optionFilters’], true);
foreach ($filters as $key => $value) {
$components = explode(’:’, $key, 2);

    if (count($components) === 2) {
        if (in_array(strtolower($components[0]), ['or', 'and'])) {
            list($operator, $key) = $components;
        }
    }

    $option = preg_replace('#\:.*#', '', $key);
    $key = str_replace($option, $option . '.value', $key);

    if (!in_array($option, $joinedOptions)) {
        $leftJoin[$option] = array(
            'class' => 'msProductOption',
            'on' => "`{$option}`.product_id = Data.id AND `{$option}`.key = '{$option}'",
        );
        $joinedOptions[] = $option;
    }

    $index = isset($operator) && in_array(strtolower($operator), ['or', 'and'], true)
        ? sprintf('%s:%s', strtoupper($operator), $key)
        : $key;
    $where[$index] = $value;
}

}

// Add sort by options
if (!empty($scriptProperties[‘sortbyOptions’])) {
$sorts = array_map(‘trim’, explode(’,’, $scriptProperties[‘sortbyOptions’]));
foreach ($sorts as $sort) {
$sort = explode(’:’, $sort);
$option = $sort[0];
if (preg_match("#\b{$option}\b#", $scriptProperties[‘sortby’], $matches)) {
$type = ‘string’;
if (isset($sort[1])) {
$type = $sort[1];
}
switch ($type) {
case ‘number’:
case ‘decimal’:
$sortbyOptions = “CAST({$option}.value AS DECIMAL(13,3))”;
break;
case ‘int’:
case ‘integer’:
$sortbyOptions = “CAST({$option}.value AS UNSIGNED INTEGER)”;
break;
case ‘date’:
case ‘datetime’:
$sortbyOptions = “CAST({$option}.value AS DATETIME)”;
break;
default:
$sortbyOptions = “{$option}.value”;
break;
}
$scriptProperties[‘sortby’] = preg_replace("#\b{$option}\b#", $sortbyOptions, $scriptProperties[‘sortby’]);
$groupby = “{$option}.value”;
}

    if (!in_array($option, $joinedOptions)) {
        $leftJoin[$option] = array(
            'class' => 'msProductOption',
            'on' => "`{$option}`.product_id = Data.id AND `{$option}`.key = '{$option}'",
        );
        $joinedOptions[] = $option;
    }

}

}

$default = array(
‘class’ => ‘msProduct’,
‘where’ => $where,
‘leftJoin’ => $leftJoin,
‘innerJoin’ => $innerJoin,
‘select’ => $select,
‘sortby’ => ‘msProduct.id’,
‘sortdir’ => ‘ASC’,
‘groupby’ => implode(’, ', $groupby),
‘return’ => ‘data’,
‘nestedChunkPrefix’ => ‘minishop2_’,
);
// Merge all properties and run!
$pdoFetch->setConfig(array_merge($default, $scriptProperties), false);
$rows = $pdoFetch->run();

// Process rows
$output = array();
if (!empty($rows) && is_array($rows)) {
$c = $modx->newQuery(‘modPluginEvent’, array(‘event:IN’ => array(‘msOnGetProductPrice’, ‘msOnGetProductWeight’, ‘msOnGetProductFields’)));
$c->innerJoin(‘modPlugin’, ‘modPlugin’, ‘modPlugin.id = modPluginEvent.pluginid’);
$c->where(‘modPlugin.disabled = 0’);

$modifications = $modx->getOption('ms2_price_snippet', null, false, true) ||
    $modx->getOption('ms2_weight_snippet', null, false, true) || $modx->getCount('modPluginEvent', $c);
if ($modifications) {
    /** @var msProductData $product */
    $product = $modx->newObject('msProductData');
}
$pdoFetch->addTime('Checked the active modifiers');

$opt_time = 0;
foreach ($rows as $k => $row) {
    if ($modifications) {
        $product->fromArray($row, '', true, true);
        $tmp = $row['price'];
        $row['price'] = $product->getPrice($row);
        $row['weight'] = $product->getWeight($row);
        // A discount here, so we should replace old price
        if ($row['price'] < $tmp) {
            $row['old_price'] = $tmp;
        }
        $row = $product->modifyFields($row);
    }
    $row['price'] = $miniShop2->formatPrice($row['price']);
    $row['old_price'] = $miniShop2->formatPrice($row['old_price']);
    $row['weight'] = $miniShop2->formatWeight($row['weight']);
    $row['idx'] = $pdoFetch->idx++;

    $opt_time_start = microtime(true);
    $options = $modx->call('msProductData', 'loadOptions', array($modx, $row['id']));
    $row = array_merge($row, $options);
    $opt_time += microtime(true) - $opt_time_start;

    $tpl = $pdoFetch->defineChunk($row);
    $output[] = $pdoFetch->getChunk($tpl, $row);
}
$pdoFetch->addTime('Time to load products options', $opt_time);

}

$log = ‘’;
if ($modx->user->hasSessionContext(‘mgr’) && !empty($showLog)) {
$log .= ‘

’ . print_r($pdoFetch->getTime(), 1) . ‘
’;
}

// Return output
if (is_string($rows)) {
$modx->setPlaceholder(‘msProducts.log’, $log);
if (!empty($toPlaceholder)) {
$modx->setPlaceholder($toPlaceholder, $rows);
} else {
return $rows;
}
} elseif (!empty($toSeparatePlaceholders)) {
$output[‘log’] = $log;
$modx->setPlaceholders($output, $toSeparatePlaceholders);
} else {
if (empty($outputSeparator)) {
$outputSeparator = “\n”;
}
$output[‘log’] = $log;
$output = implode($outputSeparator, $output);

if (!empty($tplWrapper) && (!empty($wrapIfEmpty) || !empty($output))) {
    $output = $pdoFetch->getChunk($tplWrapper, array(
        'output' => $output,
    ));
}

if (!empty($toPlaceholder)) {
    $modx->setPlaceholder($toPlaceholder, $output);
} else {
    return $output;
}

}and this is the chunk of the Product.content:

[[+new:isnot=``:then=`[[%ms2_frontend_new]]`]] [[+popular:isnot=``:then=`[[%ms2_frontend_popular]]`]] [[+favorite:isnot=``:then=`[[%ms2_frontend_favorite]]`]]
[[!msGallery]]
<div class="col-12 col-md-6" itemtype="http://schema.org/AggregateOffer" itemprop="offers" itemscope>
    <meta itemprop="category" content="[[#[[*parent]].pagetitle]]">
    <meta itemprop="offerCount" content="1">
   

    <form class="form-horizontal ms2_form" method="post">
        <input type="hidden" name="id" value="[[*id]]"/>

      
        

        [[msOptions?options=`color,size`]]

        [[msProductOptions]]

        <div class="form-group row align-items-center">
            <div class="col-12 offset-md-3 col-md-9 text-center text-md-left">
                
            </div>
        </div>
    </form>

</div>

[[%ms2_product_article]]: [[+article:default=`-`]]
[[-+article:default=`-`]]
                <a href="mailto:Example@mail.com?subject=Product request<Artikel Nummer:[[+article]],{foreach $options as $option}{if $option.caption is 'size'}{$option.value}{/if}{/foreach}, [[+weight ]] Kg> "> Produktanfrage </a>-->
                </button>
                
                
                
[[*content]]
` i hope you mean that :confused:

Oh, I meant your msProducts snippet call not it’s code itself :slight_smile:

Please check this snippet parameter includeContent msProducts / Snippets / miniShop2 / docs.modx.pro maybe this will help!

Thank you very much :slight_smile: I understand that, but I only need a connection to the content that can be seen on the product page. This should then only be linked to the product preview and displayed. I just have to know how to call up and display the content of the product outside of the product page.

In your call to “msProducts” you have to set the property includeContent to 1.

[[!msProducts?
    &includeContent=`1`
	...
]]
//or maybe
[[!pdoPage?
	&element=`msProducts`
	&includeContent=`1`
]]

Then use {$content} in your “tpl.msProducts.row” chunk.

Probably I know what you want now :slight_smile:
For Fenom you can use this: {9 | resource : 'content'} where 9 is ID or desired product resource.
Regarding to yours tpl.msProducts.row this should look like the next: {$id | resource : 'content'}

Also fastField can be useful with/without Fenom, you can get any resource field.

Guys, thank you very much! I got it! you are really awesome! <3

This topic was automatically closed 2 days after discussion ended and a solution was marked. New replies are no longer allowed. You can open a new topic by clicking the link icon below the original post or solution and selecting “+ New Topic”.