Module: Models::SchemaMarkup
- Extended by:
- ActiveSupport::Concern
- Included in:
- Article
- Defined in:
- app/concerns/models/schema_markup.rb
Overview
ActiveSupport::Concern mixin: schema markup.
Instance Method Summary collapse
-
#add_schema(schema) ⇒ Object
Schema markup helper methods.
- #clear_schema_markup ⇒ Object
-
#consolidated_faq_page_schema ⇒ Object
Build a single FAQPage schema merging: (1) FAQPage mainEntity from schema_markup, (2) FAQs from embedded blocks (by ID via FaqPresenter).
-
#content_has_embedded_faq_schema? ⇒ Boolean
Check if content has embedded FAQ oEmbed blocks for extractor/rules that need to skip or strip that block.
-
#embedded_faq_ids_from_content ⇒ Object
Collect FAQ IDs from embedded oEmbed blocks (data-faq-ids), in document order.
- #has_schema_type?(type) ⇒ Boolean
- #render_schema_markup ⇒ Object
- #schema_count ⇒ Object
- #schema_types ⇒ Object
- #schemas_by_type(type) ⇒ Object
Instance Method Details
#add_schema(schema) ⇒ Object
Schema markup helper methods
9 10 11 12 13 14 15 |
# File 'app/concerns/models/schema_markup.rb', line 9 def add_schema(schema) return unless schema.is_a?(Hash) schema['@context'] = 'https://schema.org' unless schema['@context'] self.schema_markup ||= [] self.schema_markup << schema end |
#clear_schema_markup ⇒ Object
126 127 128 |
# File 'app/concerns/models/schema_markup.rb', line 126 def clear_schema_markup self.schema_markup = [] end |
#consolidated_faq_page_schema ⇒ Object
Build a single FAQPage schema merging: (1) FAQPage mainEntity from schema_markup, (2) FAQs from embedded blocks (by ID via FaqPresenter).
Deduplicates by question name. Returns a hash suitable for JSON-LD or nil if nothing to output.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'app/concerns/models/schema_markup.rb', line 72 def consolidated_faq_page_schema = extracted_faq_schemas = (schema_markup || []).select { |s| s['@type'] == 'FAQPage' } extracted_entities = extracted_faq_schemas.flat_map { |s| (s['mainEntity'] || s[:mainEntity] || []).map(&:with_indifferent_access) } = if .any? ordered_ids = .uniq faqs = ArticleFaq .where(id: ordered_ids) .published .order(Arel.sql("ARRAY_POSITION(ARRAY[#{ordered_ids.join(',')}]::integer[], id)")) if faqs.empty? [] else FaqPresenter.new(faqs).schema_dot_org_structure.mainEntity.map(&:to_json_struct) end else [] end all_entities = (extracted_entities + ) return nil if all_entities.empty? # Deduplicate by question name (first occurrence wins) seen = Set.new main_entity = all_entities.filter_map do |entity| name = entity['name'] || entity[:name] next if name.blank? || seen.include?(name) seen.add(name) entity end return nil if main_entity.empty? { '@context' => 'https://schema.org', '@type' => 'FAQPage', 'mainEntity' => main_entity } end |
#content_has_embedded_faq_schema? ⇒ Boolean
Check if content has embedded FAQ oEmbed blocks for extractor/rules that need to skip or strip that block
115 116 117 118 119 120 121 122 123 124 |
# File 'app/concerns/models/schema_markup.rb', line 115 def return false unless respond_to?(:localized_solution) rendered = localized_solution.to_s return true if rendered.match?(/wy-faq-embed|data-wy-oembed="faq"/i) return true if rendered.include?('application/ld+json') && rendered.include?('"FAQPage"') false end |
#embedded_faq_ids_from_content ⇒ Object
Collect FAQ IDs from embedded oEmbed blocks (data-faq-ids), in document order.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'app/concerns/models/schema_markup.rb', line 51 def return [] unless respond_to?(:localized_solution) content = localized_solution.to_s return [] if content.blank? ids = [] doc = Nokogiri::HTML(content) doc.css('figure.wy-faq-embed, figure[data-wy-oembed="faq"]').each do |figure| figure['data-faq-ids'].to_s.split(',').each do |id_str| id = id_str.strip.to_i ids << id if id.positive? end end ids.uniq end |
#has_schema_type?(type) ⇒ Boolean
23 24 25 |
# File 'app/concerns/models/schema_markup.rb', line 23 def has_schema_type?(type) schema_types.include?(type) end |
#render_schema_markup ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'app/concerns/models/schema_markup.rb', line 33 def render_schema_markup # Build one consolidated FAQPage (extracted schema_markup FAQ + embedded oEmbed FAQs), then other schemas consolidated_faq = consolidated_faq_page_schema other_schemas = (schema_markup || []).reject { |s| s['@type'] == 'FAQPage' } parts = [] parts << consolidated_faq if consolidated_faq.present? parts.concat(other_schemas) return '' if parts.empty? parts.map do |schema| hash = schema.is_a?(Hash) ? schema : schema.with_indifferent_access "<script type=\"application/ld+json\">#{hash.to_json}</script>" end.join("\n").html_safe end |
#schema_count ⇒ Object
130 131 132 |
# File 'app/concerns/models/schema_markup.rb', line 130 def schema_count schema_markup&.length || 0 end |
#schema_types ⇒ Object
17 18 19 20 21 |
# File 'app/concerns/models/schema_markup.rb', line 17 def schema_types return [] if schema_markup.blank? schema_markup.pluck('@type').compact.uniq end |
#schemas_by_type(type) ⇒ Object
27 28 29 30 31 |
# File 'app/concerns/models/schema_markup.rb', line 27 def schemas_by_type(type) return [] if schema_markup.blank? schema_markup.select { |schema| schema['@type'] == type } end |