PHPackages                             scalecommerce/videooptimizer-sulu - 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. [Image &amp; Media](/categories/media)
4. /
5. scalecommerce/videooptimizer-sulu

ActiveSulu-bundle[Image &amp; Media](/categories/media)

scalecommerce/videooptimizer-sulu
=================================

Integrates ScaleCommerce VideoOptimizer into the Sulu 3.0 admin: pick, upload and manage CDN-delivered videos without a separate VideoOptimizer login.

v1.5.2(1mo ago)036↓66.7%MITPHPPHP &gt;=8.2CI passing

Since Jul 17Pushed 1mo agoCompare

[ Source](https://github.com/ScaleCommerce/videooptimizer-sulu)[ Packagist](https://packagist.org/packages/scalecommerce/videooptimizer-sulu)[ Docs](https://videooptimizer.eu/)[ RSS](/packages/scalecommerce-videooptimizer-sulu/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (28)Versions (15)Used By (0)

🎬 VideoOptimizer for Sulu
=========================

[](#-videooptimizer-for-sulu)

**Pick, upload and manage CDN-delivered videos — right inside the Sulu admin.**

[![CI](https://github.com/ScaleCommerce/videooptimizer-sulu/actions/workflows/ci.yml/badge.svg)](https://github.com/ScaleCommerce/videooptimizer-sulu/actions/workflows/ci.yml)[![Latest Version](https://camo.githubusercontent.com/ef8e821cd8912db18dede3870c4a52372bf3668c82b8cb777c19f4874ef68635/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7363616c65636f6d6d657263652f766964656f6f7074696d697a65722d73756c752e737667)](https://packagist.org/packages/scalecommerce/videooptimizer-sulu)[![PHP](https://camo.githubusercontent.com/f667e37b6a3d8713b5fa97311d6d8a68f0cb939fe26e313a0ac007abae497eb5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d254532253839254135253230382e322d3737376262342e7376673f6c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://www.php.net/)[![Sulu](https://camo.githubusercontent.com/2be5fa89aac182dfd8a6020d853c0d63c303d055a7a0ac19e89c00ed9e48c9ae/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53756c752d332e302d3532623165382e737667)](https://sulu.io/)[![License: MIT](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)

[Product](https://videooptimizer.eu/) · [API &amp; docs](https://api.videooptimizer.eu/) · [Report a bug](https://github.com/ScaleCommerce/videooptimizer-sulu/issues)

---

Give your editorial team adaptive, CDN-streamed video without ever leaving Sulu. This bundle adds a **`video_optimizer` content field**, a **selection &amp; upload dialog**, **library management**, and four **ready-to-use content blocks** to the Sulu 3.0 admin — while the organization's API token stays on the server, encrypted at rest. Editors just pick a video and hit publish.

> Built and maintained by **[ScaleCommerce GmbH](https://scale.sc/)**, the team behind [VideoOptimizer](https://videooptimizer.eu/). Part of the `scalecommerce/videooptimizer-`plugin family.

[![Videos view in the Sulu admin — libraries as folder tiles and videos as a thumbnail grid](https://raw.githubusercontent.com/ScaleCommerce/videooptimizer-sulu/main/docs/screenshots/videos-grid.jpg)](https://raw.githubusercontent.com/ScaleCommerce/videooptimizer-sulu/main/docs/screenshots/videos-grid.jpg)

Browse videos right inside Sulu — libraries as folder tiles, videos as a thumbnail grid. *(Thumbnails and titles blurred/renamed for the demo.)*

✨ Highlights
------------

[](#-highlights)

- 🎥 **`video_optimizer` field type** — drop it into any page, snippet or article template.
- 🗂️ **Media-style admin** — browse libraries as folder tiles, videos as a thumbnail grid, with title search and a "ready only" filter.
- ⬆️ **Big-file uploads** — presigned multipart upload straight from the browser to storage, with live processing status. Or ingest from a remote URL.
- 🖼️ **Full asset control** — pick auto-generated thumbnails, upload a custom poster (from disk or the Sulu media library), edit titles and player options, delete videos.
- 🧱 **Four content blocks** — `media split`, `background hero`, `spotlight` and a `video grid`, with facade / lightbox / direct presentation modes.
- 🔐 **Token never touches the browser** — stored server-side, encrypted with libsodium; all API calls are proxied.
- ⚡ **Core-Web-Vitals friendly** — lazy poster loading, `IntersectionObserver`-gated players, `above-the-fold` priority hint, and a single lightweight embed per video.
- 🌍 **Global CDN delivery** — adaptive-bitrate HLS, edge-cached worldwide, resilient under traffic spikes.

**Why deliver video through VideoOptimizer's CDN?**Compared to serving `.mp4` files from your own origin:

- **Fast, global playback** — cached on edge servers near each viewer, so streams start quickly with minimal buffering, worldwide.
- **Adaptive bitrate (HLS)** — every upload is transcoded into a resolution ladder; the player serves the right quality for the connection and device.
- **Scales under load** — the CDN absorbs traffic spikes, so campaigns or viral pages never overload your CMS origin, and you avoid origin bandwidth costs on every view.
- **Resilient** — multiple edge locations mean high availability; one node or origin outage doesn't break playback.
- **Effortless for editors** — upload once and posters, thumbnails and renditions are generated automatically; embedding is a single lightweight iframe that keeps heavy media off the page's critical path (better Core Web Vitals &amp; SEO).

[![Library cockpit with the encoding ladder as codec and resolution chips](https://raw.githubusercontent.com/ScaleCommerce/videooptimizer-sulu/main/docs/screenshots/library-cockpit.jpg)](https://raw.githubusercontent.com/ScaleCommerce/videooptimizer-sulu/main/docs/screenshots/library-cockpit.jpg)

Library cockpit: manage the encoding ladder as codec/resolution chips, with paid add-ons clearly flagged.

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

[](#requirements)

PHP≥ 8.2 with `ext-sodium`Sulu^3.0Symfony^6.4 || ^7.0A VideoOptimizer accountgrab an API token at [videooptimizer.eu](https://videooptimizer.eu/) → Account → API Tokens🚀 Quick start
-------------

[](#-quick-start)

**TL;DR** (with Symfony Flex, which registers the bundle for you):

```
composer require scalecommerce/videooptimizer-sulu
bin/adminconsole scale:videooptimizer:install        # routes + admin JS wiring + settings table
bin/adminconsole cache:clear                         # so the new routes are served
(cd assets/admin && npm install && npm run build)    # build the admin frontend
```

Then open **Settings → VideoOptimizer** in the admin and paste your API token. That's it. The detailed steps follow.

---

**1. Install**

```
composer require scalecommerce/videooptimizer-sulu
```

**2. Register the bundle.** Symfony Flex does this automatically on `composer require`. Only if you run without Flex, add it to `config/bundles.php` yourself:

```
Scale\VideoOptimizerBundle\ScaleVideoOptimizerBundle::class => ['all' => true],
```

**3. Run the installer.** The bundle ships a console command that does the steps a plain `composer require` cannot — it imports the admin API routes, wires its (pre-compiled) admin JS into `assets/admin`, and creates the settings table:

```
bin/adminconsole scale:videooptimizer:install
bin/adminconsole cache:clear                 # so the freshly imported routes are served
```

The installer is idempotent (safe to re-run) and only fills in what's missing; add `--dry-run` to preview. The `cache:clear` is a separate command on purpose — clearing the cache from inside the running installer would delete the cache it is still using.

What it does — or set it up by hand instead- **Admin API routes** — creates `config/routes/scale_videooptimizer_admin.yaml`:

    ```
    scale_videooptimizer_api:
        resource: "@ScaleVideoOptimizerBundle/Resources/config/routing_admin.yaml"
        prefix: /admin/api
    ```
- **Admin JS wiring** — adds the dependency to `assets/admin/package.json` and imports it in `assets/admin/app.js` (the JS ships pre-compiled, so no `webpack.config.js` change is needed):

    ```
    "videooptimizer-sulu": "file:../../vendor/scalecommerce/videooptimizer-sulu/src/Resources/js"
    ```

    ```
    import 'videooptimizer-sulu';
    ```
- **Settings table** — creates `vo_settings` from the `VideoOptimizerSettings` entity. If your team tracks schema through migrations, run `bin/adminconsole doctrine:migrations:diff` then `:migrate`instead.

**4. Build the admin frontend:**

```
cd assets/admin && npm install && npm run build
```

This is Sulu's standard admin build — the admin is a webpack app compiled in your project, so it's a plain `npm run build` (use `npm run watch` while developing). `bin/console sulu:build` is unrelated — it builds the data layer (database/content), not the admin JS.

> **Do not use `sulu:admin:update-build` to install this bundle.** That command syncs `assets/admin`with the official Sulu skeleton (it either downloads the pre-built skeleton assets — which do *not*include this bundle's JS — or offers to overwrite your `assets/admin` files). Its default for `package.json` is to overwrite, which would strip the `videooptimizer-sulu` dependency that `scale:videooptimizer:install` added. Always build the admin JS with `cd assets/admin && npm install && npm run build`.

> After updating the bundle, hard-reload the admin (the build hash changes) so the browser doesn't run the stale bundle.

**5. Add your token.** In the Sulu admin, open **Settings → VideoOptimizer** and paste your `vp_…` API token. It's stored encrypted and never returned to the browser. Done — editors can now pick videos. 🎉

[![VideoOptimizer settings page with the write-only, encrypted API token field](https://raw.githubusercontent.com/ScaleCommerce/videooptimizer-sulu/main/docs/screenshots/settings.jpg)](https://raw.githubusercontent.com/ScaleCommerce/videooptimizer-sulu/main/docs/screenshots/settings.jpg)

One organization-wide token, stored encrypted server-side — the write-only field never echoes it back.

**6. See the blocks in action (optional).** Run `bin/console assets:install`, then create a page with the **"VideoOptimizer showcase"** template (shipped by the bundle, no setup) — it already has all four content blocks wired up and renders them on a self-contained page. See [Content blocks](#-content-blocks).

> **Optional:** a [Symfony Flex recipe](#optional-zero-config-install-with-symfony-flex) is included that can register the bundle (step 2) automatically.

Optional: zero-config install with Symfony Flex
-----------------------------------------------

[](#optional-zero-config-install-with-symfony-flex)

A [Symfony Flex](https://symfony.com/doc/current/setup/flex.html) recipe is included in the repository under [`.recipe/`](.recipe/). It is **not published** to [`symfony/recipes-contrib`](https://github.com/symfony/recipes-contrib) — the steps above are the supported path. If you want a Flex-enabled project to register the bundle in `config/bundles.php` and import the admin routes on `composer require`, you can submit the recipe yourself; see [`.recipe/README.md`](.recipe/README.md). The `scale:videooptimizer:install` command still handles the admin JS wiring and the settings table.

Troubleshooting
---------------

[](#troubleshooting)

SymptomCauseFixThe **VideoOptimizer navigation appears but clicking does nothing** / no view opensThe admin JS was not wired into the buildRun `bin/adminconsole scale:videooptimizer:install`, then `cd assets/admin && npm run build`, then hard-reload the adminViews open but show **"…admin API is not reachable (404)"**The proxy routes are not imported, or the cache is staleRun `bin/adminconsole scale:videooptimizer:install` (imports the routes) then `bin/adminconsole cache:clear`A view says **"No VideoOptimizer token is configured yet"**No API token storedOpen **Settings → VideoOptimizer** and save your `vp_…` tokenSettings shows an error but the form is still usableExpected on a fresh/misconfigured install — the form never blocks so you can always enter the tokenEnter the token and save; fix routes if the error mentions 404Upgrading
---------

[](#upgrading)

Because this package follows semantic versioning, the `^1.0` constraint written by `composer require`receives every 1.x feature and fix automatically — updating is a one-liner plus a rebuild:

```
# 1. Pull the latest 1.x release
composer update scalecommerce/videooptimizer-sulu

# 2. Republish the bundle's frontend assets (new/changed CSS/JS land in public/)
bin/console assets:install

# 3. Rebuild the compiled admin UI so new views/labels ship
cd assets/admin && npm run build

# 4. Clear the caches (admin translations + website container/routes)
bin/adminconsole cache:clear
bin/console cache:clear
```

Then **hard-reload the admin** in your browser (the build hash changes, so a normal reload may serve the old bundle). Skipping step 2 leaves stale frontend assets in `public/`; skipping step 3 or 4 makes new admin labels show their raw translation key.

> **Check the [CHANGELOG](CHANGELOG.md)** before upgrading across a minor version — it lists every notable change, and any manual follow-up (e.g. a new config option or a migration) is called out there. To pin a specific version instead of tracking `^1.0`, set the exact constraint in your `composer.json`(e.g. `"scalecommerce/videooptimizer-sulu": "1.5.2"`).

Configuration (optional)
------------------------

[](#configuration-optional)

The API and embed base URLs default to VideoOptimizer's production hosts. Override them (e.g. to point at a staging API) under the `scale_video_optimizer` key:

```
# config/packages/scale_video_optimizer.yaml
scale_video_optimizer:
    api_base_url: 'https://api.videooptimizer.eu/api/v1'
    embed_base_url: 'https://videooptimizer.eu'
    auto_inject_assets: true   # default; set false to load the frontend CSS/JS manually (see below)
```

### Frontend assets load automatically

[](#frontend-assets-load-automatically)

Once the bundle assets are published (`bin/console assets:install`), the frontend CSS/JS load automatically on any page that renders a VideoOptimizer surface — **no template edit required**. A `kernel.response` listener injects the stylesheet before `` and the deferred script before ``, only when the page actually contains a VideoOptimizer block or embed, and never twice.

Set `auto_inject_assets: false` to opt out (e.g. strict CSP or ESI setups where you need full control over the ``), then load the assets yourself from a page view's `{% block stylesheets %}`:

```
{% block stylesheets %}{{ parent() }}
    {{ include('@ScaleVideoOptimizer/partials/assets.html.twig', { blocks: content.content }) }}
{% endblock %}
```

Uninstalling
------------

[](#uninstalling)

```
bin/adminconsole scale:videooptimizer:uninstall   # add --force to skip the drop-table confirmation
```

Removes the route import and admin-JS wiring and drops the `vo_settings` table (which holds the encrypted token, so it asks for confirmation first; `--dry-run` previews). Afterwards remove the bundle from `config/bundles.php` and run `composer remove scalecommerce/videooptimizer-sulu`.

Usage
-----

[](#usage)

Add the field to a template (`config/templates/pages/*.xml`):

```

        Video

```

Render the CDN player in Twig:

```
{% if content.video and content.video.uuid %}
    {{ video_optimizer_embed(content.video, content.title) }}
{% endif %}
```

The stored value is `{ uuid, libraryId, title, posterUrl }`; the embed points at `https://videooptimizer.eu/embed/`.

🧱 Content blocks
----------------

[](#-content-blocks)

Beyond the single field, the bundle ships four ready-to-use **Sulu content blocks** for richer video-driven pages — each delivered as an XML template fragment plus a matching Twig view, so there's nothing to copy-paste.

Block typePurposeTwig view`vo_media_split`Video beside text, `side` left/right`blocks/vo_media_split.html.twig``vo_background_hero`Full-bleed native `` HLS background`blocks/vo_background_hero.html.twig``vo_spotlight`Poster that opens the video in a lightbox`blocks/vo_spotlight.html.twig``vo_video_grid`Repeatable grid of videos, each opening a lightbox`blocks/vo_video_grid.html.twig`### Fastest path: the shipped showcase template

[](#fastest-path-the-shipped-showcase-template)

The bundle ships a ready-to-use **"VideoOptimizer showcase"** page template with all four blocks already wired in and a self-contained view. It is **registered automatically** — nothing to copy. After `bin/console assets:install`, pick it when creating a page, add blocks, publish, and you're done.

Use this to explore the blocks immediately, or as a reference for wiring them into your own templates (below).

### Wiring blocks into your own templates

[](#wiring-blocks-into-your-own-templates)

Prefer your own theme/template? The bundle registers its block directory globally, so all four blocks are available as **referenceable block types** in every page and snippet template — no XInclude, no file paths to juggle. Add one `` line per block wherever you define a block property:

```

        ...

```

The `ref` keys (`vo_media_split`, `vo_background_hero`, `vo_spotlight`, `vo_video_grid`) match the blocks' `` values. In the admin block picker they show up prefixed with `[VO]` so editors can tell they come from this bundle. Because the block types are registered globally (via the bundle's DI `prepend()`), there is nothing to copy and the same `ref` works in any template.

> Want the blocks available in **all** templates? Sulu has no single switch for that — each template lists its own block types. Add the four `` lines to every page/snippet template that should offer the VideoOptimizer blocks.

**Registering assets &amp; Twig dispatch**Publish the bundle's CSS/JS like any other bundle asset:

```
bin/console assets:install
```

**That's it — the assets load automatically.** The bundle's `AssetInjectionListener` injects the stylesheet before `` and the deferred script before `` on any page that renders a VideoOptimizer surface, and never twice. You don't hardcode asset paths or include a partial.

To opt out (`scale_video_optimizer.auto_inject_assets: false`), load them yourself from a page view's `{% block stylesheets %}` — the bundle still owns the paths, so you never hardcode them:

```
{% block stylesheets %}{{ parent() }}
    {{ include('@ScaleVideoOptimizer/partials/assets.html.twig', { blocks: content.content }) }}
{% endblock %}
```

Omit the `blocks` argument to always emit the tags (e.g. on a template guaranteed to show the blocks).

Then dispatch the blocks to the bundle's views. Wrap them in a container with `data-vo-base` so `vo-blocks.js` can locate the bundled `hls.light.min.js` (it otherwise falls back to `/bundles/scalevideooptimizer/`):

```

    {% for block in content.content %}
        {% include '@ScaleVideoOptimizer/blocks/' ~ block.type ~ '.html.twig' with { block: block } only %}
    {% endfor %}

```

**Theming**`vo-blocks.css` scopes all block styling under `.vo-blocks` via CSS custom properties, so a host theme can restyle everything without touching the bundle's CSS:

PropertyPurpose`--vo-accent`Accent color (links, controls)`--vo-text`Primary text color`--vo-muted`Secondary/muted text color`--vo-bg`Block background color`--vo-surface`Card/surface background color`--vo-radius`Corner radius for cards/media`--vo-gap`Vertical rhythm between sections`--vo-max-width`Max content width`--vo-overlay`Gradient overlay on media/hero`--vo-shadow`Drop shadow for cards/media`--vo-font`Font family (defaults to `inherit`)🔐 How it works
--------------

[](#-how-it-works)

The API token is stored **once**, organization-wide, encrypted with libsodium's `secretbox`. Editors never see or handle it. Every call to VideoOptimizer is proxied through the bundle's admin controllers so the token stays server-side — the browser only ever receives short-lived **presigned URLs** for the direct-to-storage part uploads. List endpoints are cursor-paginated and resolved server-side into a flat array; rate limits (`429`) are retried once, honoring `Retry-After`.

Development
-----------

[](#development)

```
composer install
vendor/bin/phpunit
```

**Working on the admin UI**The admin UI source lives under `src/Resources/js` (React 17 + MobX). It is shipped **pre-compiled**to `src/Resources/js/dist` (via Babel, mirroring Sulu's own config) so consumers don't need to widen their webpack babel config. **After editing the source, rebuild the compiled output and commit it:**

```
cd src/Resources/js && npm install && npm run build   # regenerates dist/
```

CI verifies `dist/` is in sync with the source, so a stale build fails the pipeline. State mutations in admin field/view handlers must be wrapped in MobX `@action` (the Sulu production build enforces actions).

Contributing
------------

[](#contributing)

Issues and pull requests are welcome at [github.com/ScaleCommerce/videooptimizer-sulu](https://github.com/ScaleCommerce/videooptimizer-sulu). Please run `vendor/bin/phpunit` before opening a PR.

License
-------

[](#license)

Released under the [MIT License](LICENSE), © ScaleCommerce GmbH.

Ships [hls.js](https://github.com/video-dev/hls.js) (Apache License 2.0) for HLS playback in the content blocks — see [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md).

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance92

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

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

14

Last Release

39d ago

Major Versions

v0.3.0 → v1.0.02026-07-17

### Community

Maintainers

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

---

Tags

videocmscdnsuluhlssulu-bundlevideooptimizer

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/scalecommerce-videooptimizer-sulu/health.svg)

```
[![Health](https://phpackages.com/badges/scalecommerce-videooptimizer-sulu/health.svg)](https://phpackages.com/packages/scalecommerce-videooptimizer-sulu)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.7M445](/packages/easycorp-easyadmin-bundle)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.4k1.4M241](/packages/sulu-sulu)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

605.9M717](/packages/shopware-core)[contao/core-bundle

Contao Open Source CMS

1231.7M3.2k](/packages/contao-core-bundle)[pimcore/pimcore

Content &amp; Product Management Framework (CMS/PIM/E-Commerce)

3.8k4.0M552](/packages/pimcore-pimcore)[open-dxp/opendxp

Content &amp; Product Management Framework (CMS/PIM)

9830.9k80](/packages/open-dxp-opendxp)

PHPackages © 2026

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