From 9b78dd4168c85fa6726489c9dcbe7b295e4b24c8 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Thu, 25 Jun 2026 15:49:57 -0400 Subject: [PATCH 1/3] Post Figma imports to local Studio --- docs/figma-studio-runner.md | 15 +++--- plugins/figma-to-wordpress-studio/README.md | 17 +++---- plugins/figma-to-wordpress-studio/src/ui.html | 2 +- plugins/figma-to-wordpress-studio/src/ui.ts | 46 ++++++++++++++++++- 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/docs/figma-studio-runner.md b/docs/figma-studio-runner.md index 65fcfa6..f74f9ce 100644 --- a/docs/figma-studio-runner.md +++ b/docs/figma-studio-runner.md @@ -1,6 +1,6 @@ # Figma to WordPress Studio -`plugins/figma-to-wordpress-studio` moves a Figma file into WordPress by preparing a Studio CLI source for `studio create --from `. Studio creates the site and imports the result with Static Site Importer and Blocks Engine. +`plugins/figma-to-wordpress-studio` moves a Figma file into WordPress by posting a Studio import source to the local WordPress Studio app. Studio creates the site and imports the result with Static Site Importer and Blocks Engine. ## Architecture @@ -8,12 +8,12 @@ Figma plugin UI -> Figma document scene data -> Studio import artifact JSON - -> studio create --from + -> local WordPress Studio handoff endpoint -> WordPress Studio site -> Static Site Importer / Blocks Engine inside WordPress ``` -The TypeScript boundary stops at artifact construction and a user-facing CLI command. WordPress, PHP, Static Site Importer, Blocks Engine, and Studio site orchestration remain Studio runtime concerns. +The TypeScript boundary stops at artifact construction and a local handoff request. WordPress, PHP, Static Site Importer, Blocks Engine, and Studio site orchestration remain Studio runtime concerns. ## Figma Iframe Limits @@ -27,7 +27,7 @@ Practical constraints for this browser-based flow: - Clipboard access can require user activation. - Local file URLs can behave differently between desktop Figma, browser Figma, and development builds. -Because of those constraints, the primary integration shape is a CLI handoff: the plugin saves an artifact JSON source and presents/copies `studio create --from `. If a native bridge or deeper Studio integration exists later, it can consume the same artifact source. +Because of those constraints, the primary integration shape is a local Studio handoff: the plugin posts an artifact JSON source to Studio's loopback endpoint. If Studio is not running, the plugin saves the same artifact JSON source and presents/copies `studio create --from ` as a fallback. ## Studio And PHP Role @@ -41,7 +41,7 @@ Implemented now: - `GeneratedWebsiteArtifact` for static generated files from Figma. - `blocks-engine/php-transformer/site-artifact/v1` for the Studio CLI artifact handoff. -- A Figma UI client that downloads the artifact JSON and copies `studio create --from ./.studio-import.json`. +- A Figma UI client that posts the artifact JSON to local Studio and falls back to `studio create --from ./.studio-import.json`. Not implemented yet: @@ -62,8 +62,9 @@ Figma development test: 1. Run `npm run build --prefix plugins/figma-to-wordpress-studio`. 2. Load `plugins/figma-to-wordpress-studio/manifest.json` as a Figma development plugin. 3. Run the plugin. -4. Use `Save Studio import payload`. -5. Run the copied `studio create --from ./.studio-import.json` command from a terminal, adjusting the path to the saved artifact if needed. +4. Start a compatible WordPress Studio build. +5. Use `Open in WordPress Studio`. +6. Confirm the new site details in Studio. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. ## Next Integration Step diff --git a/plugins/figma-to-wordpress-studio/README.md b/plugins/figma-to-wordpress-studio/README.md index c03de27..0312cb8 100644 --- a/plugins/figma-to-wordpress-studio/README.md +++ b/plugins/figma-to-wordpress-studio/README.md @@ -1,8 +1,8 @@ # Figma to WordPress Studio -This plugin moves a Figma file into WordPress by preparing a Studio CLI import payload for `studio create --from `. +This plugin moves a Figma file into WordPress by sending a Studio import payload to the local WordPress Studio app. -It does not port Static Site Importer, Blocks Engine, WordPress, PHP, or Studio internals to TypeScript. The TypeScript code extracts Figma scene data, prepares an artifact JSON source, and gives the user the `studio create --from ...` command. Studio owns site creation, import through Static Site Importer, and cleanup after a successful import. +It does not port Static Site Importer, Blocks Engine, WordPress, PHP, or Studio internals to TypeScript. The TypeScript code extracts Figma scene data, prepares an artifact JSON source, and posts it to Studio's local handoff endpoint. Studio owns site creation, import through Static Site Importer, and cleanup after a successful import. If Studio is not running, the plugin saves the same payload and copies a `studio create --from ...` fallback command. ## Flow @@ -10,7 +10,7 @@ It does not port Static Site Importer, Blocks Engine, WordPress, PHP, or Studio Figma plugin controller + UI -> whole Figma document scene data -> Studio import artifact JSON - -> studio create --from + -> local WordPress Studio handoff endpoint -> WordPress Studio site -> Static Site Importer imports through Blocks Engine ``` @@ -19,7 +19,7 @@ Figma plugin controller + UI - Implemented: a Figma Desktop-loadable plugin shell with whole-file export. - Implemented: a reusable scene-to-HTML/CSS artifact generator with diagnostics and tests for the current local handoff. -- Implemented: a Studio CLI import payload and copyable `studio create --from ...` command. +- Implemented: a Studio local handoff request with a `studio create --from ...` fallback command. - Not implemented: running Static Site Importer from TypeScript. - Not implemented: automated visual parity/block validation after import. @@ -36,8 +36,9 @@ Figma plugin controller + UI 1. Run `npm run build --prefix plugins/figma-to-wordpress-studio`. 2. In Figma Desktop, use Plugins -> Development -> Import plugin from manifest, then select `plugins/figma-to-wordpress-studio/manifest.json`. -3. Open the plugin and choose `Save Studio import payload`. -4. Run the copied `studio create --from ./.studio-import.json` command from a terminal, adjusting the path to the saved artifact if needed. +3. Start a compatible WordPress Studio build. +4. Open the plugin and choose `Open in WordPress Studio`. +5. Confirm the new site details in Studio. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. For quick syntax verification without a full Figma build pipeline: @@ -47,8 +48,8 @@ npm run build --prefix plugins/figma-to-wordpress-studio npm test --prefix plugins/figma-to-wordpress-studio ``` -## Studio CLI Boundary +## Studio Handoff Boundary -Figma plugin UIs run in a constrained iframe-like environment and cannot spawn local shell commands. The supported boundary is a CLI handoff: the plugin saves the import artifact and presents/copies `studio create --from `. Studio accepts the artifact source, creates the site, runs Static Site Importer, and removes SSI after a successful import. +Figma plugin UIs run in a constrained iframe-like environment and cannot spawn local shell commands. The supported boundary is a local Studio handoff: the plugin posts the import artifact to Studio's loopback endpoint. Studio accepts the artifact source, creates the site, runs Static Site Importer, and removes SSI after a successful import. The CLI payload remains as an operator fallback and regression-friendly artifact. See [`../../docs/figma-studio-runner.md`](../../docs/figma-studio-runner.md) for the integration notes. diff --git a/plugins/figma-to-wordpress-studio/src/ui.html b/plugins/figma-to-wordpress-studio/src/ui.html index 518f09e..8a28156 100644 --- a/plugins/figma-to-wordpress-studio/src/ui.html +++ b/plugins/figma-to-wordpress-studio/src/ui.html @@ -109,7 +109,7 @@

