Skip to content

Commit 820a6fd

Browse files
authored
Create Customer segments.md
1 parent 0ab4344 commit 820a6fd

File tree

1 file changed

+259
-0
lines changed

1 file changed

+259
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# Customer Segments
2+
3+
Conditions:
4+
5+
- customer address attributes
6+
- customer attributes
7+
- cart item, total qty, totals
8+
- products in cart, in wishlist, viewed products, ordered products, viewed date, ordered date
9+
- order address, totals, number of orders, average total amount, order date, order status - only logged in
10+
11+
Listens all model evetns, matches conditions by \Magento\CustomerSegment\Model\Segment\Condition\Order\Address::getMatchedEvents
12+
13+
14+
## Database
15+
16+
- magento_customersegment_segment - name, conditions, actions
17+
- magento_customersegment_website - many-to-many
18+
- magento_customersegment_customer - website, added/updated date
19+
- magento_customersegment_event - after saving segment rule, holds events that related to selected conditions
20+
21+
22+
## Admin conditions
23+
24+
namespace Magento\CustomerSegment;
25+
26+
Admin form - old widget style tabs:
27+
28+
- Block\Adminhtml\Customersegment\Edit\Tab\General
29+
- Block\Adminhtml\Customersegment\Edit\Tab\Conditions
30+
31+
Rendering conditions form:
32+
33+
render conditions -> renderer \Magento\Rule\Block\Conditions -> segment.getConditions -> root Model\Segment\Condition\Combine\Root
34+
35+
36+
Condition classes - hold matching rules:
37+
38+
- Model\Condition\Combine\AbstractCombine
39+
- Model\Segment\Condition\Order\Address - order_address join sales_order join customer_entity
40+
- Model\Segment\Condition\Sales\Combine
41+
- Model\Segment\Condition\Sales\Ordersnumber - COUNT(*)
42+
- Model\Segment\Condition\Sales\Salesamount - sum/avg sales_order.base_grand_total
43+
- Model\Segment\Condition\Sales\Purchasedquantity - sum/avg sales_order.total_qty_ordered
44+
- Model\Segment\Condition\Customer\Address
45+
- Model\Segment\Condition\Customer\Address\DefaultAddress
46+
47+
48+
## Refresh Segment Data
49+
50+
Some conditions don't work for guest visitors, despite description! Example - cart grand total amount:
51+
52+
- click "Refresh" inside segment admin
53+
- Controller\Adminhtml\Report\Customer\Customersegment\Refresh::execute
54+
- Model\Segment::matchCustomers
55+
- Model\ResourceModel\Segment::aggregateMatchedCustomers
56+
- Model\ResourceModel\Segment::processConditions
57+
- Model\Segment\Condition\Combine\Root::getSatisfiedIds
58+
- // individual conditions
59+
- Model\Segment\Condition\Shoppingcart\Amount::getSatisfiedIds
60+
61+
```SQL
62+
SELECT `quote`.`customer_id` FROM `quote`
63+
WHERE (quote.is_active=1) AND (quote.store_id IN('1')) AND (quote.base_grand_total >= '100') AND (customer_id IS NOT NULL)
64+
```
65+
66+
67+
## Viewed product index
68+
69+
Condition by recently viewed events **SEEMS BROKEN** when full page cache is enabled.
70+
This condition relies on `report_viewed_product_index` table, which is handled by report module.
71+
72+
Configuration:
73+
74+
- `reports/options/enabled`
75+
- `reports/options/product_view_enabled`
76+
77+
\Magento\Reports\Model\ReportStatus::isReportEnabled
78+
79+
\Magento\Reports\Model\Product\Index\Viewed
80+
81+
`catalog_controller_product_view` -> \Magento\Reports\Observer\CatalogProductViewObserver
82+
- save into `report_viewed_product_index`
83+
- save into `report_event`, take customer from session
84+
85+
This does not work when full page cache is enabled and Varnish returns HTML directly.
86+
87+
88+
## Listening to events and updating matched customers
89+
90+
Segments needs to listen to some events related to conditions. After segment with conditions is saved,
91+
table `magento_customersegment_event` holds events that it listens to.
92+
93+
Segment rule table holds rendered `condition_sql` column with placeholders:
94+
- :customer_id
95+
- :website_id
96+
- :quote_id
97+
- :visitor_id
98+
99+
Updating customer segments on events:
100+
101+
- event `customer_login`
102+
- Observer\ProcessEventObserver::execute
103+
- Model\Customer::processEvent
104+
- Model\Customer::getActiveSegmentsForEvent
105+
- Model\ResourceModel\Segment\Collection::addEventFilter - join table `magento_customersegment_event`
106+
- Model\Customer::_processSegmentsValidation
107+
- Model\Segment::validateCustomer
108+
* visitor_id, quote_id passed for guest
109+
- Model\Segment\Condition\Combine\Root::isSatisfiedBy
110+
* all conditions[].isSatisfiedBy
111+
* all conditions[].Model\Condition\Combine\AbstractCombine::getConditionsSql
112+
113+
114+
Result:
115+
116+
- Matched segments are added to `magento_customersegment_customer`
117+
- http context \Magento\CustomerSegment\Helper\Data::CONTEXT_SEGMENT = 'customer_segment' is updated with new segments
118+
- customerSession.setCustomerSegmentIds
119+
120+
121+
Event -> interested segment rules.
122+
123+
124+
## Impact on performance
125+
126+
1. Customer segments are added to full page cache keys
127+
128+
\Magento\CustomerSegment\Helper\Data::CONTEXT_SEGMENT = 'customer_segment'
129+
130+
\Magento\PageCache\Model\App\Response\HttpPlugin::beforeSendResponse
131+
\Magento\Framework\App\Response\Http::sendVary
132+
\Magento\Framework\App\Http\Context::getVaryString
133+
134+
Example:
135+
136+
```php
137+
sha1($this->serializer->serialize([
138+
'customer_group' => '1',
139+
'customer_logged_in' => true,
140+
'customer_segment' => ["1"]
141+
]))
142+
```
143+
144+
This lowers chances of hitting cached page, increasing load on the server.
145+
146+
1. Listens to many object save events, calculates matching conditions
147+
148+
149+
## DepersonalizePlugin
150+
151+
Does 2 things:
152+
153+
1. Makes sure customerSession.CustomerSegmentIds is not deleted by Customer module DepersonalizePlugin
154+
1. Sets full page cache key httpContext->setValue(Data::CONTEXT_SEGMENT)
155+
156+
157+
\Magento\Framework\Pricing\Render\Layout::loadLayout:
158+
```
159+
$this->layout->getUpdate()->load();
160+
// 1. \Magento\Customer\Model\Layout\DepersonalizePlugin::beforeGenerateXml:
161+
// - remember customerGroupId and formKey from session
162+
// 2. \Magento\CustomerSegment\Model\Layout\DepersonalizePlugin::beforeGenerateXml:
163+
// - remember customerSegmentIds from customer session
164+
$this->layout->generateXml();
165+
$this->layout->generateElements();
166+
// 3. \Magento\PageCache\Model\Layout\DepersonalizePlugin::afterGenerateElements:
167+
// - event `depersonalize_clear_session`
168+
// - session_write_close();
169+
// - clear message session
170+
// 4. \Magento\Customer\Model\Layout\DepersonalizePlugin::afterGenerateElements:
171+
// - clear customer session
172+
// - restore session._form_key
173+
// - restore customer session.customerGroupId, empty customer object with customer group
174+
// 5. \Magento\Catalog\Model\Layout\DepersonalizePlugin::afterGenerateElements:
175+
// - clear catalog session
176+
// 6. \Magento\Persistent\Model\Layout\DepersonalizePlugin::afterGenerateElements:
177+
// - clear persistent session
178+
// 7. \Magento\CustomerSegment\Model\Layout\DepersonalizePlugin::afterGenerateElements:
179+
// - httpContext->setValue(Data::CONTEXT_SEGMENT)
180+
// - restore customerSession->setCustomerSegmentIds
181+
// 8. \Magento\Checkout\Model\Layout\DepersonalizePlugin::afterGenerateElements:
182+
// - clear checkout session
183+
```
184+
185+
## All Depersonalize examples
186+
187+
\Magento\Catalog\Model\Layout\DepersonalizePlugin::afterGenerateElements:
188+
- clear catalog session
189+
190+
191+
192+
## Catalog frontend action
193+
194+
Magento has alternative implementation of recently viewed products, handled by Catalog module.
195+
It works with full page cache, but:
196+
197+
- is **not integrated** into customer segment conditions
198+
- frontend synchronization must be enabled, adding extra calls on every page
199+
200+
When sync is enabled, it makes 2 AJAX calls with every page opening:
201+
- synchronize recently viewed products from local storage
202+
- synchronize recently compared products from local storage
203+
204+
Configuration:
205+
206+
- `catalog/recently_products/synchronize_with_backend` = 0
207+
- `catalog/recently_products/recently_viewed_lifetime` = 1000
208+
- `catalog/recently_products/scope` - store view, store, website
209+
210+
Other:
211+
212+
- db table `catalog_product_frontend_action`
213+
- cron `catalog_product_frontend_actions_flush` - every minute \Magento\Catalog\Cron\FrontendActionsFlush:
214+
- deletes compared, viewed older than (default 1000) seconds
215+
- frontend controller 'catalog/product_frontend_action/synchronize'
216+
217+
Notable classes:
218+
219+
- Magento\Catalog\Model\FrontendStorageConfigurationPool
220+
- Magento\Catalog\Model\Widget\RecentlyViewedStorageConfiguration
221+
222+
223+
\Magento\Catalog\Block\FrontendStorageManager:
224+
225+
- recently_viewed_product
226+
- recently_compared_product
227+
- product_data_storage
228+
- vendor/magento/module-catalog/view/frontend/web/js/storage-manager.js
229+
230+
customer data section:
231+
232+
- recently_viewed_product
233+
- recently_compared_product
234+
- product_data_storage
235+
236+
Triggering recently viewed update on frontend:
237+
238+
- catalog_product_view.xml
239+
- Magento\Catalog\Block\Ui\ProductViewCounter
240+
- vendor/magento/module-catalog/view/frontend/templates/product/view/counter.phtml
241+
- vendor/magento/module-catalog/view/frontend/web/js/product/view/provider.js
242+
243+
\Magento\Catalog\Model\ProductRender - DTO
244+
245+
\Magento\Catalog\Ui\DataProvider\Product\ProductRenderCollectorComposite::collect:
246+
247+
- Url - url, addToCartButton, addToCompareButton
248+
- AdditionalInfo - isSalable, type, name, id
249+
- Image - images
250+
- Price - priceInfo
251+
- ... wishlist, review, tax, gift card, bundle price
252+
253+
254+
widget `catalog_recently_compared` template `product/widget/compared/list.phtml`:
255+
256+
- UI component `widget_recently_compared` - listing, columns
257+
- Magento_Catalog/js/product/provider-compared.js
258+
- Magento_Catalog/js/product/storage/storage-service.js
259+
- Magento_Catalog/js/product/storage/data-storage.js - get product data from customer section. recently viewed, compared

0 commit comments

Comments
 (0)