SvelteKit · Svelte 5
Visual editing for SvelteKit, on WordPress.
Load pages in +page.server.ts, start the bridge from the root layout, spread field() on your elements.
- 01
Allow the editor to display your site
Copy this into src/hooks.server.ts.
src/hooks.server.ts import type { Handle } from '@sveltejs/kit'; export const handle: Handle = async ({ event, resolve }) => { const response = await resolve(event); response.headers.set('Content-Security-Policy', "frame-ancestors 'self' https://cms.example.com"); return response; };Prerendered pages are served as static files: set the same header on your host.
- 02
Add the bridge
Install the package, then load the bridge from the root layout.
Terminal npm install leihosrc/routes/+layout.svelte <script> import { onMount } from 'svelte'; let { children } = $props(); onMount(() => { if (window.self === window.top) return; import('leiho').then(({ initLeihoBridge }) => { // Already on screen: don't hide the page. initLeihoBridge({ wpOrigin: 'https://cms.example.com', cloakTimeout: 0 }); }); }); </script> {@render children()} - 03
Read the content
Load each page in +page.server.ts.
src/routes/[...path]/+page.server.ts import { error } from '@sveltejs/kit'; import { loadLeihoContent, indexLeihoContent } from 'leiho/content'; export async function load({ url }) { const { data } = await loadLeihoContent({ url: 'https://cms.example.com/wp-json/leiho/v1/export' }); const page = indexLeihoContent(data).byPath(url.pathname); if (!page) error(404, 'Not found'); return { page }; }Serverless host with a read-only disk? Pass snapshot: false to loadLeihoContent.
- 04
Mark what editors can change
Spread field() on each element editors should change. Always render the element, even when its value is empty.
Svelte <script> import { field, entry } from 'leiho'; // field() writes data-wp-post + data-wp-field, entry() names a section. // Flexible content rows: block(page, 'sections', i, 'Label'). let { page } = $props(); </script> <section {...entry(page, 'Hero')}> <h1 {...field(page, 'hero_title')}>{page.fields.hero_title}</h1> <img {...field(page, 'hero_image')} src={page.fields.hero_image?.url} alt={page.fields.hero_image?.alt} /> {#each page.fields.cards ?? [] as card, i} <article {...field(page, `cards.${i}.title`)}>{card.title}</article> {/each} </section>
Replace https://cms.example.com with your WordPress address. In wp-admin, Leiho → Get started shows these steps with your address filled in, checks each one, and can give the whole setup to your coding agent as one prompt.
Edit the real site.
Free and open source. Try it on a real WordPress, in your browser.