wedevelopnl / silverstripe-grid
Grid-based content block system for SilverStripe
Package info
github.com/wedevelopnl/silverstripe-grid
Type:silverstripe-vendormodule
pkg:composer/wedevelopnl/silverstripe-grid
Requires
- php: ^8.3
- silverstripe/admin: ^3.0
- silverstripe/cms: ^6.0
- silverstripe/framework: ^6.0
- silverstripe/vendor-plugin: ^3.0
- silverstripe/versioned: ^3.0
- unclecheese/display-logic: ^4.0
- wedevelopnl/silverstripe-media-field: ^6.0
Requires (Dev)
- cambis/silverstan: ^2.1
- infection/infection: ^0.32
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpunit/phpunit: ^11.3
- tomasvotruba/type-coverage: ^2.0
- wernerkrauss/silverstripe-rector: ^1.0
Suggests
- silverstripe/reports: Enables the Grid Elements report in CMS → Reports
- tractorcow/silverstripe-fluent: Required for multi-locale support with isolated element records per locale
Conflicts
This package is auto-updated.
Last update: 2026-04-21 00:34:45 UTC
README
Introduction
A grid-based content block system for SilverStripe CMS, enabling structured Section → Row → Column layouts with configurable CSS framework adapters (Bootstrap, Tailwind, Bulma).
Requirements
- PHP ^8.3
- silverstripe/framework ^6.0
- silverstripe/cms ^6.0
- silverstripe/admin ^3.0
- silverstripe/versioned ^3.0
- silverstripe/vendor-plugin ^3.0
- Node >=24 (for frontend build)
Optional:
silverstripe/reportsenables the Grid Elements report in CMS Reports.
Conflict: This module conflicts with
dnadesign/silverstripe-elementaland replaces its functionality.
Installation
composer require wedevelopnl/silverstripe-grid
Usage
The module ships GridPageExtension which adds a grid editor to page types. Apply it to the page types that need grid editing in your project's YAML config:
# app/_config/grid.yml Page: extensions: Grid: WeDevelop\Grid\Extensions\GridPageExtension
By default each page with the extension uses the grid editor and the standard Content HTMLEditorField is removed from the CMS form.
Page templates
Use $UseGrid in page templates to render grid sections with a fallback to $Content:
<% if $UseGrid %>
<% loop $Sections %>$Me<% end_loop %>
<% else %>
$Content
<% end_if %>
This pattern works whether or not the editor toggle is enabled — $UseGrid stays true when the toggle is off, so the <% else %> branch simply never runs. Projects that do not use the toggle can simplify to <% loop $Sections %>$Me<% end_loop %>.
Enabling the editor toggle
To let CMS users switch between the grid editor and the Content HTMLEditorField on a per-page basis, opt in on the page type:
App\Pages\ArticlePage: enable_editor_toggle: true
With the toggle enabled, a "Use grid on this page" checkbox appears in the CMS form and the editor shown reflects the stored UseGrid value.
Configuring the default
The grid is enabled by default on new pages. Override this per page type in YAML:
App\Pages\ArticlePage: use_grid_by_default: true # default — grid editor on new pages App\Pages\JobPage: use_grid_by_default: false # content editor on new pages (only effective when enable_editor_toggle: true)
Development
Prerequisites
- Docker Desktop (or compatible)
- Node >=24 (see
.nvmrc) - Composer
Quick start
composer install make up # Provisions Docker services, prints CMS URL when ready npm install npm run build # Vite production build
make up provisions a full SilverStripe 6 dev environment (FrankenPHP 8.3 + MySQL 8 + Caddy). It auto-generates .docker/.env with deterministic ports hashed from the directory name, builds the Docker images, runs dev/build, and prints the CMS URL once the app is healthy.
First boot takes ~1–2 minutes while Composer installs vendors inside the container and
dev/buildruns. Wait formake upto print the URL.
What you get
- CMS: the URL printed by
make up(typicallyhttps://localhost:80xx— the exact port lives in.docker/.envasWEB_PORT) - Admin:
<that URL>/admin— loginadmin/admin - Database: MySQL 8 exposed on
127.0.0.1:<DB_PORT>(also in.docker/.env); databasesilverstripe, usersilverstripe, passwordsilverstripe - Optional multi-language profile:
make ensure-up-fluentboots a second app container with Fluent installed against databasesilverstripe_fluent
Day-to-day
| Command | Description |
|---|---|
npm run dev |
Vite watch mode — rebuilds the client bundle on change |
make dev-build |
Run dev/build flush=1 inside the container |
make flush |
Clear SilverStripe cache |
make up |
Start (or resume) services |
make down |
Stop services (keeps DB volume) |
make destroy |
Stop services and drop volumes (full reset — wipes DB) |
Port conflict after renaming or copying the worktree? Run
rm .docker/.env && make upto regenerate a fresh port set.View container logs:
docker compose -f .docker/compose.yml logs -f app
Dev fixture endpoint
When running in the dev environment, the module exposes endpoints to load the same YAML fixtures used by E2E tests into the CMS for manual exploration:
| Method | URL | Purpose |
|---|---|---|
POST |
/dev/grid-fixtures/load?fixture=<Name> |
Load tests/E2E/Fixture/<Name>.yml |
POST |
/dev/grid-fixtures/reset |
Remove all fixture-created pages |
See src/Dev/FixtureController.php. The endpoints are gated by Director::isDev() and refuse to run outside the dev environment.
Testing
| Command | Description |
|---|---|
make test |
Run all tests (PHP unit + integration + functional + JS) |
make test-unit |
PHP unit tests only (no database/framework) |
make test-integration |
PHP integration tests (full SilverStripe env) |
make test-functional |
PHP functional/HTTP controller tests |
make test-fluent |
Run integration + fluent tests in the Fluent environment |
npm run test |
JavaScript tests (Vitest) |
npm run test:watch |
Vitest in watch mode |
make test-e2e |
Playwright E2E tests (auto-starts Docker if needed) |
make test-e2e-ui |
Playwright E2E tests with the interactive UI |
Coverage & mutation testing
| Command | Description |
|---|---|
make coverage |
Merged PHP coverage (HTML + Clover, written to coverage/) |
make coverage-unit |
PHP unit test coverage only |
make coverage-integration |
PHP integration test coverage only |
make coverage-functional |
PHP functional test coverage only |
make coverage-js |
JavaScript test coverage (Vitest) |
make coverage-check |
Fail if combined PHP coverage < 90% |
make mutate |
PHP mutation testing (Infection) |
make mutate-js |
JavaScript mutation testing (Stryker) |
Quality
| Command | Description |
|---|---|
make analyse |
PHPStan static analysis (level max + Silverstan, 100% type coverage) |
make rector-dry |
Preview Rector refactorings |
make rector |
Apply Rector refactorings |
npm run lint |
Biome (JS/TS) + Stylelint (SCSS) |
npm run format |
Biome format --write (JS/TS) |
npm run typecheck |
TypeScript type checking |
make qa |
Full QA suite — PHPStan + coverage + lint + typecheck + JS tests (parallel) |
make qa-js |
JS-only QA — lint + typecheck + Vitest (parallel) |
Architecture
See the architecture documentation for detailed design documents:
- Backend Architecture — data model, API layer, service design, validation, grid adapters
- Drag and Drop — frontend dnd-kit integration and backend reorder pipeline
Migrating from Elemental / ElementalGrid
Projects upgrading from WeDevelop ElementalGrid (SS5) or plain dnadesign/silverstripe-elemental can use the built-in migration tasks. See Migrating from Elemental / ElementalGrid for the step-by-step guide, strategy diagrams, and extension hooks.
Changelog
See CHANGELOG.md for release history.
License
See License
Maintainers
Development and contribution
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.