diff --git a/src/js/_enqueues/admin/inline-edit-post.js b/src/js/_enqueues/admin/inline-edit-post.js index 9d6f66c3b0034..5963a2211e6fd 100644 --- a/src/js/_enqueues/admin/inline-edit-post.js +++ b/src/js/_enqueues/admin/inline-edit-post.js @@ -250,7 +250,7 @@ window.wp = window.wp || {}; if ( ! $( this ).parent().find( 'input[name="indeterminate_post_category[]"]' ).length ) { // Get the term label text. var label = $( this ).parent().text(); - // Set indeterminate states for the backend. Add accessible text for indeterminate inputs. + // Set indeterminate states for the backend. Add accessible text for indeterminate inputs. $( this ).after( '' ).attr( 'aria-label', label.trim() + ': ' + wp.i18n.__( 'Some selected posts have this category' ) ); } } @@ -603,9 +603,9 @@ $( function() { inlineEditPost.init(); } ); // Show/hide locks on posts. $( function() { - // Set the heartbeat interval to 15 seconds. + // Set the heartbeat interval to 10 seconds. if ( typeof wp !== 'undefined' && wp.heartbeat ) { - wp.heartbeat.interval( 15 ); + wp.heartbeat.interval( 10 ); } }).on( 'heartbeat-tick.wp-check-locked-posts', function( e, data ) { var locked = data['wp-check-locked-posts'] || {}; diff --git a/src/js/_enqueues/admin/post.js b/src/js/_enqueues/admin/post.js index 557465bb2794e..e0b4f117dc9f0 100644 --- a/src/js/_enqueues/admin/post.js +++ b/src/js/_enqueues/admin/post.js @@ -343,9 +343,9 @@ jQuery( function($) { } }).filter(':visible').find('.wp-tab-first').trigger( 'focus' ); - // Set the heartbeat interval to 15 seconds if post lock dialogs are enabled. + // Set the heartbeat interval to 10 seconds if post lock dialogs are enabled. if ( wp.heartbeat && $('#post-lock-dialog').length ) { - wp.heartbeat.interval( 15 ); + wp.heartbeat.interval( 10 ); } // The form is being submitted by the user. diff --git a/src/js/_enqueues/wp/heartbeat.js b/src/js/_enqueues/wp/heartbeat.js index f3a92b0a1f78e..65635177d9f66 100644 --- a/src/js/_enqueues/wp/heartbeat.js +++ b/src/js/_enqueues/wp/heartbeat.js @@ -132,16 +132,17 @@ } /* - * The interval can be from 15 to 120 seconds and can be set temporarily to 5 seconds. - * It can be set in the initial options or changed later through JS and/or through PHP. + * Logic check: the interval can be from 1 to 3600 seconds and can be set temporarily + * to 5 seconds. It can be set in the initial options or changed later from JS + * or from PHP through the AJAX responses. */ if ( options.interval ) { settings.mainInterval = options.interval; - if ( settings.mainInterval < 15 ) { - settings.mainInterval = 15; - } else if ( settings.mainInterval > 120 ) { - settings.mainInterval = 120; + if ( settings.mainInterval < 1 ) { + settings.mainInterval = 1; + } else if ( settings.mainInterval > 3600 ) { + settings.mainInterval = 3600; } } @@ -721,10 +722,10 @@ * * @memberOf wp.heartbeat.prototype * - * @param {string|number} speed Interval: 'fast' or 5, 15, 30, 60, 120. + * @param {string|number} speed Interval: 'fast' or integer between 1 and 3600 (seconds). * Fast equals 5. - * @param {string} ticks Tells how many ticks before the interval reverts - * back. Used with speed = 'fast' or 5. + * @param {number} ticks Tells how many ticks before the interval reverts back. + * Value must be between 1 and 30. Used with speed = 'fast' or 5. * * @return {number} Current interval in seconds. */ @@ -733,35 +734,28 @@ oldInterval = settings.tempInterval ? settings.tempInterval : settings.mainInterval; if ( speed ) { - switch ( speed ) { - case 'fast': - case 5: - newInterval = 5000; - break; - case 15: - newInterval = 15000; - break; - case 30: - newInterval = 30000; - break; - case 60: - newInterval = 60000; - break; - case 120: - newInterval = 120000; - break; - case 'long-polling': - // Allow long polling (experimental). - settings.mainInterval = 0; - return 0; - default: + if ( 'fast' === speed ) { + // Special case, see below. + newInterval = 5000; + } else if ( 'long-polling' === speed ) { + // Allow long polling (experimental). + settings.mainInterval = 0; + return 0; + } else { + speed = parseInt( speed, 10 ); + + if ( speed >= 1 && speed <= 3600 ) { + newInterval = speed * 1000; + } else { newInterval = settings.originalInterval; + } } if ( settings.minimalInterval && newInterval < settings.minimalInterval ) { newInterval = settings.minimalInterval; } + // Special case, runs for a number of ticks then reverts to the previous interval. if ( 5000 === newInterval ) { ticks = parseInt( ticks, 10 ) || 30; ticks = ticks < 1 || ticks > 30 ? 30 : ticks; diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css index 17d9493161386..287f2ee7b4958 100644 --- a/src/wp-admin/css/common.css +++ b/src/wp-admin/css/common.css @@ -1180,6 +1180,17 @@ th.action-links { overflow: hidden; } +.wp-filter .favorites-form .favorites-username { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.5rem; +} + +.wp-filter .favorites-form .favorites-username input { + margin: 0; +} + .show-filters .filter-drawer, .show-favorites-form .favorites-form { display: block; @@ -1288,11 +1299,13 @@ th.action-links { } .filtered-by .tags { - display: inline; + display: flex; + align-items: flex-start; + flex-wrap: wrap; + gap: 8px; } .filtered-by .tag { - margin: 0 5px; padding: 4px 8px; border: 1px solid #dcdcde; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); @@ -1307,7 +1320,10 @@ th.action-links { } .filters-applied .filtered-by { - display: block; + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 10px; } .filters-applied .filter-drawer { diff --git a/src/wp-admin/edit-form-blocks.php b/src/wp-admin/edit-form-blocks.php index 91e4b1e37df62..e6abe9998028f 100644 --- a/src/wp-admin/edit-form-blocks.php +++ b/src/wp-admin/edit-form-blocks.php @@ -123,6 +123,14 @@ static function ( $classes ) { 'before' ); +// Set Heartbeat interval to 10 seconds, used to refresh post locks. +wp_add_inline_script( + 'heartbeat', + 'if ( window.wp && window.wp.heartbeat ) { + window.wp.heartbeat.interval( 10 ); + }' +); + /* * Get all available templates for the post/page attributes meta-box. * The "Default template" array element should only be added if the array is diff --git a/src/wp-admin/theme-install.php b/src/wp-admin/theme-install.php index 1cebf3405f117..bfd962d4fdb1c 100644 --- a/src/wp-admin/theme-install.php +++ b/src/wp-admin/theme-install.php @@ -230,7 +230,7 @@ ?>

-

+

diff --git a/src/wp-includes/block-patterns.php b/src/wp-includes/block-patterns.php index d672ffd900d15..851898d006a98 100644 --- a/src/wp-includes/block-patterns.php +++ b/src/wp-includes/block-patterns.php @@ -26,7 +26,6 @@ function _register_core_block_patterns_and_categories() { 'query-grid-posts', 'query-large-title-posts', 'query-offset-posts', - 'social-links-shared-background-color', ); foreach ( $core_block_patterns as $core_block_pattern ) { diff --git a/src/wp-includes/block-patterns/social-links-shared-background-color.php b/src/wp-includes/block-patterns/social-links-shared-background-color.php index 2ed16071b733d..37aac3f4e4eb9 100644 --- a/src/wp-includes/block-patterns/social-links-shared-background-color.php +++ b/src/wp-includes/block-patterns/social-links-shared-background-color.php @@ -3,6 +3,8 @@ * Social links with a shared background color. * * @package WordPress + * @since 5.8.0 + * @deprecated 6.7.0 This pattern is deprecated. Please use the Social Links block instead. */ return array( diff --git a/src/wp-includes/class-wp-network.php b/src/wp-includes/class-wp-network.php index d835765c6bd05..5bb745d79633b 100644 --- a/src/wp-includes/class-wp-network.php +++ b/src/wp-includes/class-wp-network.php @@ -131,7 +131,7 @@ public static function get_instance( $network_id ) { */ public function __construct( $network ) { foreach ( get_object_vars( $network ) as $key => $value ) { - $this->$key = $value; + $this->__set( $key, $value ); } $this->_set_site_name(); diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index eaaf2e77a5115..93b25a8dc89c4 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -4943,7 +4943,7 @@ private function step_in_foreign_content(): bool { $this->state->stack_of_open_elements->pop(); } - return $this->step( self::REPROCESS_CURRENT_NODE ); + goto in_foreign_content_process_in_current_insertion_mode; } /* @@ -5019,6 +5019,7 @@ private function step_in_foreign_content(): bool { goto in_foreign_content_end_tag_loop; } + in_foreign_content_process_in_current_insertion_mode: switch ( $this->state->insertion_mode ) { case WP_HTML_Processor_State::INSERTION_MODE_INITIAL: return $this->step_initial(); @@ -5169,17 +5170,13 @@ public function get_tag(): ?string { $tag_name = parent::get_tag(); - switch ( $tag_name ) { - case 'IMAGE': - /* - * > A start tag whose tag name is "image" - * > Change the token's tag name to "img" and reprocess it. (Don't ask.) - */ - return 'IMG'; - - default: - return $tag_name; - } + /* + * > A start tag whose tag name is "image" + * > Change the token's tag name to "img" and reprocess it. (Don't ask.) + */ + return ( 'IMAGE' === $tag_name && 'html' === $this->get_namespace() ) + ? 'IMG' + : $tag_name; } /** diff --git a/src/wp-includes/link-template.php b/src/wp-includes/link-template.php index 4cfc47f83ec05..08320dc792f4d 100644 --- a/src/wp-includes/link-template.php +++ b/src/wp-includes/link-template.php @@ -1618,14 +1618,18 @@ function get_edit_comment_link( $comment_id = 0, $context = 'display' ) { $location = admin_url( $action ) . $comment->comment_ID; + // Ensure the $comment_id variable passed to the filter is always an ID. + $comment_id = (int) $comment->comment_ID; + /** * Filters the comment edit link. * + * @since 2.3.0 * @since 6.7.0 The $comment_id and $context parameters are now being passed to the filter. * - * @param string $location The edit link. - * @param int $comment_id Optional. Unique ID of the comment to generate an edit link. - * @param int $context Optional. Context to include HTML entities in link. Default 'display'. + * @param string $location The edit link. + * @param int $comment_id Unique ID of the comment to generate an edit link. + * @param string $context Context to include HTML entities in link. Default 'display'. */ return apply_filters( 'get_edit_comment_link', $location, $comment_id, $context ); } diff --git a/src/wp-includes/meta.php b/src/wp-includes/meta.php index 32838b135dd34..6f6dd928e0498 100644 --- a/src/wp-includes/meta.php +++ b/src/wp-includes/meta.php @@ -1369,6 +1369,7 @@ function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = * @since 5.3.0 Valid meta types expanded to include "array" and "object". * @since 5.5.0 The `$default` argument was added to the arguments array. * @since 6.4.0 The `$revisions_enabled` argument was added to the arguments array. + * @since 6.7.0 The `label` argument was added to the arguments array. * * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', * or any other object type with an associated meta table. @@ -1380,6 +1381,7 @@ function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = * the meta key will be registered on the entire object type. Default empty. * @type string $type The type of data associated with this meta key. * Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'. + * @type string $label A human-readable label of the data attached to this meta key. * @type string $description A description of the data attached to this meta key. * @type bool $single Whether the meta key has one value per object, or an array of values per object. * @type mixed $default The default value returned from get_metadata() if no value has been set yet. @@ -1412,6 +1414,7 @@ function register_meta( $object_type, $meta_key, $args, $deprecated = null ) { $defaults = array( 'object_subtype' => '', 'type' => 'string', + 'label' => '', 'description' => '', 'default' => '', 'single' => false, diff --git a/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php b/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php index 5f3b55843e23a..aa0bc644bc1ce 100644 --- a/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php +++ b/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php @@ -478,6 +478,7 @@ protected function get_registered_fields() { $default_schema = array( 'type' => $default_args['type'], + 'title' => empty( $args['label'] ) ? '' : $args['label'], 'description' => empty( $args['description'] ) ? '' : $args['description'], 'default' => isset( $args['default'] ) ? $args['default'] : null, ); diff --git a/src/wp-includes/update.php b/src/wp-includes/update.php index c623b248b9308..79ed9cd5743c8 100644 --- a/src/wp-includes/update.php +++ b/src/wp-includes/update.php @@ -115,24 +115,26 @@ function wp_version_check( $extra_stats = array(), $force_check = false ) { // Filter to supported values. $gd_info = array_filter( $gd_info ); - // Add data for GD WebP and AVIF support. + // Add data for GD WebP, AVIF and HEIC support. $query['image_support']['gd'] = array_keys( array_filter( array( 'webp' => isset( $gd_info['WebP Support'] ), 'avif' => isset( $gd_info['AVIF Support'] ), + 'heic' => isset( $gd_info['HEIC Support'] ), ) ) ); } if ( class_exists( 'Imagick' ) ) { - // Add data for Imagick WebP and AVIF support. + // Add data for Imagick WebP, AVIF and HEIC support. $query['image_support']['imagick'] = array_keys( array_filter( array( 'webp' => ! empty( Imagick::queryFormats( 'WEBP' ) ), 'avif' => ! empty( Imagick::queryFormats( 'AVIF' ) ), + 'heic' => ! empty( Imagick::queryFormats( 'HEIC' ) ), ) ) ); diff --git a/tests/phpunit/tests/canonical.php b/tests/phpunit/tests/canonical.php index b83e9563d1fa0..886b09312910e 100644 --- a/tests/phpunit/tests/canonical.php +++ b/tests/phpunit/tests/canonical.php @@ -430,10 +430,11 @@ public function test_utf8_query_keys_canonical() { $this->go_to( get_permalink( $p ) ); - $url = redirect_canonical( add_query_arg( '%D0%BA%D0%BE%D0%BA%D0%BE%D0%BA%D0%BE', 1, site_url( '/' ) ), false ); - $this->assertNull( $url ); + $redirect = redirect_canonical( add_query_arg( '%D0%BA%D0%BE%D0%BA%D0%BE%D0%BA%D0%BE', 1, site_url( '/' ) ), false ); delete_option( 'page_on_front' ); + + $this->assertNull( $redirect ); } /** @@ -456,11 +457,12 @@ public function test_feed_canonical_with_not_exists_query() { ) ); - $url = redirect_canonical( get_term_feed_link( self::$terms['/category/parent/'] ), false ); + $redirect = redirect_canonical( get_term_feed_link( self::$terms['/category/parent/'] ), false ); + // Restore original global. $GLOBALS['wp_query'] = $global_query; - $this->assertNull( $url ); + $this->assertNull( $redirect ); } /** diff --git a/tests/phpunit/tests/canonical/https.php b/tests/phpunit/tests/canonical/https.php index 4b02f087651f2..11152e8d3c30e 100644 --- a/tests/phpunit/tests/canonical/https.php +++ b/tests/phpunit/tests/canonical/https.php @@ -61,8 +61,8 @@ public function test_https_request_with_https_home() { $redirect = redirect_canonical( $this->https, false ); - $this->assertNull( $redirect ); - remove_filter( 'home_url', array( $this, 'set_https' ) ); + + $this->assertNull( $redirect ); } } diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 17dd2ff7fbd68..bd6607935d220 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -54,6 +54,57 @@ public function test_get_tag_is_null_once_document_is_finished() { $this->assertNull( $processor->get_tag() ); } + /** + * Ensures that the proper tag-name remapping happens for the `IMAGE` tag. + * + * An HTML parser should treat an IMAGE tag as if it were an IMG tag, but + * only when found in the HTML namespace. As part of this rule, IMAGE tags + * in the HTML namespace are also void elements, while those in foreign + * content are not, making the self-closing flag significant. + * + * Example: + * + * // This input... + * + * + * // ...is equivalent to this normative HTML. + * + * + * @ticket 61576 + * + * @covers WP_HTML_Processor::get_tag + */ + public function test_get_tag_replaces_image_with_namespace_awareness() { + $processor = WP_HTML_Processor::create_fragment( '' ); + + $this->assertTrue( + $processor->next_tag(), + 'Could not find initial "" tag: check test setup.' + ); + + $this->assertSame( + 'IMG', + $processor->get_tag(), + 'HTML tags with the name "IMAGE" should be remapped to "IMG"' + ); + + $this->assertTrue( + $processor->next_tag(), + 'Could not find "" tag: check test setup.' + ); + + $this->assertTrue( + $processor->next_tag(), + 'Could not find SVG "" tag: check test setup.' + ); + + $this->assertSame( + 'IMAGE', + $processor->get_tag(), + 'Should not remap "IMAGE" to "IMG" for foreign elements.' + ); + } + /** * Ensures that the HTML Processor maintains its internal state through seek calls. * diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php b/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php index 54d60f8c78a66..4862ba981e6f0 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php @@ -21,6 +21,8 @@ * @group html-api-html5lib-tests */ class Tests_HtmlApi_Html5lib extends WP_UnitTestCase { + const TREE_INDENT = ' '; + /** * Skip specific tests that may not be supported or have known issues. */ @@ -49,9 +51,9 @@ class Tests_HtmlApi_Html5lib extends WP_UnitTestCase { * * @dataProvider data_external_html5lib_tests * - * @param string $fragment_context Context element in which to parse HTML, such as BODY or SVG. - * @param string $html Given test HTML. - * @param string $expected_tree Tree structure of parsed HTML. + * @param string|null $fragment_context Context element in which to parse HTML, such as BODY or SVG. + * @param string $html Given test HTML. + * @param string $expected_tree Tree structure of parsed HTML. */ public function test_parse( ?string $fragment_context, string $html, string $expected_tree ) { try { @@ -170,9 +172,8 @@ private static function build_tree_representation( ?string $fragment_context, st * and requires adjustment to initial parameters. * The full parser will not. */ - $output = $fragment_context ? "\n \n \n" : ''; - $indent_level = $fragment_context ? 2 : 0; - $indent = ' '; + $output = ''; + $indent_level = 0; $was_text = null; $text_node = ''; @@ -225,7 +226,7 @@ private static function build_tree_representation( ?string $fragment_context, st ++$indent_level; } - $output .= str_repeat( $indent, $tag_indent ) . "<{$tag_name}>\n"; + $output .= str_repeat( self::TREE_INDENT, $tag_indent ) . "<{$tag_name}>\n"; $attribute_names = $processor->get_attribute_names_with_prefix( '' ); if ( $attribute_names ) { @@ -278,18 +279,18 @@ static function ( $a, $b ) { if ( true === $val ) { $val = ''; } - $output .= str_repeat( $indent, $tag_indent + 1 ) . "{$display_name}=\"{$val}\"\n"; + $output .= str_repeat( self::TREE_INDENT, $tag_indent + 1 ) . "{$display_name}=\"{$val}\"\n"; } } // Self-contained tags contain their inner contents as modifiable text. $modifiable_text = $processor->get_modifiable_text(); if ( '' !== $modifiable_text ) { - $output .= str_repeat( $indent, $tag_indent + 1 ) . "\"{$modifiable_text}\"\n"; + $output .= str_repeat( self::TREE_INDENT, $tag_indent + 1 ) . "\"{$modifiable_text}\"\n"; } if ( 'html' === $namespace && 'TEMPLATE' === $token_name ) { - $output .= str_repeat( $indent, $indent_level ) . "content\n"; + $output .= str_repeat( self::TREE_INDENT, $indent_level ) . "content\n"; ++$indent_level; } @@ -303,14 +304,14 @@ static function ( $a, $b ) { } $was_text = true; if ( '' === $text_node ) { - $text_node .= str_repeat( $indent, $indent_level ) . '"'; + $text_node .= str_repeat( self::TREE_INDENT, $indent_level ) . '"'; } $text_node .= $text_content; break; case '#funky-comment': // Comments must be "<" then "!-- " then the data then " -->". - $output .= str_repeat( $indent, $indent_level ) . "\n"; + $output .= str_repeat( self::TREE_INDENT, $indent_level ) . "\n"; break; case '#comment': @@ -333,7 +334,7 @@ static function ( $a, $b ) { throw new Error( "Unhandled comment type for tree construction: {$processor->get_comment_type()}" ); } // Comments must be "<" then "!-- " then the data then " -->". - $output .= str_repeat( $indent, $indent_level ) . "\n"; + $output .= str_repeat( self::TREE_INDENT, $indent_level ) . "\n"; break; default: @@ -449,7 +450,7 @@ public static function parse_html5_dat_testfile( $filename ) { * context element as context. */ case 'document-fragment': - $test_context_element = explode( ' ', $line )[0]; + $test_context_element = trim( $line ); break; /* diff --git a/tests/phpunit/tests/link/getEditCommentLink.php b/tests/phpunit/tests/link/getEditCommentLink.php index 1d574d40286d1..f5b939779813a 100644 --- a/tests/phpunit/tests/link/getEditCommentLink.php +++ b/tests/phpunit/tests/link/getEditCommentLink.php @@ -127,4 +127,29 @@ function ( $location, $comment_id, $context ) { $this->assertSame( $expected_url_display, $actual_url_display ); $this->assertSame( $expected_url, $actual_url ); } + + /** + * Tests that the 'get_edit_comment_link' filter receives the comment ID, even when a comment object is passed. + * + * @ticket 61727 + */ + public function test_get_edit_comment_link_filter_uses_id() { + // Add a filter just to catch the $comment_id filter parameter value. + $comment_id_filter_param = null; + add_filter( + 'get_edit_comment_link', + function ( $location, $comment_id ) use ( &$comment_id_filter_param ) { + $comment_id_filter_param = $comment_id; + return $location; + }, + 10, + 2 + ); + + // Pass a comment object to get_edit_comment_link(). + get_edit_comment_link( get_comment( self::$comment_id ) ); + + // The filter should still always receive the comment ID, not the object. + $this->assertSame( self::$comment_id, $comment_id_filter_param ); + } } diff --git a/tests/phpunit/tests/meta/registerMeta.php b/tests/phpunit/tests/meta/registerMeta.php index 329321dd9bc67..30b6920bdea0d 100644 --- a/tests/phpunit/tests/meta/registerMeta.php +++ b/tests/phpunit/tests/meta/registerMeta.php @@ -92,6 +92,7 @@ public function test_register_meta_with_post_object_type_populates_wp_meta_keys( '' => array( 'flight_number' => array( 'type' => 'string', + 'label' => '', 'description' => '', 'single' => false, 'sanitize_callback' => null, @@ -117,6 +118,7 @@ public function test_register_meta_with_term_object_type_populates_wp_meta_keys( '' => array( 'category_icon' => array( 'type' => 'string', + 'label' => '', 'description' => '', 'single' => false, 'sanitize_callback' => null, @@ -172,6 +174,7 @@ public function test_register_meta_with_current_sanitize_callback_populates_wp_m '' => array( 'flight_number' => array( 'type' => 'string', + 'label' => '', 'description' => '', 'single' => false, 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ), @@ -256,6 +259,19 @@ public function test_get_registered_meta_keys_with_invalid_type_is_empty() { $this->assertEmpty( $meta_keys ); } + /** + * @ticket 61998 + */ + public function test_get_registered_meta_keys_label_arg() { + register_meta( 'post', 'registered_key1', array( 'label' => 'Field label' ) ); + + $meta_keys = get_registered_meta_keys( 'post' ); + + unregister_meta_key( 'post', 'registered_key1' ); + + $this->assertSame( 'Field label', $meta_keys['registered_key1']['label'] ); + } + public function test_get_registered_meta_keys_description_arg() { register_meta( 'post', 'registered_key1', array( 'description' => 'I\'m just a field, take a good look at me' ) ); @@ -340,6 +356,7 @@ public function test_register_meta_with_subtype_populates_wp_meta_keys( $type, $ $subtype => array( 'flight_number' => array( 'type' => 'string', + 'label' => '', 'description' => '', 'single' => false, 'sanitize_callback' => null, @@ -394,6 +411,7 @@ public function test_unregister_meta_without_subtype_keeps_subtype_meta_key( $ty $subtype => array( 'flight_number' => array( 'type' => 'string', + 'label' => '', 'description' => '', 'single' => false, 'sanitize_callback' => null, diff --git a/tests/phpunit/tests/multisite/network.php b/tests/phpunit/tests/multisite/network.php index c7fb78e54778f..71e80383f2292 100644 --- a/tests/phpunit/tests/multisite/network.php +++ b/tests/phpunit/tests/multisite/network.php @@ -126,7 +126,11 @@ public function get_main_network_id() { } /** + * Tests that the `WP_Network::$id` property is an integer. + * * @ticket 37050 + * + * @covers WP_Network::__get */ public function test_wp_network_object_id_property_is_int() { $id = self::factory()->network->create(); @@ -136,6 +140,65 @@ public function test_wp_network_object_id_property_is_int() { $this->assertSame( (int) $id, $network->id ); } + /** + * Tests that the `WP_Network::$id` property is stored as an integer. + * + * Uses reflection to access the private property. + * Differs from using the public getter method, which casts to an integer. + * + * @ticket 62035 + * + * @covers WP_Network::__construct + */ + public function test_wp_network_object_id_property_stored_as_int() { + $id = self::factory()->network->create(); + + $network = WP_Network::get_instance( $id ); + + $reflection = new ReflectionObject( $network ); + $property = $reflection->getProperty( 'id' ); + $property->setAccessible( true ); + + $this->assertSame( (int) $id, $property->getValue( $network ) ); + } + + /** + * Tests that the `WP_Network::$blog_id` property is a string. + * + * @ticket 62035 + * + * @covers WP_Network::__get + */ + public function test_wp_network_object_blog_id_property_is_int() { + $id = self::factory()->network->create(); + + $network = WP_Network::get_instance( $id ); + + $this->assertIsString( $network->blog_id ); + } + + /** + * Tests that the `WP_Network::$blog_id` property is stored as a string. + * + * Uses reflection to access the private property. + * Differs from using the public getter method, which casts to a string. + * + * @ticket 62035 + * + * @covers WP_Network::__construct + */ + public function test_wp_network_object_blog_id_property_stored_as_string() { + $id = self::factory()->network->create(); + + $network = WP_Network::get_instance( $id ); + + $reflection = new ReflectionObject( $network ); + $property = $reflection->getProperty( 'blog_id' ); + $property->setAccessible( true ); + + $this->assertIsString( $property->getValue( $network ) ); + } + /** * @ticket 22917 */ diff --git a/tests/phpunit/tests/rest-api/rest-post-meta-fields.php b/tests/phpunit/tests/rest-api/rest-post-meta-fields.php index 2546076b2ae1d..47eada094d0ee 100644 --- a/tests/phpunit/tests/rest-api/rest-post-meta-fields.php +++ b/tests/phpunit/tests/rest-api/rest-post-meta-fields.php @@ -243,6 +243,18 @@ public function set_up() { ) ); + register_post_meta( + 'post', + 'with_label', + array( + 'type' => 'string', + 'single' => true, + 'show_in_rest' => true, + 'label' => 'Meta Label', + 'default' => '', + ) + ); + /** @var WP_REST_Server $wp_rest_server */ global $wp_rest_server; $wp_rest_server = new Spy_REST_Server(); @@ -3091,8 +3103,21 @@ public function test_default_is_added_to_schema() { $response = rest_do_request( $request ); $schema = $response->get_data()['schema']['properties']['meta']['properties']['with_default']; - $this->assertArrayHasKey( 'default', $schema ); - $this->assertSame( 'Goodnight Moon', $schema['default'] ); + $this->assertArrayHasKey( 'default', $schema, 'Schema is expected to have the default property' ); + $this->assertSame( 'Goodnight Moon', $schema['default'], 'Schema default is expected to be defined and contain the value of the meta default argument.' ); + } + + /** + * @ticket 61998 + */ + public function test_title_is_added_to_schema() { + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' ); + $response = rest_do_request( $request ); + + $schema = $response->get_data()['schema']['properties']['meta']['properties']['with_label']; + + $this->assertArrayHasKey( 'title', $schema, 'Schema is expected to have the title property' ); + $this->assertSame( 'Meta Label', $schema['title'], 'Schema title is expected to be defined and contain the value of the meta label argument.' ); } /** diff --git a/tests/phpunit/tests/term/cache.php b/tests/phpunit/tests/term/cache.php index f299bf9bed643..99a73f7823e71 100644 --- a/tests/phpunit/tests/term/cache.php +++ b/tests/phpunit/tests/term/cache.php @@ -445,4 +445,56 @@ public function test_get_object_term_cache_should_return_error_if_any_term_is_an $terms = get_the_terms( $p, 'wptests_tax' ); $this->assertWPError( $terms ); } + + /** + * Ensures that the term query cache is cleared when a child term is inserted. + * + * @ticket 62031 + */ + public function test_inserting_child_term_clears_the_query_cache() { + register_taxonomy( + 'wptests_tax', + 'post', + array( + 'hierarchical' => true, + ) + ); + + $parent = self::factory()->term->create( + array( + 'taxonomy' => 'wptests_tax', + ) + ); + + $children = get_terms( + array( + 'taxonomy' => 'wptests_tax', + 'hide_empty' => false, + 'parent' => $parent, + 'fields' => 'ids', + ) + ); + + $this->assertEmpty( $children, 'No child terms are expected to exist.' ); + + $child = wp_insert_term( + 'child-term-62031', + 'wptests_tax', + array( + 'parent' => $parent, + ) + ); + + $children = get_terms( + array( + 'taxonomy' => 'wptests_tax', + 'hide_empty' => false, + 'parent' => $parent, + 'fields' => 'ids', + ) + ); + + $this->assertNotEmpty( $children, 'Child terms are expected to exist.' ); + $this->assertContains( $child['term_id'], $children, 'Querying by parent ID is expected to include the new child term.' ); + } } diff --git a/tests/phpunit/tests/user/wpRegisterPersistedPreferencesMeta.php b/tests/phpunit/tests/user/wpRegisterPersistedPreferencesMeta.php index 8af6ae9b81533..a45b015ad9728 100644 --- a/tests/phpunit/tests/user/wpRegisterPersistedPreferencesMeta.php +++ b/tests/phpunit/tests/user/wpRegisterPersistedPreferencesMeta.php @@ -31,6 +31,7 @@ public function test_should_register_persisted_preferences_meta() { $this->assertSame( array( 'type' => 'object', + 'label' => '', 'description' => '', 'single' => true, 'sanitize_callback' => null,