Magento 2: How Products Are Showing in Recently Viewed Products Widget

We all know that recently viewed products are easy to show anywhere on a Magento 2 website. There are many ways to show recently viewed products. The easiest way would be the widget way. For example, if you add the following content in your site

File: `app/code/[NameSpace]/[Module]/view/frontend/layout/default.xml`

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="footer-container">
            <block class="Magento\Catalog\Block\Widget\RecentlyViewed"
                   name="footer_recently_viewed_widget"
                   template="Magento_Catalog::product/widget/viewed/grid.phtml"
                   before="footer_new_links">
                <arguments>
                    <argument name="uiComponent" xsi:type="string">widget_recently_viewed</argument>
                    <argument name="page_size" xsi:type="number">16</argument>
                    <argument name="show_attributes" xsi:type="string">name,image,price,learn_more</argument>
                    <argument name="show_buttons" xsi:type="string">add_to_wishlist,add_to_cart</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

This will add recently viewed widget in all (well, most of the pages) Magento 2 pages footer section.

How is data passing to the widget from backend

Here I am going to explain how this widget will be rendered with product data. The widget configuration is defined and well, they can be altered by widget_recently_viewed.xml file. We can do this because the recently viewed widget is basically a uiComponent.

Since the widget is actually a uiComponent, it comes with well-defined facilities which are providing by Magento. One such facility is feed data to the uiComponent. This facility is known as dataSource. In the case of recently-viewed-widget, it uses Magento_Catalog/js/product/provider js component as it’s data provider. This is defined in the file widget_recently_viewed.xml file available in the Magento_Catalog module.

So whenever we visit a product details page, you can see that the Magento_Catalog/js/product/provider component is fed by the product data. The product data we can see here is actually the same that we get when we use Magento API service “. The data structure is shown below:

