Packages
phoenix_kit
1.7.76
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
Current section
Files
lib/modules/publishing/schemas/publishing_content.ex
defmodule PhoenixKit.Modules.Publishing.PublishingContent do
@moduledoc """
Schema for publishing content — one row per language per version.
Stores one content entry per language per version. Each content
row has its own title, content body, status, and optional URL slug.
## Data JSONB Keys
- `description` - SEO meta description
- `previous_url_slugs` - List of previous URL slugs for 301 redirects
- `featured_image_uuid` - Per-language featured image override
- `seo_title` - Custom SEO title (if different from title)
- `excerpt` - Custom excerpt (if different from auto-generated)
- `custom_css` - Per-language custom CSS
- `updated_by_uuid` - UUID of last editor for this language
"""
use Ecto.Schema
import Ecto.Changeset
alias PhoenixKit.Modules.Publishing
@primary_key {:uuid, UUIDv7, autogenerate: true}
@foreign_key_type UUIDv7
@type t :: %__MODULE__{
uuid: UUIDv7.t() | nil,
version_uuid: UUIDv7.t(),
language: String.t(),
title: String.t(),
content: String.t() | nil,
status: String.t(),
url_slug: String.t() | nil,
data: map(),
inserted_at: DateTime.t() | nil,
updated_at: DateTime.t() | nil
}
schema "phoenix_kit_publishing_contents" do
field :language, :string
field :title, :string
field :content, :string
field :status, :string, default: "draft"
field :url_slug, :string
field :data, :map, default: %{}
belongs_to :version, PhoenixKit.Modules.Publishing.PublishingVersion,
foreign_key: :version_uuid,
references: :uuid,
type: UUIDv7
timestamps(type: :utc_datetime)
end
@doc """
Changeset for creating or updating publishing content.
"""
def changeset(content, attrs) do
content
|> cast(attrs, [:version_uuid, :language, :title, :content, :status, :url_slug, :data],
empty_values: []
)
|> validate_required([:version_uuid, :language, :status])
|> default_if_nil(:title, "")
|> default_if_nil(:content, "")
|> normalize_empty_to_nil(:url_slug)
|> validate_inclusion(:status, Publishing.Constants.content_statuses())
|> validate_length(:language, max: Publishing.Constants.max_language_code_length())
|> validate_length(:title, max: Publishing.Constants.max_title_length())
|> validate_length(:url_slug, max: Publishing.Constants.max_slug_length())
|> unique_constraint([:version_uuid, :language],
name: :idx_publishing_contents_version_language
)
|> foreign_key_constraint(:version_uuid, name: :fk_publishing_contents_version)
end
defp default_if_nil(changeset, field, default) do
if get_field(changeset, field) == nil do
put_change(changeset, field, default)
else
changeset
end
end
defp normalize_empty_to_nil(changeset, field) do
if get_field(changeset, field) == "" do
put_change(changeset, field, nil)
else
changeset
end
end
# Data JSONB accessors
@doc "Returns the SEO description."
def get_description(%__MODULE__{data: data}), do: Map.get(data, "description")
@doc "Returns previous URL slugs for 301 redirects."
def get_previous_url_slugs(%__MODULE__{data: data}),
do: Map.get(data, "previous_url_slugs", [])
@doc "Returns the per-language featured image UUID."
def get_featured_image_uuid(%__MODULE__{data: data}), do: Map.get(data, "featured_image_uuid")
@doc "Returns the custom SEO title."
def get_seo_title(%__MODULE__{data: data}), do: Map.get(data, "seo_title")
@doc "Returns the custom excerpt."
def get_excerpt(%__MODULE__{data: data}), do: Map.get(data, "excerpt")
@doc "Returns the UUID of the last editor for this language."
def get_updated_by_uuid(%__MODULE__{data: data}), do: Map.get(data, "updated_by_uuid")
end