Figma to WordPress Studio

- +
diff --git a/plugins/figma-to-wordpress-studio/src/ui.ts b/plugins/figma-to-wordpress-studio/src/ui.ts index 85466d2..9639264 100644 --- a/plugins/figma-to-wordpress-studio/src/ui.ts +++ b/plugins/figma-to-wordpress-studio/src/ui.ts @@ -8,6 +8,7 @@ const refreshButton = document.querySelector("#refresh"); const studioButton = document.querySelector("#studio"); const copyCommandButton = document.querySelector("#copy-command"); const commandElement = document.querySelector("#studio-command"); +const studioHandoffEndpoint = "http://127.0.0.1:48732/figma-to-wordpress/import"; function log(message: string, details?: unknown) { if (typeof details === "undefined") { @@ -97,6 +98,49 @@ function downloadStudioPayload() { void copyStudioCommand(); } +async function openInStudio() { + if (!currentArtifact) { + log("Studio import requested before artifact was ready."); + return; + } + + if (studioButton) { + studioButton.disabled = true; + } + setStatus("Sending this Figma file to WordPress Studio..."); + + try { + const response = await fetch(studioHandoffEndpoint, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + artifact: currentArtifact.studioImportPayload, + siteName: currentArtifact.title, + }), + }); + const data = await response.json().catch(() => null) as { success?: boolean; error?: string } | null; + + if (!response.ok || !data?.success) { + throw new Error(data?.error || `Studio handoff failed with HTTP ${response.status}.`); + } + + setStatus("Studio is opening the import. Confirm the new site details in WordPress Studio."); + sendToPlugin({ type: "notify", message: "Sent to WordPress Studio." }); + log("Studio import handoff accepted.", { + endpoint: studioHandoffEndpoint, + ...artifactBundleSummary(currentArtifact), + }); + } catch (error) { + console.error("[Figma to WordPress Studio] Studio handoff failed.", error); + setStatus("Could not reach WordPress Studio. Saved the import payload and copied the CLI fallback command."); + downloadStudioPayload(); + } finally { + updateActions(); + } +} + function countDesignScreens(selection: NormalizedSelection): number { let count = 0; @@ -149,7 +193,7 @@ window.onmessage = (event: MessageEvent<{ pluginMessage?: PluginToUiMessage }>) }; refreshButton?.addEventListener("click", () => sendToPlugin({ type: "refresh-document" })); -studioButton?.addEventListener("click", downloadStudioPayload); +studioButton?.addEventListener("click", () => void openInStudio()); copyCommandButton?.addEventListener("click", () => void copyStudioCommand()); log("UI loaded."); From bf74e692bc63102d999c6a50d9faa674cd36bab8 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Thu, 25 Jun 2026 16:15:47 -0400 Subject: [PATCH 2/3] Open Figma imports directly in Studio --- docs/figma-studio-runner.md | 2 +- plugins/figma-to-wordpress-studio/README.md | 2 +- plugins/figma-to-wordpress-studio/src/ui.html | 24 ------------------- plugins/figma-to-wordpress-studio/src/ui.ts | 7 +----- 4 files changed, 3 insertions(+), 32 deletions(-) diff --git a/docs/figma-studio-runner.md b/docs/figma-studio-runner.md index f74f9ce..af1d982 100644 --- a/docs/figma-studio-runner.md +++ b/docs/figma-studio-runner.md @@ -64,7 +64,7 @@ Figma development test: 3. Run the plugin. 4. Start a compatible WordPress Studio build. 5. Use `Open in WordPress Studio`. -6. Confirm the new site details in Studio. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. +6. Studio creates the site and opens the local site URL in your browser. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. ## Next Integration Step diff --git a/plugins/figma-to-wordpress-studio/README.md b/plugins/figma-to-wordpress-studio/README.md index 0312cb8..cfb5468 100644 --- a/plugins/figma-to-wordpress-studio/README.md +++ b/plugins/figma-to-wordpress-studio/README.md @@ -38,7 +38,7 @@ Figma plugin controller + UI 2. In Figma Desktop, use Plugins -> Development -> Import plugin from manifest, then select `plugins/figma-to-wordpress-studio/manifest.json`. 3. Start a compatible WordPress Studio build. 4. Open the plugin and choose `Open in WordPress Studio`. -5. Confirm the new site details in Studio. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. +5. Studio creates the site and opens the local site URL in your browser. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. For quick syntax verification without a full Figma build pipeline: diff --git a/plugins/figma-to-wordpress-studio/src/ui.html b/plugins/figma-to-wordpress-studio/src/ui.html index 8a28156..1f07ed4 100644 --- a/plugins/figma-to-wordpress-studio/src/ui.html +++ b/plugins/figma-to-wordpress-studio/src/ui.html @@ -60,25 +60,6 @@ opacity: 0.55; } - label { - display: grid; - gap: 6px; - font-weight: 600; - } - - textarea { - box-sizing: border-box; - width: 100%; - border: 1px solid var(--figma-color-border, #d9d9d9); - border-radius: 8px; - padding: 8px 10px; - color: var(--figma-color-text, #1e1e1e); - background: var(--figma-color-bg, #fff); - font: inherit; - min-height: 54px; - resize: vertical; - } - .panel { display: grid; gap: 10px; @@ -104,13 +85,8 @@

