diff --git a/CHANGELOG.md b/CHANGELOG.md
index 138eedef..fb85796a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Changelog
+## Unreleased
+
+### New features
+
+#### Exclude individual pages from search engine indexes
+
+You can now exclude individual pages from search engine indexes by including `prevent_indexing: true` in the frontmatter for the page.
+
+This was added in [pull request #192: Fixes and improvements to meta tags](https://github.com/alphagov/tech-docs-gem/pull/192).
+
+### Fixes
+
+We’ve made fixes to the Tech Docs Gem in the following pull requests:
+
+- [#192: Fixes and improvements to meta tags](https://github.com/alphagov/tech-docs-gem/pull/192)
+
## 2.0.13
- [Pull request #189: Update orange code highlight colour to meet minimum AA colour contrast ratio criterion](https://github.com/alphagov/tech-docs-gem/pull/189)
diff --git a/example/source/index.html.md.erb b/example/source/index.html.md.erb
index 528d67e9..00105684 100644
--- a/example/source/index.html.md.erb
+++ b/example/source/index.html.md.erb
@@ -1,5 +1,6 @@
---
title: GOV.UK Documentation Example
+description: Example of a documentation homepage
old_paths:
- /something/old-as-well.html
---
diff --git a/example/source/prevent-index-page.html.md b/example/source/prevent-index-page.html.md
new file mode 100644
index 00000000..e3a55482
--- /dev/null
+++ b/example/source/prevent-index-page.html.md
@@ -0,0 +1,10 @@
+---
+title: Un-indexed Page
+prevent_indexing: true
+hide_in_navigation: true
+---
+
+# Un-indexed page
+
+This page should not be indexed by search engines, because it contains a
+`` tag.
diff --git a/lib/govuk_tech_docs/meta_tags.rb b/lib/govuk_tech_docs/meta_tags.rb
index 25d69bd1..76850e1b 100644
--- a/lib/govuk_tech_docs/meta_tags.rb
+++ b/lib/govuk_tech_docs/meta_tags.rb
@@ -8,12 +8,8 @@ def initialize(config, current_page)
def tags
all_tags = {
"description" => page_description,
- "og:description" => page_description,
- "og:image" => page_image,
- "og:site_name" => site_name,
- "og:title" => page_title,
- "og:type" => "object",
- "og:url" => canonical_url,
+ "google-site-verification" => google_site_verification,
+ "robots" => robots,
"twitter:card" => "summary",
"twitter:domain" => URI.parse(host).host,
"twitter:image" => page_image,
@@ -24,6 +20,21 @@ def tags
Hash[all_tags.select { |_k, v| v }]
end
+ # OpenGraph uses the non-standard property attribute instead of name, so we
+ # return these separately so we can output them correctly.
+ def opengraph_tags
+ all_opengraph_tags = {
+ "og:description" => page_description,
+ "og:image" => page_image,
+ "og:site_name" => site_name,
+ "og:title" => page_title,
+ "og:type" => "object",
+ "og:url" => canonical_url,
+ }
+
+ Hash[all_opengraph_tags.select { |_k, v| v }]
+ end
+
def browser_title
[page_title, site_name].select(&:present?).uniq.join(" - ")
end
@@ -45,11 +56,19 @@ def site_name
end
def page_description
- locals[:description] || frontmatter.description
+ locals[:description] || frontmatter[:description]
end
def page_title
- locals[:title] || frontmatter.title
+ locals[:title] || frontmatter[:title]
+ end
+
+ def robots
+ "noindex" if config[:tech_docs][:prevent_indexing] || frontmatter[:prevent_indexing]
+ end
+
+ def google_site_verification
+ config[:tech_docs][:google_site_verification]
end
def host
diff --git a/lib/source/layouts/core.erb b/lib/source/layouts/core.erb
index 2237909b..64ca034f 100644
--- a/lib/source/layouts/core.erb
+++ b/lib/source/layouts/core.erb
@@ -4,9 +4,6 @@
- <% if config[:tech_docs][:prevent_indexing] %>
-
- <% end %>
<%= meta_tags.browser_title %>
@@ -14,11 +11,11 @@
- <% if config[:tech_docs][:google_site_verification] %>
-
+ <% meta_tags.tags.each do |name, content| %>
+ <%= tag :meta, name: name, content: content %>
<% end %>
- <% meta_tags.tags.each do |property, content| %>
+ <% meta_tags.opengraph_tags.each do |property, content| %>
<%= tag :meta, property: property, content: content %>
<% end %>
diff --git a/spec/features/integration_spec.rb b/spec/features/integration_spec.rb
index 878bf2ad..5195172b 100644
--- a/spec/features/integration_spec.rb
+++ b/spec/features/integration_spec.rb
@@ -34,6 +34,9 @@
when_i_view_a_page_with_no_sidebar
then_there_is_no_sidebar
+
+ when_i_view_a_page_with_prevent_indexing
+ then_there_is_a_robots_noindex_metatag
end
def when_the_site_is_created
@@ -58,6 +61,7 @@ def then_there_is_a_sidebar
def and_there_are_proper_meta_tags
expect(page).to have_title "GOV.UK Documentation Example - My First Service"
+ expect(page).to have_css 'meta[name="description"]', visible: false
expect(page).to have_css 'meta[property="og:site_name"]', visible: false
end
@@ -124,4 +128,12 @@ def when_i_view_a_page_with_no_sidebar
def then_there_is_no_sidebar
expect(page).to have_no_css "div.app-pane__toc"
end
+
+ def when_i_view_a_page_with_prevent_indexing
+ visit "/prevent-index-page.html"
+ end
+
+ def then_there_is_a_robots_noindex_metatag
+ expect(page).to have_css 'meta[name="robots"][content="noindex"]', visible: false
+ end
end
diff --git a/spec/govuk_tech_docs/meta_tags_spec.rb b/spec/govuk_tech_docs/meta_tags_spec.rb
index b8463d86..1b1b69fd 100644
--- a/spec/govuk_tech_docs/meta_tags_spec.rb
+++ b/spec/govuk_tech_docs/meta_tags_spec.rb
@@ -24,7 +24,7 @@ def generate_title(site_name:, page_title:)
)
current_page = double("current_page",
- data: double("page_frontmatter", description: "The description.", title: page_title),
+ data: { description: "The description.", title: page_title },
metadata: { locals: {} })
GovukTechDocs::MetaTags.new(config, current_page).browser_title
@@ -32,7 +32,7 @@ def generate_title(site_name:, page_title:)
end
describe "#tags" do
- it "returns all the extra meta tags" do
+ it "returns standard meta tags" do
config = generate_config(
host: "https://www.example.org",
service_name: "Foo",
@@ -40,51 +40,77 @@ def generate_title(site_name:, page_title:)
)
current_page = double("current_page",
- data: double("page_frontmatter", description: "The description.", title: "The Title"),
+ data: { description: "The description.", title: "The Title" },
url: "/foo.html",
metadata: { locals: {} })
tags = GovukTechDocs::MetaTags.new(config, current_page).tags
- expect(tags).to eql("description" => "The description.",
- "og:description" => "The description.",
- "og:image" => "https://www.example.org/images/govuk-large.png",
- "og:site_name" => "Test Site",
- "og:title" => "The Title",
- "og:type" => "object",
- "og:url" => "https://www.example.org/foo.html",
+ expect(tags).to eql(
+ "description" => "The description.",
"twitter:card" => "summary",
"twitter:domain" => "www.example.org",
"twitter:image" => "https://www.example.org/images/govuk-large.png",
"twitter:title" => "The Title - Test Site",
- "twitter:url" => "https://www.example.org/foo.html")
+ "twitter:url" => "https://www.example.org/foo.html",
+ )
end
- it "uses the local variable as page description for proxied pages" do
+ it "adds a noindex robots tag when the site config prevents indexing" do
+ config = generate_config(
+ prevent_indexing: true,
+ )
+
current_page = double("current_page",
- data: double("page_frontmatter", description: "The description.", title: "The Title"),
+ data: {},
url: "/foo.html",
- metadata: { locals: { description: "The local variable description." } })
+ metadata: { locals: {} })
+
+ tags = GovukTechDocs::MetaTags.new(config, current_page).tags
+
+ expect(tags["robots"]).to eql("noindex")
+ end
+
+ it "adds a noindex robots tag when the page frontmatter prevents indexing" do
+ current_page = double("current_page",
+ data: { prevent_indexing: true },
+ url: "/foo.html",
+ metadata: { locals: {} })
tags = GovukTechDocs::MetaTags.new(generate_config, current_page).tags
- expect(tags["description"]).to eql("The local variable description.")
+ expect(tags["robots"]).to eql("noindex")
end
- it "uses the local variable as page title for proxied pages" do
+ it "adds a google site validation meta tag when provided in config" do
+ config = generate_config(
+ google_site_verification: "LEGIT-VALIDATION-TOKEN",
+ )
+
current_page = double("current_page",
- data: double("page_frontmatter", description: "The description.", title: "The Title"),
+ data: {},
url: "/foo.html",
- metadata: { locals: { title: "The local variable title." } })
+ metadata: { locals: {} })
+
+ tags = GovukTechDocs::MetaTags.new(config, current_page).tags
+
+ expect(tags["google-site-verification"]).to eql("LEGIT-VALIDATION-TOKEN")
+ end
+
+ it "uses the local variable as page description for proxied pages" do
+ current_page = double("current_page",
+ data: { description: "The description." },
+ url: "/foo.html",
+ metadata: { locals: { description: "The local variable description." } })
tags = GovukTechDocs::MetaTags.new(generate_config, current_page).tags
- expect(tags["og:title"]).to eql("The local variable title.")
+ expect(tags["description"]).to eql("The local variable description.")
end
it "works even when no config is set" do
current_page = double("current_page",
- data: double("page_frontmatter", description: "The description.", title: "The Title"),
+ data: {},
url: "/foo.html",
metadata: { locals: { title: "The local variable title." } })
@@ -96,6 +122,43 @@ def generate_title(site_name:, page_title:)
end
end
+ describe "#opengraph_tags" do
+ it "returns opengraph meta tags" do
+ config = generate_config(
+ host: "https://www.example.org",
+ service_name: "Foo",
+ full_service_name: "Test Site",
+ )
+
+ current_page = double("current_page",
+ data: { description: "The description.", title: "The Title" },
+ url: "/foo.html",
+ metadata: { locals: {} })
+
+ og_tags = GovukTechDocs::MetaTags.new(config, current_page).opengraph_tags
+
+ expect(og_tags).to eql(
+ "og:description" => "The description.",
+ "og:image" => "https://www.example.org/images/govuk-large.png",
+ "og:site_name" => "Test Site",
+ "og:title" => "The Title",
+ "og:type" => "object",
+ "og:url" => "https://www.example.org/foo.html",
+ )
+ end
+
+ it "uses the local variable as page title for proxied pages" do
+ current_page = double("current_page",
+ data: { description: "The description." },
+ url: "/foo.html",
+ metadata: { locals: { title: "The local variable title." } })
+
+ tags = GovukTechDocs::MetaTags.new(generate_config, current_page).opengraph_tags
+
+ expect(tags["og:title"]).to eql("The local variable title.")
+ end
+ end
+
def generate_config(config = {})
{
tech_docs: {