Table Of Contents
Who is this for
Summary
The SEO Module handles archive and per-page meta titles, descriptions, TLDR summaries, breadcrumb labels, canonical URLs, and robots directives. Along with Advanced SEO, Image SEO and Redirections. This hub orients you to child documentation; open specific guides from the module navigation when editing content.
SEO Post meta keys
get_post_meta / update_post_meta / delete_post_meta
Nine distinct keys. Values are per post.
| Key | Type / notes | Read | Write |
|---|---|---|---|
scos_seo_breadcrumb_title | string | Meta_Box.php, breadcrumb-shortcode.php, scos-migration.php | Meta_Box.php (update_or_delete), scos-migration.php |
scos_seo_tldr | string (HTML allowed on save) | Meta_Box.php, FAQ_Module.php | Meta_Box.php (update_or_delete) |
scos_seo_title | string | Meta_Box.php, Head_Output.php, brighter-og-meta.php, scos-migration.php | Meta_Box.php, scos-migration.php |
scos_seo_description | string | Meta_Box.php, Head_Output.php, brighter-og-meta.php, scos-migration.php | Meta_Box.php, scos-migration.php |
scos_seo_canonical | URL string | Meta_Box.php, Head_Output.php, scos-migration.php | Meta_Box.php, scos-migration.php |
scos_seo_robots | array (noindex, nofollow, noimageindex, nosnippet) | Meta_Box.php, Head_Output.php, scos-migration.php | Meta_Box.php (always update_post_meta), scos-migration.php |
scos_seo_sitemap_exclude | array (xml, html, news) | Meta_Box.php, views/meta-box.php | Meta_Box.php (update_post_meta) |
scos_seo_freeze_og_date | '1' / '0' — freeze post_modified for OG/schema freshness | Meta_Box.php, views/meta-box.php | Meta_Box.php (update_post_meta on every save) |
Registered (REST/auth only, not extra keys): Meta_Fields.php registers all except scos_seo_freeze_og_date (used in code but not in register_post_meta).
Not post-meta storage (same prefix, different purpose):
scos_seo_meta— metabox DOM id (Meta_Box.php)scos_seo_schema— Schema metabox id (SeoSchema/Meta_Box.php); actual schema meta isscos_schema_custom(see schema module)
Gap: [tldr] shortcode (brighter-core/includes/tldr-shortcode.php) still reads bw_tldr, not scos_seo_tldr. Meta_Box dual-writes bw_tldr on save so the shortcode keeps working.
SEO wp_options keys
(get_option / update_option / delete_option)
options are created on first update_option, No add_option( 'scos_seo_*' )
Fixed option keys
| Key | Purpose | Read | Write |
|---|---|---|---|
scos_seo_freeze_modified_date | Global “freeze modified date” ('1' or empty) | Meta_Box.php, views/archive-meta.php | Archive_Settings.php (update_option on Meta Tags save) |
scos_seo_author_rewrite_ver | MD5 of custom author base; triggers one flush_rewrite_rules | Archive_Settings.php | update_option / delete_option in Archive_Settings.php |
Dynamic option keys (pattern)
| Pattern | Purpose | Read | Write |
|---|---|---|---|
scos_seo_archive_{slug} | Serialized array of archive SEO settings | Archive_Settings::get() → get_option( OPTION_PREFIX . sanitize_key( $slug ) ) | Archive_Settings::save() → update_option(...) |
{slug} values come from Archive_Settings::get_archives():
post— blog archive- Every public, non–built-in CPT (e.g.
project,service,faq, … — site-specific) author,date,search,404— special archives
Each option stores a merged array (fields vary by slug).
Common keys inside the array: title, description, breadcrumb_title, robots, tldr, sitemap_exclude, og_image_id, pagination_noindex, canonical_paged, rel_prevnext; author/date/search also disabled, redirect_url; author also author_slug.
Not an option: scos_seo_title_sep is a apply_filters() hook name in Archive_Settings.php, not get_option.
Notes
- Admin query param
?scos_seo=disabledinAdmin_UI.php
Claude MCP/WP-CLI grep cheat sheet, post-meta set is:
scos_seo_breadcrumb_title, scos_seo_tldr, scos_seo_title, scos_seo_description, scos_seo_canonical, scos_seo_robots, scos_seo_sitemap_exclude, scos_seo_freeze_og_date.
Archive SEO Meta Update request.
MCP Archive SEO Meta Update request.
MCP task: fill SEO archive options (Meta Tags tab)
Admin UI (reference only): wp-admin/admin.php?page=site-essentials-seo&tab=meta
Storage: one option per archive slug: scos_seo_archive_{slug}
Same tab also sets: scos_seo_freeze_modified_date (global, not per archive)
1. Discover slugs on this site (run first)
Do not guess CPT/taxonomy names. Build the slug list the same way Archive_Settings::handle_save() does:
# Post type archives: always includes “post” + public non-builtin CPTs
wp post-type list –_builtin=0 –public=1 –field=name
# Special archives (fixed)
# author | date | search | 404
# Taxonomy archives: category, post_tag, then other public taxonomies
wp taxonomy list –public=1 –field=name
Option key rule: scos_seo_archive_ + sanitize_key( $slug )
Examples: scos_seo_archive_post, scos_seo_archive_project, scos_seo_archive_category, scos_seo_archive_scos_content_cluster (if that taxonomy exists).
2. Read before write (merge, do not blind overwrite)
wp option get scos_seo_archive_post –format=json
If missing, treat as {}. When updating one slug, only change that option key; other scos_seo_archive_* keys are independent (unlike the admin form, which re-saves every slug on one submit).
3. Write with wp option update (preferred)
Use JSON and WordPress will store the PHP array correctly:
wp option update scos_seo_archive_post ‘{
“title”: “%title% %sep% %sitename%”,
“description”: “%description%”,
“breadcrumb_title”: “Blog”,
“tldr”: “”,
“robots”: [],
“sitemap_exclude”: [],
“og_image_id”: 0,
“pagination_noindex”: false,
“canonical_paged”: false,
“rel_prevnext”: false
}’ –format=json
Global on same tab (optional):
wp option update scos_seo_freeze_modified_date ‘1’ # enable
# or
wp option update scos_seo_freeze_modified_date ” # disable
4. Payload schema by slug type
A. Post type archives — slug post or any public CPT name
| Field | Type | Notes |
|---|---|---|
title | string | Template; tokens below |
description | string | Template; multiline OK |
breadcrumb_title | string | Plain text |
tldr | string | Plain text |
robots | string[] | Subset: noindex, nofollow, noimageindex, nosnippet |
sitemap_exclude | string[] | Subset: xml, html, news |
og_image_id | int | Attachment ID |
pagination_noindex | bool | |
canonical_paged | bool | |
rel_prevnext | bool |
B. Taxonomy archives — slug = taxonomy name (category, post_tag, custom)
Same fields as A (taxonomies are not “special” slugs).
Extra tokens useful here: %term%, %taxonomy%, %description%.
C. Special archives — author, date, search, 404
Base fields only: title, description, breadcrumb_title, robots
(No tldr, sitemap_exclude, og_image_id, pagination flags — admin save strips them for special slugs except author partial extras.)
author, date, search also:
| Field | Type |
|---|---|
disabled | bool |
redirect_url | string (URL) |
author also:
| Field | Type |
|---|---|
author_slug | string |
tldr | string |
og_image_id | int |
404: base fields only (no disable/redirect).
5. Template tokens (title / description only)
| Token | Use |
|---|---|
%title% | Archive / term / author / blog title |
%sitename% | Site name |
%sep% | Separator (default –; filter scos_seo_title_sep) |
%page% | Page N on paginated archives |
%term% | Term name (taxonomy) |
%taxonomy% | Taxonomy plural label |
%description% | Term description (taxonomy) |
%author% | Author display name |
%search% | Search query |
Example title: %title% %sep% %sitename%
Important: Do not run values through sanitize_text_field() in a way that breaks % tokens (e.g. %description% is valid). Plain strings are fine for MCP; PHP admin uses sanitize_template_field() which preserves tokens.
6. Verify after write
wp option get scos_seo_archive_post –format=json
wp eval ‘var_export( \SiteEssentials\Modules\SeoMeta\Archive_Settings::get(“post”) );’
Second line confirms merged defaults + saved values (only works if Site Essentials is loaded in CLI — otherwise option get is enough).
Frontend output is consumed by Head_Output.php via Archive_Settings::get( $slug ) — no separate meta keys.
7. What NOT to do
| Avoid | Why |
|---|---|
wp post meta update for archive SEO | Wrong storage layer |
| Guessing slugs from another site | CPT/tax list is per site |
POSTing to admin-post.php?action=site_essentials_save_archive_meta without full scos_archive[all-slugs] | Omitted slugs save as empty arrays for every slug in the loop |
Setting scos_seo_author_rewrite_ver manually | Internal; admin deletes it on save to flush rewrites |
Legacy export keys scos_seo_breadcrumb, scos_seo_isnoindex | Not used by this module |
8. Optional: mimic admin save (usually worse for MCP)
Only if you must use the UI pipeline:
- URL:
admin-post.php - action:
site_essentials_save_archive_meta - nonce:
scos_archive_meta_nonce/ actionscos_save_archive_meta - Capability:
manage_options - Body:
scos_archive[{slug}][title], etc., plusscos_global[freeze_modified_date]if needed
Requires a logged-in admin session or nonce generation. wp option update per slug is simpler and safer.
9. Copy-paste MCP system prompt (short)
Task: Fill SCOS SEO archive settings for {site}.
1. List slugs: wp post-type list –_builtin=0 –public=1 –field=name;
add “post”; add special author,date,search,404;
wp taxonomy list –public=1 –field=name.
2. For each slug in scope, read wp option get scos_seo_archive_{slug} –format=json.
3. Write with wp option update scos_seo_archive_{slug} ‘<json>’ –format=json
using the correct schema (CPT/tax vs special vs author).
4. Use template tokens in title/description where appropriate.
5. Optionally set scos_seo_freeze_modified_date to “1” or “”.
6. Verify with wp option get. Do not use post meta. Do not POST admin form unless updating all slugs at once.
Reference: site-essentials/Modules/SeoMeta/Archive_Settings.php
10. Author slug side effect
If you set author_slug on scos_seo_archive_author, the next normal admin save (or code path that calls Archive_Settings::set_author_slug()) may flush rewrite rules. After CLI-only author slug changes, tell the operator to visit Settings → Permalinks → Save once if author URLs look wrong.
If you want this wired into scos-meta-fill as a sub-skill, the stable contract is: option prefix scos_seo_archive_ + site-specific slug list + JSON schemas above — not the admin URL itself.
Page/Post SEO Meta Output
(pages/posts is slightly different – shown in bold)
Example for Pages
<head>
<title>Website Design Ballarat | Conversion Infrastructure</title>
<meta name='robots' content='max-image-preview:large' />
<!-- OG Image Tags -->
<meta property="og:image" content="https://brighterwebsites.com.au/wp-content/uploads/2026/01/brighter-websites-logo-web-design-1200x630.jpg">
<meta property="og:image:type" content="image/jpeg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Brighter websites colourful graphical representation of website design on multiple devices">
<!-- Twitter Card (after image) -->
<meta name="twitter:card" content="summary_large_image">
<meta name="author" content="Vanessa Wood">
<!-- SCOS SEO Meta -->
<meta name="description" content="Custom web design for Ballarat and regional Australian businesses. Infrastructure-first — schema markup, Core Web Vitals, and AI-ready architecture included." />
<link rel="canonical" href="https://brighterwebsites.com.au/services/website-design/" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://brighterwebsites.com.au/services/website-design/" />
<meta property="og:site_name" content="Brighter Websites" />
<meta property="og:locale" content="en_AU" />
<meta property="og:title" content="Website Design Ballarat | Conversion Infrastructure" />
<meta property="og:description" content="Custom web design for Ballarat and regional Australian businesses. Infrastructure-first — schema markup, Core Web Vitals, and AI-ready architecture included." />
<meta property="og:updated_time" content="2026-04-10T12:08:21+10:00" />
<!-- /SCOS SEO Meta -->
<link rel="icon" href="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-150x150.png" sizes="32x32" />
<link rel="icon" href="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-300x300.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-300x300.png" />
<meta name="msapplication-TileImage" content="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-300x300.png" />Example for Articles
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>How I Made Contact Forms Ready for AI Agents – Brighter Websites</title>
<meta name='robots' content='max-image-preview:large' />
<!-- OG Image Tags -->
<meta property="og:image" content="https://brighterwebsites.com.au/wp-content/uploads/2026/05/webmcp-tool-testing-dev-tools-1-1200x630.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<!-- Twitter Card (after image) -->
<meta name="twitter:card" content="summary_large_image">
<meta name="author" content="Vanessa Wood">
<!-- SCOS SEO Meta -->
<link rel="canonical" href="https://brighterwebsites.com.au/blog/how-i-made-contact-forms-ready-for-ai-agents/" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://brighterwebsites.com.au/blog/how-i-made-contact-forms-ready-for-ai-agents/" />
<meta property="og:site_name" content="Brighter Websites" />
<meta property="og:locale" content="en_AU" />
<meta property="og:title" content="How I Made Contact Forms Ready for AI Agents" />
<meta property="article:published_time" content="2026-05-28T10:26:02+10:00" />
<meta property="article:modified_time" content="2026-06-04T16:23:34+10:00" />
<meta property="article:author" content="https://brighterwebsites.com.au/author/vanessa-wood/" />
<!-- /SCOS SEO Meta -->
<link rel="icon" href="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-150x150.png" sizes="32x32" />
<link rel="icon" href="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-300x300.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-300x300.png" />
<meta name="msapplication-TileImage" content="https://brighterwebsites.com.au/wp-content/uploads/2026/01/bw-favico2026-300x300.png" />
Archive SEO Tokens Available
Template Tokens you can use in Meta Title and Meta Description fields
%title% | Archive name — CPT plural label, term name, author name, or blog page title |
|---|---|
%sitename% | Site name from Settings › General |
%sep% | Separator (default –, filterable via scos_seo_title_sep) |
%page% | “Page 2” on paginated views, blank on page 1 |
%term% | Taxonomy term name (alias for %title% on term archives) |
%taxonomy% | Taxonomy plural label (e.g. “Categories”, “Tags”) |
%description% | Term description — the description set on the taxonomy term edit screen |
%author% | Author display name (author archives) |
%search% | Search query string (search results archives) |
Example: %title% %sep% %sitename% → Posts (Blog) – Brighter Websites