Hugo SEO / Social Partials

I think the idea of building in author as a first class type in Hugo makes sense. If that’s the case then it needs to be defined as a struct with methods. This shouldn’t be flexible. You should have a fixed set of fields. People are welcome to use what they want from it, but we can’t have on calling it “firstName” and another calling it “givenName”.

For me, I see social just as a map. I’m fine with a semi-standard list, but am all for keeping it flexible and flat.

Having it as a map with expected keys is a much better idea, I updated my PR to reflect that for Authors and also added a top level Social map. I’m not quite sure how Site and SiteInfo work throughout the system, so I added them Authors and Social to both.

Social would only need to be in site info. It’s likely authors would also only need to be there, though there could be a case to use it in Site as well.

Alrighty, I removed those from the Site struct. If there’s a reason to add Authors back, I’ll let you make that call.

Unless there are any other strong opinions, I feel like the Author & Social metadata is pretty locked down. What about standardizing media now?

I’ve finally had a chance to look at this. I have a couple of different suggestions for Author/Social metadata.

First, I’m not sure that map[string]string is right for AuthorSocial, but that could probably be (mostly) ameliorated with proper support from themes. I’ll have to think how I’d change cabaret to support this. That said, there is one case where I think that map[string](map[string]string) (if that can be represented cleanly in Go) would be better, and that’s Google+ and Facebook (and similar networks). If I’m presenting my social details in a linked list, I may not want to be listed as some.user.1632, but as my given name. In my own site, I do something like this:

  icon = "twitter"
  site = "Twitter"
  url = ""
  user = "@halostatue"

Now, out of that, icon could be automated based on the key name (and for that, I’ll suggest a different list of names, below); we can probably automate site, but maybe not—that needs to be mapped somewhere, and it needs to be mapped in an I18n-ready way, probably (that list of names). url can be automated based on the value provided, but user…can’t be guaranteed to be automated. I mean, yes, Twitter is always @<username>…but do you want to be +132342512342 if you haven’t claimed your Google+ name?

As a theme author/content producer, I need to have a way to specify that the site name may be different than the display name the user wants to show. That’s why I would prefer AuthorSocial be map[string]interface{} or map[string](map[string]string). This probably also applies to SiteSocial, but I’m not sure how that’s used (I’m still at the top of the code in review).

Now, that list of names I suggest. You put googleplus; I suggest google-plus…because it’s the name of the Font Awesome icon for Google+. (And, with a lot of these, you can also put -square after it for a squared version of the icon.) So, I have a few groups of suggested names:

Large Social Networks & Products

  • facebook, flickr, google-plus, instagram, linkedin, pinterest, qq, renren, skype, spotify, tencent-weibo, tumblr, twitter, vimeo, vine, vk, weibo, weixin, yahoo, youtube

vimeo is mildly problematic because its icon in FA is vimeo-square, and vk is short for vkontakte (the major Russian social network). tencent-weibo is different than weibo (sometimes called Sina Weibo). These are the minimum that we should probably build some support for.

Smaller Social Networks & Products

  • bitbucket, codepen, delicious, deviantart, digg, dropbox, foursquare, github, hacker-news, jsfiddle, lastfm, reddit, slack, slideshare, soundcloud, stack-exchange, stack-overflow, steam, stumbleupon, trello, twitch, xing, yelp

These are ones that we, as developers, are more likely to be interested in. Yes, it’s a bit more than just developers, but these are what I (personally) consider to be second-order networks.

Useful Things Without Icons

  • keybase, newsblur, pinboard, quora, website

At least developer useful, but these also don’t have icons in FA. In particular, I do want keybase to be on my social icons as an author, because that’s where you can find my GPG key, so I specify key as the FA icon for that one. Imperfect, but it works.

More thoughts later as I get further through this.

1 Like

I still think that @spf13’s map[string]string suggestion is the best way to store social data on the site and author level. This is a great list of social networks you’ve got here, and I think they should all be on the recommended key list.

@halostatue You’re right that the theme is going to be in charge of display and everything else related. All this PR is trying to do is to provide a unified location for storing that data, which for most intents and purposes is going to be hard coded into the appropriate places in the theme, probably something like the following:

{{ with .Author }}
  Contact me at:
  Twitter: [@{{ .Social.twitter }}]({{ .Social.twitter }})
  Facebook: [{{ .GivenName }}]({{ .Social.facebook }})
  Google+: [<i class="fa fa-google-plus-square"></i>]({{ .Social "google-plus" }})
{{ end }}

There is very little that users should need other than their ID, which is what the map is storing per author. Any icons, internationalization or other display properties are up to the discretion of the theme developers, not Hugo.

The SiteSocial is just storing links for the business / publisher, for sitewide links to social pages.

1 Like

Would like to offer my little two cents as I’ve been doing SEO for the last 15 years.

There should be a complete separation from the Social bit and the SEO bit which should be limited to fields like

Title, meta description, author (as in meta author just to give some credit, though autorship as now gone) and canonical.

There should be also the necessity to include the alternate tag, just in case a blog post is written in more than a language and you want to support Google crawling and indexation task.

Also, in all this conversation, I didn’t see a mention about the sitemap.xml file that should be autogenerated.

@Andrea_Moro: a sitemap is automatically generated in all cases at this point unless you DisableSitemap in the configuration.

