[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/blocks/ -> playlist.php (source)

   1  <?php
   2  /**
   3   * Server-side rendering of the `core/playlist` block.
   4   *
   5   * @package WordPress
   6   */
   7  
   8  /**
   9   * Renders the `core/playlist` block on server.
  10   *
  11   * @since 7.1.0
  12   *
  13   * @param array    $attributes The block attributes.
  14   * @param string   $content    The block content.
  15   * @param WP_Block $block      The block instance.
  16   *
  17   * @return string Returns the Playlist.
  18   */
  19  function render_block_core_playlist( $attributes, $content, $block ) {
  20      $playlist_id              = wp_unique_id( 'playlist-' );
  21      $playlist_tracks          = array();
  22      $tracks_data              = array();
  23      $show_play_button_artwork = ! empty( $attributes['showPlayButtonArtwork'] );
  24  
  25      // Parse inner blocks to extract track data.
  26      // This approach avoids duplicating track data in the HTML output.
  27      if ( ! empty( $block->inner_blocks ) ) {
  28          foreach ( $block->inner_blocks as $inner_block ) {
  29              if ( 'core/playlist-track' === $inner_block->name ) {
  30                  $track_attributes = $inner_block->attributes;
  31  
  32                  if ( empty( $track_attributes['id'] ) ) {
  33                      continue;
  34                  }
  35  
  36                  $track_id          = 'track-' . count( $playlist_tracks );
  37                  $playlist_tracks[] = $track_id;
  38  
  39                  // Extract track metadata from block attributes.
  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;
  52  
  53                  if ( $title && $artist && $album ) {
  54                      $aria_label = sprintf(
  55                          /* translators: %1$s: track title, %2$s: artist name, %3$s: album name. */
  56                          _x( '%1$s by %2$s from the album %3$s', 'track title, artist name, album name' ),
  57                          $title,
  58                          $artist,
  59                          $album
  60                      );
  61                  }
  62  
  63                  // Data is passed to wp_interactivity_state() which JSON-encodes it,
  64                  // so we use wp_strip_all_tags() instead of esc_html() to prevent
  65                  // HTML injection without double-encoding. URLs still use esc_url().
  66                  $tracks_data[ $track_id ] = array(
  67                      'url'       => esc_url( $url ),
  68                      'title'     => wp_strip_all_tags( $title ),
  69                      'artist'    => wp_strip_all_tags( $artist ),
  70                      'album'     => wp_strip_all_tags( $album ),
  71                      'image'     => esc_url( $image ),
  72                      'imageAlt'  => wp_strip_all_tags( $image_alt ),
  73                      'ariaLabel' => wp_strip_all_tags( $aria_label ),
  74                  );
  75              }
  76          }
  77      }
  78  
  79      if ( empty( $playlist_tracks ) ) {
  80          return '';
  81      }
  82  
  83      wp_enqueue_script_module( '@wordpress/block-library/playlist/view' );
  84  
  85      // Add the playlist tracks to the global state,
  86      // but keep them isolated from other playlists with the help of playlistId.
  87      wp_interactivity_state(
  88          'core/playlist',
  89          array(
  90              'playlists' => array(
  91                  $playlist_id => array(
  92                      'tracks' => $tracks_data,
  93                  ),
  94              ),
  95          )
  96      );
  97  
  98      // Add waveform player container with translated button labels.
  99      $label_play  = esc_attr__( 'Play' );
 100      $label_pause = esc_attr__( 'Pause' );
 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 . '
 140          data-wp-watch="callbacks.initWaveformPlayer"
 141          data-label-play="' . $label_play . '"
 142          data-label-pause="' . $label_pause . '"
 143          data-label-seek="' . $label_seek . '"
 144          data-label-seek-value="' . $label_seek_value . '"
 145      ></div>';
 146  
 147      // Add the waveform player container inside the figure.
 148      $figure = null;
 149      preg_match( '/<figure[^>]*>/', $content, $figure );
 150      if ( ! empty( $figure[0] ) ) {
 151          $content = preg_replace( '/(<figure[^>]*>)/', '$1' . $html, $content, 1 );
 152      }
 153  
 154      $processor = new WP_HTML_Tag_Processor( $content );
 155      $processor->next_tag( 'figure' );
 156      $processor->set_attribute( 'data-wp-interactive', 'core/playlist' );
 157  
 158      $waveform_style = $attributes['waveformStyle'] ?? 'bars';
 159  
 160      $processor->set_attribute(
 161          'data-wp-context',
 162          wp_json_encode(
 163              array(
 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' ),
 172              )
 173          )
 174      );
 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  
 199      return $processor->get_updated_html();
 200  }
 201  
 202  /**
 203   * Registers the `core/playlist` block on server.
 204   *
 205   * @since 7.1.0
 206   */
 207  function register_block_core_playlist() {
 208      register_block_type_from_metadata(
 209          __DIR__ . '/playlist',
 210          array(
 211              'render_callback' => 'render_block_core_playlist',
 212          )
 213      );
 214  }
 215  add_action( 'init', 'register_block_core_playlist' );


Generated : Tue Sep 15 08:20:32 2026 Cross-referenced by PHPXref