{
    "items": [
        {
            "add_to_cart_button": {
                "post_data": "{\"action\":\"http:\\/\\/example.test\\/checkout\\/cart\\/add\\/uenc\\/%25uenc%25\\/product\\/1195\\/\",\"data\":{\"product\":\"1195\",\"uenc\":\"%uenc%\"}}",
                "url": "http://example.test/checkout/cart/add/uenc/%25uenc%25/product/1195/",
                "required_options": true
            },
            "add_to_compare_button": {
                "post_data": null,
                "url": "{\"action\":\"http:\\/\\/example.test\\/catalog\\/product_compare\\/add\\/\",\"data\":{\"product\":\"1195\",\"uenc\":\"aHR0cDovL2xpdmVycG9vbC50ZXN0L3Jlc3QvVjEvcHJvZHVjdHMtcmVuZGVyLWluZm8_c2VhcmNoQ3JpdGVyaWFbcGFnZVNpemVdPTEmc2VhcmNoQ3JpdGVyaWFbY3VycmVudFBhZ2VdJTIwPTEmc3RvcmVJZD0xJmN1cnJlbmN5Q29kZT1VU0Qmc2VhcmNoQ3JpdGVyaWFbZmlsdGVyX2dyb3Vwc11bMF1bZmlsdGVyc11bMF1bZmllbGRdPWVudGl0eV9pZCZzZWFyY2hDcml0ZXJpYVtmaWx0ZXJfZ3JvdXBzXVswXVtmaWx0ZXJzXVswXVt2YWx1ZV09MTE5NQ,,\"}}",
                "required_options": null
            },
            "price_info": {
                "final_price": 65,
                "max_price": 65,
                "max_regular_price": 65,
                "minimal_regular_price": 65,
                "special_price": 65,
                "minimal_price": 65,
                "regular_price": 59.99,
                "formatted_prices": {
                    "final_price": "<span class=\"price\">$65.00</span>",
                    "max_price": "<span class=\"price\">$65.00</span>",
                    "minimal_price": "<span class=\"price\">$65.00</span>",
                    "max_regular_price": "<span class=\"price\">$65.00</span>",
                    "minimal_regular_price": null,
                    "special_price": "<span class=\"price\">$65.00</span>",
                    "regular_price": "<span class=\"price\">$59.99</span>"
                },
                "extension_attributes": {
                    "msrp": {
                        "msrp_price": "<span class=\"price\">$0.00</span>",
                        "is_applicable": "",
                        "is_shown_price_on_gesture": "",
                        "msrp_message": "",
                        "explanation_message": "Our price is lower than the manufacturer&#039;s &quot;minimum advertised price.&quot; As a result, we cannot show you the price in catalog or the product page. <br><br> You have no obligation to purchase the product once you know the price. You can simply remove the item from your cart."
                    },
                    "tax_adjustments": {
                        "final_price": 50,
                        "max_price": 50,
                        "max_regular_price": 50,
                        "minimal_regular_price": 50,
                        "special_price": 50,
                        "minimal_price": 50,
                        "regular_price": 59.99,
                        "formatted_prices": {
                            "final_price": "<span class=\"price\">$50.00</span>",
                            "max_price": "<span class=\"price\">$50.00</span>",
                            "minimal_price": "<span class=\"price\">$50.00</span>",
                            "max_regular_price": "<span class=\"price\">$50.00</span>",
                            "minimal_regular_price": null,
                            "special_price": "<span class=\"price\">$50.00</span>",
                            "regular_price": "<span class=\"price\">$59.99</span>"
                        }
                    },
                    "weee_attributes": [],
                    "weee_adjustment": "<span class=\"price\">$50.00</span>"
                }
            },
            "images": [
                {
                    "url": "http://example.test/static/version1588244834/frontend/Magento/default/en_GB/Magento_Catalog/images/product/placeholder/small_image.jpg",
                    "code": "recently_viewed_products_grid_content_widget",
                    "height": 440,
                    "width": 355,
                    "label": "Mens European Home Shirt 19/20",
                    "resized_width": 135,
                    "resized_height": 135
                },
                {
                    "url": "http://example.test/static/version1588244834/frontend/Magento/default/en_GB/Magento_Catalog/images/product/placeholder/small_image.jpg",
                    "code": "recently_viewed_products_list_content_widget",
                    "height": 270,
                    "width": 270,
                    "label": "Mens European Home Shirt 19/20",
                    "resized_width": 135,
                    "resized_height": 135
                },
                {
                    "url": "http://example.test/static/version1588244834/frontend/Magento/default/en_GB/Magento_Catalog/images/product/placeholder/small_image.jpg",
                    "code": "recently_viewed_products_images_names_widget",
                    "height": 90,
                    "width": 75,
                    "label": "Mens European Home Shirt 19/20",
                    "resized_width": 135,
                    "resized_height": 135
                },
                {
                    "url": "http://example.test/static/version1588244834/frontend/Magento/default/en_GB/Magento_Catalog/images/product/placeholder/small_image.jpg",
                    "code": "recently_compared_products_grid_content_widget",
                    "height": 300,
                    "width": 240,
                    "label": "Mens European Home Shirt 19/20",
                    "resized_width": 135,
                    "resized_height": 135
                },
                {
                    "url": "http://example.test/static/version1588244834/frontend/Magento/default/en_GB/Magento_Catalog/images/product/placeholder/small_image.jpg",
                    "code": "recently_compared_products_list_content_widget",
                    "height": 207,
                    "width": 270,
                    "label": "Mens European Home Shirt 19/20",
                    "resized_width": 135,
                    "resized_height": 135
                },
                {
                    "url": "http://example.test/static/version1588244834/frontend/Magento/default/en_GB/Magento_Catalog/images/product/placeholder/thumbnail.jpg",
                    "code": "recently_compared_products_images_names_widget",
                    "height": 90,
                    "width": 75,
                    "label": "Mens European Home Shirt 19/20",
                    "resized_width": 50,
                    "resized_height": 50
                }
            ],
            "url": "http://example.test/home-ss-euro-jersey-19-20",
            "id": 1195,
            "name": "Mens European Home Shirt 19/20",
            "type": "configurable",
            "is_salable": "1",
            "store_id": 1,
            "currency_code": "USD",
            "extension_attributes": {
                "wishlist_button": {
                    "post_data": null,
                    "url": "{\"action\":\"http:\\/\\/example.test\\/wishlist\\/index\\/add\\/\",\"data\":{\"product\":1195,\"uenc\":\"aHR0cDovL2xpdmVycG9vbC50ZXN0L3Jlc3QvVjEvcHJvZHVjdHMtcmVuZGVyLWluZm8_c2VhcmNoQ3JpdGVyaWFbcGFnZVNpemVdPTEmc2VhcmNoQ3JpdGVyaWFbY3VycmVudFBhZ2VdJTIwPTEmc3RvcmVJZD0xJmN1cnJlbmN5Q29kZT1VU0Qmc2VhcmNoQ3JpdGVyaWFbZmlsdGVyX2dyb3Vwc11bMF1bZmlsdGVyc11bMF1bZmllbGRdPWVudGl0eV9pZCZzZWFyY2hDcml0ZXJpYVtmaWx0ZXJfZ3JvdXBzXVswXVtmaWx0ZXJzXVswXVt2YWx1ZV09MTE5NQ,,\"}}",
                    "required_options": null
                },
                "review_html": ""
            }
        }
    ]
}

In case you are wondering how Magento provide this details, then it is done by the block class Magento\Catalog\Block\Ui\ProductViewCounter::getCurrentProductData(). This block is available in every product details page and its template adds below code in frontend:

<script type="text/x-magento-init">
    {
        "*": {
                "Magento_Catalog/js/product/view/provider": {
                    "data": <?= /* @noEscape */ $block->getCurrentProductData() ?>
            }
        }
    }
</script>

How data is showing in the frontend?

Now I hope it is clear how data is passing to the component. It is time to discuss how this is going to be used in the frontend.

I already mentioned that the recently-viewed-widget is actually a uiComponent. It is basically Listing type uiComponent which means it is basically Magento_Ui/js/grid/listing component. You can see following mapping in this component.

....
 
return Collection.extend({
        defaults: {
            ...

            imports: {
                rows: '${ $.provider }:data.items'
            },

            ....
        },

        ....

As you can see it map ${provider}:data.items details to rows property. this.rows is what actually used by listing component to show the details. The only question is here is what is ${provider} mentioning above. It is as I mentioned Magento_Catalog/js/product/provider. You can see below in this component:

...

return Element.extend({
        ....

        dataStorageHandler: function (dataStorage) {
            this.productStorage = dataStorage;
            this.productStorage.add(this.data.items);
        },
        
        ...

what we want to understand here is the data this.data.items is stored into local storage with the key product_data_storage and this is what recently-viewed-widget uiComponent is holding in this.rows.

So long story short, if you want to see the the product data details which is using by recently-viewed-widget can be seen in your browser under local-storage section. In chrome browser it will look like this.

I hope next time you see a recently viewed widget or recently compared widget, the above points will be definitely going to help you in great extend. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *