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

Url Manager Laravel Package

rayzenai/url-manager

Laravel package to manage URLs, redirects, SEO metadata, visit tracking, and XML sitemaps, with redirect-loop protection and automatic old→new slug redirects. Includes Filament 4 admin panel integration (UrlInput) and optional media SEO via file-manager.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation:

    composer require rayzenai/url-manager
    php artisan vendor:publish --tag=url-manager-config
    php artisan vendor:publish --tag=url-manager-migrations
    php artisan migrate
    
  2. Configure Location Service (for visitor tracking):

    • Download MaxMind database and configure config/location.php
    • Or set up MaxMind web service credentials in .env
  3. Register Filament Plugin:

    // In app/Providers/Filament/AdminPanelProvider.php
    ->plugin(UrlManagerPlugin::make())
    
  4. Add Redirect Middleware (critical for slug updates):

    // In bootstrap/app.php
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->web(prepend: [
            HandleUrlRedirects::class,
        ]);
    });
    
  5. First Model Integration:

    php artisan url-manager:make-model Product
    

    Then add use HasUrl to your model and implement webUrlPath().

  6. Generate URLs:

    php artisan urls:generate
    

First Use Case: Safe Slug Updates

  1. Update a model's slug (e.g., from old-product to new-product)
  2. The package automatically creates a redirect record
  3. Visitors to /old-product are automatically redirected to /new-product (301 by default)
  4. No 404 errors for existing links

Implementation Patterns

Core Workflows

1. Model Integration Pattern

// In your Eloquent model
use RayzenAI\UrlManager\Traits\HasUrl;

class Product extends Model
{
    use HasUrl;

    public function webUrlPath(): string
    {
        return 'products/' . $this->slug;
    }

    // Optional overrides
    public function activeUrlField(): string
    {
        return 'is_published';
    }

    public function ogTags(): array
    {
        return [
            'title' => $this->name,
            'description' => $this->description,
            'image' => $this->image_url,
        ];
    }
}

Key Methods to Implement:

  • webUrlPath() (required) - Defines the URL structure
  • activeUrlField() (optional) - Customize active status field
  • SEO methods (ogTags(), getSeoMetadata()) - For rich SEO data

2. Redirect Management Pattern

// Creating redirects
Url::createRedirect('old-path', 'new-path', 301);

// Checking redirects in routes
Route::get('/legacy/{slug}', function ($slug) {
    $redirect = Url::findRedirect('legacy/' . $slug);
    if ($redirect) {
        return redirect($redirect->destination, $redirect->status_code);
    }
    // Fallback logic
})->name('legacy.route');

3. Sitemap Generation Pattern

// Generate sitemap
php artisan sitemap:generate

// Customize sitemap output location
config([
    'url-manager.sitemap.path' => public_path('sitemaps'),
]);

// Include custom static routes
config([
    'url-manager.sitemap.custom_routes' => [
        ['path' => '/about', 'priority' => 0.7],
        ['path' => '/contact', 'priority' => 0.6],
    ],
]);

4. Visit Tracking Pattern

// Track visits automatically (via middleware)
UrlManager::trackVisit($model, $userId);

// Manual tracking
UrlManager::trackVisit($product, auth()->id());

// Get visit analytics
$visits = UrlManager::getVisitAnalytics($product, 'last_7_days');

Integration Tips

  1. Middleware Order:

    • Always prepend HandleUrlRedirects middleware to catch redirects before route resolution
    • Place it before TrimStrings, ConvertEmptyStringsToNull, and ValidateSignature
  2. Model Events:

    // In your model's boot method
    static::saved(function ($model) {
        if ($model->wasChanged('slug')) {
            UrlManager::createRedirect(
                $model->getPreviousUrl(),
                $model->webUrlPath(),
                301
            );
        }
    });
    
  3. Filament Customization:

    // Extend the UrlInput component
    use RayzenAI\UrlManager\Components\UrlInput;
    
    UrlInput::macro('withCustomValidation', function () {
        return $this->extraAttributes([
            'data-validation' => 'required|url',
        ]);
    });
    
  4. Performance Optimization:

    • Add indexes to urls.path and urls.slug columns
    • Use database query caching for frequent redirect lookups
    • // In config/url-manager.php
      'cache' => [
          'enabled' => true,
          'ttl' => 60, // Cache redirects for 60 seconds
      ]
      
  5. Bulk URL Generation:

    # For large datasets, process in chunks
    php artisan urls:generate --chunk=1000
    
    # Or use queue jobs
    php artisan urls:generate --queue
    

