BLUDIT PRO 3.22.0 —DEVELOPER REFERENCE (RAW TEXT) Patched codebase (incorporates all fixes from the 3.22.0 patch manifest) Build 20260510, codename "BrownBear" ================================================================================ 1. IDENTIFICATION ================================================================================ BLUDIT_VERSION : '3.22.0' BLUDIT_CODENAME : 'BrownBear' BLUDIT_BUILD : '20260510' BLUDIT_RELEASE_DATE : '2026-05-10' BLUDIT_PRO : true (when pro file is loaded) BLUDIT_PRO_HASH : substr(md5(BLUDIT_BUILD), 0, 8) -> e.g. '5d2fcbb4' Pro file loading (init.php): define('BLUDIT_PRO_HASH', substr(md5(BLUDIT_BUILD), 0, 8)); $_bluditProFile = PATH_KERNEL . 'bludit.pro.' . BLUDIT_PRO_HASH . '.php'; if (file_exists($_bluditProFile)) { include($_bluditProFile); } The pro file is named 'bludit.pro.5d2fcbb4.php' (hash varies per build). ================================================================================ 2. COMPLETE BOOT SEQUENCE (SITE SIDE) ================================================================================ index.php └─ init.php ├─ Constants: BLUDIT_VERSION, codename, build, debug flags ├─ PHP ini (display_errors=0, html_errors=0, log_errors=1) ├─ PATH constants (LANGUAGES, THEMES, PLUGINS, KERNEL, CONTENT, etc.) ├─ User environment variables (boot/variables.php) ├─ mb_internal_encoding / mb_http_output set to CHARSET ├─ Abstract classes (dbjson, dblist, plugin) ├─ Core classes (pages, users, tags, language, site, categories, │ syslog, pagex, category, tag, user, url, login, parsedown, security) ├─ functions.php loaded ├─ Helper classes (text, log, date, theme, session, redirect, sanitize, │ valid, email, filesystem, alert, paginator, image, tcp, dom, cookie) ├─ BLUDIT_PRO_HASH computed, pro file included if exists ├─ Objects created: $pages, $users, $tags, $categories, $site, $url, │ $security, $syslog ├─ HTML_PATH_ROOT and all DOMAIN_* / HTML_PATH_* constants defined ├─ $language = new Language($site->language()) ├─ $url->checkFilters($site->uriFilters()) ├─ TAG_URI_FILTER, CATEGORY_URI_FILTER, PAGE_URI_FILTER defined ├─ ORDER_BY, EXTREME_FRIENDLY_URL, AUTOSAVE_INTERVAL, IMAGE_RESTRICT, │ IMAGE_RELATIVE_TO_ABSOLUTE, MARKDOWN_PARSER defined ├─ THEME_DIR_* and DOMAIN_* constants finalized ├─ $ID_EXECUTION = uniqid() ├─ $WHERE_AM_I = $url->whereAmI() └─ $L = $language (shortcut) └─ site.php ├─ 60.plugins.php → buildPlugins() populates $plugins, $pluginsInstalled ├─ Theme::plugins('beforeAll') ├─ 60.router.php → trailing-slash redirects ├─ 69.pages.php → builds $content, $page, $staticContent │ ├─ Scheduler auto-publishes scheduled pages and fires │ │ 'afterPageCreate' hooks for each key (patched: passes correct key array) │ ├─ Preview tokens use site's random previewSalt (patched) │ ├─ buildStaticPages() → $staticContent │ ├─ If homepage set + whereAmI='home' → buildThePage() w/ homepage slug │ ├─ Else if whereAmI='page' → buildThePage() │ ├─ Else if whereAmI='tag' → buildPagesByTag() │ ├─ Else if whereAmI='category' → buildPagesByCategory() │ ├─ Else if whereAmI='home' or 'blog' → buildPagesForHome() │ ├─ $page = $content[0] (if set) │ └─ If $url->notFound() → $page = buildErrorPage() ├─ 99.header.php → HTTP status header + X-Powered-By ├─ 99.paginator.php → Populates Paginator::$pager │ └─ Theme::plugins('paginator') ├─ 99.themes.php → Loads theme language, $themePlugin = getPlugin($site->theme()) ├─ Theme::plugins('beforeSiteLoad') ├─ Theme init.php (if exists) ├─ Theme index.php ← THEME RENDERS HERE ├─ Theme::plugins('afterSiteLoad') └─ Theme::plugins('afterAll') ================================================================================ 3. ADMIN BOOT SEQUENCE ================================================================================ admin.php ├─ Session::start() ├─ $login = new Login() ├─ $layout array built from URL slug ├─ 60.plugins.php → $pluginsInstalled populated ├─ Plugin admin controller detection (case-insensitive) ├─ If slug === 'ajax' → 99.security.php → load AJAX file └─ Else (admin area): ├─ 69.pages.php ├─ 99.header.php ├─ 99.paginator.php ├─ 99.themes.php ├─ 99.security.php ├─ If notFound or not logged → login ├─ Theme::plugins('beforeAdminLoad') ├─ Admin theme init.php (if exists) ├─ Controller loaded ├─ Admin theme index.php or login.php └─ Theme::plugins('afterAdminLoad') ================================================================================ 4. COMPLETE HOOKS REGISTRY ================================================================================ Site Hooks: beforeAll – site.php, before router (earliest hook) afterAll – site.php, after theme (final hook) beforeSiteLoad – site.php, before theme init (content built, paginator ready) afterSiteLoad – site.php, after theme render siteHead – Must be called by theme in
siteBodyBegin – Theme start siteBodyEnd – Theme siteSidebar – Theme sidebar (sorted by plugin position) pageBegin – Before page content pageEnd – After page content paginator – 99.paginator.php, after Paginator::$pager populated Admin Hooks: beforeAdminLoad – admin.php, before theme afterAdminLoad – admin.php, after theme adminHead – Admin adminBodyBegin – Admin start adminBodyEnd – Admin adminSidebar – Admin sidebar (plugin sidebar links) adminContentSidebar– Admin content sidebar dashboard – Admin dashboard area editorToolbar – Content editor toolbar Content Lifecycle Hooks: afterPageCreate – Page created (args: array($key)). Fires for manual and scheduler creation. afterPageModify – Page edited (args: array($key)) afterPageDelete – Page deleted (args: array($key)) Login Hooks: loginHead – Login page loginBodyBegin – Login page body start loginBodyEnd – Login page body end ================================================================================ 5. PLUGIN SYSTEM INTERNALS ================================================================================ 5.1 Plugin Base Class (Plugin – /bl-kernel/abstract/plugin.class.php) Constructor Lifecycle: 1. $this->dbFields = array() 2. $this->customHooks = array() 3. Directory name auto-detected via ReflectionClass 4. Class name auto-detected 5. $this->formButtons = true 6. $this->init() – YOUR CODE: define dbFields, customHooks 7. $this->db = $this->dbFields (default values) 8. filenameDb and filenameMetadata set 9. If plugin is installed: - Database loaded from file into $this->db - $this->prepare() called 5.2 Plugin Properties $this->dbFields (array) – Set in init() $this->db (array) – Set by constructor $this->formButtons (bool) – Set in init() $this->customHooks (array) – Set in init() $this->directoryName (string) – Auto-detected $this->className (string) – Auto-detected $this->metadata (array) – Auto-detected 5.3 Plugin Methods (complete) init() – Define $this->dbFields prepare() – Called after database loaded form() – Return settings HTML post() – Handle settings form POST save() – Persist database install($position) – Create workspace + database uninstall() – Delete workspace + database installed() – Check if database file exists getValue($field, $html=true) – Returns sanitized value; returns null when field is not defined (patched: isset check before accessing dbFields fallback) setField($field, $value) – Set + persist setPosition($position) – Sidebar position getMetadata($key) – Read metadata setMetadata($key, $value) – Set metadata (runtime) includeCSS($filename) – Output tag includeJS($filename) – Output