Skip to content

Commit 6db0659

Browse files
author
Soare Robert-Daniel
committed
dev: add docs and tweaks
1 parent 5a22f12 commit 6db0659

23 files changed

Lines changed: 1552 additions & 196 deletions

.github/workflows/copilot.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
jobs:
2+
copilot-setup-steps:
3+
4+
# You can define any steps you want, and they will run before the agent starts.
5+
steps:
6+
- uses: actions/checkout@master
7+
- uses: actions/setup-node@v6
8+
with:
9+
node-version: "20"
10+
cache: "npm"
11+
- name: Install Agent Browser
12+
run: |
13+
npm install -g agent-browser
14+
agent-browser install
15+
- name: Install NPM deps
16+
run: |
17+
npm ci
18+
npm install -g playwright-cli
19+
npx playwright install --with-deps chromium
20+
- name: Install composer deps
21+
run: composer install --no-dev
22+
- name: Install environment
23+
run: |
24+
npm run wp-env start

.github/workflows/test-php.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,19 @@ jobs:
4646
composer install --no-progress
4747
- name: Run phpstan
4848
run: composer run phpstan
49+
phpcs:
50+
name: PHPCS
51+
runs-on: ubuntu-latest
52+
steps:
53+
- name: Setup PHP version
54+
uses: shivammathur/setup-php@v2
55+
with:
56+
php-version: "7.4"
57+
extensions: simplexml
58+
- name: Checkout source code
59+
uses: actions/checkout@master
60+
- name: Install composer
61+
run: |
62+
composer install --no-progress
63+
- name: Run linter for PHP
64+
run: composer run lint

.wp-env.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
"."
55
],
66
"phpVersion": "8.1"
7-
}
7+
}

AGENTS.md

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ npm run test:unit:php # Run PHPUnit tests
2929
# Run a single PHPUnit test file
3030
wp-env run --env-cwd='wp-content/plugins/woocommerce-product-addon' tests-wordpress vendor/bin/phpunit -c phpunit.xml --filter TestClassName
3131

32-
# E2E tests (Playwright, Chromium only)
32+
# E2E tests (Playwright, Chromium only) that runs on docker.
3333
npm run test:e2e
3434
npm run test:e2e:debug # Opens Playwright UI
3535

@@ -38,14 +38,23 @@ composer run phpstan # PHPStan level 6
3838
composer run phpstan:generate:baseline
3939
```
4040

41+
You can also use `agent-browser` CLI if available with WP Docker environments for a more interactive testing experience, with credentials:
42+
43+
```
44+
Username: admin
45+
Password: password
46+
```
47+
4148
## Code Quality
4249

4350
- **PHP standard**: Themeisle ruleset (WordPress-based) via `phpcs.xml`. Text domain: `woocommerce-product-addon`.
44-
- **PHPStan**: Level 6 with a large baseline file (`phpstan-baseline.neon`). Scans `inc/`, `classes/`, `backend/`, `templates/`, and the main plugin file.
45-
- **Min PHP**: 7.2 (composer platform config). CI runs PHPStan on PHP 7.4.
51+
- **PHPStan**: Level 8 with a large baseline file (`phpstan-baseline.neon`). Scans `inc/`, `classes/`, `backend/`, `templates/`, and the main plugin file.
52+
- **Min PHP**: 7.4
4653

4754
## Architecture
4855

56+
You can read more about it on `./ARCHITECTURE.md`, but here’s a high-level overview of the main components and their relationships.
57+
4958
### Entry Point & Bootstrap
5059

5160
`woocommerce-product-addon.php` — defines constants, loads Composer autoload, manually `require_once`s all class/include files (no PSR-4 autoloading for plugin code), then hooks `PPOM()` on `woocommerce_init`.
@@ -116,14 +125,49 @@ Declares WooCommerce Custom Order Tables compatibility via `FeaturesUtil::declar
116125

117126
## WooCommerce Security + Workflow
118127

