Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion app/helpers/better_together/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ def host_community_logo_url
rails_storage_proxy_url(attachment)
end

# Returns the canonical URL for the current request, allowing overrides via
# +content_for(:canonical_url)+.
def canonical_url
content_for?(:canonical_url) ? content_for(:canonical_url) : request.original_url
end

# Builds SEO-friendly meta tags for the current view. Defaults are derived
# from translations and fall back to the Open Graph description when set.
# rubocop:todo Metrics/MethodLength
Expand All @@ -94,9 +100,17 @@ def seo_meta_tags # rubocop:todo Metrics/AbcSize, Metrics/MethodLength

keywords = content_for?(:meta_keywords) ? content_for(:meta_keywords) : nil

canonical = canonical_url
hreflang_tags = I18n.available_locales.map do |locale|
tag.link(rel: 'alternate', hreflang: locale, href: url_for(locale:, only_path: false))
end
hreflang_tags << content_for(:hreflang_links) if content_for?(:hreflang_links)

tags = []
tags << tag.meta(name: 'description', content: description)
tags << tag.meta(name: 'keywords', content: keywords) if keywords.present?
tags << tag.link(rel: 'canonical', href: canonical)
tags.concat(hreflang_tags)

safe_join(tags, "\n")
end
Expand All @@ -121,7 +135,7 @@ def open_graph_meta_tags # rubocop:todo Metrics/AbcSize, Metrics/MethodLength, M
t('og.default_description', platform_name: host_platform.name)
end

og_url = content_for?(:og_url) ? content_for(:og_url) : request.original_url
og_url = content_for?(:og_url) ? content_for(:og_url) : canonical_url

og_image = content_for?(:og_image) ? content_for(:og_image) : host_community_logo_url

Expand Down
27 changes: 27 additions & 0 deletions docs/seo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# SEO

The engine exposes helpers that output common search engine optimisation tags.

## Canonical URL

`seo_meta_tags` includes a canonical `<link>` tag pointing to the current request
URL. You can override the URL by setting a `content_for` block:

```erb
<% content_for :canonical_url, article_url(@article, locale: :en) %>
```

## Hreflang links

Alternate language links are generated for each available locale. Additional
links can be appended using `content_for :hreflang_links` and are merged with the
default set:

```erb
<% content_for :hreflang_links do %>
<%= tag.link rel: 'alternate', hreflang: 'x-default', href: root_url %>
<% end %>
```

Links supplied via `content_for` are merged with the automatically generated
links rather than replacing them.
50 changes: 50 additions & 0 deletions spec/helpers/better_together/application_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

require 'rails_helper'

module BetterTogether
RSpec.describe ApplicationHelper, type: :helper do
before do
allow(helper).to receive(:host_platform).and_return(double(name: 'Test Platform', cache_key_with_version: 'test-platform'))
allow(helper).to receive(:host_community_logo_url).and_return(nil)
allow(controller.request).to receive(:original_url).and_return('http://test.host/en/current')
allow(I18n).to receive(:available_locales).and_return(%i[en fr])
allow(helper).to receive(:url_for) do |opts|
"http://test.host/#{opts[:locale]}/current"
end
end

describe '#seo_meta_tags' do
it 'includes default canonical and hreflang links' do
html = helper.seo_meta_tags
expect(html).to include('<link rel="canonical" href="http://test.host/en/current"')
expect(html).to include('<link rel="alternate" hreflang="fr" href="http://test.host/fr/current"')
end

it 'merges content_for overrides' do
helper.content_for(:canonical_url, 'http://example.com/custom')
helper.content_for(:hreflang_links, tag.link(rel: 'alternate', hreflang: 'es', href: 'http://test.host/es/current'))

html = helper.seo_meta_tags
expect(html).to include('<link rel="canonical" href="http://example.com/custom"')
expect(html).to include('<link rel="alternate" hreflang="fr" href="http://test.host/fr/current"')
expect(html).to include('<link rel="alternate" hreflang="es" href="http://test.host/es/current"')
end
end

describe '#open_graph_meta_tags' do
it 'defaults og:url to canonical_url' do
allow(helper).to receive(:canonical_url).and_return('http://test.host/en/current')
html = helper.open_graph_meta_tags
expect(html).to include('<meta property="og:url" content="http://test.host/en/current"')
end

it 'allows og_url override' do
helper.content_for(:og_url, 'http://example.com/og')
allow(helper).to receive(:canonical_url).and_return('http://test.host/en/current')
html = helper.open_graph_meta_tags
expect(html).to include('<meta property="og:url" content="http://example.com/og"')
end
end
end
end
Loading