Installation Run:
composer require stiwl/page-bundle
Ensure all 13 dependencies (SonataAdmin, IvoryGoogleMap, CKEditor, etc.) are installed via Composer.
Bundle Enable
Add to config/bundles.php:
return [
// ...
Stiwl\PageBundle\StiwlPageBundle::class => ['all' => true],
];
Database & Fixtures Run migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Load demo data (if needed):
php bin/console doctrine:fixtures:load --append
First Use Case
Access the Sonata Admin dashboard at /admin to manage Pages, Menus, or News via the UI. Example:
Page Management
stiwl_page Twig extension to fetch pages by slug/ID:
{{ render(stiwl_page.getPage('about-us')) }}
Stiwl\PageBundle\Entity\Page to add custom fields (e.g., metaTitle, customCta).Menu Integration
// src/Controller/DefaultController.php
use Knp\Menu\MenuItemInterface;
use Stiwl\PageBundle\Menu\PageMenuBuilder;
public function menuAction(MenuBuilder $menuBuilder)
{
$menu = $menuBuilder->createMenu();
$menu->addChild('Home', ['route' => 'homepage']);
$menu->addChild('Pages', ['route' => 'stiwl_page_list']);
}
config/sonata_admin.yml:
sonata_admin:
options:
menu:
- label: 'Pages'
uri: '~/admin/page/'
Multilingual Content
SonataIntlBundle for translations. Example in a Page entity:
// src/Entity/Page.php
use Gedmo\Mapping\Annotation as Gedmo;
/**
* @Gedmo\Translatable
*/
private $title;
Contact Form + Google Maps
{{ form_start(form) }}
{{ form_widget(form.name) }}
{{ form_widget(form.email) }}
{{ render(ivory_google_map({
'address': '123 Main St',
'zoom': 12,
'width': '100%',
'height': '400px'
})) }}
{{ form_end(form) }}
public function contactAction(Request $request)
{
$form = $this->createForm(ContactType::class);
if ($request->isMethod('POST') && $form->handleRequest($request)) {
$this->mailer->send($form->getData());
return $this->redirectToRoute('homepage');
}
return $this->render('contact.html.twig', ['form' => $form->createView()]);
}
CKEditor Integration
config/packages/ckeditor.yaml:
ckeditor:
editor_configs:
default:
toolbar: [['bold', 'italic'], ['numberedList']]
{{ form_row(form.content, {'attr': {'class': 'ckeditor'}}) }}
Dependency Hell
composer why-not stiwl/page-bundle
composer.lock from a working project or pin versions in composer.json.Sonata Admin Overrides
base.html.twig) may break updates. Use:
# config/packages/sonata_admin.yaml
sonata_admin:
templates:
layout: 'StiwlPageBundle:layout.html.twig'
Multilingual Quirks
php bin/console doctrine:query:sql "UPDATE page_translations SET title = ? WHERE locale = ? AND page_id = ?"
SonataIntlBundle's sonata_intl_update command:
php bin/console sonata_intl_update
Google Maps API Key
IvoryGoogleMapBundle, which requires a Google Maps API key. Configure in .env:
IVORY_GOOGLE_MAP_KEY=your_api_key_here
php bin/console debug:config ivory_google_map
CKEditor Asset Conflicts
php bin/console assets:install
php bin/console cache:clear
Sonata Admin Debugging
sonata_admin events in dev.log.doctrine:query:
php bin/console doctrine:query:sql "SELECT * FROM page WHERE slug = ?" "about-us"
Menu Builder Issues
PageMenuBuilder is tagged as a service:
# config/services.yaml
Stiwl\PageBundle\Menu\PageMenuBuilder:
tags: ['knp_menu.menu_builder']
Translation Sync
// src/EventListener/TranslationListener.php
use Gedmo\Translatable\TranslatableListener;
public function __construct()
{
$this->translatableListener = new TranslatableListener();
}
public function onKernelRequest(GetResponseEvent $event)
{
$this->translatableListener->preFlush();
}
Custom Page Types
Page entity:
// src/Entity/CustomPage.php
use Stiwl\PageBundle\Entity\Page;
class CustomPage extends Page
{
/**
* @ORM\Column(type="string", nullable=true)
*/
private $customField;
}
StiwlPageBundle config:
stiwl_page:
page_classes:
- App\Entity\CustomPage
Override Sonata Admin Templates
vendor/sonata-project/admin-bundle/Resources/views/ to templates/sonata/admin/ and modify.Add Custom Blocks
# config/services.yaml
app.block.custom:
class: App\Block\CustomBlock
tags:
- { name: sonata.block }
Sonata\BlockBundle\Block\BlockInterface.Extend Contact Form
ContactType:
// src/Form/Type/CustomContactType.php
use Stiwl\PageBundle\Form\Type\ContactType as BaseContactType;
class CustomContactType extends BaseContactType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('customField', TextType::class);
}
}
routing.yml:
stiwl_page_contact:
path: /contact
defaults: { _controller: 'App\Controller\DefaultController::contact' }
How can I help you explore Laravel packages today?