From b84aeb14a56fb0a43f01ae57f13a0364c37d6cc4 Mon Sep 17 00:00:00 2001 From: Poli Gilad <83961704+poligilad-auto@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:16:11 +0200 Subject: [PATCH] Improve custom fields editing flow --- src/js/_enqueues/admin/post.js | 150 ++++++++++++- src/wp-admin/css/edit.css | 212 +++++++++++++++--- src/wp-admin/includes/meta-boxes.php | 6 + src/wp-admin/includes/post.php | 168 +++++++++++++- src/wp-admin/includes/template.php | 75 ++++--- .../phpunit/tests/admin/includesTemplate.php | 128 +++++++++++ 6 files changed, 657 insertions(+), 82 deletions(-) diff --git a/src/js/_enqueues/admin/post.js b/src/js/_enqueues/admin/post.js index d50fe6007d33b..7505134472884 100644 --- a/src/js/_enqueues/admin/post.js +++ b/src/js/_enqueues/admin/post.js @@ -689,7 +689,126 @@ jQuery( function($) { // Custom Fields postbox. if ( $('#postcustom').length ) { - $( '#the-list' ).wpList( { + var $postCustom = $( '#postcustom' ), + $newMeta = $postCustom.find( '#newmeta' ), + $addCustomFieldButton = $postCustom.find( '#add-custom-field-button' ), + $addCustomFieldHeading = $postCustom.find( '.custom-field-add-heading' ), + $addCustomFieldSubmit = $postCustom.find( '#postcustomstuff .add-custom-field' ), + $cancelNewMetaButton = $postCustom.find( '#newmeta-cancel' ), + $customFieldsNotice = $postCustom.find( '.custom-fields-notice' ), + $customFieldsNoticeMessage, + $enterNewMetaButton = $postCustom.find( '#newmeta-button' ), + $listTable = $postCustom.find( '#list-table' ), + $metaKeyInput = $postCustom.find( '#metakeyinput' ), + $metaKeySelect = $postCustom.find( '#metakeyselect' ), + $metaValue = $postCustom.find( '#metavalue' ), + clearNewMeta, + hideNewMeta, + resetMetaKeyInput, + showCustomFieldsNotice, + showMetaKeyInput, + showNewMeta; + + if ( ! $customFieldsNotice.length ) { + $customFieldsNotice = $( '' ); + $customFieldsNotice.find( '.screen-reader-text' ).text( __( 'Dismiss this notice.' ) ); + $postCustom.find( '#postcustomstuff' ).before( $customFieldsNotice ); + } + + $customFieldsNoticeMessage = $customFieldsNotice.find( 'p' ); + + showCustomFieldsNotice = function( message ) { + if ( ! $customFieldsNotice.length ) { + return; + } + + $customFieldsNoticeMessage.text( message ); + $customFieldsNotice.removeClass( 'hidden' ); + + wp.a11y.speak( message ); + }; + + resetMetaKeyInput = function() { + if ( $metaKeySelect.length ) { + $metaKeySelect.prop( 'selectedIndex', 0 ).removeClass( 'hidden' ); + $metaKeyInput.val( '' ).addClass( 'hidden' ); + $postCustom.find( '#enternew' ).removeClass( 'hidden' ); + $postCustom.find( '#cancelnew' ).addClass( 'hidden' ); + } + }; + + showMetaKeyInput = function() { + $metaKeySelect.addClass( 'hidden' ); + $metaKeyInput.removeClass( 'hidden' ); + $postCustom.find( '#enternew' ).addClass( 'hidden' ); + $postCustom.find( '#cancelnew' ).removeClass( 'hidden' ); + $metaKeyInput.trigger( 'focus' ); + }; + + clearNewMeta = function() { + $metaValue.val( '' ); + resetMetaKeyInput(); + + if ( ! $metaKeySelect.length ) { + $metaKeyInput.val( '' ); + } + }; + + showNewMeta = function( shouldFocus ) { + $newMeta.addClass( 'is-visible' ).show(); + $addCustomFieldHeading.addClass( 'is-visible' ); + $addCustomFieldSubmit.addClass( 'is-visible' ); + $addCustomFieldButton.attr( 'aria-expanded', 'true' ); + + if ( false !== shouldFocus ) { + ( $metaKeySelect.is( ':visible' ) ? $metaKeySelect : $metaKeyInput ).trigger( 'focus' ); + } + }; + + hideNewMeta = function( shouldFocus ) { + clearNewMeta(); + $newMeta.removeClass( 'is-visible' ).hide(); + $addCustomFieldHeading.removeClass( 'is-visible' ); + $addCustomFieldSubmit.removeClass( 'is-visible' ); + $addCustomFieldButton.attr( 'aria-expanded', 'false' ); + + if ( false !== shouldFocus ) { + $addCustomFieldButton.trigger( 'focus' ); + } + }; + + $addCustomFieldButton.on( 'click', function( event ) { + event.preventDefault(); + showNewMeta(); + } ); + + $enterNewMetaButton.on( 'click', function( event ) { + event.preventDefault(); + + if ( $metaKeyInput.hasClass( 'hidden' ) ) { + showMetaKeyInput(); + } else { + resetMetaKeyInput(); + $metaKeySelect.trigger( 'focus' ); + } + } ); + + $cancelNewMetaButton.on( 'click', function( event ) { + event.preventDefault(); + hideNewMeta(); + } ); + + $customFieldsNotice.on( 'click', '.notice-dismiss', function() { + $customFieldsNotice.addClass( 'hidden' ); + } ); + + if ( $listTable.hasClass( 'is-empty' ) ) { + showNewMeta( false ); + } + + $postCustom.find( '#the-list' ).wpList( { + addColor: 'none', + delColor: 'none', /** * Add current post_ID to request to fetch custom fields * @@ -700,7 +819,7 @@ jQuery( function($) { * @return {Object} Data modified with post_ID attached. */ addBefore: function( s ) { - s.data += '&post_id=' + $('#post_ID').val(); + s.data += '&post_id=' + $( '#post_ID' ).val(); return s; }, /** @@ -708,8 +827,31 @@ jQuery( function($) { * * @ignore */ - addAfter: function() { - $('table#list-table').show(); + addAfter: function( returnedResponse, settings ) { + var message = 'newmeta' === settings.element ? __( 'Custom field added.' ) : __( 'Custom field updated.' ); + + if ( true === settings.parsed || ! settings.parsed || settings.parsed.errors ) { + return; + } + + $listTable.removeClass( 'is-empty' ).addClass( 'has-fields' ).show(); + showCustomFieldsNotice( message ); + + if ( 'newmeta' === settings.element ) { + hideNewMeta(); + } + }, + delAfter: function( returnedResponse, settings ) { + if ( ! settings.parsed || settings.parsed.errors ) { + return; + } + + $postCustom.find( '#' + settings.element ).remove(); + showCustomFieldsNotice( __( 'Custom field deleted.' ) ); + + if ( ! $postCustom.find( '#the-list tr.is-saved' ).length ) { + $listTable.removeClass( 'has-fields' ).addClass( 'is-empty' ).hide(); + } } }); } diff --git a/src/wp-admin/css/edit.css b/src/wp-admin/css/edit.css index f1dd76ac31474..c264ef4e8f51e 100644 --- a/src/wp-admin/css/edit.css +++ b/src/wp-admin/css/edit.css @@ -1085,82 +1085,222 @@ form#tags-filter { 11.1 - Custom Fields ------------------------------------------------------------------------------*/ +#postcustom .inside { + margin-top: 0; + padding: 12px; +} + +.block-editor-page .edit-post-meta-boxes-area #postcustom .inside { + padding-right: 24px; + padding-left: 24px; +} + #postcustomstuff thead th { padding: 5px 8px 8px; background-color: #f0f0f1; } -#postcustom #postcustomstuff .submit { - border: 0 none; - float: none; - padding: 0 8px 8px; +#postcustomstuff table { + margin: 0; + width: 100%; + border: 1px solid #dcdcde; + border-spacing: 0; + background-color: #f6f7f7; } -#postcustom #postcustomstuff .add-custom-field { - padding: 12px 8px 8px; +#postcustomstuff tr { + vertical-align: top; } -#side-sortables #postcustom #postcustomstuff .submit { - margin: 0; +#postcustomstuff #list-table, +#postcustomstuff #newmeta { + border: 0; + border-spacing: 0; + background: transparent; +} + +#postcustomstuff #list-table tbody, +#postcustomstuff #newmeta tbody { + display: block; +} + +#postcustomstuff #list-table thead, +#postcustomstuff #newmeta thead { + display: none; +} + +#postcustomstuff .custom-field-add-heading { + margin: 0 0 8px; +} + +.js #postcustomstuff .custom-field-add-heading { + display: none; +} + +.js #postcustomstuff .custom-field-add-heading.is-visible { + display: block; +} + +#postcustomstuff #list-table.has-fields ~ .custom-field-add-heading.is-visible { + padding-top: 16px; + border-top: 1px solid #dcdcde; +} + +#postcustomstuff .custom-field-row, +#postcustomstuff #newmeta tbody tr { + display: grid; + gap: 8px 12px; padding: 0; + border-bottom: 1px solid #dcdcde; + background: transparent; } -#side-sortables #postcustom #postcustomstuff #the-list textarea { - height: 85px; +#postcustomstuff .custom-field-row { + grid-template-columns: minmax(160px, 24%) minmax(0, 1fr) auto; } -#side-sortables #postcustom #postcustomstuff td.left input, -#side-sortables #postcustom #postcustomstuff td.left select, -#side-sortables #postcustomstuff #newmetaleft a { - margin: 3px 3px 0; +#postcustomstuff #newmeta tbody tr { + grid-template-columns: minmax(160px, 24%) minmax(0, 1fr) auto; } -#postcustomstuff table { +#postcustomstuff .custom-field-row.is-saved { + padding: 0 0 16px; + border-bottom: 0; +} + +#postcustom .custom-fields-notice { + margin: 0 0 12px; +} + +#postcustom .custom-fields-notice p { + margin: 0.5em 0; +} + +#postcustomstuff #newmeta { + border-bottom: 0; +} + +#postcustomstuff #newmeta tbody tr { + border-bottom: 0; +} + +#postcustomstuff #list-table.has-fields ~ #newmeta.is-visible tbody tr { + padding-top: 0; +} + +.js #postcustomstuff #newmeta { + display: none; +} + +.js #postcustomstuff #newmeta.is-visible { + display: table; +} + +#postcustomstuff .custom-field-row td, +#postcustomstuff #newmeta td { + display: block; + padding: 0; +} + +#postcustomstuff .custom-field-label { + display: block; margin: 0; - width: 100%; - border: 1px solid #dcdcde; - border-spacing: 0; - background-color: #f6f7f7; + padding: 2px 0; } -#postcustomstuff tr { - vertical-align: top; +#postcustomstuff .custom-field-key, +#postcustomstuff .custom-field-value-field { + display: block; + box-sizing: border-box; + width: 100%; + max-width: none; + margin: 0; } -#postcustomstuff table input, -#postcustomstuff table select, -#postcustomstuff table textarea { - width: 96%; - margin: 8px; +#postcustomstuff .custom-field-value-field { + min-height: 40px; } -#side-sortables #postcustomstuff table input, -#side-sortables #postcustomstuff table select, -#side-sortables #postcustomstuff table textarea { - margin: 3px; +#postcustomstuff .custom-field-key.hidden { + display: none; } #postcustomstuff th.left, #postcustomstuff td.left { - width: 38%; + width: auto; +} + +#postcustomstuff .custom-field-actions, +#postcustom #postcustomstuff .submit { + margin: 8px 0 0; + padding: 0; + border: 0; + float: none; +} + +#postcustom #postcustomstuff .custom-field-row .custom-field-actions { + display: flex; + gap: 16px; + align-items: center; + align-self: start; + justify-content: flex-end; + margin: 0; + padding-top: 22px; + padding-right: 4px; + white-space: nowrap; } -#postcustomstuff .submit input { +#postcustomstuff .custom-field-actions button, +#postcustomstuff .custom-field-actions input { margin: 0; width: auto; } -#postcustomstuff #newmetaleft a, -#postcustomstuff #newmeta-button { +#postcustomstuff .custom-field-enter-new { display: inline-block; - margin: 0 8px 8px; - text-decoration: none; + margin-top: 8px; +} + +#postcustomstuff .custom-field-enter-new.hidden { + display: none; +} + +#postcustom #postcustomstuff .add-custom-field { + display: flex; +} + +.js #postcustom #postcustomstuff .add-custom-field { + display: none; +} + +.js #postcustom #postcustomstuff .add-custom-field.is-visible { + display: flex; +} + +#postcustomstuff .custom-field-add-toggle { + margin: 0; +} + +.js #postcustomstuff .custom-field-add-toggle[aria-expanded="true"] { + display: none; } .no-js #postcustomstuff #enternew { display: none; } +#side-sortables #postcustomstuff .custom-field-row, +#side-sortables #postcustomstuff #newmeta tbody tr { + grid-template-columns: 1fr; +} + +@media screen and (max-width: 782px) { + #postcustomstuff .custom-field-row, + #postcustomstuff #newmeta tbody tr { + grid-template-columns: 1fr; + } +} + #post-body-content .compat-attachment-fields { margin-bottom: 20px; } diff --git a/src/wp-admin/includes/meta-boxes.php b/src/wp-admin/includes/meta-boxes.php index 535a00cd3fe94..35206a7f3a236 100644 --- a/src/wp-admin/includes/meta-boxes.php +++ b/src/wp-admin/includes/meta-boxes.php @@ -812,6 +812,12 @@ function post_trackback_meta_box( $post ) { */ function post_custom_meta_box( $post ) { ?> +

' ); + \$customFieldsNotice.find( '.screen-reader-text' ).text( '{$dismiss_notice}' ); + \$postCustom.find( '#postcustomstuff' ).before( \$customFieldsNotice ); + } + + \$customFieldsNoticeMessage = \$customFieldsNotice.find( 'p' ); + + function showCustomFieldsNotice( message ) { + if ( ! \$customFieldsNotice.length ) { + return; + } + + \$customFieldsNoticeMessage.text( message ); + \$customFieldsNotice.removeClass( 'hidden' ); + + wp.a11y.speak( message ); + } + + function resetMetaKeyInput() { + if ( \$metaKeySelect.length ) { + \$metaKeySelect.prop( 'selectedIndex', 0 ).removeClass( 'hidden' ); + \$metaKeyInput.val( '' ).addClass( 'hidden' ); + \$postCustom.find( '#enternew' ).removeClass( 'hidden' ); + \$postCustom.find( '#cancelnew' ).addClass( 'hidden' ); + } + } + + function showMetaKeyInput() { + \$metaKeySelect.addClass( 'hidden' ); + \$metaKeyInput.removeClass( 'hidden' ); + \$postCustom.find( '#enternew' ).addClass( 'hidden' ); + \$postCustom.find( '#cancelnew' ).removeClass( 'hidden' ); + \$metaKeyInput.trigger( 'focus' ); + } + + function clearNewMeta() { + \$metaValue.val( '' ); + resetMetaKeyInput(); + + if ( ! \$metaKeySelect.length ) { + \$metaKeyInput.val( '' ); + } + } + + function showNewMeta( shouldFocus ) { + \$newMeta.addClass( 'is-visible' ).show(); + \$addCustomFieldHeading.addClass( 'is-visible' ); + \$addCustomFieldSubmit.addClass( 'is-visible' ); + \$addCustomFieldButton.attr( 'aria-expanded', 'true' ); + + if ( false !== shouldFocus ) { + ( \$metaKeySelect.is( ':visible' ) ? \$metaKeySelect : \$metaKeyInput ).trigger( 'focus' ); + } + } + + function hideNewMeta( shouldFocus ) { + clearNewMeta(); + \$newMeta.removeClass( 'is-visible' ).hide(); + \$addCustomFieldHeading.removeClass( 'is-visible' ); + \$addCustomFieldSubmit.removeClass( 'is-visible' ); + \$addCustomFieldButton.attr( 'aria-expanded', 'false' ); + + if ( false !== shouldFocus ) { + \$addCustomFieldButton.trigger( 'focus' ); + } + } + + \$addCustomFieldButton.on( 'click', function( event ) { + event.preventDefault(); + showNewMeta(); + } ); + + \$enterNewMetaButton.on( 'click', function( event ) { + event.preventDefault(); + + if ( \$metaKeyInput.hasClass( 'hidden' ) ) { + showMetaKeyInput(); + } else { + resetMetaKeyInput(); + \$metaKeySelect.trigger( 'focus' ); + } + } ); + + \$cancelNewMetaButton.on( 'click', function( event ) { + event.preventDefault(); + hideNewMeta(); + } ); + + \$customFieldsNotice.on( 'click', '.notice-dismiss', function() { + \$customFieldsNotice.addClass( 'hidden' ); + } ); + + if ( \$listTable.hasClass( 'is-empty' ) ) { + showNewMeta( false ); + } + + \$postCustom.find( '#the-list' ).wpList( { + addColor: 'none', + delColor: 'none', addBefore: function( s ) { s.data += '&post_id=$post->ID'; return s; }, - addAfter: function() { - $('table#list-table').show(); + addAfter: function( returnedResponse, settings ) { + var message = 'newmeta' === settings.element ? '$custom_field_added' : '$custom_field_updated'; + + if ( true === settings.parsed || ! settings.parsed || settings.parsed.errors ) { + return; + } + + \$listTable.removeClass( 'is-empty' ).addClass( 'has-fields' ).show(); + showCustomFieldsNotice( message ); + + if ( 'newmeta' === settings.element ) { + hideNewMeta(); + } + }, + delAfter: function( returnedResponse, settings ) { + if ( ! settings.parsed || settings.parsed.errors ) { + return; + } + + \$postCustom.find( '#' + settings.element ).remove(); + showCustomFieldsNotice( '$custom_field_deleted' ); + + if ( ! \$postCustom.find( '#the-list tr.is-saved' ).length ) { + \$listTable.removeClass( 'has-fields' ).addClass( 'is-empty' ).hide(); + } } }); } + + initializeCustomFields(); + $( initializeCustomFields ); + + if ( window.MutationObserver ) { + new window.MutationObserver( initializeCustomFields ).observe( document.body, { + childList: true, + subtree: true + } ); + } } )( jQuery );"; wp_enqueue_script( 'wp-lists' ); wp_add_inline_script( 'wp-lists', $script ); diff --git a/src/wp-admin/includes/template.php b/src/wp-admin/includes/template.php index 6680bca89691a..6497009c34017 100644 --- a/src/wp-admin/includes/template.php +++ b/src/wp-admin/includes/template.php @@ -586,7 +586,7 @@ function list_meta( $meta ) { // Exit if no meta. if ( ! $meta ) { echo ' - + @@ -601,7 +601,7 @@ function list_meta( $meta ) { } $count = 0; ?> - +
@@ -659,24 +659,21 @@ function _list_meta_row( $entry, &$count ) { $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] ); - $r .= "\n\t"; - $r .= "\n\t\t'; + $r .= "\n\t"; + $r .= "\n\t\t"; - $r .= "\n\t\t\n\t"; + ""; + $r .= ''; + + $r .= "\n\t\t' . "\n\t"; return $r; } @@ -735,20 +732,21 @@ function meta_form( $post = null ) { natcasesort( $keys ); } ?> -

-
"; - - $r .= "\n\t\t
"; - $r .= get_submit_button( __( 'Delete' ), 'deletemeta small', "deletemeta[{$entry['meta_id']}]", false, array( 'data-wp-lists' => "delete:the-list:meta-{$entry['meta_id']}::_ajax_nonce=$delete_nonce" ) ); - $r .= "\n\t\t"; - $r .= get_submit_button( __( 'Update' ), 'updatemeta small', "meta-{$entry['meta_id']}-submit", false, array( 'data-wp-lists' => "add:the-list:meta-{$entry['meta_id']}::_ajax_nonce-add-meta=$update_nonce" ) ); - $r .= '
'; - $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false ); - $r .= '
"; + $r .= ''; + $r .= ''; + $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false ); + $r .= '
+

+
- - + + - - - - -
+ + - - - + + - + +
-
+ -
+ + + + + + assertFalse( $wp_meta_boxes['attachment']['advanced']['default']['testbox1'] ); } + /** + * @covers ::_list_meta_row + */ + public function test_list_meta_row_outputs_modern_custom_field_controls() { + $count = 0; + $row = _list_meta_row( + array( + 'meta_id' => 123, + 'meta_key' => 'event_location', + 'meta_value' => 'Marnixstraat 234, Haarlem 3459RD, The Netherlands', + ), + $count + ); + + $this->assertStringContainsString( "id='meta-123' class='custom-field-row is-saved'", $row ); + $this->assertStringContainsString( "class='custom-field-label' for='meta-123-key'", $row ); + $this->assertStringContainsString( '>Name', $row ); + $this->assertStringContainsString( "class='custom-field-key regular-text'", $row ); + $this->assertStringContainsString( "class='custom-field-value-field large-text'", $row ); + $this->assertStringContainsString( "rows='1'", $row ); + $this->assertStringNotContainsString( 'regular-text code', $row ); + $this->assertStringNotContainsString( 'large-text code', $row ); + $this->assertStringContainsString( 'custom-field-delete', $row ); + $this->assertStringContainsString( '>Delete', $row ); + $this->assertStringNotContainsString( 'dashicons-trash', $row ); + $this->assertStringContainsString( 'custom-field-update', $row ); + $this->assertStringContainsString( 'button button-secondary updatemeta custom-field-update', $row ); + } + + /** + * @covers ::meta_form + */ + public function test_meta_form_outputs_collapsible_add_custom_field_controls() { + $post = self::factory()->post->create_and_get(); + + add_filter( + 'postmeta_form_keys', + static function () { + return array( 'event_location' ); + } + ); + + ob_start(); + meta_form( $post ); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'id="newmeta" class="custom-field-row is-new"', $output ); + $this->assertStringContainsString( 'class="custom-field-label" for="metakeyselect"', $output ); + $this->assertStringContainsString( 'class="custom-field-key regular-text"', $output ); + $this->assertStringContainsString( 'class="hidden custom-field-key regular-text"', $output ); + $this->assertStringContainsString( 'class="custom-field-value-field large-text"', $output ); + $this->assertStringContainsString( 'rows="1"', $output ); + $this->assertStringContainsString( 'id="newmeta-button"', $output ); + $this->assertStringContainsString( 'id="enternew"', $output ); + $this->assertStringContainsString( 'id="cancelnew"', $output ); + $this->assertStringContainsString( 'Use existing', $output ); + $this->assertStringContainsString( 'id="newmeta-cancel"', $output ); + $this->assertStringContainsString( 'class="button-link custom-field-cancel hide-if-no-js"', $output ); + $this->assertStringContainsString( 'class="button button-primary"', $output ); + $this->assertStringNotContainsString( 'dashicons-no-alt', $output ); + $this->assertStringContainsString( '

Add new custom field

', $output ); + $this->assertStringContainsString( 'class="submit add-custom-field custom-field-actions"', $output ); + $this->assertStringContainsString( 'Save', $output ); + $this->assertStringNotContainsString( 'Save field', $output ); + $this->assertStringContainsString( 'Cancel', $output ); + $this->assertStringContainsString( 'id="add-custom-field-button" class="button button-secondary custom-field-add-toggle hide-if-no-js"', $output ); + $this->assertStringContainsString( 'Add new custom field', $output ); + $this->assertStringNotContainsString( 'dashicons-plus-alt2', $output ); + } + + /** + * @covers ::post_custom_meta_box + */ + public function test_post_custom_meta_box_outputs_custom_fields_notice_before_fields() { + $post = self::factory()->post->create_and_get(); + + require_once ABSPATH . 'wp-admin/includes/meta-boxes.php'; + + wp_set_current_user( self::$editor_id ); + + ob_start(); + post_custom_meta_box( $post ); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'id="custom-fields-notice"', $output ); + $this->assertStringContainsString( 'class="custom-fields-notice notice notice-success is-dismissible hidden"', $output ); + $this->assertStringContainsString( 'class="screen-reader-text">Dismiss this notice.', $output ); + $this->assertLessThan( + strpos( $output, 'id="postcustomstuff"' ), + strpos( $output, 'id="custom-fields-notice"' ) + ); + $this->assertLessThan( + strpos( $output, 'id="list-table"' ), + strpos( $output, 'id="custom-fields-notice"' ) + ); + } + + /** + * @covers ::list_meta + */ + public function test_list_meta_outputs_empty_state_class_when_there_are_no_custom_fields() { + ob_start(); + list_meta( array() ); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'id="list-table" class="custom-fields-list is-empty"', $output ); + } + + /** + * @covers ::list_meta + */ + public function test_list_meta_outputs_has_fields_class_when_there_are_custom_fields() { + ob_start(); + list_meta( + array( + array( + 'meta_id' => 123, + 'meta_key' => 'event_location', + 'meta_value' => 'Marnixstraat 234, Haarlem 3459RD, The Netherlands', + ), + ) + ); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'id="list-table" class="custom-fields-list has-fields"', $output ); + $this->assertStringContainsString( "id='meta-123' class='custom-field-row is-saved'", $output ); + } + /** * @ticket 50019 */