<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[56635] trunk: Themes: Deprecate usage of `TEMPLATEPATH` and `STYLESHEETPATH` constants.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/56635">56635</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/56635","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>flixos90</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2023-09-20 17:25:26 +0000 (Wed, 20 Sep 2023)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Themes: Deprecate usage of `TEMPLATEPATH` and `STYLESHEETPATH` constants.

While generally the functions `get_template_directory()` and `get_stylesheet_directory()` were long recommended to use to get the parent or child theme directory, the `TEMPLATEPATH` and `STYLESHEETPATH` constants were still used in a few places in core, most importantly in template related logic.

The remaining usage was problematic as it prevented testability of certain key components of WordPress core.

This changeset replaces all remaining usage with the corresponding functions and effectively marks these constants as deprecated. It also adds test coverage accordingly and even unlocks some existing, previously commented out test coverage to work as expected.

Performance of the new approach has been benchmarked and shows no notable differences. Yet, given that the current theme directories are not expected to change within a regular WordPress page load, the `get_template_directory()` and `get_stylesheet_directory()` functions were amended with in-memory caching of the result, unless one of the defining values is being filtered.

Props thekt12, spacedmonkey, mukesh27, aaroncampbell, scribu, lloydbudd, cais, chipbennett, toscho, omarabid, CrazyJaco, DrewAPicture, obenland, wonderboymusic, nacin, helen, dd32, chriscct7, SergeyBiryukov, swissspidy, joemcgill, flixos90.
Fixes <a href="https://core.trac.wordpress.org/ticket/18298">#18298</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminincludesthemephp">trunk/src/wp-admin/includes/theme.php</a></li>
<li><a href="#trunksrcwpincludescommenttemplatephp">trunk/src/wp-includes/comment-template.php</a></li>
<li><a href="#trunksrcwpincludesdefaultconstantsphp">trunk/src/wp-includes/default-constants.php</a></li>
<li><a href="#trunksrcwpincludesloadphp">trunk/src/wp-includes/load.php</a></li>
<li><a href="#trunksrcwpincludestemplatephp">trunk/src/wp-includes/template.php</a></li>
<li><a href="#trunksrcwpincludesthemephp">trunk/src/wp-includes/theme.php</a></li>
<li><a href="#trunktestsphpunittestscommentcommentsTemplatephp">trunk/tests/phpunit/tests/comment/commentsTemplate.php</a></li>
<li><a href="#trunktestsphpunittestscommentwpListCommentsphp">trunk/tests/phpunit/tests/comment/wpListComments.php</a></li>
<li><a href="#trunktestsphpunittestsgeneraltemplatephp">trunk/tests/phpunit/tests/general/template.php</a></li>
<li><a href="#trunktestsphpunitteststemplatephp">trunk/tests/phpunit/tests/template.php</a></li>
<li><a href="#trunktestsphpunitteststhemephp">trunk/tests/phpunit/tests/theme.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminincludesthemephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/theme.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/theme.php     2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/src/wp-admin/includes/theme.php       2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1166,11 +1166,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * creating a fatal error.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! empty( $redirect ) ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $stylesheet_path = get_stylesheet_directory();
+               $template_path   = get_template_directory();
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $functions_path = '';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( str_contains( STYLESHEETPATH, $extension ) ) {
-                       $functions_path = STYLESHEETPATH . '/functions.php';
-               } elseif ( str_contains( TEMPLATEPATH, $extension ) ) {
-                       $functions_path = TEMPLATEPATH . '/functions.php';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( str_contains( $stylesheet_path, $extension ) ) {
+                       $functions_path = $stylesheet_path . '/functions.php';
+               } elseif ( str_contains( $template_path, $extension ) ) {
+                       $functions_path = $template_path . '/functions.php';
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! empty( $functions_path ) ) {
</span></span></pre></div>
<a id="trunksrcwpincludescommenttemplatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/comment-template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/comment-template.php        2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/src/wp-includes/comment-template.php  2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1381,7 +1381,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * and the post ID respectively.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * The `$file` path is passed through a filter hook called {@see 'comments_template'},
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * which includes the TEMPLATEPATH and $file combined. Tries the $filtered path
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * which includes the template directory and $file combined. Tries the $filtered path
</ins><span class="cx" style="display: block; padding: 0 10px">  * first and if it fails it will require the default comment template from the
</span><span class="cx" style="display: block; padding: 0 10px">  * default theme. If either does not exist, then the WordPress process will be
</span><span class="cx" style="display: block; padding: 0 10px">  * halted. It is advised for that reason, that the default theme is not deleted.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1600,8 +1600,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                define( 'COMMENTS_TEMPLATE', true );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $theme_template = STYLESHEETPATH . $file;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $stylesheet_path = get_stylesheet_directory();
+       $template_path   = get_template_directory();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $theme_template = $stylesheet_path . $file;
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><span class="cx" style="display: block; padding: 0 10px">         * Filters the path to the theme template file used for the comments template.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1613,8 +1616,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( file_exists( $include ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                require $include;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } elseif ( file_exists( TEMPLATEPATH . $file ) ) {
-               require TEMPLATEPATH . $file;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ } elseif ( file_exists( $template_path . $file ) ) {
+               require $template_path . $file;
</ins><span class="cx" style="display: block; padding: 0 10px">         } else { // Backward compat code will be removed in a future release.
</span><span class="cx" style="display: block; padding: 0 10px">                require ABSPATH . WPINC . '/theme-compat/comments.php';
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span></span></pre></div>
<a id="trunksrcwpincludesdefaultconstantsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/default-constants.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/default-constants.php       2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/src/wp-includes/default-constants.php 2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -407,6 +407,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Filesystem path to the current active template directory.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 1.5.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @deprecated 6.4.0 Use get_template_directory() instead.
+        * @see get_template_directory()
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        define( 'TEMPLATEPATH', get_template_directory() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -414,6 +416,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Filesystem path to the current active template stylesheet directory.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 2.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @deprecated 6.4.0 Use get_stylesheet_directory() instead.
+        * @see get_stylesheet_directory()
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        define( 'STYLESHEETPATH', get_stylesheet_directory() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludesloadphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/load.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/load.php    2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/src/wp-includes/load.php      2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1049,11 +1049,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                return $themes;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( TEMPLATEPATH !== STYLESHEETPATH ) {
-               $themes[] = STYLESHEETPATH;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $stylesheet_path = get_stylesheet_directory();
+       $template_path   = get_template_directory();
+
+       if ( $template_path !== $stylesheet_path ) {
+               $themes[] = $stylesheet_path;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $themes[] = TEMPLATEPATH;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $themes[] = $template_path;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /*
</span><span class="cx" style="display: block; padding: 0 10px">         * Remove themes from the list of active themes when we're on an endpoint
</span></span></pre></div>
<a id="trunksrcwpincludestemplatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/template.php        2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/src/wp-includes/template.php  2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -684,8 +684,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Retrieves the name of the highest priority template file that exists.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Searches in the STYLESHEETPATH before TEMPLATEPATH and wp-includes/theme-compat
- * so that themes which inherit from a parent theme can just overload one file.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Searches in the stylesheet directory before the template directory and
+ * wp-includes/theme-compat so that themes which inherit from a parent theme
+ * can just overload one file.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 2.7.0
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 5.5.0 The `$args` parameter was added.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -699,16 +700,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @return string The template filename if one is located.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function locate_template( $template_names, $load = false, $load_once = true, $args = array() ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $stylesheet_path = get_stylesheet_directory();
+       $template_path   = get_template_directory();
+       $is_child_theme  = $stylesheet_path !== $template_path;
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $located = '';
</span><span class="cx" style="display: block; padding: 0 10px">        foreach ( (array) $template_names as $template_name ) {
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $template_name ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        continue;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) {
-                       $located = STYLESHEETPATH . '/' . $template_name;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( file_exists( $stylesheet_path . '/' . $template_name ) ) {
+                       $located = $stylesheet_path . '/' . $template_name;
</ins><span class="cx" style="display: block; padding: 0 10px">                         break;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                } elseif ( is_child_theme() && file_exists( TEMPLATEPATH . '/' . $template_name ) ) {
-                       $located = TEMPLATEPATH . '/' . $template_name;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         } elseif ( $is_child_theme && file_exists( $template_path . '/' . $template_name ) ) {
+                       $located = $template_path . '/' . $template_name;
</ins><span class="cx" style="display: block; padding: 0 10px">                         break;
</span><span class="cx" style="display: block; padding: 0 10px">                } elseif ( file_exists( ABSPATH . WPINC . '/theme-compat/' . $template_name ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $located = ABSPATH . WPINC . '/theme-compat/' . $template_name;
</span></span></pre></div>
<a id="trunksrcwpincludesthemephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/theme.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/theme.php   2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/src/wp-includes/theme.php     2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -157,7 +157,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @return bool True if a child theme is in use, false otherwise.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function is_child_theme() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return ( TEMPLATEPATH !== STYLESHEETPATH );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ return get_template_directory() !== get_stylesheet_directory();
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -187,24 +187,40 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Retrieves stylesheet directory path for the active theme.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 1.5.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.4.0 Memoizes filter execution so that it only runs once for the current theme.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @global string $wp_stylesheet_path Current theme stylesheet directory path.
+ *
</ins><span class="cx" style="display: block; padding: 0 10px">  * @return string Path to active theme's stylesheet directory.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function get_stylesheet_directory() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $stylesheet     = get_stylesheet();
-       $theme_root     = get_theme_root( $stylesheet );
-       $stylesheet_dir = "$theme_root/$stylesheet";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ global $wp_stylesheet_path;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        /**
-        * Filters the stylesheet directory path for the active theme.
-        *
-        * @since 1.5.0
-        *
-        * @param string $stylesheet_dir Absolute path to the active theme.
-        * @param string $stylesheet     Directory name of the active theme.
-        * @param string $theme_root     Absolute path to themes directory.
-        */
-       return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( null === $wp_stylesheet_path ) {
+               $stylesheet     = get_stylesheet();
+               $theme_root     = get_theme_root( $stylesheet );
+               $stylesheet_dir = "$theme_root/$stylesheet";
+
+               /**
+                * Filters the stylesheet directory path for the active theme.
+                *
+                * @since 1.5.0
+                *
+                * @param string $stylesheet_dir Absolute path to the active theme.
+                * @param string $stylesheet     Directory name of the active theme.
+                * @param string $theme_root     Absolute path to themes directory.
+                */
+               $stylesheet_dir = apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
+
+               // If there are filter callbacks, force the logic to execute on every call.
+               if ( has_filter( 'stylesheet' ) || has_filter( 'theme_root' ) || has_filter( 'stylesheet_directory' ) ) {
+                       return $stylesheet_dir;
+               }
+
+               $wp_stylesheet_path = $stylesheet_dir;
+       }
+
+       return $wp_stylesheet_path;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -321,24 +337,40 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Retrieves template directory path for the active theme.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 1.5.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.4.0 Memoizes filter execution so that it only runs once for the current theme.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @global string $wp_template_path Current theme template directory path.
+ *
</ins><span class="cx" style="display: block; padding: 0 10px">  * @return string Path to active theme's template directory.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function get_template_directory() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $template     = get_template();
-       $theme_root   = get_theme_root( $template );
-       $template_dir = "$theme_root/$template";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ global $wp_template_path;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        /**
-        * Filters the active theme directory path.
-        *
-        * @since 1.5.0
-        *
-        * @param string $template_dir The path of the active theme directory.
-        * @param string $template     Directory name of the active theme.
-        * @param string $theme_root   Absolute path to the themes directory.
-        */
-       return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( null === $wp_template_path ) {
+               $template     = get_template();
+               $theme_root   = get_theme_root( $template );
+               $template_dir = "$theme_root/$template";
+
+               /**
+                * Filters the active theme directory path.
+                *
+                * @since 1.5.0
+                *
+                * @param string $template_dir The path of the active theme directory.
+                * @param string $template     Directory name of the active theme.
+                * @param string $theme_root   Absolute path to the themes directory.
+                */
+               $template_dir = apply_filters( 'template_directory', $template_dir, $template, $theme_root );
+
+               // If there are filter callbacks, force the logic to execute on every call.
+               if ( has_filter( 'template' ) || has_filter( 'theme_root' ) || has_filter( 'template_directory' ) ) {
+                       return $template_dir;
+               }
+
+               $wp_template_path = $template_dir;
+       }
+
+       return $wp_template_path;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -744,11 +776,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @global WP_Customize_Manager $wp_customize
</span><span class="cx" style="display: block; padding: 0 10px">  * @global array                $sidebars_widgets
</span><span class="cx" style="display: block; padding: 0 10px">  * @global array                $wp_registered_sidebars
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @global string               $wp_stylesheet_path
+ * @global string               $wp_template_path
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @param string $stylesheet Stylesheet name.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function switch_theme( $stylesheet ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        global $wp_theme_directories, $wp_customize, $sidebars_widgets, $wp_registered_sidebars;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ global $wp_theme_directories, $wp_customize, $sidebars_widgets, $wp_registered_sidebars, $wp_stylesheet_path, $wp_template_path;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $requirements = validate_theme_requirements( $stylesheet );
</span><span class="cx" style="display: block; padding: 0 10px">        if ( is_wp_error( $requirements ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -832,6 +866,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        update_option( 'theme_switched', $old_theme->get_stylesheet() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /*
+        * Reset globals to force refresh the next time these directories are
+        * accessed via `get_stylesheet_directory()` / `get_template_directory()`.
+        */
+       $wp_stylesheet_path = null;
+       $wp_template_path   = null;
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><span class="cx" style="display: block; padding: 0 10px">         * Fires after the theme is switched.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span></span></pre></div>
<a id="trunktestsphpunittestscommentcommentsTemplatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/comment/commentsTemplate.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/comment/commentsTemplate.php    2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/tests/phpunit/tests/comment/commentsTemplate.php      2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -10,6 +10,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> class Tests_Comment_CommentsTemplate extends WP_UnitTestCase {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Performs setup tasks for every test.
+        */
+       public function set_up() {
+               parent::set_up();
+               switch_theme( 'default' );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * @ticket 8071
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function test_should_respect_comment_order_asc_when_default_comments_page_is_newest() {
</span></span></pre></div>
<a id="trunktestsphpunittestscommentwpListCommentsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/comment/wpListComments.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/comment/wpListComments.php      2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/tests/phpunit/tests/comment/wpListComments.php        2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -6,7 +6,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @covers ::wp_list_comments
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> class Tests_Comment_WpListComments extends WP_UnitTestCase {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Performs setup tasks for every test.
+        */
+       public function set_up() {
+               parent::set_up();
+               switch_theme( 'default' );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * @ticket 35175
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function test_should_respect_page_param() {
</span></span></pre></div>
<a id="trunktestsphpunittestsgeneraltemplatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/general/template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/general/template.php    2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/tests/phpunit/tests/general/template.php      2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -10,6 +10,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require_once ABSPATH . 'wp-admin/includes/class-wp-site-icon.php';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> class Tests_General_Template extends WP_UnitTestCase {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">         protected $wp_site_icon;
</span><span class="cx" style="display: block; padding: 0 10px">        public $site_icon_id;
</span><span class="cx" style="display: block; padding: 0 10px">        public $site_icon_url;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41,6 +42,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public function set_up() {
</span><span class="cx" style="display: block; padding: 0 10px">                parent::set_up();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                switch_theme( 'default' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->wp_site_icon = new WP_Site_Icon();
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsphpunitteststemplatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/template.php    2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/tests/phpunit/tests/template.php      2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -629,6 +629,44 @@
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * Tests that `locate_template()` uses the current theme even after switching the theme.
+        *
+        * @ticket 18298
+        *
+        * @covers ::locate_template
+        */
+       public function test_locate_template_uses_current_theme() {
+               $themes = wp_get_themes();
+
+               // Look for parent themes with an index.php template.
+               $relevant_themes = array();
+               foreach ( $themes as $theme ) {
+                       if ( $theme->get_stylesheet() !== $theme->get_template() ) {
+                               continue;
+                       }
+                       $php_templates = $theme['Template Files'];
+                       if ( ! isset( $php_templates['index.php'] ) ) {
+                               continue;
+                       }
+                       $relevant_themes[] = $theme;
+               }
+               if ( count( $relevant_themes ) < 2 ) {
+                       $this->markTestSkipped( 'Test requires at least two parent themes with an index.php template.' );
+               }
+
+               $template_names = array( 'index.php' );
+
+               $old_theme = $relevant_themes[0];
+               $new_theme = $relevant_themes[1];
+
+               switch_theme( $old_theme->get_stylesheet() );
+               $this->assertSame( $old_theme->get_stylesheet_directory() . '/index.php', locate_template( $template_names ), 'Incorrect index template found in initial theme.' );
+
+               switch_theme( $new_theme->get_stylesheet() );
+               $this->assertSame( $new_theme->get_stylesheet_directory() . '/index.php', locate_template( $template_names ), 'Incorrect index template found in theme after switch.' );
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         public function assertTemplateHierarchy( $url, array $expected, $message = '' ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $this->go_to( $url );
</span><span class="cx" style="display: block; padding: 0 10px">                $hierarchy = $this->get_template_hierarchy();
</span></span></pre></div>
<a id="trunktestsphpunitteststhemephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/theme.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/theme.php       2023-09-20 16:47:44 UTC (rev 56634)
+++ trunk/tests/phpunit/tests/theme.php 2023-09-20 17:25:26 UTC (rev 56635)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36,8 +36,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                parent::set_up();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Sets up the `wp-content/themes/` directory to ensure consistency when running tests.
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->orig_theme_dir = $wp_theme_directories;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $wp_theme_directories = array( WP_CONTENT_DIR . '/themes' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $wp_theme_directories = array( WP_CONTENT_DIR . '/themes', realpath( DIR_TESTDATA . '/themedir1' ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                add_filter( 'extra_theme_headers', array( $this, 'theme_data_extra_headers' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                wp_clean_themes_cache();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -282,6 +283,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                for ( $i = 0; $i < 3; $i++ ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        foreach ( $themes as $name => $theme ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                // Skip invalid theme directory names (such as `block_theme-[0.4.0]`).
+                               if ( ! preg_match( '/^[a-z0-9-]+$/', $theme['Stylesheet'] ) ) {
+                                       continue;
+                               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 // Switch to this theme.
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( 2 === $i ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        switch_theme( $theme['Template'], $theme['Stylesheet'] );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -289,16 +295,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        switch_theme( $theme['Stylesheet'] );
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->assertSame( $name, get_current_theme() );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $this->assertSame( $theme['Name'], get_current_theme() );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                // Make sure the various get_* functions return the correct values.
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->assertSame( $theme['Template'], get_template() );
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->assertSame( $theme['Stylesheet'], get_stylesheet() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $root_fs = get_theme_root();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $root_fs = $theme->get_theme_root();
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $this->assertTrue( is_dir( $root_fs ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $root_uri = get_theme_root_uri();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $root_uri = $theme->get_theme_root_uri();
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $this->assertNotEmpty( $root_uri );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->assertSame( $root_fs . '/' . get_stylesheet(), get_stylesheet_directory() );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -309,19 +315,38 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->assertSame( $root_fs . '/' . get_template(), get_template_directory() );
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->assertSame( $root_uri . '/' . get_template(), get_template_directory_uri() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                // get_query_template()
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         // Skip block themes for get_query_template() tests since this test is focused on classic templates.
+                               if ( wp_is_block_theme() && current_theme_supports( 'block-templates' ) ) {
+                                       continue;
+                               }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                // Template file that doesn't exist.
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->assertSame( '', get_query_template( 'nonexistant' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                // Template files that do exist.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                /*
</del><span class="cx" style="display: block; padding: 0 10px">                                 foreach ( $theme['Template Files'] as $path ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $file = basename($path, '.php');
-                                       FIXME: untestable because get_query_template() uses TEMPLATEPATH.
-                                       $this->assertSame('', get_query_template($file));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 $file = basename( $path, '.php' );
+
+                                       // The functions.php file is not a template.
+                                       if ( 'functions' === $file ) {
+                                               continue;
+                                       }
+
+                                       // Underscores are not supported by `locate_template()`.
+                                       if ( 'taxonomy-post_format' === $file ) {
+                                               $file = 'taxonomy';
+                                       }
+
+                                       $child_theme_file  = get_stylesheet_directory() . '/' . $file . '.php';
+                                       $parent_theme_file = get_template_directory() . '/' . $file . '.php';
+                                       if ( file_exists( $child_theme_file ) ) {
+                                               $this->assertSame( $child_theme_file, get_query_template( $file ) );
+                                       } elseif ( file_exists( $parent_theme_file ) ) {
+                                               $this->assertSame( $parent_theme_file, get_query_template( $file ) );
+                                       } else {
+                                               $this->assertSame( '', get_query_template( $file ) );
+                                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                                 }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                */
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                // These are kind of tautologies but at least exercise the code.
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->assertSame( get_404_template(), get_query_template( '404' ) );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -855,6 +880,184 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Tests that a theme in the custom test data theme directory is recognized.
+        *
+        * @ticket 18298
+        */
+       public function test_theme_in_custom_theme_dir_is_valid() {
+               switch_theme( 'block-theme' );
+               $this->assertTrue( wp_get_theme()->exists() );
+       }
+
+       /**
+        * Tests that `is_child_theme()` returns true for child theme.
+        *
+        * @ticket 18298
+        *
+        * @covers ::is_child_theme
+        */
+       public function test_is_child_theme_true() {
+               switch_theme( 'block-theme-child' );
+               $this->assertTrue( is_child_theme() );
+       }
+
+       /**
+        * Tests that `is_child_theme()` returns false for parent theme.
+        *
+        * @ticket 18298
+        *
+        * @covers ::is_child_theme
+        */
+       public function test_is_child_theme_false() {
+               switch_theme( 'block-theme' );
+               $this->assertFalse( is_child_theme() );
+       }
+
+       /**
+        * Tests that the child theme directory is correctly detected.
+        *
+        * @ticket 18298
+        *
+        * @covers ::get_stylesheet_directory
+        */
+       public function test_get_stylesheet_directory() {
+               switch_theme( 'block-theme-child' );
+               $this->assertSame( realpath( DIR_TESTDATA ) . '/themedir1/block-theme-child', get_stylesheet_directory() );
+       }
+
+       /**
+        * Tests that the parent theme directory is correctly detected.
+        *
+        * @ticket 18298
+        *
+        * @covers ::get_template_directory
+        */
+       public function test_get_template_directory() {
+               switch_theme( 'block-theme-child' );
+               $this->assertSame( realpath( DIR_TESTDATA ) . '/themedir1/block-theme', get_template_directory() );
+       }
+
+       /**
+        * Tests that get_stylesheet_directory() behaves correctly with filters.
+        *
+        * @ticket 18298
+        * @dataProvider data_get_stylesheet_directory_with_filter
+        *
+        * @covers ::get_stylesheet_directory
+        *
+        * @param string   $theme     Theme slug / directory name.
+        * @param string   $hook_name Filter hook name.
+        * @param callable $callback  Filter callback.
+        * @param string   $expected  Expected stylesheet directory with the filter active.
+        */
+       public function test_get_stylesheet_directory_with_filter( $theme, $hook_name, $callback, $expected ) {
+               switch_theme( $theme );
+
+               // Add filter, then call get_stylesheet_directory() to compute value.
+               add_filter( $hook_name, $callback );
+               $this->assertSame( $expected, get_stylesheet_directory(), 'Stylesheet directory returned incorrect result not considering filters' );
+
+               // Remove filter again, then ensure result is recalculated and not the same as before.
+               remove_filter( $hook_name, $callback );
+               $this->assertNotSame( $expected, get_stylesheet_directory(), 'Stylesheet directory returned previous value even though filters were removed' );
+       }
+
+       /**
+        * Data provider for `test_get_stylesheet_directory_with_filter()`.
+        *
+        * @return array[]
+        */
+       public function data_get_stylesheet_directory_with_filter() {
+               return array(
+                       'with stylesheet_directory filter' => array(
+                               'block-theme',
+                               'stylesheet_directory',
+                               static function ( $dir ) {
+                                       return str_replace( realpath( DIR_TESTDATA ) . '/themedir1', '/fantasy-dir', $dir );
+                               },
+                               '/fantasy-dir/block-theme',
+                       ),
+                       'with theme_root filter'           => array(
+                               'block-theme',
+                               'theme_root',
+                               static function () {
+                                       return '/fantasy-dir';
+                               },
+                               '/fantasy-dir/block-theme',
+                       ),
+                       'with stylesheet filter'           => array(
+                               'block-theme',
+                               'stylesheet',
+                               static function () {
+                                       return 'another-theme';
+                               },
+                               // Because the theme does not exist, `get_theme_root()` returns the default themes directory.
+                               WP_CONTENT_DIR . '/themes/another-theme',
+                       ),
+               );
+       }
+
+       /**
+        * Tests that get_template_directory() behaves correctly with filters.
+        *
+        * @ticket 18298
+        * @dataProvider data_get_template_directory_with_filter
+        *
+        * @covers ::get_template_directory
+        *
+        * @param string   $theme     Theme slug / directory name.
+        * @param string   $hook_name Filter hook name.
+        * @param callable $callback  Filter callback.
+        * @param string   $expected  Expected template directory with the filter active.
+        */
+       public function test_get_template_directory_with_filter( $theme, $hook_name, $callback, $expected ) {
+               switch_theme( $theme );
+
+               // Add filter, then call get_template_directory() to compute value.
+               add_filter( $hook_name, $callback );
+               $this->assertSame( $expected, get_template_directory(), 'Template directory returned incorrect result not considering filters' );
+
+               // Remove filter again, then ensure result is recalculated and not the same as before.
+               remove_filter( $hook_name, $callback );
+               $this->assertNotSame( $expected, get_template_directory(), 'Template directory returned previous value even though filters were removed' );
+       }
+
+       /**
+        * Data provider for `test_get_template_directory_with_filter()`.
+        *
+        * @return array[]
+        */
+       public function data_get_template_directory_with_filter() {
+               return array(
+                       'with template_directory filter' => array(
+                               'block-theme',
+                               'template_directory',
+                               static function ( $dir ) {
+                                       return str_replace( realpath( DIR_TESTDATA ) . '/themedir1', '/fantasy-dir', $dir );
+                               },
+                               '/fantasy-dir/block-theme',
+                       ),
+                       'with theme_root filter'         => array(
+                               'block-theme',
+                               'theme_root',
+                               static function () {
+                                       return '/fantasy-dir';
+                               },
+                               '/fantasy-dir/block-theme',
+                       ),
+                       'with template filter'           => array(
+                               'block-theme',
+                               'template',
+                               static function () {
+                                       return 'another-theme';
+                               },
+                               // Because the theme does not exist, `get_theme_root()` returns the default themes directory.
+                               WP_CONTENT_DIR . '/themes/another-theme',
+                       ),
+               );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Helper function to ensure that a block theme is available and active.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        private function helper_requires_block_theme() {
</span></span></pre>
</div>
</div>

</body>
</html>