Themes: Enable video in custom headers.

This adds the ability for themes to add support for videos in custom headers
by passing `'video' => true` as an argument when adding theme support for
custom headers.

Custom video headers are managed through the “Header Visuals” (i.e. “Header Image”)
panel in the Customizer where you can select a video from the media library or set a
URL to an external video (YouTube for now) for use in custom headers.

This introduces several new functions:

`has_header_video()` – Check whether a header video is set or not.
`get_header_video_url()` – Retrieve header video URL for custom header.
`the_header_video_url()` – Display header video URL.
`get_header_video_settings()` – Retrieve header video settings.
`has_custom_header()` – Check whether a custom header is set or not.
`get_custom_header_markup()` – Retrieve the markup for a custom header.
`the_custom_header_markup()` – Print the markup for a custom header.

And a new file, `wp-includes/js/wp-custom-header.js` that handles loading videos
in custom headers.

This also enables video headers in the Twenty Seventeen and Twenty Fourteen themes.

Props davidakennedy, celloexpressions, bradyvercher, laurelfulford, joemcgill.
Fixes #38172.
Built from https://develop.svn.wordpress.org/trunk@38985


git-svn-id: http://core.svn.wordpress.org/trunk@38928 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Joe McGill 2016-10-27 21:51:31 +00:00
parent 7b0abd1cea
commit 030bc377dd
21 changed files with 552 additions and 62 deletions

View File

@ -434,7 +434,7 @@ function twentyfourteen_body_classes( $classes ) {
$classes[] = 'group-blog'; $classes[] = 'group-blog';
} }
if ( get_header_image() ) { if ( get_header_image() || function_exists( 'has_header_video' ) && has_header_video() ) {
$classes[] = 'header-image'; $classes[] = 'header-image';
} elseif ( ! in_array( $GLOBALS['pagenow'], array( 'wp-activate.php', 'wp-signup.php' ) ) ) { } elseif ( ! in_array( $GLOBALS['pagenow'], array( 'wp-activate.php', 'wp-signup.php' ) ) ) {
$classes[] = 'masthead-fixed'; $classes[] = 'masthead-fixed';

View File

@ -32,7 +32,11 @@
<body <?php body_class(); ?>> <body <?php body_class(); ?>>
<div id="page" class="hfeed site"> <div id="page" class="hfeed site">
<?php if ( get_header_image() ) : ?> <?php if ( function_exists( 'has_header_video' ) && has_header_video() ) : ?>
<div id="site-header">
<?php the_custom_header_markup(); ?>
</div>
<?php elseif ( get_header_image() ) : ?>
<div id="site-header"> <div id="site-header">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"> <a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
<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' ) ); ?>"> <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' ) ); ?>">

View File

