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
--- 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
@@ -5,12 +5,16 @@ namespace WordCamp\Site_Cloner;
 defined( 'WPINC' ) or die();
 
 /**
- * Custom Customizer Control for a WordCamp site
+ * Custom Customizer Control for Search WordCamp sites to clone
  */
 class Site_Control extends \WP_Customize_Control {
-	public $site_id, $site_name, $screenshot_url, $theme_slug;
-	public $settings = 'wcsc_source_site_id';
-	public $section  = 'wcsc_sites';
+
+	public function __construct( $manager, $id, $args = [ ] ) {
+		parent::__construct( $manager, $id, $args );
+
+		$this->capability = 'edit_theme_options';
+		$this->section = 'wcsc_sites';
+	}
 
 	/**
 	 * Enqueue scripts and styles
@@ -18,20 +22,18 @@ class Site_Control extends \WP_Customize_Control {
 	public function enqueue() {
 		wp_enqueue_style(  'wordcamp-site-cloner' );
 		wp_enqueue_script( 'wordcamp-site-cloner' );
+		add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_view_templates' ) );
 	}
 
-	/**
-	 * Render the control's content
-	 */
 	public function render_content() {
-		$preview_url = add_query_arg(
-			array(
-				'theme'               => rawurlencode( $this->theme_slug ),
-				'wcsc_source_site_id' => rawurlencode( $this->site_id ),
-			),
-			admin_url( 'customize.php' )
-		);
-
 		require( dirname( __DIR__ ) . '/templates/site-control.php' );
 	}
+
+	public function print_view_templates() {
+		?>
+		<script id="tmpl-wcsc-site-option" type="text/html">
+			<?php include dirname( __DIR__ ) . '/templates/site-option.php'; ?>
+		</script>
+		<?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
--- 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
@@ -1,15 +1,20 @@
-<?php defined( 'WPINC' ) or die(); ?>
+<?php
+defined( 'WPINC' ) or die();
 
-<div id="wcsc-site-<?php echo esc_attr( $this->site_id ); ?>" class="wcscSite" data-preview-url="<?php echo esc_url( $preview_url ); ?>">
-	<div class="wcsc-site-screenshot">
-		<img src="<?php echo esc_url( $this->screenshot_url ); ?>" alt="<?php echo esc_attr( $this->site_name ); ?>" />
-	</div>
-
-	<h3 class="wcsc-site-name">
-		<?php echo esc_html( $this->site_name ); ?>
+/**
+ *  Top level template for the output of the Site Cloner Customizer Control
+ */
+?>
+<div id="wcsc-cloner">
+	<h3>
+		<?php esc_html_e( 'WordCamp Sites', 'wordcamporg' ); ?>
+		<span id="wcsc-sites-count" class="title-count wcsc-sites-count"></span>
 	</h3>
+	<div class="filters">
+	</div>
 
-	<span id="live-preview-label-<?php echo esc_attr( $this->site_id ); ?>" class="wcsc-live-preview-label">
-		<?php _e( 'Live Preview', 'wordcamporg' ); ?>
-	</span>
-</div>
+	<div class="wcsc-search">
+		<ul id="wcsc-results">
+		</ul>
+	</div>
+</div>
\ No newline at end of file
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
--- /dev/null
+++ wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/site-option.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ *  Template for a single Site representation within the Site Cloner Control
+ */
+
+defined( 'WPINC' ) or die();
+
+?>
+	<div class="wcsc-site-screenshot">
+		<img src="{{ data.screenshot_url }}" alt="{{ data.name }}"/>
+	</div>
+
+	<h3 class="wcsc-site-name">
+		{{ data.name }}
+	</h3>
+
+	<span id="live-preview-label-{{ data.site_id }}" class="wcsc-live-preview-label">
+		<?php _e( 'Live Preview', 'wordcamporg' ); ?>
+	</span>
+<?php
\ No newline at end of file
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
--- wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/templates/sites-section.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php defined( 'WPINC' ) or die(); ?>
-
-<li id="section-<?php echo esc_attr( $this->id ); ?>" class="accordion-section control-section control-section-<?php echo esc_attr( $this->type ); ?>">
-	<h3>
-		<?php esc_html_e( 'WordCamp Sites' ); ?>
-
-		<span class="title-count wcsc-sites-count">
-			<?php echo count( $this->controls ); ?>
-		</span>
-	</h3>
-
-	<div class="wcsc-sites-section-content">
-		<ul id="wcsc-sites"></ul>
-	</div>
-</li>
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
--- 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
@@ -6,7 +6,7 @@
 		overflow: auto;
 	}
 
-		.wcscSite {
+		.wcsc-site {
 			position: relative;
 			cursor: pointer;
 			border: 1px solid #DEDEDE;
@@ -17,7 +17,7 @@
 				transition: opacity 0.2s ease-in-out 0s;
 			}
 
-				.wcscSite:hover .wcsc-site-screenshot {
+				.wcsc-site:hover .wcsc-site-screenshot {
 					opacity: 0.4;
 				}
 
@@ -38,6 +38,14 @@
 				transition: opacity 0.1s ease-in-out 0s;
 			}
 
-				.wcscSite:hover .wcsc-live-preview-label {
+				.wcsc-site:hover .wcsc-live-preview-label {
 					opacity: 1;
 				}
+
+#wcsc-cloner div.filters {
+	padding: 8px;
+}
+
+#wcsc-cloner div.filters label {
+	position: relative;
+}
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
--- 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
@@ -1,67 +1,397 @@
-( function( wp, $ ) {
+( function ( wp, $, Backbone, win ) {
 	'use strict';
 
 	if ( ! wp || ! wp.customize ) {
 		return;
 	}
 
-	var api = wp.customize;
+	var api = wp.customize,
+	    wcsc;
 
-	/**
-	 * The Clone Another WordCamp panel
-	 */
-	api.panelConstructor.wcscPanel = api.Panel.extend( {
-		/**
-		 * Initialize the panel after it's loaded
-		 *
-		 * Ideally, the Previewer would be set to the requested site ID during the initial PHP request, rather than
-		 * loading the host site in the Previewer, and then refreshing it to use the requested site. That became a
-		 * rabbit hole, though, so it's done this way instead.
-		 */
-		ready : function() {
-			var urlParams = getUrlParams( window.location.href );
+	wcsc = wp.wcSiteCloner = { models: {}, views: {}, collections: {}, settings: {} };
 
-			if ( urlParams.hasOwnProperty( 'wcsc_source_site_id' ) ) {
-				this.expand();
-				api( 'wcsc_source_site_id' ).set( urlParams.wcsc_source_site_id );
+	// @todo dynamically set the real URL
+	wcsc.settings.apiUrl = win.location.protocol + '//' + win.location.hostname + '/wp-admin/customize.php?get_wordcamp_sites=1';
+
+	// @todo implement real l10n
+	var l10n = wcsc.settings.l10n = {
+		search: 'Search'
+	};
+
+
+	// Model for a single site
+	wcsc.models.Site = Backbone.Model.extend( {
+		idAttribute: 'site_id'
+	} );
+
+	// Top level view for the Site Cloner Control
+	wcsc.views.SiteSearch = Backbone.View.extend( {
+		el: '#wcsc-cloner .wcsc-search',
+
+		// index of the currently viewed page of results
+		page: 0,
+
+		initialize: function ( options ) {
+
+			// update scroller position
+			_.bindAll( this, 'scroller' );
+
+			this.$searchContainer = $( '#wcsc-cloner div.filters' );
+
+			// container that will be scrolled within
+			this.$container = $( '#wcsc-cloner' ).parents( 'ul.accordion-section-content' );
+
+			// bind scrolling within the container to check for infinite scroll
+			this.$container.bind( 'scroll', _.throttle( this.scroller, 300 ) );
+		},
+
+		render: function () {
+
+			// View for listing the matching sites
+			this.resultsView = new wcsc.views.SearchResults( {
+				collection: this.collection,
+				parent: this
+			} );
+
+			// render search form
+			this.renderSearch();
+
+			this.resultsView.render();
+			this.$el.empty().append( this.resultsView.el );
+		},
+
+		// Render the search input view
+		renderSearch: function () {
+			var self = this,
+			    view;
+
+			view = new wcsc.views.SearchInput( {
+				collection: this.collection,
+				parent: this
+			} );
+
+			view.render();
+
+			this.$searchContainer
+				.append( $.parseHTML( '<label class="screen-reader-text" for="wp-filter-search-input">' + l10n.search + '</label>' ) );
+			this.$searchContainer
+				.append( view.el );
+		},
+
+		// Checks if a user has reached the bottom of the list
+		// and triggers a scroll event to show more sites if needed
+		scroller: function () {
+			var visibleBottom, threshold, elementHeight, containerHeight, scrollTop;
+
+			scrollTop = this.$container.scrollTop();
+			containerHeight = this.$container.innerHeight();
+			elementHeight = this.$container.get( 0 ).scrollHeight;
+
+			visibleBottom = scrollTop + containerHeight;
+			threshold = Math.round( elementHeight * 0.9 );
+
+			if ( visibleBottom > threshold ) {
+				this.trigger( 'wcsc:scroll' );
 			}
 		}
+
 	} );
 
-	/**
-	 * Custom control representing a site that can be previewed/imported
-	 */
-	api.controlConstructor.wcscSite = api.Control.extend( {
-		/**
-		 * Initialize the control after it's loaded
-		 */
-		ready : function() {
-			this.container.on( 'click', '.wcscSite', this.previewSite );
-		},
-
-		/**
-		 * Preview the selected site
-		 *
-		 * If the site is using a different theme, then reload the entire Customizer with the theme URL parameter
-		 * set, so that the Theme Switcher will handle previewing the new theme for us. Otherwise just set the ID
-		 * to refresh the Previewer with the current theme and the new site's CSS, etc.
-		 *
-		 * @param {object} event
-		 */
-		previewSite : function( event ) {
-			var previewUrl       = $( this ).data( 'preview-url' ),
-				previewUrlParams = getUrlParams( previewUrl );
-
-			if ( api( 'wcsc_source_site_id' ).get() == previewUrlParams.wcsc_source_site_id ) {
+	// Collection representing the list of cloneable sites
+	wcsc.collections.Sites = Backbone.Collection.extend( {
+		model: wcsc.models.Site,
+		terms: '',
+		url: wcsc.settings.apiUrl,
+
+		// Runs the search against the current collection and triggers the update event
+		doSearch: function ( value ) {
+
+			//duplicate search
+			if ( this.terms === value ) {
+				return;
+			}
+
+			this.terms = value;
+
+			//if there are terms, run the serach filter
+			if ( this.terms.length > 0 ) {
+				this.search( this.terms );
+			}
+
+			if ( this.terms === '' ) {
+				this.resetCanonical();
+			}
+
+			this.trigger( 'wcsc:updated' );
+		},
+
+		// resets this collection to the filtered search results
+		search: function ( term ) {
+			var match, results, haystack, name;
+
+			this.resetCanonical( { silent: true } );
+
+			// Escape the term string for RegExp meta characters
+			term = term.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' );
+
+			// Consider spaces as word delimiters and match the whole string
+			// so matching terms can be combined
+			term = term.replace( / /g, ')(?=.*' );
+			match = new RegExp( '^(?=.*' + term + ').+', 'i' );
+
+			// Find results
+			// _.filter and .test
+			results = this.filter( function ( data ) {
+				name = data.get( 'name' ).replace( /(<([^>]+)>)/ig, '' );
+
+				return match.test( name );
+			} );
+
+			if ( results.length === 0 ) {
+				this.trigger( 'query:empty' );
+			}
+
+			this.reset( results );
+		},
+
+		paginate: function ( pageIndex ) {
+			var collection = this;
+			pageIndex = pageIndex || 0;
+
+			collection = _( collection.rest( 20 * pageIndex ) );
+			collection = _( collection.first( 20 ) );
+			return collection;
+		},
+
+		// Resets the site collection dataset to the canonical list originally pulled from the api
+		resetCanonical: function ( options ) {
+			options = options || {};
+			this.reset( wcsc.settings.siteData, options );
+		}
+	} );
+
+
+	// View for a single site
+	wcsc.views.Site = Backbone.View.extend( {
+		className: 'wcsc-site',
+
+		attributes: function () {
+			return {
+				'id': 'wcsc-site-' + this.model.get( 'site_id' ),
+				'data-site-id': this.model.get( 'site_id' )
+			}
+		},
+
+		html: wp.template( 'wcsc-site-option' ),
+
+		touchDrag: false,
+
+		events: {
+			'click': 'preview',
+			'keydown': 'preview',
+			'touchend': 'preview',
+			'touchmove': 'preventPreview'
+		},
+
+		initialize: function ( options ) {
+			this.parent = options.parent;
+
+			this.render();
+		},
+
+		render: function () {
+			var data = this.model.toJSON();
+
+			this.$el.html( this.html( data ) );
+		},
+
+		preventPreview: function () {
+			this.touchDrag = true;
+		},
+
+		preview: function ( event ) {
+			var current, preview;
+
+			event = event || window.event;
+
+			//ignore touches caused by scrolling
+			if ( this.touchDrag === true ) {
+				this.touchDrag = false;
+			}
+
+			event.preventDefault();
+
+			this.$el.trigger( 'wcsc:previewSite', this.model );
+		}
+
+	} );
+
+	wcsc.views.SearchResults = Backbone.View.extend( {
+		className: 'wcsc-results',
+
+		liveSiteCount: 0,
+
+		initialize: function ( options ) {
+			var self = this;
+
+			this.parent = options.parent;
+
+			this.$siteCount = $( '#wcsc-sites-count' );
+
+			// Rerender the view whenever a collection change is complete
+			this.listenTo( self.collection, 'wcsc:updated', function () {
+				//reset pagination
+				self.parent.page = 0;
+				self.render( this );
+			} );
+
+			this.listenTo( this.parent, 'wcsc:scroll', function () {
+				self.renderSites( self.parent.page );
+			} );
+		},
+
+		render: function () {
+			this.$el.empty();
+
+			//if ( this.options.collection.size() > 0 ) {
+			this.renderSites( this.parent.page );
+			//}
+
+			this.$siteCount.text( this.collection.length );
+		},
+
+		renderSites: function ( page ) {
+			var self = this;
+
+			// get a collection of just the requested page
+			this.instance = this.collection.paginate( page );
+
+			if ( this.instance.size() === 0 ) {
+				this.parent.trigger( 'wcsc:end' );
 				return;
 			}
 
-			if ( api.settings.theme.stylesheet === previewUrlParams.theme ) {
-				api( 'wcsc_source_site_id' ).set( previewUrlParams.wcsc_source_site_id );
+			this.instance.each( function ( site ) {
+				var siteView = new wcsc.views.Site( {
+					model: site,
+					parent: self
+				} );
+
+				siteView.render();
+
+				self.$el.append( siteView.el );
+			} );
+
+			this.parent.page++;
+		}
+
+	} );
+
+	// View for the search input field
+	wcsc.views.SearchInput = Backbone.View.extend( {
+		tagName: 'input',
+		className: 'wcsc-filter-search',
+		id: 'wcsc-filter-search-input',
+		searching: false,
+
+		attributes: {
+			type: 'search',
+
+		},
+
+		events: {
+			'input': 'search',
+			'keyup': 'search',
+			'blur': 'pushState'
+		},
+
+		initialize: function ( options ) {
+			this.parent = options.parent;
+		},
+
+		search: function ( event ) {
+			// Clear on escape.
+			if ( event.type === 'keyup' && event.which === 27 ) {
+				event.target.value = '';
+			}
+
+			/**
+			 * Since doSearch is debounced, it will only run when user input comes to a rest
+			 */
+			this.doSearch( event );
+		},
+
+		doSearch: _.debounce( function ( event ) {
+			var options = {};
+
+			this.collection.doSearch( event.target.value );
+
+			// if search is initiated and key is not return
+			if ( this.searching && event.which !== 13 ) {
+				options.replace = true;
+			} else {
+				this.searching = true;
+			}
+
+		}, 500 ),
+
+		pushState: function ( event ) {
+			this.searching = false;
+		}
+	} );
+
+	api.controlConstructor.wcscSearch = api.Control.extend( {
+		ready: function () {
+			var control        = this,
+			    urlParams      = getUrlParams( win.location.href ),
+			    siteCollection = new wcsc.collections.Sites();
+
+			//setup the backbone view for the control
+			//@todo would be nice to delay the fetch until this section is loaded
+			siteCollection.fetch( {
+				success: function ( collection ) {
+					wcsc.settings.siteData = collection.toJSON();
+
+					control.view = new wcsc.views.SiteSearch( {
+						parent: this,
+						collection: collection
+					} );
+
+					control.renderSearch();
+				}
+			} );
+
+			// if the wcsc_source_site_id is set, its most likely from a user previewing a site, so bring them back
+			if ( urlParams.hasOwnProperty( 'wcsc_source_site_id' ) ) {
+				api.section( this.section() ).expand();
+				api( 'wcsc_source_site_id' ).set( urlParams.wcsc_source_site_id );
+			}
+
+			$( '#wcsc-cloner' ).on( 'wcsc:previewSite', '.wcsc-site', function ( event, site ) {
+				control.previewSite( site );
+			} );
+		},
+
+		previewSite: function ( site ) {
+
+			if ( api( 'wcsc_source_site_id' ).get() == site.get( 'site_id' ) ) {
+				//we're already previewing this site
+				return;
+			}
+
+			if ( api.settings.theme.stylesheet === site.get( 'theme_slug' ) ) {
+				api( 'wcsc_source_site_id' ).set( site.get( 'site_id' ) );
 			} else {
-				window.parent.location = previewUrl;
+				//@todo properly set this
+				win.parent.location = win.location.protocol + '//' + win.location.hostname +
+					'/wp-admin/customize.php?theme=' + site.get( 'theme_slug' ) + '&wcsc_source_site_id=' + site.get( 'site_id' );
 			}
+		},
+
+		renderSearch: function () {
+			this.view.render();
 		}
+
 	} );
 
 	/**
@@ -96,4 +426,4 @@
 
 		return urlParams;
 	}
-} )( window.wp, jQuery );
+} )( window.wp, jQuery, Backbone, window );
\ No newline at end of file
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
--- 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
@@ -7,7 +7,7 @@ defined( 'WPINC' ) or die();
 /*
 Plugin Name: WordCamp Site Cloner
 Description: Allows organizers to clone another WordCamp's theme and custom CSS as a starting point for their site.
-Version:     0.1
+Version:     0.2.0-alpha
 Author:      WordCamp.org
 Author URI:  http://wordcamp.org
 License:     GPLv2 or later
@@ -34,7 +34,7 @@ function register_scripts() {
 	wp_register_script(
 		'wordcamp-site-cloner',
 		plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.js',
-		array( 'jquery', 'customize-controls' ),
+		array( 'jquery', 'customize-controls', 'wp-backbone' ),
 		1,
 		true
 	);
@@ -63,52 +63,29 @@ function add_submenu_page() {
  */
 function register_customizer_components( $wp_customize ) {
 	require_once( __DIR__ . '/includes/source-site-id-setting.php' );
-	require_once( __DIR__ . '/includes/sites-section.php' );
 	require_once( __DIR__ . '/includes/site-control.php' );
 
-	$wp_customize->register_control_type( __NAMESPACE__ . '\Site_Control' );
-
 	$wp_customize->add_setting( new Source_Site_ID_Setting(
 		$wp_customize,
 		'wcsc_source_site_id',
 		array()
 	) );
 
-	$wp_customize->add_panel(
-		'wordcamp_site_cloner',
-		array(
-			'type'        => 'wcscPanel',
-			'title'       => __( 'Clone Another WordCamp', 'wordcamporg' ),
-			'description' => __( "Clone another WordCamp's theme and custom CSS as a starting point for your site.", 'wordcamporg' ),
+	$wp_customize->add_section( 'wcsc_sites', array(
+			'title' => __( 'Clone Another WordCamp', 'wordcamporg' ),
 		)
 	);
 
-	$wp_customize->add_section( new Sites_Section(
+	$wp_customize->add_control( new Site_Control(
 		$wp_customize,
-		'wcsc_sites',
+		'wcsc_site_search',
 		array(
-			'panel' => 'wordcamp_site_cloner',
-			'title' => __( 'WordCamp Sites', 'wordcamporg' ),
+			'type'     => 'wcscSearch',
+			'label'    => __( 'Search', 'wordcamporg' ),
+			'settings' => 'wcsc_source_site_id',
+			'section'  => 'wcsc_sites'
 		)
 	) );
-
-	foreach( get_wordcamp_sites() as $wordcamp ) {
-		if ( get_current_blog_id() == $wordcamp['site_id'] ) {
-			continue;
-		}
-
-		$wp_customize->add_control( new Site_Control(
-			$wp_customize,
-			'wcsc_site_id_' . $wordcamp['site_id'],
-			array(
-				'type'           => 'wcscSite',                      // todo should be able to set this in control instead of here, but if do that then control contents aren't rendered
-				'site_id'        => $wordcamp['site_id'],
-				'site_name'      => $wordcamp['name'],
-				'theme_slug'     => $wordcamp['theme_slug'],
-				'screenshot_url' => $wordcamp['screenshot_url'],
-			)
-		) );
-	}
 }
 
 /**
@@ -195,3 +172,40 @@ function get_screenshot_url( $site_url ) {
 
 	return apply_filters( 'wcsc_site_screenshot_url', $screenshot_url );
 }
+
+/**
+ * Quick and ugly handling to provide a JSON endpoint for the WordCamp Sites data
+ *
+ * @todo Make a real API
+ */
+add_action( 'wp_loaded', function() {
+	if ( ! empty( $_GET[ 'get_wordcamp_sites' ] ) ) {
+		$sites = \WordCamp\Site_Cloner\get_wordcamp_sites();
+
+		$fakeSites = array_merge( $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites,
+			$sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites, $sites );
+
+		//hack to expand with fake data for now so the front-end can be worked on without having to create 100s of sites
+		if ( defined( 'WCSC_MOCK_FILL_SITES' ) && WCSC_MOCK_FILL_SITES ) {
+			$fake_site_id = 10000;
+			foreach ( $fakeSites as &$site ) {
+				$site[ 'site_id' ] = $fake_site_id;
+				$site[ 'name' ] = $site[ 'name' ] . " Mock Only (Don't Click) - " . $fake_site_id;
+				$fake_site_id++;
+			}
+
+			$sites = array_merge( $sites, $fakeSites );
+		}
+
+		wp_send_json( $sites );
+	}
+} );
\ No newline at end of file
