From f82ea47534a1e1a2a8af2bc66df2110913f9e74d Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Mon, 16 Jan 2017 17:18:50 -0500 Subject: [PATCH 01/28] Fix Google Structured Data Requests Fixes missing author and name in blogPosting types with organization. --- lib/template.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/template.html b/lib/template.html index 1c9f3ea..c1b1fcf 100644 --- a/lib/template.html +++ b/lib/template.html @@ -62,6 +62,9 @@ {% endif %} {% endif %} {% assign seo_author_twitter = seo_author_twitter | replace:"@","" %} + {% if seo_author.name %} + {% assign seo_author_name = seo_author.name %} + {% else %} {% endif %} {% if page.seo and page.seo.type %} @@ -206,6 +209,10 @@ "headline": {{ seo_page_title | jsonify }}, {% endif %} +{% if seo_author_name %} + "author": {{ seo_author_name | jsonify }}, +{% endif %} + {% if seo_page_image %} "image": {{ seo_page_image | jsonify }}, {% endif %} @@ -221,6 +228,9 @@ {% if seo_site_logo %} "publisher": { "@type": "Organization", + {% if seo_author_name %} + "Name": {{ seo_author_name | jsonify }}, + {% endif %} "logo": { "@type": "ImageObject", "url": {{ seo_site_logo | jsonify }} From 8d2febf86c2f811f5223fc7deb31c1db09303e32 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Mon, 16 Jan 2017 17:21:08 -0500 Subject: [PATCH 02/28] Fix typo. Oops. --- lib/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index c1b1fcf..ab0cd6a 100644 --- a/lib/template.html +++ b/lib/template.html @@ -64,7 +64,7 @@ {% assign seo_author_twitter = seo_author_twitter | replace:"@","" %} {% if seo_author.name %} {% assign seo_author_name = seo_author.name %} - {% else %} + {% endif %} {% endif %} {% if page.seo and page.seo.type %} From 2ddab030f326b9e6a0b15a75159090810bb905da Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Mon, 16 Jan 2017 17:49:37 -0500 Subject: [PATCH 03/28] Fix word casing --- lib/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index ab0cd6a..2dea55c 100644 --- a/lib/template.html +++ b/lib/template.html @@ -229,7 +229,7 @@ "publisher": { "@type": "Organization", {% if seo_author_name %} - "Name": {{ seo_author_name | jsonify }}, + "name": {{ seo_author_name | jsonify }}, {% endif %} "logo": { "@type": "ImageObject", From 4868d22b1b6342e68f93cd7335859dac2593ed13 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Tue, 17 Jan 2017 09:39:41 -0500 Subject: [PATCH 04/28] Add the rest of the JSON tags to pass blogPosting Errors/Warnings This adds the rest of the JSON fields to pass all errors and blog postings. - Adds page.image.url for the image url. (Will default to image if not present). - Add page.image.height and page.image.width for an image object (Will default back to image url if not present). - Add dateModified (will capture from yaml if present, if not it will use datePublished) - (I feel there should be a manual option for this as I sometimes save parts of my blog that shouldn't update the modified field, but still change the file timestamp). This should create JSON that will pass all warnings/strong recommendations/errors from [Google's Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool). --- lib/template.html | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/template.html b/lib/template.html index 2dea55c..34a972a 100644 --- a/lib/template.html +++ b/lib/template.html @@ -92,7 +92,7 @@ {% endif %} {% if page.image %} - {% assign seo_page_image = page.image.path | default: page.image.facebook | default: page.image %} + {% assign seo_page_image = page.image.path | default: page.image.url | default: page.image.facebook | default: page.image %} {% unless seo_page_image contains "://" %} {% assign seo_page_image = seo_page_image | absolute_url %} {% endunless %} @@ -214,13 +214,28 @@ {% endif %} {% if seo_page_image %} - "image": {{ seo_page_image | jsonify }}, + {% if page.image.height && page.image.width %} + "image": { + "@type": "ImageObject", + "url": {{ seo_page_image | jsonify }}, + "height": {{ page.image.height | jsonify }}, + "width": {{ page.image.width | jsonify }} + }, + {% else %} + "image": {{ seo_page_image | jsonify }}, + {% endif %} {% endif %} {% if page.date %} "datePublished": {{ page.date | date_to_xmlschema | jsonify }}, {% endif %} +{% if page.dateModified %} + "dateModified": {{ page.dateModified | date_to_xmlschema | jsonify }}, +{% elseif page.date %} + "dateModified": {{ page.date | date_to_xmlschema | jsonify }}, +{% endif %} + {% if seo_description %} "description": {{ seo_description | jsonify }}, {% endif %} @@ -238,6 +253,13 @@ }, {% endif %} +{% if seo_type == "BlogPosting" %} + "mainEntityOfPage": { + "@type": "WebPage", + "@id": {{ page.url | replace:'/index.html','/' | absolute_url | jsonify }} + }, +{% endif %} + {% if seo_links %} "sameAs": {{ seo_links | jsonify }}, {% endif %} From 30d4ffc1a3000fecad70c0dc9814b84e98e54c15 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Tue, 17 Jan 2017 09:50:54 -0500 Subject: [PATCH 05/28] Fix language mistake Well.... looks like I added an 'e'. Whoops. --- lib/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index 34a972a..853d155 100644 --- a/lib/template.html +++ b/lib/template.html @@ -232,7 +232,7 @@ {% if page.dateModified %} "dateModified": {{ page.dateModified | date_to_xmlschema | jsonify }}, -{% elseif page.date %} +{% elsif page.date %} "dateModified": {{ page.date | date_to_xmlschema | jsonify }}, {% endif %} From a2a2c560cea2701956257fbcbbdb97ef5957c5cf Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Tue, 17 Jan 2017 11:20:48 -0500 Subject: [PATCH 06/28] Add pull request documentation Adds documentation on new image behavior, dateModified, and author field. --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 58b17fa..f04550e 100644 --- a/README.md +++ b/README.md @@ -185,27 +185,43 @@ The following options can be set for any particular page. While the default opti * `name` - If the name of the thing that the page represents is different from the page title. (i.e.: "Frank's Café" vs "Welcome to Frank's Café") * `type` - The type of things that the page represents. This must be a [Schema.org type](http://schema.org/docs/schemas.html), and will probably usually be something like [`BlogPosting`](http://schema.org/BlogPosting), [`NewsArticle`](http://schema.org/NewsArticle), [`Person`](http://schema.org/Person), [`Organization`](http://schema.org/Organization), etc. * `links` - An array of other URLs that represent the same thing that this page represents. For instance, Jane's bio page might include links to Jane's GitHub and Twitter profiles. + * `dateModified` - An override for the `dateModified` field in the JSON-LD output. Useful when the file timestamp does not match the true time that the content was modified. + * `author` - The `author` field will match the JSON-LD author output where applicable. ### Customizing image output For most users, setting `image: [path-to-image]` on a per-page basis should be enough. If you need more control over how images are represented, the `image` property can also be an object, with the following options: * `path` - The relative path to the image. Same as `image: [path-to-image]` +* `url` - The path to the image to be used in the JSON-LD image object `url`. * `twitter` - The relative path to a Twitter-specific image. * `facebook` - The relative path to a Facebook-specific image. -* `height` - The height of the Facebook (`og:image`) image -* `width` - The width of the Facebook (`og:image`) image +* `height` - The height of the Facebook (`og:image`) image and JSON-LD image object. +* `width` - The width of the Facebook (`og:image`) image and JSON-LD image object. + +The JSON-LD will default to the `image: ` tag unless `url: ` `height: ` and `width: `. You can use any of the above, optional properties, like so: ```yml image: + url: /img/banner.png twitter: /img/twitter.png facebook: /img/facebook.png height: 100 width: 100 ``` +Or if you have no site specific images simply: + +```yml +image: + url: /img/banner.png + height: 100 + width: 100 +``` + + ### Setting a default image You can define a default image using [Front Matter default](https://jekyllrb.com/docs/configuration/#front-matter-defaults), to provide a default Twitter Card or OGP image to all of your posts and pages. From 8cc9b2d52cc92e96992ac5be2f649f3207ecf514 Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 18 Jan 2017 14:14:29 -0500 Subject: [PATCH 07/28] Add test for image object with dimensions --- spec/jekyll_seo_tag_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index d273a26..be695d5 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -196,6 +196,22 @@ describe Jekyll::SeoTag do end end + context "with image.url, image.height, and image.width" do + let(:meta) do + { + "image" => {"url" => "/img/banner.png","height" => 1,"width" => 2}, + "url" => "http://example.invalid" + } + end + let(:page) { make_post(meta) } + + it "outputs the image object with dimensions" do + expect(json_data["image"]["url"]).to eql("http://example.invalid/img/banner.png") + expect(json_data["image"]["height"]).to eql(1) + expect(json_data["image"]["width"]).to eql(2) + end + end + context "with site.title" do let(:site) { make_site("title" => "Foo", "url" => "http://example.invalid") } From 9aa2cbfb09cb773964f6398c14e93244d929ca92 Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 18 Jan 2017 14:57:36 -0500 Subject: [PATCH 08/28] Wite tests for implemented features. --- lib/template.html | 4 +-- spec/jekyll_seo_tag_spec.rb | 71 +++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/lib/template.html b/lib/template.html index 853d155..2bce881 100644 --- a/lib/template.html +++ b/lib/template.html @@ -62,8 +62,8 @@ {% endif %} {% endif %} {% assign seo_author_twitter = seo_author_twitter | replace:"@","" %} - {% if seo_author.name %} - {% assign seo_author_name = seo_author.name %} + {% if seo_author %} + {% assign seo_author_name = seo_author %} {% endif %} {% endif %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index be695d5..a2b03ea 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -212,6 +212,77 @@ describe Jekyll::SeoTag do end end + context "with image.url only" do + let(:meta) do + { + "image" => {"url" => "/img/banner.png"}, + "url" => "http://example.invalid" + } + end + let(:page) { make_post(meta) } + + it "outputs the image object" do + expect(json_data["image"]).to eql("http://example.invalid/img/banner.png") + end + end + + context "with page.author" do + let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } + let(:page) { make_post("author" => "Mr. Foo") } + + it "outputs the author" do + expect(json_data["author"]).to eql("Mr. Foo") + end + + it "outputs the publisher author" do + expect(json_data["publisher"]["name"]).to eql("Mr. Foo") + end + end + + context "with page.date only" do + let(:page) { make_post("date" => "2017-01-01T01:00:00-05:00") } + + it "outputs the datePublished" do + expect(json_data["datePublished"]).to eql("2017-01-01T01:00:00-05:00") + expect(json_data["dateModified"]).to eql("2017-01-01T01:00:00-05:00") + end + end + + context "with page.dateModified" do + let(:page) { make_post("date" => "2017-01-01T01:00:00-05:00", "dateModified" => "2017-02-02T02:00:00-05:00") } + + it "outputs the datePublished" do + expect(json_data["datePublished"]).to eql("2017-01-01T01:00:00-05:00") + end + + it "outputs the dateModified" do + expect(json_data["dateModified"]).to eql("2017-02-02T02:00:00-05:00") + end + end + + context "with page.author" do + let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } + let(:page) { make_post("author" => "Mr. Foo") } + + it "outputs the author" do + expect(json_data["author"]).to eql("Mr. Foo") + end + + it "outputs the publisher author" do + expect(json_data["publisher"]["name"]).to eql("Mr. Foo") + end + end + + context "with seo type is BlogPosting" do + let(:site) { make_site("url" => "http://example.invalid") } + let(:page) { make_post("seo" => {"type" => "BlogPosting"},"permalink" => "/foo/") } + + it "outputs the mainEntityOfPage" do + expect(json_data["mainEntityOfPage"]["@type"]).to eql("WebPage") + expect(json_data["mainEntityOfPage"]["@id"]).to eql("http://example.invalid/foo/") + end + end + context "with site.title" do let(:site) { make_site("title" => "Foo", "url" => "http://example.invalid") } From 10d5f82984bf192a48f008b864b0aeadfe982c75 Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 18 Jan 2017 15:01:48 -0500 Subject: [PATCH 09/28] Travis doesn't like my timestamps for testing. --- spec/jekyll_seo_tag_spec.rb | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index a2b03ea..9802db1 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -239,27 +239,6 @@ describe Jekyll::SeoTag do end end - context "with page.date only" do - let(:page) { make_post("date" => "2017-01-01T01:00:00-05:00") } - - it "outputs the datePublished" do - expect(json_data["datePublished"]).to eql("2017-01-01T01:00:00-05:00") - expect(json_data["dateModified"]).to eql("2017-01-01T01:00:00-05:00") - end - end - - context "with page.dateModified" do - let(:page) { make_post("date" => "2017-01-01T01:00:00-05:00", "dateModified" => "2017-02-02T02:00:00-05:00") } - - it "outputs the datePublished" do - expect(json_data["datePublished"]).to eql("2017-01-01T01:00:00-05:00") - end - - it "outputs the dateModified" do - expect(json_data["dateModified"]).to eql("2017-02-02T02:00:00-05:00") - end - end - context "with page.author" do let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } let(:page) { make_post("author" => "Mr. Foo") } From b04f73960ef71d70ddceec8df924d3f5c1d63008 Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 18 Jan 2017 15:28:54 -0500 Subject: [PATCH 10/28] Match rubocop styling. --- spec/jekyll_seo_tag_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 9802db1..61c5b43 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -199,8 +199,8 @@ describe Jekyll::SeoTag do context "with image.url, image.height, and image.width" do let(:meta) do { - "image" => {"url" => "/img/banner.png","height" => 1,"width" => 2}, - "url" => "http://example.invalid" + "image" => { "url" => "/img/banner.png", "height" => 1, "width" => 2 }, + "url" => "http://example.invalid" } end let(:page) { make_post(meta) } @@ -215,8 +215,8 @@ describe Jekyll::SeoTag do context "with image.url only" do let(:meta) do { - "image" => {"url" => "/img/banner.png"}, - "url" => "http://example.invalid" + "image" => { "url" => "/img/banner.png" }, + "url" => "http://example.invalid" } end let(:page) { make_post(meta) } @@ -254,7 +254,7 @@ describe Jekyll::SeoTag do context "with seo type is BlogPosting" do let(:site) { make_site("url" => "http://example.invalid") } - let(:page) { make_post("seo" => {"type" => "BlogPosting"},"permalink" => "/foo/") } + let(:page) { make_post("seo" => { "type" => "BlogPosting" }, "permalink" => "/foo/") } it "outputs the mainEntityOfPage" do expect(json_data["mainEntityOfPage"]["@type"]).to eql("WebPage") From fd5246a4cdf3c3c93cb21e947bcef6910d5a0b14 Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 25 Jan 2017 11:05:38 -0500 Subject: [PATCH 11/28] Test output manually with Google Markup. Change inferred type. Improve test coverage --- lib/template.html | 7 +++++-- spec/jekyll_seo_tag_spec.rb | 12 +++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/template.html b/lib/template.html index 2bce881..5a28563 100644 --- a/lib/template.html +++ b/lib/template.html @@ -63,7 +63,7 @@ {% endif %} {% assign seo_author_twitter = seo_author_twitter | replace:"@","" %} {% if seo_author %} - {% assign seo_author_name = seo_author %} + {% assign seo_author_name = seo_author.name | default: seo_author %} {% endif %} {% endif %} @@ -210,7 +210,10 @@ {% endif %} {% if seo_author_name %} - "author": {{ seo_author_name | jsonify }}, + "author": { + "@type": "Person", + "name": {{ seo_author_name | jsonify }} + }, {% endif %} {% if seo_page_image %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 61c5b43..a065e7f 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -226,12 +226,13 @@ describe Jekyll::SeoTag do end end - context "with page.author" do + context "with page.author.name" do let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } let(:page) { make_post("author" => "Mr. Foo") } it "outputs the author" do - expect(json_data["author"]).to eql("Mr. Foo") + expect(json_data["author"]["@type"]).to eql("Person") + expect(json_data["author"]["name"]).to eql("Mr. Foo") end it "outputs the publisher author" do @@ -239,12 +240,13 @@ describe Jekyll::SeoTag do end end - context "with page.author" do + context "with only page.author" do let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } - let(:page) { make_post("author" => "Mr. Foo") } + let(:page) { make_post("author" => { "name" => "Mr. Foo" }) } it "outputs the author" do - expect(json_data["author"]).to eql("Mr. Foo") + expect(json_data["author"]["@type"]).to eql("Person") + expect(json_data["author"]["name"]).to eql("Mr. Foo") end it "outputs the publisher author" do From 543793421414b6fdb98a85c3fc4510eaf0c812fd Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 25 Jan 2017 11:35:18 -0500 Subject: [PATCH 12/28] Implement PR #103 for my own use. Change template to better fit existing style. --- lib/template.html | 15 ++++++++------- spec/jekyll_seo_tag_spec.rb | 16 +--------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/lib/template.html b/lib/template.html index 5a28563..e4baf2d 100644 --- a/lib/template.html +++ b/lib/template.html @@ -62,9 +62,6 @@ {% endif %} {% endif %} {% assign seo_author_twitter = seo_author_twitter | replace:"@","" %} - {% if seo_author %} - {% assign seo_author_name = seo_author.name | default: seo_author %} - {% endif %} {% endif %} {% if page.seo and page.seo.type %} @@ -107,6 +104,10 @@ {% endif %} +{% if seo_author %} + +{% endif %} + {% if seo_description %} @@ -209,10 +210,10 @@ "headline": {{ seo_page_title | jsonify }}, {% endif %} -{% if seo_author_name %} +{% if seo_author %} "author": { "@type": "Person", - "name": {{ seo_author_name | jsonify }} + "name": {{ seo_author | jsonify }} }, {% endif %} @@ -246,8 +247,8 @@ {% if seo_site_logo %} "publisher": { "@type": "Organization", - {% if seo_author_name %} - "name": {{ seo_author_name | jsonify }}, + {% if seo_author %} + "name": {{ seo_author | jsonify }}, {% endif %} "logo": { "@type": "ImageObject", diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index a065e7f..6ffbf4f 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -226,7 +226,7 @@ describe Jekyll::SeoTag do end end - context "with page.author.name" do + context "with page.author" do let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } let(:page) { make_post("author" => "Mr. Foo") } @@ -240,20 +240,6 @@ describe Jekyll::SeoTag do end end - context "with only page.author" do - let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } - let(:page) { make_post("author" => { "name" => "Mr. Foo" }) } - - it "outputs the author" do - expect(json_data["author"]["@type"]).to eql("Person") - expect(json_data["author"]["name"]).to eql("Mr. Foo") - end - - it "outputs the publisher author" do - expect(json_data["publisher"]["name"]).to eql("Mr. Foo") - end - end - context "with seo type is BlogPosting" do let(:site) { make_site("url" => "http://example.invalid") } let(:page) { make_post("seo" => { "type" => "BlogPosting" }, "permalink" => "/foo/") } From 644e976fbd624f69ae1846a24d7cec3613901815 Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 25 Jan 2017 11:37:35 -0500 Subject: [PATCH 13/28] Add test for PR #103 --- spec/jekyll_seo_tag_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 6ffbf4f..232c788 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -70,6 +70,14 @@ describe Jekyll::SeoTag do end end + context "with page.author" do + let(:page) { make_page("author" => "Mr. Foo") } + + it "uses the page author" do + expect(output).to match(%r!!) + end + end + context "with page.excerpt" do let(:page) { make_page("excerpt" => "foo") } From a0f65888e3881b938048aac78394c92a1aa15d9b Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 25 Jan 2017 12:18:29 -0500 Subject: [PATCH 14/28] Remove Author tag. I guess it really isn't used anymore. --- lib/template.html | 4 ---- spec/jekyll_seo_tag_spec.rb | 8 -------- 2 files changed, 12 deletions(-) diff --git a/lib/template.html b/lib/template.html index e4baf2d..eddc637 100644 --- a/lib/template.html +++ b/lib/template.html @@ -104,10 +104,6 @@ {% endif %} -{% if seo_author %} - -{% endif %} - {% if seo_description %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 232c788..6ffbf4f 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -70,14 +70,6 @@ describe Jekyll::SeoTag do end end - context "with page.author" do - let(:page) { make_page("author" => "Mr. Foo") } - - it "uses the page author" do - expect(output).to match(%r!!) - end - end - context "with page.excerpt" do let(:page) { make_page("excerpt" => "foo") } From da498c7c5fb2d7dc129ba59b85c106967df6143c Mon Sep 17 00:00:00 2001 From: kyle Date: Mon, 30 Jan 2017 10:37:27 -0500 Subject: [PATCH 15/28] Simplify documentation. Change to snake_case. Use Path instead of adding URL. --- README.md | 10 ++++------ lib/template.html | 6 +++--- spec/jekyll_seo_tag_spec.rb | 8 ++++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f04550e..06a5c89 100644 --- a/README.md +++ b/README.md @@ -185,27 +185,25 @@ The following options can be set for any particular page. While the default opti * `name` - If the name of the thing that the page represents is different from the page title. (i.e.: "Frank's Café" vs "Welcome to Frank's Café") * `type` - The type of things that the page represents. This must be a [Schema.org type](http://schema.org/docs/schemas.html), and will probably usually be something like [`BlogPosting`](http://schema.org/BlogPosting), [`NewsArticle`](http://schema.org/NewsArticle), [`Person`](http://schema.org/Person), [`Organization`](http://schema.org/Organization), etc. * `links` - An array of other URLs that represent the same thing that this page represents. For instance, Jane's bio page might include links to Jane's GitHub and Twitter profiles. - * `dateModified` - An override for the `dateModified` field in the JSON-LD output. Useful when the file timestamp does not match the true time that the content was modified. - * `author` - The `author` field will match the JSON-LD author output where applicable. + * `date_modified` - An override for the `dateModified` field in the JSON-LD output. Useful when the file timestamp does not match the true time that the content was modified. ### Customizing image output For most users, setting `image: [path-to-image]` on a per-page basis should be enough. If you need more control over how images are represented, the `image` property can also be an object, with the following options: * `path` - The relative path to the image. Same as `image: [path-to-image]` -* `url` - The path to the image to be used in the JSON-LD image object `url`. * `twitter` - The relative path to a Twitter-specific image. * `facebook` - The relative path to a Facebook-specific image. * `height` - The height of the Facebook (`og:image`) image and JSON-LD image object. * `width` - The width of the Facebook (`og:image`) image and JSON-LD image object. -The JSON-LD will default to the `image: ` tag unless `url: ` `height: ` and `width: `. +The JSON-LD will default to the `image: ` tag unless `path: ` `height: ` and `width: `. You can use any of the above, optional properties, like so: ```yml image: - url: /img/banner.png + path: /img/banner.png twitter: /img/twitter.png facebook: /img/facebook.png height: 100 @@ -216,7 +214,7 @@ Or if you have no site specific images simply: ```yml image: - url: /img/banner.png + path: /img/banner.png height: 100 width: 100 ``` diff --git a/lib/template.html b/lib/template.html index eddc637..cf4c885 100644 --- a/lib/template.html +++ b/lib/template.html @@ -89,7 +89,7 @@ {% endif %} {% if page.image %} - {% assign seo_page_image = page.image.path | default: page.image.url | default: page.image.facebook | default: page.image %} + {% assign seo_page_image = page.image.path | default: page.image.facebook | default: page.image %} {% unless seo_page_image contains "://" %} {% assign seo_page_image = seo_page_image | absolute_url %} {% endunless %} @@ -230,8 +230,8 @@ "datePublished": {{ page.date | date_to_xmlschema | jsonify }}, {% endif %} -{% if page.dateModified %} - "dateModified": {{ page.dateModified | date_to_xmlschema | jsonify }}, +{% if page.date_modified %} + "dateModified": {{ page.date_modified | date_to_xmlschema | jsonify }}, {% elsif page.date %} "dateModified": {{ page.date | date_to_xmlschema | jsonify }}, {% endif %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 6ffbf4f..7a391c4 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -196,10 +196,10 @@ describe Jekyll::SeoTag do end end - context "with image.url, image.height, and image.width" do + context "with image.path, image.height, and image.width" do let(:meta) do { - "image" => { "url" => "/img/banner.png", "height" => 1, "width" => 2 }, + "image" => { "path" => "/img/banner.png", "height" => 1, "width" => 2 }, "url" => "http://example.invalid" } end @@ -212,10 +212,10 @@ describe Jekyll::SeoTag do end end - context "with image.url only" do + context "with image.path only" do let(:meta) do { - "image" => { "url" => "/img/banner.png" }, + "image" => { "path" => "/img/banner.png" }, "url" => "http://example.invalid" } end From 6ebc866c5e9cbc245a9a3efdb9cc79c06bf4c9e3 Mon Sep 17 00:00:00 2001 From: kyle Date: Mon, 30 Jan 2017 10:46:22 -0500 Subject: [PATCH 16/28] Appease RuboCop --- spec/jekyll_seo_tag_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 38efcc4..bbae600 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -200,7 +200,7 @@ describe Jekyll::SeoTag do let(:meta) do { "image" => { "path" => "/img/banner.png", "height" => 1, "width" => 2 }, - "url" => "http://example.invalid" + "url" => "http://example.invalid", } end let(:page) { make_post(meta) } @@ -216,7 +216,7 @@ describe Jekyll::SeoTag do let(:meta) do { "image" => { "path" => "/img/banner.png" }, - "url" => "http://example.invalid" + "url" => "http://example.invalid", } end let(:page) { make_post(meta) } From 8e36fe4da1651f837ca8b9741326771cee410ee2 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Wed, 15 Feb 2017 12:41:30 -0500 Subject: [PATCH 17/28] Update docs. Add use case. Add test. --- README.md | 3 +-- lib/template.html | 2 +- spec/jekyll_seo_tag_spec.rb | 10 ++++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 06a5c89..a01ecdc 100644 --- a/README.md +++ b/README.md @@ -215,10 +215,9 @@ Or if you have no site specific images simply: ```yml image: path: /img/banner.png - height: 100 - width: 100 ``` +> Using the image dimensions are optional, but the [Google Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/u/0/) will consider the JSON-LD to have errors when an image does not have specified dimensions. ### Setting a default image diff --git a/lib/template.html b/lib/template.html index 1438e4b..a872638 100755 --- a/lib/template.html +++ b/lib/template.html @@ -266,7 +266,7 @@ }, {% endif %} -{% if seo_type == "BlogPosting" %} +{% if seo_type == "BlogPosting" or seo_type == "CreativeWork" %} "mainEntityOfPage": { "@type": "WebPage", "@id": {{ page.url | replace:'/index.html','/' | absolute_url | jsonify }} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index bbae600..0d12b77 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -250,6 +250,16 @@ describe Jekyll::SeoTag do end end + context "with seo type is CreativeWork" do + let(:site) { make_site("url" => "http://example.invalid") } + let(:page) { make_post("seo" => { "type" => "CreativeWork" }, "permalink" => "/foo/") } + + it "outputs the mainEntityOfPage" do + expect(json_data["mainEntityOfPage"]["@type"]).to eql("WebPage") + expect(json_data["mainEntityOfPage"]["@id"]).to eql("http://example.invalid/foo/") + end + end + context "with site.title" do let(:site) { make_site("title" => "Foo", "url" => "http://example.invalid") } From ba16b955c8b85c122178e349737cb299d0847aa0 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Thu, 16 Feb 2017 14:07:35 -0500 Subject: [PATCH 18/28] Propose new image handling method. --- README.md | 28 ++++++++------ lib/template.html | 73 +++++++++++++++++++++++++------------ spec/jekyll_seo_tag_spec.rb | 23 ++---------- 3 files changed, 70 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index a01ecdc..b053ff4 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,8 @@ The following options can be set for any particular page. While the default opti * `name` - If the name of the thing that the page represents is different from the page title. (i.e.: "Frank's Café" vs "Welcome to Frank's Café") * `type` - The type of things that the page represents. This must be a [Schema.org type](http://schema.org/docs/schemas.html), and will probably usually be something like [`BlogPosting`](http://schema.org/BlogPosting), [`NewsArticle`](http://schema.org/NewsArticle), [`Person`](http://schema.org/Person), [`Organization`](http://schema.org/Organization), etc. * `links` - An array of other URLs that represent the same thing that this page represents. For instance, Jane's bio page might include links to Jane's GitHub and Twitter profiles. - * `date_modified` - An override for the `dateModified` field in the JSON-LD output. Useful when the file timestamp does not match the true time that the content was modified. + * `date_modified` - (YYYY-MM-DD hh:mm) A manual override for the `dateModified` field in the JSON-LD output. This field will take **first priority** for the `dateModified` output. This is useful when the file timestamp does not match the true time that the content was modified. + * A user may also install [Last Modified At](https://github.com/gjtorikian/jekyll-last-modified-at) which will offer an alternative way of providing for the `dateModified` field. ### Customizing image output @@ -194,30 +195,33 @@ For most users, setting `image: [path-to-image]` on a per-page basis should be e * `path` - The relative path to the image. Same as `image: [path-to-image]` * `twitter` - The relative path to a Twitter-specific image. * `facebook` - The relative path to a Facebook-specific image. -* `height` - The height of the Facebook (`og:image`) image and JSON-LD image object. -* `width` - The width of the Facebook (`og:image`) image and JSON-LD image object. +* `height` - The height of the image in pixels. +* `width` - The width of image in pixels. The JSON-LD will default to the `image: ` tag unless `path: ` `height: ` and `width: `. You can use any of the above, optional properties, like so: ```yml -image: - path: /img/banner.png - twitter: /img/twitter.png - facebook: /img/facebook.png - height: 100 - width: 100 +image: /img/banner.png ``` -Or if you have no site specific images simply: +Or if you have Facebook or Twitter specific images simply use: ```yml image: - path: /img/banner.png + default: + path: /img/banner.png + height: 100 + width: 100 + facebook: + path: /img/facebook.png + height: 90 + width: 90 + twitter: /img/twitter.png ``` -> Using the image dimensions are optional, but the [Google Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/u/0/) will consider the JSON-LD to have errors when an image does not have specified dimensions. +Using the image dimensions are optional, but the [Google Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/u/0/) will consider the JSON-LD to have errors with certain types (i.e. BlogPosting) when an image does not have specified dimensions. ### Setting a default image diff --git a/lib/template.html b/lib/template.html index a872638..e0e9b52 100755 --- a/lib/template.html +++ b/lib/template.html @@ -73,6 +73,10 @@ {% assign seo_author_twitter = seo_author_twitter | replace:"@","" %} {% endif %} +{% if page.date_modified or page.last_modified_at or page.date %} + {% assign seo_date_modified = page.seo.date_modified | default: page.last_modified_at | default: page.date %} +{% endif %} + {% if page.seo and page.seo.type %} {% assign seo_type = page.seo.type %} {% elsif seo_homepage_or_about %} @@ -98,11 +102,27 @@ {% endif %} {% if page.image %} - {% assign seo_page_image = page.image.path | default: page.image.facebook | default: page.image %} - {% unless seo_page_image contains "://" %} - {% assign seo_page_image = seo_page_image | absolute_url %} + {% assign seo_page_image_default = page.image.default.path | default: page.image.default | default: page.image %} + {% unless seo_page_image_default contains "://" %} + {% assign seo_page_image_default = seo_page_image_default | absolute_url %} {% endunless %} - {% assign seo_page_image = seo_page_image | escape %} + {% assign seo_page_image_default = seo_page_image_default | escape %} + {% assign seo_page_image_default_width = page.image.default.width %} + {% assign seo_page_image_default_height = page.image.default.height %} + + {% assign seo_page_image_facebook = page.image.facebook.path | default: page.image.facebook %} + {% unless seo_page_image_facebook contains "://" %} + {% assign seo_page_image_facebook = seo_page_image_facebook | absolute_url %} + {% endunless %} + {% assign seo_page_image_facebook = seo_page_image_facebook | escape %} + {% assign seo_page_image_facebook_width = page.image.facebook.width %} + {% assign seo_page_image_facebook_height = page.image.facebook.height %} + + {% assign seo_page_image_twitter = page.image.twitter.path | default: page.image.twitter %} + {% unless seo_page_image_twitter contains "://" %} + {% assign seo_page_image_twitter = seo_page_image_twitter | absolute_url %} + {% endunless %} + {% assign seo_page_image_twitter = seo_page_image_twitter | escape %} {% endif %} {% if seo_tag.title and seo_title %} @@ -131,18 +151,27 @@ {% endif %} -{% if seo_page_image %} - - {% if page.image.height %} - +{% if page.image %} + {% if page.image.facebook %} + {% assign local_seo_page_image = seo_page_image_facebook %} + {% assign local_seo_page_image_height = seo_page_image_facebook_height %} + {% assign local_seo_page_image_width = seo_page_image_facebook_width %} + {% else %} + {% assign local_seo_page_image = seo_page_image_default %} + {% assign local_seo_page_image_height = seo_page_image_default_height %} + {% assign local_seo_page_image_width = seo_page_image_default_width %} {% endif %} - {% if page.image.width %} - + + {% if local_seo_page_image_height %} + + {% endif %} + {% if local_seo_page_image_width %} + {% endif %} {% endif %} {% if page.image.twitter %} - + {% endif %} {% if page.date %} @@ -158,7 +187,7 @@ {% endif %} {% if site.twitter %} - {% if seo_page_image or page.image.twitter %} + {% if page.image or page.image.twitter %} {% else %} @@ -226,16 +255,16 @@ }, {% endif %} -{% if seo_page_image %} - {% if page.image.height && page.image.width %} +{% if seo_page_image_default %} + {% if seo_page_image_default_height && seo_page_image_default_width %} "image": { "@type": "ImageObject", - "url": {{ seo_page_image | jsonify }}, - "height": {{ page.image.height | jsonify }}, - "width": {{ page.image.width | jsonify }} + "url": {{ seo_page_image_default | jsonify }}, + "height": {{ seo_page_image_default_height | jsonify }}, + "width": {{ seo_page_image_default_width | jsonify }} }, {% else %} - "image": {{ seo_page_image | jsonify }}, + "image": {{ seo_page_image_default | jsonify }}, {% endif %} {% endif %} @@ -243,10 +272,8 @@ "datePublished": {{ page.date | date_to_xmlschema | jsonify }}, {% endif %} -{% if page.date_modified %} - "dateModified": {{ page.date_modified | date_to_xmlschema | jsonify }}, -{% elsif page.date %} - "dateModified": {{ page.date | date_to_xmlschema | jsonify }}, +{% if seo_date_modified %} + "dateModified": {{ seo_date_modified | date_to_xmlschema | jsonify }}, {% endif %} {% if seo_description %} @@ -266,7 +293,7 @@ }, {% endif %} -{% if seo_type == "BlogPosting" or seo_type == "CreativeWork" %} +{% if seo_type == "BlogPosting" or seo_type == "CreativeWork"%} "mainEntityOfPage": { "@type": "WebPage", "@id": {{ page.url | replace:'/index.html','/' | absolute_url | jsonify }} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 0d12b77..52e3829 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -141,7 +141,7 @@ describe Jekyll::SeoTag do context "with page.image as an object" do context "when given a path" do - let(:page) { make_page("image" => { "path" => "/img/foo.png" }) } + let(:page) { make_page("image" => { "default" => "/img/foo.png" }) } it "outputs the image" do expected = %r!! @@ -168,8 +168,7 @@ describe Jekyll::SeoTag do end context "when given the image height and width" do - let(:image) { { "facebook" => "/img/foo.png", "height" => 1, "width" => 2 } } - let(:page) { make_page("image" => image) } + let(:page) { make_page("image" => { "facebook" => { "path" => "/img/foo.png", "height" => 1, "width" => 2 } }) } it "outputs the image" do expected = %r!! @@ -196,10 +195,10 @@ describe Jekyll::SeoTag do end end - context "with image.path, image.height, and image.width" do + context "with image.default.path, image.default.height, and image.default.width" do let(:meta) do { - "image" => { "path" => "/img/banner.png", "height" => 1, "width" => 2 }, + "image" => { "default" => { "path" => "/img/banner.png", "height" => 1, "width" => 2 } }, "url" => "http://example.invalid", } end @@ -212,20 +211,6 @@ describe Jekyll::SeoTag do end end - context "with image.path only" do - let(:meta) do - { - "image" => { "path" => "/img/banner.png" }, - "url" => "http://example.invalid", - } - end - let(:page) { make_post(meta) } - - it "outputs the image object" do - expect(json_data["image"]).to eql("http://example.invalid/img/banner.png") - end - end - context "with page.author" do let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } let(:page) { make_post("author" => "Mr. Foo") } From a847a69eeafb403b42488e4b4ad3dcf9ce9dc17c Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Thu, 16 Feb 2017 14:16:11 -0500 Subject: [PATCH 19/28] Fix small test case blunder. --- lib/template.html | 2 +- spec/jekyll_seo_tag_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/template.html b/lib/template.html index e0e9b52..ebc0697 100755 --- a/lib/template.html +++ b/lib/template.html @@ -102,7 +102,7 @@ {% endif %} {% if page.image %} - {% assign seo_page_image_default = page.image.default.path | default: page.image.default | default: page.image %} + {% assign seo_page_image_default = page.image.default.path | default: page.image.default | default: page.image.path | default: page.image %} {% unless seo_page_image_default contains "://" %} {% assign seo_page_image_default = seo_page_image_default | absolute_url %} {% endunless %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 52e3829..8637da4 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -141,7 +141,7 @@ describe Jekyll::SeoTag do context "with page.image as an object" do context "when given a path" do - let(:page) { make_page("image" => { "default" => "/img/foo.png" }) } + let(:page) { make_page("image" => { "path" => "/img/foo.png" }) } it "outputs the image" do expected = %r!! From 318de343b032fc483c90c6a9a9fb5ddbc2c22b07 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Thu, 16 Feb 2017 14:49:06 -0500 Subject: [PATCH 20/28] Remove unnecessary/confusing wording. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b053ff4..b3810c7 100644 --- a/README.md +++ b/README.md @@ -198,8 +198,6 @@ For most users, setting `image: [path-to-image]` on a per-page basis should be e * `height` - The height of the image in pixels. * `width` - The width of image in pixels. -The JSON-LD will default to the `image: ` tag unless `path: ` `height: ` and `width: `. - You can use any of the above, optional properties, like so: ```yml From 4c577ffb47b84fc293e1ff44e6374fa9174681e1 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Fri, 17 Feb 2017 10:30:44 -0500 Subject: [PATCH 21/28] Add legacy test and maintain old methods --- lib/template.html | 4 ++-- spec/jekyll_seo_tag_spec.rb | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/template.html b/lib/template.html index ebc0697..41bc2b0 100755 --- a/lib/template.html +++ b/lib/template.html @@ -115,8 +115,8 @@ {% assign seo_page_image_facebook = seo_page_image_facebook | absolute_url %} {% endunless %} {% assign seo_page_image_facebook = seo_page_image_facebook | escape %} - {% assign seo_page_image_facebook_width = page.image.facebook.width %} - {% assign seo_page_image_facebook_height = page.image.facebook.height %} + {% assign seo_page_image_facebook_width = page.image.facebook.width | default: page.image.width %} + {% assign seo_page_image_facebook_height = page.image.facebook.height | default: page.image.height %} {% assign seo_page_image_twitter = page.image.twitter.path | default: page.image.twitter %} {% unless seo_page_image_twitter contains "://" %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 8637da4..929c5ad 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -177,6 +177,17 @@ describe Jekyll::SeoTag do expect(output).to match(expected) end end + + context "when given the image height and width (legacy)" do + let(:page) { make_page("image" => { "facebook" => "/img/foo.png", "height" => 1, "width" => 2 } ) } + + it "outputs the image" do + expected = %r!! + expect(output).to match(expected) + expected = %r!! + expect(output).to match(expected) + end + end end context "with site.logo" do From 02eb92629300750aa90727c977dee388b94a4cd1 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Fri, 17 Feb 2017 10:33:39 -0500 Subject: [PATCH 22/28] Appease RuboCop --- 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 929c5ad..bab0a23 100644 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -179,7 +179,7 @@ describe Jekyll::SeoTag do end context "when given the image height and width (legacy)" do - let(:page) { make_page("image" => { "facebook" => "/img/foo.png", "height" => 1, "width" => 2 } ) } + let(:page) { make_page("image" => { "facebook" => "/img/foo.png", "height" => 1, "width" => 2 }) } it "outputs the image" do expected = %r!! From c31f4c65b1f7e3dbde17fb9e817c6bcc7e5079d1 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Fri, 24 Feb 2017 15:04:36 -0500 Subject: [PATCH 23/28] Better test coverage. Some overlap, but easier to understand. Some tests slightly refactored. --- spec/jekyll_seo_tag_spec.rb | 133 ++++++++++++++++++++++++++++++------ 1 file changed, 111 insertions(+), 22 deletions(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 53f25d0..695dbef 100755 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -140,7 +140,7 @@ describe Jekyll::SeoTag do end context "with page.image as an object" do - context "when given a path" do + context "when given 'image' with a path" do let(:page) { make_page("image" => { "path" => "/img/foo.png" }) } it "outputs the image" do @@ -149,6 +149,47 @@ describe Jekyll::SeoTag do end end + context "when given a default image" do + let(:page) { make_page("image" => { "default" => "/img/default.png" }) } + + it "outputs the image" do + expected = %r!! + expect(output).to match(expected) + end + + it "outputs the default image JSON item" do + expect(json_data["image"]).to eql("http://example.invalid/img/default.png") + end + end + + context "when given a default image as a path" do + let(:page) { make_page("image" => { "default" => { "path" => "/img/default.png" } }) } + + it "outputs the image" do + expected = %r!! + expect(output).to match(expected) + end + + it "outputs the default image JSON item" do + expect(json_data["image"]).to eql("http://example.invalid/img/default.png") + end + end + + context "when given a default image with dimensions" do + let(:page) { make_page("image" => { "default" => { "path" => "/img/default.png", "height" => 1, "width" => 2 } }) } + + it "outputs the image" do + expected = %r!! + expect(output).to match(expected) + end + + it "outputs the default image JSON object with dimensions" do + expect(json_data["image"]["url"]).to eql("http://example.invalid/img/default.png") + expect(json_data["image"]["height"]).to eql(1) + expect(json_data["image"]["width"]).to eql(2) + end + end + context "when given a facebook image" do let(:page) { make_page("image" => { "facebook" => "/img/facebook.png" }) } @@ -158,6 +199,67 @@ describe Jekyll::SeoTag do end end + context "when given a facebook image as a path" do + let(:page) { make_page("image" => { "facebook" => { "path" => "/img/facebook.png" } }) } + + it "outputs the image" do + expected = %r!! + expect(output).to match(expected) + end + end + + # Ensuring the facebook image takes priority for OG tags, and Default for JSON + context "when given a facebook image (with dimensions) and a default image (with different dimensions)" do + let(:meta) do + { + "image" => { + "facebook" => { "path" => "/img/facebook.png", "height" => 1, "width" => 2 }, + "default" => { "path" => "/img/default.png", "height" => 3, "width" => 4 }, + }, + } + end + let(:page) { make_page(meta) } + + it "outputs the facebook image with its dimensions" do + expected = %r!! + expect(output).to match(expected) + expected = %r!! + expect(output).to match(expected) + end + + it "outputs the default image JSON object with dimensions" do + expect(json_data["image"]["url"]).to eql("http://example.invalid/img/default.png") + expect(json_data["image"]["height"]).to eql(3) + expect(json_data["image"]["width"]).to eql(4) + end + end + + # Making sure the facebook image does not inherit the default image dimensions + context "when given a facebook image without dimensions and a default image with dimensions" do + let(:meta) do + { + "image" => { + "facebook" => { "path" => "/img/facebook.png" }, + "default" => { "path" => "/img/default.png", "height" => 3, "width" => 4 }, + }, + } + end + let(:page) { make_page(meta) } + + it "outputs the facebook image without dimensions" do + expected = %r!! + expect(output).not_to match(expected) + expected = %r!! + expect(output).not_to match(expected) + end + + it "outputs the default image JSON object with dimensions" do + expect(json_data["image"]["url"]).to eql("http://example.invalid/img/default.png") + expect(json_data["image"]["height"]).to eql(3) + expect(json_data["image"]["width"]).to eql(4) + end + end + context "when given a twitter image" do let(:page) { make_page("image" => { "twitter" => "/img/twitter.png" }) } @@ -167,17 +269,16 @@ describe Jekyll::SeoTag do end end - context "when given the image height and width" do - let(:page) { make_page("image" => { "facebook" => { "path" => "/img/foo.png", "height" => 1, "width" => 2 } }) } + context "when given a twitter image as a path" do + let(:page) { make_page("image" => { "twitter" => { "path" => "/img/twitter.png" } }) } it "outputs the image" do - expected = %r!! - expect(output).to match(expected) - expected = %r!! + expected = %r!! expect(output).to match(expected) end end + # A legacy test for an old implementation of facebook height and width context "when given the image height and width (legacy)" do let(:page) { make_page("image" => { "facebook" => "/img/foo.png", "height" => 1, "width" => 2 }) } @@ -199,30 +300,18 @@ describe Jekyll::SeoTag do end context "with absolute site.logo" do - let(:site) { make_site("logo" => "http://cdn.example.invalid/logo.png", "url" => "http://example.invalid") } + let(:site) { make_site("logo" => "http://cdn.example.invalid/logo.png", "url" => "http://example.invalid", "author" => "Mr. Foo") } it "outputs the logo" do expect(json_data["publisher"]["logo"]["url"]).to eql("http://cdn.example.invalid/logo.png") end - end - context "with image.default.path, image.default.height, and image.default.width" do - let(:meta) do - { - "image" => { "default" => { "path" => "/img/banner.png", "height" => 1, "width" => 2 } }, - "url" => "http://example.invalid", - } - end - let(:page) { make_post(meta) } - - it "outputs the image object with dimensions" do - expect(json_data["image"]["url"]).to eql("http://example.invalid/img/banner.png") - expect(json_data["image"]["height"]).to eql(1) - expect(json_data["image"]["width"]).to eql(2) + it "outputs the author" do + expect(json_data["publisher"]["name"]).to eql("Mr. Foo") end end - context "with page.author" do + context "with page author" do let(:site) { make_site("logo" => "/logo.png", "url" => "http://example.invalid") } let(:page) { make_post("author" => "Mr. Foo") } From 74c2d3dbe70a20d425b98145b370fc83db25fa17 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Sat, 25 Feb 2017 10:23:40 -0500 Subject: [PATCH 24/28] Code deprecated note --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index b3810c7..409da96 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,17 @@ image: Using the image dimensions are optional, but the [Google Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/u/0/) will consider the JSON-LD to have errors with certain types (i.e. BlogPosting) when an image does not have specified dimensions. +#### Deprecated image output + +The older method for setting facebook image dimensions (shown below) is **no longer recommended**. It will continue work as intended, but is no longer the suggested procedure due to the lack of clarity in where these dimensions are assigned. + +```yml +image: + facebook: /img/bad_facebook_example.png + height: 100 + width: 100 +``` + ### Setting a default image You can define a default image using [Front Matter default](https://jekyllrb.com/docs/configuration/#front-matter-defaults), to provide a default Twitter Card or OGP image to all of your posts and pages. From 48ba2852510fa1c398a3f03d94075bd722b8366e Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Mon, 3 Apr 2017 13:36:29 -0400 Subject: [PATCH 25/28] Image changes should be removed --- README.md | 38 +++--------- lib/template.html | 70 ++++++--------------- spec/jekyll_seo_tag_spec.rb | 119 ++---------------------------------- 3 files changed, 29 insertions(+), 198 deletions(-) diff --git a/README.md b/README.md index 166854f..b413a2d 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ The SEO tag will respect any of the following if included in your site's `_confi * `social` - For [specifying social profiles](https://developers.google.com/structured-data/customize/social-profiles). The following properties are available: * `name` - If the user or organization name differs from the site's name * `links` - An array of links to social media profiles. + * `date_modified` - (YYYY-MM-DD hh:mm) A manual override for the `dateModified` field in the JSON-LD output. This field will take **first priority** for the `dateModified` output. This is useful when the file timestamp does not match the true time that the content was modified. + * A user may also install [Last Modified At](https://github.com/gjtorikian/jekyll-last-modified-at) which will offer an alternative way of providing for the `dateModified` field. ```yml social: @@ -185,8 +187,6 @@ The following options can be set for any particular page. While the default opti * `name` - If the name of the thing that the page represents is different from the page title. (i.e.: "Frank's Café" vs "Welcome to Frank's Café") * `type` - The type of things that the page represents. This must be a [Schema.org type](http://schema.org/docs/schemas.html), and will probably usually be something like [`BlogPosting`](http://schema.org/BlogPosting), [`NewsArticle`](http://schema.org/NewsArticle), [`Person`](http://schema.org/Person), [`Organization`](http://schema.org/Organization), etc. * `links` - An array of other URLs that represent the same thing that this page represents. For instance, Jane's bio page might include links to Jane's GitHub and Twitter profiles. - * `date_modified` - (YYYY-MM-DD hh:mm) A manual override for the `dateModified` field in the JSON-LD output. This field will take **first priority** for the `dateModified` output. This is useful when the file timestamp does not match the true time that the content was modified. - * A user may also install [Last Modified At](https://github.com/gjtorikian/jekyll-last-modified-at) which will offer an alternative way of providing for the `dateModified` field. ### Customizing image output @@ -195,41 +195,17 @@ For most users, setting `image: [path-to-image]` on a per-page basis should be e * `path` - The relative path to the image. Same as `image: [path-to-image]` * `twitter` - The relative path to a Twitter-specific image. * `facebook` - The relative path to a Facebook-specific image. -* `height` - The height of the image in pixels. -* `width` - The width of image in pixels. +* `height` - The height of the Facebook (`og:image`) image +* `width` - The width of the Facebook (`og:image`) image You can use any of the above, optional properties, like so: -```yml -image: /img/banner.png -``` - -Or if you have Facebook or Twitter specific images simply use: - ```yml image: - default: - path: /img/banner.png - height: 100 - width: 100 - facebook: - path: /img/facebook.png - height: 90 - width: 90 twitter: /img/twitter.png -``` - -Using the image dimensions are optional, but the [Google Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool/u/0/) will consider the JSON-LD to have errors with certain types (i.e. BlogPosting) when an image does not have specified dimensions. - -#### Deprecated image output - -The older method for setting facebook image dimensions (shown below) is **no longer recommended**. It will continue work as intended, but is no longer the suggested procedure due to the lack of clarity in where these dimensions are assigned. - -```yml -image: - facebook: /img/bad_facebook_example.png - height: 100 - width: 100 + facebook: /img/facebook.png + height: 100 + width: 100 ``` ### Setting a default image diff --git a/lib/template.html b/lib/template.html index 6a129fd..df44a0a 100755 --- a/lib/template.html +++ b/lib/template.html @@ -94,27 +94,11 @@ {% endif %} {% if page.image %} - {% assign seo_page_image_default = page.image.default.path | default: page.image.default | default: page.image.path | default: page.image %} - {% unless seo_page_image_default contains "://" %} - {% assign seo_page_image_default = seo_page_image_default | absolute_url %} + {% assign seo_page_image = page.image.path | default: page.image.facebook | default: page.image %} + {% unless seo_page_image contains "://" %} + {% assign seo_page_image = seo_page_image | absolute_url %} {% endunless %} - {% assign seo_page_image_default = seo_page_image_default | escape %} - {% assign seo_page_image_default_width = page.image.default.width %} - {% assign seo_page_image_default_height = page.image.default.height %} - - {% assign seo_page_image_facebook = page.image.facebook.path | default: page.image.facebook %} - {% unless seo_page_image_facebook contains "://" %} - {% assign seo_page_image_facebook = seo_page_image_facebook | absolute_url %} - {% endunless %} - {% assign seo_page_image_facebook = seo_page_image_facebook | escape %} - {% assign seo_page_image_facebook_width = page.image.facebook.width | default: page.image.width %} - {% assign seo_page_image_facebook_height = page.image.facebook.height | default: page.image.height %} - - {% assign seo_page_image_twitter = page.image.twitter.path | default: page.image.twitter %} - {% unless seo_page_image_twitter contains "://" %} - {% assign seo_page_image_twitter = seo_page_image_twitter | absolute_url %} - {% endunless %} - {% assign seo_page_image_twitter = seo_page_image_twitter | escape %} + {% assign seo_page_image = seo_page_image | escape %} {% endif %} {% if seo_tag.title and seo_title %} @@ -143,27 +127,18 @@ {% endif %} -{% if page.image %} - {% if page.image.facebook %} - {% assign local_seo_page_image = seo_page_image_facebook %} - {% assign local_seo_page_image_height = seo_page_image_facebook_height %} - {% assign local_seo_page_image_width = seo_page_image_facebook_width %} - {% else %} - {% assign local_seo_page_image = seo_page_image_default %} - {% assign local_seo_page_image_height = seo_page_image_default_height %} - {% assign local_seo_page_image_width = seo_page_image_default_width %} +{% if seo_page_image %} + + {% if page.image.height %} + {% endif %} - - {% if local_seo_page_image_height %} - - {% endif %} - {% if local_seo_page_image_width %} - + {% if page.image.width %} + {% endif %} {% endif %} {% if page.image.twitter %} - + {% endif %} {% if page.date %} @@ -179,7 +154,7 @@ {% endif %} {% if site.twitter %} - {% if page.image or page.image.twitter %} + {% if seo_page_image or page.image.twitter %} {% else %} @@ -242,22 +217,13 @@ {% if seo_author %} "author": { - "@type": "Person", - "name": {{ seo_author | jsonify }} + "@type": "Person", + "name": {{ seo_author | jsonify }} }, {% endif %} -{% if seo_page_image_default %} - {% if seo_page_image_default_height && seo_page_image_default_width %} - "image": { - "@type": "ImageObject", - "url": {{ seo_page_image_default | jsonify }}, - "height": {{ seo_page_image_default_height | jsonify }}, - "width": {{ seo_page_image_default_width | jsonify }} - }, - {% else %} - "image": {{ seo_page_image_default | jsonify }}, - {% endif %} +{% if seo_page_image %} + "image": {{ seo_page_image | jsonify }}, {% endif %} {% if page.date %} @@ -287,8 +253,8 @@ {% if seo_type == "BlogPosting" or seo_type == "CreativeWork"%} "mainEntityOfPage": { - "@type": "WebPage", - "@id": {{ page.url | replace:'/index.html','/' | absolute_url | jsonify }} + "@type": "WebPage", + "@id": {{ page.url | replace:'/index.html','/' | absolute_url | jsonify }} }, {% endif %} diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 9d26732..7ba257b 100755 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -188,7 +188,7 @@ describe Jekyll::SeoTag do end context "with page.image as an object" do - context "when given 'image' with a path" do + context "when given a path" do let(:page) { make_page("image" => { "path" => "/img/foo.png" }) } it "outputs the image" do @@ -197,47 +197,6 @@ describe Jekyll::SeoTag do end end - context "when given a default image" do - let(:page) { make_page("image" => { "default" => "/img/default.png" }) } - - it "outputs the image" do - expected = %r!! - expect(output).to match(expected) - end - - it "outputs the default image JSON item" do - expect(json_data["image"]).to eql("http://example.invalid/img/default.png") - end - end - - context "when given a default image as a path" do - let(:page) { make_page("image" => { "default" => { "path" => "/img/default.png" } }) } - - it "outputs the image" do - expected = %r!! - expect(output).to match(expected) - end - - it "outputs the default image JSON item" do - expect(json_data["image"]).to eql("http://example.invalid/img/default.png") - end - end - - context "when given a default image with dimensions" do - let(:page) { make_page("image" => { "default" => { "path" => "/img/default.png", "height" => 1, "width" => 2 } }) } - - it "outputs the image" do - expected = %r!! - expect(output).to match(expected) - end - - it "outputs the default image JSON object with dimensions" do - expect(json_data["image"]["url"]).to eql("http://example.invalid/img/default.png") - expect(json_data["image"]["height"]).to eql(1) - expect(json_data["image"]["width"]).to eql(2) - end - end - context "when given a facebook image" do let(:page) { make_page("image" => { "facebook" => "/img/facebook.png" }) } @@ -247,67 +206,6 @@ describe Jekyll::SeoTag do end end - context "when given a facebook image as a path" do - let(:page) { make_page("image" => { "facebook" => { "path" => "/img/facebook.png" } }) } - - it "outputs the image" do - expected = %r!! - expect(output).to match(expected) - end - end - - # Ensuring the facebook image takes priority for OG tags, and Default for JSON - context "when given a facebook image (with dimensions) and a default image (with different dimensions)" do - let(:meta) do - { - "image" => { - "facebook" => { "path" => "/img/facebook.png", "height" => 1, "width" => 2 }, - "default" => { "path" => "/img/default.png", "height" => 3, "width" => 4 }, - }, - } - end - let(:page) { make_page(meta) } - - it "outputs the facebook image with its dimensions" do - expected = %r!! - expect(output).to match(expected) - expected = %r!! - expect(output).to match(expected) - end - - it "outputs the default image JSON object with dimensions" do - expect(json_data["image"]["url"]).to eql("http://example.invalid/img/default.png") - expect(json_data["image"]["height"]).to eql(3) - expect(json_data["image"]["width"]).to eql(4) - end - end - - # Making sure the facebook image does not inherit the default image dimensions - context "when given a facebook image without dimensions and a default image with dimensions" do - let(:meta) do - { - "image" => { - "facebook" => { "path" => "/img/facebook.png" }, - "default" => { "path" => "/img/default.png", "height" => 3, "width" => 4 }, - }, - } - end - let(:page) { make_page(meta) } - - it "outputs the facebook image without dimensions" do - expected = %r!! - expect(output).not_to match(expected) - expected = %r!! - expect(output).not_to match(expected) - end - - it "outputs the default image JSON object with dimensions" do - expect(json_data["image"]["url"]).to eql("http://example.invalid/img/default.png") - expect(json_data["image"]["height"]).to eql(3) - expect(json_data["image"]["width"]).to eql(4) - end - end - context "when given a twitter image" do let(:page) { make_page("image" => { "twitter" => "/img/twitter.png" }) } @@ -317,18 +215,9 @@ describe Jekyll::SeoTag do end end - context "when given a twitter image as a path" do - let(:page) { make_page("image" => { "twitter" => { "path" => "/img/twitter.png" } }) } - - it "outputs the image" do - expected = %r!! - expect(output).to match(expected) - end - end - - # A legacy test for an old implementation of facebook height and width - context "when given the image height and width (legacy)" do - let(:page) { make_page("image" => { "facebook" => "/img/foo.png", "height" => 1, "width" => 2 }) } + context "when given the image height and width" do + let(:image) { { "facebook" => "/img/foo.png", "height" => 1, "width" => 2 } } + let(:page) { make_page("image" => image) } it "outputs the image" do expected = %r!! From bc32658d36afddff99c7544510e0ade4ad3f8835 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Mon, 3 Apr 2017 14:25:29 -0400 Subject: [PATCH 26/28] Clarify documentation --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index cd664f9..dc913d4 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,7 @@ The SEO tag will respect any of the following if included in your site's `_confi * `social` - For [specifying social profiles](https://developers.google.com/structured-data/customize/social-profiles). The following properties are available: * `name` - If the user or organization name differs from the site's name * `links` - An array of links to social media profiles. - * `date_modified` - (YYYY-MM-DD hh:mm) A manual override for the `dateModified` field in the JSON-LD output. This field will take **first priority** for the `dateModified` output. This is useful when the file timestamp does not match the true time that the content was modified. - * A user may also install [Last Modified At](https://github.com/gjtorikian/jekyll-last-modified-at) which will offer an alternative way of providing for the `dateModified` field. + * `date_modified` - Manually specify the `dateModified` field in the JSON-LD output to override Jekyll's own `dateModified`. This field will take **first priority** for the `dateModified` JSON-LD output. This is useful when the file timestamp does not match the true time that the content was modified. A user may also install [Last Modified At](https://github.com/gjtorikian/jekyll-last-modified-at) which will offer an alternative way of providing for the `dateModified` field. ```yml social: From 6009b495ea6523ef6fe12cfb2dda8ea2044e47f8 Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Mon, 3 Apr 2017 15:13:43 -0400 Subject: [PATCH 27/28] Separate tests. --- spec/jekyll_seo_tag_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/jekyll_seo_tag_spec.rb b/spec/jekyll_seo_tag_spec.rb index 115b18d..d504617 100755 --- a/spec/jekyll_seo_tag_spec.rb +++ b/spec/jekyll_seo_tag_spec.rb @@ -237,11 +237,15 @@ describe Jekyll::SeoTag do end context "with absolute site.logo" do - let(:site) { make_site("logo" => "http://cdn.example.invalid/logo.png", "url" => "http://example.invalid", "author" => "Mr. Foo") } + let(:site) { make_site("logo" => "http://cdn.example.invalid/logo.png", "url" => "http://example.invalid") } it "outputs the logo" do expect(json_data["publisher"]["logo"]["url"]).to eql("http://cdn.example.invalid/logo.png") end + end + + context "with site.logo and page.author" do + let(:site) { make_site("logo" => "http://cdn.example.invalid/logo.png", "url" => "http://example.invalid", "author" => "Mr. Foo") } it "outputs the author" do expect(json_data["publisher"]["name"]).to eql("Mr. Foo") From 61d4c91f3ec3ff753a6e26cbedff861e9523499d Mon Sep 17 00:00:00 2001 From: Kyle Niewiada Date: Tue, 4 Apr 2017 13:15:12 -0400 Subject: [PATCH 28/28] Remove date default handle --- lib/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/template.html b/lib/template.html index cdb58b9..e3375c2 100755 --- a/lib/template.html +++ b/lib/template.html @@ -66,7 +66,7 @@ {% endif %} {% if page.date_modified or page.last_modified_at or page.date %} - {% assign seo_date_modified = page.seo.date_modified | default: page.last_modified_at | default: page.date %} + {% assign seo_date_modified = page.seo.date_modified | default: page.last_modified_at %} {% endif %} {% if page.seo and page.seo.type %}