diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 34cb23bc0..a7583bdad 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,6 +19,12 @@ def retrieve_title content_for?(:title) ? content_for(:title) : t(:brand) end + # Absolute URL for a social preview image, falling back to the codebar social image + def social_image_url(url = nil) + image = url.presence || image_url('codebar-social.jpg') + image.start_with?('/') ? URI.join(request.base_url, image).to_s : image + end + def dot_markdown(text) # Commonmarker sanitises raw HTML; `.html_safe` prevents Rails double-escaping the result # rubocop:disable Rails/OutputSafety diff --git a/app/views/events/_meta_tags.html.haml b/app/views/events/_meta_tags.html.haml new file mode 100644 index 000000000..a30fc3cb2 --- /dev/null +++ b/app/views/events/_meta_tags.html.haml @@ -0,0 +1,20 @@ +:ruby + url = request.original_url + image = social_image_url(event.venue&.avatar&.url) + description = truncate(strip_tags(event.description), length: 200) + += content_for :meta_tags do + %meta{ property: 'og:title', content: event.name } + %meta{ property: 'og:type', content: 'event' } + %meta{ property: 'og:url', content: url } + %meta{ property: 'og:image', content: image } + %meta{ property: 'og:description', content: description } + %meta{ property: 'og:site_name', content: 'codebar' } + %meta{ property: 'og:locale', content: 'en_GB' } + + -# Only Twitter-specific tag needed + %meta{ name: 'twitter:card', content: 'summary_large_image' } + + -# Event timing + %meta{ property: 'event:start_time', content: event.date_and_time } + %meta{ property: 'event:end_time', content: event.ends_at } diff --git a/app/views/events/show.html.haml b/app/views/events/show.html.haml index ec09d0201..d6323df1d 100644 --- a/app/views/events/show.html.haml +++ b/app/views/events/show.html.haml @@ -1,3 +1,5 @@ += render partial: 'meta_tags', locals: { event: @event } + .container.py-4.py-lg-5 .row .col-12.col-lg-9 diff --git a/app/views/workshops/_meta_tags.html.haml b/app/views/workshops/_meta_tags.html.haml index 1cfe2fa37..ce6862d06 100644 --- a/app/views/workshops/_meta_tags.html.haml +++ b/app/views/workshops/_meta_tags.html.haml @@ -5,7 +5,7 @@ t('workshop.title', host: workshop.host&.name || 'codebar', date: humanize_date(workshop.date_and_time)) end url = request.original_url - image = workshop.host.try(:image_url).presence || image_url('codebar-social.jpg') + image = social_image_url(workshop.host&.avatar&.url) description = (workshop.virtual? ? t('workshops.virtual.lead') : t('workshops.lead')) = content_for :meta_tags do diff --git a/spec/features/view_event_spec.rb b/spec/features/view_event_spec.rb index dd6002cb4..36dacf028 100644 --- a/spec/features/view_event_spec.rb +++ b/spec/features/view_event_spec.rb @@ -27,6 +27,13 @@ expect(page).to have_link('Join our community') expect(page).to have_no_link('Attend as a coach') end + + scenario 'event link preview meta tags' do + expect(find("meta[property='og:title']", visible: false)[:content]).to eq(closed_event.name) + expect(find("meta[property='og:image']", visible: false)[:content]).to include('uploads/sponsor/') + expect(find("meta[property='og:description']", visible: false)[:content]).to eq(closed_event.description) + expect(find("meta[property='event:start_time']", visible: false)[:content]).to be_present + end end context 'when an authenticated user' do diff --git a/spec/features/viewing_a_workshop_spec.rb b/spec/features/viewing_a_workshop_spec.rb index 8d097f77c..43529c7bb 100644 --- a/spec/features/viewing_a_workshop_spec.rb +++ b/spec/features/viewing_a_workshop_spec.rb @@ -27,6 +27,14 @@ end include_examples 'viewing workshop details' + + scenario 'link preview meta tags' do + og_title = find("meta[property='og:title']", visible: false)[:content] + expect(og_title).to eq("Workshop at #{workshop.host.name} - #{humanize_date(workshop.date_and_time)}") + + og_image = find("meta[property='og:image']", visible: false)[:content] + expect(og_image).to include('uploads/sponsor/') + end end describe '#actions' do @@ -56,6 +64,11 @@ end include_examples 'viewing workshop details' + + scenario 'link preview meta tags use the fallback image' do + expect(find("meta[property='og:image']", visible: false)[:content]) + .to include('codebar-social') + end end describe '#actions' do