@mytechtoday/augment-extensions 0.1.1 → 0.2.0

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.
Files changed (79) hide show
  1. package/augment-extensions/domain-rules/wordpress/README.md +163 -0
  2. package/augment-extensions/domain-rules/wordpress/module.json +32 -0
  3. package/augment-extensions/domain-rules/wordpress/rules/coding-standards.md +617 -0
  4. package/augment-extensions/domain-rules/wordpress/rules/directory-structure.md +270 -0
  5. package/augment-extensions/domain-rules/wordpress/rules/file-patterns.md +423 -0
  6. package/augment-extensions/domain-rules/wordpress/rules/gutenberg-blocks.md +493 -0
  7. package/augment-extensions/domain-rules/wordpress/rules/performance.md +568 -0
  8. package/augment-extensions/domain-rules/wordpress/rules/plugin-development.md +510 -0
  9. package/augment-extensions/domain-rules/wordpress/rules/project-detection.md +251 -0
  10. package/augment-extensions/domain-rules/wordpress/rules/rest-api.md +501 -0
  11. package/augment-extensions/domain-rules/wordpress/rules/security.md +564 -0
  12. package/augment-extensions/domain-rules/wordpress/rules/theme-development.md +388 -0
  13. package/augment-extensions/domain-rules/wordpress/rules/woocommerce.md +441 -0
  14. package/augment-extensions/domain-rules/wordpress-plugin/README.md +139 -0
  15. package/augment-extensions/domain-rules/wordpress-plugin/examples/ajax-plugin.md +1599 -0
  16. package/augment-extensions/domain-rules/wordpress-plugin/examples/custom-post-type-plugin.md +1727 -0
  17. package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block-plugin.md +428 -0
  18. package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block.md +422 -0
  19. package/augment-extensions/domain-rules/wordpress-plugin/examples/mvc-plugin.md +1623 -0
  20. package/augment-extensions/domain-rules/wordpress-plugin/examples/object-oriented-plugin.md +1343 -0
  21. package/augment-extensions/domain-rules/wordpress-plugin/examples/rest-endpoint.md +734 -0
  22. package/augment-extensions/domain-rules/wordpress-plugin/examples/settings-page-plugin.md +1350 -0
  23. package/augment-extensions/domain-rules/wordpress-plugin/examples/simple-procedural-plugin.md +503 -0
  24. package/augment-extensions/domain-rules/wordpress-plugin/examples/singleton-plugin.md +971 -0
  25. package/augment-extensions/domain-rules/wordpress-plugin/module.json +53 -0
  26. package/augment-extensions/domain-rules/wordpress-plugin/rules/activation-hooks.md +770 -0
  27. package/augment-extensions/domain-rules/wordpress-plugin/rules/admin-interface.md +874 -0
  28. package/augment-extensions/domain-rules/wordpress-plugin/rules/ajax-handlers.md +629 -0
  29. package/augment-extensions/domain-rules/wordpress-plugin/rules/asset-management.md +559 -0
  30. package/augment-extensions/domain-rules/wordpress-plugin/rules/context-providers.md +709 -0
  31. package/augment-extensions/domain-rules/wordpress-plugin/rules/cron-jobs.md +736 -0
  32. package/augment-extensions/domain-rules/wordpress-plugin/rules/database-management.md +1057 -0
  33. package/augment-extensions/domain-rules/wordpress-plugin/rules/documentation-standards.md +463 -0
  34. package/augment-extensions/domain-rules/wordpress-plugin/rules/frontend-functionality.md +478 -0
  35. package/augment-extensions/domain-rules/wordpress-plugin/rules/gutenberg-blocks.md +818 -0
  36. package/augment-extensions/domain-rules/wordpress-plugin/rules/internationalization.md +416 -0
  37. package/augment-extensions/domain-rules/wordpress-plugin/rules/migration.md +667 -0
  38. package/augment-extensions/domain-rules/wordpress-plugin/rules/performance-optimization.md +878 -0
  39. package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-architecture.md +693 -0
  40. package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-structure.md +352 -0
  41. package/augment-extensions/domain-rules/wordpress-plugin/rules/rest-api.md +818 -0
  42. package/augment-extensions/domain-rules/wordpress-plugin/rules/scaffolding-workflow.md +624 -0
  43. package/augment-extensions/domain-rules/wordpress-plugin/rules/security-best-practices.md +866 -0
  44. package/augment-extensions/domain-rules/wordpress-plugin/rules/testing-patterns.md +1165 -0
  45. package/augment-extensions/domain-rules/wordpress-plugin/rules/testing.md +414 -0
  46. package/augment-extensions/domain-rules/wordpress-plugin/rules/vscode-integration.md +751 -0
  47. package/augment-extensions/domain-rules/wordpress-plugin/rules/woocommerce-integration.md +949 -0
  48. package/augment-extensions/domain-rules/wordpress-plugin/rules/wordpress-org-submission.md +458 -0
  49. package/augment-extensions/examples/gutenberg-block-plugin/README.md +101 -0
  50. package/augment-extensions/examples/gutenberg-block-plugin/examples/testimonial-block.md +428 -0
  51. package/augment-extensions/examples/gutenberg-block-plugin/module.json +40 -0
  52. package/augment-extensions/examples/rest-api-plugin/README.md +98 -0
  53. package/augment-extensions/examples/rest-api-plugin/examples/task-manager-api.md +1299 -0
  54. package/augment-extensions/examples/rest-api-plugin/module.json +40 -0
  55. package/augment-extensions/examples/woocommerce-extension/README.md +98 -0
  56. package/augment-extensions/examples/woocommerce-extension/examples/product-customizer.md +763 -0
  57. package/augment-extensions/examples/woocommerce-extension/module.json +40 -0
  58. package/augment-extensions/workflows/wordpress-plugin/README.md +232 -0
  59. package/augment-extensions/workflows/wordpress-plugin/ai-prompts.md +839 -0
  60. package/augment-extensions/workflows/wordpress-plugin/bead-decomposition-patterns.md +854 -0
  61. package/augment-extensions/workflows/wordpress-plugin/examples/complete-plugin-example.md +540 -0
  62. package/augment-extensions/workflows/wordpress-plugin/examples/custom-post-type-example.md +1083 -0
  63. package/augment-extensions/workflows/wordpress-plugin/examples/feature-addition-workflow.md +669 -0
  64. package/augment-extensions/workflows/wordpress-plugin/examples/plugin-creation-workflow.md +597 -0
  65. package/augment-extensions/workflows/wordpress-plugin/examples/secure-form-handler-example.md +925 -0
  66. package/augment-extensions/workflows/wordpress-plugin/examples/security-audit-workflow.md +752 -0
  67. package/augment-extensions/workflows/wordpress-plugin/examples/wordpress-org-submission-workflow.md +773 -0
  68. package/augment-extensions/workflows/wordpress-plugin/module.json +49 -0
  69. package/augment-extensions/workflows/wordpress-plugin/rules/best-practices.md +942 -0
  70. package/augment-extensions/workflows/wordpress-plugin/rules/development-workflow.md +702 -0
  71. package/augment-extensions/workflows/wordpress-plugin/rules/submission-workflow.md +728 -0
  72. package/augment-extensions/workflows/wordpress-plugin/rules/testing-workflow.md +775 -0
  73. package/cli/dist/cli.js +5 -1
  74. package/cli/dist/cli.js.map +1 -1
  75. package/cli/dist/commands/show.d.ts.map +1 -1
  76. package/cli/dist/commands/show.js +41 -0
  77. package/cli/dist/commands/show.js.map +1 -1
  78. package/modules.md +52 -0
  79. package/package.json +1 -1
