Filesystem storage helpers for publishing posts.
Content is stored under:
priv/publishing/<group>/<YYYY-MM-DD>/<HH:MM>/<language>.phkWhere <language> is determined by the site's content language setting. Files use the .phk (PhoenixKit) format, which supports XML-style component markup for building pages with swappable design variants.
Submodules
This module delegates to specialized submodules for better organization:
Storage.Paths- Path management and resolutionStorage.Languages- Language operations and i18nStorage.Slugs- Slug validation and generationStorage.Versions- Version managementStorage.Deletion- Trash and delete operationsStorage.Helpers- Shared utilities
Summary
Functions
Adds a new language file to an existing post (timestamp mode).
Adds a new language file to a slug-mode post.
Checks if the content or title has changed.
Counts the number of posts on a specific date for a blog. Used to determine if time should be included in URLs.
Creates a new version of a post by copying from the source version.
Creates a new post (timestamp mode), returning its metadata and content.
Creates a slug-mode post, returning metadata and paths for the primary language.
Creates a new version of a post from a specified source version or blank.
Lists posts for the given blog (timestamp mode). Accepts optional preferred_language to show titles in user's language.
Lists slug-mode posts for the given blog.
Lists all time folders (posts) for a specific date in a blog. Returns a list of time strings in HH:MM format, sorted.
Migrates a single post from legacy structure to versioned structure.
Moves an entire publishing group to the trash folder.
Moves a slug-mode post to a new slug.
Publishes a version, atomically archiving all other versions.
Reads a post for a specific language (timestamp mode).
Reads a slug-mode post.
Renames a publishing group directory on disk when the slug changes.
Sets the status of a specific translation (language file) in a version.
Deprecated: Use publish_version/3 instead.
Checks whether a new version should be created based on changes. Currently always returns false - users create new versions explicitly.
Checks if only the status is being changed (no content or title changes). Status-only changes don't require a new version.
Updates a post's metadata/content (timestamp mode).
Updates slug-mode posts in place (no slug change).
Updates slug-mode posts.
Types
@type post() :: %{ group: String.t() | nil, slug: String.t() | nil, date: Date.t() | nil, time: Time.t() | nil, path: String.t(), full_path: String.t(), metadata: map(), content: String.t(), language: String.t(), available_languages: [String.t()], language_statuses: %{required(String.t()) => String.t() | nil}, mode: :slug | :timestamp | nil, version: integer() | nil, available_versions: [integer()], version_statuses: %{required(integer()) => String.t()}, version_dates: %{required(integer()) => String.t() | nil}, is_legacy_structure: boolean() }
A post with metadata and content.
The language_statuses field is preloaded when fetching posts via list_posts/2
or read_post/2 to avoid redundant file reads. It maps language codes to their
publication status (e.g., %{"en" => "published", "es" => "draft"}).
Version fields:
version: Current version number (1, 2, 3...)available_versions: List of all version numbers for this postversion_statuses: Map of version => status for quick lookup
Functions
See PhoenixKit.Modules.Publishing.Storage.Paths.absolute_path/1.
Adds a new language file to an existing post (timestamp mode).
@spec add_language_to_post_slug_mode( String.t(), String.t(), String.t(), integer() | nil ) :: {:ok, post()} | {:error, any()}
Adds a new language file to a slug-mode post.
See PhoenixKit.Modules.Publishing.Storage.Languages.check_primary_language_status/2.
See PhoenixKit.Modules.Publishing.Storage.Paths.cleanup_empty_legacy_root/0.
See PhoenixKit.Modules.Publishing.Storage.Slugs.clear_url_slug_from_post/3.
Checks if the content or title has changed.
@spec count_posts_on_date(String.t(), Date.t() | String.t()) :: non_neg_integer()
Counts the number of posts on a specific date for a blog. Used to determine if time should be included in URLs.
@spec create_new_version(String.t(), post(), map(), map() | keyword()) :: {:ok, post()} | {:error, any()}
Creates a new version of a post by copying from the source version.
Creates a new post (timestamp mode), returning its metadata and content.
@spec create_post_slug_mode( String.t(), String.t() | nil, String.t() | nil, map() | keyword() ) :: {:ok, post()} | {:error, any()}
Creates a slug-mode post, returning metadata and paths for the primary language.
@spec create_version_from(String.t(), String.t(), integer() | nil, map(), map()) :: {:ok, post()} | {:error, any()}
Creates a new version of a post from a specified source version or blank.
See PhoenixKit.Modules.Publishing.Storage.Deletion.delete_language/4.
See PhoenixKit.Modules.Publishing.Storage.Deletion.delete_version/3.
See PhoenixKit.Modules.Publishing.Storage.Languages.detect_available_languages/2.
See PhoenixKit.Modules.Publishing.Storage.Versions.detect_post_structure/1.
See PhoenixKit.Modules.Publishing.Storage.Languages.enabled_language_codes/0.
See PhoenixKit.Modules.Publishing.Storage.Paths.ensure_group_root/1.
See PhoenixKit.Modules.Publishing.Storage.Slugs.generate_unique_slug/4.
See PhoenixKit.Modules.Publishing.Storage.Languages.get_display_code/2.
See PhoenixKit.Modules.Publishing.Storage.Languages.get_language_info/1.
See PhoenixKit.Modules.Publishing.Storage.Versions.get_latest_published_version/2.
See PhoenixKit.Modules.Publishing.Storage.Versions.get_latest_version/2.
See PhoenixKit.Modules.Publishing.Storage.Languages.get_post_primary_language/3.
See PhoenixKit.Modules.Publishing.Storage.Languages.get_primary_language/0.
See PhoenixKit.Modules.Publishing.Storage.Versions.get_published_version/2.
See PhoenixKit.Modules.Publishing.Storage.Versions.get_version_date/4.
See PhoenixKit.Modules.Publishing.Storage.Versions.get_version_metadata/4.
See PhoenixKit.Modules.Publishing.Storage.Versions.get_version_status/4.
See PhoenixKit.Modules.Publishing.Storage.Paths.group_path/1.
See PhoenixKit.Modules.Publishing.Storage.Paths.has_legacy_groups?/0.
See PhoenixKit.Modules.Publishing.Storage.Languages.language_enabled?/2.
See PhoenixKit.Modules.Publishing.Storage.Languages.language_filename/0.
See PhoenixKit.Modules.Publishing.Storage.Languages.language_filename/1.
See PhoenixKit.Modules.Publishing.Storage.Paths.legacy_group?/1.
See PhoenixKit.Modules.Publishing.Storage.Paths.legacy_root_path/0.
Lists posts for the given blog (timestamp mode). Accepts optional preferred_language to show titles in user's language.
Lists slug-mode posts for the given blog.
Lists all time folders (posts) for a specific date in a blog. Returns a list of time strings in HH:MM format, sorted.
See PhoenixKit.Modules.Publishing.Storage.Versions.list_versions/2.
See PhoenixKit.Modules.Publishing.Storage.Languages.load_language_statuses/2.
See PhoenixKit.Modules.Publishing.Storage.Versions.load_version_dates/4.
See PhoenixKit.Modules.Publishing.Storage.Versions.load_version_statuses/4.
See PhoenixKit.Modules.Publishing.Storage.Paths.migrate_group/1.
Migrates a single post from legacy structure to versioned structure.
Moves an entire publishing group to the trash folder.
@spec move_post_to_new_slug(String.t(), post(), String.t(), map(), map() | keyword()) :: {:ok, post()} | {:error, any()}
Moves a slug-mode post to a new slug.
See PhoenixKit.Modules.Publishing.Storage.Paths.new_root_path/0.
See PhoenixKit.Modules.Publishing.Storage.Languages.order_languages_for_display/3.
See PhoenixKit.Modules.Publishing.Storage.Versions.parse_version_number/1.
See PhoenixKit.Modules.Publishing.Storage.Languages.propagate_status_to_translations/3.
Publishes a version, atomically archiving all other versions.
Reads a post for a specific language (timestamp mode).
@spec read_post_slug_mode(String.t(), String.t(), String.t() | nil, integer() | nil) :: {:ok, post()} | {:error, any()}
Reads a slug-mode post.
Renames a publishing group directory on disk when the slug changes.
See PhoenixKit.Modules.Publishing.Storage.Paths.root_path/0.
@spec set_translation_status( String.t(), String.t(), integer(), String.t(), String.t() ) :: :ok | {:error, any()}
Sets the status of a specific translation (language file) in a version.
Deprecated: Use publish_version/3 instead.
Checks whether a new version should be created based on changes. Currently always returns false - users create new versions explicitly.
See PhoenixKit.Modules.Publishing.Storage.Slugs.slug_exists?/2.
Checks if only the status is being changed (no content or title changes). Status-only changes don't require a new version.
See PhoenixKit.Modules.Publishing.Storage.Deletion.trash_language/2.
See PhoenixKit.Modules.Publishing.Storage.Deletion.trash_post/2.
Updates a post's metadata/content (timestamp mode).
See PhoenixKit.Modules.Publishing.Storage.Languages.update_post_primary_language/3.
@spec update_post_slug_in_place(String.t(), post(), map(), map() | keyword()) :: {:ok, post()} | {:error, any()}
Updates slug-mode posts in place (no slug change).
@spec update_post_slug_mode(String.t(), post(), map(), map() | keyword()) :: {:ok, post()} | {:error, any()}
Updates slug-mode posts.
See PhoenixKit.Modules.Publishing.Storage.Slugs.valid_slug?/1.
See PhoenixKit.Modules.Publishing.Storage.Slugs.validate_slug/1.
See PhoenixKit.Modules.Publishing.Storage.Slugs.validate_url_slug/4.
See PhoenixKit.Modules.Publishing.Storage.Versions.version_dir?/1.
See PhoenixKit.Modules.Publishing.Storage.Versions.version_path/3.
See PhoenixKit.Modules.Publishing.Storage.Paths.write_root_path/0.