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

Sulu Content Extra Bundle Laravel Package

alengo/sulu-content-extra-bundle

Extends Sulu CMS 3.x Pages and Articles with an Additional Data tab, built-in entities, configurable mapping for localized/unlocalized fields, auto entity registration, navigation link markers, and sortable template groups. PHP 8.2+, Symfony 7.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require alengo/sulu-content-extra-bundle
    

    Register the bundle in config/bundles.php:

    Alengo\SuluContentExtraBundle\AlengoContentExtraBundle::class => ['all' => true],
    
  2. Define Forms: Create a form XML file (e.g., config/forms/page_additional_data.xml) with your desired fields. Example:

    <form xmlns="...">
        <key>page_additional_data</key>
        <properties>
            <property name="template_theme" type="select" mandatory="false">
                <meta><title lang="en">Theme</title></meta>
                <params><param name="values" type="collection"><param name="default" type="collection"><param name="title" value="Default"/><param name="name" value="default"/></param></param></params>
            </property>
        </properties>
    </form>
    
  3. Configure Field Mapping (optional): Create config/packages/alengo_content_extra.yaml to define which fields are unlocalized/localized:

    alengo_content_extra:
        page:
            unlocalized_keys:
                - template_theme
            localized_keys:
                - notes
    
  4. Clear Cache:

    php bin/console cache:clear
    

First Use Case

Add a theme selector to Pages:

  • Configure template_theme as an unlocalized field (shared across languages).
  • Use it in templates via {{ page.additionalData.template_theme }}.
  • Example: Dynamically apply CSS themes based on the selected value.

Implementation Patterns

Core Workflows

