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

Laravel Filament Publishable Laravel Package

novius/laravel-filament-publishable

Manage Laravel Publishable models in Filament 4: add publication status fields, columns, filters, and bulk actions to your resources for Laravel 11+ and PHP 8.2+.

View on GitHub
Deep Wiki
Context7

Getting Started

Verify the foundation before touching Filament. This package is a thin UI adapter over novius/laravel-publishable — it does not define publishing behavior, it only binds Filament components to that trait. Before installing, confirm:

  • The target model uses the novius/laravel-publishable trait.
  • The table has publication_status, published_at, and expired_at columns (matching names — the components and filters assume them).
  • Stack is Laravel ≥ 11, PHP ≥ 8.2, Filament ≥ 4. Older stacks need the 2.x branch docs.
  • AGPL v3 has been cleared for your distribution model (internal tooling is usually fine; distributed proprietary SaaS often is not).

Install.

composer require novius/laravel-filament-publishable

No migrations, no config, no manual provider registration. If the Novius\LaravelFilamentPublishable\Filament\* classes aren't resolvable after install, you're on a mismatched branch.

Where to look first — the parent library, then vendor/. The parent (novius/laravel-publishable) owns the state machine, scopes, and timestamp semantics. Read that before trusting this package's README, which is a snippet with at least two real bugs. Then open vendor/novius/laravel-filament-publishable/src/ to confirm real class namespaces and constructor signatures — particularly for PublishedFirstAt, whose README example binds the wrong column name.

First use case — a single resource, form fields only. Pick one low-risk model already using the trait. Add only the form fields and open the resource in the panel to confirm state round-trips:

use Novius\LaravelFilamentPublishable\Filament\Form\Components\PublicationStatus;
use Novius\LaravelFilamentPublishable\Filament\Form\Components\PublishedAt;
use Novius\LaravelFilamentPublishable\Filament\Form\Components\ExpiredAt;

public static function form(Form $form): Form
{
    return $form->schema([
        PublicationStatus::make('publication_status'),
        PublishedAt::make('published_at'),
        ExpiredAt::make('expired_at'),
        // PublishedFirstAt — check the vendor source for the correct column name
    ]);
}

Only after that works, add PublicationColumn to the table, then PublicationStatusFilter, then PublicationBulkAction. Each step is independently testable and independently revertable.

Implementation Patterns

Incremental resource rollout. Form fields → table column → filter → bulk action, on one resource, in that order. Each component is independently useful and independently removable. Rolling this out across every content resource in a single PR makes the pilot un-revertable and turns a "let's try it" into a migration.

Standard table wiring. Keep the filter's and column's field name identical to the trait column so the package's own scope is hit, not a Filament where clause doing a full scan:

->columns([
    PublicationColumn::make('publication_status'),
])
->filters([
    PublicationStatusFilter::make('publication_status'),
])
->bulkActions([
    PublicationBulkAction::make(),
])

Wrap, don't sprinkle. For a 4-star, zero-dependent, single-maintainer package, the strongest day-to-day pattern is a thin local facade: define App\Filament\Components\Publish\* classes extending or statically delegating to the package equivalents. If the package is abandoned, the license becomes a blocker, or Filament 5 breaks it, you swap the base class in one directory instead of editing every resource. Costs ~30 lines; buys replacement optionality.

Publish side effects live in the model, not the bulk action closure. If you need cache invalidation, webhooks, notifications, or audit rows on publish, hang them off model observers/events on the publishable trait. Wiring them into a custom ->action() on the bulk action will diverge from the single-record edit-path publish and you'll get inconsistent behavior between "publish one" and "publish ten."

Authorization is your responsibility. Filament policies gate the resource, not the publish transition. If editors can edit but not publish, add a check inside the bulk action:

PublicationBulkAction::make()
    ->visible(fn () => auth()->user()->can('publish', Post::class));

Decide this convention before rollout. Retrofitting it per-resource later is exactly the kind of drift the package is supposed to prevent.

Translations. Publish language files for non-English editors:

php artisan vendor:publish --tag=lang

Ignore the README's provider class name in that command — it's a Nova-era leftover. The --tag=lang form works; verify files land in lang/vendor/.

Pair evaluation, not package evaluation. If the team hasn't already adopted novius/laravel-publishable, you're adopting two packages. The build option is four form fields, a column, a filter, a bulk action, plus translations and auth glue — roughly an afternoon. Buy is only clearly better once the trait is already in place.

Gotchas and Tips

The README contains real bugs. PublishedFirstAt::make('expired_at') binds the wrong column, and the vendor:publish command references LaravelNovaPublishableServiceProvider. Treat the README as a sketch; the src/ directory is the source of truth. Budget a short spike to verify component behavior rather than trusting the docs.

Date/timezone semantics are inherited, not defined here. PublishedAt and ExpiredAt write to model timestamps; how "published" is evaluated at query time and in what timezone is decided by novius/laravel-publishable. Test the boundary explicitly: a record published "now" in the admin — does it appear immediately, or only after the next scheduled transition? That answer determines whether the UI is honest about state.

Bulk action behavior under load is opaque. Before rollout, check whether PublicationBulkAction runs per-record save() (dispatching events) or a single update (bypassing them), and whether it wraps in a transaction. Run it against a few hundred rows and inspect the query log. Partial failures with no per-row feedback are the classic failure mode for pre-built bulk actions.

"The field does nothing" — debug in this order: (1) model isn't using the trait; (2) column doesn't exist or is misnamed in migrations — the trait expects publication_status / published_at / expired_at; (3) the Filament field name doesn't match the column (the README's own example gets this wrong); (4) the form isn't statePath-wired the way the component expects. Model first, vendor source second.

It's not a CMS or a workflow engine. Approval chains, editorial roles, multi-step review, scheduled-publish jobs, and audit trails are all extension work. If the roadmap needs those, you're writing them regardless — decide whether the AGPL + coupling cost is worth it for what you actually get: standard status UI.

Pin deliberately. Filament 4 and Laravel 11 are moving targets, and this package's compatibility matrix moves with them. Pin in composer.json and treat any Filament major upgrade as a coordinated task that includes verifying this package, not an incidental composer update.

License is a hard gate, not a checkbox. AGPL v3 is incompatible with many proprietary and SaaS distribution models. Get sign-off before the pilot, not after — otherwise the pilot is spent for nothing.

Replacement is cheap only if you invest in it. The entire UI surface is a handful of form fields, one column, one filter, one bulk action. With the local wrapper in place, replacing it with ~100 lines against the same trait is a contained afternoon. Skip the wrapper and it becomes a search-and-replace across every resource in the app.

Pilot, don't platform-commit. Low stars, zero dependents, single maintainer, no commercial support. Validate on one resource, keep the wrapper, and only expand once the parent library and this adapter are both proven in your stack.

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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style