Skip to content

Commit a81802a

Browse files
committed
MC-22572: Shuffle related, up-sale and cross-sale products either by priority and weight
- Fix random order of related, up-sell and cross-sell products - Add support for weighted random order of related, up-sell and cross-sell products
1 parent d585442 commit a81802a

File tree

3 files changed

+137
-28
lines changed

3 files changed

+137
-28
lines changed

app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ switch ($type = $block->getType()) {
2323
$items = $block->getAllItems();
2424
$limit = $block->getPositionLimit();
2525
$shuffle = (int) $block->isShuffled();
26+
$isWeightedRandom = (int) $block->getRotation()->isWeightedRandom($block->getProductListType());
2627
$canItemsAddToCart = $block->canItemsAddToCart();
2728

2829
$showAddTo = true;
@@ -43,6 +44,7 @@ switch ($type = $block->getType()) {
4344
$items = $block->getItems();
4445
$limit = 0;
4546
$shuffle = 0;
47+
$isWeightedRandom = 0;
4648
$canItemsAddToCart = $block->canItemsAddToCart();
4749

4850
$showAddTo = true;
@@ -62,6 +64,7 @@ switch ($type = $block->getType()) {
6264
$items = $block->getAllItems();
6365
$limit = $block->getPositionLimit();
6466
$shuffle = (int) $block->isShuffled();
67+
$isWeightedRandom = (int) $block->getRotation()->isWeightedRandom($block->getProductListType());
6568

6669
$showAddTo = false;
6770
$showCart = false;
@@ -82,6 +85,7 @@ switch ($type = $block->getType()) {
8285
$items = $block->getItemCollection()->getItems();
8386
$limit = $block->getItemLimit('upsell');
8487
$shuffle = 0;
88+
$isWeightedRandom = 0;
8589

8690
$showAddTo = false;
8791
$showCart = false;
@@ -156,9 +160,9 @@ switch ($type = $block->getType()) {
156160

157161
<?php if ($type == 'related' || $type == 'upsell') :?>
158162
<?php if ($type == 'related') :?>
159-
<div class="block <?= $block->escapeHtmlAttr($class) ?>" data-mage-init='{"relatedProducts":{"relatedCheckbox":".related.checkbox"}}' data-limit="<?= $block->escapeHtmlAttr($limit) ?>" data-shuffle="<?= /* @noEscape */ $shuffle ?>">
163+
<div class="block <?= $block->escapeHtmlAttr($class) ?>" data-mage-init='{"relatedProducts":{"relatedCheckbox":".related.checkbox"}}' data-limit="<?= $block->escapeHtmlAttr($limit) ?>" data-shuffle="<?= /* @noEscape */ $shuffle ?>" data-shuffle-weighted="<?= /* @noEscape */ $isWeightedRandom ?>">
160164
<?php else :?>
161-
<div class="block <?= $block->escapeHtmlAttr($class) ?>" data-mage-init='{"upsellProducts":{}}' data-limit="<?= $block->escapeHtmlAttr($limit) ?>" data-shuffle="<?= /* @noEscape */ $shuffle ?>">
165+
<div class="block <?= $block->escapeHtmlAttr($class) ?>" data-mage-init='{"upsellProducts":{}}' data-limit="<?= $block->escapeHtmlAttr($limit) ?>" data-shuffle="<?= /* @noEscape */ $shuffle ?>" data-shuffle-weighted="<?= /* @noEscape */ $isWeightedRandom ?>">
162166
<?php endif; ?>
163167
<?php else :?>
164168
<div class="block <?= $block->escapeHtmlAttr($class) ?>">
@@ -183,7 +187,7 @@ switch ($type = $block->getType()) {
183187
<?php endif; ?>
184188
<?php endif; ?>
185189
<?php if ($type == 'related' || $type == 'upsell') :?>
186-
<li class="item product product-item" style="display: none;">
190+
<li class="item product product-item" style="display: none;" data-shuffle-group="<?= $block->escapeHtmlAttr($_item->getPriority()) ?>" >
187191
<?php else :?>
188192
<li class="item product product-item">
189193
<?php endif; ?>

app/code/Magento/Catalog/view/frontend/web/js/related-products.js

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ define([
2828
_create: function () {
2929
$(this.options.selectAllLink, this.element).on('click', $.proxy(this._selectAllRelated, this));
3030
$(this.options.relatedCheckbox, this.element).on('click', $.proxy(this._addRelatedToProduct, this));
31+
32+
if (this.element.data('shuffle')) {
33+
this._shuffle(this.element.find(this.options.elementsSelector));
34+
}
3135
this._showRelatedProducts(
3236
this.element.find(this.options.elementsSelector),
3337
this.element.data('limit'),
34-
this.element.data('shuffle')
38+
this.element.data('shuffle-weighted')
3539
);
3640
},
3741

@@ -69,24 +73,66 @@ define([
6973
);
7074
},
7175

76+
/* jscs:disable */
77+
/* eslint-disable */
7278
/**
7379
* Show related products according to limit. Shuffle if needed.
7480
* @param {*} elements
7581
* @param {*} limit
76-
* @param {*} shuffle
82+
* @param weightedRandom
7783
* @private
7884
*/
79-
_showRelatedProducts: function (elements, limit, shuffle) {
80-
var index;
81-
82-
if (shuffle) {
83-
this._shuffle(elements);
84-
}
85+
_showRelatedProducts: function (elements, limit, weightedRandom) {
86+
var index, weights = [], random = [], weight = 2, shown = 0, $element, currentGroup, prevGroup;
8587

8688
if (limit === 0) {
8789
limit = elements.length;
8890
}
8991

92+
if (weightedRandom && limit > 0 && limit < elements.length) {
93+
for (index = 0; index < limit; index++) {
94+
$element = $(elements[index]);
95+
if ($element.data('shuffle-group') !== '') {
96+
break;
97+
}
98+
$element.show();
99+
shown++;
100+
}
101+
limit -= shown;
102+
for (index = elements.length - 1; index >= 0; index--) {
103+
$element = $(elements[index]);
104+
currentGroup = $element.data('shuffle-group');
105+
if (currentGroup !== '') {
106+
weights.push([index, Math.log(weight)]);
107+
if (typeof prevGroup !== 'undefined' && prevGroup !== currentGroup) {
108+
weight += 2;
109+
}
110+
prevGroup = currentGroup;
111+
}
112+
}
113+
114+
if (weights.length === 0) {
115+
return;
116+
}
117+
118+
for (index = 0; index < weights.length; index++) {
119+
random.push([weights[index][0], Math.pow(Math.random(), 1 / weights[index][1])]);
120+
}
121+
122+
random.sort(function(a, b) {
123+
a = a[1];
124+
b = b[1];
125+
return a < b ? 1 : (a > b ? -1 : 0);
126+
});
127+
index = 0;
128+
while (limit) {
129+
$(elements[random[index][0]]).show();
130+
limit--;
131+
index++
132+
}
133+
return;
134+
}
135+
90136
for (index = 0; index < limit; index++) {
91137
$(elements[index]).show();
92138
}
@@ -96,12 +142,19 @@ define([
96142
/* eslint-disable */
97143
/**
98144
* Shuffle an array
99-
* @param {Array} o
145+
* @param {Array} elements
100146
* @returns {*}
101147
*/
102-
_shuffle: function shuffle(o) { //v1.0
103-
for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
104-
return o;
148+
_shuffle: function shuffle(elements) {
149+
var parent, child, lastSibling;
150+
if (elements.length) {
151+
parent = $(elements[0]).parent();
152+
}
153+
while (elements.length) {
154+
child = elements.splice(Math.floor(Math.random() * elements.length), 1)[0];
155+
lastSibling = parent.find('[data-shuffle-group="' + $(child).data('shuffle-group') + '"]').last();
156+
lastSibling.after(child);
157+
}
105158
}
106159

107160
/* jscs:disable */

app/code/Magento/Catalog/view/frontend/web/js/upsell-products.js

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,98 @@ define([
1919
* @private
2020
*/
2121
_create: function () {
22+
if (this.element.data('shuffle')) {
23+
this._shuffle(this.element.find(this.options.elementsSelector));
24+
}
2225
this._showUpsellProducts(
2326
this.element.find(this.options.elementsSelector),
2427
this.element.data('limit'),
25-
this.element.data('shuffle')
28+
this.element.data('shuffle-weighted')
2629
);
2730
},
2831

32+
/* jscs:disable */
33+
/* eslint-disable */
2934
/**
3035
* Show upsell products according to limit. Shuffle if needed.
3136
* @param {*} elements
3237
* @param {Number} limit
33-
* @param {Boolean} shuffle
38+
* @param {Boolean} weightedRandom
3439
* @private
3540
*/
36-
_showUpsellProducts: function (elements, limit, shuffle) {
37-
var index;
38-
39-
if (shuffle) {
40-
this._shuffle(elements);
41-
}
41+
_showUpsellProducts: function (elements, limit, weightedRandom) {
42+
var index, weights = [], random = [], weight = 2, shown = 0, $element, currentGroup, prevGroup;
4243

4344
if (limit === 0) {
4445
limit = elements.length;
4546
}
4647

48+
if (weightedRandom && limit > 0 && limit < elements.length) {
49+
for (index = 0; index < limit; index++) {
50+
$element = $(elements[index]);
51+
if ($element.data('shuffle-group') !== '') {
52+
break;
53+
}
54+
$element.show();
55+
shown++;
56+
}
57+
limit -= shown;
58+
for (index = elements.length - 1; index >= 0; index--) {
59+
$element = $(elements[index]);
60+
currentGroup = $element.data('shuffle-group');
61+
if (currentGroup !== '') {
62+
weights.push([index, Math.log(weight)]);
63+
if (typeof prevGroup !== 'undefined' && prevGroup !== currentGroup) {
64+
weight += 2;
65+
}
66+
prevGroup = currentGroup;
67+
}
68+
}
69+
70+
if (weights.length === 0) {
71+
return;
72+
}
73+
74+
for (index = 0; index < weights.length; index++) {
75+
random.push([weights[index][0], Math.pow(Math.random(), 1 / weights[index][1])]);
76+
}
77+
78+
random.sort(function(a, b) {
79+
a = a[1];
80+
b = b[1];
81+
return a < b ? 1 : (a > b ? -1 : 0);
82+
});
83+
index = 0;
84+
while (limit) {
85+
$(elements[random[index][0]]).show();
86+
limit--;
87+
index++
88+
}
89+
return;
90+
}
91+
4792
for (index = 0; index < limit; index++) {
48-
$(this.element).find(elements[index]).show();
93+
$(elements[index]).show();
4994
}
5095
},
5196

5297
/* jscs:disable */
5398
/* eslint-disable */
5499
/**
55100
* Shuffle an array
56-
* @param o
101+
* @param elements
57102
* @returns {*}
58103
*/
59-
_shuffle: function shuffle(o){ //v1.0
60-
for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
61-
return o;
104+
_shuffle: function shuffle(elements){ //v1.0
105+
var parent, child, lastSibling;
106+
if (elements.length) {
107+
parent = $(elements[0]).parent();
108+
}
109+
while (elements.length) {
110+
child = elements.splice(Math.floor(Math.random() * elements.length), 1)[0];
111+
lastSibling = parent.find('[data-shuffle-group="' + $(child).data('shuffle-group') + '"]').last();
112+
lastSibling.after(child);
113+
}
62114
}
63115

64116
/* jscs:disable */

0 commit comments

Comments
 (0)