add page url slug management functions
Context functions for custom page URLs: - list_pages_with_custom_urls/0 for admin overview - get_published_page_by_effective_url/1 for routing lookups - update_page_url_slug/2 with automatic redirect creation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f56e04390c
commit
1004865013
@ -90,6 +90,28 @@ defmodule Berrypod.Pages do
|
||||
list_system_pages() ++ list_custom_pages()
|
||||
end
|
||||
|
||||
@doc "Lists pages that have a custom URL slug set. Used by Routes cache."
|
||||
def list_pages_with_custom_urls do
|
||||
from(p in Page, where: not is_nil(p.url_slug))
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@doc "Gets a published page by its effective URL (url_slug or slug)."
|
||||
def get_published_page_by_effective_url(url) do
|
||||
# First check for custom url_slug match
|
||||
case Repo.one(from p in Page, where: p.url_slug == ^url and p.published == true) do
|
||||
nil ->
|
||||
# Fall back to slug match for custom pages
|
||||
Repo.one(
|
||||
from p in Page,
|
||||
where: p.slug == ^url and p.type == "custom" and p.published == true
|
||||
)
|
||||
|
||||
page ->
|
||||
page
|
||||
end
|
||||
end
|
||||
|
||||
# ── Write ─────────────────────────────────────────────────────────
|
||||
|
||||
@doc """
|
||||
@ -272,7 +294,91 @@ defmodule Berrypod.Pages do
|
||||
meta_description: page.meta_description,
|
||||
show_in_nav: page.show_in_nav,
|
||||
nav_label: page.nav_label,
|
||||
nav_position: page.nav_position
|
||||
nav_position: page.nav_position,
|
||||
url_slug: page.url_slug
|
||||
}
|
||||
end
|
||||
|
||||
# ── URL customisation ────────────────────────────────────────────
|
||||
|
||||
@doc """
|
||||
Updates a page's custom URL slug. Creates a redirect from the old
|
||||
effective URL to the new one, and invalidates the R module cache.
|
||||
|
||||
Pass nil or empty string to clear the custom URL.
|
||||
"""
|
||||
def update_page_url_slug(%Page{} = page, url_slug) do
|
||||
old_effective_url = Page.effective_url(page)
|
||||
|
||||
# Normalise empty string to nil
|
||||
url_slug = if url_slug == "", do: nil, else: url_slug
|
||||
|
||||
changeset_fn =
|
||||
if Page.system_slug?(page.slug),
|
||||
do: &Page.system_changeset/2,
|
||||
else: &Page.custom_changeset/2
|
||||
|
||||
result =
|
||||
page
|
||||
|> changeset_fn.(%{url_slug: url_slug})
|
||||
|> Repo.update()
|
||||
|
||||
case result do
|
||||
{:ok, updated} ->
|
||||
new_effective_url = Page.effective_url(updated)
|
||||
|
||||
# Create redirect if URL changed
|
||||
if old_effective_url != new_effective_url do
|
||||
# Delete any stale redirect FROM the new URL (it's now a live page)
|
||||
delete_stale_redirect("/#{new_effective_url}")
|
||||
|
||||
# Create redirect from old URL to new URL
|
||||
Berrypod.Redirects.create_auto(%{
|
||||
from_path: "/#{old_effective_url}",
|
||||
to_path: "/#{new_effective_url}",
|
||||
source: "auto_slug_change"
|
||||
})
|
||||
end
|
||||
|
||||
# Invalidate caches synchronously to avoid race conditions
|
||||
PageCache.invalidate(page.slug)
|
||||
BerrypodWeb.R.invalidate_all_sync()
|
||||
|
||||
{:ok, updated}
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
|
||||
def update_page_url_slug(slug, url_slug) when is_binary(slug) do
|
||||
case get_page_struct(slug) do
|
||||
nil ->
|
||||
# Page doesn't exist in DB - create it from defaults if it's a system page
|
||||
if Page.system_slug?(slug) do
|
||||
defaults = Defaults.for_slug(slug)
|
||||
|
||||
case save_page(slug, defaults) do
|
||||
{:ok, page} -> update_page_url_slug(page, url_slug)
|
||||
error -> error
|
||||
end
|
||||
else
|
||||
{:error, :not_found}
|
||||
end
|
||||
|
||||
page ->
|
||||
update_page_url_slug(page, url_slug)
|
||||
end
|
||||
end
|
||||
|
||||
# When a URL becomes a live page, delete any redirect from that URL
|
||||
defp delete_stale_redirect(path) do
|
||||
case Repo.one(from r in Berrypod.Redirects.Redirect, where: r.from_path == ^path) do
|
||||
%Berrypod.Redirects.Redirect{} = redirect ->
|
||||
Berrypod.Redirects.delete_redirect(redirect)
|
||||
|
||||
nil ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user