PHPackages                             kukux/pdf-template-builder - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. kukux/pdf-template-builder

ActiveLibrary[Templating &amp; Views](/categories/templating)

kukux/pdf-template-builder
==========================

A drag-and-drop PDF template builder plugin for Filament Admin. Upload a PDF background, bind Eloquent model fields, and place them visually on the canvas.

v1.2.19(4w ago)024MITPHPPHP ^8.2

Since May 5Pushed 4w agoCompare

[ Source](https://github.com/cortejojicoy/pdf-template-builder)[ Packagist](https://packagist.org/packages/kukux/pdf-template-builder)[ RSS](/packages/kukux-pdf-template-builder/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (10)Versions (24)Used By (0)

PDF Template Builder
====================

[](#pdf-template-builder)

[![Latest Version on Packagist](https://camo.githubusercontent.com/2f801dd7a6828bd79bd847082ab13a568c56902dcf8ed55067621f59944a9a22/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b756b75782f7064662d74656d706c6174652d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kukux/pdf-template-builder)[![Total Downloads](https://camo.githubusercontent.com/4f02fb3edf35cba1988d6bf12b45e9a904eab5e514d34532ceefb833d442fa3a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6b756b75782f7064662d74656d706c6174652d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kukux/pdf-template-builder)[![License](https://camo.githubusercontent.com/c56edb33dcb79e925c4936fd3c7233de5f230267a7efb3f04a95951a66ebb1a1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6b756b75782f7064662d74656d706c6174652d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kukux/pdf-template-builder)

Installation
============

[](#installation)

1. Require the package
----------------------

[](#1-require-the-package)

```
composer require kukux/pdf-template-builder
```

2. Publish and run the migration
--------------------------------

[](#2-publish-and-run-the-migration)

```
php artisan vendor:publish --tag=pdf-template-builder-migrations
php artisan migrate
```

3. Publish assets
-----------------

[](#3-publish-assets)

The builder UI is a React SPA bundled with Vite. The package ships pre-built JS in `resources/dist/`. Publish to `public/`:

```
php artisan vendor:publish --tag=pdf-template-builder-assets
```

> Re-run this command after each package update to get the latest bundle.

**For maintainers / contributors** — to rebuild the bundle from JSX source:

```
npm install
npm run build      # one-shot build → resources/dist/pdf-builder.js
npm run dev        # rebuild on save
```

ⓘ Filament v3 / v4 / v5 auto-detection
--------------------------------------

[](#ⓘ-filament-v3--v4--v5-auto-detection)

The plugin ships two parallel Resource implementations and aliases the canonical class name to the right one based on the Filament major version installed in your project.

DetectedClass actually loadedFilament v3 (no `Filament\Schemas\Schema` class)`Kukux\PdfTemplateBuilder\Filament\Resources\V3\PdfTemplateResource`Filament v4 / v5 (`Filament\Schemas\Schema` exists)`Kukux\PdfTemplateBuilder\Filament\Resources\V4\PdfTemplateResource`Detection happens in `PdfTemplateBuilderServiceProvider::register()` via `class_alias`, before Filament's panel resolves any resource. You always reference the canonical `Kukux\PdfTemplateBuilder\Filament\Resources\PdfTemplateResource::class` — never the V3/V4 variants directly.

If you ever see `Class "Kukux\…\PdfTemplateResource" not found` after upgrading, run `composer dump-autoload`. PSR-4 lookup needs to miss so the alias can be consulted, and a stale optimized classmap can short-circuit that.

4. Register the plugin in your Filament panel
---------------------------------------------

[](#4-register-the-plugin-in-your-filament-panel)

In your `PanelProvider` (e.g. `app/Providers/Filament/AdminPanelProvider.php`):

```
use Kukux\PdfTemplateBuilder\PdfTemplateBuilderPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...your existing config...
        ->plugin(
            PdfTemplateBuilderPlugin::make()
        );
}
```

5. Register your models (optional but recommended)
--------------------------------------------------

[](#5-register-your-models-optional-but-recommended)

Configure the Eloquent models whose fields will appear in the builder sidebar:

```
->plugin(
    PdfTemplateBuilderPlugin::make()
        ->models([
            'invoice' => [
                'label'  => 'Invoice',
                'icon'   => 'receipt',
                'class'  => App\Models\Invoice::class,
                'fields' => [
                    ['key' => 'invoice.number',    'label' => 'Number',    'type' => 'text',     'sample' => 'INV-0001'],
                    ['key' => 'invoice.issued_at', 'label' => 'Issued at', 'type' => 'date',     'sample' => 'Jan 1, 2026'],
                    ['key' => 'invoice.due_at',    'label' => 'Due at',    'type' => 'date',     'sample' => 'Feb 1, 2026'],
                    ['key' => 'invoice.subtotal',  'label' => 'Subtotal',  'type' => 'currency', 'sample' => '$1,000.00'],
                    ['key' => 'invoice.tax',       'label' => 'Tax',       'type' => 'currency', 'sample' => '$100.00'],
                    ['key' => 'invoice.total',     'label' => 'Total',     'type' => 'currency', 'sample' => '$1,100.00'],
                    ['key' => 'invoice.notes',     'label' => 'Notes',     'type' => 'longtext', 'sample' => 'Thank you.'],
                    ['key' => 'invoice.line_items','label' => 'Line items','type' => 'table',    'sample' => '[table]'],
                ],
                'relations' => [
                    'customer' => [
                        'label'  => 'Customer',
                        'fields' => [
                            ['key' => 'customer.name',    'label' => 'Name',    'type' => 'text',     'sample' => 'Acme Inc.'],
                            ['key' => 'customer.email',   'label' => 'Email',   'type' => 'text',     'sample' => 'hi@acme.co'],
                            ['key' => 'customer.address', 'label' => 'Address', 'type' => 'longtext', 'sample' => '221B Baker St'],
                        ],
                    ],
                ],
            ],
        ])
)
```

Alternatively, configure them in `config/pdf-template-builder.php` after publishing the config:

```
php artisan vendor:publish --tag=pdf-template-builder-config
```

6. (Optional) Customize sidebar navigation
------------------------------------------

[](#6-optional-customize-sidebar-navigation)

You can place the "PDF Templates" entry inside a Filament navigation group and control its sort order:

```
->plugin(
    PdfTemplateBuilderPlugin::make()
        ->navigationGroup('Documents') // must be a string, never null
        ->navigationSort(50)
)
```

Or via the published config (`config/pdf-template-builder.php`):

```
'navigation_group' => 'Documents', // string only — leave as '' to disable grouping, do NOT set to null
```

> **Heads up — avoid this error**
>
> ```
> Kukux\PdfTemplateBuilder\PdfTemplateBuilderPlugin::getNavigationGroup():
> Return value must be of type string, null returned
>
> ```
>
>
>
> This is thrown when `config('pdf-template-builder.navigation_group')` resolves to `null`. To prevent it:
>
> - If you published the config before v1.2.0, open `config/pdf-template-builder.php` and change `'navigation_group' => null` to `'navigation_group' => ''` (or to your preferred group name).
> - Or set `PDF_TEMPLATE_NAVIGATION_GROUP=""` in your `.env` rather than leaving it unset.
> - Or call `->navigationGroup('')` explicitly when registering the plugin.
>
> The same applies if you override the value at runtime — always pass a string, never `null`.

7. (Optional) Configure storage
-------------------------------

[](#7-optional-configure-storage)

By default PDF backgrounds are stored on the `public` disk under `pdf-templates/backgrounds/`. Override via the plugin or `.env`:

```
PDF_TEMPLATE_DISK=s3
```

Or via the plugin:

```
PdfTemplateBuilderPlugin::make()->disk('s3')->uploadPath('my-path/pdfs')
```

---

What gets added to your app
---------------------------

[](#what-gets-added-to-your-app)

- **Navigation**: A "PDF Templates" item in your Filament sidebar.
- **Template list**: Browse, search, and filter saved templates.
- **Create form**: Upload a background PDF, pick a model, set page size.
- **Visual builder**: Drag fields from the sidebar onto the PDF canvas, resize them, style their typography, and save the layout.
- **API routes** at `/filament-pdf-builder/api/*` (web + auth middleware).
- **`pdf_templates` table** in your database.

Generating PDFs
---------------

[](#generating-pdfs)

### 1. Install a PDF engine (optional but recommended)

[](#1-install-a-pdf-engine-optional-but-recommended)

The plugin auto-detects [`dompdf/dompdf`](https://github.com/dompdf/dompdf) and uses it for output. Without it, `render()` falls back to HTML (browser print → save as PDF still works).

```
composer require dompdf/dompdf
```

### 2. Drop a "Generate PDF" button into any Filament page

[](#2-drop-a-generate-pdf-button-into-any-filament-page)

**On a ViewRecord / EditRecord page (header action):**

```
use Kukux\PdfTemplateBuilder\Filament\Actions\GeneratePdfAction;

protected function getHeaderActions(): array
{
    return [
        GeneratePdfAction::make()
            ->template('invoice-default'),  // by template name
    ];
}
```

**As a row action on a Resource table:**

```
use Kukux\PdfTemplateBuilder\Filament\Actions\GeneratePdfTableAction;

->actions([
    GeneratePdfTableAction::make()
        ->template(1),                       // by template id
])
```

**Dynamic template selection:**

```
GeneratePdfAction::make()
    ->templateUsing(fn ($record) => $record->is_quote ? 'quote' : 'invoice')
    ->withContexts(fn ($record) => ['org' => $record->organization]);
```

### 3. Programmatic rendering

[](#3-programmatic-rendering)

```
use Kukux\PdfTemplateBuilder\Models\PdfTemplate;

$template = PdfTemplate::where('name', 'invoice-default')->firstOrFail();
$invoice  = Invoice::find(42);

// Get the response (PDF if dompdf is installed, else HTML)
return $template->stream($invoice);

// Or just the rendered HTML:
$html = $template->render($invoice);
```

### 4. Field token resolution

[](#4-field-token-resolution)

Fields placed in the builder have a `key` like `invoice.number` or `customer.email`. At render time:

- The leading segment matching the template's `model_key` is stripped, then the remainder is resolved against the record via `data_get()`.
- Otherwise the full key is resolved against the record (so relations work: `customer.name` → `$invoice->customer->name`).
- Pass extra named contexts via `->withContexts(['org' => $org])` and reference them with `org.name` in field tokens.

### 5. Choosing a PDF engine

[](#5-choosing-a-pdf-engine)

The plugin ships three engines. Pick based on your needs:

EngineWhen to useRequires`HtmlEngine` *(default fallback)*Quick preview; user prints to PDF from browser.—`DompdfEngine` *(auto-detected)*Generic HTML→PDF. Good for templates with no background or simple backgrounds.`composer require dompdf/dompdf``FpdiEngine`**You uploaded a designed PDF as the background and want the original PDF preserved exactly.** Stamps fields directly onto the original page.`composer require setasign/fpdi tecnickcom/tcpdf`Wire your choice on the plugin:

```
use Kukux\PdfTemplateBuilder\Rendering\Engines\FpdiEngine;

PdfTemplateBuilderPlugin::make()->engine(FpdiEngine::class)
```

You can also implement `Kukux\PdfTemplateBuilder\Rendering\Contracts\PdfEngine` (or `TemplateAwarePdfEngine` for non-HTML pipelines like Browsershot) and register your own.

### 6. Running the test suite

[](#6-running-the-test-suite)

```
composer install
vendor/bin/pest
```

The package ships with Pest tests covering routes, the field resolver, the HTML renderer, the filename pattern, and basic model persistence. Run them after every change.

### 7. Authorization

[](#7-authorization)

Templates use a default-permissive `PdfTemplatePolicy`. Override it in your `AuthServiceProvider`:

```
Gate::policy(
    \Kukux\PdfTemplateBuilder\Models\PdfTemplate::class,
    \App\Policies\PdfTemplatePolicy::class,
);
```

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance94

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

23

Last Release

28d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/34363543?v=4)[cortejojicoy](/maintainers/cortejojicoy)[@cortejojicoy](https://github.com/cortejojicoy)

---

Top Contributors

[![cortejojicoy](https://avatars.githubusercontent.com/u/34363543?v=4)](https://github.com/cortejojicoy "cortejojicoy (82 commits)")

---

Tags

laravelpdfbuildertemplatefilamentfilament-plugindrag-drop

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/kukux-pdf-template-builder/health.svg)

```
[![Health](https://phpackages.com/badges/kukux-pdf-template-builder/health.svg)](https://phpackages.com/packages/kukux-pdf-template-builder)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k51.0M7.4k](/packages/larastan-larastan)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9732.3M121](/packages/roots-acorn)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

76318.2M110](/packages/laravel-mcp)[spatie/laravel-health

Monitor the health of a Laravel application

88011.3M149](/packages/spatie-laravel-health)[api-platform/laravel

API Platform support for Laravel

59156.3k10](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
