Skip to content

Commit 6e969a5

Browse files
authored
Merge pull request #146 from TeamEver/codex/add-shortcodes-for-best-sellers
Add feature best sales shortcodes
2 parents 11493ad + c4d5e64 commit 6e969a5

File tree

2 files changed

+212
-0
lines changed

2 files changed

+212
-0
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ You can create your own shortcodes from the "Shortcodes" tab accessible in the "
105105
- `[best-sales 10 carousel=true]`: Displays the top ten best-selling products. Optional parameters: `days`, `orderby`, `orderway`.
106106
- `[categorybestsales id="8" nb="10"]`: Displays the best-selling products from category ID 8. Optional parameters: `orderby`, `orderway`.
107107
- `[brandbestsales id="3" nb="10"]`: Displays the best-selling products from brand ID 3. Optional parameters: `orderby`, `orderway`.
108+
- `[featurebestsales id="2" nb="10"]`: Displays the best-selling products with feature ID 2. Optional parameters: `orderby`, `orderway`.
109+
- `[featurevaluebestsales id="5" nb="10"]`: Displays the best-selling products with feature value ID 5. Optional parameters: `orderby`, `orderway`.
108110
- `[random_product nb="10" carousel=true]`: Displays ten random products in a carousel.
109111
- `[linkedproducts nb="8" orderby="date_add" orderway="DESC"]`: Displays products linked to the current product in a Bootstrap carousel.
110112
- `[accessories nb="8" orderby="date_add" orderway="DESC"]`: Displays accessories of the current product in a Bootstrap carousel.
@@ -304,6 +306,8 @@ Vous pouvez créer vos propres shortcodes depuis l'onglet "Shortcodes" accessibl
304306
- `[best-sales 10 carousel=true]` : Affiche les dix meilleures ventes. Paramètres optionnels : `days`, `orderby`, `orderway`.
305307
- `[categorybestsales id="8" nb="10"]` : Affiche les meilleures ventes de la catégorie 8. Paramètres optionnels : `orderby`, `orderway`.
306308
- `[brandbestsales id="3" nb="10"]` : Affiche les meilleures ventes de la marque 3. Paramètres optionnels : `orderby`, `orderway`.
309+
- `[featurebestsales id="2" nb="10"]` : Affiche les meilleures ventes associées à la caractéristique 2. Paramètres optionnels : `orderby`, `orderway`.
310+
- `[featurevaluebestsales id="5" nb="10"]` : Affiche les meilleures ventes pour la valeur de caractéristique 5. Paramètres optionnels : `orderby`, `orderway`.
307311
- `[random_product nb="10" carousel=true]` : Affiche dix produits aléatoires en carousel.
308312
- `[linkedproducts nb="8" orderby="date_add" orderway="DESC"]` : Affiche les produits liés au produit courant en carousel Bootstrap.
309313
- `[accessories nb="8" orderby="date_add" orderway="DESC"]` : Affiche les accessoires du produit courant en carousel Bootstrap.
@@ -488,6 +492,8 @@ Puedes crear tus propios shortcodes desde la pestaña "Shortcodes" disponible en
488492
- `[best-sales 10 carousel=true]`: Muestra los diez productos más vendidos. Parámetros opcionales: `days`, `orderby`, `orderway`.
489493
- `[categorybestsales id="8" nb="10"]`: Muestra los productos más vendidos de la categoría 8. Parámetros opcionales: `orderby`, `orderway`.
490494
- `[brandbestsales id="3" nb="10"]`: Muestra los productos más vendidos de la marca 3. Parámetros opcionales: `orderby`, `orderway`.
495+
- `[featurebestsales id="2" nb="10"]`: Muestra los productos más vendidos con la característica 2. Parámetros opcionales: `orderby`, `orderway`.
496+
- `[featurevaluebestsales id="5" nb="10"]`: Muestra los productos más vendidos con el valor de característica 5. Parámetros opcionales: `orderby`, `orderway`.
491497
- `[random_product nb="10" carousel=true]`: Muestra diez productos aleatorios en carrusel.
492498
- `[linkedproducts nb="8" orderby="date_add" orderway="DESC"]`: Muestra productos relacionados con el producto actual en un carrusel Bootstrap.
493499
- `[accessories nb="8" orderby="date_add" orderway="DESC"]`: Muestra los accesorios del producto actual en un carrusel Bootstrap.
@@ -672,6 +678,8 @@ Puoi creare i tuoi shortcode dalla scheda "Shortcodes" nel sottomenu "Ever block
672678
- `[best-sales 10 carousel=true]`: Mostra i dieci prodotti più venduti. Parametri opzionali: `days`, `orderby`, `orderway`.
673679
- `[categorybestsales id="8" nb="10"]`: Mostra i prodotti più venduti della categoria 8. Parametri opzionali: `orderby`, `orderway`.
674680
- `[brandbestsales id="3" nb="10"]`: Mostra i prodotti più venduti del marchio 3. Parametri opzionali: `orderby`, `orderway`.
681+
- `[featurebestsales id="2" nb="10"]`: Mostra i prodotti più venduti con la caratteristica 2. Parametri opzionali: `orderby`, `orderway`.
682+
- `[featurevaluebestsales id="5" nb="10"]`: Mostra i prodotti più venduti con il valore caratteristica 5. Parametri opzionali: `orderby`, `orderway`.
675683
- `[random_product nb="10" carousel=true]`: Mostra dieci prodotti casuali in carosello.
676684
- `[linkedproducts nb="8" orderby="date_add" orderway="DESC"]`: Mostra i prodotti collegati a quello attuale in un carosello Bootstrap.
677685
- `[accessories nb="8" orderby="date_add" orderway="DESC"]`: Mostra gli accessori del prodotto corrente in un carosello Bootstrap.

