From 917150bbe6ac64929f067ee323d89219765048d6 Mon Sep 17 00:00:00 2001 From: Steve Ross Date: Wed, 10 Dec 2025 19:44:32 +0000 Subject: [PATCH] a working react/php dynamic wordpress block example integrated with the Vite build process --- app/blocks.php | 84 +++++++--- composer.json | 2 +- functions.php | 2 +- package-lock.json | 153 +++++++++++++++++- package.json | 1 + .../Editor/Editor.blade.php | 0 .../{blocks => acf-blocks}/Editor/Editor.jpg | Bin .../{blocks => acf-blocks}/Editor/Editor.php | 2 +- .../{blocks => acf-blocks}/Editor/Editor.scss | 0 resources/views/blocks/example/block.json | 12 ++ resources/views/blocks/example/editor.scss | 3 + resources/views/blocks/example/index.jsx | 12 ++ .../views/blocks/example/render.blade.php | 3 + resources/views/blocks/example/style.scss | 3 + vite.config.js | 4 + 15 files changed, 247 insertions(+), 34 deletions(-) rename resources/views/{blocks => acf-blocks}/Editor/Editor.blade.php (100%) rename resources/views/{blocks => acf-blocks}/Editor/Editor.jpg (100%) rename resources/views/{blocks => acf-blocks}/Editor/Editor.php (98%) rename resources/views/{blocks => acf-blocks}/Editor/Editor.scss (100%) create mode 100644 resources/views/blocks/example/block.json create mode 100644 resources/views/blocks/example/editor.scss create mode 100644 resources/views/blocks/example/index.jsx create mode 100644 resources/views/blocks/example/render.blade.php create mode 100644 resources/views/blocks/example/style.scss diff --git a/app/blocks.php b/app/blocks.php index 634366f..ae10807 100644 --- a/app/blocks.php +++ b/app/blocks.php @@ -6,6 +6,7 @@ namespace App; +// Add the badegg block category add_filter( 'block_categories_all' , function ( $categories ) { // Adding a new category. @@ -19,29 +20,70 @@ add_filter( 'block_categories_all' , function ( $categories ) { return $categories; }); -// add_action('init', function () { -// $blocks = glob(get_theme_file_path('resources/blocks/*/block.json')); +// Auto register WP blocks +add_action('init', function () { + $blocks = glob(get_theme_file_path('resources/views/blocks/*/block.json')); -// foreach ($blocks as $block_json) { -// register_block_type($block_json, [ -// 'render_callback' => function ($attributes, $content, $block) { -// $slug = basename($block->name); -// $view = "blocks.{$slug}.render"; + foreach ($blocks as $block_json) { + $slug = basename(dirname($block_json)); -// if (\Roots\view()->exists($view)) { -// return \Roots\view($view, [ -// 'attributes' => $attributes, -// 'content' => $content, -// 'block' => $block, -// ]); -// } + // Editor JS + $editor_js_path = "resources/views/blocks/{$slug}/index.jsx"; + if (file_exists(get_theme_file_path($editor_js_path))) { + wp_register_script( + "{$slug}-editor-script", + \Vite::asset($editor_js_path), + ['wp-blocks', 'wp-element', 'wp-editor'], + null, + true + ); + } -// return $content; -// } -// ]); -// } -// }); + // Editor SCSS (compiled to CSS) + $editor_css_path = "resources/views/blocks/{$slug}/editor.scss"; + if (file_exists(get_theme_file_path($editor_css_path))) { + wp_register_style( + "{$slug}-editor-style", + \Vite::asset($editor_css_path), + [], + null + ); + } + // Frontend SCSS (compiled to CSS) + $style_css_path = "resources/views/blocks/{$slug}/style.scss"; + if (file_exists(get_theme_file_path($style_css_path))) { + wp_register_style( + "{$slug}-style", + \Vite::asset($style_css_path), + [], + null + ); + } + + register_block_type($block_json, [ + 'editor_script' => "{$slug}-editor-script", + 'editor_style' => "{$slug}-editor-style", + 'style' => "{$slug}-style", + 'render_callback' => function ($attributes, $content, $block) { + $slug = basename($block->name); + $view = "blocks.{$slug}.render"; + + if (\Roots\view()->exists($view)) { + return \Roots\view($view, [ + 'attributes' => $attributes, + 'content' => $content, + 'block' => $block, + ]); + } + + return $content; + } + ]); + } +}); + +// Disable most of the core blocks add_action('allowed_block_types_all', function(){ $blocks = array_keys( \WP_Block_Type_Registry::get_instance()->get_all_registered() ); $blacklist = array_diff(block_blacklist(), block_whitelist()); @@ -76,7 +118,3 @@ function block_all() return array_values($enabled_blocks); } - -add_action('wp_footer', function(){ - echo '
',print_r(block_all()),'
'; -}); diff --git a/composer.json b/composer.json index 97c8917..d1fdb56 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "autoload": { "psr-4": { "App\\": "app/", - "Blocks\\": "resources/views/blocks" + "Blocks\\": "resources/views/acf-blocks" } }, "require": { diff --git a/functions.php b/functions.php index 247a50a..9b2edbb 100644 --- a/functions.php +++ b/functions.php @@ -60,7 +60,7 @@ autoload_psr4('Admin'); autoload_psr4('Ajax'); function autoload_psr4_blocks() { - $path = __dir__ . '/resources/views/blocks/*'; + $path = __dir__ . '/resources/views/acf-blocks/*'; $namespace = 'Blocks\\'; foreach(glob($path, GLOB_ONLYDIR) as $directory) { diff --git a/package-lock.json b/package-lock.json index 5c9e3ee..7bb8154 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "name": "sage", "devDependencies": { "@roots/vite-plugin": "^1.0.2", + "fast-glob": "^3.3.3", "laravel-vite-plugin": "^1.2.0", "sass": "^1.93.2", "vite": "^6.2.0" @@ -512,6 +513,44 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@parcel/watcher": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", @@ -1505,7 +1544,6 @@ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -1781,6 +1819,23 @@ "license": "MIT", "peer": true }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", @@ -1799,6 +1854,16 @@ "license": "BSD-3-Clause", "peer": true }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -1823,7 +1888,6 @@ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1846,6 +1910,19 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -1886,7 +1963,6 @@ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -1897,7 +1973,6 @@ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1911,7 +1986,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.12.0" } @@ -1998,13 +2072,22 @@ "license": "MIT", "peer": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -2019,7 +2102,6 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8.6" }, @@ -2144,6 +2226,27 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -2180,6 +2283,17 @@ "node": ">=0.10.0" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.52.5", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", @@ -2222,6 +2336,30 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2441,7 +2579,6 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "is-number": "^7.0.0" }, diff --git a/package.json b/package.json index af11a4d..8b7c8d3 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@roots/vite-plugin": "^1.0.2", + "fast-glob": "^3.3.3", "laravel-vite-plugin": "^1.2.0", "sass": "^1.93.2", "vite": "^6.2.0" diff --git a/resources/views/blocks/Editor/Editor.blade.php b/resources/views/acf-blocks/Editor/Editor.blade.php similarity index 100% rename from resources/views/blocks/Editor/Editor.blade.php rename to resources/views/acf-blocks/Editor/Editor.blade.php diff --git a/resources/views/blocks/Editor/Editor.jpg b/resources/views/acf-blocks/Editor/Editor.jpg similarity index 100% rename from resources/views/blocks/Editor/Editor.jpg rename to resources/views/acf-blocks/Editor/Editor.jpg diff --git a/resources/views/blocks/Editor/Editor.php b/resources/views/acf-blocks/Editor/Editor.php similarity index 98% rename from resources/views/blocks/Editor/Editor.php rename to resources/views/acf-blocks/Editor/Editor.php index cc01fd0..632a792 100644 --- a/resources/views/blocks/Editor/Editor.php +++ b/resources/views/acf-blocks/Editor/Editor.php @@ -70,7 +70,7 @@ class Editor $data['template'] = $this->default_template(); $data['block'] = $block; - echo \Roots\view("blocks.$name.$name", [ + echo \Roots\view("acf-blocks.$name.$name", [ 'data' => $data, 'block' => $block, ])->render(); diff --git a/resources/views/blocks/Editor/Editor.scss b/resources/views/acf-blocks/Editor/Editor.scss similarity index 100% rename from resources/views/blocks/Editor/Editor.scss rename to resources/views/acf-blocks/Editor/Editor.scss diff --git a/resources/views/blocks/example/block.json b/resources/views/blocks/example/block.json new file mode 100644 index 0000000..96ff4c8 --- /dev/null +++ b/resources/views/blocks/example/block.json @@ -0,0 +1,12 @@ +{ + "apiVersion": 3, + "name": "badegg/example", + "title": "Example", + "category": "badegg", + "icon": "cover-image", + "description": "This is an example of a custom Wordpress Block created using the offical method.", + "editorScript": "example-editor-script", + "editorStyle": "example-editor-style", + "style": "example-style", + "render": "resources/blocks/example/render.blade.php" +} diff --git a/resources/views/blocks/example/editor.scss b/resources/views/blocks/example/editor.scss new file mode 100644 index 0000000..3677994 --- /dev/null +++ b/resources/views/blocks/example/editor.scss @@ -0,0 +1,3 @@ +.block-badegg-example-editor { + display: block; +} diff --git a/resources/views/blocks/example/index.jsx b/resources/views/blocks/example/index.jsx new file mode 100644 index 0000000..edf11dc --- /dev/null +++ b/resources/views/blocks/example/index.jsx @@ -0,0 +1,12 @@ +import { registerBlockType } from '@wordpress/blocks'; + +registerBlockType('badegg/example', { + apiVersion: 3, // optional in JS, primarily in block.json + edit() { + return ( +
+

Bad Egg Block Example

+
+ ); + }, +}); diff --git a/resources/views/blocks/example/render.blade.php b/resources/views/blocks/example/render.blade.php new file mode 100644 index 0000000..aac89b8 --- /dev/null +++ b/resources/views/blocks/example/render.blade.php @@ -0,0 +1,3 @@ +
+

Bad Egg Example Block (Blade)

+
diff --git a/resources/views/blocks/example/style.scss b/resources/views/blocks/example/style.scss new file mode 100644 index 0000000..575266f --- /dev/null +++ b/resources/views/blocks/example/style.scss @@ -0,0 +1,3 @@ +.block-badegg-hero { + display: block; +} diff --git a/vite.config.js b/vite.config.js index 3931d8c..47969d7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,6 +1,9 @@ import { defineConfig } from 'vite' import laravel from 'laravel-vite-plugin' import { wordpressPlugin, wordpressThemeJson } from '@roots/vite-plugin'; +import fg from 'fast-glob' + +const blockEntries = fg.sync('resources/views/blocks/**/{index.jsx,style.scss,editor.js,editor.scss}') export default defineConfig({ base: '/app/themes/badegg/public/build/', @@ -11,6 +14,7 @@ export default defineConfig({ 'resources/js/app.js', 'resources/css/editor.scss', 'resources/js/editor.js', + ...blockEntries, ], refresh: true, url: process.env.APP_URL,