false, 'license_key' => '', 'site_id' => '', 'site_token' => '', 'plan' => 'free', 'cdn_base' => '', // What the service does for this site's plan: images, assets and critical only count (see // SERVICE_FEATURES). cache, js and delay run inside the plugin and are on for everyone. 'features' => array( 'cache' => true, 'images' => true, 'assets' => true, 'js' => true, 'delay' => true, 'critical' => false, ), // Features switched off by the Safety Check: feature => reason. 'disabled' => array(), // Pages where each of those features broke; later checks look at them again. 'disabled_pages' => array(), 'rules' => array(), 'rules_fetched' => 0, 'quota' => array(), 'cdn_paused' => false, 'critical_css' => array(), 'last_selftest' => array(), 'selftest_job' => '', 'last_score' => array(), 'last_error' => '', 'activated_at' => 0, 'cache_ttl' => 36000, // upper bound; the real TTL also stays under half the nonce life (Page_Cache::effective_ttl) 'purge_token' => '', 'badge' => false, 'share_email' => false, 'pending_reg' => array(), // registration waiting for the ownership check 'connected_host' => '', // address the token was issued for; a copy on another address disconnects 'cloudflare_detected' => false, 'cloudflare_token' => '', 'cloudflare_zone' => '', ); } public static function all() { if ( null === self::$cache ) { $o = get_option( self::KEY, array() ); self::$cache = array_merge( self::defaults(), is_array( $o ) ? $o : array() ); } return self::$cache; } public static function get( $key, $default = null ) { $o = self::all(); return array_key_exists( $key, $o ) ? $o[ $key ] : $default; } public static function set( $key, $value ) { self::update( array( $key => $value ) ); return $value; } public static function update( array $patch ) { // Merge the patch into what is stored NOW, not into the copy this request read at its start. // A cron run that waited 10 s on the edge would otherwise write back its stale copy and undo // whatever happened meanwhile (seen live: a license activated during a heartbeat was lost). wp_cache_delete( self::KEY, 'options' ); $fresh = get_option( self::KEY, array() ); $o = array_merge( self::defaults(), is_array( $fresh ) ? $fresh : array(), $patch ); self::$cache = $o; update_option( self::KEY, $o, false ); if ( class_exists( 'ZeroConfig_Page_Cache' ) ) { ZeroConfig_Page_Cache::write_config(); } } /** * A lock that survives across requests and processes (two cron runners, WP-CLI next to a visit). * add_option() is a single INSERT, so only one caller can create the row; a lock older than $ttl * is taken over (its holder died). Returns true when this caller holds it. */ public static function lock( $name, $ttl ) { $key = 'zeroconfig_lock_' . $name; $got = add_option( $key, time() + (int) $ttl, '', false ); if ( ! $got ) { wp_cache_delete( $key, 'options' ); if ( (int) get_option( $key, 0 ) < time() ) { delete_option( $key ); $got = add_option( $key, time() + (int) $ttl, '', false ); } } if ( $got ) { // Released even when the request dies on a fatal error, so a crash does not block the next run for $ttl. if ( ! self::$locks ) { register_shutdown_function( array( __CLASS__, 'unlock_all' ) ); } self::$locks[ $name ] = true; } return $got; } private static $locks = array(); public static function unlock( $name ) { unset( self::$locks[ $name ] ); delete_option( 'zeroconfig_lock_' . $name ); } public static function unlock_all() { foreach ( array_keys( self::$locks ) as $name ) { self::unlock( $name ); } } /** Work done on the service's servers. Only these follow the plan; everything else runs in the plugin, free. */ const SERVICE_FEATURES = array( 'images', 'assets', 'critical' ); /** The plan allows this feature: always for what runs in the plugin, per plan for the service's work. */ public static function feature_allowed( $feature ) { if ( ! in_array( $feature, self::SERVICE_FEATURES, true ) ) { return true; } $o = self::all(); return ! empty( $o['features'][ $feature ] ); } /** * A feature is live when: engine on, allowed (see feature_allowed), the Safety Check has not * disabled it, and the compatibility rules do not switch it off for this site (a theme or plugin * known to break with it). */ public static function feature_on( $feature ) { $o = self::all(); if ( empty( $o['engine'] ) || ! self::feature_allowed( $feature ) || ! empty( $o['disabled'][ $feature ] ) ) { return false; } $off = isset( $o['rules']['features_off'] ) ? (array) $o['rules']['features_off'] : array(); return ! in_array( $feature, $off, true ); } public static function is_connected() { $o = self::all(); return ! empty( $o['site_id'] ) && ! empty( $o['site_token'] ); } public static function brand() { $brand = defined( 'ZEROCONFIG_WHITE_LABEL' ) && ZEROCONFIG_WHITE_LABEL ? ZEROCONFIG_WHITE_LABEL : 'ZeroConfig'; return apply_filters( 'zeroconfig_brand', $brand ); } public static function is_white_label() { return 'ZeroConfig' !== self::brand(); } }