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 +105 -38 23.2.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,19 +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' );
157 +
158 + $waveform_style = $attributes['waveformStyle'] ?? 'bars';
159 +
121 160 $processor->set_attribute(
122 161 'data-wp-context',
123 - json_encode(
162 + wp_json_encode(
124 163 array(
125 - 'playlistId' => $playlist_id,
126 - 'currentId' => $current_unique_id,
127 - 'tracks' => $playlist_tracks,
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' ),
128 172 )
129 173 )
130 174 );
131 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 +
132 199 return $processor->get_updated_html();
133 200 }
134 201
135 202 /**
@@ -134,9 +201,9 @@
134 201
135 202 /**
136 203 * Registers the `core/playlist` block on server.
137 204 *
138 - * @since 6.9.0
205 + * @since 7.1.0
139 206 */
140 207 function gutenberg_register_block_core_playlist() {
141 208 register_block_type_from_metadata(
142 209 __DIR__ . '/playlist',