Class: PostPresenter

Inherits:
BasePresenter show all
Includes:
Memery
Defined in:
app/presenters/post_presenter.rb

Instance Attribute Summary

Attributes inherited from BasePresenter

#current_account, #options, #url_helper

Instance Method Summary collapse

Methods inherited from BasePresenter

#can?, #capture, #concat, #content_tag, #fa_icon, #h, #initialize, #link_to, #number_to_currency, #present, presents, #r, #safe_present, #simple_format, #u

Constructor Details

This class inherits a constructor from BasePresenter

Instance Method Details

#article_body(preview_mode: false) ⇒ Object



58
59
60
# File 'app/presenters/post_presenter.rb', line 58

def article_body(preview_mode: false)
  localized_solution_with_toc(preview_mode: preview_mode).body
end

#article_body_descObject



72
73
74
# File 'app/presenters/post_presenter.rb', line 72

def article_body_desc
  h.truncate(post&.description || stripped_article_body, length: 300)
end

#article_published_atObject



166
167
168
169
# File 'app/presenters/post_presenter.rb', line 166

def 
  # Must be DateTime YYYY-MM-DDThh:mm:ssTZD
  r.effective_published_date&.to_datetime
end

#article_published_at_formattedObject



171
172
173
174
175
# File 'app/presenters/post_presenter.rb', line 171

def 
  return unless 

  .strftime('%B %-d, %Y')
end

#article_revised_atObject



177
178
179
# File 'app/presenters/post_presenter.rb', line 177

def article_revised_at
  r.revised_at&.to_datetime
end

#article_revised_at_formattedObject



181
182
183
184
185
# File 'app/presenters/post_presenter.rb', line 181

def article_revised_at_formatted
  return unless article_revised_at

  article_revised_at.strftime('%B %-d, %Y')
end

#article_sectionObject



204
205
206
207
# File 'app/presenters/post_presenter.rb', line 204

def article_section
  # Return the first keyword or first tag, or 'Uncategorized'
  r.meta_keywords&.split(',')&.first&.strip.presence || r.tags&.first.presence || 'Uncategorized'
end

#article_tagsObject



197
198
199
200
201
202
# File 'app/presenters/post_presenter.rb', line 197

def 
  keywords = r.meta_keywords&.split(',')&.map(&:strip)
  keywords = r.tags if keywords.blank?
  # Exclude internal "for-*-page" tags which are used for page content placement
  (keywords || []).reject { |t| t.to_s.start_with?('for-') }
end

#article_toc(preview_mode: false) ⇒ Object



54
55
56
# File 'app/presenters/post_presenter.rb', line 54

def article_toc(preview_mode: false)
  localized_solution_with_toc(preview_mode: preview_mode).toc
end

#author_nameObject



113
114
115
116
117
# File 'app/presenters/post_presenter.rb', line 113

def author_name
  return 'https://www.facebook.com/WarmlyYours/' unless r.author&.full_name

  r.author&.full_name
end

#author_twitterObject



159
160
161
162
163
164
# File 'app/presenters/post_presenter.rb', line 159

def author_twitter
  '@WarmlyYours'
  # Later when this is defined we can use an employee twitter handle, today this does not exist
  # unless r.author&.twitter_handle
  # r.author&.twitter_handle
end


16
17
18
19
20
21
22
23
24
25
26
27
# File 'app/presenters/post_presenter.rb', line 16

def breadcrumbs_hash
  bc_array = [{ name: 'Radiant Journal', url: h.cms_link('/posts') }]
  custom_breadcrumbs = r.breadcrumbs_hash.dup
  if custom_breadcrumbs.blank? && (main_tag = r.main_public_tag)
    # make a breadcrumb out of it
    tag_title, tag = Post.category_tags_for_select.detect { |to| to[1] == main_tag }
    bc_array << { name: tag_title, url: h.cms_link("/posts/#{tag}/tag") } if tag_title && tag
  else
    bc_array.concat(custom_breadcrumbs)
  end
  bc_array
