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

Canonical Url Bundle Laravel Package

camelot/canonical-url-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require camelot/canonical-url-bundle
    

    Ensure Camelot\CanonicalUrlBundle\CamelotCanonicalUrlBundle is enabled in config/bundles.php.

  2. Configuration: Add to config/packages/canonical_url.yaml:

    camelot_canonical_url:
        site_url: 'https://example.org'  # Your primary domain
        trailing_slash: true             # Force trailing slashes (default: false)
        www_redirect: true               # Redirect www to non-www (default: false)
        https_redirect: true              # Force HTTPS (default: false)
    
  3. First Use Case:

    • Test with a request to http://example.org/about-us → Should redirect to https://example.org/about-us/ (if configured).
    • Verify the <link rel="canonical"> tag appears in Twig templates:
      {{ canonical_url() }}
      

Implementation Patterns

Core Workflows

  1. URL Normalization:

    • Use the bundle’s event listener (CanonicalUrlListener) to auto-redirect non-canonical URLs.
    • Example: http://www.example.org/pagehttps://example.org/page/.
  2. Twig Integration:

    • Embed {{ canonical_url() }} in layouts (e.g., base.html.twig) to ensure consistency.
    • Override canonical URLs per route via annotations or services:
      # config/routes.yaml
      about:
          path: /about
          controller: App\Controller\AboutController
          canonical_url: 'https://example.org/about-us'  # Custom canonical
      
  3. Dynamic Canonical URLs:

    • Extend the CanonicalUrlGenerator service to generate URLs dynamically (e.g., for localized content):
      // src/Service/CustomCanonicalUrlGenerator.php
      class CustomCanonicalUrlGenerator extends CanonicalUrlGenerator {
          public function generate(string $path, array $params = []): string {
              // Custom logic (e.g., append locale)
              return parent::generate($path, $params);
          }
      }
      
      Register as a service with tags: ['canonical_url.generator'].
  4. API Responses:

    • Add canonical headers to API responses (e.g., Link: <https://example.org/resource>; rel="canonical"):
      use Symfony\Component\HttpFoundation\Response;
      
      return new Response(json_encode($data), 200, [
          'Link' => '<https://example.org/resource>; rel="canonical"',
      ]);
      

Integration Tips

  • Symfony Router: Combine with symfony/routing to validate canonical URLs before redirects.
  • Caching: Cache canonical URLs for static routes (e.g., using Symfony\Component\HttpKernel\CacheWarmer).
  • Testing: Mock the CanonicalUrlListener in PHPUnit to test redirects:
    $listener = $this->createMock(CanonicalUrlListener::class);
    $listener->method('onKernelRequest')->willReturnCallback(function ($event) {
        $event->setResponse(new RedirectResponse('https://example.org'));
    });
    $container->set('canonical_url.listener', $listener);
    

Gotchas and Tips

Pitfalls

  1. Configuration Overrides:

    • Bundle settings in config/packages/canonical_url.yaml must be merged with defaults. Omitting keys uses defaults (e.g., trailing_slash: false if not set).
    • Fix: Explicitly define all options to avoid unexpected behavior.
  2. Route Conflicts:

    • Redirects may interfere with existing routes (e.g., /about vs /about/).
    • Fix: Use canonical_url route option to override defaults:
      about:
          path: /about
          canonical_url: 'https://example.org/about'  # No trailing slash
      
  3. HTTPS/SSL Issues:

    • https_redirect: true requires a valid SSL certificate. Misconfigurations may cause infinite redirects.
    • Fix: Test with https_redirect: false in staging, then enable in production.
  4. Twig Template Caching:

    • The canonical_url() Twig function may break cached templates if the canonical URL changes dynamically.
    • Fix: Use {{ app.canonical_url() }} (if available) or cache the function’s output.
  5. Subdomains:

    • The bundle does not handle subdomains (e.g., blog.example.org). Redirects will fail if site_url is misconfigured.
    • Fix: Use a wildcard or configure separate bundles for subdomains.

Debugging

  • Check Redirects:

    • Enable Symfony’s profiler (_profiler) to inspect the CanonicalUrlListener response.
    • Log redirects in CanonicalUrlListener::onKernelRequest:
      $this->logger->debug('Redirecting to canonical URL', ['url' => $canonicalUrl]);
      
  • Validate Canonical Tags:

    • Inspect HTML source or use browser dev tools to verify <link rel="canonical"> exists.
    • Tool: Canonical URL Checker.

Extension Points

  1. Custom Redirect Logic:

    • Override CanonicalUrlListener::getCanonicalUrl() to implement business rules (e.g., exclude certain paths):
      public function getCanonicalUrl(Request $request): string {
          if ($request->getPathInfo() === '/admin') {
              return $request->getUri();
          }
          return parent::getCanonicalUrl($request);
      }
      
  2. Event Subscribers:

    • Listen to kernel.request to modify canonical URLs dynamically:
      // src/EventListener/CustomCanonicalListener.php
      class CustomCanonicalListener implements EventSubscriber {
          public static function getSubscribedEvents() {
              return ['kernel.request' => 'onKernelRequest'];
          }
      
          public function onKernelRequest(GetResponseEvent $event) {
              $request = $event->getRequest();
              if ($request->attributes->get('_route') === 'product') {
                  $request->attributes->set('canonical_url', 'https://example.org/products/' . $request->get('slug'));
              }
          }
      }
      
  3. API Headers:

    • Extend the bundle to add canonical headers to API responses via a ResponseEventSubscriber:
      public function onKernelResponse(FilterResponseEvent $event) {
          $response = $event->getResponse();
          if ($response->headers->has('Content-Type') && strpos($response->headers->get('Content-Type'), 'application/json') !== false) {
              $response->headers->set('Link', '<' . $this->canonicalUrl . '>; rel="canonical"');
          }
      }
      
  4. Multi-Site Support:

    • Use environment variables or parameter bags to switch site_url per environment:
      # config/packages/canonical_url.yaml
      camelot_canonical_url:
          site_url: '%env(APP_CANONICAL_URL)%'
      
      Set APP_CANONICAL_URL in .env.
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.
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
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