SC Website — Brand Page, Deck & Asset Publishing
Overview
- What: Publish brand-ready content on Symphony Core's primary website (
symphonycore.com) in three forms, each with a stable, shareable URL that stays crawlable and on-brand: (A) custom-coded HTML webpages and components, (B) ready HTML/PDF decks delivered as a "always-latest" download link, and (C) brand assets (logo, founder/CEO photo, product imagery) at fixed public links. - When: Whenever a new brand-ready page, deck, or asset needs to live on the primary site — and whenever an already-published deck or asset needs to be refreshed without breaking the link already shared with clients.
- Who: Implementation Lead owns the SOP; a Web Specialist (WP admin + Elementor access) executes. SEO checks may be delegated to an SEO Operator.
- Time Required: 30–60 min for a new page; 15–30 min for a deck; 10–20 min for an asset set. Refreshing an already-published deck/asset is ~10 min.
The Core Problem This Solves
Two recurring failures motivate this SOP:
- SEO-invisible HTML. When brand-ready HTML is placed on the site the wrong way — wrapped in a cross-origin
<iframe>, injected purely by client-side JavaScript, or baked into an image — search crawlers see an empty shell instead of the content. The page renders fine for humans but ranks for nothing and silently drops out of the sitemap. This is the same lesson already learned with GHL funnel pages (see the Native HTML Embed policy); it applies equally to any custom-coded brand content. - Email-attachment churn. Brand decks and assets get emailed to clients as attachments, so every revision means another email and clients end up holding stale copies. The fix is to publish once at a stable URL and update the file in place behind that URL — the link you shared stays correct forever, and clients always pull the latest version.
Prerequisites
- WP admin access to
symphonycore.com/wp-admin(the Symphony Core LLC sub-account site — see WordPress Hosting Infrastructure). - The site running the standard stack per the SC WordPress Stack Standard: Astra + Elementor Pro, SearchAtlas (OTTO) for SEO, Auctollo for the sitemap. No additional page builder, SEO suite, or "media replace" plugin — those are prohibited.
- Brand-ready source: colors, type, logo lockups, and component styling must conform to the SC Design Kit and SC Brand Foundation. Do not improvise brand tokens.
- For pages, the approved copy (from
02-marketing-brand/website/) and the keyword/meta intent (from02-marketing-brand/seo/). - The HTML source for any custom component lives in the repo under
02-marketing-brand/website/(e.g., the existingfaq-page-code.html,homepage-results-section.html). Binary exports (PDF decks, logo/photo files) are never committed to this repo — see the routing note in Part C and generated-outputs-to-drive.
Part A — Brand-Ready HTML Webpages (SEO-safe)
Goal: a custom-coded, on-brand page or section that a crawler reads exactly as a human does.
A1. Choose an SEO-safe placement method
The single rule: the content must appear in the server-rendered raw HTML of the WordPress URL — never behind a cross-origin frame, never assembled only by JavaScript, never trapped inside an image.
| Method to place brand HTML | Crawlable? | Use when |
|---|---|---|
| Elementor HTML widget / Gutenberg Custom HTML block (server-rendered) | ✅ Yes — markup is in page source | Default for brand-ready components and custom-coded sections (this is how homepage-results-section.html and faq-page-code.html ship) |
| Native Elementor section with real headings and text | ✅ Yes | Standard page layout |
Cross-origin <iframe> embedding an externally hosted HTML page | ❌ No — the WP URL is a near-empty shell | Never for content meant to rank; only for deliberately noindex flows |
| Pure client-side JS injection (DOM built after load) | ⚠️ Unreliable — may never be indexed | Avoid for any primary content |
| Text baked into an image / infographic | ❌ No — text is not machine-readable | Never for headings or body copy; use real text and reserve images for decoration with descriptive alt |
The homepage already shows the right instinct: a low-quality infographic that carried real copy was replaced with a true HTML component (see
homepage-change-instructions.md§10). Follow that pattern — copy is text, not pixels.
A2. Author the HTML to brand and SEO standards
When writing or pasting the component:
- One
<h1>per page, then<h2>/<h3>in order — semantic headings, not styled<div>s. Section headings carry the keyword intent from02-marketing-brand/seo/. - Real, selectable text for all copy. Images get descriptive
alt; decorative-only images get emptyalt="". - Brand tokens from the Design Kit — colors, fonts, radius, spacing. Inline
<style>scoped to the component is fine (as in the existing HTML files); do not pull in external fonts/CSS that block render. - No
display:none/ off-screen hiding of meaningful content — crawlers discount hidden text and it reads as cloaking. - Links are real
<a href>with descriptive anchor text, not JS click handlers.
A3. Publish on the page and set SEO metadata
- In Elementor, drop an HTML widget and paste the component (or build the section natively). Update the page.
- In the SearchAtlas/SEO panel set: SEO title (≤60 chars, brand suffix
| Symphony Core), meta description (≤160 chars), and canonical = the page's own URL. - Add schema where it fits (Organization, FAQ, Article) via SearchAtlas OTTO.
- Confirm the page is not set to
noindex(unless intentionally — see Part B). Indexation toggles per the SearchAtlas Indexation Control SOP.
A4. Verify crawlability (do not skip)
- View the raw HTML, not just the browser:
curl -sS https://symphonycore.com/<path>/ | less(or Ctrl/Cmd+U). Confirm the headline copy, body text, and<title>/meta description are present in the source. If the content is missing fromcurloutput, the placement method is wrong — return to A1. - Confirm exactly one
<h1>and a sensible heading outline in the source. - Confirm no
noindexdirective in<meta name="robots">. - Regenerate the Auctollo sitemap and confirm the URL appears at
/sitemap.xml. - Request indexing for the URL in Google Search Console (see GSC Setup SOP).
- Check mobile (≤375 px): no horizontal scroll, tap targets ≥44 px, readable text.
Part B — Deck Hosting (link instead of email; always latest)
Goal: replace emailing decks as attachments with one stable link that always serves the current version. The link never changes; the file behind it does.
B1. Decide the deck's surface and visibility
- Canonical share link = a WordPress page at a memorable, permanent slug, e.g.
symphonycore.com/brand-deck. This is the URL you give clients. Once shared, the slug never changes (see Stable-link governance). - Visibility: A deck is a sharing surface, not a page meant to rank, so set it
noindexby default (via SearchAtlas Indexation Control) and exclude it from the sitemap. Only leave it indexable if the deck is genuinely intended to be discovered in search. - Format: support both as needed —
- View in browser: embed the HTML deck inline using the Part A SEO-safe method (HTML widget). Even on a
noindexpage, build it as real HTML so it renders reliably — never a cross-origin iframe to a third-party host you don't control. - Download: a "Download the latest deck" button linking to the current file (PDF or self-contained HTML/ZIP) in the WordPress Media Library.
- View in browser: embed the HTML deck inline using the Part A SEO-safe method (HTML widget). Even on a
B2. Publish the deck
- Build the deck HTML in the repo source area if it's a maintained component, or export the deck file (PDF/HTML).
- Upload the download file to the WordPress Media Library (GHL hosting serves it over the CDN). Note its URL.
- Create/edit the WordPress page at the permanent slug. Add the inline HTML deck (if offering in-browser view) and the Download button pointing at the file URL from step 2.
- Set the page
noindex(default) per B1. - Apply brand styling per the Design Kit (header, footer, CTA).
B3. Refresh an already-published deck (the "always-latest" mechanic)
Pick one mechanic and stay consistent per deck:
- Default — repoint behind a fixed slug: upload the new file, update the page's Download button to the new file URL, and refresh the inline HTML. The shared link (
/brand-deck) is unchanged; clients re-download and get the new version. Old file URL can be left in place or removed. - Literal fixed file URL (optional): if a client integration hard-codes the file URL, use SearchAtlas redirect management to keep a stable path like
symphonycore.com/downloads/brand-deck.pdf301-redirecting to the current file. Update the redirect target on each refresh; the stable path never changes. (This is the SEO-suite-free way to get "overwrite-in-place" behavior without a media-replace plugin.)
B4. Verify
- Open the share link in incognito; confirm the deck renders and the Download button serves the current file.
- After a refresh, confirm the link still resolves and now delivers the new version (hard-refresh / check file metadata).
- Confirm a
noindexdeck page is absent from/sitemap.xmland carries thenoindexdirective in source. - Confirm SSL padlock and no mixed-content warnings.
Part C — Brand Asset Hosting (logo, founder/CEO photo, imagery)
Goal: fixed public links for brand assets so anyone (clients, press, partners) can pull the current logo, founder/CEO photo, or product image without being emailed a file.
C1. Default home — a Brand Media Kit page
- Create one Brand Media Kit page at a permanent slug (e.g.
symphonycore.com/media-kitor/brand-assets). This page is the stable link you share. It lists each asset with a preview and a download link, grouped: Logos (primary, mono, mark, light/dark), Leadership (founder/CEO photo), Product/Brand imagery, and usage notes from the Design Kit. - Assets live in the WordPress Media Library on
symphonycore.com; they are public by default and CDN-served. The Media Kit page is public (it may be indexable — a media kit ranking for "Symphony Core logo" is fine). - Always-latest: refresh exactly as decks do (B3) — replace the file and repoint the page's download link behind the fixed slug, or keep a SearchAtlas redirect (e.g.
/downloads/sc-logo.svg) pointing at the current file. The public link stays constant. - Provide each logo in the formats the Design Kit specifies (SVG for vector, PNG with transparency, plus a sized JPG/PNG for the founder photo). Name files descriptively and losslessly:
symphony-core-logo-primary.svg,symphony-core-founder-ceo.jpg.
C2. Optional — Cloudflare R2 for true overwrite-in-place
Symphony Core has a Cloudflare media stack at media.symphonycore.com (R2 + Worker; see the Cloudflare Media Setup Guide). R2 supports overwriting an object at the same key, which gives the cleanest "same URL, always-latest" file link.
Prerequisite, not a current capability: the existing Worker is referrer-locked to
team.symphonycore.comfor internal docs, so it will 403 public/client requests today. Using R2 for client-shareable brand assets requires a one-time setup of a public read path (e.g. allow unauthenticated GET on apublic/brand/prefix) before any public link is shared. Do not hand amedia.symphonycore.comURL to a client until that public path is configured and verified. Until then, use the WordPress Media Kit page (C1) as the client-facing surface.
C3. Verify
- Open the Media Kit page in incognito (logged out) and download each asset — confirm public access with no login/referrer block.
- After a refresh, confirm the same link now serves the updated asset.
- Confirm logos display correctly on light and dark backgrounds; founder photo is the approved, current image at the Design Kit's dimensions.
- If using R2: confirm a logged-out request to the public asset URL returns 200 (not 403) before sharing it.
Stable-link governance
The whole value of this workflow is that links don't rot. Therefore:
- Never change a slug or file path once it has been shared externally. Refresh the content behind it instead (B3 / C1).
- If a URL truly must change, set a 301 redirect from the old path to the new one (SearchAtlas redirect management) so previously shared links keep working.
- Keep a short index of published share links (page slug → purpose → owner) in the website backlog or a Drive worksheet so the team knows which links are "live in the wild" and must not be broken.
- Maintained HTML source is versioned in git under
02-marketing-brand/website/; published binaries are versioned by replacement behind the stable link, not by emailing new copies.
Troubleshooting
Page content missing from curl/View Source but visible in browser. The content is in a cross-origin iframe or JS-injected. Re-place it via the Elementor HTML widget / native section (A1). This is the #1 SEO-invisibility cause.
Page dropped out of /sitemap.xml. Either it's set noindex, or it's an iframe wrapper that Auctollo correctly omits. Confirm robots meta, fix placement, regenerate the sitemap. (Same mechanism documented in the GHL Asset Handoff SOP §3.7.)
Client says the deck/logo they downloaded is outdated. They bookmarked a file URL that changed instead of the stable share link, or the refresh repointed the page but a redirect/cache still serves the old file. Confirm the share link is the slug (not a raw file URL), clear cache, verify B3 was completed.
media.symphonycore.com asset returns 403 for a client. Expected — the Worker is referrer-locked to internal use. Serve the asset from the WordPress Media Kit page (C1) or configure the public R2 path first (C2).
Custom HTML looks unstyled or off-brand after paste. External CSS/fonts didn't load, or brand tokens were guessed. Scope styling inline in the component and pull tokens from the Design Kit.
Tempted to install a plugin (media-replace, SEO suite, page builder, caching). Don't — they're prohibited by the stack standard. Use the redirect/repoint mechanics above instead, or run the exception-approval process.
Verification (summary checklist)
- Page/deck/asset content present in raw HTML (
curl), not just the browser. - Exactly one
<h1>; semantic heading outline; real text (no text-in-image for copy). - SEO title, meta description, canonical set; schema where applicable.
- Indexable pages appear in
/sitemap.xmland are submitted in GSC; deck pages intentionallynoindexare absent. - Share link is a permanent slug; refresh updates the file behind it; no shared slug changed.
- Assets/decks download publicly (no login/referrer block) and serve the current version.
- Brand styling matches the Design Kit on desktop and mobile; SSL valid, no mixed content.
Related Documents
- SC WordPress Stack Standard — approved stack, prohibited plugins, and the Native HTML Embed SEO policy this SOP generalizes.
- GHL Asset Handoff to WordPress Dev Team — the funnel-page precedent for crawlable HTML vs iframe (§Key Concept, §3.7).
- SearchAtlas Indexation Control Setup SOP —
noindexand instant-indexing controls used in Parts A/B. - Auctollo XML Sitemap Setup SOP — the canonical sitemap that includes/excludes pages by index status.
- Google Search Console Setup SOP — request-indexing step in Part A.
- Cloudflare Media Infrastructure Setup Guide — R2/Worker asset stack referenced in Part C (currently internal-only).
- WordPress Hosting Infrastructure — where
symphonycore.comis hosted. - SC Design Kit / SC Brand Foundation — brand-ready source of truth.
- WordPress Blog Post Publishing SOP — adjacent publishing flow (articles, not custom pages/decks/assets).
Revision History
| Date | Version | Change | Author |
|---|---|---|---|
| 2026-06-11 | 1.0 | Initial draft. Defines SEO-safe custom HTML page publishing, stable-link deck hosting, and public brand-asset hosting on symphonycore.com. | Symphony Core Systems Team |