Simple Sitemap in Phoenix Elixir

For this website, we built a sitemap with Phoenix. I wanted to share what we did to make this happen.

Keep in mind, this is really simple and probably the easiest way to get a sitemap up and running. If your site has a ton of pages, I would recommend trying to cache this file as it can get quite large.

If you have done the example tutorial in the Phoenix guides, you should be able to follow this guide exactly.

Let's get started:

First off, let’s add to lib/hello_web/router.ex a new pipeline.

pipeline :xml do
  plug :accepts, ["xml"]
  plug :put_layout, {HelloWeb.LayoutView, :none}
  plug :put_resp_content_type, "application/xml"
end

Looking at this pipeline, we noticed a few things. The line plug :accepts, ["xml"] tells us to only accept requests for XML. We select :none as our layout since the whole page will be defined in our template. We also set our response content type to application/xml. This tells the page to respond with XML.

Now let’s add to our router the path:

scope "sitemap", HelloWeb do
  pipe_through :xml

  get "/", SitemapController, :index
end

We are using the pipeline we created earlier and defining the path to the sitemap controller.

Next, we need to create the controller for our sitemap. It looks like this:

defmodule HelloWeb.SitemapController do
  use HelloWeb, :controller

  alias Hello.CMS

  def index(conn, _params) do
    pages = CMS.list_pages()
    render(conn, "index.xml", pages: pages)
  end
end

We first fetch all the pages using our CMS context and then render index.xml with all the pages set as assigns.

We need to also make a view for our sitemap:

defmodule HelloWeb.SitemapView do
  use HelloWeb, :view
end

For this simple example, we don’t need to add anything to our view.

Lastly, we need to add our /lib/hello_web/templates/sitemap/index.xml.eex:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <%= for page <- @pages do %>
    <url>
      <loc><%= page_url(@conn, :show, page) %></loc>
    </url>
  <% end %>
</urlset>