Make WordPress Core

Ticket #38172: 38172.16.diff

File 38172.16.diff, 30.5 KB (added by joemcgill, 7 years ago)
  • src/wp-content/themes/twentyfourteen/functions.php

    diff --git src/wp-content/themes/twentyfourteen/functions.php src/wp-content/themes/twentyfourteen/functions.php
    index 74141dc..2db330b 100644
    function twentyfourteen_body_classes( $classes ) { 
    434434                $classes[] = 'group-blog';
    435435        }
    436436
    437         if ( get_header_image() ) {
     437        if ( get_header_image() || function_exists( 'has_header_video' ) && has_header_video() ) {
    438438                $classes[] = 'header-image';
    439439        } elseif ( ! in_array( $GLOBALS['pagenow'], array( 'wp-activate.php', 'wp-signup.php' ) ) ) {
    440440                $classes[] = 'masthead-fixed';
  • src/wp-content/themes/twentyfourteen/header.php

    diff --git src/wp-content/themes/twentyfourteen/header.php src/wp-content/themes/twentyfourteen/header.php
    index 7286d88..0a4953c 100644
     
    3232
    3333<body <?php body_class(); ?>>
    3434<div id="page" class="hfeed site">
    35         <?php if ( get_header_image() ) : ?>
     35        <?php if ( function_exists( 'has_header_video' ) && has_header_video() ) : ?>
     36                <div id="site-header">
     37                        <?php the_custom_header_markup(); ?>
     38                </div>
     39        <?php elseif ( get_header_image() ) : ?>
    3640        <div id="site-header">
    3741                <a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
    3842                        <img src="<?php header_image(); ?>" width="<?php echo get_custom_header()->width; ?>" height="<?php echo get_custom_header()->height; ?>" alt="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>">
  • src/wp-content/themes/twentyfourteen/inc/custom-header.php

    diff --git src/wp-content/themes/twentyfourteen/inc/custom-header.php src/wp-content/themes/twentyfourteen/inc/custom-header.php
    index 287b106..bb77307 100644
    function twentyfourteen_custom_header_setup() { 
    4040                'width'                  => 1260,
    4141                'height'                 => 240,
    4242                'flex-height'            => true,
     43                'video'                  => true,
    4344                'wp-head-callback'       => 'twentyfourteen_header_style',
    4445                'admin-head-callback'    => 'twentyfourteen_admin_header_style',
    4546                'admin-preview-callback' => 'twentyfourteen_admin_header_image',
  • src/wp-content/themes/twentyfourteen/js/functions.js

    diff --git src/wp-content/themes/twentyfourteen/js/functions.js src/wp-content/themes/twentyfourteen/js/functions.js
    index a21849e..6642152 100644
     
    9595                 */
    9696                if ( _window.width() > 781 ) {
    9797                        var mastheadHeight = $( '#masthead' ).height(),
    98                                 toolbarOffset, mastheadOffset;
     98                                mastheadOffset;
    9999
    100100                        if ( mastheadHeight > 48 ) {
    101101                                body.removeClass( 'masthead-fixed' );
    102102                        }
    103103
    104104                        if ( body.is( '.header-image' ) ) {
    105                                 toolbarOffset  = body.is( '.admin-bar' ) ? $( '#wpadminbar' ).height() : 0;
    106                                 mastheadOffset = $( '#masthead' ).offset().top - toolbarOffset;
    107 
    108105                                _window.on( 'scroll.twentyfourteen', function() {
     106                                        // Recaculate the header height in case state has changed after initial load.
     107                                        mastheadOffset = $( '#site-header' ).height();
     108
    109109                                        if ( _window.scrollTop() > mastheadOffset && mastheadHeight < 49 ) {
    110110                                                body.addClass( 'masthead-fixed' );
    111111                                        } else {
    112112                                                body.removeClass( 'masthead-fixed' );
    113113                                        }
    114114                                } );
     115
     116                                // Update masthead offset after a selective refresh.
     117                                if ( 'undefined' !== typeof wp && wp.customize && wp.customize.selectiveRefresh ) {
     118                                        wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function() {
     119                                                mastheadOffset = $( '#site-header' ).height();
     120                                        } );
     121                                }
    115122                        }
    116123                }
    117124
  • src/wp-content/themes/twentyfourteen/style.css

    diff --git src/wp-content/themes/twentyfourteen/style.css src/wp-content/themes/twentyfourteen/style.css
    index bf5ec11..72b320f 100644
    canvas, 
    8888video {
    8989        display: inline-block;
    9090        max-width: 100%;
     91        height: auto;
    9192}
    9293
    9394html {
    video { 
    608609        max-width: 100%;
    609610}
    610611
     612#wp-custom-header iframe,
     613#wp-custom-header video {
     614        margin-bottom: -8px;
     615}
     616
    611617p > embed,
    612618p > iframe,
    613619p > object,
  • src/wp-content/themes/twentyseventeen/assets/css/ie8.css

    diff --git src/wp-content/themes/twentyseventeen/assets/css/ie8.css src/wp-content/themes/twentyseventeen/assets/css/ie8.css
    index 89d2f70..c18f240 100644
    img { 
    6868        padding: 45px 0;
    6969}
    7070
     71.has-header-image .custom-header-image img,
     72.has-header-image .custom-header-image video {
     73        left: 0;
     74        top: 0;
     75}
     76
    7177.site-title {
    7278        font-size: 36px;
    7379        font-weight: bolder;
  • src/wp-content/themes/twentyseventeen/footer.php

    diff --git src/wp-content/themes/twentyseventeen/footer.php src/wp-content/themes/twentyseventeen/footer.php
    index 2d72029..dacc418 100644
     
    1414
    1515?>
    1616
    17         </div><!-- #content -->
     17                </div><!-- #content -->
    1818
    19         <footer id="colophon" class="site-footer" role="contentinfo">
    20                 <div class="wrap">
    21                         <?php
    22                         get_template_part( 'template-parts/footer/footer', 'widgets' );
     19                <footer id="colophon" class="site-footer" role="contentinfo">
     20                        <div class="wrap">
     21                                <?php
     22                                get_template_part( 'template-parts/footer/footer', 'widgets' );
    2323
    24                         if ( has_nav_menu( 'social' ) ) : ?>
    25                                 <nav class="social-navigation" role="navigation" aria-label="<?php _e( 'Footer Social Links Menu', 'twentyseventeen' ); ?>">
    26                                         <?php
    27                                                 wp_nav_menu( array(
    28                                                         'theme_location' => 'social',
    29                                                         'menu_class'     => 'social-links-menu',
    30                                                         'depth'          => 1,
    31                                                         'link_before'    => '<span class="screen-reader-text">',
    32                                                         'link_after'     => '</span>' . twentyseventeen_get_svg( array( 'icon' => 'chain' ) ),
    33                                                 ) );
    34                                         ?>
    35                                 </nav><!-- .social-navigation -->
    36                         <?php endif;
     24                                if ( has_nav_menu( 'social' ) ) : ?>
     25                                        <nav class="social-navigation" role="navigation" aria-label="<?php _e( 'Footer Social Links Menu', 'twentyseventeen' ); ?>">
     26                                                <?php
     27                                                        wp_nav_menu( array(
     28                                                                'theme_location' => 'social',
     29                                                                'menu_class'     => 'social-links-menu',
     30                                                                'depth'          => 1,
     31                                                                'link_before'    => '<span class="screen-reader-text">',
     32                                                                'link_after'     => '</span>' . twentyseventeen_get_svg( array( 'icon' => 'chain' ) ),
     33                                                        ) );
     34                                                ?>
     35                                        </nav><!-- .social-navigation -->
     36                                <?php endif;
    3737
    38                         get_template_part( 'template-parts/footer/site', 'info' );
    39                         ?>
    40                 </div><!-- .wrap -->
    41         </footer><!-- #colophon -->
     38                                get_template_part( 'template-parts/footer/site', 'info' );
     39                                ?>
     40                        </div><!-- .wrap -->
     41                </footer><!-- #colophon -->
     42        </div><!-- .site-content-contain -->
    4243</div><!-- #page -->
    4344<?php wp_footer(); ?>
    4445
  • src/wp-content/themes/twentyseventeen/header.php

    diff --git src/wp-content/themes/twentyseventeen/header.php src/wp-content/themes/twentyseventeen/header.php
    index dc173d6..30d7d2a 100644
     
    4949        endif;
    5050        ?>
    5151
    52         <div id="content" class="site-content">
     52        <div class="site-content-contain">
     53                <div id="content" class="site-content">
  • src/wp-content/themes/twentyseventeen/inc/custom-header.php

    diff --git src/wp-content/themes/twentyseventeen/inc/custom-header.php src/wp-content/themes/twentyseventeen/inc/custom-header.php
    index d14f5aa..a535f5f 100644
    function twentyseventeen_custom_header_setup() { 
    3939                'width'              => 2000,
    4040                'height'             => 1200,
    4141                'flex-height'        => true,
     42                'video'              => true,
    4243                'wp-head-callback'   => 'twentyseventeen_header_style',
    4344        ) ) );
    4445
  • src/wp-content/themes/twentyseventeen/inc/template-functions.php

    diff --git src/wp-content/themes/twentyseventeen/inc/template-functions.php src/wp-content/themes/twentyseventeen/inc/template-functions.php
    index 5ea106b..25b579b 100644
    function twentyseventeen_body_classes( $classes ) { 
    3535        }
    3636
    3737        // Add a class if there is a custom header.
    38         if ( has_header_image() ) {
     38        if ( has_header_image() || has_header_video() && is_front_page() ) {
    3939                $classes[] = 'has-header-image';
    4040        }
    4141
  • src/wp-content/themes/twentyseventeen/style.css

    diff --git src/wp-content/themes/twentyseventeen/style.css src/wp-content/themes/twentyseventeen/style.css
    index cd5ce02..f268711 100644
    a:hover .nav-title, 
    13141314        border-top: 1px solid #eee;
    13151315        font-size: 16px;
    13161316        font-size: 1rem;
     1317        position: relative;
    13171318}
    13181319
    13191320.navigation-top .wrap {
    body { 
    15551556
    15561557.site-branding {
    15571558        padding: 1em 0;
     1559        position: relative;
    15581560        -webkit-transition: margin-bottom 0.2s;
    15591561        transition: margin-bottom 0.2s;
     1562        z-index: 3;
    15601563}
    15611564
    15621565.site-branding a {
    body:not(.title-tagline-hidden) .site-branding-text { 
    16501653}
    16511654
    16521655.custom-header-image {
    1653         background-position: center center;
    1654         background-repeat: no-repeat;
    1655         -webkit-background-size: cover;
    1656         background-size: cover;
    16571656        bottom: 0;
    16581657        left: 0;
     1658        overflow: hidden;
    16591659        position: absolute;
    16601660        right: 0;
    16611661        top: 0;
     1662        width: 100%;
    16621663}
    16631664
    16641665.custom-header-image:before {
    body:not(.title-tagline-hidden) .site-branding-text { 
    16741675        left: 0;
    16751676        position: absolute;
    16761677        right: 0;
     1678        z-index: 2;
    16771679}
    16781680
    1679 .has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-image {
    1680         background-position: center bottom;
     1681.has-header-image .custom-header-image img,
     1682.has-header-image .custom-header-image video,
     1683.has-header-image .custom-header-image iframe {
     1684        position: fixed;
     1685        height: auto;
     1686        left: 50%;
     1687        max-width: 1000%;
     1688        min-height: 100%;
     1689        min-width: 100%;
     1690        min-width: 100vw; /* vw prevents 1px gap on left that 100% has */
     1691        width: auto;
     1692        top: 50%;
     1693        -ms-transform: translateX(-50%) translateY(-50%);
     1694        -moz-transform: translateX(-50%) translateY(-50%);
     1695        -webkit-transform: translateX(-50%) translateY(-50%);
     1696        transform: translateX(-50%) translateY(-50%);
     1697}
     1698
     1699.has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-image img {
     1700        bottom: 0;
     1701        position: absolute;
     1702        top: auto;
     1703        -ms-transform: translateX(-50%) translateY(0);
     1704        -moz-transform: translateX(-50%) translateY(0);
     1705        -webkit-transform: translateX(-50%) translateY(0);
     1706        transform: translateX(-50%) translateY(0);
    16811707}
    16821708
    16831709body:not(.has-header-image) .custom-header-image {
    body:not(.has-header-image) .custom-header-image { 
    17771803## Regular Content
    17781804--------------------------------------------------------------*/
    17791805
     1806.site-content-contain {
     1807        background-color: #fff;
     1808        position: relative;
     1809}
     1810
    17801811.site-content {
    17811812        padding: 2.5em 0 0;
    17821813}
    h2.widget-title { 
    26422673# Media
    26432674--------------------------------------------------------------*/
    26442675
    2645 img {
     2676img,
     2677video {
    26462678        height: auto; /* Make sure images are scaled correctly. */
    26472679        max-width: 100%; /* Adhere to container width. */
    26482680}
    article.panel-placeholder { 
    32873319
    32883320        .has-header-image.twentyseventeen-front-page .custom-header,
    32893321        .has-header-image.home.blog .custom-header {
    3290                 display: block;
    32913322                min-height: 0;
    32923323        }
    32933324
    article.panel-placeholder { 
    32963327                position: relative;
    32973328        }
    32983329
     3330        .twentyseventeen-front-page.has-header-image .custom-header-image,
     3331        .home.blog.has-header-image .custom-header-image {
     3332                height: 0;
     3333                position: relative;
     3334        }
     3335
    32993336        .has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-image {
    33003337                bottom: 0;
    33013338                height: auto;
    article.panel-placeholder { 
    33053342                top: 0;
    33063343        }
    33073344
    3308         .twentyseventeen-front-page.has-header-image .custom-header-image,
    3309         .home.blog.has-header-image .custom-header-image {
    3310                 height: 0;
    3311                 padding-top: 66%;
    3312                 position: relative;
    3313         }
    3314 
    33153345        .custom-logo-link {
    33163346                padding-right: 2em;
    33173347        }
    article.panel-placeholder { 
    35913621                height: 1200px;
    35923622                height: 100vh;
    35933623                max-height: 100%;
    3594                 padding: 10% 0;
     3624                overflow: hidden;
     3625                /* padding: 10% 0; */
    35953626        }
    35963627
    35973628        .twentyseventeen-front-page.has-header-image .custom-header-image:before,
    article.panel-placeholder { 
    39383969
    39393970@media screen and ( min-width: 55em ) {
    39403971
    3941         .twentyseventeen-front-page.has-header-image .custom-header-image,
    3942         .home.blog.has-header-image .custom-header-image {
    3943                 background-attachment: fixed;
    3944         }
    3945 
    39463972        .panel-image {
    39473973                background-attachment: fixed;
    39483974        }
  • src/wp-content/themes/twentyseventeen/template-parts/header/header-image.php

    diff --git src/wp-content/themes/twentyseventeen/template-parts/header/header-image.php src/wp-content/themes/twentyseventeen/template-parts/header/header-image.php
    index 2c4b0f8..de03a60 100644
     
    1414        $header_image = get_header_image();
    1515
    1616        // Check if Custom Header image has been added.
    17         if ( ! empty( $header_image ) ) : ?>
     17        if ( has_custom_header() ) :
     18        ?>
    1819
    19                 <div class="custom-header-image" style="background-image: url(<?php echo esc_url( $header_image ); ?>)"></div>
     20                <?php // Output the full custom header - video and/or image fallback. ?>
     21                <div class="custom-header-image">
     22                        <?php the_custom_header_markup(); ?>
     23                </div>
    2024                <?php get_template_part( 'template-parts/header/site', 'branding' ); ?>
    2125
    2226        <?php else : ?>
     27
    2328                <?php // Otherwise, show a blank header. ?>
    2429                <div class="custom-header-simple">
    2530                        <?php get_template_part( 'template-parts/header/site', 'branding' ); ?>
  • src/wp-includes/class-wp-customize-manager.php

    diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
    index d32eca6..9ed0a72 100644
    final class WP_Customize_Manager { 
    363363                add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_section_templates' ), 1 );
    364364                add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_control_templates' ), 1 );
    365365
     366                // Export header video settings with the partial response.
     367                add_filter( 'customize_render_partials_response', array( $this, 'export_header_video_settings' ), 10, 3 );
     368
    366369                // Export the settings to JS via the _wpCustomizeSettings variable.
    367370                add_action( 'customize_controls_print_footer_scripts', array( $this, 'customize_pane_settings' ), 1000 );
    368371
    final class WP_Customize_Manager { 
    32493252
    32503253                /* Custom Header */
    32513254
     3255                if ( current_theme_supports( 'custom-header', 'video' ) ) {
     3256                        $title = __( 'Header Visuals' );
     3257                        $description = __( 'If you add a video, the image will be used as a fallback while the video loads.' );
     3258                        $width = absint( get_theme_support( 'custom-header', 'width' ) );
     3259                        $height = absint( get_theme_support( 'custom-header', 'height' ) );
     3260                        if ( $width && $height ) {
     3261                                /* translators: %s: header size in pixels */
     3262                                $control_description = sprintf( __( 'Upload your video in <code>.mp4</code> format and minimize its file size for best results. Your theme recommends dimensions of %s pixels.' ),
     3263                                        sprintf( '<strong>%s &times; %s</strong>', $width, $height )
     3264                                );
     3265                        } elseif ( $width ) {
     3266                                /* translators: %s: header width in pixels */
     3267                                $control_description = sprintf( __( 'Upload your video in <code>.mp4</code> format and minimize its file size for best results. Your theme recommends a width of %s pixels.' ),
     3268                                        sprintf( '<strong>%s</strong>', $width )
     3269                                );
     3270                        } else {
     3271                                /* translators: %s: header height in pixels */
     3272                                $control_description = sprintf( __( 'Upload your video in <code>.mp4</code> format and minimize its file size for best results. Your theme recommends a height of %s pixels.' ),
     3273                                        sprintf( '<strong>%s</strong>', $height )
     3274                                );
     3275                        }
     3276                } else {
     3277                        $title = __( 'Header Image' );
     3278                        $description = '';
     3279                        $control_description = '';
     3280                }
     3281
    32523282                $this->add_section( 'header_image', array(
    3253                         'title'          => __( 'Header Image' ),
     3283                        'title'          => $title,
     3284                        'description'    => $description,
    32543285                        'theme_supports' => 'custom-header',
    32553286                        'priority'       => 60,
    32563287                ) );
    32573288
     3289                $this->add_setting( 'header_video', array(
     3290                        'theme_supports'    => array( 'custom-header', 'video' ),
     3291                        'transport'         => 'postMessage',
     3292                        'sanitize_callback' => 'absint',
     3293                        'validate_callback' => array( $this, '_validate_header_video' ),
     3294                ) );
     3295
     3296                $this->add_setting( 'external_header_video', array(
     3297                        'theme_supports'    => array( 'custom-header', 'video' ),
     3298                        'transport'         => 'postMessage',
     3299                        'sanitize_callback' => 'esc_url',
     3300                        'validate_callback' => array( $this, '_validate_external_header_video' ),
     3301                ) );
     3302
    32583303                $this->add_setting( new WP_Customize_Filter_Setting( $this, 'header_image', array(
    32593304                        'default'        => get_theme_support( 'custom-header', 'default-image' ),
    32603305                        'theme_supports' => 'custom-header',
    final class WP_Customize_Manager { 
    32653310                        'theme_supports' => 'custom-header',
    32663311                ) ) );
    32673312
     3313                $this->add_control( new WP_Customize_Media_Control( $this, 'header_video', array(
     3314                        'theme_supports' => array( 'custom-header', 'video' ),
     3315                        'label'          => __( 'Header Video' ),
     3316                        'description'    => $control_description,
     3317                        'section'        => 'header_image',
     3318                        'mime_type'      => 'video',
     3319                ) ) );
     3320
     3321                $this->add_control( 'external_header_video', array(
     3322                        'theme_supports' => array( 'custom-header', 'video' ),
     3323                        'type'           => 'url',
     3324                        'description'    => __( 'Or, enter a YouTube or Vimeo URL:' ),
     3325                        'section'        => 'header_image',
     3326                ) );
     3327
    32683328                $this->add_control( new WP_Customize_Header_Image_Control( $this ) );
    32693329
     3330                $this->selective_refresh->add_partial( 'header_video', array(
     3331                        'selector'            => '#wp-custom-header',
     3332                        'render_callback'     => 'the_custom_header',
     3333                        'settings'            => array( 'header_video', 'external_header_video', 'header_image' ), // The image is used as a video fallback here.
     3334                        'container_inclusive' => true,
     3335                ) );
     3336
    32703337                /* Custom Background */
    32713338
    32723339                $this->add_section( 'background_image', array(
    final class WP_Customize_Manager { 
    37053772        }
    37063773
    37073774        /**
     3775         * Export header video settings to facilitate selective refresh.
     3776         *
     3777         * @since 4.7.0
     3778         *
     3779         * @param array $response Response.
     3780         * @param WP_Customize_Selective_Refresh $selective_refresh Selective refresh component.
     3781         * @param array $partials Array of partials.
     3782         * @return array
     3783         */
     3784        public function export_header_video_settings( $response, $selective_refresh, $partials ) {
     3785                if ( isset( $partials['header_video'] ) || isset( $partials['external_header_video'] ) ) {
     3786                        $response['custom_header_settings'] = get_header_video_settings();
     3787                }
     3788
     3789                return $response;
     3790        }
     3791
     3792        /**
     3793         * Callback for validating the header_video value.
     3794         *
     3795         * Ensures that the selected video is less than 8MB and provides an error message.
     3796         *
     3797         * @since 4.7.0
     3798         *
     3799         * @param WP_Error $validity
     3800         * @param mixed $value
     3801         * @return mixed
     3802         */
     3803        public function _validate_header_video( $validity, $value ) {
     3804                $video = get_attached_file( absint( $value ) );
     3805                if ( $video ) {
     3806                        $size = filesize( $video );
     3807                        if ( 8 < $size / pow( 1024, 2 ) ) { // Check whether the size is larger than 8MB.
     3808                                $validity->add( 'size_too_large', __( 'This video file is too large to use as a header video. Try a shorter video or optimize the compression settings and re-upload a file that is less than 8MB. Or, upload your video to YouTube and link it with the option below.' ) );
     3809                        }
     3810                        if ( '.mp4' !== substr( $video, -4 ) && '.mov' !== substr( $video, -4 ) ) { // Check for .mp4 or .mov format, which (assuming h.264 encoding) are the only cross-browser-supported formats.
     3811                                $validity->add( 'invalid_file_type', __( 'Only <code>.mp4</code> or <code>.mov</code> files may be used for header video. Please convert your video file and try again, or, upload your video to YouTube and link it with the option below.' ) );
     3812                        }
     3813                }
     3814                return $validity;
     3815        }
     3816
     3817        /**
     3818         * Callback for validating the external_header_video value.
     3819         *
     3820         * Ensures that the provided URL is for YouTube or Vimeo.
     3821         *
     3822         * @since 4.7.0
     3823         *
     3824         * @param WP_Error $validity
     3825         * @param mixed $value
     3826         * @return mixed
     3827         */
     3828        public function _validate_external_header_video( $validity, $value ) {
     3829                $video = esc_url( $value );
     3830                if ( $video ) {
     3831                        if ( ! preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video )
     3832                             && ! preg_match( '#^https?://(.+\.)?vimeo\.com/.*#', $video ) ) {
     3833                                $validity->add( 'invalid_url', __( 'Please enter a valid YouTube or Vimeo video URL.' ) );
     3834                        }
     3835                }
     3836                return $validity;
     3837        }
     3838
     3839        /**
    37083840         * Callback for rendering the custom logo, used in the custom_logo partial.
    37093841         *
    37103842         * This method exists because the partial object and context data are passed
  • src/wp-includes/customize/class-wp-customize-header-image-control.php

    diff --git src/wp-includes/customize/class-wp-customize-header-image-control.php src/wp-includes/customize/class-wp-customize-header-image-control.php
    index 16ebae7..baf12c8 100644
    class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control { 
    166166                $height = absint( get_theme_support( 'custom-header', 'height' ) );
    167167                ?>
    168168                <div class="customize-control-content">
    169                         <p class="customizer-section-intro">
     169                        <?php if ( current_theme_supports( 'custom-header', 'video' ) ) {
     170                                echo '<span class="customize-control-title">' . $this->label . '</span>';
     171                        } ?>
     172                        <p class="customizer-section-intro customize-control-description">
    170173                                <?php
    171                                 if ( $width && $height ) {
     174                                if ( current_theme_supports( 'custom-header', 'video' ) ) {
     175                                        _e( 'While you can crop images to your liking after clicking <strong>Add new image</strong>, we recommend matching the size of your video.' );
     176                                } elseif ( $width && $height ) {
    172177                                        /* translators: %s: header size in pixels */
    173178                                        printf( __( 'While you can crop images to your liking after clicking <strong>Add new image</strong>, your theme recommends a header size of %s pixels.' ),
    174179                                                sprintf( '<strong>%s &times; %s</strong>', $width, $height )
  • new file src/wp-includes/js/wp-custom-header.js

    diff --git src/wp-includes/js/wp-custom-header.js src/wp-includes/js/wp-custom-header.js
    new file mode 100644
    index 0000000..0ef1fb2
    - +  
     1(function( window, settings ) {
     2
     3        function wpCustomHeader() {
     4                var handlers = {
     5                        native: {
     6                                test: function( settings ) {
     7                                        var video = document.createElement( 'video' );
     8                                        return video.canPlayType( settings.mimeType );
     9                                },
     10                                callback: nativeHandler
     11                        },
     12                        youtube: {
     13                                test: function( settings ) {
     14                                        return 'video/x-youtube' === settings.mimeType;
     15                                },
     16                                callback: youtubeHandler
     17                        }
     18                };
     19
     20                function initialize() {
     21                        settings.container = document.getElementById( 'wp-custom-header' );
     22
     23                        if ( supportsVideo() ) {
     24                                for ( id in handlers ) {
     25                                        var handler = handlers[ id ];
     26
     27                                        if ( handlers.hasOwnProperty( id ) && handler.test( settings ) ) {
     28                                                handler.callback( settings );
     29                                                break;
     30                                        }
     31                                }
     32                        }
     33                }
     34
     35                function supportsVideo() {
     36                        // Don't load video on small screens. @todo: consider bandwidth and other factors.
     37                        if ( window.innerWidth < settings.minWidth  || window.innerHeight < settings.minHeight ) {
     38                                return false;
     39                        }
     40
     41                        return true;
     42                }
     43
     44                return {
     45                        handlers: handlers,
     46                        initialize: initialize,
     47                        supportsVideo: supportsVideo
     48                }
     49        }
     50
     51        function nativeHandler( settings ) {
     52                var video = document.createElement( 'video' );
     53
     54                video.id = 'wp-custom-header-video';
     55                video.autoplay = 'autoplay';
     56                video.loop = 'loop';
     57                video.muted = 'muted';
     58                video.width = settings.width;
     59                video.height = settings.height;
     60
     61                video.addEventListener( 'click', function() {
     62                        if ( video.paused ) {
     63                                video.play();
     64                        } else {
     65                                video.pause();
     66                        }
     67                });
     68
     69                settings.container.innerHTML = '';
     70                settings.container.appendChild( video );
     71                video.src = settings.videoUrl;
     72        }
     73
     74        function youtubeHandler( settings ) {
     75                // @link http://stackoverflow.com/a/27728417
     76                var VIDEO_ID_REGEX = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/,
     77                        videoId = settings.videoUrl.match( VIDEO_ID_REGEX )[1];
     78
     79                function loadVideo() {
     80                        YT.ready(function() {
     81                                var video = document.createElement( 'div' );
     82                                video.id = 'wp-custom-header-video';
     83                                settings.container.innerHTML = '';
     84                                settings.container.appendChild( video );
     85
     86                                new YT.Player( video, {
     87                                        height: settings.height,
     88                                        width: settings.width,
     89                                        videoId: videoId,
     90                                        events: {
     91                                                onReady: function( e ) {
     92                                                        e.target.mute();
     93                                                },
     94                                                onStateChange: function( e ) {
     95                                                        if ( YT.PlayerState.ENDED === e.data ) {
     96                                                                e.target.playVideo();
     97                                                        }
     98                                                }
     99                                        },
     100                                        playerVars: {
     101                                                autoplay: 1,
     102                                                controls: 0,
     103                                                disablekb: 1,
     104                                                fs: 0,
     105                                                iv_load_policy: 3,
     106                                                loop: 1,
     107                                                modestbranding: 1,
     108                                                //origin: '',
     109                                                playsinline: 1,
     110                                                rel: 0,
     111                                                showinfo: 0
     112                                        }
     113                                });
     114                        });
     115                }
     116
     117                if ( 'YT' in window ) {
     118                        loadVideo();
     119                } else {
     120                        tag = document.createElement( 'script' );
     121                        tag.src = 'https://www.youtube.com/player_api';
     122                        tag.onload = function () { loadVideo(); };
     123                        document.getElementsByTagName( 'head' )[0].appendChild( tag );
     124                }
     125        }
     126
     127        window.wp = window.wp || {};
     128        window.wp.customHeader = new wpCustomHeader();
     129        document.addEventListener( 'DOMContentLoaded', window.wp.customHeader.initialize, false );
     130
     131        if ( 'customize' in window.wp ) {
     132                wp.customize.selectiveRefresh.bind( 'render-partials-response', function( response ) {
     133                        if ( 'custom_header_settings' in response ) {
     134                                settings = response.custom_header_settings;
     135                        }
     136                });
     137
     138                wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
     139                        if ( 'header_video' === placement.partial.id || 'external_header_video' === placement.partial.id ) {
     140                                window.wp.customHeader.initialize();
     141                        }
     142                });
     143        }
     144
     145})( window, window._wpCustomHeaderSettings || {} );
  • src/wp-includes/script-loader.php

    diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
    index 89bcc06..378ce1a 100644
    function wp_default_scripts( &$scripts ) { 
    479479        $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu' ), false, 1 );
    480480        $scripts->add( 'customize-preview-nav-menus', "/wp-includes/js/customize-preview-nav-menus$suffix.js", array( 'jquery', 'wp-util', 'customize-preview', 'customize-selective-refresh' ), false, 1 );
    481481
     482        $scripts->add( 'wp-custom-header', "/wp-includes/js/wp-custom-header$suffix.js", array(), false, 1 );
     483
    482484        $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 );
    483485
    484486        $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 );
  • src/wp-includes/theme.php

    diff --git src/wp-includes/theme.php src/wp-includes/theme.php
    index 606e254..a120661 100644
    function get_custom_header() { 
    12641264                'thumbnail_url' => '',
    12651265                'width'         => get_theme_support( 'custom-header', 'width' ),
    12661266                'height'        => get_theme_support( 'custom-header', 'height' ),
     1267                'video'         => get_theme_support( 'custom-header', 'video' ),
    12671268        );
    12681269        return (object) wp_parse_args( $data, $default );
    12691270}
    function unregister_default_headers( $header ) { 
    13111312}
    13121313
    13131314/**
     1315 * Check whether a header video is set or not.
     1316 *
     1317 * @since 4.7.0
     1318 *
     1319 * @see get_header_video_url()
     1320 *
     1321 * @return bool Whether a header video is set or not.
     1322 */
     1323function has_header_video() {
     1324        return (bool) get_header_video_url();
     1325}
     1326
     1327/* Retrieve header video URL for custom header.
     1328 *
     1329 * Uses a local video if present, or falls back to an external video. Returns false if there is no video.
     1330 *
     1331 * @since 4.7.0
     1332 *
     1333 * @return string|false
     1334 */
     1335function get_header_video_url() {
     1336        $id = absint( get_theme_mod( 'header_video' ) );
     1337        $url = esc_url( get_theme_mod( 'external_header_video' ) );
     1338
     1339        if ( ! $id && ! $url ) {
     1340                return false;
     1341        }
     1342
     1343        if ( $id ) {
     1344                // Get the file URL from the attachment ID.
     1345                $url = wp_get_attachment_url( $id );
     1346        }
     1347
     1348        return esc_url_raw( set_url_scheme( $url ) );
     1349}
     1350
     1351/**
     1352 * Display header video URL.
     1353 *
     1354 * @since 4.7.0
     1355 */
     1356function the_header_video_url() {
     1357        $video = get_header_video_url();
     1358        if ( $video ) {
     1359                echo esc_url( $video );
     1360        }
     1361}
     1362
     1363/**
     1364 * Retrieve header video settings.
     1365 *
     1366 * @since 4.7.0
     1367 *
     1368 * @return array
     1369 */
     1370function get_header_video_settings() {
     1371        $header     = get_custom_header();
     1372        $video_url  = get_header_video_url();
     1373        $video_type = wp_check_filetype( $video_url, wp_get_mime_types() );
     1374
     1375        $settings = array(
     1376                'mimeType'  => '',
     1377                'posterUrl' => get_header_image(),
     1378                'videoUrl'  => $video_url,
     1379                'width'     => absint( $header->width ),
     1380                'height'    => absint( $header->height ),
     1381                'minWidth'  => 900,
     1382                'minHeight' => 500,
     1383        );
     1384
     1385        if ( preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video_url ) ) {
     1386                $settings['mimeType'] = 'video/x-youtube';
     1387        } elseif ( preg_match( '#^https?://(.+\.)?vimeo\.com/.*#', $video_url ) ) {
     1388                $settings['mimeType'] = 'video/x-vimeo';
     1389        } elseif ( ! empty( $video_type['type'] ) ) {
     1390                $settings['mimeType'] = $video_type['type'];
     1391        }
     1392
     1393        return apply_filters( 'header_video_settings', $settings );
     1394}
     1395
     1396/**
     1397 * Retrieve the markup for a custom header.
     1398 *
     1399 * @since 4.7.0
     1400 *
     1401 * @retrun bool True if a custom header is set. False if not.
     1402 */
     1403function has_custom_header() {
     1404        if ( has_header_image() || ( is_front_page() && has_header_video() ) ) {
     1405                return true;
     1406        }
     1407
     1408        return false;
     1409}
     1410
     1411/**
     1412 * Retrieve the markup for a custom header.
     1413 *
     1414 * @since 4.7.0
     1415 *
     1416 * @return string|false The markup for a custom header on success. False if not.
     1417 */
     1418function get_custom_header_markup() {
     1419        if ( ! has_custom_header() ) {
     1420                return false;
     1421        }
     1422
     1423        return sprintf(
     1424                '<div id="wp-custom-header" class="wp-custom-header">%s</div>',
     1425                get_header_image_tag()
     1426        );
     1427}
     1428
     1429/**
     1430 * Print the markup for a custom header.
     1431 *
     1432 * @since 4.7.0
     1433 */
     1434function the_custom_header_markup() {
     1435        if ( ! $custom_header = get_custom_header_markup() ) {
     1436                return;
     1437        }
     1438
     1439        echo $custom_header;
     1440
     1441        if ( has_header_video() && ( is_front_page() || is_customize_preview() ) ) {
     1442                wp_enqueue_script( 'wp-custom-header' );
     1443                wp_localize_script( 'wp-custom-header', '_wpCustomHeaderSettings', get_header_video_settings() );
     1444        }
     1445}
     1446
     1447/**
    13141448 * Retrieve background image for custom background.
    13151449 *
    13161450 * @since 3.0.0
    function add_theme_support( $feature ) { 
    17321866                                'wp-head-callback' => '',
    17331867                                'admin-head-callback' => '',
    17341868                                'admin-preview-callback' => '',
     1869                                'video' => false,
    17351870                        );
    17361871
    17371872                        $jit = isset( $args[0]['__jit'] );