Commit 6a7859dccdb for woocommerce
commit 6a7859dccdbaa8bac28fe40b57a8a657d678db71
Author: James Kemp <me@jckemp.com>
Date: Tue Feb 24 10:18:17 2026 +0000
Fix template override detection in System Status to show actual runtime behavior (#62964)
* Fix template override detection in System Status to show actual runtime behavior
The previous implementation had issues:
- Called wc_get_template filter with incorrect first parameter ($file instead of located path)
- Showed theme overrides that would actually be replaced by plugin filters at runtime
- Incorrectly showed WC core templates as overrides (e.g., block-notices)
This change:
- Uses wc_locate_template() to properly locate templates including plugin filter overrides
- Applies wc_get_template filter with correct parameters matching runtime behavior
- Removes redundant elseif chain (now handled by wc_locate_template)
- Shows the template that will actually be used at runtime
Adds unit test for filter override detection.
* Add changefile(s) from automation for the following project(s): woocommerce
* Normalize template override paths to be relative to ABSPATH
---------
Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
diff --git a/plugins/woocommerce/changelog/62964-fix-template-override-detection b/plugins/woocommerce/changelog/62964-fix-template-override-detection
new file mode 100644
index 00000000000..a0035ca2b79
--- /dev/null
+++ b/plugins/woocommerce/changelog/62964-fix-template-override-detection
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix System Status template override detection to show actual runtime behavior, including plugin filter overrides.
\ No newline at end of file
diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php
index 986a90e9d4a..f5a1c3499d6 100644
--- a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php
+++ b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php
@@ -1355,24 +1355,31 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
$scan_files[] = 'taxonomy-product_cat.php';
$scan_files[] = 'taxonomy-product_tag.php';
+ $wc_templates_dir = WC()->plugin_path() . '/templates/';
+
foreach ( $scan_files as $file ) {
- $located = apply_filters( 'wc_get_template', $file, $file, array(), WC()->template_path(), WC()->plugin_path() . '/templates/' );
-
- if ( file_exists( $located ) ) {
- $theme_file = $located;
- } elseif ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
- $theme_file = get_stylesheet_directory() . '/' . $file;
- } elseif ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . $file ) ) {
- $theme_file = get_stylesheet_directory() . '/' . WC()->template_path() . $file;
- } elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
- $theme_file = get_template_directory() . '/' . $file;
- } elseif ( file_exists( get_template_directory() . '/' . WC()->template_path() . $file ) ) {
- $theme_file = get_template_directory() . '/' . WC()->template_path() . $file;
- } else {
- $theme_file = false;
+ $located = wc_locate_template( $file, WC()->template_path(), $wc_templates_dir );
+
+ /**
+ * Allow 3rd party plugins to filter the template file location.
+ *
+ * @param string $located The located template path.
+ * @param string $file The template file name.
+ * @param array $args Template arguments.
+ * @param string $template_path The template path.
+ * @param string $default_path The default path.
+ *
+ * @since 2.1.0
+ */
+ $located = apply_filters( 'wc_get_template', $located, $file, array(), WC()->template_path(), $wc_templates_dir );
+
+ // Check if the template is overridden (located outside WC core templates dir).
+ $override_file = false;
+ if ( 0 !== strpos( $located, $wc_templates_dir ) && file_exists( $located ) ) {
+ $override_file = $located;
}
- if ( ! empty( $theme_file ) ) {
+ if ( ! empty( $override_file ) ) {
$core_file = $file;
// Update *-product_<cat|tag> template name before searching in core.
@@ -1380,16 +1387,16 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
$core_file = str_replace( '_', '-', $core_file );
}
- $core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $core_file );
- $theme_version = WC_Admin_Status::get_file_version( $theme_file );
- if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
+ $core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $core_file );
+ $override_version = WC_Admin_Status::get_file_version( $override_file );
+ if ( $core_version && ( empty( $override_version ) || version_compare( $override_version, $core_version, '<' ) ) ) {
if ( ! $outdated_templates ) {
$outdated_templates = true;
}
}
$override_files[] = array(
- 'file' => str_replace( WP_CONTENT_DIR . '/themes/', '', $theme_file ),
- 'version' => $theme_version,
+ 'file' => str_replace( ABSPATH, '', $override_file ),
+ 'version' => $override_version,
'core_version' => $core_version,
);
}
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller-test.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller-test.php
new file mode 100644
index 00000000000..971e07c1be9
--- /dev/null
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller-test.php
@@ -0,0 +1,64 @@
+<?php
+declare( strict_types = 1 );
+
+/**
+ * Tests for WC_REST_System_Status_V2_Controller.
+ *
+ * @since 10.6.0
+ */
+class WC_REST_System_Status_V2_Controller_Test extends WC_REST_Unit_Test_Case {
+
+ /**
+ * The System Under Test.
+ *
+ * @var WC_REST_System_Status_V2_Controller
+ */
+ private $sut;
+
+ /**
+ * Set up test fixtures.
+ */
+ public function setUp(): void {
+ parent::setUp();
+ $this->sut = new WC_REST_System_Status_V2_Controller();
+ delete_transient( 'wc_system_status_theme_info' );
+ }
+
+ /**
+ * Tear down test fixtures.
+ */
+ public function tearDown(): void {
+ parent::tearDown();
+ remove_all_filters( 'wc_get_template' );
+ delete_transient( 'wc_system_status_theme_info' );
+ }
+
+ /**
+ * @testdox Should detect template override via wc_get_template filter.
+ */
+ public function test_get_theme_info_detects_wc_get_template_filter_override(): void {
+ $template_to_override = 'cart/cart.php';
+ $override_path = WC()->plugin_path() . '/includes/class-woocommerce.php';
+
+ add_filter(
+ 'wc_get_template',
+ function ( $template, $template_name ) use ( $template_to_override, $override_path ) {
+ if ( $template_to_override === $template_name ) {
+ return $override_path;
+ }
+ return $template;
+ },
+ 10,
+ 2
+ );
+
+ $theme_info = $this->sut->get_theme_info();
+
+ $override_files = array_column( $theme_info['overrides'], 'file' );
+ $this->assertContains(
+ str_replace( ABSPATH, '', $override_path ),
+ $override_files,
+ 'Template overridden via wc_get_template filter should appear in overrides'
+ );
+ }
+}