diff --git a/hugolib/author.go b/hugolib/author.go new file mode 100644 index 000000000..83803b290 --- /dev/null +++ b/hugolib/author.go @@ -0,0 +1,49 @@ +// Copyright © 2013 Steve Francia . +// +// Licensed under the Simple Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://opensource.org/licenses/Simple-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hugolib + +/* + * An author list is a list of all authors and their metadata + */ +type AuthorList map[string]Author + +/* + * An author contains details about the author of a page + */ +type Author struct { + GivenName string + FamilyName string + DisplayName string + Thumbnail string + Image string + ShortBio string + LongBio string + Email string + Social AuthorSocial +} + +// AuthorSocial is a place to put social details per author. These are the +// standard keys that themes will expect to have available, but can be +// expanded to any others on a per site basis +// - website +// - github +// - facebook +// - twitter +// - googleplus +// - pinterest +// - instagram +// - youtube +// - linkedin +// - skype +type AuthorSocial map[string]string diff --git a/hugolib/media.go b/hugolib/media.go new file mode 100644 index 000000000..489c998d1 --- /dev/null +++ b/hugolib/media.go @@ -0,0 +1,60 @@ +// Copyright © 2013 Steve Francia . +// +// Licensed under the Simple Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://opensource.org/licenses/Simple-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hugolib + +// An image contains metadata for images + image sitemaps +// https://support.google.com/webmasters/answer/178636?hl=en +type Image struct { + + // The URL of the image. In some cases, the image URL may not be on the + // same domain as your main site. This is fine, as long as both domains + // are verified in Webmaster Tools. If, for example, you use a + // content delivery network (CDN) to host your images, make sure that the + // hosting site is verified in Webmaster Tools OR that you submit your + // sitemap using robots.txt. In addition, make sure that your robots.txt + // file doesn’t disallow the crawling of any content you want indexed. + URL string + Title string + Caption string + AltText string + + // The geographic location of the image. For example, + // Limerick, Ireland. + GeoLocation string + + // A URL to the license of the image. + License string +} + +// An video contains metadata for videos + video sitemaps +// https://support.google.com/webmasters/answer/80471?hl=en +type Video struct { + ThumbnailLoc string + Title string + Description string + ContentLoc string + PlayerLoc string + Duration string + ExpirationDate string + Rating string + ViewCount string + PublicationDate string + FamilyFriendly string + Restriction string + GalleryLoc string + Price string + RequiresSubscription string + Uploader string + Live string +} diff --git a/hugolib/page.go b/hugolib/page.go index 7bf9e7fec..7eda69589 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -40,7 +40,8 @@ type Page struct { Summary template.HTML Aliases []string Status string - Images []string + Images []Image + Videos []Video TableOfContents template.HTML Truncated bool Draft bool @@ -68,7 +69,6 @@ type Source struct { Content []byte source.File } - type PageMeta struct { WordCount int FuzzyWordCount int @@ -98,6 +98,32 @@ func (p *Page) IsPage() bool { return true } +func (p *Page) Author() Author { + authors := p.Authors() + + for _, author := range authors { + return author + } + return Author{} +} + +func (p *Page) Authors() AuthorList { + authorKeys, ok := p.Params["authors"] + authors := authorKeys.([]string) + if !ok || len(authors) < 1 || len(p.Site.Authors) < 1 { + return AuthorList{} + } + + al := make(AuthorList) + for _, author := range authors { + a, ok := p.Site.Authors[author] + if ok { + al[author] = a + } + } + return al +} + func (p *Page) UniqueId() string { return p.Source.UniqueId() } diff --git a/hugolib/site.go b/hugolib/site.go index 75f34386c..e2c62a4f5 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -88,6 +88,8 @@ type targetList struct { type SiteInfo struct { BaseUrl template.URL Taxonomies TaxonomyList + Authors AuthorList + Social SiteSocial Indexes *TaxonomyList // legacy, should be identical to Taxonomies Sections Taxonomy Pages *Pages @@ -105,6 +107,21 @@ type SiteInfo struct { BuildDrafts bool } +// SiteSocial is a place to put social details on a site level. These are the +// standard keys that themes will expect to have available, but can be +// expanded to any others on a per site basis +// github +// facebook +// facebook_admin +// twitter +// twitter_domain +// googleplus +// pinterest +// instagram +// youtube +// linkedin +type SiteSocial map[string]string + func (s *SiteInfo) GetParam(key string) interface{} { v := s.Params[strings.ToLower(key)] diff --git a/tpl/template_embedded.go b/tpl/template_embedded.go index 85015c50e..eeab7ba5c 100644 --- a/tpl/template_embedded.go +++ b/tpl/template_embedded.go @@ -96,4 +96,83 @@ func (t *GoHtmlTemplate) EmbedTemplates() { comments powered by Disqus{{end}}`) + // Add SEO & Social metadata + t.AddInternalTemplate("_default", "opengraph.html", ` + + + +{{ with .Params.images }}{{ range first 6 . }} + +{{ end }}{{ end }} + +{{ with .Params.audio }} +{{ end }}{{ with .Params.locale }} +{{ end }}{{ with .Site.Params.title }} +{{ end }}{{ with .Params.videos }} +{{ range .Params.videos }} + +{{ end }} + + +{{ $permalink := .Permalink }} +{{ $siteSeries := .Site.Taxonomies.series }}{{ with .Params.series }} +{{ range $name := . }} + {{ $series := index $siteSeries $name }} + {{ range $page := first 6 $series.Pages }} + {{ if ne $page.Permalink $permalink }}{{ end }} + {{ end }} +{{ end }}{{ end }} + +{{ if .IsPage }} +{{ range .Site.Authors }}{{ with .Social.facebook }} +{{ end }}{{ with .Site.Social.facebook }} +{{ end }} + + + +{{ with .Params.tags }}{{ range first 6 . }} + {{ end }}{{ end }} +{{ end }} + + +{{ with .Site.Social.facebook_admin }}{{ end }}`) + + t.AddInternalTemplate("_default", "twitter_cards.html", `{{ if .IsPage }} +{{ with .Params.images }} + + + +{{ else }} + +{{ end }} + + + + +{{ with .Site.Social.twitter }}{{ end }} +{{ with .Site.Social.twitter_domain }}{{ end }} +{{ range .Site.Authors }} + {{ with .twitter }}{{ end }} +{{ end }}{{ end }}`) + + t.AddInternalTemplate("_default", "google_news.html", `{{ if .IsPage }}{{ with .Params.news_keywords }} + +{{ end }}{{ end }}`) + + t.AddInternalTemplate("_default", "schema.html", `{{ with .Site.Social.GooglePlus }}{{ end }} + + + +{{if .IsPage}} + + + +{{ with .Params.images }}{{ range first 6 . }} + +{{ end }}{{ end }} + + + +{{ end }}{{ end }}`) + }