diff --git a/app/helpers/better_together/application_helper.rb b/app/helpers/better_together/application_helper.rb index 7470d9d88..41eead32c 100644 --- a/app/helpers/better_together/application_helper.rb +++ b/app/helpers/better_together/application_helper.rb @@ -6,6 +6,7 @@ module BetterTogether # platform configurations, and navigation items. module ApplicationHelper # rubocop:todo Metrics/ModuleLength include MetricsHelper + include StructuredDataHelper # Returns the base URL configured for BetterTogether. def base_url diff --git a/app/helpers/better_together/structured_data_helper.rb b/app/helpers/better_together/structured_data_helper.rb new file mode 100644 index 000000000..f1e6914b2 --- /dev/null +++ b/app/helpers/better_together/structured_data_helper.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module BetterTogether + # Helper methods for rendering JSON-LD structured data for schema.org + module StructuredDataHelper + def structured_data_tag(data) + return if data.blank? + + tag.script(type: 'application/ld+json') do + raw(Array.wrap(data).to_json) + end + end + + def platform_structured_data(platform) + { + '@context': 'https://schema.org', + '@type': 'WebSite', + name: platform.name, + url: platform.url + } + end + + def community_structured_data(community) + data = { + '@context': 'https://schema.org', + '@type': 'Organization', + name: community.name, + url: community_url(community) + } + data[:description] = community.description.to_plain_text if community.respond_to?(:description) && community.description.present? + if community.logo.attached? + attachment = community.respond_to?(:optimized_logo) ? community.optimized_logo : community.logo + data[:logo] = rails_storage_proxy_url(attachment) + end + data + end + + def event_structured_data(event) + data = { + '@context': 'https://schema.org', + '@type': 'Event', + name: event.name, + startDate: event.starts_at&.iso8601, + endDate: event.ends_at&.iso8601, + url: event_url(event) + } + data[:description] = event.description.to_plain_text if event.respond_to?(:description) && event.description.present? + data[:location] = event.location.to_s if event.respond_to?(:location) && event.location.present? + data.compact + end + end +end diff --git a/app/views/better_together/events/show.html.erb b/app/views/better_together/events/show.html.erb index 2122d927d..4ea94ee2a 100644 --- a/app/views/better_together/events/show.html.erb +++ b/app/views/better_together/events/show.html.erb @@ -2,6 +2,10 @@ <%= @resource.name %> | <%= resource_class.model_name.human.pluralize %> <% end %> +<% content_for :structured_data do %> + <%= structured_data_tag(event_structured_data(@event)) %> +<% end %> +
diff --git a/app/views/layouts/better_together/application.html.erb b/app/views/layouts/better_together/application.html.erb index 5a40356a7..46480ddd6 100644 --- a/app/views/layouts/better_together/application.html.erb +++ b/app/views/layouts/better_together/application.html.erb @@ -12,6 +12,8 @@ <%= (yield(:page_title) + ' | ') if content_for?(:page_title) %><%= host_platform.name %> <%= open_graph_meta_tags %> <%= seo_meta_tags %> + <%= structured_data_tag([platform_structured_data(host_platform), community_structured_data(host_community)]) %> + <%= yield(:structured_data) if content_for?(:structured_data) %> <%= robots_meta_tag %> diff --git a/app/views/layouts/better_together/turbo_native.html.erb b/app/views/layouts/better_together/turbo_native.html.erb index 68f193a01..5cd17efad 100644 --- a/app/views/layouts/better_together/turbo_native.html.erb +++ b/app/views/layouts/better_together/turbo_native.html.erb @@ -12,6 +12,8 @@ <%= (yield(:page_title) + ' | ') if content_for?(:page_title) %><%= host_platform.name %> <%= open_graph_meta_tags %> <%= seo_meta_tags %> + <%= structured_data_tag([platform_structured_data(host_platform), community_structured_data(host_community)]) %> + <%= yield(:structured_data) if content_for?(:structured_data) %> <%= robots_meta_tag %> diff --git a/spec/helpers/better_together/structured_data_helper_spec.rb b/spec/helpers/better_together/structured_data_helper_spec.rb new file mode 100644 index 000000000..95f687ded --- /dev/null +++ b/spec/helpers/better_together/structured_data_helper_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe BetterTogether::StructuredDataHelper, type: :helper do + let(:platform) { build(:platform, name: 'Platform', url: 'https://example.com') } + let(:event) { BetterTogether::Event.new(name: 'Event', starts_at: Time.zone.parse('2024-01-01 12:00:00')) } + + before do + allow(helper).to receive(:event_url).and_return('https://example.com/events/event') + end + + describe '#structured_data_tag' do + it 'wraps JSON-LD data in a script tag' do + data = platform_structured_data(platform) + html = structured_data_tag(data) + expect(html).to include('application/ld+json') + expect(html).to include('Platform') + end + end + + describe '#event_structured_data' do + it 'includes event properties' do + data = event_structured_data(event) + expect(data[:name]).to eq('Event') + expect(data[:url]).to eq('https://example.com/events/event') + expect(data[:startDate]).to eq('2024-01-01T12:00:00Z') + end + end +end