alengo/sulu-category-extra-bundle
Adds an “Additional Data” tab to Sulu CMS categories. Configure fields via a standard Sulu form XML file and store values as a JSON column on the existing ca_categories table (no extra tables). Tab title, form key, and resource key are configurable.
Install the Bundle
composer require alengo/sulu-category-extra-bundle
Add to config/bundles.php:
Alengo\SuluCategoryExtraBundle\AlengoSuluCategoryExtraBundle::class => ['all' => true],
Register Routes
Add to config/routes/sulu_admin.yaml:
CategoryExtraBundle:
resource: "@AlengoSuluCategoryExtraBundle/Resources/config/routing_admin_api.yaml"
prefix: /admin/api
Define the Form
Create config/forms/category_additional_data.xml with a basic field (e.g., text_line):
<form xmlns="...">
<key>category_additional_data</key>
<properties>
<property name="custom_field" type="text_line" colspan="12">
<meta>
<title lang="en">Custom Field</title>
</meta>
</property>
</properties>
</form>
Run Migration
php bin/console doctrine:schema:update --force
Access the Tab Navigate to Sulu Admin → Categories → Edit Category and verify the "Additional Data" tab appears.
custom_field).ca_categories.additionalData).Form Configuration
single_select, media_selection, text_editor).single_select with predefined values) or a rich text field (text_editor).Entity Access in Twig
Alengo\SuluCategoryExtraBundle\Entity\Category before accessing additionalData:
{% if category instanceof Alengo\SuluCategoryExtraBundle\Entity\Category %}
{{ dump(category.additionalData.custom_field) }}
{% endif %}
API Integration
/admin/api/category-additional-data/{id} endpoints for custom backend logic (e.g., syncing with external services).$client = \Symfony\Panther\Client::createChromeClient();
$response = $client->request('GET', '/admin/api/category-additional-data/123');
$data = json_decode($response->getContent(), true);
Dynamic Forms
additionalData:
{% if category.additionalData.theme == 'blue' %}
<style>body { background: lightblue; }</style>
{% endif %}
Sulu Events: Listen to sulu.category.post_persist or sulu.category.post_update to trigger actions when additionalData changes:
// src/EventListener/CategoryExtraListener.php
public function onCategoryUpdate(CategoryEvent $event): void {
$category = $event->getCategory();
if ($category->hasAdditionalData() && $category->getAdditionalData()['custom_field'] === 'trigger') {
// Execute logic (e.g., send email, update related content).
}
}
Validation: Add custom validation to the form XML using validation tags:
<property name="email" type="text_line" colspan="12">
<meta>
<title lang="en">Email</title>
</meta>
<validation>
<constraint name="NotBlank" />
<constraint name="Email" />
</validation>
</property>
Localization: Translate field labels and placeholders in the form XML:
<meta>
<title lang="en">Custom Field</title>
<title lang="de">Benutzerdefiniertes Feld</title>
<placeholder lang="en">Enter value</placeholder>
</meta>
Database Schema
additionalData column won’t exist.ALTER TABLE ca_categories ADD additionalData JSON;
Entity Type Mismatch
Category entity (default behavior), additionalData won’t be available via getAdditionalData().Category entity extends Alengo\SuluCategoryExtraBundle\Entity\Category:
use Alengo\SuluCategoryExtraBundle\Entity\Category as BaseCategory;
class Category extends BaseCategory { ... }
Form Key Mismatch
form_key in config/packages/alengo_sulu_category_extra.yaml must match the <key> in your form XML.Caching Issues
php bin/console sulu:cache:clear
JSON Data Corruption
additionalData (e.g., unclosed braces) will break the admin UI.json_encode()/json_decode() when updating data programmatically.Check API Responses
Use Postman or cURL to test the /admin/api/category-additional-data/{id} endpoints:
curl -X GET http://your-sulu-admin/admin/api/category-additional-data/1 \
-H "Authorization: Bearer YOUR_TOKEN"
Log Additional Data
Add a debug listener to log additionalData changes:
public function onCategoryUpdate(CategoryEvent $event): void {
$this->logger->info('Additional Data:', [
'id' => $event->getCategory()->getId(),
'data' => $event->getCategory()->getAdditionalData(),
]);
}
Verify Form XML Use Sulu’s form validator to check for syntax errors:
php bin/console sulu:form:validate config/forms/category_additional_data.xml
Custom Entity Class
Extend the default Category entity to add methods or logic:
class CustomCategory extends Alengo\SuluCategoryExtraBundle\Entity\Category {
public function isFeatured(): bool {
return $this->getAdditionalData()['featured'] ?? false;
}
}
Update config/packages/alengo_sulu_category_extra.yaml:
alengo_sulu_category_extra:
entity_class: App\Entity\CustomCategory
Dynamic Form Loading Override the form key dynamically based on category type (e.g., blog vs. product categories):
// In a pre-persist listener
$category->setAdditionalDataFormKey('blog_category_data');
Third-Party Integrations
Use the PUT API endpoint to sync data with external services (e.g., Google Analytics, CRM):
$client->request('PUT', '/admin/api/category-additional-data/123', [
'json' => [
'id' => 123,
'custom_field' => 'updated_value',
'external_id' => '1001',
],
]);
Migration Hooks
Seed default additionalData during migrations:
// src/Migrations/Version20230101000000.php
public function up(Schema $schema): void {
$this->addSql('UPDATE ca_categories SET additionalData = \'{"theme": "default"}\' WHERE id = 1');
}
How can I help you explore Laravel packages today?