Bug class (org-wide)
Every Sure-family admin SPA hard-codes the vertical overhead above its app and sizes itself with viewport math like calc(100dvh - 96px) (desktop) / calc(100dvh - 110px) (mobile). The constants assume exactly two things above the app: the WP admin bar (32px / 46px) and the plugin's own 64px topbar.
That assumption is false whenever ANY other plugin injects content into the admin above our app (in_admin_header, unclassed banners, promo bars). The math does not know the banner exists, so the app overflows the viewport and its bottom controls (Save button, sidebar items) are pushed off-screen.
Real-world impact: SureCookie support ticket 1507247 - MemberPress Courses' admin banner clipped SureCookie's Save button with no way to scroll to it; the customer's only workaround was browser zoom-out.
Confirmed occurrences of the same copy-forwarded pattern:
- surecookie:
src/admin/AdminApp.jsx - grid-rows-[64px_calc(100dvh_-_96px)] + h-[calc(100vh-64px)] (fixed height, worst symptom: content clipped, unreachable) - fixed via mechanism 2 below
- surerank:
src/apps/admin-components/layout/sidebar-layout.js:619 - min-h-[calc(100dvh_-_96px)] / 110px
- suremails:
src/App.js:37 - min-h-[calc(100dvh_-_96px)] / 110px
- reported also in sureforms and surecontact (same template lineage)
Root cause: the admin layout was copied plugin-to-plugin instead of living in the shared library, so the wrong constant shipped everywhere. A build-time constant can never be correct here - other plugins' banner heights are unknowable.
Proper fix - two technically sound mechanisms
Mechanism 1 - flow-based, CSS-only (recommended for the shared component):
Scoped to the plugin's own admin screen (body class), turn the WP containers into a flex column and let the app take the remaining space:
body.toplevel_page_[slug] #wpcontent,
body.toplevel_page_[slug] #wpbody,
body.toplevel_page_[slug] #wpbody-content {
display: flex;
flex-direction: column;
padding: 0;
}
body.toplevel_page_[slug] #wpcontent {
min-height: calc(100vh - var(--wp-admin--admin-bar--height, 32px));
}
.[app-root] {
flex: 1 1 auto;
min-height: 0;
}
WP core owns --wp-admin--admin-bar--height (32px, 46px under 783px - wp-includes/css/admin-bar.css), so the only remaining constant is maintained by core itself. Injected banners become normal flex items: they take their natural height, the app takes the rest, and a dismissed banner reflows automatically with zero JS. Needs a QA pass for float-era markup (#wpfooter, screen-meta) inside the flex column, scoped per plugin page only.
Mechanism 2 - measured offset (JS, shipped in SureCookie as reference):
Measure the app container's real document offset into a CSS custom property and use it in the height calcs; re-measure via ResizeObserver on the parent + window resize (banners render late, resize, or get dismissed):
const compute = () => {
const top = Math.max( 0, Math.round( node.getBoundingClientRect().top + window.scrollY ) );
node.style.setProperty( '--admin-top', `${ top }px` );
};
// heights: calc(100dvh - <own topbar> - var(--admin-top, 32px))
Reference implementation: surecookie src/admin/AdminApp.jsx (ticket 1507247 fix). Verified against a simulated 72px in_admin_header banner.
Proposal: fix once in force-ui, adopt everywhere
- Ship an
AdminPageLayout (topbar slot + optional sidebar slot + content slot) in force-ui that implements one of the mechanisms internally - so no consumer ever writes viewport math again. Minimally: export a documented useWpAdminOffset() hook + layout recipe.
- Migrate surecookie, surerank, sureforms, suremails, surecontact, suredash to the shared component and delete the per-plugin
calc(100dvh - 96px) grids.
Acceptance criteria
- With a 72px banner injected via
in_admin_header, every plugin's admin app shows all controls (Save, full sidebar) without zooming.
- Dismissing the banner reclaims the space without reload.
- Mobile admin bar (46px at <=782px) handled without a separate hard-coded variant.
Repro harness (drop in mu-plugins):
add_action( 'in_admin_header', function () {
echo '<div style="height:72px;background:#fde68a;">Simulated third-party banner</div>';
} );
Bug class (org-wide)
Every Sure-family admin SPA hard-codes the vertical overhead above its app and sizes itself with viewport math like
calc(100dvh - 96px)(desktop) /calc(100dvh - 110px)(mobile). The constants assume exactly two things above the app: the WP admin bar (32px / 46px) and the plugin's own 64px topbar.That assumption is false whenever ANY other plugin injects content into the admin above our app (
in_admin_header, unclassed banners, promo bars). The math does not know the banner exists, so the app overflows the viewport and its bottom controls (Save button, sidebar items) are pushed off-screen.Real-world impact: SureCookie support ticket 1507247 - MemberPress Courses' admin banner clipped SureCookie's Save button with no way to scroll to it; the customer's only workaround was browser zoom-out.
Confirmed occurrences of the same copy-forwarded pattern:
src/admin/AdminApp.jsx-grid-rows-[64px_calc(100dvh_-_96px)]+h-[calc(100vh-64px)](fixed height, worst symptom: content clipped, unreachable) - fixed via mechanism 2 belowsrc/apps/admin-components/layout/sidebar-layout.js:619-min-h-[calc(100dvh_-_96px)]/110pxsrc/App.js:37-min-h-[calc(100dvh_-_96px)]/110pxRoot cause: the admin layout was copied plugin-to-plugin instead of living in the shared library, so the wrong constant shipped everywhere. A build-time constant can never be correct here - other plugins' banner heights are unknowable.
Proper fix - two technically sound mechanisms
Mechanism 1 - flow-based, CSS-only (recommended for the shared component):
Scoped to the plugin's own admin screen (body class), turn the WP containers into a flex column and let the app take the remaining space:
WP core owns
--wp-admin--admin-bar--height(32px, 46px under 783px -wp-includes/css/admin-bar.css), so the only remaining constant is maintained by core itself. Injected banners become normal flex items: they take their natural height, the app takes the rest, and a dismissed banner reflows automatically with zero JS. Needs a QA pass for float-era markup (#wpfooter, screen-meta) inside the flex column, scoped per plugin page only.Mechanism 2 - measured offset (JS, shipped in SureCookie as reference):
Measure the app container's real document offset into a CSS custom property and use it in the height calcs; re-measure via
ResizeObserveron the parent + windowresize(banners render late, resize, or get dismissed):Reference implementation: surecookie
src/admin/AdminApp.jsx(ticket 1507247 fix). Verified against a simulated 72pxin_admin_headerbanner.Proposal: fix once in force-ui, adopt everywhere
AdminPageLayout(topbar slot + optional sidebar slot + content slot) in force-ui that implements one of the mechanisms internally - so no consumer ever writes viewport math again. Minimally: export a documenteduseWpAdminOffset()hook + layout recipe.calc(100dvh - 96px)grids.Acceptance criteria
in_admin_header, every plugin's admin app shows all controls (Save, full sidebar) without zooming.Repro harness (drop in mu-plugins):