[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80627":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":11,"contributorsCount":11,"subscribersCount":11,"size":11,"stars1d":11,"stars7d":11,"stars30d":11,"stars90d":11,"forks30d":11,"starsTrendScore":11,"compositeScore":13,"rankGlobal":8,"rankLanguage":8,"license":14,"archived":15,"fork":15,"defaultBranch":16,"hasWiki":17,"hasPages":15,"topics":18,"createdAt":8,"pushedAt":8,"updatedAt":19,"readmeContent":20,"aiSummary":21,"trendingCount":11,"starSnapshotCount":11,"syncStatus":22,"lastSyncTime":23,"discoverSource":24},80627,"gutenberg-control-blocks-lite","wordpress-gcb\u002Fgutenberg-control-blocks-lite","wordpress-gcb",null,"PHP",61,0,1,37,"GNU General Public License v2.0",false,"main",true,[],"2026-06-12 04:01:29","# GCB Lite\n\n[![Tests](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgutenberg-control-blocks-lite\u002Factions\u002Fworkflows\u002Ftests.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgutenberg-control-blocks-lite\u002Factions\u002Fworkflows\u002Ftests.yml)\n\n> ### ⏩ [Try it in your browser — no install needed](https:\u002F\u002Fplayground.wordpress.net\u002F?blueprint-url=https:\u002F\u002Fraw.githubusercontent.com\u002Fwordpress-gcb\u002Fgutenberg-control-blocks-lite\u002Fmain\u002Fplayground\u002Fblueprint.json)\n>\n> A full WordPress install boots in a WASM tab with gcb-lite + demo blocks\n> pre-loaded. ~10 seconds. No backend, no signup, no risk.\n\n---\n\n**WordPress as a typed-field CMS for a React frontend.** Write one component,\nrender it in both the Gutenberg editor and your public Next.js site. No\n`edit.js` to maintain in parallel with your real frontend. No headless-WP\nauthoring blind spots.\n\n```\nYou write:                 wp-admin shows:           Public site shows:\n─────────────              ────────────────          ──────────────────\nHero.jsx                   Hero.jsx                  Hero.jsx\n  + Hero.fields.json         (SSR via plugin)         (rendered directly)\n```\n\nOne source of truth. The editor preview is the same React component you ship\nto production, server-rendered and handed to wp-admin as HTML.\n\n**Two demos:**\n\n- **[Try it in your browser, no install →](https:\u002F\u002Fplayground.wordpress.net\u002F?blueprint-url=https:\u002F\u002Fraw.githubusercontent.com\u002Fwordpress-gcb\u002Fgutenberg-control-blocks-lite\u002Fmain\u002Fplayground\u002Fblueprint.json)** —\n  a full WordPress install runs in a WASM tab with the plugin and four demo\n  blocks pre-installed. ~10 seconds to boot, no backend, no signup.\n- **[See the React-frontend demo →](https:\u002F\u002Fgcb-next-starter.vercel.app\u002F)** —\n  a landing page built from gcb-lite blocks, rendered by a Next.js\n  frontend in front of a real WordPress backend.\n\n---\n\n## The gap this exists to close\n\nHeadless WordPress has been viable for years. Headless WordPress with a\ngood editor experience hasn't.\n\n- **Vanilla Gutenberg** assumes your frontend is PHP. Build a custom block\n  and you write `edit.js` (editor preview), `save.js` (saved markup), and\n  your real React component. Three representations of the same thing,\n  drifting from each other forever.\n- **WP 7's `autoRegister`** gives you typed Inspector controls for simple\n  blocks. Render is still PHP. Doesn't help when your public site is Next,\n  Astro, or anything else.\n- **ACF Blocks** give you rich field types and PHP render. Nothing about\n  your React frontend.\n- **Headless + WPGraphQL** gives you the data but punts on the editor\n  preview. Authors edit blind, see a placeholder in wp-admin, and reload\n  the public site to find out what they made.\n\nYou want Gutenberg's authoring UX (inserter, drag-and-drop, transforms,\npatterns), ACF's field richness, and a real React frontend — all at once.\nGCB Lite is what happens when those stop being mutually exclusive.\n\n---\n\n## The architecture\n\nThe plugin defines a narrow protocol between WordPress and your frontend.\nWhat sits on either side is your call.\n\n### 1. One component, two contexts\n\nA `gcb\u002F*` block points at a React component on your Next.js frontend (or\nAstro, or any HTTP-SSR service — Next is the default; the reference\nstarter lives at [wordpress-gcb\u002Fgcb-next-starter](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgcb-next-starter)).\nWhen the\neditor needs a preview, WordPress calls your frontend server-to-server\nand embeds the returned HTML. When a visitor hits the public site, the\nsame component renders directly. There is no React inside wp-admin — just\nrendered HTML.\n\n```\n┌──────────────────┐        ┌─────────────────────┐        ┌──────────────────────┐\n│  wp-admin editor │  REST  │  GCB Lite plugin    │  HTTP  │  Your Next.js app    │\n│                  │ ─────▶ │  (this repo)        │ ─────▶ │  (renders blocks)    │\n│  author edits    │        │                     │        │                      │\n│  Hero block      │ ◀───── │  \u002Frender-batch      │ ◀───── │  GET \u002Fwordpress\u002F     │\n│                  │  HTML  │  HtmlExtractor      │  HTML  │  render\u002Fhero         │\n└──────────────────┘        └─────────────────────┘        └──────────────────────┘\n                                                                      ▲\n                                                                      │\n                                                       Visitors hit ──┘\n                                                       the same app\n```\n\nThe contract is one HTTP route returning one wrapper element:\n\n```html\n\u003Cwp-block-wrapper data-block-name=\"hero\" data-cache-timestamp=\"1716435847\">\n  \u003C!-- your component's HTML -->\n\u003C\u002Fwp-block-wrapper>\n```\n\nThat's the entire protocol. Implement it in Next.js, Astro, Express,\nanything that can SSR React. The reference Next.js implementation —\n[wordpress-gcb\u002Fgcb-next-starter](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgcb-next-starter) —\nships with three working blocks and a richer block library on its\n[`examples` branch](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgcb-next-starter\u002Ftree\u002Fexamples).\n\n**Crucially: this is not a third moving part.** The frontend that serves\nvisitors is the same frontend that serves the editor preview. You add\none route to the Next.js app you already deploy.\n\n### 2. PHP and React are first-class peers\n\nEach block picks its own render path by file existence:\n\n| If the block has…       | The plugin…                                  |\n|-------------------------|----------------------------------------------|\n| `render.php`            | Runs it locally. Standard WP block.          |\n| no `render.php`         | Calls your frontend for HTML.                |\n\nYou can adopt GCB Lite for the typed-field schema alone, ship every block\nas `render.php`, and never run a React frontend. Or write one block in\nReact and leave the rest in PHP. Or go all-in. It's per-block, not\nstack-wide.\n\nFor client work, this is the de-risk: the novel piece — server-to-server\nReact SSR — is opt-in per block. The boring fallback — PHP render callback\n— is the most well-trodden code path in WordPress.\n\n---\n\n## A block, end to end\n\nThree files in your active theme.\n\n**`themes\u002F{your-theme}\u002Fblocks\u002Fhero\u002Fblock.json`**\n\n```json\n{\n  \"$schema\": \"https:\u002F\u002Fschemas.wp.org\u002Ftrunk\u002Fblock.json\",\n  \"apiVersion\": 3,\n  \"name\": \"gcb\u002Fhero\",\n  \"title\": \"Hero\",\n  \"category\": \"widgets\",\n  \"icon\": \"cover-image\",\n  \"textdomain\": \"gcb\",\n  \"attributes\": {},\n  \"supports\": {}\n}\n```\n\nStandard WordPress block metadata. No GCB-specific keys. `attributes` is\nempty on purpose — they're generated from the controls.\n\n**`themes\u002F{your-theme}\u002Fblocks\u002Fhero\u002Fblock.fields.json`**\n\n```json\n{\n  \"controls\": [\n    {\n      \"id\": \"ctrl_heading\",\n      \"type\": \"text\",\n      \"label\": \"Heading\",\n      \"attributeKey\": \"heading\"\n    },\n    {\n      \"id\": \"ctrl_image\",\n      \"type\": \"image\",\n      \"label\": \"Background\",\n      \"attributeKey\": \"image\",\n      \"enableFocalPoint\": true,\n      \"enableFixedBackground\": true\n    },\n    {\n      \"id\": \"ctrl_align\",\n      \"type\": \"toggle-group\",\n      \"label\": \"Alignment\",\n      \"attributeKey\": \"align\",\n      \"options\": [\n        { \"label\": \"Left\",   \"value\": \"left\" },\n        { \"label\": \"Center\", \"value\": \"center\" }\n      ],\n      \"default\": \"center\"\n    }\n  ]\n}\n```\n\nThe plugin validates this, generates WP block attributes with correct types\nand defaults, and renders the Inspector panel. No `edit.js`, no `save.js`.\n\n**Pick your render path**\n\nA. PHP — `themes\u002F{your-theme}\u002Fblocks\u002Fhero\u002Frender.php`:\n\n```php\n\u003C?php\n$wrap = get_block_wrapper_attributes([\n    'class'      => 'hero',\n    'data-align' => $attributes['align'],\n]);\n$image = $attributes['image'] ?? [];\n?>\n\u003Csection \u003C?php echo $wrap; ?> style=\"background-image: url('\u003C?php echo esc_url($image['url'] ?? ''); ?>')\">\n  \u003Ch1>\u003C?php echo esc_html($attributes['heading']); ?>\u003C\u002Fh1>\n\u003C\u002Fsection>\n```\n\nB. React — in your Next.js frontend's `components\u002FHero.jsx`:\n\n```jsx\nexport default function Hero({ attributes }) {\n  const { heading, image, align } = attributes;\n  const fpx = image?.focalPoint?.x ?? 0.5;\n  const fpy = image?.focalPoint?.y ?? 0.5;\n  return (\n    \u003Csection className={`hero hero--${align}`}>\n      \u003Cimg\n        src={image?.url}\n        alt={image?.alt}\n        style={{ objectFit: 'cover', objectPosition: `${fpx*100}% ${fpy*100}%` }}\n      \u002F>\n      \u003Ch1>{heading}\u003C\u002Fh1>\n    \u003C\u002Fsection>\n  );\n}\n```\n\n…wired into the frontend's block registry:\n\n```js\nimport Hero from '..\u002F..\u002Fcomponents\u002FHero';\nexport const WP_BLOCK_REGISTRY = { 'gcb\u002Fhero': Hero };\n```\n\nThat's it. Either path, the block appears in the inserter, the Inspector\nrenders three controls (with a real focal point picker and a media library\nconnection on the image field), and the editor preview is server-rendered\nHTML that matches what visitors see.\n\n---\n\n## What you get\n\n**30+ Inspector control types**, with the rich ones being the point:\n\n- **`image`** — media library, focal point picker, cover\u002Fcontain\u002Fauto, custom width, repeat, fixed-background toggles\n- **`gallery`** — drag-to-reorder via @dnd-kit, per-image alt text and ordering\n- **`post-object`** — search and select published posts of any type, with filters\n- **`taxonomy`** — pick terms with hierarchy support\n- **`user`** — author picker\n- **`relationship`** — bidirectional post relationships\n- **`icon`** — Dashicons picker (Lucide \u002F custom sources planned)\n- **`color`**, **`range`**, **`code`**, **`datetime`**, **`url`**, **`google-map`**, **`file`**, **`wysiwyg`**, **`oembed`**\n- **`select`**, **`radio`**, **`checkbox`**, **`checkbox-group`**, **`toggle`**, **`toggle-group`**, **`button-group`**\n- **`size`**, **`spacing`**, **`page-link`**, **`message`**, **`text`**, **`textarea`**, **`number`**, **`email`**, **`date`**\n\nPlus structural types (`group`, `panel`, `tools-panel`) that organise the\nInspector into collapsible sections via `parentPanelId` references. Plus\nbasic conditional logic (`==`, `!=`, `in`, `contains`, `>`, `\u003C` over sibling\nattribute values) for show\u002Fhide on any field.\n\n**Native Gutenberg authoring.** Authors get the standard inserter,\ndrag-to-reorder, transforms, copy\u002Fpaste, patterns, multi-select. GCB Lite\nis not a page builder. It's how the dev side of Gutenberg should have\nshipped.\n\n**Repeater inner blocks.** Emit a `\u003Crepeater allowedBlocks='[\"gcb\u002Fteam-member\"]' \u002F>`\nmarker from your render output and the editor swaps it for a real\nInnerBlocks UI — Add button, drag-to-reorder, child-type constraints. On\nthe public side, the same marker swaps for the rendered children. One\ndeclaration, two contexts. Works identically for PHP-rendered and\nReact-rendered parents.\n\n**Batched rendering.** Open a 30-block page in the editor; GCB Lite fires\none `\u002Frender-batch` HTTP call, not thirty. A singleton coordinator\ndebounces 1ms, supersedes in-flight requests on attribute change, and\ndemuxes responses by `clientId`.\n\n**Caching with proper invalidation.** Per-block-per-attribute-hash\ntransients, keyed on a `data-cache-timestamp` your frontend stamps into\nevery response. Restart the frontend, the timestamp changes, the cache\ninvalidates. Network failures fall back to the last good HTML instead of\nbreaking the editor.\n\n**Headless-ready REST surface**, public-readable:\n\n| Endpoint                                        | What it gives you                                                                                            |\n|-------------------------------------------------|--------------------------------------------------------------------------------------------------------------|\n| `GET \u002Fwp-json\u002Fwp\u002Fv2\u002Fpages?slug=...`             | Includes `blocks_raw` — raw markup with block comments intact, so your frontend can walk the tree.           |\n| `GET \u002Fwp-json\u002Fgcblite\u002Fv1\u002Fblocks`                | Schemas + defaults for every registered block. WordPress only persists attrs that differ from defaults.      |\n| `POST \u002Fwp-json\u002Fgcblite\u002Fv1\u002Frender-batch`         | Render any block(s) to HTML server-side. Useful for blocks you haven't React-implemented yet.                |\n\n**theme.json integration.** Your spacing, colors, and custom tokens flow\ninto the editor under `window.gcbLite.tokens` and are consumed by controls\nthat bind via `tokenGroup`. Authors pick from your design system, not a\nfree-form colour wheel.\n\n**WP 7 Abilities API.** On WordPress 7.0+, `gcblite\u002Flist-blocks` and\n`gcblite\u002Frender-block` are registered as typed abilities — surfaced to\nthe WP command palette and to MCP clients (Claude Desktop, the WordPress\nMCP adapter, anything that speaks the protocol) for LLM tool use. AI\nagents can introspect your block library and render blocks server-side\nwithout anyone writing custom glue. Gated on\n`function_exists('wp_register_ability')` so the plugin continues to work\nfine on WP 6.x.\n\n**WP-CLI scaffold.**\n\n```bash\nwp gcblite scaffold team-grid --title=\"Team Grid\" --controls=\"heading:text,intro:textarea\"\n```\n\nAlso reads JSON specs from stdin, designed for AI agents to drive\nend-to-end.\n\n---\n\n## How it compares\n\n|                              | Vanilla Gutenberg | WP 7 autoRegister | ACF Blocks | Headless + WPGraphQL | **GCB Lite**                          |\n|------------------------------|-------------------|-------------------|------------|----------------------|---------------------------------------|\n| Field types                  | Basic             | Basic typed       | Rich       | Whatever you wire    | 30+, including focal point, gallery   |\n| Editor preview               | `edit.js` (parallel) | PHP            | PHP        | None \u002F broken        | Same component as the public site     |\n| Public render                | `save.js` HTML    | PHP               | PHP        | Your stack           | PHP or React, your call per block     |\n| Authoring UX                 | Gutenberg         | Gutenberg         | Gutenberg  | Gutenberg (blind)    | Gutenberg, with full preview parity   |\n| Headless-ready               | Hard              | Hard              | Hard       | Yes                  | Built for it                          |\n| Editor\u002Fpublic drift          | High              | Low               | Low        | Severe (no preview)  | Impossible — same source              |\n\nEvery other approach forces a trade between Gutenberg authoring parity and\na real React frontend. GCB Lite stops making that a choice.\n\n---\n\n## When to reach for autoRegister instead\n\nIf you have a PHP-rendered block with a handful of typed atoms and no\nheadless frontend in the picture, WP 7's `supports: { autoRegister: true }`\nis lighter, ships in core, and is the right call.\n\nReach for GCB Lite when any of these are true:\n\n- You need richer field types than core gives you (image with focal point,\n  gallery, post relationships, etc.).\n- Your frontend is React (Next, Astro, Remix) and you want one component\n  driving both contexts.\n- You're shipping a block library across multiple client sites and want\n  one schema-driven authoring story.\n\n---\n\n## Quick start\n\nWant to see what you're getting first?\n**[Open the live demo](https:\u002F\u002Fgcb-next-starter.vercel.app\u002F)** — it's the\ngcb-next-starter `examples` branch deployed as-is. The whole page is\ncomposed from three GCB Lite blocks (Hero, FeatureTrio, Cta) rendered in\nReact.\n\n**To use the plugin** (most people start here):\n\nGrab the latest pre-built zip from the\n[Releases page](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgutenberg-control-blocks-lite\u002Freleases),\nthen in wp-admin: **Plugins → Add New Plugin → Upload Plugin** → pick the\nzip → Install Now → Activate.\n\n```bash\n# Optional: skip wp-admin and drop the unzipped folder straight in\ncurl -L https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgutenberg-control-blocks-lite\u002Freleases\u002Flatest\u002Fdownload\u002Fgcb-lite-0.1.0.zip -o gcb-lite.zip\nunzip gcb-lite.zip -d wp-content\u002Fplugins\u002F\n```\n\n**To hack on the plugin** (contributors):\n\n```bash\ncd wp-content\u002Fplugins\ngit clone https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgutenberg-control-blocks-lite gcb-lite\ncd gcb-lite\ncomposer install\nnpm install\nnpm run build\n```\n\nThe release zip ships with `vendor\u002F` and `build\u002F` already populated —\nthat's what makes the wp-admin-upload path work without you needing a\nPHP\u002FNode toolchain. Cloning the source repo needs the toolchain because\nthose folders are gitignored.\n\n**The React frontend** (skip if you only ship PHP-rendered blocks):\n\n```bash\n# Lives in its own repo; clone anywhere convenient.\ncd ~\u002Fcode\ngit clone https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgcb-next-starter\ncd gcb-next-starter\ncp .env.local.example .env.local   # set NEXT_PUBLIC_WP_URL\nnpm install\nnpm run dev   # http:\u002F\u002Flocalhost:3001\n```\n\nActivate the plugin in wp-admin. In your active theme, create a\n`blocks\u002F{slug}\u002F` directory with `block.json` and `block.fields.json` as\nshown above. Add either a `render.php` or a React component plus a\nregistry entry on the frontend. The block shows up in the inserter on the\nnext editor load.\n\nTo point the plugin at a different frontend URL:\n\n```php\n\u002F\u002F wp-config.php\ndefine('GCBLITE_COMPONENT_SERVER_URL', 'https:\u002F\u002Fyour-frontend.example.com');\n```\n\n…or via filter:\n\n```php\nadd_filter('gcblite_frontend_url', fn () => 'https:\u002F\u002Fyour-frontend.example.com');\n```\n\nFor a 60-second demo against three working blocks, see the\n[gcb-next-starter quick start](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgcb-next-starter#quick-start-60-seconds).\n\n---\n\n## Production reality\n\nVersion 0.1.0, public alpha. The architecture is settled; specific APIs\nmay move before 1.0. If you're shipping client work on it, pin to a\ncommit and follow the issue tracker.\n\nTwo trade-offs every team adopting GCB Lite for a real project should\nweigh:\n\n**The contract is bespoke.** WordPress-fetches-HTML-from-your-Next-app is\nnot a path a million people have walked. WPGraphQL → JSON → React is.\nThe advantage is editor\u002Ffrontend parity nothing else gives you; the\ntrade-off is that if the maintainers walk, the adopter inherits ~1,500\nlines of PHP and JS to keep running. The code is straightforward and the\ncontract is documented — it's forkable. But it is a thing to own.\n\n**Pre-1.0 means the contract can shift.** APIs may move before 1.0. Every\nbreaking change will be documented with a migration path, but if you're\nlaunching to production this week, expect to upgrade deliberately.\n\nIf those trade-offs are wrong for your client, use WPGraphQL + Next.js.\nIt's the boring, well-trodden path, and \"boring\" is the right answer for\na lot of projects.\n\n---\n\n## Documentation\n\n- [AGENTS.md](.\u002FAGENTS.md) — block-authoring guide. Field types in detail,\n  the `\u003Crepeater>` and `\u003Cinnerblocks>` patterns, editor-SSR caveats,\n  conventions for shadcn\u002FRadix UI. Required reading before building a\n  non-trivial block.\n- [gcb-next-starter](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgcb-next-starter) —\n  reference Next.js frontend (separate repo). Has three working blocks\n  on `main`, a richer library on the `examples` branch.\n\n---\n\n## Tests\n\nThree suites land on every push. CI runs the lot on each PR — see the\nbadge at the top of this file.\n\n| Suite | Run locally | Notes |\n|---|---|---|\n| PHPUnit (unit) | `composer test:unit` | Pure functions: `Validator`, `Conditional`, `Frontend\\Url`, `Integrations\\GoogleMapsKey`. Stubs WP. ~7 ms. |\n| PHPUnit (integration) | `composer test:integration` | Real WordPress + SQLite. First run: `composer install-wp-tests` to download WP + the WP test framework into `\u002Ftmp`. Covers `save_post`, REST meta registration, draft-on-invalid behaviour. |\n| Jest | `npm test` | JS-side mirror of the PHP validation rules + the conditional-logic helpers. |\n\nAdding a rule to `Validator.php`? Add the matching one to `validation.js`\n(and tests in both) — drift between the two would let invalid input pass\nthe client and fail at save.\n\n---\n\n## Contributing\n\nGCB Lite is GPL-2.0-or-later. The wire contract is intentionally minimal —\nwhat sits on either side of it is yours — and the implementation around\nthat contract is still early. Good first contributions:\n\n- More example blocks in [gcb-next-starter](https:\u002F\u002Fgithub.com\u002Fwordpress-gcb\u002Fgcb-next-starter)'s\n  `examples` branch covering common patterns: forms, embeds, navigation,\n  image-text variants.\n- Tests, especially around the editor-side marker swap\n  (`src\u002Futils\u002Fparse-preview.js`) and the batched render coordinator.\n- Reference frontends in Astro and Remix to prove out the wire-contract\n  portability claim.\n- Real-world feedback. If you're using GCB Lite in production, that's the\n  most valuable signal we can get right now — open an issue and say hi.\n\n---\n\n## License\n\nGPL-2.0-or-later. See [LICENSE](.\u002FLICENSE).\n","GCB Lite 是一个旨在改善WordPress与React前端集成体验的插件。它通过让开发者仅需编写一个React组件即可在Gutenberg编辑器和公共Next.js网站中渲染，从而简化了开发流程。该插块支持类型化字段定义，确保编辑器预览与实际生产环境中的组件一致，避免了维护多个版本代码的问题。此外，GCB Lite还提供了一个基于WebAssembly的在线试用环境，无需安装即可快速体验其功能。此项目特别适合那些希望利用WordPress作为内容管理系统同时保持现代化前端技术栈（如React、Next.js）的应用场景。",2,"2026-06-11 04:01:25","CREATED_QUERY"]