diff -r 7b1b88e27a20 -r 48c4eec2b7e6 wp/wp-includes/theme.php --- a/wp/wp-includes/theme.php Thu Sep 29 08:06:27 2022 +0200 +++ b/wp/wp-includes/theme.php Fri Sep 05 18:40:08 2025 +0200 @@ -45,8 +45,10 @@ $theme_directories = search_theme_directories(); if ( is_array( $wp_theme_directories ) && count( $wp_theme_directories ) > 1 ) { - // Make sure the active theme wins out, in case search_theme_directories() picks the wrong - // one in the case of a conflict. (Normally, last registered theme root wins.) + /* + * Make sure the active theme wins out, in case search_theme_directories() picks the wrong + * one in the case of a conflict. (Normally, last registered theme root wins.) + */ $current_theme = get_stylesheet(); if ( isset( $theme_directories[ $current_theme ] ) ) { $root_of_current_theme = get_raw_theme_root( $current_theme ); @@ -89,7 +91,7 @@ if ( null !== $args['errors'] ) { foreach ( $themes as $theme => $wp_theme ) { - if ( $wp_theme->errors() != $args['errors'] ) { + if ( (bool) $wp_theme->errors() !== $args['errors'] ) { unset( $themes[ $theme ] ); } } @@ -151,11 +153,17 @@ * Whether a child theme is in use. * * @since 3.0.0 + * @since 6.5.0 Makes use of global template variables. + * + * @global string $wp_stylesheet_path Path to current theme's stylesheet directory. + * @global string $wp_template_path Path to current theme's template directory. * * @return bool True if a child theme is in use, false otherwise. */ function is_child_theme() { - return ( TEMPLATEPATH !== STYLESHEETPATH ); + global $wp_stylesheet_path, $wp_template_path; + + return $wp_stylesheet_path !== $wp_template_path; } /** @@ -185,6 +193,8 @@ * Retrieves stylesheet directory path for the active theme. * * @since 1.5.0 + * @since 6.4.0 Memoizes filter execution so that it only runs once for the current theme. + * @since 6.4.2 Memoization removed. * * @return string Path to active theme's stylesheet directory. */ @@ -319,6 +329,8 @@ * Retrieves template directory path for the active theme. * * @since 1.5.0 + * @since 6.4.0 Memoizes filter execution so that it only runs once for the current theme. + * @since 6.4.1 Memoization removed. * * @return string Path to active theme's template directory. */ @@ -457,7 +469,7 @@ * to use in get_theme_root(). */ foreach ( $wp_theme_directories as $theme_root ) { - if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) { + if ( str_starts_with( $theme_root, WP_CONTENT_DIR ) ) { $relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root; } else { $relative_theme_roots[ $theme_root ] = $theme_root; @@ -502,7 +514,7 @@ // Start with directories in the root of the active theme directory. $dirs = @ scandir( $theme_root ); if ( ! $dirs ) { - trigger_error( "$theme_root is not readable", E_USER_NOTICE ); + wp_trigger_error( __FUNCTION__, "$theme_root is not readable" ); continue; } foreach ( $dirs as $dir ) { @@ -510,19 +522,23 @@ continue; } if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) { - // wp-content/themes/a-single-theme - // wp-content/themes is $theme_root, a-single-theme is $dir. + /* + * wp-content/themes/a-single-theme + * wp-content/themes is $theme_root, a-single-theme is $dir. + */ $found_themes[ $dir ] = array( 'theme_file' => $dir . '/style.css', 'theme_root' => $theme_root, ); } else { $found_theme = false; - // wp-content/themes/a-folder-of-themes/* - // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs. + /* + * wp-content/themes/a-folder-of-themes/* + * wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs. + */ $sub_dirs = @ scandir( $theme_root . '/' . $dir ); if ( ! $sub_dirs ) { - trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE ); + wp_trigger_error( __FUNCTION__, "$theme_root/$dir is not readable" ); continue; } foreach ( $sub_dirs as $sub_dir ) { @@ -538,8 +554,10 @@ ); $found_theme = true; } - // Never mind the above, it's just a theme missing a style.css. - // Return it; WP_Theme will catch the error. + /* + * Never mind the above, it's just a theme missing a style.css. + * Return it; WP_Theme will catch the error. + */ if ( ! $found_theme ) { $found_themes[ $dir ] = array( 'theme_file' => $dir . '/style.css', @@ -559,7 +577,7 @@ $theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative. } - if ( get_site_transient( 'theme_roots' ) != $theme_roots ) { + if ( get_site_transient( 'theme_roots' ) !== $theme_roots ) { set_site_transient( 'theme_roots', $theme_roots, $cache_expiration ); } @@ -587,8 +605,10 @@ if ( $stylesheet_or_template ) { $theme_root = get_raw_theme_root( $stylesheet_or_template ); if ( $theme_root ) { - // Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory. - // This gives relative theme roots the benefit of the doubt when things go haywire. + /* + * Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory. + * This gives relative theme roots the benefit of the doubt when things go haywire. + */ if ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) { $theme_root = WP_CONTENT_DIR . $theme_root; } @@ -634,11 +654,11 @@ if ( $stylesheet_or_template && $theme_root ) { if ( in_array( $theme_root, (array) $wp_theme_directories, true ) ) { // Absolute path. Make an educated guess. YMMV -- but note the filter below. - if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) { + if ( str_starts_with( $theme_root, WP_CONTENT_DIR ) ) { $theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) ); - } elseif ( 0 === strpos( $theme_root, ABSPATH ) ) { + } elseif ( str_starts_with( $theme_root, ABSPATH ) ) { $theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) ); - } elseif ( 0 === strpos( $theme_root, WP_PLUGIN_DIR ) || 0 === strpos( $theme_root, WPMU_PLUGIN_DIR ) ) { + } elseif ( str_starts_with( $theme_root, WP_PLUGIN_DIR ) || str_starts_with( $theme_root, WPMU_PLUGIN_DIR ) ) { $theme_root_uri = plugins_url( basename( $theme_root ), $theme_root ); } else { $theme_root_uri = $theme_root; @@ -685,9 +705,9 @@ // If requesting the root for the active theme, consult options to avoid calling get_theme_roots(). if ( ! $skip_cache ) { - if ( get_option( 'stylesheet' ) == $stylesheet_or_template ) { + if ( get_option( 'stylesheet' ) === $stylesheet_or_template ) { $theme_root = get_option( 'stylesheet_root' ); - } elseif ( get_option( 'template' ) == $stylesheet_or_template ) { + } elseif ( get_option( 'template' ) === $stylesheet_or_template ) { $theme_root = get_option( 'template_root' ); } } @@ -733,11 +753,12 @@ * @global array $wp_theme_directories * @global WP_Customize_Manager $wp_customize * @global array $sidebars_widgets + * @global array $wp_registered_sidebars * * @param string $stylesheet Stylesheet name. */ function switch_theme( $stylesheet ) { - global $wp_theme_directories, $wp_customize, $sidebars_widgets; + global $wp_theme_directories, $wp_customize, $sidebars_widgets, $wp_registered_sidebars; $requirements = validate_theme_requirements( $stylesheet ); if ( is_wp_error( $requirements ) ) { @@ -814,11 +835,39 @@ } } + // Stores classic sidebars for later use by block themes. + if ( $new_theme->is_block_theme() ) { + set_theme_mod( 'wp_classic_sidebars', $wp_registered_sidebars ); + } + update_option( 'theme_switched', $old_theme->get_stylesheet() ); + /* + * Reset template globals when switching themes outside of a switched blog + * context to ensure templates will be loaded from the new theme. + */ + if ( ! is_multisite() || ! ms_is_switched() ) { + wp_set_template_globals(); + } + + // Clear pattern caches. + if ( ! is_multisite() ) { + $new_theme->delete_pattern_cache(); + $old_theme->delete_pattern_cache(); + } + + // Set autoload=no for the old theme, autoload=yes for the switched theme. + $theme_mods_options = array( + 'theme_mods_' . $stylesheet => 'yes', + 'theme_mods_' . $old_theme->get_stylesheet() => 'no', + ); + wp_set_option_autoload_values( $theme_mods_options ); + /** * Fires after the theme is switched. * + * See {@see 'after_switch_theme'}. + * * @since 1.5.0 * @since 4.5.0 Introduced the `$old_theme` parameter. * @@ -893,7 +942,7 @@ * if it turns out there is no default theme installed. (That's `false`.) */ $default = WP_Theme::get_core_default_theme(); - if ( false === $default || get_stylesheet() == $default->get_stylesheet() ) { + if ( false === $default || get_stylesheet() === $default->get_stylesheet() ) { return true; } @@ -991,18 +1040,18 @@ /** * Retrieves theme modification value for the active theme. * - * If the modification name does not exist and `$default` is a string, then the + * If the modification name does not exist and `$default_value` is a string, then the * default will be passed through the {@link https://www.php.net/sprintf sprintf()} * PHP function with the template directory URI as the first value and the * stylesheet directory URI as the second value. * * @since 2.1.0 * - * @param string $name Theme modification name. - * @param mixed $default Optional. Theme modification default value. Default false. + * @param string $name Theme modification name. + * @param mixed $default_value Optional. Theme modification default value. Default false. * @return mixed Theme modification value. */ -function get_theme_mod( $name, $default = false ) { +function get_theme_mod( $name, $default_value = false ) { $mods = get_theme_mods(); if ( isset( $mods[ $name ] ) ) { @@ -1020,17 +1069,17 @@ return apply_filters( "theme_mod_{$name}", $mods[ $name ] ); } - if ( is_string( $default ) ) { + if ( is_string( $default_value ) ) { // Only run the replacement if an sprintf() string format pattern was found. - if ( preg_match( '#(?ID ) ); + $url = sanitize_url( wp_get_attachment_url( $header->ID ) ); $header_data = wp_get_attachment_metadata( $header->ID ); $header_index = $header->ID; @@ -1479,7 +1567,7 @@ if ( ! empty( $_wp_default_headers ) ) { foreach ( (array) $_wp_default_headers as $default_header ) { $url = vsprintf( $default_header['url'], $directory_args ); - if ( $data['url'] == $url ) { + if ( $data['url'] === $url ) { $data = $default_header; $data['url'] = $url; $data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args ); @@ -1589,7 +1677,7 @@ return false; } - return esc_url_raw( set_url_scheme( $url ) ); + return sanitize_url( set_url_scheme( $url ) ); } /** @@ -1786,8 +1874,10 @@ // $background is the saved custom image, or the default image. $background = set_url_scheme( get_background_image() ); - // $color is the saved custom color. - // A default has to be specified in style.css. It will not be printed here. + /* + * $color is the saved custom color. + * A default has to be specified in style.css. It will not be printed here. + */ $color = get_background_color(); if ( get_theme_support( 'custom-background', 'default-color' ) === $color ) { @@ -1806,7 +1896,7 @@ $style = $color ? "background-color: #$color;" : ''; if ( $background ) { - $image = ' background-image: url("' . esc_url_raw( $background ) . '");'; + $image = ' background-image: url("' . sanitize_url( $background ) . '");'; // Background Position. $position_x = get_theme_mod( 'background_position_x', get_theme_support( 'custom-background', 'default-position-x' ) ); @@ -2054,7 +2144,8 @@ } // Trigger creation of a revision. This should be removed once #30854 is resolved. - if ( 0 === count( wp_get_post_revisions( $r ) ) ) { + $revisions = wp_get_latest_revision_id_and_total_count( $r ); + if ( ! is_wp_error( $revisions ) && 0 === $revisions['count'] ) { wp_save_post_revision( $r ); } } @@ -2146,7 +2237,7 @@ // Support externally referenced styles (like, say, fonts). foreach ( $editor_styles as $key => $file ) { if ( preg_match( '~^(https?:)?//~', $file ) ) { - $stylesheets[] = esc_url_raw( $file ); + $stylesheets[] = sanitize_url( $file ); unset( $editor_styles[ $key ] ); } } @@ -2355,7 +2446,7 @@ '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’re a business with a mission to describe.', 'Theme starter content' ) + _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( @@ -2460,8 +2551,10 @@ } break; - // All that's left now are posts (besides attachments). - // Not a default case for the sake of clarity and future work. + /* + * 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 ) ) { @@ -2523,6 +2616,8 @@ * @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. @@ -2533,17 +2628,32 @@ * @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. + * @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. * * @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' @@ -2555,21 +2665,25 @@ * - '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' - * - 'wp-block-styles' * - '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. */ @@ -2685,14 +2799,18 @@ $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.) + /* + * 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. + /* + * 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 ); } @@ -2702,7 +2820,7 @@ * 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. + * Constants should be avoided. Don't reference them. This is just for backward compatibility. */ if ( defined( 'NO_HEADER_TEXT' ) ) { @@ -2739,8 +2857,10 @@ $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 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; @@ -3107,12 +3227,12 @@ * * @param string $feature The feature being checked. See add_theme_support() for the list * of possible values. - * @param string $include Path to the file. + * @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, $include ) { +function require_if_theme_supports( $feature, $file ) { if ( current_theme_supports( $feature ) ) { - require $include; + require $file; return true; } return false; @@ -3316,6 +3436,7 @@ * @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. */ @@ -3323,19 +3444,24 @@ $attachment_image = wp_get_attachment_url( $id ); $header_image = get_header_image(); $background_image = get_background_image(); - $custom_logo_id = get_theme_mod( 'custom_logo' ); - - if ( $custom_logo_id && $custom_logo_id == $id ) { + $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 ( $header_image && $header_image == $attachment_image ) { + 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 ) { + if ( $background_image && $background_image === $attachment_image ) { remove_theme_mod( 'background_image' ); } } @@ -3362,13 +3488,14 @@ if ( $old_theme->exists() ) { /** - * Fires on the first WP load after a theme switch if the old theme still exists. + * Fires on the next WP load after the theme has been switched. * - * This action fires multiple times and the parameters differs - * according to the context, if the old theme exists or not. - * If the old theme is missing, the parameter will be the slug + * 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. @@ -3436,12 +3563,16 @@ $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. + /* + * 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 fo false since defaults to true for back-compat; - // can be overridden via the customize_changeset_branching filter. + /* + * 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'] ) ) { @@ -3500,7 +3631,6 @@ * @since 4.7.0 * @access private * - * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Customize_Manager $wp_customize Customizer instance. * * @param string $new_status New post status. @@ -3508,7 +3638,7 @@ * @param WP_Post $changeset_post Changeset post object. */ function _wp_customize_publish_changeset( $new_status, $old_status, $changeset_post ) { - global $wp_customize, $wpdb; + global $wp_customize; $is_publishing_changeset = ( 'customize_changeset' === $changeset_post->post_type @@ -3549,7 +3679,7 @@ 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 */ + /** 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 ); @@ -3601,7 +3731,7 @@ 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'] ) ); + $cross_domain = ( strtolower( $admin_origin['host'] ) !== strtolower( $home_origin['host'] ) ); $browser = array( 'mobile' => wp_is_mobile(), @@ -3666,10 +3796,10 @@ 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'] ) ); - $type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"'; + $cross_domain = ( strtolower( $admin_origin['host'] ) !== strtolower( $home_origin['host'] ) ); + ob_start(); ?> - __( '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.' ), @@ -4009,6 +4147,13 @@ ) ); 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', @@ -4084,6 +4229,31 @@ ) ); 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.' ), @@ -4179,16 +4349,31 @@ * * @since 5.9.0 * - * @return boolean Whether the active theme is a block-based theme or not. + * @return bool Whether the active theme is a block-based theme or not. */ function wp_is_block_theme() { return wp_get_theme()->is_block_theme(); } /** - * Adds default theme supports for block themes when the 'setup_theme' action fires. - * - * See {@see 'setup_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 @@ -4210,4 +4395,23 @@ 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 + ); }