( new Odyssey_Config_Data() )->get_data(), 'config_variable_name' => 'configData', 'enqueue_css' => true, ); $options = wp_parse_args( $options, $default_options ); if ( file_exists( __DIR__ . "/../dist/{$asset_name}.js" ) ) { // Load local assets for the convinience of development. Assets::register_script( $asset_handle, "../dist/{$asset_name}.js", __FILE__, array( 'in_footer' => true, 'textdomain' => 'jetpack-stats-admin', ) ); Assets::enqueue_script( $asset_handle ); } else { // In production, we load the assets from our CDN. wp_register_script( $asset_handle, sprintf( self::ODYSSEY_CDN_URL, self::ODYSSEY_STATS_VERSION, "{$asset_name}.js", $this->get_cdn_asset_cache_buster() ), self::JS_DEPENDENCIES, $this->get_cdn_asset_cache_buster(), true ); wp_enqueue_script( $asset_handle ); // Enqueue CSS if needed. if ( $options['enqueue_css'] ) { $css_url = $asset_name . ( is_rtl() ? '.rtl' : '' ) . '.css'; $css_handle = $asset_handle . '-style'; wp_register_style( $css_handle, sprintf( self::ODYSSEY_CDN_URL, self::ODYSSEY_STATS_VERSION, $css_url, $this->get_cdn_asset_cache_buster() ), array(), $this->get_cdn_asset_cache_buster() ); wp_enqueue_style( $css_handle ); } } wp_add_inline_script( $asset_handle, ( new Odyssey_Config_Data() )->get_js_config_data( $options['config_variable_name'], $options['config_data'] ), 'before' ); } /** * Returns cache buster string for assets. * Development mode doesn't need this, as it's handled by `Assets` class. * * @return string */ protected function get_cdn_asset_cache_buster() { $now_in_ms = floor( microtime( true ) * 1000 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( isset( $_GET['force_refresh'] ) ) { update_option( self::ODYSSEY_STATS_CACHE_BUSTER_CACHE_KEY, $this->get_cache_buster_option_value( $now_in_ms ), false ); } // Use cached cache buster in production. $remote_asset_version = get_option( self::ODYSSEY_STATS_CACHE_BUSTER_CACHE_KEY ); if ( ! empty( $remote_asset_version ) ) { $remote_asset_version = json_decode( $remote_asset_version, true ); // If cache buster is cached and not expired (valid in 15 min), return it. if ( ! empty( $remote_asset_version['cache_buster'] ) && $remote_asset_version['cached_at'] > $now_in_ms - MINUTE_IN_SECONDS * 1000 * 15 ) { return $remote_asset_version['cache_buster']; } } // If no cached cache buster, we fetch it from CDN and set to transient. $response = wp_remote_get( sprintf( self::ODYSSEY_CDN_URL, self::ODYSSEY_STATS_VERSION, 'build_meta.json', $now_in_ms ), array( 'timeout' => 5 ) ); if ( is_wp_error( $response ) ) { // fallback to current timestamp. return (string) $now_in_ms; } $build_meta = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! empty( $build_meta['cache_buster'] ) ) { // Cache the cache buster for 15 mins. update_option( self::ODYSSEY_STATS_CACHE_BUSTER_CACHE_KEY, $this->get_cache_buster_option_value( $build_meta['cache_buster'] ), false ); return $build_meta['cache_buster']; } // fallback to current timestamp. return (string) $now_in_ms; } /** * Get the cache buster option value. * * @param string|int|float $cache_buster The cache buster. * @return string|false */ protected function get_cache_buster_option_value( $cache_buster ) { return wp_json_encode( array( 'cache_buster' => (string) $cache_buster, 'cached_at' => floor( microtime( true ) * 1000 ), // milliseconds. ) ); } }