⌘K

Routing

Every unknown URL is rewritten to index.php by the root .htaccess. parseRequestUri() (in core/data-functions.php) then turns the URI into a routing decision.

ℹ️

parseRequestUri() reads $GLOBALS['data']['page'] directly and its position in the bootstrap order is fixed — index.php also writes its results back into $_GET. Treat $_GET as untrusted in this request cycle regardless of where a value appears to originate.


parseRequestUri(): array

Reads the url_slug_* values from the active front-end locale, splits the URI into segments, and applies:

SegmentsPatternResult
(empty)Homepage
{plural_slug}/e.g. articles/Content-type list page
{cat_slug}/2+ segments, prefix = category slugCategory page
{tag_slug}/{name}/Tag page
{type_slug}/{slug}/Article or page, no categorySingle content item
{type_slug}/{cat…}/{slug}/Project with hierarchical categorySingle project

Returns a normalised [type, slug, category, tag] array.


Localized URL slugs

"url_slug_article":  "article",
"url_slug_articles": "articles",
"url_slug_project":  "project",
"url_slug_projects": "projects",
"url_slug_page":     "page",
"url_slug_pages":    "pages",
"url_slug_category": "category",
"url_slug_tag":      "tag"

These same keys drive cleanUrl() (URL generation), parseRequestUri() (parsing), and admin content links — one source of truth. Settings → Reading can rename content types for display, but the URL segments themselves still come from these locale keys.


Bootstrap load order

index.php
  ├── core/llms.php or llms-full.php   ← short-circuits before functions.php if ?_llms is set
  └── core/functions.php
        ├── core-functions.php
        ├── data-functions.php
        ├── render/theme-api.php  →  tf-markdown, tf-shortcodes, tf-cards, tf-navigation, tf-page
        ├── data-layer.php
        ├── plugin-api.php           ← pl_load_active_plugins()
        └── lang-cache.php
  ↓
loadConfig()
sl_build_data_array(['article','page','project'], false)  → $GLOBALS['data']
  ↓
parseRequestUri()  → routing
  ↓
if single item:  sl_load_item_by_slug()  →  $data[$type] = [$fullItem]
  ↓
processContent() / renderCategoryPage() / renderTagPage()
  ↓
loadThemeTemplate('header', …) → echo $pageContent → loadThemeTemplate('footer', …)

Plugin hooks fire at two points in this cycle: early_request right after functions.php finishes loading (before routing or output — for blocking/redirecting the whole request), and after_routing once the route is resolved, with a flag for whether it's a genuine 404.