[IMP] website: change CTA based on website main objective

If user selects 'schedule appointments' as main objective in the configurator
and if the website_calendar module is installed then the Call To Action of
snippets s_banner, s_cover and s_call_to_action is changed to 'Schedule an
appointment' and redirect user to '/calendar' on click.

task-2518565

closes odoo/odoo#71162

Related: odoo/enterprise#18690
Related: odoo/design-themes#5
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
This commit is contained in:
Sébastien Mottet (oms)
2021-07-02 09:32:56 +00:00
committed by Jeremy Kersten
parent 731a173d49
commit cd3ca50548
9 changed files with 91 additions and 18 deletions
+60 -8
View File
@@ -8,7 +8,7 @@ import hashlib
import requests
import re
from lxml import html
from lxml import etree
from werkzeug import urls
from werkzeug.datastructures import OrderedMultiDict
from werkzeug.exceptions import NotFound
@@ -287,6 +287,9 @@ class Website(models.Model):
endpoint = website_api_endpoint + route
return iap_tools.iap_jsonrpc(endpoint, params=params)
def get_cta_data(self, website_purpose, website_type):
return {'cta_btn_text': False, 'cta_btn_href': '/contactus'}
@api.model
def configurator_init(self):
r = dict()
@@ -348,10 +351,15 @@ class Website(models.Model):
result = self.env['website'].new_page(name=feature_id.name, add_menu=True, template=feature_id.page_view_id.key)
pages_views[feature_id.iap_page_code] = result['view_id']
modules._button_immediate_function(lambda self: self.button_install())
modules.button_immediate_install()
# Force to refresh env after install of modules
self._cr.commit()
api.Environment.reset()
self.env = api.Environment(modules._cr, modules._uid, modules._context)
return pages_views
def configure_page(page_code, snippet_list, pages_views):
def configure_page(page_code, snippet_list, pages_views, cta_data):
if page_code == 'homepage':
page_view_id = website.homepage_id.view_id
else:
@@ -362,8 +370,7 @@ class Website(models.Model):
try:
view_id = self.env['website'].with_context(website_id=website.id).viewref(snippet)
if view_id:
rendered_snippet = pycompat.to_text(view_id._render())
el = html.fragment_fromstring(rendered_snippet)
el = etree.fromstring(view_id._render(values=cta_data))
# Add the data-snippet attribute to identify the snippet
# for compatibility code
@@ -382,8 +389,7 @@ class Website(models.Model):
shape_el = el.xpath("//*[hasclass('o_we_shape')]")
if shape_el:
shape_el[0].attrib['class'] += ' o_footer_extra_shape_mapping'
rendered_snippet = pycompat.to_text(html.tostring(el))
rendered_snippet = pycompat.to_text(etree.tostring(el))
rendered_snippets.append(rendered_snippet)
except ValueError as e:
logger.warning(e)
@@ -433,6 +439,9 @@ class Website(models.Model):
# modules
pages_views = set_features(kwargs.get('selected_features'))
# We need to refresh the environment of website because set_features installed some new module
# and we need the overrides of these new menus e.g. for .get_cta_data()
website = self.env['website'].browse(website.id)
# Load suggestion from iap for selected pages
requested_pages = list(pages_views.keys())
@@ -443,10 +452,53 @@ class Website(models.Model):
}
custom_resources = self._website_api_rpc('/api/website/1/configurator/custom_resources/%s' % kwargs.get('industry_id'), params)
# Update CTA
cta_data = website.get_cta_data(kwargs.get('website_purpose'), kwargs.get('website_type'))
if cta_data['cta_btn_text']:
xpath_view = 'website.snippets'
parent_view = self.env['website'].with_context(website_id=website.id).viewref(xpath_view)
self.env['ir.ui.view'].create({
'name': parent_view.key + ' CTA',
'key': parent_view.key + "_cta",
'inherit_id': parent_view.id,
'website_id': website.id,
'type': 'qweb',
'priority': 32,
'arch_db': """
<data>
<xpath expr="//t[@t-set='cta_btn_href']" position="replace">
<t t-set="cta_btn_href">%s</t>
</xpath>
<xpath expr="//t[@t-set='cta_btn_text']" position="replace">
<t t-set="cta_btn_text">%s</t>
</xpath>
</data>
""" % (cta_data['cta_btn_href'], cta_data['cta_btn_text'])
})
header_ids = [
'website.template_header_default_oe_structure_header_default_1',
'website.template_header_hamburger_oe_structure_header_hamburger_1',
'website.template_header_slogan_oe_structure_header_slogan_2',
'website.template_header_boxed_oe_structure_header_boxed_2',
'website.template_header_image_oe_structure_header_image_2',
]
for header_id in header_ids:
try:
view_id = self.env['website'].viewref(header_id)
if view_id:
el = etree.fromstring(view_id.arch_db)
btn_cta_el = el.xpath("//a[hasclass('btn_cta')]")
if btn_cta_el:
btn_cta_el[0].attrib['href'] = cta_data['cta_btn_href']
btn_cta_el[0].text = cta_data['cta_btn_text']
view_id.with_context(website_id=website.id).write({'arch_db': etree.tostring(el)})
except ValueError as e:
logger.warning(e)
# Update pages
pages = custom_resources.get('pages', {})
for page_code, snippet_list in pages.items():
configure_page(page_code, snippet_list, pages_views)
configure_page(page_code, snippet_list, pages_views, cta_data)
images = custom_resources.get('images', [])
set_images(images)
@@ -16,7 +16,7 @@ class WebsiteConfiguratorFeature(models.Model):
description = fields.Char(translate=True)
icon = fields.Char()
iap_page_code = fields.Char(help='Page code used to tell IAP website_service for which page a snippet list should be generated')
website_types_preselection = fields.Char(help='Comma-separated list of website type for which this feature should be pre-selected')
website_types_preselection = fields.Char(help='Comma-separated list of website type/purpose for which this feature should be pre-selected')
type = fields.Selection([('page', "Page"), ('app', "App")], compute='_compute_type')
page_view_id = fields.Many2one('ir.ui.view', ondelete='cascade')
module_id = fields.Many2one('ir.module.module', ondelete='cascade')
@@ -24,7 +24,8 @@ const WEBSITE_PURPOSES = {
1: {id: 1, label: _lt("get leads"), name: 'get_leads'},
2: {id: 2, label: _lt("develop the brand"), name: 'develop_brand'},
3: {id: 3, label: _lt("sell more"), name: 'sell_more'},
4: {id: 4, label: _lt("inform customers"), name: 'inform_customers'}
4: {id: 4, label: _lt("inform customers"), name: 'inform_customers'},
5: {id: 5, label: _lt("schedule appointments"), name: 'schedule_appointments'}
};
const PALETTE_NAMES = [
@@ -354,6 +355,10 @@ const actions = {
state.selectedType = id;
},
selectWebsitePurpose({state}, id) {
Object.values(state.features).filter((feature) => feature.module_state !== 'installed').forEach((feature) => {
// need to check id, since we set to undefined in mount() to avoid the auto next screen on back button
feature.selected |= id && feature.website_types_preselection.includes(WEBSITE_PURPOSES[id].name);
});
state.selectedPurpose = id;
},
selectIndustry({state}, id) {
@@ -475,6 +480,8 @@ async function applyConfigurator(self, themeName) {
industry_id: self.state.selectedIndustry,
selected_palette: selectedPalette,
theme_name: themeName,
website_purpose: WEBSITE_PURPOSES[self.state.selectedPurpose].name,
website_type: WEBSITE_TYPES[self.state.selectedType].name,
};
const resp = await rpc.query({
model: 'website',
+1 -1
View File
@@ -9,7 +9,7 @@
<div class="col-lg-6 jumbotron rounded o_cc o_cc1 pt32 pb32" data-name="Box">
<h1><font style="font-size: 62px;">Sell Online. Easily.</font></h1>
<p class="lead">This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
<a href="#" class="btn btn-primary mb-2">Contact Us</a>
<a t-att-href="cta_btn_href" class="btn btn-primary mb-2"><t t-esc="cta_btn_text">Contact Us</t></a>
</div>
</div>
</div>
@@ -11,7 +11,7 @@
</div>
<div class="col-lg-3 pt8">
<p style="text-align: right;">
<a href="/contactus" class="btn btn-primary btn-lg mb-2">Contact us</a>
<a t-att-href="cta_btn_href" class="btn btn-primary btn-lg mb-2"><t t-esc="cta_btn_text">Contact us</t></a>
</p>
</div>
</div>
+1 -1
View File
@@ -9,7 +9,7 @@
<h1 style="text-align: center;"><font style="font-size: 62px; font-weight: bold;">Catchy Headline</font></h1>
<p class="lead" style="text-align: center;">Write one or two paragraphs describing your product, services or a specific feature.<br/> To be successful your content needs to be useful to your readers.</p>
<p style="text-align: center;">
<a href="/contactus" class="btn btn-primary mb-2">Contact us</a>
<a t-att-href="cta_btn_href" class="btn btn-primary mb-2"><t t-esc="cta_btn_text">Contact us</t></a>
</p>
</div>
</section>
@@ -11,6 +11,8 @@
</xpath>
<xpath expr="//t[@id='default_snippets']" position="replace">
<t id="default_snippets">
<t t-set="cta_btn_text" t-value="False"/>
<t t-set="cta_btn_href">/contactus</t>
<div id="snippet_mega_menu" class="o_panel d-none">
<div class="o_panel_header">Mega Menu</div>
<div class="o_panel_body">
+10 -5
View File
@@ -125,6 +125,11 @@
<attribute name="data-name">Header</attribute>
</xpath>
<xpath expr="//header" position="before">
<t t-set="cta_btn_text" t-value="False"/>
<t t-set="cta_btn_href">/contactus</t>
</xpath>
<xpath expr="//footer" position="attributes">
<attribute name="data-name">Footer</attribute>
<!-- Background now controlled by css configuration, using color combinations -->
@@ -273,7 +278,7 @@
<div class="oe_structure oe_structure_solo" id="oe_structure_header_default_1">
<section class="s_text_block" data-snippet="s_text_block" data-name="Text">
<div class="container">
<a href="/contactus" class="btn btn-primary ml-4">Contact Us</a>
<a href="/contactus" class="btn btn-primary ml-4 btn_cta">Contact Us</a>
</div>
</section>
</div>
@@ -349,7 +354,7 @@
<div class="oe_structure oe_structure_solo" id="oe_structure_header_hamburger_1">
<section class="s_text_block" data-snippet="s_text_block" data-name="Text">
<div class="container">
<a href="/contactus" class="btn btn-primary ml-4">Contact Us</a>
<a href="/contactus" class="btn btn-primary ml-4 btn_cta">Contact Us</a>
</div>
</section>
</div>
@@ -697,7 +702,7 @@
<div class="oe_structure oe_structure_solo" id="oe_structure_header_slogan_2">
<section class="s_text_block" data-snippet="s_text_block" data-name="Text">
<div class="container">
<a href="/contactus" class="btn btn-primary ml-4">Contact Us</a>
<a href="/contactus" class="btn btn-primary ml-4 btn_cta">Contact Us</a>
</div>
</section>
</div>
@@ -926,7 +931,7 @@
<div class="oe_structure oe_structure_solo" id="oe_structure_header_boxed_2">
<section class="s_text_block" data-snippet="s_text_block" name="Text">
<div class="container">
<a href="/contactus" class="btn btn-primary ml-lg-4">Contact Us</a>
<a href="/contactus" class="btn btn-primary ml-lg-4 btn_cta">Contact Us</a>
</div>
</section>
</div>
@@ -1043,7 +1048,7 @@
<div class="oe_structure oe_structure_solo" id="oe_structure_header_image_2">
<section class="s_text_block" data-snippet="s_text_block" data-name="Text">
<div class="container">
<a href="/contactus" class="btn btn-primary mt-3 mt-lg-0 ml-lg-3">Contact Us</a>
<a href="/contactus" class="btn btn-primary mt-3 mt-lg-0 ml-lg-3 btn_cta">Contact Us</a>
</div>
</section>
</div>
+7
View File
@@ -12,3 +12,10 @@ class Website(models.Model):
suggested_controllers = super(Website, self).get_suggested_controllers()
suggested_controllers.append((_('Events'), url_for('/event'), 'website_event'))
return suggested_controllers
def get_cta_data(self, website_purpose, website_type):
cta_data = super(Website, self).get_cta_data(website_purpose, website_type)
if website_purpose == 'sell_more' and website_type == 'event':
cta_btn_text = _('Next Events')
return {'cta_btn_text': cta_btn_text, 'cta_btn_href': '/event'}
return cta_data