Gotchas and Tips

Common Pitfalls

  1. Redirect Middleware Placement:

    • Problem: Redirects not working after slug updates
    • Solution: Ensure HandleUrlRedirects is prepended in middleware
    • Debug: Check if middleware runs by adding a log in handle() method
  2. Circular Redirects:

    • Problem: A→B→C→A creates infinite loops
    • Solution: The package detects this automatically, but test with:
      php artisan url-manager:check-loops
      
  3. Sitemap Generation Failures:

    • Problem: Large sites (>50k URLs) time out
    • Solution:
      • Increase PHP memory: php -d memory_limit=4G artisan sitemap:generate
      • Process in chunks: php artisan sitemap:generate --chunk=5000
      • Use queue: php artisan sitemap:generate --queue
  4. SEO Metadata Conflicts:

    • Problem: Duplicate meta tags when using both HasUrl and Laravel's built-in SEO packages
    • Solution: Implement getSeoMetadata() to merge data:
      public function getSeoMetadata(): array
      {
          return array_merge(
              parent::getSeoMetadata(),
              ['custom_tag' => 'value']
          );
      }
      
  5. Visit Tracking Accuracy:

    • Problem: Country detection fails
    • Solution:
      • Verify MaxMind database path in config/location.php
      • Check database permissions for the GeoLite2 file
      • Fallback to IP-based detection if MaxMind fails

Debugging Tips

  1. URL Generation Issues:

    # Check model configuration
    php artisan url-manager:check App\Models\Product
    
    # View generated URLs
    php artisan tinker
    >>> \RayzenAI\UrlManager\Models\Url::where('model_type', 'App\Models\Product')->get();
    
  2. Redirect Debugging:

    // Add to HandleUrlRedirects middleware
    public function handle($request, Closure $next)
    {
        $redirect = Url::findRedirect($request->path());
        if ($redirect) {
            \Log::info("Redirecting {$request->path()} to {$redirect->destination}");
        }
        return $next($request);
    }
    
  3. Sitemap Validation:

    # Test sitemap generation
    php artisan sitemap:generate --dry-run
    
    # Validate against Google guidelines
    composer require squizlabs/php_codesniffer
    vendor/bin/phpcs --standard=Google sitemap.xml
    

Configuration Quirks

  1. Active URL Field:

    • Defaults to is_active, but can be customized:
      public function activeUrlField(): string
      {
          return 'published'; // For models using 'published' instead
      }
      
  2. Slug Generation:

    • Customize slug generation in config/url-manager.php:
      'slug' => [
          'separator' => '-',
          'max_length' => 100,
          'transliterate' => true,
      ]
      
  3. Visit Tracking:

    • Disable tracking for specific models:
      public function shouldTrackVisits(): bool
      {
          return false; // Opt out of tracking
      }
      
  4. SEO Metadata Priority:

    • Control which metadata takes precedence:
      // In config/url-manager.php
      'seo' => [
          'priority' => [
              'model' => 10, // Highest
              'route' => 5,   // Middle
              'fallback' => 1, // Lowest
          ],
      ]
      

Extension Points

  1. Custom Redirect Logic:
    // Extend the redirect finder
    
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.
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php
agtp/mod-php
centraldesktop/protobuf-php
trappistes/laravel-custom-fields
splash/sonata-admin
splash/metadata