Module: Middleman::Blog::BlogArticle

Extended by:
Gem::Deprecate
Defined in:
lib/middleman-blog/blog_article.rb

Overview

A module that adds blog-article-specific methods to Resources. A BlogArticle can be retrieved via Helpers#current_article or methods on BlogData (like Middleman::Blog::BlogData#articles).

Instance Method Summary collapse

Instance Method Details

#article_locale_nextMiddleman::Sitemap::Resource

The next (chronologically later) article after this one in the current locale or nil if this is the most recent article.

Returns:

  • (Middleman::Sitemap::Resource)


325
326
327
# File 'lib/middleman-blog/blog_article.rb', line 325

def article_locale_next
  blog_data.local_articles.reverse.find { |a| a.date > date }
end

#article_locale_previousBlogArticle

The previous (chronologically earlier) article before this one in the current locale, or nil if this is the first article.

Returns:



315
316
317
# File 'lib/middleman-blog/blog_article.rb', line 315

def article_locale_previous
  blog_data.local_articles.find { |a| a.date < date }
end

#article_nextMiddleman::Sitemap::Resource

The next (chronologically later) article after this one or nil if this is the most recent article.

Returns:

  • (Middleman::Sitemap::Resource)


305
306
307
# File 'lib/middleman-blog/blog_article.rb', line 305

def article_next
  blog_data.articles.reverse.find { |a| a.date > date }
end

#article_previousBlogArticle

The previous (chronologically earlier) article before this one or nil if this is the first article.

Returns:



295
296
297
# File 'lib/middleman-blog/blog_article.rb', line 295

def article_previous
  blog_data.articles.find { |a| a.date < date }
end

#blog_dataBlogData

A reference to the Middleman::Blog::BlogData for this article's blog.

Returns:



28
29
30
# File 'lib/middleman-blog/blog_article.rb', line 28

def blog_data
  blog_controller.data
end

#blog_optionsConfigurationManager

The options for this article's blog.

Returns:

  • (ConfigurationManager)


37
38
39
# File 'lib/middleman-blog/blog_article.rb', line 37

def blog_options
  blog_controller.options
end

#bodyString

The body of this article, in HTML (no layout). This is for things like RSS feeds or lists of articles - individual articles will automatically be rendered from their template.

Returns:

  • (String)


103
104
105
# File 'lib/middleman-blog/blog_article.rb', line 103

def body
  render layout: false
end

#dateTimeWithZone

Attempt to figure out the date of the post. The date should be present in the source path, but users may also provide a date in the frontmatter in order to provide a time of day for sorting reasons.

Returns:

  • (TimeWithZone)


207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/middleman-blog/blog_article.rb', line 207

def date
  return @_date if @_date

  frontmatter_date = data['date']

  # First get the date from frontmatter
  @_date = if frontmatter_date.is_a? Time
    frontmatter_date.in_time_zone
  else
    Time.zone.parse(frontmatter_date.to_s)
  end

  # Next figure out the date from the filename
  source_vars = blog_data.source_template.variables

  if source_vars.include?('year') &&
     source_vars.include?('month') &&
     source_vars.include?('day')

    filename_date = Time.zone.local(path_part('year').to_i, path_part('month').to_i, path_part('day').to_i)
    if @_date
      raise "The date in #{path}'s filename doesn't match the date in its frontmatter" unless @_date.to_date == filename_date.to_date
    else
      @_date = filename_date.to_time.in_time_zone
    end

  end

  raise "Blog post #{path} needs a date in its filename or frontmatter" unless @_date

  @_date
end

#default_summary_generator(rendered, length, ellipsis) ⇒ Object

The default summary generator first tries to find the summary_separator and take the text before it. If that doesn't work, it will truncate text without splitting the middle of an HTML tag, using a Nokogiri-based TruncateHTML utility.

Parameters:

  • rendered (String)

    The rendered blog article

  • length (Integer)

    The length in characters to truncate to. -1 or nil will return the whole article.

  • ellipsis (String)

    The ellipsis string to use when content is trimmed.



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/middleman-blog/blog_article.rb', line 143

def default_summary_generator(rendered, length, ellipsis)
  if blog_options.summary_separator && rendered.match(blog_options.summary_separator)
    require 'middleman-blog/truncate_html'
    TruncateHTML.truncate_at_separator(rendered, blog_options.summary_separator)

  elsif length && length >= 0
    require 'middleman-blog/truncate_html'
    TruncateHTML.truncate_at_length(rendered, length, ellipsis)

  elsif blog_options.summary_length&.positive?
    require 'middleman-blog/truncate_html'
    TruncateHTML.truncate_at_length(rendered, blog_options.summary_length, ellipsis)

  else
    rendered
  end
end

#localeSymbol Also known as: lang

The language of the article. The language can be present in the frontmatter or in the source path. If both are present, they must match. If neither specifies a lang, I18n's default_locale will be used. If lang is set to nil, or the :i18n extension is not activated at all, nil will be returned.

Returns:

  • (Symbol)

    Language code (for example, :en or :de)



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/middleman-blog/blog_article.rb', line 185

