PHPackages                             thelia/backoffice-default-twig-template - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. thelia/backoffice-default-twig-template

ActiveThelia-backoffice-template[Templating &amp; Views](/categories/templating)

thelia/backoffice-default-twig-template
=======================================

Thelia 3 back-office template based on Twig, Symfony UX and Bootstrap 5.

0.1.0(3w ago)061↑300%LGPL-3.0+PHPPHP &gt;=8.3

Since May 17Pushed 1w agoCompare

[ Source](https://github.com/thelia-templates/default-twig)[ Packagist](https://packagist.org/packages/thelia/backoffice-default-twig-template)[ RSS](/packages/thelia-backoffice-default-twig-template/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (7)Versions (4)Used By (0)

Thelia back-office — Twig template (`default-twig`)
===================================================

[](#thelia-back-office--twig-template-default-twig)

Modern Bootstrap 5 / Twig / Stimulus port of the legacy Smarty back-office. Lives side by side with `templates/backOffice/default/` during the transition.

Activation
----------

[](#activation)

```
# fresh install
ddev exec php bin/install \
  --frontoffice_theme=flexy --backoffice_theme=default-twig \
  --pdf_theme=default --email_theme=default \
  --with-demo --with-admin \
  --admin_login=thelia --admin_password=thelia \
  --admin_first_name=thelia --admin_last_name=thelia \
  --admin_email=thelia@example.com

# already installed: switch active template
ddev exec bin/console template:set backOffice default-twig
ddev exec bin/console cache:warmup -e dev

# build assets
ddev exec bash -c "cd templates/backOffice/default-twig && npm install && npm run build"
```

URL:

Architecture
------------

[](#architecture)

```
templates/backOffice/default-twig/
├── _side_nav.html.twig      # sidebar (mirrors includes/main-menu.html)
├── _top_nav.html.twig       # top bar (logo, search, locale, profile, logout)
├── _footer.html.twig        # copyright + social
├── _thelia_logo.html.twig   # inline SVG logo (variant: dark|light)
├── base.html.twig           # base layout
├── auth-layout.html.twig    # login screen
├── home.html.twig           # dashboard
├── /                # one folder per business domain (catalog, customer, ...)
│   ├── list.html.twig
│   ├── edit.html.twig
│   ├── _create_modal.html.twig
│   └── _delete_modal.html.twig
├── components/              # reusable Twig components (BoDataTable, BoDashboard, ...)
├── form/
│   └── bo_form_theme.html.twig   # custom Bootstrap 5 form theme
├── config/packages/twig.yaml      # registers form_themes
├── assets/                  # SCSS + JS + img + flags
│   ├── app.js
│   ├── controllers/         # Stimulus controllers
│   ├── styles/
│   │   ├── main.scss
│   │   └── _variables.scss   # Bootstrap overrides + Thelia palette
│   └── img/
│       ├── logo-thelia-34px.png
│       └── svgFlags/         # 256 country flags
└── src/
    ├── BackOfficeDefaultTwigBundle.php
    ├── Controller/
    │   ├── Catalog/         # Product, Category, Brand
    │   ├── Configuration/   # Language, Currency, Variable, Profile, ...
    │   ├── Customer/        # Customer, Address
    │   ├── Folder/          # Folder, Content
    │   ├── Module/          # Module, ModuleHook
    │   ├── Order/
    │   └── NewsletterController.php
    ├── DTO/                 # immutable data transfer objects
    ├── EventListener/
    │   ├── AdminContextRequestListener.php
    │   └── AdminLocaleListener.php   # syncs ?lang= with the Symfony locale
    ├── Form/                # Symfony forms (CustomerType, AddressType, ...)
    ├── Hook/Attribute/      # #[AsHook] custom attribute
    ├── Security/AdminVoter.php
    ├── Service/Admin/       # AdminFormAction, AdminAccessChecker, ...
    ├── Twig/                # BoUrl, BoData, BoHook extensions
    └── UiComponents/        # AsTwigComponent / AsLiveComponent

```

Stack
-----

[](#stack)

- **Bootstrap 5.3** with overrides aligned on the thelia.net public palette (orange `#f26041`, soft slate text).
- **Bootstrap Icons** (1.13).
- **Symfony UX** (Stimulus, TwigComponent, LiveComponent).
- **HTMX 2** for progressive enhancement.
- **Symfony forms** with the custom `bo_form_theme.html.twig` theme.

Working on the back-office
--------------------------

[](#working-on-the-back-office)

### Local dev

[](#local-dev)

```
# watch SCSS / JS rebuild
ddev exec bash -c "cd templates/backOffice/default-twig && npm run watch"

# clear cache after editing a Twig template
ddev exec bin/console cache:clear -e dev
```

### Adding a new admin domain

[](#adding-a-new-admin-domain)

The proven recipe (Folder → Content → CustomerTitle → Country → State → Newsletter → Message):

1. **Form** — `src/Form//Type.php`: `final class extends AbstractType`, options `include_id` / `include_description`.
2. **Controller** — `src/Controller//Controller.php`: `#[Route('/admin/...', name: 'admin.X.')]`. Inject `AdminFormAction`, `AdminAccessChecker`, `Environment`, `FormFactoryInterface`, `UrlGeneratorInterface`, `TokenProvider`, `TranslatorInterface`.
3. **Methods** — `list()` (GET), `create()` (POST), `updateView({id})` (GET), `processUpdate()` (POST), `delete()` (POST/GET), `updatePosition()` (POST/GET).
4. **Events** — use `$this->action->submit(form: ..., eventFactory: ..., eventName: TheliaEvents::X_CREATE)` for forms; `$this->action->tokenAction(event: ..., eventName: ...)` for single-shot actions.
5. **Templates** — `list.html.twig` (DataTable + create modal), `edit.html.twig` (form\_start + form\_end).

### ACL

[](#acl)

Resources live in `core/lib/Thelia/Core/Security/Resource/AdminResources.php`. Check with `is_granted('VIEW', 'admin.foo')` or `$this->access->check(self::RESOURCE, [], AccessManager::VIEW)`.

### Hooks (back-office)

[](#hooks-back-office)

Twig functions exposed by `BackOfficeDefaultTwigBundle\Twig\HookExtension`:

```
{{ safe_hook('main.head-css') }}        {# tolerant fallback for buggy listeners #}
{% for block in hook_block('home.block', { foo: bar }) %}
    {{ block.title }}
    {{ block.content|raw }}
{% endfor %}
{% if has_hook('product.tab') %}{% endif %}
```

Most hook names are kept iso with the legacy Smarty template. The few that were renamed are bridged to their legacy name (see [Cohabitation &amp; breaking changes](#cohabitation--breaking-changes)), so third-party modules keep working unchanged.

#### Hook contract for third-party modules

[](#hook-contract-for-third-party-modules)

The back-office emits ~200 native hooks. The **conventional extension points** a module can rely on are emitted systematically:

ConventionEmitted fromExample`.top` / `.bottom`every screen`attributes.top`, `product-edit.bottom``.table-header` / `.table-row``BoDataTable` (every list)`attributes.table-row``.create-form``BoCreateDialog` (derived from `testid`)`brand.create-form``.delete-form``BoConfirmDialog` (derived from `testid`)`brand.delete-form``.update-form`edit screens`feature.update-form``.tab` / `.tab-content`tabbed edit screens`product.tab`Hooks consumed by bundled modules (CustomerFamily, SEOne, HookAdminHome, VirtualProductControl, TheliaBlocks) are all wired. A hook code that is **not** emitted is considered deprecated for the Twig back-office — open an issue if your module needs one that is missing. The `.js` / `.edit-js` script hooks are emitted on a per-screen basis as screens are migrated.

Tests
-----

[](#tests)

- **PHPStan**: `ddev exec composer phpstan` (baseline 60 errors).
- **Coding style**: `ddev exec composer cs` / `ddev exec composer cs-diff`.
- **PHPUnit**: `ddev exec composer test`.
- **Playwright (BO Twig)**: ```
    cd tests/Playwright && BO_TEMPLATE=default-twig npx playwright test specs/backoffice
    ```

Cohabitation &amp; breaking changes
-----------------------------------

[](#cohabitation--breaking-changes)

This template runs side by side with the legacy Smarty back-office. A few names diverge from the legacy ones; here is how third-party modules are affected.

### Hooks — bridged, no change required

[](#hooks--bridged-no-change-required)

Renamed hooks are replayed under their legacy Smarty name by `Service\Hook\LegacyHookAliases`(wired into `HookExtension`), so a module listening on the old name keeps contributing. Render arguments follow the new (Twig) convention — adapt listeners that read a renamed argument.

Legacy Smarty hookTwig hook`attribute-edit-form.bottom``attribute.update-form``feature-edit-form.bottom``feature.update-form``administrator.update-form``administrator.edit-form``advanced-configuration``advanced-configuration.top`The `wysiwyg.js` hook on the hook-edit screen keeps its legacy `wysiwyg-hook-edit-js` location.

### ACL — bridged

[](#acl--bridged)

The advanced-configuration screen accepts both the new `admin.configuration.advanced` resource and the legacy `admin.cache` one, so existing profiles keep access without a data migration.

### Routes — update your module

[](#routes--update-your-module)

Renamed route names are **not** aliased. A module referencing an old name through `path()` / `url()`must update it:

Legacy route nameTwig route name`admin.sale.reset``admin.sale.reset-status``admin.configuration.order-status.*``admin.order-status.*``admin.configuration.mailing-system.*``admin.mailingSystem.*`The ACL resource for the mailing system stays `admin.configuration.mailing-system`.

License
-------

[](#license)

LGPL-3.0+ — same as Thelia core.

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance97

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

23d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2196919?v=4)[thelia](/maintainers/thelia)[@thelia](https://github.com/thelia)

---

Top Contributors

[![anoziere](https://avatars.githubusercontent.com/u/118798868?v=4)](https://github.com/anoziere "anoziere (277 commits)")

---

Tags

thelia-backoffice-templatethelia-twigthelia-bootstrap-5

### Embed Badge

![Health badge](/badges/thelia-backoffice-default-twig-template/health.svg)

```
[![Health](https://phpackages.com/badges/thelia-backoffice-default-twig-template/health.svg)](https://phpackages.com/packages/thelia-backoffice-default-twig-template)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.8M710](/packages/sylius-sylius)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.5M370](/packages/easycorp-easyadmin-bundle)[symfony/web-profiler-bundle

Provides a development tool that gives detailed information about the execution of any request

2.3k156.8M1.1k](/packages/symfony-web-profiler-bundle)[forumify/forumify-platform

132.0k12](/packages/forumify-forumify-platform)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.1k16.8k](/packages/prestashop-prestashop)[kimai/kimai

Kimai - Time Tracking

4.7k8.7k1](/packages/kimai-kimai)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
