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