9.0 KiB
WP Lovable
Use this skill when turning a Lovable export into a Websimple WordPress project, especially when the output should become a normal WordPress marketing site rather than a detached static React app.
Use related references as needed:
references/wp-project.mdandreferences/wp-local-site.mdfor resolving, creating, provisioning, or checking local WordPress sites.references/websimple-stack.mdfor local stack protocol/domain configuration and Traefik SSL routing.references/wp-kaliroots.mdfor Kaliroots child-theme structure and template wrapper decisions.references/wp-theme-dev.mdfor general theme PHP organization.references/wp-assets.mdfor frontend source, Vite/Tailwind, build output, and enqueue integration.references/wp-acf.mdfor editable content models, local JSON, options pages, and section data.references/wp-browser.mdfor frontend/wp-admin smoke tests and visual checks.
Core Approach
Keep WordPress as the application shell and source of truth. Treat the Lovable project as frontend source material to port into the active theme, not as a static app to drop into WordPress unchanged.
For new Websimple WordPress projects, start from the wp-boilerplate template unless the user or project context says otherwise:
https://gitea.websimple.com/templates/wp-boilerplate
Prefer this shape for a Websimple WordPress conversion:
wp-content/themes/{child-theme}/
acf-json/
includes/
core/
assets.php
theme-setup.php
vendors/
acf.php
gravityforms.php
templates/
src/
components/
hooks/
lib/
pages/
main.tsx
index.css
dist/
package.json
vite.config.ts
tailwind.config.*
postcss.config.*
Adapt the paths to the existing theme. Do not reorganize established projects broadly without approval.
First Pass
Before editing, inspect both sides:
- Identify the Lovable source project, its framework, routes, components, CSS/Tailwind setup, static assets, forms, and data assumptions.
- Identify the WordPress site, active theme, parent theme, template wrappers, ACF setup, menus, SEO plugin, forms plugin, and asset pipeline.
- Check git status in the WordPress project and avoid touching unrelated dirty files.
- Decide which Lovable pieces are presentation components and which are actually content, navigation, SEO, media, forms, or settings that belong in WordPress.
Use rg --files, package.json, vite.config.*, tailwind.config.*, src/, includes/, templates/, and acf-json/ as the main inspection points.
Porting Rules
Port reusable React/Tailwind UI into the child theme src/. Keep TypeScript path aliases, component names, and Tailwind conventions only when they still make sense inside the theme.
Move editable site concerns into WordPress:
- page and section content into pages, ACF fields, flexible content, or options pages;
- navigation into WordPress menus;
- images and downloadable media into the media library or ACF media fields;
- SEO title, canonical, OpenGraph/Twitter, schema, and indexing behavior into the SEO plugin and WordPress-rendered document head;
- contact forms into Gravity Forms or the existing WordPress form plugin;
- global settings such as phone, address, social links, CTAs, and layout toggles into ACF options when they are truly site-wide.
React should render serialized WordPress data with safe fallbacks. It should not become the CMS.
Routing And SEO
Avoid pure React Router SPA behavior for normal WordPress marketing pages.
Prefer WordPress-rendered URLs and document navigation so SEO plugins can output correct per-page titles, canonical URLs, OpenGraph/Twitter tags, JSON-LD, breadcrumbs, and indexing controls.
Use React routing only when the requested result is an actual app-like interface where client-side routing is intentional. For standard pages, replace internal SPA links with normal document links and let WordPress resolve the route.
Bundler Pattern
For modern Lovable migrations, Vite in the child theme is usually the cleanest fit:
- keep the app entry at
src/main.tsxor the existing theme entrypoint; - keep Tailwind/PostCSS config in the theme root;
- use an alias such as
@to point atsrconly if the source already uses it or it improves the port; - output production assets to
dist/; - generate
dist/.vite/manifest.json; - set production
baseto/wp-content/themes/{child-theme}/dist/when assets are served from the theme; - have PHP enqueue code read the manifest rather than hardcoding hashed filenames;
- mark Vite client and app scripts as
type="module"when needed.
For local development, bind Vite to the local WordPress host on a fixed port and expose CORS headers so the WordPress page can load the dev server assets.
Mirror Mooncake's local SSL pattern when the Websimple stack uses HTTPS:
import basicSsl from "@vitejs/plugin-basic-ssl";
import { homedir } from "os";
import { resolve } from "path";
const isHttps = process.env.LOCAL_PROTOCOL === "https";
export default defineConfig({
plugins: [
...(isHttps ? [basicSsl({ certDir: resolve(homedir(), ".local/share/certs") })] : []),
],
server: {
host: `${resolve(__dirname, "../../..").split("/").pop()}.${process.env.TLD || "ledevsimple.ca"}`,
port: 3001,
strictPort: true,
headers: { "Access-Control-Allow-Origin": "*" },
},
});
Resolve LOCAL_PROTOCOL and TLD from the local stack configuration whenever possible:
LOCAL_PROTOCOLshould match$WEBSIMPLE_STACK_PROTOCOL, usuallyhttpswhen Traefik serves local sites with TLS.TLDshould match$WEBSIMPLE_STACK_DOMAIN, for exampleledevsimple.ca.- Prefer package scripts, shell environment, or generated local env files that pass those values through to Vite.
- If the stack protocol cannot be discovered, inspect
references/websimple-stack.mdconfig and the current local site URL before choosinghttporhttps.
Do not let leftover dist/.vite/manifest.json silently force production mode if the local workflow expects the dev server. Prefer an explicit local/dev switch, an environment constant, or a detection strategy that matches the project's generated-output policy.
PHP Integration
Keep PHP integration small and explicit:
- enqueue assets from
includes/core/assets.phpor the existing asset module; - localize or inline only the WordPress data React needs to render;
- keep data preparation in helpers/includes when it becomes non-trivial;
- keep template files responsible for mounting the frontend and providing page context;
- keep ACF and vendor integrations in the existing vendor/module files.
For Kaliroots child themes, use Kaliroots wrapper and template conventions instead of inventing top-level WordPress templates.
Forms
Do not rebuild normal WordPress forms in React just because the Lovable export included form markup.
Prefer a WordPress-native form flow:
- Add an ACF field for a form selector or section configuration.
- Render the selected Gravity Form or existing form plugin output in PHP or through a focused React wrapper fed by WordPress data.
- Style the generated form in theme source CSS.
- Verify submit behavior, validation, notifications, spam protection, and accessibility in the browser.
Only build a custom React form when the project specifically needs custom app behavior and the backend handling is clear.
What To Avoid
- Do not drop the Lovable export into WordPress as a static page dump.
- Do not make WordPress serve a one-route SPA for normal marketing content.
- Do not hard-code editor-controlled content, layout settings, form IDs, media, menus, or SEO metadata in React.
- Do not edit compiled
dist/assets manually when source exists. - Do not migrate build tools, package managers, or theme architecture as a side effect unless the user approved that scope.
- Do not assume Lovable's placeholder copy, mock data, or generated routes are production information.
- Do not use manifest existence alone as the only dev/prod signal if generated output may be checked in or left over locally.
Verification
Use the smallest checks that cover the migration risk:
pnpm build
find wp-content/themes/{child-theme} -name '*.php' -print0 | xargs -0 -n1 php -l
Then smoke-test representative URLs in the browser:
- home page;
- at least one inner page;
- contact/form page;
- mobile viewport;
- browser console;
- SEO/head output for title, canonical, OpenGraph/Twitter, JSON-LD, and no accidental SPA-only metadata.
Report changed source files, generated files, existing dirty files left untouched, and any checks that could not run.
Reference Pattern
The first known conversion following this pattern was:
Lovable source: https://github.com/Moonthewhite/chemineeschaleurs
WordPress site: https://gitea.websimple.com/wp-sites/chemineeschaleurs
Child theme: wp-content/themes/cheminees
That project used a Kaliroots child theme, React/Tailwind source under src/, Vite output under dist/, ACF local JSON under acf-json/, PHP enqueueing under includes/core/assets.php, WordPress/ACF-owned section layout settings, and Gravity Forms for the contact form.