From 0bc2d7f6b0e9d52ee98f907ce6c61c43c27523c9 Mon Sep 17 00:00:00 2001 From: David Stone Date: Thu, 7 May 2026 19:35:50 -0600 Subject: [PATCH] fix(checkout-editor): make mobile editor and Add Field modal usable on phones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mobile (<=782px) view of the checkout form editor had three usability defects that made the screen effectively unusable on phones: 1. The expanded-row layout for TYPE / SLUG / MOVE columns relied on WordPress core's responsive list-table CSS, which absolutely positions the data-colname label in a 32%-wide strip on the left of each cell. Inside the narrow checkout-editor postbox that strip is too thin and the label collapses to one character per line ('T..s it e_ ur l' instead of 'Type: site_url'), with the value text overlapping it. 2. The 'Add new Field' wubox modal used a 600px fixed pixel width set inline by wubox.js, overflowing the viewport on phones and clipping labels on both edges. 3. The field-type tile grid used wu-w-1/4 (4 columns), producing ~24vw tiles on phones — too narrow for labels like 'PASSWORD', 'TEMPLATES', and 'DOMAIN SELECTION'. Fixes: - Add a new @media (max-width: 782px) block to checkout-editor.css that switches the expanded-row layout to a stacked block layout (label on its own row above the value), hides the ORDER and MOVE columns, and stacks the postbox header and step action buttons vertically. - Bump the existing wubox responsive breakpoint in admin.css from 400px to 782px (the WordPress admin mobile breakpoint) and override the inline pixel width with width: 100vw !important so the modal fills the screen on phones. - Drop the field-type tile grid from 4 columns to 2 on mobile so each label has room to render. Production users load checkout-editor.min.css and admin.min.css, which are rebuilt only at release time. Per PR #1135, feature branches must not hand-edit the .min.css files. To ship the fix to production users immediately, the same @media block is also injected via wp_add_inline_style() from Checkout_Form_Edit_Admin_Page::register_scripts(). The source .css and inline-PHP copies cross-reference each other so they stay in sync. Tests: - Extends tests/unit/Checkout_Editor_Assets_Test.php (introduced in PR #1135) with a new test asserting the wp_add_inline_style call is wired up and contains the expected selectors and rules. The existing source-only guard remains intact: checkout-editor.min.css is not modified on this branch. Verified at 390x844 (collapsed, expanded, modal, per-field edit) and 1280x800 (5 columns, modal centered at 600px) — desktop unaffected. --- assets/css/admin.css | 14 +++- assets/css/checkout-editor.css | 72 ++++++++++++++++++- .../class-checkout-form-edit-admin-page.php | 36 ++++++++++ tests/unit/Checkout_Editor_Assets_Test.php | 52 ++++++++++++++ 4 files changed, 171 insertions(+), 3 deletions(-) diff --git a/assets/css/admin.css b/assets/css/admin.css index 13b1f4ee..8366294c 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -1937,11 +1937,21 @@ body.wu-page-wp-ultimo-settings .selectize-control.single .selectize-input::afte margin-top: -6px; } -@media screen and (max-width: 400px) { +/* WUBox modal responsive layout. wubox.js sets the modal width inline (default + 630px, often 600px for the checkout-form-editor field selector) and centers + it with negative margins. On phones (<=782px, the WordPress admin mobile + breakpoint) that fixed pixel width overflows the viewport — labels get clipped + on both edges. Force the modal to use the full viewport, reset the inline + negative margins, and let WP-Ultimo's grid layouts re-flow inside. + These rules are also injected via wp_add_inline_style() from + Checkout_Form_Edit_Admin_Page::register_scripts() so they reach users + loading the minified admin.min.css before the next release rebuild. */ +@media screen and (max-width: 782px) { /* stylelint-disable */ #WUB_window, #WUB_ajaxContent { - max-width: 100%; + width: 100vw !important; + max-width: 100vw !important; height: 100% !important; margin-top: 0 !important; margin-left: 0 !important; diff --git a/assets/css/checkout-editor.css b/assets/css/checkout-editor.css index 631f8e07..4fc9289a 100644 --- a/assets/css/checkout-editor.css +++ b/assets/css/checkout-editor.css @@ -38,7 +38,12 @@ display: none; } -/* Mobile responsive styles for checkout form editor */ +/* Mobile responsive styles for checkout form editor. + * These rules are also injected via wp_add_inline_style() from + * Checkout_Form_Edit_Admin_Page::register_scripts() so they ship to users + * loading the minified stylesheet (production). Keep both copies in sync; + * the inline copy is the authoritative one for end users until the next + * release rebuilds checkout-editor.min.css. */ @media screen and (max-width: 782px) { /* Stack the top header bar vertically */ @@ -70,6 +75,44 @@ display: none !important; } + /* Fix the expanded-row layout when the user taps "Show more details". + WordPress core's responsive list-table CSS positions the `::before` data-colname + label absolutely on the left (left: 10px; width: 32%) and reserves padding-left:35% + on the cell for the value. Inside the narrow checkout-editor postbox that 32% strip + is too thin for "Type"/"Slug" and the label collapses to one character per line + ("T..s it e_ ur l" instead of "Type: site_url"), and the value text overlaps the + label. Switch to a stacked block layout: label on its own row above the value. */ + #wu-checkout-editor-app tr.is-expanded td.column-type, + #wu-checkout-editor-app tr.is-expanded td.column-slug, + #wu-checkout-editor-app tr.is-expanded td.column-move { + position: relative !important; + display: block !important; + width: auto !important; + padding: 6px 12px !important; + text-align: left !important; + } + #wu-checkout-editor-app tr.is-expanded td.column-type::before, + #wu-checkout-editor-app tr.is-expanded td.column-slug::before, + #wu-checkout-editor-app tr.is-expanded td.column-move::before { + position: static !important; + display: block !important; + float: none !important; + width: auto !important; + padding: 0 0 4px 0 !important; + overflow: visible !important; + white-space: normal !important; + text-overflow: clip !important; + font-weight: 600; + text-align: left !important; + } + + /* The MOVE column is hidden in collapsed view above; also hide it in expanded + view because drag handles are not actionable on touch and the empty + placeholder just adds noise. */ + #wu-checkout-editor-app tr.is-expanded td.column-move { + display: none !important; + } + /* Ensure the step action buttons stack properly on mobile */ #wu-checkout-editor-app .wu-bg-gray-100 ul { flex-direction: column; @@ -79,4 +122,31 @@ margin-left: 0 !important; margin-bottom: 4px; } + + /* "Add new Field" wubox modal: cap modal width at 100vw and reset the + inline negative margins set by wubox.js so the modal fits a phone. The + same width override appears in assets/css/admin.css for global wubox + coverage; this duplicate keeps the rule local to the checkout editor in + case admin.min.css has not been rebuilt with the wider breakpoint yet. */ + /* stylelint-disable */ + #WUB_window, + #WUB_ajaxContent { + width: 100vw !important; + max-width: 100vw !important; + height: 100% !important; + margin-top: 0 !important; + margin-left: 0 !important; + top: 0 !important; + left: 0 !important; + border-radius: 0 !important; + } + /* stylelint-enable */ + + /* Field-type selector grid: drop from 4 columns to 2 so each tile has + enough room for its label ("PASSWORD", "TEMPLATES", "DOMAIN SELECTION"). + Without this rule the 4-column wu-w-1/4 grid produces ~24vw tiles and + the labels truncate ("PA", "HIDD", "LANGUA", "NETWOR") on phones. */ + #WUB_ajaxContent ul[data-wu-app="add_checkout_form_field"] .wu-w-1\/4 { + width: 50% !important; + } } \ No newline at end of file diff --git a/inc/admin-pages/class-checkout-form-edit-admin-page.php b/inc/admin-pages/class-checkout-form-edit-admin-page.php index 92492b8f..9a237bdb 100644 --- a/inc/admin-pages/class-checkout-form-edit-admin-page.php +++ b/inc/admin-pages/class-checkout-form-edit-admin-page.php @@ -1323,6 +1323,42 @@ public function register_scripts(): void { wp_enqueue_script('wu-checkout-form-editor'); wp_enqueue_style('wu-checkout-form-editor', wu_get_asset('checkout-editor.css', 'css'), [], wu_get_version()); + + /* + * Inline mobile rules. Shipped via wp_add_inline_style so they reach + * users loading checkout-editor.min.css (which is regenerated only at + * release time) without hand-editing the minified asset on feature + * branches. Keep this block in sync with the @media block in + * assets/css/checkout-editor.css. + */ + wp_add_inline_style( + 'wu-checkout-form-editor', + '@media screen and (max-width:782px){' + . '#wu-checkout-editor-app .postbox>.wu-flex.wu-items-center{flex-direction:column;gap:8px}' + . '#wu-checkout-editor-app .postbox>.wu-flex.wu-items-center>div{width:100%!important;text-align:center}' + . '#wu-checkout-editor-app .postbox>.wu-flex.wu-items-center>div:last-child{text-align:center}' + . '#wu-checkout-editor-app .postbox>.wu-flex.wu-items-center>div ul{justify-content:center}' + . '#wu-checkout-editor-app .column-order{display:none!important}' + . '#wu-checkout-editor-app .column-move{display:none!important}' + . '#wu-checkout-editor-app tr.is-expanded td.column-type,' + . '#wu-checkout-editor-app tr.is-expanded td.column-slug,' + . '#wu-checkout-editor-app tr.is-expanded td.column-move{position:relative!important;display:block!important;width:auto!important;padding:6px 12px!important;text-align:left!important}' + . '#wu-checkout-editor-app tr.is-expanded td.column-type::before,' + . '#wu-checkout-editor-app tr.is-expanded td.column-slug::before,' + . '#wu-checkout-editor-app tr.is-expanded td.column-move::before{position:static!important;display:block!important;float:none!important;width:auto!important;padding:0 0 4px 0!important;overflow:visible!important;white-space:normal!important;text-overflow:clip!important;font-weight:600;text-align:left!important}' + . '#wu-checkout-editor-app tr.is-expanded td.column-move{display:none!important}' + . '#wu-checkout-editor-app .wu-bg-gray-100 ul{flex-direction:column;align-items:center}' + . '#wu-checkout-editor-app .wu-bg-gray-100 ul li{margin-left:0!important;margin-bottom:4px}' + // WUBox modal: cap width at 100vw and reset inline negative margins so the + // field-type selector and per-field edit forms fit phones. The same rule + // lives in assets/css/admin.css for the next release rebuild. + . '#WUB_window,#WUB_ajaxContent{width:100vw!important;max-width:100vw!important;height:100%!important;margin-top:0!important;margin-left:0!important;top:0!important;left:0!important;border-radius:0!important}' + // "Add new Field" tile grid: drop from 4 columns to 2 so labels like + // "PASSWORD", "TEMPLATES", "DOMAIN SELECTION" stay readable. The grid uses + // wu-w-1/4 (25%) which becomes ~24vw on phones — too narrow for label text. + . '#WUB_ajaxContent ul[data-wu-app="add_checkout_form_field"] .wu-w-1\/4{width:50%!important}' + . '}' + ); } /** diff --git a/tests/unit/Checkout_Editor_Assets_Test.php b/tests/unit/Checkout_Editor_Assets_Test.php index 16a606eb..d9ed6e45 100644 --- a/tests/unit/Checkout_Editor_Assets_Test.php +++ b/tests/unit/Checkout_Editor_Assets_Test.php @@ -22,4 +22,56 @@ public function test_checkout_editor_mobile_styles_stay_in_source_css_only(): vo $this->assertStringNotContainsString('@media screen and (max-width:782px)', $min_contents, 'Generated checkout-editor.min.css should not contain the manually inlined mobile styles from PR #1073'); $this->assertStringNotContainsString('flex-direction:column', $min_contents, 'Generated checkout-editor.min.css should remain at its pre-PR #1073 state on feature branches'); } + + /** + * Production users load checkout-editor.min.css, which is rebuilt only at + * release time. To ship mobile fixes immediately we inject the @media + * block via wp_add_inline_style() from the admin page class. Verify that + * registration is wired up so the rules actually reach end users. + */ + public function test_checkout_editor_mobile_styles_are_injected_inline_for_min_css_users(): void { + $admin_page_path = __DIR__ . '/../../inc/admin-pages/class-checkout-form-edit-admin-page.php'; + + $this->assertFileExists($admin_page_path, 'class-checkout-form-edit-admin-page.php does not exist'); + + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading local fixture assets in a standalone PHPUnit test. + $admin_page_contents = file_get_contents($admin_page_path); + $this->assertNotFalse($admin_page_contents); + + $this->assertStringContainsString( + "wp_add_inline_style(\n\t\t\t'wu-checkout-form-editor'", + $admin_page_contents, + 'Expected register_scripts() to call wp_add_inline_style on wu-checkout-form-editor so mobile rules ship without rebuilding the .min.css' + ); + $this->assertStringContainsString( + '@media screen and (max-width:782px)', + $admin_page_contents, + 'Expected the inline style block to contain the mobile @media query so production users receive the mobile checkout editor fixes' + ); + $this->assertStringContainsString( + '.column-order{display:none!important}', + $admin_page_contents, + 'Expected the inline style block to hide the ORDER column on mobile' + ); + $this->assertStringContainsString( + 'tr.is-expanded td.column-slug', + $admin_page_contents, + 'Expected the inline style block to fix the broken expanded-row layout (vertical 1-character text wrap) for the SLUG cell' + ); + $this->assertStringContainsString( + '#WUB_window,#WUB_ajaxContent{width:100vw', + $admin_page_contents, + 'Expected the inline style block to cap the wubox modal at viewport width on mobile so the "Add new Field" dialogue fits a phone' + ); + $this->assertStringContainsString( + 'add_checkout_form_field', + $admin_page_contents, + 'Expected the inline style block to scope the field-type grid rule to the add_checkout_form_field Vue app' + ); + $this->assertStringContainsString( + '.wu-w-1\/4{width:50%!important}', + $admin_page_contents, + 'Expected the inline style block to drop the field-type tile grid from 4 columns to 2 on mobile so labels (PASSWORD, TEMPLATES, DOMAIN SELECTION) stay readable' + ); + } }