Skip to content

Commit cba9665

Browse files
authored
Merge pull request #1999 from WordPress/enhance/view-transition-names-support
Add support for dynamic view transition names for global elements, and certain post elements to View Transitions plugin
2 parents 565ed5e + b970e29 commit cba9665

File tree

11 files changed

+431
-1
lines changed

11 files changed

+431
-1
lines changed

.eslintrc.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ const config = {
2525
'/dist',
2626
'/**/*.min.js',
2727
],
28+
overrides: [
29+
...( wpConfig?.overrides || [] ),
30+
{
31+
files: [ 'plugins/view-transitions/js/**/*.js' ],
32+
rules: {
33+
'jsdoc/no-undefined-types': [
34+
'error',
35+
{ definedTypes: [ 'PageSwapEvent', 'PageRevealEvent' ] },
36+
],
37+
},
38+
},
39+
],
2840
};
2941

3042
module.exports = config;

plugins/view-transitions/hooks.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ function plvt_render_generator(): void {
2929
* Filters related to the View Transitions functionality.
3030
*/
3131
add_action( 'after_setup_theme', 'plvt_polyfill_theme_support', PHP_INT_MAX );
32+
add_action( 'init', 'plvt_sanitize_view_transitions_theme_support', 1 );
3233
add_action( 'wp_enqueue_scripts', 'plvt_load_view_transitions' );
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
/**
3+
* Utility functions for View Transitions.
4+
*
5+
* @package view-transitions
6+
* @since 1.0.0
7+
*/
8+
9+
/**
10+
* Gets the path to a script or stylesheet.
11+
*
12+
* @since 1.0.0
13+
* @access private
14+
*
15+
* @param string $src_path Source path, relative to plugin root.
16+
* @param string|null $min_path Minified path. If not supplied, then '.min' is injected before the file extension in the source path.
17+
* @return string Full path to script or stylesheet.
18+
*
19+
* @noinspection PhpDocMissingThrowsInspection
20+
*/
21+
function plvt_get_asset_path( string $src_path, ?string $min_path = null ): string {
22+
if ( null === $min_path ) {
23+
// Note: wp_scripts_get_suffix() is not used here because we need access to both the source and minified paths.
24+
$min_path = (string) preg_replace( '/(?=\.\w+$)/', '.min', $src_path );
25+
}
26+
27+
$plugin_dir = trailingslashit( dirname( __DIR__ ) );
28+
29+
$force_src = false;
30+
if ( WP_DEBUG && ! file_exists( $plugin_dir . $min_path ) ) {
31+
$force_src = true;
32+
/**
33+
* No WP_Exception is thrown by wp_trigger_error() since E_USER_ERROR is not passed as the error level.
34+
*
35+
* @noinspection PhpUnhandledExceptionInspection
36+
*/
37+
wp_trigger_error(
38+
__FUNCTION__,
39+
sprintf(
40+
/* translators: %s is the minified asset path */
41+
__( 'Minified asset has not been built: %s', 'view-transitions' ),
42+
$min_path
43+
),
44+
E_USER_WARNING
45+
);
46+
}
47+
48+
if ( SCRIPT_DEBUG || $force_src ) {
49+
return $plugin_dir . $src_path;
50+
}
51+
52+
return $plugin_dir . $min_path;
53+
}

plugins/view-transitions/includes/theme.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,67 @@ function plvt_polyfill_theme_support(): void {
2727
add_theme_support( 'view-transitions' );
2828
}
2929

30+
/**
31+
* Sanitizes theme support arguments for the 'view-transitions' feature.
32+
*
33+
* If the feature was part of WordPress Core, the logic of this function would become part of the `add_theme_support()`
34+
* function instead. There is no action or filter that could be used though, hence it is implemented here in a separate
35+
* function that runs after `after_setup_theme`, but before the 'view-transitions' feature arguments are possibly used.
36+
*
37+
* @since 1.0.0
38+
*
39+
* @global array<string, mixed> $_wp_theme_features Theme support features added and their arguments.
40+
*/
41+
function plvt_sanitize_view_transitions_theme_support(): void {
42+
global $_wp_theme_features;
43+
44+
if ( ! isset( $_wp_theme_features['view-transitions'] ) ) {
45+
return;
46+
}
47+
48+
$args = $_wp_theme_features['view-transitions'];
49+
50+
$defaults = array(
51+
'post-selector' => '.wp-block-post.post, article.post, body.single main',
52+
'global-transition-names' => array(
53+
'header' => 'header',
54+
'main' => 'main',
55+
),
56+
'post-transition-names' => array(
57+
'.wp-block-post-title, .entry-title' => 'post-title',
58+
'.wp-post-image' => 'post-thumbnail',
59+
'.wp-block-post-content, .entry-content' => 'post-content',
60+
),
61+
);
62+
63+
// If no specific `$args` were provided, simply use the defaults.
64+
if ( true === $args ) {
65+
$args = $defaults;
66+
} else {
67+
/*
68+
* By default, `add_theme_support()` will take all function parameters as `$args`, but for the
69+
* 'view-transitions' feature, only a single associative array of arguments is relevant, which is expected as
70+
* the sole (optional) parameter.
71+
*/
72+
if ( count( $args ) === 1 && isset( $args[0] ) && is_array( $args[0] ) ) {
73+
$args = $args[0];
74+
}
75+
76+
$args = wp_parse_args( $args, $defaults );
77+
78+
// Enforce correct types.
79+
if ( ! is_array( $args['global-transition-names'] ) ) {
80+
$args['global-transition-names'] = array();
81+
}
82+
if ( ! is_array( $args['post-transition-names'] ) ) {
83+
$args['post-transition-names'] = array();
84+
}
85+
}
86+
87+
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
88+
$_wp_theme_features['view-transitions'] = $args;
89+
}
90+
3091
/**
3192
* Loads view transitions based on the current configuration.
3293
*
@@ -42,4 +103,44 @@ function plvt_load_view_transitions(): void {
42103
wp_register_style( 'wp-view-transitions', false, array(), null ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
43104
wp_add_inline_style( 'wp-view-transitions', $stylesheet );
44105
wp_enqueue_style( 'wp-view-transitions' );
106+
107+
$theme_support = get_theme_support( 'view-transitions' );
108+
109+
/*
110+
* No point in loading the script if no specific view transition names are configured.
111+
*/
112+
if (
113+
( ! is_array( $theme_support['global-transition-names'] ) || count( $theme_support['global-transition-names'] ) === 0 ) &&
114+
( ! is_array( $theme_support['post-transition-names'] ) || count( $theme_support['post-transition-names'] ) === 0 )
115+
) {
116+
return;
117+
}
118+
119+
$config = array(
120+
'postSelector' => $theme_support['post-selector'],
121+
'globalTransitionNames' => $theme_support['global-transition-names'],
122+
'postTransitionNames' => $theme_support['post-transition-names'],
123+
);
124+
125+
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
126+
$src_script = file_get_contents( plvt_get_asset_path( 'js/view-transitions.js' ) );
127+
if ( false === $src_script || '' === $src_script ) {
128+
// This clause should never be entered, but is needed to please PHPStan. Can't hurt to be safe.
129+
return;
130+
}
131+
132+
$init_script = sprintf(
133+
'plvtInitViewTransitions( %s )',
134+
wp_json_encode( $config, JSON_FORCE_OBJECT )
135+
);
136+
137+
/*
138+
* This must be in the <head>, not in the footer.
139+
* This is because the pagereveal event listener must be added before the first rAF occurs since that is when the event fires. See <https://issues.chromium.org/issues/40949146#comment10>.
140+
* An inline script is used to avoid an extra request.
141+
*/
142+
wp_register_script( 'wp-view-transitions', false, array(), null, array() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
143+
wp_add_inline_script( 'wp-view-transitions', $src_script );
144+
wp_add_inline_script( 'wp-view-transitions', $init_script );
145+
wp_enqueue_script( 'wp-view-transitions' );
45146
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export type ViewTransitionsConfig = {
2+
postSelector?: string;
3+
globalTransitionNames?: Record< string, string >;
4+
postTransitionNames?: Record< string, string >;
5+
};
6+
7+
export type InitViewTransitionsFunction = (
8+
config: ViewTransitionsConfig
9+
) => void;
10+
11+
declare global {
12+
interface Window {
13+
plvtInitViewTransitions?: InitViewTransitionsFunction;
14+
navigation?: {
15+
activation: NavigationActivation;
16+
};
17+
}
18+
}
19+
20+
export type PageSwapListenerFunction = ( event: PageSwapEvent ) => void;
21+
export type PageRevealListenerFunction = ( event: PageRevealEvent ) => void;

0 commit comments

Comments
 (0)