Skip to content

Commit def0796

Browse files
committed
Allow setting a canonical URL via ogp_canonical_url
1 parent b308949 commit def0796

File tree

3 files changed

+29
-16
lines changed

3 files changed

+29
-16
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ Users hosting documentation on Read The Docs *do not* need to set any of the fol
5353
* This is not required. List of custom html snippets to insert.
5454
* `ogp_enable_meta_description`
5555
* This is not required. When `True`, generates `<meta name="description" content="...">` from the page.
56+
* `ogp_canonical_url`
57+
* This is not required. This option can be used to override the "canonical" URL for the page,
58+
and is used for `og:url` and the URL text in generated social media preview cards.
59+
It is most useful with versioned documentation, where you intend to set the "stable"
60+
or "latest" version as the canonical location of each page, similarly to `rel="canonical"`.
61+
If not set, the option defaults to the value of `ogp_site_url`.
5662

5763
## Example Config
5864

sphinxext/opengraph/__init__.py

+17-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import os
4+
import posixpath
45
from pathlib import Path
56
from typing import TYPE_CHECKING
67
from urllib.parse import urljoin, urlparse, urlsplit, urlunsplit
@@ -100,11 +101,16 @@ def get_tags(
100101
tags["og:type"] = config.ogp_type
101102

102103
if not config.ogp_site_url and os.getenv("READTHEDOCS"):
103-
config.ogp_site_url = read_the_docs_site_url(config.html_baseurl)
104+
ogp_site_url = read_the_docs_site_url(config.html_baseurl)
105+
else:
106+
ogp_site_url = config.ogp_site_url
107+
108+
# If ogp_canonical_url is not set, default to the value of ogp_site_url
109+
ogp_canonical_url = config.ogp_canonical_url or ogp_site_url
104110

105111
# url tag
106112
# Get the URL of the specific page
107-
page_url = urljoin(config.ogp_site_url, builder.get_target_uri(context["pagename"]))
113+
page_url = urljoin(ogp_canonical_url, builder.get_target_uri(context["pagename"]))
108114
tags["og:url"] = page_url
109115

110116
# site name tag, False disables, default to project if ogp_site_name not
@@ -156,6 +162,8 @@ def get_tags(
156162
title=title,
157163
description=description,
158164
pagename=context["pagename"],
165+
ogp_site_url=ogp_site_url,
166+
ogp_canonical_url=ogp_canonical_url,
159167
srcdir=srcdir,
160168
outdir=outdir,
161169
config=config,
@@ -202,7 +210,7 @@ def get_tags(
202210
else: # ogp_image is set
203211
# ogp_image is defined as being relative to the site root.
204212
# This workaround is to keep that functionality from breaking.
205-
root = config.ogp_site_url
213+
root = ogp_site_url
206214

207215
image_url = urljoin(root, image_url_parsed.path)
208216
tags["og:image"] = image_url
@@ -251,6 +259,8 @@ def social_card_for_page(
251259
title: str,
252260
description: str,
253261
pagename: str,
262+
ogp_site_url: str,
263+
ogp_canonical_url: str,
254264
*,
255265
srcdir: str | Path,
256266
outdir: str | Path,
@@ -272,7 +282,7 @@ def social_card_for_page(
272282
# Site URL
273283
site_url = config_social.get("site_url", True)
274284
if site_url is True:
275-
url_text = config.ogp_site_url.split("://")[-1]
285+
url_text = ogp_canonical_url.split("://")[-1]
276286
elif isinstance(site_url, str):
277287
url_text = site_url
278288

@@ -286,15 +296,12 @@ def social_card_for_page(
286296
pagename,
287297
srcdir=srcdir,
288298
outdir=outdir,
289-
config=config,
290299
env=env,
300+
html_logo=config.html_logo,
291301
)
292302

293303
# Link the image in our page metadata
294-
# We use os.path.sep to standardize behavior acros *nix and Windows
295-
url = config.ogp_site_url.strip("/")
296-
image_path = str(image_path).replace(os.path.sep, "/").strip("/")
297-
return f"{url}/{image_path}"
304+
return posixpath.join(ogp_site_url, image_path.as_posix())
298305

299306

300307
def html_page_context(
@@ -320,6 +327,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
320327
# ogp_site_url="" allows relative by default, even though it's not
321328
# officially supported by OGP.
322329
app.add_config_value("ogp_site_url", "", "html")
330+
app.add_config_value("ogp_canonical_url", "", "html")
323331
app.add_config_value("ogp_description_length", DEFAULT_DESCRIPTION_LENGTH, "html")
324332
app.add_config_value("ogp_image", None, "html")
325333
app.add_config_value("ogp_image_alt", None, "html")

sphinxext/opengraph/socialcards.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
from matplotlib.figure import Figure
1919
from matplotlib.text import Text
20-
from sphinx.config import Config
2120
from sphinx.environment import BuildEnvironment
2221

2322
PltObjects: TypeAlias = tuple[Figure, Text, Text, Text, Text]
@@ -68,8 +67,8 @@ def create_social_card(
6867
*,
6968
srcdir: str | Path,
7069
outdir: str | Path,
71-
config: Config,
7270
env: BuildEnvironment,
71+
html_logo: str | None = None,
7372
) -> Path:
7473
"""Create a social preview card according to page metadata.
7574
@@ -105,8 +104,8 @@ def create_social_card(
105104
# Large image to the top right
106105
if cs_image := config_social.get("image"):
107106
kwargs_fig["image"] = Path(srcdir) / cs_image
108-
elif config.html_logo:
109-
kwargs_fig["image"] = Path(srcdir) / config.html_logo
107+
elif html_logo:
108+
kwargs_fig["image"] = Path(srcdir) / html_logo
110109

111110
# Mini image to the bottom right
112111
if cs_image_mini := config_social.get("image_mini"):
@@ -133,10 +132,10 @@ def create_social_card(
133132
kwargs_fig[img] = None
134133

135134
# These are passed directly from the user configuration to our plotting function
136-
pass_through_config = ["text_color", "line_color", "background_color", "font"]
135+
pass_through_config = ("text_color", "line_color", "background_color", "font")
137136
for config in pass_through_config:
138-
if config_social.get(config):
139-
kwargs_fig[config] = config_social.get(config)
137+
if cs_config := config_social.get(config):
138+
kwargs_fig[config] = cs_config
140139

141140
# Generate the image and store the matplotlib objects so that we can re-use them
142141
try:

0 commit comments

Comments
 (0)