File Structure
Front-end root /
| File | Role |
|---|---|
index.php | Main front-end router |
install.php | First-run installer |
config.json | Site settings flat-file database |
plugins.json | Plugin activation registry — { "slug": { "active": bool } }, created on first activation |
version.json | Current CMS version |
config.json was renamed from settings.json as part of the v1.3.3 core restructure. Existing installs are migrated automatically on first load — no manual action needed.
Core libraries /core/
As of v1.3.3, all front-end PHP libraries live under /core/ instead of the CMS root. This keeps the root directory limited to entry points and config, and makes the core/theme/plugin boundary explicit at a glance.
| File | Role |
|---|---|
functions.php | Bootstrap loader — includes every file below, in order |
core-functions.php | Routing helpers, breadcrumbs, galleries, search helpers, resolve_admin_dir() |
data-functions.php | Routing, SEO, category/tag page rendering, parseRequestUri() |
data-layer.php | Read-only split-file layer (sl_* functions, internal $GLOBALS cache) |
admin-data-layer.php | Write split-file layer (sl_admin_* functions, atomic operations) |
plugin-api.php | Plugin registry, activation state, admin-menu registration, and the pl_* hook system (see Plugins below) |
lang-cache.php | i18n cache and locale management (__t(), _e(), __n(), lang_js_bridge()) |
search.php | Search endpoint (JSON, mb_* safe) |
contact-process.php | Contact form handler (CSRF, rate-limit, hCaptcha, header injection guard) |
feed.php | RSS feed |
Rendering /core/render/
Rendering-specific files are grouped one level deeper:
| File | Role |
|---|---|
tf-page.php | Page renderers: SEO tags, header scripts, logo/favicon, featured image, date, category, tags, footer, social icons, search UI |
tf-cards.php | Card renderers: article/project cards, homepage sections, article summary, related items, custom fields |
tf-shortcodes.php | render_content_html() pipeline, all shortcode render functions, contact form, excerpt helpers |
tf-navigation.php | Navigation and menu rendering: render_menu(), renderHierarchicalMenu(), renderDefaultMenu() |
tf-markdown.php | Markdown parser: _md_to_html(), _md_inline(), container directives (:::type) |
theme-api.php | Hooks, filters, theme options system |
Data directory /data/
data/
├── articles/
│ ├── _index.json — Lightweight index (metadata only)
│ ├── my-article.json — Full article data (content, SEO, galleries, all fields)
│ └── other-article.json
├── pages/
│ ├── _index.json
│ └── my-page.json
├── projects/
│ ├── _index.json
│ └── my-project.json
├── categories.json — Category store (slug → {name, parent, description})
└── tags.json — Tag store (slug → {name, description})
Compiled cache /cache/
A dedicated /cache/ directory at the CMS root (separate from /admin/cache/, see below) holds runtime-generated files. None of these are meant to be edited directly, and all are safe to delete — they rebuild automatically on the next request:
| Path | Contains |
|---|---|
/cache/lang/front/{locale}.php | Compiled, OPcache-friendly front-end locale strings |
/cache/lang/admin/{locale}.php | Compiled admin locale strings |
/cache/sl_idx_article.cache, sl_idx_page.cache, sl_idx_project.cache | Compiled index caches for the split-file data layer |
/cache/sl_categories.cache, sl_tags.cache | Compiled category/tag store caches |
/cache/media-stats.json | Cached media library statistics |
Other key directories
| Path | Purpose |
|---|---|
/assets/css/ | System CSS (gallery layouts, lightbox, search, shortcodes) |
/assets/js/main.js | Front-end JS (search engine, UI) |
/bckps/ | Database backups and template editor backups — direct access blocked by .htaccess |
/bckps/templates/ | Template editor backups, organised by theme name |
/files/ | Media uploads |
/lang/front/ | Front-end locale files (en.json, fr.json, es.json…) |
/lang/admin/ | Admin panel locale files |
/private/contact.secret | 32-byte HMAC key for contact form CSRF tokens |
/private/contact_rate.json | Contact form rate-limiting data per IP (max 5/hour, SHA-256 hashed IPs). Created on the first contact form submission — absent on installs that haven't received one yet |
/private/auth_rate.json | Admin login rate-limiting data — a separate store from the contact form, tracking failed login attempts per IP |
/theme/ | Themes directory |
/plugins/ | Installed plugins — see Plugins below |
/admin/drafts/ | Autosave draft files (draft_*.json) |
Admin panel /admin/
| File | Role |
|---|---|
index.php | Admin router (dispatches via ?action=) — also routes ?action=plugin_page to a plugin's own admin page (see Plugins) |
admin-credentials.php | Hashed admin password, written at install time |
dashboard.php | Dashboard page |
content.php | Content management hub |
file-manager.php | Media manager (drag & drop) |
template-editor.php | Template editor — browse and edit all active theme files (PHP, CSS, JS, JSON) with per-file backups |
batch-optimize.php | Batch image optimisation and WebP conversion |
seo-overview.php | SEO overview for all published content |
sitemap-generator.php | Sitemap generator |
settings.php | Settings handler |
theme-preview.php | Live theme preview (HMAC token-based) |
extension-upload.php | ZIP theme and ZIP plugin import endpoint (read plugin.json or theme.json) |
autosave.php | Draft autosave AJAX endpoint |
auth.php | Authentication (login/logout, IP-based rate limiting) |
alt-text-assistant.php | Gallery image alt text and caption management |
backup-dl.php | Secure backup download proxy |
list-content.php | AJAX endpoint for server-side pagination, search, and sorting |
preview.php | Post preview (published and unpublished, HTML and Markdown) |
forgot-password.php | Password reset request with email link |
reset-password.php | Password reset form |
change-password.php | In-admin password change |
translations-api.php | AJAX endpoint for the translation editor (read/write locale files) |
file-upload.php | File upload endpoint for the media manager |
image-optimization.php | Single image optimisation and WebP conversion endpoint |
get-files.php | File listing endpoint for the media manager |
save-profile.php | Account profile save endpoint |
progress-helpers.php | Server-sent events helper for batch operation progress |
Admin includes /admin/includes/
Shared admin scaffolding, separate from the single-purpose files above and from /admin/templates/:
| File | Role |
|---|---|
admin-functions.php | Shared admin helper functions |
backup-functions.php | Backup creation/restore logic |
extension-update-functions.php | Theme/plugin update-check logic |
session-config.php | Shared session cookie configuration (also required by the front-end index.php for the admin bar) |
header.php, footer.php, layout.php, sidebar.php | Admin panel chrome |
Admin cache /admin/cache/
Distinct from the root-level /cache/ — holds admin-only runtime data:
| File | Contains |
|---|---|
extensions-check.json | Cached plugin/theme update-check results |
update-check.json | Cached core version update-check result |
news-cache.json | Cached admin dashboard news feed |
Admin templates /admin/templates/
| Template | Renders |
|---|---|
content-add.php | Add content form |
content-edit.php | Edit content form |
content-list.php | Content list table |
menu-builder.php | Visual menu builder |
settings-view.php | Settings page |
theme-manager.php | Theme manager with live preview |
categories-manage.php | Category management |
tags-manage.php | Tag management |
drafts.php | Drafts list |
backup.php | Backup management |
account.php | Account settings (name, password) |
translations.php | Translation editor |
update.php | Auto-update interface |
plugins-manager.php | Extensions page — install, activate/deactivate, delete plugins |
contact.php | Contact form submissions viewer |
Plugins
A plugin is a self-contained folder under /plugins/ — its own PHP files, its own JSON data storage, and optionally its own admin page. Plugins never modify core files; installing or deleting one is a matter of adding or removing its folder.
plugins/
└── my-plugin/
├── plugin.json — Manifest: name, slug, version, entry file.
│ Must contain "synaptik_plugin": true or the
│ folder is ignored by the plugin scanner.
├── my-plugin-init.php — Entry file (declared in plugin.json).
│ Registers the admin_menu hook and any
│ front-end behaviour.
├── data/ — Plugin's own data store, .htaccess-protected,
│ created automatically on first write
├── private/ — CSRF secrets, rate-limit stores, etc.,
│ .htaccess-protected
├── admin/
│ ├── admin-page.php — Exposes "{slug}_render_admin_page($view)",
│ │ the contract read by admin/index.php's
│ │ plugin_page router
│ └── actions.php — POST-only endpoint for state-changing
│ admin operations (CSRF-protected)
├── assets/ — Plugin-specific CSS/JS
└── lang/ — Translations, front + admin
How plugins are tracked
plugins.json at the CMS root is the activation registry: { "slug": { "active": true|false } }. A plugin present in /plugins/ but absent from this file (or marked inactive) is installed but dormant — none of its code runs. Activating a plugin from Admin → Extensions is what actually loads it on every request, via pl_load_active_plugins() (called once from core/functions.php).
How plugins integrate with the CMS
- Admin sidebar — a plugin registers its own entry via the
admin_menuhook (pl_on_admin_menu()inplugin-api.php). Its admin page then renders inside the standard admin layout (same sidebar, top bar, footer) throughadmin/index.php?action=plugin_page&slug={slug}. - Front-end output — the core's shortcode pipeline (
render_content_html()) has no filter hook for third-party shortcodes, so a plugin adding one (e.g.[newsletter_signup]) buffers the full page output and resolves its own shortcode string directly, only on genuine front-end HTML responses. - Data storage — each plugin owns its own flat JSON files under its
data/folder, entirely separate from/data/(CMS content). Deactivating a plugin preserves this data; deleting the plugin folder removes it permanently. - Security — plugins do not depend on the core's CSRF/session internals beyond reusing
$_SESSION['admin']for auth. CSRF tokens, rate-limit stores, and any HMAC secrets are generated and stored inside the plugin's ownprivate/folder.
Themes
To learn how themes are structured, please visit the Theme Structure page.
Path changes in v1.2
The following directories were moved in version 1.2. If you are upgrading from 1.1 or earlier and have hardcoded any of these paths in a theme or external script, update them accordingly.
| Before 1.2 | From 1.2 |
|---|---|
/css/ | /assets/css/ |
/js/ | /assets/js/ |
/lang/en.json, /lang/fr.json… | /lang/front/en.json, /lang/front/fr.json… |
Path changes in v1.3.3
The following changes ship in v1.3.3's core restructure. Existing installs are migrated automatically (config key rename, file cleanup) on the first request after upgrading — no manual action needed.
| Before 1.3.3 | From 1.3.3 |
|---|---|
settings.json (root) | config.json (root) |
functions.php, core-functions.php, data-functions.php, data-layer.php, admin-data-layer.php, plugin-api.php, lang-cache.php, search.php, contact-process.php, feed.php (root) | /core/ |
tf-page.php, tf-cards.php, tf-shortcodes.php, tf-navigation.php, tf-markdown.php, theme-api.php (root) | /core/render/ |
/private/contact_rate.json is unchanged — still written by contact-process.php on the first contact form submission. It sits alongside the new /private/auth_rate.json, which is a separate store introduced for admin login rate-limiting; the two do not overlap.
Theme code using the standard API (render_header_scripts(), __t(), _e(), etc.) is unaffected by any of the above — paths are resolved internally and no theme-facing function signature changed.
