Changeset 4280 for sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.php
- Timestamp:
- 10/21/2016 04:10:02 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-site-cloner/wordcamp-site-cloner.php
r2933 r4280 1 1 <?php 2 3 namespace WordCamp\Site_Cloner;4 5 defined( 'WPINC' ) or die();6 2 7 3 /* 8 4 Plugin Name: WordCamp Site Cloner 9 5 Description: Allows organizers to clone another WordCamp's theme and custom CSS as a starting point for their site. 10 Version: 0. 16 Version: 0.2 11 7 Author: WordCamp.org 12 8 Author URI: http://wordcamp.org … … 14 10 */ 15 11 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' ); 19 add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\register_scripts' ); 20 add_action( 'admin_menu', __NAMESPACE__ . '\add_submenu_page' ); 21 add_action( 'customize_register', __NAMESPACE__ . '\register_customizer_components' ); 12 namespace WordCamp\Site_Cloner; 13 defined( 'WPINC' ) or die(); 14 15 const PRIME_SITES_CRON_ACTION = 'wcsc_prime_sites'; 16 const WORDCAMP_SITES_TRANSIENT_KEY = 'wcsc_sites'; 17 18 /** 19 * Initialization 20 */ 21 function initialize() { 22 // We rely on the Custom CSS module being available 23 if ( ! class_exists( '\Jetpack' ) ) { 24 return; 25 } 26 27 add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\register_scripts' ); 28 add_action( 'admin_menu', __NAMESPACE__ . '\add_submenu_page' ); 29 add_action( 'customize_register', __NAMESPACE__ . '\register_customizer_components' ); 30 add_action( 'rest_api_init', __NAMESPACE__ . '\register_api_endpoints' ); 31 add_action( PRIME_SITES_CRON_ACTION, __NAMESPACE__ . '\prime_wordcamp_sites' ); 32 33 if ( ! wp_next_scheduled( PRIME_SITES_CRON_ACTION ) ) { 34 wp_schedule_event( time(), 'daily', PRIME_SITES_CRON_ACTION ); 35 } 36 } 37 add_action( 'plugins_loaded', __NAMESPACE__ . '\initialize' ); // After Jetpack has loaded 22 38 23 39 /** … … 29 45 plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.css', 30 46 array(), 31 147 2 32 48 ); 33 49 … … 35 51 'wordcamp-site-cloner', 36 52 plugin_dir_url( __FILE__ ) . 'wordcamp-site-cloner.js', 37 array( 'jquery', 'customize-controls' ),38 1,53 array( 'jquery', 'customize-controls', 'wp-backbone' ), 54 2, 39 55 true 40 56 ); 57 58 wp_localize_script( 59 'wordcamp-site-cloner', 60 '_wcscSettings', 61 array( 62 'apiUrl' => get_rest_url( null, '/wordcamp-site-cloner/v1/sites/' ), 63 'customizerUrl' => admin_url( 'customize.php' ), 64 'themes' => get_available_themes(), 65 ) 66 ); 67 } 68 69 /** 70 * Get all of the available themes 71 * 72 * @return array 73 */ 74 function get_available_themes() { 75 /** @var \WP_Theme $theme */ 76 $available_themes = array(); 77 $raw_themes = wp_get_themes( array( 'allowed' => true ) ); 78 79 foreach ( $raw_themes as $theme ) { 80 $theme_name = $theme->display( 'Name' ); 81 $available_themes[] = array( 82 'slug' => $theme->get_stylesheet(), 83 'name' => $theme_name ?: $theme->get_stylesheet() 84 ); 85 } 86 87 return $available_themes; 41 88 } 42 89 … … 53 100 __( 'Clone Another WordCamp', 'wordcamporg' ), 54 101 'switch_themes', 55 'customize.php?autofocus[ panel]=wordcamp_site_cloner'102 'customize.php?autofocus[section]=wcsc_sites' 56 103 ); 57 104 } … … 64 111 function register_customizer_components( $wp_customize ) { 65 112 require_once( __DIR__ . '/includes/source-site-id-setting.php' ); 66 require_once( __DIR__ . '/includes/sites-section.php' );67 113 require_once( __DIR__ . '/includes/site-control.php' ); 68 69 $wp_customize->register_control_type( __NAMESPACE__ . '\Site_Control' );70 114 71 115 $wp_customize->add_setting( new Source_Site_ID_Setting( 72 116 $wp_customize, 73 117 'wcsc_source_site_id', 74 array( )118 array( 'capability' => 'switch_themes' ) 75 119 ) ); 76 120 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 ) 84 ); 85 86 $wp_customize->add_section( new Sites_Section( 87 $wp_customize, 121 $wp_customize->add_section( 88 122 'wcsc_sites', 89 123 array( 90 'panel' => 'wordcamp_site_cloner', 91 'title' => __( 'WordCamp Sites', 'wordcamporg' ), 124 'title' => __( 'Clone Another WordCamp', 'wordcamporg' ), 125 'capability' => 'switch_themes' 126 ) 127 ); 128 129 $wp_customize->add_control( new Site_Control( 130 $wp_customize, 131 'wcsc_site_search', 132 array( 133 'type' => 'wcscSearch', 134 'label' => __( 'Search', 'wordcamporg' ), 135 'settings' => 'wcsc_source_site_id', 136 'section' => 'wcsc_sites' 92 137 ) 93 138 ) ); 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 rendered 105 '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 } 113 114 /** 115 * Get required data for relevant WordCamp sites 116 * 117 * This isn't actually used until register_customizer_components(), but it's called during `plugins_loaded` in 118 * order to prime the cache. That has to be done before `setup_theme`, because the Theme Switcher will override 119 * the current theme when `?theme=` is present in the URL parameters, and it's safer to just avoid that than to 120 * muck with the internals and try to reverse it on the fly. 139 } 140 141 /** 142 * Register the REST API endpoint for the Customizer to use to retriever the site list 143 */ 144 function register_api_endpoints() { 145 if ( ! current_user_can( 'switch_themes' ) ) { 146 return; 147 148 // todo - use `permission_callback` instead 149 } 150 151 register_rest_route( 152 'wordcamp-site-cloner/v1', 153 '/sites', 154 array( 155 'methods' => 'GET', 156 'callback' => __NAMESPACE__ . '\sites_endpoint', 157 ) 158 ); 159 } 160 161 /** 162 * Handle the response for the Sites endpoint 163 * 164 * This always pulls cached data, because Central needs to be the site generating it. See get_wordcamp_sites(). 121 165 * 122 166 * @return array 123 167 */ 168 function sites_endpoint() { 169 $sites = array(); 170 $cached_sites = get_site_transient( WORDCAMP_SITES_TRANSIENT_KEY ); 171 172 if ( $cached_sites ) { 173 unset( $cached_sites[ get_current_blog_id() ] ); 174 175 $sites = array_values( $cached_sites ); 176 } 177 178 return $sites; 179 } 180 181 /** 182 * Prime the cache of cloneable WordCamp sites 183 * 184 * This is called via WP Cron. 185 * 186 * @todo - Reintroduce batching from `1112.3.diff` to get more than 500 sites 187 */ 188 function prime_wordcamp_sites() { 189 // This only needs to run on a single site, then the whole network can use the cached result 190 if ( ! is_main_site() ) { 191 return; 192 } 193 194 // Keep the cache longer than needed, just to be sure that it doesn't expire before the cron job runs again 195 set_site_transient( WORDCAMP_SITES_TRANSIENT_KEY, get_wordcamp_sites(), DAY_IN_SECONDS * 2 ); 196 } 197 198 /** 199 * Get WordCamp sites that are suitable for cloning 200 * 201 * @return array 202 */ 124 203 function get_wordcamp_sites() { 125 require_once( WP_PLUGIN_DIR . '/wcpt/wcpt-wordcamp/wordcamp-loader.php' ); 126 127 // 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'] ) ) { 204 /* 205 * The post statuses that \WordCamp_Loader::get_public_post_statuses() returns are only created on Central, 206 * because the plugin isn't active on any other sites. 207 */ 208 if ( ! is_main_site() ) { 129 209 return array(); 130 210 } 131 211 132 $transient_key = 'wcsc_sites'; 133 134 if ( $sites = get_site_transient( $transient_key ) ) { 135 return $sites; 212 if ( ! \Jetpack::is_module_active( 'custom-css' ) ) { 213 \Jetpack::activate_module( 'custom-css', false, false ); 136 214 } 137 215 138 216 switch_to_blog( BLOG_ID_CURRENT_SITE ); // central.wordcamp.org 139 217 140 $sites = array(); 141 $wordcamps = get_posts( array( 142 'post_type' => 'wordcamp', 218 $wordcamp_query = new \WP_Query( array( 219 'post_type' => WCPT_POST_TYPE_ID, 143 220 '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 manageable221 'posts_per_page' => 500, 145 222 'meta_key' => 'Start Date (YYYY-mm-dd)', 146 223 'orderby' => 'meta_value_num', 224 'order' => 'DESC', 147 225 148 226 'meta_query' => array( 149 227 array( 228 // New sites won't have finished designs, so ignore them 150 229 'key' => 'Start Date (YYYY-mm-dd)', 151 230 'value' => strtotime( 'now - 1 month' ), 152 231 'compare' => '<' 153 ) ,232 ) 154 233 ), 155 234 ) ); 156 235 157 foreach( $wordcamps as $wordcamp ) { 158 $site_id = get_wordcamp_site_id( $wordcamp ); 159 $site_url = get_post_meta( $wordcamp->ID, 'URL', true ); 160 161 if ( ! $site_id || ! $site_url ) { 236 $sites = get_filtered_wordcamp_sites( $wordcamp_query->get_posts() ); 237 238 uasort( $sites, __NAMESPACE__ . '\sort_sites_by_year' ); 239 240 restore_current_blog(); 241 242 return $sites; 243 } 244 245 /** 246 * Filter out sites that aren't relevant to the Cloner 247 * 248 * @param array $wordcamps 249 * 250 * @return array 251 */ 252 function get_filtered_wordcamp_sites( $wordcamps ) { 253 $sites = array(); 254 255 foreach ( $wordcamps as $wordcamp ) { 256 $site_id = get_wordcamp_site_id( $wordcamp ); 257 $site_url = get_post_meta( $wordcamp->ID, 'URL', true ); 258 $start_date = get_post_meta( $wordcamp->ID, 'Start Date (YYYY-mm-dd)', true ); 259 260 if ( ! $site_id || ! $site_url || ! $start_date ) { 162 261 continue; 163 262 } … … 165 264 switch_to_blog( $site_id ); 166 265 167 $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 ), 172 ); 266 /* 267 * Sites with Coming Soon enabled probably don't have a finished design yet, so there's no point in 268 * cloning it. 269 */ 270 if ( ! coming_soon_plugin_enabled() ) { 271 $preprocessor = \Jetpack_Custom_CSS::get_preprocessor(); 272 $preprocessor = isset( $preprocessor[ 'name' ] ) ? $preprocessor[ 'name' ] : 'none'; 273 274 $sites[ $site_id ] = array( 275 'site_id' => $site_id, 276 'name' => get_wordcamp_name(), 277 'theme_slug' => get_stylesheet(), 278 'screenshot_url' => get_screenshot_url( $site_url ), 279 'year' => date( 'Y', $start_date ), 280 'css_preprocessor' => $preprocessor, 281 ); 282 } 173 283 174 284 restore_current_blog(); 175 285 } 176 286 177 restore_current_blog();178 179 set_site_transient( $transient_key, $sites, DAY_IN_SECONDS );180 181 287 return $sites; 288 } 289 290 /** 291 * Determine if the Coming Soon plugin is enabled for the current site 292 * 293 * @return bool 294 */ 295 function coming_soon_plugin_enabled() { 296 global $WCCSP_Settings; 297 $enabled = false; 298 299 if ( ! is_callable( 'WCCSP_Settings::get_settings' ) ) { 300 return $enabled; 301 } 302 303 // We may need to instantiate the class if this is the first time calling this function 304 if ( ! is_a( $WCCSP_Settings, 'WCCSP_Settings' ) ) { 305 $WCCSP_Settings = new \WCCSP_Settings(); 306 } 307 308 $settings = $WCCSP_Settings->get_settings(); 309 310 if ( isset( $settings[ 'enabled' ] ) && 'on' === $settings[ 'enabled' ] ) { 311 $enabled = true; 312 } 313 314 return $enabled; 182 315 } 183 316 … … 196 329 return apply_filters( 'wcsc_site_screenshot_url', $screenshot_url ); 197 330 } 331 332 /** 333 * Sort arrays by the year 334 * 335 * @param array $site_a 336 * @param array $site_b 337 * 338 * @return int 339 */ 340 function sort_sites_by_year( $site_a, $site_b ) { 341 if ( $site_a[ 'year' ] === $site_b[ 'year' ] ) { 342 return 0; 343 } 344 345 return ( $site_a[ 'year' ] < $site_b[ 'year' ] ? 1 : -1 ); 346 }
Note: See TracChangeset
for help on using the changeset viewer.