'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-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 * * @return boolean Whether the active theme is a block-based theme or not. */ function wp_is_block_theme() { 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 'setup_theme' action fires. * * See {@see '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' ); /* * 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 ); } } if ( shortcode_exists( $tag ) ) { preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); if ( empty( $matches ) ) { return false; } foreach ( $matches as $shortcode ) { if ( $tag === $shortcode[2] ) { return true; } elseif ( ! empty( $shortcode[5] ) && has_shortcode( $shortcode[5], $tag ) ) { return true; } } } return false; } /** * Returns a list of registered shortcode names found in the given content. * * Example usage: * * get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' ); * // array( 'audio', 'gallery' ) * * @since 6.3.2 * * @param string $content The content to check. * @return string[] An array of registered shortcode names found in the content. */ function get_shortcode_tags_in_content( $content ) { if ( false === strpos( $content, '[' ) ) { return array(); } preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); if ( empty( $matches ) ) { return array(); } $tags = array(); foreach ( $matches as $shortcode ) { $tags[] = $shortcode[2]; if ( ! empty( $shortcode[5] ) ) { $deep_tags = get_shortcode_tags_in_content( $shortcode[5] ); if ( ! empty( $deep_tags ) ) { $tags = array_merge( $tags, $deep_tags ); } } } return $tags; } /** * Searches content for shortcodes and filter shortcodes through their hooks. * * This function is an alias for do_shortcode(). * * @since 5.4.0 * * @see do_shortcode() * * @param string $content Content to search for shortcodes. * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. * Default false. * @return string Content with shortcodes filtered out. */ function apply_shortcodes( $content, $ignore_html = false ) { return do_shortcode( $content, $ignore_html ); } /** * Searches content for shortcodes and filter shortcodes through their hooks. * * If there are no shortcode tags defined, then the content will be returned * without any filtering. This might cause issues when plugins are disabled but * the shortcode will still show up in the post or content. * * @since 2.5.0 * * @global array $shortcode_tags List of shortcode tags and their callback hooks. * * @param string $content Content to search for shortcodes. * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. * Default false. * @return string Content with shortcodes filtered out. */ function do_shortcode( $content, $ignore_html = false ) { global $shortcode_tags; if ( ! str_contains( $content, '[' ) ) { return $content; } if ( empty( $shortcode_tags ) || ! is_array( $shortcode_tags ) ) { return $content; } // Find all registered tag names in $content. preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches ); $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] ); if ( empty( $tagnames ) ) { return $content; } // Ensure this context is only added once if shortcodes are nested. $has_filter = has_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' ); $filter_added = false; if ( ! $has_filter ) { $filter_added = add_filter( 'wp_get_attachment_image_context', '_filter_do_shortcode_context' ); } $content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ); $pattern = get_shortcode_regex( $tagnames ); $content = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $content ); // Always restore square braces so we don't break things like