<!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>[59742] trunk: Editor: Fix block template registration failing for custom post types containing underscore characters.</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/59742">59742</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/59742","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>2025-01-30 21:17:04 +0000 (Thu, 30 Jan 2025)</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'>Editor: Fix block template registration failing for custom post types containing underscore characters.
Custom post types may contain underscores, however block template registration has been using a regular expression that disallows underscores. Since the block template name for certain templates is directly associated with which post type it applies to, this regular expression was causing unexpected failures. This changeset adjusts the regular expression to allow block template names with underscore characters, effectively allowing block templates to be registered for any custom post type.
Props alexandrebuffet, ankitkumarshah, gaambo, jorbin, karthickmurugan, oglekler, poena, sukhendu2002.
Fixes <a href="https://core.trac.wordpress.org/ticket/62523">#62523</a>.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpblocktemplatesregistryphp">trunk/src/wp-includes/class-wp-block-templates-registry.php</a></li>
<li><a href="#trunktestsphpunittestsblocktemplatesWpBlockTemplatesRegistryphp">trunk/tests/phpunit/tests/block-templates/WpBlockTemplatesRegistry.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesclasswpblocktemplatesregistryphp"></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/class-wp-block-templates-registry.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-block-templates-registry.php 2025-01-30 20:42:03 UTC (rev 59741)
+++ trunk/src/wp-includes/class-wp-block-templates-registry.php 2025-01-30 21:17:04 UTC (rev 59742)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50,7 +50,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> } elseif ( preg_match( '/[A-Z]+/', $template_name ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $error_message = __( 'Template names must not contain uppercase characters.' );
</span><span class="cx" style="display: block; padding: 0 10px"> $error_code = 'template_name_no_uppercase';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- } elseif ( ! preg_match( '/^[a-z0-9-]+\/\/[a-z0-9-]+$/', $template_name ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ } elseif ( ! preg_match( '/^[a-z0-9_\-]+\/\/[a-z0-9_\-]+$/', $template_name ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $error_message = __( 'Template names must contain a namespace prefix. Example: my-plugin//my-custom-template' );
</span><span class="cx" style="display: block; padding: 0 10px"> $error_code = 'template_no_prefix';
</span><span class="cx" style="display: block; padding: 0 10px"> } elseif ( $this->is_registered( $template_name ) ) {
</span></span></pre></div>
<a id="trunktestsphpunittestsblocktemplatesWpBlockTemplatesRegistryphp"></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/block-templates/WpBlockTemplatesRegistry.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/block-templates/WpBlockTemplatesRegistry.php 2025-01-30 20:42:03 UTC (rev 59741)
+++ trunk/tests/phpunit/tests/block-templates/WpBlockTemplatesRegistry.php 2025-01-30 21:17:04 UTC (rev 59742)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -267,4 +267,51 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertEquals( $template, $unregistered_template, 'Unregistered template should be the same as the registered one.' );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertFalse( self::$registry->is_registered( $template_name ), 'Template should not be registered after unregistering.' );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ /**
+ * Data provider for test_template_name_validation.
+ *
+ * @return array[] Test data.
+ */
+ public static function data_template_name_validation() {
+ return array(
+ 'valid_simple_name' => array(
+ 'my-plugin//my-template',
+ true,
+ 'Valid template name with simple characters should be accepted',
+ ),
+ 'valid_with_underscores' => array(
+ 'my-plugin//my_template',
+ true,
+ 'Template name with underscores should be accepted',
+ ),
+ 'valid_cpt_archive' => array(
+ 'my-plugin//archive-my_post_type',
+ true,
+ 'Template name for CPT archive with underscore should be accepted',
+ ),
+ );
+ }
+
+ /**
+ * Tests template name validation with various inputs.
+ *
+ * @ticket 62523
+ *
+ * @dataProvider data_template_name_validation
+ *
+ * @param string $template_name The template name to test.
+ * @param bool $expected Expected validation result.
+ * @param string $message Test assertion message.
+ */
+ public function test_template_name_validation( $template_name, $expected, $message ) {
+ $result = self::$registry->register( $template_name, array() );
+
+ if ( $expected ) {
+ self::$registry->unregister( $template_name );
+ $this->assertNotWPError( $result, $message );
+ } else {
+ $this->assertWPError( $result, $message );
+ }
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>
</body>
</html>