diff --git a/includes/forms/form-user.php b/includes/forms/form-user.php index 14531b58..f23e7d38 100644 --- a/includes/forms/form-user.php +++ b/includes/forms/form-user.php @@ -63,6 +63,71 @@ function admin_enqueue_scripts() { // enqueue acf_enqueue_scripts(); + + // Fix SCF field layout on user profile/edit screens. + if ( ! acf_is_screen( array( 'profile', 'user-edit', 'profile-network', 'user-edit-network' ) ) ) { + return; + } + + wp_add_inline_style( 'acf-input', $this->get_user_form_layout_css() ); + } + + /** + * Returns custom CSS to improve SCF field layout on user profile/edit screens. + * + * @since ACF 6.8.2 + * + * @return string + */ + public function get_user_form_layout_css() { + return <<<'CSS' +table.form-table tr.acf-field > td.acf-label { + width: 200px; + vertical-align: top; + padding-top: 14px; +} + +table.form-table tr.acf-field > td.acf-input { + vertical-align: top; +} + +table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="text"], +table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="password"], +table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="email"], +table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="number"], +table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="url"], +table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="search"], +table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="tel"], +table.form-table tr.acf-field > td.acf-input textarea { + width: 100%; + max-width: 25em; +} + +table.form-table tr.acf-field > td.acf-input .select2-container { + width: 100% !important; + max-width: 25em; +} + +@media screen and (max-width: 782px) { + table.form-table tr.acf-field > td.acf-label, + table.form-table tr.acf-field > td.acf-input { + display: block; + width: auto; + } + + table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="text"], + table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="password"], + table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="email"], + table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="number"], + table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="url"], + table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="search"], + table.form-table tr.acf-field > td.acf-input .acf-input-wrap input[type="tel"], + table.form-table tr.acf-field > td.acf-input textarea, + table.form-table tr.acf-field > td.acf-input .select2-container { + max-width: 100%; + } +} +CSS; } @@ -358,4 +423,4 @@ function filter_pre_load_value( $null, $post_id, $field ) { acf_new_instance( 'ACF_Form_User' ); endif; // class_exists check -?> \ No newline at end of file +?> diff --git a/tests/e2e/field-helpers.js b/tests/e2e/field-helpers.js index 1aaa7d7d..abeaf26d 100644 --- a/tests/e2e/field-helpers.js +++ b/tests/e2e/field-helpers.js @@ -141,7 +141,10 @@ async function waitForMetaBoxes( page ) { */ async function uploadImageViaModal( page, imagePath ) { // Wait for media modal to open - await page.waitForSelector( '.media-modal', { state: 'visible' } ); + await page.waitForSelector( '.media-modal', { + state: 'visible', + timeout: 20000, + } ); // Click "Upload files" tab if not already there const uploadTab = page.locator( '.media-modal #menu-item-upload' ); @@ -153,11 +156,23 @@ async function uploadImageViaModal( page, imagePath ) { const fileInput = page.locator( '.media-modal input[type="file"]' ); await fileInput.setInputFiles( imagePath ); - // Wait for upload to complete - await page.waitForSelector( '.media-modal .attachment.selected', { - state: 'visible', - timeout: 15000, - } ); + // Wait for upload to complete and ensure an attachment is selected. + try { + await page.waitForSelector( '.media-modal .attachment.selected', { + state: 'visible', + timeout: 30000, + } ); + } catch { + await page.waitForSelector( '.media-modal .attachments .attachment', { + state: 'visible', + timeout: 30000, + } ); + await page.locator( '.media-modal .attachments .attachment' ).first().click(); + await page.waitForSelector( '.media-modal .attachment.selected', { + state: 'visible', + timeout: 10000, + } ); + } // Click "Select" button const selectButton = page.locator( diff --git a/tests/e2e/field-type-image.spec.ts b/tests/e2e/field-type-image.spec.ts index ba8f0184..d9a276ef 100644 --- a/tests/e2e/field-type-image.spec.ts +++ b/tests/e2e/field-type-image.spec.ts @@ -9,6 +9,7 @@ const { PLUGIN_SLUG, deleteFieldGroups, waitForMetaBoxes, + uploadImageViaModal, } = require( './field-helpers' ); const path = require( 'path' ); @@ -81,34 +82,7 @@ test.describe( 'Field Type > Image', () => { '.acf-field[data-name="test_image"] .acf-image-uploader[data-uploader="wp"] .acf-button-edit, .acf-field[data-name="test_image"] .acf-image-uploader a[data-name="add"]' ); await addImageButton.click(); - - // Wait for media modal - await page.waitForSelector( '.media-modal', { state: 'visible' } ); - - // Click "Upload files" tab - const uploadTab = page.locator( '.media-modal #menu-item-upload' ); - if ( await uploadTab.isVisible() ) { - await uploadTab.click(); - } - - // Upload the file - const fileInput = page.locator( '.media-modal input[type="file"]' ); - await fileInput.setInputFiles( TEST_IMAGE_PATH ); - - // Wait for upload to complete - await page.waitForSelector( '.media-modal .attachment.selected', { - state: 'visible', - timeout: 30000, - } ); - - // Click "Select" button - const selectButton = page.locator( - '.media-modal .media-toolbar-primary .media-button-select' - ); - await selectButton.click(); - - // Wait for modal to close - await page.waitForSelector( '.media-modal', { state: 'hidden' } ); + await uploadImageViaModal( page, TEST_IMAGE_PATH ); // Verify image is displayed in the field const imagePreview = page.locator( @@ -174,28 +148,7 @@ test.describe( 'Field Type > Image', () => { '.acf-field[data-name="removable_image"] .acf-image-uploader a[data-name="add"]' ); await addImageButton.click(); - - await page.waitForSelector( '.media-modal', { state: 'visible' } ); - - const uploadTab = page.locator( '.media-modal #menu-item-upload' ); - if ( await uploadTab.isVisible() ) { - await uploadTab.click(); - } - - const fileInput = page.locator( '.media-modal input[type="file"]' ); - await fileInput.setInputFiles( TEST_IMAGE_PATH ); - - await page.waitForSelector( '.media-modal .attachment.selected', { - state: 'visible', - timeout: 30000, - } ); - - const selectButton = page.locator( - '.media-modal .media-toolbar-primary .media-button-select' - ); - await selectButton.click(); - - await page.waitForSelector( '.media-modal', { state: 'hidden' } ); + await uploadImageViaModal( page, TEST_IMAGE_PATH ); // Verify image is there const imagePreview = page.locator( diff --git a/tests/php/includes/forms/test-form-user.php b/tests/php/includes/forms/test-form-user.php index 6ce3d2a3..aec0b1dc 100644 --- a/tests/php/includes/forms/test-form-user.php +++ b/tests/php/includes/forms/test-form-user.php @@ -358,6 +358,31 @@ function () use ( &$enqueue_called ) { $this->assertFalse( $enqueue_called, 'acf_enqueue_scripts should not be called when not on user screen' ); } + /** + * Test user form layout CSS includes expected rules. + */ + public function test_get_user_form_layout_css_contains_expected_rules() { + $form_user = new ACF_Form_User(); + $css = $form_user->get_user_form_layout_css(); + + $this->assertIsString( $css, 'CSS should be a string' ); + $this->assertStringContainsString( + 'table.form-table tr.acf-field > td.acf-label', + $css, + 'CSS should target ACF labels in user form table rows' + ); + $this->assertStringContainsString( + 'input[type="text"]', + $css, + 'CSS should target text-like input fields' + ); + $this->assertStringContainsString( + '@media screen and (max-width: 782px)', + $css, + 'CSS should include responsive rules for mobile viewports' + ); + } + /** * Test render_edit renders nothing without field groups. */