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()
|
list_system_pages() ++ list_custom_pages()
|
||||||
end
|
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 ─────────────────────────────────────────────────────────
|
# ── Write ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@ -272,7 +294,91 @@ defmodule Berrypod.Pages do
|
|||||||
meta_description: page.meta_description,
|
meta_description: page.meta_description,
|
||||||
show_in_nav: page.show_in_nav,
|
show_in_nav: page.show_in_nav,
|
||||||
nav_label: page.nav_label,
|
nav_label: page.nav_label,
|
||||||
nav_position: page.nav_position
|
nav_position: page.nav_position,
|
||||||
|
url_slug: page.url_slug
|
||||||
}
|
}
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user