Ticket #1112: 1112-site-cloner-scaling.diff
File 1112-site-cloner-scaling.diff, 25.7 KB (added by , 9 years ago) |
---|
-
includes/site-control.php
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';14 11 15 /** 16 * Enqueue scripts and styles 17 */ 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 } 18 18 19 public function enqueue() { 19 wp_enqueue_style( 20 wp_enqueue_style( 'wordcamp-site-cloner' ); 20 21 wp_enqueue_script( 'wordcamp-site-cloner' ); 22 add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_view_templates' ) ); 21 23 } 22 24 23 /**24 * Render the control's content25 */26 25 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 ); 26 include dirname( __DIR__ ) . '/templates/site-control.php'; 27 } 34 28 35 require( dirname( __DIR__ ) . '/templates/site-control.php' ); 29 public function print_view_templates() { 30 ?> 31 <script id="tmpl-wcsc-site-option" type="text/html"> 32 <?php include dirname( __DIR__ ) . '/templates/site-option.php'; ?> 33 </script> 34 <?php 36 35 } 37 36 } -
templates/site-control.php
1 <?php defined( 'WPINC' ) or die(); ?> 1 <?php 2 /** 3 * Top level template for the output of the Site Cloner Customizer Control 4 */ 2 5 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 defined( 'WPINC' ) or die(); 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> 12 </h3> 13 <div class="filters"> 6 14 </div> 7 15 8 <h3 class="wcsc-site-name"> 9 <?php echo esc_html( $this->site_name ); ?> 10 </h3> 11 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 -
wordcamp-site-cloner.css
1 #wcsc-cloner div.filters{ 2 padding: 8px; 3 } 4 5 #wcsc-cloner div.filters label{ 6 position: relative; 7 } 8 1 9 .control-section-wcsc-sites { 2 10 padding: 0 8px; 3 11 } 4 12 5 6 7 13 #wcsc-sites { 14 overflow: auto; 15 } 8 16 9 .wcscSite {10 11 12 13 box-shadow: 0 1px 1px -1px rgba( 0, 0, 0, 0.1);14 17 .wcsc-site { 18 position: relative; 19 cursor: pointer; 20 border: 1px solid #DEDEDE; 21 box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1); 22 } 15 23 16 17 18 24 .wcsc-site-screenshot { 25 transition: opacity 0.2s ease-in-out 0s; 26 } 19 27 20 .wcscSite:hover .wcsc-site-screenshot {21 22 28 .wcsc-site:hover .wcsc-site-screenshot { 29 opacity: 0.4; 30 } 23 31 24 25 26 27 28 29 30 background: rgba( 0, 0, 0, 0.7) none repeat scroll 0 0;31 32 33 text-shadow: 0 1px 0 rgba( 0, 0, 0, 0.6);34 35 36 37 38 39 32 .wcsc-live-preview-label { 33 opacity: 0; 34 position: absolute; 35 top: 35%; 36 right: 25%; 37 left: 25%; 38 background: rgba(0, 0, 0, 0.7) none repeat scroll 0 0; 39 color: #FFF; 40 font-size: 15px; 41 text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6); 42 font-weight: 600; 43 padding: 15px 12px; 44 text-align: center; 45 border-radius: 3px; 46 transition: opacity 0.1s ease-in-out 0s; 47 } 40 48 41 .wcscSite:hover .wcsc-live-preview-label {42 43 49 .wcsc-site:hover .wcsc-live-preview-label { 50 opacity: 1; 51 } -
wordcamp-site-cloner.js
1 ( function( wp, $) {1 (function ( $, Backbone, win, wp ) { 2 2 'use strict'; 3 3 4 if ( ! wp || ! wp.customize ) { 4 var api = wp.customize, 5 wcsc; 6 7 if ( !wp || !wp.customize ) { 5 8 return; 6 9 } 7 10 8 var api = wp.customize;11 wcsc = wp.wcSiteCloner = { models: {}, views: {}, collections: {}, settings: {} }; 9 12 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 ); 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'; 23 15 24 if ( urlParams.hasOwnProperty( 'wcsc_source_site_id' ) ) { 25 this.expand(); 26 api( 'wcsc_source_site_id' ).set( urlParams.wcsc_source_site_id ); 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 ); 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' ); 40 126 }, 41 127 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 ); 128 // resets this collection to the filtered search results 129 search: function ( term ) { 130 var match, results, haystack, name; 54 131 55 if ( api( 'wcsc_source_site_id' ).get() == previewUrlParams.wcsc_source_site_id ) { 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; 61 332 } else { 62 window.parent.location = previewUrl;333 this.searching = true; 63 334 } 335 336 }, 500 ), 337 338 pushState: function ( event ) { 339 this.searching = false; 64 340 } 65 341 } ); 66 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 } 368 369 $( '#wcsc-cloner' ).on( 'wcsc:previewSite', '.wcsc-site', function ( event, site ) { 370 control.previewSite( site ); 371 } ); 372 }, 373 374 previewSite: function ( site ) { 375 376 if ( api( 'wcsc_source_site_id' ).get() == site.get( 'site_id' ) ) { 377 //we're already previewing this site 378 return; 379 } 380 381 if ( api.settings.theme.stylesheet === site.get( 'theme_slug' ) ) { 382 api( 'wcsc_source_site_id' ).set( site.get( 'site_id' ) ); 383 } else { 384 //@todo properly set this 385 win.parent.location = win.location.protocol + '//' + win.location.hostname + 386 '/wp-admin/customize.php?theme=' + site.get( 'theme_slug' ) + '&wcsc_source_site_id=' + site.get( 'site_id' ); 387 } 388 }, 389 390 renderSearch: function () { 391 this.view.render(); 392 } 393 394 } ); 395 67 396 /** 68 397 * Parse the URL parameters 69 398 * … … 75 404 */ 76 405 function getUrlParams( url ) { 77 406 var match, questionMarkIndex, query, 78 79 80 81 82 83 407 urlParams = {}, 408 pl = /\+/g, // Regex for replacing addition symbol with a space 409 search = /([^&=]+)=?([^&]*)/g, 410 decode = function ( s ) { 411 return decodeURIComponent( s.replace( pl, " " ) ); 412 }; 84 413 85 414 questionMarkIndex = url.indexOf( '?' ); 86 415 … … 96 425 97 426 return urlParams; 98 427 } 99 } )( window.wp, jQuery ); 428 })( jQuery, Backbone, window, wp ) 429 No newline at end of file -
wordcamp-site-cloner.php
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 14 14 */ 15 15 16 16 // todo if Jetpack_Custom_CSS:get_css is callable, register these, otherwise fatal errors 17 18 add_action( 'plugins_loaded', __NAMESPACE__ . '\get_wordcamp_sites' ); 17 add_action( 'plugins_loaded', __NAMESPACE__ . '\get_wordcamp_sites' ); 19 18 add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\register_scripts' ); 20 add_action( 'admin_menu', 21 add_action( 'customize_register', 19 add_action( 'admin_menu', __NAMESPACE__ . '\add_submenu_page' ); 20 add_action( 'customize_register', __NAMESPACE__ . '\register_customizer_components' ); 22 21 23 22 /** 24 23 * Register scripts and styles 25 24 */ 26 25 function register_scripts() { 27 26 wp_register_style( 28 'wordcamp-site-cloner',29 plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.css',30 array(),31 127 'wordcamp-site-cloner', 28 plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.css', 29 array(), 30 1 32 31 ); 33 32 34 33 wp_register_script( 35 'wordcamp-site-cloner',36 plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.js',37 array( 'jquery', 'customize-controls' ),38 1,39 true34 'wordcamp-site-cloner', 35 plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.js', 36 array( 'jquery', 'customize-controls', 'wp-backbone' ), 37 1, 38 true 40 39 ); 41 40 } 42 41 … … 48 47 */ 49 48 function add_submenu_page() { 50 49 \add_submenu_page( 51 'themes.php',52 __( 'Clone Another WordCamp', 'wordcamporg' ),53 __( 'Clone Another WordCamp', 'wordcamporg' ),54 'switch_themes',55 'customize.php?autofocus[panel]=wordcamp_site_cloner'50 'themes.php', 51 __( 'Clone Another WordCamp', 'wordcamporg' ), 52 __( 'Clone Another WordCamp', 'wordcamporg' ), 53 'switch_themes', 54 'customize.php?autofocus[panel]=wordcamp_site_cloner' 56 55 ); 57 56 } 58 57 … … 63 62 */ 64 63 function register_customizer_components( $wp_customize ) { 65 64 require_once( __DIR__ . '/includes/source-site-id-setting.php' ); 66 require_once( __DIR__ . '/includes/sites-section.php' );67 65 require_once( __DIR__ . '/includes/site-control.php' ); 68 66 69 $wp_customize->register_control_type( __NAMESPACE__ . '\Site_Control' );70 71 67 $wp_customize->add_setting( new Source_Site_ID_Setting( 72 $wp_customize,73 'wcsc_source_site_id',74 array()68 $wp_customize, 69 'wcsc_source_site_id', 70 array() 75 71 ) ); 76 72 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' ), 83 ) 73 $wp_customize->add_section( 'wcsc_sites', array( 74 'title' => __( 'Clone Another WordCamp', 'wordcamporg' ), 75 ) 84 76 ); 85 77 86 $wp_customize->add_section( new Sites_Section( 87 $wp_customize, 88 'wcsc_sites', 89 array( 90 'panel' => 'wordcamp_site_cloner', 91 'title' => __( 'WordCamp Sites', 'wordcamporg' ), 92 ) 93 ) ); 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( 78 $wp_customize->add_control( new Site_Control( 101 79 $wp_customize, 102 'wcsc_site_ id_' . $wordcamp['site_id'],80 'wcsc_site_search', 103 81 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 rendered 105 'site_id' => $wordcamp['site_id'], 106 'site_name' => $wordcamp['name'], 107 'theme_slug' => $wordcamp['theme_slug'], 108 'screenshot_url' => $wordcamp['screenshot_url'], 82 'type' => 'wcscSearch', 83 'label' => __( 'Search', 'wordcamporg' ), 84 'settings' => 'wcsc_source_site_id', 85 'section' => 'wcsc_sites' 109 86 ) 110 ) ); 111 } 87 ) ); 112 88 } 113 89 114 90 /** … … 125 101 require_once( WP_PLUGIN_DIR . '/wcpt/wcpt-wordcamp/wordcamp-loader.php' ); 126 102 127 103 // plugins_loaded is runs on every screen, but we only need this when loading the Customizer and Previewer 128 if ( 'customize.php' != basename( $_SERVER[ 'SCRIPT_NAME'] ) && empty( $_REQUEST['wp_customize'] ) ) {104 if ( 'customize.php' != basename( $_SERVER[ 'SCRIPT_NAME' ] ) && empty( $_REQUEST[ 'wp_customize' ] ) ) { 129 105 return array(); 130 106 } 131 107 … … 139 115 140 116 $sites = array(); 141 117 $wordcamps = get_posts( array( 142 'post_type' => 'wordcamp',143 'post_status' => \WordCamp_Loader::get_public_post_statuses(),144 'posts_per_page' => 125, // todo temporary workaround until able to add filters to make hundreds of sites manageable145 'meta_key' => 'Start Date (YYYY-mm-dd)',146 'orderby' => 'meta_value_num',118 'post_type' => 'wordcamp', 119 'post_status' => \WordCamp_Loader::get_public_post_statuses(), 120 'posts_per_page' => 125, // todo temporary workaround until able to add filters to make hundreds of sites manageable 121 'meta_key' => 'Start Date (YYYY-mm-dd)', 122 'orderby' => 'meta_value_num', 147 123 148 'meta_query' => array( 149 array( 150 'key' => 'Start Date (YYYY-mm-dd)', 151 'value' => strtotime( 'now - 1 month' ), 152 'compare' => '<' 124 'meta_query' => array( 125 array( 126 'key' => 'Start Date (YYYY-mm-dd)', 127 'value' => strtotime( 'now - 1 month' ), 128 'compare' => '<' 129 ), 153 130 ), 154 ),155 131 ) ); 156 132 157 foreach ( $wordcamps as $wordcamp ) {158 $site_id 133 foreach ( $wordcamps as $wordcamp ) { 134 $site_id = get_wordcamp_site_id( $wordcamp ); 159 135 $site_url = get_post_meta( $wordcamp->ID, 'URL', true ); 160 136 161 137 if ( ! $site_id || ! $site_url ) { … … 165 141 switch_to_blog( $site_id ); 166 142 167 143 $sites[] = array( 168 'site_id' => $site_id,169 'name' => get_wordcamp_name(),170 'theme_slug' => get_stylesheet(),171 'screenshot_url' => get_screenshot_url( $site_url ),144 'site_id' => $site_id, 145 'name' => get_wordcamp_name(), 146 'theme_slug' => get_stylesheet(), 147 'screenshot_url' => get_screenshot_url( $site_url ), 172 148 ); 173 149 174 150 restore_current_blog(); … … 195 171 196 172 return apply_filters( 'wcsc_site_screenshot_url', $screenshot_url ); 197 173 } 174 175 /** 176 * Quick and ugly handling to provide a JSON endpoint for the WordCamp Sites data 177 * 178 * @todo Make a real API 179 */ 180 add_action( 'wp_loaded', function() { 181 if ( ! empty( $_GET[ 'get_wordcamp_sites' ] ) ) { 182 $sites = \WordCamp\Site_Cloner\get_wordcamp_sites(); 183 184 $fakeSites = array_merge( $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, 185 $sites, $sites, $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 196 //hack to expand with fake data for now so the front-end can be worked on without having to create 100s of sites 197 if ( defined( 'WCSC_MOCK_FILL_SITES' ) && WCSC_MOCK_FILL_SITES ) { 198 $fake_site_id = 10000; 199 foreach ( $fakeSites as &$site ) { 200 $site[ 'site_id' ] = $fake_site_id; 201 $site[ 'name' ] = $site[ 'name' ] . " Mock Only (Don't Click) - " . $fake_site_id; 202 $fake_site_id++; 203 } 204 205 $sites = array_merge( $sites, $fakeSites ); 206 } 207 208 wp_send_json( $sites ); 209 } 210 } ); 211 No newline at end of file