end

#cache_keyObject



8
9
10
# File 'app/presenters/post_presenter.rb', line 8

def cache_key
  "#{I18n.locale}/#{post.cache_key}"
end


76
77
78
# File 'app/presenters/post_presenter.rb', line 76

def canonical_link
  h.cms_link(h.post_url(r), strip_params: true)
end

#get_imageObject



48
49
50
51
52
# File 'app/presenters/post_presenter.rb', line 48

def get_image
  return unless r.preview_image

  h.og_image_asset_url(r.preview_image)
end

#get_keywordsObject



12
13
14
# File 'app/presenters/post_presenter.rb', line 12

def get_keywords
  r.meta_keywords.presence || r.tags&.join(', ')
end

#localized_solution_with_toc(preview_mode: false) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'app/presenters/post_presenter.rb', line 209

def localized_solution_with_toc(preview_mode: false)
  s = OpenStruct.new(body: localized_solution(nil, preview_mode: preview_mode), toc: nil, body_html_doc: nil)
  return s unless r.has_toc

  # Parse toc headers and embed an anchor in them
  doc = localized_solution_html_doc(preview_mode: preview_mode)
  toc_headers = doc.css(toc_selector.presence || 'h2')
  toc = {}
  toc_headers.each do |element|
    next unless (title = element.text.strip.presence)

    element_anchor = element.text.parameterize
    toc[title] = element_anchor
    h.(:a, title, name: element_anchor)
    element['id'] = element_anchor
  end
  s.body_html_doc = doc
  s.body = doc.at('body')&.inner_html.presence&.html_safe
  s.toc = h.render(partial: '/posts/toc', locals: { toc: toc })
  s
end

#meta_description(max_length: 160) ⇒ Object



132
133
134
135
136
137
138
# File 'app/presenters/post_presenter.rb', line 132

def meta_description(max_length: 160)
  description = r.meta_description.presence
  description ||= r.description.presence
  description ||= r.subject.presence
  h.truncate(description, length: max_length, separator: ' ')
  # description << " (#{Country.country_name_from_locale})" if description && I18n.locale.to_s != 'en-US'
end

#meta_keywordsObject



140
141
142
# File 'app/presenters/post_presenter.rb', line 140

def meta_keywords
  r.meta_keywords.presence || r.tags&.join(', ').presence
end

#post_comments_sizeObject



105
106
107
# File 'app/presenters/post_presenter.rb', line 105

def post_comments_size
  r.post_comments.size
end

#preview_image_presenterObject



42
43
44
45
46
# File 'app/presenters/post_presenter.rb', line 42

def preview_image_presenter
  return unless r.preview_image

  h.present(r.preview_image, Www::ImagePresenter)
end

#publish_labelObject



187
188
189
190
191
192
193
194
195
# File 'app/presenters/post_presenter.rb', line 187

def publish_label
  return unless 

  if article_revised_at && article_revised_at > 
    "Updated on #{article_revised_at_formatted}"
  else
    "Published on #{}"
  end
end


29
30
31
32
33
34
35
36
37
38
39
40
# File 'app/presenters/post_presenter.rb', line 29

def quick_links_hash
  ql_array = breadcrumbs_hash.dup
  if breadcrumbs_hash.any? { |h| h[:url].match?(/floor|indoor-heating/) }
    ql_array << { name: 'Instant Quote', url: h.cms_link('/floor-heating/quote-builder') }
    ql_array << { name: 'Running Costs', url: h.cms_link('/floor-heating/cost-calculator') }
  end
  if breadcrumbs_hash.any? { |h| h[:url].match?(%r{/snow-melting|outdoor-heating}) }
    ql_array << { name: 'Instant Quote', url: h.cms_link('/snow-melting/quote-builder') }
    ql_array << { name: 'Running Costs', url: h.cms_link('/snow-melting/cost-calculator') }
  end
  ql_array.uniq { |h| h[:url] }.sort_by { |h| h[:name] }
