Журнал изменений
getTemplateDebugComment() previously returned an HTML comment in dev mode, invisible to developers scanning page output. Now it renders a visible warning block via the new/alert fragment for immediate notice.
Core changes:
- Upgrade debug output (core/classes/template.php):
Build a human-readable error message using _TPLMISS sprintf pattern
- Shows the expected directory path and recommended filename
Attempt to render via new/alert fragment (is_warn=true) using safe text
- Falls back to plain escaped text if the alert fragment is missing
- Add _TPLMISS lang constant (lang/*.php — all 6 languages):
- Format: sprintf-compatible with %1$s (path) and %2$s (filename)
- Added to de, en, fr, pl, ru, uk
Benefits:
- Template errors are immediately visible in dev mode, not buried in source
- Localised error message gives the exact path and filename to create
Technical notes:
- Only active when isDevMode() returns true — no production impact
- Safe fallback: if alert fragment itself is missing, returns escaped text
Two enhancements to tab state management in the admin UI, both needed for the config module where tabs are URL-persistent (tab=N param).
Core changes:
- Support data-sl-tabs-index on root tab container:
Before restoring from sessionStorage, check data-sl-tabs-index attr
- PHP sets this attribute to the server-known active tab index
- Takes priority over sessionStorage to ensure correct initial state
- Sync info-link href when user switches tabs:
- On tab click, find all [data-sl-tab-info-link="group"] anchors
Update their href's ?tab= param to match the newly active tab index
- Ensures the INFO link always opens the info page on the correct tab
Benefits:
- Tab state survives page reloads without sessionStorage inconsistency
- INFO navigation link stays in sync with visible tab across all switches
Technical notes:
- Uses URL/searchParams API with try/catch for IE11 safety
- data-sl-tab-info-link is scoped to a tab group name to avoid conflicts
Add optional rendering attributes to core admin fragments to support richer module UI without PHP-level HTML construction.
Core changes:
- alert.html:
Add 'lines' array support: renders each line in a <div> inside the alert
- Usable alongside or instead of 'text'
- input.html:
- Add 'is_config' flag: appends class="sl-select-config" when set
- textarea.html:
- Add 'is_config' flag: appends class="sl-select-config" when set
- Add 'is_required' flag: appends required attribute
- form.html:
- Guard 'rows' block with {% if rows %} to allow forms with no table rows
- Add 'content_html' slot: raw HTML rendered after rows (before submit)
- tabs.html:
Add 'init_attr' slot: raw HTML attributes injected into root <div>
- Used to pass data-sl-tabs-index from PHP
- tabs-link.html:
Add 'link_attr' slot: raw HTML attributes injected into <a> tag
- Used for data-sl-tab-info-link on info navigation links
Benefits:
- Reduces ad-hoc HTML string construction in PHP modules
- Enables tab index persistence and info-link URL sync via data attributes
Previously admin info pages required callers to pass 'tab' explicitly to select the active tab (e.g. 'tab' => 3). This was brittle: adding or reordering tabs broke the highlight silently.
Core changes:
- Fix default tab selection (core/helpers.php):
setTplAdminInfoPage: if 'tab' not provided, default to last tab index
- Was: $tab = (int)($data['tab'] ?? 0) — always selected first tab
- Now: auto-selects last tab ($tabs ? count($tabs) - 1 : 0)
- Remove hardcoded 'tab' from admin modules:
- admins.php: remove 'tab' => 2 from info()
- blocks.php: remove 'tab' => 5 from info(); expand inline call to multiline
- comments.php: remove 'tab' => 3 from info()
- content/admin/index.php: remove 'tab' => 3 and inline $ops variable
Benefits:
- Info tab auto-highlights without manual index tracking
- Immune to tab reordering: callers no longer need to count tabs
Technical notes:
- 'tab' key still accepted if caller needs to override default
- blocks.php inline expanded to multiline for readability only
block-error.js used window.onerror = () => true to silently suppress all JS errors globally — a pattern common in CMS code circa 2005-2012, now considered an antipattern that blocks error monitoring tools.
Core changes:
- Remove JS error suppressor (plugins/system/block-error.js):
Delete block-error.js file entirely
- SymError / window.onerror global suppression removed
- Clean up runtime injection (core/system.php):
- Remove conditional array_merge that injected block-error.js into script list
- Remove error_java setting (config/security.php, admin/modules/security.php):
- Drop error_java key from config defaults
- Remove config() field row and configsave() handler for error_java
- Remove hardcoded tab index from info()
- Remove _SEC_VIEW_JAVA lang constant (admin/lang/*.php):
- Deleted from all 6 language files (de, en, fr, pl, ru, uk)
Benefits:
- Removes antipattern that silently hid JS errors in production
- Allows error monitoring tools (Sentry etc.) to work correctly
- Simplifies security config: one less setting to maintain
Technical notes:
- No backward-compatibility concern: setting was opt-in, default was suppression-on
- Admin UI no longer shows the JS error toggle
Continues the systematic migration of admin modules to the canonical new/* fragment layer, replacing all legacy helper functions and old fragment names with the new unified API. Adds CSRF token protection to all state-changing operations and introduces new template fragments for comments and pagination.
Core changes:
- Admin module — admins (admin/modules/admins.php):
- Replace getTplAdminNavi() → getTplAdminTabs() throughout
- Migrate all form fields to new/input, new/checkbox, new/select, new/textarea
- Inline getAdminself() and getAdminmods() into call sites; remove dead functions
- Add checkSiteToken() guard to save() and delete()
- Switch delete() from POST aid to GET req with token validation
- Migrate table head to array format for new/table fragment
- Admin module — blocks (admin/modules/blocks.php):
- Replace all getTplAdminNavi() → getTplAdminTabs()
- Migrate all form rows to new/form with row array structure
- Add checkSiteToken() guard to addsave() and filecode()
- Validate bfile via regex before use; sanitize filenames in filecode()
- Fix block-file code extraction regex (cleaner preg_replace approach)
- Pass getSiteToken() into getAdminBlockList()
- Admin module — categories (admin/modules/categories.php):
- Same API migration pattern as admins/blocks
- Admin module — comments (admin/modules/comments.php):
- Same API migration pattern; new comment and bulk-action fragments
- System layer (core/system.php):
- Supporting changes for new fragment API helpers
- New template fragments:
- templates/admin/fragments/comment-bulk-actions.html
- templates/admin/fragments/comment.html
- templates/admin/fragments/new/label-item.html
- templates/admin/fragments/pagenum.html
- templates/admin/fragments/pager-link.html
- Updated fragments:
- admin-admins-delete-form.html — adapted to new API shape
- admin-admins-permission-cell.html — adapted to new API shape
- templates/admin/assets/css/new.css — style adjustments
Benefits:
- CSRF protection on all mutating admin operations
- Uniform new/* fragment API across all migrated modules
- Input validation tightened (bfile, lang filters)
Technical notes:
- getAdminself() and getAdminmods() removed; logic inlined at call sites
- delete() now reads aid from req (GET) instead of POST
- Backward compatibility with old fragment names dropped intentionally
Backup of core/helpers.php prior to legacy function removal. Kept for reference during the migration wave.
Establishes the canonical new/* fragment base layer for the admin panel and migrates modules/content and admin/modules/security to the new API. Also consolidates core/helpers.php by removing legacy helper functions.
Core changes:
- New fragment base layer (templates/admin/fragments/new/):
Added 30+ structural fragments: form, div-row, div, input, textarea, select, checkbox, radio, button, submit, hidden, label-hint, title-tip, alert, edit-tip, pager, pager-link, pager-dots, table, table-row, table-row-content, th, tabs, tabs-link, tabs-panel, module-head, user-search, row-actions, radio-group, div-collapse
- Added new.css with full sl-* class definitions for all new fragments
- Added box.html partial as canonical content box wrapper
- Content module (modules/content/admin/index.php):
- Migrated all functions to new fragment API
- Replaced setArticleNumbers() with getTplPager() helper
- rows passed as arrays, not string concatenation
- Prepared SQL with named placeholders throughout
- Security module (admin/modules/security.php):
- Further alignment with new fragment contracts
- Updated language constants across all 6 lang files
- Core consolidation (core/helpers.php, core/system.php):
- Removed legacy helper functions migrated to fragments
- Reduced helpers.php by ~1200 lines
Benefits:
- Unified admin output through neutral structural fragment contracts
- sl-* CSS naming convention enforced throughout new layer
- Legacy sl_* calls replaced in migrated modules
Technical notes:
- system.css pruned of styles now covered by new.css
- tabs.js updated to data-* runtime contract
- getTplPager() replaces setArticleNumbers() for admin pagination
Complete the admin fragment refactor for security.php: replace the monolithic admin-security-ban-user-form fragment and getTplAdminForm calls with typed sub-fragments (add-div-input, add-div-textarea, add-div-check, add-div-collapse, add-div-user-search, tabs-panels). Delete stale planning docs now superseded by .agents/ + .rules/.
Core changes:
- Ban form (admin/modules/security.php):
Replace getTplAdminForm/getTplAdminFormRow with add-div fragment
- IP/CIDR ban form migrated to typed row data arrays
- User ban form replaces admin-security-ban-user-form monolith
- mail/collapse row uses new add-div-collapse + add-div-check
- Fix getVar key: 'name' -> 'uname' in user ban lookup
- Replace admin-uploads-config-tabs with tabs-panels fragment
- New canonical fragments (templates/admin/fragments/):
- add-div-check.html, add-div-collapse.html, add-div-input.html
- add-div-submit.html, add-div-textarea.html, add-div-user-search.html
- tabs-panels.html, tabs-panels-item.html
- Removed legacy fragments:
- admin-conf-save.html, admin-security-ban-user-form.html, form-submit.html
- Docs cleanup:
- Delete ADMIN_PLAN.md, FRONTEND_PLAN.md, RAW_SLOTS_ADMIN.md
- Update TEMPLATES.md and TEMPLATE_STATUS.md to reflect new fragment set
Benefits:
- All admin forms now use a uniform typed-row API
- Monolithic per-form fragments replaced by composable sub-fragments
- Stale planning docs removed; authoritative specs live in .agents/.rules/
Update security.php, database.php, and modules/content/admin/index.php to use the canonical input/label-hint/table/edit-tip fragments and add CSRF token verification to all mutating operations in the security module.
Core changes:
- Security module CSRF hardening (admin/modules/security.php):
bansave(), passsave(), configsave(), delete(): add checkSiteToken() guard at function entry; render _TOKENMISS alert and return early on failure
- All delete action URLs now include &token=getSiteToken() query parameter
- banlist() ban-add form: hidden token field added via getTplHiddenInput()
- passwd() form: hidden token field added
- config() configsave form: hidden array now passed to config-div.html loop
- Fragment migration (admin/modules/security.php):
getTplAdminHintLabel() → $tpl->getHtmlFrag('label-hint', [...]) for IP/CIDR, admin file, and dump-skip labels
getTplTextInput() → $tpl->getHtmlFrag('input', [...]) for blocker_cookie and afile text inputs
- Database module (admin/modules/database.php):
getHtmlFrag('admin-input', [...]) → getHtmlFrag('input', [...]) for both submit buttons in dump()
- Content module (modules/content/admin/index.php):
content(): list view migrated from getTplAdminTableHead/getTplAdminTableRow to $tpl->getHtmlFrag('table', [...]) with head array of column descriptors
- Row rendering migrated to getHtmlFrag('table-row') + getHtmlFrag('table-row-content')
- Action menu migrated to getHtmlFrag('edit-tip', [...]) with CSRF token on delete URL
- Title cell migrated to getHtmlFrag('title-tip', ['items' => [...]]) + cutstr()
add(): form rows converted to array-based descriptor format; input/label-hint fragments used for title and RSS URL fields; getTplRefreshTimeSelect() for refresh select; getTplAddDateTime() for date picker; fields_in() replaced by getTplAddFieldRows(); body preview replaced by getTplPreviewContent()
- Field input normalised: getVar('post', 'field[]', 'raw') + filterFields()
Benefits:
- CSRF coverage extended to all mutating security module operations
- Consistent fragment usage eliminates module-specific HTML builders
- content/add form now uses the same add-div layout as other modules
Technical notes:
- checkSiteToken() added to bansave (ids 1/2/3), passsave, configsave, delete
- config-div.html hidden loop expects array of ['nameattr', 'valueattr'] maps
- field[] input now read as raw array and normalised via filterFields()