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

Seo Bundle Laravel Package

symfony-cmf/seo-bundle

Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the bundle to your composer.json:

    composer require symfony-cmf/seo-bundle
    

    Enable it in config/bundles.php:

    return [
        // ...
        SymfonyCmf\Bundle\SeoBundle\SymfonyCmfSeoBundle::class => ['all' => true],
    ];
    
  2. Configuration Publish the default config:

    php artisan vendor:publish --tag=seo-bundle-config
    

    Update config/seo.php with your preferred settings (e.g., canonical URLs, meta tags).

  3. First Use Case Generate SEO metadata for a route (e.g., App\PageController@show):

    use SymfonyCmf\Bundle\SeoBundle\Seo\SeoMetadataFactoryInterface;
    
    class PageController extends Controller
    {
        public function show(SeoMetadataFactoryInterface $seoFactory, Page $page)
        {
            $metadata = $seoFactory->createMetadata($page);
            return $this->render('page/show.html.twig', [
                'metadata' => $metadata,
            ]);
        }
    }
    
  4. Twig Integration In your template, render metadata:

    {{ metadata.title }}
    {{ metadata.description }}
    {{ metadata.canonicalUrl }}
    

Implementation Patterns

Common Workflows

  1. Dynamic Metadata Generation Extend the default metadata factory to customize behavior:

    use SymfonyCmf\Bundle\SeoBundle\Seo\Metadata\MetadataFactory;
    use SymfonyCmf\Bundle\SeoBundle\Seo\Metadata\MetadataFactoryInterface;
    
    class CustomMetadataFactory extends MetadataFactory implements MetadataFactoryInterface
    {
        public function createMetadata($content, $routeParameters = [])
        {
            $metadata = parent::createMetadata($content, $routeParameters);
            $metadata->setTitle($metadata->getTitle() . ' | Custom Suffix');
            return $metadata;
        }
    }
    

    Register the service in config/services.yaml:

    SymfonyCmf\Bundle\SeoBundle\Seo\SeoMetadataFactory:
        class: App\Seo\CustomMetadataFactory
    
  2. Route-Based SEO Use the SeoMetadataFactory in route controllers or event subscribers:

    use Symfony\Component\HttpKernel\Event\ResponseEvent;
    
    class SeoSubscriber implements EventSubscriberInterface
    {
        public function onKernelResponse(ResponseEvent $event)
        {
            $metadata = $this->seoFactory->createMetadata($event->getController()[1]);
            $event->getResponse()->headers->set('X-Seo-Title', $metadata->getTitle());
        }
    }
    
  3. Content-Type-Specific Rules Define metadata rules per content type (e.g., Page, BlogPost) using YAML:

    # config/seo/rules.yml
    App\Entity\BlogPost:
        title: "%post.title% - %site.name%"
        description: "%post.excerpt%"
        robots: "index,follow"
    
  4. Canonical URLs Ensure canonical URLs are set dynamically:

    $metadata->setCanonicalUrl($this->generateUrl('canonical_route', ['id' => $page->getId()]));
    
  5. OpenGraph/Social Media Tags Extend metadata for social sharing:

    $metadata->setProperty('og:type', 'article');
    $metadata->setProperty('og:image', $page->getFeaturedImageUrl());
    

Integration Tips

  1. Symfony Event Dispatcher Listen to kernel.response to inject SEO metadata globally:

    $event->getResponse()->setContent(
        $this->renderView('seo/metadata.html.twig', ['metadata' => $metadata])
    );
    
  2. Doctrine Lifecycle Callbacks Update SEO metadata when entities change:

    use Doctrine\ORM\Event\LifecycleEventArgs;
    
    class Page
    {
        public function preUpdate(LifecycleEventArgs $args)
        {
            $em = $args->getEntityManager();
            $em->getEventManager()->dispatchEvent(
                'seo.update',
                new SeoUpdateEvent($this)
            );
        }
    }
    
  3. API Responses Serialize metadata for API consumers:

    return $this->json([
        'data' => $page,
        'seo' => [
            'title' => $metadata->getTitle(),
            'canonical_url' => $metadata->getCanonicalUrl(),
        ],
    ]);
    
  4. Caching Cache metadata for performance:

    $cacheKey = 'seo:metadata:' . $page->getId();
    $metadata = $this->cache->get($cacheKey);
    
    if (!$metadata) {
        $metadata = $this->seoFactory->createMetadata($page);
        $this->cache->set($cacheKey, $metadata, 3600);
    }
    

Gotchas and Tips

Pitfalls

  1. Deprecated Bundle

    • The bundle is archived (last release: 2018). Consider alternatives like:
    • Fork or migrate if long-term support is critical.
  2. Configuration Overrides

    • Default rules in config/seo/rules.yml may conflict with your templates. Explicitly override in your config:
      seo:
          rules:
              App\Entity\Page:
                  title: "%page.title%"  # Override default
      
  3. Route Parameter Mismatches

    • Ensure $routeParameters passed to createMetadata() match the route definition. Example:
      // Correct: Parameters must align with route {id}
      $metadata = $seoFactory->createMetadata($page, ['id' => $page->getId()]);
      
  4. Twig Auto-escaping

    • SEO metadata (e.g., og:image) may break if Twig escapes URLs. Use |raw filter:
      <meta property="og:image" content="{{ metadata.properties.og_image|raw }}" />
      
  5. Canonical URL Conflicts

    • Avoid duplicate canonical tags. Validate with:
      if ($metadata->getCanonicalUrl() !== $request->getUri()) {
          $metadata->setCanonicalUrl($request->getUri());
      }
      

Debugging Tips

  1. Dump Metadata Inspect generated metadata in a controller:

    dump($metadata->getTitle());
    dump($metadata->getProperties());
    
  2. Check Rules Loading Verify YAML rules are loaded:

    $this->container->get('seo.rules')->getRules();
    
  3. Event Debugging Listen for SEO events to trace execution:

    $dispatcher->addListener('seo.metadata', function ($event) {
        error_log('SEO Event: ' . print_r($event->getMetadata(), true));
    });
    
  4. HTTP Headers Validate metadata in browser dev tools or curl:

    curl -I http://your-site.com/page
    

Extension Points

  1. Custom Metadata Factories Implement MetadataFactoryInterface for content-specific logic:

    class BlogPostMetadataFactory implements MetadataFactoryInterface
    {
        public function createMetadata($content, array $routeParameters = [])
        {
            $metadata = new Metadata();
            $metadata->setTitle(sprintf('Post: %s', $content->getTitle()));
            return $metadata;
        }
    }
    
  2. Metadata Normalizers Extend MetadataNormalizerInterface to transform metadata for APIs:

    class ApiMetadataNormalizer implements MetadataNormalizerInterface
    {
        public function normalize(Metadata $metadata)
        {
            return [
                'title' => $metadata->getTitle(),
                'canonical_url' => $metadata->getCanonicalUrl(),
                'properties' => $metadata->getProperties(),
            ];
        }
    }
    
  3. Dynamic Rule Providers Fetch SEO rules from a database or external service:

    class DatabaseRuleProvider implements RuleProviderInterface
    {
        public function getRules()
        {
            return $this->entityManager->getRepository(Rule::class)->findAll();
        }
    }
    
  4. Event Subscribers Extend SEO behavior via events:

    // src/EventListener/SeoListener.php
    class SeoListener implements EventSubscriberInterface
    {
        public static function getSubscribedEvents()
        {
            return [
                'seo.metadata' => 'onSeoMetadata',
            ];
        }
    
        public function onSeoMetadata(
    
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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware