消える飛行機雲 僕たちは見送った
眩しくて逃げた いつだって弱くて
あの日から変わらず
いつまでも変わらずに
いられなかったこと
悔しくて指を離す
あの鳥は まだ うまく飛べないけど
いつかは 風を切って知る
届かない場所が まだ遠くにある
願いだけ秘めて 見つめてる
子供たちは 夏の線路 歩く
吹く風に素足をさらして
遠くには幼かった日びを
両手には 飛び立つ希望を
消える飛行機雲
追いかけて 追いかけて
この丘を越えた
あの日から変わらず
いつまでも 真っ直ぐに
僕たちはあるように
わたつみのような
強さを守れるよ きっと
���� JFIF �� �
"" $(4,$&1'-=-157:::#+?D?8C49:7
7%%77777777777777777777777777777777777777777777777777�� { �" �� �� 5 !1AQa"q�2��BR��#b������� �� �� ? ��D@DDD@DDD@DDkK��6 �UG�4V�1��
�����릟�@�#���RY�dqp�
����� �o�7�m�s�<��VPS�e~V�چ8���X�T��$��c�� 9��ᘆ�m6@ WU�f�Don��r��5}9��}��hc�fF��/r=hi�� �͇�*�� b�.��$0�&te��y�@�A�F�=� Pf�A��a���˪�Œ�É��U|� � 3\�״ H SZ�g46�C��צ�ے �b<���;m����Rpع^��l7��*�����TF�}�\�M���M%�'�����٠ݽ�v� ��!-�����?�N!La��A+[`#���M����'�~oR�?��v^)��=��h����A��X�.���˃����^Æï¿½ï¿½Ü¯sO"B�c>;
�e�4��5�k��/CB��.
�J?��;�҈�������������������~�<�VZ�ê¼2/)Í”jC���ע�V�G�!���!�F������\�� Kj�R�oc�h���:Þ I��1"2�q×°8��Р@ז���_C0�ր��A��lQ��@纼�!7��F�� �]�sZ
B�62r�v�z~�K�7�c��5�.���ӄq&�Z�d�<�kk���T&8�|���I���� Ws}���ǽ�cqnΑ�_���3��|N�-y,��i���ȗ_�\60���@��6����D@DDD@DDD@DDD@DDD@DDc�KN66<�c��64=r�����
Ď0��h���t&(�hnb[� ?��^��\��â|�,�/h�\��R��5�?
�0�!צ܉-����G����٬��Q�zA���1�����V��� �:R���`�$��ik��H����D4�����#dk����� h�}����7���w%�������*o8wG�LycuT�.���ܯ7��I��u^���)��/c�,s�Nq�ۺ�;�ך�YH2���.5B���DDD@DDD@DDD@DDD@DDD@V|�a�j{7c��X�F\�3MuA׾hb� ��n��F������ ��8�(��e����Pp�\"G�`s��m��ާaW�K��O����|;ei����֋�[�q��";a��1����Y�G�W/�߇�&�<���Ќ�H'q�m���)�X+!���=�m�ۚ丷~6a^X�)���,�>#&6G���Y��{����"" """ """ """ """ ""��at\/�a�8 �yp%�lhl�n����)���i�t��B�������������?�� $value ) {
$html .= ' ' . $name . '="' . $value . '"';
}
$html .= ' />';
/**
* Filters the markup of header images.
*
* @since 4.4.0
*
* @param string $html The HTML image tag markup being filtered.
* @param object $header The custom header object returned by 'get_custom_header()'.
* @param array $attr Array of the attributes for the image tag.
*/
return apply_filters( 'get_header_image_tag', $html, $header, $attr );
}
/**
* Displays the image markup for a custom header image.
*
* @since 4.4.0
*
* @param array $attr Optional. Attributes for the image markup. Default empty.
*/
function the_header_image_tag( $attr = array() ) {
echo get_header_image_tag( $attr );
}
/**
* Gets random header image data from registered images in theme.
*
* @since 3.4.0
*
* @access private
*
* @global array $_wp_default_headers
*
* @return object
*/
function _get_random_header_data() {
global $_wp_default_headers;
static $_wp_random_header = null;
if ( empty( $_wp_random_header ) ) {
$header_image_mod = get_theme_mod( 'header_image', '' );
$headers = array();
if ( 'random-uploaded-image' === $header_image_mod ) {
$headers = get_uploaded_header_images();
} elseif ( ! empty( $_wp_default_headers ) ) {
if ( 'random-default-image' === $header_image_mod ) {
$headers = $_wp_default_headers;
} else {
if ( current_theme_supports( 'custom-header', 'random-default' ) ) {
$headers = $_wp_default_headers;
}
}
}
if ( empty( $headers ) ) {
return new stdClass();
}
$_wp_random_header = (object) $headers[ array_rand( $headers ) ];
$_wp_random_header->url = sprintf(
$_wp_random_header->url,
get_template_directory_uri(),
get_stylesheet_directory_uri()
);
$_wp_random_header->thumbnail_url = sprintf(
$_wp_random_header->thumbnail_url,
get_template_directory_uri(),
get_stylesheet_directory_uri()
);
}
return $_wp_random_header;
}
/**
* Gets random header image URL from registered images in theme.
*
* @since 3.2.0
*
* @return string Path to header image.
*/
function get_random_header_image() {
$random_image = _get_random_header_data();
if ( empty( $random_image->url ) ) {
return '';
}
return $random_image->url;
}
/**
* Checks if random header image is in use.
*
* Always true if user expressly chooses the option in Appearance > Header.
* Also true if theme has multiple header images registered, no specific header image
* is chosen, and theme turns on random headers with add_theme_support().
*
* @since 3.2.0
*
* @param string $type The random pool to use. Possible values include 'any',
* 'default', 'uploaded'. Default 'any'.
* @return bool
*/
function is_random_header_image( $type = 'any' ) {
$header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
if ( 'any' === $type ) {
if ( 'random-default-image' === $header_image_mod
|| 'random-uploaded-image' === $header_image_mod
|| ( empty( $header_image_mod ) && '' !== get_random_header_image() )
) {
return true;
}
} else {
if ( "random-$type-image" === $header_image_mod ) {
return true;
} elseif ( 'default' === $type
&& empty( $header_image_mod ) && '' !== get_random_header_image()
) {
return true;
}
}
return false;
}
/**
* Displays header image URL.
*
* @since 2.1.0
*/
function header_image() {
$image = get_header_image();
if ( $image ) {
echo esc_url( $image );
}
}
/**
* Gets the header images uploaded for the active theme.
*
* @since 3.2.0
*
* @return array
*/
function get_uploaded_header_images() {
$header_images = array();
$headers = get_posts(
array(
'post_type' => 'attachment',
'meta_key' => '_wp_attachment_is_custom_header',
'meta_value' => get_option( 'stylesheet' ),
'orderby' => 'none',
'nopaging' => true,
)
);
if ( empty( $headers ) ) {
return array();
}
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 );
$header_images[ $header_index ]['attachment_parent'] = $header_data['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'];
}
}
return $header_images;
}
/**
* Gets the header image data.
*
* @since 3.4.0
*
* @global array $_wp_default_headers
*
* @return object
*/
function get_custom_header() {
global $_wp_default_headers;
if ( is_random_header_image() ) {
$data = _get_random_header_data();
} else {
$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 = array();
$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 = $default_header;
$data['url'] = $url;
$data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args );
break;
}
}
}
}
}
$default = array(
'url' => '',
'thumbnail_url' => '',
'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.
*
* @since 3.0.0
*
* @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()
* @since 3.0.0
*
* @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 ] );
return true;
} else {
return false;
}
}
/**
* Checks 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();
}
/**
* Retrieves header video URL for custom header.
*
* Uses a local video if present, or falls back to an external video.
*
* @since 4.7.0
*
* @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' ) );
if ( $id ) {
// Get the file URL from the attachment ID.
$url = wp_get_attachment_url( $id );
} else {
$url = get_theme_mod( 'external_header_video' );
}
/**
* Filters the header video URL.
*
* @since 4.7.3
*
* @param string $url Header video URL, if available.
*/
$url = apply_filters( 'get_header_video_url', $url );
if ( ! $id && ! $url ) {
return false;
}
return sanitize_url( set_url_scheme( $url ) );
}
/**
* Displays header video URL.
*
* @since 4.7.0
*/
function the_header_video_url() {
$video = get_header_video_url();
if ( $video ) {
echo esc_url( $video );
}
}
/**
* Retrieves 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,
'l10n' => array(
'pause' => __( 'Pause' ),
'play' => __( 'Play' ),
'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.
*
* @since 4.7.0
*
* @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.
*
* @since 4.7.0
*
* @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() ) ) {
return true;
}
return false;
}
/**
* Checks whether the custom header video is eligible to show on the current page.
*
* @since 4.7.0
*
* @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' ) ) {
return false;
}
$video_active_cb = get_theme_support( 'custom-header', 'video-active-callback' );
if ( empty( $video_active_cb ) || ! is_callable( $video_active_cb ) ) {
$show_video = true;
} else {
$show_video = call_user_func( $video_active_cb );
}
/**
* Filters whether the custom header video is eligible to show on the current page.
*
* @since 4.7.0
*
* @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.
*
* @since 4.7.0
*
* @return string The markup for a custom header on success.
*/
function get_custom_header_markup() {
if ( ! has_custom_header() && ! is_customize_preview() ) {
return '';
}
return sprintf(
'
* add_filter( 'customize_value_custom_css', function( $value, $setting ) {
* $post = wp_get_custom_css_post( $setting->stylesheet );
* if ( $post && ! empty( $post->post_content_filtered ) ) {
* $css = $post->post_content_filtered;
* }
* return $css;
* }, 10, 2 );
*
*
* @since 4.7.0
* @param array $data {
* Custom CSS data.
*
* @type string $css CSS stored in `post_content`.
* @type string $preprocessed Pre-processed CSS stored in `post_content_filtered`.
* Normally empty string.
* }
* @param array $args {
* The args passed into `wp_update_custom_css_post()` merged with defaults.
*
* @type string $css The original CSS passed in to be updated.
* @type string $preprocessed The original preprocessed CSS passed in to be updated.
* @type string $stylesheet The stylesheet (theme) being updated.
* }
*/
$data = apply_filters( 'update_custom_css_data', $data, array_merge( $args, compact( 'css' ) ) );
$post_data = array(
'post_title' => $args['stylesheet'],
'post_name' => sanitize_title( $args['stylesheet'] ),
'post_type' => 'custom_css',
'post_status' => 'publish',
'post_content' => $data['css'],
'post_content_filtered' => $data['preprocessed'],
);
// Update post if it already exists, otherwise create a new one.
$post = wp_get_custom_css_post( $args['stylesheet'] );
if ( $post ) {
$post_data['ID'] = $post->ID;
$r = wp_update_post( wp_slash( $post_data ), true );
} else {
$r = wp_insert_post( wp_slash( $post_data ), true );
if ( ! is_wp_error( $r ) ) {
if ( get_stylesheet() === $args['stylesheet'] ) {
set_theme_mod( 'custom_css_post_id', $r );
}
// Trigger creation of a revision. This should be removed once #30854 is resolved.
$revisions = wp_get_latest_revision_id_and_total_count( $r );
if ( ! is_wp_error( $revisions ) && 0 === $revisions['count'] ) {
wp_save_post_revision( $r );
}
}
}
if ( is_wp_error( $r ) ) {
return $r;
}
return get_post( $r );
}
/**
* Adds callback for custom TinyMCE editor stylesheets.
*
* The parameter $stylesheet is the name of the stylesheet, relative to
* the theme root. It also accepts an array of stylesheets.
* It is optional and defaults to 'editor-style.css'.
*
* This function automatically adds another stylesheet with -rtl prefix, e.g. editor-style-rtl.css.
* If that file doesn't exist, it is removed before adding the stylesheet(s) to TinyMCE.
* If an array of stylesheets is passed to add_editor_style(),
* RTL is only added for the first stylesheet.
*
* Since version 3.4 the TinyMCE body has .rtl CSS class.
* It is a better option to use that class and add any RTL styles to the main stylesheet.
*
* @since 3.0.0
*
* @global array $editor_styles
*
* @param array|string $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
* Defaults to 'editor-style.css'
*/
function add_editor_style( $stylesheet = 'editor-style.css' ) {
global $editor_styles;
add_theme_support( 'editor-style' );
$editor_styles = (array) $editor_styles;
$stylesheet = (array) $stylesheet;
if ( is_rtl() ) {
$rtl_stylesheet = str_replace( '.css', '-rtl.css', $stylesheet[0] );
$stylesheet[] = $rtl_stylesheet;
}
$editor_styles = array_merge( $editor_styles, $stylesheet );
}
/**
* Removes all visual editor stylesheets.
*
* @since 3.1.0
*
* @global array $editor_styles
*
* @return bool True on success, false if there were no stylesheets to remove.
*/
function remove_editor_styles() {
if ( ! current_theme_supports( 'editor-style' ) ) {
return false;
}
_remove_theme_support( 'editor-style' );
if ( is_admin() ) {
$GLOBALS['editor_styles'] = array();
}
return true;
}
/**
* Retrieves any registered editor stylesheet URLs.
*
* @since 4.0.0
*
* @global array $editor_styles Registered editor stylesheets
*
* @return string[] If registered, a list of editor stylesheet URLs.
*/
function get_editor_stylesheets() {
$stylesheets = array();
// Load editor_style.css if the active theme supports it.
if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
$editor_styles = $GLOBALS['editor_styles'];
$editor_styles = array_unique( array_filter( $editor_styles ) );
$style_uri = get_stylesheet_directory_uri();
$style_dir = get_stylesheet_directory();
// Support externally referenced styles (like, say, fonts).
foreach ( $editor_styles as $key => $file ) {
if ( preg_match( '~^(https?:)?//~', $file ) ) {
$stylesheets[] = sanitize_url( $file );
unset( $editor_styles[ $key ] );
}
}
// Look in a parent theme first, that way child theme CSS overrides.
if ( is_child_theme() ) {
$template_uri = get_template_directory_uri();
$template_dir = get_template_directory();
foreach ( $editor_styles as $key => $file ) {
if ( $file && file_exists( "$template_dir/$file" ) ) {
$stylesheets[] = "$template_uri/$file";
}
}
}
foreach ( $editor_styles as $file ) {
if ( $file && file_exists( "$style_dir/$file" ) ) {
$stylesheets[] = "$style_uri/$file";
}
}
}
/**
* Filters the array of URLs of stylesheets applied to the editor.
*
* @since 4.3.0
*
* @param string[] $stylesheets Array of URLs of stylesheets to be applied to the editor.
*/
return apply_filters( 'editor_stylesheets', $stylesheets );
}
/**
* Expands a theme's starter content configuration using core-provided data.
*
* @since 4.7.0
*
* @return array Array of starter content.
*/
function get_theme_starter_content() {
$theme_support = get_theme_support( 'starter-content' );
if ( is_array( $theme_support ) && ! empty( $theme_support[0] ) && is_array( $theme_support[0] ) ) {
$config = $theme_support[0];
} else {
$config = array();
}
$core_content = array(
'widgets' => array(
'text_business_info' => array(
'text',
array(
'title' => _x( 'Find Us', 'Theme starter content' ),
'text' => implode(
'',
array(
'' . _x( 'Address', 'Theme starter content' ) . "\n",
_x( '123 Main Street', 'Theme starter content' ) . "\n",
_x( 'New York, NY 10001', 'Theme starter content' ) . "\n\n",
'' . _x( 'Hours', 'Theme starter content' ) . "\n",
_x( 'Monday–Friday: 9:00AM–5:00PM', 'Theme starter content' ) . "\n",
_x( 'Saturday & Sunday: 11:00AM–3:00PM', 'Theme starter content' ),
)
),
'filter' => true,
'visual' => true,
),
),
'text_about' => array(
'text',
array(
'title' => _x( 'About This Site', 'Theme starter content' ),
'text' => _x( 'This may be a good place to introduce yourself and your site or include some credits.', 'Theme starter content' ),
'filter' => true,
'visual' => true,
),
),
'archives' => array(
'archives',
array(
'title' => _x( 'Archives', 'Theme starter content' ),
),
),
'calendar' => array(
'calendar',
array(
'title' => _x( 'Calendar', 'Theme starter content' ),
),
),
'categories' => array(
'categories',
array(
'title' => _x( 'Categories', 'Theme starter content' ),
),
),
'meta' => array(
'meta',
array(
'title' => _x( 'Meta', 'Theme starter content' ),
),
),
'recent-comments' => array(
'recent-comments',
array(
'title' => _x( 'Recent Comments', 'Theme starter content' ),
),
),
'recent-posts' => array(
'recent-posts',
array(
'title' => _x( 'Recent Posts', 'Theme starter content' ),
),
),
'search' => array(
'search',
array(
'title' => _x( 'Search', 'Theme starter content' ),
),
),
),
'nav_menus' => array(
'link_home' => array(
'type' => 'custom',
'title' => _x( 'Home', 'Theme starter content' ),
'url' => home_url( '/' ),
),
'page_home' => array( // Deprecated in favor of 'link_home'.
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{home}}',
),
'page_about' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{about}}',
),
'page_blog' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{blog}}',
),
'page_news' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{news}}',
),
'page_contact' => array(
'type' => 'post_type',
'object' => 'page',
'object_id' => '{{contact}}',
),
'link_email' => array(
'title' => _x( 'Email', 'Theme starter content' ),
'url' => 'mailto:wordpress@example.com',
),
'link_facebook' => array(
'title' => _x( 'Facebook', 'Theme starter content' ),
'url' => 'https://www.facebook.com/wordpress',
),
'link_foursquare' => array(
'title' => _x( 'Foursquare', 'Theme starter content' ),
'url' => 'https://foursquare.com/',
),
'link_github' => array(
'title' => _x( 'GitHub', 'Theme starter content' ),
'url' => 'https://github.com/wordpress/',
),
'link_instagram' => array(
'title' => _x( 'Instagram', 'Theme starter content' ),
'url' => 'https://www.instagram.com/explore/tags/wordcamp/',
),
'link_linkedin' => array(
'title' => _x( 'LinkedIn', 'Theme starter content' ),
'url' => 'https://www.linkedin.com/company/1089783',
),
'link_pinterest' => array(
'title' => _x( 'Pinterest', 'Theme starter content' ),
'url' => 'https://www.pinterest.com/',
),
'link_twitter' => array(
'title' => _x( 'Twitter', 'Theme starter content' ),
'url' => 'https://twitter.com/wordpress',
),
'link_yelp' => array(
'title' => _x( 'Yelp', 'Theme starter content' ),
'url' => 'https://www.yelp.com',
),
'link_youtube' => array(
'title' => _x( 'YouTube', 'Theme starter content' ),
'url' => 'https://www.youtube.com/channel/UCdof4Ju7amm1chz1gi1T2ZA',
),
),
'posts' => array(
'home' => array(
'post_type' => 'page',
'post_title' => _x( 'Home', 'Theme starter content' ),
'post_content' => sprintf(
"\n
%s
\n", _x( 'Welcome to your site! This is your homepage, which is what most visitors will see when they come to your site for the first time.', 'Theme starter content' ) ), ), 'about' => array( 'post_type' => 'page', 'post_title' => _x( 'About', 'Theme starter content' ), 'post_content' => sprintf( "\n%s
\n", _x( 'You might be an artist who would like to introduce yourself and your work here or maybe you are a business with a mission to describe.', 'Theme starter content' ) ), ), 'contact' => array( 'post_type' => 'page', 'post_title' => _x( 'Contact', 'Theme starter content' ), 'post_content' => sprintf( "\n%s
\n", _x( 'This is a page with some basic contact information, such as an address and phone number. You might also try a plugin to add a contact form.', 'Theme starter content' ) ), ), 'blog' => array( 'post_type' => 'page', 'post_title' => _x( 'Blog', 'Theme starter content' ), ), 'news' => array( 'post_type' => 'page', 'post_title' => _x( 'News', 'Theme starter content' ), ), 'homepage-section' => array( 'post_type' => 'page', 'post_title' => _x( 'A homepage section', 'Theme starter content' ), 'post_content' => sprintf( "\n%s
\n", _x( 'This is an example of a homepage section. Homepage sections can be any page other than the homepage itself, including the page that shows your latest blog posts.', 'Theme starter content' ) ), ), ), ); $content = array(); foreach ( $config as $type => $args ) { switch ( $type ) { // Use options and theme_mods as-is. case 'options': case 'theme_mods': $content[ $type ] = $config[ $type ]; break; // Widgets are grouped into sidebars. case 'widgets': foreach ( $config[ $type ] as $sidebar_id => $widgets ) { foreach ( $widgets as $id => $widget ) { if ( is_array( $widget ) ) { // Item extends core content. if ( ! empty( $core_content[ $type ][ $id ] ) ) { $widget = array( $core_content[ $type ][ $id ][0], array_merge( $core_content[ $type ][ $id ][1], $widget ), ); } $content[ $type ][ $sidebar_id ][] = $widget; } elseif ( is_string( $widget ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $widget ] ) ) { $content[ $type ][ $sidebar_id ][] = $core_content[ $type ][ $widget ]; } } } break; // And nav menu items are grouped into nav menus. case 'nav_menus': foreach ( $config[ $type ] as $nav_menu_location => $nav_menu ) { // Ensure nav menus get a name. if ( empty( $nav_menu['name'] ) ) { $nav_menu['name'] = $nav_menu_location; } $content[ $type ][ $nav_menu_location ]['name'] = $nav_menu['name']; foreach ( $nav_menu['items'] as $id => $nav_menu_item ) { if ( is_array( $nav_menu_item ) ) { // Item extends core content. if ( ! empty( $core_content[ $type ][ $id ] ) ) { $nav_menu_item = array_merge( $core_content[ $type ][ $id ], $nav_menu_item ); } $content[ $type ][ $nav_menu_location ]['items'][] = $nav_menu_item; } elseif ( is_string( $nav_menu_item ) && ! empty( $core_content[ $type ] ) && ! empty( $core_content[ $type ][ $nav_menu_item ] ) ) { $content[ $type ][ $nav_menu_location ]['items'][] = $core_content[ $type ][ $nav_menu_item ]; } } } break; // Attachments are posts but have special treatment. case 'attachments': foreach ( $config[ $type ] as $id => $item ) { if ( ! empty( $item['file'] ) ) { $content[ $type ][ $id ] = $item; } } break; /* * All that's left now are posts (besides attachments). * Not a default case for the sake of clarity and future work. */ case 'posts': foreach ( $config[ $type ] as $id => $item ) { if ( is_array( $item ) ) { // Item extends core content. if ( ! empty( $core_content[ $type ][ $id ] ) ) { $item = array_merge( $core_content[ $type ][ $id ], $item ); } // Enforce a subset of fields. $content[ $type ][ $id ] = wp_array_slice_assoc( $item, array( 'post_type', 'post_title', 'post_excerpt', 'post_name', 'post_content', 'menu_order', 'comment_status', 'thumbnail', 'template', ) ); } elseif ( is_string( $item ) && ! empty( $core_content[ $type ][ $item ] ) ) { $content[ $type ][ $item ] = $core_content[ $type ][ $item ]; } } break; } } /** * Filters the expanded array of starter content. * * @since 4.7.0 * * @param array $content Array of starter content. * @param array $config Array of theme-specific starter content configuration. */ return apply_filters( 'get_theme_starter_content', $content, $config ); } /** * Registers theme support for a given feature. * * Must be called in the theme's functions.php file to work. * If attached to a hook, it must be {@see 'after_setup_theme'}. * The {@see 'init'} hook may be too late for some features. * * Example usage: * * add_theme_support( 'title-tag' ); * add_theme_support( 'custom-logo', array( * 'height' => 480, * 'width' => 720, * ) ); * * @since 2.9.0 * @since 3.4.0 The `custom-header-uploads` feature was deprecated. * @since 3.6.0 The `html5` feature was added. * @since 3.6.1 The `html5` feature requires an array of types to be passed. Defaults to * 'comment-list', 'comment-form', 'search-form' for backward compatibility. * @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'. * @since 4.1.0 The `title-tag` feature was added. * @since 4.5.0 The `customize-selective-refresh-widgets` feature was added. * @since 4.7.0 The `starter-content` feature was added. * @since 5.0.0 The `responsive-embeds`, `align-wide`, `dark-editor-style`, `disable-custom-colors`, * `disable-custom-font-sizes`, `editor-color-palette`, `editor-font-sizes`, * `editor-styles`, and `wp-block-styles` features were added. * @since 5.3.0 The `html5` feature now also accepts 'script' and 'style'. * @since 5.3.0 Formalized the existing and already documented `...$args` parameter * by adding it to the function signature. * @since 5.4.0 The `disable-custom-gradients` feature limits to default gradients or gradients added * through `editor-gradient-presets` theme support. * @since 5.5.0 The `core-block-patterns` feature was added and is enabled by default. * @since 5.5.0 The `custom-logo` feature now also accepts 'unlink-homepage-logo'. * @since 5.6.0 The `post-formats` feature warns if no array is passed as the second parameter. * @since 5.8.0 The `widgets-block-editor` feature enables the Widgets block editor. * @since 5.8.0 The `block-templates` feature indicates whether a theme uses block-based templates. * @since 6.0.0 The `html5` feature warns if no array is passed as the second parameter. * @since 6.1.0 The `block-template-parts` feature allows to edit any reusable template part from site editor. * @since 6.1.0 The `disable-layout-styles` feature disables the default layout styles. * @since 6.3.0 The `link-color` feature allows to enable the link color setting. * @since 6.3.0 The `border` feature allows themes without theme.json to add border styles to blocks. * @since 6.5.0 The `appearance-tools` feature enables a few design tools for blocks, * see `WP_Theme_JSON::APPEARANCE_TOOLS_OPT_INS` for a complete list. * @since 6.6.0 The `editor-spacing-sizes` feature was added. * @since 7.0.0 The `html5` feature's 'script' and 'style' arguments are deprecated and unused. * * @global array $_wp_theme_features * * @param string $feature The feature being added. Likely core values include: * - 'admin-bar' * - 'align-wide' * - 'appearance-tools' * - 'automatic-feed-links' * - 'block-templates' * - 'block-template-parts' * - 'border' * - 'core-block-patterns' * - 'custom-background' * - 'custom-header' * - 'custom-line-height' * - 'custom-logo' * - 'customize-selective-refresh-widgets' * - 'custom-spacing' * - 'custom-units' * - 'dark-editor-style' * - 'disable-custom-colors' * - 'disable-custom-font-sizes' * - 'disable-custom-gradients' * - 'disable-layout-styles' * - 'editor-color-palette' * - 'editor-gradient-presets' * - 'editor-font-sizes' * - 'editor-spacing-sizes' * - 'editor-styles' * - 'featured-content' * - 'html5' * - 'link-color' * - 'menus' * - 'post-formats' * - 'post-thumbnails' * - 'responsive-embeds' * - 'starter-content' * - 'title-tag' * - 'widgets' * - 'widgets-block-editor' * - 'wp-block-styles' * @param mixed ...$args Optional extra arguments to pass along with certain features. * @return void|false Void on success, false on failure. */ function add_theme_support( $feature, ...$args ) { global $_wp_theme_features; if ( ! $args ) { $args = true; } switch ( $feature ) { case 'post-thumbnails': // All post types are already supported. if ( true === get_theme_support( 'post-thumbnails' ) ) { return; } /* * Merge post types with any that already declared their support * for post thumbnails. */ if ( isset( $args[0] ) && is_array( $args[0] ) && isset( $_wp_theme_features['post-thumbnails'] ) ) { $args[0] = array_unique( array_merge( $_wp_theme_features['post-thumbnails'][0], $args[0] ) ); } break; case 'post-formats': if ( isset( $args[0] ) && is_array( $args[0] ) ) { $post_formats = get_post_format_slugs(); unset( $post_formats['standard'] ); $args[0] = array_intersect( $args[0], array_keys( $post_formats ) ); } else { _doing_it_wrong( "add_theme_support( 'post-formats' )", __( 'You need to pass an array of post formats.' ), '5.6.0' ); return false; } break; case 'html5': // You can't just pass 'html5', you need to pass an array of types. if ( empty( $args[0] ) || ! is_array( $args[0] ) ) { _doing_it_wrong( "add_theme_support( 'html5' )", __( 'You need to pass an array of types.' ), '3.6.1' ); if ( ! empty( $args[0] ) && ! is_array( $args[0] ) ) { return false; } // Build an array of types for back-compat. $args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) ); } // Calling 'html5' again merges, rather than overwrites. if ( isset( $_wp_theme_features['html5'] ) ) { $args[0] = array_merge( $_wp_theme_features['html5'][0], $args[0] ); } break; case 'custom-logo': if ( true === $args ) { $args = array( 0 => array() ); } $defaults = array( 'width' => null, 'height' => null, 'flex-width' => false, 'flex-height' => false, 'header-text' => '', 'unlink-homepage-logo' => false, ); $args[0] = wp_parse_args( array_intersect_key( $args[0], $defaults ), $defaults ); // Allow full flexibility if no size is specified. if ( is_null( $args[0]['width'] ) && is_null( $args[0]['height'] ) ) { $args[0]['flex-width'] = true; $args[0]['flex-height'] = true; } break; case 'custom-header-uploads': return add_theme_support( 'custom-header', array( 'uploads' => true ) ); case 'custom-header': if ( true === $args ) { $args = array( 0 => array() ); } $defaults = array( 'default-image' => '', 'random-default' => false, 'width' => 0, 'height' => 0, 'flex-height' => false, 'flex-width' => false, 'default-text-color' => '', 'header-text' => true, 'uploads' => true, 'wp-head-callback' => '', 'admin-head-callback' => '', 'admin-preview-callback' => '', 'video' => false, 'video-active-callback' => 'is_front_page', ); $jit = isset( $args[0]['__jit'] ); unset( $args[0]['__jit'] ); /* * Merge in data from previous add_theme_support() calls. * The first value registered wins. (A child theme is set up first.) */ if ( isset( $_wp_theme_features['custom-header'] ) ) { $args[0] = wp_parse_args( $_wp_theme_features['custom-header'][0], $args[0] ); } /* * Load in the defaults at the end, as we need to insure first one wins. * This will cause all constants to be defined, as each arg will then be set to the default. */ if ( $jit ) { $args[0] = wp_parse_args( $args[0], $defaults ); } /* * If a constant was defined, use that value. Otherwise, define the constant to ensure * the constant is always accurate (and is not defined later, overriding our value). * As stated above, the first value wins. * Once we get to wp_loaded (just-in-time), define any constants we haven't already. * Constants should be avoided. Don't reference them. This is just for backward compatibility. */ if ( defined( 'NO_HEADER_TEXT' ) ) { $args[0]['header-text'] = ! NO_HEADER_TEXT; } elseif ( isset( $args[0]['header-text'] ) ) { define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) ); } if ( defined( 'HEADER_IMAGE_WIDTH' ) ) { $args[0]['width'] = (int) HEADER_IMAGE_WIDTH; } elseif ( isset( $args[0]['width'] ) ) { define( 'HEADER_IMAGE_WIDTH', (int) $args[0]['width'] ); } if ( defined( 'HEADER_IMAGE_HEIGHT' ) ) { $args[0]['height'] = (int) HEADER_IMAGE_HEIGHT; } elseif ( isset( $args[0]['height'] ) ) { define( 'HEADER_IMAGE_HEIGHT', (int) $args[0]['height'] ); } if ( defined( 'HEADER_TEXTCOLOR' ) ) { $args[0]['default-text-color'] = HEADER_TEXTCOLOR; } elseif ( isset( $args[0]['default-text-color'] ) ) { define( 'HEADER_TEXTCOLOR', $args[0]['default-text-color'] ); } if ( defined( 'HEADER_IMAGE' ) ) { $args[0]['default-image'] = HEADER_IMAGE; } elseif ( isset( $args[0]['default-image'] ) ) { define( 'HEADER_IMAGE', $args[0]['default-image'] ); } if ( $jit && ! empty( $args[0]['default-image'] ) ) { $args[0]['random-default'] = false; } /* * If headers are supported, and we still don't have a defined width or height, * we have implicit flex sizes. */ if ( $jit ) { if ( empty( $args[0]['width'] ) && empty( $args[0]['flex-width'] ) ) { $args[0]['flex-width'] = true; } if ( empty( $args[0]['height'] ) && empty( $args[0]['flex-height'] ) ) { $args[0]['flex-height'] = true; } } break; case 'custom-background': if ( true === $args ) { $args = array( 0 => array() ); } $defaults = array( 'default-image' => '', 'default-preset' => 'default', 'default-position-x' => 'left', 'default-position-y' => 'top', 'default-size' => 'auto', 'default-repeat' => 'repeat', 'default-attachment' => 'scroll', 'default-color' => '', 'wp-head-callback' => '_custom_background_cb', 'admin-head-callback' => '', 'admin-preview-callback' => '', ); $jit = isset( $args[0]['__jit'] ); unset( $args[0]['__jit'] ); // Merge in data from previous add_theme_support() calls. The first value registered wins. if ( isset( $_wp_theme_features['custom-background'] ) ) { $args[0] = wp_parse_args( $_wp_theme_features['custom-background'][0], $args[0] ); } if ( $jit ) { $args[0] = wp_parse_args( $args[0], $defaults ); } if ( defined( 'BACKGROUND_COLOR' ) ) { $args[0]['default-color'] = BACKGROUND_COLOR; } elseif ( isset( $args[0]['default-color'] ) || $jit ) { define( 'BACKGROUND_COLOR', $args[0]['default-color'] ); } if ( defined( 'BACKGROUND_IMAGE' ) ) { $args[0]['default-image'] = BACKGROUND_IMAGE; } elseif ( isset( $args[0]['default-image'] ) || $jit ) { define( 'BACKGROUND_IMAGE', $args[0]['default-image'] ); } break; // Ensure that 'title-tag' is accessible in the admin. case 'title-tag': // Can be called in functions.php but must happen before wp_loaded, i.e. not in header.php. if ( did_action( 'wp_loaded' ) ) { _doing_it_wrong( "add_theme_support( 'title-tag' )", sprintf( /* translators: 1: title-tag, 2: wp_loaded */ __( 'Theme support for %1$s should be registered before the %2$s hook.' ), 'title-tag',
'wp_loaded'
),
'4.1.0'
);
return false;
}
}
$_wp_theme_features[ $feature ] = $args;
}
/**
* Registers the internal custom header and background routines.
*
* @since 3.4.0
* @access private
*
* @global Custom_Image_Header $custom_image_header
* @global Custom_Background $custom_background
*/
function _custom_header_background_just_in_time() {
global $custom_image_header, $custom_background;
if ( current_theme_supports( 'custom-header' ) ) {
// In case any constants were defined after an add_custom_image_header() call, re-run.
add_theme_support( 'custom-header', array( '__jit' => true ) );
$args = get_theme_support( 'custom-header' );
if ( $args[0]['wp-head-callback'] ) {
add_action( 'wp_head', $args[0]['wp-head-callback'] );
}
if ( is_admin() ) {
require_once ABSPATH . 'wp-admin/includes/class-custom-image-header.php';
$custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
}
}
if ( current_theme_supports( 'custom-background' ) ) {
// In case any constants were defined after an add_custom_background() call, re-run.
add_theme_support( 'custom-background', array( '__jit' => true ) );
$args = get_theme_support( 'custom-background' );
add_action( 'wp_head', $args[0]['wp-head-callback'] );
if ( is_admin() ) {
require_once ABSPATH . 'wp-admin/includes/class-custom-background.php';
$custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
}
}
}
/**
* Adds CSS to hide header text for custom logo, based on Customizer setting.
*
* @since 4.5.0
* @access private
*/
function _custom_logo_header_styles() {
if ( ! current_theme_supports( 'custom-header', 'header-text' )
&& get_theme_support( 'custom-logo', 'header-text' )
&& ! get_theme_mod( 'header_text', true )
) {
$classes = (array) get_theme_support( 'custom-logo', 'header-text' );
$classes = array_map( 'sanitize_html_class', $classes );
$classes = '.' . implode( ', .', $classes );
?>
false ) );
return true; // Do not continue - custom-header-uploads no longer exists.
}
if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
return false;
}
switch ( $feature ) {
case 'custom-header':
if ( ! did_action( 'wp_loaded' ) ) {
break;
}
$support = get_theme_support( 'custom-header' );
if ( isset( $support[0]['wp-head-callback'] ) ) {
remove_action( 'wp_head', $support[0]['wp-head-callback'] );
}
if ( isset( $GLOBALS['custom_image_header'] ) ) {
remove_action( 'admin_menu', array( $GLOBALS['custom_image_header'], 'init' ) );
unset( $GLOBALS['custom_image_header'] );
}
break;
case 'custom-background':
if ( ! did_action( 'wp_loaded' ) ) {
break;
}
$support = get_theme_support( 'custom-background' );
if ( isset( $support[0]['wp-head-callback'] ) ) {
remove_action( 'wp_head', $support[0]['wp-head-callback'] );
}
remove_action( 'admin_menu', array( $GLOBALS['custom_background'], 'init' ) );
unset( $GLOBALS['custom_background'] );
break;
}
unset( $_wp_theme_features[ $feature ] );
return true;
}
/**
* Checks a theme's support for a given feature.
*
* Example usage:
*
* current_theme_supports( 'custom-logo' );
* current_theme_supports( 'html5', 'comment-form' );
*
* @since 2.9.0
* @since 5.3.0 Formalized the existing and already documented `...$args` parameter
* by adding it to the function signature.
*
* @global array $_wp_theme_features
*
* @param string $feature The feature being checked. See add_theme_support() for the list
* of possible values.
* @param mixed ...$args Optional extra arguments to be checked against certain features.
* @return bool True if the active theme supports the feature, false otherwise.
*/
function current_theme_supports( $feature, ...$args ) {
global $_wp_theme_features;
if ( 'custom-header-uploads' === $feature ) {
return current_theme_supports( 'custom-header', 'uploads' );
}
if ( ! isset( $_wp_theme_features[ $feature ] ) ) {
return false;
}
// If no args passed then no extra checks need to be performed.
if ( ! $args ) {
/** This filter is documented in wp-includes/theme.php */
return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[ $feature ] ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
switch ( $feature ) {
case 'post-thumbnails':
/*
* post-thumbnails can be registered for only certain content/post types
* by passing an array of types to add_theme_support().
* If no array was passed, then any type is accepted.
*/
if ( true === $_wp_theme_features[ $feature ] ) { // Registered for all types.
return true;
}
$content_type = $args[0];
return in_array( $content_type, $_wp_theme_features[ $feature ][0], true );
case 'html5':
case 'post-formats':
/*
* Specific post formats can be registered by passing an array of types
* to add_theme_support().
*
* Specific areas of HTML5 support *must* be passed via an array to add_theme_support().
*/
$type = $args[0];
return in_array( $type, $_wp_theme_features[ $feature ][0], true );
case 'custom-logo':
case 'custom-header':
case 'custom-background':
// Specific capabilities can be registered by passing an array to add_theme_support().
return ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) && $_wp_theme_features[ $feature ][0][ $args[0] ] );
}
/**
* Filters whether the active theme supports a specific feature.
*
* The dynamic portion of the hook name, `$feature`, refers to the specific
* theme feature. See add_theme_support() for the list of possible values.
*
* @since 3.4.0
*
* @param bool $supports Whether the active theme supports the given feature. Default true.
* @param array $args Array of arguments for the feature.
* @param string $feature The theme feature.
*/
return apply_filters( "current_theme_supports-{$feature}", true, $args, $_wp_theme_features[ $feature ] ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
/**
* Checks a theme's support for a given feature before loading the functions which implement it.
*
* @since 2.9.0
*
* @param string $feature The feature being checked. See add_theme_support() for the list
* of possible values.
* @param string $file Path to the file.
* @return bool True if the active theme supports the supplied feature, false otherwise.
*/
function require_if_theme_supports( $feature, $file ) {
if ( current_theme_supports( $feature ) ) {
require $file;
return true;
}
return false;
}
/**
* Registers a theme feature for use in add_theme_support().
*
* This does not indicate that the active theme supports the feature, it only describes
* the feature's supported options.
*
* @since 5.5.0
*
* @see add_theme_support()
*
* @global array $_wp_registered_theme_features
*
* @param string $feature The name uniquely identifying the feature. See add_theme_support()
* for the list of possible values.
* @param array $args {
* Data used to describe the theme.
*
* @type string $type The type of data associated with this feature.
* Valid values are 'string', 'boolean', 'integer',
* 'number', 'array', and 'object'. Defaults to 'boolean'.
* @type bool $variadic Does this feature utilize the variadic support
* of add_theme_support(), or are all arguments specified
* as the second parameter. Must be used with the "array" type.
* @type string $description A short description of the feature. Included in
* the Themes REST API schema. Intended for developers.
* @type bool|array $show_in_rest {
* Whether this feature should be included in the Themes REST API endpoint.
* Defaults to not being included. When registering an 'array' or 'object' type,
* this argument must be an array with the 'schema' key.
*
* @type array $schema Specifies the JSON Schema definition describing
* the feature. If any objects in the schema do not include
* the 'additionalProperties' keyword, it is set to false.
* @type string $name An alternate name to be used as the property name
* in the REST API.
* @type callable $prepare_callback A function used to format the theme support in the REST API.
* Receives the raw theme support value.
* }
* }
* @return true|WP_Error True if the theme feature was successfully registered, a WP_Error object if not.
*/
function register_theme_feature( $feature, $args = array() ) {
global $_wp_registered_theme_features;
if ( ! is_array( $_wp_registered_theme_features ) ) {
$_wp_registered_theme_features = array();
}
$defaults = array(
'type' => 'boolean',
'variadic' => false,
'description' => '',
'show_in_rest' => false,
);
$args = wp_parse_args( $args, $defaults );
if ( true === $args['show_in_rest'] ) {
$args['show_in_rest'] = array();
}
if ( is_array( $args['show_in_rest'] ) ) {
$args['show_in_rest'] = wp_parse_args(
$args['show_in_rest'],
array(
'schema' => array(),
'name' => $feature,
'prepare_callback' => null,
)
);
}
if ( ! in_array( $args['type'], array( 'string', 'boolean', 'integer', 'number', 'array', 'object' ), true ) ) {
return new WP_Error(
'invalid_type',
__( 'The feature "type" is not valid JSON Schema type.' )
);
}
if ( true === $args['variadic'] && 'array' !== $args['type'] ) {
return new WP_Error(
'variadic_must_be_array',
__( 'When registering a "variadic" theme feature, the "type" must be an "array".' )
);
}
if ( false !== $args['show_in_rest'] && in_array( $args['type'], array( 'array', 'object' ), true ) ) {
if ( ! is_array( $args['show_in_rest'] ) || empty( $args['show_in_rest']['schema'] ) ) {
return new WP_Error(
'missing_schema',
__( 'When registering an "array" or "object" feature to show in the REST API, the feature\'s schema must also be defined.' )
);
}
if ( 'array' === $args['type'] && ! isset( $args['show_in_rest']['schema']['items'] ) ) {
return new WP_Error(
'missing_schema_items',
__( 'When registering an "array" feature, the feature\'s schema must include the "items" keyword.' )
);
}
if ( 'object' === $args['type'] && ! isset( $args['show_in_rest']['schema']['properties'] ) ) {
return new WP_Error(
'missing_schema_properties',
__( 'When registering an "object" feature, the feature\'s schema must include the "properties" keyword.' )
);
}
}
if ( is_array( $args['show_in_rest'] ) ) {
if ( isset( $args['show_in_rest']['prepare_callback'] )
&& ! is_callable( $args['show_in_rest']['prepare_callback'] )
) {
return new WP_Error(
'invalid_rest_prepare_callback',
sprintf(
/* translators: %s: prepare_callback */
__( 'The "%s" must be a callable function.' ),
'prepare_callback'
)
);
}
$args['show_in_rest']['schema'] = wp_parse_args(
$args['show_in_rest']['schema'],
array(
'description' => $args['description'],
'type' => $args['type'],
'default' => false,
)
);
if ( is_bool( $args['show_in_rest']['schema']['default'] )
&& ! in_array( 'boolean', (array) $args['show_in_rest']['schema']['type'], true )
) {
// Automatically include the "boolean" type when the default value is a boolean.
$args['show_in_rest']['schema']['type'] = (array) $args['show_in_rest']['schema']['type'];
array_unshift( $args['show_in_rest']['schema']['type'], 'boolean' );
}
$args['show_in_rest']['schema'] = rest_default_additional_properties_to_false( $args['show_in_rest']['schema'] );
}
$_wp_registered_theme_features[ $feature ] = $args;
return true;
}
/**
* Gets the list of registered theme features.
*
* @since 5.5.0
*
* @global array $_wp_registered_theme_features
*
* @return array[] List of theme features, keyed by their name.
*/
function get_registered_theme_features() {
global $_wp_registered_theme_features;
if ( ! is_array( $_wp_registered_theme_features ) ) {
return array();
}
return $_wp_registered_theme_features;
}
/**
* Gets the registration config for a theme feature.
*
* @since 5.5.0
*
* @global array $_wp_registered_theme_features
*
* @param string $feature The feature name. See add_theme_support() for the list
* of possible values.
* @return array|null The registration args, or null if the feature was not registered.
*/
function get_registered_theme_feature( $feature ) {
global $_wp_registered_theme_features;
if ( ! is_array( $_wp_registered_theme_features ) ) {
return null;
}
return $_wp_registered_theme_features[ $feature ] ?? null;
}
/**
* Checks an attachment being deleted to see if it's a header or background image.
*
* If true it removes the theme modification which would be pointing at the deleted
* attachment.
*
* @access private
* @since 3.0.0
* @since 4.3.0 Also removes `header_image_data`.
* @since 4.5.0 Also removes custom logo theme mods.
* @since 6.6.0 Also removes `site_logo` option set by the site logo block.
*
* @param int $id The attachment ID.
*/
function _delete_attachment_theme_mod( $id ) {
$attachment_image = wp_get_attachment_url( $id );
$header_image = get_header_image();
$background_image = get_background_image();
$custom_logo_id = (int) get_theme_mod( 'custom_logo' );
$site_logo_id = (int) get_option( 'site_logo' );
if ( $custom_logo_id && $custom_logo_id === $id ) {
remove_theme_mod( 'custom_logo' );
remove_theme_mod( 'header_text' );
}
if ( $site_logo_id && $site_logo_id === $id ) {
delete_option( 'site_logo' );
}
if ( $header_image && $header_image === $attachment_image ) {
remove_theme_mod( 'header_image' );
remove_theme_mod( 'header_image_data' );
}
if ( $background_image && $background_image === $attachment_image ) {
remove_theme_mod( 'background_image' );
}
}
/**
* Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load.
*
* See {@see 'after_switch_theme'}.
*
* @since 3.3.0
*/
function check_theme_switched() {
$stylesheet = get_option( 'theme_switched' );
if ( $stylesheet ) {
$old_theme = wp_get_theme( $stylesheet );
// Prevent widget & menu mapping from running since Customizer already called it up front.
if ( get_option( 'theme_switched_via_customizer' ) ) {
remove_action( 'after_switch_theme', '_wp_menus_changed' );
remove_action( 'after_switch_theme', '_wp_sidebars_changed' );
update_option( 'theme_switched_via_customizer', false );
}
if ( $old_theme->exists() ) {
/**
* Fires on the next WP load after the theme has been switched.
*
* The parameters differ according to whether the old theme exists or not.
* If the old theme is missing, the old name will instead be the slug
* of the old theme.
*
* See {@see 'switch_theme'}.
*
* @since 3.3.0
*
* @param string $old_name Old theme name.
* @param WP_Theme $old_theme WP_Theme instance of the old theme.
*/
do_action( 'after_switch_theme', $old_theme->get( 'Name' ), $old_theme );
} else {
/** This action is documented in wp-includes/theme.php */
do_action( 'after_switch_theme', $stylesheet, $old_theme );
}
flush_rewrite_rules();
update_option( 'theme_switched', false );
}
}
/**
* Includes and instantiates the WP_Customize_Manager class.
*
* Loads the Customizer at plugins_loaded when accessing the customize.php admin
* page or when any request includes a wp_customize=on param or a customize_changeset
* param (a UUID). This param is a signal for whether to bootstrap the Customizer when
* WordPress is loading, especially in the Customizer preview
* or when making Customizer Ajax requests for widgets or menus.
*
* @since 3.4.0
*
* @global WP_Customize_Manager $wp_customize
*/
function _wp_customize_include() {
$is_customize_admin_page = ( is_admin() && 'customize.php' === basename( $_SERVER['PHP_SELF'] ) );
$should_include = (
$is_customize_admin_page
||
( isset( $_REQUEST['wp_customize'] ) && 'on' === $_REQUEST['wp_customize'] )
||
( ! empty( $_GET['customize_changeset_uuid'] ) || ! empty( $_POST['customize_changeset_uuid'] ) )
);
if ( ! $should_include ) {
return;
}
/*
* Note that wp_unslash() is not being used on the input vars because it is
* called before wp_magic_quotes() gets called. Besides this fact, none of
* the values should contain any characters needing slashes anyway.
*/
$keys = array(
'changeset_uuid',
'customize_changeset_uuid',
'customize_theme',
'theme',
'customize_messenger_channel',
'customize_autosaved',
);
$input_vars = array_merge(
wp_array_slice_assoc( $_GET, $keys ),
wp_array_slice_assoc( $_POST, $keys )
);
$theme = null;
$autosaved = null;
$messenger_channel = null;
/*
* Value false indicates UUID should be determined after_setup_theme
* to either re-use existing saved changeset or else generate a new UUID if none exists.
*/
$changeset_uuid = false;
/*
* Set initially to false since defaults to true for back-compat;
* can be overridden via the customize_changeset_branching filter.
*/
$branching = false;
if ( $is_customize_admin_page && isset( $input_vars['changeset_uuid'] ) ) {
$changeset_uuid = sanitize_key( $input_vars['changeset_uuid'] );
} elseif ( ! empty( $input_vars['customize_changeset_uuid'] ) ) {
$changeset_uuid = sanitize_key( $input_vars['customize_changeset_uuid'] );
}
// Note that theme will be sanitized via WP_Theme.
if ( $is_customize_admin_page && isset( $input_vars['theme'] ) ) {
$theme = $input_vars['theme'];
} elseif ( isset( $input_vars['customize_theme'] ) ) {
$theme = $input_vars['customize_theme'];
}
if ( ! empty( $input_vars['customize_autosaved'] ) ) {
$autosaved = true;
}
if ( isset( $input_vars['customize_messenger_channel'] ) ) {
$messenger_channel = sanitize_key( $input_vars['customize_messenger_channel'] );
}
/*
* Note that settings must be previewed even outside the customizer preview
* and also in the customizer pane itself. This is to enable loading an existing
* changeset into the customizer. Previewing the settings only has to be prevented
* here in the case of a customize_save action because this will cause WP to think
* there is nothing changed that needs to be saved.
*/
$is_customize_save_action = (
wp_doing_ajax()
&&
isset( $_REQUEST['action'] )
&&
'customize_save' === wp_unslash( $_REQUEST['action'] )
);
$settings_previewed = ! $is_customize_save_action;
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
$GLOBALS['wp_customize'] = new WP_Customize_Manager(
compact(
'changeset_uuid',
'theme',
'messenger_channel',
'settings_previewed',
'autosaved',
'branching'
)
);
}
/**
* Publishes a snapshot's changes.
*
* @since 4.7.0
* @access private
*
* @global WP_Customize_Manager $wp_customize Customizer instance.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $changeset_post Changeset post object.
*/
function _wp_customize_publish_changeset( $new_status, $old_status, $changeset_post ) {
global $wp_customize;
$is_publishing_changeset = (
'customize_changeset' === $changeset_post->post_type
&&
'publish' === $new_status
&&
'publish' !== $old_status
);
if ( ! $is_publishing_changeset ) {
return;
}
if ( empty( $wp_customize ) ) {
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
$wp_customize = new WP_Customize_Manager(
array(
'changeset_uuid' => $changeset_post->post_name,
'settings_previewed' => false,
)
);
}
if ( ! did_action( 'customize_register' ) ) {
/*
* When running from CLI or Cron, the customize_register action will need
* to be triggered in order for core, themes, and plugins to register their
* settings. Normally core will add_action( 'customize_register' ) at
* priority 10 to register the core settings, and if any themes/plugins
* also add_action( 'customize_register' ) at the same priority, they
* will have a $wp_customize with those settings registered since they
* call add_action() afterward, normally. However, when manually doing
* the customize_register action after the setup_theme, then the order
* will be reversed for two actions added at priority 10, resulting in
* the core settings no longer being available as expected to themes/plugins.
* So the following manually calls the method that registers the core
* settings up front before doing the action.
*/
remove_action( 'customize_register', array( $wp_customize, 'register_controls' ) );
$wp_customize->register_controls();
/** This filter is documented in wp-includes/class-wp-customize-manager.php */
do_action( 'customize_register', $wp_customize );
}
$wp_customize->_publish_changeset_values( $changeset_post->ID );
/*
* Trash the changeset post if revisions are not enabled. Unpublished
* changesets by default get garbage collected due to the auto-draft status.
* When a changeset post is published, however, it would no longer get cleaned
* out. This is a problem when the changeset posts are never displayed anywhere,
* since they would just be endlessly piling up. So here we use the revisions
* feature to indicate whether or not a published changeset should get trashed
* and thus garbage collected.
*/
if ( ! wp_revisions_enabled( $changeset_post ) ) {
$wp_customize->trash_changeset_post( $changeset_post->ID );
}
}
/**
* Filters changeset post data upon insert to ensure post_name is intact.
*
* This is needed to prevent the post_name from being dropped when the post is
* transitioned into pending status by a contributor.
*
* @since 4.7.0
*
* @see wp_insert_post()
*
* @param array $post_data An array of slashed post data.
* @param array $supplied_post_data An array of sanitized, but otherwise unmodified post data.
* @return array Filtered data.
*/
function _wp_customize_changeset_filter_insert_post_data( $post_data, $supplied_post_data ) {
if ( isset( $post_data['post_type'] ) && 'customize_changeset' === $post_data['post_type'] ) {
// Prevent post_name from being dropped, such as when contributor saves a changeset post as pending.
if ( empty( $post_data['post_name'] ) && ! empty( $supplied_post_data['post_name'] ) ) {
$post_data['post_name'] = $supplied_post_data['post_name'];
}
}
return $post_data;
}
/**
* Adds settings for the customize-loader script.
*
* @since 3.4.0
*/
function _wp_customize_loader_settings() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
$cross_domain = ( strtolower( $admin_origin['host'] ) !== strtolower( $home_origin['host'] ) );
$browser = array(
'mobile' => wp_is_mobile(),
'ios' => wp_is_mobile() && preg_match( '/iPad|iPod|iPhone/', $_SERVER['HTTP_USER_AGENT'] ),
);
$settings = array(
'url' => esc_url( admin_url( 'customize.php' ) ),
'isCrossDomain' => $cross_domain,
'browser' => $browser,
'l10n' => array(
'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ),
'mainIframeTitle' => __( 'Customizer' ),
),
);
$script = 'var _wpCustomizeLoaderSettings = ' . wp_json_encode( $settings, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ';';
$wp_scripts = wp_scripts();
$data = $wp_scripts->get_data( 'customize-loader', 'data' );
if ( $data ) {
$script = "$data\n$script";
}
$wp_scripts->add_data( 'customize-loader', 'data', $script );
}
/**
* Returns a URL to load the Customizer.
*
* @since 3.4.0
*
* @param string $stylesheet Optional. Theme to customize. Defaults to active theme.
* The theme's stylesheet will be urlencoded if necessary.
* @return string
*/
function wp_customize_url( $stylesheet = '' ) {
$url = admin_url( 'customize.php' );
if ( $stylesheet ) {
$url = add_query_arg( 'theme', urlencode( $stylesheet ), $url );
}
return esc_url( $url );
}
/**
* Prints a script to check whether or not the Customizer is supported,
* and apply either the no-customize-support or customize-support class
* to the body.
*
* This function MUST be called inside the body tag.
*
* Ideally, call this function immediately after the body tag is opened.
* This prevents a flash of unstyled content.
*
* It is also recommended that you add the "no-customize-support" class
* to the body tag by default.
*
* @since 3.4.0
* @since 4.7.0 Support for IE8 and below is explicitly removed via conditional comments.
* @since 5.5.0 IE8 and older are no longer supported.
*/
function wp_customize_support_script() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
$cross_domain = ( strtolower( $admin_origin['host'] ) !== strtolower( $home_origin['host'] ) );
ob_start();
?>
is_preview();
}
/**
* Makes sure that auto-draft posts get their post_date bumped or status changed
* to draft to prevent premature garbage-collection.
*
* When a changeset is updated but remains an auto-draft, ensure the post_date
* for the auto-draft posts remains the same so that it will be
* garbage-collected at the same time by `wp_delete_auto_drafts()`. Otherwise,
* if the changeset is updated to be a draft then update the posts
* to have a far-future post_date so that they will never be garbage collected
* unless the changeset post itself is deleted.
*
* When a changeset is updated to be a persistent draft or to be scheduled for
* publishing, then transition any dependent auto-drafts to a draft status so
* that they likewise will not be garbage-collected but also so that they can
* be edited in the admin before publishing since there is not yet a post/page
* editing flow in the Customizer. See #39752.
*
* @link https://core.trac.wordpress.org/ticket/39752
*
* @since 4.8.0
* @access private
* @see wp_delete_auto_drafts()
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $new_status Transition to this post status.
* @param string $old_status Previous post status.
* @param \WP_Post $post Post data.
*/
function _wp_keep_alive_customize_changeset_dependent_auto_drafts( $new_status, $old_status, $post ) {
global $wpdb;
unset( $old_status );
// Short-circuit if not a changeset or if the changeset was published.
if ( 'customize_changeset' !== $post->post_type || 'publish' === $new_status ) {
return;
}
$data = json_decode( $post->post_content, true );
if ( empty( $data['nav_menus_created_posts']['value'] ) ) {
return;
}
/*
* Actually, in lieu of keeping alive, trash any customization drafts here if the changeset itself is
* getting trashed. This is needed because when a changeset transitions to a draft, then any of the
* dependent auto-draft post/page stubs will also get transitioned to customization drafts which
* are then visible in the WP Admin. We cannot wait for the deletion of the changeset in which
* _wp_delete_customize_changeset_dependent_auto_drafts() will be called, since they need to be
* trashed to remove from visibility immediately.
*/
if ( 'trash' === $new_status ) {
foreach ( $data['nav_menus_created_posts']['value'] as $post_id ) {
if ( ! empty( $post_id ) && 'draft' === get_post_status( $post_id ) ) {
wp_trash_post( $post_id );
}
}
return;
}
$post_args = array();
if ( 'auto-draft' === $new_status ) {
/*
* Keep the post date for the post matching the changeset
* so that it will not be garbage-collected before the changeset.
*/
$post_args['post_date'] = $post->post_date; // Note wp_delete_auto_drafts() only looks at this date.
} else {
/*
* Since the changeset no longer has an auto-draft (and it is not published)
* it is now a persistent changeset, a long-lived draft, and so any
* associated auto-draft posts should likewise transition into having a draft
* status. These drafts will be treated differently than regular drafts in
* that they will be tied to the given changeset. The publish meta box is
* replaced with a notice about how the post is part of a set of customized changes
* which will be published when the changeset is published.
*/
$post_args['post_status'] = 'draft';
}
foreach ( $data['nav_menus_created_posts']['value'] as $post_id ) {
if ( empty( $post_id ) || 'auto-draft' !== get_post_status( $post_id ) ) {
continue;
}
$wpdb->update(
$wpdb->posts,
$post_args,
array( 'ID' => $post_id )
);
clean_post_cache( $post_id );
}
}
/**
* Creates the initial theme features when the 'setup_theme' action is fired.
*
* See {@see 'setup_theme'}.
*
* @since 5.5.0
* @since 6.0.1 The `block-templates` feature was added.
*/
function create_initial_theme_features() {
register_theme_feature(
'align-wide',
array(
'description' => __( 'Whether theme opts in to wide alignment CSS class.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'automatic-feed-links',
array(
'description' => __( 'Whether posts and comments RSS feed links are added to head.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'block-templates',
array(
'description' => __( 'Whether a theme uses block-based templates.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'block-template-parts',
array(
'description' => __( 'Whether a theme uses block-based template parts.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'custom-background',
array(
'description' => __( 'Custom background if defined by the theme.' ),
'type' => 'object',
'show_in_rest' => array(
'schema' => array(
'properties' => array(
'default-image' => array(
'type' => 'string',
'format' => 'uri',
),
'default-preset' => array(
'type' => 'string',
'enum' => array(
'default',
'fill',
'fit',
'repeat',
'custom',
),
),
'default-position-x' => array(
'type' => 'string',
'enum' => array(
'left',
'center',
'right',
),
),
'default-position-y' => array(
'type' => 'string',
'enum' => array(
'left',
'center',
'right',
),
),
'default-size' => array(
'type' => 'string',
'enum' => array(
'auto',
'contain',
'cover',
),
),
'default-repeat' => array(
'type' => 'string',
'enum' => array(
'repeat-x',
'repeat-y',
'repeat',
'no-repeat',
),
),
'default-attachment' => array(
'type' => 'string',
'enum' => array(
'scroll',
'fixed',
),
),
'default-color' => array(
'type' => 'string',
),
),
),
),
)
);
register_theme_feature(
'custom-header',
array(
'description' => __( 'Custom header if defined by the theme.' ),
'type' => 'object',
'show_in_rest' => array(
'schema' => array(
'properties' => array(
'default-image' => array(
'type' => 'string',
'format' => 'uri',
),
'random-default' => array(
'type' => 'boolean',
),
'width' => array(
'type' => 'integer',
),
'height' => array(
'type' => 'integer',
),
'flex-height' => array(
'type' => 'boolean',
),
'flex-width' => array(
'type' => 'boolean',
),
'default-text-color' => array(
'type' => 'string',
),
'header-text' => array(
'type' => 'boolean',
),
'uploads' => array(
'type' => 'boolean',
),
'video' => array(
'type' => 'boolean',
),
),
),
),
)
);
register_theme_feature(
'custom-logo',
array(
'type' => 'object',
'description' => __( 'Custom logo if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'properties' => array(
'width' => array(
'type' => 'integer',
),
'height' => array(
'type' => 'integer',
),
'flex-width' => array(
'type' => 'boolean',
),
'flex-height' => array(
'type' => 'boolean',
),
'header-text' => array(
'type' => 'array',
'items' => array(
'type' => 'string',
),
),
'unlink-homepage-logo' => array(
'type' => 'boolean',
),
),
),
),
)
);
register_theme_feature(
'customize-selective-refresh-widgets',
array(
'description' => __( 'Whether the theme enables Selective Refresh for Widgets being managed with the Customizer.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'dark-editor-style',
array(
'description' => __( 'Whether theme opts in to the dark editor style UI.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-custom-colors',
array(
'description' => __( 'Whether the theme disables custom colors.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-custom-font-sizes',
array(
'description' => __( 'Whether the theme disables custom font sizes.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-custom-gradients',
array(
'description' => __( 'Whether the theme disables custom gradients.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'disable-layout-styles',
array(
'description' => __( 'Whether the theme disables generated layout styles.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'editor-color-palette',
array(
'type' => 'array',
'description' => __( 'Custom color palette if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'slug' => array(
'type' => 'string',
),
'color' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-font-sizes',
array(
'type' => 'array',
'description' => __( 'Custom font sizes if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'size' => array(
'type' => 'number',
),
'slug' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-gradient-presets',
array(
'type' => 'array',
'description' => __( 'Custom gradient presets if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'gradient' => array(
'type' => 'string',
),
'slug' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-spacing-sizes',
array(
'type' => 'array',
'description' => __( 'Custom spacing sizes if defined by the theme.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'size' => array(
'type' => 'string',
),
'slug' => array(
'type' => 'string',
),
),
),
),
),
)
);
register_theme_feature(
'editor-styles',
array(
'description' => __( 'Whether theme opts in to the editor styles CSS wrapper.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'html5',
array(
'type' => 'array',
'description' => __( 'Allows use of HTML5 markup for search forms, comment forms, comment lists, gallery, and caption.' ),
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'string',
'enum' => array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'script',
'style',
),
),
),
),
)
);
register_theme_feature(
'post-formats',
array(
'type' => 'array',
'description' => __( 'Post formats supported.' ),
'show_in_rest' => array(
'name' => 'formats',
'schema' => array(
'items' => array(
'type' => 'string',
'enum' => get_post_format_slugs(),
),
'default' => array( 'standard' ),
),
'prepare_callback' => static function ( $formats ) {
$formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
$formats = array_merge( array( 'standard' ), $formats );
return $formats;
},
),
)
);
register_theme_feature(
'post-thumbnails',
array(
'type' => 'array',
'description' => __( 'The post types that support thumbnails or true if all post types are supported.' ),
'show_in_rest' => array(
'type' => array( 'boolean', 'array' ),
'schema' => array(
'items' => array(
'type' => 'string',
),
),
),
)
);
register_theme_feature(
'responsive-embeds',
array(
'description' => __( 'Whether the theme supports responsive embedded content.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'title-tag',
array(
'description' => __( 'Whether the theme can manage the document title tag.' ),
'show_in_rest' => true,
)
);
register_theme_feature(
'wp-block-styles',
array(
'description' => __( 'Whether theme opts in to default WordPress block styles for viewing.' ),
'show_in_rest' => true,
)
);
}
/**
* Returns whether the active theme is a block-based theme or not.
*
* @since 5.9.0
*
* @global string[] $wp_theme_directories
*
* @return bool Whether the active theme is a block-based theme or not.
*/
function wp_is_block_theme() {
if ( empty( $GLOBALS['wp_theme_directories'] ) ) {
_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before the theme directory is registered.' ), '6.8.0' );
return false;
}
return wp_get_theme()->is_block_theme();
}
/**
* Given an element name, returns a class name.
*
* Alias of WP_Theme_JSON::get_element_class_name.
*
* @since 6.1.0
*
* @param string $element The name of the element.
*
* @return string The name of the class.
*/
function wp_theme_get_element_class_name( $element ) {
return WP_Theme_JSON::get_element_class_name( $element );
}
/**
* Adds default theme supports for block themes when the 'after_setup_theme' action fires.
*
* See {@see 'after_setup_theme'}.
*
* @since 5.9.0
* @access private
*/
function _add_default_theme_supports() {
if ( ! wp_is_block_theme() ) {
return;
}
add_theme_support( 'post-thumbnails' );
add_theme_support( 'responsive-embeds' );
add_theme_support( 'editor-styles' );
/*
* Makes block themes support HTML5 by default for the comment block and search form
* (which use default template functions) and `[caption]` and `[gallery]` shortcodes.
* Other blocks contain their own HTML5 markup.
*/
add_theme_support( 'html5', array( 'comment-form', 'comment-list', 'search-form', 'gallery', 'caption', 'style', 'script' ) );
add_theme_support( 'automatic-feed-links' );
add_filter( 'should_load_separate_core_block_assets', '__return_true' );
add_filter( 'should_load_block_assets_on_demand', '__return_true' );
/*
* Remove the Customizer's Menus panel when block theme is active.
*/
add_filter(
'customize_panel_active',
static function ( $active, WP_Customize_Panel $panel ) {
if (
'nav_menus' === $panel->id &&
! current_theme_supports( 'menus' ) &&
! current_theme_supports( 'widgets' )
) {
$active = false;
}
return $active;
},
10,
2
);
}