PhoenixKit.Modules.Pages.Storage.Slugs (phoenix_kit v1.7.71)

Copy Markdown View Source

Slug validation and generation for pages storage.

Handles slug format validation, uniqueness checking, URL slug validation for per-language slugs, and slug generation.

Summary

Functions

Clears custom url_slugs that conflict with a given directory slug.

Clears a specific url_slug from all translations of a single post.

Generates a unique slug based on title and optional preferred slug.

Checks if a slug already exists within the given pages group.

Validates whether the given string is a slug and not a reserved language code.

Validates whether the given string is a valid slug format and not a reserved language code.

Validates a per-language URL slug for uniqueness within a group+language combination.

Functions

clear_conflicting_url_slugs(group_slug, directory_slug)

@spec clear_conflicting_url_slugs(String.t(), String.t()) :: [
  {String.t(), String.t()}
]

Clears custom url_slugs that conflict with a given directory slug.

When a new post is created with directory slug X, any other posts that have custom url_slug = X need to have their url_slugs cleared (so they fall back to their own directory slug). Directory slugs have priority.

Returns the list of {post_slug, language} tuples that were cleared.

clear_url_slug_from_post(group_slug, post_slug, url_slug_to_clear)

@spec clear_url_slug_from_post(String.t(), String.t(), String.t()) :: [String.t()]

Clears a specific url_slug from all translations of a single post.

This is used when saving a post with a conflicting url_slug - we clear the url_slug from all translations of the same post that have that value.

Returns the list of language codes that were cleared.

generate_unique_slug(group_slug, title, preferred_slug \\ nil, opts \\ [])

@spec generate_unique_slug(String.t(), String.t(), String.t() | nil, keyword()) ::
  {:ok, String.t()} | {:error, :invalid_format | :reserved_language_code}

Generates a unique slug based on title and optional preferred slug.

Returns {:ok, slug} or {:error, reason} where reason can be:

  • :invalid_format - slug has invalid format
  • :reserved_language_code - slug is a reserved language code

slug_exists?(group_slug, post_slug)

@spec slug_exists?(String.t(), String.t()) :: boolean()

Checks if a slug already exists within the given pages group.

valid_slug?(slug)

@spec valid_slug?(String.t()) :: boolean()

Validates whether the given string is a slug and not a reserved language code.

Blog slugs cannot be language codes (like 'en', 'es', 'fr') to prevent routing ambiguity.

validate_slug(slug)

@spec validate_slug(String.t()) ::
  {:ok, String.t()} | {:error, :invalid_format | :reserved_language_code}

Validates whether the given string is a valid slug format and not a reserved language code.

Returns:

  • {:ok, slug} if valid
  • {:error, :invalid_format} if format is invalid
  • {:error, :reserved_language_code} if slug is a language code

Blog slugs cannot be language codes (like 'en', 'es', 'fr') to prevent routing ambiguity.

validate_url_slug(group_slug, url_slug, language, exclude_post_slug \\ nil)

@spec validate_url_slug(String.t(), String.t(), String.t(), String.t() | nil) ::
  {:ok, String.t()} | {:error, atom()}

Validates a per-language URL slug for uniqueness within a group+language combination.

URL slugs have the same format requirements as directory slugs, plus:

  • Cannot be reserved route words (admin, api, assets, etc.)
  • Must be unique within the group+language combination

Parameters

  • group_slug - The pages group
  • url_slug - The URL slug to validate
  • language - The language code
  • exclude_post_slug - Optional post slug to exclude from uniqueness check (for updates)

Returns

  • {:ok, url_slug} - Valid and unique
  • {:error, :invalid_format} - Invalid format
  • {:error, :reserved_language_code} - Is a language code
  • {:error, :reserved_route_word} - Is a reserved route word
  • {:error, :slug_already_exists} - Already in use for this language
  • {:error, :conflicts_with_directory_slug} - Conflicts with another post's directory slug