feat(pages): improve SEO meta tags for blog posts and landing pages
Add comprehensive Open Graph and Twitter Card meta tags for blog post detail pages. Use blog post title, subtitle, and featured image when available. Add og:url and twitter:title/description tags. Set twitter:card to summary_large_image when images present, otherwise summary. Add twitter:site support from SEO config. Generates canonical page URL from request context (handles http/https based on TLS).
This commit is contained in:
@@ -157,6 +157,13 @@ func setupLandingPageContext(ctx *context.Context, repo *repo_model.Repository,
|
||||
ctx.Data["PageIsPagesLanding"] = true
|
||||
ctx.Data["RepoURL"] = repo.HTMLURL()
|
||||
ctx.Data["LogoURL"] = resolveLogoURL(ctx, repo, config)
|
||||
|
||||
// Build canonical page URL for og:url
|
||||
scheme := "https"
|
||||
if ctx.Req.TLS == nil && strings.HasPrefix(ctx.Req.Host, "localhost") {
|
||||
scheme = "http"
|
||||
}
|
||||
ctx.Data["PageURL"] = scheme + "://" + ctx.Req.Host + ctx.Req.URL.RequestURI()
|
||||
ctx.Data["NumStars"] = repo.NumStars
|
||||
ctx.Data["NumForks"] = repo.NumForks
|
||||
ctx.Data["Year"] = time.Now().Year()
|
||||
|
||||
@@ -3,21 +3,55 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{{if and .PageIsBlogDetail .BlogPost}}
|
||||
<title>{{.BlogPost.Title}} - {{if .Config.Brand.Name}}{{.Config.Brand.Name}}{{else}}{{.Repository.Name}}{{end}}</title>
|
||||
<meta name="description" content="{{if .BlogPost.Subtitle}}{{.BlogPost.Subtitle}}{{else}}{{.Repository.Description}}{{end}}">
|
||||
{{else}}
|
||||
<title>{{if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}} - {{.Repository.Owner.Name}}</title>
|
||||
<meta name="description" content="{{if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}">
|
||||
<meta property="og:title" content="{{if .Config.SEO.Title}}{{.Config.SEO.Title}}{{else if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}">
|
||||
<meta property="og:description" content="{{if .Config.SEO.Description}}{{.Config.SEO.Description}}{{else if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}">
|
||||
<meta property="og:type" content="website">
|
||||
{{if .Config.SEO.UseMediaKitOG}}
|
||||
{{end}}
|
||||
{{if and .PageIsBlogDetail .BlogPost}}
|
||||
<meta property="og:title" content="{{.BlogPost.Title}}">
|
||||
<meta property="og:description" content="{{if .BlogPost.Subtitle}}{{.BlogPost.Subtitle}}{{else if .Config.SEO.Description}}{{.Config.SEO.Description}}{{else}}{{.Repository.Description}}{{end}}">
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:url" content="{{.PageURL}}">
|
||||
<meta name="twitter:title" content="{{.BlogPost.Title}}">
|
||||
<meta name="twitter:description" content="{{if .BlogPost.Subtitle}}{{.BlogPost.Subtitle}}{{else if .Config.SEO.Description}}{{.Config.SEO.Description}}{{else}}{{.Repository.Description}}{{end}}">
|
||||
{{if .BlogPost.FeaturedImage}}
|
||||
<meta property="og:image" content="{{.BlogPost.FeaturedImage.DownloadURL}}">
|
||||
<meta name="twitter:image" content="{{.BlogPost.FeaturedImage.DownloadURL}}">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
{{else if .Config.SEO.UseMediaKitOG}}
|
||||
<meta property="og:image" content="{{AppUrl}}{{.Repository.OwnerName}}/{{.Repository.Name}}/social-preview">
|
||||
<meta name="twitter:image" content="{{AppUrl}}{{.Repository.OwnerName}}/{{.Repository.Name}}/social-preview">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
{{else if .Config.SEO.OGImage}}
|
||||
<meta property="og:image" content="{{.Config.SEO.OGImage}}">
|
||||
<meta name="twitter:image" content="{{.Config.SEO.OGImage}}">
|
||||
{{end}}
|
||||
{{if or .Config.SEO.UseMediaKitOG .Config.SEO.OGImage}}
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
{{else}}
|
||||
<meta name="twitter:card" content="summary">
|
||||
{{end}}
|
||||
{{else}}
|
||||
<meta property="og:title" content="{{if .Config.SEO.Title}}{{.Config.SEO.Title}}{{else if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}">
|
||||
<meta property="og:description" content="{{if .Config.SEO.Description}}{{.Config.SEO.Description}}{{else if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{.PageURL}}">
|
||||
<meta name="twitter:title" content="{{if .Config.SEO.Title}}{{.Config.SEO.Title}}{{else if .Config.Hero.Headline}}{{.Config.Hero.Headline}}{{else}}{{.Repository.Name}}{{end}}">
|
||||
<meta name="twitter:description" content="{{if .Config.SEO.Description}}{{.Config.SEO.Description}}{{else if .Config.Hero.Subheadline}}{{.Config.Hero.Subheadline}}{{else}}{{.Repository.Description}}{{end}}">
|
||||
{{if .Config.SEO.UseMediaKitOG}}
|
||||
<meta property="og:image" content="{{AppUrl}}{{.Repository.OwnerName}}/{{.Repository.Name}}/social-preview">
|
||||
<meta name="twitter:image" content="{{AppUrl}}{{.Repository.OwnerName}}/{{.Repository.Name}}/social-preview">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
{{else if .Config.SEO.OGImage}}
|
||||
<meta property="og:image" content="{{.Config.SEO.OGImage}}">
|
||||
<meta name="twitter:image" content="{{.Config.SEO.OGImage}}">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
{{else}}
|
||||
<meta name="twitter:card" content="summary">
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .Config.SEO.TwitterSite}}<meta name="twitter:site" content="{{.Config.SEO.TwitterSite}}">{{end}}
|
||||
{{if .Config.SEO.Keywords}}<meta name="keywords" content="{{StringUtils.Join .Config.SEO.Keywords ","}}">{{end}}
|
||||
{{if .LangSwitcherEnabled}}{{range .AvailableLanguages}}
|
||||
<link rel="alternate" hreflang="{{.}}" href="?lang={{.}}">{{end}}
|
||||
|
||||
Reference in New Issue
Block a user