ultimate-jekyll-manager 1.9.5 → 1.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/assets/css/core/_initialize.scss +0 -11
  2. package/dist/assets/css/core/_utilities.scss +5 -2
  3. package/dist/assets/js/libs/form-manager.js +5 -10
  4. package/dist/defaults/_.gitignore +4 -0
  5. package/dist/defaults/dist/_includes/core/body.html +1 -7
  6. package/package.json +8 -1
  7. package/.nvmrc +0 -1
  8. package/CHANGELOG.md +0 -804
  9. package/CLAUDE-ATTRIBUTION.md +0 -215
  10. package/PROGRESS.md +0 -36
  11. package/TODO-ATTRIBUTION2.md +0 -753
  12. package/TODO-AUTH-TESTING.md +0 -165
  13. package/TODO-BACKEND.md +0 -13
  14. package/TODO-CHAT1.md +0 -41
  15. package/TODO-CONSENT-LIVETEST.md +0 -201
  16. package/TODO-NEW.md +0 -21
  17. package/TODO-themes.md +0 -34
  18. package/TODO-tracking.md +0 -69
  19. package/TODO-tracking2.md +0 -103
  20. package/TODO.md +0 -415
  21. package/_notes/CLAUDE-pages.md +0 -19
  22. package/_notes/CLAUDE-pages2.md +0 -18
  23. package/_notes/LOGOS.md +0 -1
  24. package/_notes/NOTES-app.md +0 -92
  25. package/_notes/NOTES-sub-2.md +0 -42
  26. package/_notes/NOTES-sub-ai.md +0 -165
  27. package/_notes/NOTES-sub-endpoints.md +0 -44
  28. package/_notes/NOTES-sub-example.md +0 -92
  29. package/_notes/NOTES-sub-plan.md +0 -36
  30. package/_notes/NOTES-sub-status.md +0 -123
  31. package/_notes/TODO-Claude.rtf +0 -105
  32. package/_notes/TODO-FileStructure.md +0 -249
  33. package/_notes/TODO-checkout.md +0 -33
  34. package/_notes/TODO-frontend.md +0 -61
  35. package/_notes/TODO-legacy.md +0 -18
  36. package/_notes/TODO-template-system.md +0 -73
  37. package/_notes/TODO-theme.md +0 -17
  38. package/logs/test.log +0 -144
  39. package/plans/fix-translation-exclude-404s.md +0 -113
