Packages
phoenix_kit
1.7.66
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
Current section
Files
lib/modules/sitemap/sources/source.ex
defmodule PhoenixKit.Modules.Sitemap.Sources.Source do
@moduledoc """
Behaviour for sitemap data sources.
Each source module must implement this behaviour to provide URL entries
for sitemap generation.
## Required Callbacks
- `source_name/0` - Unique atom identifier for the source
- `enabled?/0` - Whether this source is active
- `collect/1` - Collect URL entries from this source
## Optional Callbacks
- `sitemap_filename/0` - Custom filename for the module's sitemap file
- `sub_sitemaps/1` - Split into multiple sub-sitemap files (e.g., per-blog, per-entity-type)
"""
require Logger
alias PhoenixKit.Modules.Sitemap.UrlEntry
@doc """
Returns the unique name/identifier for this source.
"""
@callback source_name() :: atom()
@doc """
Checks if this source is enabled and should be included in sitemap.
"""
@callback enabled?() :: boolean()
@doc """
Collects all URL entries from this source.
"""
@callback collect(opts :: keyword()) :: [UrlEntry.t()]
@doc """
Returns the base filename for this source's sitemap file (without .xml extension).
Default: `"sitemap-\#{source_name()}"`
"""
@callback sitemap_filename() :: String.t()
@doc """
Returns a list of sub-sitemaps for sources that produce multiple files.
Return `nil` for a single file, or a list of `{group_name, entries}` tuples
for per-group splitting (e.g., per-blog, per-entity-type).
Each group will be saved as `sitemap-{source}-{group_name}.xml`.
"""
@callback sub_sitemaps(opts :: keyword()) :: [{String.t(), [UrlEntry.t()]}] | nil
@optional_callbacks [sitemap_filename: 0, sub_sitemaps: 1]
@doc """
Helper function to check if a source module is valid.
"""
@spec valid_source?(module()) :: boolean()
def valid_source?(module) when is_atom(module) do
case Code.ensure_loaded(module) do
{:module, _} ->
function_exported?(module, :source_name, 0) and
function_exported?(module, :enabled?, 0) and
function_exported?(module, :collect, 1)
{:error, _} ->
false
end
end
def valid_source?(_), do: false
@doc """
Returns the sitemap filename for a source module.
Calls the optional `sitemap_filename/0` callback if implemented,
otherwise returns `"sitemap-\#{source_name()}"`.
"""
@spec get_sitemap_filename(module()) :: String.t()
def get_sitemap_filename(source_module) do
if function_exported?(source_module, :sitemap_filename, 0) do
source_module.sitemap_filename()
else
"sitemap-#{source_module.source_name()}"
end
end
@doc """
Returns sub-sitemaps for a source module, or nil if not implemented.
"""
@spec get_sub_sitemaps(module(), keyword()) :: [{String.t(), [UrlEntry.t()]}] | nil
def get_sub_sitemaps(source_module, opts \\ []) do
if function_exported?(source_module, :sub_sitemaps, 1) do
source_module.sub_sitemaps(opts)
else
nil
end
end
@doc """
Safely collects entries from a source, handling errors gracefully.
"""
@spec safe_collect(module(), keyword()) :: [UrlEntry.t()]
def safe_collect(source_module, opts \\ []) do
force = Keyword.get(opts, :force, false)
if valid_source?(source_module) and (force or source_module.enabled?()) do
source_module.collect(opts)
else
[]
end
rescue
error ->
Logger.warning(
"Sitemap source #{inspect(source_module)} failed to collect: #{inspect(error)}"
)
[]
end
end