Figma to WordPress Studio

Preparing this Figma file for WordPress Studio.

-
-
diff --git a/plugins/figma-to-wordpress-studio/src/ui.ts b/plugins/figma-to-wordpress-studio/src/ui.ts index 9639264..1c3f76c 100644 --- a/plugins/figma-to-wordpress-studio/src/ui.ts +++ b/plugins/figma-to-wordpress-studio/src/ui.ts @@ -6,8 +6,6 @@ let currentSelection: NormalizedSelection | null = null; const statusElement = document.querySelector("#status"); const refreshButton = document.querySelector("#refresh"); const studioButton = document.querySelector("#studio"); -const copyCommandButton = document.querySelector("#copy-command"); -const commandElement = document.querySelector("#studio-command"); const studioHandoffEndpoint = "http://127.0.0.1:48732/figma-to-wordpress/import"; function log(message: string, details?: unknown) { @@ -42,8 +40,6 @@ function updateActions() { const disabled = !currentArtifact; if (studioButton) studioButton.disabled = disabled; - if (copyCommandButton) copyCommandButton.disabled = disabled; - if (commandElement) commandElement.value = currentArtifact ? studioCreateCommand(currentArtifact) : ""; } function artifactFileName(artifact: GeneratedArtifact): string { @@ -126,7 +122,7 @@ async function openInStudio() { throw new Error(data?.error || `Studio handoff failed with HTTP ${response.status}.`); } - setStatus("Studio is opening the import. Confirm the new site details in WordPress Studio."); + setStatus("Studio created the WordPress site and is opening it in your browser."); sendToPlugin({ type: "notify", message: "Sent to WordPress Studio." }); log("Studio import handoff accepted.", { endpoint: studioHandoffEndpoint, @@ -194,7 +190,6 @@ window.onmessage = (event: MessageEvent<{ pluginMessage?: PluginToUiMessage }>) refreshButton?.addEventListener("click", () => sendToPlugin({ type: "refresh-document" })); studioButton?.addEventListener("click", () => void openInStudio()); -copyCommandButton?.addEventListener("click", () => void copyStudioCommand()); log("UI loaded."); sendToPlugin({ type: "refresh-document" }); From 6d3101e320b039225a7b9ac3efc31ed4de212529 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Thu, 25 Jun 2026 16:57:44 -0400 Subject: [PATCH 3/3] Remove Figma Studio fallback path --- docs/figma-studio-runner.md | 6 +-- plugins/figma-to-wordpress-studio/README.md | 8 +-- plugins/figma-to-wordpress-studio/src/ui.ts | 55 +-------------------- 3 files changed, 8 insertions(+), 61 deletions(-) diff --git a/docs/figma-studio-runner.md b/docs/figma-studio-runner.md index af1d982..334b156 100644 --- a/docs/figma-studio-runner.md +++ b/docs/figma-studio-runner.md @@ -27,7 +27,7 @@ Practical constraints for this browser-based flow: - Clipboard access can require user activation. - Local file URLs can behave differently between desktop Figma, browser Figma, and development builds. -Because of those constraints, the primary integration shape is a local Studio handoff: the plugin posts an artifact JSON source to Studio's loopback endpoint. If Studio is not running, the plugin saves the same artifact JSON source and presents/copies `studio create --from ` as a fallback. +Because of those constraints, the integration shape is a local Studio handoff: the plugin posts an artifact JSON source to Studio's loopback endpoint. If Studio is not running, the plugin surfaces the connection error. ## Studio And PHP Role @@ -41,7 +41,7 @@ Implemented now: - `GeneratedWebsiteArtifact` for static generated files from Figma. - `blocks-engine/php-transformer/site-artifact/v1` for the Studio CLI artifact handoff. -- A Figma UI client that posts the artifact JSON to local Studio and falls back to `studio create --from ./.studio-import.json`. +- A Figma UI client that posts the artifact JSON to local Studio. Not implemented yet: @@ -64,7 +64,7 @@ Figma development test: 3. Run the plugin. 4. Start a compatible WordPress Studio build. 5. Use `Open in WordPress Studio`. -6. Studio creates the site and opens the local site URL in your browser. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. +6. Studio creates the site and opens the local site URL in your browser. If Studio is not reachable, the plugin reports the connection error. ## Next Integration Step diff --git a/plugins/figma-to-wordpress-studio/README.md b/plugins/figma-to-wordpress-studio/README.md index cfb5468..ee6c8c0 100644 --- a/plugins/figma-to-wordpress-studio/README.md +++ b/plugins/figma-to-wordpress-studio/README.md @@ -2,7 +2,7 @@ This plugin moves a Figma file into WordPress by sending a Studio import payload to the local WordPress Studio app. -It does not port Static Site Importer, Blocks Engine, WordPress, PHP, or Studio internals to TypeScript. The TypeScript code extracts Figma scene data, prepares an artifact JSON source, and posts it to Studio's local handoff endpoint. Studio owns site creation, import through Static Site Importer, and cleanup after a successful import. If Studio is not running, the plugin saves the same payload and copies a `studio create --from ...` fallback command. +It does not port Static Site Importer, Blocks Engine, WordPress, PHP, or Studio internals to TypeScript. The TypeScript code extracts Figma scene data, prepares an artifact JSON source, and posts it to Studio's local handoff endpoint. Studio owns site creation, import through Static Site Importer, and cleanup after a successful import. If Studio is not running, the plugin surfaces the connection error. ## Flow @@ -19,7 +19,7 @@ Figma plugin controller + UI - Implemented: a Figma Desktop-loadable plugin shell with whole-file export. - Implemented: a reusable scene-to-HTML/CSS artifact generator with diagnostics and tests for the current local handoff. -- Implemented: a Studio local handoff request with a `studio create --from ...` fallback command. +- Implemented: a Studio local handoff request. - Not implemented: running Static Site Importer from TypeScript. - Not implemented: automated visual parity/block validation after import. @@ -38,7 +38,7 @@ Figma plugin controller + UI 2. In Figma Desktop, use Plugins -> Development -> Import plugin from manifest, then select `plugins/figma-to-wordpress-studio/manifest.json`. 3. Start a compatible WordPress Studio build. 4. Open the plugin and choose `Open in WordPress Studio`. -5. Studio creates the site and opens the local site URL in your browser. If Studio is not reachable, run the copied `studio create --from ./.studio-import.json` fallback command from a terminal, adjusting the path to the saved artifact if needed. +5. Studio creates the site and opens the local site URL in your browser. If Studio is not reachable, the plugin reports the connection error. For quick syntax verification without a full Figma build pipeline: @@ -50,6 +50,6 @@ npm test --prefix plugins/figma-to-wordpress-studio ## Studio Handoff Boundary -Figma plugin UIs run in a constrained iframe-like environment and cannot spawn local shell commands. The supported boundary is a local Studio handoff: the plugin posts the import artifact to Studio's loopback endpoint. Studio accepts the artifact source, creates the site, runs Static Site Importer, and removes SSI after a successful import. The CLI payload remains as an operator fallback and regression-friendly artifact. +Figma plugin UIs run in a constrained iframe-like environment and cannot spawn local shell commands. The supported boundary is a local Studio handoff: the plugin posts the import artifact to Studio's loopback endpoint. Studio accepts the artifact source, creates the site, runs Static Site Importer, and removes SSI after a successful import. See [`../../docs/figma-studio-runner.md`](../../docs/figma-studio-runner.md) for the integration notes. diff --git a/plugins/figma-to-wordpress-studio/src/ui.ts b/plugins/figma-to-wordpress-studio/src/ui.ts index 1c3f76c..bdb5cad 100644 --- a/plugins/figma-to-wordpress-studio/src/ui.ts +++ b/plugins/figma-to-wordpress-studio/src/ui.ts @@ -42,58 +42,6 @@ function updateActions() { if (studioButton) studioButton.disabled = disabled; } -function artifactFileName(artifact: GeneratedArtifact): string { - const slug = artifact.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "figma-wordpress-import"; - - return `${slug}.studio-import.json`; -} - -function studioCreateCommand(artifact: GeneratedArtifact): string { - return `studio create --from ./${artifactFileName(artifact)}`; -} - -async function copyStudioCommand() { - if (!currentArtifact) { - return; - } - - const command = studioCreateCommand(currentArtifact); - - try { - await navigator.clipboard.writeText(command); - setStatus("Studio command copied. Save the import payload beside the path in the command, then run it in a terminal."); - sendToPlugin({ type: "notify", message: "Studio command copied." }); - } catch (error) { - console.error("[Figma to WordPress Studio] Could not copy Studio command.", error); - setStatus("Copy failed. Select the command text and copy it manually."); - } -} - -function downloadStudioPayload() { - if (!currentArtifact) { - log("Studio import payload requested before artifact was ready."); - return; - } - - const fileName = artifactFileName(currentArtifact); - const blob = new Blob([JSON.stringify(currentArtifact.studioImportPayload, null, 2)], { type: "application/json" }); - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - - link.href = url; - link.download = fileName; - link.click(); - URL.revokeObjectURL(url); - - setStatus(`Saved ${fileName}. Run the Studio command with the file path to create the WordPress site.`); - log("Studio import payload prepared.", { - fileName, - command: studioCreateCommand(currentArtifact), - ...artifactBundleSummary(currentArtifact), - }); - void copyStudioCommand(); -} - async function openInStudio() { if (!currentArtifact) { log("Studio import requested before artifact was ready."); @@ -130,8 +78,7 @@ async function openInStudio() { }); } catch (error) { console.error("[Figma to WordPress Studio] Studio handoff failed.", error); - setStatus("Could not reach WordPress Studio. Saved the import payload and copied the CLI fallback command."); - downloadStudioPayload(); + setStatus(error instanceof Error ? error.message : "Could not reach WordPress Studio."); } finally { updateActions(); }