process( $html ); } if ( ZeroConfig_Page_Cache::storable() ) { ZeroConfig_Page_Cache::store( $html ); } return $html; } /** We decide lazy loading ourselves (LCP-aware); let core stay out of it. */ public function native_lazy( $enabled, $tag ) { return ZeroConfig_Options::feature_on( 'images' ) && 'img' === $tag ? false : $enabled; } public function headers( $headers ) { if ( ZeroConfig_Options::get( 'engine' ) && ! ZeroConfig_Options::is_white_label() ) { $headers['X-ZeroConfig-Engine'] = 'ZeroConfig/' . ZEROCONFIG_VERSION; } return $headers; } public function register_cli() { if ( defined( 'WP_CLI' ) && WP_CLI ) { WP_CLI::add_command( 'zeroconfig', function ( $args ) { $cmd = isset( $args[0] ) ? $args[0] : 'status'; switch ( $cmd ) { case 'on': self::turn_on(); WP_CLI::success( 'Engine on.' ); break; case 'off': self::turn_off(); WP_CLI::success( 'Engine off.' ); break; case 'purge': if ( ! empty( $args[1] ) ) { ZeroConfig_Page_Cache::purge_url( $args[1] ); ZeroConfig_CDN_Purge::run_queue(); WP_CLI::success( 'Purged ' . $args[1] ); break; } ZeroConfig_Page_Cache::purge_all( 'cli' ); ZeroConfig_CDN_Purge::run_queue(); // an explicit purge is believed at once WP_CLI::success( 'Cache purged (local, upstream, edge).' ); break; case 'check': ZeroConfig_Safe_Mode::schedule( 1 ); WP_CLI::success( 'Safety Check scheduled.' ); break; case 'doctor': // the five rows and their reason codes, for pasting into a support ticket $d = ZeroConfig_Doctor::run(); if ( ! empty( $d['off'] ) ) { WP_CLI::log( 'Engine is off.' ); break; } foreach ( ZeroConfig_Doctor::ROWS as $row ) { $r = $d['rows'][ $row ]; WP_CLI::log( sprintf( '%-5s %s', strtoupper( $r['status'] ), ZeroConfig_Doctor::row_label( $row ) ) ); foreach ( $r['items'] as $item ) { list( $owner, $text, $fix ) = ZeroConfig_Doctor::reason( $item['code'], $item['args'] ); WP_CLI::log( " [{$item['code']}] $text" . ( '' !== $fix ? "\n → $fix" : '' ) ); } } WP_CLI::log( 'probe: ' . wp_json_encode( $d['probe'] ) ); break; case 'warm': $w = ZeroConfig_Warm::run(); WP_CLI::log( wp_json_encode( array_diff_key( $w, array( 'items' => 1 ) ) ) ); break; default: // Secrets stay out of terminals and support tickets. $all = ZeroConfig_Options::all(); foreach ( array( 'site_token', 'cloudflare_token', 'purge_token', 'license_key' ) as $secret ) { $all[ $secret ] = '' === (string) $all[ $secret ] ? '' : '(set)'; } WP_CLI::log( wp_json_encode( $all, JSON_PRETTY_PRINT ) ); } } ); } } /* ---------- switch ---------- */ /** * The only place the site connects to the ZeroConfig service. It runs when an * admin presses "Turn on" under a disclosure of exactly what is sent. */ public static function turn_on() { // One network shares wp-config.php, .htaccess and advanced-cache.php: a single site's admin must // not change them for every site. Multisite is not supported yet. if ( is_multisite() ) { return new WP_Error( 'zc_multisite', __( 'ZeroConfig does not support WordPress multisite networks yet.', 'zeroconfig' ) ); } ZeroConfig_Options::update( array( 'engine' => true, 'activated_at' => time(), 'disabled' => array(), 'disabled_pages' => array() ) ); ZeroConfig_Cron::ensure(); // The page cache works locally right away; edge features follow once the site is verified. $dropin = ZeroConfig_Page_Cache::install_dropin(); ZeroConfig_CDN_Purge::purge_token(); // One purge per click: on_connected() purges once the edge URLs are known; otherwise purge here. $purged = false; if ( ZeroConfig_Options::is_connected() ) { $hb = ZeroConfig_API::heartbeat(); if ( ZeroConfig_Options::is_connected() && ! is_wp_error( $hb ) ) { self::on_connected( 'turn_on' ); $purged = true; } } else { ZeroConfig_API::register_site(); // ownership check runs in the background; see claim_pending() } if ( ! $purged ) { ZeroConfig_Page_Cache::purge_all( 'turn_on' ); } return $dropin; } /** Edge features that need a verified connection. */ public static function on_connected( $source = 'connected' ) { if ( ! ZeroConfig_Options::get( 'engine' ) ) { return; } if ( ! ZeroConfig_Options::get( 'rules' ) ) { ZeroConfig_API::fetch_rules(); } // Reconnected after a reinstall or move: put the saved licence back on (fails harmlessly if its seats are used). $key = (string) ZeroConfig_Options::get( 'license_key' ); if ( '' !== $key && 'free' === ZeroConfig_Options::get( 'plan' ) ) { ZeroConfig_API::activate_license( $key ); } ZeroConfig_Page_Cache::purge_all( $source ); // cached HTML must pick up edge URLs ZeroConfig_Cron::request_critical(); ZeroConfig_Safe_Mode::schedule( 90 ); } public static function turn_off() { $was_on = (bool) ZeroConfig_Options::get( 'engine' ); ZeroConfig_Options::update( array( 'engine' => false ) ); if ( $was_on ) { ZeroConfig_API::heartbeat_off(); // the service stops its visits; nothing else is sent after this } ZeroConfig_Page_Cache::purge_all( 'turn_off' ); ZeroConfig_CDN_Purge::run_queue(); // background events are cleared below: Cloudflare must hear it now ZeroConfig_Page_Cache::remove_dropin(); ZeroConfig_Cron::clear(); // engine off = no background calls to the service at all } /* ---------- lifecycle ---------- */ public static function activate( $network_wide = false ) { // Activation is local only. Nothing is sent anywhere until an admin presses "Turn on". wp_mkdir_p( ZEROCONFIG_CACHE_DIR ); ZeroConfig_Page_Cache::write_config(); // Open the settings page once, for the admin who activated it in the browser. if ( ! $network_wide && ! ( defined( 'WP_CLI' ) && WP_CLI ) && get_current_user_id() ) { set_transient( 'zeroconfig_activation_redirect', get_current_user_id(), 60 ); } } public static function deactivate() { self::turn_off(); ZeroConfig_Cron::clear(); } }