From c3d331e93a8278c0941acaae165d5891b962c5ab Mon Sep 17 00:00:00 2001
From: Piyush <296399266+skikken@users.noreply.github.com>
Date: Thu, 10 Sep 2026 21:29:37 +0530
Subject: [PATCH] fix(themes): escape current theme action links
The action links for the active theme on themes.php were assembled as
raw relative URL strings with unescaped labels, so a submenu label
containing markup was emitted verbatim. The section also duplicated
six near-identical anchors.
Compute the URL and class list per item and emit a single escaped
anchor. Keep the hide-if-no-customize class, which the rule in
wp-admin/css/themes.css relies on.
Refs https://core.trac.wordpress.org/ticket/31365
---
src/wp-admin/themes.php | 44 +++++++++++++++++++++++++++++++++--------
1 file changed, 36 insertions(+), 8 deletions(-)
diff --git a/src/wp-admin/themes.php b/src/wp-admin/themes.php
index ac2cd4a9824cb..00c34d546b50e 100644
--- a/src/wp-admin/themes.php
+++ b/src/wp-admin/themes.php
@@ -366,7 +366,7 @@
);
foreach ( (array) $submenu['themes.php'] as $item ) {
- $class = '';
+ $classes = array( 'button', 'button-compact' );
if ( in_array( $item[2], $forbidden_paths, true ) || str_starts_with( $item[2], 'customize.php' ) ) {
continue;
@@ -376,7 +376,7 @@
if ( 0 === strcmp( $self, $item[2] ) && empty( $parent_file )
|| $parent_file && $item[2] === $parent_file
) {
- $class = ' current';
+ $classes[] = 'current';
}
if ( ! empty( $submenu[ $item[2] ] ) ) {
@@ -384,18 +384,39 @@
$menu_hook = get_plugin_page_hook( $submenu[ $item[2] ][0][2], $item[2] );
if ( file_exists( WP_PLUGIN_DIR . "/{$submenu[$item[2]][0][2]}" ) || ! empty( $menu_hook ) ) {
- $current_theme_actions[] = "{$item[0]}";
+ $url = admin_url( "admin.php?page={$submenu[$item[2]][0][2]}" );
} else {
- $current_theme_actions[] = "{$item[0]}";
+ $url = admin_url( $submenu[ $item[2] ][0][2] );
}
+
+ $current_theme_actions[] = sprintf(
+ '%s',
+ esc_attr( implode( ' ', $classes ) ),
+ esc_url( $url ),
+ esc_html( $item[0] )
+ );
} elseif ( ! empty( $item[2] ) && current_user_can( $item[1] ) ) {
$menu_file = $item[2];
if ( current_user_can( 'customize' ) ) {
if ( 'custom-header' === $menu_file ) {
- $current_theme_actions[] = "{$item[0]}";
+ $customize_url = add_query_arg( array( 'autofocus' => array( 'control' => 'header_image' ) ), 'customize.php' );
+
+ $current_theme_actions[] = sprintf(
+ '%s',
+ esc_attr( implode( ' ', array_merge( $classes, array( 'hide-if-no-customize' ) ) ) ),
+ esc_url( admin_url( $customize_url ) ),
+ esc_html( $item[0] )
+ );
} elseif ( 'custom-background' === $menu_file ) {
- $current_theme_actions[] = "{$item[0]}";
+ $customize_url = add_query_arg( array( 'autofocus' => array( 'control' => 'background_image' ) ), 'customize.php' );
+
+ $current_theme_actions[] = sprintf(
+ '%s',
+ esc_attr( implode( ' ', array_merge( $classes, array( 'hide-if-no-customize' ) ) ) ),
+ esc_url( admin_url( $customize_url ) ),
+ esc_html( $item[0] )
+ );
}
}
@@ -405,10 +426,17 @@
}
if ( file_exists( ABSPATH . "wp-admin/$menu_file" ) ) {
- $current_theme_actions[] = "{$item[0]}";
+ $url = admin_url( $item[2] );
} else {
- $current_theme_actions[] = "{$item[0]}";
+ $url = admin_url( "themes.php?page={$item[2]}" );
}
+
+ $current_theme_actions[] = sprintf(
+ '%s',
+ esc_attr( implode( ' ', $classes ) ),
+ esc_url( $url ),
+ esc_html( $item[0] )
+ );
}
}
}