optix/eloquent-draftable
A Laravel package that adds draft and published states to Eloquent models, letting you save work-in-progress records and publish them later. Drafts stay separate from live content, so unfinished entries remain hidden from your application's normal queries until you're ready.
composer require optix/eloquent-draftable. The package ships a service provider (auto-discovered on Laravel 5.5+); no manual registration needed unless you've opted out.drafts table keyed by draftable_id / draftable_type with a JSON payload column). Run php artisan vendor:publish --provider="Optix\Draftable\DraftableServiceProvider" and inspect exactly what schema you get before writing app code. Confirm the column type (longText vs native json) against your DB driver.use Optix\Draftable\Draftable;. This gives you the draft relationship and save/publish helpers. Check the README for the exact method names on your tagged version — the API has been stable, so the docs should match, but confirm against the tagged source rather than master.Post model. Create a draft ($post->saveAsDraft($request->validated()) or equivalent — verify the exact signature), preview it by reading the draft payload without touching the published row, and publish it back onto the source model. That is the whole value proposition: the public site keeps serving the published row while editors iterate on a draft.Where to look first: the README's API section, the Draftable trait (to see which Eloquent events it hooks), and the migration stub (to verify the JSON column type). If you're upgrading from an older tag, read the composer.json diff for v2.1.0 first — the Laravel constraint and the PHP floor are the two things that can break your build before any app code runs.
show route unchanged. Keep a single view component that renders either the draft or published instance so previews always match production output.PostPublished) after committing — don't rely on the package to fire model events for draft saves, because they generally don't.Post::with('draft')->paginate() (confirm the relationship name in the trait).preview and publish abilities on the model are a clean place to encode that.^2.1 and add PHP 7.3 / Laravel 8 to your test matrix explicitly. If your CI still runs PHP 7.2 anywhere (older Docker images, a shared base image, a matrix leg you forgot about), it will fail at composer install — not at runtime — which is easy to misread as a package bug.publish/preview actions so swapping it out later is a contained change. Pin the version: "optix/eloquent-draftable": "^2.1".composer update optix/eloquent-draftable --with-dependencies -W in a scratch branch and diff composer.lock. Anything else in your tree still requiring php: ^7.2 constraints can produce a confusing conflict.published_at to a datetime or tags to an array, you must reapply that casting when reading the draft back. Keep a toDraftArray() / fromDraftArray() pair on the model to centralize this.Post won't carry its comments, categories, or media attachments. If the editor needs to touch relations, either defer relation editing until after publish or store them in the draft JSON yourself.json casting behavior. Even on a supported version, verify round-tripping of arrays, empty strings, and null through save → read → publish with a test, rather than assuming the 2020-era behavior still holds on your Laravel 8 point release.draft_updated_at column (or a cache lock keyed on the model) if concurrent editing is realistic.longText vs text), (b) mass-assignment — the package uses fill()/forceFill() on the draft model, so $fillable on the draft model matters, not your source model, and (c) JSON encoding failures on floats/NAN from form casts. After the v2.1.0 bump, also confirm the installed version matches what you expect: composer show optix/eloquent-draftable.publish/preview actions so you can swap the strategy later without rewriting controllers.assertDatabaseHas('posts', [...]) for the published row and assertDatabaseHas('drafts', [...]) for the payload. This is the cheapest way to catch a regression where "Save draft" silently overwrites the live row.How can I help you explore Laravel packages today?