ultimate-jekyll-manager 1.9.4 → 1.9.6
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/CLAUDE.md +6 -0
- package/dist/assets/css/core/_utilities.scss +5 -2
- package/dist/assets/js/libs/form-manager.js +7 -8
- package/dist/commands/install.js +2 -2
- package/dist/commands/setup.js +2 -1
- package/dist/defaults/.github/workflows/build.yml +3 -1
- package/dist/defaults/dist/_includes/core/body.html +1 -7
- package/dist/defaults/dist/_includes/themes/classy/frontend/sections/footer.html +9 -1
- package/dist/defaults/dist/_layouts/blueprint/admin/calendar/index.html +1 -1
- package/dist/defaults/dist/_layouts/blueprint/admin/firebase/index.html +2 -2
- package/dist/defaults/dist/_layouts/blueprint/admin/studio/index.html +1 -1
- package/dist/defaults/dist/_layouts/blueprint/admin/users/index.html +2 -2
- package/dist/defaults/dist/_layouts/blueprint/admin/users/new.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +13 -13
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/reset.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/feedback.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +2 -6
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/checkout.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/portal/email-preferences.html +2 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/status.html +1 -1
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/index.html +1 -1
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/contact.html +1 -1
- package/dist/defaults/dist/pages/test/libraries/form-manager.html +31 -31
- package/dist/lib/safe-install.js +13 -0
- package/package.json +8 -1
- package/.nvmrc +0 -1
- package/CHANGELOG.md +0 -792
- package/CLAUDE-ATTRIBUTION.md +0 -215
- package/PROGRESS.md +0 -27
- package/TODO-ATTRIBUTION2.md +0 -753
- package/TODO-AUTH-TESTING.md +0 -165
- package/TODO-BACKEND.md +0 -13
- package/TODO-CHAT1.md +0 -41
- package/TODO-CONSENT-LIVETEST.md +0 -201
- package/TODO-NEW.md +0 -21
- package/TODO-themes.md +0 -34
- package/TODO-tracking.md +0 -69
- package/TODO-tracking2.md +0 -103
- package/TODO.md +0 -415
- package/_notes/CLAUDE-pages.md +0 -19
- package/_notes/CLAUDE-pages2.md +0 -18
- package/_notes/LOGOS.md +0 -1
- package/_notes/NOTES-app.md +0 -92
- package/_notes/NOTES-sub-2.md +0 -42
- package/_notes/NOTES-sub-ai.md +0 -165
- package/_notes/NOTES-sub-endpoints.md +0 -44
- package/_notes/NOTES-sub-example.md +0 -92
- package/_notes/NOTES-sub-plan.md +0 -36
- package/_notes/NOTES-sub-status.md +0 -123
- package/_notes/TODO-Claude.rtf +0 -105
- package/_notes/TODO-FileStructure.md +0 -249
- package/_notes/TODO-checkout.md +0 -33
- package/_notes/TODO-frontend.md +0 -61
- package/_notes/TODO-legacy.md +0 -18
- package/_notes/TODO-template-system.md +0 -73
- package/_notes/TODO-theme.md +0 -17
- package/logs/test.log +0 -144
package/CLAUDE-ATTRIBUTION.md
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
# Attribution Tracking System — Design & Implementation Plan
|
|
2
|
-
|
|
3
|
-
> Working design doc for the unified attribution system. Captures UTM/ITM tags, affiliate codes, and ad click IDs with a per-type "first-touch with 30-day refresh" model, plus auto-sync to the server when authenticated.
|
|
4
|
-
|
|
5
|
-
## Goals
|
|
6
|
-
|
|
7
|
-
An all-in-one system to track how users arrive at the site so we can:
|
|
8
|
-
1. Do UTM tracking (external marketing attribution)
|
|
9
|
-
2. Do ITM tracking (internal mechanisms — exit popups, extension prompts, etc.)
|
|
10
|
-
3. Capture ad click IDs for server-side conversion events (GA, Meta CAPI, TikTok Events API)
|
|
11
|
-
4. Properly attribute recurring purchases that happen offline (subscription renewals)
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Design Decisions (settled)
|
|
16
|
-
|
|
17
|
-
- **Attribution Model**: First-touch with 30-day refresh, **per-type basis**
|
|
18
|
-
- Each category (UTM, ITM, affiliate, adClicks) has independent freshness
|
|
19
|
-
- If no data exists for a type → save it
|
|
20
|
-
- If data exists AND is < 30 days old → preserve (first-touch protection)
|
|
21
|
-
- If data exists AND is >= 30 days old → overwrite (new journey)
|
|
22
|
-
- Categories are independent: can overwrite stale UTM while keeping fresh affiliate
|
|
23
|
-
- **Freshness TTL**: 30 days globally for all types
|
|
24
|
-
- **Ad click IDs**: lumped into a single `adClicks` object (user only arrives from one ad at a time; they share one timestamp)
|
|
25
|
-
- **Server Sync**: on attribution change (if signed in) + signup + checkout
|
|
26
|
-
- `_meta.needsSync` flag for deferred sync when user later signs in (mirrors `notifications.syncSubscription()` pattern in web-manager)
|
|
27
|
-
- **Storage**: User doc (rolling latest) + Subscription doc (frozen snapshot at purchase)
|
|
28
|
-
- **`getFresh()` returns ALL fresh data** — server decides what's recent enough to attribute. Subscription gets a frozen snapshot used for ALL recurring conversions, even years later.
|
|
29
|
-
- **No backwards compatibility** — replace the old shape cleanly, remove the ad-hoc 30-day check.
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Storage Structure
|
|
34
|
-
|
|
35
|
-
```javascript
|
|
36
|
-
// localStorage key: "attribution"
|
|
37
|
-
{
|
|
38
|
-
utm: {
|
|
39
|
-
tags: { utm_source, utm_medium, utm_campaign, utm_term, utm_content },
|
|
40
|
-
timestamp: "ISO string",
|
|
41
|
-
url: "full landing URL",
|
|
42
|
-
page: "/path"
|
|
43
|
-
},
|
|
44
|
-
itm: {
|
|
45
|
-
tags: { itm_source, itm_medium, itm_campaign, itm_content },
|
|
46
|
-
timestamp: "ISO string",
|
|
47
|
-
url: "full URL",
|
|
48
|
-
page: "/path"
|
|
49
|
-
},
|
|
50
|
-
affiliate: {
|
|
51
|
-
code: "partner123",
|
|
52
|
-
timestamp: "ISO string",
|
|
53
|
-
url: "full URL",
|
|
54
|
-
page: "/path"
|
|
55
|
-
},
|
|
56
|
-
adClicks: {
|
|
57
|
-
// All ad click IDs lumped together (user only arrives from one ad at a time)
|
|
58
|
-
fbclid: "from URL param",
|
|
59
|
-
fbc: "from _fbc cookie",
|
|
60
|
-
gclid: "from URL param",
|
|
61
|
-
ttclid: "from URL param",
|
|
62
|
-
timestamp: "ISO string",
|
|
63
|
-
url: "full URL",
|
|
64
|
-
page: "/path"
|
|
65
|
-
},
|
|
66
|
-
_meta: {
|
|
67
|
-
needsSync: false, // true if attribution changed while signed out
|
|
68
|
-
lastSynced: "ISO string" // last successful server sync
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## Data Captured
|
|
76
|
-
|
|
77
|
-
| Category | Source | Params |
|
|
78
|
-
|---|---|---|
|
|
79
|
-
| **UTM** | URL query | `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content` |
|
|
80
|
-
| **ITM** | URL query (internal links, e.g. exit popup) | `itm_source`, `itm_medium`, `itm_campaign`, `itm_content` |
|
|
81
|
-
| **Affiliate** | URL query | `aff` or `ref` |
|
|
82
|
-
| **Ad Clicks** | URL query + cookie | `fbclid`, `fbc` (`_fbc` cookie), `gclid`, `ttclid` |
|
|
83
|
-
|
|
84
|
-
ITM tags are emitted by internal mechanisms. Example: `exit-popup.js` already sets `itm_source=website&itm_medium=modal&itm_campaign=exit-popup&itm_content=<pathname>` on its CTA link. Those land as a query string on the next page and get captured like UTM.
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## Files to Modify
|
|
89
|
-
|
|
90
|
-
### 1. `src/assets/js/core/query-strings.js` — Core refactor
|
|
91
|
-
|
|
92
|
-
Currently captures UTM + affiliate only (no freshness, no ITM, no ad clicks, no sync). Becomes the single owner of attribution capture + sync.
|
|
93
|
-
|
|
94
|
-
Add:
|
|
95
|
-
1. Constants: `ATTRIBUTION_KEY = 'attribution'`, `FRESHNESS_DAYS = 30`, `FRESHNESS_MS = 30 * 24 * 60 * 60 * 1000`
|
|
96
|
-
2. `shouldPreserveAttribution(existingData)` — returns `true` if existing data is < 30 days old (preserve), `false` if missing or stale (allow overwrite)
|
|
97
|
-
3. `processUTMParams()` / `processITMParams()` / `processAffiliateParams()` / `processAdClickParams()` — each:
|
|
98
|
-
- Reads its params, quits if none present
|
|
99
|
-
- Applies `shouldPreserveAttribution()` first-touch check
|
|
100
|
-
- Writes its category + metadata (timestamp/url/page)
|
|
101
|
-
- Returns `true` if it changed anything
|
|
102
|
-
4. `getFbcCookie()` — parse `document.cookie` for `_fbc`
|
|
103
|
-
5. `getAttribution()` — raw stored object (all, regardless of age)
|
|
104
|
-
6. `getFreshAttribution()` — only categories < 30 days old, excludes `_meta`. This is the canonical thing sent to the server.
|
|
105
|
-
7. `syncAttribution()`:
|
|
106
|
-
- If user signed in → POST fresh attribution to backend-manager, set `_meta.lastSynced`, clear `_meta.needsSync`
|
|
107
|
-
- If not signed in → set `_meta.needsSync = true`
|
|
108
|
-
8. Auth-state listener for deferred sync: on sign-in, if `_meta.needsSync` is true, call `syncAttribution()`
|
|
109
|
-
9. Public API on `webManager._ujLibrary.attribution`:
|
|
110
|
-
```javascript
|
|
111
|
-
{
|
|
112
|
-
get: () => getAttribution(), // raw, all ages — debugging
|
|
113
|
-
getFresh: () => getFreshAttribution(), // < 30 days — USE THIS
|
|
114
|
-
sync: () => syncAttribution(), // manual sync (usually automatic)
|
|
115
|
-
clear: () => clearAttribution() // wipe all attribution
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
`processQueryStrings()` orchestrates: run each processor, OR their return values; if anything changed, save to storage and call `syncAttribution()`.
|
|
120
|
-
|
|
121
|
-
### 2. `src/assets/js/core/auth.js` — Use fresh attribution in signup
|
|
122
|
-
|
|
123
|
-
`sendUserSignupMetadata(account)` currently reads raw `webManager.storage().get('attribution', {})` (line ~283). Change to:
|
|
124
|
-
```javascript
|
|
125
|
-
const attribution = webManager.uj().attribution.getFresh();
|
|
126
|
-
```
|
|
127
|
-
Everything else (the `flags.signupProcessed` SSOT gate, `/backend-manager/user/signup` endpoint, consent payload) stays as-is. Sync-on-change in query-strings.js is complementary — signup still sends attribution + context + consent in one shot.
|
|
128
|
-
|
|
129
|
-
### 3. `src/assets/js/pages/payment/checkout/modules/api.js` — Use fresh attribution
|
|
130
|
-
|
|
131
|
-
Line ~60 currently sends raw storage:
|
|
132
|
-
```javascript
|
|
133
|
-
attribution: webManager.storage().get('attribution', {}),
|
|
134
|
-
```
|
|
135
|
-
Change to:
|
|
136
|
-
```javascript
|
|
137
|
-
attribution: webManager.uj().attribution.getFresh(),
|
|
138
|
-
```
|
|
139
|
-
(The old ad-hoc 30-day UTM check from the former `session.js` is already gone — this just swaps raw → fresh so stale categories are dropped before the server snapshots them onto the subscription.)
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
## Sync Flow
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
User lands with ?utm_source=google (or itm_/fbclid/etc.)
|
|
147
|
-
│
|
|
148
|
-
▼
|
|
149
|
-
processQueryStrings()
|
|
150
|
-
- per-type freshness check (first-touch w/ 30-day refresh)
|
|
151
|
-
- update localStorage
|
|
152
|
-
- did anything change?
|
|
153
|
-
│ yes
|
|
154
|
-
▼
|
|
155
|
-
Is user signed in?
|
|
156
|
-
├── YES → syncAttribution() now → set _meta.lastSynced
|
|
157
|
-
└── NO → set _meta.needsSync = true
|
|
158
|
-
│
|
|
159
|
-
▼ (later) user signs in
|
|
160
|
-
auth-state listener
|
|
161
|
-
- _meta.needsSync? → syncAttribution() → clear flag
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## Server-Side Data Flow (informational — backend out of scope here)
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
USER DOC /users/{uid}
|
|
170
|
-
attribution: { utm, itm, affiliate, adClicks } ← rolling update on each sync
|
|
171
|
-
|
|
172
|
-
│ on purchase, snapshot →
|
|
173
|
-
▼
|
|
174
|
-
SUBSCRIPTION DOC /users/{uid}/subscriptions/{subId}
|
|
175
|
-
attribution: { ... } ← FROZEN at purchase time
|
|
176
|
-
→ used for ALL recurring billing conversion events (even years later)
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
When a renewal fires months later, the server reads the subscription's frozen `attribution.adClicks.fbclid` (or gclid/ttclid) to send a server-side conversion event, attributing the recurring revenue to the original campaign.
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## Public API Reference
|
|
184
|
-
|
|
185
|
-
```javascript
|
|
186
|
-
webManager.uj().attribution.get() // raw stored attribution (all ages)
|
|
187
|
-
webManager.uj().attribution.getFresh() // only < 30 days — send this to server
|
|
188
|
-
webManager.uj().attribution.sync() // manual sync (normally automatic)
|
|
189
|
-
webManager.uj().attribution.clear() // wipe all attribution
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## Testing Checklist
|
|
195
|
-
|
|
196
|
-
- [ ] UTM params captured on landing
|
|
197
|
-
- [ ] ITM params captured (via exit-popup CTA link)
|
|
198
|
-
- [ ] Affiliate code captured (`aff` / `ref`)
|
|
199
|
-
- [ ] Ad click IDs captured (`fbclid`, `gclid`, `ttclid`)
|
|
200
|
-
- [ ] `_fbc` cookie read correctly
|
|
201
|
-
- [ ] First-touch protected per-type (revisit doesn't overwrite fresh data)
|
|
202
|
-
- [ ] 30-day refresh per-type (stale category overwritten, fresh ones kept)
|
|
203
|
-
- [ ] `getFresh()` excludes stale categories and `_meta`
|
|
204
|
-
- [ ] Sync fires when signed in + attribution changes
|
|
205
|
-
- [ ] `_meta.needsSync` set when signed out + attribution changes
|
|
206
|
-
- [ ] Deferred sync fires on sign-in when `needsSync` is true
|
|
207
|
-
- [ ] Signup (`auth.js`) sends `getFresh()` attribution
|
|
208
|
-
- [ ] Checkout (`api.js`) sends `getFresh()` attribution
|
|
209
|
-
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
## Open Questions / Notes
|
|
213
|
-
|
|
214
|
-
- Confirm the backend `user/signup` and checkout endpoints accept the new nested `adClicks` / `itm` shape (no backwards-compat shim — server should be updated in lockstep).
|
|
215
|
-
- Decide the sync command/endpoint for the standalone `syncAttribution()` call (e.g. `user/attribution` vs reusing signup). Signup already carries attribution, so sync-on-change is mainly for users who change attribution *after* signup but *before* checkout.
|
package/PROGRESS.md
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Project Progress Tracker
|
|
2
|
-
> Agents and maintainers should update this file regularly to reflect the current state of the project.
|
|
3
|
-
|
|
4
|
-
## Current Focus
|
|
5
|
-
* **Goal:** FormManager disabled-state refactor (snapshot-and-restore)
|
|
6
|
-
* **Current Phase:** Phase 1 — implementation + tests complete, docs pending
|
|
7
|
-
* **Priority:** Medium
|
|
8
|
-
* **Last Updated:** 2026-06-20 11:03 PM PDT
|
|
9
|
-
* **Notes:** FM disabled-state refactor done + comprehensive FM test suite added (110 tests total, up from 80). Blog post ad insertion fix applied (Phase 2). Docs (javascript-libraries.md, CHANGELOG) still need updating before shipping.
|
|
10
|
-
|
|
11
|
-
## Active Task List
|
|
12
|
-
* [ ] Phase 1: FormManager disabled-state snapshot-and-restore
|
|
13
|
-
* [x] Task 1.1: Refactor `_setDisabled` to use snapshot instead of `data-fm-keep-disabled`
|
|
14
|
-
* [x] Task 1.2: Add `_permanentlyDisabled` Set, populated in `_init()` before first disable
|
|
15
|
-
* [x] Task 1.3: Write page-layer tests (5 tests: snapshot capture, full disable, selective re-enable, cycle durability, onsubmit HTML guard)
|
|
16
|
-
* [x] Task 1.4: All 85 tests passing
|
|
17
|
-
* [x] Task 1.5: Add visual Test 7 to FM test page (form-manager.html + JS) with permanently disabled fields + rapid-cycle demo
|
|
18
|
-
* [x] Task 1.6: Write comprehensive FM page-layer tests — getData/setData (12 tests), validation/honeypot/file-accept (13 tests). 110 total.
|
|
19
|
-
* [ ] Task 1.7: Update `docs/javascript-libraries.md` — replace `data-fm-keep-disabled` docs with new snapshot pattern + `onsubmit="return false"` + `data-form-state="initializing"` CSS guard
|
|
20
|
-
* [ ] Task 1.8: Update CHANGELOG with the change
|
|
21
|
-
* [ ] Task 1.9: Ship (commit, push, publish)
|
|
22
|
-
|
|
23
|
-
* [x] Phase 2: Fix blog post ad insertion inside blockquotes
|
|
24
|
-
* [x] Task 2.1: Filter out `<p>` elements inside `<blockquote>`, `<details>`, `<figure>` from ad insertion candidates in `post.js`
|
|
25
|
-
|
|
26
|
-
## Completed Task List
|
|
27
|
-
* [x] Phase 0: v1.9.0 release — MCP OAuth flow + CDP debugging docs + dev-URL updates
|