@ -40,6 +40,7 @@ function twentyfourteen_custom_header_setup() {
'width' => 1260, 'width' => 1260,
'height' => 240, 'height' => 240,
'flex-height' => true, 'flex-height' => true,
'video' => true,
'wp-head-callback' => 'twentyfourteen_header_style', 'wp-head-callback' => 'twentyfourteen_header_style',
'admin-head-callback' => 'twentyfourteen_admin_header_style', 'admin-head-callback' => 'twentyfourteen_admin_header_style',
'admin-preview-callback' => 'twentyfourteen_admin_header_image', 'admin-preview-callback' => 'twentyfourteen_admin_header_image',

View File

@ -19,6 +19,8 @@ function twentyfourteen_customize_register( $wp_customize ) {
$wp_customize->get_setting( 'blogname' )->transport = 'postMessage'; $wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
$wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
$wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage'; $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';
$wp_customize->get_setting( 'header_image' )->transport = 'postMessage';
$wp_customize->get_setting( 'header_image_data' )->transport = 'postMessage';
if ( isset( $wp_customize->selective_refresh ) ) { if ( isset( $wp_customize->selective_refresh ) ) {
$wp_customize->selective_refresh->add_partial( 'blogname', array( $wp_customize->selective_refresh->add_partial( 'blogname', array(

View File

@ -95,15 +95,20 @@
*/ */
if ( _window.width() > 781 ) { if ( _window.width() > 781 ) {
var mastheadHeight = $( '#masthead' ).height(), var mastheadHeight = $( '#masthead' ).height(),
toolbarOffset, mastheadOffset; mastheadOffset;
if ( mastheadHeight > 48 ) { if ( mastheadHeight > 48 ) {
body.removeClass( 'masthead-fixed' ); body.removeClass( 'masthead-fixed' );
} }
mastheadOffset = $( '#site-header' ).height();
if ( body.is( '.header-image' ) ) { if ( body.is( '.header-image' ) ) {
toolbarOffset = body.is( '.admin-bar' ) ? $( '#wpadminbar' ).height() : 0;
mastheadOffset = $( '#masthead' ).offset().top - toolbarOffset; // Recaculate the header height when a custom header loads.
$( 'body' ).on( 'wp-custom-header-video-loaded', function() {
mastheadOffset = $( '#site-header' ).height();
} );
_window.on( 'scroll.twentyfourteen', function() { _window.on( 'scroll.twentyfourteen', function() {
if ( _window.scrollTop() > mastheadOffset && mastheadHeight < 49 ) { if ( _window.scrollTop() > mastheadOffset && mastheadHeight < 49 ) {
@ -112,6 +117,13 @@
body.removeClass( 'masthead-fixed' ); body.removeClass( 'masthead-fixed' );
} }
} ); } );
// Update masthead offset after a selective refresh.
if ( 'undefined' !== typeof wp && wp.customize && wp.customize.selectiveRefresh ) {
wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function() {
mastheadOffset = $( '#site-header' ).height();
} );
}
} }
} }

View File

@ -88,6 +88,7 @@ canvas,
video { video {
display: inline-block; display: inline-block;
max-width: 100%; max-width: 100%;
height: auto;
} }
html { html {
@ -608,6 +609,11 @@ video {
max-width: 100%; max-width: 100%;
} }
#wp-custom-header iframe,
#wp-custom-header video {
margin-bottom: -8px;
}
p > embed, p > embed,
p > iframe, p > iframe,
p > object, p > object,

View File

@ -68,6 +68,12 @@ img {
padding: 45px 0; padding: 45px 0;
} }
.has-header-image .custom-header-image img,
.has-header-image .custom-header-image video {
left: 0;
top: 0;
}
.site-title { .site-title {
font-size: 36px; font-size: 36px;
font-weight: bolder; font-weight: bolder;

View File

@ -39,6 +39,7 @@
?> ?>
</div><!-- .wrap --> </div><!-- .wrap -->
</footer><!-- #colophon --> </footer><!-- #colophon -->
</div><!-- .site-content-contain -->
</div><!-- #page --> </div><!-- #page -->
<?php wp_footer(); ?> <?php wp_footer(); ?>

View File

@ -49,4 +49,5 @@
endif; endif;
?> ?>
<div class="site-content-contain">
<div id="content" class="site-content"> <div id="content" class="site-content">

View File

@ -39,6 +39,7 @@ function twentyseventeen_custom_header_setup() {
'width' => 2000, 'width' => 2000,
'height' => 1200, 'height' => 1200,
'flex-height' => true, 'flex-height' => true,
'video' => true,
'wp-head-callback' => 'twentyseventeen_header_style', 'wp-head-callback' => 'twentyseventeen_header_style',
) ) ); ) ) );

View File

@ -16,6 +16,8 @@ function twentyseventeen_customize_register( $wp_customize ) {
$wp_customize->get_setting( 'blogname' )->transport = 'postMessage'; $wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
$wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
$wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage'; $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';
$wp_customize->get_setting( 'header_image' )->transport = 'postMessage';
$wp_customize->get_setting( 'header_image_data' )->transport = 'postMessage';
$wp_customize->selective_refresh->add_partial( 'blogname', array( $wp_customize->selective_refresh->add_partial( 'blogname', array(
'selector' => '.site-title a', 'selector' => '.site-title a',

View File

@ -35,7 +35,7 @@ function twentyseventeen_body_classes( $classes ) {
} }
// Add a class if there is a custom header. // Add a class if there is a custom header.
if ( has_header_image() ) { if ( has_header_image() || has_header_video() && is_front_page() ) {
$classes[] = 'has-header-image'; $classes[] = 'has-header-image';
} }

View File

@ -1314,6 +1314,7 @@ a:hover .nav-title,
border-top: 1px solid #eee; border-top: 1px solid #eee;
font-size: 16px; font-size: 16px;
font-size: 1rem; font-size: 1rem;
position: relative;
} }
.navigation-top .wrap { .navigation-top .wrap {
@ -1555,8 +1556,10 @@ body {
.site-branding { .site-branding {
padding: 1em 0; padding: 1em 0;
position: relative;
-webkit-transition: margin-bottom 0.2s; -webkit-transition: margin-bottom 0.2s;
transition: margin-bottom 0.2s; transition: margin-bottom 0.2s;
z-index: 3;
} }
.site-branding a { .site-branding a {
@ -1650,15 +1653,13 @@ body:not(.title-tagline-hidden) .site-branding-text {
} }
.custom-header-image { .custom-header-image {
background-position: center center;
background-repeat: no-repeat;
-webkit-background-size: cover;
background-size: cover;
bottom: 0; bottom: 0;
left: 0; left: 0;
overflow: hidden;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
width: 100%;
} }
.custom-header-image:before { .custom-header-image:before {
@ -1674,10 +1675,35 @@ body:not(.title-tagline-hidden) .site-branding-text {
left: 0; left: 0;
position: absolute; position: absolute;
right: 0; right: 0;
z-index: 2;
} }
.has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-image { .has-header-image .custom-header-image img,
background-position: center bottom; .has-header-image .custom-header-image video,
.has-header-image .custom-header-image iframe {
position: fixed;
height: auto;
left: 50%;
max-width: 1000%;
min-height: 100%;
min-width: 100%;
min-width: 100vw; /* vw prevents 1px gap on left that 100% has */
width: auto;
top: 50%;
-ms-transform: translateX(-50%) translateY(-50%);
-moz-transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
.has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-image img {
bottom: 0;
position: absolute;
top: auto;
-ms-transform: translateX(-50%) translateY(0);
-moz-transform: translateX(-50%) translateY(0);
-webkit-transform: translateX(-50%) translateY(0);
transform: translateX(-50%) translateY(0);
} }
body:not(.has-header-image) .custom-header-image { body:not(.has-header-image) .custom-header-image {
@ -1777,6 +1803,11 @@ body:not(.has-header-image) .custom-header-image {
## Regular Content ## Regular Content
--------------------------------------------------------------*/ --------------------------------------------------------------*/
.site-content-contain {
background-color: #fff;
position: relative;
}
.site-content { .site-content {
padding: 2.5em 0 0; padding: 2.5em 0 0;
} }
@ -2642,7 +2673,8 @@ h2.widget-title {
# Media # Media
--------------------------------------------------------------*/ --------------------------------------------------------------*/
img { img,
video {
height: auto; /* Make sure images are scaled correctly. */ height: auto; /* Make sure images are scaled correctly. */
max-width: 100%; /* Adhere to container width. */ max-width: 100%; /* Adhere to container width. */
} }
@ -3287,7 +3319,6 @@ article.panel-placeholder {
.has-header-image.twentyseventeen-front-page .custom-header, .has-header-image.twentyseventeen-front-page .custom-header,
.has-header-image.home.blog .custom-header { .has-header-image.home.blog .custom-header {
display: block;
min-height: 0; min-height: 0;
} }
@ -3296,6 +3327,12 @@ article.panel-placeholder {
position: relative; position: relative;
} }
.twentyseventeen-front-page.has-header-image .custom-header-image,
.home.blog.has-header-image .custom-header-image {
height: 0;
position: relative;
}
.has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-image { .has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-image {
bottom: 0; bottom: 0;
height: auto; height: auto;
@ -3305,13 +3342,6 @@ article.panel-placeholder {
top: 0; top: 0;
} }
.twentyseventeen-front-page.has-header-image .custom-header-image,
.home.blog.has-header-image .custom-header-image {
height: 0;
padding-top: 66%;
position: relative;
}
.custom-logo-link { .custom-logo-link {
padding-right: 2em; padding-right: 2em;
} }
@ -3591,7 +3621,8 @@ article.panel-placeholder {
height: 1200px; height: 1200px;
height: 100vh; height: 100vh;
max-height: 100%; max-height: 100%;
padding: 10% 0; overflow: hidden;
/* padding: 10% 0; */
} }
.twentyseventeen-front-page.has-header-image .custom-header-image:before, .twentyseventeen-front-page.has-header-image .custom-header-image:before,
@ -3938,11 +3969,6 @@ article.panel-placeholder {
@media screen and ( min-width: 55em ) { @media screen and ( min-width: 55em ) {
.twentyseventeen-front-page.has-header-image .custom-header-image,
.home.blog.has-header-image .custom-header-image {
background-attachment: fixed;
}
.panel-image { .panel-image {
background-attachment: fixed; background-attachment: fixed;
} }

View File

@ -14,12 +14,17 @@
$header_image = get_header_image(); $header_image = get_header_image();
// Check if Custom Header image has been added. // Check if Custom Header image has been added.
if ( ! empty( $header_image ) ) : ?> if ( has_custom_header() ) :
?>
<div class="custom-header-image" style="background-image: url(<?php echo esc_url( $header_image ); ?>)"></div> <?php // Output the full custom header - video and/or image fallback. ?>
<div class="custom-header-image">
<?php the_custom_header_markup(); ?>
</div>
<?php get_template_part( 'template-parts/header/site', 'branding' ); ?> <?php get_template_part( 'template-parts/header/site', 'branding' ); ?>
<?php else : ?> <?php else : ?>
<?php // Otherwise, show a blank header. ?> <?php // Otherwise, show a blank header. ?>
<div class="custom-header-simple"> <div class="custom-header-simple">
<?php get_template_part( 'template-parts/header/site', 'branding' ); ?> <?php get_template_part( 'template-parts/header/site', 'branding' ); ?>

View File

@ -363,6 +363,9 @@ final class WP_Customize_Manager {
add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_section_templates' ), 1 ); add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_section_templates' ), 1 );
add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_control_templates' ), 1 ); add_action( 'customize_controls_print_footer_scripts', array( $this, 'render_control_templates' ), 1 );
// Export header video settings with the partial response.
add_filter( 'customize_render_partials_response', array( $this, 'export_header_video_settings' ), 10, 3 );
// Export the settings to JS via the _wpCustomizeSettings variable. // Export the settings to JS via the _wpCustomizeSettings variable.
add_action( 'customize_controls_print_footer_scripts', array( $this, 'customize_pane_settings' ), 1000 ); add_action( 'customize_controls_print_footer_scripts', array( $this, 'customize_pane_settings' ), 1000 );
@ -3249,12 +3252,54 @@ final class WP_Customize_Manager {
/* Custom Header */ /* Custom Header */
if ( current_theme_supports( 'custom-header', 'video' ) ) {
$title = __( 'Header Visuals' );
$description = __( 'If you add a video, the image will be used as a fallback while the video loads.' );
$width = absint( get_theme_support( 'custom-header', 'width' ) );
$height = absint( get_theme_support( 'custom-header', 'height' ) );
if ( $width && $height ) {
/* translators: %s: header size in pixels */
$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.' ),
sprintf( '<strong>%s &times; %s</strong>', $width, $height )
);
} elseif ( $width ) {
/* translators: %s: header width in pixels */
$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.' ),
sprintf( '<strong>%s</strong>', $width )
);
} else {
/* translators: %s: header height in pixels */
$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.' ),
sprintf( '<strong>%s</strong>', $height )
);
}
} else {
$title = __( 'Header Image' );
$description = '';
$control_description = '';
}
$this->add_section( 'header_image', array( $this->add_section( 'header_image', array(
'title' => __( 'Header Image' ), 'title' => $title,
'description' => $description,
'theme_supports' => 'custom-header', 'theme_supports' => 'custom-header',
'priority' => 60, 'priority' => 60,
) ); ) );
$this->add_setting( 'header_video', array(
'theme_supports' => array( 'custom-header', 'video' ),
'transport' => 'postMessage',
'sanitize_callback' => 'absint',
'validate_callback' => array( $this, '_validate_header_video' ),
) );
$this->add_setting( 'external_header_video', array(
'theme_supports' => array( 'custom-header', 'video' ),
'transport' => 'postMessage',
'sanitize_callback' => 'esc_url',
'validate_callback' => array( $this, '_validate_external_header_video' ),
) );
$this->add_setting( new WP_Customize_Filter_Setting( $this, 'header_image', array( $this->add_setting( new WP_Customize_Filter_Setting( $this, 'header_image', array(
'default' => get_theme_support( 'custom-header', 'default-image' ), 'default' => get_theme_support( 'custom-header', 'default-image' ),
'theme_supports' => 'custom-header', 'theme_supports' => 'custom-header',
@ -3265,8 +3310,30 @@ final class WP_Customize_Manager {
'theme_supports' => 'custom-header', 'theme_supports' => 'custom-header',
) ) ); ) ) );
$this->add_control( new WP_Customize_Media_Control( $this, 'header_video', array(
'theme_supports' => array( 'custom-header', 'video' ),
'label' => __( 'Header Video' ),
'description' => $control_description,
'section' => 'header_image',
'mime_type' => 'video',
) ) );
$this->add_control( 'external_header_video', array(
'theme_supports' => array( 'custom-header', 'video' ),
'type' => 'url',
'description' => __( 'Or, enter a YouTube or Vimeo URL:' ),
'section' => 'header_image',
) );
$this->add_control( new WP_Customize_Header_Image_Control( $this ) ); $this->add_control( new WP_Customize_Header_Image_Control( $this ) );
$this->selective_refresh->add_partial( 'custom_header', array(
'selector' => '#wp-custom-header',
'render_callback' => 'the_custom_header_markup',
'settings' => array( 'header_video', 'external_header_video', 'header_image' ), // The image is used as a video fallback here.
'container_inclusive' => true,
) );
/* Custom Background */ /* Custom Background */
$this->add_section( 'background_image', array( $this->add_section( 'background_image', array(
@ -3704,6 +3771,71 @@ final class WP_Customize_Manager {
return $value; return $value;
} }
/**
* Export header video settings to facilitate selective refresh.
*
* @since 4.7.0
*
* @param array $response Response.
* @param WP_Customize_Selective_Refresh $selective_refresh Selective refresh component.
* @param array $partials Array of partials.
* @return array
*/
public function export_header_video_settings( $response, $selective_refresh, $partials ) {
if ( isset( $partials['header_video'] ) || isset( $partials['external_header_video'] ) ) {
$response['custom_header_settings'] = get_header_video_settings();
}
return $response;
}
/**
* Callback for validating the header_video value.
*
* Ensures that the selected video is less than 8MB and provides an error message.
*
* @since 4.7.0
*
* @param WP_Error $validity
* @param mixed $value
* @return mixed
*/
public function _validate_header_video( $validity, $value ) {
$video = get_attached_file( absint( $value ) );
if ( $video ) {
$size = filesize( $video );
if ( 8 < $size / pow( 1024, 2 ) ) { // Check whether the size is larger than 8MB.
$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.' ) );
}
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.
$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.' ) );
}
}
return $validity;
}
/**
* Callback for validating the external_header_video value.
*
* Ensures that the provided URL is for YouTube or Vimeo.
*
* @since 4.7.0
*
* @param WP_Error $validity
* @param mixed $value
* @return mixed
*/
public function _validate_external_header_video( $validity, $value ) {
$video = esc_url( $value );
if ( $video ) {
if ( ! preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video )
&& ! preg_match( '#^https?://(.+\.)?vimeo\.com/.*#', $video ) ) {
$validity->add( 'invalid_url', __( 'Please enter a valid YouTube or Vimeo video URL.' ) );
}
}
return $validity;
}
/** /**
* Callback for rendering the custom logo, used in the custom_logo partial. * Callback for rendering the custom logo, used in the custom_logo partial.
* *

View File

@ -166,9 +166,14 @@ class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
$height = absint( get_theme_support( 'custom-header', 'height' ) ); $height = absint( get_theme_support( 'custom-header', 'height' ) );
?> ?>
<div class="customize-control-content"> <div class="customize-control-content">
<p class="customizer-section-intro"> <?php if ( current_theme_supports( 'custom-header', 'video' ) ) {
echo '<span class="customize-control-title">' . $this->label . '</span>';
} ?>
<p class="customizer-section-intro customize-control-description">
<?php <?php
if ( $width && $height ) { if ( current_theme_supports( 'custom-header', 'video' ) ) {
_e( 'While you can crop images to your liking after clicking <strong>Add new image</strong>, we recommend matching the size of your video.' );
} elseif ( $width && $height ) {
/* translators: %s: header size in pixels */ /* translators: %s: header size in pixels */
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.' ), 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.' ),
sprintf( '<strong>%s &times; %s</strong>', $width, $height ) sprintf( '<strong>%s &times; %s</strong>', $width, $height )

View File

@ -0,0 +1,149 @@
(function( window, $, settings ) {
function wpCustomHeader() {
var handlers = {
nativeVideo: {
test: function( settings ) {
var video = document.createElement( 'video' );
return video.canPlayType( settings.mimeType );
},
callback: nativeHandler
},
youtube: {
test: function( settings ) {
return 'video/x-youtube' === settings.mimeType;
},
callback: youtubeHandler
}
};
function initialize() {
settings.container = document.getElementById( 'wp-custom-header' );
if ( supportsVideo() ) {
for ( var id in handlers ) {
var handler = handlers[ id ];
if ( handlers.hasOwnProperty( id ) && handler.test( settings ) ) {
handler.callback( settings );
break;
}
}
$( 'body' ).trigger( 'wp-custom-header-video-loaded' );
}
}
function supportsVideo() {
// Don't load video on small screens. @todo: consider bandwidth and other factors.
if ( window.innerWidth < settings.minWidth || window.innerHeight < settings.minHeight ) {
return false;
}
return true;
}
return {
handlers: handlers,
initialize: initialize,
supportsVideo: supportsVideo
};
}
function nativeHandler( settings ) {
var video = document.createElement( 'video' );
video.id = 'wp-custom-header-video';
video.autoplay = 'autoplay';
video.loop = 'loop';
video.muted = 'muted';
video.width = settings.width;
video.height = settings.height;
video.addEventListener( 'click', function() {
if ( video.paused ) {
video.play();
} else {
video.pause();
}
});
settings.container.innerHTML = '';
settings.container.appendChild( video );
video.src = settings.videoUrl;
}
function youtubeHandler( settings ) {
// @link http://stackoverflow.com/a/27728417
var VIDEO_ID_REGEX = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/,
videoId = settings.videoUrl.match( VIDEO_ID_REGEX )[1];
function loadVideo() {
var YT = window.YT || {};
YT.ready(function() {
var video = document.createElement( 'div' );
video.id = 'wp-custom-header-video';
settings.container.innerHTML = '';
settings.container.appendChild( video );
new YT.Player( video, {
height: settings.height,
width: settings.width,
videoId: videoId,
events: {
onReady: function( e ) {
e.target.mute();
},
onStateChange: function( e ) {
if ( YT.PlayerState.ENDED === e.data ) {
e.target.playVideo();
}
}
},
playerVars: {
autoplay: 1,
controls: 0,
disablekb: 1,
fs: 0,
iv_load_policy: 3,
loop: 1,
modestbranding: 1,
//origin: '',
playsinline: 1,
rel: 0,
showinfo: 0
}
});
});
}
if ( 'YT' in window ) {
loadVideo();
} else {
var tag = document.createElement( 'script' );
tag.src = 'https://www.youtube.com/player_api';
tag.onload = function () { loadVideo(); };
document.getElementsByTagName( 'head' )[0].appendChild( tag );
}
}
window.wp = window.wp || {};
window.wp.customHeader = new wpCustomHeader();
document.addEventListener( 'DOMContentLoaded', window.wp.customHeader.initialize, false );
if ( 'customize' in window.wp ) {
wp.customize.selectiveRefresh.bind( 'render-partials-response', function( response ) {
if ( 'custom_header_settings' in response ) {
settings = response.custom_header_settings;
}
});
wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
if ( 'custom_header' === placement.partial.id ) {
window.wp.customHeader.initialize();
}
});
}
})( window, jQuery, window._wpCustomHeaderSettings || {} );

View File

@ -0,0 +1 @@
!function(a,b,c){function d(){function d(){if(c.container=document.getElementById("wp-custom-header"),g()){for(var a in h){var d=h[a];if(h.hasOwnProperty(a)&&d.test(c)){d.callback(c);break}}b("body").trigger("wp-custom-header-video-loaded")}}function g(){return!(a.innerWidth<c.minWidth||a.innerHeight<c.minHeight)}var h={nativeVideo:{test:function(a){var b=document.createElement("video");return b.canPlayType(a.mimeType)},callback:e},youtube:{test:function(a){return"video/x-youtube"===a.mimeType},callback:f}};return{handlers:h,initialize:d,supportsVideo:g}}function e(a){var b=document.createElement("video");b.id="wp-custom-header-video",b.autoplay="autoplay",b.loop="loop",b.muted="muted",b.width=a.width,b.height=a.height,b.addEventListener("click",function(){b.paused?b.play():b.pause()}),a.container.innerHTML="",a.container.appendChild(b),b.src=a.videoUrl}function f(b){function c(){var c=a.YT||{};c.ready(function(){var a=document.createElement("div");a.id="wp-custom-header-video",b.container.innerHTML="",b.container.appendChild(a),new c.Player(a,{height:b.height,width:b.width,videoId:e,events:{onReady:function(a){a.target.mute()},onStateChange:function(a){c.PlayerState.ENDED===a.data&&a.target.playVideo()}},playerVars:{autoplay:1,controls:0,disablekb:1,fs:0,iv_load_policy:3,loop:1,modestbranding:1,playsinline:1,rel:0,showinfo:0}})})}var d=/^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/,e=b.videoUrl.match(d)[1];if("YT"in a)c();else{var f=document.createElement("script");f.src="https://www.youtube.com/player_api",f.onload=function(){c()},document.getElementsByTagName("head")[0].appendChild(f)}}a.wp=a.wp||{},a.wp.customHeader=new d,document.addEventListener("DOMContentLoaded",a.wp.customHeader.initialize,!1),"customize"in a.wp&&(wp.customize.selectiveRefresh.bind("render-partials-response",function(a){"custom_header_settings"in a&&(c=a.custom_header_settings)}),wp.customize.selectiveRefresh.bind("partial-content-rendered",function(b){"custom_header"===b.partial.id&&a.wp.customHeader.initialize()}))}(window,jQuery,window._wpCustomHeaderSettings||{});

View File

@ -479,6 +479,8 @@ function wp_default_scripts( &$scripts ) {
$scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu' ), false, 1 ); $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu' ), false, 1 );
$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 ); $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 );
$scripts->add( 'wp-custom-header', "/wp-includes/js/wp-custom-header$suffix.js", array(), false, 1 );
$scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 ); $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 );
$scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 ); $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 );

View File

@ -1264,6 +1264,7 @@ function get_custom_header() {
'thumbnail_url' => '', 'thumbnail_url' => '',
'width' => get_theme_support( 'custom-header', 'width' ), 'width' => get_theme_support( 'custom-header', 'width' ),
'height' => get_theme_support( 'custom-header', 'height' ), 'height' => get_theme_support( 'custom-header', 'height' ),
'video' => get_theme_support( 'custom-header', 'video' ),
); );
return (object) wp_parse_args( $data, $default ); return (object) wp_parse_args( $data, $default );
} }
@ -1310,6 +1311,138 @@ function unregister_default_headers( $header ) {
} }
} }
/**
* Check whether a header video is set or not.
*
* @since 4.7.0
*
* @see get_header_video_url()
*
* @return bool Whether a header video is set or not.
*/
function has_header_video() {
return (bool) get_header_video_url();
}
/* Retrieve header video URL for custom header.
*
* Uses a local video if present, or falls back to an external video. Returns false if there is no video.
*
* @since 4.7.0
*
* @return string|false
*/
function get_header_video_url() {
$id = absint( get_theme_mod( 'header_video' ) );
$url = esc_url( get_theme_mod( 'external_header_video' ) );
if ( ! $id && ! $url ) {
return false;
}
if ( $id ) {
// Get the file URL from the attachment ID.
$url = wp_get_attachment_url( $id );
}
return esc_url_raw( set_url_scheme( $url ) );
}
/**
* Display header video URL.
*
* @since 4.7.0
*/
function the_header_video_url() {
$video = get_header_video_url();
if ( $video ) {
echo esc_url( $video );
}
}
/**
* Retrieve header video settings.
*
* @since 4.7.0
*
* @return array
*/
function get_header_video_settings() {
$header = get_custom_header();
$video_url = get_header_video_url();
$video_type = wp_check_filetype( $video_url, wp_get_mime_types() );
$settings = array(
'mimeType' => '',
'posterUrl' => get_header_image(),
'videoUrl' => $video_url,
'width' => absint( $header->width ),
'height' => absint( $header->height ),
'minWidth' => 900,
'minHeight' => 500,
);
if ( preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video_url ) ) {
$settings['mimeType'] = 'video/x-youtube';
} elseif ( preg_match( '#^https?://(.+\.)?vimeo\.com/.*#', $video_url ) ) {
$settings['mimeType'] = 'video/x-vimeo';
} elseif ( ! empty( $video_type['type'] ) ) {
$settings['mimeType'] = $video_type['type'];
}
return apply_filters( 'header_video_settings', $settings );
}
/**
* Check whether a custom header is set or not.
*
* @since 4.7.0
*
* @return bool True if a custom header is set. False if not.
*/
function has_custom_header() {
if ( has_header_image() || ( is_front_page() && has_header_video() ) ) {
return true;
}
return false;
}
/**
* Retrieve the markup for a custom header.
*
* @since 4.7.0
*
* @return string|false The markup for a custom header on success. False if not.
*/
function get_custom_header_markup() {
if ( ! has_custom_header() ) {
return false;
}
return sprintf(
'<div id="wp-custom-header" class="wp-custom-header">%s</div>',
get_header_image_tag()
);
}
/**
* Print the markup for a custom header.
*
* @since 4.7.0
*/
function the_custom_header_markup() {
if ( ! $custom_header = get_custom_header_markup() ) {
return;
}
echo $custom_header;
if ( has_header_video() && is_front_page() ) {
wp_enqueue_script( 'wp-custom-header' );
wp_localize_script( 'wp-custom-header', '_wpCustomHeaderSettings', get_header_video_settings() );
}
}
/** /**
* Retrieve background image for custom background. * Retrieve background image for custom background.
* *
@ -1732,6 +1865,7 @@ function add_theme_support( $feature ) {
'wp-head-callback' => '', 'wp-head-callback' => '',
'admin-head-callback' => '', 'admin-head-callback' => '',
'admin-preview-callback' => '', 'admin-preview-callback' => '',
'video' => false,
); );
$jit = isset( $args[0]['__jit'] ); $jit = isset( $args[0]['__jit'] );

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.7-alpha-38984'; $wp_version = '4.7-alpha-38985';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.