Data Layer

SynaptikCMS uses a split-file architecture: each content item is stored in its own JSON file, with a lightweight index per type for fast loading without reading every item.


Two layers, two responsibilities

FileFunction prefixRole
data-layer.phpsl_Read-only — index, items, categories, tags, internal cache
admin-data-layer.phpsl_admin_Write — save item, update index, delete, save categories/tags

The read layer maintains an internal cache in $GLOBALS['_sl_cache'] to avoid re-reading files multiple times per request. The write layer invalidates this cache after every operation.


Index vs. full item

Lightweight index (_index.json) — loaded on every request. Contains metadata only:

_file, slug, custom_slug, title, date, category, tags, image, show_in_menu, menu_order

Additional per-type fields: articles → summary, show_on_homepage; projects → description, show_on_homepage; pages → page_template.

Full item file ({slug}.json) — loaded only for single-item views. Contains everything: HTML content, SEO fields, galleries, show_date, show_title, og_image, etc.


How index.php loads data

Step 1 — Lightweight index for all types (always):

$data = sl_build_data_array(['article', 'page', 'project'], false);
$GLOBALS['data'] = $data;

Step 2 — Full item for single-item views:

// On /article/my-slug/
$data['article'] = [$fullItem]; // Overwrites the index with a single full item
$GLOBALS['data'] = $data;

⚠️

$data[$type] is volatile. On list pages it contains the full index. On single-item pages it contains only that one item. Never assume $GLOBALS['data']['article'] holds all articles — use slloadindex('article') when you need the full catalogue.


Read layer functions (sl_*)

sl_load_index(string $type): array

Load and return the lightweight index for a type ('article', 'page', 'project'). Result is cached for the full request.

sl_load_item(string $type, string $fileSlug): array

Load full data for an item from its individual file. $fileSlug is the _file field from the index.

sl_load_item_by_slug(string $type, string $effectiveSlug): ?array

Load a full item by its public slug (custom_slug ?: slug). Used by the router.

sl_load_all_items(string $type): array

Load all full items for a type. Expensive — use only when content bodies are needed (search, SEO overview, sitemap).

sl_load_categories(): array

Load the category store. Result is cached.

sl_load_tags(): array

Load the tag store. Result is cached.

sl_build_data_array(array $types, bool $fullItems = false): array

Build the legacy-compatible $data array.
$fullItems = false → lightweight index.
$fullItems = true → full items.

sl_effective_slug(array $item): string

Return custom_slug ?: slug for an item or index entry.

sl_file_slug(array $entry): string

Return the _file slug from an index entry (JSON filename without .json).

sl_find_in_index(string $type, string $effectiveSlug): ?array

Search an index for an entry by public slug. Returns [entry, position] or null.