Skip to content
7 changes: 7 additions & 0 deletions src/wp-admin/css/view-transitions.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@view-transition {
navigation: auto;
}

#adminmenu > .menu-top {
view-transition-name: attr(id type(<custom-ident>), none);
}
1 change: 1 addition & 0 deletions src/wp-includes/default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,7 @@
add_action( 'admin_enqueue_scripts', 'wp_localize_jquery_ui_datepicker', 1000 );
add_action( 'admin_enqueue_scripts', 'wp_common_block_scripts_and_styles' );
add_action( 'admin_enqueue_scripts', 'wp_enqueue_command_palette_assets' );
add_action( 'admin_enqueue_scripts', 'wp_enqueue_view_transitions_admin_css' );
add_action( 'enqueue_block_assets', 'wp_enqueue_classic_theme_styles' );
add_action( 'enqueue_block_assets', 'wp_enqueue_registered_block_scripts_and_styles' );
add_action( 'enqueue_block_assets', 'enqueue_block_styles_assets', 30 );
Expand Down
3 changes: 3 additions & 0 deletions src/wp-includes/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -1699,6 +1699,9 @@ function wp_default_styles( $styles ) {
$wp_edit_blocks_dependencies
);

$styles->add( 'wp-view-transitions-admin', false );
did_action( 'init' ) && $styles->add_inline_style( 'wp-view-transitions-admin', wp_get_view_transitions_admin_css() );

$package_styles = array(
'block-editor' => array( 'wp-components', 'wp-preferences' ),
'block-library' => array(),
Expand Down
30 changes: 30 additions & 0 deletions src/wp-includes/view-transitions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
/**
* View Transitions API.
*
* @package WordPress
* @subpackage View Transitions
* @since 7.0.0
*/

/**
* Enqueues View Transitions CSS for the admin.
*
* @since 7.0.0
*/
function wp_enqueue_view_transitions_admin_css(): void {
wp_enqueue_style( 'wp-view-transitions-admin' );
}

/**
* Gets the CSS for View Transitions in the admin.
*
* @since 7.0.0
*
* @return string The CSS.
*/
function wp_get_view_transitions_admin_css(): string {
$affix = SCRIPT_DEBUG ? '' : '.min';
$path = ABSPATH . "wp-admin/css/view-transitions{$affix}.css";
return file_get_contents( $path );
Comment on lines +28 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$path = ABSPATH . "wp-admin/css/view-transitions{$affix}.css";
return file_get_contents( $path );
$path = ABSPATH . "wp-admin/css/view-transitions{$affix}.css";
if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
return '';
}
return file_get_contents( $path );

Should we check whether the file exists and return an empty string if it doesn’t?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we needs to add filter so we can extend the CSS? Something like:

return apply_filters( 'wp_view_transitions_admin_css', file_get_contents( $path ) );

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check whether the file exists and return an empty string if it doesn’t?

It should exist. If not, it's an error. We don't do a file_exists() check in _print_emoji_detection_script(), for example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha.

Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file_get_contents() call lacks error handling. If the file doesn't exist or can't be read (e.g., file permissions issue), this will generate a PHP warning and return false, which could cause issues when the CSS is added inline. Consider adding error handling with is_readable() check before reading the file, similar to the pattern used in script-loader.php line 3026.

Suggested change
return file_get_contents( $path );
$contents = '';
if ( is_readable( $path ) ) {
$contents = file_get_contents( $path );
}
return is_string( $contents ) ? $contents : '';

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file will always exist. So this isn't necessary.

}
1 change: 1 addition & 0 deletions src/wp-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@
require ABSPATH . WPINC . '/class-wp-url-pattern-prefixer.php';
require ABSPATH . WPINC . '/class-wp-speculation-rules.php';
require ABSPATH . WPINC . '/speculative-loading.php';
require ABSPATH . WPINC . '/view-transitions.php';

add_action( 'after_setup_theme', array( wp_script_modules(), 'add_hooks' ) );
add_action( 'after_setup_theme', array( wp_interactivity(), 'add_hooks' ) );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Tests for the wp_enqueue_view_transitions_admin_css() function.
*
* @package WordPress
* @subpackage View Transitions
*/

/**
* @group view-transitions
* @covers ::wp_enqueue_view_transitions_admin_css
*/
class Tests_View_Transitions_wpEnqueueViewTransitionsAdminCss extends WP_UnitTestCase {

private ?WP_Styles $original_wp_styles = null;

public function set_up() {
global $wp_styles;

parent::set_up();
$this->original_wp_styles = $wp_styles;
}

public function tear_down() {
global $wp_styles;

$wp_styles = $this->original_wp_styles;
parent::tear_down();
}

/**
* Tests that the hook for enqueuing admin view transitions CSS is set up.
*
* @ticket 64470
*/
public function test_hook() {
$this->assertSame( 10, has_action( 'admin_enqueue_scripts', 'wp_enqueue_view_transitions_admin_css' ) );
}

/**
* Tests that the admin view transitions style handle includes the inline CSS.
*
* @ticket 64470
*
* @covers ::wp_get_view_transitions_admin_css
*/
public function test_inline_css_included() {
$after_data = wp_styles()->get_data( 'wp-view-transitions-admin', 'after' );
$this->assertIsArray( $after_data, 'Expected `after` data to be an array.' );
$css = wp_get_view_transitions_admin_css();
$this->assertStringContainsString( '@view-transition', $css );
$this->assertContains( $css, $after_data );
Comment on lines +47 to +52
Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test doesn't verify that the function handles missing CSS files gracefully. If the file doesn't exist (e.g., minified version), wp_get_view_transitions_admin_css() will throw a fatal error. Add a test case to verify error handling when the CSS file is not found.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will always exist. This isn't necessary.

}

/**
* Tests enqueuing admin view transitions CSS.
*
* @ticket 64470
*/
public function test_wp_enqueue_view_transitions_admin_css() {
$this->assertFalse( wp_style_is( 'wp-view-transitions-admin' ) );

wp_enqueue_view_transitions_admin_css();
$this->assertTrue( wp_style_is( 'wp-view-transitions-admin' ) );
}
}
Loading