From dfd43ef9675f5488b769941abee2f82e6ad84643 Mon Sep 17 00:00:00 2001 From: Kenneth Sese Date: Fri, 1 Aug 2025 12:29:39 -0400 Subject: [PATCH 1/4] allow renderhook to accept array of data --- packages/support/src/View/ViewManager.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/support/src/View/ViewManager.php b/packages/support/src/View/ViewManager.php index 1d5eb328df..2427361940 100644 --- a/packages/support/src/View/ViewManager.php +++ b/packages/support/src/View/ViewManager.php @@ -6,6 +6,7 @@ use Closure; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Arr; use Illuminate\Support\HtmlString; +use Illuminate\View\View; use function Filament\Support\is_app_url; @@ -42,13 +43,13 @@ class ViewManager /** * @param string | array | null $scopes */ - public function renderHook(string $name, string | array | null $scopes = null): Htmlable + public function renderHook(string $name, string | array | null $scopes = null, ?array $data = null): Htmlable { $renderedHooks = []; $scopes = Arr::wrap($scopes); - $renderHook = function (callable $hook) use (&$renderedHooks, $scopes): ?string { + $renderHook = function (callable $hook) use (&$renderedHooks, $scopes, $data): ?string { $hookId = spl_object_id($hook); if (in_array($hookId, $renderedHooks)) { @@ -57,7 +58,13 @@ class ViewManager $renderedHooks[] = $hookId; - return (string) app()->call($hook, ['scopes' => $scopes]); + $result = app()->call($hook, ['scopes' => $scopes]); + + if (filled($data) && $result instanceof View) { + $result->with($data); + } + + return (string) $result; }; $hooks = array_map( From 1c7353944bd0d84a473d0166cba5266376c87257 Mon Sep 17 00:00:00 2001 From: Kenneth Sese Date: Fri, 1 Aug 2025 12:30:16 -0400 Subject: [PATCH 2/4] add filter indicator renderhook --- .../tables/resources/views/index.blade.php | 94 ++++++++++--------- packages/tables/src/View/TablesRenderHook.php | 2 + 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/packages/tables/resources/views/index.blade.php b/packages/tables/resources/views/index.blade.php index 493e1b8d6f..0aae2d5dba 100644 --- a/packages/tables/resources/views/index.blade.php +++ b/packages/tables/resources/views/index.blade.php @@ -608,55 +608,63 @@ @endif @if ($filterIndicators) -
-
- - {{ __('filament-tables::table.filters.indicator') }} - + @php + $renderedFilterIndicators = \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::FILTER_INDICATORS, scopes: static::class, data: ['filterIndicators' => $filterIndicators]); + @endphp -
- @foreach ($filterIndicators as $indicator) - @php - $indicatorColor = $indicator->getColor(); - @endphp + @if ($renderedFilterIndicators) + {{ $renderedFilterIndicators }} + @else +
+
+ + {{ __('filament-tables::table.filters.indicator') }} + - - {{ $indicator->getLabel() }} +
+ @foreach ($filterIndicators as $indicator) + @php + $indicatorColor = $indicator->getColor(); + @endphp - @if ($indicator->isRemovable()) - @php - $indicatorRemoveLivewireClickHandler = $indicator->getRemoveLivewireClickHandler(); - @endphp + + {{ $indicator->getLabel() }} - - @endif - - @endforeach + @if ($indicator->isRemovable()) + @php + $indicatorRemoveLivewireClickHandler = $indicator->getRemoveLivewireClickHandler(); + @endphp + + + @endif + + @endforeach +
-
- @if (collect($filterIndicators)->contains(fn (\Filament\Tables\Filters\Indicator $indicator): bool => $indicator->isRemovable())) - - @endif -
+ @if (collect($filterIndicators)->contains(fn (\Filament\Tables\Filters\Indicator $indicator): bool => $indicator->isRemovable())) + + @endif +
+ @endif @endif @if (((! $content) && (! $hasColumnsLayout)) || ($records === null) || count($records)) diff --git a/packages/tables/src/View/TablesRenderHook.php b/packages/tables/src/View/TablesRenderHook.php index 0135ca915e..281e6f5cb8 100644 --- a/packages/tables/src/View/TablesRenderHook.php +++ b/packages/tables/src/View/TablesRenderHook.php @@ -36,6 +36,8 @@ class TablesRenderHook const TOOLBAR_START = 'tables::toolbar.start'; + const FILTER_INDICATORS = 'tables::filter.indicators'; + /** * @deprecated Use `TOOLBAR_COLUMN_MANAGER_TRIGGER_AFTER` instead. */ From 1cb98db5218cd119c6f79954287c513d6237e9d1 Mon Sep 17 00:00:00 2001 From: Kenneth Sese Date: Fri, 1 Aug 2025 12:51:35 -0400 Subject: [PATCH 3/4] stan --- packages/support/src/View/ViewManager.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/support/src/View/ViewManager.php b/packages/support/src/View/ViewManager.php index 2427361940..acf6786805 100644 --- a/packages/support/src/View/ViewManager.php +++ b/packages/support/src/View/ViewManager.php @@ -42,6 +42,7 @@ class ViewManager /** * @param string | array | null $scopes + * @param array | null $data */ public function renderHook(string $name, string | array | null $scopes = null, ?array $data = null): Htmlable { From 446e432d4c792be65c77b9288d0a07c52a0cba4d Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Sat, 2 Aug 2025 13:40:11 +0100 Subject: [PATCH 4/4] pass data to hooks differently, docs --- docs/09-advanced/01-render-hooks.md | 23 +++++++++- packages/support/src/View/ViewManager.php | 11 ++--- .../tables/resources/views/index.blade.php | 42 +++++++++---------- tests/src/Support/RenderHooksTest.php | 16 +++++-- 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/docs/09-advanced/01-render-hooks.md b/docs/09-advanced/01-render-hooks.md index 0e95e864db..61697728b4 100644 --- a/docs/09-advanced/01-render-hooks.md +++ b/docs/09-advanced/01-render-hooks.md @@ -132,6 +132,7 @@ All these render hooks [can be scoped](#scoping-render-hooks) to any table Livew use Filament\Tables\View\TablesRenderHook; ``` +- `TablesRenderHook::FILTER_INDICATORS` - Replace the existing filter indicators, receives `filterIndicators` data as `array` - `TablesRenderHook::SELECTION_INDICATOR_ACTIONS_AFTER` - After the "select all" and "deselect all" action buttons in the selection indicator bar - `TablesRenderHook::SELECTION_INDICATOR_ACTIONS_BEFORE` - Before the "select all" and "deselect all" action buttons in the selection indicator bar - `TablesRenderHook::HEADER_AFTER` - After the header container @@ -220,6 +221,20 @@ FilamentView::registerRenderHook( ); ``` +## Passing data to render hooks + +Render hooks can receive "data" from when the hook is rendered. To access data from a render hook, you can inject it using an `array $data` parameter to the hook's rendering function: + +```php +use Filament\Support\Facades\FilamentView; +use Filament\Tables\View\TablesRenderHook; + +FilamentView::registerRenderHook( + TablesRenderHook::FILTER_INDICATORS, + fn (array $data): View => view('filter-indicators', ['indicators' => $data['filterIndicators']]), +); +``` + ## Rendering hooks Plugin developers might find it useful to expose render hooks to their users. You do not need to register them anywhere, simply output them in Blade like so: @@ -228,7 +243,7 @@ Plugin developers might find it useful to expose render hooks to their users. Yo {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_START) }} ``` -To provide scope your render hook, you can pass it as the second argument to `renderHook()`. For instance, if your hook is inside a Livewire component, you can pass the class of the component using `static::class`: +To provide [scope](#scoping-render-hooks) your render hook, you can pass it as the second argument to `renderHook()`. For instance, if your hook is inside a Livewire component, you can pass the class of the component using `static::class`: ```blade {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_START, scopes: $this->getRenderHookScopes()) }} @@ -239,3 +254,9 @@ You can even pass multiple scopes as an array, and all render hooks that match a ```blade {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_START, scopes: [static::class, \App\Filament\Resources\Users\UserResource::class]) }} ``` + +You can pass [data](#passing-data-to-render-hooks) to a render hook using a `data` argument to the `renderHook()` function: + +```blade +{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::FILTER_INDICATORS, data: ['filterIndicators' => $filterIndicators]) }} +``` diff --git a/packages/support/src/View/ViewManager.php b/packages/support/src/View/ViewManager.php index acf6786805..c4a32d045b 100644 --- a/packages/support/src/View/ViewManager.php +++ b/packages/support/src/View/ViewManager.php @@ -6,7 +6,6 @@ use Closure; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\Arr; use Illuminate\Support\HtmlString; -use Illuminate\View\View; use function Filament\Support\is_app_url; @@ -42,9 +41,9 @@ class ViewManager /** * @param string | array | null $scopes - * @param array | null $data + * @param array $data */ - public function renderHook(string $name, string | array | null $scopes = null, ?array $data = null): Htmlable + public function renderHook(string $name, string | array | null $scopes = null, array $data = []): Htmlable { $renderedHooks = []; @@ -59,11 +58,7 @@ class ViewManager $renderedHooks[] = $hookId; - $result = app()->call($hook, ['scopes' => $scopes]); - - if (filled($data) && $result instanceof View) { - $result->with($data); - } + $result = app()->call($hook, ['data' => $data, 'scopes' => $scopes]); return (string) $result; }; diff --git a/packages/tables/resources/views/index.blade.php b/packages/tables/resources/views/index.blade.php index 0aae2d5dba..844ccd120a 100644 --- a/packages/tables/resources/views/index.blade.php +++ b/packages/tables/resources/views/index.blade.php @@ -2,12 +2,14 @@ use Filament\Support\Enums\Alignment; use Filament\Support\Enums\VerticalAlignment; use Filament\Support\Enums\Width; + use Filament\Support\Facades\FilamentView; use Filament\Tables\Actions\HeaderActionsPosition; use Filament\Tables\Columns\Column; use Filament\Tables\Columns\ColumnGroup; use Filament\Tables\Enums\FiltersLayout; use Filament\Tables\Enums\RecordActionsPosition; use Filament\Tables\Enums\RecordCheckboxPosition; + use Filament\Tables\View\TablesRenderHook; use Illuminate\Support\Str; use Illuminate\View\ComponentAttributeBag; @@ -163,7 +165,7 @@ x-show="@js($hasHeader) || @js($hasNonBulkToolbarAction) || (getSelectedRecordsCount() && @js(count($toolbarActions)))" class="fi-ta-header-ctn" > - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::HEADER_BEFORE, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::HEADER_BEFORE, scopes: static::class) }} @if ($header) {{ $header }} @@ -202,7 +204,7 @@
@endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::HEADER_AFTER, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::HEADER_AFTER, scopes: static::class) }} @if ($hasFiltersAboveContent)
@endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_BEFORE, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_BEFORE, scopes: static::class) }}
- {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_START, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_START, scopes: static::class) }}
- {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_REORDER_TRIGGER_BEFORE, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_REORDER_TRIGGER_BEFORE, scopes: static::class) }} @if ($isReorderable) {{ $reorderRecordsTriggerAction }} @endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_REORDER_TRIGGER_AFTER, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_REORDER_TRIGGER_AFTER, scopes: static::class) }} @if ((! $isReordering) && count($toolbarActions)) @foreach ($toolbarActions as $action) @@ -255,7 +257,7 @@ @endforeach @endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_BEFORE, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_BEFORE, scopes: static::class) }} @if ($areGroupingSettingsVisible)
@endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_AFTER, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_AFTER, scopes: static::class) }}
@if ($isGlobalSearchVisible || $hasFiltersDialog || $hasColumnManagerDropdown)
- {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_SEARCH_BEFORE, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_SEARCH_BEFORE, scopes: static::class) }} @if ($isGlobalSearchVisible) @php @@ -417,7 +419,7 @@ /> @endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_SEARCH_AFTER, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_SEARCH_AFTER, scopes: static::class) }} @if ($hasFiltersDialog || $hasColumnManagerDropdown) @if ($hasFiltersDialog) @@ -494,7 +496,7 @@ @endif @endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_BEFORE, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_BEFORE, scopes: static::class) }} @if ($hasColumnManagerDropdown) @php @@ -526,15 +528,15 @@ @endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_AFTER, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_AFTER, scopes: static::class) }} @endif
@endif - {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_END) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_END) }}
- {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_AFTER) }} + {{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_AFTER) }}
@if ($isReordering) @@ -578,7 +580,7 @@ @if (! $isSelectionDisabled)
- {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::SELECTION_INDICATOR_ACTIONS_BEFORE, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::SELECTION_INDICATOR_ACTIONS_BEFORE, scopes: static::class) }}
- {{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::SELECTION_INDICATOR_ACTIONS_AFTER, scopes: static::class) }} + {{ FilamentView::renderHook(TablesRenderHook::SELECTION_INDICATOR_ACTIONS_AFTER, scopes: static::class) }}
@endif
@endif @if ($filterIndicators) - @php - $renderedFilterIndicators = \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::FILTER_INDICATORS, scopes: static::class, data: ['filterIndicators' => $filterIndicators]); - @endphp - - @if ($renderedFilterIndicators) - {{ $renderedFilterIndicators }} + @if ($filterIndicatorsView = FilamentView::renderHook(TablesRenderHook::FILTER_INDICATORS, scopes: static::class, data: ['filterIndicators' => $filterIndicators])) + {{ $filterIndicatorsView }} @else
diff --git a/tests/src/Support/RenderHooksTest.php b/tests/src/Support/RenderHooksTest.php index 48137ca308..41eb2346fa 100644 --- a/tests/src/Support/RenderHooksTest.php +++ b/tests/src/Support/RenderHooksTest.php @@ -28,7 +28,7 @@ test('render hooks can render view files', function (): void { ->toHtml()->toContain('bar'); }); -test('render hooks can be scopes:d', function (): void { +test('render hooks can be scoped', function (): void { FilamentView::registerRenderHook('foo', function (): string { return Blade::render('bar'); }); @@ -42,7 +42,7 @@ test('render hooks can be scopes:d', function (): void { ->toHtml()->toBe('barbar'); }); -test('render hooks can be scopes:d to multiple scopes:s', function (): void { +test('render hooks can be scoped to multiple scoped', function (): void { FilamentView::registerRenderHook('foo', function (): string { return Blade::render('bar'); }); @@ -60,7 +60,7 @@ test('render hooks can be scopes:d to multiple scopes:s', function (): void { ->toHtml()->toBe('barbar'); }); -test('render hooks can be scopes:d to multiple scopes:s but only ever output once', function (): void { +test('render hooks can be scoped to multiple scoped but only ever output once', function (): void { FilamentView::registerRenderHook('foo', function (): string { return Blade::render('bar'); }); @@ -73,3 +73,13 @@ test('render hooks can be scopes:d to multiple scopes:s but only ever output onc ->toBeInstanceOf(HtmlString::class) ->toHtml()->toBe('barbar'); }); + +test('render hooks can be passed data', function (): void { + FilamentView::registerRenderHook('foo', function ($data): string { + return $data['foo']; + }); + + expect(FilamentView::renderHook('foo', data: ['foo' => 'bar'])) + ->toBeInstanceOf(HtmlString::class) + ->toHtml()->toBe('bar'); +});