← All changes
|
jetpack_vendor/automattic/jetpack-videopress/src/class-initializer.php
+198
-27
16.3-a.1
→
16.3
View file →
| @@ -11,8 +11,16 @@ | ||
| 11 | 11 | * Initialized the VideoPress package |
| 12 | 12 | */ |
| 13 | 13 | class Initializer { |
| 14 | 14 | |
| 15 | + /** | |
| 16 | + * Bounds of the Latest Videos Playlist block's "Number of videos" setting; | |
| 17 | + * the editor control uses the same range. | |
| 18 | + */ | |
| 19 | + const LATEST_VIDEOS_PLAYLIST_MIN_COUNT = 1; | |
| 20 | + const LATEST_VIDEOS_PLAYLIST_MAX_COUNT = 20; | |
| 21 | + const LATEST_VIDEOS_PLAYLIST_DEFAULT_COUNT = 5; | |
| 22 | + | |
| 15 | 23 | const JETPACK_VIDEOPRESS_IFRAME_API_HANDLER = 'jetpack-videopress-iframe-api'; |
| 16 | 24 | |
| 17 | 25 | /** |
| 18 | 26 | * Initialization optinos |
| @@ -127,8 +135,9 @@ | ||
| 127 | 135 | new WPCOM_REST_API_V2_Endpoint_VideoPress(); |
| 128 | 136 | new WPCOM_REST_API_V2_Endpoint_VideoPress_Caption_Tracks(); |
| 129 | 137 | new WPCOM_REST_API_V2_Attachment_VideoPress_Field(); |
| 130 | 138 | new WPCOM_REST_API_V2_Attachment_VideoPress_Data(); |
| 139 | + new WPCOM_REST_API_V2_Endpoint_VideoPress_Edits(); | |
| 131 | 140 | }; |
| 132 | 141 | add_action( 'rest_api_init', $register_rest_api_v2_endpoints, 0 ); |
| 133 | 142 | add_action( 'restapi_theme_init', $register_rest_api_v2_endpoints, 0 ); |
| 134 | 143 | |
| @@ -194,8 +203,11 @@ | ||
| 194 | 203 | Caption_Tracks::init(); |
| 195 | 204 | Initial_State::init(); |
| 196 | 205 | XMLRPC::init(); |
| 197 | 206 | Block_Editor_Content::init(); |
| 207 | + Channel::init(); | |
| 208 | + Playlist_Index::init(); | |
| 209 | + Analytics_Dashboard::init(); | |
| 198 | 210 | |
| 199 | 211 | /* |
| 200 | 212 | * These endpoints only add their routes on REST init, so defer calling |
| 201 | 213 | * init() (and autoloading the endpoint classes) until a REST request is |
| @@ -276,11 +288,30 @@ | ||
| 276 | 288 | self::register_videopress_video_block(); |
| 277 | 289 | |
| 278 | 290 | // Register Video Playlist block. |
| 279 | 291 | self::register_videopress_playlist_block(); |
| 292 | + | |
| 293 | + // Register Latest Videos Playlist block. | |
| 294 | + self::register_videopress_latest_videos_playlist_block(); | |
| 295 | + | |
| 296 | + // Register All Playlists block. | |
| 297 | + self::register_videopress_all_playlists_block(); | |
| 280 | 298 | } |
| 281 | 299 | |
| 282 | 300 | /** |
| 301 | + * Register the All Playlists block, which lists the site's Video Playlist | |
| 302 | + * blocks from the playlist index. | |
| 303 | + * | |
| 304 | + * @param string|null $metadata_file Path to the block.json metadata file. Defaults to the | |
| 305 | + * package build output; tests can point it at a fixture. | |
| 306 | + * | |
| 307 | + * @return void | |
| 308 | + */ | |
| 309 | + public static function register_videopress_all_playlists_block( $metadata_file = null ) { | |
| 310 | + All_Playlists_Block::register( $metadata_file ); | |
| 311 | + } | |
| 312 | + | |
| 313 | + /** | |
| 283 | 314 | * VideoPress video block render method |
| 284 | 315 | * |
| 285 | 316 | * @global \WP_Embed $wp_embed WordPress embed handler. |
| 286 | 317 | * |
| @@ -428,9 +459,13 @@ | ||
| 428 | 459 | $video_wrapper_classes, |
| 429 | 460 | Inline_Player::render( |
| 430 | 461 | $guid, |
| 431 | 462 | Inline_Player::get_player_options( $block_attributes ), |
| 432 | - $block_attributes['videoRatio'] ?? null | |
| 463 | + $block_attributes['videoRatio'] ?? null, | |
| 464 | + array( | |
| 465 | + 'poster' => Inline_Player::get_poster_url( $guid, $block_attributes ), | |
| 466 | + 'title' => $block_attributes['title'] ?? '', | |
| 467 | + ) | |
| 433 | 468 | ) |
| 434 | 469 | ); |
| 435 | 470 | } elseif ( $videopress_url ) { |
| 436 | 471 | $videopress_url = wp_kses_post( $videopress_url ); |
| @@ -630,8 +665,77 @@ | ||
| 630 | 665 | ); |
| 631 | 666 | } |
| 632 | 667 | |
| 633 | 668 | /** |
| 669 | + * Register the Latest Videos Playlist block. | |
| 670 | + * | |
| 671 | + * It reuses the Video Playlist block's registered view script and styles, so | |
| 672 | + * it is only registered once that block is. Its inner Video Playlist block is | |
| 673 | + * the editor canvas only: the front end renders the newest videos fresh. | |
| 674 | + * | |
| 675 | + * @param string|null $metadata_file Path to the block.json metadata file. Defaults to the | |
| 676 | + * package build output; tests can point it at a fixture. | |
| 677 | + * | |
| 678 | + * @return void | |
| 679 | + */ | |
| 680 | + public static function register_videopress_latest_videos_playlist_block( $metadata_file = null ) { | |
| 681 | + if ( ! \WP_Block_Type_Registry::get_instance()->is_registered( 'videopress/playlist' ) ) { | |
| 682 | + return; | |
| 683 | + } | |
| 684 | + | |
| 685 | + if ( null === $metadata_file ) { | |
| 686 | + $metadata_file = __DIR__ . '/../build/block-editor/blocks/latest-videos-playlist/block.json'; | |
| 687 | + } | |
| 688 | + | |
| 689 | + if ( ! file_exists( $metadata_file ) ) { | |
| 690 | + return; | |
| 691 | + } | |
| 692 | + | |
| 693 | + $metadata = json_decode( | |
| 694 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents | |
| 695 | + file_get_contents( $metadata_file ) | |
| 696 | + ); | |
| 697 | + | |
| 698 | + if ( empty( $metadata->name ) | |
| 699 | + || \WP_Block_Type_Registry::get_instance()->is_registered( $metadata->name ) | |
| 700 | + ) { | |
| 701 | + return; | |
| 702 | + } | |
| 703 | + | |
| 704 | + register_block_type( | |
| 705 | + $metadata_file, | |
| 706 | + array( | |
| 707 | + 'render_callback' => array( __CLASS__, 'render_videopress_latest_videos_playlist_block' ), | |
| 708 | + 'skip_inner_blocks' => true, | |
| 709 | + ) | |
| 710 | + ); | |
| 711 | + } | |
| 712 | + | |
| 713 | + /** | |
| 714 | + * Latest Videos Playlist block render callback: the newest VideoPress videos | |
| 715 | + * on the site, rendered by the Video Playlist block's callback. | |
| 716 | + * | |
| 717 | + * @param array $block_attributes Block attributes. | |
| 718 | + * @param string $content Current block markup, unused: the inner block is never rendered. | |
| 719 | + * @param \WP_Block|null $block Current block. | |
| 720 | + * | |
| 721 | + * @return string Block markup, or an empty string when the site has no VideoPress videos. | |
| 722 | + */ | |
| 723 | + public static function render_videopress_latest_videos_playlist_block( $block_attributes, $content = '', $block = null ) { | |
| 724 | + $count = isset( $block_attributes['count'] ) && is_numeric( $block_attributes['count'] ) | |
| 725 | + ? (int) $block_attributes['count'] | |
| 726 | + : self::LATEST_VIDEOS_PLAYLIST_DEFAULT_COUNT; | |
| 727 | + $count = max( self::LATEST_VIDEOS_PLAYLIST_MIN_COUNT, min( self::LATEST_VIDEOS_PLAYLIST_MAX_COUNT, $count ) ); | |
| 728 | + | |
| 729 | + $block_attributes['videos'] = Data::get_latest_videopress_playlist_entries( $count ); | |
| 730 | + | |
| 731 | + // Dynamic playlists have no title of their own, so no heading either. | |
| 732 | + unset( $block_attributes['playlistTitle'], $block_attributes['showPlaylistTitle'] ); | |
| 733 | + | |
| 734 | + return self::render_videopress_playlist_block( $block_attributes, '', $block ); | |
| 735 | + } | |
| 736 | + | |
| 737 | + /** | |
| 634 | 738 | * Sanitize the playlist block's videos attribute into rendering-ready entries. |
| 635 | 739 | * |
| 636 | 740 | * @param mixed $videos Raw attribute value. |
| 637 | 741 | * |
| @@ -636,9 +740,9 @@ | ||
| 636 | 740 | * @param mixed $videos Raw attribute value. |
| 637 | 741 | * |
| 638 | 742 | * @return array Entries with guid, title, durationMs, height and poster keys. |
| 639 | 743 | */ |
| 640 | - private static function sanitize_playlist_entries( $videos ) { | |
| 744 | + public static function sanitize_playlist_entries( $videos ) { | |
| 641 | 745 | if ( ! is_array( $videos ) ) { |
| 642 | 746 | return array(); |
| 643 | 747 | } |
| 644 | 748 | |
| @@ -765,9 +869,9 @@ | ||
| 765 | 869 | /** |
| 766 | 870 | * Video Playlist block render callback. |
| 767 | 871 | * |
| 768 | 872 | * @param array $block_attributes Block attributes. |
| 769 | - * @param string $content Current block markup. | |
| 873 | + * @param string $content Rendered inner blocks: the title heading, when there is one. | |
| 770 | 874 | * @param \WP_Block|null $block Current block. |
| 771 | 875 | * |
| 772 | 876 | * @return string Block markup, or an empty string when the playlist has no playable entries. |
| 773 | 877 | */ |
| @@ -793,8 +897,14 @@ | ||
| 793 | 897 | $layout = isset( $block_attributes['layout'] ) && in_array( $block_attributes['layout'], array( 'side-rail', 'grid', 'strip' ), true ) |
| 794 | 898 | ? $block_attributes['layout'] |
| 795 | 899 | : 'side-rail'; |
| 796 | 900 | |
| 901 | + $show_player = $enabled( 'showPlayer' ); | |
| 902 | + // A hidden player can still be revealed by the first click on an entry. | |
| 903 | + $reveal_player = ! $show_player | |
| 904 | + && isset( $block_attributes['entryClickAction'] ) | |
| 905 | + && 'show-player' === $block_attributes['entryClickAction']; | |
| 906 | + $has_player = $show_player || $reveal_player; | |
| 797 | 907 | $show_thumbnail = $enabled( 'showThumbnail' ); |
| 798 | 908 | $show_title = $enabled( 'showTitle' ); |
| 799 | 909 | $show_res = $enabled( 'showResolution' ); |
| 800 | 910 | $show_duration = $enabled( 'showDuration' ); |
| @@ -805,8 +915,11 @@ | ||
| 805 | 915 | $classes = array( 'videopress-playlist', 'is-layout-' . $layout ); |
| 806 | 916 | if ( $enabled( 'darkPlayer', false ) ) { |
| 807 | 917 | $classes[] = 'is-dark'; |
| 808 | 918 | } |
| 919 | + if ( ! $show_player ) { | |
| 920 | + $classes[] = 'hide-player'; | |
| 921 | + } | |
| 809 | 922 | if ( ! $show_thumbnail ) { |
| 810 | 923 | $classes[] = 'hide-thumbnails'; |
| 811 | 924 | } |
| 812 | 925 | if ( ! $show_title ) { |
| @@ -882,28 +995,57 @@ | ||
| 882 | 995 | $duration_markup = '' !== $timecode |
| 883 | 996 | ? sprintf( '<span class="videopress-playlist__entry-duration">%s</span>', esc_html( $timecode ) ) |
| 884 | 997 | : ''; |
| 885 | 998 | |
| 999 | + if ( $has_player ) { | |
| 1000 | + $is_current = $show_player && 0 === $index; | |
| 1001 | + $entry_open = sprintf( | |
| 1002 | + '<button type="button" class="videopress-playlist__select%1$s"%2$s data-guid="%3$s" data-embed-url="%4$s" data-title="%5$s" data-position="%6$s" data-details="%7$s" data-progress="%8$s">', | |
| 1003 | + $is_current ? ' is-current' : '', | |
| 1004 | + $is_current ? ' aria-current="true"' : '', | |
| 1005 | + esc_attr( $entry['guid'] ), | |
| 1006 | + esc_url( self::playlist_embed_url( $entry['guid'], true, $muted ) ), | |
| 1007 | + esc_attr( $title ), | |
| 1008 | + esc_attr( $position ), | |
| 1009 | + esc_attr( $details ), | |
| 1010 | + esc_attr( $progress ) | |
| 1011 | + ); | |
| 1012 | + $entry_close = '</button>'; | |
| 1013 | + } else { | |
| 1014 | + // No player to load the video into: the entry opens its VideoPress page instead. | |
| 1015 | + $entry_open = sprintf( | |
| 1016 | + '<a class="videopress-playlist__select" href="%1$s" target="_blank" rel="noopener noreferrer" data-guid="%2$s" data-title="%3$s" data-position="%4$s" data-details="%5$s">', | |
| 1017 | + /** | |
| 1018 | + * Filters where a playlist entry opens when the block has no player. | |
| 1019 | + * | |
| 1020 | + * @since 0.55.0 | |
| 1021 | + * | |
| 1022 | + * @param string $url The video's page on videopress.com. | |
| 1023 | + * @param string $guid The video GUID. | |
| 1024 | + */ | |
| 1025 | + esc_url( apply_filters( 'videopress_playlist_entry_url', 'https://videopress.com/v/' . $entry['guid'], $entry['guid'] ) ), | |
| 1026 | + esc_attr( $entry['guid'] ), | |
| 1027 | + esc_attr( $title ), | |
| 1028 | + esc_attr( $position ), | |
| 1029 | + esc_attr( $details ) | |
| 1030 | + ); | |
| 1031 | + $entry_close = '</a>'; | |
| 1032 | + } | |
| 1033 | + | |
| 886 | 1034 | $items .= sprintf( |
| 887 | - '<li class="videopress-playlist__entry"><button type="button" class="videopress-playlist__select%1$s"%2$s data-guid="%3$s" data-embed-url="%4$s" data-title="%5$s" data-position="%6$s" data-details="%7$s" data-progress="%8$s">' . | |
| 888 | - '%9$s<span class="videopress-playlist__entry-thumb"><span class="videopress-playlist__entry-flag">%10$s</span>%15$s%11$s</span>' . | |
| 889 | - '<span class="videopress-playlist__entry-body"><span class="videopress-playlist__entry-title">%12$s</span><span class="videopress-playlist__entry-meta">%13$s%14$s</span></span>' . | |
| 890 | - '</button></li>', | |
| 891 | - 0 === $index ? ' is-current' : '', | |
| 892 | - 0 === $index ? ' aria-current="true"' : '', | |
| 893 | - esc_attr( $entry['guid'] ), | |
| 894 | - esc_url( self::playlist_embed_url( $entry['guid'], true, $muted ) ), | |
| 895 | - esc_attr( $title ), | |
| 896 | - esc_attr( $position ), | |
| 897 | - esc_attr( $details ), | |
| 898 | - esc_attr( $progress ), | |
| 1035 | + '<li class="videopress-playlist__entry">%1$s' . | |
| 1036 | + '%2$s<span class="videopress-playlist__entry-thumb"><span class="videopress-playlist__entry-flag">%3$s</span>%4$s%5$s</span>' . | |
| 1037 | + '<span class="videopress-playlist__entry-body"><span class="videopress-playlist__entry-title">%6$s</span><span class="videopress-playlist__entry-meta">%7$s%8$s</span></span>' . | |
| 1038 | + '%9$s</li>', | |
| 1039 | + $entry_open, | |
| 899 | 1040 | $number_markup, |
| 900 | 1041 | esc_html__( 'Playing', 'jetpack-videopress-pkg' ), |
| 1042 | + $lock_markup, | |
| 901 | 1043 | $time_markup, |
| 902 | 1044 | esc_html( $title ), |
| 903 | 1045 | $resolution_markup, |
| 904 | 1046 | $duration_markup, |
| 905 | - $lock_markup | |
| 1047 | + $entry_close | |
| 906 | 1048 | ); |
| 907 | 1049 | } |
| 908 | 1050 | |
| 909 | 1051 | $first = $entries[0]; |
| @@ -930,17 +1072,30 @@ | ||
| 930 | 1072 | esc_html( $count_label . ' · ' . $runtime_label ) |
| 931 | 1073 | ) |
| 932 | 1074 | : ''; |
| 933 | 1075 | |
| 934 | - $stage_markup = sprintf( | |
| 935 | - '<div class="videopress-playlist__stage">' . | |
| 936 | - '<div class="videopress-playlist__player"><iframe class="videopress-playlist__iframe" title="%1$s" src="%2$s" allowfullscreen allow="clipboard-write"></iframe></div>%3$s</div>', | |
| 937 | - esc_attr( $first_title ), | |
| 938 | - esc_url( self::playlist_embed_url( $first['guid'], false, $muted ) ), | |
| 939 | - $now_markup | |
| 940 | - ); | |
| 1076 | + if ( $show_player ) { | |
| 1077 | + $stage_markup = sprintf( | |
| 1078 | + '<div class="videopress-playlist__stage">' . | |
| 1079 | + '<div class="videopress-playlist__player"><iframe class="videopress-playlist__iframe" title="%1$s" src="%2$s" allowfullscreen allow="clipboard-write"></iframe></div>%3$s</div>', | |
| 1080 | + esc_attr( $first_title ), | |
| 1081 | + esc_url( self::playlist_embed_url( $first['guid'], false, $muted ) ), | |
| 1082 | + $now_markup | |
| 1083 | + ); | |
| 1084 | + } elseif ( $reveal_player ) { | |
| 1085 | + // No src: nothing loads until the view script reveals the stage on a click. | |
| 1086 | + $stage_markup = sprintf( | |
| 1087 | + '<div class="videopress-playlist__stage" hidden>' . | |
| 1088 | + '<div class="videopress-playlist__player"><iframe class="videopress-playlist__iframe" title="%1$s" allowfullscreen allow="clipboard-write"></iframe></div></div>%2$s', | |
| 1089 | + esc_attr( $first_title ), | |
| 1090 | + $now_markup | |
| 1091 | + ); | |
| 1092 | + } else { | |
| 1093 | + // Without a player only the grid layout's runtime line remains of the stage. | |
| 1094 | + $stage_markup = $now_markup; | |
| 1095 | + } | |
| 941 | 1096 | |
| 942 | - $progress_markup = '' !== $total_timecode | |
| 1097 | + $progress_markup = $has_player && '' !== $total_timecode | |
| 943 | 1098 | ? sprintf( |
| 944 | 1099 | '<span class="videopress-playlist__list-progress">%s</span>', |
| 945 | 1100 | /* translators: 1: position of the current video. 2: number of videos. 3: total playlist timecode. */ |
| 946 | 1101 | esc_html( sprintf( __( '%1$d / %2$d · %3$s total', 'jetpack-videopress-pkg' ), 1, $count, $total_timecode ) ) |
| @@ -952,9 +1107,11 @@ | ||
| 952 | 1107 | '<div class="videopress-playlist__list-header">' . |
| 953 | 1108 | '<span class="videopress-playlist__list-label videopress-playlist__list-label--rail">%1$s</span>' . |
| 954 | 1109 | '<span class="videopress-playlist__list-label videopress-playlist__list-label--strip">%2$s</span>%3$s%4$s</div>' . |
| 955 | 1110 | '<ol class="videopress-playlist__entries">%5$s</ol></div>', |
| 956 | - esc_html__( 'Up next', 'jetpack-videopress-pkg' ), | |
| 1111 | + $show_player | |
| 1112 | + ? esc_html__( 'Up next', 'jetpack-videopress-pkg' ) | |
| 1113 | + : esc_html__( 'Playlist', 'jetpack-videopress-pkg' ), | |
| 957 | 1114 | /* translators: %s: number of videos in the playlist, e.g. "5 videos". */ |
| 958 | 1115 | esc_html( sprintf( __( 'Playlist — %s', 'jetpack-videopress-pkg' ), $count_label ) ), |
| 959 | 1116 | $list_meta_markup, |
| 960 | 1117 | $progress_markup, |
| @@ -991,11 +1148,21 @@ | ||
| 991 | 1148 | } |
| 992 | 1149 | |
| 993 | 1150 | $wrapper_attributes = get_block_wrapper_attributes( $wrapper_extra_attributes ); |
| 994 | 1151 | |
| 1152 | + // The Heading inner block saved with the post; an empty title renders none. | |
| 1153 | + $playlist_title = isset( $block_attributes['playlistTitle'] ) && is_string( $block_attributes['playlistTitle'] ) | |
| 1154 | + ? trim( $block_attributes['playlistTitle'] ) | |
| 1155 | + : ''; | |
| 1156 | + $content = is_string( $content ) ? trim( $content ) : ''; | |
| 1157 | + $heading_markup = $enabled( 'showPlaylistTitle' ) && '' !== $playlist_title && '' !== $content | |
| 1158 | + ? '<div class="videopress-playlist__heading">' . $content . '</div>' | |
| 1159 | + : ''; | |
| 1160 | + | |
| 995 | 1161 | return sprintf( |
| 996 | - '<figure %1$s><div class="videopress-playlist__body">%2$s%3$s</div></figure>', | |
| 1162 | + '<figure %1$s>%2$s<div class="videopress-playlist__body">%3$s%4$s</div></figure>', | |
| 997 | 1163 | $wrapper_attributes, |
| 1164 | + $heading_markup, | |
| 998 | 1165 | $stage_markup, |
| 999 | 1166 | $list_markup |
| 1000 | 1167 | ); |
| 1001 | 1168 | } |
| @@ -1073,10 +1240,14 @@ | ||
| 1073 | 1240 | if ( null === $guid ) { |
| 1074 | 1241 | return null; |
| 1075 | 1242 | } |
| 1076 | 1243 | |
| 1244 | + $attributes = Inline_Player::get_attributes_from_embed_url( $url ); | |
| 1245 | + | |
| 1077 | 1246 | return Inline_Player::render( |
| 1078 | 1247 | $guid, |
| 1079 | - Inline_Player::get_player_options( Inline_Player::get_attributes_from_embed_url( $url ) ) | |
| 1248 | + Inline_Player::get_player_options( $attributes ), | |
| 1249 | + null, | |
| 1250 | + array( 'poster' => Inline_Player::get_poster_url( $guid, $attributes ) ) | |
| 1080 | 1251 | ); |
| 1081 | 1252 | } |
| 1082 | 1253 | } |