diff --git a/docs/user_guide/analytics.rst b/docs/user_guide/analytics.rst index 3016ddf91..6e18ab4f5 100644 --- a/docs/user_guide/analytics.rst +++ b/docs/user_guide/analytics.rst @@ -1,6 +1,57 @@ Analytics and usage services ============================ +The theme supports several web analytics services via the ``analytics`` option. It is configured +by passing a dictionary with options. See the sections bellow for relevant +options depending on the analytics provider that you want to use. + +.. code:: python + + html_theme_options = { + # See below for options for each service + "analytics": analytics_options, + } + +Generally speaking we recommend using Plausible over Google Analytics because +it has a better story around user security and privacy. In addition, it is more +open-source and transparent. In fact, +`you can self-host a Plausible server `__. + +.. admonition:: Get a self-hosted Plausible server at ``scientific-python.org`` + :class: tip + + If your documentation is for a package that is part of the SciPy / PyData + ecosystem, they might be able to host a Plausible server for you at + ``.scientific-python.org``. + To ask about this, contact them on the social media platform of your choice + and learn more at `scientific-python.org `__. + +Plausible Analytics +=================== + +`plausible.io `__ can be used to gather simple +and privacy-friendly analytics for the site. To configure, you will need to provide two things: + +- A URL pointing to the JavaScript analytics script that is served by your Plausible server +- A domain that reflects where your documentation lives + +Plausible' javascript will be included in all html pages to gather metrics. +The dashboard with analytics results will be accessible at ``https:///``. + +.. code:: python + + # To be re-used in html_theme_options["analytics"] + analytics_options = { + # The domain you'd like to use for this analytics instance + "plausible_analytics_domain": "my-domain", + # The analytics script that is served by Plausible + "plausible_analytics_url": "https://.../script.js", + } + +.. seealso:: + + See the `Plausible Documentation `__ for more information about this script. + Google Analytics ================ @@ -9,6 +60,7 @@ Google Analytics' javascript is included in the html pages. .. code:: python - html_theme_options = { + # To be re-used in html_theme_options["analytics"] + analytics_options = { "google_analytics_id": "G-XXXXXXXXXX", } diff --git a/src/pydata_sphinx_theme/__init__.py b/src/pydata_sphinx_theme/__init__.py index 32ea3702e..59b8e15c1 100644 --- a/src/pydata_sphinx_theme/__init__.py +++ b/src/pydata_sphinx_theme/__init__.py @@ -2,6 +2,7 @@ Bootstrap-based sphinx theme from the PyData community """ import os +import warnings from pathlib import Path import jinja2 @@ -49,33 +50,59 @@ def update_config(app, env): ) # Add an analytics ID to the site if provided - # Currently only supports the two types of Google Analytics id. + analytics = theme_options.get("analytics", {}) + # deprecated options for Google Analytics + # TODO: deprecate >= v0.12 gid = theme_options.get("google_analytics_id") if gid: - # In this case it is "new-style" google analytics - if "G-" in gid: - gid_js_path = f"https://www.googletagmanager.com/gtag/js?id={gid}" - gid_script = f""" - window.dataLayer = window.dataLayer || []; - function gtag(){{ dataLayer.push(arguments); }} - gtag('js', new Date()); - gtag('config', '{gid}'); - """ - # In this case it is "old-style" google analytics - else: - gid_js_path = "https://www.google-analytics.com/analytics.js" - gid_script = f""" - window.ga = window.ga || function () {{ - (ga.q = ga.q || []).push(arguments) }}; - ga.l = +new Date; - ga('create', '{gid}', 'auto'); - ga('set', 'anonymizeIp', true); - ga('send', 'pageview'); + msg = ( + "'google_analytics_id' is deprecated and will be removed in " + "version 0.11, please refer to the documentation " + "and use 'analytics' instead." + ) + warnings.warn(msg, DeprecationWarning, stacklevel=2) + analytics.update({"google_analytics_id": gid}) + + if analytics: + # Plausible analytics + plausible_domain = analytics.get("plausible_analytics_domain") + plausible_url = analytics.get("plausible_analytics_url") + + # Ref: https://plausible.io/docs/plausible-script + if plausible_domain and plausible_url: + plausible_script = f""" + data-domain={plausible_domain} src={plausible_url} """ - - # Link the JS files - app.add_js_file(gid_js_path, loading_method="async") - app.add_js_file(None, body=gid_script) + # Link the JS file + app.add_js_file(None, body=plausible_script, loading_method="defer") + + # Two types of Google Analytics id. + gid = analytics.get("google_analytics_id") + if gid: + # In this case it is "new-style" google analytics + if "G-" in gid: + gid_js_path = f"https://www.googletagmanager.com/gtag/js?id={gid}" + gid_script = f""" + window.dataLayer = window.dataLayer || []; + function gtag(){{ dataLayer.push(arguments); }} + gtag('js', new Date()); + gtag('config', '{gid}'); + """ + # In this case it is "old-style" google analytics + else: + gid_js_path = "https://www.google-analytics.com/analytics.js" + gid_script = f""" + window.ga = window.ga || function () {{ + (ga.q = ga.q || []).push(arguments) }}; + ga.l = +new Date; + ga('create', '{gid}', 'auto'); + ga('set', 'anonymizeIp', true); + ga('send', 'pageview'); + """ + + # Link the JS files + app.add_js_file(gid_js_path, loading_method="async") + app.add_js_file(None, body=gid_script) def prepare_html_config(app, pagename, templatename, context, doctree): diff --git a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf index 8fde846ae..7908fc168 100644 --- a/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf +++ b/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/theme.conf @@ -17,7 +17,7 @@ gitlab_url = twitter_url = icon_links_label = Icon Links icon_links = -google_analytics_id = +analytics = favicons = show_prev_next = True search_bar_text = Search the docs ... @@ -43,3 +43,6 @@ announcement = # DEPRECATE after 0.11 logo_text = + +# DEPRECATE after 0.12 +google_analytics_id = diff --git a/tests/test_build.py b/tests/test_build.py index 5e7f726d2..1fea01388 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -540,22 +540,55 @@ def test_edit_page_url(sphinx_build_factory, html_context, edit_url): assert edit_link[0].attrs["href"] == edit_url, f"edit link didn't match {edit_link}" -def test_new_google_analytics_id(sphinx_build_factory): - confoverrides = {"html_theme_options.google_analytics_id": "G-XXXXX"} - sphinx_build = sphinx_build_factory("base", confoverrides=confoverrides) - sphinx_build.build() - index_html = sphinx_build.html_tree("index.html") - - # Search all the scripts and make sure one of them has the Google tag in there - tags_found = False - for script in index_html.select("script"): - if script.string and "gtag" in script.string and "G-XXXXX" in script.string: - tags_found = True - assert tags_found is True - - -def test_old_google_analytics_id(sphinx_build_factory): - confoverrides = {"html_theme_options.google_analytics_id": "UA-XXXXX"} +@pytest.mark.parametrize( + "provider,tags", + [ + # TODO: Deprecate old-style analytics config >= 0.12 + # new_google_analytics_id + ({"html_theme_options.google_analytics_id": "G-XXXXX"}, ["gtag", "G-XXXXX"]), + # old_google_analytics_id + ({"html_theme_options.google_analytics_id": "UA-XXXXX"}, ["ga", "UA-XXXXX"]), + # google analytics + ( + {"html_theme_options.analytics": {"google_analytics_id": "G-XXXXX"}}, + ["gtag", "G-XXXXX"], + ), + # plausible + ( + { + "html_theme_options.analytics": { + "plausible_analytics_domain": "toto", + "plausible_analytics_url": "http://.../script.js", + } + }, + ["data-domain", "toto"], + ), + # google and plausible + ( + { + "html_theme_options.analytics": { + "google_analytics_id": "G-XXXXX", + "plausible_analytics_domain": "toto", + "plausible_analytics_url": "http://.../script.js", + } + }, + ["gtag", "G-XXXXX"], + ), + # TODO: Deprecate old-style analytics config >= 0.12 + ( + { + "html_theme_options.analytics": { + "plausible_analytics_domain": "toto", + "plausible_analytics_url": "http://.../script.js", + }, + "html_theme_options.google_analytics_id": "G-XXXXX", + }, + ["gtag", "G-XXXXX"], + ), + ], +) +def test_analytics(sphinx_build_factory, provider, tags): + confoverrides = provider sphinx_build = sphinx_build_factory("base", confoverrides=confoverrides) sphinx_build.build() index_html = sphinx_build.html_tree("index.html") @@ -563,7 +596,7 @@ def test_old_google_analytics_id(sphinx_build_factory): # Search all the scripts and make sure one of them has the Google tag in there tags_found = False for script in index_html.select("script"): - if script.string and "ga" in script.string and "UA-XXXXX" in script.string: + if script.string and tags[0] in script.string and tags[1] in script.string: tags_found = True assert tags_found is True