-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhandoff-blocks.php
More file actions
408 lines (358 loc) · 13.2 KB
/
Copy pathhandoff-blocks.php
File metadata and controls
408 lines (358 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
<?php
/**
* Plugin Name: Handoff Blocks
* Plugin URI: https://handoff.com
* Description: A collection of Gutenberg blocks built from the Handoff design system.
* Version: 0.0.41
* Author: Brad Mering
* Author URI: https://www.handoff.com
* License: MIT
* License URI: https://opensource.org/licenses/MIT
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
define('HANDOFF_BLOCKS_PATH', plugin_dir_path(__FILE__));
define('HANDOFF_BLOCKS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('HANDOFF_BLOCKS_URL', plugin_dir_url(__FILE__));
$handoff_composer = json_decode(file_get_contents(HANDOFF_BLOCKS_PATH . 'composer.json'), true);
define('HANDOFF_BLOCKS_VERSION', $handoff_composer['version'] ?? '0.0.0');
/**
* Resolve the content directory where project-specific blocks live.
*
* Priority:
* 1. Explicit constant in wp-config.php (always wins)
* 2. Plugin directory itself — if it contains actual compiled blocks (local dev / wp-env)
* 3. wp-content/handoff nested inside the plugin dir — covers the case where
* the full repo (including wp-content/handoff/) is mounted as a plugin
* in wp-env before the separate wp-content mapping takes effect
* 4. WP_CONTENT_DIR . '/handoff' (Composer installs / production)
*
* Override in wp-config.php if you want a different location:
*
* define( 'HANDOFF_CONTENT_DIR', WP_CONTENT_DIR . '/handoff' );
*/
if (!defined('HANDOFF_CONTENT_DIR')) {
$handoff_nested = rtrim(HANDOFF_BLOCKS_PATH, '/') . '/wp-content/handoff';
if (handoff_has_local_blocks(HANDOFF_BLOCKS_PATH)) {
define('HANDOFF_CONTENT_DIR', HANDOFF_BLOCKS_PATH);
} elseif (is_dir($handoff_nested) && handoff_has_local_blocks($handoff_nested)) {
define('HANDOFF_CONTENT_DIR', $handoff_nested);
} else {
define('HANDOFF_CONTENT_DIR', WP_CONTENT_DIR . '/handoff');
}
}
/**
* Check whether a directory contains actual compiled block content
* (as opposed to just an empty blocks/ dir or the admin build output).
*/
function handoff_has_local_blocks(string $base): bool {
$dirs_to_check = ['blocks', 'build'];
foreach ($dirs_to_check as $sub) {
$dir = rtrim($base, '/') . '/' . $sub;
if (!is_dir($dir)) continue;
foreach (scandir($dir) as $item) {
if ($item === '.' || $item === '..' || $item === '.gitkeep' || $item === 'admin') continue;
if (is_dir($dir . '/' . $item) && file_exists($dir . '/' . $item . '/block.json')) {
return true;
}
}
}
return false;
}
/**
* Derive a web-accessible URL for the content directory.
*/
if (!defined('HANDOFF_CONTENT_URL')) {
if (HANDOFF_CONTENT_DIR === HANDOFF_BLOCKS_PATH) {
define('HANDOFF_CONTENT_URL', HANDOFF_BLOCKS_URL);
} else {
$content_dir_real = rtrim(wp_normalize_path(HANDOFF_CONTENT_DIR), '/');
$wp_content_real = rtrim(wp_normalize_path(WP_CONTENT_DIR), '/');
if (strpos($content_dir_real, $wp_content_real) === 0) {
$relative = substr($content_dir_real, strlen($wp_content_real));
define('HANDOFF_CONTENT_URL', content_url($relative) . '/');
} else {
$abspath_real = rtrim(wp_normalize_path(ABSPATH), '/');
$relative = substr($content_dir_real, strlen($abspath_real));
define('HANDOFF_CONTENT_URL', site_url($relative) . '/');
}
}
}
/**
* Returns true when running in a local/development environment.
*
* In development mode the REST API permission callbacks are relaxed so that
* tools like Postman can hit the endpoints without a WordPress session cookie
* or Application Password.
*
* Detection order:
* 1. HANDOFF_DEV_AUTH constant — define( 'HANDOFF_DEV_AUTH', true ) in wp-config.php
* to force-enable regardless of environment.
* 2. PHP_ENV server variable (set by Docker / the server) equals "development".
*
* NEVER enable this in production. The constant check exists so you can explicitly
* turn it on/off in wp-config.php without relying on the env var.
*/
function handoff_is_dev_env() {
if (defined('HANDOFF_DEV_AUTH') && HANDOFF_DEV_AUTH === true) {
return true;
}
$env = isset($_SERVER['PHP_ENV']) ? $_SERVER['PHP_ENV'] : getenv('PHP_ENV');
return $env === 'development';
}
// Include the auto-generated categories file — prefer the content dir copy
$handoff_cats_file = rtrim(HANDOFF_CONTENT_DIR, '/') . '/includes/handoff-categories.php';
if (!file_exists($handoff_cats_file)) {
$handoff_cats_file = HANDOFF_BLOCKS_PATH . 'includes/handoff-categories.php';
}
if (file_exists($handoff_cats_file)) {
require_once $handoff_cats_file;
}
// Include admin dashboard
if (file_exists(HANDOFF_BLOCKS_PATH . 'includes/class-handoff-admin.php')) {
require_once HANDOFF_BLOCKS_PATH . 'includes/class-handoff-admin.php';
}
// Include WP-CLI commands
if (defined('WP_CLI') && WP_CLI) {
if (file_exists(HANDOFF_BLOCKS_PATH . 'includes/class-handoff-cli.php')) {
require_once HANDOFF_BLOCKS_PATH . 'includes/class-handoff-cli.php';
}
}
// Include the field resolver for dynamic array mapping
if (file_exists(HANDOFF_BLOCKS_PATH . 'includes/handoff-field-resolver.php')) {
require_once HANDOFF_BLOCKS_PATH . 'includes/handoff-field-resolver.php';
}
if (file_exists(HANDOFF_BLOCKS_PATH . 'includes/handoff-editor-styles.php')) {
require_once HANDOFF_BLOCKS_PATH . 'includes/handoff-editor-styles.php';
}
// Include the REST API endpoints
if (file_exists(HANDOFF_BLOCKS_PATH . 'includes/handoff-rest-api.php')) {
require_once HANDOFF_BLOCKS_PATH . 'includes/handoff-rest-api.php';
}
// Include migration tooling
if (file_exists(HANDOFF_BLOCKS_PATH . 'includes/class-handoff-migration.php')) {
require_once HANDOFF_BLOCKS_PATH . 'includes/class-handoff-migration.php';
}
if (file_exists(HANDOFF_BLOCKS_PATH . 'includes/handoff-migration-rest.php')) {
require_once HANDOFF_BLOCKS_PATH . 'includes/handoff-migration-rest.php';
}
/**
* Fix asset URLs for blocks that live outside wp-content/plugins/.
*
* register_block_type_from_metadata() uses plugins_url() to resolve
* file: URIs in block.json. That only produces correct URLs when the
* block.json is inside WP_PLUGIN_DIR. When blocks live under
* HANDOFF_CONTENT_DIR (e.g. wp-content/handoff/build/), we intercept
* the filter and derive the URL from HANDOFF_CONTENT_URL instead.
*/
function handoff_fix_block_asset_urls($url, $path, $plugin) {
if (empty($plugin)) {
return $url;
}
$content_dir = wp_normalize_path(rtrim(HANDOFF_CONTENT_DIR, '/'));
$plugin_norm = wp_normalize_path($plugin);
$content_dir_real = wp_normalize_path(rtrim(realpath(HANDOFF_CONTENT_DIR) ?: HANDOFF_CONTENT_DIR, '/'));
if (strpos($plugin_norm, $content_dir . '/') === 0) {
$relative_dir = substr(dirname($plugin_norm), strlen($content_dir));
} elseif (strpos($plugin_norm, $content_dir_real . '/') === 0) {
$relative_dir = substr(dirname($plugin_norm), strlen($content_dir_real));
} else {
return $url;
}
$content_url = rtrim(HANDOFF_CONTENT_URL, '/');
return $content_url . $relative_dir . '/' . ltrim(wp_normalize_path($path), '/');
}
$handoff_content_norm = wp_normalize_path(rtrim(HANDOFF_CONTENT_DIR, '/'));
$handoff_plugin_norm = wp_normalize_path(rtrim(HANDOFF_BLOCKS_PATH, '/'));
if ($handoff_content_norm !== $handoff_plugin_norm) {
add_filter('plugins_url', 'handoff_fix_block_asset_urls', 10, 3);
}
/**
* Register all Handoff blocks
*/
function handoff_blocks_register_blocks() {
$blocks_dir = rtrim(HANDOFF_CONTENT_DIR, '/') . '/build/';
if (!is_dir($blocks_dir)) {
return;
}
$blocks = scandir($blocks_dir);
foreach ($blocks as $block) {
if ($block === '.' || $block === '..') {
continue;
}
$block_path = $blocks_dir . $block;
if (is_dir($block_path) && file_exists($block_path . '/block.json')) {
register_block_type($block_path);
}
}
}
add_action('init', 'handoff_blocks_register_blocks');
/**
* Enqueue Handoff design system (frontend) and per-project editor canvas CSS.
* See includes/handoff-editor-styles.php.
*/
add_action('enqueue_block_assets', 'handoff_enqueue_design_assets');
/**
* Warn in the block editor when a Handoff block is no longer in the compile output.
*/
function handoff_enqueue_block_deprecation_script() {
$candidates = array(
array(
'path' => HANDOFF_BLOCKS_PATH . 'build/editor/block-deprecation.js',
'url' => HANDOFF_BLOCKS_URL . 'build/editor/block-deprecation.js',
),
array(
'path' => rtrim(HANDOFF_CONTENT_DIR, '/') . '/build/editor/block-deprecation.js',
'url' => rtrim(HANDOFF_CONTENT_URL, '/') . '/build/editor/block-deprecation.js',
),
);
$script = null;
foreach ($candidates as $candidate) {
if (file_exists($candidate['path'])) {
$script = $candidate;
break;
}
}
if ($script === null) {
return;
}
$asset_file = dirname($script['path']) . '/block-deprecation.asset.php';
if (file_exists($asset_file)) {
$asset = require $asset_file;
} else {
$asset = array(
'dependencies' => array('wp-blocks', 'wp-element', 'wp-components', 'wp-hooks', 'wp-compose', 'wp-block-editor', 'wp-i18n'),
'version' => HANDOFF_BLOCKS_VERSION,
);
}
wp_enqueue_script(
'handoff-block-deprecation',
$script['url'],
$asset['dependencies'],
$asset['version'],
true
);
}
add_action('enqueue_block_editor_assets', 'handoff_enqueue_block_deprecation_script');
/**
* Register block categories
* Uses the auto-generated categories from handoff-categories.php if available
*/
function handoff_blocks_block_category($categories, $post) {
// Use auto-generated categories if available, otherwise fall back to default
if (function_exists('handoff_get_block_categories')) {
$handoff_categories = handoff_get_block_categories();
} else {
// Fallback to default category
$handoff_categories = [
[
'slug' => 'handoff',
'title' => __('Handoff Blocks', 'handoff'),
'icon' => 'admin-customizer',
],
];
}
return array_merge($categories, $handoff_categories);
}
add_filter('block_categories_all', 'handoff_blocks_block_category', 10, 2);
/**
* Load plugin textdomain
*/
function handoff_blocks_load_textdomain() {
load_plugin_textdomain(
'handoff',
false,
dirname(plugin_basename(__FILE__)) . '/languages'
);
}
add_action('plugins_loaded', 'handoff_blocks_load_textdomain');
/**
* Control which blocks are available in the editor
*
* This disables all core Gutenberg blocks by default and only allows:
* - All Handoff blocks (handoff/*)
* - A curated list of essential core blocks
*
* To add more core blocks, add them to the $allowed_core_blocks array.
* To disable this filter entirely, set HANDOFF_ALLOW_ALL_BLOCKS to true.
*/
function handoff_blocks_allowed_block_types($allowed_block_types, $editor_context) {
// Allow disabling this filter via constant
if (defined('HANDOFF_ALLOW_ALL_BLOCKS') && HANDOFF_ALLOW_ALL_BLOCKS) {
return $allowed_block_types;
}
// Essential core blocks that should remain available
// Add or remove blocks from this list as needed
$allowed_core_blocks = [
// Text blocks
'core/paragraph',
'core/heading',
'core/list',
'core/list-item',
'core/quote',
'core/code',
'core/preformatted',
'core/pullquote',
'core/verse',
// Media blocks
// 'core/image',
// 'core/gallery',
// 'core/audio',
// 'core/video',
// 'core/file',
// 'core/media-text',
// // Layout blocks
// 'core/group',
// 'core/columns',
// 'core/column',
// 'core/separator',
// 'core/spacer',
// 'core/buttons',
// 'core/button',
// // Widget blocks
// 'core/shortcode',
// 'core/html',
// // Embed blocks
// 'core/embed',
// // Reusable blocks
// 'core/block',
// 'core/pattern',
];
// Get all registered Handoff blocks
$handoff_blocks = [];
$registered_blocks = WP_Block_Type_Registry::get_instance()->get_all_registered();
foreach ($registered_blocks as $block_name => $block_type) {
if (strpos($block_name, 'handoff/') === 0) {
$handoff_blocks[] = $block_name;
}
}
// Combine allowed core blocks with all Handoff blocks
$allowed_blocks = array_merge($allowed_core_blocks, $handoff_blocks);
// Apply filter to allow themes/plugins to modify the list
$allowed_blocks = apply_filters('handoff_allowed_blocks', $allowed_blocks, $editor_context);
return $allowed_blocks;
}
add_filter('allowed_block_types_all', 'handoff_blocks_allowed_block_types', 10, 2);
/**
* Remove unwanted block patterns from core
* This cleans up the pattern inserter to focus on custom patterns
*/
function handoff_blocks_remove_core_patterns() {
// Remove remote patterns from WordPress.org
remove_theme_support('core-block-patterns');
}
add_action('after_setup_theme', 'handoff_blocks_remove_core_patterns');
/**
* Optionally hide specific block categories
* Uncomment and modify to hide entire categories from the inserter
*/
// function handoff_blocks_filter_categories($categories, $editor_context) {
// // Remove categories you don't want
// $hidden_categories = ['widgets', 'embed', 'theme'];
//
// return array_filter($categories, function($category) use ($hidden_categories) {
// return !in_array($category['slug'], $hidden_categories);
// });
// }
// add_filter('block_categories_all', 'handoff_blocks_filter_categories', 20, 2);