← All changes
|
includes/abilities/widgets/wdesignkit-import-widget.php
+21
-8
2.6.3
→
2.7.1
View file →
| @@ -56,8 +56,9 @@ | ||
| 56 | 56 | ], |
| 57 | 57 | 'execute_callback' => 'wdesignkit_mcp_import_widget', |
| 58 | 58 | 'permission_callback' => 'wdesignkit_mcp_permission_callback', |
| 59 | 59 | 'meta' => [ |
| 60 | + 'public' => true, | |
| 60 | 61 | 'show_in_rest' => true, |
| 61 | 62 | 'mcp' => ['public' => true], |
| 62 | 63 | 'annotations' => [ |
| 63 | 64 | 'instructions' => implode("\n", [ |
| @@ -106,12 +107,15 @@ | ||
| 106 | 107 | return ['success' => false, 'message' => "Unsupported builder type: {$builder}."]; |
| 107 | 108 | } |
| 108 | 109 | |
| 109 | 110 | $overwrite = !empty($input['overwrite']); |
| 110 | - $safe_name = sanitize_file_name($widget_name); | |
| 111 | - $safe_id = sanitize_file_name($widget_id); | |
| 112 | - $folder_name = str_replace(' ', '-', $safe_name) . '_' . $safe_id; | |
| 113 | - $file_name = str_replace(' ', '_', $safe_name) . '_' . $safe_id; | |
| 111 | + // Canonical helpers: they replace spaces BEFORE sanitize_file_name(). Sanitising first | |
| 112 | + // (as this did) already collapsed spaces to hyphens, so the underscore pass was a no-op | |
| 113 | + // and a multi-word title produced "My-Widget_id.json" while the builder's own save path | |
| 114 | + // writes "My_Widget_id.php". The registry resolves the JSON by swapping .php for .json, | |
| 115 | + // so that pair never matched and the widget was skipped for good (ClickUp 86d41cck5). | |
| 116 | + $folder_name = wdesignkit_widget_folder_name($widget_name, $widget_id); | |
| 117 | + $file_name = wdesignkit_widget_file_name($widget_name, $widget_id); | |
| 114 | 118 | $builder_dir = WDKIT_BUILDER_PATH . '/' . $builder; |
| 115 | 119 | $widget_dir = $builder_dir . '/' . $folder_name; |
| 116 | 120 | |
| 117 | 121 | // Duplicate check / overwrite: scan for any existing folder sharing the same widget_id. |
| @@ -215,12 +219,17 @@ | ||
| 215 | 219 | } |
| 216 | 220 | } |
| 217 | 221 | |
| 218 | 222 | if ($img_bytes !== '') { |
| 219 | - $img_ext = preg_replace('/[^a-z0-9]/', '', strtolower($img_ext)); | |
| 220 | - if ($img_ext === '') { | |
| 221 | - $img_ext = 'png'; | |
| 222 | - } | |
| 223 | + // Both branches above take the extension from caller-supplied data — a data-URI subtype or | |
| 224 | + // the remote URL. The old preg_replace() only stripped punctuation, so "php" survived and | |
| 225 | + // this write could drop executable PHP into the builder directory (CWE-434, | |
| 226 | + // ClickUp 86d41cczd). Verify against the decoded bytes instead; '' means not an image. | |
| 227 | + // The synthetic "image.<ext>" filename lets the helper read either branch's extension. | |
| 228 | + $img_ext = wdesignkit_safe_image_extension('image.' . strtolower((string) $img_ext), $img_bytes); | |
| 229 | + } | |
| 230 | + | |
| 231 | + if ($img_bytes !== '' && $img_ext !== '') { | |
| 223 | 232 | $img_path = $widget_dir . '/' . $file_name . '.' . $img_ext; |
| 224 | 233 | if (@file_put_contents($img_path, $img_bytes) !== false) { |
| 225 | 234 | $image_saved = true; |
| 226 | 235 | // Point the JSON at the local thumbnail so it renders in the library and push finds it. |
| @@ -234,8 +243,12 @@ | ||
| 234 | 243 | |
| 235 | 244 | $thumb_note = $image_saved |
| 236 | 245 | ? ($image_source === 'bundled' ? ' Bundled thumbnail imported.' : ' Thumbnail downloaded.') |
| 237 | 246 | : ''; |
| 247 | + | |
| 248 | + if (function_exists('wdesignkit_invalidate_widget_registry')) { | |
| 249 | + wdesignkit_invalidate_widget_registry($builder); | |
| 250 | + } | |
| 238 | 251 | |
| 239 | 252 | return [ |
| 240 | 253 | 'success' => true, |
| 241 | 254 | 'message' => "Widget '{$widget_name}' imported successfully." . $thumb_note, |