@ai-kits/wp-ag-kit 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -8
- package/STRUCTURE.md +9 -7
- package/agents/woocommerce-expert.md +32 -0
- package/agents/wordpress-expert.md +4 -2
- package/package.json +5 -3
- package/skills/woocommerce/SKILL.md +54 -0
- package/skills/woocommerce/references/backend-dev-guide.md +44 -0
- package/skills/woocommerce/references/code-entities.md +186 -0
- package/skills/woocommerce/references/code-quality.md +273 -0
- package/skills/woocommerce/references/code-review-guide.md +71 -0
- package/skills/woocommerce/references/coding-conventions.md +182 -0
- package/skills/woocommerce/references/copy-guidelines-guide.md +17 -0
- package/skills/woocommerce/references/data-integrity.md +164 -0
- package/skills/woocommerce/references/dependency-injection.md +102 -0
- package/skills/woocommerce/references/dev-cycle-guide.md +32 -0
- package/skills/woocommerce/references/file-entities.md +73 -0
- package/skills/woocommerce/references/hooks.md +87 -0
- package/skills/woocommerce/references/js-i18n-patterns.md +298 -0
- package/skills/woocommerce/references/markdown-guide.md +358 -0
- package/skills/woocommerce/references/markdown-linting.md +202 -0
- package/skills/woocommerce/references/php-i18n-patterns.md +83 -0
- package/skills/woocommerce/references/php-linting-patterns.md +304 -0
- package/skills/woocommerce/references/running-tests.md +249 -0
- package/skills/woocommerce/references/security-patterns.md +109 -0
- package/skills/woocommerce/references/sentence-case.md +177 -0
- package/skills/woocommerce/references/type-annotations.md +161 -0
- package/skills/woocommerce/references/unit-tests.md +362 -0
- package/skills/woocommerce/references/woocommerce-global-objects.md +89 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# PHP Linting Patterns and Common Issues
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Critical Rule: Lint Only Specific Files](#critical-rule-lint-only-specific-files)
|
|
6
|
+
- [Common PHP Linting Issues & Fixes](#common-php-linting-issues--fixes)
|
|
7
|
+
- [Translators Comment Placement](#translators-comment-placement)
|
|
8
|
+
- [PSR-12 File Header Order](#psr-12-file-header-order)
|
|
9
|
+
- [Mock Classes with Intentional Violations](#mock-classes-with-intentional-violations)
|
|
10
|
+
- [Multi-line Condition Alignment](#multi-line-condition-alignment)
|
|
11
|
+
- [Unused Closure Parameters](#unused-closure-parameters)
|
|
12
|
+
- [Array and Operator Alignment](#array-and-operator-alignment)
|
|
13
|
+
- [Indentation Rules](#indentation-rules)
|
|
14
|
+
- [Workflow for Fixing PHP Linting Issues](#workflow-for-fixing-php-linting-issues)
|
|
15
|
+
- [Quick Command Reference](#quick-command-reference)
|
|
16
|
+
|
|
17
|
+
## Critical Rule: Lint Only Specific Files
|
|
18
|
+
|
|
19
|
+
**NEVER run linting on the entire codebase.** Always lint specific files, changed files or staged files only.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# ✅ CORRECT: Check only changed files at the branch level
|
|
23
|
+
pnpm lint:php:changes
|
|
24
|
+
|
|
25
|
+
# ✅ CORRECT: Check only changed files that are staged
|
|
26
|
+
pnpm lint:php:changes:staged
|
|
27
|
+
|
|
28
|
+
# ✅ CORRECT: Lint specific file
|
|
29
|
+
pnpm lint:php -- path/to/file.php
|
|
30
|
+
pnpm lint:php:fix -- path/to/file.php
|
|
31
|
+
|
|
32
|
+
# ❌ WRONG: Lints entire codebase
|
|
33
|
+
pnpm lint:php
|
|
34
|
+
pnpm lint:php:fix
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Common PHP Linting Issues & Fixes
|
|
38
|
+
|
|
39
|
+
### Quick Reference Table
|
|
40
|
+
|
|
41
|
+
| Issue | Wrong | Correct |
|
|
42
|
+
|-------|-------|---------|
|
|
43
|
+
| **Translators comment** | Before return | Before function call |
|
|
44
|
+
| **File docblock (PSR-12)** | After `declare()` | Before `declare()` |
|
|
45
|
+
| **Indentation** | Spaces | Tabs only |
|
|
46
|
+
| **Array alignment** | Inconsistent | Align `=>` with context |
|
|
47
|
+
| **Equals alignment** | Inconsistent | Match surrounding style |
|
|
48
|
+
|
|
49
|
+
## Translators Comment Placement
|
|
50
|
+
|
|
51
|
+
Translators comments must be placed **immediately before the translation function call**, not before the return statement.
|
|
52
|
+
|
|
53
|
+
### Wrong - Comment Before Return
|
|
54
|
+
|
|
55
|
+
```php
|
|
56
|
+
/* translators: %s: Gateway name. */
|
|
57
|
+
return sprintf(
|
|
58
|
+
esc_html__( '%s is not supported.', 'woocommerce' ),
|
|
59
|
+
'Gateway'
|
|
60
|
+
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Correct - Comment Before Translation Function
|
|
64
|
+
|
|
65
|
+
```php
|
|
66
|
+
return sprintf(
|
|
67
|
+
/* translators: %s: Gateway name. */
|
|
68
|
+
esc_html__( '%s is not supported.', 'woocommerce' ),
|
|
69
|
+
'Gateway'
|
|
70
|
+
);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Multiple Parameters
|
|
74
|
+
|
|
75
|
+
```php
|
|
76
|
+
return sprintf(
|
|
77
|
+
/* translators: 1: Gateway name, 2: Country code. */
|
|
78
|
+
esc_html__( '%1$s is not available in %2$s.', 'woocommerce' ),
|
|
79
|
+
$gateway_name,
|
|
80
|
+
$country_code
|
|
81
|
+
);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## PSR-12 File Header Order
|
|
85
|
+
|
|
86
|
+
File docblocks must come **before** the `declare()` statement, not after.
|
|
87
|
+
|
|
88
|
+
### Wrong - Docblock After declare()
|
|
89
|
+
|
|
90
|
+
```php
|
|
91
|
+
<?php
|
|
92
|
+
declare( strict_types=1 );
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* File docblock
|
|
96
|
+
*
|
|
97
|
+
* @package WooCommerce
|
|
98
|
+
*/
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Correct - Docblock Before declare()
|
|
102
|
+
|
|
103
|
+
```php
|
|
104
|
+
<?php
|
|
105
|
+
/**
|
|
106
|
+
* File docblock
|
|
107
|
+
*
|
|
108
|
+
* @package WooCommerce
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
declare( strict_types=1 );
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Mock Classes with Intentional Violations
|
|
115
|
+
|
|
116
|
+
When creating mock classes that must match external class names, use phpcs:disable comments:
|
|
117
|
+
|
|
118
|
+
```php
|
|
119
|
+
if ( ! class_exists( 'WC_Payments_Utils' ) ) {
|
|
120
|
+
/**
|
|
121
|
+
* Mock class for testing.
|
|
122
|
+
*
|
|
123
|
+
* phpcs:disable Squiz.Classes.ClassFileName.NoMatch
|
|
124
|
+
* phpcs:disable Suin.Classes.PSR4.IncorrectClassName
|
|
125
|
+
* phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
|
|
126
|
+
*/
|
|
127
|
+
class WC_Payments_Utils {
|
|
128
|
+
/**
|
|
129
|
+
* Mock implementation.
|
|
130
|
+
*/
|
|
131
|
+
public static function supported_countries() {
|
|
132
|
+
return array( 'US', 'GB' );
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Multi-line Condition Alignment
|
|
139
|
+
|
|
140
|
+
Use tabs for continuation lines in multi-line conditions:
|
|
141
|
+
|
|
142
|
+
```php
|
|
143
|
+
// Correct - tabs for continuation
|
|
144
|
+
if ( class_exists( '\WC_Payments_Utils' ) &&
|
|
145
|
+
is_callable( '\WC_Payments_Utils::supported_countries' ) ) {
|
|
146
|
+
// code
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Also correct - align with opening parenthesis
|
|
150
|
+
if ( class_exists( '\WC_Payments_Utils' ) &&
|
|
151
|
+
is_callable( '\WC_Payments_Utils::supported_countries' ) ) {
|
|
152
|
+
// code
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Unused Closure Parameters
|
|
157
|
+
|
|
158
|
+
When creating closures with parameters required by signature but unused, use `unset()` to avoid PHPCS errors:
|
|
159
|
+
|
|
160
|
+
### The Problem
|
|
161
|
+
|
|
162
|
+
```php
|
|
163
|
+
// ❌ WRONG - PHPCS error: Generic.CodeAnalysis.UnusedFunctionParameter
|
|
164
|
+
'callback' => function ( string $return_url ) {
|
|
165
|
+
return array( 'success' => true );
|
|
166
|
+
},
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### The Solution
|
|
170
|
+
|
|
171
|
+
```php
|
|
172
|
+
// ✅ CORRECT - unset unused parameters
|
|
173
|
+
'callback' => function ( string $return_url ) {
|
|
174
|
+
unset( $return_url ); // Avoid parameter not used PHPCS errors.
|
|
175
|
+
return array( 'success' => true );
|
|
176
|
+
},
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Multiple Unused Parameters
|
|
180
|
+
|
|
181
|
+
```php
|
|
182
|
+
'callback' => function ( $arg1, $arg2, $arg3 ) {
|
|
183
|
+
unset( $arg1, $arg2 ); // Avoid parameter not used PHPCS errors.
|
|
184
|
+
return $arg3;
|
|
185
|
+
},
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Common Scenarios
|
|
189
|
+
|
|
190
|
+
- Mock method callbacks in PHPUnit tests
|
|
191
|
+
- Array/filter callbacks where signature is fixed
|
|
192
|
+
- Interface implementations with unused parameters
|
|
193
|
+
|
|
194
|
+
**Reference:** `tests/php/src/Internal/Admin/Settings/PaymentsRestControllerIntegrationTest.php:1647-1655`
|
|
195
|
+
|
|
196
|
+
## Array and Operator Alignment
|
|
197
|
+
|
|
198
|
+
### Array Arrow Alignment
|
|
199
|
+
|
|
200
|
+
Align `=>` arrows consistently within each array context:
|
|
201
|
+
|
|
202
|
+
```php
|
|
203
|
+
// Correct - aligned arrows
|
|
204
|
+
$options = array(
|
|
205
|
+
'gateway_id' => 'stripe',
|
|
206
|
+
'enabled' => true,
|
|
207
|
+
'country_code' => 'US',
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// Also correct - no alignment for short arrays
|
|
211
|
+
$small = array(
|
|
212
|
+
'id' => 123,
|
|
213
|
+
'name' => 'Test',
|
|
214
|
+
);
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Assignment Operator Alignment
|
|
218
|
+
|
|
219
|
+
Match the surrounding code style:
|
|
220
|
+
|
|
221
|
+
```php
|
|
222
|
+
// When surrounding code aligns, align:
|
|
223
|
+
$gateway_id = 'stripe';
|
|
224
|
+
$enabled = true;
|
|
225
|
+
$country_code = 'US';
|
|
226
|
+
|
|
227
|
+
// When surrounding code doesn't align, don't align:
|
|
228
|
+
$gateway_id = 'stripe';
|
|
229
|
+
$enabled = true;
|
|
230
|
+
$country_code = 'US';
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Indentation Rules
|
|
234
|
+
|
|
235
|
+
**Always use tabs, never spaces, for indentation.**
|
|
236
|
+
|
|
237
|
+
```php
|
|
238
|
+
// ✅ Correct - tabs for indentation
|
|
239
|
+
public function process_payment( $order_id ) {
|
|
240
|
+
→ $order = wc_get_order( $order_id );
|
|
241
|
+
→
|
|
242
|
+
→ if ( ! $order ) {
|
|
243
|
+
→ → return false;
|
|
244
|
+
→ }
|
|
245
|
+
→
|
|
246
|
+
→ return true;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ❌ Wrong - spaces for indentation
|
|
250
|
+
public function process_payment( $order_id ) {
|
|
251
|
+
$order = wc_get_order( $order_id );
|
|
252
|
+
|
|
253
|
+
if ( ! $order ) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Workflow for Fixing PHP Linting Issues
|
|
262
|
+
|
|
263
|
+
1. **Run linting on changed files:**
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
pnpm lint:php:changes
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
2. **Auto-fix what you can:**
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
pnpm lint:php:fix -- path/to/file.php
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
3. **Review remaining errors** - Common issues that require manual fixing:
|
|
276
|
+
- Translators comment placement
|
|
277
|
+
- File docblock order (PSR-12)
|
|
278
|
+
- Unused closure parameters (add `unset()`)
|
|
279
|
+
|
|
280
|
+
4. **Address remaining issues manually**
|
|
281
|
+
|
|
282
|
+
5. **Verify the output is clean:**
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
pnpm lint:php -- path/to/file.php
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
6. **Commit**
|
|
289
|
+
|
|
290
|
+
## Quick Command Reference
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Check changed files
|
|
294
|
+
pnpm lint:php:changes
|
|
295
|
+
|
|
296
|
+
# Check specific file
|
|
297
|
+
pnpm lint:php -- src/Internal/Admin/ClassName.php
|
|
298
|
+
|
|
299
|
+
# Fix specific file
|
|
300
|
+
pnpm lint:php:fix -- src/Internal/Admin/ClassName.php
|
|
301
|
+
|
|
302
|
+
# Check with error details
|
|
303
|
+
vendor/bin/phpcs -s path/to/file.php
|
|
304
|
+
```
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Running Tests
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [PHP Unit Tests](#php-unit-tests)
|
|
6
|
+
- [Basic Test Commands](#basic-test-commands)
|
|
7
|
+
- [Examples](#examples)
|
|
8
|
+
- [Common Test Commands](#common-test-commands)
|
|
9
|
+
- [Test Environment](#test-environment)
|
|
10
|
+
- [Troubleshooting Tests](#troubleshooting-tests)
|
|
11
|
+
- [Interpreting Test Output](#interpreting-test-output)
|
|
12
|
+
- [Best Practices](#best-practices)
|
|
13
|
+
- [Test Configuration](#test-configuration)
|
|
14
|
+
- [JavaScript/Jest Tests](#javascriptjest-tests)
|
|
15
|
+
- [Notes](#notes)
|
|
16
|
+
|
|
17
|
+
## PHP Unit Tests
|
|
18
|
+
|
|
19
|
+
To run PHP unit tests in the WooCommerce plugin directory, use the following commands:
|
|
20
|
+
|
|
21
|
+
### Basic Test Commands
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Run all PHP unit tests
|
|
25
|
+
pnpm run test:php:env
|
|
26
|
+
|
|
27
|
+
# Run specific test class
|
|
28
|
+
pnpm run test:php:env -- --filter TestClassName
|
|
29
|
+
|
|
30
|
+
# Run specific test method
|
|
31
|
+
pnpm run test:php:env -- --filter TestClassName::test_method_name
|
|
32
|
+
|
|
33
|
+
# Run tests with verbose output
|
|
34
|
+
pnpm run test:php:env -- --verbose --filter TestClassName
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Examples
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Run payment extension suggestions tests
|
|
41
|
+
pnpm run test:php:env -- --filter PaymentsExtensionSuggestionsTest
|
|
42
|
+
|
|
43
|
+
# Run specific test method
|
|
44
|
+
pnpm run test:php:env -- --filter PaymentsExtensionSuggestionsTest::test_get_country_extensions_count_with_merchant_selling_online
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Common Test Commands
|
|
48
|
+
|
|
49
|
+
### Run Tests for a Directory
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Run all tests in a directory
|
|
53
|
+
pnpm run test:php:env -- tests/php/src/Internal/Admin/
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Run Tests Matching a Pattern
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Run all Admin tests
|
|
60
|
+
pnpm run test:php:env -- --filter "Admin.*Test"
|
|
61
|
+
|
|
62
|
+
# Run all tests with "Payment" in the name
|
|
63
|
+
pnpm run test:php:env -- --filter "Payment"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Stop on First Failure
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Useful during development to quickly identify issues
|
|
70
|
+
pnpm run test:php:env -- --stop-on-failure
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Get Test Coverage
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Get coverage report (if configured)
|
|
77
|
+
pnpm run test:php:env -- --coverage-text
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Test Environment
|
|
81
|
+
|
|
82
|
+
### How It Works
|
|
83
|
+
|
|
84
|
+
Tests run in Docker via `wp-env` with auto-configured WordPress/WooCommerce (PHPUnit 9.6.24, PHP 8.1).
|
|
85
|
+
|
|
86
|
+
### Environment Setup
|
|
87
|
+
|
|
88
|
+
The test environment is managed automatically, but you can control it if needed:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Start the test environment
|
|
92
|
+
wp-env start
|
|
93
|
+
|
|
94
|
+
# Stop the test environment
|
|
95
|
+
wp-env stop
|
|
96
|
+
|
|
97
|
+
# Restart the test environment
|
|
98
|
+
wp-env restart
|
|
99
|
+
|
|
100
|
+
# Destroy and recreate the environment
|
|
101
|
+
wp-env destroy
|
|
102
|
+
wp-env start
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Troubleshooting Tests
|
|
106
|
+
|
|
107
|
+
| Problem | Solution |
|
|
108
|
+
|---------|----------|
|
|
109
|
+
| "Class not found" errors | Run `pnpm install` |
|
|
110
|
+
| Tests hang/fail to start | `wp-env stop && wp-env start` or `wp-env destroy && wp-env start` |
|
|
111
|
+
| Permission errors | Check Docker permissions |
|
|
112
|
+
| Xdebug warnings | Ignore (don't affect results) |
|
|
113
|
+
|
|
114
|
+
## Interpreting Test Output
|
|
115
|
+
|
|
116
|
+
### Successful Test Run
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
PHPUnit 9.6.24
|
|
120
|
+
|
|
121
|
+
.................................................. 50 / 100 ( 50%)
|
|
122
|
+
.................................................. 100 / 100 (100%)
|
|
123
|
+
|
|
124
|
+
Time: 00:02.345, Memory: 24.00 MB
|
|
125
|
+
|
|
126
|
+
OK (100 tests, 250 assertions)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Failed Test
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
PHPUnit 9.6.24
|
|
133
|
+
|
|
134
|
+
.....F................................................. 50 / 100 ( 50%)
|
|
135
|
+
.................................................. 100 / 100 (100%)
|
|
136
|
+
|
|
137
|
+
Time: 00:02.345, Memory: 24.00 MB
|
|
138
|
+
|
|
139
|
+
There was 1 failure:
|
|
140
|
+
|
|
141
|
+
1) PaymentsExtensionSuggestionsTest::test_get_country_extensions_count_for_online_merchants with data set "United States" ('US', 5)
|
|
142
|
+
Expected 5 extensions for online merchant in US
|
|
143
|
+
Failed asserting that 4 matches expected 5.
|
|
144
|
+
|
|
145
|
+
/path/to/test/file.php:123
|
|
146
|
+
|
|
147
|
+
FAILURES!
|
|
148
|
+
Tests: 100, Assertions: 250, Failures: 1.
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Understanding Failures
|
|
152
|
+
|
|
153
|
+
Test failures provide:
|
|
154
|
+
|
|
155
|
+
- **Which test failed:** Test class and method name
|
|
156
|
+
- **Test data:** Data set used (if using data providers)
|
|
157
|
+
- **Expected vs actual:** What was expected and what was received
|
|
158
|
+
- **Location:** File and line number where assertion failed
|
|
159
|
+
|
|
160
|
+
## Best Practices
|
|
161
|
+
|
|
162
|
+
### During Development
|
|
163
|
+
|
|
164
|
+
1. **Run specific tests** for the code you're changing:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pnpm run test:php:env -- --filter YourTestClass
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
2. **Use verbose mode** when debugging:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
pnpm run test:php:env -- --verbose --filter YourTestClass
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
3. **Stop on first failure** to focus on one issue at a time:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
pnpm run test:php:env -- --stop-on-failure --filter YourTestClass
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Before Committing
|
|
183
|
+
|
|
184
|
+
1. **Run all affected tests:**
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pnpm run test:php:env -- tests/php/src/Internal/YourFeature/
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
2. **Ensure all tests pass** before committing
|
|
191
|
+
|
|
192
|
+
3. **Check code quality** (see code-quality.md)
|
|
193
|
+
|
|
194
|
+
## Test Configuration
|
|
195
|
+
|
|
196
|
+
Test configuration file: `plugins/woocommerce/phpunit.xml`
|
|
197
|
+
|
|
198
|
+
This file contains:
|
|
199
|
+
|
|
200
|
+
- Test suite definitions
|
|
201
|
+
- Bootstrap files
|
|
202
|
+
- Coverage settings
|
|
203
|
+
- Logging configuration
|
|
204
|
+
|
|
205
|
+
## JavaScript/Jest Tests
|
|
206
|
+
|
|
207
|
+
### Running JavaScript Tests
|
|
208
|
+
|
|
209
|
+
To run JavaScript tests for the admin client, navigate to the `client/admin` directory:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Navigate to client/admin directory first
|
|
213
|
+
cd client/admin
|
|
214
|
+
|
|
215
|
+
# Run all JavaScript tests
|
|
216
|
+
pnpm test:js
|
|
217
|
+
|
|
218
|
+
# Run tests in watch mode
|
|
219
|
+
pnpm test:js -- --watch
|
|
220
|
+
|
|
221
|
+
# Run a specific test file
|
|
222
|
+
pnpm test:js -- status-badge.test.tsx
|
|
223
|
+
|
|
224
|
+
# Run tests with coverage
|
|
225
|
+
pnpm test:js -- --coverage
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Test File Locations
|
|
229
|
+
|
|
230
|
+
- JavaScript/Jest tests: `client/admin/client/**/*.test.tsx` or `*.test.ts`
|
|
231
|
+
- Jest configuration: `client/admin/jest.config.js`
|
|
232
|
+
|
|
233
|
+
### Troubleshooting JavaScript Tests
|
|
234
|
+
|
|
235
|
+
For detailed Jest configuration and testing patterns, see `client/admin/CLAUDE.md`.
|
|
236
|
+
|
|
237
|
+
Common issues:
|
|
238
|
+
|
|
239
|
+
- **Tests not found**: Ensure you're in the `client/admin` directory
|
|
240
|
+
- **Module resolution errors**: Run `pnpm install` in the `client/admin` directory
|
|
241
|
+
- **Cache issues**: Try `pnpm test:js -- --clearCache`
|
|
242
|
+
|
|
243
|
+
## Notes
|
|
244
|
+
|
|
245
|
+
- The test environment handles WordPress/WooCommerce setup automatically
|
|
246
|
+
- Extension counts in payment tests must match the actual implementation exactly
|
|
247
|
+
- Test data providers are useful for testing multiple scenarios
|
|
248
|
+
- Always check test output for helpful error messages
|
|
249
|
+
- For React/TypeScript testing patterns, refer to `client/admin/CLAUDE.md`
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Security Patterns for WooCommerce
|
|
2
|
+
|
|
3
|
+
This guide covers security best practices for WooCommerce development, focusing on data sanitization, validation, and escaping.
|
|
4
|
+
|
|
5
|
+
## Data Sanitization (Inputs)
|
|
6
|
+
|
|
7
|
+
Always sanitize user input before using it in logic or saving to the database.
|
|
8
|
+
|
|
9
|
+
| Type | Function |
|
|
10
|
+
|------|----------|
|
|
11
|
+
| Text | `sanitize_text_field()` |
|
|
12
|
+
| Email | `sanitize_email()` |
|
|
13
|
+
| URL | `esc_url_raw()` |
|
|
14
|
+
| Key/Slug | `sanitize_key()` |
|
|
15
|
+
| Array | `array_map( 'sanitize_text_field', $array )` |
|
|
16
|
+
|
|
17
|
+
```php
|
|
18
|
+
$product_name = sanitize_text_field( $_POST['product_name'] ?? '' );
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Data Validation
|
|
22
|
+
|
|
23
|
+
Verify data before processing it.
|
|
24
|
+
|
|
25
|
+
```php
|
|
26
|
+
if ( ! is_numeric( $order_id ) ) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if ( ! is_email( $user_email ) ) {
|
|
31
|
+
throw new Exception( 'Invalid email' );
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Data Escaping (Outputs)
|
|
36
|
+
|
|
37
|
+
Always escape data right before echoing it. This is the last line of defense against XSS.
|
|
38
|
+
|
|
39
|
+
| Type | Function |
|
|
40
|
+
|------|----------|
|
|
41
|
+
| HTML Content | `esc_html()` |
|
|
42
|
+
| HTML Attributes | `esc_attr()` |
|
|
43
|
+
| URLs | `esc_url()` |
|
|
44
|
+
| JavaScript | `esc_js()` |
|
|
45
|
+
| textarea | `esc_textarea()` |
|
|
46
|
+
|
|
47
|
+
```php
|
|
48
|
+
echo '<div class="name">' . esc_html( $name ) . '</div>';
|
|
49
|
+
echo '<input value="' . esc_attr( $value ) . '">';
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Nonces
|
|
53
|
+
|
|
54
|
+
Always use nonces to protect against CSRF attacks in forms and AJAX requests.
|
|
55
|
+
|
|
56
|
+
### Form Verification
|
|
57
|
+
|
|
58
|
+
```php
|
|
59
|
+
// In the form
|
|
60
|
+
wp_nonce_field( 'my_plugin_action', 'my_plugin_nonce' );
|
|
61
|
+
|
|
62
|
+
// In the processing logic
|
|
63
|
+
if ( ! isset( $_POST['my_plugin_nonce'] ) || ! wp_verify_nonce( $_POST['my_plugin_nonce'], 'my_plugin_action' ) ) {
|
|
64
|
+
wp_die( 'Security check failed' );
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### URL/AJAX Verification
|
|
69
|
+
|
|
70
|
+
```php
|
|
71
|
+
// Creating link
|
|
72
|
+
$url = wp_nonce_url( admin_url( 'admin-post.php?action=my_action' ), 'my_action_nonce' );
|
|
73
|
+
|
|
74
|
+
// Verification
|
|
75
|
+
check_admin_referer( 'my_action_nonce' );
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Database Safety
|
|
79
|
+
|
|
80
|
+
Use `$wpdb->prepare()` for custom SQL queries to prevent SQL injection.
|
|
81
|
+
|
|
82
|
+
```php
|
|
83
|
+
global $wpdb;
|
|
84
|
+
$id = 123;
|
|
85
|
+
$results = $wpdb->get_results( $wpdb->prepare(
|
|
86
|
+
"SELECT * FROM {$wpdb->prefix}posts WHERE ID = %d",
|
|
87
|
+
$id
|
|
88
|
+
) );
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Capabilities and Permissions
|
|
92
|
+
|
|
93
|
+
Always check if the current user has the authority to perform an action.
|
|
94
|
+
|
|
95
|
+
```php
|
|
96
|
+
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if ( ! $order->get_customer_id() === get_current_user_id() ) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## WooCommerce Specific Security
|
|
106
|
+
|
|
107
|
+
- Use `WC_Validation` class for common e-commerce validation (postcodes, phone numbers).
|
|
108
|
+
- Use `WC_Data` getters and setters which perform some internal checks.
|
|
109
|
+
- Be careful with `WC_Checkout::process_checkout` and related hooks.
|