.blade.php. */ #[Layout('layouts.app')] class Index extends Component { /** Help topics in display order. */ private const TOPICS = [ 'overview', 'domain-tls', 'security', 'updates', 'commands', 'servers', 'sessions', 'email', 'audit', 'wireguard', 'recovery', ]; #[Url] public string $topic = 'overview'; // mount() handles the test/parameter-injection path (Livewire::test($class, ['topic' => …])). // Browser deep links populate $topic via the #[Url] attribute above and bypass mount on // hydration. Both paths are validated by the render() clamp below. public function mount(?string $topic = null): void { if ($topic !== null) { $this->topic = $topic; // clamped to a known topic in render() } } public function render() { // Authoritative guard: any unknown topic (deep link, tampered property) → overview, so // the view never @includes a missing content partial. if (! in_array($this->topic, self::TOPICS, true)) { $this->topic = 'overview'; } $labels = [ 'overview' => __('help.topic_overview'), 'domain-tls' => __('help.topic_domain_tls'), 'security' => __('help.topic_security'), 'updates' => __('help.topic_updates'), 'commands' => __('help.topic_commands'), 'servers' => __('help.topic_servers'), 'sessions' => __('help.topic_sessions'), 'email' => __('help.topic_email'), 'audit' => __('help.topic_audit'), 'wireguard' => __('help.topic_wireguard'), 'recovery' => __('help.topic_recovery'), ]; $topics = array_map(fn (string $key): array => ['key' => $key, 'label' => $labels[$key]], self::TOPICS); return view('livewire.help.index', ['topics' => $topics])->title(__('help.title')); } }