1. Adding Additional Data to Pages/Articles

  • Form Integration: The bundle auto-registers a tab in the Sulu admin for Pages/Articles (configurable via tab_title). Define fields in config/forms/{form_key}.xml (e.g., page_additional_data.xml). Example fields:

    <property name="campaign_id" type="text" mandatory="false">
        <meta><title lang="en">Campaign ID</title></meta>
    </property>
    <property name="seo_overrides" type="textarea" mandatory="false">
        <meta><title lang="en">SEO Overrides (JSON)</title></meta>
    </property>
    
  • Field Localization: Use unlocalized_keys/localized_keys in config to control storage:

    alengo_content_extra:
        page:
            unlocalized_keys: [template_theme, campaign_id]  # Shared across languages
            localized_keys: [notes, seo_overrides]          # Per-language
    
    • Unlocalized fields are stored in the base Page/Article entity.
    • Localized fields are stored in PageDimensionContent/ArticleDimensionContent.
  • Accessing Data in Templates:

    {# Page template #}
    <div class="theme-{{ page.additionalData.template_theme }}">
        {{ page.additionalData.notes[locale] }}  {# Localized notes #}
    </div>
    
    {# Article template #}
    {% if article.additionalData.seo_overrides[locale] is not empty %}
        <meta name="description" content="{{ article.additionalData.seo_overrides[locale].description }}">
    {% endif %}
    

2. Navigation Link Enhancements

  • Enable for Link-Type Pages: The bundle adds sourceLink (bool) and sourceUuid (string) to link-type pages. Example config (auto-enabled by default):

    alengo_content_extra:
        page:
            enabled: true
    
  • Use in Templates: Access via the navlink content section (bypasses Sulu’s TemplateResolver):

    {# Check if a page is a redirect #}
    {% if navlink.sourceLink %}
        <div class="redirect-indicator">This page redirects to: {{ navlink.sourceUuid }}</div>
    {% endif %}
    
    {# Dynamic logic based on source #}
    {% if navlink.sourceUuid == 'product-landing-page-uuid' %}
        <script>trackRedirect('product_landing');</script>
    {% endif %}
    

3. Custom Entity Overrides

  • Override default entities via config:
    alengo_content_extra:
        page:
            page_class: App\Entity\CustomPage
            entity_class: App\Entity\CustomPageDimensionContent
    
  • Ensure your custom entities extend the bundle’s base classes:
    // src/Entity/CustomPage.php
    namespace App\Entity;
    
    use Alengo\SuluContentExtraBundle\Entity\Page as BasePage;
    
    class CustomPage extends BasePage {}
    

4. Sortable Template Groups

  • Decorates Sulu’s metadata_group_provider to order admin tabs by translation keys.
  • Example: Reorder Article admin tabs by defining sulu_admin.template_group.* in translations:
    # translations/admin+intl-icu.en.yaml
    sulu_admin:
        template_group:
            basic: Basic Information
            additional_data: Additional Data  {# Will appear after "basic" #}
            seo: SEO Settings
    

Integration Tips

  • Validation: Add validation to forms or use Symfony’s constraints in XML:

    <property name="campaign_id" type="text" mandatory="false">
        <meta><title lang="en">Campaign ID</title></meta>
        <constraints>
            <constraint name="Regex" options='{"pattern": "/^[A-Za-z0-9_-]+$/"}' />
        </constraints>
    </property>
    
  • Migrations: If upgrading or adding new fields, create a migration to handle the additionalData JSON column:

    // src/Migration/VersionYYYYMMDDHHMMSS.php
    public function up(SchemaManagerInterface $sm): void
    {
        $sm->getConnection()->getSchemaManager()->createTable('pa_page_dimension_contents', function (CreateTable $table) {
            $table->json('additional_data')->nullable()->default(null);
        });
    }
    
  • API Exposure: Expose additional data via Sulu’s API by extending the PageResource/ArticleResource:

    // src/Serializer/Normalizer/PageNormalizer.php
    use Alengo\SuluContentExtraBundle\Model\AdditionalDataInterface;
    
    class PageNormalizer implements NormalizerInterface
    {
        public function normalize($object, $format = null, array $context = []): array
        {
            $data = parent::normalize($object, $format, $context);
            if ($object instanceof AdditionalDataInterface) {
                $data['additionalData'] = $object->getAdditionalData();
            }
            return $data;
        }
    }
    
  • Event Listeners: React to changes in additional data via Sulu’s events:

    // src/EventListener/AdditionalDataListener.php
    use Alengo\SuluContentExtraBundle\Model\AdditionalDataInterface;
    use Sulu\Bundle\CoreBundle\Event\UpdateContentEvent;
    
    class AdditionalDataListener
    {
        public function onUpdateContent(UpdateContentEvent $event): void
        {
            $content = $event->getContent();
            if ($content instanceof AdditionalDataInterface) {
                $data = $content->getAdditionalData();
                if (isset($data['campaign_id'])) {
                    // Trigger analytics or other logic
                }
            }
        }
    }
    

    Register the listener in services.yaml:

    services:
        App\EventListener\AdditionalDataListener:
            tags:
                - { name: kernel.event_listener, event: sulu_core.update_content, method: onUpdateContent }
    

Gotchas and Tips

Pitfalls

  1. Proxy Generation in Production:

    • Issue: Doctrine proxy classes may still be generated in production if not configured correctly.
    • Fix: Explicitly disable proxy generation in config/packages/prod/doctrine.yaml:
      when@prod:
          doctrine:
              orm:
                  auto_generate_proxy_classes: false
                  proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
      
    • Note: Proxies are generated during cache:warmup (part of deploy).
  2. Field Name Conflicts:

    • Issue: If a field name conflicts with Sulu’s reserved fields (e.g., title, published), data may be overwritten or lost.
    • Fix: Use unique field names (e.g., custom_title_override).
  3. Localization Mismatches:

    • Issue: Localized fields may not appear in the admin if the locale is not selected or the dimension content is not created.
    • Fix: Ensure the locale dimension is active in Sulu’s admin and that the field is marked as localized in the config.
  4. Navigation Markers Not Appearing:

    • Issue: sourceLink/`source
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.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony