Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Simple Draft Laravel Package

ronssij/filament-simple-draft

Filament Simple Draft adds lightweight draft and publish support to Filament resources. Save unpublished changes, preview drafts, and publish when ready without duplicating records or building complex workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal steps

  1. composer require ronssij/filament-simple-draft — on a Filament 3/4/5 app the new ^3.0|^4.0|^5.0 constraint on filament/support resolves without flags.
  2. Publish and run the migration stub: php artisan vendor:publish --tag="filament-simple-draft-migrations" && php artisan migrate.
  3. Apply the package trait to the model(s) you want draftable, then add the draft column(s) to your resource form/table.

Where to look first

  • The model trait / interface shipped by the package — this is the source of truth for the draft state API (whether it's a boolean, an enum, or a published_at timestamp) and for any query scopes it registers.
  • The published migration — check exactly which columns are added before writing form fields against them.
  • The resource or action classes the plugin registers — these tell you whether publishing is a table action, a form action, or both, and where to hook authorization.
  • The composer.json of the package for the service provider / plugin registration name if it isn't auto-discovered.

First use case

Take a single PostResource with an existing posts table. Add the trait, add the publish action to the table's row and header actions, and confirm an editor can save a draft that is invisible to the public-facing Post::all() while still visible in the Filament table. That one loop exercises the trait, the migration, the scope, and the action — everything else in the package layers on top of it.

Implementation Patterns

Trait on the model, plugin on the panel

Keep the model trait as the single place draft semantics live, and register the Filament plugin/actions once per panel in the PanelProvider. Resources then opt in individually, which lets you roll drafts out to PostResource first and PageResource later without a flag day.

Publish as an explicit, authorized action

Treat "publish" as a privileged operation distinct from "edit". Gate the action (or the underlying method) behind its own policy ability — publish rather than update — so a contributor can save drafts while only an editor can make them public. This is the pattern most teams want and the one most likely to be missing by default.

Preview flows

The common day-to-day requirement is "let the author see the draft on the real front end before publishing." Implement this as a separate route guarded by auth plus a policy check on the model, not by loosening the global scope. If you need shareable previews, use URL::temporarySignedRoute() and check $request->hasValidSignature() — do not put draft visibility behind a token in the query string.

Draft-aware queries at the edges

Rather than relying solely on a global scope, make the public entry points explicit: a published() scope on the model, a repository/query object, or a PublishedPost read model. Then the admin table can deliberately call withoutGlobalScope(...) or withDrafts(). This keeps the "which contexts see drafts" question answerable by reading the code.

Testing the workflow

Use Livewire tests against the table action to assert the state transition end-to-end (livewire(ManagePosts::class)->callTableAction(PublishAction::class, $post)), and a plain model test asserting that a draft is excluded from your public query. Both tests survive package upgrades better than asserting on internal column names.

Scheduled publishing

If your domain needs "publish at a time," don't bolt it onto the publish action. Keep the package's immediate publish for the UI, and add a separate published_at column plus a scheduled command that promotes rows. Mixing the two into one column tends to make the admin table ambiguous about what "draft" means.

Upgrade path (v1.1 → v1.2)

This release is additive — the only change is a widened filament/support constraint plus a README banner. There is no migration, no config change, no code change. Bump the constraint and run your existing test suite; the release notes state the plugin was verified against Filament v5.7.6 + Livewire v4.4.0 with no plugin code changes.

Gotchas and Tips

The widened constraint is on filament/support, not filament/filament

^3.0|^4.0|^5.0 applies to the low-level support package. Composer will still resolve filament/filament and friends from your app's own constraint. If you see a conflict, it is almost always because filament/support is pinned by a transitive requirement elsewhere — inspect with composer why filament/support rather than assuming the plugin is at fault.

Filament 5 implies Livewire 4

Per the release notes, Filament v5 exists mainly to support Livewire v4 without changing the Filament API surface. Practically: if your app is still on Livewire 3, stay on Filament 4 and plugin v1.1.x. Do not attempt a Livewire major bump as part of a plugin upgrade — sequence it separately so you can attribute any breakage.

Drafts and unique constraints

If slug (or email, or any business key) is unique, a draft occupying the same value as a published row will collide at insert time. Decide the rule up front: either drop uniqueness on drafts and enforce it only among published rows (partial index on Postgres, generated column on MySQL), or suffix drafts and rewrite the slug on publish.

Global scopes vs. the admin panel

A scope that hides drafts globally is convenient for the public site and a trap in the admin table and in ->count() calls in dashboard widgets. Prefer explicit scopes with an obvious opt-out, and audit every aggregate/report query when you adopt drafts — silent under-counting is the classic failure mode.

Uploads made in draft

Files attached to a draft are real objects in storage regardless of publish state. Plan for orphan cleanup (a scheduled command deleting media whose owner never published within N days) and make sure your CDN/storage rules do not serve draft-attached assets at guessable paths.

Side effects should not fire on draft save

Observers, notifications, sitemap regeneration, and search indexing should key off the publish transition, not saved. Wire them to the publish action or to a published_at change check (wasChanged('published_at')), otherwise every autosave of a draft sends mail or pings a webhook.

Authorization is two questions

"Can this user edit this record?" and "can this user publish it?" are different. A single policy check on the resource covers the table row but usually not the action, so test both.

Cache invalidation on publish

Publishing is the moment your cached public page becomes stale. Hook cache busting to the publish path explicitly; do not rely on the model's generic saved event if drafts are saved frequently.

Understand the scope of the package

The name says "simple," and it should be read literally: expect one draft state per record, not revision history, not concurrent drafts, not a diff/review workflow. If the requirement grows into editorial versioning, reach for a dedicated package or a revisions table rather than stretching this one.

The banner image is cosmetic

The other v1.2.0 change is a README banner. No functional impact and nothing to verify.

Extension points worth knowing before you need them

Confirm whether the package lets you override the action classes or views via publishing (vendor:publish --tag=...-views) — customizing the publish button's label, color, or confirmation modal is the most frequently requested tweak and is much cheaper through an override than a fork.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle