|
| 1 | +""" |
| 2 | +auto_siteurl — Automatically prefix root-absolute paths in content with SITEURL. |
| 3 | +
|
| 4 | +When deployed at a subpath (e.g. https://example.com/pr/428), root-absolute |
| 5 | +paths like href="/download" break because they resolve to the domain root |
| 6 | +instead of the subpath. This plugin prepends SITEURL so they become |
| 7 | +href="https://example.com/pr/428/download". |
| 8 | +
|
| 9 | +Scope — what this plugin covers: |
| 10 | + - href and src attributes in rendered article/page content (the HTML |
| 11 | + generated from .md files). This avoids having to patch every content |
| 12 | + file with {filename} syntax. |
| 13 | +
|
| 14 | +What this plugin does NOT cover (handled separately): |
| 15 | + - Template files (*.html under theme/templates/): these use Jinja2 |
| 16 | + directly and need explicit {{ SITEURL }} interpolation at the point |
| 17 | + of use (e.g. href="{{ SITEURL }}/path"). |
| 18 | + - Static CSS files (*.css under theme/static/): these are not processed |
| 19 | + by Pelican at all. Use CSS-relative paths instead (e.g. url('../images/') |
| 20 | + rather than url('/theme/images/')). |
| 21 | + - feed.xml: generated by Pelican's feed writer, which constructs URLs |
| 22 | + independently of the content pipeline. |
| 23 | +""" |
| 24 | + |
| 25 | +import re |
| 26 | +import logging |
| 27 | +from pelican import signals |
| 28 | + |
| 29 | +logger = logging.getLogger(__name__) |
| 30 | + |
| 31 | + |
| 32 | +def prefix_absolute_paths(content_object): |
| 33 | + siteurl = content_object.settings.get("SITEURL", "") |
| 34 | + if not siteurl: |
| 35 | + return |
| 36 | + |
| 37 | + if not hasattr(content_object, "_content") or not content_object._content: |
| 38 | + return |
| 39 | + |
| 40 | + # Replace href="/path" → href="SITEURL/path" and src="/path" → src="SITEURL/path". |
| 41 | + # The negative lookahead (?!/) skips protocol-relative URLs like //cdn.example.com. |
| 42 | + content_object._content = re.sub( |
| 43 | + r'(href|src)="/(?!/)', |
| 44 | + lambda m: f'{m.group(1)}="{siteurl}/', |
| 45 | + content_object._content, |
| 46 | + ) |
| 47 | + |
| 48 | + |
| 49 | +def register(): |
| 50 | + signals.content_object_init.connect(prefix_absolute_paths) |
0 commit comments