Weave Code
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

Add Laravel Publishable support to Filament resources: ready-made form fields, table column, filter, and bulk action to manage publication status plus published/expired dates for your Eloquent models. Compatible with Laravel 11+, Filament 4+.

View on GitHub
Deep Wiki
Context7

Implementation Patterns

Core Workflows

1. Basic Publishable Field Integration

Add publishable fields to a Filament Resource form and table:

use Novius\FilamentPublishable\Fields\PublicationStatus;
use Novius\FilamentPublishable\Fields\PublishedAt;
use Novius\FilamentPublishable\Fields\ExpiredAt;
use Novius\FilamentPublishable\Columns\PublicationColumn;
use Novius\FilamentPublishable\Filters\PublicationStatusFilter;

public static function form(Form $form): Form
{
    return $form->schema([
        PublicationStatus::make('publication_status')
            ->required()
            ->default(PublicationStatus::DRAFT),
        PublishedAt::make('published_at')
            ->requiredIf(fn ($record) => $record->publication_status === PublicationStatus::PUBLISHED),
        ExpiredAt::make('expired_at')
            ->nullable(),
    ]);
}

public static function table(Table $table): Table
{
    return $table
        ->columns([
            PublicationColumn::make('publication_status')
                ->badge()
                ->color(fn ($state) => match ($state) {
                    PublicationStatus::DRAFT => 'gray',
                    PublicationStatus::PUBLISHED => 'green',
                    PublicationStatus::EXPIRED => 'red',
                }),
        ])
        ->filters([
            PublicationStatusFilter::make('publication_status'),
        ]);
}

2. Bulk Actions for Publishable Models

Enable bulk publishing/expiring in the table:

use Novius\FilamentPublishable\Actions\PublicationBulkAction;

public static function table(Table $table): Table
{
    return $table
        ->actions([
            Tables\Actions\EditAction::make(),
        ])
        ->bulkActions([
            PublicationBulkAction::make()
                ->label('Publish Selected')
                ->action('publish'),
            PublicationBulkAction::make()
                ->label('Expire Selected')
                ->action('expire'),
        ]);
}

3. Customizing Field Behavior

Override defaults (e.g., disable PublishedAt for drafts):

PublishedAt::make('published_at')
    ->disabled(fn ($record) => $record->publication_status === PublicationStatus::DRAFT)
    ->requiredIf(fn ($record) => $record->publication_status === PublicationStatus::PUBLISHED),

4. Integration with Model Observers

Sync Filament UI with model events (e.g., auto-expire after 30 days):

// In your model observer
public function expired(Post $post)
{
    if ($post->expired_at && $post->expired_at->isPast()) {
        $post->update(['publication_status' => PublicationStatus::EXPIRED]);
    }
}

Advanced Patterns

1. Dynamic Field Visibility

Show/hide fields based on publishable state:

public static function getFormSchema(): array
{
    return [
        PublicationStatus::make('status'),
        PublishedAt::make('published_at')
            ->visible(fn ($record) => $record->status === PublicationStatus::PUBLISHED),
        ExpiredAt::make('expired_at')
            ->visible(fn ($record) => $record->status === PublicationStatus::EXPIRED),
    ];
}

2. Custom Validation Rules

Add validation for publishable fields:

PublishedAt::make('published_at')
    ->rules([
        'required_if:publication_status,' . PublicationStatus::PUBLISHED,
        'after:now',
    ]),

3. Extending the Package

Create a custom field (e.g., PublishableToggle):

use Filament\Forms\Components\Toggle;

class PublishableToggle extends Toggle
{
    protected string $fieldName = 'publication_status';

    public function mount(): void
    {
        $this->options([
            PublicationStatus::DRAFT => 'Draft',
            PublicationStatus::PUBLISHED => 'Published',
        ]);
    }
}

4. Query Scoping for Publishable Models

Filter table data by publishable state:

public static function getTableQuery(): Builder
{
    return parent::getTableQuery()
        ->where('publication_status', PublicationStatus::PUBLISHED)
        ->orWhereNull('published_at');
}

