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 @@
+
@@ -53,6 +54,20 @@ + +
+
+

Analytics

+
+
+
+