Packages

phoenix_kit

1.7.0
1.7.209 1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit sitemap sources static.ex
Raw

lib/phoenix_kit/sitemap/sources/static.ex

defmodule PhoenixKit.Sitemap.Sources.Static do
@moduledoc """
Static routes source for sitemap generation.
Collects configurable static routes for the sitemap. Routes are configured
through Settings and resolved via RouteResolver - NO hardcoded fallbacks.
## Settings
- `sitemap_static_routes` - JSON array of route configurations
- `sitemap_custom_urls` - JSON array of custom URL entries
## Route Configuration Format
Each route in `sitemap_static_routes` can have:
%{
"plug" => "PhoenixKitWeb.Users.Registration", # Module to resolve via RouteResolver
"path" => "/custom/path", # OR explicit path (overrides plug)
"priority" => 0.7, # Sitemap priority (0.0-1.0)
"changefreq" => "monthly", # Change frequency
"title" => "Register", # Display title
"category" => "Authentication", # Category for grouping
"prefixed" => true # Use PhoenixKit URL prefix
}
## Custom URL Format
Each entry in `sitemap_custom_urls`:
%{
"path" => "/about-us",
"priority" => 0.8,
"changefreq" => "monthly",
"title" => "About Us",
"category" => "Company"
}
## Default Configuration
By default, includes:
- Homepage (/) - Priority: 0.9, daily
- Registration page - Priority: 0.7, monthly (if route exists)
- Login page - Priority: 0.7, monthly (if route exists)
## No Hardcoded Fallbacks
If RouteResolver cannot find a route and no explicit path is configured,
the route is skipped. This ensures sitemap only contains valid URLs.
"""
@behaviour PhoenixKit.Sitemap.Sources.Source
alias PhoenixKit.Settings
alias PhoenixKit.Sitemap.RouteResolver
alias PhoenixKit.Sitemap.UrlEntry
alias PhoenixKit.Utils.Routes
@default_static_routes [
%{
"path" => "/",
"priority" => 0.9,
"changefreq" => "daily",
"title" => "Home",
"category" => "Main",
"prefixed" => false
},
%{
"plug" => "PhoenixKitWeb.Users.Registration",
"priority" => 0.7,
"changefreq" => "monthly",
"title" => "Register",
"category" => "Authentication",
"prefixed" => true
},
%{
"plug" => "PhoenixKitWeb.Users.Login",
"priority" => 0.7,
"changefreq" => "monthly",
"title" => "Login",
"category" => "Authentication",
"prefixed" => true
}
]
@impl true
def source_name, do: :static
@impl true
def enabled?, do: true
@impl true
def collect(opts \\ []) do
base_url = Keyword.get(opts, :base_url)
static_entries = collect_static_routes(base_url)
custom_entries = collect_custom_urls(base_url)
(static_entries ++ custom_entries)
|> Enum.reject(&is_nil/1)
rescue
error ->
require Logger
Logger.warning("Static routes sitemap source failed to collect: #{inspect(error)}")
[]
end
defp collect_static_routes(base_url) do
get_static_routes_config()
|> Enum.map(&build_static_entry(&1, base_url))
end
defp collect_custom_urls(base_url) do
get_custom_urls_config()
|> Enum.map(&build_custom_entry(&1, base_url))
end
defp get_static_routes_config do
case Settings.get_setting("sitemap_static_routes") do
nil ->
@default_static_routes
json_string when is_binary(json_string) ->
case Jason.decode(json_string) do
{:ok, routes} when is_list(routes) -> routes
_ -> @default_static_routes
end
routes when is_list(routes) ->
routes
_ ->
@default_static_routes
end
end
defp get_custom_urls_config do
case Settings.get_setting("sitemap_custom_urls") do
nil ->
[]
json_string when is_binary(json_string) ->
case Jason.decode(json_string) do
{:ok, urls} when is_list(urls) -> urls
_ -> []
end
urls when is_list(urls) ->
urls
_ ->
[]
end
end
defp build_static_entry(config, base_url) do
path = resolve_path(config)
if path do
prefixed = Map.get(config, "prefixed", false)
url = build_url(path, base_url, prefixed)
UrlEntry.new(%{
loc: url,
lastmod: nil,
changefreq: Map.get(config, "changefreq", "weekly"),
priority: Map.get(config, "priority", 0.5),
title: Map.get(config, "title", path),
category: Map.get(config, "category", "Static"),
source: :static
})
else
# Route not found and no explicit path - skip
nil
end
end
defp build_custom_entry(config, base_url) do
path = Map.get(config, "path")
if path do
url = build_url(path, base_url, false)
UrlEntry.new(%{
loc: url,
lastmod: nil,
changefreq: Map.get(config, "changefreq", "weekly"),
priority: Map.get(config, "priority", 0.5),
title: Map.get(config, "title", path),
category: Map.get(config, "category", "Custom"),
source: :static
})
else
nil
end
end
# Resolve path from config: explicit path OR via RouteResolver
defp resolve_path(%{"path" => path}) when is_binary(path) and path != "" do
path
end
defp resolve_path(%{"plug" => plug_string}) when is_binary(plug_string) do
# Try to resolve module via RouteResolver
module = String.to_existing_atom("Elixir." <> plug_string)
RouteResolver.find_route(module)
rescue
# Module doesn't exist - return nil (no hardcoded fallback!)
_ -> nil
end
defp resolve_path(_), do: nil
# Build URL with or without PhoenixKit prefix
defp build_url(path, base_url, true = _prefixed) do
build_prefixed_url(path, base_url)
end
defp build_url(path, base_url, false = _prefixed) do
build_public_url(path, base_url)
end
# Build URL for public pages (no PhoenixKit prefix)
defp build_public_url(path, nil) do
base = Settings.get_setting("site_url", "")
normalized_base = String.trim_trailing(base, "/")
"#{normalized_base}#{path}"
end
defp build_public_url(path, base_url) when is_binary(base_url) do
normalized_base = String.trim_trailing(base_url, "/")
"#{normalized_base}#{path}"
end
# Build URL for PhoenixKit pages (with prefix)
defp build_prefixed_url(path, nil) do
Routes.url(path)
end
defp build_prefixed_url(path, base_url) when is_binary(base_url) do
normalized_base = String.trim_trailing(base_url, "/")
full_path = Routes.path(path)
"#{normalized_base}#{full_path}"
end
end