diff --git a/addons/website/__manifest__.py b/addons/website/__manifest__.py
index a910a2d7c6f..9dbd274884a 100644
--- a/addons/website/__manifest__.py
+++ b/addons/website/__manifest__.py
@@ -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': [
diff --git a/addons/website/controllers/backend.py b/addons/website/controllers/backend.py
index 87f9a42eb9a..2022acc97a7 100644
--- a/addons/website/controllers/backend.py
+++ b/addons/website/controllers/backend.py
@@ -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')
diff --git a/addons/website/data/website_data.xml b/addons/website/data/website_data.xml
index 3502bd06dba..23ce296082a 100644
--- a/addons/website/data/website_data.xml
+++ b/addons/website/data/website_data.xml
@@ -189,6 +189,7 @@
+
diff --git a/addons/website/models/res_config_settings.py b/addons/website/models/res_config_settings.py
index 2a7e8d791e9..0f510bffe8f 100644
--- a/addons/website/models/res_config_settings.py
+++ b/addons/website/models/res_config_settings.py
@@ -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:
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 595c58c7d50..593275a01f0 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -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.
diff --git a/addons/website/static/src/js/plausible.js b/addons/website/static/src/js/plausible.js
new file mode 100644
index 00000000000..fa8e3027faf
--- /dev/null
+++ b/addons/website/static/src/js/plausible.js
@@ -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});
+ },
+});
diff --git a/addons/website/static/src/scss/website.backend.scss b/addons/website/static/src/scss/website.backend.scss
index 1a1a1d7a4c2..874a9a728b4 100644
--- a/addons/website/static/src/scss/website.backend.scss
+++ b/addons/website/static/src/scss/website.backend.scss
@@ -116,11 +116,11 @@
}
}
- .o_dashboard_visits {
+ .o_box > h2 {
+ padding: 15px;
+ }
- h2 {
- padding: 15px;
- }
+ .o_dashboard_visits {
.o_demo_background {
diff --git a/addons/website/static/src/xml/website.backend.xml b/addons/website/static/src/xml/website.backend.xml
index f272f847144..c54f98dd540 100644
--- a/addons/website/static/src/xml/website.backend.xml
+++ b/addons/website/static/src/xml/website.backend.xml
@@ -29,6 +29,7 @@
Analytics
+