# Formipay — Product Requirements Document **Version:** 1.0 **Date:** April 17, 2026 **Status:** Approved for Implementation --- ## 1. Current State Formipay is a WordPress payment form plugin (~60 files, ~15,000 lines). It supports: - Custom post types for Forms, Products, Coupons, Access Items, Licenses - Payment gateways: PayPal, Bank Transfer - Custom database tables for Orders, Customers, Tokens, Notification Logs - Admin pages via WPCFTO framework + Vue.js partial editor - Public form rendering via PHP shortcode `[formipay]` A comprehensive audit (`FINDINGS.md`) identified **6 critical bugs**, **6 moderate bugs**, **10 security concerns**, and **12 performance issues**. Several features are stubs or incomplete (ExchangeRateAPI, License API, stock management, tax system). --- ## 2. Product Vision Transform Formipay into a production-ready, modern WordPress payment plugin using an **incremental modernization** strategy: - **Fix all critical bugs** immediately (Phase 1) - **Introduce React for admin UX** (Phase 2) - **Enhance frontend with React islands** while preserving SSR as default (Phase 3) - **Complete missing features** (Phase 4) This follows the same pattern used by WooCommerce, GiveWP, and Gravity Forms: SSR for public forms, React for admin. --- ## 3. Phase 1 — Critical Fixes & Stabilization (Weeks 1–2) ### Goal Make the plugin production-ready. Zero fatal errors, no critical security holes, acceptable performance. ### Requirements | ID | Requirement | Files | |----|-------------|-------| | F1.1 | Fix `Customer::update()` undefined `$table_name` and `$new_args` — fatal error on every update | `includes/Customer.php` | | F1.2 | Fix `Order::delete()` — uses `$id` instead of `$order_id` parameter | `includes/Order.php` | | F1.3 | Fix `Order::formipay_bulk_delete_order()` — iterates `$ids` but calls `delete($order_id)` instead of loop variable | `includes/Order.php` | | F1.4 | Fix `Email::send_email()` — calls non-existent `\Formipay_Notification::` instead of `parent::` | `includes/Notification/Email.php` | | F1.5 | Fix `Paypal::auto_cancel_order_on_timeout()` — missing `use Formipay\Order as Order` import | `includes/Integration/Paypal.php` | | F1.6 | Fix `Paypal::paypal_settings` — undefined property, no declaration | `includes/Integration/Paypal.php` | | F1.7 | Fix `BankTransfer::add_unique_code_details()` — calls `check_unique_code()` 3 times, may get different values | `includes/Payment/BankTransfer.php` | | F1.8 | Fix color field label showing "Number" instead of "Color" | `admin/functions.php` | | F1.9 | Add nonce check to `Customer::formipay_tabledata_customers()` | `includes/Customer.php` | | F1.10 | Replace `maybe_serialize()` in cookie handling with `json_encode()` | `includes/Order.php` | | F1.11 | Move `flush_rewrite_rules()` from `init` to activation hook only (Thankyou + Payment) | `includes/Thankyou.php`, `includes/Payment/Payment.php` | | F1.12 | Add PayPal webhook signature verification | `includes/Integration/Paypal.php` | | F1.13 | Cache `formipay_currency_array()` and `formipay_country_array()` JSON reads in static variables | `admin/functions.php` | | F1.14 | Add pagination to `Customer::formipay_tabledata_customers()` | `includes/Customer.php` | | F1.15 | Optimize `Order::formipay_tabledata_orders()` — use `COUNT(*) GROUP BY status` | `includes/Order.php` | | F1.16 | Delete `Paypal.phpbak` backup file from production | `includes/Integration/Paypal.phpbak` | | F1.17 | Add `uninstall.php` for cleanup (options, tables, scheduled events) | `uninstall.php` (new) | ### Success Criteria - Zero PHP fatal errors on all CRUD operations (Customer, Order, Product, Coupon) - All admin-ajax endpoints have nonce verification - `flush_rewrite_rules()` fires only on activation/deactivation - PayPal webhook rejects unsigned payloads - Customer table pagination works for 10,000+ records --- ## 4. Phase 2 — React Admin Foundation (Weeks 3–6) ### Goal Set up React build pipeline and migrate the highest-value admin pages to React. ### Requirements | ID | Requirement | Deliverable | |----|-------------|-------------| | F2.1 | Set up `@wordpress/scripts` build pipeline with webpack | `package.json`, `webpack.config.js` | | F2.2 | Create React component library structure (DataTable, SettingsPanel, Modal, StatusBadge) | `src/admin/components/` | | F2.3 | Create API client layer with nonce handling | `src/admin/api/client.js` | | F2.4 | Build drag-and-drop form builder (replace Vue editor) | `src/admin/pages/FormBuilder/` | | F2.5 | Build order list page with filters and status management | `src/admin/pages/Orders/` | | F2.6 | Build order detail view (replace Handlebars templates) | `src/admin/pages/Orders/Detail.jsx` | | F2.7 | Build analytics dashboard (orders, revenue, charts) | `src/admin/pages/Dashboard/` | | F2.8 | Build global settings page (replace WPCFTO dependency) | `src/admin/pages/Settings/` | | F2.9 | Build product editor page | `src/admin/pages/Products/` | | F2.10 | Build coupon editor page | `src/admin/pages/Coupons/` | | F2.11 | Build notification log viewer | `src/admin/pages/Notifications/` | | F2.12 | Build license management page | `src/admin/pages/Licenses/` | ### Success Criteria - `npm run build` produces working admin bundle - Form builder supports drag-and-drop, live preview, field settings - Order management supports filtering, status changes, pagination - All existing WPCFTO settings migrated to React UI - Vue admin code deprecated but not yet removed --- ## 5. Phase 3 — Frontend Enhancements (Weeks 7–10) ### Goal Add React-powered frontend features while keeping SSR as the default rendering mode. ### Requirements | ID | Requirement | Deliverable | |----|-------------|-------------| | F3.1 | Implement React island architecture — optional React mode alongside SSR | `src/frontend/widgets/FormRenderer.jsx` | | F3.2 | Add render mode setting per form: "Classic (SSR)" or "Modern (React)" | Admin setting + Render.php update | | F3.3 | Implement multi-step form navigation (missing in current SSR) | `src/frontend/widgets/MultiStepForm.jsx` | | F3.4 | Register Gutenberg block `formipay/form` with `block.json` | `src/frontend/blocks/formipay-form/` | | F3.5 | Build customer order history page | `src/frontend/widgets/CustomerPortal/` | | F3.6 | Build order detail / download access page | `src/frontend/widgets/OrderDetail.jsx` | | F3.7 | Add `[formipay_my_orders]` shortcode for customer portal | PHP + React widget | ### Success Criteria - SSR mode works identically to current behavior (no regression) - React mode provides multi-step navigation and real-time validation - Gutenberg block renders form in editor with live preview - Customer portal shows order history and download links - Both render modes share the same PHP backend API --- ## 6. Phase 4 — Missing Features (Weeks 11–16) ### Goal Complete all stubbed and missing features identified in the audit. ### Requirements | ID | Requirement | Priority | |----|-------------|----------| | F4.1 | Implement ExchangeRateAPI (currently empty class) | High | | F4.2 | Implement License API endpoints (verify, activate, deactivate, revoke — currently stubs) | High | | F4.3 | Add Stripe payment gateway | High | | F4.4 | Add tax calculation engine | Medium | | F4.5 | Implement stock management (decrement on order, validation, "out of stock" UI) | Medium | | F4.6 | Add product variations on frontend (variation dropdown rendered) | Medium | | F4.7 | Build donation form mode (pay-what-you-want, suggested amounts) | Medium | | F4.8 | Add refund workflow (full and partial refunds) | Medium | | F4.9 | Add PDF invoice generation | Medium | | F4.10 | Add CSV export for orders, customers, products | Low | | F4.11 | Add outgoing webhook system (Zapier, Slack, custom endpoints) | Low | | F4.12 | Add rate limiting on public endpoints (retrieve_form_data, check_coupon_code) | Medium | | F4.13 | Add form analytics (view tracking, conversion rate, abandonment) | Low | | F4.14 | Full i18n — generate .pot file, wrap all hardcoded strings in `__()` | Medium | ### Success Criteria - Exchange rates fetched and cached with configurable TTL - License API actually validates, activates, deactivates licenses against DB - Stripe payments complete end-to-end with webhook verification - Stock decrements on successful order, prevents overselling - Tax calculated per-product or per-order based on settings - PDF invoices downloadable from order detail page --- ## 7. Non-Functional Requirements | Category | Requirement | |----------|-------------| | **Security** | All AJAX/REST endpoints have nonce checks + capability checks (`manage_options` for admin) | | **Security** | No `maybe_serialize()` in cookie/session handling | | **Security** | All payment webhooks verify signatures | | **Performance** | `flush_rewrite_rules()` only on activation/settings save | | **Performance** | `dbDelta()` runs only on activation or schema version change | | **Performance** | Currency/country data cached in static vars or transients | | **Performance** | Admin tables use server-side pagination | | **Compatibility** | PHP 7.4+ minimum, tested through PHP 8.3 | | **Compatibility** | WordPress 6.0+ minimum | | **Code Quality** | PSR-4 autoloading via Composer | | **Code Quality** | Remove `.phpbak` files, commented-out code, dead code | | **Build** | `npm run build` produces optimized production bundles | | **Build** | `.distignore` for clean WordPress.org packaging | --- ## 8. Architecture Overview ``` PHP Backend (existing, fixed) React Admin (new) ├── Custom Post Types ├── Form Builder ├── Custom DB Tables ├── Order Management ├── Payment Gateways ├── Product/Coupon Editor ├── Email Notifications ├── Dashboard/Analytics ├── REST API Endpoints ◄──────► ├── Settings Pages ├── Webhook Handlers └── Notification Log └── Cron Jobs React Frontend (optional) SSR Form Renderer (default) ├── Multi-step Navigation ├── [formipay] shortcode ├── Customer Portal ├── Thank-you page └── Gutenberg Block └── No-JS fallback ``` --- *End of PRD.*