@DerekPerkins: I think that the only thing that I would want, as a theme author, is to make it easy for someone to add a social network and/or icon that I don’t know about. Your model is pretty good, but what if I want to range through .Author.Social (which is what I do now on my site’s The list of social icons in the lower left part of the left panel (top panel if you’re on a small enough screen) at is automatically generated from; the list of contact info in my About/Where is also generated. The more I can make my theme data driven, the more flexible my theme can be for people who aren’t me.

I also think, that if at all possible, we should make it easier for someone to switch themes without having to have their own layouts overrides (one of the reasons that I put an extra.html in most of the partial directories in cabaret, and put most of the rest of the stuff in configuration/presence wrappers).

To illustrate what I mean, I’m going to include my shortcodes/socialsites.html (from my blog) and the cabaret partials/sidebar/social.html.


{{ range }}
    {{ if .user }}{{ .site }} <a href="{{ .url }}">{{ .user }}</a>
    {{ else }}<a href="{{ .url }}">{{ .site }}</a>{{ end }}
{{ end }}

partials/sidebar/social.html from cabaret:

{{ if }}
<div class="social-buttons">
  {{ range }}
    {{ if and (isset . "url") (isset . "icon") }}
    <a href="{{ .url }}"><i class="fa lg fa-{{ .icon }}"></i></a>
    {{ end }}
  {{ end }}
{{ end }}

@halostatue I think it’s pretty standard for a theme / plugin to specifically list which social platforms they support, and in the off chance that someone wanted to support one that isn’t in the pretty extensive list you showed earlier, it would be a pretty quick feature request. You could still range through whatever social keys are set and use the same keys to map to your internal partials / definitions, generating your same lists on your site.

  1. It’s the easiest for people to configure by just adding their username / ID / handle
  2. Every theme is going to have different ways of displaying the data, and that support should live in the theme. I’m not advocating user layout overrides, for the same reasons you mentioned.

I think I know what I would actually want here, and I’m not currently sure how to do it. I almost want to be able to have a config.toml (or something like that) that provides theme configuration for stuff like this, that provides default behaviour and a good example of how to perform extra configuration for something like this. (That way, I can write cabaret to know how to deal with a fairly large set, but make it easy for a user to add another set in the site config.toml).

I need to think about how this would work and propose it a bit more formally. If we have that capability, then I’m pretty OK with this as written for Author and Social. (I’ll look at media soon.)

Does anyone else care to chime in? @spf13 @bjornerik @mohae @michael_henderson

My approach to this is one of iteration. I think if we believe we know how everyone will want to use it now we are mistaken. I think we should take a reasonable step based on what we think is right and then let the community give us feedback and revise.

I’ve had some ideas on where to take the theme system, but am worried about over engineering it.
I’ll ask you all (specifically @halostatue) , what’s the simplest way to accomplish your wants here?

Is the readme sufficient?

Should we consider adding a theme configuration section in both the site’s config file as well as the themes one?

To reply to the general question in this thread. I think the fundamental approach should be one of users providing their ids/urls. Let the theme handle the display however it wants.

I’m OK with the proposal as made, for now. My comments have been based on how I’ve implemented cabaret, which was based on my site, which was based on @natefinch’s site originally.

Beyond that, I am definitely going to explore how themes can have configuration files, too, and make it easy to override from the user configuration, because I think that’s what I need for how I’m doing it. cabaret and my site have three different ways to handle social sites (I use two of them and inherited one from redlounge):

  1. A list of sites in the sidebar, shown as icons, and only for items with icons. On my site, this is my social tags. On a group blog, or a product blog, it should be the group (product, company, etc.), not the author’s. If it’s shown at all. The icons are part of the metadata that I have for social sites.

  2. A list of sites in my About page, no icons. Again, this is probably mostly doable with and another bit which identifies whether the social site renderer should use the site-id/url or the author name.

  3. Social sites for authors of blog posts (good for multi-user blogs). Limited in scope because it’s next to the byline.

What I’m trying to avoid in my theme is making it so that the sites are hardcoded in the templates, but are instead encoded in configuration which is used intelligently by the theme. This is mostly because I want to avoid having to have people do local overrides of templates if they choose to use cabaret (which is not recommended right now, because it’s a bleeding-edge theme).

@Andrea_Moro pointed out the importance of the “alternate” tag if more than a language is present. This reconnects to multilanguages and to it’s discussion:

This thread seems pretty old but I wonder how I should implement this now, since I will relaunch my site soon. Is any of this built in? Or do I just need to manually copy the partial files into my site?

Some of this is bult-in, but not very well documented. @DerekPerkins - feeling obligated?

1 Like

Thanks. I’d love to learn more.

Today I worked on partials especially the head-related ones looking at bepsays repo, the repo, the halostatue cabaret repo and this nozzle repo. So many good references.

Google is supporting json-ld for markup, and it is pretty simple in that it is just json in a script tag, just for the parser side. I like it better that markup with itemprop etc.

Since has various schema such as aboutPage, blogPost etc, I’m hoping to be specific. And it seems like post types are a good candidate for such specific markup. Perhaps a post is under content/post, but has Param type = video, a la Tumblr.

I am aware of how to test for a page using ispage, as opposed to a node, but can someone say, how does one test for a page in a specific section, like the standard /post/?

{{ if eq .Section "post" }}

Or you may want to use Type instead:

{{ if eq .Type "post" }}
1 Like

appreciate that, @bjornerik