Checkpoint before implementation. Includes audit findings (FINDINGS.md), architectural recommendation (RECOMMENDATION.md), and existing code changes to Form, Order, Render, and form-action.js from recent development. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
470 lines
18 KiB
Markdown
470 lines
18 KiB
Markdown
# 🏗️ Formipay — Architectural Recommendation
|
|
|
|
**Date:** April 17, 2026
|
|
**Context:** Based on `FINDINGS.md` audit
|
|
|
|
---
|
|
|
|
## The Question
|
|
|
|
> **Rebuild the plugin with React (admin + frontend), or keep the current SSR shortcode + Vue admin approach and fix all findings?**
|
|
|
|
---
|
|
|
|
## TL;DR — The Recommendation
|
|
|
|
### **Option B: Incremental Modernization (Keep SSR + Vue, Fix & Upgrade)**
|
|
|
|
**Do NOT do a full rewrite.** Instead, adopt a **phased modernization strategy** that:
|
|
|
|
1. **Fixes all critical bugs immediately** (Phase 1 — weeks 1-2)
|
|
2. **Introduces React only where it adds clear value** (Phase 2 — weeks 3-6)
|
|
3. **Gradually migrates Vue admin → React** as features are touched (Phase 3 — ongoing)
|
|
|
|
This is the industry-standard approach for WordPress plugins at this stage. Here's why and how.
|
|
|
|
---
|
|
|
|
## Why NOT a Full React Rebuild
|
|
|
|
| Factor | Full React Rebuild | Incremental Modernization |
|
|
|--------|--------------------|---------------------------|
|
|
| **Time** | 3-4 months minimum | 2-4 weeks for critical fixes |
|
|
| **Risk** | Complete rewrite = complete regression risk | Fixes are targeted and testable |
|
|
| **Revenue** | No updates for 3-4 months | Continuous delivery |
|
|
| **WordPress ecosystem** | Fighting against WP conventions | Working with WP conventions |
|
|
| **SEO / Accessibility** | Client-side rendering = SEO problems for public forms | SSR = perfect SEO & accessibility |
|
|
| **Complexity** | Need build pipeline, state management, API layer | Build on what works |
|
|
| **Team onboarding** | Entire codebase unfamiliar | Familiar patterns + gradual React intro |
|
|
|
|
### Industry Precedent
|
|
|
|
- **WooCommerce** — Still PHP/SSR for storefront, React only for admin (block editor, settings). Did NOT rewrite frontend in React.
|
|
- **Easy Digital Downloads** — Same approach. PHP templates + React for admin features.
|
|
- **GiveWP** — PHP/SSR frontend, React for admin dashboard and form builder.
|
|
- **Gravity Forms** — PHP/SSR rendering, React for the form builder only.
|
|
|
|
**The pattern is clear:** WordPress payment/e-commerce plugins keep **SSR for public-facing forms** (SEO, accessibility, speed, no-JS fallback) and use **React for admin UX** (form builder, dashboards, settings).
|
|
|
|
---
|
|
|
|
## Recommended Architecture
|
|
|
|
### What to KEEP (SSR / PHP)
|
|
|
|
```
|
|
✅ Public form rendering (shortcode → PHP template)
|
|
✅ Order processing & payment flow (PHP backend)
|
|
✅ Email notifications (PHP wp_mail)
|
|
✅ Database layer (custom tables via dbDelta)
|
|
✅ Webhook handlers (REST routes in PHP)
|
|
✅ Thank-you page (PHP template)
|
|
```
|
|
|
|
**Why:** Server-side rendered forms are the **correct choice** for WordPress checkout forms. They provide:
|
|
- Zero JavaScript dependency (forms work without JS)
|
|
- Perfect SEO (crawlers see full HTML)
|
|
- Fast initial paint (no JS bundle download needed)
|
|
- Native WordPress shortcode/block integration
|
|
- Accessibility out of the box (screen readers work)
|
|
|
|
### What to MIGRATE to React
|
|
|
|
```
|
|
🔄 Admin form builder (currently partial Vue → full React)
|
|
🔄 Admin dashboard / analytics (new)
|
|
🔄 Admin order details view (currently Handlebars → React)
|
|
🔄 Admin settings pages (currently WPCFTO → custom React)
|
|
🔄 Gutenberg block (new — React is required)
|
|
```
|
|
|
|
### What to ADD as React
|
|
|
|
```
|
|
🆕 React-powered shortcode replacement (as <script> islands)
|
|
🆕 React-based order tracking widget for customer portal
|
|
🆕 React-based product catalog (optional)
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Plan
|
|
|
|
### Phase 1: Critical Fixes & Stabilization (Weeks 1-2)
|
|
|
|
**Goal:** Make the existing plugin production-ready.
|
|
|
|
```
|
|
Week 1 — Critical Bug Fixes:
|
|
├── Fix Customer::update() undefined variables
|
|
├── Fix Order::delete() $id → $order_id
|
|
├── Fix Order::bulk_delete() loop variable
|
|
├── Fix Email::send_email() class reference
|
|
├── Fix Paypal::auto_cancel_order_on_timeout() import
|
|
├── Fix BankTransfer unique_code triple-call
|
|
├── Fix color field label ('Number' → 'Color')
|
|
└── Add missing nonce checks (Customer::tabledata)
|
|
|
|
Week 2 — Performance & Security:
|
|
├── Remove flush_rewrite_rules() from init → activation hook only
|
|
├── Replace maybe_serialize() in cookies with json_encode()
|
|
├── Add PayPal webhook signature verification
|
|
├── Add rate limiting on public AJAX endpoints
|
|
├── Cache currency/country JSON reads in static vars
|
|
├── Add pagination to Customer::tabledata
|
|
├── Optimize Order::tabledata queries (COUNT + GROUP BY)
|
|
└── Add uninstall.php for cleanup
|
|
```
|
|
|
|
### Phase 2: React Admin Foundation (Weeks 3-6)
|
|
|
|
**Goal:** Set up React build pipeline and migrate the most impactful admin pages.
|
|
|
|
```
|
|
Week 3 — Build Pipeline:
|
|
├── Set up @wordpress/scripts (wp-scripts) build system
|
|
├── Configure webpack with React Fast Refresh
|
|
├── Create React component library structure
|
|
├── Set up API layer (fetch wrapper with nonce handling)
|
|
└── Create admin page shell component (sidebar + routing)
|
|
|
|
Week 4 — Form Builder (highest admin ROI):
|
|
├── Build drag-and-drop field palette (React)
|
|
├── Build field settings panel (React)
|
|
├── Build live preview canvas (React)
|
|
├── Connect to existing PHP save endpoints
|
|
└── Replace current Vue/Classic Editor metabox
|
|
|
|
Week 5 — Order Management & Dashboard:
|
|
├── Build order list page with filters (React + TanStack Table)
|
|
├── Build order detail view (replace Handlebars templates)
|
|
├── Build status change workflow with timeline
|
|
├── Build simple analytics dashboard (orders, revenue, charts)
|
|
└── Build notification log viewer
|
|
|
|
Week 6 — Settings & Product Editor:
|
|
├── Build global settings page (replace WPCFTO dependency)
|
|
├── Build product editor page (replace classic editor metaboxes)
|
|
├── Build coupon editor page
|
|
├── Build access items manager
|
|
└── Build license management page
|
|
```
|
|
|
|
### Phase 3: Frontend Enhancements (Weeks 7-10)
|
|
|
|
**Goal:** Add React-powered frontend features while keeping SSR as the default.
|
|
|
|
```
|
|
Week 7-8 — React Island Architecture:
|
|
├── Create a render_php() method (existing SSR — default)
|
|
├── Create a render_react() method (new — optional)
|
|
├── Build React form renderer component
|
|
├── Implement "island hydration" — React attaches to SSR HTML
|
|
├── Add setting: "Render Mode: Classic (SSR) | Modern (React)"
|
|
└── Add multi-step form navigation (missing in current SSR)
|
|
|
|
Week 9 — Gutenberg Block:
|
|
├── Register formipay/form block with block.json
|
|
├── Block renders shortcode server-side in edit.js preview
|
|
├── Full React experience in editor
|
|
├── Settings panel in InspectorControls
|
|
└── Replace shortcode-only workflow
|
|
|
|
Week 10 — Customer Portal:
|
|
├── Build customer order history page (React)
|
|
├── Build order detail / download access page (React)
|
|
├── Build access link request form (React)
|
|
├── Integrate with WordPress user accounts
|
|
└── Shortcode [formipay_my_orders] for portal
|
|
```
|
|
|
|
### Phase 4: Complete Missing Features (Weeks 11-16)
|
|
|
|
```
|
|
Week 11-12 — Payment & Commerce:
|
|
├── Implement ExchangeRateAPI (currently empty)
|
|
├── Implement License API endpoints (currently stubs)
|
|
├── Add Stripe payment gateway
|
|
├── Add tax calculation engine
|
|
└── Add product variations on frontend
|
|
|
|
Week 13-14 — Stock & Shipping:
|
|
├── Implement stock management (decrement, validation, messages)
|
|
├── Add weight-based shipping calculation
|
|
├── Add shipping zone support
|
|
└── Add order fulfillment workflow
|
|
|
|
Week 15-16 — Advanced Features:
|
|
├── Build donation form mode (pay-what-you-want, suggested amounts)
|
|
├── Add PDF invoice generation
|
|
├── Add CSV export for orders/customers
|
|
├── Add webhook notification system
|
|
└── Add analytics & reporting dashboard
|
|
```
|
|
|
|
---
|
|
|
|
## Technical Architecture Diagram
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ WordPress Plugin │
|
|
│ │
|
|
│ ┌──────────────────────┐ ┌──────────────────────────┐ │
|
|
│ │ PHP Backend Core │ │ React Admin (wp-scripts)│ │
|
|
│ │ │ │ │ │
|
|
│ │ • Custom Post Types │◄──►│ • Form Builder │ │
|
|
│ │ • Custom DB Tables │ │ • Order Management │ │
|
|
│ │ • Payment Gateways │ │ • Product Editor │ │
|
|
│ │ • Email System │ │ • Settings Pages │ │
|
|
│ │ • REST API Endpoints│ │ • Dashboard/Analytics │ │
|
|
│ │ • Webhook Handlers │ │ • License Manager │ │
|
|
│ │ • Cron Jobs │ │ • Notification Log │ │
|
|
│ └──────────┬───────────┘ └──────────────────────────┘ │
|
|
│ │ │
|
|
│ ┌──────────▼───────────┐ ┌──────────────────────────┐ │
|
|
│ │ SSR Form Renderer │ │ React Frontend Islands │ │
|
|
│ │ (PHP + Shortcode) │ │ (Optional Enhancement) │ │
|
|
│ │ │ │ │ │
|
|
│ │ • [formipay] render │ │ • Multi-step navigation │ │
|
|
│ │ • Thank-you page │ │ • Real-time validation │ │
|
|
│ │ • Payment confirm │ │ • Customer portal │ │
|
|
│ │ • No-JS fallback ✅ │ │ • Gutenberg block │ │
|
|
│ └──────────────────────┘ └──────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ Shared API Layer (WordPress REST API + admin-ajax) │ │
|
|
│ │ • /wp-json/formipay/v1/* │ │
|
|
│ │ • admin-ajax.php actions (backward compat) │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Build Toolchain
|
|
|
|
```
|
|
formipay/
|
|
├── package.json # @wordpress/scripts + deps
|
|
├── webpack.config.js # Extend wp-scripts config
|
|
├── .eslintrc.js # ESLint with WP rules
|
|
├── .prettierrc # Prettier config
|
|
├── tsconfig.json # TypeScript (recommended)
|
|
│
|
|
├── src/ # React source code
|
|
│ ├── admin/ # Admin React app
|
|
│ │ ├── index.js # Entry point
|
|
│ │ ├── components/ # Shared components
|
|
│ │ │ ├── DataTable/ # Reusable table component
|
|
│ │ │ ├── SettingsPanel/ # Settings form builder
|
|
│ │ │ ├── Modal/ # Confirmation modals
|
|
│ │ │ └── StatusBadge/ # Order status badges
|
|
│ │ ├── pages/ # Page components
|
|
│ │ │ ├── Dashboard/
|
|
│ │ │ ├── FormBuilder/
|
|
│ │ │ ├── Orders/
|
|
│ │ │ ├── Products/
|
|
│ │ │ ├── Customers/
|
|
│ │ │ ├── Coupons/
|
|
│ │ │ ├── Licenses/
|
|
│ │ │ ├── AccessItems/
|
|
│ │ │ └── Settings/
|
|
│ │ ├── hooks/ # Custom React hooks
|
|
│ │ │ ├── useOrders.js
|
|
│ │ │ ├── useProducts.js
|
|
│ │ │ └── useSettings.js
|
|
│ │ └── api/ # API client
|
|
│ │ ├── client.js # Fetch wrapper with nonce
|
|
│ │ ├── orders.js
|
|
│ │ ├── products.js
|
|
│ │ └── settings.js
|
|
│ │
|
|
│ ├── frontend/ # Frontend React islands
|
|
│ │ ├── blocks/ # Gutenberg blocks
|
|
│ │ │ └── formipay-form/
|
|
│ │ │ ├── block.json
|
|
│ │ │ ├── edit.jsx
|
|
│ │ │ └── view.js
|
|
│ │ └── widgets/ # Embeddable widgets
|
|
│ │ ├── CustomerPortal/
|
|
│ │ └── OrderTracker/
|
|
│ │
|
|
│ └── shared/ # Shared between admin/frontend
|
|
│ ├── utils/
|
|
│ └── constants/
|
|
│
|
|
├── assets/build/ # Compiled output (gitignored)
|
|
│ ├── admin.bundle.js
|
|
│ ├── admin.bundle.css
|
|
│ ├── frontend.bundle.js
|
|
│ └── blocks/
|
|
│
|
|
├── includes/ # PHP backend (existing, fixed)
|
|
├── admin/ # PHP admin pages (kept for PHP render)
|
|
├── public/ # Public templates (SSR)
|
|
├── vendor/ # Composer dependencies (new)
|
|
└── templates/ # WordPress templates
|
|
```
|
|
|
|
### `package.json` (minimal)
|
|
|
|
```json
|
|
{
|
|
"name": "formipay",
|
|
"version": "1.0.0",
|
|
"private": true,
|
|
"scripts": {
|
|
"build": "wp-scripts build",
|
|
"start": "wp-scripts start",
|
|
"lint:js": "wp-scripts lint-js src/",
|
|
"lint:css": "wp-scripts lint-style",
|
|
"format": "wp-scripts format src/"
|
|
},
|
|
"dependencies": {
|
|
"react": "^18.2.0",
|
|
"react-dom": "^18.2.0",
|
|
"@wordpress/api-fetch": "^6.0.0",
|
|
"@wordpress/components": "^25.0.0",
|
|
"@wordpress/data": "^9.0.0",
|
|
"@wordpress/element": "^5.0.0",
|
|
"@wordpress/i18n": "^4.0.0",
|
|
"@tanstack/react-table": "^8.0.0",
|
|
"@tanstack/react-query": "^5.0.0",
|
|
"recharts": "^2.10.0"
|
|
},
|
|
"devDependencies": {
|
|
"@wordpress/scripts": "^27.0.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## React Frontend Integration Strategy
|
|
|
|
### Pattern: React Islands (Hybrid SSR + React)
|
|
|
|
The key pattern is **"islands of interactivity"** — the PHP renders the initial HTML (SSR), and React optionally hydrates specific sections:
|
|
|
|
```php
|
|
// Render.php — The shortcode handler
|
|
public function shortcode($atts) {
|
|
// ... existing SSR rendering (default) ...
|
|
|
|
// Option: If React mode is enabled, render a mount point instead
|
|
if ($render_mode === 'react') {
|
|
return sprintf(
|
|
'<div id="formipay-react-form-%d" data-form-id="%d" data-nonce="%s"></div>',
|
|
$post_id,
|
|
$post_id,
|
|
wp_create_nonce('formipay_order_submit')
|
|
);
|
|
}
|
|
|
|
// Default: existing PHP-rendered form (SSR)
|
|
return $this->render_php_form($post_id);
|
|
}
|
|
```
|
|
|
|
```jsx
|
|
// src/frontend/widgets/FormRenderer.jsx
|
|
import { createRoot } from '@wordpress/element';
|
|
import Form from './components/Form';
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
document.querySelectorAll('[id^="formipay-react-form-"]').forEach(el => {
|
|
const formId = parseInt(el.dataset.formId);
|
|
const nonce = el.dataset.nonce;
|
|
createRoot(el).render(<Form formId={formId} nonce={nonce} />);
|
|
});
|
|
});
|
|
```
|
|
|
|
This gives you:
|
|
- **Backward compatibility** — existing `[formipay]` shortcodes keep working with SSR
|
|
- **Opt-in React** — new features use React when enabled
|
|
- **Gutenberg block** — renders React in editor, SSR or React on frontend
|
|
- **No lock-in** — each form can use either mode independently
|
|
|
|
---
|
|
|
|
## What to Do With the Vue Code
|
|
|
|
The existing Vue admin code (`admin/assets/vue/`) should be **deprecated, not deleted immediately**:
|
|
|
|
1. **Keep** Vue code working during Phase 1 (critical fixes)
|
|
2. **Build** React equivalents in Phase 2 alongside Vue
|
|
3. **Switch** admin pages to React one at a time (form builder first)
|
|
4. **Remove** Vue code once all pages are migrated in Phase 3
|
|
|
|
Do NOT try to mix Vue and React on the same page — they'll conflict. Migrate page-by-page.
|
|
|
|
---
|
|
|
|
## Gutenberg Block Strategy
|
|
|
|
```jsx
|
|
// src/frontend/blocks/formipay-form/block.json
|
|
{
|
|
"apiVersion": 3,
|
|
"name": "formipay/form",
|
|
"title": "Formipay Form",
|
|
"category": "widgets",
|
|
"attributes": {
|
|
"formId": { "type": "number", "default": 0 },
|
|
"renderMode": { "type": "string", "default": "ssr" }
|
|
},
|
|
"supports": {
|
|
"html": false,
|
|
"align": true
|
|
},
|
|
"editorScript": "file:./index.js",
|
|
"editorStyle": "file:./index.css",
|
|
"style": "file:./style-index.css",
|
|
"render": "file:./render.php"
|
|
}
|
|
```
|
|
|
|
The `render.php` file uses Server-Side Rendering (required by WordPress for blocks), which calls the existing PHP form renderer. The editor experience (`edit.jsx`) is fully React.
|
|
|
|
---
|
|
|
|
## Testing Strategy
|
|
|
|
```
|
|
Phase 1: Manual testing of all bug fixes
|
|
Phase 2: PHPUnit for backend + Jest for React components
|
|
Phase 3: E2E tests with Playwright for critical flows
|
|
Phase 4: CI/CD with GitHub Actions
|
|
|
|
Coverage targets:
|
|
├── Backend (PHP): 80% on payment + order paths
|
|
├── Admin (React): 70% on components
|
|
├── Frontend: E2E for form submission, payment, thank-you
|
|
└── API: Integration tests for all REST endpoints
|
|
```
|
|
|
|
---
|
|
|
|
## Cost-Benefit Summary
|
|
|
|
| Approach | Time | Cost | Risk | Deliverable |
|
|
|----------|------|------|------|-------------|
|
|
| **Full React rebuild** | 3-4 months | Very high | Very high | Complete rewrite, likely with new bugs |
|
|
| **Keep PHP + fix only** | 2-3 weeks | Low | Low | Fixes bugs, no UX improvement |
|
|
| **Incremental modernization** ✅ | 4-6 weeks for Phases 1-2 | Medium | Low-Medium | Bugs fixed + modern admin UX |
|
|
|
|
### Recommended: **Incremental Modernization**
|
|
|
|
This approach:
|
|
1. **Delivers value immediately** — critical bugs fixed in Week 1
|
|
2. **Reduces risk** — changes are targeted and testable
|
|
3. **Follows WordPress conventions** — SSR forms, React admin
|
|
4. **Enables future growth** — React foundation for new features
|
|
5. **Matches industry patterns** — same approach as WooCommerce, GiveWP, Gravity Forms
|
|
|
|
---
|
|
|
|
*End of recommendation.*
|