<!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>[8713] sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks: WordCamp Blocks: Refactor Sponsors to use data store, other improvements</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/8713">8713</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/8713","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>coreymckrill</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2019-05-01 22:13:13 +0000 (Wed, 01 May 2019)</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'>WordCamp Blocks: Refactor Sponsors to use data store, other improvements

* Changes to block code structure to more closely match other blocks
* Changes to HTML markup of block content
* Memoize the select options
* Add missing doc blocks
* JS linting cleanup

Props vedjain, coreymckrill</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsblockcontentjs">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-content.js</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsblockcontrolsjs">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-controls.js</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorseditjs">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/edit.js</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsindexjs">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/index.js</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsinspectorcontrolsjs">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/inspector-controls.js</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksincludessponsorsphp">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/includes/sponsors.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksviewsponsorsphp">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/view/sponsors.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorssponsorsselectjs">sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/sponsors-select.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsblockcontentjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-content.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-content.js    2019-05-01 22:11:33 UTC (rev 8712)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-content.js      2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,187 +1,132 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * External dependencies
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-import { get, difference } from 'lodash';
-import classnames          from 'classnames';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+import { get }    from 'lodash';
+import classnames from 'classnames';
</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">  * WordPress dependencies
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> const { Component }       = wp.element;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-const { escapeAttribute } = wp.escapeHtml;
</del><span class="cx" style="display: block; padding: 0 10px"> const { __ }              = wp.i18n;
</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">  * Internal dependencies
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-import FeaturedImage                  from '../shared/featured-image';
-import GridContentLayout              from '../shared/grid-layout/block-content';
-import {ItemTitle, ItemHTMLContent, ItemPermalink} from '../shared/block-content';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+import FeaturedImage                                                 from '../shared/featured-image';
+import GridContentLayout                                             from '../shared/grid-layout/block-content';
+import { ItemTitle, ItemHTMLContent, ItemPermalink, BlockNoContent } from '../shared/block-content';
+import { filterEntities }                                            from '../blocks-store';
</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">- * Renders individual sponsor post inside editor.
- *
- * @param {Object} sponsorPost
- * @param {Object} attributes
- *
- * @return {Element}
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Component for displaying the block content.
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-function SponsorDetail( { sponsorPost, attributes } ) {
-       const { show_name, show_logo, content, featured_image_width } = attributes;
-       const displayContent = 'full' === content ? sponsorPost.content.rendered.trim() : sponsorPost.excerpt.rendered.trim();
-
-       return (
-               <div className={ 'wordcamp-sponsor-details wordcamp-sponsor-details-' + escapeAttribute( sponsorPost.slug ) }>
-
-                       { ( show_name || show_name === undefined ) &&
-                               <ItemTitle
-                                       className="wordcamp-sponsor-title"
-                                       headingLevel={ 3 }
-                                       title={ sponsorPost.title.rendered.trim() }
-                                       link={ sponsorPost.link }
-                               />
-                       }
-
-                       { ( show_logo || show_logo === undefined ) &&
-                               <FeaturedImage
-                                       imageData={ get( sponsorPost, '_embedded.wp:featuredmedia[0]', {} ) }
-                                       width={ featured_image_width }
-                                       className={ classnames( 'wordcamp-sponsor-featured-image', 'wordcamp-sponsor-logo' ) }
-                                       imageLink={ sponsorPost.link }
-                               />
-                       }
-
-                       { ( 'none' !== content ) &&
-                               <ItemHTMLContent
-                                       className={ classnames( 'wordcamp-sponsor-content' ) }
-                                       content={ displayContent }
-                               />
-                       }
-
-                       { ( 'full' === content ) &&
-                               <ItemPermalink
-                                       link={ sponsorPost.link }
-                                       linkText={ __( 'Visit sponsor page', 'wordcamporg' ) }
-                               />
-                       }
-               </div>
-       );
-}
-
-/**
- * Component for rendering Sponsors post inside editor.
- */
-class SponsorBlockContent extends Component {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+class SponsorsBlockContent extends Component {
+       /**
+        * Run additional operations during component initialization.
+        *
+        * @param {Object} props
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         constructor( props ) {
</span><span class="cx" style="display: block; padding: 0 10px">                super( props );
</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.state = {
-                       selectedPosts : [],
-                       sortBy        : 'name_asc',
-               };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         this.getFilteredPosts = this.getFilteredPosts.bind( this );
</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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Call back for when featured image URL is changed for a post.
-        * We are storing the URL object as JSON stringified value because I was
-        * not able to get object type to work properly. Maybe its not supported in
-        * Gutenberg yet.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * Filter and sort the content that will be rendered.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @param {number} sponsorId
-        * @param {string} imageURL
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * @returns {Array}
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        setFeaturedImageURL( sponsorId, imageURL ) {
-               const sponsor_image_urls        = this.sponsorImageUrl || {};
-               sponsor_image_urls[ sponsorId ] = imageURL;
-               this.sponsorImageUrl            = sponsor_image_urls;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ getFilteredPosts() {
+               const { attributes, entities } = this.props;
+               const { wcb_sponsor: posts } = entities;
+               const { mode, item_ids, sort } = attributes;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                const { setAttributes }         = this.props;
-               const sponsor_image_urls_latest = this.sponsorImageUrl;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         const args = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                setAttributes( {
-                       sponsor_image_urls: encodeURIComponent( JSON.stringify( sponsor_image_urls_latest ) ),
-               } );
-       }
-
-       componentWillReceiveProps( nextProps ) {
-               // Sort the sponsor posts. Since this could potentially be expensive, lets do it in componentWillReceiveProps hook and set state with result if anything is changed.
-               const { selectedPosts: newSelectedPosts, attributes: newAttributes, sponsorTermOrder: newSponsorTermOrder } = nextProps;
-               const { sort_by: newSortBy } = newAttributes;
-               const newSelectedPostIds = newSelectedPosts.map( ( post ) => post.id ).sort();
-
-               const { selectedPosts, sortBy } = this.state;
-               const selectedPostsIds = selectedPosts.map( ( post ) => post.id ).sort();
-
-               if ( sortBy === newSortBy && newSelectedPosts.length === selectedPosts.length && difference( selectedPostsIds, newSelectedPostIds ).length === 0 ) {
-                       // Everything is same. No need to calculate sorting. Lets bail.
-                       return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( Array.isArray( item_ids ) && item_ids.length > 0 ) {
+                       args.filter  = [
+                               {
+                                       fieldName  : mode === 'wcb_sponsor' ? 'id' : 'wcb_sponsor_level',
+                                       fieldValue : item_ids,
+                               },
+                       ];
</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">-                let sortedPosts;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         args.sort = sort;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                switch ( newSortBy ) {
-                       case 'sponsor_level' :
-                               if ( ! Array.isArray( newSponsorTermOrder ) ||
-                                       newSponsorTermOrder.length === 0 ) {
-                                       break;
-                               }
-                               sortedPosts = newSelectedPosts.sort( ( sponsor1, sponsor2 ) => {
-                                       return newSponsorTermOrder.indexOf( ( sponsor1.sponsor_level || [] )[ 0 ] ) - newSponsorTermOrder.indexOf( ( sponsor2.sponsor_level || [] )[ 0 ] );
-                               } );
-                               break;
-
-                       case 'name_desc' :
-                               sortedPosts = newSelectedPosts.sort( ( sponsor1, sponsor2 ) => {
-                                       const title1 = sponsor1.title.rendered.trim();
-                                       const title2 = sponsor2.title.rendered.trim();
-                                       return title1 > title2 ? -1 : 1;
-                               } );
-                               break;
-
-                       case 'name_asc' :
-                       default:
-                               sortedPosts = newSelectedPosts.sort( ( sponsor1, sponsor2 ) => {
-                                       const title1 = sponsor1.title.rendered.trim();
-                                       const title2 = sponsor2.title.rendered.trim();
-                                       return title1 < title2 ? -1 : 1;
-                               } );
-                               break;
-               }
-
-               this.setState( {
-                       selectedPosts : sortedPosts,
-                       sortBy        : newSortBy,
-               } );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return filterEntities( posts, args );
</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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Renders Sponsor Block content inside editor.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * Render the block content.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @return {Element}
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        render() {
</span><span class="cx" style="display: block; padding: 0 10px">                const { attributes } = this.props;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                const { selectedPosts } = this.state;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         const { show_name, show_logo, content, featured_image_width } = attributes;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                const posts     = this.getFilteredPosts();
+               const isLoading = ! Array.isArray( posts );
+               const hasPosts  = ! isLoading && posts.length > 0;
+
+               if ( isLoading || ! hasPosts ) {
+                       return (
+                               <BlockNoContent loading={ isLoading } />
+                       );
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 return (
</span><span class="cx" style="display: block; padding: 0 10px">                        <GridContentLayout
</span><span class="cx" style="display: block; padding: 0 10px">                                className="wordcamp-sponsors-block"
</span><span class="cx" style="display: block; padding: 0 10px">                                { ...this.props }
</span><span class="cx" style="display: block; padding: 0 10px">                        >
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                {
-                                       selectedPosts.map( ( post ) => {
-                                               return (
-                                                       <SponsorDetail
-                                                               key={ post.id }
-                                                               sponsorPost={ post }
-                                                               attributes={ attributes }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         { posts.map( ( post ) =>
+                                       <div
+                                               key={ post.slug }
+                                               className={ classnames(
+                                                       'wordcamp-sponsor',
+                                                       'wordcamp-sponsor-' + post.slug,
+                                               ) }
+                                       >
+                                               { show_name &&
+                                                       <ItemTitle
+                                                               className="wordcamp-sponsor-title"
+                                                               headingLevel={ 3 }
+                                                               title={ post.title.rendered.trim() }
+                                                               link={ post.link }
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         }
+
+                                               { show_logo &&
+                                                       <FeaturedImage
+                                                               imageData={ get( post, '_embedded.wp:featuredmedia[0]', {} ) }
+                                                               width={ featured_image_width }
+                                                               className={ classnames( 'wordcamp-sponsor-featured-image', 'wordcamp-sponsor-logo' ) }
+                                                               imageLink={ post.link }
+                                                       />
+                                               }
+
+                                               { ( 'none' !== content ) &&
+                                                       <ItemHTMLContent
+                                                               className={ classnames( 'wordcamp-sponsor-content-' + content ) }
+                                                               content={ 'full' === content ? post.content.rendered.trim() : post.excerpt.rendered.trim() }
+                                                       />
+                                               }
+
+                                               { ( 'full' === content ) &&
+                                                       <ItemPermalink
+                                                               link={ post.link }
+                                                               linkText={ __( 'Visit sponsor page', 'wordcamporg' ) }
+                                                       />
+                                               }
+                                       </div>
+                               ) }
</ins><span class="cx" style="display: block; padding: 0 10px">                         </GridContentLayout>
</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><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-export default SponsorBlockContent;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+export default SponsorsBlockContent;
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsblockcontrolsjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-controls.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-controls.js   2019-05-01 22:11:33 UTC (rev 8712)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/block-controls.js     2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,342 +1,93 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * External dependencies
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-import { get, includes, intersection } from 'lodash';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+import classnames from 'classnames';
</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">  * WordPress dependencies
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-const { __ } = wp.i18n;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+const { Button, Placeholder } = wp.components;
+const { __ }                  = wp.i18n;
</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">  * Internal dependencies
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-import { BlockControls, PlaceholderNoContent } from '../shared/block-controls';
-import SponsorBlockContent from './block-content';
-import ItemSelect from '../shared/item-select';
-import { LABEL } from './index';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+import { BlockControls, PlaceholderSpecificMode } from '../shared/block-controls';
+import SponsorsBlockContent                       from './block-content';
+import SponsorsSelect                             from './sponsors-select';
+import { LABEL }                                  from './index';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-const { Button, Placeholder } = wp.components;
-
-function SponsorOption( option ) {
-       let sponsorOption;
-
-       if ( 'post' === option.type ) {
-               sponsorOption = SponsorPostOption( option );
-       } else {
-               sponsorOption = SponsorLevelOption( option );
-       }
-
-       return sponsorOption;
-}
-
-function SponsorPostOption( sponsor ) {
-       return (
-               <span>
-                       { sponsor.label }
-               </span>
-       );
-}
-
-function SponsorLevelOption( sponsorLevel ) {
-       return (
-               <span className="wordcamp-item-select-option-label">
-                       { sponsorLevel.label }
-                       <span className="wordcamp-item-select-option-label-term-count">
-                               { sponsorLevel.count }
-                       </span>
-               </span>
-       );
-}
-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Implements sponsor block controls.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Component for displaying a UI within the block.
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-class SponsorBlockControls extends BlockControls {
-       constructor( props ) {
-               super( props );
-
-               this.state = {
-                       posts            : [],
-                       terms            : [],
-                       loading          : true,
-                       selectedPosts    : [],
-                       sponsorTermOrder : [],
-               };
-
-               this.fetchSelectOptions( props );
-       }
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+class SponsorsBlockControls extends BlockControls {
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Set selectedPosts in state so that SponsorsContentBlock can use them.
-        */
-       setSelectedPosts() {
-               const { fetchedPosts }             = this.state;
-               const { attributes }               = this.props;
-               const { post_ids, term_ids, mode } = attributes;
-               const selectedPosts                = [];
-
-               if ( ! fetchedPosts || ! fetchedPosts.length ) {
-                       return;
-               }
-
-               for ( const post of fetchedPosts ) {
-                       if ( ! post.hasOwnProperty( 'id' ) ) {
-                               continue;
-                       }
-
-                       switch ( mode ) {
-                               case 'all':
-                                       selectedPosts.push( post );
-                                       break;
-
-                               case 'specific_posts':
-                                       if ( -1 !== post_ids.indexOf( post.id ) ) {
-                                               selectedPosts.push( post );
-                                       }
-                                       break;
-
-                               case 'specific_terms':
-                                       if ( intersection( term_ids, post.sponsor_level || [] ).length ) {
-                                               selectedPosts.push( post );
-                                       }
-                                       break;
-
-                               default:
-                                       break;
-                       }
-               }
-
-               this.setState( { selectedPosts } );
-       }
-
-       /**
-        * Initialize posts and terms arrays and sets loading state till promises
-        * are not resolved. We will also set posts and terms in array that we want to display.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * Render the internal block UI.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @param {Object} props
-        */
-       fetchSelectOptions( props ) {
-               const { sponsorPosts, sponsorLevels, siteSettings } = props;
-
-               const parsedPosts = sponsorPosts.then(
-                       ( fetchedPosts ) => {
-                               const posts = fetchedPosts.map(
-                                       ( post ) => {
-                                               const label = post.title.rendered.trim() || __( '(Untitled)', 'wordcamporg' );
-
-                                               return {
-                                                       label             : label,
-                                                       value             : post.id,
-                                                       type              : 'post',
-                                                       featuredImageData : get( post, '_embedded.wp:featuredmedia[0].media_details', '' ),
-                                               };
-                                       }
-                               );
-
-                               this.setState( { fetchedPosts } );
-                               this.setState( { posts } );
-                       }
-               ).catch( ( e ) => {
-                       console.error( 'Error fetching data', e );
-               } );
-
-               const parsedTerms = sponsorLevels.then(
-                       ( fetchedTerms ) => {
-                               const terms = fetchedTerms.map( ( term ) => {
-                                       return {
-                                               label : term.name.trim() || __( '(Untitled)', 'wordcamporg' ),
-                                               value : term.id,
-                                               type  : 'term',
-                                               count : term.count,
-                                       };
-                               } );
-
-                               this.setState( { fetchedTerms } );
-                               this.setState( { terms } );
-                       }
-               ).catch( ( e ) => {
-                       console.error( 'Error fetching data', e );
-               } );
-
-               const parsedSettings = siteSettings.then(
-                       ( fetchedSettings ) => {
-                               const sponsorTermOrder = fetchedSettings.wcb_sponsor_level_order;
-
-                               this.setState( { sponsorTermOrder } );
-                       }
-               );
-
-               Promise.all( [ parsedPosts, parsedTerms, parsedSettings ] ).then( () => {
-                       this.setState( { loading: false } );
-
-                       // Enqueue selected posts in next event loop, so that state is up to date when `setSelectedPosts` method actually runs.
-                       setTimeout( () => this.setSelectedPosts() );
-               } );
-       }
-
-       /**
-        * Sets `mode`, `term_ids` and `post_ids` attribute when `Apply` button is
-        * clicked. Pass `onChange` prop to override.
-        *
-        * @param {Array} selectedOptions Array of values, type of selected options
-        */
-       onChange( selectedOptions = {} ) {
-               const { setAttributes } = this.props;
-               const newValue          = selectedOptions.item_ids;
-               const chosen            = selectedOptions.mode;
-
-               if ( newValue && chosen ) {
-                       switch ( chosen ) {
-                               case 'post' :
-                                       setAttributes( {
-                                               mode     : 'specific_posts',
-                                               post_ids : newValue,
-                                       } );
-                                       break;
-
-                               case 'term' :
-                                       setAttributes( {
-                                               mode     : 'specific_terms',
-                                               term_ids : newValue,
-                                       } );
-                                       break;
-                       }
-               } else {
-                       setAttributes( {
-                               mode     : '',
-                               post_ids : [],
-                               term_ids : [],
-                       } );
-               }
-
-               setTimeout( () => this.setSelectedPosts() );
-       }
-
-       /**
-        * Generate options array to be passed to select2.
-        *
-        * @return {Array}
-        */
-       buildSelectOptions() {
-               const { posts, terms } = this.state;
-               const options = [];
-
-               options.push( {
-                       label   : __( 'Sponsor Levels', 'wordcamporg' ),
-                       options : terms,
-               } );
-
-               options.push( {
-                       label   : __( 'Sponsors', 'wordcamporg' ),
-                       options : posts,
-               } );
-
-               return options;
-       }
-
-       /**
-        * Renders Sponsor Block Control view
-        *
</del><span class="cx" style="display: block; padding: 0 10px">          * @return {Element}
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        render() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                const { icon, attributes, setAttributes, sponsorPosts } = this.props;
-               const { mode, post_ids, term_ids } = attributes;
-               const { fetchedPosts, posts, terms, selectedPosts, sponsorTermOrder } = this.state;
-               const hasPosts = Array.isArray( fetchedPosts ) && fetchedPosts.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         const { icon, attributes, setAttributes } = this.props;
+               const { mode } = attributes;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Check if posts are still loading.
-               if ( mode && ! hasPosts ) {
-                       return (
-                               <PlaceholderNoContent
-                                       label={ LABEL }
-                                       loading={ () => {
-                                               return ! Array.isArray( sponsorPosts );
-                                       } }
-                               />
-                       );
-               }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         let output;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                let selectedOptions = [];
-
</del><span class="cx" style="display: block; padding: 0 10px">                 switch ( mode ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        case 'all' :
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                output = (
+                                       <SponsorsBlockContent { ...this.props } />
+                               );
</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">-                        case 'specific_posts' :
-                               selectedOptions = posts.filter( ( post ) => {
-                                       return includes( post_ids, post.value );
-                               } );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       case 'wcb_sponsor' :
+                       case 'wcb_sponsor_level' :
+                               output = (
+                                       <PlaceholderSpecificMode
+                                               label={ this.getModeLabel( mode ) }
+                                               icon={ icon }
+                                               content={
+                                                       <SponsorsBlockContent { ...this.props } />
+                                               }
+                                               placeholderChildren={
+                                                       <SponsorsSelect { ...this.props } />
+                                               }
+                                       />
+                               );
</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">-                        case 'specific_terms' :
-                               selectedOptions = terms.filter( ( term ) => {
-                                       return includes( term_ids, term.value );
-                               } );
-                               break;
-                       default:
-                               break;
-               }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return (
-                       <div>
-                               <SponsorBlockContent
-                                       selectedPosts={ selectedPosts }
-                                       sponsorTermOrder={ sponsorTermOrder }
-                                       { ...this.props }
-                               />
-
-                               { 'all' !== mode &&
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 default :
+                               output = (
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <Placeholder
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                className={ classnames( 'wordcamp-block-edit-placeholder', 'wordcamp-block-edit-placeholder-no-mode' ) }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 icon={ icon }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                label={ __( 'Sponsors', 'wordcamporg' ) }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         label={ LABEL }
</ins><span class="cx" style="display: block; padding: 0 10px">                                         >
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                <div className="" >
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         <div className="wordcamp-block-edit-mode-option">
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         <Button
</span><span class="cx" style="display: block; padding: 0 10px">                                                                isDefault
</span><span class="cx" style="display: block; padding: 0 10px">                                                                isLarge
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                onClick={
-                                                                       () => {
-                                                                               setAttributes( { mode: 'all' } );
-                                                                               setTimeout( () => this.setSelectedPosts() );
-                                                                       }
-                                                               }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                         onClick={ () => {
+                                                                       setAttributes( { mode: 'all' } );
+                                                               } }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         >
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                { __( 'List all sponsors', 'wordcamporg' ) }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                         { this.getModeLabel( 'all' ) }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         </Button>
</span><span class="cx" style="display: block; padding: 0 10px">                                                </div>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                                <div className="wordcamp-block-edit-mode-option">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        <ItemSelect
-                                                               buildSelectOptions={
-                                                                       () => {
-                                                                               return this.buildSelectOptions();
-                                                                       }
-                                                               }
-                                                               isLoading={ this.state.loading }
-                                                               onChange={
-                                                                       ( newOptions ) => {
-                                                                               return this.onChange( newOptions );
-                                                                       }
-                                                               }
-                                                               selectProps={
-                                                                       {
-                                                                               formatOptionLabel: ( optionData ) => {
-                                                                                       return (
-                                                                                               <SponsorOption { ...optionData } />
-                                                                                       );
-                                                                               },
-                                                                       }
-                                                               }
-                                                               label={ __( 'Or, choose specific sponsors or levels', 'wordcamporg' ) }
-                                                               value={ selectedOptions }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 <SponsorsSelect
+                                                               icon={ icon }
+                                                               label={ __( 'Choose specific sponsors or levels', 'wordcamporg' ) }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                                 { ...this.props }
</span><span class="cx" style="display: block; padding: 0 10px">                                                        />
</span><span class="cx" style="display: block; padding: 0 10px">                                                </div>
</span><span class="cx" style="display: block; padding: 0 10px">                                        </Placeholder>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                }
-                       </div>
-               );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         );
+                               break;
+               }
+
+               return output;
</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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-export default SponsorBlockControls;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+export default SponsorsBlockControls;
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorseditjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/edit.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/edit.js     2019-05-01 22:11:33 UTC (rev 8712)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/edit.js       2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,91 +1,62 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Internal dependencies
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * WordPress dependencies
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-import SponsorInspectorControls from './inspector-controls';
-import SponsorBlockControls     from './block-controls';
-import GridToolbar              from '../shared/grid-layout/toolbar';
-import { ICON }                 from './index';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+const { Component, Fragment } = wp.element;
+const { withSelect }          = wp.data;
</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">- * WordPress dependencies
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Internal dependencies
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-const { Component, Fragment } = wp.element;
-const apiFetch                = wp.apiFetch;
-const { addQueryArgs }        = wp.url;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+import SponsorsInspectorControls from './inspector-controls';
+import SponsorsBlockControls     from './block-controls';
+import GridToolbar               from '../shared/grid-layout/toolbar';
+import { ICON }                  from './index';
+import { WC_BLOCKS_STORE } from '../blocks-store';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-const MAX_PAGE = 100;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+const blockData = window.WordCampBlocks.sponsors || {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * Top-level component for the editing UI for the block.
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> class SponsorsEdit extends Component {
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Constructor for SponsorsEdit block.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * Render the block's editing UI.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @param {Array} props
-        */
-       constructor( props ) {
-               super( props );
-
-               this.fetchSponsors();
-       }
-
-       fetchSponsors() {
-               const sponsorQuery = {
-                       orderby  : 'title',
-                       order    : 'asc',
-                       per_page : MAX_PAGE,
-                       _embed   : true,
-               };
-
-               const sponsorLevelQuery = {
-                       orderby  : 'id',
-                       order    : 'asc',
-                       per_page : MAX_PAGE,
-                       _embed   : true,
-               };
-
-               this.state = {
-                       sponsorPosts  : apiFetch( { path: addQueryArgs( '/wp/v2/sponsors', sponsorQuery ) } ),
-                       sponsorLevels : apiFetch( { path: addQueryArgs( '/wp/v2/sponsor_level', sponsorLevelQuery ) } ),
-                       siteSettings  : apiFetch( { path: addQueryArgs( '/wp/v2/settings', {} ) } ),
-               };
-       }
-
-       /**
-        * Renders SponsorEdit component.
-        *
</del><span class="cx" style="display: block; padding: 0 10px">          * @return {Element}
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        render() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                const { sponsorPosts, sponsorLevels, siteSettings } = this.state;
-               const { attributes }                                = this.props;
-               const { mode }                                      = attributes;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         const { mode } = this.props.attributes;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                return (
</span><span class="cx" style="display: block; padding: 0 10px">                        <Fragment>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                {
-                                       <SponsorBlockControls
-                                               icon={ ICON }
-                                               sponsorPosts={ sponsorPosts }
-                                               sponsorLevels={ sponsorLevels }
-                                               siteSettings={ siteSettings }
-                                               { ...this.props }
-                                       />
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <SponsorsBlockControls
+                                       icon={ ICON }
+                                       { ...this.props }
+                               />
+                               { mode &&
+                                       <Fragment>
+                                               <SponsorsInspectorControls { ...this.props } />
+                                               <GridToolbar { ...this.props } />
+                                       </Fragment>
</ins><span class="cx" style="display: block; padding: 0 10px">                                 }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                <Fragment>
-                                       <SponsorInspectorControls
-                                               sponsorPosts={ sponsorPosts }
-                                               sponsorLevels={ sponsorLevels }
-                                               { ...this.props }
-                                       />
-
-                                       { mode &&
-                                               <GridToolbar
-                                                       { ...this.props }
-                                               />
-                                       }
-                               </Fragment>
</del><span class="cx" style="display: block; padding: 0 10px">                         </Fragment>
</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><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-export const edit = SponsorsEdit;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+const sponsorSelect = ( select ) => {
+       const { getEntities, getSiteSettings } = select( WC_BLOCKS_STORE );
+
+       const entities = {
+               wcb_sponsor       : getEntities( 'postType', 'wcb_sponsor', { _embed: true } ),
+               wcb_sponsor_level : getEntities( 'taxonomy', 'wcb_sponsor_level' ),
+       };
+
+       return {
+               blockData    : blockData,
+               entities     : entities,
+               siteSettings : getSiteSettings(),
+       };
+};
+
+export const edit = withSelect( sponsorSelect )( SponsorsEdit );
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsindexjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/index.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/index.js    2019-05-01 22:11:33 UTC (rev 8712)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/index.js      2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13,7 +13,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> export const ICON  = 'heart';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> const supports = {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        'align': [ 'wide', 'full' ],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ align: [ 'wide', 'full' ],
</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"> export const settings = {
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorsinspectorcontrolsjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/inspector-controls.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/inspector-controls.js       2019-05-01 22:11:33 UTC (rev 8712)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/inspector-controls.js 2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,31 +12,26 @@
</span><span class="cx" style="display: block; padding: 0 10px"> import GridInspectorControl           from '../shared/grid-layout/inspector-control';
</span><span class="cx" style="display: block; padding: 0 10px"> import FeaturedImageInspectorControls from '../shared/featured-image/inspector-control';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+const DEFAULT_OPTIONS = {
+       align_image : {},
+       content     : {},
+       sort        : {},
+};
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Class for defining Inspector control in sponsor block.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Component for block controls that appear in the Inspector Panel.
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-class SponsorInspectorControls extends Component {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+class SponsorsInspectorControls extends Component {
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Renders inspector controls.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * Render the controls.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @return {Element}
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        render() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                const sortOptions = [
-                       { label: __( 'Name (A to Z)', 'wordcamporg' ), value: 'name_asc'      },
-                       { label: __( 'Name (Z to A)', 'wordcamporg' ), value: 'name_desc'     },
-                       { label: __( 'Sponsor Level', 'wordcamporg' ), value: 'sponsor_level' },
-               ];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         const { attributes, setAttributes, blockData } = this.props;
+               const { show_name, show_logo, sort, content } = attributes;
+               const { options = DEFAULT_OPTIONS } = blockData;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                const contentOptions = [
-                       { label: __( 'Full',    'wordcamporg' ), value: 'full'    },
-                       { label: __( 'Excerpt', 'wordcamporg' ), value: 'excerpt' },
-                       { label: __( 'None',    'wordcamporg' ), value: 'none'    },
-               ];
-
-               const { attributes, setAttributes }                            = this.props;
-               const { show_name, show_logo, sort_by, content } = attributes;
-
</del><span class="cx" style="display: block; padding: 0 10px">                 return (
</span><span class="cx" style="display: block; padding: 0 10px">                        <InspectorControls>
</span><span class="cx" style="display: block; padding: 0 10px">                                <GridInspectorControl
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51,37 +46,33 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                                <ToggleControl
</span><span class="cx" style="display: block; padding: 0 10px">                                                        label={ __( 'Name', 'wordcamporg' ) }
</span><span class="cx" style="display: block; padding: 0 10px">                                                        help={ __( 'Show or hide sponsor name', 'wordcamporg' ) }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        checked={ show_name === undefined ? true : show_name }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 checked={ show_name }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         onChange={ ( value ) => setAttributes( { show_name: value } ) }
</span><span class="cx" style="display: block; padding: 0 10px">                                                />
</span><span class="cx" style="display: block; padding: 0 10px">                                        </PanelRow>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                                         <PanelRow>
</span><span class="cx" style="display: block; padding: 0 10px">                                                <ToggleControl
</span><span class="cx" style="display: block; padding: 0 10px">                                                        label={ __( 'Logo', 'wordcamporg' ) }
</span><span class="cx" style="display: block; padding: 0 10px">                                                        help={ __( 'Show or hide sponsor logo', 'wordcamporg' ) }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        checked={ show_logo === undefined ? true : show_logo }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 checked={ show_logo }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         onChange={ ( value ) => setAttributes( { show_logo: value } ) }
</span><span class="cx" style="display: block; padding: 0 10px">                                                />
</span><span class="cx" style="display: block; padding: 0 10px">                                        </PanelRow>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                                         <PanelRow>
</span><span class="cx" style="display: block; padding: 0 10px">                                                <SelectControl
</span><span class="cx" style="display: block; padding: 0 10px">                                                        label={ __( 'Description', 'wordcamporg' ) }
</span><span class="cx" style="display: block; padding: 0 10px">                                                        value={ content }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        options={ contentOptions }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 options={ options.content }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         help={ __( 'Length of sponsor description', 'wordcamporg' ) }
</span><span class="cx" style="display: block; padding: 0 10px">                                                        onChange={ ( value ) => setAttributes( { content: value } ) }
</span><span class="cx" style="display: block; padding: 0 10px">                                                />
</span><span class="cx" style="display: block; padding: 0 10px">                                        </PanelRow>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                                         <PanelRow>
</span><span class="cx" style="display: block; padding: 0 10px">                                                <SelectControl
</span><span class="cx" style="display: block; padding: 0 10px">                                                        label={ __( 'Sort by', 'wordcamporg' ) }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        options={ sortOptions }
-                                                       value={ sort_by || 'name_asc' }
-                                                       onChange={ ( value ) => setAttributes( { sort_by: value } ) }
-                                                       help={ __( 'Configure sponsor levels from the Sponsor -> Order Sponsor Levels page.', 'wordcamporg' ) }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 options={ options.sort }
+                                                       value={ sort }
+                                                       onChange={ ( value ) => setAttributes( { sort: value } ) }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 />
</span><span class="cx" style="display: block; padding: 0 10px">                                        </PanelRow>
</span><span class="cx" style="display: block; padding: 0 10px">                                </PanelBody>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -97,4 +88,4 @@
</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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-export default SponsorInspectorControls;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+export default SponsorsInspectorControls;
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksassetssrcsponsorssponsorsselectjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/sponsors-select.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/sponsors-select.js                          (rev 0)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/assets/src/sponsors/sponsors-select.js    2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,129 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * External dependencies
+ */
+import { every, flatMap, includes } from 'lodash';
+
+/**
+ * WordPress dependencies
+ */
+const { Component } = wp.element;
+const { __ }        = wp.i18n;
+
+/**
+ * Internal dependencies
+ */
+import ItemSelect, { buildOptions, Option } from '../shared/item-select';
+
+/**
+ * Component for selecting posts/terms for populating the block content.
+ */
+class SponsorsSelect extends Component {
+       /**
+        * Run additional operations during component initialization.
+        *
+        * @param {Object} props
+        */
+       constructor( props ) {
+               super( props );
+
+               this.buildSelectOptions    = this.buildSelectOptions.bind( this );
+               this.getCurrentSelectValue = this.getCurrentSelectValue.bind( this );
+               this.isLoading             = this.isLoading.bind( this );
+       }
+
+       /**
+        * Build or retrieve the options that will populate the Select dropdown.
+        *
+        * @return {Array}
+        */
+       buildSelectOptions() {
+               const { entities } = this.props;
+               const { wcb_sponsor, wcb_sponsor_level } = entities;
+
+               const optionGroups = [
+                       {
+                               entityType : 'post',
+                               type       : 'wcb_sponsor',
+                               label      : __( 'Sponsors', 'wordcamporg' ),
+                               items      : wcb_sponsor,
+                       },
+                       {
+                               entityType : 'term',
+                               type       : 'wcb_sponsor_level',
+                               label      : __( 'Sponsors Levels', 'wordcamporg' ),
+                               items      : wcb_sponsor_level,
+                       },
+               ];
+
+               return buildOptions( optionGroups );
+       }
+
+       /**
+        * Determine the currently selected options in the Select dropdown based on block attributes.
+        *
+        * @return {Array}
+        */
+       getCurrentSelectValue() {
+               const { attributes } = this.props;
+               const { mode, item_ids } = attributes;
+
+               const options = flatMap( this.buildSelectOptions(), ( group ) => {
+                       return group.options;
+               } );
+
+               let value = [];
+
+               if ( mode && item_ids.length ) {
+                       value = options.filter( ( option ) => {
+                               return mode === option.type && includes( item_ids, option.value );
+                       } );
+               }
+
+               return value;
+       }
+
+       /**
+        * Check if all of the entity groups have finished loading.
+        *
+        * @return {boolean}
+        */
+       isLoading() {
+               const { entities } = this.props;
+
+               return ! every( entities, ( value ) => {
+                       return Array.isArray( value );
+               } );
+       }
+
+       /**
+        * Render an ItemSelect component with block-specific settings.
+        *
+        * @return {Element}
+        */
+       render() {
+               const { label, icon, setAttributes } = this.props;
+
+               return (
+                       <ItemSelect
+                               className="wordcamp-sponsors-select"
+                               label={ label }
+                               value={ this.getCurrentSelectValue() }
+                               onChange={ ( changed ) => setAttributes( changed ) }
+                               selectProps={ {
+                                       options           : this.buildSelectOptions(),
+                                       isLoading         : this.isLoading(),
+                                       formatOptionLabel : ( optionData ) => {
+                                               return (
+                                                       <Option
+                                                               icon={ 'wcb_sponsor_level' === optionData.type ? icon : null }
+                                                               { ...optionData }
+                                                       />
+                                               );
+                                       },
+                               } }
+                       />
+               );
+       }
+}
+
+export default SponsorsSelect;
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksincludessponsorsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/includes/sponsors.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/includes/sponsors.php   2019-05-01 22:11:33 UTC (rev 8712)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/includes/sponsors.php     2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3,6 +3,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> namespace WordCamp\Blocks\Sponsors;
</span><span class="cx" style="display: block; padding: 0 10px"> use WordCamp\Blocks;
</span><span class="cx" style="display: block; padding: 0 10px"> use function WordCamp\Blocks\Shared\Components\{ render_grid_layout };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use function WordCamp\Blocks\Shared\Definitions\{ get_shared_definitions, get_shared_definition };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> defined( 'WPINC' ) || die();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -14,10 +15,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'wordcamp/sponsors',
</span><span class="cx" style="display: block; padding: 0 10px">                [
</span><span class="cx" style="display: block; padding: 0 10px">                        'attributes'      => get_attributes_schema(),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'render_callback' => __NAMESPACE__ . '\render',
</ins><span class="cx" style="display: block; padding: 0 10px">                         'editor_script'   => 'wordcamp-blocks',
</span><span class="cx" style="display: block; padding: 0 10px">                        'editor_style'    => 'wordcamp-blocks',
</span><span class="cx" style="display: block; padding: 0 10px">                        'style'           => 'wordcamp-blocks',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        'render_callback' => __NAMESPACE__ . '\render',
</del><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">@@ -32,7 +33,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @return false|string
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function render( $attributes ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $sponsors = get_sponsor_posts( $attributes );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $defaults   = wp_list_pluck( get_attributes_schema(), 'default' );
+       $attributes = wp_parse_args( $attributes, $defaults );
+       $sponsors   = get_sponsor_posts( $attributes );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $container_classes = array(
</span><span class="cx" style="display: block; padding: 0 10px">                'wordcamp-block',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -53,10 +56,29 @@
</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">        $html = render_grid_layout( $attributes['layout'], $attributes['grid_columns'], $rendered_sponsor_posts, $container_classes );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">         return $html;
</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">+ * Add data to be used by the JS scripts in the block editor.
+ *
+ * @param array $data
+ *
+ * @return array
+ */
+function add_script_data( array $data ) {
+       $data['sponsors'] = [
+               'schema'  => get_attributes_schema(),
+               'options' => get_options(),
+       ];
+
+       return $data;
+}
+
+add_filter( 'wordcamp_blocks_script_data', __NAMESPACE__ . '\add_script_data' );
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Return sponsor posts what will rendered based on attributes.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @param array $attributes
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -65,7 +87,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function get_sponsor_posts( $attributes ) {
</span><span class="cx" style="display: block; padding: 0 10px">        if ( empty( $attributes['mode'] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return array();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return [];
</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">        $post_args = array(
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -74,141 +96,131 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'posts_per_page' => - 1,
</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">+        $sort = explode( '_', $attributes['sort'] );
+
+       if ( 2 === count( $sort ) ) {
+               $post_args['orderby'] = $sort[0];
+               $post_args['order']   = $sort[1];
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         switch ( $attributes['mode'] ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                case 'specific_posts':
-                       $post_args['post__in'] = $attributes['post_ids'];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         case 'wcb_sponsor':
+                       $post_args['post__in'] = $attributes['item_ids'];
</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">-                case 'specific_terms':
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               case 'wcb_sponsor_level':
</ins><span class="cx" style="display: block; padding: 0 10px">                         $post_args['tax_query'] = [
</span><span class="cx" style="display: block; padding: 0 10px">                                [
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        'taxonomy' => 'wcb_sponsor_level',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 'taxonomy' => $attributes['mode'],
</ins><span class="cx" style="display: block; padding: 0 10px">                                         'field'    => 'id',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        'terms'    => $attributes['term_ids'],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 'terms'    => $attributes['item_ids'],
</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">                        break;
</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">-        switch ( $attributes['sort_by'] ) {
-               case 'name_asc':
-                       $post_args['orderby'] = 'title';
-                       $post_args['order']   = 'asc';
-                       break;
-               case 'name_desc':
-                       $post_args['orderby'] = 'title';
-                       $post_args['order']   = 'desc';
-                       break;
-               // We will deal with case `sponsor_level` later.
-       }
-
-       $posts = get_posts( $post_args );
-
-       if ( 'sponsor_level' === $attributes['sort_by'] ) {
-               usort( $posts, sponsor_level_sort( $posts ) );
-       }
-
-       return $posts;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ return get_posts( $post_args );
</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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Helper function for sorting based on sponsor levels.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Get attribute schema for Sponsor block
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @param array $posts Sponsor posts to sort.
- *
- * @return callable
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @return array
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-function sponsor_level_sort( $posts ) {
-       $sponsor_level_order = get_option( 'wcb_sponsor_level_order' );
-       $sponsor_terms_cache = array();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+function get_attributes_schema() {
+       $schema = array_merge(
+               get_shared_definitions(
+                       [
+                               'content',
+                               'grid_columns',
+                               'item_ids',
+                               'layout',
+                       ],
+                       'attribute'
+               ),
+               [
+                       'align'                => get_shared_definition( 'align_block', 'attribute' ),
+                       'className'            => get_shared_definition( 'string_empty', 'attribute' ),
+                       'featured_image_width' => array(
+                               'type'    => 'integer',
+                               'default' => 150,
+                       ),
+                       'image_align'          => get_shared_definition( 'align_image', 'attribute' ),
+                       'image_size'           => [
+                               'type'    => 'integer',
+                               'minimum' => 25,
+                               'maximum' => 600,
+                               'default' => 150,
+                       ],
+                       'mode'                 => [
+                               'type'    => 'string',
+                               'enum'    => wp_list_pluck( get_options( 'mode' ), 'value' ),
+                               'default' => '',
+                       ],
+                       'show_logo'            => get_shared_definition( 'boolean_true', 'attribute' ),
+                       'show_name'            => get_shared_definition( 'boolean_true', 'attribute' ),
+                       'sort'                 => [
+                               'type'    => 'string',
+                               'enum'    => wp_list_pluck( get_options( 'sort' ), 'value' ),
+                               'default' => 'title_asc',
+                       ],
+               ]
+       );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        //Build the terms cache.
-       foreach ( $posts as $post ) {
-               $sponsor_level_terms = get_the_terms( $post->ID, 'wcb_sponsor_level' );
-               if ( is_array( $sponsor_level_terms ) ) {
-                       $sponsor_terms_cache[ $post->ID ] = wp_list_pluck( $sponsor_level_terms, 'term_id' )[0];
-               } else {
-                       $sponsor_terms_cache[ $post->ID ] = array();
-               }
-       }
-
-       return function ( $sponsor1, $sponsor2 ) use ( $sponsor_level_order, $sponsor_terms_cache ) {
-               $index1 = array_search( $sponsor_terms_cache[ $sponsor1->ID ], $sponsor_level_order, true );
-               $index2 = array_search( $sponsor_terms_cache[ $sponsor2->ID ], $sponsor_level_order, true );
-
-               if ( false === $index1 && false === $index2 ) {
-                       return 0;
-               }
-
-               if ( false === $index1 ) {
-                       return 1;
-               }
-
-               if ( false === $index2 ) {
-                       return -1;
-               }
-
-               return $index1 - $index2;
-       };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ return $schema;
</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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Get attribute schema for Sponsor block
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Get the label/value pairs for all options or a specific type.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @param string $type
+ *
</ins><span class="cx" style="display: block; padding: 0 10px">  * @return array
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-function get_attributes_schema() {
-       return array(
-               'mode'                  => array(
-                       'type' => 'string',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+function get_options( $type = '' ) {
+       $options = array_merge(
+               get_shared_definitions(
+                       [
+                               'align_block',
+                               'align_image',
+                               'content',
+                               'layout',
+                       ],
+                       'option'
</ins><span class="cx" style="display: block; padding: 0 10px">                 ),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                'post_ids'              => array(
-                       'type'    => 'array',
-                       'default' => array(),
-                       'items'   => array(
-                               'type' => 'integer',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         [
+                       'mode' => [
+                               [
+                                       'label' => '',
+                                       'value' => '',
+                               ],
+                               [
+                                       'label' => _x( 'List all sponsors', 'mode option', 'wordcamporg' ),
+                                       'value' => 'all',
+                               ],
+                               [
+                                       'label' => _x( 'Choose sponsors', 'mode option', 'wordcamporg' ),
+                                       'value' => 'wcb_sponsor',
+                               ],
+                               [
+                                       'label' => _x( 'Choose sponsor level', 'mode option', 'wordcamporg' ),
+                                       'value' => 'wcb_sponsor_level',
+                               ],
+                       ],
+                       'sort' => array_merge(
+                               get_shared_definition( 'sort_title', 'option' ),
+                               get_shared_definition( 'sort_date', 'option' )
</ins><span class="cx" style="display: block; padding: 0 10px">                         ),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                ),
-               'term_ids'              => array(
-                       'type'    => 'array',
-                       'default' => array(),
-                       'items'   => array(
-                               'type' => 'integer',
-                       ),
-               ),
-               'sponsor_image_urls'    => array(
-                       'type'    => 'string',
-                       'default' => '{}',
-               ),
-               'show_name'             => array(
-                       'type'    => 'bool',
-                       'default' => true,
-               ),
-               'show_logo'             => array(
-                       'type'    => 'bool',
-                       'default' => true,
-               ),
-               'content'               => array(
-                       'type'    => 'string',
-                       'default' => 'full',
-               ),
-               'grid_columns'          => array(
-                       'type'    => 'integer',
-                       'minimum' => 1,
-                       'maximum' => 4,
-                       'default' => 1,
-               ),
-               'layout'                => array(
-                       'type'    => 'string',
-                       'enum'    => array( 'list', 'grid' ),
-                       'default' => 'list',
-               ),
-               'featured_image_width'  => array(
-                       'type'    => 'integer',
-                       'default' => 150,
-               ),
-               'sort_by'               => array(
-                       'type'    => 'string',
-                       'default' => 'name_asc',
-               ),
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $type ) {
+               if ( ! empty( $options[ $type ] ) ) {
+                       return $options[ $type ];
+               } else {
+                       return [];
+               }
+       }
+
+       return $options;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentmupluginsblocksviewsponsorsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/view/sponsors.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/view/sponsors.php       2019-05-01 22:11:33 UTC (rev 8712)
+++ sites/trunk/wordcamp.org/public_html/wp-content/mu-plugins/blocks/view/sponsors.php 2019-05-01 22:13:13 UTC (rev 8713)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,38 +12,40 @@
</span><span class="cx" style="display: block; padding: 0 10px"> setup_postdata( $sponsor );
</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">-<div class="wordcamp-sponsor-details wordcamp-sponsor-details-<?php echo sanitize_html_class( $sponsor->post_name ); ?> ">
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <?php if ( $attributes['show_name'] ) { ?>
-               <h3 class="wordcamp-sponsor-title wordcamp-item-title">
-                       <a href="<?php echo esc_attr( get_permalink( $sponsor->ID ) ); ?>"><?php echo esc_html( get_the_title( $sponsor ) ); ?></a>
-               </h3>
-       <?php } ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php if ( true === $attributes['show_name'] ) : ?>
+       <h3 class="wordcamp-sponsor-title wordcamp-item-title">
+               <a href="<?php echo esc_attr( get_permalink( $sponsor ) ); ?>">
+                       <?php echo wp_kses_post( get_the_title( $sponsor ) ); ?>
+               </a>
+       </h3>
+<?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <?php if ( $attributes['show_logo'] ) { ?>
-               <?php echo wp_kses_post(
-                       render_featured_image(
-                               $sponsor,
-                               $attributes['featured_image_width'],
-                               [ 'wordcamp-sponsor-featured-image', 'wordcamp-sponsor-logo' ],
-                               get_permalink( $sponsor )
-                       )
-               ); ?>
-       <?php } ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php if ( true === $attributes['show_logo'] ) : ?>
+       <?php echo wp_kses_post(
+               render_featured_image(
+                       $sponsor,
+                       $attributes['featured_image_width'],
+                       [ 'wordcamp-sponsor-featured-image', 'wordcamp-sponsor-logo' ],
+                       get_permalink( $sponsor )
+               )
+       ); ?>
+<?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <?php if ( 'none' !== $attributes['content'] ) { ?>
-               <?php if ( 'full' === $attributes['content'] ) { ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php if ( 'none' !== $attributes['content'] ) : ?>
+       <div class="wordcamp-item-content wordcamp-sponsor-content-<?php echo esc_attr( $attributes['content'] ); ?>">
+               <?php if ( 'full' === $attributes['content'] ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                         <?php echo wp_kses_post( wpautop( get_all_the_content( $sponsor ) ) ); ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <?php } elseif ( 'excerpt' === $attributes['content'] ) { ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <?php elseif ( 'excerpt' === $attributes['content'] ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                         <?php echo wp_kses_post( wpautop( apply_filters( 'the_excerpt', get_the_excerpt() ) ) ); ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <?php } ?>
-       <?php } ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <?php endif; ?>
+       </div>
+<?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <?php if ( 'full' === $attributes['content'] ) : ?>
-               <p class="wordcamp-item-permalink">
-                       <a href="<?php echo esc_url( get_permalink( $sponsor ) ); ?>">
-                               <?php esc_html_e( 'Visit sponsor page', 'wordcamporg' ); ?>
-                       </a>
-               </p>
-       <?php endif; ?>
-</div>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php if ( 'full' === $attributes['content'] ) : ?>
+       <p class="wordcamp-item-permalink">
+               <a href="<?php echo esc_url( get_permalink( $sponsor ) ); ?>">
+                       <?php esc_html_e( 'Visit sponsor page', 'wordcamporg' ); ?>
+               </a>
+       </p>
+<?php endif; ?>
</ins></span></pre>
</div>
</div>

</body>
</html>