Sitemaps are very important for SEO reasons. Search engines, such as Google or Bing, can use sitemaps to find information about your website as well as additional content. It doesn't hurt to try and rank higher in search results.

For this walkthough, we'll go through how to generate a sitemap for content that doesn't change often and create a mix task to help.

Generating the Sitemap

For generating a sitemap, we can use sitemap package to help. With sitemap, you can generate sitemaps several types of content, such as articles, images, and video.

In your mix.exs add the sitemap package to your application's dependencies. Set the :runtime key to false for web content that's generated at compile-time.

{:sitemap, "~> 1.1", runtime: false}

Create a new module where you want to define a sitemap and add the relevant URLs that should appear in the sitemap.

defmodule MyAppWeb.Sitemap do
  @moduledoc """
  Defines a generates a sitemap.
  """
  
  use Sitemap,
    compress: false,
    host: "https://coolelixir.app",
    files_path: "priv/static/sitemaps",
    public_path: "sitemaps/"

  alias MyAppWeb.Endpoint
  alias MyAppWeb.Router.Helpers, as: Routes

  def generate do
    create do
      add Routes.page_path(Endpoint, :index), priority: 0.5, changefreq: "hourly"
      add Routes.page_path(Endpoint, :faq), priority: 0.5, changefreq: "hourly"
      add Routes.page_path(Endpoint, :terms), priority: 0.5, changefreq: "hourly"
      add Routes.page_path(Endpoint, :privacy), priority: 0.5, changefreq: "hourly"
      add Routes.session_path(Endpoint, :new), priority: 0.5, changefreq: "hourly"
      add Routes.user_path(Endpoint, :new), priority: 0.5, changefreq: "hourly"
    end
  end

end

Update the endpoint file to allow Plug.Static to serve the new sitemap directory.

defmodule MyAppWeb.Endpoint do
  # ...
  
  plug Plug.Static,
    at: "/", from: :my_app,
    only: ~w(... sitemaps)
end

Creating a Mix Task

We can leverage a mix task to automatically generate the sitemaps. Create a new file lib/mix/tasks/sitemap.ex.

defmodule Mix.Tasks.Sitemap do
  @moduledoc """
  Generates a sitemap.
  """
  
  use Mix.Task

  def run(_) do
    # Don't require a running HTTP server
    Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
    # Don't start any repos
    Application.put_env(:progress_plum, :ecto_repos, [])
    
    # Start the application
    Mix.Task.run "app.start", []
    
    # Start the Sitemap process
    Sitemap.start(nil, nil)
    
    # Generate the sitemap
    MyAppWeb.Sitemap.generate()
  end
end

Now we can generate a sitemap simply by running mix sitemap.

Generating the Sitemap at Build-time

To ensure that our sitemap is always up to date in production, we need to run our new mix task before our code is deployed. Depending on how you deploy, your steps my differ.

If you're using Heroku, execute the mix task after the compile step. Add the following to your elixir_buildpack.config.

hook_post_compile="mix sitemap"

For deploys using mix phx.digest, just make sure to run mix sitemap as the prior step.

Wrap-up

Generating sitemaps for Phoenix applications is straightfoward and can be done with very few lines of code leveraging the sitemap package.