PHPackages                             madcoders/sylius-brand-plugin - 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. madcoders/sylius-brand-plugin

ActiveSylius-plugin

madcoders/sylius-brand-plugin
=============================

Brand plugin for Sylius 2.x - manage brands in the admin, resolve them from a product attribute, and show a brand overview, brand product listings and brand badges in the shop.

1.0.x-dev(3d ago)01↑2900%EUPL-1.2PHPPHP ^8.3CI passing

Since Aug 24Pushed 3d agoCompare

[ Source](https://github.com/mad-coders/sylius-brand-plugin)[ Packagist](https://packagist.org/packages/madcoders/sylius-brand-plugin)[ RSS](/packages/madcoders-sylius-brand-plugin/feed)WikiDiscussions 1.0 Synced today

READMEChangelog (2)Dependencies (35)Versions (3)Used By (0)

Sylius Brand Plugin
===================

[](#sylius-brand-plugin)

Brands for Sylius 2.x: a brand overview page, per-brand product listings, and brand badges on the product page and product tiles - driven by a product attribute you already have.

 [![CI](https://github.com/mad-coders/sylius-brand-plugin/actions/workflows/ci.yaml/badge.svg?branch=1.0)](https://github.com/mad-coders/sylius-brand-plugin/actions/workflows/ci.yaml) [![License](https://camo.githubusercontent.com/72a7b0ef8cb7ce31c35ea9123e069ce191c9a7da5cdc2132d8956c47e0443b7d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4555504c2d2d312e322d626c75652e737667)](LICENSE)

> **Status: 1.0 release candidate.** Functionally complete and green across the supported Sylius/Symfony/database matrix. The API - service ids, settings paths, table names - is frozen for 1.0; what it still wants is real-world use. Please report anything you hit.
>
> ```
> composer require madcoders/sylius-brand-plugin:^1.0@RC
> ```
>
>
>
> The brand hookable is reusable on your own product grids - see [Putting brands on your own product grids](#putting-brands-on-your-own-product-grids).

What it does
------------

[](#what-it-does)

- **Brands as a first-class resource.** Code, logo, translatable name, slug and description, an enabled flag and four display toggles, all managed from a Sylius admin grid.
- **Products map to brands through a product attribute.** Most catalogues already carry the brand as an attribute (from a PIM, an import or a feed). Point the plugin at that attribute and it resolves each product to a brand - no re-tagging, no second source of truth.
- **A mapping table for messy data.** `"Nike"`, `"Nike Inc."` and `"NIKE Sportswear"` can all map onto the single `nike` brand. Without a mapping the plugin assumes a 1:1 match between the attribute value and the brand code.
- **Shop pages.** A brand overview at `/brands`, a per-brand product listing at `/brands/{slug}`, a brand strip on the homepage, a brand badge on the product page and on product tiles - each one switched on per brand.
- **Reusable on your own grids.** The brand hookable is configurable, so you can attach it to any hook that has a product in context without copying a template - see [below](#putting-brands-on-your-own-product-grids). Twig helpers are provided for custom markup.
- **One feature toggle.** The whole feature can be turned off from the admin without touching configuration files or removing the bundle.

Configuration lives in the admin, through [MonsieurBiz' Settings plugin](https://github.com/monsieurbiz/SyliusSettingsPlugin).

Requirements
------------

[](#requirements)

PHP`^8.3`Sylius`^2.0` (tested against `~2.0`, `~2.1`, `~2.2`)Symfony`^6.4 || ^7.4`Settings`monsieurbiz/sylius-settings-plugin ^2.0`DatabaseMySQL 8.4 or MariaDB 11.4. **PostgreSQL is not supported** - see below.> **PostgreSQL.** This plugin's own migration is platform-neutral, but `monsieurbiz/sylius-settings-plugin` - a hard dependency - creates its table with raw MySQL DDL and no platform guard, so migrations fail on PostgreSQL before this plugin is reached. Nothing here can work around that; it has to be fixed upstream.

Installation
------------

[](#installation)

```
composer require madcoders/sylius-brand-plugin
```

Then follow [`docs/INSTALLATION.md`](docs/INSTALLATION.md) - the plugin needs its bundle registered, its configuration and routes imported, its entities declared, and the `brand` extension applied to your `Product`.

How a product finds its brand
-----------------------------

[](#how-a-product-finds-its-brand)

```
product attribute value        mapping (optional)        brand
"Nike Inc."          ───────►  nike            ───────►  Brand(code: "nike")
"NIKE Sportswear"    ───────►  nike            ───────►
"adidas"             ───────►  (no entry: 1:1) ───────►  Brand(code: "adidas")

```

The attribute stays the source of truth, but the resolved brand is **denormalised onto `sylius_product.brand_id`** so listings, filters and sorting are ordinary indexed queries. The column is kept in sync whenever a product is saved through the resource layer, and `bin/console madcoders:brand:resync-products` rebuilds it in bulk after an import or a change to the mapping. The reasoning is in [`docs/adr-log/0004-brand-resolution-from-a-product-attribute.md`](docs/adr-log/0004-brand-resolution-from-a-product-attribute.md).

Configuration
-------------

[](#configuration)

Admin → Settings → **Brands**:

SettingScopeMeaning`enabled`per channelDisplay toggle. When off, the shop routes 404 and every brand hook renders nothing. Products still resolve to their brand, so the data stays correct underneath.`brand_attribute`globalCode of the product attribute carrying the brand.`brand_mapping`globalAttribute value → brand code pairs. Empty means a 1:1 match.The last two are global on purpose: a product has one `brand_id`, so a per-channel attribute would have no single right answer. They are only offered on the "all channels" tab, and a channel-scoped value left behind by an older install is ignored.

Putting brands on your own product grids
----------------------------------------

[](#putting-brands-on-your-own-product-grids)

The plugin ships the brand on three surfaces out of the box - the homepage strip, the product page and Sylius' product card. Anywhere else - a custom listing, search results, a cross-sell carousel, your own theme's card - you attach it yourself. There is nothing to copy: the same template the plugin uses is configurable, so you point a hook at it and pass configuration.

```
# config/packages/madcoders_sylius_brand.yaml
sylius_twig_hooks:
    hooks:
        # any hook that has a product in its context
        'sylius_shop.product.index.content.body.main.products':
            madcoders_brand:
                template: '@MadcodersSyliusBrandPlugin/shop/product/brand.html.twig'
                configuration:
                    surface: product_tile
                priority: 50
```

configurationdefaultwhat it does`context_key``product`where the product lives in the hook's context, if it isn't called `product``surface``product_tile`which display toggle to respect: `homepage`, `product_page`, `product_tile`, `brand_overview`, or `any` to ignore the toggles`show_logo``false`render the logo before the name`link``true`link to the brand page (falls back to plain text when that brand's page is not reachable)`label``false`prefix with a translated "Brand:" label`class`muted small lineCSS classes for the wrapper`link_class``fw-semibold text-reset`CSS classes for the name itselfThe template renders **nothing** when the feature is off, the product has no brand, the brand is disabled, or that brand's toggle for the chosen surface is off - so you never have to guard the hook yourself.

### Twig helpers

[](#twig-helpers)

If you want your own markup, use the helpers directly. These are public API.

functionreturns`madcoders_brand_for(product, surface = 'product_tile')`the brand to show for that product on that surface, or `null``madcoders_brands_enabled()`whether the feature is on for the current channel`madcoders_homepage_brands(limit = 12)`brands flagged for the homepage, ordered by position```
{% set brand = madcoders_brand_for(product, 'any') %}
{% if brand is not null %}
    {{ brand.name }}
{% endif %}
```

**Use `madcoders_brand_for()` rather than reading `product.brand`.** It applies the feature toggle, the brand's enabled flag and the surface toggle for you - and, less obviously, it answers every row of a listing from a single query. Reading `product.brand` directly initialises a Doctrine proxy per row and loads the brand *and* its translation, which on a 12-product grid is up to 24 extra queries.

### Admin helpers

[](#admin-helpers)

functionreturns`madcoders_brand_product_count(brand)`how many products point at that brand`madcoders_brand_diagnostics(product)`the resolution chain: configured attribute, the product's value for it, what it maps to, and the resulting brandDevelopment
-----------

[](#development)

```
make setup          # deps + docker (MySQL on 3307) + assets + database
make install-hooks  # pre-commit quality gate and commit template
make verify         # fast gate: composer validate + phpstan + ecs + unit tests
make test           # phpunit + behat
make help           # every available target
```

Contributor guide: [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md). Working on this with an AI agent? Start from [`AGENTS.md`](AGENTS.md).

The primary branch is **`1.0`** - this repository has no `main` or `master`, following the Sylius version-branch model.

Credits
-------

[](#credits)

Built and maintained by [Madcoders](https://www.madcoders.co).

License
-------

[](#license)

[EUPL-1.2](LICENSE).

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance99

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity35

Early-stage or recently created project

 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

Every ~0 days

Total

3

Last Release

3d ago

### Community

Maintainers

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

---

Top Contributors

[![plewandowski](https://avatars.githubusercontent.com/u/2155836?v=4)](https://github.com/plewandowski "plewandowski (8 commits)")

---

Tags

syliussylius-pluginbrandmanufacturer

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Type Coverage Yes

### Embed Badge

![Health badge](/badges/madcoders-sylius-brand-plugin/health.svg)

```
[![Health](https://phpackages.com/badges/madcoders-sylius-brand-plugin/health.svg)](https://phpackages.com/packages/madcoders-sylius-brand-plugin)
```

###  Alternatives

[sylius/paypal-plugin

PayPal plugin for Sylius.

461.5M7](/packages/sylius-paypal-plugin)[sylius/refund-plugin

Plugin provides basic refunds functionality for Sylius application.

721.8M22](/packages/sylius-refund-plugin)[sylius/invoicing-plugin

Invoicing plugin for Sylius.

911.1M2](/packages/sylius-invoicing-plugin)[webgriffe/sylius-akeneo-plugin

Plugin allowing to import products data from Akeneo PIM to your Sylius store.

2481.7k](/packages/webgriffe-sylius-akeneo-plugin)[odiseoteam/sylius-vendor-plugin

Vendor plugin for Sylius. Add Vendor (Brand) to your products

6269.0k1](/packages/odiseoteam-sylius-vendor-plugin)[markocupic/calendar-event-booking-bundle

Contao Calendar Event Booking Bundle

125.3k1](/packages/markocupic-calendar-event-booking-bundle)

PHPackages © 2026

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