⌘K

File Structure

Root /

FileRole
index.phpFront-end router
install.phpFirst-run installer
config.jsonSite settings flat-file store (admin folder name, active theme, language, SEO defaults, canonical_host…) — direct access blocked
version.jsonCurrent CMS version, checked against the update registry

plugins.json (plugin activation registry) lives in /plugins/, not the root — see Plugins.

composer.json/package.json at the root are dev-only tooling (PHPUnit, JS/CSS minifiers for the release build) — never shipped, excluded by export-release.sh. There is still no runtime Composer autoloader and no build step for the CMS itself.


Core libraries /core/

Most of these are now thin loaders (a handful of require_once lines, no logic of their own) that pull in focused modules from a matching subdirectory. This split happened without renaming any public function, so every call site elsewhere in the codebase — and everything in this doc — still refers to the loader's filename, not the module it delegates to.

FileRole
functions.phpBootstrap loader — requires core-functions.php, data-functions.php, render/theme-api.php, data-layer.php, plugin-api.php, then lang-cache.php, then the active theme's functions.php (and its child-theme override, if any), then pl_load_active_plugins()
core-functions.phpLoader → core/content/render-helpers.php, dispatch.php, galleries.php
data-functions.phpRouting, SEO, category/tag page rendering, parseRequestUri(), getCategoryPath() — not split, still one file
data-layer.phpLoader → core/data/* (read-only sl_* functions)
admin-data-layer.phpLoader → core/admin/* (write sl_admin_* functions)
plugin-api.phpPlugin registry, activation state, admin-menu hook, pl_* hook/filter system — not split
lang-cache.phpi18n cache and locale management (__t(), _e(), __n(), lang_js_bridge())
search.phpSearch endpoint
contact-process.phpContact form handler
feed.phpRSS feed
llms.php / llms-full.phpServe /llms.txt and /llms-full.txt (LLM indexer files) — loaded standalone, before functions.php, to stay lightweight

core/content/ — what core-functions.php now delegates to

FileRole
render-helpers.phpresolve_admin_dir() and related front-end render helpers
dispatch.phpprocessContent() — resolves a request into a rendered item, including the content-generic fallback for custom content types
galleries.phpgetGalleryScripts() and other gallery-layout helpers

core/data/ — what data-layer.php loads

FileCovers
cache.php_sl_cache_get()/_sl_cache_set() — APCu-or-file cache primitive
page-cache.phpFull-page HTML cache (sl_page_cache_get/set, _sl_page_cache_file()) — see Security for the cache-key rule
item-store.phpsl_load_index(), sl_load_item(), sl_load_item_by_slug(), sl_item_path(), sl_load_all_items()
taxonomy-store.phpCategory/tag loading
type-registry.phpsl_content_types(), sl_content_type(), sl_content_type_exists(), sl_all_type_slugs(), sl_type_dir() — the content-type registry read side, see Data Layer
misc.phpBootstrap-adjacent helpers that didn't fit elsewhere

core/admin/ — what admin-data-layer.php loads

FileCovers
bootstrap.phpsl_admin_ensure_dirs() and other setup helpers
media.phpMedia/upload bookkeeping used by the write path
writer.php_sl_write_json() — atomic write, temp file (PID-suffixed, see Security) + rename()
content-types.phpsl_admin_register_content_type(), sl_admin_update_content_type(), sl_admin_unregister_content_type() — the registry write side
activity-log.phpAdmin activity log writes
items.phpContent save/update entry points
trash.phpTrash/restore
revisions.phpRevision snapshots and diffing
index-store.phpRewriting a type's _index.json after a write

Rendering /core/render/

FileRole
theme-api.phpRequires the render files below, plus the hook/filter/theme-options system
tf-page.phpLoader → core/render/page/*
tf-cards.phpArticle/project cards, homepage sections, summaries, related items, custom fields
tf-shortcodes.phprender_content_html() pipeline and every shortcode renderer
tf-navigation.phprenderHierarchicalMenu(), renderDefaultMenu()
tf-markdown.phpMarkdown parser, container directives (:::type)
asset-registry.phpenqueue_css()/enqueue_js()/render_enqueued_assets(), plus sl_content_needs_shortcode_assets()/sl_content_needs_gallery_assets() — see Front-End Asset Registry

core/render/page/ — what tf-page.php loads

FileCovers
identity.phpSite logo/favicon helpers
meta.phprender_meta_tags()
assets.phprender_header_scripts(), the highlight.js/collapsibles conditional includes (reads global $pageContent)
content-pieces.phpPer-item render helpers: title, date, category, tags, gallery
footer.phprender_footer_content()
theme-helpers.phpMisc theme-facing helpers
search.phprender_search_ui(), render_search_icon()

Data directory /data/

data/
├── content-types.json          — custom content-type registry (built-ins are not stored here, see Data Layer)
├── articles/{_index.json, {slug}.json…}
├── pages/{_index.json, {slug}.json…}
├── projects/{_index.json, {slug}.json…}
├── {custom-type}/{_index.json, {slug}.json…}   — one directory per registered custom type
├── drafts/{draft_*.json…}       — in-progress items before first publish
├── categories.json
└── tags.json

A custom type's storage directory is its identifier exactly as entered (no automatic pluralization) — only the three built-in types get the legacy s-suffixed directory name. Every content item also has its own trash and revisions store, created on demand next to its type folder (see Data Layer).


Cache /cache/

Nothing here is hand-edited; every file rebuilds automatically and is safe to delete.

PathContains
lang/front/{locale}.php, lang/admin/{locale}.phpCompiled locale strings
sl_idx_{type}.cache.phpCompiled index caches
sl_categories.cache.php, sl_tags.cache.phpCompiled taxonomy caches
media-stats.jsonCached media library stats
htaccess-check.jsonCached dashboard check for public /data/ exposure on nginx

Other key directories

PathPurpose
/assets/css/search.css, shortcodes.css, gallery-layout.css (galleries and collapsibles/tabs — the name is legacy, see Front-End CSS Tokens), lightbox.css, hljs-theme.css, and the synaptikCSS.php combiner
/assets/js/front-boot.js (data islands, always loaded) plus features/{search,lightbox,collapsibles}.js (search always loaded, the other two conditional — see Front-End Asset Registry)
/bckps/Backups: full-site exports, update safety snapshots, template editor file backups
/files/Media uploads
/lang/front/, /lang/admin/Locale files
/private/Never web-accessible: users.json, contact.secret, theme_preview.secret, contact_rate.json, auth_rate.json, search_rate.json, activity-log.json, audit-log.json
/theme/Installed themes, plus theme/child_theme/{name}/ overrides
/plugins/Installed plugins, plus plugins.json (activation registry)

Admin panel /admin/

The admin folder name is configurable at install time and read from config.json['admin_dir'] — never hardcoded. Key files:

FileRole
index.phpAdmin router (?action=), including ?action=plugin_page for plugin admin pages
content.phpContent save/delete/trash/restore/revision action dispatch — delegates the heavy lifting to admin/includes/content-handlers.php
manage-users.phpMulti-user account create/update/delete/role-change
file-manager.php, file-upload.php, get-files.php, image-optimization.php, batch-optimize.phpMedia manager
template-editor.phpTheme file editor with per-file backups
theme-preview.phpLive theme preview (signed token) — also backs the editor's Preview button (there is no separate preview.php anymore)
extension-upload.phpZIP import for themes and plugins
autosave.phpDraft autosave endpoint
seo-overview.php, alt-text-assistant.php, sitemap-generator.phpSEO tools
auth.php, forgot-password.php, reset-password.php, change-password.phpAuthentication
translations-api.phpTranslation editor AJAX endpoint
list-content.phpServer-side pagination/search/sort for the content list
backup-dl.phpBackup download proxy

/admin/includes/

admin-functions.php is now a loader → admin/includes/functions/{bootstrap,config,users,content-builder,session-bridge,themes,theme-editor,updates}.php. Alongside it: content-handlers.php (content add/edit/menu-sync/image-upload logic used by content.php), content-purify.php, backup-functions.php, extension-update-functions.php, admin-icons.php, zip-validation.php, htaccess-manager.php, session-config.php, layout.php (admin <head>/topbar/sidebar shell), sidebar.php, template-renderer.php (admin_render_template() — explicit $vars array instead of ambient-scope include, used by every action-dispatch template include in content.php).

/admin/assets/

admin/assets/css/ and admin/assets/js/ hold the admin panel's own stylesheets and scripts (distinct from the front-end /assets/ at the project root) — admin-base.css, admin-components.css, admin-content.css, admin-sidebar.css, editor-layout.css, admin-filemanager.css, and one JS file per admin screen plus shared boot scripts (admin-boot.js, theme-boot.js, common.js, etc.).

/admin/templates/

content-add.php, content-edit.php, content-list.php, content-types-manage.php, trash.php, revision-diff.php, pending-diff.php, activity-log.php, users.php, system-info.php, menu-builder.php, settings-view.php, theme-manager.php, categories-manage.php, tags-manage.php, backup.php, account.php, translations.php, update.php, plugins-manager.php, contact.php. Each is called via admin_render_template() with an explicit variable list, not raw include.

/admin/cache/

extensions-check.json, update-check.json, news-cache.json — all disposable, admin-only, distinct from the root /cache/.


Plugins

plugins/
├── plugins.json          — activation registry: { "slug": { "active": bool } }
└── my-plugin/
    ├── plugin.json        — manifest, must set "synaptik_plugin": true
    ├── my-plugin-init.php — entry file declared in plugin.json
    ├── data/               — plugin's own JSON store, .htaccess-protected
    ├── private/            — CSRF secrets, rate-limit stores, .htaccess-protected
    ├── admin/{admin-page.php, actions.php}
    ├── assets/
    └── lang/

A plugin present on disk but absent (or inactive) in plugins.json never runs — activating it is what loads it, via pl_load_active_plugins() in core/functions.php. See the Plugins category for the hook/filter API and integration points.


Version history of this layout

ChangeSince
/css/, /js/ → /assets/css/, /assets/js/; /lang/*.json → /lang/front/*.json1.2
settings.json → config.json; root PHP libraries moved to /core/ and /core/render/; plugin registry moved to /plugins/plugins.json1.3.3
Autosave drafts moved from /admin/drafts/ into /data/drafts/ (drafts are now real, trashable, revisable content)1.4.0
/private/users.json (multi-user accounts), /private/activity-log.json, per-item trash and revisions folders added1.4.0
data/content-types.json (custom content-type registry); admin/css/, admin/js/ moved to admin/assets/css/, admin/assets/js/; admin/preview.php removed (folded into theme-preview.php)1.4.6
core/data-layer.php, core/admin-data-layer.php, core/core-functions.php, core/render/tf-page.php, and admin/includes/admin-functions.php became thin loaders over core/data/, core/admin/, core/content/, core/render/page/, and admin/includes/functions/ respectively — a maintainability split, no function renamed or moved in behavior1.4.6

Upgrades migrate all of the above automatically on first load — no manual action needed. Theme code using the standard API (render_header_scripts(), __t(), _e(), etc.) is never affected by internal path changes.