helpers
1 day ago
routes
1 day ago
src
1 day ago
CLAUDE.md
4 months ago
config.php
1 day ago
helpers.php
4 months ago
hooks.php
2 months ago
CLAUDE.md
106 lines
| 1 | # SureCart PHP Backend Patterns |
| 2 | |
| 3 | Patterns and conventions for working in the `app/` directory. See root `CLAUDE.md` for architecture overview. |
| 4 | |
| 5 | ## Adding a New Model |
| 6 | |
| 7 | ```php |
| 8 | // app/src/Models/MyModel.php |
| 9 | namespace SureCart\Models; |
| 10 | |
| 11 | class MyModel extends Model { // or DatabaseModel for WP DB storage |
| 12 | protected $endpoint = 'my_models'; // maps to api.surecart.com/my_models |
| 13 | protected $object_name = 'my_model'; |
| 14 | } |
| 15 | ``` |
| 16 | |
| 17 | Available traits: `HasDates`, `HasCustomer`, `HasPurchases`, `HasBillingAddress`, `HasShippingAddress`, `HasPaymentIntent`, `HasPaymentMethod`, `HasDiscount`, `CanFinalize`, `CanDuplicate`, `HasImageSizes`, `HasSubscriptions`, `HasProcessorType`, `HasShippingChoices`, `HasCommissionStructure` |
| 18 | |
| 19 | ## Adding a New REST Endpoint |
| 20 | |
| 21 | Three-file pattern, then register in `app/config.php`: |
| 22 | |
| 23 | ```php |
| 24 | // 1. Model (see above) |
| 25 | |
| 26 | // 2. app/src/Controllers/Rest/MyModelController.php |
| 27 | class MyModelController extends RestController { |
| 28 | protected $class = MyModel::class; |
| 29 | } |
| 30 | |
| 31 | // 3. app/src/Rest/MyModelRestServiceProvider.php |
| 32 | class MyModelRestServiceProvider extends RestServiceProvider { |
| 33 | protected $endpoint = 'my_models'; // /wp-json/surecart/v1/my_models |
| 34 | protected $controller = MyModelController::class; |
| 35 | protected $methods = ['index', 'create', 'find', 'edit', 'delete']; |
| 36 | } |
| 37 | |
| 38 | // 4. Add MyModelRestServiceProvider::class to 'providers' array in app/config.php |
| 39 | ``` |
| 40 | |
| 41 | Permission callbacks use `current_user_can('edit_sc_my_models')` pattern. |
| 42 | |
| 43 | ## Error Handling |
| 44 | |
| 45 | ```php |
| 46 | // Controllers: propagate WP_Error upward — REST layer auto-converts to response |
| 47 | $result = MyModel::create($data); |
| 48 | if (is_wp_error($result)) { |
| 49 | return $result; |
| 50 | } |
| 51 | |
| 52 | // Integrations: wrap in try-catch to prevent one integration killing others |
| 53 | try { |
| 54 | do_action('surecart/purchase_created', $purchase); |
| 55 | } catch (\Exception $e) { |
| 56 | error_log($e->getMessage()); |
| 57 | } |
| 58 | ``` |
| 59 | |
| 60 | `ErrorsTranslationService` translates API error codes to user messages automatically via lookup files in `Support/Errors/`. Do not duplicate translation logic. |
| 61 | |
| 62 | ## Adding a New Integration |
| 63 | |
| 64 | All integrations extend `IntegrationService` and implement `PurchaseSyncInterface`: |
| 65 | |
| 66 | ```php |
| 67 | // Required abstract methods from IntegrationService: |
| 68 | getName(), getModel(), getLogo(), getLabel(), getItemLabel(), getItemHelp() |
| 69 | |
| 70 | // Required from PurchaseSyncInterface: |
| 71 | onPurchaseCreated($integration, $wp_user) |
| 72 | onPurchaseInvoked($integration, $wp_user) |
| 73 | onPurchaseRevoked($integration, $wp_user) |
| 74 | ``` |
| 75 | |
| 76 | - Integration data (product/price/variant -> third-party item mapping) stored in `surecart_integrations` table via `Integration` model (DatabaseModel) |
| 77 | - Register service provider in `app/config.php` under `'providers'` |
| 78 | - Actions fire from `DraftCheckoutsController::finalize()` and webhook processor — do not hook them manually |
| 79 | |
| 80 | ## Routes and Middleware |
| 81 | |
| 82 | ```php |
| 83 | // app/routes/admin.php pattern: |
| 84 | \SureCart::route()->get() |
| 85 | ->where('admin', 'sc-products') |
| 86 | ->middleware('user.can:edit_sc_products') |
| 87 | ->middleware('assets.components') // loads Stencil component assets |
| 88 | ->handle('ProductsController@index'); |
| 89 | ``` |
| 90 | |
| 91 | Non-obvious middleware alias keys: `assets.components`, `assets.brand_colors`, `assets.admin_colors`, `nonce`, `webhooks`, `edit_model`, `archive_model` |
| 92 | |
| 93 | ## Webhook Event -> WordPress Action Mapping |
| 94 | |
| 95 | | API Event | WordPress Action | |
| 96 | |---|---| |
| 97 | | `purchase.created` | `surecart/purchase_created` | |
| 98 | | `purchase.revoked` | `surecart/purchase_revoked` | |
| 99 | | `purchase.invoked` | `surecart/purchase_invoked` | |
| 100 | | `purchase.updated` | `surecart/purchase_updated` | |
| 101 | | `customer.updated` | `surecart/customer_updated` | |
| 102 | | `account.updated` | `surecart/account_updated` | |
| 103 | | `subscription.renewed` | `surecart/subscription_renewed` | |
| 104 | |
| 105 | Price/product CRUD events also fire but are rarely hooked externally. |
| 106 |