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 Redirects Laravel Package

wotz/filament-redirects

Filament Redirects provides a simple admin interface for creating and managing URL redirects in Laravel Filament apps. Define source and destination paths, choose redirect status codes, and keep legacy or changed URLs working—all from a dedicated Filament resource.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm compatibility before installing. The package is a Filament plugin, so the first thing to check is the composer.json of the package itself — specifically the filament/filament constraint (v3 vs v4 are not interchangeable) and the PHP/Laravel constraints. With zero stars and zero dependents, treat the version constraint as the contract.

composer require wotz/filament-redirects

2. Publish and migrate. Most Filament plugins ship a service provider with publishable migrations and config:

php artisan vendor:publish --tag="filament-redirects-migrations"
php artisan vendor:publish --tag="filament-redirects-config"
php artisan migrate

Read the published migration before running it — you want to see the source/destination (or from/to) columns and, critically, whether source is indexed and unique. That single detail determines whether the package is usable on a site with thousands of redirects.

3. Register the plugin on the panel in app/Providers/Filament/AdminPanelProvider.php:

use Wotz\FilamentRedirects\FilamentRedirectsPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(FilamentRedirectsPlugin::make());
}

If the plugin exposes a ->navigationGroup() or ->navigationLabel() fluent method, set it here so the resource doesn't land in an orphaned nav group.

4. First use case — the one that pays for the package immediately. Open the new "Redirects" resource, create a redirect from a dead URL (/old-blog-post) to a live one (/blog/new-post) with a 301, then hit the old URL in a browser and confirm the redirect fires. If nothing happens, the package manages data only and you are responsible for the lookup layer — see Implementation Patterns below.

Where to look first in the source:

  • src/FilamentRedirectsPlugin.php — what the plugin actually registers (resources, pages, widgets).
  • src/Models/ — the redirect model, its casts, scopes, and whether it fires events.
  • src/Http/Middleware/ — if present, this is your resolution layer; if absent, you own it.
  • database/migrations/ — indexes and uniqueness.

Implementation Patterns

Manual management via the Filament resource. This is the package's stated core: a CRUD table for redirects inside the admin panel. Give content editors the ability to fix broken links without a deploy. Restrict access with a policy rather than relying on panel access alone, since redirects are effectively a routing surface.

Bulk import for migrations and site relaunches. The import path is the highest-value feature for day-to-day work — a site relaunch typically produces a spreadsheet of hundreds of old→new URL pairs. Typical workflow:

  1. Export the legacy URL map (Screaming Frog, RedirectMapper, or a CMS export).
  2. Normalise to the columns the package expects (source path, destination, status code).
  3. Import via the Filament action or the package's importer command.
  4. Spot-check 10–20 rows, then crawl the old sitemap with curl -I to verify status codes in bulk.
# Rough verification loop after import
while read -r path; do
  printf "%s -> " "$path"
  curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" "https://example.test$path"
done < old-paths.txt

Resolution layer — decide where matching happens. Two viable approaches, and the package may only give you one:

Middleware (if shipped): registered globally or on the web group, it looks up request()->path() against the redirects table and returns a redirect response. Cheapest to adopt, but runs on every request unless you scope it to 404 handling.

404 handler (if not shipped): catch NotFoundHttpException in bootstrap/app.php and consult the table there. This avoids a DB hit on every successful page load:

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (NotFoundHttpException $e, Request $request) {
        $redirect = Redirect::query()
            ->where('source', ltrim($request->path(), '/'))
            ->where('is_active', true)
            ->first();

        return $redirect
            ? redirect($redirect->destination, $redirect->status_code)
            : null;
    });
});

Auto-generate redirects on slug change. The pattern that prevents most 404s in the first place: an observer on your content models that writes a redirect when a slug changes.