@@ -0,0 +1,564 @@
1
+ # WordPress Security Best Practices
2
+
3
+ ## Overview
4
+
5
+ This document provides comprehensive security guidelines for WordPress development, covering input sanitization, output escaping, authentication, and common vulnerabilities.
6
+
7
+ ## Critical Security Rules
8
+
9
+ ### 🔴 NEVER
10
+
11
+ ❌ Trust user input
12
+ ❌ Use `eval()` or similar dangerous functions
13
+ ❌ Store passwords in plain text
14
+ ❌ Use `$_GET`, `$_POST`, `$_REQUEST` directly without sanitization
15
+ ❌ Output data without escaping
16
+ ❌ Use SQL queries without prepared statements
17
+ ❌ Hardcode credentials
18
+ ❌ Disable security features for convenience
19
+ ❌ Use deprecated functions
20
+ ❌ Ignore WordPress security updates
21
+
22
+ ### ✅ ALWAYS
23
+
24
+ ✅ Sanitize all input
25
+ ✅ Escape all output
26
+ ✅ Use nonces for form submissions
27
+ ✅ Check user capabilities
28
+ ✅ Use prepared statements for database queries
29
+ ✅ Validate and verify data
30
+ ✅ Use HTTPS
31
+ ✅ Keep WordPress, themes, and plugins updated
32
+ ✅ Use strong passwords
33
+ ✅ Implement proper error handling
34
+
35
+ ## Input Sanitization
36
+
37
+ ### Text Fields
38
+
39
+ ```php
40
+ // Sanitize text field
41
+ $clean_text = sanitize_text_field( $_POST['field'] );
42
+
43
+ // Sanitize textarea
44
+ $clean_textarea = sanitize_textarea_field( $_POST['textarea'] );
45
+
46
+ // Sanitize title
47
+ $clean_title = sanitize_title( $_POST['title'] );
48
+
49
+ // Sanitize key (lowercase alphanumeric with dashes and underscores)
50
+ $clean_key = sanitize_key( $_POST['key'] );
51
+ ```
52
+
53
+ ### Email and URL
54
+
55
+ ```php
56
+ // Sanitize email
57
+ $clean_email = sanitize_email( $_POST['email'] );
58
+
59
+ // Validate email
60
+ if ( ! is_email( $clean_email ) ) {
61
+ wp_die( __( 'Invalid email address', 'my-plugin' ) );
62
+ }
63
+
64
+ // Sanitize URL
65
+ $clean_url = esc_url_raw( $_POST['url'] );
66
+
67
+ // Sanitize file name
68
+ $clean_filename = sanitize_file_name( $_FILES['file']['name'] );
69
+ ```
70
+
71
+ ### HTML and Rich Content
72
+
73
+ ```php
74
+ // Sanitize HTML (allows safe HTML tags)
75
+ $clean_html = wp_kses_post( $_POST['content'] );
76
+
77
+ // Sanitize with custom allowed tags
78
+ $allowed_tags = array(
79
+ 'a' => array(
80
+ 'href' => array(),
81
+ 'title' => array(),
82
+ ),
83
+ 'br' => array(),
84
+ 'em' => array(),
85
+ 'strong' => array(),
86
+ );
87
+ $clean_html = wp_kses( $_POST['content'], $allowed_tags );
88
+
89
+ // Strip all HTML tags
90
+ $clean_text = wp_strip_all_tags( $_POST['content'] );
91
+ ```
92
+
93
+ ### Arrays and Complex Data
94
+
95
+ ```php
96
+ // Sanitize array of text fields
97
+ $clean_array = array_map( 'sanitize_text_field', $_POST['items'] );
98
+
99
+ // Sanitize array recursively
100
+ function sanitize_array( $array ) {
101
+ foreach ( $array as $key => &$value ) {
102
+ if ( is_array( $value ) ) {
103
+ $value = sanitize_array( $value );
104
+ } else {
105
+ $value = sanitize_text_field( $value );
106
+ }
107
+ }
108
+ return $array;
109
+ }
110
+ $clean_data = sanitize_array( $_POST['data'] );
111
+ ```
112
+
113
+ ### Numbers and Booleans
114
+
115
+ ```php
116
+ // Sanitize integer
117
+ $clean_int = absint( $_POST['number'] ); // Absolute integer (always positive)
118
+ $clean_int = intval( $_POST['number'] ); // Can be negative
119
+
120
+ // Sanitize float
121
+ $clean_float = floatval( $_POST['price'] );
122
+
123
+ // Sanitize boolean
124
+ $clean_bool = (bool) $_POST['checkbox'];
125
+ $clean_bool = rest_sanitize_boolean( $_POST['checkbox'] ); // REST API
126
+ ```
127
+
128
+ ## Output Escaping
129
+
130
+ ### HTML Context
131
+
132
+ ```php
133
+ // Escape HTML
134
+ echo esc_html( $text );
135
+
136
+ // Escape HTML with translation
137
+ echo esc_html__( 'Text to translate', 'my-plugin' );
138
+ echo esc_html_e( 'Text to translate', 'my-plugin' ); // Echo version
139
+
140
+ // Escape and translate with variables
141
+ echo esc_html( sprintf( __( 'Hello %s', 'my-plugin' ), $name ) );
142
+ ```
143
+
144
+ ### Attribute Context
145
+
146
+ ```php
147
+ // Escape attributes
148
+ echo '<div class="' . esc_attr( $class ) . '">';
149
+ echo '<input type="text" value="' . esc_attr( $value ) . '" />';
150
+
151
+ // Escape attribute with translation
152
+ echo '<div title="' . esc_attr__( 'Title text', 'my-plugin' ) . '">';
153
+ ```
154
+
155
+ ### URL Context
156
+
157
+ ```php
158
+ // Escape URL
159
+ echo '<a href="' . esc_url( $url ) . '">';
160
+
161
+ // Escape URL for database storage
162
+ $clean_url = esc_url_raw( $url );
163
+ ```
164
+
165
+ ### JavaScript Context
166
+
167
+ ```php
168
+ // Escape JavaScript
169
+ echo '<script>var data = "' . esc_js( $data ) . '";</script>';
170
+
171
+ // Better: Use wp_localize_script or wp_json_encode
172
+ wp_localize_script( 'my-script', 'myData', array(
173
+ 'value' => $data,
174
+ ) );
175
+
176
+ // Or use JSON encoding
177
+ echo '<script>var data = ' . wp_json_encode( $data ) . ';</script>';
178
+ ```
179
+
180
+ ### Textarea Context
181
+
182
+ ```php
183
+ // Escape textarea
184
+ echo '<textarea>' . esc_textarea( $content ) . '</textarea>';
185
+ ```
186
+
187
+ ## Nonce Verification
188
+
189
+ ### Creating Nonces
190
+
191
+ ```php
192
+ // Create nonce field in form
193
+ wp_nonce_field( 'my_action', 'my_nonce_field' );
194
+
195
+ // Create nonce URL
196
+ $url = wp_nonce_url( 'admin.php?page=my-page&action=delete', 'delete_action' );
197
+
198
+ // Create nonce value
199
+ $nonce = wp_create_nonce( 'my_action' );
200
+ ```
201
+
202
+ ### Verifying Nonces
203
+
204
+ ```php
205
+ // Verify nonce in form submission
206
+ if ( ! isset( $_POST['my_nonce_field'] ) || ! wp_verify_nonce( $_POST['my_nonce_field'], 'my_action' ) ) {
207
+ wp_die( __( 'Security check failed', 'my-plugin' ) );
208
+ }
209
+
210
+ // Verify nonce in URL
211
+ if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'delete_action' ) ) {
212
+ wp_die( __( 'Security check failed', 'my-plugin' ) );
213
+ }
214
+
215
+ // Verify nonce in AJAX
216
+ check_ajax_referer( 'my_ajax_action', 'security' );
217
+ ```
218
+
219
+ ### Nonce in AJAX
220
+
221
+ ```php
222
+ // Localize nonce for AJAX
223
+ wp_localize_script( 'my-ajax-script', 'myAjax', array(
224
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
225
+ 'nonce' => wp_create_nonce( 'my_ajax_action' ),
226
+ ) );
227
+
228
+ // JavaScript
229
+ jQuery.ajax({
230
+ url: myAjax.ajaxurl,
231
+ type: 'POST',
232
+ data: {
233
+ action: 'my_ajax_action',
234
+ security: myAjax.nonce,
235
+ data: 'value'
236
+ },
237
+ success: function(response) {
238
+ console.log(response);
239
+ }
240
+ });
241
+
242
+ // PHP handler
243
+ function my_ajax_handler() {
244
+ check_ajax_referer( 'my_ajax_action', 'security' );
245
+
246
+ // Process request
247
+ $data = sanitize_text_field( $_POST['data'] );
248
+
249
+ wp_send_json_success( array( 'message' => 'Success' ) );
250
+ }
251
+ add_action( 'wp_ajax_my_ajax_action', 'my_ajax_handler' );
252
+ ```
253
+
254
+ ## Capability Checks
255
+
256
+ ### Check User Capabilities
257
+
258
+ ```php
259
+ // Check if user can manage options
260
+ if ( ! current_user_can( 'manage_options' ) ) {
261
+ wp_die( __( 'You do not have sufficient permissions', 'my-plugin' ) );
262
+ }
263
+
264
+ // Check if user can edit posts
265
+ if ( ! current_user_can( 'edit_posts' ) ) {
266
+ return;
267
+ }
268
+
269
+ // Check if user can edit specific post
270
+ if ( ! current_user_can( 'edit_post', $post_id ) ) {
271
+ wp_die( __( 'You cannot edit this post', 'my-plugin' ) );
272
+ }
273
+
274
+ // Check if user can delete users
275
+ if ( ! current_user_can( 'delete_users' ) ) {
276
+ return;
277
+ }
278
+ ```
279
+
280
+ ### Common Capabilities
281
+
282
+ - `manage_options` - Administrator
283
+ - `edit_posts` - Editor, Author, Contributor
284
+ - `publish_posts` - Editor, Author
285
+ - `edit_published_posts` - Editor, Author
286
+ - `delete_posts` - Editor, Author, Contributor
287
+ - `upload_files` - Editor, Author
288
+ - `edit_pages` - Editor
289
+ - `edit_users` - Administrator
290
+ - `delete_users` - Administrator
291
+ - `install_plugins` - Administrator
292
+ - `activate_plugins` - Administrator
293
+
294
+ ## Database Security
295
+
296
+ ### Prepared Statements
297
+
298
+ ```php
299
+ global $wpdb;
300
+
301
+ // Correct: Use prepared statements
302
+ $user_id = 123;
303
+ $results = $wpdb->get_results(
304
+ $wpdb->prepare(
305
+ "SELECT * FROM {$wpdb->prefix}my_table WHERE user_id = %d",
306
+ $user_id
307
+ )
308
+ );
309
+
310
+ // Correct: Multiple placeholders
311
+ $name = 'John';
312
+ $age = 30;
313
+ $wpdb->query(
314
+ $wpdb->prepare(
315
+ "INSERT INTO {$wpdb->prefix}my_table (name, age) VALUES (%s, %d)",
316
+ $name,
317
+ $age
318
+ )
319
+ );
320
+
321
+ // WRONG: Direct variable insertion (SQL injection risk)
322
+ $results = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}my_table WHERE user_id = $user_id" );
323
+ ```
324
+
325
+ ### Placeholder Types
326
+
327
+ - `%s` - String
328
+ - `%d` - Integer
329
+ - `%f` - Float
330
+
331
+ ### Safe Database Operations
332
+
333
+ ```php
334
+ // Insert
335
+ $wpdb->insert(
336
+ $wpdb->prefix . 'my_table',
337
+ array(
338
+ 'name' => sanitize_text_field( $_POST['name'] ),
339
+ 'age' => absint( $_POST['age'] ),
340
+ ),
341
+ array( '%s', '%d' )
342
+ );
343
+
344
+ // Update
345
+ $wpdb->update(
346
+ $wpdb->prefix . 'my_table',
347
+ array( 'name' => sanitize_text_field( $_POST['name'] ) ),
348
+ array( 'id' => absint( $_POST['id'] ) ),
349
+ array( '%s' ),
350
+ array( '%d' )
351
+ );
352
+
353
+ // Delete
354
+ $wpdb->delete(
355
+ $wpdb->prefix . 'my_table',
356
+ array( 'id' => absint( $_POST['id'] ) ),
357
+ array( '%d' )
358
+ );
359
+ ```
360
+
361
+ ## File Upload Security
362
+
363
+ ### Validate File Uploads
364
+
365
+ ```php
366
+ function validate_file_upload( $file ) {
367
+ // Check if file was uploaded
368
+ if ( ! isset( $file['error'] ) || is_array( $file['error'] ) ) {
369
+ wp_die( __( 'Invalid file upload', 'my-plugin' ) );
370
+ }
371
+
372
+ // Check for upload errors
373
+ if ( $file['error'] !== UPLOAD_ERR_OK ) {
374
+ wp_die( __( 'Upload error', 'my-plugin' ) );
375
+ }
376
+
377
+ // Check file size (5MB max)
378
+ if ( $file['size'] > 5242880 ) {
379
+ wp_die( __( 'File too large', 'my-plugin' ) );
380
+ }
381
+
382
+ // Check file type
383
+ $allowed_types = array( 'image/jpeg', 'image/png', 'image/gif' );
384
+ $finfo = finfo_open( FILEINFO_MIME_TYPE );
385
+ $mime_type = finfo_file( $finfo, $file['tmp_name'] );
386
+ finfo_close( $finfo );
387
+
388
+ if ( ! in_array( $mime_type, $allowed_types, true ) ) {
389
+ wp_die( __( 'Invalid file type', 'my-plugin' ) );
390
+ }
391
+
392
+ // Sanitize filename
393
+ $filename = sanitize_file_name( $file['name'] );
394
+
395
+ return true;
396
+ }
397
+ ```
398
+
399
+ ### Use WordPress Upload Functions
400
+
401
+ ```php
402
+ // Use WordPress file upload handler
403
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
404
+
405
+ $uploaded_file = wp_handle_upload( $_FILES['file'], array( 'test_form' => false ) );
406
+
407
+ if ( isset( $uploaded_file['error'] ) ) {
408
+ wp_die( $uploaded_file['error'] );
409
+ }
410
+
411
+ // File uploaded successfully
412
+ $file_url = $uploaded_file['url'];
413
+ $file_path = $uploaded_file['file'];
414
+ ```
415
+
416
+ ## Authentication and Authorization
417
+
418
+ ### Check if User is Logged In
419
+
420
+ ```php
421
+ if ( ! is_user_logged_in() ) {
422
+ wp_redirect( wp_login_url() );
423
+ exit;
424
+ }
425
+ ```
426
+
427
+ ### Verify User Identity
428
+
429
+ ```php
430
+ // Check if current user owns the post
431
+ $post = get_post( $post_id );
432
+ if ( $post->post_author != get_current_user_id() ) {
433
+ wp_die( __( 'You do not own this post', 'my-plugin' ) );
434
+ }
435
+ ```
436
+
437
+ ### Password Hashing
438
+
439
+ ```php
440
+ // Hash password (WordPress handles this automatically)
441
+ $user_id = wp_create_user( $username, $password, $email );
442
+
443
+ // Verify password
444
+ $user = get_user_by( 'login', $username );
445
+ if ( $user && wp_check_password( $password, $user->user_pass, $user->ID ) ) {
446
+ // Password is correct
447
+ }
448
+
449
+ // Update password
450
+ wp_set_password( $new_password, $user_id );
451
+ ```
452
+
453
+ ## Common Vulnerabilities
454
+
455
+ ### SQL Injection Prevention
456
+
457
+ ```php
458
+ // ✅ CORRECT
459
+ $wpdb->prepare( "SELECT * FROM {$wpdb->posts} WHERE ID = %d", $id );
460
+
461
+ // ❌ WRONG
462
+ $wpdb->query( "SELECT * FROM {$wpdb->posts} WHERE ID = $id" );
463
+ ```
464
+
465
+ ### Cross-Site Scripting (XSS) Prevention
466
+
467
+ ```php
468
+ // ✅ CORRECT
469
+ echo esc_html( $user_input );
470
+
471
+ // ❌ WRONG
472
+ echo $user_input;
473
+ ```
474
+
475
+ ### Cross-Site Request Forgery (CSRF) Prevention
476
+
477
+ ```php
478
+ // ✅ CORRECT
479
+ wp_nonce_field( 'my_action', 'my_nonce' );
480
+ wp_verify_nonce( $_POST['my_nonce'], 'my_action' );
481
+
482
+ // ❌ WRONG
483
+ // No nonce verification
484
+ ```
485
+
486
+ ### Directory Traversal Prevention
487
+
488
+ ```php
489
+ // ✅ CORRECT
490
+ $file = basename( $_GET['file'] );
491
+ $path = WP_CONTENT_DIR . '/uploads/' . $file;
492
+
493
+ // Verify file is in allowed directory
494
+ if ( strpos( realpath( $path ), WP_CONTENT_DIR . '/uploads/' ) !== 0 ) {
495
+ wp_die( __( 'Invalid file path', 'my-plugin' ) );
496
+ }
497
+
498
+ // ❌ WRONG
499
+ $file = $_GET['file'];
500
+ include( WP_CONTENT_DIR . '/uploads/' . $file );
501
+ ```
502
+
503
+ ## Security Headers
504
+
505
+ ### Add Security Headers
506
+
507
+ ```php
508
+ /**
509
+ * Add security headers
510
+ */
511
+ function add_security_headers() {
512
+ header( 'X-Content-Type-Options: nosniff' );
513
+ header( 'X-Frame-Options: SAMEORIGIN' );
514
+ header( 'X-XSS-Protection: 1; mode=block' );
515
+ header( 'Referrer-Policy: strict-origin-when-cross-origin' );
516
+ }
517
+ add_action( 'send_headers', 'add_security_headers' );
518
+ ```
519
+
520
+ ## Best Practices Summary
521
+
522
+ ### Input Handling
523
+
524
+ ✅ Sanitize all input using appropriate functions
525
+ ✅ Validate data types and formats
526
+ ✅ Use whitelist validation when possible
527
+ ✅ Never trust user input
528
+
529
+ ### Output Handling
530
+
531
+ ✅ Escape all output based on context
532
+ ✅ Use `esc_html()`, `esc_attr()`, `esc_url()`, `esc_js()`
533
+ ✅ Escape late (just before output)
534
+
535
+ ### Database
536
+
537
+ ✅ Always use prepared statements
538
+ ✅ Use `$wpdb->prepare()` for custom queries
539
+ ✅ Use WordPress database functions when possible
540
+
541
+ ### Authentication
542
+
543
+ ✅ Use nonces for all form submissions
544
+ ✅ Check user capabilities
545
+ ✅ Verify user identity for sensitive operations
546
+ ✅ Use HTTPS for login and admin areas
547
+
548
+ ### Files
549
+
550
+ ✅ Validate file uploads
551
+ ✅ Check file types and sizes
552
+ ✅ Use WordPress upload functions
553
+ ✅ Store uploads outside web root when possible
554
+
555
+ ### General
556
+
557
+ ✅ Keep WordPress, themes, and plugins updated
558
+ ✅ Use strong passwords
559
+ ✅ Limit login attempts
560
+ ✅ Regular security audits
561
+ ✅ Monitor error logs
562
+ ✅ Use security plugins
563
+ ✅ Regular backups
564
+