Skip to content

Commit f9a97a3

Browse files
paradox460mhanberg
andauthored
feat: sitemap extension (#45)
Co-authored-by: Mitchell Hanberg <[email protected]>
1 parent 8a1bc73 commit f9a97a3

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
defmodule Tableau.SitemapExtension.Config do
2+
@moduledoc false
3+
4+
def new(input), do: {:ok, input}
5+
end
6+
7+
defmodule Tableau.SitemapExtension do
8+
@moduledoc """
9+
Generate a sitemap.xml for your site, for improved search-engine indexing.
10+
11+
## Configuration
12+
13+
- `:enabled` - boolean - Extension is active or not.
14+
15+
### Example
16+
17+
```elixir
18+
config :tableau, Tableau.SitemapExtension,
19+
enabled: true,
20+
```
21+
22+
## Custom attributes
23+
24+
Any page may add attributes to its sitemap `<url>` entry by adding a `sitemap` entry, with a map of elements to add
25+
26+
### Frontmatter
27+
28+
```yaml
29+
title: "Some Page"
30+
sitemap:
31+
priority: 0.8
32+
changefreq: hourly
33+
```
34+
35+
### `Tableau.Page`
36+
37+
```elixir
38+
defmodule MySite.AboutPage do
39+
use Tableau.Page,
40+
layout: MySite.RootLayout,
41+
permalink: "/about",
42+
sitemap: %{priority: 0.8, changefreq: "monthly"}
43+
44+
# ...
45+
end
46+
```
47+
48+
Generated sitemap is stored in the root of your site, at /sitemap.xml.
49+
50+
For more information about sitemaps, see <https://www.sitemaps.org>.
51+
"""
52+
53+
use Tableau.Extension, key: :sitemap, type: :post_write, priority: 300
54+
55+
def run(%{site: %{config: %{url: root}, pages: pages}} = token) do
56+
urls =
57+
for page <- pages, uniq: true do
58+
loc =
59+
[{:loc, nil, URI.merge(root, page.permalink)}]
60+
|> prepend_lastmod(page)
61+
|> prepend_sitemap_assigns(page)
62+
63+
{:url, nil, loc}
64+
end
65+
66+
xml =
67+
XmlBuilder.document(
68+
:urlset,
69+
[
70+
xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9",
71+
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
72+
"xsi:schemaLocation":
73+
"http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
74+
],
75+
urls
76+
)
77+
78+
File.mkdir_p!("_site")
79+
File.write!("_site/sitemap.xml", XmlBuilder.generate_iodata(xml))
80+
81+
{:ok, token}
82+
end
83+
84+
defp prepend_lastmod(body, %{date: date}) do
85+
[{:lastmod, nil, DateTime.to_iso8601(date)} | body]
86+
end
87+
88+
defp prepend_lastmod(body, _), do: body
89+
90+
defp prepend_sitemap_assigns(body, %{sitemap: sitemap_data}) do
91+
for {key, value} <- sitemap_data, reduce: body do
92+
acc -> [{key, [], value} | acc]
93+
end
94+
end
95+
96+
defp prepend_sitemap_assigns(body, _), do: body
97+
end

mix.exs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ defmodule Tableau.MixProject do
4444
{:websock_adapter, "~> 0.5"},
4545
{:yaml_elixir, "~> 2.9"},
4646
{:floki, "~> 0.34"},
47+
{:xml_builder, "~> 2.1"},
4748

4849
# dev
4950
{:ex_doc, ">= 0.0.0", only: :dev},

mix.lock

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"web_dev_utils": {:hex, :web_dev_utils, "0.1.0", "0c41285667b4c9944eaa2c3189f22ec3a915c349c4b879b5ae023e8ca0824657", [:mix], [{:file_system, "~> 0.2", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "af82e1723fe76c09d817a9a9baf85160f7ed572cb4af854194d3f7609ae92f10"},
2828
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
2929
"websock_adapter": {:hex, :websock_adapter, "0.5.4", "7af8408e7ed9d56578539594d1ee7d8461e2dd5c3f57b0f2a5352d610ddde757", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d2c238c79c52cbe223fcdae22ca0bb5007a735b9e933870e241fce66afb4f4ab"},
30+
"xml_builder": {:hex, :xml_builder, "2.2.0", "cc5f1eeefcfcde6e90a9b77fb6c490a20bc1b856a7010ce6396f6da9719cbbab", [:mix], [], "hexpm", "9d66d52fb917565d358166a4314078d39ef04d552904de96f8e73f68f64a62c9"},
3031
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
3132
"yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"},
3233
}

0 commit comments

Comments
 (0)