Current section

Files

Jump to
tableau lib tableau extensions sitemap_extension.ex
Raw

lib/tableau/extensions/sitemap_extension.ex

defmodule Tableau.SitemapExtension do
@moduledoc """
Generate a sitemap.xml for your site, for improved search-engine indexing.
## Configuration
- `:enabled` - boolean - Extension is active or not.
### Example
```elixir
config :tableau, Tableau.SitemapExtension,
enabled: true,
```
## Custom attributes
Any page may add attributes to its sitemap `<url>` entry by adding a `sitemap` entry, with a map of elements to add
### Frontmatter
```yaml
title: "Some Page"
sitemap:
priority: 0.8
changefreq: hourly
```
### Tableau.Page
```elixir
defmodule MySite.AboutPage do
use Tableau.Page,
layout: MySite.RootLayout,
permalink: "/about",
sitemap: %{priority: 0.8, changefreq: "monthly"}
# ...
end
```
Generated sitemap is stored in the root of your site, at /sitemap.xml.
For more information about sitemaps, see <https://www.sitemaps.org>.
"""
use Tableau.Extension, key: :sitemap, priority: 300
require Logger
@impl Tableau.Extension
def post_write(%{site: %{config: %{url: root, out_dir: out_dir}, pages: pages}} = token) do
urls =
for page <- pages, uniq: true do
loc =
["<loc>", root |> URI.merge(page.permalink) |> URI.to_string(), "</loc>"]
|> prepend_lastmod(page)
|> prepend_sitemap_assigns(page)
["<url>", loc, "</url>"]
end
xml = [
~s|<?xml version="1.0" encoding="UTF-8"?>|,
"<urlset",
" ",
~s|xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"|,
" ",
~s|xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"|,
" ",
~s|xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"|,
">",
urls,
"</urlset>"
]
File.mkdir_p!(out_dir)
File.write!("#{out_dir}/sitemap.xml", xml)
{:ok, token}
rescue
e ->
Logger.error(Exception.format(:error, e, __STACKTRACE__))
{:error, :fail}
end
defp prepend_lastmod(body, %{date: date}) do
["<lastmod>", DateTime.to_iso8601(date), "</lastmod>" | body]
end
defp prepend_lastmod(body, _), do: body
defp prepend_sitemap_assigns(body, %{sitemap: sitemap_data}) do
sitemap_data = Enum.sort(sitemap_data)
for {key, value} <- sitemap_data, reduce: body do
acc -> ["<#{key}>", "#{value}", "</#{key}>" | acc]
end
end
defp prepend_sitemap_assigns(body, _), do: body
end