[IMP] website[_event,_sale]: add plausible as Analytics solution

This commit add the way to specify the Plausible shared key auth token and
the plausible domain on your website to have the Plausible Dashboard integrated
in your Website > Dashboard > Analytics menu.

Some custom event are already pre-configured as:

Push an event 'Shop' on confirmation on ecommerce (with amount bucket +/- 50)
Push an event 'Lead Generation' on:
    'Thank you' page of contactus
    Confirmation of subscription for an event

From this way, the end user can just add a goal 'Lead Generation'
or 'Shop' on Plausible to have the Goal values visible.

closes odoo/odoo#91058

Related: odoo/documentation#2007
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
This commit is contained in:
Jeremy Kersten
2022-05-18 20:33:34 +02:00
parent 3bec61a95b
commit cccd6eb01d
12 changed files with 146 additions and 5 deletions
+1
View File
@@ -134,6 +134,7 @@
'website/static/src/js/menu/navbar.js',
'website/static/src/js/show_password.js',
'website/static/src/js/post_link.js',
'website/static/src/js/plausible.js',
'website/static/src/js/user_custom_javascript.js',
],
'web.assets_frontend_minimal': [
+1
View File
@@ -38,6 +38,7 @@ class WebsiteBackend(http.Controller):
ga_client_id=current_website.google_management_client_id or '',
ga_analytics_key=current_website.google_analytics_key or '',
)
dashboard_data['dashboards']['plausible_share_url'] = current_website._get_plausible_share_url()
return dashboard_data
@http.route('/website/dashboard/set_ga_data', type='json', auth='user')
+1
View File
@@ -189,6 +189,7 @@
</div>
</section>
</div>
<input t-if='website.plausible_shared_key' type='hidden' class='js_plausible_push' data-event-name='Lead Generation' data-event-params='{"CTA": "Contact Us"}' />
</t>
</t>
</field>
+38 -1
View File
@@ -6,6 +6,8 @@ from odoo import api, fields, models
from odoo.exceptions import UserError
from odoo.tools.translate import _
from werkzeug import urls
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
@@ -74,7 +76,14 @@ class ResConfigSettings(models.TransientModel):
'Google Search Console',
related='website_id.google_search_console',
readonly=False)
plausible_shared_key = fields.Char(
'Plausible auth Key',
related='website_id.plausible_shared_key',
readonly=False)
plausible_site = fields.Char(
'Plausible Site (e.g. domain.com)',
related='website_id.plausible_site',
readonly=False)
cdn_activated = fields.Boolean(
related='website_id.cdn_activated',
readonly=False)
@@ -118,6 +127,10 @@ class ResConfigSettings(models.TransientModel):
"Use a image by default for sharing",
compute='_compute_has_default_share_image',
inverse='_inverse_has_default_share_image')
has_plausible_shared_key = fields.Boolean(
"Plausible Analytics",
compute='_compute_has_plausible_shared_key',
inverse='_inverse_has_plausible_shared_key')
module_website_livechat = fields.Boolean()
module_marketing_automation = fields.Boolean()
@@ -126,6 +139,18 @@ class ResConfigSettings(models.TransientModel):
for config in self:
config.shared_user_account = not config.website_id.specific_user_account
@api.onchange('plausible_shared_key')
def _onchange_shared_key(self):
for config in self:
value = config.plausible_shared_key
if value and value.startswith('http'):
try:
url = urls.url_parse(value)
config.plausible_shared_key = urls.url_decode(url.query).get('auth', '')
config.plausible_site = url.path.split('/')[-1]
except Exception: # noqa
pass
def _inverse_shared_user_account(self):
for config in self:
config.website_id.specific_user_account = not config.shared_user_account
@@ -141,6 +166,18 @@ class ResConfigSettings(models.TransientModel):
for config in self:
config.website_id.auth_signup_uninvited = config.auth_signup_uninvited
@api.depends('website_id')
def _compute_has_plausible_shared_key(self):
for config in self:
config.has_plausible_shared_key = bool(config.plausible_shared_key)
def _inverse_has_plausible_shared_key(self):
for config in self:
if config.has_plausible_shared_key:
continue
config.plausible_shared_key = False
config.plausible_site = False
@api.depends('website_id')
def _compute_has_google_analytics(self):
for config in self:
+19
View File
@@ -113,6 +113,9 @@ class Website(models.Model):
google_maps_api_key = fields.Char('Google Maps API Key')
plausible_shared_key = fields.Char()
plausible_site = fields.Char()
user_id = fields.Many2one('res.users', string='Public User', required=True)
cdn_activated = fields.Boolean('Content Delivery Network (CDN)')
cdn_url = fields.Char('CDN Base URL', default='')
@@ -731,6 +734,22 @@ class Website(models.Model):
page_temp = page_url + (inc and "-%s" % inc or "")
return page_temp
def _get_plausible_script_url(self):
return self.env['ir.config_parameter'].sudo().get_param(
'website.plausible_script',
'https://plausible.io/js/plausible.js'
)
def _get_plausible_server(self):
return self.env['ir.config_parameter'].sudo().get_param(
'website.plausible_server',
'https://plausible.io'
)
def _get_plausible_share_url(self):
embed_url = f'/share/{self.plausible_site}?auth={self.plausible_shared_key}&embed=true&theme=system'
return self.plausible_shared_key and urls.url_join(self._get_plausible_server(), embed_url) or ''
def get_unique_key(self, string, template_module=False):
""" Given a string, return an unique key including module prefix.
It will be suffixed by a counter if it already exists to garantee uniqueness.
+32
View File
@@ -0,0 +1,32 @@
/** @odoo-module **/
import publicWidget from 'web.public.widget';
publicWidget.registry.o_plausible_push = publicWidget.Widget.extend({
selector: '.js_plausible_push',
/**
* @override
*/
start() {
window.plausible = window.plausible || function () {
(window.plausible.q = window.plausible.q || []).push(arguments);
};
this._push();
return this._super(...arguments);
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Pushes the event `data-event-name` to Plausible with params
* `data-event-params`
*/
_push() {
const evName = this.$el.data('event-name');
const evParams = this.$el.data('event-params') || {};
window.plausible(evName, {props: evParams});
},
});
@@ -116,11 +116,11 @@
}
}
.o_dashboard_visits {
.o_box > h2 {
padding: 15px;
}
h2 {
padding: 15px;
}
.o_dashboard_visits {
.o_demo_background {
@@ -29,6 +29,7 @@
<t t-name="website.dashboard_content">
<div class="o_website_dashboard_content">
<t t-call="website.plausible_content"/>
<t t-call="website.google_analytics_content"/>
</div>
</t>
@@ -53,6 +54,20 @@
</div>
</div>
</t>
<t t-name="website.plausible_content">
<div class="row" t-if="widget.groups.website_designer &amp;&amp; widget.dashboards_data.plausible_share_url">
<div class="col-12 o_box">
<h2>Analytics</h2>
<div>
<div class="row">
<div class="embed-responsive embed-responsive-1by1">
<iframe t-att-src='widget.dashboards_data.plausible_share_url' class="embed-responsive-item" frameborder="0" loading="lazy"/>
</div>
</div>
</div>
</div>
</div>
</t>
<div t-name="website.unauthorized_analytics" class="col-12 js_unauthorized_message mb16">
<span t-if="reason === 'not_connected'">You need to log in to your Google Account before: </span>
@@ -282,6 +282,36 @@
</div>
</div>
</div>
<div class="col-12 col-lg-offset-6 col-lg-6 o_setting_box" id="plausbile_setting">
<div class="o_setting_left_pane">
<field name="has_plausible_shared_key"/>
</div>
<div class="o_setting_right_pane">
<label for="has_plausible_shared_key"/>
<div class="text-muted">
Use Plausible.io, Simple and privacy-friendly Google Analytics alternative
</div>
<div class="content-group" attrs="{'invisible': [('has_plausible_shared_key', '=', False)]}">
<div class="row mt16">
<label class="col-lg-3 o_light_label" string="Shared Link Auth" for="plausible_shared_key"/>
<field name="plausible_shared_key"
attrs="{'required': [('has_plausible_shared_key', '=', True)]}"/>
</div>
<div class="row mt16">
<label class="col-lg-3 o_light_label" string="Site" for="plausible_site"/>
<field name="plausible_site"
attrs="{'required': [('has_plausible_shared_key', '=', True)]}"/>
</div>
</div>
<div attrs="{'invisible': [('has_plausible_shared_key', '=', False)]}">
<a href="https://www.odoo.com/documentation/master/applications/websites/website/optimize/plausible.html"
class="oe_link" target="_blank">
<i class="fa fa-arrow-right"/>
How to create my Plausible Shared Link
</a>
</div>
</div>
</div>
</div>
</div>
</xpath>
@@ -154,6 +154,9 @@
gtag('config', '<t t-esc="website.google_analytics_key"/>');
</script>
</t>
<t t-if="website and website.plausible_shared_key and not editable">
<script id="plausible_script" name="plausible" defer="defer" t-att-data-domain="website.plausible_site" t-att-src="website._get_plausible_script_url()"></script>
</t>
</xpath>
<!-- Page options -->
@@ -406,6 +406,7 @@
</div>
</div>
</div>
<input t-if='website.plausible_shared_key' type='hidden' class='js_plausible_push' data-event-name='Lead Generation' t-attf-data-event-params='{"CTA": "Event Registration"}' />
</t>
</template>
+1
View File
@@ -1875,6 +1875,7 @@
</div>
<div class="oe_structure" id="oe_structure_website_sale_confirmation_3"/>
</div>
<input t-if='website.plausible_shared_key' type='hidden' class='js_plausible_push' data-event-name='Shop' t-attf-data-event-params='{"CTA": "Order Confirmed", "amount": "#{"%3s-%3s" % (max(0, round(order.amount_total/100)*100 - 50), round(order.amount_total/100)*100 + 50)}"}' />
</t>
</template>