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,301 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "js-fp-wordpress"
|
|
3
|
+
description: "FP patterns for JavaScript in WordPress/Bootstrap context - ecosystem-native patterns, jQuery guidance, pure business logic"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# JavaScript FP - WordPress/Bootstrap
|
|
7
|
+
|
|
8
|
+
Functional programming patterns for JavaScript in WordPress environments where jQuery is already loaded and Bootstrap is the UI framework.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
- Building WordPress plugin/theme JavaScript
|
|
13
|
+
- Need guidance on jQuery vs Vanilla JS decisions
|
|
14
|
+
- Implementing pure business logic in browser JavaScript
|
|
15
|
+
- Working with Gravity Forms, ACF, or other jQuery-dependent plugins
|
|
16
|
+
- Creating form handlers, AJAX operations, or DOM interactions
|
|
17
|
+
|
|
18
|
+
## Core Philosophy
|
|
19
|
+
|
|
20
|
+
**"Use what's simple and native to the ecosystem. In WordPress, jQuery IS native."**
|
|
21
|
+
|
|
22
|
+
**Key Insight**: The js-fp principle "Native patterns > FP utilities" targets AI-generated abstractions like custom `pipe()` and `curry()` functions - it does NOT mean "avoid established ecosystem libraries like jQuery."
|
|
23
|
+
|
|
24
|
+
**Foundation**: This skill builds on `js-fp` core principles. Reference `../js-fp/SKILL.md` for purity, composition, dependency injection, and testing patterns.
|
|
25
|
+
|
|
26
|
+
## TL;DR Decision Matrix
|
|
27
|
+
|
|
28
|
+
| Context | Recommendation | Rationale |
|
|
29
|
+
|---------|---------------|-----------|
|
|
30
|
+
| **New isolated component** | Vanilla JS | No jQuery event coupling needed |
|
|
31
|
+
| **AJAX operations** | jQuery `$.ajax` | Cleaner than `fetch` + error handling |
|
|
32
|
+
| **DOM event delegation** | Either | Both work well |
|
|
33
|
+
| **Integrating with WP plugins** | jQuery | Match ecosystem patterns |
|
|
34
|
+
| **Animation** | CSS transitions | Neither jQuery nor vanilla JS |
|
|
35
|
+
| **Pure business logic** | Vanilla JS | No DOM, fully testable |
|
|
36
|
+
|
|
37
|
+
## Critical Context: WordPress Reality Check
|
|
38
|
+
|
|
39
|
+
**jQuery IS guaranteed available** in WordPress because:
|
|
40
|
+
1. WordPress core depends on jQuery
|
|
41
|
+
2. Bootstrap 5 JavaScript works with or without jQuery
|
|
42
|
+
3. Gravity Forms, ACF, and most plugins use jQuery
|
|
43
|
+
4. The overhead argument is **irrelevant** - it's already loaded (0 additional bytes)
|
|
44
|
+
|
|
45
|
+
### Arguments That DON'T Apply Here
|
|
46
|
+
|
|
47
|
+
| Common Argument | Why It Doesn't Apply |
|
|
48
|
+
|-----------------|---------------------|
|
|
49
|
+
| "jQuery adds bundle size" | Already loaded - 0 additional bytes |
|
|
50
|
+
| "jQuery is a dependency" | Already a core WordPress dependency |
|
|
51
|
+
| "Modern browsers don't need jQuery" | True, but jQuery is still there |
|
|
52
|
+
| "jQuery is slower" | Negligible for DOM operations |
|
|
53
|
+
|
|
54
|
+
## Practical Guidelines
|
|
55
|
+
|
|
56
|
+
### 1. Don't Rewrite Working jQuery Code
|
|
57
|
+
|
|
58
|
+
**YAGNI applies**. If existing code works, leave it:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
// KEEP: Working jQuery AJAX handler
|
|
62
|
+
(function($) {
|
|
63
|
+
'use strict';
|
|
64
|
+
|
|
65
|
+
$('.ima-form').on('submit', function(e) {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
var $form = $(this);
|
|
68
|
+
|
|
69
|
+
$.ajax({
|
|
70
|
+
url: imaAjax.url,
|
|
71
|
+
type: 'POST',
|
|
72
|
+
data: $form.serialize(),
|
|
73
|
+
success: function(response) {
|
|
74
|
+
$form.find('.ima-response').html(response.message);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
})(jQuery);
|
|
80
|
+
|
|
81
|
+
// DON'T: Rewrite to vanilla "just because" - No benefit, adds risk
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 2. New Code: Choose Based on Context
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
// jQuery: When integrating with WordPress plugins
|
|
88
|
+
(function($) {
|
|
89
|
+
'use strict';
|
|
90
|
+
|
|
91
|
+
// Gravity Forms event - MUST use jQuery
|
|
92
|
+
$(document).on('gform_post_render', function(event, formId) {
|
|
93
|
+
initImaFields($('#gform_' + formId));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
})(jQuery);
|
|
97
|
+
|
|
98
|
+
// Vanilla JS: Isolated component with no WP plugin interaction
|
|
99
|
+
(function() {
|
|
100
|
+
'use strict';
|
|
101
|
+
|
|
102
|
+
class RepeaterController {
|
|
103
|
+
constructor(element) {
|
|
104
|
+
this.container = element;
|
|
105
|
+
this.template = element.querySelector('[data-repeater-template]');
|
|
106
|
+
this.init();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
init() {
|
|
110
|
+
this.container.addEventListener('click', this.handleClick.bind(this));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Pure method - no DOM side effects
|
|
114
|
+
generateRowId() {
|
|
115
|
+
return 'row_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
document.querySelectorAll('[data-repeater-container]').forEach(function(el) {
|
|
120
|
+
new RepeaterController(el);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
})();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 3. Prefer Consistency Within Files
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// AVOID: Mixing jQuery and vanilla in same file
|
|
130
|
+
(function($) {
|
|
131
|
+
document.querySelectorAll('.foo').forEach(function(el) { // Vanilla
|
|
132
|
+
$(el).on('click', handler); // jQuery - inconsistent!
|
|
133
|
+
});
|
|
134
|
+
})(jQuery);
|
|
135
|
+
|
|
136
|
+
// GOOD: Consistent jQuery throughout
|
|
137
|
+
(function($) {
|
|
138
|
+
'use strict';
|
|
139
|
+
$('.foo').each(function() {
|
|
140
|
+
$(this).on('click', handler);
|
|
141
|
+
});
|
|
142
|
+
})(jQuery);
|
|
143
|
+
|
|
144
|
+
// GOOD: Consistent vanilla throughout
|
|
145
|
+
(function() {
|
|
146
|
+
'use strict';
|
|
147
|
+
document.querySelectorAll('.foo').forEach(function(el) {
|
|
148
|
+
el.addEventListener('click', handler);
|
|
149
|
+
});
|
|
150
|
+
})();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Pure Business Logic Pattern
|
|
154
|
+
|
|
155
|
+
**Rule**: Extract pure JavaScript functions from DOM-dependent code.
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
(function($) {
|
|
159
|
+
'use strict';
|
|
160
|
+
|
|
161
|
+
// Pure business logic (testable without DOM)
|
|
162
|
+
function calculatePricing(quantity, unitPrice, discountPercent) {
|
|
163
|
+
var subtotal = Math.max(0, quantity) * Math.max(0, unitPrice);
|
|
164
|
+
var discountAmount = subtotal * (Math.min(100, Math.max(0, discountPercent)) / 100);
|
|
165
|
+
return {
|
|
166
|
+
subtotal: subtotal,
|
|
167
|
+
discountAmount: discountAmount,
|
|
168
|
+
total: subtotal - discountAmount
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function formatCurrency(amount) {
|
|
173
|
+
return '$' + amount.toFixed(2);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// DOM wrapper (side effects isolated here)
|
|
177
|
+
function PriceCalculator($container) {
|
|
178
|
+
this.$container = $container;
|
|
179
|
+
this.$container.on('change', 'input', this.update.bind(this));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
PriceCalculator.prototype.update = function() {
|
|
183
|
+
var values = {
|
|
184
|
+
quantity: parseInt(this.$container.find('#quantity').val()) || 0,
|
|
185
|
+
unitPrice: parseFloat(this.$container.find('#unit-price').val()) || 0,
|
|
186
|
+
discount: parseFloat(this.$container.find('#discount').val()) || 0
|
|
187
|
+
};
|
|
188
|
+
var pricing = calculatePricing(values.quantity, values.unitPrice, values.discount);
|
|
189
|
+
this.$container.find('#total').text(formatCurrency(pricing.total));
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Export for testing
|
|
193
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
194
|
+
module.exports = { calculatePricing: calculatePricing, formatCurrency: formatCurrency };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
})(jQuery);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Anti-Patterns (AVOID)
|
|
201
|
+
|
|
202
|
+
### Rewriting Working jQuery for No Benefit
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
// DON'T: Same functionality, more code, no benefit
|
|
206
|
+
// Before (working): $('.btn').on('click', handler);
|
|
207
|
+
// After (unnecessary):
|
|
208
|
+
document.querySelectorAll('.btn').forEach(function(btn) {
|
|
209
|
+
btn.addEventListener('click', handler);
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Fighting the WordPress Ecosystem
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
// DON'T: Ignore GF jQuery events (this won't work!)
|
|
217
|
+
document.addEventListener('gform_post_render', function() {});
|
|
218
|
+
|
|
219
|
+
// DO: Use jQuery for GF integration
|
|
220
|
+
$(document).on('gform_post_render', function(event, formId) {});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Custom FP Utilities
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
// NEVER: Create custom FP utilities
|
|
227
|
+
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x)
|
|
228
|
+
|
|
229
|
+
// INSTEAD: Direct function calls
|
|
230
|
+
function processFormData(data) {
|
|
231
|
+
var sanitized = sanitizeData(data);
|
|
232
|
+
var validated = validateData(sanitized);
|
|
233
|
+
return formatData(validated);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Quality Gates
|
|
238
|
+
|
|
239
|
+
Before implementing JavaScript in WordPress:
|
|
240
|
+
|
|
241
|
+
1. **Ecosystem check**: Does this need to interact with jQuery-based plugins (GF, ACF)?
|
|
242
|
+
2. **Existing code**: Is there working code that just needs enhancement?
|
|
243
|
+
3. **Pure logic**: Is business logic separated from DOM operations?
|
|
244
|
+
4. **Consistency**: Is the file using one approach consistently?
|
|
245
|
+
5. **Testability**: Can pure functions be tested without DOM?
|
|
246
|
+
6. **YAGNI**: Are we adding complexity without clear benefit?
|
|
247
|
+
|
|
248
|
+
## Reference Files
|
|
249
|
+
|
|
250
|
+
Load these as needed for detailed patterns:
|
|
251
|
+
|
|
252
|
+
### AJAX Patterns
|
|
253
|
+
**File**: [references/ajax-patterns.md](references/ajax-patterns.md)
|
|
254
|
+
**When**: Need AJAX implementation patterns
|
|
255
|
+
**Contains**: jQuery $.ajax, vanilla fetch, error handling, retry patterns
|
|
256
|
+
|
|
257
|
+
### Event Patterns
|
|
258
|
+
**File**: [references/event-patterns.md](references/event-patterns.md)
|
|
259
|
+
**When**: Need event delegation or DOMContentLoaded patterns
|
|
260
|
+
**Contains**: jQuery delegation, vanilla delegation, document ready patterns
|
|
261
|
+
|
|
262
|
+
### WordPress Integration
|
|
263
|
+
**File**: [references/wp-integration.md](references/wp-integration.md)
|
|
264
|
+
**When**: Integrating with Gravity Forms, ACF, or WordPress admin
|
|
265
|
+
**Contains**: GF hooks, ACF hooks, admin JS, pure logic extraction, testing
|
|
266
|
+
|
|
267
|
+
### PHP Integration
|
|
268
|
+
**File**: `../php-fp-wordpress/SKILL.md`
|
|
269
|
+
**When**: Need server-side integration patterns
|
|
270
|
+
**Contains**: WordPress AJAX handlers, security practices, PHP/JS coordination
|
|
271
|
+
|
|
272
|
+
### Core FP Principles
|
|
273
|
+
**File**: `../js-fp/SKILL.md`
|
|
274
|
+
**When**: Need foundational FP patterns
|
|
275
|
+
**Contains**: Purity, composition, dependency injection, immutability, testing
|
|
276
|
+
|
|
277
|
+
## File Organization
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
plugin-name/
|
|
281
|
+
└── assets/
|
|
282
|
+
└── js/
|
|
283
|
+
├── plugin-base.js # jQuery - AJAX, GF integration
|
|
284
|
+
├── plugin-admin.js # jQuery - Admin UI interactions
|
|
285
|
+
├── plugin-repeater.js # Vanilla - Isolated component
|
|
286
|
+
└── pure/
|
|
287
|
+
├── formatting.js # Pure functions (testable)
|
|
288
|
+
└── calculations.js # Pure functions (testable)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Success Metrics
|
|
292
|
+
|
|
293
|
+
- **Ecosystem Fit**: JavaScript integrates smoothly with WordPress/plugins
|
|
294
|
+
- **Consistency**: Files use one approach throughout
|
|
295
|
+
- **Testability**: Pure business logic has unit tests
|
|
296
|
+
- **Maintainability**: Clear separation of concerns
|
|
297
|
+
- **Pragmatism**: Working code not rewritten without benefit
|
|
298
|
+
|
|
299
|
+
## Philosophy
|
|
300
|
+
|
|
301
|
+
*"In WordPress, jQuery IS native. Use what's simple and matches the ecosystem. Separate pure business logic for testability, but don't fight the platform. Working code > ideological purity."*
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# AJAX Patterns for WordPress
|
|
2
|
+
|
|
3
|
+
WordPress AJAX patterns with jQuery and vanilla JS approaches.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [jQuery AJAX (Recommended)](#jquery-ajax-recommended)
|
|
8
|
+
2. [Vanilla fetch Alternative](#vanilla-fetch-alternative)
|
|
9
|
+
3. [Error Handling Patterns](#error-handling-patterns)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## jQuery AJAX (Recommended)
|
|
14
|
+
|
|
15
|
+
Standard WordPress AJAX pattern with jQuery:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
(function($) {
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
function submitForm($form, successCallback, errorCallback) {
|
|
22
|
+
$.ajax({
|
|
23
|
+
url: imaAjax.url,
|
|
24
|
+
type: 'POST',
|
|
25
|
+
data: {
|
|
26
|
+
action: 'ima_process_form',
|
|
27
|
+
nonce: imaAjax.nonce,
|
|
28
|
+
form_data: $form.serialize()
|
|
29
|
+
},
|
|
30
|
+
beforeSend: function() {
|
|
31
|
+
$form.find('button[type="submit"]').prop('disabled', true);
|
|
32
|
+
$form.find('.ima-loading').show();
|
|
33
|
+
},
|
|
34
|
+
success: function(response) {
|
|
35
|
+
if (response.success) {
|
|
36
|
+
successCallback(response.data);
|
|
37
|
+
} else {
|
|
38
|
+
errorCallback(response.data || 'Unknown error');
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
error: function(xhr, status, error) {
|
|
42
|
+
errorCallback('Network error: ' + error);
|
|
43
|
+
},
|
|
44
|
+
complete: function() {
|
|
45
|
+
$form.find('button[type="submit"]').prop('disabled', false);
|
|
46
|
+
$form.find('.ima-loading').hide();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Usage
|
|
52
|
+
$('.ima-ajax-form').on('submit', function(e) {
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
var $form = $(this);
|
|
55
|
+
|
|
56
|
+
submitForm(
|
|
57
|
+
$form,
|
|
58
|
+
function(data) {
|
|
59
|
+
$form.find('.ima-response').html(data.message).removeClass('error').addClass('success');
|
|
60
|
+
},
|
|
61
|
+
function(error) {
|
|
62
|
+
$form.find('.ima-response').html(error).removeClass('success').addClass('error');
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
})(jQuery);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Vanilla fetch Alternative
|
|
73
|
+
|
|
74
|
+
Use when building isolated components without WP plugin interaction:
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
(function() {
|
|
78
|
+
'use strict';
|
|
79
|
+
|
|
80
|
+
// Pure function - formats data for WordPress AJAX
|
|
81
|
+
function buildFormData(action, nonce, data) {
|
|
82
|
+
var formData = new FormData();
|
|
83
|
+
formData.append('action', action);
|
|
84
|
+
formData.append('nonce', nonce);
|
|
85
|
+
|
|
86
|
+
Object.keys(data).forEach(function(key) {
|
|
87
|
+
formData.append(key, data[key]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return formData;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Wrapper with side effects
|
|
94
|
+
function submitToWordPress(action, data) {
|
|
95
|
+
return fetch(imaAjax.url, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
credentials: 'same-origin',
|
|
98
|
+
body: buildFormData(action, imaAjax.nonce, data)
|
|
99
|
+
})
|
|
100
|
+
.then(function(response) {
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error('Network response was not ok');
|
|
103
|
+
}
|
|
104
|
+
return response.json();
|
|
105
|
+
})
|
|
106
|
+
.then(function(data) {
|
|
107
|
+
if (!data.success) {
|
|
108
|
+
throw new Error(data.data || 'Unknown error');
|
|
109
|
+
}
|
|
110
|
+
return data.data;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Usage
|
|
115
|
+
document.querySelectorAll('.ima-fetch-form').forEach(function(form) {
|
|
116
|
+
form.addEventListener('submit', function(e) {
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
|
|
119
|
+
var formData = new FormData(form);
|
|
120
|
+
var data = {};
|
|
121
|
+
formData.forEach(function(value, key) {
|
|
122
|
+
data[key] = value;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
submitToWordPress('ima_process_form', data)
|
|
126
|
+
.then(function(result) {
|
|
127
|
+
form.querySelector('.ima-response').textContent = result.message;
|
|
128
|
+
})
|
|
129
|
+
.catch(function(error) {
|
|
130
|
+
form.querySelector('.ima-response').textContent = error.message;
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
})();
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Error Handling Patterns
|
|
141
|
+
|
|
142
|
+
### Centralized Error Handler
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
(function($) {
|
|
146
|
+
'use strict';
|
|
147
|
+
|
|
148
|
+
var AjaxHandler = {
|
|
149
|
+
handleError: function(error, $container) {
|
|
150
|
+
var message = typeof error === 'string' ? error : 'An error occurred';
|
|
151
|
+
$container.find('.ima-response')
|
|
152
|
+
.html(message)
|
|
153
|
+
.removeClass('success')
|
|
154
|
+
.addClass('error');
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
handleSuccess: function(data, $container) {
|
|
158
|
+
$container.find('.ima-response')
|
|
159
|
+
.html(data.message || 'Success')
|
|
160
|
+
.removeClass('error')
|
|
161
|
+
.addClass('success');
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
window.ImaAjaxHandler = AjaxHandler;
|
|
166
|
+
|
|
167
|
+
})(jQuery);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Retry Pattern
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
function ajaxWithRetry($form, maxRetries) {
|
|
174
|
+
var attempts = 0;
|
|
175
|
+
|
|
176
|
+
function attempt() {
|
|
177
|
+
attempts++;
|
|
178
|
+
return $.ajax({
|
|
179
|
+
url: imaAjax.url,
|
|
180
|
+
type: 'POST',
|
|
181
|
+
data: $form.serialize()
|
|
182
|
+
}).fail(function(xhr, status, error) {
|
|
183
|
+
if (attempts < maxRetries && status === 'timeout') {
|
|
184
|
+
return attempt();
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return attempt();
|
|
191
|
+
}
|
|
192
|
+
```
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Event Delegation Patterns
|
|
2
|
+
|
|
3
|
+
Event handling patterns for WordPress JavaScript.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [jQuery Event Delegation](#jquery-event-delegation)
|
|
8
|
+
2. [Vanilla Event Delegation](#vanilla-event-delegation)
|
|
9
|
+
3. [DOMContentLoaded Patterns](#domcontentloaded-patterns)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## jQuery Event Delegation
|
|
14
|
+
|
|
15
|
+
### Document-Level Delegation
|
|
16
|
+
|
|
17
|
+
For dynamically added elements:
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
(function($) {
|
|
21
|
+
'use strict';
|
|
22
|
+
|
|
23
|
+
// Delegated events - works with dynamically added elements
|
|
24
|
+
$(document).on('click', '.ima-toggle-btn', function(e) {
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
var $target = $($(this).data('target'));
|
|
27
|
+
$target.toggleClass('is-visible');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
})(jQuery);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Scoped Delegation (More Efficient)
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
(function($) {
|
|
37
|
+
'use strict';
|
|
38
|
+
|
|
39
|
+
// Scoped delegation - better performance
|
|
40
|
+
$('.ima-component').on('click', '.ima-action-btn', function(e) {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
handleAction($(this).data('action'), $(this).closest('.ima-item'));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
})(jQuery);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Vanilla Event Delegation
|
|
51
|
+
|
|
52
|
+
### Document-Level Pattern
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
(function() {
|
|
56
|
+
'use strict';
|
|
57
|
+
|
|
58
|
+
// Delegated events using event bubbling
|
|
59
|
+
document.addEventListener('click', function(e) {
|
|
60
|
+
// Toggle button delegation
|
|
61
|
+
if (e.target.matches('.ima-toggle-btn') || e.target.closest('.ima-toggle-btn')) {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
var btn = e.target.closest('.ima-toggle-btn');
|
|
64
|
+
var target = document.querySelector(btn.dataset.target);
|
|
65
|
+
if (target) {
|
|
66
|
+
target.classList.toggle('is-visible');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
})();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Scoped Delegation Pattern
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
(function() {
|
|
78
|
+
'use strict';
|
|
79
|
+
|
|
80
|
+
// Scoped delegation
|
|
81
|
+
document.querySelectorAll('.ima-component').forEach(function(component) {
|
|
82
|
+
component.addEventListener('click', function(e) {
|
|
83
|
+
var actionBtn = e.target.closest('.ima-action-btn');
|
|
84
|
+
if (actionBtn) {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
var action = actionBtn.dataset.action;
|
|
87
|
+
var item = actionBtn.closest('.ima-item');
|
|
88
|
+
handleAction(action, item);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
})();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## DOMContentLoaded Patterns
|
|
99
|
+
|
|
100
|
+
### jQuery Document Ready
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
// Standard WordPress pattern
|
|
104
|
+
(function($) {
|
|
105
|
+
$(document).ready(function() {
|
|
106
|
+
// DOM is ready
|
|
107
|
+
initComponents();
|
|
108
|
+
});
|
|
109
|
+
})(jQuery);
|
|
110
|
+
|
|
111
|
+
// Shorthand (equivalent)
|
|
112
|
+
jQuery(function($) {
|
|
113
|
+
initComponents();
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Vanilla DOMContentLoaded
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
(function() {
|
|
121
|
+
'use strict';
|
|
122
|
+
|
|
123
|
+
function init() {
|
|
124
|
+
initComponents();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Handle both loading states
|
|
128
|
+
if (document.readyState === 'loading') {
|
|
129
|
+
document.addEventListener('DOMContentLoaded', init);
|
|
130
|
+
} else {
|
|
131
|
+
// DOM already loaded (script loaded with defer or at bottom)
|
|
132
|
+
init();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
})();
|
|
136
|
+
```
|