WooCommerce Security
Before writing code
Fetch live docs:
- Web-search
site:developer.wordpress.org plugins security for WordPress security handbook
- Web-search
site:developer.woocommerce.com security best practices for WooCommerce security
- Web-search
wordpress security hardening latest for current hardening guidance
Nonces (CSRF Protection)
How Nonces Work
WordPress nonces prevent Cross-Site Request Forgery:
- Generate:
wp_create_nonce( 'my_action' ) or wp_nonce_field( 'my_action', 'my_nonce' ) (for forms)
- Verify:
wp_verify_nonce( $_POST['my_nonce'], 'my_action' ) or check_admin_referer( 'my_action', 'my_nonce' )
- Valid for 24 hours (two 12-hour ticks)
AJAX Nonces
- Generate:
wp_create_nonce( 'my_ajax_action' )
- Pass to JS via
wp_localize_script(): ['nonce' => wp_create_nonce('my_ajax_action')]
- Verify in handler:
check_ajax_referer( 'my_ajax_action', 'nonce' )
REST API Nonces
- Cookie auth uses
X-WP-Nonce header with wp_create_nonce( 'wp_rest' )
- API key auth doesn't need nonces (keys provide authentication)
Capabilities (Authorization)
WordPress Capability System
Always check capabilities before performing actions:
current_user_can( 'manage_woocommerce' ) — WooCommerce admin
current_user_can( 'edit_shop_orders' ) — order management
current_user_can( 'edit_products' ) — product management
current_user_can( 'view_woocommerce_reports' ) — view reports
WooCommerce Capabilities
| Capability |
Access |
manage_woocommerce |
Full WooCommerce admin |
edit_products |
Create/edit products |
edit_shop_orders |
Manage orders |
view_woocommerce_reports |
View analytics/reports |
edit_shop_coupons |
Manage coupons |
Custom Capabilities
Register custom capabilities via add_cap() on role objects during plugin activation.
Input Sanitization
Sanitization Functions
Always sanitize data before using or storing it:
| Function |
Use For |
sanitize_text_field() |
Single-line text input |
sanitize_textarea_field() |
Multi-line text |
sanitize_email() |
Email addresses |
sanitize_url() |
URLs |
absint() |
Positive integers |
intval() |
Integers (any sign) |
floatval() |
Float numbers |
wp_kses() |
HTML with allowed tags |
wp_kses_post() |
HTML safe for post content |
wc_clean() |
WooCommerce string/array sanitizer |
wc_sanitize_textarea() |
WooCommerce textarea sanitizer |
Array Sanitization
wc_clean() recursively sanitizes arrays — use for multi-value inputs.
File Upload Validation
- Validate MIME type with
wp_check_filetype()
- Use
wp_handle_upload() for proper file upload processing
- Never trust file extensions — validate content
Output Escaping
Escaping Functions
Always escape data on output:
| Function |
Context |
esc_html() |
Inside HTML tags |
esc_attr() |
HTML attribute values |
esc_url() |
URLs (href, src) |
esc_js() |
Inline JavaScript |
esc_textarea() |
Inside textarea elements |
wp_kses() |
HTML with specific allowed tags |
wp_kses_post() |
HTML safe for post content |
Translation + Escaping
Combine translation with escaping:
esc_html__() / esc_html_e() — escaped translated strings
esc_attr__() / esc_attr_e() — escaped for attributes
wp_kses( sprintf(...), $allowed_html ) — formatted HTML
The Rule
Sanitize early (on input), escape late (on output). Never trust any data from users, databases, or external APIs.
Data Validation
Validation Patterns
- Validate data type, format, and range before processing
- Use
is_email(), wp_http_validate_url(), WordPress validators
- WooCommerce validators:
wc_format_decimal(), wc_is_valid_url()
- Return errors via
WP_Error or wc_add_notice( $msg, 'error' )
SQL Injection Prevention
Prepared Statements
Always use $wpdb->prepare() for custom queries:
$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}my_table WHERE id = %d", $id )
- Placeholders:
%d (integer), %s (string), %f (float)
- Never concatenate user input into SQL strings
Use CRUD/APIs Instead
Prefer WooCommerce CRUD and WordPress APIs over raw SQL:
wc_get_orders(), wc_get_products() — safe query builders
$order->get_meta(), $product->get_price() — safe data access
PCI Compliance Considerations
- Never store raw credit card numbers
- Use tokenized payment methods (Stripe, Braintree SDKs handle card data client-side)
- Serve checkout over HTTPS
- Keep WordPress, WooCommerce, and all plugins up to date
- Use payment gateways that are PCI DSS compliant
Additional Hardening
- Set
DISALLOW_FILE_EDIT in wp-config.php
- Limit login attempts (plugin or
.htaccess)
- Use strong admin passwords and enforce password policies
- Enable two-factor authentication for admin users
- Keep all software updated (WordPress, WooCommerce, plugins, PHP)
- Use HTTPS everywhere
- Set secure cookie flags
- Restrict REST API access where appropriate (
rest_authentication_errors filter)
- Disable XML-RPC if not needed:
add_filter( 'xmlrpc_enabled', '__return_false' )
Best Practices
- Check nonces on every form submission and AJAX request
- Check capabilities before every privileged operation
- Sanitize ALL input — even from trusted sources
- Escape ALL output — even data from the database
- Use
$wpdb->prepare() for any custom SQL
- Never store sensitive data in plain text
- Use WordPress APIs instead of raw PHP functions for security-sensitive operations
- Run security audits with WPScan or similar tools
Fetch the WordPress Security handbook and WooCommerce security documentation for exact function signatures, capability mappings, and current best practices before implementing.
1---2name: woo-security3description: Implement WooCommerce security — nonces, capabilities, input sanitization, output escaping, data validation, PCI compliance considerations, and WordPress security best practices. Use when hardening a WooCommerce store or reviewing security posture.4---5
6# WooCommerce Security
7
8## Before writing code
9
10**Fetch live docs**:
111. Web-search `site:developer.wordpress.org plugins security` for WordPress security handbook
122. Web-search `site:developer.woocommerce.com security best practices` for WooCommerce security
133. Web-search `wordpress security hardening latest` for current hardening guidance
14
15## Nonces (CSRF Protection)
16
17### How Nonces Work
18
19WordPress nonces prevent Cross-Site Request Forgery:
20- Generate: `wp_create_nonce( 'my_action' )` or `wp_nonce_field( 'my_action', 'my_nonce' )` (for forms)
21- Verify: `wp_verify_nonce( $_POST['my_nonce'], 'my_action' )` or `check_admin_referer( 'my_action', 'my_nonce' )`
22- Valid for 24 hours (two 12-hour ticks)
23
24### AJAX Nonces
25
26- Generate: `wp_create_nonce( 'my_ajax_action' )`
27- Pass to JS via `wp_localize_script()`: `['nonce' => wp_create_nonce('my_ajax_action')]`
28- Verify in handler: `check_ajax_referer( 'my_ajax_action', 'nonce' )`
29
30### REST API Nonces
31
32- Cookie auth uses `X-WP-Nonce` header with `wp_create_nonce( 'wp_rest' )`
33- API key auth doesn't need nonces (keys provide authentication)
34
35## Capabilities (Authorization)
36
37### WordPress Capability System
38
39Always check capabilities before performing actions:
40- `current_user_can( 'manage_woocommerce' )` — WooCommerce admin
41- `current_user_can( 'edit_shop_orders' )` — order management
42- `current_user_can( 'edit_products' )` — product management
43- `current_user_can( 'view_woocommerce_reports' )` — view reports
44
45### WooCommerce Capabilities
46
47| Capability | Access |
48|------------|--------|
49| `manage_woocommerce` | Full WooCommerce admin |
50| `edit_products` | Create/edit products |
51| `edit_shop_orders` | Manage orders |
52| `view_woocommerce_reports` | View analytics/reports |
53| `edit_shop_coupons` | Manage coupons |
54
55### Custom Capabilities
56
57Register custom capabilities via `add_cap()` on role objects during plugin activation.
58
59## Input Sanitization
60
61### Sanitization Functions
62
63Always sanitize data before using or storing it:
64
65| Function | Use For |
66|----------|---------|
67| `sanitize_text_field()` | Single-line text input |
68| `sanitize_textarea_field()` | Multi-line text |
69| `sanitize_email()` | Email addresses |
70| `sanitize_url()` | URLs |
71| `absint()` | Positive integers |
72| `intval()` | Integers (any sign) |
73| `floatval()` | Float numbers |
74| `wp_kses()` | HTML with allowed tags |
75| `wp_kses_post()` | HTML safe for post content |
76| `wc_clean()` | WooCommerce string/array sanitizer |
77| `wc_sanitize_textarea()` | WooCommerce textarea sanitizer |
78
79### Array Sanitization
80
81`wc_clean()` recursively sanitizes arrays — use for multi-value inputs.
82
83### File Upload Validation
84
85- Validate MIME type with `wp_check_filetype()`
86- Use `wp_handle_upload()` for proper file upload processing
87- Never trust file extensions — validate content
88
89## Output Escaping
90
91### Escaping Functions
92
93Always escape data on output:
94
95| Function | Context |
96|----------|---------|
97| `esc_html()` | Inside HTML tags |
98| `esc_attr()` | HTML attribute values |
99| `esc_url()` | URLs (href, src) |
100| `esc_js()` | Inline JavaScript |
101| `esc_textarea()` | Inside textarea elements |
102| `wp_kses()` | HTML with specific allowed tags |
103| `wp_kses_post()` | HTML safe for post content |
104
105### Translation + Escaping
106
107Combine translation with escaping:
108- `esc_html__()` / `esc_html_e()` — escaped translated strings
109- `esc_attr__()` / `esc_attr_e()` — escaped for attributes
110- `wp_kses( sprintf(...), $allowed_html )` — formatted HTML
111
112### The Rule
113
114**Sanitize early (on input), escape late (on output).** Never trust any data from users, databases, or external APIs.
115
116## Data Validation
117
118### Validation Patterns
119
120- Validate data type, format, and range before processing
121- Use `is_email()`, `wp_http_validate_url()`, WordPress validators
122- WooCommerce validators: `wc_format_decimal()`, `wc_is_valid_url()`
123- Return errors via `WP_Error` or `wc_add_notice( $msg, 'error' )`
124
125## SQL Injection Prevention
126
127### Prepared Statements
128
129Always use `$wpdb->prepare()` for custom queries:
130- `$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}my_table WHERE id = %d", $id )`
131- Placeholders: `%d` (integer), `%s` (string), `%f` (float)
132- Never concatenate user input into SQL strings
133
134### Use CRUD/APIs Instead
135
136Prefer WooCommerce CRUD and WordPress APIs over raw SQL:
137- `wc_get_orders()`, `wc_get_products()` — safe query builders
138- `$order->get_meta()`, `$product->get_price()` — safe data access
139
140## PCI Compliance Considerations
141
142- **Never** store raw credit card numbers
143- Use tokenized payment methods (Stripe, Braintree SDKs handle card data client-side)
144- Serve checkout over HTTPS
145- Keep WordPress, WooCommerce, and all plugins up to date
146- Use payment gateways that are PCI DSS compliant
147
148## Additional Hardening
149
150- Set `DISALLOW_FILE_EDIT` in wp-config.php
151- Limit login attempts (plugin or `.htaccess`)
152- Use strong admin passwords and enforce password policies
153- Enable two-factor authentication for admin users
154- Keep all software updated (WordPress, WooCommerce, plugins, PHP)
155- Use HTTPS everywhere
156- Set secure cookie flags
157- Restrict REST API access where appropriate (`rest_authentication_errors` filter)
158- Disable XML-RPC if not needed: `add_filter( 'xmlrpc_enabled', '__return_false' )`
159
160## Best Practices
161
162- Check nonces on every form submission and AJAX request
163- Check capabilities before every privileged operation
164- Sanitize ALL input — even from trusted sources
165- Escape ALL output — even data from the database
166- Use `$wpdb->prepare()` for any custom SQL
167- Never store sensitive data in plain text
168- Use WordPress APIs instead of raw PHP functions for security-sensitive operations
169- Run security audits with WPScan or similar tools
170
171Fetch the WordPress Security handbook and WooCommerce security documentation for exact function signatures, capability mappings, and current best practices before implementing.