+ // 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 stylesheets applied to the editor.
+ *
+ * @since 4.3.0
+ *
+ * @param array $stylesheets Array of stylesheets to be applied to the editor.
+ */
+ return apply_filters( 'editor_stylesheets', $stylesheets );
+}
+
+/**
+ * Expand 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' => join( '', array(
+ '<p><strong>' . _x( 'Address', 'Theme starter content' ) . '</strong><br />',
+ _x( '123 Main Street', 'Theme starter content' ) . '<br />' . _x( 'New York, NY 10001', 'Theme starter content' ) . '</p>',
+ '<p><strong>' . _x( 'Hours', 'Theme starter content' ) . '</strong><br />',
+ _x( 'Monday—Friday: 9:00AM–5:00PM', 'Theme starter content' ) . '<br />' . _x( 'Saturday & Sunday: 11:00AM–3:00PM', 'Theme starter content' ) . '</p>'
+ ) ),
+ ) ),
+ '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' ),
+ ) ),
+ '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 home_link.
+ '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' => _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' => _x( 'You might be an artist who would like to introduce yourself and your work here or maybe you’re a business with a mission to describe.', 'Theme starter content' ),
+ ),
+ 'contact' => array(
+ 'post_type' => 'page',
+ 'post_title' => _x( 'Contact', 'Theme starter content' ),
+ 'post_content' => _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' => _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.
+ *
+ * @since 2.9.0
+ * @since 3.6.0 The `html5` feature was added
+ * @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
+ *
+ * @global array $_wp_theme_features
+ *
+ * @param string $feature The feature being added. Likely core values include 'post-formats',
+ * 'post-thumbnails', 'html5', 'custom-logo', 'custom-header-uploads',
+ * 'custom-header', 'custom-background', 'title-tag', 'starter-content', etc.
+ * @param mixed $args,... Optional extra arguments to pass along with certain features.
+ * @return void|bool False on failure, void otherwise.
+ */
+function add_theme_support( $feature ) {
+ global $_wp_theme_features;
+
+ if ( func_num_args() == 1 )
+ $args = true;
+ else
+ $args = array_slice( func_get_args(), 1 );
+
+ 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 ( 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 ( is_array( $args[0] ) ) {
+ $post_formats = get_post_format_slugs();
+ unset( $post_formats['standard'] );
+
+ $args[0] = array_intersect( $args[0], array_keys( $post_formats ) );
+ }
+ break;
+
+ case 'html5' :
+ // You can't just pass 'html5', you need to pass an array of types.
+ if ( empty( $args[0] ) ) {
+ // Build an array of types for back-compat.
+ $args = array( 0 => array( 'comment-list', 'comment-form', 'search-form' ) );
+ } elseif ( ! is_array( $args[0] ) ) {
+ _doing_it_wrong( "add_theme_support( 'html5' )", __( 'You need to pass an array of types.' ), '3.6.1' );
+ return false;
+ }
+
+ // 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 ( ! is_array( $args ) ) {
+ $args = array( 0 => array() );
+ }
+ $defaults = array(
+ 'width' => null,
+ 'height' => null,
+ 'flex-width' => false,
+ 'flex-height' => false,
+ 'header-text' => '',
+ );
+ $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 ( ! is_array( $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 are lame. 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 ( ! is_array( $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' ) ) {
+ /* translators: 1: Theme support 2: hook name */
+ _doing_it_wrong( "add_theme_support( 'title-tag' )", sprintf( __( 'Theme support for %1$s should be registered before the %2$s hook.' ),
+ '<code>title-tag</code>', '<code>wp_loaded</code>' ), '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/custom-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/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 );
+
+ ?>
+ <!-- Custom Logo: hide header text -->
+ <style id="custom-logo-css" type="text/css">
+ <?php echo $classes; ?> {
+ position: absolute;
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ </style>
+ <?php
+ }
+}
+
+/**
+ * Gets the theme support arguments passed when registering that support
+ *
+ * @since 3.1.0
+ *
+ * @global array $_wp_theme_features