meta-tags 2.22.3 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +83 -0
- data/README.md +191 -60
- data/SECURITY.md +40 -0
- data/lib/generators/meta_tags/install_generator.rb +5 -0
- data/lib/generators/meta_tags/templates/config/initializers/meta_tags.rb +16 -5
- data/lib/meta_tags/configuration.rb +31 -10
- data/lib/meta_tags/content_tag.rb +3 -4
- data/lib/meta_tags/controller_helper.rb +11 -8
- data/lib/meta_tags/meta_tags_collection.rb +123 -50
- data/lib/meta_tags/railtie.rb +5 -0
- data/lib/meta_tags/renderer.rb +124 -84
- data/lib/meta_tags/tag.rb +10 -8
- data/lib/meta_tags/text_normalizer.rb +54 -40
- data/lib/meta_tags/version.rb +1 -1
- data/lib/meta_tags/view_helper.rb +65 -75
- data/lib/meta_tags.rb +6 -2
- data/sig/{lib/_internal/rails.rbs → _private/rails_support.rbs} +5 -19
- data/sig/lib/meta_tags/configuration.rbs +5 -3
- data/sig/lib/meta_tags/controller_helper.rbs +1 -1
- data/sig/lib/meta_tags/meta_tags_collection.rbs +9 -3
- data/sig/lib/meta_tags/rails_interfaces.rbs +15 -0
- data/sig/lib/meta_tags/renderer.rbs +11 -7
- data/sig/lib/meta_tags/tag.rbs +1 -1
- data/sig/lib/meta_tags/view_helper.rbs +9 -37
- data/sig/lib/meta_tags.rbs +5 -1
- data.tar.gz.sig +0 -0
- metadata +22 -5
- metadata.gz.sig +0 -0
data/SECURITY.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
Security fixes are provided for the latest released version of `meta-tags`.
|
|
6
|
+
|
|
7
|
+
Older releases may not receive security updates. If you are reporting a vulnerability, please confirm whether it affects the latest release.
|
|
8
|
+
|
|
9
|
+
## Reporting a Vulnerability
|
|
10
|
+
|
|
11
|
+
Please do not report security issues through public GitHub issues, discussions, or pull requests.
|
|
12
|
+
|
|
13
|
+
Use GitHub's private vulnerability reporting feature in the repository's `Security` tab to report a vulnerability.
|
|
14
|
+
|
|
15
|
+
If private reporting through GitHub is unavailable for any reason, send a report by email to `kpumuk@kpumuk.info` with `SECURITY` in the subject line.
|
|
16
|
+
|
|
17
|
+
When possible, include:
|
|
18
|
+
|
|
19
|
+
- a short description of the issue
|
|
20
|
+
- the affected version, commit, or tag
|
|
21
|
+
- any required environment or configuration details
|
|
22
|
+
- step-by-step reproduction instructions
|
|
23
|
+
- proof-of-concept code, logs, or screenshots
|
|
24
|
+
- an explanation of the likely impact
|
|
25
|
+
|
|
26
|
+
## Disclosure Policy
|
|
27
|
+
|
|
28
|
+
Please allow a reasonable amount of time to investigate and prepare a fix before making the issue public.
|
|
29
|
+
|
|
30
|
+
If the report is confirmed, the fix will be released as soon as practical. Public disclosure will generally happen through a GitHub security advisory and/or release notes after a fix is available.
|
|
31
|
+
|
|
32
|
+
## Scope Notes
|
|
33
|
+
|
|
34
|
+
`meta-tags` is a Ruby gem for Rails applications that renders HTML metadata such as titles, descriptions, canonical links, robots directives, and social tags.
|
|
35
|
+
|
|
36
|
+
Some behavior may depend on the host Rails application, layouts, templates, framework version, gem version, or deployment/runtime configuration. If a report depends on a specific setup, include those details.
|
|
37
|
+
|
|
38
|
+
## Response Expectations
|
|
39
|
+
|
|
40
|
+
This is a single-maintainer project, so response times may vary. Good-faith reports are appreciated, and I will try to acknowledge valid reports as quickly as practical.
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MetaTags
|
|
4
|
+
# Rails generators for MetaTags.
|
|
4
5
|
module Generators
|
|
6
|
+
# Installs the default MetaTags initializer into a Rails application.
|
|
5
7
|
class InstallGenerator < Rails::Generators::Base
|
|
6
8
|
desc "Copy MetaTags default files"
|
|
7
9
|
source_root File.expand_path("templates", __dir__)
|
|
8
10
|
|
|
11
|
+
# Copies the default MetaTags initializer template.
|
|
12
|
+
#
|
|
13
|
+
# @return [void]
|
|
9
14
|
def copy_config
|
|
10
15
|
template "config/initializers/meta_tags.rb"
|
|
11
16
|
end
|
|
@@ -18,25 +18,36 @@ MetaTags.configure do |config|
|
|
|
18
18
|
# a Unicode space (/\p{Space}/).
|
|
19
19
|
# config.truncate_on_natural_separator = " "
|
|
20
20
|
|
|
21
|
+
# When true, arrays passed to `title` and `keywords` stop at item
|
|
22
|
+
# boundaries instead of partially truncating the overflowing item.
|
|
23
|
+
# Single-item arrays are still truncated normally. Default is false.
|
|
24
|
+
# config.truncate_array_items_at_boundaries = false
|
|
25
|
+
|
|
21
26
|
# Maximum length of the page description. Default is 300.
|
|
22
27
|
# Set to nil or 0 to remove limits.
|
|
23
28
|
# config.description_limit = 300
|
|
24
29
|
|
|
25
|
-
#
|
|
30
|
+
# Legacy compatibility: maximum length of the keywords meta tag.
|
|
31
|
+
# Most search engines ignore this tag. Default is 255.
|
|
26
32
|
# config.keywords_limit = 255
|
|
27
33
|
|
|
28
|
-
#
|
|
29
|
-
#
|
|
34
|
+
# Legacy compatibility: default separator for the keywords meta tag
|
|
35
|
+
# when an Array is passed. Default is ", ".
|
|
30
36
|
# config.keywords_separator = ', '
|
|
31
37
|
|
|
32
|
-
#
|
|
33
|
-
# appear on the page as is. Default is true.
|
|
38
|
+
# Legacy compatibility: when true, keywords will be converted to lowercase.
|
|
39
|
+
# Otherwise they will appear on the page as is. Default is true.
|
|
34
40
|
# config.keywords_lowercase = true
|
|
35
41
|
|
|
36
42
|
# When true, the output will not include new line characters between meta tags.
|
|
37
43
|
# Default is false.
|
|
38
44
|
# config.minify_output = false
|
|
39
45
|
|
|
46
|
+
# When true, Symbols inside nested meta tag arrays resolve as references to
|
|
47
|
+
# normalized top-level tags. Default is false until MetaTags 3.0, when this
|
|
48
|
+
# behavior will become the default.
|
|
49
|
+
# config.resolve_symbolic_references_in_arrays = false
|
|
50
|
+
|
|
40
51
|
# When false, generated meta tags will be self-closing (<meta ... />) instead
|
|
41
52
|
# of open (`<meta ...>`). Default is true.
|
|
42
53
|
# config.open_meta_tags = true
|
|
@@ -15,6 +15,10 @@ module MetaTags
|
|
|
15
15
|
# A string or regexp separator to truncate text at a natural break.
|
|
16
16
|
attr_accessor :truncate_on_natural_separator
|
|
17
17
|
|
|
18
|
+
# When true, multi-item arrays stop at item boundaries instead of
|
|
19
|
+
# truncating the overflowing item.
|
|
20
|
+
attr_accessor :truncate_array_items_at_boundaries
|
|
21
|
+
|
|
18
22
|
# How many characters to truncate description to.
|
|
19
23
|
attr_accessor :description_limit
|
|
20
24
|
|
|
@@ -24,7 +28,7 @@ module MetaTags
|
|
|
24
28
|
# Keywords separator - a string to join keywords with.
|
|
25
29
|
attr_accessor :keywords_separator
|
|
26
30
|
|
|
27
|
-
# Should keywords forced into lowercase?
|
|
31
|
+
# Should keywords be forced into lowercase?
|
|
28
32
|
attr_accessor :keywords_lowercase
|
|
29
33
|
|
|
30
34
|
# Switches between open (<meta ... >) and closed (<meta ... />) meta tags.
|
|
@@ -35,13 +39,18 @@ module MetaTags
|
|
|
35
39
|
# Default is false.
|
|
36
40
|
attr_accessor :minify_output
|
|
37
41
|
|
|
38
|
-
#
|
|
39
|
-
# -
|
|
42
|
+
# When true, Symbols inside nested meta tag arrays resolve as references to
|
|
43
|
+
# normalized top-level tags. Default is false until MetaTags 3.0.
|
|
44
|
+
attr_accessor :resolve_symbolic_references_in_arrays
|
|
45
|
+
|
|
46
|
+
# Custom meta tags that should use the `property` attribute instead of `name`.
|
|
47
|
+
# An array of strings or symbols representing their names or name prefixes.
|
|
40
48
|
attr_reader :property_tags
|
|
41
49
|
|
|
42
|
-
# Configure
|
|
43
|
-
#
|
|
44
|
-
#
|
|
50
|
+
# Configure whether MetaTags should skip canonical links on pages with
|
|
51
|
+
# `noindex: true`.
|
|
52
|
+
# John Mueller has noted that mixing `noindex` and `rel=canonical` sends
|
|
53
|
+
# contradictory signals.
|
|
45
54
|
# https://www.reddit.com/r/TechSEO/comments/8yahdr/2_questions_about_the_canonical_tag/e2dey9i/
|
|
46
55
|
attr_accessor :skip_canonical_links_on_noindex
|
|
47
56
|
|
|
@@ -50,16 +59,20 @@ module MetaTags
|
|
|
50
59
|
reset_defaults!
|
|
51
60
|
end
|
|
52
61
|
|
|
62
|
+
# Returns the default meta tag prefixes and names that use `property`.
|
|
63
|
+
#
|
|
64
|
+
# @return [Array<String>] default property tag names.
|
|
53
65
|
def default_property_tags
|
|
54
66
|
[
|
|
55
|
-
# App
|
|
67
|
+
# App Links metadata https://developers.facebook.com/docs/applinks/metadata-reference
|
|
56
68
|
"al",
|
|
57
69
|
# Open Graph Markup https://developers.facebook.com/docs/sharing/webmasters#markup
|
|
58
70
|
"fb",
|
|
59
71
|
"og",
|
|
60
|
-
# Facebook
|
|
61
|
-
#
|
|
62
|
-
# 'restaurant:category', 'restaurant:price_rating', and
|
|
72
|
+
# Facebook Open Graph object types https://developers.facebook.com/docs/reference/opengraph
|
|
73
|
+
# These tags are matched as exact property names or namespace prefixes, so e.g.
|
|
74
|
+
# 'restaurant' affects 'restaurant:category', 'restaurant:price_rating', and other
|
|
75
|
+
# properties under that namespace.
|
|
63
76
|
"article",
|
|
64
77
|
"book",
|
|
65
78
|
"books",
|
|
@@ -75,14 +88,21 @@ module MetaTags
|
|
|
75
88
|
].freeze
|
|
76
89
|
end
|
|
77
90
|
|
|
91
|
+
# Indicates whether meta tags should be rendered with open tag syntax.
|
|
92
|
+
#
|
|
93
|
+
# @return [Boolean] true when open meta tags are enabled.
|
|
78
94
|
def open_meta_tags?
|
|
79
95
|
!!open_meta_tags
|
|
80
96
|
end
|
|
81
97
|
|
|
98
|
+
# Restores the default configuration values.
|
|
99
|
+
#
|
|
100
|
+
# @return [void]
|
|
82
101
|
def reset_defaults!
|
|
83
102
|
@title_limit = 70
|
|
84
103
|
@truncate_site_title_first = false
|
|
85
104
|
@truncate_on_natural_separator = " "
|
|
105
|
+
@truncate_array_items_at_boundaries = false
|
|
86
106
|
@title_tag_attributes = {}
|
|
87
107
|
@description_limit = 300
|
|
88
108
|
@keywords_limit = 255
|
|
@@ -91,6 +111,7 @@ module MetaTags
|
|
|
91
111
|
@property_tags = default_property_tags.dup
|
|
92
112
|
@open_meta_tags = true
|
|
93
113
|
@minify_output = false
|
|
114
|
+
@resolve_symbolic_references_in_arrays = false
|
|
94
115
|
@skip_canonical_links_on_noindex = false
|
|
95
116
|
end
|
|
96
117
|
end
|
|
@@ -4,13 +4,12 @@ module MetaTags
|
|
|
4
4
|
# Represents an HTML meta tag with content (<tag></tag>).
|
|
5
5
|
# Content should be passed as a `:content` attribute.
|
|
6
6
|
class ContentTag < Tag
|
|
7
|
-
#
|
|
7
|
+
# Renders the tag in a Rails view.
|
|
8
8
|
#
|
|
9
|
-
# @param [ActionView::Base]
|
|
9
|
+
# @param view [ActionView::Base] instance of a Rails view.
|
|
10
10
|
# @return [String] HTML string for the tag.
|
|
11
|
-
#
|
|
12
11
|
def render(view)
|
|
13
|
-
view.content_tag(name, attributes[:content],
|
|
12
|
+
view.content_tag(name, attributes[:content], serialize_iso8601_attributes(attributes.except(:content)))
|
|
14
13
|
end
|
|
15
14
|
end
|
|
16
15
|
end
|
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
module MetaTags
|
|
4
4
|
# Contains methods to use in controllers.
|
|
5
|
-
#
|
|
6
5
|
# You can define several instance variables to set meta tags:
|
|
7
6
|
# @page_title = 'Member Login'
|
|
8
7
|
# @page_description = 'Member login page.'
|
|
9
|
-
# @page_keywords = 'Site, Login, Members'
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# as {ViewHelper#set_meta_tags}.
|
|
13
|
-
#
|
|
8
|
+
# @page_keywords = 'Site, Login, Members' # legacy keywords tag
|
|
9
|
+
# You can also use the {#set_meta_tags} method, which has the same
|
|
10
|
+
# parameters as {ViewHelper#set_meta_tags}.
|
|
14
11
|
module ControllerHelper
|
|
15
|
-
# Processes the <tt>@page_title</tt>, <tt>@
|
|
16
|
-
# <tt>@
|
|
12
|
+
# Processes the <tt>@page_title</tt>, <tt>@page_description</tt>, and
|
|
13
|
+
# legacy <tt>@page_keywords</tt> instance variables and calls +render+.
|
|
14
|
+
#
|
|
15
|
+
# @param args [Array<Object>] positional arguments forwarded to +render+.
|
|
16
|
+
# @param block [Proc, nil] optional block forwarded to +render+.
|
|
17
|
+
# @yield optional block forwarded to +render+.
|
|
18
|
+
# @yieldreturn [Object] result of the render block.
|
|
17
19
|
def render(*args, &block)
|
|
18
20
|
meta_tags[:title] = @page_title if defined?(@page_title) && @page_title
|
|
19
21
|
meta_tags[:keywords] = @page_keywords if defined?(@page_keywords) && @page_keywords
|
|
@@ -24,6 +26,7 @@ module MetaTags
|
|
|
24
26
|
|
|
25
27
|
# Set meta tags for the page.
|
|
26
28
|
#
|
|
29
|
+
# @param meta_tags [Hash] list of meta tags to merge into the page state.
|
|
27
30
|
# See <tt>MetaTags::ViewHelper#set_meta_tags</tt> for details.
|
|
28
31
|
def set_meta_tags(meta_tags)
|
|
29
32
|
self.meta_tags.update(meta_tags)
|
|
@@ -1,42 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MetaTags
|
|
4
|
-
#
|
|
4
|
+
# This class represents a collection of meta tags. Basically a wrapper around
|
|
5
5
|
# HashWithIndifferentAccess, with some additional helper methods.
|
|
6
6
|
class MetaTagsCollection
|
|
7
7
|
attr_reader :meta_tags
|
|
8
8
|
|
|
9
9
|
# Initializes a new instance of MetaTagsCollection.
|
|
10
|
-
#
|
|
11
10
|
def initialize
|
|
12
11
|
@meta_tags = ActiveSupport::HashWithIndifferentAccess.new
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
# Returns meta tag value by name.
|
|
16
15
|
#
|
|
17
|
-
# @param [String, Symbol]
|
|
16
|
+
# @param name [String, Symbol] meta tag name.
|
|
18
17
|
# @return meta tag value.
|
|
19
|
-
#
|
|
20
18
|
def [](name)
|
|
21
19
|
@meta_tags[name]
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
# Sets meta tag value by name.
|
|
25
23
|
#
|
|
26
|
-
# @param [String, Symbol]
|
|
24
|
+
# @param name [String, Symbol] meta tag name.
|
|
27
25
|
# @param value meta tag value.
|
|
28
26
|
# @return meta tag value.
|
|
29
|
-
#
|
|
30
27
|
def []=(name, value)
|
|
31
28
|
@meta_tags[name] = value
|
|
32
29
|
end
|
|
33
30
|
|
|
34
|
-
# Recursively merges a Hash of meta tag attributes into current list.
|
|
31
|
+
# Recursively merges a Hash of meta tag attributes into the current list.
|
|
35
32
|
#
|
|
36
|
-
# @param [Hash, #to_meta_tags]
|
|
33
|
+
# @param object [Hash, #to_meta_tags] Hash of meta tags (or object responding
|
|
37
34
|
# to #to_meta_tags and returning a hash) to merge into the current list.
|
|
38
35
|
# @return [Hash] result of the merge.
|
|
39
|
-
#
|
|
40
36
|
def update(object = {})
|
|
41
37
|
meta_tags = if object.respond_to?(:to_meta_tags)
|
|
42
38
|
# @type var object: _MetaTagish & Object
|
|
@@ -48,11 +44,10 @@ module MetaTags
|
|
|
48
44
|
@meta_tags.deep_merge! normalize_open_graph(meta_tags)
|
|
49
45
|
end
|
|
50
46
|
|
|
51
|
-
#
|
|
47
|
+
# Temporarily merges defaults with the current meta tags list and yields the block.
|
|
52
48
|
#
|
|
53
|
-
# @param [Hash]
|
|
49
|
+
# @param defaults [Hash] list of default meta tag attributes.
|
|
54
50
|
# @return result of the block call.
|
|
55
|
-
#
|
|
56
51
|
def with_defaults(defaults = {})
|
|
57
52
|
old_meta_tags = @meta_tags
|
|
58
53
|
@meta_tags = normalize_open_graph(defaults).deep_merge!(@meta_tags)
|
|
@@ -63,9 +58,8 @@ module MetaTags
|
|
|
63
58
|
|
|
64
59
|
# Constructs the full title as if it would be rendered in title meta tag.
|
|
65
60
|
#
|
|
66
|
-
# @param [Hash]
|
|
61
|
+
# @param defaults [Hash] list of default meta tag attributes.
|
|
67
62
|
# @return [String] page title.
|
|
68
|
-
#
|
|
69
63
|
def full_title(defaults = {})
|
|
70
64
|
with_defaults(defaults) { extract_full_title }
|
|
71
65
|
end
|
|
@@ -73,30 +67,26 @@ module MetaTags
|
|
|
73
67
|
# Constructs the title without site title (for normalized parameters). When title is empty,
|
|
74
68
|
# use the site title instead.
|
|
75
69
|
#
|
|
70
|
+
# @param defaults [Hash] list of default meta tag attributes.
|
|
76
71
|
# @return [String] page title.
|
|
77
|
-
#
|
|
78
72
|
def page_title(defaults = {})
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
ensure
|
|
84
|
-
@meta_tags[:site] = old_site
|
|
73
|
+
with_defaults(defaults) do
|
|
74
|
+
site = extract(:site)
|
|
75
|
+
extract_full_title.presence || site || ""
|
|
76
|
+
end
|
|
85
77
|
end
|
|
86
78
|
|
|
87
79
|
# Deletes and returns a meta tag value by name.
|
|
88
80
|
#
|
|
89
|
-
# @param [String, Symbol]
|
|
81
|
+
# @param name [String, Symbol] meta tag name.
|
|
90
82
|
# @return [Object] meta tag value.
|
|
91
|
-
#
|
|
92
83
|
def extract(name)
|
|
93
84
|
@meta_tags.delete(name)
|
|
94
85
|
end
|
|
95
86
|
|
|
96
87
|
# Deletes specified meta tags.
|
|
97
88
|
#
|
|
98
|
-
# @param [Array<String, Symbol>]
|
|
99
|
-
#
|
|
89
|
+
# @param names [Array<String, Symbol>] list of meta tags to delete.
|
|
100
90
|
def delete(*names)
|
|
101
91
|
names.each { |name| @meta_tags.delete(name) }
|
|
102
92
|
end
|
|
@@ -104,7 +94,6 @@ module MetaTags
|
|
|
104
94
|
# Extracts full page title and deletes all related meta tags.
|
|
105
95
|
#
|
|
106
96
|
# @return [String] page title.
|
|
107
|
-
#
|
|
108
97
|
def extract_full_title
|
|
109
98
|
site_title = extract(:site) || ""
|
|
110
99
|
title = extract_title
|
|
@@ -117,14 +106,20 @@ module MetaTags
|
|
|
117
106
|
# Extracts page title as an array of segments without site title and separators.
|
|
118
107
|
#
|
|
119
108
|
# @return [Array<String>] segments of page title.
|
|
120
|
-
#
|
|
121
109
|
def extract_title
|
|
110
|
+
lowercase = extract(:lowercase) == true
|
|
122
111
|
title = extract(:title).presence
|
|
123
112
|
return [] unless title
|
|
124
113
|
|
|
125
|
-
# @type var title: Array[String]
|
|
126
114
|
title = Array(title)
|
|
127
|
-
|
|
115
|
+
if lowercase
|
|
116
|
+
return title.map do |segment|
|
|
117
|
+
string = String.try_convert(segment)
|
|
118
|
+
raise ArgumentError, "Expected a string or an object that implements #to_str" unless string
|
|
119
|
+
|
|
120
|
+
string.downcase
|
|
121
|
+
end
|
|
122
|
+
end
|
|
128
123
|
|
|
129
124
|
title
|
|
130
125
|
end
|
|
@@ -132,7 +127,6 @@ module MetaTags
|
|
|
132
127
|
# Extracts title separator as a string.
|
|
133
128
|
#
|
|
134
129
|
# @return [String] page title separator.
|
|
135
|
-
#
|
|
136
130
|
def extract_separator
|
|
137
131
|
if meta_tags[:separator] == false
|
|
138
132
|
# Special case: if separator is hidden, do not display suffix/prefix
|
|
@@ -147,11 +141,44 @@ module MetaTags
|
|
|
147
141
|
TextNormalizer.safe_join([prefix, separator, suffix], "")
|
|
148
142
|
end
|
|
149
143
|
|
|
150
|
-
# Extracts
|
|
151
|
-
#
|
|
152
|
-
# @return [Hash<String,String>] noindex attributes.
|
|
144
|
+
# Extracts robots settings as a Hash mapping tag names to rendered values.
|
|
153
145
|
#
|
|
146
|
+
# @return [Hash{String => String}] robots attributes.
|
|
154
147
|
def extract_robots
|
|
148
|
+
result = robots
|
|
149
|
+
delete(:noindex, :index, :follow, :nofollow, :noarchive)
|
|
150
|
+
[:robots, :googlebot, :bingbot].each do |bot|
|
|
151
|
+
extract(bot) if meta_tags[bot].is_a?(Hash)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
result
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Returns whether robots settings produce a noindex directive.
|
|
158
|
+
#
|
|
159
|
+
# @return [Boolean] true when a noindex directive will be rendered.
|
|
160
|
+
def noindex?
|
|
161
|
+
contents = robots.values
|
|
162
|
+
property_tags = MetaTags.config.property_tags.map(&:to_s)
|
|
163
|
+
[:robots, :googlebot, :bingbot].each do |bot|
|
|
164
|
+
values = meta_tags[bot]
|
|
165
|
+
next if values.is_a?(Hash) || property_tags.include?(bot.to_s)
|
|
166
|
+
|
|
167
|
+
contents.concat(Array(values))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
contents.any? do |content|
|
|
171
|
+
content.to_s.split(",").any? { |directive| directive.strip.casecmp?("noindex") }
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
protected
|
|
176
|
+
|
|
177
|
+
# Returns robots settings without modifying the collection.
|
|
178
|
+
#
|
|
179
|
+
# @return [Hash{String => String}] robots attributes.
|
|
180
|
+
def robots
|
|
181
|
+
# @type var result: Hash[String, Array[String]]
|
|
155
182
|
result = Hash.new { |h, k| h[k] = [] }
|
|
156
183
|
|
|
157
184
|
[
|
|
@@ -164,58 +191,104 @@ module MetaTags
|
|
|
164
191
|
calculate_robots_attributes(result, attributes)
|
|
165
192
|
end
|
|
166
193
|
|
|
194
|
+
[:robots, :googlebot, :bingbot].each do |bot|
|
|
195
|
+
values = meta_tags[bot]
|
|
196
|
+
if values.is_a?(Hash)
|
|
197
|
+
values.each do |key, value|
|
|
198
|
+
next if value == false
|
|
199
|
+
|
|
200
|
+
directive = (value.nil? || value == true) ? key.to_s : "#{key}:#{value}"
|
|
201
|
+
result[bot.to_s] << directive
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
167
206
|
result.transform_values { |v| v.join(", ") }
|
|
168
207
|
end
|
|
169
208
|
|
|
170
|
-
protected
|
|
171
|
-
|
|
172
209
|
# Converts input hash to HashWithIndifferentAccess and renames :open_graph to :og.
|
|
210
|
+
# When both aliases contain hashes, they are deep-merged with :og taking precedence.
|
|
173
211
|
#
|
|
174
|
-
# @param [Hash]
|
|
212
|
+
# @param meta_tags [Hash] list of meta tags.
|
|
175
213
|
# @return [ActiveSupport::HashWithIndifferentAccess] normalized meta tags list.
|
|
176
|
-
#
|
|
177
214
|
def normalize_open_graph(meta_tags)
|
|
178
215
|
meta_tags = meta_tags.with_indifferent_access
|
|
179
|
-
|
|
216
|
+
if meta_tags.key?(:open_graph)
|
|
217
|
+
open_graph = meta_tags.delete(:open_graph)
|
|
218
|
+
if meta_tags.key?(:og)
|
|
219
|
+
meta_tags[:og] = open_graph.dup.deep_merge!(meta_tags[:og]) if open_graph.is_a?(Hash) && meta_tags[:og].is_a?(Hash)
|
|
220
|
+
else
|
|
221
|
+
meta_tags[:og] = open_graph
|
|
222
|
+
end
|
|
223
|
+
end
|
|
180
224
|
meta_tags
|
|
181
225
|
end
|
|
182
226
|
|
|
183
227
|
# Extracts separator segment without deleting it from meta tags list.
|
|
184
|
-
# If the value is false, empty string will be returned.
|
|
228
|
+
# If the value is false, an empty string will be returned.
|
|
185
229
|
#
|
|
186
|
-
# @param [Symbol, String]
|
|
187
|
-
# @param [String] default
|
|
230
|
+
# @param name [Symbol, String] separator segment name.
|
|
231
|
+
# @param default [String] default value.
|
|
188
232
|
# @return [String] separator segment value.
|
|
189
|
-
#
|
|
190
233
|
def extract_separator_section(name, default)
|
|
191
234
|
(meta_tags[name] == false) ? "" : (meta_tags[name] || default)
|
|
192
235
|
end
|
|
193
236
|
|
|
194
|
-
# Extracts robots attribute (noindex, nofollow, etc)
|
|
195
|
-
#
|
|
196
|
-
# @param [String, Symbol] name noindex attribute name.
|
|
197
|
-
# @return [Array<String>] pair of noindex attribute name and value.
|
|
237
|
+
# Extracts a robots attribute name/value pair (noindex, nofollow, etc.).
|
|
198
238
|
#
|
|
239
|
+
# @param name [String, Symbol] noindex attribute name.
|
|
240
|
+
# @return [Array<Object>] normalized robots tag name(s) and directive value.
|
|
199
241
|
def extract_robots_attribute(name)
|
|
200
|
-
noindex =
|
|
201
|
-
noindex_name
|
|
202
|
-
|
|
242
|
+
noindex = meta_tags[name]
|
|
243
|
+
# @type var noindex_name: String | Array[String]
|
|
244
|
+
noindex_name = if noindex.is_a?(Array)
|
|
245
|
+
noindex.reject { |target| target.is_a?(String) && target.blank? }.map(&:to_s)
|
|
246
|
+
elsif noindex.is_a?(String)
|
|
247
|
+
noindex.presence || []
|
|
248
|
+
else
|
|
249
|
+
"robots"
|
|
250
|
+
end
|
|
251
|
+
noindex_value = if robots_attribute_present?(noindex) && noindex_name.present?
|
|
252
|
+
name.to_s
|
|
253
|
+
end
|
|
203
254
|
|
|
204
255
|
[noindex_name, noindex_value]
|
|
205
256
|
end
|
|
206
257
|
|
|
258
|
+
# Returns whether a robots attribute resolves to at least one target.
|
|
259
|
+
#
|
|
260
|
+
# @param value [Object] robots attribute value.
|
|
261
|
+
# @return [Boolean] true when the attribute produces a directive.
|
|
262
|
+
def robots_attribute_present?(value)
|
|
263
|
+
!!value && (!value.is_a?(Array) || !value.empty?)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Appends resolved robots directives while preserving first-write priority.
|
|
267
|
+
#
|
|
268
|
+
# @param result [Hash{String => Array<String>}] robots directives grouped by tag name.
|
|
269
|
+
# @param attributes [Symbol, Array<Symbol>] robots attributes to resolve.
|
|
270
|
+
# @return [void]
|
|
207
271
|
def calculate_robots_attributes(result, attributes)
|
|
208
272
|
processed = Set.new
|
|
209
273
|
Array(attributes).each do |attribute|
|
|
274
|
+
# @type var attribute: String | Symbol
|
|
210
275
|
names, value = extract_robots_attribute(attribute)
|
|
211
276
|
next unless value
|
|
212
277
|
|
|
213
|
-
|
|
278
|
+
robot_names = names.is_a?(String) ? [names] : names
|
|
279
|
+
robot_names.each do |name|
|
|
214
280
|
apply_robots_value(result, name, value, processed)
|
|
215
281
|
end
|
|
216
282
|
end
|
|
217
283
|
end
|
|
218
284
|
|
|
285
|
+
# Records a robots directive unless it has already been set for the same key.
|
|
286
|
+
#
|
|
287
|
+
# @param result [Hash{String => Array<String>}] robots directives grouped by tag name.
|
|
288
|
+
# @param name [String] robots tag name.
|
|
289
|
+
# @param value [String] robots directive value.
|
|
290
|
+
# @param processed [Set<String>] names already recorded in this pass.
|
|
291
|
+
# @return [void]
|
|
219
292
|
def apply_robots_value(result, name, value, processed)
|
|
220
293
|
name = name.to_s
|
|
221
294
|
return if processed.include?(name)
|
data/lib/meta_tags/railtie.rb
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MetaTags
|
|
4
|
+
# Hooks MetaTags helpers into Rails controllers and views.
|
|
4
5
|
class Railtie < Rails::Railtie
|
|
6
|
+
initializer "meta_tags.register_deprecator", before: :load_environment_config do |app|
|
|
7
|
+
app.deprecators[:meta_tags] = MetaTags.deprecator if app.respond_to?(:deprecators)
|
|
8
|
+
end
|
|
9
|
+
|
|
5
10
|
initializer "meta_tags.setup_action_controller" do
|
|
6
11
|
ActiveSupport.on_load :action_controller do
|
|
7
12
|
include MetaTags::ControllerHelper
|