A SEO meta tag generator for Fornax
-
enhance the search engine visibility of Fornax-generated websites with:
- structured data in JSON-LD format
- OpenGraph
<meta>
tags - personalized social media links
-
try to enforce some SEO best practises, e.g. requiring absolute URLs to all content items
-
dotnet tool install fornax -g
-
Change into a project directory and scaffold a new website
fornax new
IMPORTANT
- Provide the root domain of your website:
// loaders/globalloader.fsx
#r "../_lib/Fornax.Core.dll"
type SiteInfo = {
title: string
/// The root domain of your website - must be an absolute URL
baseUrl: string
description: string
}
- Add personal authorship details, e.g.:
// loaders/globalloader.fsx
#r "nuget: Fornax.Seo"
open Fornax.Seo
let loader (projectRoot: string) (siteContent: SiteContents) =
let siteInfo =
{ title = "Sample Fornax blog"
baseUrl = "http://example.com"
description = "Just a simple blog" }
let onTheWeb =
[ "linkedin.com/in/username"
"github.com/username"
"bitbucket.org/username"
"facebook.com/username" ]
let siteAuthor = { Name = "Moi-même"; Email = "info@example.com"; SocialMedia = onTheWeb }
siteContent.Add(siteInfo)
siteContent.Add(siteAuthor)
siteContent
// generators/post.fsx
#r "../_lib/Fornax.Core.dll"
#r "nuget: Fornax.Seo"
#load "layout.fsx"
open Html
open Fornax.Seo
let generate' (ctx: SiteContents) (page: string) =
let siteInfo = ctx.TryGetValue<Globalloader.SiteInfo>()
let siteName = siteInfo |> Option.map (fun si -> si.title)
let tagline = siteInfo |> Option.map (fun si -> si.description) |> Option.defaultValue ""
let siteAuthor = ctx.TryGetValue<ContentCreator>() |> Option.defaultValue ContentCreator.Default
let siteRoot =
siteInfo
|> Option.map (fun si -> si.baseUrl)
|> Option.defaultValue ContentObject.Default.BaseUrl
let post =
ctx.TryGetValues<Postloader.Post>()
|> Option.defaultValue Seq.empty
|> Seq.find (fun p -> p.file = page)
let postMeta =
{ Title = post.title
BaseUrl = siteRoot
Url = post.file.Replace(System.IO.Path.GetExtension post.file, ".html")
Description = tagline
Author = { siteAuthor with Name = defaultArg post.author siteAuthor.Name }
SiteName = siteName
Headline = Some post.summary
ObjectType = Some "Blog"
ContentType = Some "BlogPosting"
OpenGraphType = Some "article"
Locale = Some "en-us"
Published = post.published
Modified = post.modified
Tags = Some post.tags
Meta =
Some [ ("Image", defaultArg post.image $"{siteRoot}/images/avatar.jpg")
("Publisher", defaultArg siteName siteAuthor.Name) ] }
ctx.Add(postMeta)
// . . .
// generators/layout.fsx
#r "../_lib/Fornax.Core.dll"
#r "nuget: Fornax.Seo"
open Html
open Fornax.Seo
// . . .
let layout (ctx: SiteContents) (active: string) (content: HtmlElement seq) =
let siteInfo = ctx.TryGetValue<Globalloader.SiteInfo>()
let siteAuthor = ctx.TryGetValue<ContentCreator>() |> Option.defaultValue ContentCreator.Default
let pageTitle = siteInfo |> Option.map (fun si -> si.title) |> Option.defaultValue ""
let tagline = siteInfo |> Option.map (fun si -> si.description) |> Option.defaultValue ""
let siteRoot =
siteInfo
|> Option.map (fun si -> si.baseUrl)
|> Option.defaultValue ContentObject.Default.BaseUrl
let seoData =
ctx.TryGetValues<ContentObject>()
|> Option.defaultValue Seq.empty
let pageMeta =
seoData
|> Seq.tryFind (fun p -> p.Title.Contains(active))
|> function
| Some info -> info
| _ ->
{ ContentObject.Default with
Title = pageTitle
Description = tagline
BaseUrl = siteRoot
SiteName = Some pageTitle
Headline = Some tagline
Author = siteAuthor }
html [] [
head [] [
meta [ CharSet "utf-8" ]
meta [ Name "viewport"; Content "width=device-width, initial-scale=1" ]
title [] [ !!pageTitle ]
// . . .
yield! seo pageMeta
]
body [] [
// . . .
footer [] [ yield! socialMedia siteAuthor ]
]
]
// . . .
All platforms need a .NET SDK at version 5.0.200 or later
Linux users should consider 5.0.202 the safest minimum version
Checkout the source tree and submodules:
git clone --recursive https://github.com/rdipardo/Fornax.Seo
To run unit tests and build a sample website:
scripts\ci
:: or, to also serve the site at localhost:8080
scripts\ci live
To browse a local copy of the documentation:
scripts\gendocs live
Run tests with:
scripts/ci
# or
scripts/ci live
Browse docs with:
scripts/gendocs live
Distributed under the terms of the Mozilla Public License Version 2.0.