Журнал изменений
getAdminInfo() was an AJAX duplicate of setTplAdminInfoPage() reachable only via the index.php dispatch case 'getAdminInfo', which nothing in the UI ever triggered. Drop the function and its dispatch case.
The info/help tab in every admin section reused the generic _INFO label ('Информация'). Introduce a dedicated _DOCS constant ('Справка' / 'Documentation') in all six locales and switch the tab bars to it, leaving _INFO for the generic tooltip/nav usages that genuinely mean 'information'.
Bring admin inputs to the same modern validation UX as lite and remove duplicate or ambiguous class hooks, keeping the admin palette.
Core changes:
- Modern validation (assets/css/base.css):
- Replace required:valid/:invalid text coloring with :user-invalid/:user-valid border and ring
- Add danger and success focus tokens
- Wrap the over-specific input :hover exclusions in :where() so focus and validation win
- Class consolidation (assets/css/theme.css, fragments, partials):
- Rename the .sl-field width utility to .sl-field-auto so it no longer clashes with the lite .sl-field
- Reduce the duplicated .sl-changelog-filter-field input rule to width:100%
- Toggle ids sl_block_ become sl-block-; drop the dead --sl-shadow-input fallback
Benefits:
- Consistent modern validation across both themes
- Unambiguous class names and less duplication
Technical notes:
- :user-invalid and :where() target modern browsers
- Visual behavior preserved; neutral value text
Give the lite theme one field look, modern validation, a Yes/No switch and custom checkbox aligned with admin, and remove legacy class hooks.
Core changes:
- Unified field styling (assets/css/base.css, assets/css/theme.css):
- Canonical .sl-field for input/textarea/select with focus ring and disabled state
- Field height aligned to the 30px buttons; neutral value text
- :user-invalid/:user-valid validation as border and ring, only after interaction
- Form field, checkbox and switch design tokens
- Controls aligned with admin (assets/css/theme.css, fragments):
- Custom checkbox with brand check mark
- Yes/No segmented switch (.sl-radio-switch) in the lite green palette
- Class consolidation:
- Tabs hook div[id^="sl_tabs_"] becomes .sl-tabs plus data-sl-tabs with a hyphenated id (assets/js/tabs.js, fragments/navi-tabs-wrap.html)
- Toggle ids sl_block_ become sl-block- (partials/block-sidebar.html)
- Tokenize duplicate and seasonal colors; drop the dead --sl-shadow-input fallback
Benefits:
- One field class and a consistent modern look across lite forms
- No underscore class or id hooks left
- Easier theming through tokens
Technical notes:
- :user-invalid, :where() and :has() target modern browsers
- No markup behavior change beyond class and id renames
Derive the input type from the field name in one shared place so admin and lite stop repeating per-call-site itype, and semantically equal fields can no longer drift apart.
Core changes:
- Input-type derivation (core/classes/template.php):
- Add getInputType() mapping field names to email/url/password
- Apply it in getHtmlFrag() for the input fragment
- Explicit itype always overrides the derived default
- Redundant itype sweep (admin/index.php, modules/*):
- Drop now-derived itype for mail/url/password fields across modules
- Set email/url types for guest author and site fields (files, links, auto_links)
- Keep special cases explicit (whois domain/host/dc, changelog ghtoken)
Benefits:
- Single source of truth for input type across both themes
- Native :user-invalid validation now works on email/url everywhere
- Less duplication and no per-module type drift
Technical notes:
- No database or schema changes
- Behavior preserved; only the default type derivation moved to the core
Relicense SLAED CMS from GPL-3.0 to MIT and remove the runtime license lock. The project author relicenses their own work, so attribution enforcement is dropped and the obfuscated copyright config is retired.
Core changes:
- License text and metadata (LICENSE, composer.json, package.json, README.md):
- Replace the GPL-3.0 text with the MIT license and update license fields/badges
- Source headers (~396 .php, .htaccess, setup/sql/.sql):
- Change "# License: GNU GPL 3" to "# License: MIT"
- Normalize the copyright line to "# 2005 - 2026 SLAED"
- Runtime license lock removal (core/system.php, setup/index.php):
- Remove the _NO_LICENSE admin and setup lock checks
- Drop the lic_h/lic_f config keys and their forced rewrite on config save
- Replace the four footer builders with a single getLicenseHtml()
- Decouple the legacy md5 password salt into a frozen PASS_SALT constant
- Remove the now-dead _NO_LICENSE constant from all locale files
- Documentation (README, CONTRIBUTING, SECURITY, UPGRADING, CODE_OF_CONDUCT, .rules/architecture.md):
- Replace GPL references with MIT
Technical notes:
- Legacy md5 logins keep working through the frozen PASS_SALT value
- Historical news seed data in setup/sql/insert.sql is left intact on purpose
- Third-party code under plugins and vendor is not touched
Adjust footer CSS so the MIT license line reads cleanly after the relicense changed the text length.
Core changes:
- Site footer (templates/lite/assets/css/theme.css):
- Center .sl-copyright/.sl-license and balance the wrapped lines
- Admin login footer (templates/admin/assets/css/theme.css):
Reduce .sl-admin-login-copyright font-size so the line fits one row on desktop and narrow widths
Benefits:
- Footer license stays readable and centered without clipping
Replace the hardcoded 'pages-v1' prefix in the page-cache key with the CMS version, so every SLAED release automatically invalidates stale page caches on update without a developer remembering to bump a magic string or admins running a manual cache wipe.
Core changes:
- Cache key composition (core/system.php):
- Use $conf['version'] as the first hash part in getPageHash() instead of 'pages-v1'
- Add $conf to the function globals and fall back to an empty string when unset
- Update the function comment to list the real identity parts
Benefits:
- Page cache regenerates lazily after every version upgrade, fleet-wide
- No buried version literal to maintain by hand
Technical notes:
Content edits keep invalidating through the epoch counter; the version part covers code/release level invalidation
- Regeneration is lazy per request; old files are reclaimed by the GC sweep
Surface the single-flight page-cache rebuild as an admin setting and harden the runtime so it is safe to enable on production sites. Default stays off; the behavior itself was added in the prior page-cache overhaul.
Core changes:
- Admin toggle (admin/modules/config.php):
- Add a yes/no control with hint for cache_l in the cache settings block
- Persist cache_l from the config save handler
- Read with a '0' fallback so the form is safe before local.php is regenerated
- Localized strings (admin/lang/de.php, en.php, fr.php, pl.php, ru.php, uk.php):
- Add _CACHELOCK label and _CACHELOCKINFO hint across all six languages
- Phrase the label per locale; keep the English "single-flight" term only in en
- Runtime hardening (core/system.php, core/classes/cache.php):
- Skip serving an empty stale body so waiting requests never get a blank page
- Keep held rebuild locks fresh with touch() so the sweeper leaves them alone
- Garbage-collect stale lock files via deleteStale('locks') and a SWEEP list
- Documentation (admin/info/config/ru.md):
- Describe cache_l as recommended for high-traffic projects, off by default
Benefits:
- Admins can enable single-flight rebuilds without editing config files
- No blank pages under concurrent expiry; lock directory stays bounded
Technical notes:
- cache_l default lives in config/global.php and is read via empty()
- Lock files live under storage/cache/pages/locks and are swept by the GC job
Cold-start (no stale file yet) is not de-duplicated by design; single-flight only applies once a previous version exists
Rework the full-page HTML cache so it scales for high traffic: normalize the cache key, serve correct browser/CDN headers, retain files by age, invalidate on content change, and collapse concurrent rebuilds. Generation timing now shows on cached responses without baking a stale value into the stored file.
Core changes:
- Generation timing on cached pages (core/system.php):
- Replace the per-render time string with a GEN_MARK sentinel baked into the body
Add getTimedHtml() to swap the marker for live timing right before output, or strip it when generation timing (db_t) is off
- Inject on both the live echo and the page-cache hit path
- Cache key normalization (core/classes/cache.php, core/system.php):
Add Cache::filterCacheUrl() to drop tracking parameters (utm_*, gclid, yclid, fbclid, _openstat) and order query groups while preserving array order
- Feed it into getPageHash() so equivalent URLs map to one cache file
- Browser/CDN headers and conditional GET (index.php, core/classes/cache.php, core/system.php):
- Replace the premature public header in index.php with a safe no-store default
Send public Cache-Control plus a real Last-Modified (file mtime) only for cacheable guest pages, and answer If-Modified-Since with 304
Add Cache::checkNotModified(); suppress browser caching while db_t is on so the timing line never goes stale
- Retention-based garbage collection (core/classes/cache.php, core/system.php, admin/info/config/ru.md):
- Add Cache::deleteStale() to remove page-cache files older than max(cache_t*24, 86400)
- Switch addCacheGcTask() from a full wipe to the retention sweep
Document that cache_t is HTML freshness, cache_d is browser max-age, and GC retention derives from cache_t
- Global epoch invalidation (core/classes/cache.php, core/system.php, core/classes/pdo.php, index.php):
Add Cache::getEpoch()/addEpoch() with a once-per-request flock bump; include the epoch in getPageHash() so a bump invalidates every cached page
Bump from the DB layer on successful state-changing SQL under ADMIN_FILE, which covers all admin content modules through one hook
- Bump on frontend comment, post and voting submissions
- Single-flight rebuild (core/classes/cache.php, core/system.php, config/global.php):
Add Cache::getRebuildLock()/setRebuildFree() using a non-blocking flock with shutdown release; serve the stale file when another worker already rebuilds
- Gate behind the new cache_l config flag, default off
Benefits:
- Tracking-only URL variants share one cache file instead of fragmenting it
- Cached pages can be revalidated by the browser/CDN with 304 instead of full sends
- Disk stays bounded; content edits no longer wait up to cache_t to refresh
- Concurrent expiry no longer triggers a thundering herd of full rebuilds
Technical notes:
New config flag cache_l (default 0); cache_b now also fixes public headers on non-cacheable HTML
Epoch and lock files live under storage/cache/pages; deleteStale and deleteAll preserve .htaccess and index.html
Single-flight serves stale only when cache_l is enabled; otherwise behavior is unchanged