'.esc_html($text); if (! $renew) echo ' '.esc_html(I18n::t($kind === 'affected' || $kind === 'stale' ? 'notice_action' : 'settings')).''; echo '
'; if ($renew) Admin::form('automatic', 'renew_connection'); echo ''; } public static function expiry(): void { if (! Client::connected()) return; $expires = strtotime(Store::get('connection')['expires_at']); if ($expires > time() && $expires <= time() + 14 * DAY_IN_SECONDS) self::box('expiry', Store::get('connection')['site_id'].'|'.$expires, I18n::t('expires_soon', I18n::date($expires)), 'notice-warning', true); } private static function current(array $snapshot): array { $key = $snapshot['generation'].'|'.(string) Store::get('inventory_dirty', ''); $cached = get_site_transient('flx_security_notice_inventory'); if (is_array($cached) && ($cached['key'] ?? '') === $key) return $cached; global $wpdb; $items = Inventory::collect(); $versions = array_column($items, 'version', 'id'); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- Bounded plugin-owned snapshot read, cached for five minutes and invalidated on installation changes. $rows = $wpdb->get_results($wpdb->prepare('SELECT item_key,version FROM %i WHERE generation=%s AND status=%s AND item_key NOT IN (%s,%s)', Store::table('plugins'), $snapshot['generation'], 'affected', Inventory::selfKey(), Inventory::legacyKey())); if ($wpdb->last_error !== '') throw new \RuntimeException('storage_unavailable'); $count = 0; foreach ($rows as $row) if (($versions[$row->item_key] ?? null) === $row->version) $count++; $result = ['key' => $key, 'count' => $count, 'changed' => ! hash_equals($snapshot['fingerprint'] ?? '', Inventory::fingerprint($items))]; set_site_transient('flx_security_notice_inventory', $result, 300); return $result; } public static function render(): void { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Page selection only limits a read-only notice. if (! Admin::allowed() || (int) Store::get('schema', 0) !== 2 || (isset($_GET['page']) && $_GET['page'] === 'fluxcdn-security')) return; if (ConnectionChanges::pending()) return; if (($error = Client::connectionError()) !== '') { echo ''.esc_html(I18n::t('error_'.I18n::errorCode($error))).' '.esc_html(I18n::t('connect')).'