From 8be476e19f062e8bd76fd0be08e62c07c49f7aab Mon Sep 17 00:00:00 2001 From: Julio Lucero Date: Thu, 30 Jul 2026 15:54:42 -0300 Subject: [PATCH] Treat subdomains of the site host as internal links --- CHANGELOG.md | 1 + Gemfile.lock | 2 +- README.md | 2 +- lib/jekyll-external-link-accessibility.rb | 5 +++-- .../version.rb | 2 +- ...jekyll-external-link-accessibility_spec.rb | 22 +++++++++++++++++++ 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e35976..f1492df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # main [(unreleased)](https://github.com/fastruby/jekyll-external-link-accessibility/compare/v0.2.0...main) +- [FEATURE: Treat subdomains of the site host as internal links, so they keep their link equity](https://github.com/fastruby/jekyll-external-link-accessibility/pull/7) - [CHORE: Add an RSpec test suite and CI matrix running Ruby 2.7 through 4.0](https://github.com/fastruby/jekyll-external-link-accessibility/pull/6) # v0.2.0 / 2026-07-15 [(commits)](https://github.com/fastruby/jekyll-external-link-accessibility/compare/v0.1.0...v0.2.0) diff --git a/Gemfile.lock b/Gemfile.lock index 42c62e6..b010417 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - jekyll-external-link-accessibility (0.2.0) + jekyll-external-link-accessibility (0.3.0) jekyll (~> 4.0, >= 4.0.1) nokogiri (>= 1.12.0, < 2.0) diff --git a/README.md b/README.md index 48eed3c..bbce707 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This plugin makes every link in your blog posts open in a new tab accessibly (`t The plugin edits every link in a post, internal and external: - All links open in a new tab so readers don't lose their place, with a `title`, a new-tab icon, and a screen-reader-only "opens a new window" note. Skip a specific link by adding `data-no-external="true"`, e.g. `...`. -- External links (pointing to a host other than your site's `url` in `_config.yml`) also get a `rel` attribute (`external nofollow noopener noreferrer` by default, see Configuration). The `nofollow` keeps them from passing your link equity off-site, so internal links are left without a `rel`. The `www.` prefix and host casing are ignored when comparing hosts. +- External links (pointing to a host other than your site's `url` in `_config.yml`) also get a `rel` attribute (`external nofollow noopener noreferrer` by default, see Configuration). The `nofollow` keeps them from passing your link equity off-site, so internal links are left without a `rel`. The `www.` prefix and host casing are ignored when comparing hosts, and subdomains of your site's host (e.g. `docs.example.com` when your `url` is `https://example.com`) count as internal. ### Configuration You can override the default configuration by adding the following section to your Jekyll site's `_config.yml`: diff --git a/lib/jekyll-external-link-accessibility.rb b/lib/jekyll-external-link-accessibility.rb index b0946f3..3ab3fed 100644 --- a/lib/jekyll-external-link-accessibility.rb +++ b/lib/jekyll-external-link-accessibility.rb @@ -40,13 +40,14 @@ def self.modify_links(page) end # A link is external only when it points to a different host than the site. - # Relative links ("/blog/...") and absolute links to our own domain are internal, - # so they keep their link equity (no nofollow). + # Relative links ("/blog/..."), absolute links to our own domain and links to a + # subdomain of it are internal, so they keep their link equity (no nofollow). def self.external_link?(href, site_host) return false unless href.start_with?(*EXTERNAL_SCHEMES) link_host = host_for(href) return true if link_host.nil? + return false if site_host && link_host.end_with?(".#{site_host}") link_host != site_host end diff --git a/lib/jekyll-external-link-accessibility/version.rb b/lib/jekyll-external-link-accessibility/version.rb index 9683a5d..5abd670 100644 --- a/lib/jekyll-external-link-accessibility/version.rb +++ b/lib/jekyll-external-link-accessibility/version.rb @@ -2,6 +2,6 @@ module Jekyll class ExternalLinkAccessibility - VERSION = '0.2.0' + VERSION = '0.3.0' end end diff --git a/spec/jekyll-external-link-accessibility_spec.rb b/spec/jekyll-external-link-accessibility_spec.rb index 2ae8beb..bdfc389 100644 --- a/spec/jekyll-external-link-accessibility_spec.rb +++ b/spec/jekyll-external-link-accessibility_spec.rb @@ -43,6 +43,21 @@ def rewrite(inner_html, config: { 'url' => 'https://example.com' }, wrapper: 'po expect(described_class.external_link?('https://www.example.com/blog', site_host)).to be(false) end + it 'is false for a subdomain of the site host' do + expect(described_class.external_link?('https://docs.example.com/x', site_host)).to be(false) + expect(described_class.external_link?('https://www.docs.example.com/x', site_host)).to be(false) + expect(described_class.external_link?('//docs.example.com/x', site_host)).to be(false) + end + + it 'is true for hosts that only look like a subdomain' do + expect(described_class.external_link?('https://notexample.com', site_host)).to be(true) + expect(described_class.external_link?('https://example.github.io', site_host)).to be(true) + end + + it 'is true for any host when the site has no url configured' do + expect(described_class.external_link?('https://other.com', nil)).to be(true) + end + it 'is false for relative and anchor links' do expect(described_class.external_link?('/blog/post', site_host)).to be(false) expect(described_class.external_link?('#section', site_host)).to be(false) @@ -88,6 +103,13 @@ def rewrite(inner_html, config: { 'url' => 'https://example.com' }, wrapper: 'po expect(internal['rel']).to be_nil end + it 'does not add rel to a subdomain of the site host' do + link = rewrite("x").at_css('a') + + expect(link['rel']).to be_nil + expect(link['target']).to eq('_blank') + end + it 'skips links with no href, empty href, anchors or data-no-external' do doc = rewrite(<<~HTML) no href