feat: page registry with its admin screen and signpost type

- golem15_seo_pages (migration 202610280002): the site's own frontend pages
  with an address and a name per locale, kind, origin, parent, content date
  and note; settings routes_reported_at
- SEO > Pages (golem15.seo.pages) after URL rules: list with kind, origin
  and missing filters and the missing row state, form with the P9 partial;
  the plugin's form extension saves the address and name per locale and
  refuses url_required, url_invalid, url_taken and url_owned
- menu item type seo-page with a content descriptor, so each page gets
  the SEO tab, resolves ok and is listed in the sitemaps grouped by kind
  (pages, offers, services, landing-pages, titled per locale)
- management API GET/POST /_seo/api/v1/pages, PUT/DELETE /pages/{id} and
  the MCP tools seo_list_pages, seo_create_page, seo_update_page,
  seo_delete_page (in this commit because the operations parity test maps
  every Pages operation to its tool)
This commit is contained in:
Jakub Zych
2026-11-04 13:20:45 +01:00
parent 17b810dfde
commit 9e802ec850
27 changed files with 2281 additions and 9 deletions

View File

@@ -2,6 +2,7 @@ plugin:
name: SEO
description: Search engine metadata for every content type, URL rules and global SEO settings.
nav:
pages: Pages
robots: robots.txt
notfound: 404 log
redirects: Redirects
@@ -171,6 +172,7 @@ history:
what_robots: robots.txt
what_settings: SEO settings
what_notfound: 404 log entry “:url”
what_page: Page “:url”
change_cell:
one: ':field: :before → :after'
other: ':count fields changed'
@@ -202,6 +204,7 @@ history:
kind_robots: robots.txt
kind_settings: SEO settings
kind_notfound: 404 log entry
kind_page: registry page
jobs:
generate_entries: 'SEO: generate entries'
effective:
@@ -346,3 +349,46 @@ transfer:
row_canonical: "The canonical URL redirects to “:target”"
row_rule: "No record at this address: a URL rule is created"
row_invalid: ":field: :message"
pages:
type: Site page
list_title: Pages
name: Page
new: New page
list_empty: No pages yet. Add the site's own pages here, such as the home page, contact or offer pages, so they get an SEO tab and a place in the sitemaps. The site can also report its pages automatically.
url: Address
title: Name
kind: Type
origin: Origin
content_updated: Content changed
reported: Last reported
kind_page: Page
kind_offer: Offer
kind_service: Service
kind_landing: Landing page
origin_manual: Manual
origin_reported: Reported by the site
origin_mcp: MCP
state_missing: Not on the site
filter_missing: Not on the site
filter_missing_only: Only missing
filter_missing_hide: Hide missing
url_comment: The page's path in each language, e.g. /kontakt. Leave a language empty when the page has no version in it.
title_comment: Used for the default SEO title, the HTML sitemap and breadcrumbs.
kind_comment: "Decides the sitemap file and the default structured data: offers and services become Service."
parent: Parent page
parent_none: None (top level)
parent_comment: Places the page under another one in breadcrumbs.
content_updated_comment: Sent as lastmod in the sitemaps. Change it when the page's content changes on the site.
note: Note
note_comment: Not shown on the site.
status_reported: Reported by the site on :time.
status_missing: The site's last report (:time) did not include this address. Check whether the page still exists, then delete it here or redirect it.
url_required: Enter the address in the default language.
url_invalid: Start the address with / and leave out the domain.
url_taken: Another page already uses this address.
url_owned: This address belongs to :type “:title”. Set its SEO there.
parent_loop: A page cannot be placed under itself or one of its subpages.
delete_confirm: Delete this page from the registry? Its SEO tab is deleted with it, and the address leaves the sitemaps. A page the site reports comes back with its next report.
delete_selected_confirm:
one: "Delete :count page from the registry? Its SEO tab is deleted with it."
other: "Delete :count pages from the registry? Their SEO tabs are deleted with them."