id === 'update') { return; } // Stored secrets no longer decryptable — typically after a WP salt rotation, // which changes the key they were sealed with. Shown first and non-dismissible // because everything cloud-related is silently broken until it is resolved. $mismatch = Config::keyMismatch(); if ($mismatch !== null) { echo '

'; echo esc_html__('Sentinelo: unreadable secrets.', 'sentinelo'); echo ' '; printf( /* translators: %s: name of the unreadable secret (api_key, cloud_credentials) */ esc_html__('The secret “%s” can no longer be decrypted. The WordPress security keys (salts) have probably been regenerated. Re-enter the configuration in Settings → Sentinelo to restore cloud backups.', 'sentinelo'), esc_html((string) ($mismatch['what'] ?? '?')) ); echo '

'; } // API key missing if (Config::getApiKey() === '') { echo '

'; echo esc_html__('Please configure your Sentinelo API key in Settings → Sentinelo.', 'sentinelo'); echo '

'; } // PHP version if (version_compare(PHP_VERSION, SENTINELO_MIN_PHP, '<')) { echo '

'; printf( /* translators: %s: PHP version */ esc_html__('Unsupported PHP version. This plugin requires PHP %s or higher.', 'sentinelo'), esc_html(SENTINELO_MIN_PHP) ); echo '

'; } // SSL if (!is_ssl()) { echo '

'; echo esc_html__('HTTPS is required for the Sentinelo plugin to work securely.', 'sentinelo'); echo '

'; } // Failed backups global $wpdb; $failedCount = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM %i WHERE status = 'failed' AND created_at > DATE_SUB(NOW(), INTERVAL 48 HOUR)", $wpdb->prefix . 'SENTINELO_backups') ); if ($failedCount >= 3) { echo '

'; printf( /* translators: %d: number of failed backups */ esc_html__('%d backups failed recently. Check the logs for details.', 'sentinelo'), absint($failedCount) ); echo '

'; } // Disk space $free = disk_free_space(ABSPATH); if ($free !== false && $free < 500 * 1024 * 1024) { echo '

'; echo esc_html__('Low disk space (< 500 MB). Backups may fail.', 'sentinelo'); echo '

'; } } }