Ticket #1112: 1112.diff
File 1112.diff, 22.9 KB (added by , 9 years ago) |
---|
-
wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/includes/site-control.php
diff --git wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/includes/site-control.php wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/includes/site-control.php index 8628d2c..69a517d 100644
namespace WordCamp\Site_Cloner; 5 5 defined( 'WPINC' ) or die(); 6 6 7 7 /** 8 * Custom Customizer Control for a WordCamp site8 * Custom Customizer Control for Search WordCamp sites to clone 9 9 */ 10 10 class Site_Control extends \WP_Customize_Control { 11 public $site_id, $site_name, $screenshot_url, $theme_slug; 12 public $settings = 'wcsc_source_site_id'; 13 public $section = 'wcsc_sites'; 11 12 public function __construct( $manager, $id, $args = [ ] ) { 13 parent::__construct( $manager, $id, $args ); 14 15 $this->capability = 'edit_theme_options'; 16 $this->section = 'wcsc_sites'; 17 } 14 18 15 19 /** 16 20 * Enqueue scripts and styles … … class Site_Control extends \WP_Customize_Control { 18 22 public function enqueue() { 19 23 wp_enqueue_style( 'wordcamp-site-cloner' ); 20 24 wp_enqueue_script( 'wordcamp-site-cloner' ); 25 add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_view_templates' ) ); 21 26 } 22 27 23 /**24 * Render the control's content25 */26 28 public function render_content() { 27 $preview_url = add_query_arg(28 array(29 'theme' => rawurlencode( $this->theme_slug ),30 'wcsc_source_site_id' => rawurlencode( $this->site_id ),31 ),32 admin_url( 'customize.php' )33 );34 35 29 require( dirname( __DIR__ ) . '/templates/site-control.php' ); 36 30 } 31 32 public function print_view_templates() { 33 ?> 34 <script id="tmpl-wcsc-site-option" type="text/html"> 35 <?php include dirname( __DIR__ ) . '/templates/site-option.php'; ?> 36 </script> 37 <?php 38 } 37 39 } -
wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/site-control.php
diff --git wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/site-control.php wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/site-control.php index 952a134..9b60dba 100644
1 <?php defined( 'WPINC' ) or die(); ?> 1 <?php 2 defined( 'WPINC' ) or die(); 2 3 3 <div id="wcsc-site-<?php echo esc_attr( $this->site_id ); ?>" class="wcscSite" data-preview-url="<?php echo esc_url( $preview_url ); ?>"> 4 <div class="wcsc-site-screenshot"> 5 <img src="<?php echo esc_url( $this->screenshot_url ); ?>" alt="<?php echo esc_attr( $this->site_name ); ?>" /> 6 </div> 7 8 <h3 class="wcsc-site-name"> 9 <?php echo esc_html( $this->site_name ); ?> 4 /** 5 * Top level template for the output of the Site Cloner Customizer Control 6 */ 7 ?> 8 <div id="wcsc-cloner"> 9 <h3> 10 <?php esc_html_e( 'WordCamp Sites', 'wordcamporg' ); ?> 11 <span id="wcsc-sites-count" class="title-count wcsc-sites-count"></span> 10 12 </h3> 13 <div class="filters"> 14 </div> 11 15 12 <span id="live-preview-label-<?php echo esc_attr( $this->site_id ); ?>" class="wcsc-live-preview-label"> 13 <?php _e( 'Live Preview', 'wordcamporg' ); ?> 14 </span> 15 </div> 16 <div class="wcsc-search"> 17 <ul id="wcsc-results"> 18 </ul> 19 </div> 20 </div> 21 No newline at end of file -
new file wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/site-option.php
diff --git wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/site-option.php wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/site-option.php new file mode 100644 index 0000000..453a407
- + 1 <?php 2 /** 3 * Template for a single Site representation within the Site Cloner Control 4 */ 5 6 defined( 'WPINC' ) or die(); 7 8 ?> 9 <div class="wcsc-site-screenshot"> 10 <img src="{{ data.screenshot_url }}" alt="{{ data.name }}"/> 11 </div> 12 13 <h3 class="wcsc-site-name"> 14 {{ data.name }} 15 </h3> 16 17 <span id="live-preview-label-{{ data.site_id }}" class="wcsc-live-preview-label"> 18 <?php _e( 'Live Preview', 'wordcamporg' ); ?> 19 </span> 20 <?php 21 No newline at end of file -
deleted file wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/sites-section.php
diff --git wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/sites-section.php wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/sites-section.php deleted file mode 100644 index a05272c..0000000
+ - 1 <?php defined( 'WPINC' ) or die(); ?>2 3 <li id="section-<?php echo esc_attr( $this->id ); ?>" class="accordion-section control-section control-section-<?php echo esc_attr( $this->type ); ?>">4 <h3>5 <?php esc_html_e( 'WordCamp Sites' ); ?>6 7 <span class="title-count wcsc-sites-count">8 <?php echo count( $this->controls ); ?>9 </span>10 </h3>11 12 <div class="wcsc-sites-section-content">13 <ul id="wcsc-sites"></ul>14 </div>15 </li> -
wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.css
diff --git wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.css wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.css index 0a33876..dbc3581 100644
6 6 overflow: auto; 7 7 } 8 8 9 .wcsc Site {9 .wcsc-site { 10 10 position: relative; 11 11 cursor: pointer; 12 12 border: 1px solid #DEDEDE; … … 17 17 transition: opacity 0.2s ease-in-out 0s; 18 18 } 19 19 20 .wcsc Site:hover .wcsc-site-screenshot {20 .wcsc-site:hover .wcsc-site-screenshot { 21 21 opacity: 0.4; 22 22 } 23 23 … … 38 38 transition: opacity 0.1s ease-in-out 0s; 39 39 } 40 40 41 .wcsc Site:hover .wcsc-live-preview-label {41 .wcsc-site:hover .wcsc-live-preview-label { 42 42 opacity: 1; 43 43 } 44 45 #wcsc-cloner div.filters { 46 padding: 8px; 47 } 48 49 #wcsc-cloner div.filters label { 50 position: relative; 51 } -
wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.js
diff --git wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.js wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.js index 5c05f82..2279105 100644
1 ( function ( wp, $) {1 ( function ( wp, $, Backbone, win ) { 2 2 'use strict'; 3 3 4 4 if ( ! wp || ! wp.customize ) { 5 5 return; 6 6 } 7 7 8 var api = wp.customize; 8 var api = wp.customize, 9 wcsc; 9 10 10 /** 11 * The Clone Another WordCamp panel 12 */ 13 api.panelConstructor.wcscPanel = api.Panel.extend( { 14 /** 15 * Initialize the panel after it's loaded 16 * 17 * Ideally, the Previewer would be set to the requested site ID during the initial PHP request, rather than 18 * loading the host site in the Previewer, and then refreshing it to use the requested site. That became a 19 * rabbit hole, though, so it's done this way instead. 20 */ 21 ready : function() { 22 var urlParams = getUrlParams( window.location.href ); 11 wcsc = wp.wcSiteCloner = { models: {}, views: {}, collections: {}, settings: {} }; 23 12 24 if ( urlParams.hasOwnProperty( 'wcsc_source_site_id' ) ) { 25 this.expand(); 26 api( 'wcsc_source_site_id' ).set( urlParams.wcsc_source_site_id ); 13 // @todo dynamically set the real URL 14 wcsc.settings.apiUrl = win.location.protocol + '//' + win.location.hostname + '/wp-admin/customize.php?get_wordcamp_sites=1'; 15 16 // @todo implement real l10n 17 var l10n = wcsc.settings.l10n = { 18 search: 'Search' 19 }; 20 21 22 // Model for a single site 23 wcsc.models.Site = Backbone.Model.extend( { 24 idAttribute: 'site_id' 25 } ); 26 27 // Top level view for the Site Cloner Control 28 wcsc.views.SiteSearch = Backbone.View.extend( { 29 el: '#wcsc-cloner .wcsc-search', 30 31 // index of the currently viewed page of results 32 page: 0, 33 34 initialize: function ( options ) { 35 36 // update scroller position 37 _.bindAll( this, 'scroller' ); 38 39 this.$searchContainer = $( '#wcsc-cloner div.filters' ); 40 41 // container that will be scrolled within 42 this.$container = $( '#wcsc-cloner' ).parents( 'ul.accordion-section-content' ); 43 44 // bind scrolling within the container to check for infinite scroll 45 this.$container.bind( 'scroll', _.throttle( this.scroller, 300 ) ); 46 }, 47 48 render: function () { 49 50 // View for listing the matching sites 51 this.resultsView = new wcsc.views.SearchResults( { 52 collection: this.collection, 53 parent: this 54 } ); 55 56 // render search form 57 this.renderSearch(); 58 59 this.resultsView.render(); 60 this.$el.empty().append( this.resultsView.el ); 61 }, 62 63 // Render the search input view 64 renderSearch: function () { 65 var self = this, 66 view; 67 68 view = new wcsc.views.SearchInput( { 69 collection: this.collection, 70 parent: this 71 } ); 72 73 view.render(); 74 75 this.$searchContainer 76 .append( $.parseHTML( '<label class="screen-reader-text" for="wp-filter-search-input">' + l10n.search + '</label>' ) ); 77 this.$searchContainer 78 .append( view.el ); 79 }, 80 81 // Checks if a user has reached the bottom of the list 82 // and triggers a scroll event to show more sites if needed 83 scroller: function () { 84 var visibleBottom, threshold, elementHeight, containerHeight, scrollTop; 85 86 scrollTop = this.$container.scrollTop(); 87 containerHeight = this.$container.innerHeight(); 88 elementHeight = this.$container.get( 0 ).scrollHeight; 89 90 visibleBottom = scrollTop + containerHeight; 91 threshold = Math.round( elementHeight * 0.9 ); 92 93 if ( visibleBottom > threshold ) { 94 this.trigger( 'wcsc:scroll' ); 27 95 } 28 96 } 97 29 98 } ); 30 99 31 /** 32 * Custom control representing a site that can be previewed/imported 33 */ 34 api.controlConstructor.wcscSite = api.Control.extend( { 35 /** 36 * Initialize the control after it's loaded 37 */ 38 ready : function() { 39 this.container.on( 'click', '.wcscSite', this.previewSite ); 40 }, 41 42 /** 43 * Preview the selected site 44 * 45 * If the site is using a different theme, then reload the entire Customizer with the theme URL parameter 46 * set, so that the Theme Switcher will handle previewing the new theme for us. Otherwise just set the ID 47 * to refresh the Previewer with the current theme and the new site's CSS, etc. 48 * 49 * @param {object} event 50 */ 51 previewSite : function( event ) { 52 var previewUrl = $( this ).data( 'preview-url' ), 53 previewUrlParams = getUrlParams( previewUrl ); 54 55 if ( api( 'wcsc_source_site_id' ).get() == previewUrlParams.wcsc_source_site_id ) { 100 // Collection representing the list of cloneable sites 101 wcsc.collections.Sites = Backbone.Collection.extend( { 102 model: wcsc.models.Site, 103 terms: '', 104 url: wcsc.settings.apiUrl, 105 106 // Runs the search against the current collection and triggers the update event 107 doSearch: function ( value ) { 108 109 //duplicate search 110 if ( this.terms === value ) { 111 return; 112 } 113 114 this.terms = value; 115 116 //if there are terms, run the serach filter 117 if ( this.terms.length > 0 ) { 118 this.search( this.terms ); 119 } 120 121 if ( this.terms === '' ) { 122 this.resetCanonical(); 123 } 124 125 this.trigger( 'wcsc:updated' ); 126 }, 127 128 // resets this collection to the filtered search results 129 search: function ( term ) { 130 var match, results, haystack, name; 131 132 this.resetCanonical( { silent: true } ); 133 134 // Escape the term string for RegExp meta characters 135 term = term.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' ); 136 137 // Consider spaces as word delimiters and match the whole string 138 // so matching terms can be combined 139 term = term.replace( / /g, ')(?=.*' ); 140 match = new RegExp( '^(?=.*' + term + ').+', 'i' ); 141 142 // Find results 143 // _.filter and .test 144 results = this.filter( function ( data ) { 145 name = data.get( 'name' ).replace( /(<([^>]+)>)/ig, '' ); 146 147 return match.test( name ); 148 } ); 149 150 if ( results.length === 0 ) { 151 this.trigger( 'query:empty' ); 152 } 153 154 this.reset( results ); 155 }, 156 157 paginate: function ( pageIndex ) { 158 var collection = this; 159 pageIndex = pageIndex || 0; 160 161 collection = _( collection.rest( 20 * pageIndex ) ); 162 collection = _( collection.first( 20 ) ); 163 return collection; 164 }, 165 166 // Resets the site collection dataset to the canonical list originally pulled from the api 167 resetCanonical: function ( options ) { 168 options = options || {}; 169 this.reset( wcsc.settings.siteData, options ); 170 } 171 } ); 172 173 174 // View for a single site 175 wcsc.views.Site = Backbone.View.extend( { 176 className: 'wcsc-site', 177 178 attributes: function () { 179 return { 180 'id': 'wcsc-site-' + this.model.get( 'site_id' ), 181 'data-site-id': this.model.get( 'site_id' ) 182 } 183 }, 184 185 html: wp.template( 'wcsc-site-option' ), 186 187 touchDrag: false, 188 189 events: { 190 'click': 'preview', 191 'keydown': 'preview', 192 'touchend': 'preview', 193 'touchmove': 'preventPreview' 194 }, 195 196 initialize: function ( options ) { 197 this.parent = options.parent; 198 199 this.render(); 200 }, 201 202 render: function () { 203 var data = this.model.toJSON(); 204 205 this.$el.html( this.html( data ) ); 206 }, 207 208 preventPreview: function () { 209 this.touchDrag = true; 210 }, 211 212 preview: function ( event ) { 213 var current, preview; 214 215 event = event || window.event; 216 217 //ignore touches caused by scrolling 218 if ( this.touchDrag === true ) { 219 this.touchDrag = false; 220 } 221 222 event.preventDefault(); 223 224 this.$el.trigger( 'wcsc:previewSite', this.model ); 225 } 226 227 } ); 228 229 wcsc.views.SearchResults = Backbone.View.extend( { 230 className: 'wcsc-results', 231 232 liveSiteCount: 0, 233 234 initialize: function ( options ) { 235 var self = this; 236 237 this.parent = options.parent; 238 239 this.$siteCount = $( '#wcsc-sites-count' ); 240 241 // Rerender the view whenever a collection change is complete 242 this.listenTo( self.collection, 'wcsc:updated', function () { 243 //reset pagination 244 self.parent.page = 0; 245 self.render( this ); 246 } ); 247 248 this.listenTo( this.parent, 'wcsc:scroll', function () { 249 self.renderSites( self.parent.page ); 250 } ); 251 }, 252 253 render: function () { 254 this.$el.empty(); 255 256 //if ( this.options.collection.size() > 0 ) { 257 this.renderSites( this.parent.page ); 258 //} 259 260 this.$siteCount.text( this.collection.length ); 261 }, 262 263 renderSites: function ( page ) { 264 var self = this; 265 266 // get a collection of just the requested page 267 this.instance = this.collection.paginate( page ); 268 269 if ( this.instance.size() === 0 ) { 270 this.parent.trigger( 'wcsc:end' ); 56 271 return; 57 272 } 58 273 59 if ( api.settings.theme.stylesheet === previewUrlParams.theme ) { 60 api( 'wcsc_source_site_id' ).set( previewUrlParams.wcsc_source_site_id ); 274 this.instance.each( function ( site ) { 275 var siteView = new wcsc.views.Site( { 276 model: site, 277 parent: self 278 } ); 279 280 siteView.render(); 281 282 self.$el.append( siteView.el ); 283 } ); 284 285 this.parent.page++; 286 } 287 288 } ); 289 290 // View for the search input field 291 wcsc.views.SearchInput = Backbone.View.extend( { 292 tagName: 'input', 293 className: 'wcsc-filter-search', 294 id: 'wcsc-filter-search-input', 295 searching: false, 296 297 attributes: { 298 type: 'search', 299 300 }, 301 302 events: { 303 'input': 'search', 304 'keyup': 'search', 305 'blur': 'pushState' 306 }, 307 308 initialize: function ( options ) { 309 this.parent = options.parent; 310 }, 311 312 search: function ( event ) { 313 // Clear on escape. 314 if ( event.type === 'keyup' && event.which === 27 ) { 315 event.target.value = ''; 316 } 317 318 /** 319 * Since doSearch is debounced, it will only run when user input comes to a rest 320 */ 321 this.doSearch( event ); 322 }, 323 324 doSearch: _.debounce( function ( event ) { 325 var options = {}; 326 327 this.collection.doSearch( event.target.value ); 328 329 // if search is initiated and key is not return 330 if ( this.searching && event.which !== 13 ) { 331 options.replace = true; 332 } else { 333 this.searching = true; 334 } 335 336 }, 500 ), 337 338 pushState: function ( event ) { 339 this.searching = false; 340 } 341 } ); 342 343 api.controlConstructor.wcscSearch = api.Control.extend( { 344 ready: function () { 345 var control = this, 346 urlParams = getUrlParams( win.location.href ), 347 siteCollection = new wcsc.collections.Sites(); 348 349 //setup the backbone view for the control 350 //@todo would be nice to delay the fetch until this section is loaded 351 siteCollection.fetch( { 352 success: function ( collection ) { 353 wcsc.settings.siteData = collection.toJSON(); 354 355 control.view = new wcsc.views.SiteSearch( { 356 parent: this, 357 collection: collection 358 } ); 359 360 control.renderSearch(); 361 } 362 } ); 363 364 // if the wcsc_source_site_id is set, its most likely from a user previewing a site, so bring them back 365 if ( urlParams.hasOwnProperty( 'wcsc_source_site_id' ) ) { 366 api.section( this.section() ).expand(); 367 api( 'wcsc_source_site_id' ).set( urlParams.wcsc_source_site_id ); 368 } 369 370 $( '#wcsc-cloner' ).on( 'wcsc:previewSite', '.wcsc-site', function ( event, site ) { 371 control.previewSite( site ); 372 } ); 373 }, 374 375 previewSite: function ( site ) { 376 377 if ( api( 'wcsc_source_site_id' ).get() == site.get( 'site_id' ) ) { 378 //we're already previewing this site 379 return; 380 } 381 382 if ( api.settings.theme.stylesheet === site.get( 'theme_slug' ) ) { 383 api( 'wcsc_source_site_id' ).set( site.get( 'site_id' ) ); 61 384 } else { 62 window.parent.location = previewUrl; 385 //@todo properly set this 386 win.parent.location = win.location.protocol + '//' + win.location.hostname + 387 '/wp-admin/customize.php?theme=' + site.get( 'theme_slug' ) + '&wcsc_source_site_id=' + site.get( 'site_id' ); 63 388 } 389 }, 390 391 renderSearch: function () { 392 this.view.render(); 64 393 } 394 65 395 } ); 66 396 67 397 /** … … 96 426 97 427 return urlParams; 98 428 } 99 } )( window.wp, jQuery ); 429 } )( window.wp, jQuery, Backbone, window ); 430 No newline at end of file -
wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.php
diff --git wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.php wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.php index c398534..7d40aed 100755
defined( 'WPINC' ) or die(); 7 7 /* 8 8 Plugin Name: WordCamp Site Cloner 9 9 Description: Allows organizers to clone another WordCamp's theme and custom CSS as a starting point for their site. 10 Version: 0. 110 Version: 0.2.0-alpha 11 11 Author: WordCamp.org 12 12 Author URI: http://wordcamp.org 13 13 License: GPLv2 or later … … function register_scripts() { 34 34 wp_register_script( 35 35 'wordcamp-site-cloner', 36 36 plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.js', 37 array( 'jquery', 'customize-controls' ),37 array( 'jquery', 'customize-controls', 'wp-backbone' ), 38 38 1, 39 39 true 40 40 ); … … function add_submenu_page() { 63 63 */ 64 64 function register_customizer_components( $wp_customize ) { 65 65 require_once( __DIR__ . '/includes/source-site-id-setting.php' ); 66 require_once( __DIR__ . '/includes/sites-section.php' );67 66 require_once( __DIR__ . '/includes/site-control.php' ); 68 67 69 $wp_customize->register_control_type( __NAMESPACE__ . '\Site_Control' );70 71 68 $wp_customize->add_setting( new Source_Site_ID_Setting( 72 69 $wp_customize, 73 70 'wcsc_source_site_id', 74 71 array() 75 72 ) ); 76 73 77 $wp_customize->add_panel( 78 'wordcamp_site_cloner', 79 array( 80 'type' => 'wcscPanel', 81 'title' => __( 'Clone Another WordCamp', 'wordcamporg' ), 82 'description' => __( "Clone another WordCamp's theme and custom CSS as a starting point for your site.", 'wordcamporg' ), 74 $wp_customize->add_section( 'wcsc_sites', array( 75 'title' => __( 'Clone Another WordCamp', 'wordcamporg' ), 83 76 ) 84 77 ); 85 78 86 $wp_customize->add_ section( new Sites_Section(79 $wp_customize->add_control( new Site_Control( 87 80 $wp_customize, 88 'wcsc_site s',81 'wcsc_site_search', 89 82 array( 90 'panel' => 'wordcamp_site_cloner', 91 'title' => __( 'WordCamp Sites', 'wordcamporg' ), 83 'type' => 'wcscSearch', 84 'label' => __( 'Search', 'wordcamporg' ), 85 'settings' => 'wcsc_source_site_id', 86 'section' => 'wcsc_sites' 92 87 ) 93 88 ) ); 94 95 foreach( get_wordcamp_sites() as $wordcamp ) {96 if ( get_current_blog_id() == $wordcamp['site_id'] ) {97 continue;98 }99 100 $wp_customize->add_control( new Site_Control(101 $wp_customize,102 'wcsc_site_id_' . $wordcamp['site_id'],103 array(104 'type' => 'wcscSite', // todo should be able to set this in control instead of here, but if do that then control contents aren't rendered105 'site_id' => $wordcamp['site_id'],106 'site_name' => $wordcamp['name'],107 'theme_slug' => $wordcamp['theme_slug'],108 'screenshot_url' => $wordcamp['screenshot_url'],109 )110 ) );111 }112 89 } 113 90 114 91 /** … … function get_screenshot_url( $site_url ) { 195 172 196 173 return apply_filters( 'wcsc_site_screenshot_url', $screenshot_url ); 197 174 } 175 176 /** 177 * Quick and ugly handling to provide a JSON endpoint for the WordCamp Sites data 178 * 179 * @todo Make a real API 180 */ 181 add_action( 'wp_loaded', function() { 182 if ( ! empty( $_GET[ 'get_wordcamp_sites' ] ) ) { 183 $sites = \WordCamp\Site_Cloner\get_wordcamp_sites(); 184 185 $fakeSites = array_merge( $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 186 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 187 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 188 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 189 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 190 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 191 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 192 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 193 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 194 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 195 $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites ); 196 197 //hack to expand with fake data for now so the front-end can be worked on without having to create 100s of sites 198 if ( defined( 'WCSC_MOCK_FILL_SITES' ) && WCSC_MOCK_FILL_SITES ) { 199 $fake_site_id = 10000; 200 foreach ( $fakeSites as &$site ) { 201 $site[ 'site_id' ] = $fake_site_id; 202 $site[ 'name' ] = $site[ 'name' ] . " Mock Only (Don't Click) - " . $fake_site_id; 203 $fake_site_id++; 204 } 205 206 $sites = array_merge( $sites, $fakeSites ); 207 } 208 209 wp_send_json( $sites ); 210 } 211 } ); 212 No newline at end of file