From 5638c19a5ddbe2677b23c270dd869622c819e1ee Mon Sep 17 00:00:00 2001 From: Pat Hawks Date: Tue, 12 Jan 2016 12:09:43 -0800 Subject: [PATCH 01/35] Allow author data as an object --- lib/template.html | 21 +++++++++++++++++++-- spec/jekyll_seo_tag_spec.rb | 8 ++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/template.html b/lib/template.html index 7dfc5c3..2d70329 100644 --- a/lib/template.html +++ b/lib/template.html @@ -44,6 +44,23 @@ {% assign seo_description = seo_description | markdownify | strip_html | strip_newlines | escape_once %} {% endif %} +{% if page.author %} + {% if page.author.name %} + {% assign seo_author_name = page.author.name %} + {% else %} + {% assign seo_author_name = page.author %} + {% endif %} + + {% if page.author.twitter %} + {% assign seo_author_twitter = page.author.twitter %} + {% else %} + {% assign seo_author_twitter = page.author %} + {% endif %} +{% endif %} +{% if seo_author_twitter %} + {% assign seo_author_twitter = seo_author_twitter | replace:"@","" | prepend:"@" %} +{% endif %} + {% if seo_title %} {{ seo_title }} {% endif %} @@ -106,8 +123,8 @@ {% if page.image %} {% endif %} - {% if page.author %} - + {% if seo_author_twitter %} + {% endif %} {% endif %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index bbc83cb..ada5b33 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -166,6 +166,14 @@ describe Jekyll::SeoTag do expect(subject.render(context)).to match(expected) end + it "supports author data as an object" do + site = site({"twitter" => { "username" => "jekyllrb" }}) + page = page({"author" => {"twitter" => "@test"}}) + context = context({ :site => site, :page => page }) + expected = %r!! + expect(subject.render(context)).to match(expected) + end + it "outputs valid HTML" do site.process options = { From 6dab82639ea393f93033efc5e3f5005e864de2b4 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Mon, 25 Jan 2016 14:29:48 -0800 Subject: [PATCH 02/35] use the page.excerpt if the page.description doesn't exist --- lib/template.html | 2 ++ spec/jekyll_seo_tag_spec.rb | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index 7b7e69b..4326fa3 100644 --- a/lib/template.html +++ b/lib/template.html @@ -37,6 +37,8 @@ {% if page.description %} {% assign seo_description = page.description %} +{% elsif page.excerpt %} + {% assign seo_description = page.excerpt %} {% elsif site.description %} {% assign seo_description = site.description %} {% endif %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index ada5b33..f2fafd2 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -39,7 +39,14 @@ describe Jekyll::SeoTag do expect(subject.render(context)).to match(//) end - it "uses the site description when no page description exists" do + it "uses the page excerpt when no page description exists" do + page = page({"description" => "foobar"}) + context = context({ :page => page }) + expect(subject.render(context)).to match(//) + expect(subject.render(context)).to match(//) + end + + it "uses the site description when no page description nor excerpt exist" do site = site({"description" => "foo"}) context = context({ :site => site }) expect(subject.render(context)).to match(//) From c9b19c478d11da03c062e2dc0e2e7290154dd76d Mon Sep 17 00:00:00 2001 From: Pat Hawks Date: Fri, 29 Jan 2016 10:35:40 -0800 Subject: [PATCH 03/35] Add default filter --- lib/jekyll-seo-tag.rb | 4 +++- lib/jekyll-seo-tag/filters.rb | 14 ++++++++++++++ lib/template.html | 30 +++++------------------------- 3 files changed, 22 insertions(+), 26 deletions(-) create mode 100644 lib/jekyll-seo-tag/filters.rb diff --git a/lib/jekyll-seo-tag.rb b/lib/jekyll-seo-tag.rb index 2575fc4..1b6f62b 100644 --- a/lib/jekyll-seo-tag.rb +++ b/lib/jekyll-seo-tag.rb @@ -1,3 +1,5 @@ +require 'jekyll-seo-tag/filters' + module Jekyll class SeoTag < Liquid::Tag @@ -22,7 +24,7 @@ module Jekyll def info { :registers => context.registers, - :filters => [Jekyll::Filters] + :filters => [Jekyll::Filters, JekyllSeoTag::Filters] } end diff --git a/lib/jekyll-seo-tag/filters.rb b/lib/jekyll-seo-tag/filters.rb new file mode 100644 index 0000000..0f0d6ef --- /dev/null +++ b/lib/jekyll-seo-tag/filters.rb @@ -0,0 +1,14 @@ +module JekyllSeoTag + module Filters + + # This is available in Liquid from version 3 which is required by Jekyll 3 + # Provided here for compatibility with Jekyll 2.x + def default(input, default_value = ''.freeze) + if !input || input.respond_to?(:empty?) && input.empty? + default_value + else + input + end + end + end +end diff --git a/lib/template.html b/lib/template.html index 4326fa3..165df98 100644 --- a/lib/template.html +++ b/lib/template.html @@ -2,15 +2,10 @@ {% if site.url %} {% assign seo_url = site.url | append: site.baseurl %} -{% elsif site.github.url %} - {% assign seo_url = site.github.url %} {% endif %} +{% assign seo_url = seo_url | default: site.github.url %} -{% if site.title %} - {% assign seo_site_title = site.title %} -{% elsif site.name %} - {% assign seo_site_title = site.name %} -{% endif %} +{% assign seo_site_title = site.title | default: site.name %} {% if page.title %} {% assign seo_title = page.title %} @@ -35,29 +30,14 @@ {% assign seo_page_title = seo_page_title | markdownify | strip_html | strip_newlines | escape_once %} {% endif %} -{% if page.description %} - {% assign seo_description = page.description %} -{% elsif page.excerpt %} - {% assign seo_description = page.excerpt %} -{% elsif site.description %} - {% assign seo_description = site.description %} -{% endif %} +{% assign seo_description = page.description | default: page.excerpt | default: site.description %} {% if seo_description %} {% assign seo_description = seo_description | markdownify | strip_html | strip_newlines | escape_once %} {% endif %} {% if page.author %} - {% if page.author.name %} - {% assign seo_author_name = page.author.name %} - {% else %} - {% assign seo_author_name = page.author %} - {% endif %} - - {% if page.author.twitter %} - {% assign seo_author_twitter = page.author.twitter %} - {% else %} - {% assign seo_author_twitter = page.author %} - {% endif %} + {% assign seo_author_name = page.author.name | default: page.author %} + {% assign seo_author_twitter = page.author.twitter | default: page.author %} {% endif %} {% if seo_author_twitter %} {% assign seo_author_twitter = seo_author_twitter | replace:"@","" | prepend:"@" %} From 56c7f4e238c815af4a81167f37c6131a8de1b565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Garc=C3=A9s?= Date: Sat, 30 Jan 2016 21:50:45 +0100 Subject: [PATCH 04/35] Fix HTML5 validation error Removed itemprop from canonical url due html validation error --- lib/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index 4326fa3..432599d 100644 --- a/lib/template.html +++ b/lib/template.html @@ -77,7 +77,7 @@ {% endif %} {% if seo_url %} - + {% endif %} From eac9501a2d19430602f522be3f696ea4ea1469cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Garc=C3=A9s?= Date: Sat, 30 Jan 2016 22:50:19 +0100 Subject: [PATCH 05/35] Fix travis-ci errors --- spec/jekyll_seo_tag_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index f2fafd2..d420368 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -56,7 +56,7 @@ describe Jekyll::SeoTag do it "uses the site url to build the seo url" do site = site({"url" => "http://example.invalid"}) context = context({ :site => site }) - expected = // + expected = // expect(subject.render(context)).to match(expected) expected = // expect(subject.render(context)).to match(expected) @@ -65,7 +65,7 @@ describe Jekyll::SeoTag do it "uses site.github.url to build the seo url" do site = site({"github" => { "url" => "http://example.invalid" }} ) context = context({ :site => site }) - expected = // + expected = // expect(subject.render(context)).to match(expected) expected = // expect(subject.render(context)).to match(expected) @@ -75,7 +75,7 @@ describe Jekyll::SeoTag do page = page({ "permalink" => "/page/index.html" }) site = site({ "url" => "http://example.invalid" }) context = context({ :page => page, :site => site }) - expected = %r!! + expected = %r!! expected = %r!! expect(subject.render(context)).to match(expected) end @@ -83,7 +83,7 @@ describe Jekyll::SeoTag do it "uses baseurl to build the seo url" do site = site({ "url" => "http://example.invalid", "baseurl" => "/foo" }) context = context({ :site => site }) - expected = %r!! + expected = %r!! expect(subject.render(context)).to match(expected) expected = %r!! expect(subject.render(context)).to match(expected) From f1e9b9acb1292af3b1c99d290f687319273c17c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Garc=C3=A9s?= Date: Mon, 1 Feb 2016 17:06:05 +0100 Subject: [PATCH 06/35] Use seo_description instead of page.description seo_description is used in the meta tags but not in the ld+json If page.description is not set, the the description at ld+json will be null. --- lib/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index 432599d..838fdda 100644 --- a/lib/template.html +++ b/lib/template.html @@ -112,7 +112,7 @@ "headline": {{ page.title | jsonify }}, "image": {{ page.image | jsonify }}, "datePublished": {{ page.date | date_to_xmlschema | jsonify }}, - "description": {{ page.description | jsonify }} + "description": {{ seo_description | jsonify }} } {% endif %} From 6d2f5aee1b862c8f178fec89b709aa6785987169 Mon Sep 17 00:00:00 2001 From: Pat Hawks Date: Tue, 2 Feb 2016 19:06:10 -0800 Subject: [PATCH 07/35] Update tests to work with Liquid 3 --- spec/jekyll_seo_tag_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index f2fafd2..d14e4dd 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Jekyll::SeoTag do - subject { Jekyll::SeoTag.new("seo", nil, nil) } + subject { Jekyll::SeoTag.parse("seo", nil, nil, nil) } before do Jekyll.logger.log_level = :error From a42df44513b15a4d90b0c48afe5c8bddbac30cd2 Mon Sep 17 00:00:00 2001 From: Pat Hawks Date: Tue, 2 Feb 2016 20:02:08 -0800 Subject: [PATCH 08/35] Update tests to work with Jekyll 3 --- spec/spec_helper.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c6c2a77..a391dd0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -26,8 +26,10 @@ def page(options={}) end def post(options={}) - page = Jekyll::Post.new site, CONFIG_DEFAULTS["source"], "", "2015-01-01-post.md" - page.data = options + filename = File.expand_path("2015-01-01-post.md", CONFIG_DEFAULTS["source"]) + config = { :site => site, :collection => site.collections["posts"] } + page = Jekyll::Document.new filename, config + page.merge_data!(options) page end From 244802ed89628fe3bf91bc2f5ee96b6171b94463 Mon Sep 17 00:00:00 2001 From: Bo Turnbow Date: Wed, 3 Feb 2016 10:17:04 -0700 Subject: [PATCH 09/35] Make page.image url relative to site rather than absolute --- README.md | 2 +- lib/template.html | 2 +- spec/jekyll_seo_tag_spec.rb | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c4ee3b3..75f5f65 100644 --- a/README.md +++ b/README.md @@ -69,5 +69,5 @@ The SEO tag will respect the following YAML front matter if included in a post, * `title` - The title of the post, page, or document * `description` - A short description of the page's content -* `image` - The absolute URL to an image that should be associated with the post, page, or document +* `image` - Relative URL to an image associated with the post, page, or document (e.g., `assets/page-pic.jpg`) * `author` - The username of the post, page, or document author diff --git a/lib/template.html b/lib/template.html index 838fdda..4a5db80 100644 --- a/lib/template.html +++ b/lib/template.html @@ -94,7 +94,7 @@ {% endif %} {% if page.image %} - + {% endif %} {% if page.date %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index d420368..0f21722 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -153,9 +153,10 @@ describe Jekyll::SeoTag do end it "outputs the image" do - page = page({"image" => "http://foo.invalid/foo.png"}) - context = context({ :page => page }) - expected = // + page = page({ "image" => "foo.png" }) + site = site({ "url" => "http://example.invalid" }) + context = context({ :page => page, :site => site }) + expected = %r!! expect(subject.render(context)).to match(expected) end From 594d99f752c5f35c20907323b92750165ffc1e47 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Wed, 3 Feb 2016 12:41:05 -0500 Subject: [PATCH 10/35] add google site verification meta tag --- README.md | 3 ++- lib/template.html | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 75f5f65..7ae7472 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A Jekyll plugin to add metadata tags for search engines and social networks to better index and display your site's content. -[![Gem Version](https://badge.fury.io/rb/jekyll-seo-tag.svg)](https://badge.fury.io/rb/jekyll-seo-tag) [![Build Status](https://travis-ci.org/benbalter/jekyll-seo-tag.svg)](https://travis-ci.org/benbalter/jekyll-seo-tag) +[![Gem Version](https://badge.fury.io/rb/jekyll-seo-tag.svg)](https://badge.fury.io/rb/jekyll-seo-tag) [![Build Status](https://travis-ci.org/benbalter/jekyll-seo-tag.svg)](https://travis-ci.org/benbalter/jekyll-seo-tag) ## What it does @@ -64,6 +64,7 @@ The SEO tag will respect any of the following if included in your site's `_confi * `type` - Either `person` or `organization` (defaults to `person`) * `name` - If the user or organization name differs from the site's name * `links` - An array of links to social media profiles. +* `google_site_verification` for verifying ownership via Google webmaster tools The SEO tag will respect the following YAML front matter if included in a post, page, or document: diff --git a/lib/template.html b/lib/template.html index 871348b..41b6aef 100644 --- a/lib/template.html +++ b/lib/template.html @@ -110,6 +110,10 @@ {% endif %} {% endif %} +{% if site.google_site_verification %} + +{% endif %} + {% if site.logo %} }m)[1] data = JSON.parse(data) - expect(data["name"]).to eql("Foo") - expect(data["url"]).to eql("http://example.invalid") + expect(data['name']).to eql('Foo') + expect(data['url']).to eql('http://example.invalid') end - it "outputs post meta" do - post = post({"title" => "post", "description" => "description", "image" => "/img.png" }) - context = context({ :page => post }) + it 'outputs post meta' do + post = post('title' => 'post', 'description' => 'description', 'image' => '/img.png') + context = context(page: post) output = subject.render(context) - expected = // + expected = %r{} expect(output).to match(expected) - data = output.match(/}m)[1] data = JSON.parse(data) - expect(data["headline"]).to eql("post") - expect(data["description"]).to eql("description") - expect(data["image"]).to eql("/img.png") + expect(data['headline']).to eql('post') + expect(data['description']).to eql('description') + expect(data['image']).to eql('/img.png') end - it "outputs twitter card meta" do - site = site({"twitter" => { "username" => "jekyllrb" }}) - page = page({"author" => "benbalter"}) - context = context({ :site => site, :page => page }) + it 'outputs twitter card meta' do + site = site('twitter' => { 'username' => 'jekyllrb' }) + page = page('author' => 'benbalter') + context = context(site: site, page: page) - expected = // + expected = %r{} expect(subject.render(context)).to match(expected) - expected = // + expected = %r{} expect(subject.render(context)).to match(expected) end - it "outputs social meta" do - links = ["http://foo.invalid", "http://bar.invalid"] - site = site({"social" => { "name" => "Ben", "links" => links }}) - context = context({ :site => site }) + it 'outputs social meta' do + links = ['http://foo.invalid', 'http://bar.invalid'] + site = site('social' => { 'name' => 'Ben', 'links' => links }) + context = context(site: site) output = subject.render(context) - data = output.match(/}m)[1] data = JSON.parse(data) - expect(data["@type"]).to eql("person") - expect(data["name"]).to eql("Ben") - expect(data["sameAs"]).to eql(links) + expect(data['@type']).to eql('person') + expect(data['name']).to eql('Ben') + expect(data['sameAs']).to eql(links) end - it "outputs the logo" do - site = site({"logo" => "logo.png", "url" => "http://example.invalid" }) - context = context({ :site => site }) + it 'outputs the logo' do + site = site('logo' => 'logo.png', 'url' => 'http://example.invalid') + context = context(site: site) output = subject.render(context) - data = output.match(/}m)[1] data = JSON.parse(data) - expect(data["logo"]).to eql("http://example.invalid/logo.png") - expect(data["url"]).to eql("http://example.invalid") + expect(data['logo']).to eql('http://example.invalid/logo.png') + expect(data['url']).to eql('http://example.invalid') end - it "outputs the image" do - page = page({ "image" => "foo.png" }) - site = site({ "url" => "http://example.invalid" }) - context = context({ :page => page, :site => site }) - expected = %r!! + it 'outputs the image' do + page = page('image' => 'foo.png') + site = site('url' => 'http://example.invalid') + context = context(page: page, site: site) + expected = %r{} expect(subject.render(context)).to match(expected) end - it "uses site.name if site.title is not present" do - site = site({"name" => "Site Name", "title" => nil }) - context = context({ :site => site }) - expected = %r!! + it 'uses site.name if site.title is not present' do + site = site('name' => 'Site Name', 'title' => nil) + context = context(site: site) + expected = %r{} expect(subject.render(context)).to match(expected) end - it "uses site.tile if both site.title and site.name are present" do - site = site({"name" => "Site Name", "title" => "Site Title" }) - context = context({ :site => site }) - expected = %r!! + it 'uses site.tile if both site.title and site.name are present' do + site = site('name' => 'Site Name', 'title' => 'Site Title') + context = context(site: site) + expected = %r{} expect(subject.render(context)).to match(expected) end - it "supports author data as an object" do - site = site({"twitter" => { "username" => "jekyllrb" }}) - page = page({"author" => {"twitter" => "@test"}}) - context = context({ :site => site, :page => page }) - expected = %r!! + it 'supports author data as an object' do + site = site('twitter' => { 'username' => 'jekyllrb' }) + page = page('author' => { 'twitter' => '@test' }) + context = context(site: site, page: page) + expected = %r{} expect(subject.render(context)).to match(expected) end - it "outputs valid HTML" do + it 'outputs valid HTML' do site.process options = { - :check_html => true, - :checks_to_ignore => ["ScriptCheck", "LinkCheck", "ImageCheck"] + check_html: true, + checks_to_ignore: %w(ScriptCheck LinkCheck ImageCheck) } status = HTML::Proofer.new(dest_dir, options).run expect(status).to eql(true) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a391dd0..ed7ff23 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,41 +3,41 @@ require 'jekyll' require 'jekyll-seo-tag' require 'html/proofer' -ENV["JEKYLL_LOG_LEVEL"] = "error" +ENV['JEKYLL_LOG_LEVEL'] = 'error' def dest_dir - File.expand_path("../tmp/dest", File.dirname(__FILE__)) + File.expand_path('../tmp/dest', File.dirname(__FILE__)) end def source_dir - File.expand_path("./fixtures", File.dirname(__FILE__)) + File.expand_path('./fixtures', File.dirname(__FILE__)) end CONFIG_DEFAULTS = { - "source" => source_dir, - "destination" => dest_dir, - "gems" => ["jekyll-seo-tag"] -} + 'source' => source_dir, + 'destination' => dest_dir, + 'gems' => ['jekyll-seo-tag'] +}.freeze -def page(options={}) - page = Jekyll::Page.new site, CONFIG_DEFAULTS["source"], "", "page.md" +def page(options = {}) + page = Jekyll::Page.new site, CONFIG_DEFAULTS['source'], '', 'page.md' page.data = options page end -def post(options={}) - filename = File.expand_path("2015-01-01-post.md", CONFIG_DEFAULTS["source"]) - config = { :site => site, :collection => site.collections["posts"] } +def post(options = {}) + filename = File.expand_path('2015-01-01-post.md', CONFIG_DEFAULTS['source']) + config = { site: site, collection: site.collections['posts'] } page = Jekyll::Document.new filename, config page.merge_data!(options) page end -def site(options={}) +def site(options = {}) config = Jekyll.configuration CONFIG_DEFAULTS.merge(options) Jekyll::Site.new(config) end -def context(registers={}) - Liquid::Context.new({}, {}, { :site => site, :page => page }.merge(registers)) +def context(registers = {}) + Liquid::Context.new({}, {}, { site: site, page: page }.merge(registers)) end From 2ee2f3e6e05e651c7e4b83a2592fe50570fe9e18 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 14:04:43 -0500 Subject: [PATCH 22/35] Bump to 1.1.0 --- lib/jekyll-seo-tag/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jekyll-seo-tag/version.rb b/lib/jekyll-seo-tag/version.rb index 97b1dca..01f9676 100644 --- a/lib/jekyll-seo-tag/version.rb +++ b/lib/jekyll-seo-tag/version.rb @@ -3,6 +3,6 @@ module Liquid; class Tag; end; end module Jekyll class SeoTag < Liquid::Tag - VERSION = '1.0.0'.freeze + VERSION = '1.1.0'.freeze end end From bdedd23bf20d4963c4f7c97934f3531fdb64cda3 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 14:26:06 -0500 Subject: [PATCH 23/35] expose version in HTML comment --- lib/jekyll-seo-tag.rb | 1 + lib/template.html | 2 +- spec/jekyll_seo_tag_spec.rb | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/jekyll-seo-tag.rb b/lib/jekyll-seo-tag.rb index 376772f..dd71ea7 100644 --- a/lib/jekyll-seo-tag.rb +++ b/lib/jekyll-seo-tag.rb @@ -17,6 +17,7 @@ module Jekyll def payload { + 'seo_tag' => { 'version' => VERSION }, 'page' => context.registers[:page], 'site' => context.registers[:site].site_payload['site'] } diff --git a/lib/template.html b/lib/template.html index 9a77b4c..4c45ad0 100644 --- a/lib/template.html +++ b/lib/template.html @@ -1,4 +1,4 @@ - + {% if site.url %} {% assign seo_url = site.url | append: site.baseurl %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 4408cba..86c8124 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -193,4 +193,9 @@ describe Jekyll::SeoTag do status = HTML::Proofer.new(dest_dir, options).run expect(status).to eql(true) end + + it 'outputs the plugin version' do + version = Jekyll::SeoTag::VERSION + expect(subject.render(context)).to match(/Jekyll SEO tag v#{version}/i) + end end From 86775d50f7028ce2d85cf0af5ca9702fe07f8dca Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 14:27:04 -0500 Subject: [PATCH 24/35] whitespace --- lib/jekyll-seo-tag.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jekyll-seo-tag.rb b/lib/jekyll-seo-tag.rb index dd71ea7..c2e443f 100644 --- a/lib/jekyll-seo-tag.rb +++ b/lib/jekyll-seo-tag.rb @@ -18,8 +18,8 @@ module Jekyll def payload { 'seo_tag' => { 'version' => VERSION }, - 'page' => context.registers[:page], - 'site' => context.registers[:site].site_payload['site'] + 'page' => context.registers[:page], + 'site' => context.registers[:site].site_payload['site'] } end From 546448be1b8f81aee4fa2fd708c817cdb5975f1d Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 15:49:35 -0500 Subject: [PATCH 25/35] move logic to ruby --- .rubocop.yml | 9 +++++++++ lib/jekyll-seo-tag.rb | 36 +++++++++++++++++++++++++++++++++--- lib/template.html | 36 +++--------------------------------- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9408010..ee771a6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,3 +8,12 @@ Style/Documentation: Style/FileName: Enabled: false + +Metrics/AbcSize: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false diff --git a/lib/jekyll-seo-tag.rb b/lib/jekyll-seo-tag.rb index c2e443f..9fed5e4 100644 --- a/lib/jekyll-seo-tag.rb +++ b/lib/jekyll-seo-tag.rb @@ -17,12 +17,20 @@ module Jekyll def payload { - 'seo_tag' => { 'version' => VERSION }, - 'page' => context.registers[:page], - 'site' => context.registers[:site].site_payload['site'] + 'seo_tag' => { 'version' => VERSION, 'author' => author }, + 'page' => page, + 'site' => site } end + def page + context.registers[:page] + end + + def site + context.registers[:site].site_payload['site'] + end + def info { registers: context.registers, @@ -45,6 +53,28 @@ module Jekyll File.expand_path './template.html', File.dirname(__FILE__) end end + + # Returns a hash representing the post author + # + # Sources, in order: + # + # 1. page.author, if page.author is a hash + # 2. site.author, if site.author is a hash + # 3. site.data.authors[page.author] if page.author is a string + # 4. page.author if page.author is a string + def author + author = page['author'] || site['author'] + return if author.nil? + return author if author.is_a?(Hash) + + if author.is_a?(String) + if site['data']['authors'] && site['data']['authors'][author] + site['data']['authors'][author] + else + { 'twitter' => author } + end + end + end end end diff --git a/lib/template.html b/lib/template.html index 1e38b69..23ca2bf 100644 --- a/lib/template.html +++ b/lib/template.html @@ -39,38 +39,8 @@ {% assign seo_description = seo_description | markdownify | strip_html | strip_newlines | escape_once %} {% endif %} -{% if page.author %} - {% if site.data.authors[page.author] %} - {% assign seo_author_name = site.data.authors[page.author].name %} - {% assign seo_author_twitter = site.data.authors[page.author].twitter | default: seo_author_name %} - {% elsif page.author.name %} - {% assign seo_author_name = page.author.name %} - {% assign seo_author_twitter = page.author.twitter | default: seo_author_name %} - {% elsif page.author.twitter %} - {% assign seo_author_twitter = page.author.twitter %} - {% assign seo_author_twitter = page.author.twitter %} - {% else %} - {% assign seo_author_name = page.author %} - {% assign seo_author_twitter = page.author %} - {% endif %} -{% elsif site.author %} - {% if site.data.authors[site.author] %} - {% assign seo_author_name = site.data.authors[site.author].name %} - {% assign seo_author_twitter = site.data.authors[site.author].twitter | default: seo_author_name %} - {% elsif site.author.name %} - {% assign seo_author_name = site.author.name %} - {% assign seo_author_twitter = site.author.twitter | default: seo_author_name %} - {% else %} - {% assign seo_author_name = site.author %} - {% assign seo_author_twitter = site.author %} - {% endif %} -{% endif %} -{% if seo_author_name %} - {% assign seo_author_name = seo_author_name | strip_html | escape_once %} -{% endif %} - -{% if seo_author_twitter %} - {% assign seo_author_twitter = seo_author_twitter | replace:"@","" | prepend:"@" | strip_html | escape_once %} +{% if seo_tag.author %} + {% assign seo_author_twitter = seo_tag.author.twitter | replace:"@","" %} {% endif %} {% if seo_title %} @@ -142,7 +112,7 @@ {% endif %} {% if seo_author_twitter %} - + {% endif %} {% endif %} From 0ded70bd7e088e7d07cdc818c32058f4a3e72a00 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 15:49:55 -0500 Subject: [PATCH 26/35] better specs --- spec/jekyll_seo_tag_spec.rb | 344 ++++++++++++++++++++---------------- spec/spec_helper.rb | 8 +- 2 files changed, 200 insertions(+), 152 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 86c8124..c7e74e7 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -2,186 +2,239 @@ require 'spec_helper' describe Jekyll::SeoTag do subject { Jekyll::SeoTag.parse('seo', nil, nil, nil) } + let(:page) { make_page } + let(:site) { make_site } + let(:post) { make_post } + let(:context) { make_context(page: page, site: site) } + let(:output) { subject.render(context) } before do Jekyll.logger.log_level = :error end it 'builds' do - expect(subject.render(context)).to match(/Jekyll SEO tag/i) + expect(output).to match(/Jekyll SEO tag/i) end - it 'builds the title with a page title only' do - page = page('title' => 'foo') - context = context(page: page) - expect(subject.render(context)).to match(%r{foo}) - expect(subject.render(context)).to match(%r{}) + it 'outputs the plugin version' do + version = Jekyll::SeoTag::VERSION + expect(output).to match(/Jekyll SEO tag v#{version}/i) end - it 'builds the title with a page title and site title' do - page = page('title' => 'foo') - site = site('title' => 'bar') - context = context(page: page, site: site) - expect(subject.render(context)).to match(%r{foo - bar}) + context 'with page.title' do + let(:page) { make_page('title' => 'foo') } + + it 'builds the title with a page title only' do + expect(output).to match(%r{foo}) + expected = %r{} + expect(output).to match(expected) + end + + context 'with site.title' do + let(:site) { make_site('title' => 'bar') } + + it 'builds the title with a page title and site title' do + expect(output).to match(%r{foo - bar}) + end + end end - it 'builds the title with only a site title' do - site = site('title' => 'foo') - context = context(site: site) - expect(subject.render(context)).to match(%r{foo}) + context 'with site.title' do + let(:site) { make_site('title' => 'Site title') } + + it 'builds the title with only a site title' do + expect(output).to match(%r{Site title}) + end end - it 'uses the page description' do - page = page('description' => 'foo') - context = context(page: page) - expect(subject.render(context)).to match(%r{}) - expect(subject.render(context)).to match(%r{}) + context 'with page.description' do + let(:page) { make_page('description' => 'foo') } + + it 'uses the page description' do + expect(output).to match(%r{}) + expect(output).to match(%r{}) + end end - it 'uses the page excerpt when no page description exists' do - page = page('description' => 'foobar') - context = context(page: page) - expect(subject.render(context)).to match(%r{}) - expect(subject.render(context)).to match(%r{}) + context 'with page.excerpt' do + let(:page) { make_page('excerpt' => 'foo') } + + it 'uses the page excerpt when no page description exists' do + expect(output).to match(%r{}) + expect(output).to match(%r{}) + end end - it 'uses the site description when no page description nor excerpt exist' do - site = site('description' => 'foo') - context = context(site: site) - expect(subject.render(context)).to match(%r{}) - expect(subject.render(context)).to match(%r{}) + context 'with site.description' do + let(:site) { make_site('description' => 'foo') } + + it 'uses the site description when no page description nor excerpt exist' do + expect(output).to match(%r{}) + expect(output).to match(%r{}) + end end - it 'uses the site url to build the seo url' do - site = site('url' => 'http://example.invalid') - context = context(site: site) - expected = %r{} - expect(subject.render(context)).to match(expected) - expected = %r{} - expect(subject.render(context)).to match(expected) + context 'with site.url' do + let(:site) { make_site('url' => 'http://example.invalid') } + + it 'uses the site url to build the seo url' do + expected = %r{} + expect(output).to match(expected) + expected = %r{} + expect(output).to match(expected) + end + + context 'with page.permalink' do + let(:page) { make_page('permalink' => '/page/index.html') } + + it "uses replaces '/index.html' with '/'" do + expected = %r{} + expect(output).to match(expected) + + expected = %r{} + expect(output).to match(expected) + end + end + + context 'with site.baseurl' do + let(:site) { make_site('url' => 'http://example.invalid', 'baseurl' => '/foo') } + it 'uses baseurl to build the seo url' do + expected = %r{} + expect(output).to match(expected) + expected = %r{} + expect(output).to match(expected) + end + end + + context 'with page.image' do + let(:page) { make_page('image' => 'foo.png') } + + it 'outputs the image' do + expected = %r{} + expect(output).to match(expected) + end + end + + context 'with site.logo' do + let(:site) { make_site('logo' => 'logo.png', 'url' => 'http://example.invalid') } + + it 'outputs the logo' do + data = output.match(%r{}m)[1] + data = JSON.parse(data) + + expect(data['logo']).to eql('http://example.invalid/logo.png') + expect(data['url']).to eql('http://example.invalid') + end + end + + context 'with site.title' do + let(:site) { make_site('title' => 'Foo', 'url' => 'http://example.invalid') } + + it 'outputs the site title meta' do + expect(output).to match(%r{}) + data = output.match(%r{}m)[1] + + data = JSON.parse(data) + expect(data['name']).to eql('Foo') + expect(data['url']).to eql('http://example.invalid') + end + end end - it 'uses site.github.url to build the seo url' do - site = site('github' => { 'url' => 'http://example.invalid' }) - context = context(site: site) - expected = %r{} - expect(subject.render(context)).to match(expected) - expected = %r{} - expect(subject.render(context)).to match(expected) + context 'with site.github.url' do + let(:github_namespace) { { 'url' => 'http://example.invalid' } } + let(:site) { make_site('github' => github_namespace) } + + it 'uses site.github.url to build the seo url' do + expected = %r{} + expect(output).to match(expected) + expected = %r{} + expect(output).to match(expected) + end end - it "uses replaces '/index.html' with '/'" do - page = page('permalink' => '/page/index.html') - site = site('url' => 'http://example.invalid') - context = context(page: page, site: site) + context 'posts' do + context 'with post meta' do + let(:meta) do + { + 'title' => 'post', + 'description' => 'description', + 'image' => '/img.png' + } + end + let(:page) { make_post(meta) } - expected = %r{} - expect(subject.render(context)).to match(expected) + it 'outputs post meta' do + expected = %r{} + expect(output).to match(expected) + data = output.match(%r{}m)[1] + data = JSON.parse(data) - expected = %r{} - expect(subject.render(context)).to match(expected) + expect(data['headline']).to eql('post') + expect(data['description']).to eql('description') + expect(data['image']).to eql('/img.png') + end + end end - it 'uses baseurl to build the seo url' do - site = site('url' => 'http://example.invalid', 'baseurl' => '/foo') - context = context(site: site) - expected = %r{} - expect(subject.render(context)).to match(expected) - expected = %r{} - expect(subject.render(context)).to match(expected) + context 'twitter' do + context 'with site.twitter.username' do + let(:site) { make_site('twitter' => { 'username' => 'jekyllrb' }) } + + context 'with page.author as a string' do + let(:page) { make_page('author' => 'benbalter') } + + it 'outputs twitter card meta' do + expected = %r{} + expect(output).to match(expected) + + expected = %r{} + expect(output).to match(expected) + end + end + + context 'with page.author as an object' do + let(:page) { make_page('author' => { 'twitter' => '@test' }) } + + it 'supports author data as an object' do + expected = %r{} + expect(output).to match(expected) + end + end + end end - it 'outputs the site title meta' do - site = site('title' => 'Foo', 'url' => 'http://example.invalid') - context = context(site: site) - output = subject.render(context) + context 'with site.social' do + let(:links) { ['http://foo.invalid', 'http://bar.invalid'] } + let(:social_namespace) { { 'name' => 'Ben', 'links' => links } } + let(:site) { make_site('social' => social_namespace) } - expect(output).to match(%r{}) - data = output.match(%r{}m)[1] + it 'outputs social meta' do + data = output.match(%r{}m)[1] + data = JSON.parse(data) - data = JSON.parse(data) - expect(data['name']).to eql('Foo') - expect(data['url']).to eql('http://example.invalid') + expect(data['@type']).to eql('person') + expect(data['name']).to eql('Ben') + expect(data['sameAs']).to eql(links) + end end - it 'outputs post meta' do - post = post('title' => 'post', 'description' => 'description', 'image' => '/img.png') - context = context(page: post) - output = subject.render(context) - expected = %r{} - expect(output).to match(expected) - data = output.match(%r{}m)[1] - data = JSON.parse(data) + context 'with site.name' do + let(:site) { make_site('name' => 'Site name') } - expect(data['headline']).to eql('post') - expect(data['description']).to eql('description') - expect(data['image']).to eql('/img.png') - end + it 'uses site.name if site.title is not present' do + expected = %r{} + expect(output).to match(expected) + end - it 'outputs twitter card meta' do - site = site('twitter' => { 'username' => 'jekyllrb' }) - page = page('author' => 'benbalter') - context = context(site: site, page: page) + context 'with site.title' do + let(:site) { make_site('name' => 'Site Name', 'title' => 'Site Title') } - expected = %r{} - expect(subject.render(context)).to match(expected) - - expected = %r{} - expect(subject.render(context)).to match(expected) - end - - it 'outputs social meta' do - links = ['http://foo.invalid', 'http://bar.invalid'] - site = site('social' => { 'name' => 'Ben', 'links' => links }) - context = context(site: site) - output = subject.render(context) - data = output.match(%r{}m)[1] - data = JSON.parse(data) - - expect(data['@type']).to eql('person') - expect(data['name']).to eql('Ben') - expect(data['sameAs']).to eql(links) - end - - it 'outputs the logo' do - site = site('logo' => 'logo.png', 'url' => 'http://example.invalid') - context = context(site: site) - output = subject.render(context) - data = output.match(%r{}m)[1] - data = JSON.parse(data) - - expect(data['logo']).to eql('http://example.invalid/logo.png') - expect(data['url']).to eql('http://example.invalid') - end - - it 'outputs the image' do - page = page('image' => 'foo.png') - site = site('url' => 'http://example.invalid') - context = context(page: page, site: site) - expected = %r{} - expect(subject.render(context)).to match(expected) - end - - it 'uses site.name if site.title is not present' do - site = site('name' => 'Site Name', 'title' => nil) - context = context(site: site) - expected = %r{} - expect(subject.render(context)).to match(expected) - end - - it 'uses site.tile if both site.title and site.name are present' do - site = site('name' => 'Site Name', 'title' => 'Site Title') - context = context(site: site) - expected = %r{} - expect(subject.render(context)).to match(expected) - end - - it 'supports author data as an object' do - site = site('twitter' => { 'username' => 'jekyllrb' }) - page = page('author' => { 'twitter' => '@test' }) - context = context(site: site, page: page) - expected = %r{} - expect(subject.render(context)).to match(expected) + it 'uses site.tile if both site.title and site.name are present' do + expected = %r{} + expect(output).to match(expected) + end + end end it 'outputs valid HTML' do @@ -193,9 +246,4 @@ describe Jekyll::SeoTag do status = HTML::Proofer.new(dest_dir, options).run expect(status).to eql(true) end - - it 'outputs the plugin version' do - version = Jekyll::SeoTag::VERSION - expect(subject.render(context)).to match(/Jekyll SEO tag v#{version}/i) - end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ed7ff23..4bf3092 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,13 +19,13 @@ CONFIG_DEFAULTS = { 'gems' => ['jekyll-seo-tag'] }.freeze -def page(options = {}) +def make_page(options = {}) page = Jekyll::Page.new site, CONFIG_DEFAULTS['source'], '', 'page.md' page.data = options page end -def post(options = {}) +def make_post(options = {}) filename = File.expand_path('2015-01-01-post.md', CONFIG_DEFAULTS['source']) config = { site: site, collection: site.collections['posts'] } page = Jekyll::Document.new filename, config @@ -33,11 +33,11 @@ def post(options = {}) page end -def site(options = {}) +def make_site(options = {}) config = Jekyll.configuration CONFIG_DEFAULTS.merge(options) Jekyll::Site.new(config) end -def context(registers = {}) +def make_context(registers = {}) Liquid::Context.new({}, {}, { site: site, page: page }.merge(registers)) end From 7568f6b61856ada7a76dfcdb1b7a5a037ba4dfe0 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 15:52:16 -0500 Subject: [PATCH 27/35] better json parsing --- spec/jekyll_seo_tag_spec.rb | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index c7e74e7..86e5ed9 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -7,6 +7,8 @@ describe Jekyll::SeoTag do let(:post) { make_post } let(:context) { make_context(page: page, site: site) } let(:output) { subject.render(context) } + let(:json) { output.match(%r{}m)[1] } + let(:json_data) { JSON.parse(json) } before do Jekyll.logger.log_level = :error @@ -119,11 +121,8 @@ describe Jekyll::SeoTag do let(:site) { make_site('logo' => 'logo.png', 'url' => 'http://example.invalid') } it 'outputs the logo' do - data = output.match(%r{}m)[1] - data = JSON.parse(data) - - expect(data['logo']).to eql('http://example.invalid/logo.png') - expect(data['url']).to eql('http://example.invalid') + expect(json_data['logo']).to eql('http://example.invalid/logo.png') + expect(json_data['url']).to eql('http://example.invalid') end end @@ -132,11 +131,8 @@ describe Jekyll::SeoTag do it 'outputs the site title meta' do expect(output).to match(%r{}) - data = output.match(%r{}m)[1] - - data = JSON.parse(data) - expect(data['name']).to eql('Foo') - expect(data['url']).to eql('http://example.invalid') + expect(json_data['name']).to eql('Foo') + expect(json_data['url']).to eql('http://example.invalid') end end end @@ -167,12 +163,10 @@ describe Jekyll::SeoTag do it 'outputs post meta' do expected = %r{} expect(output).to match(expected) - data = output.match(%r{}m)[1] - data = JSON.parse(data) - expect(data['headline']).to eql('post') - expect(data['description']).to eql('description') - expect(data['image']).to eql('/img.png') + expect(json_data['headline']).to eql('post') + expect(json_data['description']).to eql('description') + expect(json_data['image']).to eql('/img.png') end end end @@ -210,12 +204,9 @@ describe Jekyll::SeoTag do let(:site) { make_site('social' => social_namespace) } it 'outputs social meta' do - data = output.match(%r{}m)[1] - data = JSON.parse(data) - - expect(data['@type']).to eql('person') - expect(data['name']).to eql('Ben') - expect(data['sameAs']).to eql(links) + expect(json_data['@type']).to eql('person') + expect(json_data['name']).to eql('Ben') + expect(json_data['sameAs']).to eql(links) end end From 068a1b972a67b912c0f2a47c0b0f41250ed8e299 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 17:24:08 -0500 Subject: [PATCH 28/35] add tests --- spec/jekyll_seo_tag_spec.rb | 47 ++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 86e5ed9..8af81aa 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -173,7 +173,8 @@ describe Jekyll::SeoTag do context 'twitter' do context 'with site.twitter.username' do - let(:site) { make_site('twitter' => { 'username' => 'jekyllrb' }) } + let(:site_twitter) { { 'username' => 'jekyllrb' } } + let(:site) { make_site('twitter' => site_twitter) } context 'with page.author as a string' do let(:page) { make_page('author' => 'benbalter') } @@ -185,12 +186,52 @@ describe Jekyll::SeoTag do expected = %r{} expect(output).to match(expected) end + + context 'with an @' do + let(:page) { make_page('author' => '@benbalter') } + + it 'outputs the twitter card' do + expected = %r{} + expect(output).to match(expected) + end + end + + context 'with site.data.authors' do + let(:author_data) { {} } + let(:data) { { 'authors' => author_data } } + let(:site) { make_site('data' => data, 'twitter' => site_twitter) } + + context 'with the author in site.data.authors' do + let(:author_data) { { 'benbalter' => { 'twitter' => 'test' } } } + it 'outputs the twitter card' do + expected = %r{} + expect(output).to match(expected) + end + end + + context 'without the author in site.data.authors' do + it 'outputs the twitter card' do + expected = %r{} + expect(output).to match(expected) + end + end + end end - context 'with page.author as an object' do + context 'with page.author as a hash' do let(:page) { make_page('author' => { 'twitter' => '@test' }) } - it 'supports author data as an object' do + it 'supports author data as a hash' do + expected = %r{} + expect(output).to match(expected) + end + end + + context 'with site.author as a hash' do + let(:author) { { 'twitter' => '@test' } } + let(:site) { make_site('author' => author, 'twitter' => site_twitter) } + + it 'supports author data as an hash' do expected = %r{} expect(output).to match(expected) end From 782729fad2efc9b70780c61d60fb9f3fd3075f4a Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 17:34:02 -0500 Subject: [PATCH 29/35] remove ruby author logic --- lib/jekyll-seo-tag.rb | 36 +++--------------------------------- lib/template.html | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/lib/jekyll-seo-tag.rb b/lib/jekyll-seo-tag.rb index 9fed5e4..c2e443f 100644 --- a/lib/jekyll-seo-tag.rb +++ b/lib/jekyll-seo-tag.rb @@ -17,20 +17,12 @@ module Jekyll def payload { - 'seo_tag' => { 'version' => VERSION, 'author' => author }, - 'page' => page, - 'site' => site + 'seo_tag' => { 'version' => VERSION }, + 'page' => context.registers[:page], + 'site' => context.registers[:site].site_payload['site'] } end - def page - context.registers[:page] - end - - def site - context.registers[:site].site_payload['site'] - end - def info { registers: context.registers, @@ -53,28 +45,6 @@ module Jekyll File.expand_path './template.html', File.dirname(__FILE__) end end - - # Returns a hash representing the post author - # - # Sources, in order: - # - # 1. page.author, if page.author is a hash - # 2. site.author, if site.author is a hash - # 3. site.data.authors[page.author] if page.author is a string - # 4. page.author if page.author is a string - def author - author = page['author'] || site['author'] - return if author.nil? - return author if author.is_a?(Hash) - - if author.is_a?(String) - if site['data']['authors'] && site['data']['authors'][author] - site['data']['authors'][author] - else - { 'twitter' => author } - end - end - end end end diff --git a/lib/template.html b/lib/template.html index 23ca2bf..62ab874 100644 --- a/lib/template.html +++ b/lib/template.html @@ -39,8 +39,18 @@ {% assign seo_description = seo_description | markdownify | strip_html | strip_newlines | escape_once %} {% endif %} -{% if seo_tag.author %} - {% assign seo_author_twitter = seo_tag.author.twitter | replace:"@","" %} +{% assign seo_author = page.author | default: site.author %} +{% if seo_author %} + {% if seo_author.twitter %} + {% assign seo_author_twitter = seo_author.twitter %} + {% else %} + {% if site.data.authors and site.data.authors[seo_author] %} + {% assign seo_author_twitter = site.data.authors[seo_author].twitter %} + {% else %} + {% assign seo_author_twitter = seo_author %} + {% endif %} + {% endif %} + {% assign seo_author_twitter = seo_author_twitter | replace:"@","" %} {% endif %} {% if seo_title %} From 60a1e5169b65882b72d1bcb9e5c5676ee6ef0948 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 17:47:52 -0500 Subject: [PATCH 30/35] document --- README.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b219211..b345bc6 100644 --- a/README.md +++ b/README.md @@ -52,17 +52,22 @@ The SEO tag will respect any of the following if included in your site's `_confi * `title` - Your site's title (e.g., Ben's awesome site, The GitHub Blog, etc.) * `description` - A short description (e.g., A blog dedicated to reviewing cat gifs) * `url` - The full URL to your site. Note: `site.github.url` will be used by default. +* `author` - global author information (see below) * `twitter:username` - The site's Twitter handle. You'll want to describe it like so: + ```yml twitter: username: benbalter ``` + * `facebook:app_id` (A Facebook app ID for Facebook insights), and/or `facebook:publisher` (A Facebook page URL or ID of the publishing entity). You'll want to describe one or both like so: + ```yml facebook: app_id: 1234 publisher: 1234 ``` + * `logo` - Relative URL to a site-wide logo (e.g., `assets/your-company-logo.png`) * `social` - For [specifying social profiles](https://developers.google.com/structured-data/customize/social-profiles). The following properties are available: * `type` - Either `person` or `organization` (defaults to `person`) @@ -75,4 +80,58 @@ The SEO tag will respect the following YAML front matter if included in a post, * `title` - The title of the post, page, or document * `description` - A short description of the page's content * `image` - Relative URL to an image associated with the post, page, or document (e.g., `assets/page-pic.jpg`) -* `author` - The username of the post, page, or document author +* `author` - Page-, post-, or document-specific author information (see below) + +### Author information + +Author information is used to propagate the `creator` field of Twitter summary cards. This is should be an author-specific, not site-wide Twitter handle (the site-wide username be stored as `site.twitter.username`). + +*TL;DR*: In most cases, put `author: [your Twitter handle]` in the document's front matter, for sites with multiple authors. If you need something more complicated, read on.* + +There are several ways to convey this author-specific information. Author information is found in the following order of priority: + +1. An `author` object, in the documents's front matter, e.g.: + + ```yml + author: + twitter: benbalter + ``` + +2. An `author` object, in the site's `_config.yml`, e.g.: + + ```yml + author: + twitter: benbalter + ``` + +3. `site.data.authors[author]`, if an author is specified in the document's front matter, and a corresponding key exists in `site.data.authors`. E.g., you have the following in the document's front matter: + + ```yml + author: benbalter + ``` + + And you have the following in `_data/authors.yml`: + + ```yml + benbalter: + picture: /img/benbalter.png + twitter: jekyllrb + + potus: + picture: /img/potus.png + twitter: whitehouse + ``` + + In the above example, the author `benbalter`'s Twitter handle will be resolved to `@jekyllrb`. This allows you to centralize author information in a single `_data/authors` file for site with many authors that require more than just the author's username. + +4. An author in the document's front matter (the simplest way), e.g.: + + ```yml + author: benbalter + ``` + +5. An author in the site's `_config.yml`, e.g.: + + ```yml + author: benbalter + ``` From c9690e61cda40ccac3b1d017897f569208a8f926 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 17:48:29 -0500 Subject: [PATCH 31/35] italicize tldr --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b345bc6..9583c63 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ The SEO tag will respect the following YAML front matter if included in a post, Author information is used to propagate the `creator` field of Twitter summary cards. This is should be an author-specific, not site-wide Twitter handle (the site-wide username be stored as `site.twitter.username`). -*TL;DR*: In most cases, put `author: [your Twitter handle]` in the document's front matter, for sites with multiple authors. If you need something more complicated, read on.* +*TL;DR: In most cases, put `author: [your Twitter handle]` in the document's front matter, for sites with multiple authors. If you need something more complicated, read on.* There are several ways to convey this author-specific information. Author information is found in the following order of priority: From 902126fd4bc67373af0190a82edcd5610d859e68 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sat, 20 Feb 2016 17:50:07 -0500 Subject: [PATCH 32/35] stricter rubocop --- .rubocop.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index ee771a6..9408010 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,12 +8,3 @@ Style/Documentation: Style/FileName: Enabled: false - -Metrics/AbcSize: - Enabled: false - -Metrics/CyclomaticComplexity: - Enabled: false - -Metrics/PerceivedComplexity: - Enabled: false From 944074d21c2f32e0bd786ddc59f5fb424cd74c14 Mon Sep 17 00:00:00 2001 From: Chayoung You Date: Sun, 21 Feb 2016 13:20:12 +0900 Subject: [PATCH 33/35] Fix markdown for code snippets --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b219211..54459d3 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,13 @@ The SEO tag will respect any of the following if included in your site's `_confi * `description` - A short description (e.g., A blog dedicated to reviewing cat gifs) * `url` - The full URL to your site. Note: `site.github.url` will be used by default. * `twitter:username` - The site's Twitter handle. You'll want to describe it like so: + ```yml twitter: username: benbalter ``` * `facebook:app_id` (A Facebook app ID for Facebook insights), and/or `facebook:publisher` (A Facebook page URL or ID of the publishing entity). You'll want to describe one or both like so: + ```yml facebook: app_id: 1234 From f1cdf62b530806b5eadabca840f0fdfd80c1c065 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sun, 21 Feb 2016 13:52:49 -0500 Subject: [PATCH 34/35] add support for authors an an array --- lib/template.html | 2 +- spec/jekyll_seo_tag_spec.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index 62ab874..ee82f4c 100644 --- a/lib/template.html +++ b/lib/template.html @@ -39,7 +39,7 @@ {% assign seo_description = seo_description | markdownify | strip_html | strip_newlines | escape_once %} {% endif %} -{% assign seo_author = page.author | default: site.author %} +{% assign seo_author = page.author | default: page.authors[0] | default: site.author %} {% if seo_author %} {% if seo_author.twitter %} {% assign seo_author_twitter = seo_author.twitter %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 8af81aa..2605bc7 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -227,6 +227,15 @@ describe Jekyll::SeoTag do end end + context 'with page.authors as an array' do + let(:page) { make_page('authors' => %w(test foo)) } + + it 'supports author data as an array' do + expected = %r{} + expect(output).to match(expected) + end + end + context 'with site.author as a hash' do let(:author) { { 'twitter' => '@test' } } let(:site) { make_site('author' => author, 'twitter' => site_twitter) } From 739be5a7851ed01e96d5316e0ccbd5b57abf27c3 Mon Sep 17 00:00:00 2001 From: Ben Balter Date: Sun, 21 Feb 2016 13:55:49 -0500 Subject: [PATCH 35/35] document how to use `authors` --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9583c63..9e5b38d 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,8 @@ There are several ways to convey this author-specific information. Author inform In the above example, the author `benbalter`'s Twitter handle will be resolved to `@jekyllrb`. This allows you to centralize author information in a single `_data/authors` file for site with many authors that require more than just the author's username. + *Pro-tip: If `authors` is present in the document's front matter as an array (and `author` is not), the plugin will use the first author listed, as Twitter supports only one author.* + 4. An author in the document's front matter (the simplest way), e.g.: ```yml