Intelligent redirect management and 404 handling for Craft CMS.
- Automatic 404 Handling - Catches all 404s and attempts to redirect
- Multiple Match Types:
- Exact Match - Case-insensitive exact URL matching
- RegEx Match - Full regular expression support
- Wildcard Match - Simple * wildcards
- Prefix Match - URL starts with pattern
- Statistics Tracking - Track all 404s (handled and unhandled)
- Auto-Redirect Creation - Automatically creates redirects when entry URIs change
- Smart Caching - Fast redirect lookups with tag-based cache invalidation
- CSV Export - Export statistics for analysis
- Multi-Site Support - Site-specific or global redirects
- Logging Integration - Uses logging-library for consistent logs
- Craft CMS 5.0 or later
- PHP 8.2 or later
- Logging Library 5.0 or greater (installed automatically as dependency)
Until published on Packagist, install directly from the repository:
cd /path/to/project
composer config repositories.craft-redirect-manager vcs https://github.com/LindemannRock/craft-redirect-manager
composer require lindemannrock/craft-redirect-manager:dev-main
./craft plugin/install redirect-managerOnce published on Packagist:
cd /path/to/project
composer require lindemannrock/craft-redirect-manager
./craft plugin/install redirect-manager- Go to the Plugin Store in your Craft control panel
- Search for "Redirect Manager"
- Click "Install"
Copy src/config.php to config/redirect-manager.php and customize:
<?php
return [
// Auto create redirects when entry URIs change
'autoCreateRedirects' => true,
// Statistics retention in days (0 = keep forever)
'statisticsRetention' => 30,
// Maximum statistics records
'statisticsLimit' => 1000,
// Preserve query strings in redirects
'preserveQueryString' => false,
// Log level
'logLevel' => 'error',
];<?php
return [
'*' => [
'autoCreateRedirects' => true,
],
'production' => [
'logLevel' => 'error',
'statisticsRetention' => 90,
],
'dev' => [
'logLevel' => 'debug',
'statisticsRetention' => 7,
],
];Via Control Panel:
- Navigate to Redirect Manager → Redirects
- Click New redirect
- Fill in:
- Source URL:
/old-pageor/blog/*or regex pattern - Destination URL:
/new-pageor absolute URL - Match Type: exact, regex, wildcard, or prefix
- Status Code: 301 (permanent) or 302 (temporary)
- Source URL:
- Save
Programmatically:
use lindemannrock\redirectmanager\RedirectManager;
RedirectManager::$plugin->redirects->createRedirect([
'sourceUrl' => '/old-page',
'destinationUrl' => '/new-page',
'matchType' => 'exact',
'statusCode' => 301,
'enabled' => true,
'priority' => 0,
'siteId' => null, // null = all sites
]);Exact Match:
Source: /old-page
Matches: /old-page (case-insensitive)
Wildcard Match:
Source: /blog/*
Matches: /blog/post-1, /blog/category/news, etc.
Prefix Match:
Source: /old-
Matches: /old-page, /old-blog, /old-anything
RegEx Match:
Source: ^/blog/(\d+)/(.*)$
Destination: /article/$1/$2
Dashboard:
- Navigate to Redirect Manager → Statistics
- View handled vs unhandled 404s
- See most common 404s
- Create redirects from unhandled 404s with one click
Export CSV:
Redirect Manager → Statistics → Export CSV
When enabled (default), the plugin automatically creates redirects when:
- Entry slug changes:
/old-slug→/new-slug - Entry moves in structure:
/parent/child→/new-parent/child
Disable in settings: Redirect Manager → Settings → Auto Create Redirects
# Create a test redirect via CP:
# Source: /test-redirect
# Destination: /
# Match Type: exact
# Status Code: 301
# Test it:
curl -I http://your-site.test/test-redirect
# Should return: HTTP/1.1 301 Moved Permanently
# Location: http://your-site.test/# Visit a non-existent page:
curl -I http://your-site.test/page-that-does-not-exist
# Check statistics:
# CP → Redirect Manager → Statistics
# Should show the 404 with "Handled: No"- Create a test entry with slug
test-entry - Note the URL (e.g.,
/test-entry) - Change the slug to
renamed-entry - Save the entry
- Check Redirect Manager → Redirects
- Should see auto-created redirect:
/test-entry→/renamed-entry
# Create redirect:
# Source: /old-blog/*
# Destination: /blog/
# Match Type: wildcard
curl -I http://your-site.test/old-blog/any-post
# Should redirect to /blog/# Run cleanup job manually:
php craft queue/run
# Or test the service directly:
php craft console/controller/eval \
"echo lindemannrock\redirectmanager\RedirectManager::\$plugin->statistics->cleanupOldStatistics();"- View redirects - View redirect list
- Create redirects - Create new redirects
- Edit redirects - Modify existing redirects
- Delete redirects - Remove redirects
- View statistics - Access 404 statistics
- View logs - Access plugin logs
- Manage settings - Change plugin settings
-
Check plugin is installed:
php craft plugin/list
-
Check database tables exist:
php craft migrate/all --plugin=redirect-manager
-
Check logs:
CP → Redirect Manager → Logs -
Enable debug logging:
// config/redirect-manager.php return [ 'logLevel' => 'debug', ];
-
Clear caches:
php craft clear-caches/all
- Check Settings → Statistics → Record Remote IP is enabled
- Check statistics limit hasn't been reached
- Check database:
SELECT * FROM redirectmanager_statistics
- Check Settings → General → Auto Create Redirects is enabled
- Check entry has a URI (not disabled, not in a disabled section)
- Check logs for any errors
Listen to redirect events in your own plugins:
use lindemannrock\redirectmanager\services\RedirectsService;
use lindemannrock\redirectmanager\events\RedirectEvent;
use yii\base\Event;
Event::on(
RedirectsService::class,
RedirectsService::EVENT_BEFORE_SAVE_REDIRECT,
function(RedirectEvent $event) {
// Modify redirect before saving
$event->redirect['statusCode'] = 302;
// Or prevent saving
// $event->isValid = false;
}
);Available events:
EVENT_BEFORE_SAVE_REDIRECTEVENT_AFTER_SAVE_REDIRECTEVENT_BEFORE_DELETE_REDIRECTEVENT_AFTER_DELETE_REDIRECT
use lindemannrock\redirectmanager\RedirectManager;
// Redirects
$plugin = RedirectManager::$plugin;
$plugin->redirects->createRedirect([...]);
$plugin->redirects->updateRedirect($id, [...]);
$plugin->redirects->deleteRedirect($id);
$plugin->redirects->findRedirect($fullUrl, $pathOnly);
// Statistics
$plugin->statistics->record404($url, $handled);
$plugin->statistics->getAllStatistics($siteId, $limit);
$plugin->statistics->getChartData($siteId, $days);
$plugin->statistics->exportToCsv($siteId);
// Matching
$plugin->matching->matches($matchType, $pattern, $url);- Documentation: https://github.com/LindemannRock/craft-redirect-manager
- Issues: https://github.com/LindemannRock/craft-redirect-manager/issues
- Email: support@lindemannrock.com
This plugin is licensed under the MIT License. See LICENSE for details.
Developed by LindemannRock