Last active
October 2, 2026 16:20
-
-
Save wsydney76/a117a0d463d112984bfd13d28367bc14 to your computer and use it in GitHub Desktop.
Route Craft entry URL to Livewire fullpage-component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| use CraftCms\Cms\Entry\Elements\Entry; | |
| use CraftCms\Cms\Route\CurrentElement; | |
| use Livewire\Attributes\Computed; | |
| use Livewire\Attributes\Validate; | |
| use Livewire\Component; | |
| use Livewire\Attributes\Url; | |
| use Livewire\WithPagination; | |
| /** | |
| * A Livewire example full-page component that provides a search interface for Craft entries. | |
| * | |
| * Setup via a named route in `routes/web.php`: | |
| * | |
| * Route::livewire('/search', 'pages::search')->name('search'); | |
| * | |
| * In Craft's section settings (single), set the "URI" to `search` and the "Route" to `search`. | |
| * | |
| * URI, domain, and HTTP method in named route and Craft's settings must match. | |
| * | |
| */ | |
| new class extends Component { | |
| use WithPagination; | |
| #[Url] | |
| #[Validate('not_regex:/ or /', message: 'The "OR" operator must be uppercase.')] | |
| public string $search = ''; | |
| // Title/Teaser of the underlying entry element. | |
| // Do not define a public `Entry $entry` property, as Craft's elements are not serializable | |
| // and will throw an error when Livewire attempts to serialize the component state. | |
| public string $title; | |
| public string $teaser; | |
| // Pull in the underlying entry element. | |
| // The function signature must be exactly as this, | |
| // otherwise #[CurrentElement] will not work | |
| public function mount(#[CurrentElement] ?Entry $entry = null): void | |
| { | |
| [$this->title, $this->teaser] = [$entry->title, $entry->teaser]; | |
| $this->validate(); | |
| } | |
| #[Computed] | |
| public function entries() | |
| { | |
| return Entry::find() | |
| ->section('*') | |
| ->search($this->search) | |
| ->orderBy('score') | |
| ->withCustomFields(false) | |
| ->paginate(8); | |
| } | |
| // Set the page title passed to layout dynamically to the underlying entry's title. | |
| public function render() | |
| { | |
| return $this->view()->title($this->title); | |
| } | |
| // Goto first page when search term changes | |
| public function updatedSearch(): void | |
| { | |
| $this->resetPage(); | |
| } | |
| }; | |
| ?> | |
| {{-- | |
| The Flux card component just adds some styling, but you can use any HTML you want here. | |
| --}} | |
| <flux:card variant="soft" body="divided"> | |
| <flux:card.header> | |
| <flux:card.heading size="lg">{{ $title }}</flux:card.heading> | |
| <flux:card.subheading>{{ $teaser }}</flux:card.subheading> | |
| </flux:card.header> | |
| <flux:card.body class="space-y-4"> | |
| {{-- | |
| wire:model provides two-way binding to the reactive search property, updating it as you type. | |
| The Flux input component wraps a standard input and adds support for labels, icons, loading indicators, and error messages, | |
| while providing styling consistent with the Flux design system, including dark mode. | |
| You can use standard HTML elements instead if you prefer, | |
| and handle validation errors using Laravel's standard validation approach. | |
| --}} | |
| <flux:input | |
| label="Search for:" | |
| type="search" | |
| placeholder="Search..." | |
| icon="magnifying-glass" | |
| wire:model.live.debounce.250ms="search" | |
| /> | |
| <ul> | |
| @forelse ($this->entries as $entry) | |
| <li>{{ $entry->link }}</li> | |
| @empty | |
| <li>No entries found.</li> | |
| @endforelse | |
| </ul> | |
| </flux:card.body> | |
| <flux:card.footer> | |
| {{-- Laravel's default navigation links --}} | |
| {{ $this->entries->links() }} | |
| </flux:card.footer> | |
| </flux:card> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment