init
This commit is contained in:
4
.env
Normal file
4
.env
Normal file
@@ -0,0 +1,4 @@
|
||||
WOOCOMMERCE_URL=https://klz-cables.com
|
||||
WOOCOMMERCE_CONSUMER_KEY=ck_38d97df86880e8fefbd54ab5cdf47a9c5a9e5b39
|
||||
WOOCOMMERCE_CONSUMER_SECRET=cs_d675ee2ac2ec7c22de84ae5451c07e42b1717759
|
||||
WORDPRESS_APP_PASSWORD=DlJH 49dp fC3a Itc3 Sl7Z Wz0k
|
||||
151
plans/wordpress-to-nextjs-concept.md
Normal file
151
plans/wordpress-to-nextjs-concept.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# WordPress → Next.js Static Migration Concept (DE/EN)
|
||||
|
||||
## Goals
|
||||
- Rebuild the current WordPress site (Salient + WPBakery) as a **static** Next.js site (React + TypeScript) hosted on Vercel.
|
||||
- Preserve content types: **Pages**, **Blog Posts**, **WooCommerce Products (catalog-only)**.
|
||||
- Add **contact via form + email** using [`Resend`](plans/wordpress-to-nextjs-concept.md:1) and [`Turnstile`](plans/wordpress-to-nextjs-concept.md:1).
|
||||
- Add **analytics** using [`Vercel Analytics`](plans/wordpress-to-nextjs-concept.md:1) with **GDPR opt-in consent**.
|
||||
|
||||
## Key Constraints & Decisions
|
||||
- Access: SSH/SFTP, server DB credentials, and ability to run [`wp-cli`](plans/wordpress-to-nextjs-concept.md:1).
|
||||
- WordPress permalinks: `/%postname%/` (posts currently at `/{postSlug}`).
|
||||
- Target routes (approved):
|
||||
- Pages: `/{slug}`
|
||||
- Blog: `/blog` and `/blog/{postSlug}`
|
||||
- Products: `/product/{productSlug}`
|
||||
- Product categories: `/product-category/{slug}`
|
||||
- Redirect decision (approved): 301 all posts `/{postSlug}` → `/blog/{postSlug}`.
|
||||
- Languages: **German + English** (new requirement).
|
||||
|
||||
## Proposed Next.js Architecture (Static + Vercel)
|
||||
- Next.js App Router with **static generation** for all routes.
|
||||
- Build-time data sourcing from versioned JSON snapshots (no runtime WP calls).
|
||||
- Use serverless only for form submission endpoint.
|
||||
- Consent-gated analytics initialization.
|
||||
|
||||
### Routing Strategy with DE/EN (Polylang)
|
||||
Because Pages must remain at `/{slug}`, the cleanest multilingual scheme is:
|
||||
|
||||
**Option A (recommended): default locale unprefixed + secondary locale prefixed**
|
||||
- Default locale (unprefixed): `/{slug}`, `/blog/{postSlug}`, `/product/{productSlug}`, `/product-category/{slug}`
|
||||
- Secondary locale (prefixed): `/{locale}/{slug}`, `/{locale}/blog/{postSlug}`, `/{locale}/product/{productSlug}`, `/{locale}/product-category/{slug}`
|
||||
|
||||
Given your note that **English is likely default**, the concrete mapping becomes:
|
||||
- English (default): `/{slug}`, `/blog/{postSlug}`, `/product/{productSlug}`, `/product-category/{slug}`
|
||||
- German: `/de/{slug}`, `/de/blog/{postSlug}`, `/de/product/{productSlug}`, `/de/product-category/{slug}`
|
||||
|
||||
**Option B: both locales prefixed**
|
||||
- `/en/...` and `/de/...` for all routes (this breaks the “Pages at /{slug}” requirement unless we accept redirects from root)
|
||||
|
||||
Default recommendation: **Option A**, because it preserves existing URLs for the default language and minimizes redirects.
|
||||
|
||||
### SEO for i18n
|
||||
- Add `hreflang` alternate links per page/post/product between DE and EN.
|
||||
- Canonical URLs per locale.
|
||||
- Locale-aware sitemap(s) and robots.
|
||||
|
||||
## Content Model (Canonical)
|
||||
All entities carry a `locale` and a stable cross-locale `translationKey`.
|
||||
|
||||
### Page
|
||||
- `id`, `translationKey`, `locale`
|
||||
- `slug`, `path`
|
||||
- `titleHtml`, `contentHtml`, `excerptHtml?`
|
||||
- `featuredImage?` (asset reference)
|
||||
- `updatedAt`
|
||||
|
||||
### Post
|
||||
- `id`, `translationKey`, `locale`
|
||||
- `slug`, `path` (`/blog/{slug}` or `/de/blog/{slug}`)
|
||||
- `titleHtml`, `contentHtml`, `excerptHtml`
|
||||
- `featuredImage?`
|
||||
- `datePublished`, `updatedAt`
|
||||
|
||||
### Product (WooCommerce catalog-only)
|
||||
- `id`, `translationKey`, `locale`
|
||||
- `slug`, `path` (`/product/{slug}` or `/de/product/{slug}`)
|
||||
- `name`
|
||||
- `shortDescriptionHtml`, `descriptionHtml`
|
||||
- `images[]`, `featuredImage?`
|
||||
- `sku?`, `regularPrice?`, `salePrice?`, `currency` (global config allowed)
|
||||
- `stockStatus?`
|
||||
- `categories[]` (references), `attributes[]` (for filtering)
|
||||
- `variations[]` (if present)
|
||||
- `updatedAt`
|
||||
|
||||
### ProductCategory
|
||||
- `id`, `translationKey`, `locale`
|
||||
- `slug`, `name`, `path` (`/product-category/{slug}` or `/de/product-category/{slug}`)
|
||||
|
||||
### Nav / Redirect / Asset
|
||||
- Nav: locale-aware arrays (primary/footer)
|
||||
- Redirect rules: explicit list to avoid page/post collisions, plus per-locale patterns
|
||||
- Asset map: WordPress URL → local `/public` path, with optional width/height/alt
|
||||
|
||||
## WPBakery/Salient Migration Strategy (Fast Path)
|
||||
- Export already-rendered HTML from WordPress REST (`content.rendered`) where possible.
|
||||
- Detect unexpanded shortcode remnants (`[vc_row]`, `[nectar_*]`) and re-render via server-side shortcode expansion when exporting (WordPress is the renderer).
|
||||
- Normalize/sanitize HTML at build time (strip scripts/handlers, preserve structural classes/data attributes).
|
||||
- Add a small compatibility CSS layer for common WPBakery layout classes (grid/rows/columns) so pages render correctly without Salient JS.
|
||||
|
||||
## Multilingual Source of Truth (Polylang, DE/EN)
|
||||
Polylang is confirmed. The remaining ambiguity is which language is the **default** (unprefixed) locale; you suspect it is English.
|
||||
|
||||
### Export strategy (Polylang)
|
||||
- Prefer exporting each locale separately via WP REST + Polylang language filter (commonly `?lang=en` and `?lang=de`).
|
||||
- For products and product categories, use WooCommerce endpoints and/or WP REST endpoints with language filtering (implementation must verify which endpoints are language-aware on this site).
|
||||
- If any endpoint cannot be filtered by `lang`, fall back to `wp-cli`/DB to:
|
||||
- determine the language for each entity
|
||||
- determine the translation group and build a stable `translationKey`
|
||||
|
||||
Deliverable from this step: a stable `translationKey` shared between DE and EN versions of the same item, enabling `hreflang` and the locale switcher.
|
||||
|
||||
## Export Runbook (wp-cli + REST)
|
||||
Primary principle: **create repeatable, versioned snapshots** so theme rebuild can proceed offline.
|
||||
|
||||
### Snapshot outputs
|
||||
- `data/raw/{timestamp}/pages.{locale}.json`
|
||||
- `data/raw/{timestamp}/posts.{locale}.json`
|
||||
- `data/raw/{timestamp}/products.{locale}.json`
|
||||
- `data/raw/{timestamp}/product-categories.{locale}.json`
|
||||
- `data/raw/{timestamp}/menus.{locale}.json`
|
||||
- `data/raw/{timestamp}/media.json` + mirrored files under `/public/media/...`
|
||||
|
||||
### Commands / Techniques
|
||||
- Use [`wp option get`](plans/wordpress-to-nextjs-concept.md:1) and WooCommerce options to confirm bases.
|
||||
- Use REST for structured content (pages/posts/products/categories) when possible.
|
||||
- Use DB/wp-cli for menus and translation mappings if REST doesn’t expose them.
|
||||
- Media mirroring: download referenced attachments and build asset manifest.
|
||||
|
||||
## Redirect Strategy (DE/EN-aware)
|
||||
Base requirement: `/{postSlug}` → `/blog/{postSlug}` (301).
|
||||
|
||||
With i18n Option A (English default, German under `/de/*`):
|
||||
- English posts (current WP): `/{postSlug}` → `/blog/{postSlug}`
|
||||
- German posts (if they exist at `/de/{postSlug}`): `/de/{postSlug}` → `/de/blog/{postSlug}`
|
||||
|
||||
All redirects should be generated from export manifests to avoid false positives (pages must win at root).
|
||||
|
||||
## Minimal Page Set (approved)
|
||||
- Blog index + post detail
|
||||
- Product category pages
|
||||
- No blog tag/category archives; no product tag pages
|
||||
|
||||
## Implementation Notes (Static + Forms + Analytics)
|
||||
- Contact form:
|
||||
- Next.js route handler posts to server endpoint.
|
||||
- Validate input, verify Turnstile token, rate-limit, send via Resend.
|
||||
- Consent banner:
|
||||
- Store consent in local storage/cookie.
|
||||
- Initialize Vercel Analytics only after opt-in.
|
||||
|
||||
## Security Note (important)
|
||||
A file like [`.env`](.env:1) must never be committed with real credentials. If secrets were shared outside your team, rotate/revoke them (WooCommerce keys and any WordPress app password), then regenerate.
|
||||
|
||||
## Open Questions (to resolve during implementation)
|
||||
- Confirm default locale (unprefixed) is `en` and confirm chosen secondary prefix is `/de/*`.
|
||||
- Confirm which WP/WC REST endpoints are Polylang language-aware on this site.
|
||||
- Detect any locale-specific slugs that collide across content types.
|
||||
|
||||
## Next Step
|
||||
Proceed to implement the export pipeline and data model with locale support, then scaffold Next.js templates and routing per locale.
|
||||
Reference in New Issue
Block a user