protected static function booted(): void
{
    static::updated(function (Post $post) {
        if ($post->wasChanged('slug')) {
            Redirect::create([
                'source'      => 'blog/'.$post->getOriginal('slug'),
                'destination' => 'blog/'.$post->slug,
                'status_code' => 301,
            ]);
        }
    });
}

This is where the package earns its keep — the admin UI becomes the escape hatch, not the primary workflow.

Import idempotency. Before importing, decide whether the importer updates existing sources or duplicates them. If the source column isn't unique, wrap the import in your own updateOrCreate pass keyed on source so re-running a corrected CSV doesn't create shadow rows.

Pair with caching. On a high-traffic site, cache the redirect map (Cache::remember('redirects:map', 3600, ...)) keyed by path, and bust it from the Filament resource's afterCreate/afterSave/afterDelete hooks. This also insulates you from the package's query shape.

Gotchas and Tips

Zero stars means you are the QA team. Pin the exact version in composer.json ("wotz/filament-redirects": "1.0.3" rather than ^1.0) and read the migration and model on install. With no dependents, there is no community signal that a given Filament minor version works. Upgrade deliberately, not with composer update.

Trailing slashes and leading slashes will bite you. The single most common bug in hand-rolled redirect tables is the mismatch between request()->path() (blog/post, no leading slash) and a stored value of /blog/post. Pick one canonical form, normalise on write in the importer and in a model mutator, and normalise again on read. Also strip the query string before lookup unless you deliberately want parameter-preserving redirects.

Route order beats redirects. A redirect table is a fallback, not an override. If a live route, a Route::fallback(), or a WordPress-style catch-all matches first, your redirect never runs. Verify the middleware is registered after the router resolves but before the 404 page renders, and remember that Filament's own panel routes (/admin/...) should be excluded or they'll be shadowed.

Status codes: default to 301, but not always. 301 is cached aggressively by browsers and CDNs — effectively permanent from the user's machine. During a migration rehearsal, use 302 so you can change your mind. Once the map is final, flip to 301. Never 301 a redirect you might need to reverse.

Redirect chains and loops. Nothing in a CRUD package prevents A → B and B → C. If the destination path is itself a source, you have a chain; if it eventually points back, a loop and an infinite browser hang. Add a guard in your observer/importer that resolves the destination against the source set, and consider collapsing chains to a single hop on save.

Inactive/soft-deleted rows. Check whether the model uses SoftDeletes and whether the Filament resource filters them by default. A "deleted" redirect that still resolves is a nasty surprise. Confirm the resolution query includes whereNull('deleted_at') and any is_active flag.

Import validation. CSV imports fail silently in most packages. Validate before insert: source starts with / or is a valid path, destination is an absolute URL or a rooted path, no duplicate sources within the file, no self-redirects. Log rejected rows with line numbers rather than aborting the whole import.

Filament v3 vs v4 API drift. Resource namespaces, form(Form $form) signatures, and table action classes changed between majors. If the package targets v3 and you're on v4, expect Class not found or Method does not exist errors from the resource, not from your code. Check the panel provider registration compiles before debugging anything else.

Extension points worth knowing. Most Filament plugins let you swap the resource or model via config ('model' => YourRedirect::class) or a ->using() fluent method. If the package does, subclass the model to add scopes, casts, and observers without forking. If it doesn't, prefer observing the package's model from a service provider over editing vendor code.

Debugging resolution. When a redirect "doesn't work", work outward: does the row exist and is it active (php artisan tinker)? Does the path match exactly, byte for byte, including trailing slash? Is the middleware registered in the right group? Is a route, cache, or CDN intercepting? php artisan route:list --path=old-url and curl -I are your first two commands, in that order.

Consider the maintenance trade. The feature surface here is small — a table, a resource, and a lookup. If you hit two or three of the gotchas above, a 100-line in-house implementation with your own caching, normalisation, and chain-collapsing may cost less than fighting an unmaintained dependency. Adopt it for the admin UI and import ergonomics; keep your resolution layer thin enough to replace.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console