Dynamic snippets in Odoo 17 are modular components that allow for the dynamic display of content on web pages. These snippets can be tailored to showcase various types of information, such as product listings, testimonials, or promotional banners. What sets dynamic snippets apart is their ability to adapt and update based on predefined rules or conditions, offering a personalized and engaging browsing experience for users.
To craft a dynamic snippet, several components need to be developed: an XML file to define the snippet's view, a Python controller to retrieve data from the backend, and a JavaScript file to display backend data on the website.
Initially, generate an XML file in ‘static/src/xml/home_templates.xml’. Give an outline of the content of the snippet.
<template id="products_category_wise_template" name="Best Seller">
<!-- Template Best seller product dynamic snippet-->
<section class="best_seller_product_snippet">
<div class="ref-arrival-content">
<p class="ref-section_head ref-centerhead__underline ref-head--primary"
style="color: #0d5272;">Best Seller
</p>
</div>
<div id="top_products_carousel"/>
</section>
</template>
Once the snippet's view is defined, it's essential to integrate the snippet into the website builder's snippet blocks. To achieve this, create a view file inside the ‘views/snippet.xml ‘, Inherit the "website.snippets" template and incorporate our newly created snippet into it.
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="basic_snippet" inherit_id="website.snippets" name="Best seller Snippet">
<xpath expr="//div[@id='snippet_effect']//t[@t-snippet][last()]"
position="after">
<t t-snippet="module_name.products_category_wise_template"/>
</xpath>
</template>
</odoo>
Then create a controller file for the snippet, it is defined to retrieve data from the backend. In the provided example, we extract the total number of products sold.
import time
from odoo import http
from odoo.http import request
class DynamicSnippets(http.Controller):
"""This class is for the getting values for dynamic product snippets
"""
@http.route('/top_selling_products', type='json', auth='public')
def top_selling(self):
"""Function for getting the current website,top sold products and
its categories.
Return
products-most sold products
unique_categories-categories of all products
current_website-the current website for checking products or
"""
current_website = request.env['website'].sudo().get_current_website().id
public_categ_id = request.env[
'product.public.category'].sudo().search_read([], ['name',
'website_id'])
products = []
public_categories = []
for category in public_categ_id:
products_search_read = request.env['product.template'].with_user(
1).search_read(
[('is_published', '=', True),
('public_categ_ids.id', '=', category['id'])],
['name', 'image_1920', 'public_categ_ids', 'website_id',
'sales_count', 'list_price'], order='sales_count')
for product in products_search_read:
if product['sales_count'] != 0:
products.append(product)
public_categories.append(category)
unique_categories = [dict(categories) for categories in
{tuple(sorted(record.items())) for record in
public_categories}]
products = sorted(products, key=lambda i: i['sales_count'],
reverse=True)
unique_id = "pc-%d" % int(time.time() * 1000)
return products, unique_categories, current_website, unique_id
Next, we can define the view of the snippet with all the necessary data and styles set. Below is the code snippet, which should be placed in the ‘src/xml/best_seller_snippet_templates.xml’ file.
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Template for displaying top-selling products in categories -->
<templates id="best_seller_template" xml:space="preserve">
<t t-name="module_name.products_category_wise">
<div id="top_selling_products_carousel" class="container">
<div id="TopuniqueId" class="large-12 columns">
<div id="bestSellCarousel" class="owl-carousel owl-theme owl-loaded owl-drag">
<div class="owl-stage-outer">
<div class="owl-stage" style="transform: translate3d(-1188px, 0px, 0px); transition: all 0.25s ease 0s; width: 2376px;">
<t t-foreach="chunkData" t-as="data" t-key="data_index">
<t t-foreach="data" t-as="vals" t-key="vals_index">
<div class="owl-item" id="card_id" style="width: 178px; margin-right: 20px;">
<a class="o_carousel_product_img_link o_dynamic_product_hovered stretched-link"
t-attf-href="/shop/product/{{vals.id}}">
<div class="overflow-hidden rounded">
<img class="card-img-top o_img_product_square o_img_product_cover h-auto"
t-attf-src="data:image/jpeg;base64,{{vals.image_1920}}"/>
</div>
</a>
<div class="o_carousel_product_card_body d-flex flex-wrap flex-column justify-content-between h-100 p-3">
<div class="h6 card-title"
t-esc="vals.name"/>
</div>
<p class="ref-prdt-price"
style=" margin-top: -20px;color: #0D5272;font-weight: 600;justify-content: center;
align-items: center;font-size: 20px;
margin-left: 16px;">
<span class="ref-prdt-offer-price"
data-oe-type="monetary"
data-oe-expression="vals.list_price">$ <span
class="oe_currency_value"
t-esc="vals.list_price"/>
</span>
</p>
</div>
</t>
</t>
</div>
</div>
</div>
</div>
</div>
</t>
</templates>
Now, our snippet is part of the Dynamic snippet section. Next, to show the data on the website, we'll use JavaScript.
/** @odoo-module */
import PublicWidget from "@web/legacy/js/public/public_widget";
import { jsonrpc } from "@web/core/network/rpc_service";
import { renderToElement } from "@web/core/utils/render";
export function _chunk(array, size) {
const result = [];
for (let i = 0; i < array.length; i += size) {
result.push(array.slice(i, i + size));
}
return result;
}
var TopSellingProducts = PublicWidget.Widget.extend({
selector: '.best_seller_product_snippet',
willStart: async function () {
const data = await jsonrpc('/top_selling_products', {})
const [products, categories, website_id, unique_id] = data
Object.assign(this, {
products, categories, website_id, unique_id
})
},
start: function () {
const refEl = this.$el.find("#top_products_carousel")
const { products, categories, current_website_id, products_list} = this
const chunkData = chunk(products, 4)
refEl.html(renderToElement(module_name.products_category_wise', {
products,
categories,
current_website_id,
products_list,
chunkData
}))
}
});
PublicWidget.registry.products_category_wise_snippet = TopSellingProducts;
return TopSellingProducts;
In this step, we select sections using a class and retrieve data from the controller through jsonrpc call. Following this, we include an XML file in the data section and a JavaScript file in the asset action of the "__manifest__.py" file.
'data': [
'views/snippet.xml'
],
'assets': {
'web.assets_frontend': [
'module_name/static/src/js/best_seller_snippet.js',
'module_name/static/src/xml/best_seller_snippet_templates.xml',
'module_name/static/src/xml/home_templates.xml',
],
},
After installing or upgrading the module, navigate to the website and click on "Edit." You'll notice our snippet listed under "Dynamic Content," allowing you to easily drag and drop it onto the desired section of your webpage.
Dynamic snippets in Odoo 17 offer a powerful tool for creating engaging and personalized web content. By leveraging dynamic logic rules and intuitive editing tools, developers and designers can craft dynamic snippets that captivate audiences and drive user engagement. Embrace the possibilities of dynamic snippets in Odoo 17 and unlock a world of creative potential for your website. To read more about Snippet creation and how to Create Snippet Options in Odoo 17, please refer to our latest blog.