ima-claude 2.9.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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +463 -0
  3. package/dist/cli.js +1064 -0
  4. package/package.json +49 -0
  5. package/platforms/claude/adapter.ts +115 -0
  6. package/platforms/junie/adapter.ts +254 -0
  7. package/platforms/junie/agents-template.md +113 -0
  8. package/platforms/junie/hook-translations.md +84 -0
  9. package/platforms/shared/detector.ts +27 -0
  10. package/platforms/shared/installer.ts +202 -0
  11. package/platforms/shared/types.ts +78 -0
  12. package/plugins/ima-claude/.claude-plugin/plugin.json +25 -0
  13. package/plugins/ima-claude/agents/explorer.md +30 -0
  14. package/plugins/ima-claude/agents/implementer.md +30 -0
  15. package/plugins/ima-claude/agents/memory.md +42 -0
  16. package/plugins/ima-claude/agents/reviewer.md +53 -0
  17. package/plugins/ima-claude/agents/tester.md +33 -0
  18. package/plugins/ima-claude/agents/wp-developer.md +46 -0
  19. package/plugins/ima-claude/hooks/README.md +145 -0
  20. package/plugins/ima-claude/hooks/atlassian_prereqs.py +112 -0
  21. package/plugins/ima-claude/hooks/block_sed_edits.py +59 -0
  22. package/plugins/ima-claude/hooks/bootstrap.sh +90 -0
  23. package/plugins/ima-claude/hooks/bootstrap_utility_check.py +94 -0
  24. package/plugins/ima-claude/hooks/composer_autoload_check.py +70 -0
  25. package/plugins/ima-claude/hooks/docs_organization.py +104 -0
  26. package/plugins/ima-claude/hooks/enforce_rg_over_grep.py +56 -0
  27. package/plugins/ima-claude/hooks/fp_utility_check.py +90 -0
  28. package/plugins/ima-claude/hooks/hook_logger.py +69 -0
  29. package/plugins/ima-claude/hooks/hooks.json +239 -0
  30. package/plugins/ima-claude/hooks/jira_issue_fetch.py +79 -0
  31. package/plugins/ima-claude/hooks/jquery_in_wordpress.py +92 -0
  32. package/plugins/ima-claude/hooks/memory_bootstrap.py +79 -0
  33. package/plugins/ima-claude/hooks/memory_store_reminder.py +75 -0
  34. package/plugins/ima-claude/hooks/prompt_coach.py +125 -0
  35. package/plugins/ima-claude/hooks/prompt_coach_digest.md +48 -0
  36. package/plugins/ima-claude/hooks/prompt_coach_system.md +30 -0
  37. package/plugins/ima-claude/hooks/sequential_thinking_check.py +81 -0
  38. package/plugins/ima-claude/hooks/serena_over_grep.py +96 -0
  39. package/plugins/ima-claude/hooks/serena_over_read.py +66 -0
  40. package/plugins/ima-claude/hooks/serena_project_check.py +133 -0
  41. package/plugins/ima-claude/hooks/sql_injection_check.py +73 -0
  42. package/plugins/ima-claude/hooks/task_master_after_plan.py +31 -0
  43. package/plugins/ima-claude/hooks/task_master_before_impl.py +93 -0
  44. package/plugins/ima-claude/hooks/tavily_extract_advanced.py +48 -0
  45. package/plugins/ima-claude/hooks/vestige_before_external.py +86 -0
  46. package/plugins/ima-claude/hooks/webfetch_to_tavily.py +42 -0
  47. package/plugins/ima-claude/hooks/websearch_to_tavily.py +41 -0
  48. package/plugins/ima-claude/hooks/wp_security_check.py +150 -0
  49. package/plugins/ima-claude/personalities/README.md +45 -0
  50. package/plugins/ima-claude/personalities/enable-40k.md +69 -0
  51. package/plugins/ima-claude/personalities/enable-templars.md +69 -0
  52. package/plugins/ima-claude/skills/.research-summary.md +340 -0
  53. package/plugins/ima-claude/skills/architect/SKILL.md +304 -0
  54. package/plugins/ima-claude/skills/compound-bridge/SKILL.md +200 -0
  55. package/plugins/ima-claude/skills/discourse/SKILL.md +440 -0
  56. package/plugins/ima-claude/skills/discourse-admin/SKILL.md +192 -0
  57. package/plugins/ima-claude/skills/discourse-admin/references/api-endpoints.md +441 -0
  58. package/plugins/ima-claude/skills/discourse-admin/references/gotchas.md +107 -0
  59. package/plugins/ima-claude/skills/discourse-admin/references/staging-defaults.md +98 -0
  60. package/plugins/ima-claude/skills/discourse-admin/scripts/discourse-admin.py +319 -0
  61. package/plugins/ima-claude/skills/docs-organize/SKILL.md +254 -0
  62. package/plugins/ima-claude/skills/docs-organize/templates/active-README.md +50 -0
  63. package/plugins/ima-claude/skills/docs-organize/templates/archive-README.md +57 -0
  64. package/plugins/ima-claude/skills/docs-organize/templates/docs-README.md +43 -0
  65. package/plugins/ima-claude/skills/docs-organize/templates/phase-archive-README.md +83 -0
  66. package/plugins/ima-claude/skills/docs-organize/templates/section-README.md +48 -0
  67. package/plugins/ima-claude/skills/docs-organize/templates/transient-README.md +79 -0
  68. package/plugins/ima-claude/skills/docs-organize/templates/transient-gitignore +9 -0
  69. package/plugins/ima-claude/skills/ember-discourse/SKILL.md +496 -0
  70. package/plugins/ima-claude/skills/functional-programmer/SKILL.md +258 -0
  71. package/plugins/ima-claude/skills/ima-bootstrap/SKILL.md +278 -0
  72. package/plugins/ima-claude/skills/ima-bootstrap/references/bootstrap-patterns.md +356 -0
  73. package/plugins/ima-claude/skills/ima-bootstrap/references/ima-brand.md +273 -0
  74. package/plugins/ima-claude/skills/ima-bootstrap/references/theme-integration.md +212 -0
  75. package/plugins/ima-claude/skills/ima-brand/SKILL.md +108 -0
  76. package/plugins/ima-claude/skills/ima-brand/references/brand-identity.md +140 -0
  77. package/plugins/ima-claude/skills/ima-brand/references/digital-standards.md +180 -0
  78. package/plugins/ima-claude/skills/ima-brand/references/visual-system.md +173 -0
  79. package/plugins/ima-claude/skills/ima-forms-expert/SKILL.md +175 -0
  80. package/plugins/ima-claude/skills/ima-forms-expert/references/container-components.md +154 -0
  81. package/plugins/ima-claude/skills/ima-forms-expert/references/examples.md +328 -0
  82. package/plugins/ima-claude/skills/ima-forms-expert/references/field-components.md +298 -0
  83. package/plugins/ima-claude/skills/ima-forms-expert/references/form-factory.md +193 -0
  84. package/plugins/ima-claude/skills/ima-forms-expert/references/quick-reference.md +153 -0
  85. package/plugins/ima-claude/skills/ima-forms-expert/references/validation-engine.md +336 -0
  86. package/plugins/ima-claude/skills/jira-checkpoint/SKILL.md +178 -0
  87. package/plugins/ima-claude/skills/jquery/SKILL.md +413 -0
  88. package/plugins/ima-claude/skills/js-fp/SKILL.md +463 -0
  89. package/plugins/ima-claude/skills/js-fp/core-principles.md +487 -0
  90. package/plugins/ima-claude/skills/js-fp/examples/pure-functions.js +260 -0
  91. package/plugins/ima-claude/skills/js-fp/examples/tests/pure-functions.test.js +262 -0
  92. package/plugins/ima-claude/skills/js-fp/references/anti-patterns.md +120 -0
  93. package/plugins/ima-claude/skills/js-fp/references/performance-patterns.md +116 -0
  94. package/plugins/ima-claude/skills/js-fp/references/testing-patterns.md +134 -0
  95. package/plugins/ima-claude/skills/js-fp-api/SKILL.md +280 -0
  96. package/plugins/ima-claude/skills/js-fp-api/examples/crud-endpoint.js +258 -0
  97. package/plugins/ima-claude/skills/js-fp-api/references/middleware-patterns.md +134 -0
  98. package/plugins/ima-claude/skills/js-fp-api/references/security-sql.md +110 -0
  99. package/plugins/ima-claude/skills/js-fp-api/references/validation-patterns.md +165 -0
  100. package/plugins/ima-claude/skills/js-fp-react/SKILL.md +447 -0
  101. package/plugins/ima-claude/skills/js-fp-react/examples/ProductCard.tsx +65 -0
  102. package/plugins/ima-claude/skills/js-fp-react/references/hooks-advanced.md +136 -0
  103. package/plugins/ima-claude/skills/js-fp-react/references/performance-patterns.md +175 -0
  104. package/plugins/ima-claude/skills/js-fp-vue/SKILL.md +322 -0
  105. package/plugins/ima-claude/skills/js-fp-vue/references/complete-examples.md +397 -0
  106. package/plugins/ima-claude/skills/js-fp-vue/references/composables-advanced.md +282 -0
  107. package/plugins/ima-claude/skills/js-fp-vue/references/reactivity-patterns.md +348 -0
  108. package/plugins/ima-claude/skills/js-fp-vue/references/testing.md +314 -0
  109. package/plugins/ima-claude/skills/js-fp-wordpress/SKILL.md +301 -0
  110. package/plugins/ima-claude/skills/js-fp-wordpress/references/ajax-patterns.md +192 -0
  111. package/plugins/ima-claude/skills/js-fp-wordpress/references/event-patterns.md +136 -0
  112. package/plugins/ima-claude/skills/js-fp-wordpress/references/wp-integration.md +248 -0
  113. package/plugins/ima-claude/skills/livecanvas/SKILL.md +209 -0
  114. package/plugins/ima-claude/skills/livecanvas/references/livecanvas-features.md +311 -0
  115. package/plugins/ima-claude/skills/livecanvas/references/loops-and-logic.md +730 -0
  116. package/plugins/ima-claude/skills/livecanvas/references/picostrap.md +227 -0
  117. package/plugins/ima-claude/skills/mcp-atlassian/SKILL.md +339 -0
  118. package/plugins/ima-claude/skills/mcp-context7/SKILL.md +109 -0
  119. package/plugins/ima-claude/skills/mcp-memory/SKILL.md +182 -0
  120. package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +233 -0
  121. package/plugins/ima-claude/skills/mcp-sequential/SKILL.md +149 -0
  122. package/plugins/ima-claude/skills/mcp-serena/SKILL.md +174 -0
  123. package/plugins/ima-claude/skills/mcp-tavily/SKILL.md +118 -0
  124. package/plugins/ima-claude/skills/mcp-vestige/SKILL.md +259 -0
  125. package/plugins/ima-claude/skills/php-authnet/SKILL.md +275 -0
  126. package/plugins/ima-claude/skills/php-authnet/references/api-reference.md +624 -0
  127. package/plugins/ima-claude/skills/php-authnet/references/sandbox-testing.md +424 -0
  128. package/plugins/ima-claude/skills/php-fp/SKILL.md +333 -0
  129. package/plugins/ima-claude/skills/php-fp/examples/pure-functions.php +403 -0
  130. package/plugins/ima-claude/skills/php-fp/examples/tests/PureFunctionsTest.php +515 -0
  131. package/plugins/ima-claude/skills/php-fp/references/core-principles.md +277 -0
  132. package/plugins/ima-claude/skills/php-fp/references/testing-patterns.md +374 -0
  133. package/plugins/ima-claude/skills/php-fp-wordpress/SKILL.md +216 -0
  134. package/plugins/ima-claude/skills/php-fp-wordpress/references/fp-patterns.md +275 -0
  135. package/plugins/ima-claude/skills/php-fp-wordpress/references/plugin-architecture.md +295 -0
  136. package/plugins/ima-claude/skills/php-fp-wordpress/references/security-examples.md +203 -0
  137. package/plugins/ima-claude/skills/php-fp-wordpress/references/testing-strategy.md +259 -0
  138. package/plugins/ima-claude/skills/phpunit-wp/SKILL.md +716 -0
  139. package/plugins/ima-claude/skills/playwright/SKILL.md +434 -0
  140. package/plugins/ima-claude/skills/playwright/references/accessibility-testing.md +153 -0
  141. package/plugins/ima-claude/skills/playwright/references/ci-cd.md +268 -0
  142. package/plugins/ima-claude/skills/playwright/references/network-mocking.md +270 -0
  143. package/plugins/ima-claude/skills/playwright/references/visual-regression.md +215 -0
  144. package/plugins/ima-claude/skills/py-fp/SKILL.md +663 -0
  145. package/plugins/ima-claude/skills/py-fp/examples/pure-functions.py +185 -0
  146. package/plugins/ima-claude/skills/py-fp/examples/tests/test_pure_functions.py +244 -0
  147. package/plugins/ima-claude/skills/py-fp/references/core-principles.md +381 -0
  148. package/plugins/ima-claude/skills/py-fp/references/testing-patterns.md +283 -0
  149. package/plugins/ima-claude/skills/quasar-fp/SKILL.md +327 -0
  150. package/plugins/ima-claude/skills/quasar-fp/metadata.json +85 -0
  151. package/plugins/ima-claude/skills/quasar-fp/references/component-patterns.md +257 -0
  152. package/plugins/ima-claude/skills/quasar-fp/references/theme-integration.md +233 -0
  153. package/plugins/ima-claude/skills/quasar-fp/references/utility-classes.md +237 -0
  154. package/plugins/ima-claude/skills/quickstart/SKILL.md +129 -0
  155. package/plugins/ima-claude/skills/rails/SKILL.md +359 -0
  156. package/plugins/ima-claude/skills/resume-session/SKILL.md +68 -0
  157. package/plugins/ima-claude/skills/rg/SKILL.md +205 -0
  158. package/plugins/ima-claude/skills/ruby-fp/SKILL.md +336 -0
  159. package/plugins/ima-claude/skills/save-session/SKILL.md +81 -0
  160. package/plugins/ima-claude/skills/scorecard/SKILL.md +96 -0
  161. package/plugins/ima-claude/skills/skill-analyzer/SKILL.md +127 -0
  162. package/plugins/ima-claude/skills/skill-analyzer/references/advanced-checklist.md +44 -0
  163. package/plugins/ima-claude/skills/skill-analyzer/references/core-checklist.md +60 -0
  164. package/plugins/ima-claude/skills/skill-analyzer/scripts/analyze_skill.py +418 -0
  165. package/plugins/ima-claude/skills/skill-creator/LICENSE.txt +202 -0
  166. package/plugins/ima-claude/skills/skill-creator/SKILL.md +343 -0
  167. package/plugins/ima-claude/skills/skill-creator/references/output-patterns.md +82 -0
  168. package/plugins/ima-claude/skills/skill-creator/references/workflows.md +28 -0
  169. package/plugins/ima-claude/skills/skill-creator/scripts/init_skill.py +303 -0
  170. package/plugins/ima-claude/skills/skill-creator/scripts/package_skill.py +110 -0
  171. package/plugins/ima-claude/skills/skill-creator/scripts/quick_validate.py +103 -0
  172. package/plugins/ima-claude/skills/task-master/SKILL.md +51 -0
  173. package/plugins/ima-claude/skills/task-planner/SKILL.md +228 -0
  174. package/plugins/ima-claude/skills/task-runner/SKILL.md +192 -0
  175. package/plugins/ima-claude/skills/unit-testing/SKILL.md +198 -0
  176. package/plugins/ima-claude/skills/unit-testing/references/mock-patterns.md +181 -0
  177. package/plugins/ima-claude/skills/unit-testing/references/tdd-workflow.md +177 -0
  178. package/plugins/ima-claude/skills/unit-testing/references/test-strategy.md +126 -0
  179. package/plugins/ima-claude/skills/wp-local/SKILL.md +246 -0
  180. package/plugins/ima-claude/skills/wp-local/references/configuration.md +198 -0
  181. package/plugins/ima-claude/skills/wp-local/references/wp-cli-reference.md +406 -0
  182. package/plugins/ima-claude/skills/wp-local/scripts/wp-local.sh +61 -0