@@ -1,113 +0,0 @@
1
- # Fix: Translation exclude list not respected by footer language switcher
2
-
3
- ## Problem
4
-
5
- Every UJM site with translation enabled generates dead language links on excluded pages (e.g. blog posts), causing widespread 404s indexed by Google.
6
-
7
- **Root cause:** The footer language switcher and the `uj_translation_url` Ruby tag both generate language-prefixed URLs (`/es/blog/my-post`, `/ko/blog/my-post`) without checking the `translation.exclude` list. Meanwhile, the translation gulp task correctly skips excluded pages — so the translated HTML files are never generated, but the links to them are.
8
-
9
- **Impact:** Every blog post on every site with translation enabled has footer links to non-existent translated pages. Google discovers these via crawling, indexes them as 404s, and inflates "Page not found" stats in GA4 (often 40-50% of all pageviews). Also harms crawl budget.
10
-
11
- **Example (operst):**
12
- - Config: `translation.enabled: true`, `exclude: ["blog"]`, languages: `es`, `ko`
13
- - Footer on `/blog/my-post` links to `/es/blog/my-post` and `/ko/blog/my-post`
14
- - Neither of those pages exist — both return 404
15
- - GA4 shows "Oops! This page doesn't exist" as the #1 page at 45% of traffic
16
-
17
- ## Fix 1: Footer template (DONE)
18
-
19
- **File:** `src/defaults/dist/_includes/themes/classy/frontend/sections/footer.html`
20
-
21
- **Change:** Before rendering the language dropdown, check the current page against the exclude list. If matched, only show the default language (same behavior as when translation is disabled).
22
-
23
- ```liquid
24
- {% assign page_excluded_from_translation = false %}
25
- {% for exclude in site.translation.exclude %}
26
- {% assign exclude_folder = "/" | append: exclude | append: "/" %}
27
- {% assign exclude_page = "/" | append: exclude %}
28
- {% if page.url == exclude_page or page.url contains exclude_folder %}
29
- {% assign page_excluded_from_translation = true %}
30
- {% endif %}
31
- {% endfor %}
32
- {% if site.translation.enabled and site.translation.languages.size > 0 and page_excluded_from_translation != true %}
33
- {% assign all_languages = site.translation.languages | push: default_language %}
34
- {% else %}
35
- {% assign all_languages = "" | split: "" | push: default_language %}
36
- {% endif %}
37
- ```
38
-
39
- **Matching logic:** Uses the same pattern as `translation.js` — each exclude entry matches as both a folder prefix (`/blog/...`) and an exact page path (`/blog`).
40
-
41
- **Status:** Applied to `src/defaults/dist/_includes/themes/classy/frontend/sections/footer.html`. Needs `npm run prepare` to copy to `dist/`.
42
-
43
- ## Fix 2: `uj_translation_url` Ruby tag (DONE)
44
-
45
- **File:** `jekyll-uj-powertools` gem, `lib/tags/translation_url.rb`
46
-
47
- **Current code (v1.7.9):** The `render` method generates language-prefixed URLs without checking the exclude list at all. When called with `{% uj_translation_url "es", page.url %}` on a blog post, it returns `/es/blog/my-post` regardless of whether blog is excluded.
48
-
49
- **Proposed change:** Add an exclude check in the `render` method. If the URL path matches an exclude entry, return the un-prefixed (default language) URL instead of the language-prefixed one. This is defense-in-depth — even if a template forgets to check, the tag itself won't generate dead links.
50
-
51
- ```ruby
52
- def render(context)
53
- # ... existing argument parsing ...
54
-
55
- # Get site and translation config from context
56
- site = context.registers[:site]
57
- return '/' unless site
58
-
59
- translation_config = site.config['translation'] || {}
60
- default_language = translation_config['default'] || 'en'
61
- available_languages = translation_config['languages'] || [default_language]
62
-
63
- # NEW: Check if the URL path is excluded from translation
64
- excludes = translation_config['exclude'] || []
65
- normalized_path = normalize_path(url_path)
66
- if page_excluded?(normalized_path, excludes)
67
- # Return un-prefixed URL for excluded pages
68
- return normalized_path.empty? ? '/' : "/#{normalized_path}"
69
- end
70
-
71
- # ... rest of existing logic (validate language, generate URL) ...
72
- end
73
-
74
- private
75
-
76
- # NEW: Check if a page path matches any exclude entry
77
- def page_excluded?(normalized_path, excludes)
78
- return false if excludes.empty? || normalized_path.empty?
79
-
80
- excludes.any? do |exclude|
81
- # Match as exact page path or as folder prefix
82
- normalized_path == exclude || normalized_path.start_with?("#{exclude}/")
83
- end
84
- end
85
- ```
86
-
87
- **Applied:** `jekyll-uj-powertools` v1.7.11. Version bumped in gemspec + CHANGELOG updated.
88
-
89
- ## Fix 3: Consider — strip language dropdown entirely on excluded pages
90
-
91
- The current Fix 1 still renders a language dropdown with a single "English" option on excluded pages. An alternative is to hide the dropdown entirely when the page is excluded. This is a UX call — showing a single-language dropdown is harmless but arguably useless.
92
-
93
- To hide it entirely, wrap the `<div class="dropup uj-language-dropdown">` block in:
94
- ```liquid
95
- {% unless page_excluded_from_translation and site.translation.enabled %}
96
- <!-- language dropdown markup -->
97
- {% endunless %}
98
- ```
99
-
100
- ## Verification
101
-
102
- After applying Fix 1 and rebuilding a site:
103
-
104
- 1. Visit a blog post → footer should show only "English" (or no language dropdown)
105
- 2. Visit a non-excluded page (e.g. `/pricing`) → footer should show all languages
106
- 3. View page source on a blog post → no `href="/es/blog/..."` links in footer
107
- 4. After reindexing, GA4 "Page not found" percentage should drop significantly
108
-
109
- ## Scope
110
-
111
- - Fix 1 covers ALL UJM sites (classy is the base footer for all themes)
112
- - Fix 2 covers any future template that uses `uj_translation_url` on excluded pages
113
- - The spam bot traffic (`/ar/`, `/fr/`, etc. from disabled languages) is separate — those are fabricated URLs from crawlers, not caused by UJM. A Cloudflare WAF rule can block those if desired.