← All changes
|
includes/abilities/widgets/wdesignkit-create-widget.php
+261
-28
2.6.0
→
2.7.0
View file →
| @@ -26,9 +26,9 @@ | ||
| 26 | 26 | 'maxLength' => 64, |
| 27 | 27 | ], |
| 28 | 28 | 'builder' => [ |
| 29 | 29 | 'type' => 'string', |
| 30 | - 'description' => 'Target page builder.', | |
| 30 | + 'description' => 'Target page builder. Use "gutenberg" for Nexter Blocks / The Plus Addons for Block Editor (TPGB) — "Nexter", "Nexter Blocks", "TPGB", and "Plus Block Editor" all map to builder=gutenberg; it builds a block on the Pmgc component framework. Use "gutenberg_core" for a plain native WordPress block with no TPGB dependency. Note: "Nexter Extension" is a separate plugin, not a builder.', | |
| 31 | 31 | 'enum' => ['elementor', 'gutenberg', 'gutenberg_core', 'bricks'], |
| 32 | 32 | ], |
| 33 | 33 | 'description' => [ |
| 34 | 34 | 'type' => 'string', |
| @@ -119,8 +119,9 @@ | ||
| 119 | 119 | ], |
| 120 | 120 | 'execute_callback' => 'wdesignkit_mcp_create_widget', |
| 121 | 121 | 'permission_callback' => 'wdesignkit_mcp_permission_callback', |
| 122 | 122 | 'meta' => [ |
| 123 | + 'public' => true, | |
| 123 | 124 | 'show_in_rest' => true, |
| 124 | 125 | 'mcp' => ['public' => true], |
| 125 | 126 | 'annotations' => [ |
| 126 | 127 | 'instructions' => implode("\n", [ |
| @@ -146,8 +147,12 @@ | ||
| 146 | 147 | '### Required inputs', |
| 147 | 148 | '- name: 1–64 chars. Letters, numbers, spaces, hyphens, underscores ONLY.', |
| 148 | 149 | ' Special characters are REJECTED with an error — do not pass them. Names must be unique per builder.', |
| 149 | 150 | '- builder: one of elementor | gutenberg | gutenberg_core | bricks', |
| 151 | + ' Builder aliases — "Nexter" / "Nexter Blocks" / "TPGB" / "The Plus Addons for Block Editor" / "Plus Block Editor" all mean builder=gutenberg.', | |
| 152 | + ' gutenberg = Nexter Blocks (TPGB): block built on the Pmgc component framework', | |
| 153 | + ' (Pmgc_PanelTabs/Pmgc_Tab inspector, Pmgc_CssGenerator styling), loaded from the gutenberg/ folder.', | |
| 154 | + ' "gutenberg_core" = plain native WordPress blocks (no TPGB framework). "Nexter Extension" is a SEPARATE plugin, NOT a builder — do not treat it as the target builder.', | |
| 150 | 155 | '', |
| 151 | 156 | '### Code inputs (php_code, css_code, js_code, cdn_js, cdn_css, section_data, editor_html)', |
| 152 | 157 | '- php_code / css_code / js_code: COMPLETE file replacements, not partial snippets.', |
| 153 | 158 | '- STRONGLY RECOMMENDED: omit php_code and let the ability generate correct boilerplate.', |
| @@ -237,8 +242,18 @@ | ||
| 237 | 242 | '### After creation', |
| 238 | 243 | '- Use wdesignkit/get-widget to read back the generated files.', |
| 239 | 244 | '- Use wdesignkit/update-widget to modify code.', |
| 240 | 245 | '- Does NOT require WDesignKit cloud login.', |
| 246 | + '', | |
| 247 | + '### ⚠ Trust boundary — this ability executes PHP', | |
| 248 | + 'The php_code written here is saved to disk and require_once\'d by the builder', | |
| 249 | + 'loaders on subsequent requests, so calling this ability runs arbitrary PHP as the', | |
| 250 | + 'web server user. That is what a widget builder is, and it is gated on', | |
| 251 | + 'manage_options — the same capability WordPress requires for the plugin editor.', | |
| 252 | + 'It does mean this ability, create-widget and update-widget, must never be exposed', | |
| 253 | + 'to any automation context trusted below a full site administrator. Treat php_code', | |
| 254 | + 'from an untrusted source exactly as you would treat pasting it into wp-admin.', | |
| 255 | + '(ClickUp 86d41zavc)', | |
| 241 | 256 | ]), |
| 242 | 257 | 'readonly' => false, |
| 243 | 258 | 'destructive' => false, |
| 244 | 259 | 'idempotent' => false, |
| @@ -253,8 +268,20 @@ | ||
| 253 | 268 | 'message' => 'WDesignKit plugin is not active.', |
| 254 | 269 | ]; |
| 255 | 270 | } |
| 256 | 271 | |
| 272 | + // Site-level opt-out for generated widget PHP (ClickUp 86d41zavc). Defaults to allowed, so | |
| 273 | + // this changes nothing unless an operator explicitly filters it off: | |
| 274 | + // add_filter( 'wdesignkit_allow_widget_php_write', '__return_false' ); | |
| 275 | + // See wdesignkit_widget_php_write_allowed() for why this is a dedicated filter rather than a | |
| 276 | + // DISALLOW_FILE_MODS / DISALLOW_FILE_EDIT check. | |
| 277 | + if (function_exists('wdesignkit_widget_php_write_allowed') && !wdesignkit_widget_php_write_allowed()) { | |
| 278 | + return [ | |
| 279 | + 'success' => false, | |
| 280 | + 'message' => 'Widget creation is disabled on this site: generated widget PHP writes have been turned off via the wdesignkit_allow_widget_php_write filter.', | |
| 281 | + ]; | |
| 282 | + } | |
| 283 | + | |
| 257 | 284 | // --- Validate name --- |
| 258 | 285 | $raw_name = $input['name'] ?? ''; |
| 259 | 286 | if (!is_string($raw_name) || trim($raw_name) === '') { |
| 260 | 287 | return ['success' => false, 'message' => 'Widget name is required.']; |
| @@ -337,19 +364,16 @@ | ||
| 337 | 364 | return ['success' => false, 'message' => 'Invalid version format. Use semver format like "1.0.0".']; |
| 338 | 365 | } |
| 339 | 366 | |
| 340 | 367 | // --- Generate folder and file names matching WDesignKit convention --- |
| 341 | - // folder: kebab-case (e.g. "my-custom-card") | |
| 342 | - // file: snake_case (e.g. "my_custom_card") | |
| 343 | - // Normalize ALL separators: folder is pure kebab-case, file is pure snake_case. | |
| 344 | - // Without this, a name like "My-Custom Widget" produces "my-custom_widget" (mixed). | |
| 345 | - $folder_base = sanitize_file_name(strtolower(str_replace([' ', '_'], '-', $name))); | |
| 346 | - $file_base = sanitize_file_name(strtolower(str_replace([' ', '-'], '_', $name))); | |
| 347 | - | |
| 368 | + // folder: "My-Custom-Card_<hash>" file: "My_Custom_Card_<hash>" | |
| 369 | + // Case is PRESERVED. This used to lowercase both, which put widgets created here in a | |
| 370 | + // different folder than the one the download/import/save paths write — the same widget | |
| 371 | + // ended up in two directories differing only by case (ClickUp 86d3yk4yx). | |
| 348 | 372 | // 8-character unique hex hash — matches the real WDesignKit widget format (e.g. "kmrd6l24") |
| 349 | 373 | $widget_hash = substr(md5(uniqid('wdkit', true)), 0, 8); |
| 350 | - $folder_name_full = $folder_base . '_' . $widget_hash; | |
| 351 | - $file_name_full = $file_base . '_' . $widget_hash; | |
| 374 | + $folder_name_full = wdesignkit_widget_folder_name($name, $widget_hash); | |
| 375 | + $file_name_full = wdesignkit_widget_file_name($name, $widget_hash); | |
| 352 | 376 | |
| 353 | 377 | // widget_id = JUST the hash (matches the real widget JSON format: "widget_id":"20hzyv26") |
| 354 | 378 | $widget_id = $widget_hash; |
| 355 | 379 | |
| @@ -422,14 +446,23 @@ | ||
| 422 | 446 | $php_code = wdesignkit_mcp_generate_php( |
| 423 | 447 | $builder, $class_name, $name, $folder_name_full, $file_name_full, |
| 424 | 448 | $description, $category, $widget_hash, $version |
| 425 | 449 | ); |
| 426 | - } elseif ($builder === 'elementor') { | |
| 427 | - // Auto-correct common mistakes in AI-provided Elementor PHP: | |
| 428 | - // wrong class name, wrong get_name() return value, missing asset-enqueue methods. | |
| 429 | - $php_code = wdesignkit_mcp_fix_elementor_php( | |
| 430 | - $php_code, $file_name_full, $widget_hash, $folder_name_full, $version | |
| 431 | - ); | |
| 450 | + } else { | |
| 451 | + // Caller-supplied PHP must live in the global namespace. Every builder's widget | |
| 452 | + // loader instantiates/registers the class by its bare global name (e.g. the | |
| 453 | + // Elementor loader calls `new Wdkit_{file}()`), so a `namespace ...;` declaration | |
| 454 | + // makes the class resolve as Namespace\Wdkit_xxx and the loader fatals with | |
| 455 | + // "Class not found", crashing every editor/frontend load. Strip it before writing. | |
| 456 | + $php_code = wdesignkit_mcp_strip_php_namespace($php_code); | |
| 457 | + | |
| 458 | + if ($builder === 'elementor') { | |
| 459 | + // Auto-correct common mistakes in AI-provided Elementor PHP: | |
| 460 | + // wrong class name, wrong get_name() return value, missing asset-enqueue methods. | |
| 461 | + $php_code = wdesignkit_mcp_fix_elementor_php( | |
| 462 | + $php_code, $file_name_full, $widget_hash, $folder_name_full, $version | |
| 463 | + ); | |
| 464 | + } | |
| 432 | 465 | } |
| 433 | 466 | |
| 434 | 467 | $js_code = (string) ($input['js_code'] ?? ''); |
| 435 | 468 | if (empty($js_code)) { |
| @@ -519,8 +552,22 @@ | ||
| 519 | 552 | if (file_put_contents($widget_file_base . '.css', $css_code) === false) { |
| 520 | 553 | $write_errors[] = 'CSS'; |
| 521 | 554 | } |
| 522 | 555 | |
| 556 | + // Thumbnail: create-widget has no image input and the JSON's w_image points at | |
| 557 | + // {file}.png, so without this every new widget shows a broken image in the library | |
| 558 | + // AND push-widget's pre-flight (which scans the folder for a jpg/png/webp) blocks the | |
| 559 | + // push. Seed a real default thumbnail from the bundled placeholder so both work; the | |
| 560 | + // caller can overwrite {file}.png later with a custom image. Best-effort — never fail | |
| 561 | + // widget creation over the thumbnail. (bug: 86d3rc7n8) | |
| 562 | + $thumb_written = false; | |
| 563 | + if (defined('WDKIT_PATH')) { | |
| 564 | + $default_thumb = WDKIT_PATH . 'assets/images/jpg/placeholder.png'; | |
| 565 | + if (is_readable($default_thumb)) { | |
| 566 | + $thumb_written = @copy($default_thumb, $widget_file_base . '.png'); | |
| 567 | + } | |
| 568 | + } | |
| 569 | + | |
| 523 | 570 | if (!empty($write_errors)) { |
| 524 | 571 | return [ |
| 525 | 572 | 'success' => false, |
| 526 | 573 | 'message' => 'Failed to write files: ' . implode(', ', $write_errors) . '. Check directory permissions.', |
| @@ -526,8 +573,22 @@ | ||
| 526 | 573 | 'message' => 'Failed to write files: ' . implode(', ', $write_errors) . '. Check directory permissions.', |
| 527 | 574 | ]; |
| 528 | 575 | } |
| 529 | 576 | |
| 577 | + if (function_exists('wdesignkit_invalidate_widget_registry')) { | |
| 578 | + wdesignkit_invalidate_widget_registry($builder); | |
| 579 | + } | |
| 580 | + | |
| 581 | + $created_files = [ | |
| 582 | + $file_name_full . '.php', | |
| 583 | + $file_name_full . '.json', | |
| 584 | + $file_name_full . '.js', | |
| 585 | + $file_name_full . '.css', | |
| 586 | + ]; | |
| 587 | + if ($thumb_written) { | |
| 588 | + $created_files[] = $file_name_full . '.png'; | |
| 589 | + } | |
| 590 | + | |
| 530 | 591 | return [ |
| 531 | 592 | 'success' => true, |
| 532 | 593 | 'message' => "Widget '{$name}' created successfully for {$builder}.", |
| 533 | 594 | 'widget' => [ |
| @@ -534,14 +595,9 @@ | ||
| 534 | 595 | 'name' => $name, |
| 535 | 596 | 'builder' => $builder, |
| 536 | 597 | 'folder' => $folder_name_full, |
| 537 | 598 | 'widget_id' => $widget_id, // 8-char hash — use with activate/deactivate-widget |
| 538 | - 'files' => [ | |
| 539 | - $file_name_full . '.php', | |
| 540 | - $file_name_full . '.json', | |
| 541 | - $file_name_full . '.js', | |
| 542 | - $file_name_full . '.css', | |
| 543 | - ], | |
| 599 | + 'files' => $created_files, | |
| 544 | 600 | 'version' => $version, |
| 545 | 601 | 'css_class' => $widget_css_class, |
| 546 | 602 | ], |
| 547 | 603 | ]; |
| @@ -948,8 +1004,29 @@ | ||
| 948 | 1004 | return $php_code; |
| 949 | 1005 | } |
| 950 | 1006 | |
| 951 | 1007 | /** |
| 1008 | + * Strip a top-level `namespace ...;` declaration from caller-supplied widget PHP. | |
| 1009 | + * | |
| 1010 | + * Every WDesignKit widget loader (Elementor, Bricks, Gutenberg) instantiates or | |
| 1011 | + * registers the widget class by its bare global name. A namespace declaration makes | |
| 1012 | + * the class resolve as Namespace\Wdkit_xxx, so the loader's `new Wdkit_xxx()` fatals | |
| 1013 | + * with "Class not found" and takes down the whole site. Generated boilerplate never | |
| 1014 | + * declares a namespace — this only guards caller-supplied php_code. | |
| 1015 | + * | |
| 1016 | + * Only the common semicolon form (`namespace Foo\Bar;`) is removed; `use` statements | |
| 1017 | + * are left intact as they remain valid global aliases. | |
| 1018 | + */ | |
| 1019 | +function wdesignkit_mcp_strip_php_namespace(string $php_code): string { | |
| 1020 | + return preg_replace( | |
| 1021 | + '/\bnamespace\s+[A-Za-z0-9_\\\\]+\s*;/', | |
| 1022 | + '', | |
| 1023 | + $php_code, | |
| 1024 | + 1 | |
| 1025 | + ) ?? $php_code; | |
| 1026 | +} | |
| 1027 | + | |
| 1028 | +/** | |
| 952 | 1029 | * Generate Gutenberg / Gutenberg Core block PHP boilerplate. |
| 953 | 1030 | * |
| 954 | 1031 | * Uses wp_upload_dir() for SSL-safe asset URLs. |
| 955 | 1032 | * Uses $file_name (includes unique hash) for function name — no collision possible. |
| @@ -968,8 +1045,48 @@ | ||
| 968 | 1045 | |
| 969 | 1046 | // Collision-safe function name: derived from full $file_name (includes unique hash) |
| 970 | 1047 | $func_name = str_replace(['-', '.'], '_', $file_name); |
| 971 | 1048 | |
| 1049 | + $block_title = 'gutenberg' === $builder ? 'Nexter Blocks (TPGB) Block' : 'Gutenberg Block'; | |
| 1050 | + | |
| 1051 | + // builder=gutenberg targets Nexter Blocks / TPGB. Its editor JS uses the Pmgc | |
| 1052 | + // component framework, which lives in wkit_g_pmgc.js — registered under the handle | |
| 1053 | + // 'wkit-editor-block-pmgc' by the WDesignKit gutenberg loader (editor_assets() in | |
| 1054 | + // class-wdkit-gutenberg-files-load.php) and by nothing else. Declaring that handle | |
| 1055 | + // unconditionally would make WordPress silently drop this entire script — and the | |
| 1056 | + // block with it — on any site where WDesignKit is not active (WP_Dependencies::all_deps() | |
| 1057 | + // discards a script whose dependency was never registered). Whether WDesignKit is | |
| 1058 | + // present is a runtime fact of the destination site, so gate it on the constant. | |
| 1059 | + // Mirrors the widget builder's own output in src/widget-builder/file-creation/gutenberg_file.js. | |
| 1060 | + $deps_block = 'gutenberg' === $builder | |
| 1061 | + ? <<<PHP | |
| 1062 | + | |
| 1063 | + \$wdkit_block_deps = [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n' ]; | |
| 1064 | + | |
| 1065 | + if ( defined( 'WDKIT_VERSION' ) ) { | |
| 1066 | + \$wdkit_block_deps[] = 'wkit-editor-block-pmgc'; | |
| 1067 | + } | |
| 1068 | + | |
| 1069 | +PHP | |
| 1070 | + : ''; | |
| 1071 | + | |
| 1072 | + $deps_arg = 'gutenberg' === $builder | |
| 1073 | + ? '$wdkit_block_deps' | |
| 1074 | + : "[ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n' ]"; | |
| 1075 | + | |
| 1076 | + // The TPGB editor JS stores the per-instance id it styles through Pmgc_CssGenerator. | |
| 1077 | + $attributes_block = 'gutenberg' === $builder | |
| 1078 | + ? <<<PHP | |
| 1079 | + | |
| 1080 | + 'attributes' => [ | |
| 1081 | + 'block_id' => [ | |
| 1082 | + 'type' => 'string', | |
| 1083 | + 'default' => '', | |
| 1084 | + ], | |
| 1085 | + ], | |
| 1086 | +PHP | |
| 1087 | + : ''; | |
| 1088 | + | |
| 972 | 1089 | return <<<PHP |
| 973 | 1090 | <?php |
| 974 | 1091 | /* |
| 975 | 1092 | * Widget Name: {$name} |
| @@ -983,9 +1100,9 @@ | ||
| 983 | 1100 | exit; |
| 984 | 1101 | } |
| 985 | 1102 | |
| 986 | 1103 | /** |
| 987 | - * {$name} - Gutenberg Block | |
| 1104 | + * {$name} - {$block_title} | |
| 988 | 1105 | * {$description} |
| 989 | 1106 | */ |
| 990 | 1107 | if ( ! function_exists( 'wdkit_{$func_name}_register_block' ) ) { |
| 991 | 1108 | function wdkit_{$func_name}_register_block() { |
| @@ -990,13 +1107,13 @@ | ||
| 990 | 1107 | if ( ! function_exists( 'wdkit_{$func_name}_register_block' ) ) { |
| 991 | 1108 | function wdkit_{$func_name}_register_block() { |
| 992 | 1109 | \$upload_dir = wp_upload_dir(); |
| 993 | 1110 | \$baseurl = set_url_scheme( \$upload_dir['baseurl'], is_ssl() ? 'https' : 'http' ); |
| 994 | - | |
| 1111 | +{$deps_block} | |
| 995 | 1112 | wp_register_script( |
| 996 | 1113 | 'wdkit-{$slug}-editor', |
| 997 | 1114 | \$baseurl . '/wdesignkit/{$builder}/{$folder_name}/{$file_name}.js', |
| 998 | - [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n' ], | |
| 1115 | + {$deps_arg}, | |
| 999 | 1116 | '{$version}', |
| 1000 | 1117 | true |
| 1001 | 1118 | ); |
| 1002 | 1119 | |
| @@ -1009,9 +1126,9 @@ | ||
| 1009 | 1126 | |
| 1010 | 1127 | register_block_type( 'wdkit/{$slug}', [ |
| 1011 | 1128 | 'editor_script' => 'wdkit-{$slug}-editor', |
| 1012 | 1129 | 'editor_style' => 'wdkit-{$slug}-style', |
| 1013 | - 'style' => 'wdkit-{$slug}-style', | |
| 1130 | + 'style' => 'wdkit-{$slug}-style',{$attributes_block} | |
| 1014 | 1131 | ] ); |
| 1015 | 1132 | } |
| 1016 | 1133 | } |
| 1017 | 1134 | add_action( 'init', 'wdkit_{$func_name}_register_block' ); |
| @@ -1172,11 +1289,127 @@ | ||
| 1172 | 1289 | // WDesignKit executes widget JS in the element_ready scope automatically. |
| 1173 | 1290 | return ''; |
| 1174 | 1291 | } |
| 1175 | 1292 | |
| 1176 | - if ($builder === 'gutenberg' || $builder === 'gutenberg_core') { | |
| 1293 | + if ($builder === 'gutenberg') { | |
| 1294 | + // Nexter Blocks (TPGB) variant. The difference from gutenberg_core is the | |
| 1295 | + // component framework: the inspector is built from Pmgc_PanelTabs/Pmgc_Tab and | |
| 1296 | + // per-instance CSS is emitted through Pmgc_CssGenerator, all served by | |
| 1297 | + // wkit_g_pmgc.js. Every Pmgc component is used behind a guard with a native | |
| 1298 | + // fallback, so the block still registers and renders when Nexter Blocks is not | |
| 1299 | + // installed. Mirrors src/widget-builder/file-creation/gutenberg_file.js. | |
| 1300 | + $pmgc_id = $widget_hash !== '' ? 'wb-' . $widget_hash : 'wb-' . $slug; | |
| 1301 | + | |
| 1177 | 1302 | return <<<JS |
| 1178 | 1303 | /** |
| 1304 | + * {$name} - Nexter Blocks (TPGB) Block | |
| 1305 | + */ | |
| 1306 | +(function(blocks, element, blockEditor, components, i18n) { | |
| 1307 | + var el = element.createElement; | |
| 1308 | + var Fragment = element.Fragment; | |
| 1309 | + var __ = i18n.__; | |
| 1310 | + var InspectorControls = blockEditor.InspectorControls; | |
| 1311 | + var TextControl = components.TextControl; | |
| 1312 | + var TextareaControl = components.TextareaControl; | |
| 1313 | + var PanelBody = components.PanelBody; | |
| 1314 | + | |
| 1315 | + // Registered on window.wp by wkit_g_pmgc.js (script handle 'wkit-editor-block-pmgc'), | |
| 1316 | + // which the WDesignKit gutenberg loader enqueues in the block editor. | |
| 1317 | + var PmgcComponents = window.wp.Pmgc_Components || {}; | |
| 1318 | + var Pmgc_PanelTabs = PmgcComponents.Pmgc_PanelTabs; | |
| 1319 | + var Pmgc_Tab = PmgcComponents.Pmgc_Tab; | |
| 1320 | + var Pmgc_CssGenerator = PmgcComponents.Pmgc_CssGenerator; | |
| 1321 | + | |
| 1322 | + blocks.registerBlockType('wdkit/{$slug}', { | |
| 1323 | + title: __('{$safe_name}', 'wdesignkit'), | |
| 1324 | + description: __('{$safe_desc}', 'wdesignkit'), | |
| 1325 | + icon: el('i', { className: 'wdkit-icon tpae-wdkit-logo' }), | |
| 1326 | + category: '{$safe_cat}', | |
| 1327 | + attributes: { | |
| 1328 | + block_id: { type: 'string', default: '' }, | |
| 1329 | + title: { type: 'string', default: '{$safe_name}' }, | |
| 1330 | + description: { type: 'string', default: '{$safe_desc}' } | |
| 1331 | + }, | |
| 1332 | + | |
| 1333 | + edit: function(props) { | |
| 1334 | + var attributes = props.attributes; | |
| 1335 | + var block_id = props.clientId.substr(0, 6); | |
| 1336 | + | |
| 1337 | + if (attributes.block_id !== block_id) { | |
| 1338 | + props.setAttributes({ block_id: block_id }); | |
| 1339 | + } | |
| 1340 | + | |
| 1341 | + var settings = [ | |
| 1342 | + el(TextControl, { | |
| 1343 | + key: 'title', | |
| 1344 | + label: __('Title', 'wdesignkit'), | |
| 1345 | + value: attributes.title, | |
| 1346 | + onChange: function(val) { props.setAttributes({ title: val }); } | |
| 1347 | + }), | |
| 1348 | + el(TextareaControl, { | |
| 1349 | + key: 'description', | |
| 1350 | + label: __('Description', 'wdesignkit'), | |
| 1351 | + value: attributes.description, | |
| 1352 | + onChange: function(val) { props.setAttributes({ description: val }); } | |
| 1353 | + }) | |
| 1354 | + ]; | |
| 1355 | + | |
| 1356 | + // Nexter Blocks tabbed inspector when TPGB is available, native panel otherwise. | |
| 1357 | + var inspector = (Pmgc_PanelTabs && Pmgc_Tab) | |
| 1358 | + ? el(InspectorControls, null, | |
| 1359 | + el(Pmgc_PanelTabs, null, | |
| 1360 | + el(Pmgc_Tab, { tabTitle: __('Layout', 'wdesignkit') }, settings), | |
| 1361 | + el(Pmgc_Tab, { tabTitle: __('Style', 'wdesignkit') }) | |
| 1362 | + ) | |
| 1363 | + ) | |
| 1364 | + : el(InspectorControls, null, | |
| 1365 | + el(PanelBody, { title: __('{$safe_name} Settings', 'wdesignkit') }, settings) | |
| 1366 | + ); | |
| 1367 | + | |
| 1368 | + if (attributes.block_id && Pmgc_CssGenerator) { | |
| 1369 | + var node = document.getElementsByClassName('tpgb-block-' + block_id); | |
| 1370 | + if (null != node && 'undefined' !== typeof node) { | |
| 1371 | + Pmgc_CssGenerator(attributes, 'wdkit', '{$pmgc_id}', block_id, false, props.clientId); | |
| 1372 | + } | |
| 1373 | + } | |
| 1374 | + | |
| 1375 | + return el(Fragment, null, inspector, | |
| 1376 | + el('div', { className: 'wkit-wb-Widget_{$widget_hash} wdkit-block-' + block_id }, | |
| 1377 | + el('h3', {}, attributes.title), | |
| 1378 | + el('p', {}, attributes.description) | |
| 1379 | + ) | |
| 1380 | + ); | |
| 1381 | + }, | |
| 1382 | + | |
| 1383 | + save: function(props) { | |
| 1384 | + var attributes = props.attributes; | |
| 1385 | + var block_id = attributes.block_id; | |
| 1386 | + var styleCss = Pmgc_CssGenerator | |
| 1387 | + ? Pmgc_CssGenerator(attributes, 'wdkit', '{$pmgc_id}', block_id, true) | |
| 1388 | + : ''; | |
| 1389 | + | |
| 1390 | + return el(Fragment, null, | |
| 1391 | + el('div', { className: 'wkit-wb-Widget_{$widget_hash} wdkit-block-' + block_id }, | |
| 1392 | + el('h3', {}, attributes.title), | |
| 1393 | + el('p', {}, attributes.description) | |
| 1394 | + ), | |
| 1395 | + el('style', null, styleCss) | |
| 1396 | + ); | |
| 1397 | + } | |
| 1398 | + }); | |
| 1399 | +})( | |
| 1400 | + window.wp.blocks, | |
| 1401 | + window.wp.element, | |
| 1402 | + window.wp.blockEditor, | |
| 1403 | + window.wp.components, | |
| 1404 | + window.wp.i18n | |
| 1405 | +); | |
| 1406 | +JS; | |
| 1407 | + } | |
| 1408 | + | |
| 1409 | + if ($builder === 'gutenberg_core') { | |
| 1410 | + return <<<JS | |
| 1411 | +/** | |
| 1179 | 1412 | * {$name} - Gutenberg Block |
| 1180 | 1413 | */ |
| 1181 | 1414 | (function(blocks, element, blockEditor, components, i18n) { |
| 1182 | 1415 | var el = element.createElement; |
| @@ -2238,9 +2471,9 @@ | ||
| 2238 | 2471 | if ($wdk_type === '') { |
| 2239 | 2472 | return null; // Unsupported type — skip |
| 2240 | 2473 | } |
| 2241 | 2474 | |
| 2242 | - $json_name = $wdk_type . '_' . $php_name; | |
| 2475 | + $json_name = $php_name; | |
| 2243 | 2476 | $label = wdesignkit_mcp_php_get_string($args, 'label'); |
| 2244 | 2477 | |
| 2245 | 2478 | $ctrl = [ |
| 2246 | 2479 | '_php_name' => $php_name, // temp — removed after map update |