@@ -0,0 +1,328 @@
1
+ # Complete Form Examples
2
+
3
+ ## Contents
4
+
5
+ - [Understanding Validators-at-Registration](#understanding-validators-at-registration)
6
+ - [Contact Form with Validation Engine](#contact-form-with-validation-engine)
7
+ - [Form with Custom Cross-Field Validation](#form-with-custom-cross-field-validation)
8
+ - [Testing Patterns](#testing-patterns)
9
+ - [Anti-Patterns to Avoid](#anti-patterns-to-avoid)
10
+
11
+ ---
12
+
13
+ ## Understanding Validators-at-Registration
14
+
15
+ **Key v1.4.0 Architecture**: When you call `ima_forms_email_field()`, the field's `_register()` function builds validators as closures and stores them:
16
+
17
+ ```php
18
+ // What happens inside ima_forms_email_field_register():
19
+ $validators = [];
20
+
21
+ if ($required) {
22
+ // Validator closure captures $label via use()
23
+ $validators[] = fn($v) => ima_forms_validate_required($v, $label);
24
+ }
25
+
26
+ // Email format validator (only runs if value provided)
27
+ $validators[] = function($v) use ($label, $enhanced) {
28
+ if (empty($v)) return null;
29
+ return ima_forms_validate_email_enhanced((string) $v, $label, $enhanced);
30
+ };
31
+
32
+ // Spec stores the closures directly
33
+ ima_forms_register_field_spec($name, [
34
+ 'type' => 'email',
35
+ 'validators' => $validators, // Array of closures!
36
+ ]);
37
+ ```
38
+
39
+ **When validation runs** (inside `ima_forms_run_validators()`):
40
+ ```php
41
+ foreach ($specs as $field_name => $spec) {
42
+ $value = $sanitized[$field_name] ?? null;
43
+
44
+ foreach ($spec['validators'] as $validator) {
45
+ $error = $validator($value); // Just call the closure!
46
+ if ($error !== null) {
47
+ $errors[$field_name] = $error;
48
+ break;
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ **Benefits**:
55
+ - No type switching - validators are already built
56
+ - Single source of truth - field function defines validation once
57
+ - Testable - validators are pure functions
58
+
59
+ ---
60
+
61
+ ## Contact Form with Validation Engine
62
+
63
+ ### Template File
64
+
65
+ ```php
66
+ // Theme: templates/forms/contact-form.php
67
+ <?php
68
+ if (!defined('ABSPATH')) exit;
69
+
70
+ $errors = $args['errors'] ?? [];
71
+ $data = $args['data'] ?? [];
72
+ ?>
73
+
74
+ <?php
75
+ ima_forms_form([
76
+ 'id' => 'contact-form',
77
+ 'action' => 'contact_form_submit',
78
+ ], function() use ($data, $errors) {
79
+
80
+ ima_forms_card(['title' => 'Contact Us'], function() use ($data, $errors) {
81
+
82
+ ima_forms_text_field([
83
+ 'name' => 'name',
84
+ 'label' => 'Your Name',
85
+ 'required' => true,
86
+ 'value' => $data['name'] ?? '',
87
+ 'error' => $errors['name'] ?? '',
88
+ ]);
89
+
90
+ ima_forms_email_field([
91
+ 'name' => 'email',
92
+ 'label' => 'Email Address',
93
+ 'required' => true,
94
+ 'enhanced_validation' => true,
95
+ 'value' => $data['email'] ?? '',
96
+ 'error' => $errors['email'] ?? '',
97
+ ]);
98
+
99
+ ima_forms_textarea_field([
100
+ 'name' => 'message',
101
+ 'label' => 'Message',
102
+ 'required' => true,
103
+ 'rows' => 5,
104
+ 'maxlength' => 1000,
105
+ 'value' => $data['message'] ?? '',
106
+ 'error' => $errors['message'] ?? '',
107
+ ]);
108
+
109
+ ima_forms_submit_button([
110
+ 'text' => 'Send Message',
111
+ 'processing_text' => 'Sending...',
112
+ ]);
113
+ });
114
+ });
115
+ ?>
116
+ ```
117
+
118
+ ### AJAX Handler
119
+
120
+ ```php
121
+ // Theme: inc/forms/contact-form.php
122
+
123
+ function contact_form_ajax_handler() {
124
+ // Nonce verification
125
+ if (!wp_verify_nonce($_POST['nonce'], 'ima_forms_ajax')) {
126
+ wp_send_json_error(['message' => 'Security check failed.'], 403);
127
+ }
128
+
129
+ // Validate using template
130
+ $result = ima_forms_validate_form(
131
+ 'templates/forms/contact-form',
132
+ $_POST,
133
+ 'contact-form'
134
+ );
135
+
136
+ if (!$result['valid']) {
137
+ wp_send_json_error([
138
+ 'message' => 'Please correct the errors below.',
139
+ 'errors' => $result['errors']
140
+ ], 400);
141
+ }
142
+
143
+ // Process validated data
144
+ $data = $result['sanitized'];
145
+
146
+ $sent = wp_mail(
147
+ get_option('admin_email'),
148
+ 'New Contact Form Submission',
149
+ "Name: {$data['name']}\nEmail: {$data['email']}\n\n{$data['message']}"
150
+ );
151
+
152
+ if (!$sent) {
153
+ wp_send_json_error(['message' => 'Failed to send message.'], 500);
154
+ }
155
+
156
+ wp_send_json_success([
157
+ 'message' => 'Thank you! Your message has been sent.',
158
+ 'redirect' => home_url('/thank-you/')
159
+ ]);
160
+ }
161
+
162
+ add_action('wp_ajax_contact_form_submit', 'contact_form_ajax_handler');
163
+ add_action('wp_ajax_nopriv_contact_form_submit', 'contact_form_ajax_handler');
164
+
165
+ // Shortcode
166
+ add_shortcode('contact_form', function() {
167
+ ob_start();
168
+ get_template_part('templates/forms/contact-form');
169
+ return ob_get_clean();
170
+ });
171
+ ```
172
+
173
+ ## Form with Custom Cross-Field Validation
174
+
175
+ ```php
176
+ // Add custom validation via filter
177
+ add_filter('ima_forms_validate_registration-form', function($errors, $sanitized, $specs) {
178
+ // Cross-field validation: passwords must match
179
+ if ($sanitized['password'] !== $sanitized['password_confirm']) {
180
+ $errors['password_confirm'] = 'Passwords must match.';
181
+ }
182
+
183
+ // Business rule: age requirement
184
+ if (!empty($sanitized['age']) && $sanitized['age'] < 18) {
185
+ $errors['age'] = 'Must be 18 or older to register.';
186
+ }
187
+
188
+ // Conditional requirement
189
+ if ($sanitized['specialty'] === 'Other' && empty($sanitized['specialty_other'])) {
190
+ $errors['specialty_other'] = 'Please specify your specialty.';
191
+ }
192
+
193
+ return $errors;
194
+ }, 10, 3);
195
+ ```
196
+
197
+ ## Testing Patterns
198
+
199
+ ### Unit Tests for Validators
200
+
201
+ ```php
202
+ <?php
203
+ declare(strict_types=1);
204
+
205
+ use PHPUnit\Framework\TestCase;
206
+
207
+ class ValidatorTest extends TestCase {
208
+ /**
209
+ * @dataProvider emailProvider
210
+ */
211
+ public function test_validate_email_enhanced($email, $expected_valid, $expected_message) {
212
+ $result = ima_forms_validate_email_enhanced($email, 'Email', true);
213
+
214
+ if ($expected_valid) {
215
+ $this->assertNull($result);
216
+ } else {
217
+ $this->assertIsString($result);
218
+ if ($expected_message) {
219
+ $this->assertStringContainsString($expected_message, $result);
220
+ }
221
+ }
222
+ }
223
+
224
+ public function emailProvider() {
225
+ return [
226
+ 'valid email' => ['test@example.com', true, null],
227
+ 'disposable domain' => ['test@mailinator.com', false, 'not allowed'],
228
+ 'gmail typo' => ['test@gmial.com', false, 'gmail.com'],
229
+ 'invalid format' => ['not-an-email', false, 'valid'],
230
+ ];
231
+ }
232
+ }
233
+ ```
234
+
235
+ ### Testing Validation Engine
236
+
237
+ ```php
238
+ public function test_validation_engine_with_template() {
239
+ $_POST = [
240
+ 'name' => 'Test User',
241
+ 'email' => 'test@example.com',
242
+ 'message' => 'Test message',
243
+ ];
244
+
245
+ $result = ima_forms_validate_form(
246
+ 'templates/forms/contact-form',
247
+ $_POST,
248
+ 'contact-form'
249
+ );
250
+
251
+ $this->assertTrue($result['valid']);
252
+ $this->assertEmpty($result['errors']);
253
+ $this->assertEquals('Test User', $result['sanitized']['name']);
254
+ }
255
+ ```
256
+
257
+ ## Anti-Patterns to Avoid
258
+
259
+ ### ❌ Don't Skip Template-Driven Validation
260
+
261
+ ```php
262
+ // ❌ WRONG - Manual field map creation
263
+ $field_map = [
264
+ 'name' => 'text',
265
+ 'email' => 'email',
266
+ 'phone' => 'phone',
267
+ ];
268
+ $sanitized = ima_forms_sanitize_data($_POST, $field_map);
269
+ $validation = my_manual_validation($sanitized);
270
+
271
+ // ✅ CORRECT - Use Validation Engine
272
+ $result = ima_forms_validate_form('templates/forms/my-form', $_POST, 'my-form');
273
+ ```
274
+
275
+ ### ❌ Don't Duplicate Validation Logic
276
+
277
+ ```php
278
+ // ❌ WRONG - Manual validators when field already registers specs
279
+ function my_form_validate($data) {
280
+ $errors = [];
281
+ if (empty($data['email'])) {
282
+ $errors['email'] = 'Email is required.';
283
+ }
284
+ if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
285
+ $errors['email'] = 'Invalid email format.';
286
+ }
287
+ // ... more duplicated validation
288
+ }
289
+
290
+ // ✅ CORRECT - Let field registration handle it
291
+ $result = ima_forms_validate_form('templates/forms/my-form', $_POST, 'my-form');
292
+
293
+ // Add ONLY custom cross-field validation via filter
294
+ add_filter('ima_forms_validate_my-form', function($errors, $data) {
295
+ if ($data['password'] !== $data['password_confirm']) {
296
+ $errors['password_confirm'] = 'Passwords must match.';
297
+ }
298
+ return $errors;
299
+ }, 10, 2);
300
+ ```
301
+
302
+ ### ❌ Don't Forget Enhanced Validation
303
+
304
+ ```php
305
+ // ❌ WRONG - Basic email validation for user-facing forms
306
+ ima_forms_email_field([
307
+ 'name' => 'email',
308
+ 'enhanced_validation' => false, // Misses disposable domains!
309
+ ]);
310
+
311
+ // ✅ CORRECT - Use enhanced validation (default)
312
+ ima_forms_email_field([
313
+ 'name' => 'email',
314
+ 'enhanced_validation' => true, // Blocks spam domains, detects typos
315
+ ]);
316
+ ```
317
+
318
+ ### ❌ Don't Use Old Factory Pattern for Simple Forms
319
+
320
+ ```php
321
+ // ❌ WRONG - Unnecessary factory pattern complexity
322
+ ['render' => $render, 'validate' => $validate] = ima_forms_create_form(...);
323
+
324
+ // ✅ CORRECT - Use Validation Engine for simpler approach
325
+ $result = ima_forms_validate_form('templates/forms/my-form', $_POST, 'my-form');
326
+ ```
327
+
328
+ **Note**: Form factory pattern is still useful for programmatic field generation or complex dynamic validation composition.
@@ -0,0 +1,298 @@
1
+ # Field Components Reference
2
+
3
+ ## Contents
4
+
5
+ - [Text Input Field](#text-input-field)
6
+ - [Email Field](#email-field)
7
+ - [Password Field](#password-field)
8
+ - [Hidden Field](#hidden-field)
9
+ - [Textarea Field](#textarea-field)
10
+ - [Select Field](#select-field)
11
+ - [Checkbox Field](#checkbox-field)
12
+ - [Checkbox Group](#checkbox-group)
13
+ - [Phone Field](#phone-field)
14
+ - [URL Field](#url-field)
15
+ - [Address Fieldset](#address-fieldset)
16
+ - [Consent Agreement Field](#consent-agreement-field)
17
+ - [Repeater (Dynamic Rows)](#repeater-dynamic-rows)
18
+
19
+ ---
20
+
21
+ All field components auto-register validation specs when rendered. Use `required => true` to enable required validation.
22
+
23
+ ## Text Input Field
24
+
25
+ ```php
26
+ ima_forms_text_field([
27
+ 'name' => 'field_name',
28
+ 'label' => 'Field Label',
29
+ 'value' => $data['field_name'] ?? '',
30
+ 'required' => true,
31
+ 'placeholder' => 'Enter value...',
32
+ 'maxlength' => 100,
33
+ 'minlength' => 3,
34
+ 'pattern' => '[A-Za-z]+', // HTML5 pattern
35
+ 'wrapper_class' => 'mb-3',
36
+ 'input_class' => 'form-control',
37
+ 'help_text' => 'Additional guidance',
38
+ 'error' => $errors['field_name'] ?? '',
39
+ ]);
40
+
41
+ // Auto-registers: type, required, minlength, maxlength validation
42
+ ```
43
+
44
+ ## Email Field
45
+
46
+ ```php
47
+ ima_forms_email_field([
48
+ 'name' => 'email',
49
+ 'label' => 'Email Address',
50
+ 'value' => $data['email'] ?? '',
51
+ 'required' => true,
52
+ 'placeholder' => 'user@example.com',
53
+ 'enhanced_validation' => true, // Disposable domains + typo detection
54
+ 'wrapper_class' => 'mb-3',
55
+ 'help_text' => 'We will never share your email',
56
+ 'error' => $errors['email'] ?? '',
57
+ ]);
58
+ ```
59
+
60
+ **Enhanced validation includes**:
61
+ - RFC 5322 format validation
62
+ - Disposable domain blocking (mailinator, tempmail, etc.)
63
+ - Common typo detection (gmial.com → gmail.com)
64
+
65
+ ## Password Field
66
+
67
+ ```php
68
+ ima_forms_password_field([
69
+ 'name' => 'password',
70
+ 'label' => 'Password',
71
+ 'required' => true,
72
+ 'minlength' => 8,
73
+ 'placeholder' => 'Enter password',
74
+ 'wrapper_class' => 'mb-3',
75
+ 'help_text' => 'Minimum 8 characters',
76
+ 'error' => $errors['password'] ?? '',
77
+ 'attributes' => [
78
+ 'autocomplete' => 'new-password',
79
+ ],
80
+ ]);
81
+ ```
82
+
83
+ ## Hidden Field
84
+
85
+ ```php
86
+ ima_forms_hidden_field([
87
+ 'name' => 'form_id',
88
+ 'value' => 'contact-form',
89
+ 'label' => 'Form ID', // For debugging only
90
+ ]);
91
+ ```
92
+
93
+ ## Textarea Field
94
+
95
+ ```php
96
+ ima_forms_textarea_field([
97
+ 'name' => 'message',
98
+ 'label' => 'Message',
99
+ 'value' => $data['message'] ?? '',
100
+ 'required' => true,
101
+ 'rows' => 5,
102
+ 'maxlength' => 1000,
103
+ 'placeholder' => 'Enter your message...',
104
+ 'wrapper_class' => 'mb-3',
105
+ 'error' => $errors['message'] ?? '',
106
+ ]);
107
+ ```
108
+
109
+ ## Select Field
110
+
111
+ ```php
112
+ ima_forms_select_field([
113
+ 'name' => 'category',
114
+ 'label' => 'Category',
115
+ 'value' => $data['category'] ?? '',
116
+ 'required' => true,
117
+ 'options' => [
118
+ '' => 'Select a category...',
119
+ 'general' => 'General Inquiry',
120
+ 'support' => 'Technical Support',
121
+ 'sales' => 'Sales Question',
122
+ ],
123
+ 'wrapper_class' => 'mb-3',
124
+ 'error' => $errors['category'] ?? '',
125
+ ]);
126
+ ```
127
+
128
+ ### State Select (Pre-populated)
129
+
130
+ ```php
131
+ ima_forms_state_select_field([
132
+ 'name' => 'state',
133
+ 'label' => 'State',
134
+ 'value' => $data['state'] ?? '',
135
+ 'required' => true,
136
+ 'wrapper_class' => 'mb-3',
137
+ 'error' => $errors['state'] ?? '',
138
+ ]);
139
+
140
+ // Uses ima_forms_get_us_states() for options
141
+ ```
142
+
143
+ ## Checkbox Field
144
+
145
+ ```php
146
+ ima_forms_checkbox_field([
147
+ 'name' => 'subscribe',
148
+ 'label' => 'Subscribe to newsletter',
149
+ 'checked' => !empty($data['subscribe']),
150
+ 'required' => false,
151
+ 'wrapper_class' => 'mb-3',
152
+ 'error' => $errors['subscribe'] ?? '',
153
+ ]);
154
+ ```
155
+
156
+ ## Checkbox Group
157
+
158
+ ```php
159
+ ima_forms_checkbox_group([
160
+ 'name' => 'interests',
161
+ 'label' => 'Areas of Interest',
162
+ 'values' => $data['interests'] ?? [],
163
+ 'required' => true,
164
+ 'options' => [
165
+ 'web' => 'Web Development',
166
+ 'mobile' => 'Mobile Apps',
167
+ 'design' => 'UI/UX Design',
168
+ 'marketing' => 'Digital Marketing',
169
+ ],
170
+ 'wrapper_class' => 'mb-3',
171
+ 'errors' => $errors['interests'] ?? '',
172
+ ]);
173
+ ```
174
+
175
+ ## Phone Field
176
+
177
+ ```php
178
+ ima_forms_phone_field([
179
+ 'name' => 'phone',
180
+ 'label' => 'Phone Number',
181
+ 'value' => $data['phone'] ?? '',
182
+ 'required' => true,
183
+ 'placeholder' => '(555) 123-4567',
184
+ 'wrapper_class' => 'mb-3',
185
+ 'error' => $errors['phone'] ?? '',
186
+ ]);
187
+
188
+ // Validates: 10-15 digits, allows common formatting
189
+ ```
190
+
191
+ ## URL Field
192
+
193
+ ```php
194
+ ima_forms_url_field([
195
+ 'name' => 'website',
196
+ 'label' => 'Website URL',
197
+ 'value' => $data['website'] ?? '',
198
+ 'required' => false,
199
+ 'placeholder' => 'https://example.com',
200
+ 'wrapper_class' => 'mb-3',
201
+ 'error' => $errors['website'] ?? '',
202
+ ]);
203
+ ```
204
+
205
+ ## Address Fieldset
206
+
207
+ Composite field that registers multiple validation specs:
208
+
209
+ ```php
210
+ ima_forms_address_fieldset([
211
+ 'name_prefix' => 'billing', // Creates: billing_street, billing_city, etc.
212
+ 'label' => 'Billing Address',
213
+ 'values' => [
214
+ 'street' => $data['billing_street'] ?? '',
215
+ 'line2' => $data['billing_line2'] ?? '',
216
+ 'city' => $data['billing_city'] ?? '',
217
+ 'state' => $data['billing_state'] ?? '',
218
+ 'zip' => $data['billing_zip'] ?? '',
219
+ 'country' => $data['billing_country'] ?? 'United States',
220
+ ],
221
+ 'required' => true,
222
+ 'wrapper_class' => 'mb-3',
223
+ 'errors' => $errors, // Pass all errors, fieldset extracts relevant ones
224
+ ]);
225
+
226
+ // Registers 4 specs: {prefix}_street, {prefix}_city, {prefix}_state, {prefix}_zip
227
+ ```
228
+
229
+ ## Consent Agreement Field
230
+
231
+ Complex component with scrollable content, checkbox, and signature:
232
+
233
+ ```php
234
+ // Load agreement content
235
+ ob_start();
236
+ include get_template_directory() . '/templates/agreements/terms-of-service.php';
237
+ $agreement_html = ob_get_clean();
238
+
239
+ ima_forms_consent_agreement_field([
240
+ 'content_html' => $agreement_html,
241
+ 'checkbox_name' => 'agree_to_terms',
242
+ 'checkbox_label' => 'I have read and agree to the terms',
243
+ 'signature_name' => 'signature',
244
+ 'signature_label' => 'Type your full name as signature',
245
+ 'scroll_height' => '350px',
246
+ 'required' => true,
247
+ 'wrapper_class' => 'mb-4',
248
+ 'errors' => [
249
+ 'agree_to_terms' => $errors['agree_to_terms'] ?? '',
250
+ 'signature' => $errors['signature'] ?? '',
251
+ ],
252
+ 'checkbox_value' => $_POST['agree_to_terms'] ?? null,
253
+ 'signature_value' => $_POST['signature'] ?? '',
254
+ ]);
255
+ ```
256
+
257
+ **Features**:
258
+ - Checkbox disabled until user scrolls to bottom
259
+ - Signature field disabled until checkbox checked
260
+ - Auto-enqueues `ima-forms-consent.js`
261
+ - Registers TWO validation specs (checkbox + signature)
262
+
263
+ ## Repeater (Dynamic Rows)
264
+
265
+ ```php
266
+ ima_forms_repeater([
267
+ 'name' => 'additional_locations',
268
+ 'label' => 'Additional Locations',
269
+ 'description' => 'Add multiple practice locations',
270
+ 'min_rows' => 0,
271
+ 'max_rows' => 10,
272
+ 'add_button_text' => 'Add Location',
273
+ 'values' => $data['additional_locations'] ?? [],
274
+ 'errors' => $errors['additional_locations'] ?? [],
275
+ ], function($index, $row_data, $row_errors) {
276
+ // Row template - use array bracket notation
277
+ ima_forms_text_field([
278
+ 'name' => "additional_locations[{$index}][location_name]",
279
+ 'label' => 'Location Name',
280
+ 'value' => $row_data['location_name'] ?? '',
281
+ 'error' => $row_errors['location_name'] ?? '',
282
+ 'wrapper_class' => 'mb-3',
283
+ ]);
284
+
285
+ ima_forms_text_field([
286
+ 'name' => "additional_locations[{$index}][address]",
287
+ 'label' => 'Address',
288
+ 'value' => $row_data['address'] ?? '',
289
+ 'error' => $row_errors['address'] ?? '',
290
+ 'wrapper_class' => 'mb-3',
291
+ ]);
292
+ });
293
+ ```
294
+
295
+ **Features**:
296
+ - Auto-enqueues `ima-forms-repeater.js`
297
+ - Template placeholder uses `__INDEX__` (skipped during validation)
298
+ - Vanilla JavaScript (no jQuery dependency)