PluginProbe
Gutenberg / 24.1.0
Gutenberg v24.1.0
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.0 → 24.1.0 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',