end

#reading_time_in_minutesObject



68
69
70
# File 'app/presenters/post_presenter.rb', line 68

def reading_time_in_minutes
  (stripped_article_body.to_s.split.size / 200.0).ceil
end

#render_body(preview_mode: false) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/presenters/post_presenter.rb', line 80

def render_body(preview_mode: false)
  locale = I18n.locale
  body = Liquid::ParseEnvironment.parse(article_body(preview_mode: preview_mode).to_s).render(
    'preview_mode' => preview_mode,
    'locale' => locale.to_s,
    'canada' => %i[en-CA fr-CA].include?(locale),
    'usa' => locale == :'en-US'
  )
  return body if preview_mode

  # HtmlContentSanitizer now runs on save (via auto_sanitize_html checkbox)
  Seo::ImageOptimizer.new.process(body).html_out
end

#render_descriptionObject



94
95
96
97
98
99
100
101
102
103
# File 'app/presenters/post_presenter.rb', line 94

def render_description
  return unless r.description.present?

  locale = I18n.locale
  Liquid::ParseEnvironment.parse(r.description.to_s).render(
    'locale' => locale.to_s,
    'canada' => %i[en-CA fr-CA].include?(locale),
    'usa' => locale == :'en-US'
  ).html_safe
end

#schema_dot_org_structureObject



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'app/presenters/post_presenter.rb', line 232

def schema_dot_org_structure
  wc = word_count.to_i
  schema = SchemaDotOrg::BlogPosting.new(
    identifier: id.to_s,
    headline: subject,
    name: subject,
    description: meta_description,
    articleBody: stripped_article_body,
    keywords: ,
    wordcount: wc.positive? ? wc.to_s : nil,
    inLanguage: I18n.locale.to_s.tr('_', '-'),
    datePublished: r.effective_published_date,
    dateModified: r.effective_revised_date,
    dateCreated: created_at,
    articleSection: article_section,
    mainEntityOfPage: canon_link,
    url: canon_link,
    author: build_author_schema,
    publisher: build_publisher_schema,
    image: build_image_schema,
    comment: build_comment_graph
  )
  schema.id_iri = canon_link
  schema
end

#stripped_article_bodyObject



62
63
64
65
66
# File 'app/presenters/post_presenter.rb', line 62

def stripped_article_body
  parsed_body = Liquid::ParseEnvironment.parse(article_body.to_s)
  stripped_body = h.strip_tags(parsed_body.render)
  stripped_body&.tr('"', '')
end

#to_json_ldObject



258
259
260
# File 'app/presenters/post_presenter.rb', line 258

def to_json_ld
  schema_dot_org_structure.to_s
end

#user_imageObject



119
120
121
122
123
# File 'app/presenters/post_presenter.rb', line 119

def user_image
  return unless r.author&.email

  "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(r.author&.email&.presence)}.jpg"
end

#user_image_tagObject



125
126
127
128
129
130
# File 'app/presenters/post_presenter.rb', line 125

def user_image_tag
  img_url = user_image_url(size: '90x90>')
  return unless img_url

  h.image_tag(img_url, alt: r.author&.full_name, class: 'img-fluid', width: 90, height: 90)
end

#user_image_url(size: '90x90>') ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'app/presenters/post_presenter.rb', line 144

def user_image_url(size: '90x90>')
  return unless r.author

  if (pp = r.author&.profile_image)
    pp.image_url(size: size)
  elsif (email = r.author&.email&.presence)
    # Gravatar
    require 'digest/md5'
    hash = Digest::MD5.hexdigest(email.downcase)
    "https://www.gravatar.com/avatar/#{hash}.jpg"
  else
    nil
  end
end

#word_countObject



109
110
111
# File 'app/presenters/post_presenter.rb', line 109

def word_count
  r.localized_solution&.presence&.scan(/\w+/)&.size
end