models/EverblockTools.php

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ public static function renderShortcodes(string $txt, Context $context, Everblock
101101
if (strpos($txt, '[brandbestsales') !== false) {
102102
$txt = static::getBrandBestSalesShortcode($txt, $context, $module);
103103
}
104+
if (strpos($txt, '[featurebestsales') !== false) {
105+
$txt = static::getFeatureBestSalesShortcode($txt, $context, $module);
106+
}
107+
if (strpos($txt, '[featurevaluebestsales') !== false) {
108+
$txt = static::getFeatureValueBestSalesShortcode($txt, $context, $module);
109+
}
104110
if (strpos($txt, '[last-products') !== false) {
105111
$txt = static::getLastProductsShortcode($txt, $context, $module);
106112
}
@@ -1009,6 +1015,88 @@ protected static function getBestSellingProductIdsByBrand(int $brandId, int $lim
10091015
return EverblockCache::cacheRetrieve($cacheId);
10101016
}
10111017

1018+
protected static function getBestSellingProductIdsByFeature(int $featureId, int $limit, string $orderBy = 'total_quantity', string $orderWay = 'DESC', ?int $days = null): array
1019+
{
1020+
$context = Context::getContext();
1021+
$cacheId = 'everblock_bestSellingProductIds_feature_'
1022+
. (int) $context->shop->id . '_'
1023+
. $featureId . '_'
1024+
. $limit . '_'
1025+
. ($days ?? 'all') . '_'
1026+
. $orderBy . '_'
1027+
. $orderWay;
1028+
1029+
if (!EverblockCache::isCacheStored($cacheId)) {
1030+
$shopId = (int) $context->shop->id;
1031+
$sql = 'SELECT od.product_id, SUM(od.product_quantity) AS total_quantity'
1032+
. ' FROM ' . _DB_PREFIX_ . 'order_detail od'
1033+
. ' JOIN ' . _DB_PREFIX_ . 'orders o ON od.id_order = o.id_order'
1034+
. ' JOIN ' . _DB_PREFIX_ . 'product_shop ps ON od.product_id = ps.id_product'
1035+
. ' JOIN ' . _DB_PREFIX_ . 'feature_product fp ON od.product_id = fp.id_product'
1036+
. ' WHERE ps.active = 1'
1037+
. ' AND ps.id_shop = ' . $shopId
1038+
. ' AND o.id_shop = ' . $shopId
1039+
. ' AND fp.id_feature = ' . (int) $featureId;
1040+
1041+
if ($days !== null) {
1042+
$dateFrom = date('Y-m-d H:i:s', strtotime("-$days days"));
1043+
$sql .= ' AND o.date_add >= "' . pSQL($dateFrom) . '"';
1044+
}
1045+
1046+
$sql .= ' GROUP BY od.product_id'
1047+
. ' ORDER BY ' . pSQL($orderBy) . ' ' . pSQL($orderWay)
1048+
. ' LIMIT ' . (int) $limit;
1049+
1050+
$rows = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
1051+
$ids = array_map(fn($row) => (int) $row['product_id'], $rows);
1052+
EverblockCache::cacheStore($cacheId, $ids);
1053+
return $ids;
1054+
}
1055+
1056+
return EverblockCache::cacheRetrieve($cacheId);
1057+
}
1058+
1059+
protected static function getBestSellingProductIdsByFeatureValue(int $featureValueId, int $limit, string $orderBy = 'total_quantity', string $orderWay = 'DESC', ?int $days = null): array
1060+
{
1061+
$context = Context::getContext();
1062+
$cacheId = 'everblock_bestSellingProductIds_feature_value_'
1063+
. (int) $context->shop->id . '_'
1064+
. $featureValueId . '_'
1065+
. $limit . '_'
1066+
. ($days ?? 'all') . '_'
1067+
. $orderBy . '_'
1068+
. $orderWay;
1069+
1070+
if (!EverblockCache::isCacheStored($cacheId)) {
1071+
$shopId = (int) $context->shop->id;
1072+
$sql = 'SELECT od.product_id, SUM(od.product_quantity) AS total_quantity'
1073+
. ' FROM ' . _DB_PREFIX_ . 'order_detail od'
1074+
. ' JOIN ' . _DB_PREFIX_ . 'orders o ON od.id_order = o.id_order'
1075+
. ' JOIN ' . _DB_PREFIX_ . 'product_shop ps ON od.product_id = ps.id_product'
1076+
. ' JOIN ' . _DB_PREFIX_ . 'feature_product fp ON od.product_id = fp.id_product'
1077+
. ' WHERE ps.active = 1'
1078+
. ' AND ps.id_shop = ' . $shopId
1079+
. ' AND o.id_shop = ' . $shopId
1080+
. ' AND fp.id_feature_value = ' . (int) $featureValueId;
1081+
1082+
if ($days !== null) {
1083+
$dateFrom = date('Y-m-d H:i:s', strtotime("-$days days"));
1084+
$sql .= ' AND o.date_add >= "' . pSQL($dateFrom) . '"';
1085+
}
1086+
1087+
$sql .= ' GROUP BY od.product_id'
1088+
. ' ORDER BY ' . pSQL($orderBy) . ' ' . pSQL($orderWay)
1089+
. ' LIMIT ' . (int) $limit;
1090+
1091+
$rows = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
1092+
$ids = array_map(fn($row) => (int) $row['product_id'], $rows);
1093+
EverblockCache::cacheStore($cacheId, $ids);
1094+
return $ids;
1095+
}
1096+
1097+
return EverblockCache::cacheRetrieve($cacheId);
1098+
}
1099+
10121100
public static function getWidgetShortcode($txt)
10131101
{
10141102
$txt = preg_replace_callback('/\[widget moduleName="(.+?)" hookName="(.+?)"\]/', function ($matches) {
@@ -1581,6 +1669,122 @@ public static function getBrandBestSalesShortcode(string $txt, Context $context,
15811669
return $txt;
15821670
}
15831671

1672+
public static function getFeatureBestSalesShortcode(string $txt, Context $context, Everblock $module): string
1673+
{
1674+
preg_match_all(
1675+
'/\[featurebestsales\s+id="?(\d+)"?(?:\s+nb=(\d+))?(?:\s+limit=(\d+))?(?:\s+days=(\d+))?(?:\s+carousel=(true|false))?(?:\s+orderby="?(\w+)"?)?(?:\s+orderway="?(\w+)"?)?\]/i',
1676+
$txt,
1677+
$matches,
1678+
PREG_SET_ORDER
1679+
);
1680+
1681+
foreach ($matches as $match) {
1682+
$featureId = (int)$match[1];
1683+
$limit = isset($match[2]) && $match[2] !== '' ? (int)$match[2] : (isset($match[3]) ? (int)$match[3] : 10);
1684+
$days = isset($match[4]) ? (int)$match[4] : null;
1685+
$carousel = isset($match[5]) && $match[5] === 'true';
1686+
$orderBy = isset($match[6]) ? strtolower($match[6]) : 'total_quantity';
1687+
$orderWay = isset($match[7]) ? strtoupper($match[7]) : 'DESC';
1688+
1689+
$allowedOrderBy = ['total_quantity', 'product_id'];
1690+
$allowedOrderWay = ['ASC', 'DESC'];
1691+
if (!in_array($orderBy, $allowedOrderBy)) {
1692+
$orderBy = 'total_quantity';
1693+
}
1694+
if (!in_array($orderWay, $allowedOrderWay)) {
1695+
$orderWay = 'DESC';
1696+
}
1697+
1698+
$productIds = static::getBestSellingProductIdsByFeature($featureId, $limit, $orderBy, $orderWay, $days);
1699+
1700+
if (!empty($productIds)) {
1701+
$everPresentProducts = static::everPresentProducts($productIds, $context);
1702+
1703+
if (!empty($everPresentProducts)) {
1704+
$context->smarty->assign([
1705+
'everPresentProducts' => $everPresentProducts,
1706+
'carousel' => $carousel,
1707+
'shortcodeClass' => 'featurebestsales'
1708+
]);
1709+
1710+
$templatePath = static::getTemplatePath('hook/ever_presented_products.tpl', $module);
1711+
$replacement = $context->smarty->fetch($templatePath);
1712+
1713+
$shortcodeParts = ['[featurebestsales', 'id=' . $featureId];
1714+
if (isset($match[2]) && $match[2] !== '') { $shortcodeParts[] = 'nb=' . $match[2]; }
1715+
elseif (isset($match[3])) { $shortcodeParts[] = 'limit=' . $match[3]; }
1716+
if (isset($match[4])) { $shortcodeParts[] = 'days=' . $match[4]; }
1717+
if (isset($match[5])) { $shortcodeParts[] = 'carousel=' . $match[5]; }
1718+
if (isset($match[6])) { $shortcodeParts[] = 'orderby=' . $match[6]; }
1719+
if (isset($match[7])) { $shortcodeParts[] = 'orderway=' . $match[7]; }
1720+
$shortcode = implode(' ', $shortcodeParts) . ']';
1721+
1722+
$txt = str_replace($shortcode, $replacement, $txt);
1723+
}
1724+
}
1725+
}
1726+
1727+
return $txt;
1728+
}
1729+
1730+
public static function getFeatureValueBestSalesShortcode(string $txt, Context $context, Everblock $module): string
1731+
{
1732+
preg_match_all(
1733+
'/\[featurevaluebestsales\s+id="?(\d+)"?(?:\s+nb=(\d+))?(?:\s+limit=(\d+))?(?:\s+days=(\d+))?(?:\s+carousel=(true|false))?(?:\s+orderby="?(\w+)"?)?(?:\s+orderway="?(\w+)"?)?\]/i',
1734+
$txt,
1735+
$matches,
1736+
PREG_SET_ORDER
1737+
);
1738+
1739+
foreach ($matches as $match) {
1740+
$featureValueId = (int)$match[1];
1741+
$limit = isset($match[2]) && $match[2] !== '' ? (int)$match[2] : (isset($match[3]) ? (int)$match[3] : 10);
1742+
$days = isset($match[4]) ? (int)$match[4] : null;
1743+
$carousel = isset($match[5]) && $match[5] === 'true';
1744+
$orderBy = isset($match[6]) ? strtolower($match[6]) : 'total_quantity';
1745+
$orderWay = isset($match[7]) ? strtoupper($match[7]) : 'DESC';
1746+
1747+
$allowedOrderBy = ['total_quantity', 'product_id'];
1748+
$allowedOrderWay = ['ASC', 'DESC'];
1749+
if (!in_array($orderBy, $allowedOrderBy)) {
1750+
$orderBy = 'total_quantity';
1751+
}
1752+
if (!in_array($orderWay, $allowedOrderWay)) {
1753+
$orderWay = 'DESC';
1754+
}
1755+
1756+
$productIds = static::getBestSellingProductIdsByFeatureValue($featureValueId, $limit, $orderBy, $orderWay, $days);
1757+
1758+
if (!empty($productIds)) {
1759+
$everPresentProducts = static::everPresentProducts($productIds, $context);
1760+
1761+
if (!empty($everPresentProducts)) {
1762+
$context->smarty->assign([
1763+
'everPresentProducts' => $everPresentProducts,
1764+
'carousel' => $carousel,
1765+
'shortcodeClass' => 'featurevaluebestsales'
1766+
]);
1767+
1768+
$templatePath = static::getTemplatePath('hook/ever_presented_products.tpl', $module);
1769+
$replacement = $context->smarty->fetch($templatePath);
1770+
1771+
$shortcodeParts = ['[featurevaluebestsales', 'id=' . $featureValueId];
1772+
if (isset($match[2]) && $match[2] !== '') { $shortcodeParts[] = 'nb=' . $match[2]; }
1773+
elseif (isset($match[3])) { $shortcodeParts[] = 'limit=' . $match[3]; }
1774+
if (isset($match[4])) { $shortcodeParts[] = 'days=' . $match[4]; }
1775+
if (isset($match[5])) { $shortcodeParts[] = 'carousel=' . $match[5]; }
1776+
if (isset($match[6])) { $shortcodeParts[] = 'orderby=' . $match[6]; }
1777+
if (isset($match[7])) { $shortcodeParts[] = 'orderway=' . $match[7]; }
1778+
$shortcode = implode(' ', $shortcodeParts) . ']';
1779+
1780+
$txt = str_replace($shortcode, $replacement, $txt);
1781+
}
1782+
}
1783+
}
1784+
1785+
return $txt;
1786+
}
1787+
15841788
public static function getLinkedProductsShortcode(string $txt, Context $context, Everblock $module): string
15851789
{
15861790
if (!Tools::getValue('id_product')) {

0 commit comments

Comments
 (0)