How to Generate a Sitemap for Your Phoenix App
You've got your app built with Phoenix Framework now you want to generate a sitemap for it.
Googling one can find ways to generate a sitemap dynamically by creating a route/controller just for that.
However, in this post, I am gonna show you another approach: generating a sitemap via script and serving it statically.
Install sitemap
Add sitemap to your list of dependencies in mix.exs
:
def deps do
[{:sitemap, "~> 1.1"}]
end
Ensure sitemap is started before your application:
def application do
[extra_applications: [:sitemap]]
end
Run mix deps.get
.
For further instructions check their readme.
Create the script
Let's create the script responsible for generating the sitemap:# lib/your_app/sitemap.exs
defmodule YourApp.Sitemap do
alias YourApp.{Repo, Product}
alias YourAppWeb.{Endpoint, Router.Helpers}
use Sitemap, compress: false,
host: "https://#{Application.get_env(:your_app, Endpoint)[:url][:host]}",
files_path: "priv/static/sitemaps/"
def generate do
create do
for product <- Repo.all(Product) do
add Helpers.product_path(Endpoint, :show, product.slug),
lastmod: product.updated_at, changefreq: "daily"
end
ping()
end
end
end
YourApp.Sitemap.generate
I set compress: false
so it's easier to check the outcome, you can change it if you want.
Notice that I am iterating over all products from the database and generating a xml node for each one.
Set host in prod.exs
In order to have the proper host in get_env
above, you need to set it in prod.exs
like:
config :your_app, YourAppWeb.Endpoint,
url: [host: "yourapp.com", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json"
Allow serving of sitemaps
In the script we have files_path: "priv/static/sitemaps/"
, this means the sitemap will be generated inside this directory. We need to tell Phoenix to allow serving this folder in lib/your_app_web/endpoint.ex
:
plug Plug.Static,
at: "/",
from: :your_app,
gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt sitemaps)
Run the script
You can run the script with mix run lib/your_app/sitemap.exs
, but if you want to run it on production, you must set MIX_ENV=prod
. I like to create a make task for it:
# Makefile
generate_sitemap:
MIX_ENV=prod mix run lib/your_app/sitemap.exs
Automate script run
If you are like me and use dokku for running and deploying your application, you can run the make task above every time you make a new deploy by having app.json
like:
{
"scripts": {
"dokku": {
"predeploy": "make generate_sitemap",
"postdeploy": "mix ecto.migrate"
}
}
}
This way, we always generate the sitemap before deploying the newer version.
That's all.