<!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>[10173] sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory: Plugin dir: check for unique namespaces in the block checker.</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="http://meta.trac.wordpress.org/changeset/10173">10173</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/10173","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>tellyworth</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2020-08-17 05:23:02 +0000 (Mon, 17 Aug 2020)</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'>Plugin dir: check for unique namespaces in the block checker.

This should permit block namespaces to be reused by the same author, but otherwise require that the namespace be unique.

See <a href="http://meta.trac.wordpress.org/ticket/5303">#5303</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginsplugindirectorycliclassblockplugincheckerphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-block-plugin-checker.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginsplugindirectoryshortcodesclassblockvalidatorphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-block-validator.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginsplugindirectorycliclassblockplugincheckerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-block-plugin-checker.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-block-plugin-checker.php      2020-08-14 05:27:45 UTC (rev 10172)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-block-plugin-checker.php        2020-08-17 05:23:02 UTC (rev 10173)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -6,6 +6,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use WordPressdotorg\Plugin_Directory\Tools\SVN;
</span><span class="cx" style="display: block; padding: 0 10px"> use WordPressdotorg\Plugin_Directory\Block_JSON\Parser as Block_JSON_Parser;
</span><span class="cx" style="display: block; padding: 0 10px"> use WordPressdotorg\Plugin_Directory\Block_JSON\Validator as Block_JSON_Validator;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use WordPressdotorg\Plugin_Directory\Plugin_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">  * A class that can examine a plugin, and evaluate and return status info that would be useful for a validator or similar tool.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -98,6 +99,42 @@
</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">+         * Return the namespace part of a block name.
+        *
+        * @param string $block The block name.
+        * @return string|bool The namespace, or false if the block name was invalid.
+        */
+       public function get_namespace( $block ) {
+               $parts = explode( '/', $block, 2 );
+               if ( 2 === count( $parts ) ) {
+                       return $parts[0];
+               }
+               return false;
+       }
+
+       /**
+        * Return a list of contributors for a given plugin.
+        *
+        * @param WP_Post|int $post The post object or ID.
+        */
+       public function get_plugin_contributors( $post ) {
+               $post = get_post( $post );
+
+               $contributors = get_terms( array(
+                       'taxonomy'   => 'plugin_contributors',
+                       'object_ids' => array( $post->ID ),
+                       'orderby'    => 'term_order',
+                       'fields'     => 'names',
+               ) );
+
+               if ( is_wp_error( $contributors ) ) {
+                       return array();
+               }
+
+               return $contributors;
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Check a plugin given the URL of a Subversion or GitHub repo.
</span><span class="cx" style="display: block; padding: 0 10px">         * Note that only hosts listed in $allowed_hosts are permitted.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -356,7 +393,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        } elseif ( '(' === $token[0] ) {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                while ( $last = array_pop( $context ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        if ( T_STRING === $last[0] && function_exists( $last[1] ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 if ( is_array( $last ) && T_STRING === $last[0] && function_exists( $last[1] ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 $function_calls[] = array( $last[1], $last[2], $file );
</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">@@ -609,6 +646,92 @@
</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">+         * Namespace shouldn't clash with other plugins.
+        */
+       function check_for_unique_namespace() {
+               $namespaces = array();
+               foreach ( $this->blocks as $block ) {
+                       if ( $parts = explode( '/', $block->name ) ) {
+                               $namespaces[] = $parts[0] . '/';
+                       }
+               }
+
+               $namespaces = array_unique( $namespaces );
+
+               // Ignore known bogus namespaces
+               $namespaces = array_diff( $namespaces, array( 'cgb/', 'create-block/', 'example/', 'block/', 'core/' ) );
+
+               if ( count( $namespaces ) > 0 ) {
+                       foreach ( $namespaces as $namespace ) {
+                               $meta_query[] = array(
+                                       'key'      => 'block_name',
+                                       'value'    => $namespace,
+                                       'compare'  => 'LIKE',
+                               );
+                       }
+                       if ( count( $meta_query ) > 1 ) {
+                               $meta_query[ 'relation' ] = 'OR';
+                       }
+
+                       $args = array(
+                               'post_type' => 'plugin',
+                               'post_status' => 'publish',
+                               'nopaging' => true,
+                               'meta_query' => $meta_query,
+                       );
+
+                       $query = new \WP_Query( $args );
+
+                       foreach ( $query->posts as $post ) {
+                               if ( $post->post_name === $this->slug ) {
+                                       continue;
+                               }
+
+                               $blocks = get_post_meta( $post->ID, 'block_name', false );
+                               foreach ( $blocks as $block ) {
+                                       if ( in_array( $this->get_namespace( $block ) . '/', $namespaces ) ) {
+
+                                               if ( $this->slug ) {
+                                                       // We're testing a plugin that's in the directory already, so we can check to see if the other plugin shares some contributors.
+
+                                                       $this_plugin_contribs = $this->get_plugin_contributors( Plugin_Directory::get_plugin_post( $this->slug ) );
+                                                       $other_plugin_contribs = $this->get_plugin_contributors( $post );
+
+                                                       if ( !array_intersect( $this_plugin_contribs, $other_plugin_contribs ) ) { 
+                                                               // If the other plugin has some contributors in common, it's probably fine to share a namespace.
+                                                               // If not, it's an error that needs to be fixed.
+                                                               $this->record_result(
+                                                                       __FUNCTION__,
+                                                                       'error',
+                                                                       // translators: %1$s is the namespace, %2$s is a link to the plugin.
+                                                                       sprintf( __( 'Please use a unique block namespace. Namespace %1$s is already used by %2$s.' ), 
+                                                                               '<code>' . $this->get_namespace( $block ) . '</code>', 
+                                                                               '<a href="' . esc_url( get_permalink( $post ) ) . '">' . esc_html( $post->post_title ) . '</a>'
+                                                                       )
+                                                               );
+                                                       }
+                                               } else {
+                                                       // We're testing a plugin that's elsewhere (GitHub?) so we don't know its authors.
+                                                       // If the namespace is used by another plugin we'll just warn about it, since that might be by the same author.
+                                                       $this->record_result(
+                                                               __FUNCTION__,
+                                                               'warning',
+                                                               // translators: %1$s is the namespace, %2$s is a link to the plugin.
+                                                               sprintf( __( 'Please use a unique block namespace. Namespace %1$s is already used by %2$s.' ), 
+                                                                       '<code>' . $this->get_namespace( $block ) . '</code>', 
+                                                                       '<a href="' . esc_url( get_permalink( $post ) ) . '">' . esc_html( $post->post_title ) . '</a>'
+                                                               )
+                                                       );
+                                               }
+                                       }
+                               }
+                       }
+
+               }
+
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * There should be at least one block.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function check_for_blocks() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -687,8 +810,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        /* translators: %s is a list of block names. */
</span><span class="cx" style="display: block; padding: 0 10px">                                        __( 'More than one top-level block was found: %s', 'wporg-plugins' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        implode( ', ', $list )
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                ),
-                               $block_name
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         )
</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></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginsplugindirectoryshortcodesclassblockvalidatorphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-block-validator.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-block-validator.php    2020-08-14 05:27:45 UTC (rev 10172)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-block-validator.php      2020-08-17 05:23:02 UTC (rev 10173)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -327,6 +327,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                return __( 'Larger plugins will take longer to install. This is more noticeable in the Block Directory, where the user expects blocks to be added immediately. Try reducing your file size by optimizing images & SVGs, only including the assets you need (images, fonts, etc), and using core-provided JavaScript libraries.', 'wporg-plugins' );
</span><span class="cx" style="display: block; padding: 0 10px">                        case 'check_for_multiple_namespaces':
</span><span class="cx" style="display: block; padding: 0 10px">                                return __( 'Block plugins should contain a single main block. Any children blocks should use the same namespace prefix as the main block. Please ensure there are no extraneous blocks included by mistake.', 'wporg-plugins' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        case 'check_for_unique_namespace':
+                               return __( 'Blocks should use a namespace that is unique to the plugin or its author. It appears this namespace is already in use by another author. If that&#8217;s not you then please ensure you choose a unique namespace for your blocks. The plugin slug is a good choice.' );
</ins><span class="cx" style="display: block; padding: 0 10px">                         // This is a special case, since multiple values may be collapsed.
</span><span class="cx" style="display: block; padding: 0 10px">                        case 'check_block_json_is_valid':
</span><span class="cx" style="display: block; padding: 0 10px">                                return false;
</span></span></pre>
</div>
</div>

</body>
</html>