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.
- package/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +1064 -0
- package/package.json +49 -0
- package/platforms/claude/adapter.ts +115 -0
- package/platforms/junie/adapter.ts +254 -0
- package/platforms/junie/agents-template.md +113 -0
- package/platforms/junie/hook-translations.md +84 -0
- package/platforms/shared/detector.ts +27 -0
- package/platforms/shared/installer.ts +202 -0
- package/platforms/shared/types.ts +78 -0
- package/plugins/ima-claude/.claude-plugin/plugin.json +25 -0
- package/plugins/ima-claude/agents/explorer.md +30 -0
- package/plugins/ima-claude/agents/implementer.md +30 -0
- package/plugins/ima-claude/agents/memory.md +42 -0
- package/plugins/ima-claude/agents/reviewer.md +53 -0
- package/plugins/ima-claude/agents/tester.md +33 -0
- package/plugins/ima-claude/agents/wp-developer.md +46 -0
- package/plugins/ima-claude/hooks/README.md +145 -0
- package/plugins/ima-claude/hooks/atlassian_prereqs.py +112 -0
- package/plugins/ima-claude/hooks/block_sed_edits.py +59 -0
- package/plugins/ima-claude/hooks/bootstrap.sh +90 -0
- package/plugins/ima-claude/hooks/bootstrap_utility_check.py +94 -0
- package/plugins/ima-claude/hooks/composer_autoload_check.py +70 -0
- package/plugins/ima-claude/hooks/docs_organization.py +104 -0
- package/plugins/ima-claude/hooks/enforce_rg_over_grep.py +56 -0
- package/plugins/ima-claude/hooks/fp_utility_check.py +90 -0
- package/plugins/ima-claude/hooks/hook_logger.py +69 -0
- package/plugins/ima-claude/hooks/hooks.json +239 -0
- package/plugins/ima-claude/hooks/jira_issue_fetch.py +79 -0
- package/plugins/ima-claude/hooks/jquery_in_wordpress.py +92 -0
- package/plugins/ima-claude/hooks/memory_bootstrap.py +79 -0
- package/plugins/ima-claude/hooks/memory_store_reminder.py +75 -0
- package/plugins/ima-claude/hooks/prompt_coach.py +125 -0
- package/plugins/ima-claude/hooks/prompt_coach_digest.md +48 -0
- package/plugins/ima-claude/hooks/prompt_coach_system.md +30 -0
- package/plugins/ima-claude/hooks/sequential_thinking_check.py +81 -0
- package/plugins/ima-claude/hooks/serena_over_grep.py +96 -0
- package/plugins/ima-claude/hooks/serena_over_read.py +66 -0
- package/plugins/ima-claude/hooks/serena_project_check.py +133 -0
- package/plugins/ima-claude/hooks/sql_injection_check.py +73 -0
- package/plugins/ima-claude/hooks/task_master_after_plan.py +31 -0
- package/plugins/ima-claude/hooks/task_master_before_impl.py +93 -0
- package/plugins/ima-claude/hooks/tavily_extract_advanced.py +48 -0
- package/plugins/ima-claude/hooks/vestige_before_external.py +86 -0
- package/plugins/ima-claude/hooks/webfetch_to_tavily.py +42 -0
- package/plugins/ima-claude/hooks/websearch_to_tavily.py +41 -0
- package/plugins/ima-claude/hooks/wp_security_check.py +150 -0
- package/plugins/ima-claude/personalities/README.md +45 -0
- package/plugins/ima-claude/personalities/enable-40k.md +69 -0
- package/plugins/ima-claude/personalities/enable-templars.md +69 -0
- package/plugins/ima-claude/skills/.research-summary.md +340 -0
- package/plugins/ima-claude/skills/architect/SKILL.md +304 -0
- package/plugins/ima-claude/skills/compound-bridge/SKILL.md +200 -0
- package/plugins/ima-claude/skills/discourse/SKILL.md +440 -0
- package/plugins/ima-claude/skills/discourse-admin/SKILL.md +192 -0
- package/plugins/ima-claude/skills/discourse-admin/references/api-endpoints.md +441 -0
- package/plugins/ima-claude/skills/discourse-admin/references/gotchas.md +107 -0
- package/plugins/ima-claude/skills/discourse-admin/references/staging-defaults.md +98 -0
- package/plugins/ima-claude/skills/discourse-admin/scripts/discourse-admin.py +319 -0
- package/plugins/ima-claude/skills/docs-organize/SKILL.md +254 -0
- package/plugins/ima-claude/skills/docs-organize/templates/active-README.md +50 -0
- package/plugins/ima-claude/skills/docs-organize/templates/archive-README.md +57 -0
- package/plugins/ima-claude/skills/docs-organize/templates/docs-README.md +43 -0
- package/plugins/ima-claude/skills/docs-organize/templates/phase-archive-README.md +83 -0
- package/plugins/ima-claude/skills/docs-organize/templates/section-README.md +48 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-README.md +79 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-gitignore +9 -0
- package/plugins/ima-claude/skills/ember-discourse/SKILL.md +496 -0
- package/plugins/ima-claude/skills/functional-programmer/SKILL.md +258 -0
- package/plugins/ima-claude/skills/ima-bootstrap/SKILL.md +278 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/bootstrap-patterns.md +356 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/ima-brand.md +273 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/theme-integration.md +212 -0
- package/plugins/ima-claude/skills/ima-brand/SKILL.md +108 -0
- package/plugins/ima-claude/skills/ima-brand/references/brand-identity.md +140 -0
- package/plugins/ima-claude/skills/ima-brand/references/digital-standards.md +180 -0
- package/plugins/ima-claude/skills/ima-brand/references/visual-system.md +173 -0
- package/plugins/ima-claude/skills/ima-forms-expert/SKILL.md +175 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/container-components.md +154 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/examples.md +328 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/field-components.md +298 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/form-factory.md +193 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/quick-reference.md +153 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/validation-engine.md +336 -0
- package/plugins/ima-claude/skills/jira-checkpoint/SKILL.md +178 -0
- package/plugins/ima-claude/skills/jquery/SKILL.md +413 -0
- package/plugins/ima-claude/skills/js-fp/SKILL.md +463 -0
- package/plugins/ima-claude/skills/js-fp/core-principles.md +487 -0
- package/plugins/ima-claude/skills/js-fp/examples/pure-functions.js +260 -0
- package/plugins/ima-claude/skills/js-fp/examples/tests/pure-functions.test.js +262 -0
- package/plugins/ima-claude/skills/js-fp/references/anti-patterns.md +120 -0
- package/plugins/ima-claude/skills/js-fp/references/performance-patterns.md +116 -0
- package/plugins/ima-claude/skills/js-fp/references/testing-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/SKILL.md +280 -0
- package/plugins/ima-claude/skills/js-fp-api/examples/crud-endpoint.js +258 -0
- package/plugins/ima-claude/skills/js-fp-api/references/middleware-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/references/security-sql.md +110 -0
- package/plugins/ima-claude/skills/js-fp-api/references/validation-patterns.md +165 -0
- package/plugins/ima-claude/skills/js-fp-react/SKILL.md +447 -0
- package/plugins/ima-claude/skills/js-fp-react/examples/ProductCard.tsx +65 -0
- package/plugins/ima-claude/skills/js-fp-react/references/hooks-advanced.md +136 -0
- package/plugins/ima-claude/skills/js-fp-react/references/performance-patterns.md +175 -0
- package/plugins/ima-claude/skills/js-fp-vue/SKILL.md +322 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/complete-examples.md +397 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/composables-advanced.md +282 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/reactivity-patterns.md +348 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/testing.md +314 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/SKILL.md +301 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/ajax-patterns.md +192 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/event-patterns.md +136 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/wp-integration.md +248 -0
- package/plugins/ima-claude/skills/livecanvas/SKILL.md +209 -0
- package/plugins/ima-claude/skills/livecanvas/references/livecanvas-features.md +311 -0
- package/plugins/ima-claude/skills/livecanvas/references/loops-and-logic.md +730 -0
- package/plugins/ima-claude/skills/livecanvas/references/picostrap.md +227 -0
- package/plugins/ima-claude/skills/mcp-atlassian/SKILL.md +339 -0
- package/plugins/ima-claude/skills/mcp-context7/SKILL.md +109 -0
- package/plugins/ima-claude/skills/mcp-memory/SKILL.md +182 -0
- package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +233 -0
- package/plugins/ima-claude/skills/mcp-sequential/SKILL.md +149 -0
- package/plugins/ima-claude/skills/mcp-serena/SKILL.md +174 -0
- package/plugins/ima-claude/skills/mcp-tavily/SKILL.md +118 -0
- package/plugins/ima-claude/skills/mcp-vestige/SKILL.md +259 -0
- package/plugins/ima-claude/skills/php-authnet/SKILL.md +275 -0
- package/plugins/ima-claude/skills/php-authnet/references/api-reference.md +624 -0
- package/plugins/ima-claude/skills/php-authnet/references/sandbox-testing.md +424 -0
- package/plugins/ima-claude/skills/php-fp/SKILL.md +333 -0
- package/plugins/ima-claude/skills/php-fp/examples/pure-functions.php +403 -0
- package/plugins/ima-claude/skills/php-fp/examples/tests/PureFunctionsTest.php +515 -0
- package/plugins/ima-claude/skills/php-fp/references/core-principles.md +277 -0
- package/plugins/ima-claude/skills/php-fp/references/testing-patterns.md +374 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/SKILL.md +216 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/fp-patterns.md +275 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/plugin-architecture.md +295 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/security-examples.md +203 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/testing-strategy.md +259 -0
- package/plugins/ima-claude/skills/phpunit-wp/SKILL.md +716 -0
- package/plugins/ima-claude/skills/playwright/SKILL.md +434 -0
- package/plugins/ima-claude/skills/playwright/references/accessibility-testing.md +153 -0
- package/plugins/ima-claude/skills/playwright/references/ci-cd.md +268 -0
- package/plugins/ima-claude/skills/playwright/references/network-mocking.md +270 -0
- package/plugins/ima-claude/skills/playwright/references/visual-regression.md +215 -0
- package/plugins/ima-claude/skills/py-fp/SKILL.md +663 -0
- package/plugins/ima-claude/skills/py-fp/examples/pure-functions.py +185 -0
- package/plugins/ima-claude/skills/py-fp/examples/tests/test_pure_functions.py +244 -0
- package/plugins/ima-claude/skills/py-fp/references/core-principles.md +381 -0
- package/plugins/ima-claude/skills/py-fp/references/testing-patterns.md +283 -0
- package/plugins/ima-claude/skills/quasar-fp/SKILL.md +327 -0
- package/plugins/ima-claude/skills/quasar-fp/metadata.json +85 -0
- package/plugins/ima-claude/skills/quasar-fp/references/component-patterns.md +257 -0
- package/plugins/ima-claude/skills/quasar-fp/references/theme-integration.md +233 -0
- package/plugins/ima-claude/skills/quasar-fp/references/utility-classes.md +237 -0
- package/plugins/ima-claude/skills/quickstart/SKILL.md +129 -0
- package/plugins/ima-claude/skills/rails/SKILL.md +359 -0
- package/plugins/ima-claude/skills/resume-session/SKILL.md +68 -0
- package/plugins/ima-claude/skills/rg/SKILL.md +205 -0
- package/plugins/ima-claude/skills/ruby-fp/SKILL.md +336 -0
- package/plugins/ima-claude/skills/save-session/SKILL.md +81 -0
- package/plugins/ima-claude/skills/scorecard/SKILL.md +96 -0
- package/plugins/ima-claude/skills/skill-analyzer/SKILL.md +127 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/advanced-checklist.md +44 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/core-checklist.md +60 -0
- package/plugins/ima-claude/skills/skill-analyzer/scripts/analyze_skill.py +418 -0
- package/plugins/ima-claude/skills/skill-creator/LICENSE.txt +202 -0
- package/plugins/ima-claude/skills/skill-creator/SKILL.md +343 -0
- package/plugins/ima-claude/skills/skill-creator/references/output-patterns.md +82 -0
- package/plugins/ima-claude/skills/skill-creator/references/workflows.md +28 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/plugins/ima-claude/skills/task-master/SKILL.md +51 -0
- package/plugins/ima-claude/skills/task-planner/SKILL.md +228 -0
- package/plugins/ima-claude/skills/task-runner/SKILL.md +192 -0
- package/plugins/ima-claude/skills/unit-testing/SKILL.md +198 -0
- package/plugins/ima-claude/skills/unit-testing/references/mock-patterns.md +181 -0
- package/plugins/ima-claude/skills/unit-testing/references/tdd-workflow.md +177 -0
- package/plugins/ima-claude/skills/unit-testing/references/test-strategy.md +126 -0
- package/plugins/ima-claude/skills/wp-local/SKILL.md +246 -0
- package/plugins/ima-claude/skills/wp-local/references/configuration.md +198 -0
- package/plugins/ima-claude/skills/wp-local/references/wp-cli-reference.md +406 -0
- package/plugins/ima-claude/skills/wp-local/scripts/wp-local.sh +61 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Form Factory Pattern (v1.2.0) - Auto-Wired Validation
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Creating Forms with Auto-Validation](#creating-forms-with-auto-validation)
|
|
6
|
+
- [Auto-Wiring Field Functions](#auto-wiring-field-functions)
|
|
7
|
+
- [Extending with Custom Validation](#extending-with-custom-validation)
|
|
8
|
+
- [Form Wrapper Functions](#form-wrapper-functions)
|
|
9
|
+
- [Security Chokepoint Pattern](#security-chokepoint-pattern)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Creating Forms with Auto-Validation
|
|
14
|
+
|
|
15
|
+
The form factory pattern uses function composition to automatically wire validators to field types:
|
|
16
|
+
|
|
17
|
+
```php
|
|
18
|
+
// Create form with auto-wired validation
|
|
19
|
+
['render' => $render, 'validate' => $validate] = ima_forms_create_form(
|
|
20
|
+
'contact-form', // Form ID
|
|
21
|
+
function($register) use ($data, $errors) {
|
|
22
|
+
// Use auto-wiring field functions
|
|
23
|
+
ima_forms_email($register, [
|
|
24
|
+
'name' => 'email',
|
|
25
|
+
'label' => 'Email Address',
|
|
26
|
+
'required' => true,
|
|
27
|
+
'value' => $data['email'] ?? '',
|
|
28
|
+
'error' => $errors['email'] ?? '',
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
ima_forms_phone($register, [
|
|
32
|
+
'name' => 'phone',
|
|
33
|
+
'label' => 'Phone Number',
|
|
34
|
+
'required' => true,
|
|
35
|
+
'value' => $data['phone'] ?? '',
|
|
36
|
+
'error' => $errors['phone'] ?? '',
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
ima_forms_textarea($register, [
|
|
40
|
+
'name' => 'message',
|
|
41
|
+
'label' => 'Message',
|
|
42
|
+
'required' => true,
|
|
43
|
+
'value' => $data['message'] ?? '',
|
|
44
|
+
'error' => $errors['message'] ?? '',
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// Render form
|
|
50
|
+
$render();
|
|
51
|
+
|
|
52
|
+
// Validate (in AJAX handler)
|
|
53
|
+
$validation = $validate($sanitized_data);
|
|
54
|
+
if (!$validation['valid']) {
|
|
55
|
+
wp_send_json_error(['errors' => $validation['errors']]);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Auto-Wiring Field Functions
|
|
60
|
+
|
|
61
|
+
**Available auto-wiring functions** (automatically attach validators):
|
|
62
|
+
|
|
63
|
+
| Function | Validator |
|
|
64
|
+
|----------|-----------|
|
|
65
|
+
| `ima_forms_text($register, $args)` | Required validator |
|
|
66
|
+
| `ima_forms_email($register, $args)` | Format + enhanced validation |
|
|
67
|
+
| `ima_forms_phone($register, $args)` | Format validation |
|
|
68
|
+
| `ima_forms_url($register, $args)` | Format validation |
|
|
69
|
+
| `ima_forms_textarea($register, $args)` | Required validator |
|
|
70
|
+
| `ima_forms_select($register, $args)` | Required validator |
|
|
71
|
+
| `ima_forms_checkbox($register, $args)` | Required validator |
|
|
72
|
+
| `ima_forms_checkbox_group_field($register, $args)` | Required (array) |
|
|
73
|
+
|
|
74
|
+
## Extending with Custom Validation
|
|
75
|
+
|
|
76
|
+
```php
|
|
77
|
+
// Compose auto-wired + custom validators
|
|
78
|
+
$combined = ima_forms_compose_validators(
|
|
79
|
+
$validate, // Auto-wired from form factory
|
|
80
|
+
function($data) {
|
|
81
|
+
$errors = [];
|
|
82
|
+
// Your custom validation
|
|
83
|
+
if ($data['password'] !== $data['password_confirm']) {
|
|
84
|
+
$errors['password_confirm'] = 'Passwords must match.';
|
|
85
|
+
}
|
|
86
|
+
return ['valid' => empty($errors), 'errors' => $errors];
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Form Wrapper Functions
|
|
92
|
+
|
|
93
|
+
### Standardized Form Container
|
|
94
|
+
|
|
95
|
+
```php
|
|
96
|
+
ima_forms_form([
|
|
97
|
+
'id' => 'my-form',
|
|
98
|
+
'action' => 'my_ajax_action', // AJAX action name
|
|
99
|
+
'method' => 'post',
|
|
100
|
+
'class' => 'ima-form w-100', // Default: full width
|
|
101
|
+
'nonce_action' => 'my_form_submit',
|
|
102
|
+
'nonce_name' => 'nonce',
|
|
103
|
+
'enqueue_base' => true, // Auto-enqueue ima-forms-base.js
|
|
104
|
+
], function() {
|
|
105
|
+
// Form fields here
|
|
106
|
+
ima_forms_text_field([...]);
|
|
107
|
+
ima_forms_email_field([...]);
|
|
108
|
+
|
|
109
|
+
// Standardized submit button
|
|
110
|
+
ima_forms_submit_button([
|
|
111
|
+
'text' => 'Submit Form',
|
|
112
|
+
'processing_text' => 'Submitting...',
|
|
113
|
+
'class' => 'btn btn-primary',
|
|
114
|
+
'show_spinner' => true,
|
|
115
|
+
]);
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Benefits
|
|
120
|
+
|
|
121
|
+
- **Automatic error container**: `.ima-form-errors` populated by JavaScript
|
|
122
|
+
- **Automatic success container**: `.ima-form-success` for success messages
|
|
123
|
+
- **AJAX-ready**: `data-action` attribute for JavaScript handler
|
|
124
|
+
- **Nonce included**: WordPress nonce field automatically added
|
|
125
|
+
- **Loading states**: Submit button shows spinner and disables during submission
|
|
126
|
+
|
|
127
|
+
## Security Chokepoint Pattern
|
|
128
|
+
|
|
129
|
+
### AJAX Handler Factory (Classic Approach)
|
|
130
|
+
|
|
131
|
+
```php
|
|
132
|
+
// Create secure AJAX handler
|
|
133
|
+
$handler = ima_forms_create_ajax_handler(
|
|
134
|
+
'listing_application', // Form ID
|
|
135
|
+
'ima_form_listing_application', // Nonce action
|
|
136
|
+
'ima_listing_sanitize', // Sanitization function
|
|
137
|
+
'ima_listing_validate', // Validation function
|
|
138
|
+
'ima_listing_process' // Processing function
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Register AJAX hooks
|
|
142
|
+
add_action('wp_ajax_ima_listing_submit', $handler);
|
|
143
|
+
add_action('wp_ajax_nopriv_ima_listing_submit', $handler);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Security layers** (automatic):
|
|
147
|
+
1. **Nonce verification**: CSRF protection
|
|
148
|
+
2. **Sanitization**: Context-appropriate cleaning
|
|
149
|
+
3. **Validation**: Business rules enforcement
|
|
150
|
+
4. **Processing**: Controlled side effects
|
|
151
|
+
|
|
152
|
+
**Rate limiting**: Handled by infrastructure (WordFence, Akismet, WP Armour)
|
|
153
|
+
|
|
154
|
+
### Modern Approach with Validation Engine
|
|
155
|
+
|
|
156
|
+
```php
|
|
157
|
+
function my_form_ajax_handler() {
|
|
158
|
+
// Security: Nonce verification
|
|
159
|
+
if (!wp_verify_nonce($_POST['nonce'], 'my_form_submit')) {
|
|
160
|
+
wp_send_json_error(['message' => 'Security check failed.'], 403);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Validate + Sanitize (automatic via template)
|
|
164
|
+
$result = ima_forms_validate_form(
|
|
165
|
+
'templates/forms/my-form',
|
|
166
|
+
$_POST,
|
|
167
|
+
'my-form'
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (!$result['valid']) {
|
|
171
|
+
wp_send_json_error([
|
|
172
|
+
'message' => 'Please correct the errors.',
|
|
173
|
+
'errors' => $result['errors']
|
|
174
|
+
], 400);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Process validated data
|
|
178
|
+
$data = $result['sanitized'];
|
|
179
|
+
// ... your processing logic
|
|
180
|
+
|
|
181
|
+
wp_send_json_success(['message' => 'Success!']);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
add_action('wp_ajax_my_form_submit', 'my_form_ajax_handler');
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### When to Use Which Pattern
|
|
188
|
+
|
|
189
|
+
| Pattern | Use When |
|
|
190
|
+
|---------|----------|
|
|
191
|
+
| **Validation Engine** (v1.3.0) | Simple forms, standard validation needs |
|
|
192
|
+
| **Form Factory** (v1.2.0) | Programmatic field generation, dynamic forms |
|
|
193
|
+
| **Classic AJAX Handler** | Legacy code, complex multi-step processing |
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Quick Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Field Components](#field-components-auto-registration)
|
|
6
|
+
- [Container Components](#container-components)
|
|
7
|
+
- [Validation Engine (v1.4.0)](#validation-engine-v140)
|
|
8
|
+
- [Registry Functions](#registry-functions)
|
|
9
|
+
- [Validators](#validators)
|
|
10
|
+
- [Sanitizers](#sanitizers)
|
|
11
|
+
- [Core Functions](#core-functions)
|
|
12
|
+
- [Version Features](#version-features)
|
|
13
|
+
- [Filters](#filters)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Field Components (Auto-Registration)
|
|
18
|
+
|
|
19
|
+
| Function | Purpose |
|
|
20
|
+
|----------|---------|
|
|
21
|
+
| `ima_forms_text_field()` | Text input with validation |
|
|
22
|
+
| `ima_forms_email_field()` | Email with enhanced validation |
|
|
23
|
+
| `ima_forms_password_field()` | Password input |
|
|
24
|
+
| `ima_forms_hidden_field()` | Hidden field |
|
|
25
|
+
| `ima_forms_textarea_field()` | Multi-line text |
|
|
26
|
+
| `ima_forms_select_field()` | Dropdown select |
|
|
27
|
+
| `ima_forms_state_select_field()` | US states dropdown |
|
|
28
|
+
| `ima_forms_checkbox_field()` | Single checkbox |
|
|
29
|
+
| `ima_forms_checkbox_group()` | Multiple checkboxes |
|
|
30
|
+
| `ima_forms_phone_field()` | Phone with format validation |
|
|
31
|
+
| `ima_forms_url_field()` | URL with format validation |
|
|
32
|
+
| `ima_forms_address_fieldset()` | Composite address fields |
|
|
33
|
+
| `ima_forms_consent_agreement_field()` | Scrollable agreement + signature |
|
|
34
|
+
|
|
35
|
+
## Container Components
|
|
36
|
+
|
|
37
|
+
| Function | Purpose |
|
|
38
|
+
|----------|---------|
|
|
39
|
+
| `ima_forms_form()` | Complete form wrapper with AJAX |
|
|
40
|
+
| `ima_forms_submit_button()` | Standardized submit button |
|
|
41
|
+
| `ima_forms_card()` | Bootstrap card wrapper |
|
|
42
|
+
| `ima_forms_section()` | Section with heading |
|
|
43
|
+
| `ima_forms_column_layout()` | Responsive columns |
|
|
44
|
+
| `ima_forms_fieldset()` | Semantic fieldset |
|
|
45
|
+
| `ima_forms_repeater()` | Dynamic row repeater |
|
|
46
|
+
|
|
47
|
+
## Validation Engine (v1.4.0)
|
|
48
|
+
|
|
49
|
+
| Function | Purpose |
|
|
50
|
+
|----------|---------|
|
|
51
|
+
| `ima_forms_validate_form($template, $data, $form_id, $args)` | Main validation entry |
|
|
52
|
+
| `ima_forms_validate_against_specs($specs, $data)` | Validate data against specs |
|
|
53
|
+
| `ima_forms_run_validators($specs, $sanitized)` | Run stored validators |
|
|
54
|
+
| `ima_forms_sanitize_against_specs($specs, $data)` | Sanitize using specs |
|
|
55
|
+
| `ima_forms_debug_validation_summary($specs)` | Debug: validation preview |
|
|
56
|
+
|
|
57
|
+
## Registry Functions
|
|
58
|
+
|
|
59
|
+
| Function | Purpose |
|
|
60
|
+
|----------|---------|
|
|
61
|
+
| `ima_forms_register_field_spec($name, $spec)` | Register field spec + validators |
|
|
62
|
+
| `ima_forms_get_field_specs()` | Get all registered specs |
|
|
63
|
+
| `ima_forms_clear_field_specs()` | Clear registry |
|
|
64
|
+
| `ima_forms_has_field_spec($name)` | Check if field registered |
|
|
65
|
+
| `ima_forms_get_field_spec($name)` | Get single spec |
|
|
66
|
+
| `ima_forms_get_field_spec_count()` | Count registered specs |
|
|
67
|
+
| `ima_forms_debug_field_specs()` | Human-readable spec dump |
|
|
68
|
+
|
|
69
|
+
## Validators
|
|
70
|
+
|
|
71
|
+
| Function | Purpose |
|
|
72
|
+
|----------|---------|
|
|
73
|
+
| `ima_forms_validate_required($value, $label)` | Required check |
|
|
74
|
+
| `ima_forms_validate_email($email, $label)` | Basic RFC 5322 |
|
|
75
|
+
| `ima_forms_validate_email_enhanced($email, $label, $enhanced)` | Full email validation |
|
|
76
|
+
| `ima_forms_validate_phone($phone, $label)` | Phone format |
|
|
77
|
+
| `ima_forms_validate_url($url, $label)` | URL format |
|
|
78
|
+
| `ima_forms_validate_min_length($value, $min, $label)` | Min length |
|
|
79
|
+
| `ima_forms_validate_max_length($value, $max, $label)` | Max length |
|
|
80
|
+
| `ima_forms_validate_array_required($array, $label)` | Array not empty |
|
|
81
|
+
| `ima_forms_validate_numeric($value, $label)` | Numeric check |
|
|
82
|
+
| `ima_forms_validate_range($value, $min, $max, $label)` | Range check |
|
|
83
|
+
| `ima_forms_create_email_validator($domains, $typos)` | Pre-compiled validator |
|
|
84
|
+
|
|
85
|
+
## Sanitizers
|
|
86
|
+
|
|
87
|
+
| Function | Purpose |
|
|
88
|
+
|----------|---------|
|
|
89
|
+
| `ima_forms_sanitize_field($type, $value)` | Single field |
|
|
90
|
+
| `ima_forms_sanitize_data($data, $field_map)` | Multiple fields |
|
|
91
|
+
| `ima_forms_sanitize_repeater($rows, $field_map)` | Repeater rows |
|
|
92
|
+
| `ima_forms_sanitize_against_specs($specs, $data)` | Using specs (auto) |
|
|
93
|
+
|
|
94
|
+
## Core Functions
|
|
95
|
+
|
|
96
|
+
| Function | Purpose |
|
|
97
|
+
|----------|---------|
|
|
98
|
+
| `ima_forms_create_ajax_handler()` | Security chokepoint |
|
|
99
|
+
| `ima_forms_create_renderer()` | Template rendering |
|
|
100
|
+
| `ima_forms_load_field_template()` | Template hierarchy |
|
|
101
|
+
| `ima_forms_get_us_states()` | US states data |
|
|
102
|
+
|
|
103
|
+
## Version Features
|
|
104
|
+
|
|
105
|
+
### v1.4.0 (Validators at Registration)
|
|
106
|
+
- Validators built as closures at field registration
|
|
107
|
+
- `spec['validators']` stores closure array
|
|
108
|
+
- `ima_forms_run_validators()` just iterates and runs
|
|
109
|
+
- No type switching in engine
|
|
110
|
+
|
|
111
|
+
### v1.3.0 (Validation Engine)
|
|
112
|
+
- Template-driven validation
|
|
113
|
+
- Field spec registry
|
|
114
|
+
- Automatic sanitization from specs
|
|
115
|
+
- `ima_forms_validate_form()` as primary API
|
|
116
|
+
|
|
117
|
+
### v1.2.0 (Form Factory)
|
|
118
|
+
- Auto-wired validation via function composition
|
|
119
|
+
- `ima_forms_create_form()` factory
|
|
120
|
+
- `ima_forms_form()` and `ima_forms_submit_button()` wrappers
|
|
121
|
+
- Password and hidden field types
|
|
122
|
+
- Consent agreement component
|
|
123
|
+
- Enhanced email validation with disposable domains
|
|
124
|
+
|
|
125
|
+
### v1.1.0 (Container Components)
|
|
126
|
+
- Card, section, column layout, fieldset components
|
|
127
|
+
- Repeater with auto-enqueuing
|
|
128
|
+
- Template override system
|
|
129
|
+
|
|
130
|
+
### v1.0.0 (Foundation)
|
|
131
|
+
- Basic field components
|
|
132
|
+
- Pure validators and sanitizers
|
|
133
|
+
- Security chokepoint pattern
|
|
134
|
+
- Bootstrap 5 integration
|
|
135
|
+
|
|
136
|
+
## Filters
|
|
137
|
+
|
|
138
|
+
| Filter | Purpose |
|
|
139
|
+
|--------|---------|
|
|
140
|
+
| `ima_forms_validate_{form-id}` | Custom validation (cross-field, business rules) |
|
|
141
|
+
| `ima_forms_bad_email_domains` | Add blocked email domains |
|
|
142
|
+
| `ima_forms_email_typo_corrections` | Add typo corrections |
|
|
143
|
+
|
|
144
|
+
## Default Nonce
|
|
145
|
+
|
|
146
|
+
The default nonce action for `ima_forms_form()` is: `ima_forms_ajax`
|
|
147
|
+
|
|
148
|
+
```php
|
|
149
|
+
// In AJAX handler:
|
|
150
|
+
if (!wp_verify_nonce($_POST['nonce'], 'ima_forms_ajax')) {
|
|
151
|
+
wp_send_json_error(['message' => 'Security check failed.'], 403);
|
|
152
|
+
}
|
|
153
|
+
```
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
# Validation Engine - Validators-at-Registration Architecture
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Architecture Overview (v1.4.0)](#architecture-overview-v140)
|
|
6
|
+
- [How Field Registration Works](#how-field-registration-works)
|
|
7
|
+
- [Validation Flow](#validation-flow)
|
|
8
|
+
- [Field Spec Structure](#field-spec-structure)
|
|
9
|
+
- [Custom Validation via Filters](#custom-validation-via-filters)
|
|
10
|
+
- [Pure Validators](#pure-validators)
|
|
11
|
+
- [Enhanced Email Validator](#enhanced-email-validator)
|
|
12
|
+
- [Function Factory for Performance](#function-factory-for-performance)
|
|
13
|
+
- [Sanitization Patterns](#sanitization-patterns)
|
|
14
|
+
- [Debug Helpers](#debug-helpers)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Architecture Overview (v1.4.0)
|
|
19
|
+
|
|
20
|
+
**Core concept**: Validators are built as closures at field registration time, not by the engine via type-switching.
|
|
21
|
+
|
|
22
|
+
### Old Architecture (v1.3.0)
|
|
23
|
+
```php
|
|
24
|
+
// Field registered spec with type metadata
|
|
25
|
+
ima_forms_register_field_spec('email', ['type' => 'email', 'required' => true, ...]);
|
|
26
|
+
|
|
27
|
+
// Engine rebuilt validators based on type switching
|
|
28
|
+
switch ($spec['type']) {
|
|
29
|
+
case 'email':
|
|
30
|
+
$error = ima_forms_validate_email_enhanced($value, ...);
|
|
31
|
+
// etc.
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### New Architecture (v1.4.0)
|
|
36
|
+
```php
|
|
37
|
+
// Field builds validators at registration time
|
|
38
|
+
$validators = [];
|
|
39
|
+
$validators[] = fn($v) => ima_forms_validate_required($v, $label);
|
|
40
|
+
$validators[] = fn($v) => empty($v) ? null : ima_forms_validate_email_enhanced($v, $label, true);
|
|
41
|
+
|
|
42
|
+
ima_forms_register_field_spec('email', [
|
|
43
|
+
'type' => 'email',
|
|
44
|
+
'validators' => $validators, // Closures stored directly!
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
// Engine simply iterates and runs
|
|
48
|
+
foreach ($spec['validators'] as $validator) {
|
|
49
|
+
$error = $validator($value);
|
|
50
|
+
if ($error !== null) break;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Benefits**:
|
|
55
|
+
- **Single source of truth**: Field function defines validation once
|
|
56
|
+
- **No type switching**: Validators are closures, just iterate and run
|
|
57
|
+
- **Testable**: Validators are pure functions captured at registration time
|
|
58
|
+
- **Extensible**: Easy to add field-specific validators without touching engine
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## How Field Registration Works
|
|
63
|
+
|
|
64
|
+
Each field function has a `_register()` function that builds validators:
|
|
65
|
+
|
|
66
|
+
```php
|
|
67
|
+
function ima_forms_text_field_register(array $args): void {
|
|
68
|
+
$name = $args['name'] ?? '';
|
|
69
|
+
$label = $args['label'] ?? $name;
|
|
70
|
+
$required = $args['required'] ?? false;
|
|
71
|
+
$minlength = $args['minlength'] ?? null;
|
|
72
|
+
$maxlength = $args['maxlength'] ?? null;
|
|
73
|
+
|
|
74
|
+
// Build validators at registration time
|
|
75
|
+
$validators = [];
|
|
76
|
+
|
|
77
|
+
if ($required) {
|
|
78
|
+
$validators[] = fn($v) => ima_forms_validate_required($v, $label);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if ($minlength !== null) {
|
|
82
|
+
$validators[] = function($v) use ($label, $minlength) {
|
|
83
|
+
if (empty($v)) return null;
|
|
84
|
+
return ima_forms_validate_min_length((string) $v, (int) $minlength, $label);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if ($maxlength !== null) {
|
|
89
|
+
$validators[] = function($v) use ($label, $maxlength) {
|
|
90
|
+
if (empty($v)) return null;
|
|
91
|
+
return ima_forms_validate_max_length((string) $v, (int) $maxlength, $label);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
ima_forms_register_field_spec($name, [
|
|
96
|
+
'type' => 'text',
|
|
97
|
+
'label' => $label,
|
|
98
|
+
'required' => $required,
|
|
99
|
+
'validators' => $validators,
|
|
100
|
+
'sanitize_type' => 'text',
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Key insight**: The `$validators` array contains closures that capture the field's label and constraints via `use`. When the engine runs them, it just calls each closure with the value.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Validation Flow
|
|
110
|
+
|
|
111
|
+
```php
|
|
112
|
+
// 1. Include template → field functions register specs + validators
|
|
113
|
+
ima_forms_validate_form('templates/forms/my-form', $_POST, 'my-form');
|
|
114
|
+
|
|
115
|
+
// Inside ima_forms_validate_form():
|
|
116
|
+
// a) Clear registry (clean state)
|
|
117
|
+
ima_forms_clear_field_specs();
|
|
118
|
+
|
|
119
|
+
// b) Include template (fields register their specs + validators)
|
|
120
|
+
ob_start();
|
|
121
|
+
get_template_part($template_path, null, $template_args);
|
|
122
|
+
ob_end_clean();
|
|
123
|
+
|
|
124
|
+
// c) Get collected specs (with validators already built)
|
|
125
|
+
$specs = ima_forms_get_field_specs();
|
|
126
|
+
|
|
127
|
+
// d) Sanitize data based on specs
|
|
128
|
+
$sanitized = ima_forms_sanitize_against_specs($specs, $data);
|
|
129
|
+
|
|
130
|
+
// e) Run validators (simple iteration!)
|
|
131
|
+
$errors = ima_forms_run_validators($specs, $sanitized);
|
|
132
|
+
|
|
133
|
+
// f) Run custom validation filter
|
|
134
|
+
$errors = apply_filters("ima_forms_validate_{$form_id}", $errors, $sanitized, $specs);
|
|
135
|
+
|
|
136
|
+
// g) Return result
|
|
137
|
+
return ['valid' => empty($errors), 'errors' => $errors, 'sanitized' => $sanitized];
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Field Spec Structure
|
|
143
|
+
|
|
144
|
+
```php
|
|
145
|
+
[
|
|
146
|
+
'type' => 'email', // Field type (for sanitization fallback)
|
|
147
|
+
'label' => 'Email Address', // For error messages
|
|
148
|
+
'required' => true, // Whether field is required
|
|
149
|
+
'enhanced_validation' => true, // Email-specific: domain checking
|
|
150
|
+
'sanitize_type' => 'email', // Sanitization type
|
|
151
|
+
'validators' => [ // Array of closures!
|
|
152
|
+
fn($v) => ima_forms_validate_required($v, 'Email Address'),
|
|
153
|
+
fn($v) => empty($v) ? null : ima_forms_validate_email_enhanced($v, 'Email Address', true),
|
|
154
|
+
],
|
|
155
|
+
]
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Custom Validation via Filters
|
|
161
|
+
|
|
162
|
+
```php
|
|
163
|
+
// Add custom validation logic (runs after field validators)
|
|
164
|
+
add_filter('ima_forms_validate_my-form', function($errors, $sanitized, $specs) {
|
|
165
|
+
// Cross-field validation
|
|
166
|
+
if ($sanitized['password'] !== $sanitized['password_confirm']) {
|
|
167
|
+
$errors['password_confirm'] = 'Passwords must match.';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Business rules
|
|
171
|
+
if (!empty($sanitized['age']) && $sanitized['age'] < 18) {
|
|
172
|
+
$errors['age'] = 'Must be 18 or older.';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return $errors;
|
|
176
|
+
}, 10, 3);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Pure Validators
|
|
182
|
+
|
|
183
|
+
All validators return `null` for valid, error string for invalid:
|
|
184
|
+
|
|
185
|
+
```php
|
|
186
|
+
function ima_forms_validate_required($value, string $label): ?string {
|
|
187
|
+
if (empty($value) && $value !== '0') {
|
|
188
|
+
return "{$label} is required.";
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Available validators**:
|
|
195
|
+
- `ima_forms_validate_required($value, $label)`
|
|
196
|
+
- `ima_forms_validate_email($email, $label)` - Basic RFC 5322
|
|
197
|
+
- `ima_forms_validate_email_enhanced($email, $label, $enhanced)` - With domain/typo checking
|
|
198
|
+
- `ima_forms_validate_url($url, $label)`
|
|
199
|
+
- `ima_forms_validate_phone($phone, $label)` - 10-15 digits, allows formatting
|
|
200
|
+
- `ima_forms_validate_min_length($value, $min, $label)`
|
|
201
|
+
- `ima_forms_validate_max_length($value, $max, $label)`
|
|
202
|
+
- `ima_forms_validate_array_required($array, $label)`
|
|
203
|
+
- `ima_forms_validate_numeric($value, $label)`
|
|
204
|
+
- `ima_forms_validate_range($value, $min, $max, $label)`
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Enhanced Email Validator
|
|
209
|
+
|
|
210
|
+
```php
|
|
211
|
+
$error = ima_forms_validate_email_enhanced(
|
|
212
|
+
'user@gmial.com', // Input
|
|
213
|
+
'Email Address', // Label for error message
|
|
214
|
+
true // Enable enhanced checks
|
|
215
|
+
);
|
|
216
|
+
// Returns: "Did you mean user@gmail.com? Please check your email address."
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Features**:
|
|
220
|
+
- RFC 5322 format validation
|
|
221
|
+
- Disposable domain blocking (20+ domains: mailinator, tempmail, etc.)
|
|
222
|
+
- Common typo detection (gmial.com → gmail.com)
|
|
223
|
+
|
|
224
|
+
**Customize blocked domains**:
|
|
225
|
+
```php
|
|
226
|
+
add_filter('ima_forms_bad_email_domains', function($domains) {
|
|
227
|
+
$domains[] = 'example-spam.com';
|
|
228
|
+
return $domains;
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Customize typo corrections**:
|
|
233
|
+
```php
|
|
234
|
+
add_filter('ima_forms_email_typo_corrections', function($corrections) {
|
|
235
|
+
$corrections['customemail.co'] = 'customemail.com';
|
|
236
|
+
return $corrections;
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Function Factory for Performance
|
|
243
|
+
|
|
244
|
+
**Pre-compile email validator** for repeated validations (2-5x faster in bulk operations):
|
|
245
|
+
|
|
246
|
+
```php
|
|
247
|
+
// Create validator once with configuration
|
|
248
|
+
$validator = ima_forms_create_email_validator(
|
|
249
|
+
['spam.com', 'tempmail.com'], // Bad domains
|
|
250
|
+
['gmial.com' => 'gmail.com'] // Typo corrections
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
// Use for multiple emails (hot path optimization)
|
|
254
|
+
foreach ($emails as $email) {
|
|
255
|
+
$error = $validator($email, 'Email');
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Sanitization Patterns
|
|
262
|
+
|
|
263
|
+
### Automatic Sanitization
|
|
264
|
+
|
|
265
|
+
When using the Validation Engine, sanitization is automatic:
|
|
266
|
+
|
|
267
|
+
```php
|
|
268
|
+
$result = ima_forms_validate_form(...);
|
|
269
|
+
// $result['sanitized'] contains sanitized data
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Sanitization Type Mapping
|
|
273
|
+
|
|
274
|
+
```php
|
|
275
|
+
function ima_forms_get_sanitize_type_for_field(array $spec): string {
|
|
276
|
+
return match ($spec['type']) {
|
|
277
|
+
'email' => 'email',
|
|
278
|
+
'url' => 'url',
|
|
279
|
+
'textarea' => 'textarea',
|
|
280
|
+
'checkbox' => 'boolean',
|
|
281
|
+
'checkbox_group' => 'checkbox_array',
|
|
282
|
+
'phone' => 'phone',
|
|
283
|
+
default => 'text',
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Repeater Sanitization
|
|
289
|
+
|
|
290
|
+
```php
|
|
291
|
+
$sanitized_locations = ima_forms_sanitize_repeater(
|
|
292
|
+
$_POST['additional_locations'] ?? [],
|
|
293
|
+
['location_name' => 'text', 'contact_email' => 'email']
|
|
294
|
+
);
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Debug Helpers
|
|
300
|
+
|
|
301
|
+
### See Registered Specs
|
|
302
|
+
|
|
303
|
+
```php
|
|
304
|
+
echo ima_forms_debug_field_specs();
|
|
305
|
+
// Output:
|
|
306
|
+
// Registered Field Specs (4):
|
|
307
|
+
// - name: text [REQUIRED]
|
|
308
|
+
// - email: email [REQUIRED]
|
|
309
|
+
// - phone: phone
|
|
310
|
+
// - message: textarea [REQUIRED]
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### See Validation Summary
|
|
314
|
+
|
|
315
|
+
```php
|
|
316
|
+
$specs = ima_forms_get_field_specs();
|
|
317
|
+
echo ima_forms_debug_validation_summary($specs);
|
|
318
|
+
// Output:
|
|
319
|
+
// Validation Summary (4 fields):
|
|
320
|
+
// name (text, REQUIRED): [2 validator(s)]
|
|
321
|
+
// email (email, REQUIRED): [2 validator(s)]
|
|
322
|
+
// phone (phone, optional): [1 validator(s)]
|
|
323
|
+
// message (textarea, REQUIRED): [1 validator(s)]
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Registry Functions
|
|
327
|
+
|
|
328
|
+
| Function | Purpose |
|
|
329
|
+
|----------|---------|
|
|
330
|
+
| `ima_forms_register_field_spec($name, $spec)` | Register a field spec |
|
|
331
|
+
| `ima_forms_get_field_specs()` | Get all registered specs |
|
|
332
|
+
| `ima_forms_clear_field_specs()` | Clear registry (used by engine) |
|
|
333
|
+
| `ima_forms_has_field_spec($name)` | Check if field registered |
|
|
334
|
+
| `ima_forms_get_field_spec($name)` | Get single spec |
|
|
335
|
+
| `ima_forms_get_field_spec_count()` | Count registered specs |
|
|
336
|
+
| `ima_forms_debug_field_specs()` | Human-readable spec dump |
|