Module: Models::SchemaMarkup
- Extended by:
- ActiveSupport::Concern
- Included in:
- Article
- Defined in:
- app/concerns/models/schema_markup.rb
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
7 8 9 10 11 12 13 |
# File 'app/concerns/models/schema_markup.rb', line 7 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
124 125 126 |
# File 'app/concerns/models/schema_markup.rb', line 124 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.
70 71 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 |
# File 'app/concerns/models/schema_markup.rb', line 70 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
113 114 115 116 117 118 119 120 121 122 |
# File 'app/concerns/models/schema_markup.rb', line 113 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.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'app/concerns/models/schema_markup.rb', line 49 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
21 22 23 |
# File 'app/concerns/models/schema_markup.rb', line 21 def has_schema_type?(type) schema_types.include?(type) end |
#render_schema_markup ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'app/concerns/models/schema_markup.rb', line 31 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
128 129 130 |
# File 'app/concerns/models/schema_markup.rb', line 128 def schema_count schema_markup&.length || 0 end |
#schema_types ⇒ Object
15 16 17 18 19 |
# File 'app/concerns/models/schema_markup.rb', line 15 def schema_types return [] unless schema_markup.present? schema_markup.map { |schema| schema['@type'] }.compact.uniq end |
#schemas_by_type(type) ⇒ Object
25 26 27 28 29 |
# File 'app/concerns/models/schema_markup.rb', line 25 def schemas_by_type(type) return [] unless schema_markup.present? schema_markup.select { |schema| schema['@type'] == type } end |