Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Fancy Cms Laravel Package

particle-academy/fancy-cms

A Laravel CMS package from Particle Academy offering content management features for Fancy-based projects. Early-stage with minimal adoption and limited documentation, so review the source and test thoroughly before using it in production.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is the PHP-side implementation of the fancy-cms 0.8 page-operation spine. The mental model is simple: a PageDoc holds a page tree, a PageOp describes one edit, Reducer::reduce produces the next document, PageJson handles wire/storage encoding, and PageRenderer emits HTML/CSS.

  1. Install and confirm you have the 0.4 API surface (13 PageOp variants, Reducer, PageJson, PageDoc, PageRenderer).
  2. Look first at the PageOp variant list and Reducer::reduce — these are the contract shared with fancy-cms-ui. Anything you accept from the browser should arrive as one of these variants.
  3. Decode stored/incoming payloads with PageJson, never json_decode directly. Empty-object vs. empty-list distinctions and numeric map keys matter here.
  4. First use case: load a doc with PageJson, apply one op inside a controller action, validate implicitly through PageDoc::apply, persist the encoded result, and render.
$doc = PageJson::decode($storedJson);           // preserves [] vs {} semantics
$op  = PageOp::fromWire($request->validated()); // one of 13 variants

$next = PageDoc::apply($doc, $op);              // validates before + after

$doc->store(PageJson::encode($next));

Once that loop works, add PageRenderer and you have an end-to-end server-rendered CMS page.

Implementation Patterns

Persist the doc, not the ops. PageDoc::apply is the storage boundary — it validates the doc before and after an edit and refuses semantic no-ops. Treat the reducer as the only mutator and keep the encoded PageDoc as your source of truth. Optionally log the ops for audit/undo; replaying them is only safe if your stored docs were produced by the same reducer version.

Use Reducer::reduce for previews, dry runs and undo. Because it's pure and reduceAll exists, you can compute a speculative document without touching storage:

$preview = Reducer::reduceAll($doc, $pendingOps); // no persistence

Combine this with the JSON-wire inverses to implement client-side optimistic UI that gets reconciled server-side: the browser applies the op, and on rejection you replay the inverse.

Merge patches are shallow — send whole property objects. Property patches preserve null values and do not merge deeply. If you're updating styles, send the complete style object you want, not a nested fragment. Preserve-null means you can no longer use "missing" to mean "unset"; explicitly null things.

Generate fractional keys server-side with base-62, matching the JS. Insertions need a key between neighbours. The PHP helpers produce the same keys as fancy-cms-ui 0.8, so a key offered by the client will validate. Don't roll your own comparator ordering — use the tree helpers.

Render with the semantic-handle contract. PageRenderer puts the stable data-cms handle on a semantic element (p, h1–h6, a, ul/ol) or a landmark. This is a feature: bind into the supplied data context and let static headings, paragraphs, links/buttons, lists, landmarks and images render without custom HTML. Use theme tokens and responsive stack/grid/auto-fit controls rather than hand-authored CSS where possible; all values pass the same CSS gate as the JS emitter.

Wire integration with fancy-cms-ui: the parity suite is the contract. Keep the JS client and PHP server on matched versions; if you accept ops from a client running an older UI, expect unknown variants or rejected keys.

Register host node types. Known node types and a host registry drive validation. If you add a custom node, register it there — otherwise PageDoc validation will reject it with a structured path error at the point of use.

Gotchas and Tips

  • BREAKING in 0.4: the data-cms attribute now lands on a semantic element, not always a div. Update selectors div[data-cms] → [data-cms]. Set margins explicitly where browser defaults for p/h1/ul differ from what your old div layout assumed — this is the most likely cause of a visually "sudden" regression after upgrade.
  • The emitter silently drops invalid CSS. Invalid units, keywords, numbers and malformed declaration/rule escapes are thrown away, not raised. If styling doesn't appear, suspect a value gate rejection, not the renderer. Log the pre-emit style values and compare against the allowed length/keyword/number gates. Data URLs and quoted semicolons are supported; don't "helpfully" strip them.
  • seq is not an edit counter. It increments only on applied edits. Invalid targets, cycle moves and non-permutation root reorders leave it unchanged. Don't use seq to detect "user touched the page".
  • No-ops are refused at the storage boundary. PageDoc::apply rejects semantic no-ops — writing the same value back will fail or throw rather than bump seq. Short-circuit no-ops in your controller before calling apply.
  • Use PageJson for storage and transport. It preserves empty object vs. empty list and numeric map keys, and refuses non-JSON objects before a serialization callback can run. Passing an Eloquent model or DTO with a JsonSerializable implementation will be refused — convert to plain arrays first.
  • Bounds are enforced: nodes, JSON depth and value counts are limited, and cycle detection is iterative (so deep trees won't blow the stack, but they will hit the depth cap). Size your seeds accordingly.
  • Selector ids cannot terminate an inline stylesheet — the escaping is hardened — but keep treating ids as untrusted input in any generated CSS outside the renderer's emitter.
  • Extension points: host node registry (custom node types), known node types for validation, and the data context passed to bindings. All validation errors are structured with paths, so surface them directly in API responses rather than mapping to generic 422s.
  • Cross-runtime parity caveat: only JSON key order is normalised between runtimes. Don't assert on serialized key order in your own tests; compare decoded structures.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json