diff --git a/CHANGELOG.md b/CHANGELOG.md index d59f2af226..44758101ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ useful summary for people upgrading their application, not a replication of the commit log. +## Unreleased + +* Add FAQPage schema ([PR #1087](https://github.com/alphagov/govuk_publishing_components/pull/1087)) + ## 20.0.0 * **BREAKING:** Remove the inverse flag for contents list component ([PR #1090](https://github.com/alphagov/govuk_publishing_components/pull/1090)) diff --git a/app/views/govuk_publishing_components/components/docs/machine_readable_metadata.yml b/app/views/govuk_publishing_components/components/docs/machine_readable_metadata.yml index 3caf6390a5..52a99b49f1 100644 --- a/app/views/govuk_publishing_components/components/docs/machine_readable_metadata.yml +++ b/app/views/govuk_publishing_components/components/docs/machine_readable_metadata.yml @@ -41,6 +41,21 @@ examples: details: {} schema: :article body: "Some other body" + a_guide: + data: + content_item: + title: "How to train your dragon" + base_path: "/how-to-train-your-dragon" + details: + parts: + - slug: overview + body: A thing on how to train scaly beasts + title: Overview + - slug: treating-injuries + body: Get to know a good blacksmith + title: Treating injuries + schema: :faq + canonical_url: https://www.gov.uk/how-to-train-your-dragon person_schema: data: content_item: diff --git a/lib/govuk_publishing_components/presenters/machine_readable/faq_page_schema.rb b/lib/govuk_publishing_components/presenters/machine_readable/faq_page_schema.rb new file mode 100644 index 0000000000..9cc4e52e66 --- /dev/null +++ b/lib/govuk_publishing_components/presenters/machine_readable/faq_page_schema.rb @@ -0,0 +1,52 @@ +module GovukPublishingComponents + module Presenters + class FaqPageSchema + attr_reader :page + + def initialize(page) + @page = page + end + + def structured_data + # http://schema.org/FAQPage + data = CreativeWorkSchema.new(@page).structured_data + .merge(main_entity) + data["@type"] = "FAQPage" + data + end + + private + + def main_entity + { + "mainEntity" => questions_and_answers + } + end + + def questions_and_answers + page.parts.each_with_index.map do |part, index| + part_url = part_url(part, index) + + { + "@type" => "Question", + "name" => part['title'], + "url" => part_url, + "acceptedAnswer" => { + "@type" => "Answer", + "url" => part_url, + "text" => part['body'] + } + } + end + end + + def part_url(part, index) + if index.zero? + page.canonical_url + else + page.canonical_url + "/" + part["slug"] + end + end + end + end +end diff --git a/lib/govuk_publishing_components/presenters/machine_readable/page.rb b/lib/govuk_publishing_components/presenters/machine_readable/page.rb index dbcf54d5f3..943d2065a5 100644 --- a/lib/govuk_publishing_components/presenters/machine_readable/page.rb +++ b/lib/govuk_publishing_components/presenters/machine_readable/page.rb @@ -58,6 +58,10 @@ def content_item def logo_url local_assigns[:logo_url] end + + def parts + content_item.dig("details", "parts") || [] + end end end end diff --git a/lib/govuk_publishing_components/presenters/schema_org.rb b/lib/govuk_publishing_components/presenters/schema_org.rb index 0628bdb4ef..fdd9b6b7c1 100644 --- a/lib/govuk_publishing_components/presenters/schema_org.rb +++ b/lib/govuk_publishing_components/presenters/schema_org.rb @@ -1,6 +1,7 @@ require 'govuk_publishing_components/presenters/machine_readable/page' require 'govuk_publishing_components/presenters/machine_readable/article_schema' require 'govuk_publishing_components/presenters/machine_readable/creative_work_schema' +require 'govuk_publishing_components/presenters/machine_readable/faq_page_schema' require 'govuk_publishing_components/presenters/machine_readable/has_part_schema' require 'govuk_publishing_components/presenters/machine_readable/is_part_of_schema' require 'govuk_publishing_components/presenters/machine_readable/news_article_schema' @@ -19,7 +20,9 @@ def initialize(page) end def structured_data - if page.schema == :article + if page.schema == :faq + FaqPageSchema.new(page).structured_data + elsif page.schema == :article ArticleSchema.new(page).structured_data elsif page.schema == :news_article NewsArticleSchema.new(page).structured_data diff --git a/spec/lib/govuk_publishing_components/presenters/schema_org_spec.rb b/spec/lib/govuk_publishing_components/presenters/schema_org_spec.rb index 04f972c485..1f7829d76d 100644 --- a/spec/lib/govuk_publishing_components/presenters/schema_org_spec.rb +++ b/spec/lib/govuk_publishing_components/presenters/schema_org_spec.rb @@ -62,6 +62,43 @@ expect(structured_data['@type']).to eql("NewsArticle") end + it "generates schema.org FAQPages" do + content_item = GovukSchemas::RandomExample.for_schema(frontend_schema: "guide") do |random_item| + random_item.merge( + "base_path" => "/how-to-train-your-dragon", + "details" => { + "parts" => [ + { + "title" => "Overview", + "slug" => "overview", + "body" => "

First catch your dragon

" + }, + { + "title" => "Insurance", + "slug" => "insurance", + "body" => "

Contact the Berk insurance bureau for more details.

" + } + ] + } + ) + end + + structured_data = generate_structured_data( + content_item: content_item, + schema: :faq, + ).structured_data + + expect(structured_data['@type']).to eql("FAQPage") + + q_and_a_pairs = structured_data['mainEntity'] + expect(q_and_a_pairs.count).to eq(2) + expect(q_and_a_pairs.first["url"]).to eq("http://www.dev.gov.uk/how-to-train-your-dragon") + expect(q_and_a_pairs.second["url"]).to eq("http://www.dev.gov.uk/how-to-train-your-dragon/insurance") + + expect(q_and_a_pairs.first["name"]).to eq("Overview") + expect(q_and_a_pairs.first["acceptedAnswer"]["text"]).to eq("

First catch your dragon

") + end + it "generates schema.org Person" do content_item = GovukSchemas::RandomExample.for_schema(frontend_schema: "person")