Weave 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

Title Widget Laravel Package

friendsofvictoire/title-widget

friendsofvictoire/title-widget is a lightweight Laravel/PHP package for reusable, configurable title widgets. It helps compose page titles from parts, apply separators or suffixes, and render consistent headings and browser titles from views with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: friendsofvictoire/title-widget is not a Laravel package. It is a Symfony bundle (VictoireWidgetTitleBundle) that plugs a "Title" widget into Victoire CMS, a Symfony 2/3-era page-builder. There is no service provider, no facade, no config file to publish. You cannot composer require this into a Laravel app and get anything useful — Composer will resolve it, and then nothing will ever autoload it.

If you are actually maintaining a Victoire site:

  1. composer require friendsofvictoire/title-widget:^1.0 (pin the 2017 tag explicitly; there is only one).
  2. Register the bundle in app/AppKernel.php alongside VictoireCoreBundle:
    new Victoire\Widget\TitleBundle\VictoireWidgetTitleBundle(),
    
  3. bin/console cache:clear and bin/console assets:install --symlink.
  4. In the Victoire page editor, the widget picker now offers "Title".

Look at these four files first, in this order — they are the entire bundle:

  • Widget/WidgetTitle.php — the persisted entity (what an editor's heading actually is in the database).
  • Form/WidgetTitleType.php — the fields exposed in the editor sidebar.
  • Resources/views/show.html.twig — the frontend markup. This is what you will change most.
  • Controller/WidgetTitleController.php — the showAction that wires the widget to the template.

First use case: an editor drops a heading into a page body above a text block, sets the text, saves, and the page renders <h2>…</h2>. That is the whole feature. Budget ten minutes, not an afternoon.

Implementation Patterns

Let editors pick the heading level. Out of the box the widget is a plain text field. The most common first patch is adding a level choice:

// Form/WidgetTitleType.php
->add('level', ChoiceType::class, [
    'choices' => ['H1' => 'h1', 'H2' => 'h2', 'H3' => 'h3', 'H4' => 'h4'],
    'data' => 'h2',
])

Add the matching property + column to WidgetTitle.php, then in the template:

{% set tag = widget.level|default('h2') %}
<{{ tag }} class="widget-title">{{ widget.title }}</{{ tag }}>

Theme by override, never by fork. Symfony's bundle template inheritance means you drop a file at app/Resources/VictoireWidgetTitleBundle/views/show.html.twig and it wins. Keep the vendor copy pristine so future (hypothetical) updates don't conflict. Add your design-system classes there — class="c-heading c-heading--2" — rather than in the entity.

Compose, don't extend. In Victoire, a Title widget's job is to sit in the widget map above a Text or RichText widget. Resist adding subtitle, link, icon, and alignment fields; at that point you have a "Section Header" widget and you should copy the four-file pattern into your own bundle (one entity, one form type, one controller, one template, plus a @VictoireWidget annotation) rather than growing this one.

Treat heading level as configuration, not content. If SEO or accessibility matters, don't let every editor pick h1. Set a sane default in the entity, and only expose level on widgets used in specific slots. Editors will otherwise produce five h1s per page.

The Laravel equivalent. If you are reading this because you want the same capability in Laravel: skip the package entirely. A Blade component gets you there in one file:

{{-- resources/views/components/title.blade.php --}}
@props(['level' => 2, 'text' => null])
<h{{ $level }} {{ $attributes->class(['title', "title--{$level}"]) }}>
    {{ $text ?? $slot }}
</h{{ $level }}>

Store the level as a small integer or enum on your page-block model, render <x-title :level="$block->level">{{ $block->text }}</x-title>, and validate level with in:1,2,3,4,5,6 in a FormRequest. Filament or Nova gives you the editor UI for free. This is genuinely a 20-minute job — which is the single most important finding about this package.

Gotchas and Tips

It is abandoned. Last release 2017-05-03, one star, zero dependents. No security advisories will be issued, no PHP 8 or Symfony 4+ compatibility will arrive. Plan for it as a vendored piece of code you own, not a dependency you track.

Dependency resolution will fight you. The bundle requires victoire/core at Symfony 2.8/3.x-era constraints. On a modern Symfony app, composer require fails or forces a downgrade cascade. Don't --ignore-platform-reqs your way through it; either run the host app on a container matching the original era (PHP 7.1 is a reasonable guess) or vendor the four files into your own bundle and drop the constraint.

Silent template fallback. If your override path is wrong — wrong bundle name, views/ vs Resources/views/, missing show.html.twig filename — Symfony does not warn. You get the vendor template and wonder why your classes vanished. Verify with bin/console debug:twig | grep -i title and always cache:clear after touching templates; the dev cache will happily serve stale markup.

Saved widget data is serialized/relational and brittle. Renaming a property on WidgetTitle orphans the data for every page already authored. Add columns and fields; never rename or remove. If you must migrate, write a one-off script that walks the existing widget rows first.

Escape the title. {{ widget.title }} under Twig autoescaping is correct. The tempting |raw for "allow a bit of formatting" turns the widget into an XSS vector for anyone with editor access. If you truly need inline markup, run it through HTMLPurifier on save.

The showAction is a service, not a route you can hit. Debugging rendering means reading the controller and the @VictoireWidget annotation, not curling a URL. Dump the widget object in the template with {{ dump(widget) }} (with the debug bundle loaded) to see exactly which fields you actually have.

Extension point that works: decorate or subclass the widget's controller service in your app's services.yml to inject a menu or translation helper, rather than editing vendor code. Extension point that doesn't: don't try to make this widget handle rich text or media; the bundle is a one-field heading and every field you bolt on increases the cost of the eventual rewrite.

Bottom line: adopt only if you are already on Victoire and need a heading block immediately. If you are choosing an architecture today — Laravel or otherwise — a Blade component plus a column on your block model replaces this package completely and will still compile in 2030.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource