Feat/ettic admin UI - changes to the admin backend to get in line with new ettic backend ui styling#7
Feat/ettic admin UI - changes to the admin backend to get in line with new ettic backend ui styling#7r00bbert wants to merge 11 commits into
Conversation
Drops the shared Ettic admin design system into the plugin: - assets/css/opentrust-admin.css, assets/js/opentrust-admin.js — the design tokens, components, and dirty-tracking/toast/modal JS used by upcoming admin migrations. New asset paths and handles; existing assets/css/admin.css and assets/js/admin.js are untouched. - includes/Admin/Footer.php — branded footer used across every OpenTrust admin screen. URL_DOCS points at plugins.ettic.nl/opentrust. - includes/Admin/Settings.php — reference implementation of the design system's page shell (topbar + sections + every control type). Loaded by PHPStan path scan but NOT booted; OpenTrust's existing admin classes migrate to the same markup vocabulary in the commits that follow. - opentrust.php — defines OPENTRUST_FILE / OPENTRUST_URL as aliases for the existing OPENTRUST_PLUGIN_FILE / OPENTRUST_PLUGIN_URL, so the shared-template files run unmodified. Requires Footer.php on load. Behavior unchanged in this commit: no menu page registered by the new files, no enqueue, no markup. Just installed and ready. Template source: /Users/nolderoos/Claude Code/Ettic Admin UI (post v1).
Wraps OpenTrust_Admin_Settings::render_settings_page() in .opentrust-admin and emits the shared template's dark topbar + footer: - Topbar bar: brand mark (OpenTrust shield, 26x26 white-on-blue), version pill, dirty-changes counter (data-dirty), Discard + Save buttons. Save carries form="opentrust-settings-form" so it submits the active tab's Settings API form from outside it. Discard reloads. - Topbar head: page title + one-paragraph description; "View Trust Center" link moves into the topbar as a ghost-dark button. - Tabbar (NEW component, OpenTrust-only): the 4 tabs render as a light strip BELOW the topbar instead of inside it. The shared template's "no tabs in topbar" invariant assumes plugins use WP submenus for section nav; OpenTrust's ?tab=... URLs are user-bookmarkable so we keep them and style them as a separate component. Marked clearly in the CSS as not-for-upstream-extraction. - Footer: \OpenTrust\Admin\Footer::render() at the bottom of every tab. - AI tab "Live" pill: re-themed as .opentrust-tabbar__badge (replaces the inline-styled .ot-pill--live). General + Contact forms now have id="opentrust-settings-form" so the topbar Save submits them. The per-tab submit_button() is dropped. On the AI + IO tabs the Save/Discard buttons aren't rendered (they have bespoke admin-post forms that wire up in their respective migration commits). class-opentrust-admin.php enqueues opentrust-admin.css/js as a separate handle (opentrust-admin-ds) on plugin pages only, never on CPT meta-box screens. Existing admin.css/admin.js stay loaded for the CPT screens. Field markup inside the forms is untouched — that migrates per-tab in commits 3-7. Mid-migration the WP-native form-table rows will look a bit out of place inside the design-system wrap; that's expected.
Replaces do_settings_sections('opentrust-settings-general') with a
manual render that emits .opentrust-block + .opentrust-card + .opentrust-row
markup. The register_setting + sanitize cascade are untouched — only the
render side moves to design-system markup.
Sections:
- General → endpoint slug, page title, company name, tagline
- Branding → logo + avatar via .opentrust-media (template's wp.media wiring
via [data-opentrust-media-picker], replacing the legacy data-ot-media-*
bindings for these two fields), accent color via .opentrust-color (native
swatch + hex pair, the existing contrast-warning widget hangs beneath as
a .opentrust-row__control--stack child), credit toggle
- Visible Sections → six chip toggles (.opentrust-chip with the template's
:has(:checked) selector, no JS needed)
Color picker:
- Drops wp-color-picker for the accent field (existing $('.ot-color-picker')
init now finds nothing — kept in admin.js for commit 9 cleanup since
removing the wp-color-picker dep also requires unhooking the style/script
enqueue in class-opentrust-admin.php, out of scope here).
- admin.js accent-warning code now binds to the design system's hex text
input via `input` events. opentrust-admin.js already syncs swatch→text on
input, so swatch picks and direct hex typing both reach updateAccentWarning.
The legacy add_settings_section('opentrust_general'...) + opentrust_branding
+ opentrust_sections registrations stay in register_settings(). They no
longer render because do_settings_sections is gone, but they're harmless
and removing them is bundled into the commit 9 cleanup once Contact + AI
tabs have also migrated and the old render_*_field methods can be deleted
in one sweep.
PHPStan level 5 clean.
Replaces do_settings_sections('opentrust-settings-contact') with a manual
ds_render_section_contact() emitting .opentrust-block + .opentrust-card +
.opentrust-row markup. Same pattern as the General tab migration in the
previous commit.
Adds ds_row_text_typed() for email/url inputs so the native HTML5 type
flows through (mobile keyboards, inline validation, autofill hints) while
the row shell stays consistent with ds_row_text().
The legacy register_settings() entries for the Contact tab stay registered
but un-rendered; they get pruned together with the other un-used Settings
API registrations once AI + IO tabs have also migrated.
PHPStan level 5 clean.
Rewrites OpenTrust_Admin_AI::render_ai_tab(), the provider picker, the provider cards, and the main AI settings form to emit design-system markup. All admin-post handlers (key save/forget/refresh, summary sweep) stay untouched. - render_ai_tab() now wraps the intro + rationale in an .opentrust-block with a card containing an .opentrust-disclosure (new component — see the CSS extension block). - Transient notices switch from WP-native .notice to .opentrust-notice variants (success/error/warn/info) via a shared ds_notice() helper. - Summary backfill banner: .opentrust-notice--warn with an embedded admin-post form in .opentrust-notice__actions, primary ghost button. - Non-anthropic active warning: .opentrust-notice--warn. - Provider picker: .opentrust-block headed "Step 1 — Connect Anthropic", primary card uses .opentrust-card + .opentrust-ai-card--primary variant. Advanced disclosure wraps the existing flat grid of .opentrust-ai-card--advanced cards. - Provider card: same content (title/badge/keylink/saved-state/form) but emits design-system input + button classes, and the saved-state ✓ icon becomes a structured .opentrust-ai-card__check pill matching the design language. - AI settings form: id="opentrust-settings-form" so the topbar Save in the wrap submits it. submit_button() dropped. The table.form-table becomes two .opentrust-block sections: "Step 2 — Model & defaults" (model + budgets + rate limits + max-msg + contact URL + three toggles) and "Anti-abuse — Cloudflare Turnstile" (toggle + site key + secret key with masked-bullet placeholder for the encrypted blob). - AI tab is now treated as has_settings_form so the topbar Save + Discard render. The opentrust-admin.js dirty tracker prefers the form the Save button is wired to (via HTML5 form="..." attribute) instead of just .opentrust-admin form, so the AI tab's many sub-forms (key save, refresh, forget) don't confuse the dirty tracker. - Oversized-policies warning becomes an .opentrust-notice--error with a .opentrust-notice__list bullet list. CSS additions appended to opentrust-admin.css under an OpenTrust-only extensions block: .opentrust-disclosure, .opentrust-ai-card variants, .opentrust-ai-advanced__grid, .opentrust-ai-model-row, .opentrust-row__unit, .opentrust-field-msg--success, .opentrust-notice__list, .opentrust-notice__actions. Local ds_row_number() and ds_row_toggle() helpers live in OpenTrust_Admin_AI because OpenTrust_Admin_Settings::ds_row_* are private. Lifting them into a shared helper class can happen alongside the Settings API registrations cleanup in commit 9. PHPStan level 5 clean.
OpenTrust_Admin_Questions::render_page() now wraps in .opentrust-admin with the dark topbar (brand mark + version + back-to-AI-settings link + View Trust Center link), no Save (read-only screen), the topbar__head title block, an .opentrust-stack of section blocks, and the shared \OpenTrust\Admin\Footer at the bottom. Each surface on the page is rebuilt with design-system markup: - Logging on/off banner → .opentrust-notice--success or --warn with an inline toggle action in .opentrust-notice__actions. - Filter form → .opentrust-block + .opentrust-card with a new .opentrust-filterbar layout (label-above-input columns + grouped actions on the right). Inputs and select use design system classes. - Log table → .opentrust-card--flush (new variant — drops card padding so the table can span edges) containing a token-styled .opentrust-log-table. Refused rows highlight in warn tones; meta columns use mono, tabular-nums, and muted text. - Pagination → paginate_links() output restyled inside .opentrust-log-table__pagination (rounded chip per page, blue active, gray dots). - Danger zone → .opentrust-action-row inside a card with a .opentrust-btn--danger Clear button (kept the same confirm() flow). CSS additions (Questions-only extensions block in opentrust-admin.css): .opentrust-card--flush, .opentrust-filterbar*, .opentrust-log-table*, plus the pagination styling that overrides paginate_links()'s defaults. Logic is unchanged — same filter handling, same query, same export / clear / toggle-logging admin-post handlers. PHPStan level 5 clean.
Rewrites OpenTrust_Admin_Tools::render_tab(), render_export_panel(), render_import_panel(), and render_preview_screen() to use design-system markup. All admin-post handlers (export, import_preview, import_apply) are unchanged. - Transient notices switch to .opentrust-notice variants. - Tab intro becomes an .opentrust-block header. - Export panel: own .opentrust-block + .opentrust-card. The kind picker (content vs settings) becomes an .opentrust-seg segmented control. Content selection uses an .opentrust-io-cpt-list of <details> groups (one per CPT) with nested checkboxes. "Bundle media" becomes a .opentrust-toggle row. Submit moves into an .opentrust-action-row. - Import panel: warn banner becomes .opentrust-notice--warn. File input gets an .opentrust-input--file shim (dashed border, native chrome retained). Conflict strategy becomes an .opentrust-seg with three options. Submit moves into an .opentrust-action-row. - Preview screen: errors/warnings as .opentrust-notice--error/--warn with .opentrust-notice__list bullet lists. Per-CPT preview tables reuse .opentrust-log-table styling inside .opentrust-card--flush with a new .opentrust-card__header bar above each. Action column becomes .opentrust-io-preview-table__pill with create/update/skip/ new color variants. Confirm + Cancel buttons move into an .opentrust-io-confirm row at the bottom. CSS additions appended to opentrust-admin.css under the I&E extensions block: .opentrust-io-cpt-list / .opentrust-io-cpt*, .opentrust-input--file, .opentrust-card__header / .opentrust-card__title, the preview-table pills, and .opentrust-io-confirm. PHPStan level 5 clean.
Now that every settings tab renders through ds_render_section_*, the
old Settings API field plumbing is dead weight. Removes:
- The `add_field()` helper and every `add_settings_section` /
`add_settings_field` call from OpenTrust_Admin_Settings::register_settings()
(~95 lines of registration).
- The eight render_*_field methods + the shared render_input_field()
and render_media_field() (~190 lines). One stays on the page in
spirit — ds_row_* — but no consumer needs the legacy variants.
- The wp-color-picker style enqueue and the 'wp-color-picker' dep on
the admin.js script. Settings now uses the design system's native
.opentrust-color widget; the only place that registered the jQuery
picker had already migrated away in commit 3.
- The dead `$('[data-ot-media-field]')` block in admin.js (logo/avatar
uploads moved to the template's [data-opentrust-media-picker]).
- The .ot-logo-upload / .ot-logo-preview CSS rules. CPT meta-box
uploads use different classes (.ot-policy-attachment-*,
.ot-upload-badge, .ot-upload-artifact) and remain untouched.
Top-of-file docblock for class-opentrust-admin-settings.php updated to
match the new model: no add_settings_section / add_settings_field; page
is rendered manually with ds_render_section_*.
`wp i18n make-pot` regenerated — captures every new translatable string
from the design-system migration (mostly section labels, help copy,
button labels, and notice text).
Plain-permalinks notice (OpenTrust_Admin::render_plain_permalinks_notice)
and the WP.org review prompt are intentionally left as WP-native
`.notice` markup: they also appear on CPT edit screens which are out of
design-system scope, so swapping to .opentrust-notice classes would
leave them unstyled on those screens.
PHPStan level 5 clean. Grep -rni 'pluginslug' returns 0 hits.
…t need it
Two follow-ups from the first review of the migrated admin:
1. Tab switching silently dropped in-flight edits. Each tab is its own
page load, so navigating to ?tab=other discards anything you typed
on the current tab — and the topbar dirty counter, which reset to 0
on the next page, made it look like the changes had been saved.
Adds two guards:
- .opentrust-tabbar tab clicks are intercepted while dirty count > 0.
The user sees a typed showConfirm() modal ("Discard and switch" /
"Stay on this tab") that makes the loss explicit and offers a
clean off-ramp.
- A window beforeunload handler catches everything else — back
button, address bar nav, window close — and surfaces the browser's
native "Leave site?" prompt. A module-scoped navConsented flag
bypasses the prompt on Save click, Discard click, and confirmed
tab switch, so user-initiated nav stays frictionless.
Cross-tab persistence (sessionStorage'ing one tab's input while
editing another) was deliberately not chosen. The settings option
has encrypted secrets, file inputs, nested arrays, and masked
placeholders — snapshotting and restoring all of that in JS would
be a maintenance hazard. WP convention is "leaving the page drops
unsaved changes"; the guards just make that convention legible.
2. Tab switching felt slow. The dominant cost was wp_enqueue_media()
firing on every plugin admin screen — ~150 KB of media-uploader JS
that only the General tab (logo + AI avatar) and the CPT edit
screens (badge / artifact / policy PDF) actually use. The Contact,
AI, IO, and Questions screens load it for no reason.
Gates wp_enqueue_media() to the screens that render a media
picker. The General tab still gets it; everywhere else does not.
Other contributors (AI tab corpus warmup, IO tab's five
posts_per_page=-1 queries, libsodium decrypt of every stored key)
pre-date this PR and are out of scope here.
PHPStan level 5 clean.
Simplify pass (from three-agent review): - Fix <br> literal-text rendering in the IO import error message - Translate IO preview action pills (was English-only ucfirst()) - Use provider->label() instead of ucfirst($slug) in AI tab warning - Localize tab-switch modal strings via window.OpenTrustAdmin.i18n - Drop redundant get_current_screen() reassignment in enqueue_assets - Normalize Questions log filter param (q -> search) so pagination and export URLs stop carrying both names; also fixes pagination base URL silently overriding ?page=opentrust-questions with the pagination-page integer - Lift tab allowlist to OpenTrust_Admin_Settings::TABS const - Trim AI-style file headers on admin-settings/admin-ai - Regenerate POT for new translatable strings Visual polish (from screenshot review): - 40px gap between section blocks on every tab (the form wrapper on General/Contact/AI now flexes too, so direct-child tabs like IO no longer double-count gap + margin) - Move "View Trust Center" out of the dark sticky bar into the hero head, mirrored on the Questions screen - Dark preview background for the Logo media picker so a white-on- dark logo previews on its real surface - New .opentrust-row__control--stack-left modifier; applied to accent picker, sections chips, and IO content selection - .opentrust-io-cpt-list loses its border/bg/padding so the CPT picker flows inline under its label - Match action-row horizontal padding to .opentrust-row (8 -> 14px) - New .opentrust-notice--bare variant for the inline import warning - Free-float Cancel/Confirm under the import preview (no card wrap)
📝 WalkthroughWalkthroughThis PR introduces a comprehensive admin UI redesign by implementing a scoped design system ( ChangesAdmin Design System Implementation & Migration
🎯 4 (Complex) | ⏱️ ~75 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
| <div class="opentrust-filterbar__actions"> | ||
| <button type="submit" class="opentrust-btn opentrust-btn--primary opentrust-btn--sm"><?php esc_html_e('Apply', 'opentrust'); ?></button> | ||
| <a href="<?php echo esc_url(admin_url('admin.php?page=opentrust-questions')); ?>" class="opentrust-btn opentrust-btn--ghost opentrust-btn--sm"><?php esc_html_e('Reset', 'opentrust'); ?></a> | ||
| <a href="<?php echo esc_url($export_url); ?>" class="opentrust-btn opentrust-btn--ghost opentrust-btn--sm opentrust-filterbar__export"><?php esc_html_e('Download CSV', 'opentrust'); ?></a> |
| <?php echo esc_html($row->question); ?> | ||
| </td> | ||
| <td><code class="opentrust-log-table__model"><?php echo esc_html($row->model); ?></code></td> | ||
| <td class="opentrust-log-table__num"><?php echo (int) $row->citation_count; ?></td> |
| </td> | ||
| <td><code class="opentrust-log-table__model"><?php echo esc_html($row->model); ?></code></td> | ||
| <td class="opentrust-log-table__num"><?php echo (int) $row->citation_count; ?></td> | ||
| <td class="opentrust-log-table__meta">↓<?php echo (int) $row->tokens_in; ?> / ↑<?php echo (int) $row->tokens_out; ?></td> |
| </td> | ||
| <td><code class="opentrust-log-table__model"><?php echo esc_html($row->model); ?></code></td> | ||
| <td class="opentrust-log-table__num"><?php echo (int) $row->citation_count; ?></td> | ||
| <td class="opentrust-log-table__meta">↓<?php echo (int) $row->tokens_in; ?> / ↑<?php echo (int) $row->tokens_out; ?></td> |
| <td><code class="opentrust-log-table__model"><?php echo esc_html($row->model); ?></code></td> | ||
| <td class="opentrust-log-table__num"><?php echo (int) $row->citation_count; ?></td> | ||
| <td class="opentrust-log-table__meta">↓<?php echo (int) $row->tokens_in; ?> / ↑<?php echo (int) $row->tokens_out; ?></td> | ||
| <td class="opentrust-log-table__meta"><?php echo (int) $row->response_ms; ?>ms</td> |
| echo paginate_links([ | ||
| 'base' => add_query_arg('paged', '%#%', $base), | ||
| 'format' => '', | ||
| 'current' => $filters['page'], | ||
| 'total' => $pages, | ||
| 'prev_text' => '‹', | ||
| 'next_text' => '›', | ||
| ]); |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
assets/js/admin.js (1)
155-171:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winInitialize the override state on first render.
ot-accent-warning--overrideis only toggled after achangeevent. If the checkbox is already checked when the page loads, the warning renders with the wrong copy/state until the user touches it.💡 Suggested fix
if ($accentInput.length) { $accentInput.on('input', function () { updateAccentWarning($accentInput.val()); }); // Initial check on page load. updateAccentWarning($accentInput.val()); } + + $accentWarning.toggleClass('ot-accent-warning--override', $forceExact.is(':checked')); // Live-toggle the override class so the warning tone updates without // a page reload. The actual clamping still happens server-side — the // class only drives the admin copy/colour swap. $forceExact.on('change', function () {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@assets/js/admin.js` around lines 155 - 171, The override CSS class for the accent warning isn't initialized on page load when the checkbox ($forceExact) is already checked, so set the initial state after DOM setup: when $forceExact and $accentWarning exist, apply or remove the 'ot-accent-warning--override' class based on $forceExact.prop('checked') (in the same area where updateAccentWarning($accentInput.val()) is called), ensuring the live-toggle behavior remains via the existing $forceExact.on('change') handler.
🧹 Nitpick comments (3)
includes/Admin/Settings.php (1)
44-53: 💤 Low valueNotice suppression is aggressive but intentionally scoped.
Removing all admin notices could hide important warnings. However, this is strictly scoped to
settings_page_opentrustand documented as intentional for the dark hero layout. Consider adding a comment noting that critical notices (like plugin vulnerabilities) won't display on this page.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@includes/Admin/Settings.php` around lines 44 - 53, suppress_foreign_notices aggressively removes all admin notices on the settings page (function suppress_foreign_notices, scoped to 'settings_page_' . self::PAGE_SLUG) which can hide critical warnings; add an explanatory comment above suppress_foreign_notices documenting that this removal is intentional for the dark hero layout, explicitly note that important/system/plugin vulnerability notices will not be shown on settings_page_opentrust, and optionally add a TODO or link to an issue describing a follow-up to surface critical notices elsewhere if needed.assets/js/opentrust-admin.js (2)
566-657: 💤 Low valueModal body uses innerHTML - ensure all callers pass safe content.
The
bodyparameter is rendered viainnerHTML(line 601). Currently, all callers pass hardcoded HTML or i18n strings. This is acceptable for now, but if future callers pass user-controlled content, it could introduce XSS.Consider documenting this expectation:
/** * `@param` {Object} opts * `@param` {string} opts.body - HTML content for modal body. MUST be sanitized if containing user input. */🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@assets/js/opentrust-admin.js` around lines 566 - 657, Add a short JSDoc above the showConfirm function explaining the opts.body contract: state that opts.body is expected to be HTML (string) and MUST be sanitized before being passed if it can contain user-controlled content, list other opts (title, lede, confirmText, cancelText, danger, onConfirm) briefly, and note that callers should pass plain text (and not HTML) if they expect automatic escaping or change the caller to sanitize their content; reference the showConfirm function and the use of backdrop.querySelector('[data-modal-body]').innerHTML so reviewers can locate the innerHTML sink.
271-273: 💤 Low valueHardcoded English strings for dirty label are not internationalized.
The "unsaved change" / "unsaved changes" strings are hardcoded. For consistency with the rest of the admin UI which uses
esc_html_e()and translation functions, these should be localizable.Suggested approach
Expose i18n strings via
wp_localize_scriptfrom PHP:// In JS, use: var i18n = ( window.OpenTrustAdmin && window.OpenTrustAdmin.i18n ) || {}; labelEl.textContent = count === 1 ? ( i18n.unsavedChange || ' unsaved change' ) : ( i18n.unsavedChanges || ' unsaved changes' );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@assets/js/opentrust-admin.js` around lines 271 - 273, Replace the hardcoded English dirty-label strings in assets/js/opentrust-admin.js where labelEl.textContent is set so they come from localized data: read strings from a JS i18n object (e.g. window.OpenTrustAdmin.i18n) and fall back to the current English defaults; then ensure the corresponding PHP enqueuing code uses wp_localize_script (or wp_add_inline_script) to expose unsavedChange and unsavedChanges via OpenTrustAdmin.i18n so the JS uses those keys instead of hardcoded literals.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@includes/class-opentrust-admin-ai.php`:
- Line 317: The button text is double-escaping the ampersand because
esc_html_e() will escape HTML entities; change the string passed to esc_html_e()
from "Validate & save" to use a plain ampersand or separate words (e.g.,
"Validate & save" or "Validate and save") so the rendered label shows correctly;
update the esc_html_e(...) call in includes/class-opentrust-admin-ai.php
accordingly.
In `@includes/class-opentrust-admin-tools.php`:
- Around line 188-199: The UI text currently shows only the plugin cap
(self::UPLOAD_MAX_MB) which can mislead users if PHP/WordPress upload limits are
lower; update the render code in class-opentrust-admin-tools.php (the block that
outputs the label/paragraph and the input#ot_import_file) to compute and display
the effective upload limit by reading server settings (upload_max_filesize and
post_max_size) and converting them to MB, then use the minimum of that value and
self::UPLOAD_MAX_MB in the displayed message so the help text reflects the true
allowed size.
---
Outside diff comments:
In `@assets/js/admin.js`:
- Around line 155-171: The override CSS class for the accent warning isn't
initialized on page load when the checkbox ($forceExact) is already checked, so
set the initial state after DOM setup: when $forceExact and $accentWarning
exist, apply or remove the 'ot-accent-warning--override' class based on
$forceExact.prop('checked') (in the same area where
updateAccentWarning($accentInput.val()) is called), ensuring the live-toggle
behavior remains via the existing $forceExact.on('change') handler.
---
Nitpick comments:
In `@assets/js/opentrust-admin.js`:
- Around line 566-657: Add a short JSDoc above the showConfirm function
explaining the opts.body contract: state that opts.body is expected to be HTML
(string) and MUST be sanitized before being passed if it can contain
user-controlled content, list other opts (title, lede, confirmText, cancelText,
danger, onConfirm) briefly, and note that callers should pass plain text (and
not HTML) if they expect automatic escaping or change the caller to sanitize
their content; reference the showConfirm function and the use of
backdrop.querySelector('[data-modal-body]').innerHTML so reviewers can locate
the innerHTML sink.
- Around line 271-273: Replace the hardcoded English dirty-label strings in
assets/js/opentrust-admin.js where labelEl.textContent is set so they come from
localized data: read strings from a JS i18n object (e.g.
window.OpenTrustAdmin.i18n) and fall back to the current English defaults; then
ensure the corresponding PHP enqueuing code uses wp_localize_script (or
wp_add_inline_script) to expose unsavedChange and unsavedChanges via
OpenTrustAdmin.i18n so the JS uses those keys instead of hardcoded literals.
In `@includes/Admin/Settings.php`:
- Around line 44-53: suppress_foreign_notices aggressively removes all admin
notices on the settings page (function suppress_foreign_notices, scoped to
'settings_page_' . self::PAGE_SLUG) which can hide critical warnings; add an
explanatory comment above suppress_foreign_notices documenting that this removal
is intentional for the dark hero layout, explicitly note that
important/system/plugin vulnerability notices will not be shown on
settings_page_opentrust, and optionally add a TODO or link to an issue
describing a follow-up to surface critical notices elsewhere if needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 901776cf-8993-47c9-a05c-3d3aa7a31a7a
📒 Files selected for processing (14)
README.mdassets/css/admin.cssassets/css/opentrust-admin.cssassets/js/admin.jsassets/js/opentrust-admin.jsincludes/Admin/Footer.phpincludes/Admin/Settings.phpincludes/class-opentrust-admin-ai.phpincludes/class-opentrust-admin-questions.phpincludes/class-opentrust-admin-settings.phpincludes/class-opentrust-admin-tools.phpincludes/class-opentrust-admin.phplanguages/opentrust.potopentrust.php
💤 Files with no reviewable changes (1)
- assets/css/admin.css
| <button type="submit" class="button button-primary ot-ai-card__submit"> | ||
| <?php esc_html_e('Validate & save', 'opentrust'); ?> | ||
| <button type="submit" class="opentrust-btn opentrust-btn--primary"> | ||
| <?php esc_html_e('Validate & save', 'opentrust'); ?> |
There was a problem hiding this comment.
HTML entity will be double-escaped in button text.
The & will be rendered literally as "&" because esc_html_e() will escape the ampersand. Use a plain & or separate the words.
Proposed fix
- <?php esc_html_e('Validate & save', 'opentrust'); ?>
+ <?php esc_html_e('Validate & save', 'opentrust'); ?>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <?php esc_html_e('Validate & save', 'opentrust'); ?> | |
| <?php esc_html_e('Validate & save', 'opentrust'); ?> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/class-opentrust-admin-ai.php` at line 317, The button text is
double-escaping the ampersand because esc_html_e() will escape HTML entities;
change the string passed to esc_html_e() from "Validate & save" to use a
plain ampersand or separate words (e.g., "Validate & save" or "Validate and
save") so the rendered label shows correctly; update the esc_html_e(...) call in
includes/class-opentrust-admin-ai.php accordingly.
| <div class="opentrust-row opentrust-row--stacked"> | ||
| <div class="opentrust-row__main"> | ||
| <span class="opentrust-row__label"><?php esc_html_e('Export file', 'opentrust'); ?></span> | ||
| <p class="opentrust-row__help"> | ||
| <?php | ||
| /* translators: %d: max upload size in MB */ | ||
| printf(esc_html__('ZIP archive produced by another OpenTrust install. Max %d MB.', 'opentrust'), (int) self::UPLOAD_MAX_MB); | ||
| ?> | ||
| </p> | ||
| </div> | ||
| <div class="opentrust-row__control opentrust-row__control--stack"> | ||
| <input type="file" id="ot_import_file" name="ot_import_file" accept=".zip" required class="opentrust-input opentrust-input--file"> |
There was a problem hiding this comment.
Show the effective upload limit here, not just the plugin cap.
This always advertises 50 MB, but PHP/WordPress may reject a smaller upload before your own size check runs. In that case the user sees a misleading limit here and then hits the generic “No file uploaded” path.
💡 Suggested fix
+ <?php
+ $max_upload_mb = max(
+ 1,
+ (int) floor(min(self::UPLOAD_MAX_MB * MB_IN_BYTES, wp_max_upload_size()) / MB_IN_BYTES)
+ );
+ ?>
<div class="opentrust-row__main">
<span class="opentrust-row__label"><?php esc_html_e('Export file', 'opentrust'); ?></span>
<p class="opentrust-row__help">
<?php
/* translators: %d: max upload size in MB */
- printf(esc_html__('ZIP archive produced by another OpenTrust install. Max %d MB.', 'opentrust'), (int) self::UPLOAD_MAX_MB);
+ printf(esc_html__('ZIP archive produced by another OpenTrust install. Max %d MB.', 'opentrust'), $max_upload_mb);
?>
</p>
</div>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div class="opentrust-row opentrust-row--stacked"> | |
| <div class="opentrust-row__main"> | |
| <span class="opentrust-row__label"><?php esc_html_e('Export file', 'opentrust'); ?></span> | |
| <p class="opentrust-row__help"> | |
| <?php | |
| /* translators: %d: max upload size in MB */ | |
| printf(esc_html__('ZIP archive produced by another OpenTrust install. Max %d MB.', 'opentrust'), (int) self::UPLOAD_MAX_MB); | |
| ?> | |
| </p> | |
| </div> | |
| <div class="opentrust-row__control opentrust-row__control--stack"> | |
| <input type="file" id="ot_import_file" name="ot_import_file" accept=".zip" required class="opentrust-input opentrust-input--file"> | |
| <div class="opentrust-row opentrust-row--stacked"> | |
| <?php | |
| $max_upload_mb = max( | |
| 1, | |
| (int) floor(min(self::UPLOAD_MAX_MB * MB_IN_BYTES, wp_max_upload_size()) / MB_IN_BYTES) | |
| ); | |
| ?> | |
| <div class="opentrust-row__main"> | |
| <span class="opentrust-row__label"><?php esc_html_e('Export file', 'opentrust'); ?></span> | |
| <p class="opentrust-row__help"> | |
| <?php | |
| /* translators: %d: max upload size in MB */ | |
| printf(esc_html__('ZIP archive produced by another OpenTrust install. Max %d MB.', 'opentrust'), $max_upload_mb); | |
| ?> | |
| </p> | |
| </div> | |
| <div class="opentrust-row__control opentrust-row__control--stack"> | |
| <input type="file" id="ot_import_file" name="ot_import_file" accept=".zip" required class="opentrust-input opentrust-input--file"> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@includes/class-opentrust-admin-tools.php` around lines 188 - 199, The UI text
currently shows only the plugin cap (self::UPLOAD_MAX_MB) which can mislead
users if PHP/WordPress upload limits are lower; update the render code in
class-opentrust-admin-tools.php (the block that outputs the label/paragraph and
the input#ot_import_file) to compute and display the effective upload limit by
reading server settings (upload_max_filesize and post_max_size) and converting
them to MB, then use the minimum of that value and self::UPLOAD_MAX_MB in the
displayed message so the help text reflects the true allowed size.
This PR conflicts with changes I made on #5 please first merge #5 then rebase and merge this PR
Summary by CodeRabbit
Release Notes
New Features
Refactor
Documentation
Chores