def locale
  frontmatter_locale = data['locale'] || data['lang']
  filename_locale    = path_part('locale') || path_part('lang')

  raise "The locale in #{path}'s filename (#{filename_locale.inspect}) doesn't match the lang in its frontmatter (#{frontmatter_locale.inspect})" if frontmatter_locale && filename_locale && frontmatter_locale != filename_locale

  default_locale = I18n.default_locale if defined? ::I18n

  found_locale = frontmatter_locale || filename_locale || default_locale
  found_locale&.to_sym
end

#next_articleMiddleman::Sitemap::Resource

Deprecated.

Use #article_next instead.

The next (chronologically later) article after this one or nil if this is the most recent article.

Returns:

  • (Middleman::Sitemap::Resource)


284
285
286
# File 'lib/middleman-blog/blog_article.rb', line 284

def next_article
  article_next
end

#previous_articleBlogArticle

Deprecated.

Use #article_previous instead.

The previous (chronologically earlier) article before this one or nil if this is the first article.

Returns:



271
272
273
# File 'lib/middleman-blog/blog_article.rb', line 271

def previous_article
  article_previous
end

#published?Boolean

Whether or not this article has been published. An article is considered published in the following scenarios:

  1. Frontmatter does not set published to false and either
  2. The blog option publish_future_dated is true or
  3. The article's date is after the current time

Returns:

  • (Boolean)


92
93
94
# File 'lib/middleman-blog/blog_article.rb', line 92

def published?
  data['published'] != false && (blog_options.publish_future_dated || date <= Time.current)
end

#render(opts = {}, locs = {}, &block) ⇒ String

Render this resource to a string with the appropriate layout. Called automatically by Middleman.

Returns:

  • (String)


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/middleman-blog/blog_article.rb', line 47

def render(opts = {}, locs = {}, &block)
  unless opts.key?(:layout)
    opts[:layout] = [:options][:layout]
    opts[:layout] = blog_options.layout if opts[:layout].nil? || opts[:layout] == :_auto_layout
    opts[:layout] = opts[:layout].to_s if opts[:layout].is_a? Symbol
  end

  content = super(opts, locs, &block)

  if blog_options.summary_separator && !opts[:keep_separator]
    if content.match?(blog_options.summary_separator)
      require 'middleman-blog/truncate_html'
      
      # Only apply separator logic when rendering without layout
      if opts[:layout] == false
        content = TruncateHTML.content_after_separator(content, blog_options.summary_separator)
      else
        # When rendering with layout, just remove the separator marker but keep all content
        content = content.gsub(blog_options.summary_separator, '')
      end
    end
  end

  content
end

#slugString

The "slug" of the article that shows up in its URL. The article slug is a parametrized version of the #title (lowercase, spaces replaced with dashes, etc) and can be used in the blog permalink as :title.

Returns:

  • (String)


247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/middleman-blog/blog_article.rb', line 247

def slug
  if data['slug']
    Blog::UriTemplates.safe_parameterize(data['slug'], preserve_underscores: blog_options.preserve_underscores_in_slugs)

  elsif blog_data.source_template.variables.include?('title')
    Blog::UriTemplates.safe_parameterize(path_part('title'), preserve_underscores: blog_options.preserve_underscores_in_slugs)

  elsif title
    Blog::UriTemplates.safe_parameterize(title, preserve_underscores: blog_options.preserve_underscores_in_slugs)

  else
    raise "Can't generate a slug for #{path} because it has no :title in its path pattern or title/slug in its frontmatter."

  end
end

#summary(length = nil, ellipsis = '...') ⇒ String

The summary for this article, in HTML.

The blog option summary_generator can be set to a Proc in order to provide custom summary generation. The Proc is provided the rendered content of the article (without layout), the desired length to trim the summary to, and the ellipsis string to use. Otherwise the #default_summary_generator will be used, which returns either everything before the summary separator (set via the blog option summary_separator and defaulting to "READMORE") if it is found, or the first summary_length characters of the post.

Parameters:

  • length (Number) (defaults to: nil)

    How many characters to trim the summary to.

  • ellipsis (String) (defaults to: '...')

    The ellipsis string to use when content is trimmed.

Returns:

  • (String)


123
124
125
126
127
128
129
130
131
# File 'lib/middleman-blog/blog_article.rb', line 123

def summary(length = nil, ellipsis = '...')
  rendered = render layout: false, keep_separator: true

  if blog_options.summary_generator
    blog_options.summary_generator.call(self, rendered, length, ellipsis)
  else
    default_summary_generator(rendered, length, ellipsis)
  end
end

#tagsArray<String>

A list of tags for this article, set from frontmatter.

Returns:

  • (Array<String>)

    (never nil)



166
167
168
169
170
171
172
173
174
# File 'lib/middleman-blog/blog_article.rb', line 166

def tags
   = data['tags']

  if .is_a? String
    .split(',').map(&:strip)
  else
    Array().map(&:to_s)
  end
end

#titleString

The title of the article, set from frontmatter.

Returns:

  • (String)


78
79
80
# File 'lib/middleman-blog/blog_article.rb', line 78

def title
  data['title'].to_s
end