The theme is FA5-only, but aksrt_icon_markup() prefixed bare glyphs with
the FA4 style token, so stored icon-picker values rendered FA4 markup,
and three runtime strings still carried the FA4 double-fa form (report
modal header and submit button, comment report menu item). That left the
navigation icon contract failing at 11/12.
- aksrt_icon_markup() normalizes bare glyphs, legacy FA4 values and
style-only values to "fa fas fa-<glyph>", keeping the FA5 brand family
(fa fab) and trailing classes intact.
- aksrt_normalize_icon_key() strips the legacy FA4 prefix so stored
values resolve against the brand-icon catalog again.
- report.js and the comment report item emit FA5 markup.
- An icon-picker contract test locks the upgrade behaviour.
Verification: 338 widget-system, 12 navigation, 28 admin and 13
front-submit contract tests pass; normalization also exercised against
legacy, FA5 and brand inputs.
- Restriction: add is_suspended/get_active_suspend; comment block now covers
suspend (小黑屋) in addition to mute, with reason in the deny message
- FrontSubmitSave::persist: block post/draft/edit submission for suspended
users (reference-theme semantics: 小黑屋 loses all publishing rights)
- report.js: close icon switched from fa-times to the SVG sprite ic-close
(#icon-close), same as reference theme; textareas gain autoHeight growth
(hidden 'other reason' box skips the first measurement)
- WeChatNotify: NOTIFY_TYPES now includes report/system so report results
and account restriction notices fan out to WeChat template messages;
generic title/description fallback for template values
- contract tests: +3 tests (suspend enforcement, modal polish, wechat types)
ban_settings() derived each reason slug via sanitize_key(label), which
strips CJK text to an empty string; the frontend filter then discarded
every reason (including the schema defaults) and fell back to the
hard-coded list. Derive the slug from an ASCII key when possible and
from a stable md5 short hash of the label otherwise, and relax the
frontend filter to the label only. Adds a WP-stub harness that verifies
the defaults path end to end (tests/dev/verify-ban-settings-defaults.php).
- read preset reasons from the real source (ban_preset_reason via
UserRuntime::ban_settings); the previous injection read a
nonexistent report.categories key, so backend reasons never showed
- rebuild the modal on the reference markup contract: edit-header
warning header, reason chips toggling the reference .active class
(focus color), other-reason textarea, violation link, description,
but-average modal-buts footer
- add image evidence upload gated by user_report_img_s: new
/report/upload-image route reusing the comment upload handler with
its own permission, preview/remove UI, up to 3 images appended to
the report content
- render the backend report notice (user_report_desc, sanitized HTML)
inside the modal
- widen the dialog to the reference 600px desktop geometry and share
the form-upload preview styles with the order review modal
- extend the report contract test accordingly
- enqueue report.js on singular pages too: the single meta box and
comment report buttons rendered without their script handler, so
clicking the report item did nothing
- align the report runtime default with the admin schema and the
reference theme (user_report_s default true) so the public user
home cover menu shows the report entry
- rebuild report.js on top of AksrtModalRuntime following the
reference theme modal format: red warning header, preset reason
badges with an other-reason textarea, violation link field, detail
description and a cancel/submit footer; submit goes through the
unified /report/submit endpoint
- keep report inside the comment three-dot dropdown and enrich the
payload (target name/avatar) for the modal; inject configured
report categories via aksrtData.reportCategories
- update the report contract test accordingly
Local WP has empty permalink_structure so /wp-json/* 404s on Apache.
modal-auth fell back to /wp-json/aksrt/v1; prefer aksrtData.restUrl
(index.php?rest_route=/aksrt/v1) and join paths correctly.