PluginProbe
Gutenberg / trunk
Gutenberg vtrunk
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
← All changes | build/scripts/block-library/playlist.php +104 -44 23.5.1 → trunk View file →
@@ -7,9 +7,9 @@
7 7
8 8 /**
9 9 * Renders the `core/playlist` block on server.
10 10 *
11 - * @since 6.9.0
11 + * @since 7.1.0
12 12 *
13 13 * @param array $attributes The block attributes.
14 14 * @param string $content The block content.
15 15 * @param WP_Block $block The block instance.
@@ -16,42 +16,44 @@
16 16 *
17 17 * @return string Returns the Playlist.
18 18 */
19 19 function gutenberg_render_block_core_playlist( $attributes, $content, $block ) {
20 - if ( empty( $attributes['currentTrack'] ) ) {
21 - return '';
22 - }
20 + $playlist_id = wp_unique_id( 'playlist-' );
21 + $playlist_tracks = array();
22 + $tracks_data = array();
23 + $show_play_button_artwork = ! empty( $attributes['showPlayButtonArtwork'] );
23 24
24 - $current_media_id = $attributes['currentTrack'];
25 - $playlist_id = wp_unique_id( 'playlist-' );
26 - $playlist_tracks = array();
27 - $tracks_data = array();
28 - $current_unique_id = null;
29 -
30 25 // Parse inner blocks to extract track data.
31 26 // This approach avoids duplicating track data in the HTML output.
32 27 if ( ! empty( $block->inner_blocks ) ) {
33 28 foreach ( $block->inner_blocks as $inner_block ) {
34 29 if ( 'core/playlist-track' === $inner_block->name ) {
35 - $inner_block->context['playlistId'] = $playlist_id;
30 + $track_attributes = $inner_block->attributes;
36 31
37 - $track_attributes = $inner_block->attributes;
38 - $unique_id = $track_attributes['uniqueId'] ?? wp_unique_id( 'playlist-track-' );
39 - $playlist_tracks[] = $unique_id;
32 + if ( empty( $track_attributes['id'] ) ) {
33 + continue;
34 + }
40 35
41 - $inner_block->attributes['uniqueId'] = $unique_id;
36 + $track_id = 'track-' . count( $playlist_tracks );
37 + $playlist_tracks[] = $track_id;
42 38
43 39 // Extract track metadata from block attributes.
44 - $title = isset( $track_attributes['title'] ) && ! empty( $track_attributes['title'] ) ? $track_attributes['title'] : __( 'Unknown title' );
45 - $artist = $track_attributes['artist'] ?? '';
46 - $album = $track_attributes['album'] ?? '';
47 - $image = $track_attributes['image'] ?? '';
48 - $url = $track_attributes['src'] ?? '';
49 - $aria_label = $title;
40 + $track_title_attr = $track_attributes['title'] ?? null;
41 + $track_artist = $track_attributes['artist'] ?? null;
42 + $track_album = $track_attributes['album'] ?? null;
43 + $track_image = $track_attributes['image'] ?? null;
44 + $track_src = $track_attributes['src'] ?? null;
45 + $title = ! empty( $track_title_attr ) && is_string( $track_title_attr ) ? $track_title_attr : __( 'Unknown title' );
46 + $artist = is_string( $track_artist ) ? $track_artist : '';
47 + $album = is_string( $track_album ) ? $track_album : '';
48 + $image = is_string( $track_image ) ? $track_image : '';
49 + $image_alt = $track_attributes['imageAlt'] ?? '';
50 + $url = is_string( $track_src ) ? $track_src : '';
51 + $aria_label = $title;
50 52
51 53 if ( $title && $artist && $album ) {
52 54 $aria_label = sprintf(
53 - /* translators: %1$s: track title, %2$s artist name, %3$s: album name. */
55 + /* translators: %1$s: track title, %2$s: artist name, %3$s: album name. */
54 56 _x( '%1$s by %2$s from the album %3$s', 'track title, artist name, album name' ),
55 57 $title,
56 58 $artist,
57 59 $album
@@ -60,28 +62,22 @@
60 62
61 63 // Data is passed to wp_interactivity_state() which JSON-encodes it,
62 64 // so we use wp_strip_all_tags() instead of esc_html() to prevent
63 65 // HTML injection without double-encoding. URLs still use esc_url().
64 - $tracks_data[ $unique_id ] = array(
66 + $tracks_data[ $track_id ] = array(
65 67 'url' => esc_url( $url ),
66 68 'title' => wp_strip_all_tags( $title ),
67 69 'artist' => wp_strip_all_tags( $artist ),
68 70 'album' => wp_strip_all_tags( $album ),
69 71 'image' => esc_url( $image ),
72 + 'imageAlt' => wp_strip_all_tags( $image_alt ),
70 73 'ariaLabel' => wp_strip_all_tags( $aria_label ),
71 74 );
72 -
73 - if ( $unique_id === $current_media_id ) {
74 - $current_unique_id = $unique_id;
75 - }
76 75 }
77 76 }
78 77 }
79 78
80 - // If there are no tracks but there is a currentTrack set, do not render the block.
81 - // This can happen for example if the currentTrack was not deleted correctly
82 - // or if the block is manually edited in the code editor mode.
83 - if ( empty( $playlist_tracks ) || ! in_array( $current_media_id, $playlist_tracks, true ) ) {
79 + if ( empty( $playlist_tracks ) ) {
84 80 return '';
85 81 }
86 82
87 83 wp_enqueue_script_module( '@wordpress/block-library/playlist/view' );
@@ -101,15 +97,55 @@
101 97
102 98 // Add waveform player container with translated button labels.
103 99 $label_play = esc_attr__( 'Play' );
104 100 $label_pause = esc_attr__( 'Pause' );
105 - $html = '<div class="wp-block-playlist__waveform-player"
101 + $label_seek = esc_attr__( 'Seek' );
102 + /* translators: %1$s: current audio time, %2$s: total audio duration. */
103 + $label_seek_value = esc_attr_x(
104 + '%1$s of %2$s',
105 + 'audio current time of total duration'
106 + );
107 + $waveform_color_attribute = '';
108 + $waveform_gradient_attribute = '';
109 + $waveform_background_color_attribute = '';
110 + $waveform_background_gradient_attribute = '';
111 + if ( ! empty( $attributes['waveformColor'] ) ) {
112 + $waveform_color_attribute = sprintf(
113 + ' data-waveform-player-color="%s"',
114 + esc_attr( $attributes['waveformColor'] )
115 + );
116 + }
117 + if ( ! empty( $attributes['waveformGradient'] ) ) {
118 + $waveform_gradient_attribute = sprintf(
119 + ' data-waveform-player-gradient="%s"',
120 + esc_attr( $attributes['waveformGradient'] )
121 + );
122 + }
123 + if ( ! empty( $attributes['waveformBackgroundColor'] ) ) {
124 + $waveform_background_color_attribute = sprintf(
125 + ' data-waveform-player-background-color="%s"',
126 + esc_attr( $attributes['waveformBackgroundColor'] )
127 + );
128 + }
129 + if ( ! empty( $attributes['waveformBackgroundGradient'] ) ) {
130 + $waveform_background_gradient_attribute = sprintf(
131 + ' data-waveform-player-background-gradient="%s"',
132 + esc_attr( $attributes['waveformBackgroundGradient'] )
133 + );
134 + }
135 + $html = '<div class="wp-block-playlist__waveform-player"' .
136 + $waveform_color_attribute .
137 + $waveform_gradient_attribute .
138 + $waveform_background_color_attribute .
139 + $waveform_background_gradient_attribute . '
106 140 data-wp-watch="callbacks.initWaveformPlayer"
107 141 data-label-play="' . $label_play . '"
108 142 data-label-pause="' . $label_pause . '"
143 + data-label-seek="' . $label_seek . '"
144 + data-label-seek-value="' . $label_seek_value . '"
109 145 ></div>';
110 146
111 - // Add the HTML for the current track inside the figure.
147 + // Add the waveform player container inside the figure.
112 148 $figure = null;
113 149 preg_match( '/<figure[^>]*>/', $content, $figure );
114 150 if ( ! empty( $figure[0] ) ) {
115 151 $content = preg_replace( '/(<figure[^>]*>)/', '$1' . $html, $content, 1 );
@@ -117,26 +153,50 @@
117 153
118 154 $processor = new WP_HTML_Tag_Processor( $content );
119 155 $processor->next_tag( 'figure' );
120 156 $processor->set_attribute( 'data-wp-interactive', 'core/playlist' );
121 - // Extract the waveform style from the block style variation class.
122 - $waveform_style = 'bars';
123 - if ( ! empty( $attributes['className'] ) && preg_match( '/is-style-([\w-]+)/', $attributes['className'], $matches ) ) {
124 - $waveform_style = $matches[1];
125 - }
126 157
158 + $waveform_style = $attributes['waveformStyle'] ?? 'bars';
159 +
127 160 $processor->set_attribute(
128 161 'data-wp-context',
129 - json_encode(
162 + wp_json_encode(
130 163 array(
131 - 'playlistId' => $playlist_id,
132 - 'currentId' => $current_unique_id,
133 - 'tracks' => $playlist_tracks,
134 - 'waveformStyle' => $waveform_style,
164 + 'playlistId' => $playlist_id,
165 + 'currentId' => $playlist_tracks[0],
166 + 'isPlaying' => false,
167 + 'tracks' => $playlist_tracks,
168 + 'waveformStyle' => $waveform_style,
169 + 'showPlayButtonArtwork' => $show_play_button_artwork,
170 + 'labelPauseTrack' => __( 'Pause' ),
171 + 'labelSelectTrack' => __( 'Play' ),
135 172 )
136 173 )
137 174 );
138 175
176 + // Track IDs are render-time only. Add them after inner blocks have rendered
177 + // so track buttons can update the Interactivity API state without storing
178 + // persistent unique IDs in post content.
179 + $track_index = 0;
180 + while ( $processor->next_tag( array( 'class_name' => 'wp-block-playlist-track__button' ) ) ) {
181 + $track_id = $playlist_tracks[ $track_index ] ?? null;
182 +
183 + if ( null === $track_id ) {
184 + break;
185 + }
186 +
187 + $processor->set_attribute(
188 + 'data-wp-context',
189 + wp_json_encode(
190 + array(
191 + 'trackId' => $track_id,
192 + )
193 + )
194 + );
195 +
196 + ++$track_index;
197 + }
198 +
139 199 return $processor->get_updated_html();
140 200 }
141 201
142 202 /**
@@ -141,9 +201,9 @@
141 201
142 202 /**
143 203 * Registers the `core/playlist` block on server.
144 204 *
145 - * @since 6.9.0
205 + * @since 7.1.0
146 206 */
147 207 function gutenberg_register_block_core_playlist() {
148 208 register_block_type_from_metadata(
149 209 __DIR__ . '/playlist',