5. Localization and Labels

Customize field labels/translations:

// Publish lang file
'publication_status' => [
    'labels' => [
        'draft' => 'In Review',
        'published' => 'Live',
        'expired' => 'Archived',
    ],
],

// In your resource
PublicationStatus::make('status')
    ->label('Content Status'),

6. Integration with Filament Actions

Add publishable-specific actions:

use Filament\Resources\Actions\Action;

public static function getActions(): array
{
    return [
        Action::make('publish')
            ->label('Publish Now')
            ->action(fn (Post $record) => $record->publish()),
    ];
}

7. Testing Publishable Fields

Test field rendering and logic:

public function test_publication_status_field()
{
    $field = PublicationStatus::make('status');
    $field->fill();

    $this->assertEquals(
        PublicationStatus::DRAFT,
        $field->getState()
    );
}

Integration Tips

1. Model-View Sync

Ensure Filament reflects model state changes:

// In your model
protected static function booted()
{
    static::updated(function ($model) {
        if ($model->isDirty('publication_status')) {
            event(new PublicationStatusUpdated($model));
        }
    });
}

2. Soft Deletes + Publishable

Handle soft-deleted publishable models:

public static function getTableQuery(): Builder
{
    return parent::getTableQuery()
        ->withTrashed()
        ->whereNull('deleted_at')
        ->orWhere('publication_status', PublicationStatus::EXPIRED);
}

3. API Resource Integration

Expose publishable fields in API responses:

// In your API Resource
public function toArray($request)
{
    return [
        'status' => $this->publication_status,
        'published_at' => $this->published_at?->toDateTimeString(),
    ];
}

4. Filament Widgets for Publishable Stats

Create widgets to track publishable content:

use Novius\FilamentPublishable\Widgets\PublishableStats;

public static function getWidgets(): array
{
    return [
        PublishableStats::make()
            ->model(Post::class)
            ->columns(3),
    ];
}

5. Custom Publishable States

Extend the PublicationStatus enum:

enum PublicationStatus: string
{
    case DRAFT = 'draft';
    case REVIEW = 'review';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
}

6. Bulk Action Confirmation

Add confirmation dialogs for bulk actions:

PublicationBulkAction::make()
    ->requiresConfirmation()
    ->confirmationMessage('Are you sure you want to publish these items?'),

7. Field Dependencies

Make fields dependent on others:

ExpiredAt::make('expired_at')
    ->requiredIf(fn ($record) => $record->publication_status === PublicationStatus::PUBLISHED)
    ->after('published_at'),

8. Filament Panels Integration

Use across multiple Filament panels:

// In your FilamentServiceProvider
Filament::registerPanel(
    default: CustomPanel::make()
        ->id('admin')
        ->resources([
            PostResource::class,
            // Other publishable resources
        ]),
);

Gotchas and Tips

Common Pitfalls

1. Missing Publishable Trait

  • Issue: Fields won’t render if the model lacks the Publishable trait.
  • Fix: Add the trait to your model:
    use Novius\Publishable\Publishable;
    
    class Post extends Model
    {
        use Publishable;
    }
    

2. Field Initialization Order

  • Issue: PublishedAt/ExpiredAt may not respect publication_status defaults.
  • Fix: Set defaults in the model or use default() in the field:
    PublishedAt::make()
        ->default(now()->addDays(1)),
    

3. Timezone Mismatches

  • Issue: published_at/expired_at may not align with user timezone.
  • Fix: Use Carbon’s timezone methods:
    PublishedAt::make()
        ->default(now()->setTimezone('UTC')),
    

4. Bulk Action Conflicts

  • Issue: Bulk actions may fail if models have conflicting publishable states.
  • Fix: Add validation:
    PublicationBulkAction::make()
        ->validateUsing(fn (array $records) => collect($records)->every(fn ($record) =>
            $record->publication_status === PublicationStatus::DRAFT
        )),
    

**5

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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope