* Gets the header images uploaded for the active theme.
function get_uploaded_header_images() {
$header_images = array();
'post_type' => 'attachment',
'meta_key' => '_wp_attachment_is_custom_header',
'meta_value' => get_option( 'stylesheet' ),
if ( empty( $headers ) ) {
foreach ( (array) $headers as $header ) {
$url = sanitize_url( wp_get_attachment_url( $header->ID ) );
$header_data = wp_get_attachment_metadata( $header->ID );
$header_index = $header->ID;
$header_images[ $header_index ] = array();
$header_images[ $header_index ]['attachment_id'] = $header->ID;
$header_images[ $header_index ]['url'] = $url;
$header_images[ $header_index ]['thumbnail_url'] = $url;
$header_images[ $header_index ]['alt_text'] = get_post_meta( $header->ID, '_wp_attachment_image_alt', true );
if ( isset( $header_data['attachment_parent'] ) ) {
$header_images[ $header_index ]['attachment_parent'] = $header_data['attachment_parent'];
$header_images[ $header_index ]['attachment_parent'] = '';
if ( isset( $header_data['width'] ) ) {
$header_images[ $header_index ]['width'] = $header_data['width'];
if ( isset( $header_data['height'] ) ) {
$header_images[ $header_index ]['height'] = $header_data['height'];
* Gets the header image data.
* @global array $_wp_default_headers
function get_custom_header() {
global $_wp_default_headers;
if ( is_random_header_image() ) {
$data = _get_random_header_data();
$data = get_theme_mod( 'header_image_data' );
if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
$directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
$data['url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
$data['thumbnail_url'] = $data['url'];
if ( ! empty( $_wp_default_headers ) ) {
foreach ( (array) $_wp_default_headers as $default_header ) {
$url = vsprintf( $default_header['url'], $directory_args );
if ( $data['url'] === $url ) {
$data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args );
'width' => get_theme_support( 'custom-header', 'width' ),
'height' => get_theme_support( 'custom-header', 'height' ),
'video' => get_theme_support( 'custom-header', 'video' ),
return (object) wp_parse_args( $data, $default );
* Registers a selection of default headers to be displayed by the custom header admin UI.
* @global array $_wp_default_headers
* @param array $headers Array of headers keyed by a string ID. The IDs point to arrays
* containing 'url', 'thumbnail_url', and 'description' keys.
function register_default_headers( $headers ) {
global $_wp_default_headers;
$_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
* Unregisters default headers.
* This function must be called after register_default_headers() has already added the
* header you want to remove.
* @see register_default_headers()
* @global array $_wp_default_headers
* @param string|array $header The header string id (key of array) to remove, or an array thereof.
* @return bool|void A single header returns true on success, false on failure.
* There is currently no return value for multiple headers.
function unregister_default_headers( $header ) {
global $_wp_default_headers;
if ( is_array( $header ) ) {
array_map( 'unregister_default_headers', $header );
} elseif ( isset( $_wp_default_headers[ $header ] ) ) {
unset( $_wp_default_headers[ $header ] );
* Checks whether a header video is set or not.
* @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();
* Retrieves header video URL for custom header.
* Uses a local video if present, or falls back to an external video.
* @return string|false Header video URL or false if there is no video.
function get_header_video_url() {
$id = absint( get_theme_mod( 'header_video' ) );
// Get the file URL from the attachment ID.
$url = wp_get_attachment_url( $id );
$url = get_theme_mod( 'external_header_video' );
* Filters the header video URL.
* @param string $url Header video URL, if available.
$url = apply_filters( 'get_header_video_url', $url );
return sanitize_url( set_url_scheme( $url ) );
* Displays header video URL.
function the_header_video_url() {
$video = get_header_video_url();
* Retrieves header video settings.
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() );
'posterUrl' => get_header_image(),
'videoUrl' => $video_url,
'width' => absint( $header->width ),
'height' => absint( $header->height ),
'pause' => __( 'Pause' ),
'pauseSpeak' => __( 'Video is paused.' ),
'playSpeak' => __( 'Video is playing.' ),
if ( preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video_url ) ) {
$settings['mimeType'] = 'video/x-youtube';
} elseif ( ! empty( $video_type['type'] ) ) {
$settings['mimeType'] = $video_type['type'];
* Filters header video settings.
* @param array $settings An array of header video settings.
return apply_filters( 'header_video_settings', $settings );
* Checks whether a custom header is set or not.
* @return bool True if a custom header is set. False if not.
function has_custom_header() {
if ( has_header_image() || ( has_header_video() && is_header_video_active() ) ) {
* Checks whether the custom header video is eligible to show on the current page.
* @return bool True if the custom header video should be shown. False if not.
function is_header_video_active() {
if ( ! get_theme_support( 'custom-header', 'video' ) ) {
$video_active_cb = get_theme_support( 'custom-header', 'video-active-callback' );
if ( empty( $video_active_cb ) || ! is_callable( $video_active_cb ) ) {
$show_video = call_user_func( $video_active_cb );
* Filters whether the custom header video is eligible to show on the current page.
* @param bool $show_video Whether the custom header video should be shown. Returns the value
* of the theme setting for the `custom-header`'s `video-active-callback`.
* If no callback is set, the default value is that of `is_front_page()`.
return apply_filters( 'is_header_video_active', $show_video );
* Retrieves the markup for a custom header.
* The container div will always be returned in the Customizer preview.
* @return string The markup for a custom header on success.
function get_custom_header_markup() {
if ( ! has_custom_header() && ! is_customize_preview() ) {
'<div id="wp-custom-header" class="wp-custom-header">%s</div>',
* Prints the markup for a custom header.
* A container div will always be printed in the Customizer preview.
function the_custom_header_markup() {
$custom_header = get_custom_header_markup();
if ( empty( $custom_header ) ) {
if ( is_header_video_active() && ( has_header_video() || is_customize_preview() ) ) {
wp_enqueue_script( 'wp-custom-header' );
wp_localize_script( 'wp-custom-header', '_wpCustomHeaderSettings', get_header_video_settings() );
* Retrieves background image for custom background.
function get_background_image() {
return get_theme_mod( 'background_image', get_theme_support( 'custom-background', 'default-image' ) );
* Displays background image path.
function background_image() {
echo get_background_image();
* Retrieves value for custom background color.
function get_background_color() {
return get_theme_mod( 'background_color', get_theme_support( 'custom-background', 'default-color' ) );
* Displays background color value.
function background_color() {
echo get_background_color();
* Default custom background callback.
function _custom_background_cb() {
// $background is the saved custom image, or the default image.
$background = set_url_scheme( get_background_image() );
* $color is the saved custom color.
* A default has to be specified in style.css. It will not be printed here.
$color = get_background_color();
if ( get_theme_support( 'custom-background', 'default-color' ) === $color ) {
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
if ( ! $background && ! $color ) {
if ( is_customize_preview() ) {
printf( '<style%s id="custom-background-css"></style>', $type_attr );
$style = $color ? 'background-color: ' . maybe_hash_hex_color( $color ) . ';' : '';
$image = ' background-image: url("' . sanitize_url( $background ) . '");';
$position_x = get_theme_mod( 'background_position_x', get_theme_support( 'custom-background', 'default-position-x' ) );
$position_y = get_theme_mod( 'background_position_y', get_theme_support( 'custom-background', 'default-position-y' ) );
if ( ! in_array( $position_x, array( 'left', 'center', 'right' ), true ) ) {
if ( ! in_array( $position_y, array( 'top', 'center', 'bottom' ), true ) ) {
$position = " background-position: $position_x $position_y;";
$size = get_theme_mod( 'background_size', get_theme_support( 'custom-background', 'default-size' ) );
if ( ! in_array( $size, array( 'auto', 'contain', 'cover' ), true ) ) {
$size = " background-size: $size;";
$repeat = get_theme_mod( 'background_repeat', get_theme_support( 'custom-background', 'default-repeat' ) );
if ( ! in_array( $repeat, array( 'repeat-x', 'repeat-y', 'repeat', 'no-repeat' ), true ) ) {
$repeat = " background-repeat: $repeat;";
$attachment = get_theme_mod( 'background_attachment', get_theme_support( 'custom-background', 'default-attachment' ) );
if ( 'fixed' !== $attachment ) {
$attachment = " background-attachment: $attachment;";
$style .= $image . $position . $size . $repeat . $attachment;
<style<?php echo $type_attr; ?> id="custom-background-css">
body.custom-background { <?php echo trim( $style ); ?> }
* Renders the Custom CSS style element.
function wp_custom_css_cb() {
$styles = wp_get_custom_css();
if ( $styles || is_customize_preview() ) :
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
<style<?php echo $type_attr; ?> id="wp-custom-css">
// Note that esc_html() cannot be used because `div > span` is not interpreted properly.
echo strip_tags( $styles );
* Fetches the `custom_css` post for a given theme.
* @param string $stylesheet Optional. A theme object stylesheet name. Defaults to the active theme.
* @return WP_Post|null The custom_css post or null if none exists.
function wp_get_custom_css_post( $stylesheet = '' ) {
if ( empty( $stylesheet ) ) {
$stylesheet = get_stylesheet();
$custom_css_query_vars = array(
'post_type' => 'custom_css',
'post_status' => get_post_stati(),
'name' => sanitize_title( $stylesheet ),