Custom Codes — Reference
The Custom Codes surface is the site-wide injection layer — the place where an operator drops a snippet of HTML, JavaScript, or third-party tag that should run on every page (or a defined subset) of the site. It is the last-resort surface for things the design system, the theme, and the page-level editors cannot express on their own — analytics tags, marketing pixels, support widgets, feature flags, custom font loaders, schema markup, scroll trackers.
This page is a reference for platform engineers and integrators. The Custom Codes surface is intentionally narrow — it lives separately from Custom CSS (which carries design-system styles) and from the page body sanitizer (which strips inline andfrom saved content).Anything that needs to execute scripts or load third-party assets routes through here.
Overview
Custom Codes lives under theCustommodule group in SG-Admin,alongside its design-system sibling Custom CSS and the operator-data siblings Custom Fields,Custom Fonts,and Custom Objects.
The module is paired by convention:one half renders the list,create,edit,and migrate-legacy views;the other half handles writes — save,table refresh,soft delete,restore.
A Custom Code record carries a name,an injection location(head,body open,body close),a scope(site-wide or a page allow-list),an enabled flag,and the snippet itself.On render,the platform composes the active set of records into the page's HTML at the matching position. Records that are disabled or out of scope are skipped.
Where it lives in SG-Admin:
- Sidebar: SG-Admin → Custom → Codes
- URL prefix:
/sg-admin/custom-codes/ - View templates:
application/views/Admin/CustomCodes/
Distinct from page body content. The page body sanitizer strips and and rewrites iframe srcdoc attributes that carry embedded styles. To run a script or load a tag, route it through Custom Codes, not through a page or post body.
Legacy migration. Older SGEN sites carried codes inline on individual pages. The Custom Codes module exposes a one-time legacy-migration view that scans for those inline snippets and offers to relocate them into Custom Code records. After migration, the page records render clean.
┌──────────────────────────────────────────────────────────────────────┐│ SG-Admin → Custom → Codes [+ Add code] │├──────────────────────────────────────────────────────────────────────┤│ Name Position Scope Status ││ ───────────────────────── ───────────── ──────────── ────────││ GA4 measurement tag head site-wide active ││ Crisp chat widget body-close site-wide active ││ Fb pixel — checkout only body-close pages: 3 active ││ Holiday banner script body-open site-wide paused ││ Old loader (legacy) head site-wide trashed ││ ││ [⋯ Edit] [⋯ Duplicate] [⋯ Disable] [⋯ Delete] │└──────────────────────────────────────────────────────────────────────┘Actions
The Custom Codes surface exposes the following operations.
List and search
Returns the code records visible to the operator, paginated, with name, position, scope, status, and last-modified columns. Supports sort, free-text filter (matches name and snippet body), and filter by position or scope. Driven by the standard SG-Admin data-table contract.
Create code
Opens an empty form. Required fields: name, position, snippet body. Optional: scope (defaults to site-wide), enabled flag (defaults to true), priority (load order within the same position).
Edit code
Loads an existing record into the same form shape used for create, pre-populated. Submit replaces the stored record with the posted values.
Toggle enabled
Pauses or resumes a record without deleting it. A paused record is skipped at render but remains visible in the list under the paused filter. Use this for temporary disabling — for example, while debugging a tag conflict.
Soft delete
Marks the record as trashed. Trashed codes disappear from the default list and stop injecting immediately.
Restore
Returns a trashed record to its prior enabled state.
Permanent delete
Hard-removes a trashed record. Irreversible.
Migrate legacy codes
A one-time scan-and-relocate utility. Walks the page records, finds inline or third-party tag markup that the body sanitizer would otherwise strip on the next save, and offers per-occurrence relocation into a Custom Code record (with the source page as the scope). Operators can accept, edit, or skip each migration candidate. After acceptance, the inline markup is removed from the page and the new Custom Code record is created with the page already on its scope list.
Data model
A Custom Code record carries the following fields.
| Field | Type | Notes |
|---|---|---|
id | integer | Primary key. Stable across edits. |
name | string | Operator-readable label. Not unique; used in the list view. |
position | enum | head, body-open, body-close. Picks the injection site. |
snippet | text | The raw HTML / JS / tag markup. Stored verbatim. |
scope_mode | enum | site-wide or page-allowlist. |
scope_page_ids | array | Foreign keys to page records. Empty unless scope_mode = page-allowlist. |
enabled | boolean | true injects at render; false skips. |
priority | integer | Load order within the same position. Lower runs earlier. |
status | enum | active or trash. |
created_at | timestamp | Immutable. |
updated_at | timestamp | Touched on edit. |
created_by | integer | Foreign key to Users. |
Position semantics.headinjects betweenand
.body-openinjects immediately after.body-closeinjects immediately before.Order within a position is set bypriority,then byidas a tiebreaker.
Scope resolution.On every page render,the platform builds the active code set by filtering onenabled=trueand(scope_mode=site-wideOR the current page's ID is in scope_page_ids). The resulting set is then split by position and emitted in priority order.
CUSTOM CODE RECORD├── id integer primary key├── name string list-view label├── position enum head | body-open | body-close├── snippet text stored verbatim, no sanitization├── scope_mode enum site-wide | page-allowlist├── scope_page_ids array foreign keys to pages├── enabled boolean skip if false├── priority integer load order within position├── status enum active | trash├── created_by integer → Users└── timestamps created_at, updated_aton page render:filter (enabled = true) AND (site-wide OR page-id in allowlist)→ group by position→ emit in priority order→ drop verbatim into HTML responsePermissions
Access to the Custom Codes surface is gated tighter than most SG-Admin modules — the write capability is administrator-only by default, because a code record can ship arbitrary script that runs in every visitor's browser.
Layer 1 — admin gate.Standard admin access check at request entry.
Layer 2 — per-action capability.The default capability map ships as:
| Capability | Administrator | Editor | Designer | Viewer |
|---|---|---|---|---|
| List codes | ✔ | ✔ | ✔ | ✔ |
| Create code | ✔ | — | — | — |
| Edit code | ✔ | — | — | — |
| Toggle enabled | ✔ | — | — | — |
| Soft delete | ✔ | — | — | — |
| Restore | ✔ | — | — | — |
| Permanent delete | ✔ | — | — | — |
| Migrate legacy codes | ✔ | — | — | — |
No self-protection rulesbeyond the general admin gate.The surface assumes a privileged operator.The compensating control is the Activity Log — every code write is recorded with operator identity,snippet diff,scope diff,and status change.
Audit.Every create,edit,toggle,soft delete,restore,permanent delete,and legacy migration emits an Activity Log entry.The diff is full-snippet — useful for post-incident investigations when a code change broke the front-end.
DEFAULT ROLE MAP — narrower than most SG-Admin modulesAdministrator ─ full write(list,create,edit,toggle,delete,migrate)Editor ─ read onlyDesigner ─ read onlyViewer ─ read only┌─────────────────────────────────────────────────────────────┐│ Why narrower:││ A code record runs verbatim in every visitor's browser.││ Mis-scoped script → site-wide outage with no rollback ││ faster than a deploy.The default keeps the surface to ││ the same operators that hold theme activation and ││ database-tier capabilities.│└─────────────────────────────────────────────────────────────┘Activity Log captures every write — full snippet diff,scope diff,operator identity.Use for incident reconstruction.Related references
- Custom CSS — Reference. The design-system tier. Different surface, different sanitizer, different scope semantics. Use Custom CSS for site styles; Custom Codes for scripts, tags, and arbitrary markup.
- Custom Fonts — Reference. Self-hosted typeface uploads. Resolves into the styles-and-layouts font pickers — does not require a Custom Code record.
- Custom Objects — Reference. Operator-defined content types — different module, no overlap with code injection.
- Themes — Reference. Theme activation does not touch Custom Code records; they survive theme switches.
- Pages — Reference. Per-page scope on a Custom Code record resolves against page IDs from here.
- Settings — Reference. The Activity Log retention rule applies to Custom Code audit entries.
- SEO — Reference. Schema markup and verification tags often live as Custom Code records in the
headposition.
/docs/custom-codes.