PHPackages                             parisek/definition-kit - 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. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. parisek/definition-kit

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

parisek/definition-kit
======================

Authored per-component definition (YAML) → CMS projection generator + drift-lint. Migrates ACF field groups to a semantic definition, regenerates acf.json/block.json, and fails CI when they drift.

v0.8.2(2w ago)0790↓28.6%[7 issues](https://github.com/parisek/definition-kit/issues)GPL-3.0-or-laterPHPPHP ^8.3CI passing

Since Jul 16Pushed 2w agoCompare

[ Source](https://github.com/parisek/definition-kit)[ Packagist](https://packagist.org/packages/parisek/definition-kit)[ Docs](https://github.com/parisek/definition-kit)[ RSS](/packages/parisek-definition-kit/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (13)Versions (30)Used By (0)

parisek/definition-kit
======================

[](#parisekdefinition-kit)

[![Packagist Version](https://camo.githubusercontent.com/0f50baf6416e2ef00d73d4f939449c6e8a99dabda84e2263bc805f0f239be9f4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7061726973656b2f646566696e6974696f6e2d6b69742e737667)](https://packagist.org/packages/parisek/definition-kit)[![PHP Version](https://camo.githubusercontent.com/ed39ba68c2ec2bea7c19f3220b452ea582a0c739f8b43424274491c2ac30228c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f7061726973656b2f646566696e6974696f6e2d6b69742e737667)](https://packagist.org/packages/parisek/definition-kit)[![ACF Pro](https://camo.githubusercontent.com/82d486ae0794920f3498bd809b0ce6fb07e99821d71920aac3477cc2411b2970/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4143465f50726f2d362e382e782d626c75652e737667)](https://www.advancedcustomfields.com/pro/)[![Tests](https://github.com/parisek/definition-kit/actions/workflows/tests.yml/badge.svg)](https://github.com/parisek/definition-kit/actions/workflows/tests.yml)[![License](https://camo.githubusercontent.com/fad5fa5697e0e60c82f47a71311fb4dd77b91bc51f79367c7d1e92885aa06374/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7061726973656b2f646566696e6974696f6e2d6b69742e737667)](LICENSE)

Authored per-component **definition** (`.yaml`) → CMS **projection** generator + **drift-lint**.

A component's editable surface is authored once, as a human-readable semantic YAML definition. From it, definition-kit generates the CMS-specific implementation (WordPress ACF `acf.json` + Gutenberg `block.json` today; Drupal SDC/paragraphs planned) and a drift-lint fails CI whenever the committed projection stops matching `generate(.yaml)`. The definition is the single source of truth; `acf.json`/`block.json` become generated artifacts.

Companion to [`parisek/acf-json-schema`](https://github.com/parisek/acf-json-schema) (which *validates* ACF JSON); definition-kit *authors and generates* it.

Install
-------

[](#install)

```
composer require --dev parisek/definition-kit
```

It's a build/lint tool — a dev dependency, not a runtime one. Requires PHP 8.3+.

CLI
---

[](#cli)

Four executables land in `vendor/bin/`:

CommandDoes`fields-migrate`Bootstrap: `acf.json` (+ sibling `block.json`, + `.twig` front-comment for metadata) → authored `.yaml`.`fields-generate``.yaml` → `acf.json` + `block.json` projection.`fields-validate`Validate `.yaml` against the bundled JSON Schema.`fields-lint`Drift-lint: fail when the committed projection differs from `generate(migrate(source))`.Each accepts a single component directory or `--root=` to sweep every `component/*/` under it (`--dry-run` on `fields-migrate` writes nothing).

```
# one component
vendor/bin/fields-migrate path/to/component/service-feature

# whole tree
vendor/bin/fields-generate --root=path/to/components
vendor/bin/fields-lint --root=path/to/components
```

Wire the drift-lint into CI
---------------------------

[](#wire-the-drift-lint-into-ci)

Add a composer script and a CI step so a hand-edit to a generated `acf.json`/`block.json` (or a stale definition) fails the build:

```
{
  "scripts": {
    "lint:fields-drift": "fields-lint --root=path/to/components"
  }
}
```

The definition, briefly
-----------------------

[](#the-definition-briefly)

`.yaml` is an **authored semantic layer**, not a verbatim ACF mirror:

- **Abstract types** (`text`/`richtext`/`number`/`boolean`/`select`/`media`/`link`/`reference`/`group`/`repeater`/`date`) decouple the definition from ACF field-type names.
- Properties equal to the shared **type-defaults baseline** (`schemas/acf-defaults-baseline.yaml`) are dropped on migrate and re-added on generate — the definition holds only what's meaningful.
- Semantic annotations — `label`, `description` (editor instructions), `mcp` (AI-agent guidance), `translatable`, constraints (`maxlength`/`min`/`max`/`step`/`accept`), `visible_when`, `add_label`, `placeholder`, `options` — carry authored intent.
- A per-field / root **`wp:` escape hatch** captures genuinely CMS-specific residue verbatim (e.g. block `postTypes`/`supports`, accordion `wpml`) so the round-trip stays lossless without polluting the semantic surface.

The round-trip contract: `generate(migrate(acf.json)) == acf.json`, modulo documented ACF-export-era residuals.

Project settings — `definition-kit.yaml`
----------------------------------------

[](#project-settings--definition-kityaml)

Optional. Place it next to the components root or one directory up (the same two locations the framework-props baseline is discovered in).

```
key_style: snake   # slug (default) | snake
```

**`key_style`** decides how a component slug is spelled inside a *derived* ACF key. A component directory named `article-list` produces:

`key_style`Group keyField key`slug` (default)`group_article-list``field_article-list_title``snake``group_article_list``field_article_list_title`Both work — an ACF key is an opaque identifier and templates read fields by `name`, never by key — so this is a spelling convention, not a correctness question. It exists because projects already disagree and neither side can be migrated cheaply: **renaming a key orphans stored content** (block attributes bind `_` to the key string), so an existing spelling is frozen wherever content exists. Without the setting, a snake\_case project had to pin `key:` on every field of every multi-word component, forever — boilerplate encoding no design intent.

Three things worth knowing:

- **It governs keys only.** The Gutenberg block name (`acf/`) and the field group's `location` param stay verbatim under every style — they are the block's identity in WordPress, and folding them would point the group at a block that does not exist.
- **`slug` is the default and stays it.** Components whose committed keys match today's derivation carry no `key:` *because* they match; a changed default would spuriously pin every one of them on the next migrate.
- **Changing it on a project that already has content is not a config change.** It is a content migration — the setting decides what new keys are derived, it does not rewrite what is stored.

An unrecognised value throws and names the file. Falling back to the default would rewrite every key on the next generate, and the drift-lint would report it as your doing rather than as a typo.

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

[](#development)

```
composer install
composer check   # phpunit + phpstan (level 8)
```

Releasing
---------

[](#releasing)

See [`RELEASING.md`](RELEASING.md). Behaviour-affecting changes accumulate under `## [Unreleased]` in `CHANGELOG.md`; the **Stamp Release** GitHub Action cuts the version, tags, and publishes the GitHub Release. Packagist auto-updates via webhook.

License
-------

[](#license)

GPL-3.0-or-later.

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance97

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 66.2% 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 ~1 days

Total

26

Last Release

17d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/0f60a7484412a046d60bd8de9c5fb773cd9d59f00a1b455284fa718b786a4d93?d=identicon)[parisek](/maintainers/parisek)

---

Top Contributors

[![parisek](https://avatars.githubusercontent.com/u/10908003?v=4)](https://github.com/parisek "parisek (49 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (25 commits)")

---

Tags

wordpressyamlacfadvanced custom fieldscode-generationgutenbergdrift-lint

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/parisek-definition-kit/health.svg)

```
[![Health](https://phpackages.com/badges/parisek-definition-kit/health.svg)](https://phpackages.com/packages/parisek-definition-kit)
```

###  Alternatives

[craftcms/cms

Craft CMS

3.6k3.7M3.5k](/packages/craftcms-cms)[drupal/core

Drupal is an open source content management platform powering millions of websites and applications.

21668.5M2.0k](/packages/drupal-core)[pimcore/pimcore

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

3.8k4.0M551](/packages/pimcore-pimcore)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[friendsoftypo3/content-blocks

TYPO3 CMS Content Blocks - Content Types API | Define reusable components via YAML

103629.7k74](/packages/friendsoftypo3-content-blocks)[sulu/sulu

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

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

PHPackages © 2026

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