119-
- Treat all input as untrusted (POST/AJAX/cart session/order meta).
120-
- For state-changing actions, require both capability checks and nonce verification.
121-
- Never trust frontend option pricing; recompute server-side in cart/checkout.
122-
- Validate product/variation context with Woo objects before processing.
123-
- Sanitize on input (type-aware) and escape on output (context-aware).
124-
- Use `$wpdb->prepare()` (plus `$wpdb->esc_like()` for LIKE queries); never concatenate user input.
125-
- For uploads, enforce extension/mime/size rules and block executable files.
126-
- Prefer WooCommerce CRUD/order APIs (HPOS-safe) over direct post/meta SQL.
127-
- Keep pricing hooks idempotent, especially in `woocommerce_before_calculate_totals`.
128+
### Trust Boundaries
129+
130+
- Treat product page fields, AJAX/REST payloads, cart item data, restored sessions, order item meta, and admin imports/settings as untrusted input.
131+
- Never trust browser-sent prices, fee amounts, labels, field IDs, variation IDs, conditional flags, upload metadata, or Pro gating flags. Recompute from saved PPOM/WooCommerce configuration on the server.
132+
- Validate submitted field names/options against the field schema attached to the current product/meta group before storing or pricing anything.
133+
- Resolve product and variation IDs to real WooCommerce objects and confirm the variation belongs to the parent product before processing.
134+
135+
### Authorization + Request Integrity
136+
137+
- For every state-changing admin, AJAX, or REST action, require both a capability check and nonce verification. For REST routes, always implement a strict `permission_callback`.
138+
- Never use `is_admin()` as an authorization check.
139+
- Scope privileged actions to the narrowest capability that fits the action: field-group CRUD, settings changes, file deletion, import/export, license actions, and diagnostic tools should not share a blanket permission model.
140+
141+
### Data Handling Rules
142+
143+
- Sanitize on input with type-appropriate functions, validate against business rules, and escape on output with the correct context-aware `esc_*()` function.
144+
- Use `$wpdb->prepare()` for every query containing dynamic input, and pair `LIKE` clauses with `$wpdb->esc_like()`. Never concatenate request data into SQL.
145+
- Prefer WooCommerce CRUD APIs and order/item meta APIs over direct post/meta SQL so behavior stays HPOS-safe.
146+
- Do not persist raw `$_POST` or `$_REQUEST` payloads into cart item data, session data, or order meta. Store only the normalized values the plugin actually needs.
147+
- Do not expose addon values, upload URLs, or order item metadata in logs, notices, REST responses, emails, or templates unless the current user/context is explicitly allowed to see them.
148+
149+
### Pricing + Cart Integrity
150+
151+
- Keep all pricing logic server-authoritative and idempotent. Hooks like `woocommerce_before_calculate_totals` may run multiple times per request.
152+
- Recalculate addon totals from canonical field definitions during validation, cart restore, and checkout instead of trusting values carried forward from the browser or session.
153+
- Guard against double-charging when cart items are restored from session, when quantities change, or when multiple pricing hooks run in sequence.
154+
- When pricing depends on product type, variation, quantity, tax mode, currency, or coupon state, use current WooCommerce objects/state at calculation time instead of stale cart snapshots.
155+
156+
### Upload Safety
157+
158+
- Enforce an allowlist for extensions, MIME types, and size limits; reject executable/scriptable files, double extensions, and unexpected archive types.
159+
- Generate filenames and paths server-side, keep uploads inside the dedicated PPOM upload directory, and never trust client-provided path, MIME, or filename values.
160+
- Re-check authorization and attachment ownership before serving, deleting, or attaching uploaded files to cart/order data.
161+
162+
### WooCommerce Lifecycle
163+
128164
- Preferred option lifecycle hooks: `woocommerce_add_to_cart_validation` -> `woocommerce_add_cart_item_data` -> `woocommerce_get_cart_item_from_session` -> `woocommerce_get_item_data` -> `woocommerce_checkout_create_order_line_item`.
129-
- Minimum regression checks per addon: simple/variable products, guest/logged-in checkout, tax modes, coupons/sales, session restore, and (if enabled) multi-currency/multi-language.
165+
- Validate as early as possible, normalize before storing in cart data, and only persist to order items after the cart payload has been revalidated.
166+
- Treat session restore, reorder, and edit-cart flows as fresh untrusted input, not trusted historical state.
167+
168+
### Minimum Regression Checks
169+
170+
- Per addon/security-sensitive change, cover simple and variable products, guest and logged-in checkout, tax modes, coupons/sales, quantity changes, and session restore.
171+
- If uploads are involved, test invalid MIME/extension cases, oversized files, duplicate filenames, and cleanup paths.
172+
- If REST, AJAX, or admin writes are involved, explicitly test success, nonce failure, and capability failure paths.
173+
- If enabled in the target store, also verify multi-currency, multi-language, and HPOS behavior.

0 commit comments

Comments
 (0)