Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0902c5e1a5 | ||
|
|
1a0a1fa63a |
No files matched your search
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [1.0.10] - 2026-02-25
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Title double-encoding in Twig templates** (`inc/Template/ContextBuilder.php`): WordPress's `get_the_title()` pre-encodes `&` as `&`. When passed to Twig with autoescape enabled, the `&` in `&` was escaped again to `&`, rendering as literal `&` in the browser (e.g. "Bewerbungen & Nachrichten" instead of "Bewerbungen & Nachrichten"). Fixed by wrapping all 6 `get_the_title()` calls with `wp_specialchars_decode()` to decode WordPress entities before Twig. Twig autoescape then properly re-encodes `&` → `&`. This is XSS-safe because Twig still escapes all output.
|
||||||
|
|
||||||
## [1.0.9] - 2026-02-19
|
## [1.0.9] - 2026-02-19
|
||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
|
|||||||
@@ -98,6 +98,29 @@ Compiled .mo files are built by the Gitea CI/CD pipeline during releases. For lo
|
|||||||
for po in languages/wp-bootstrap-*.po; do msgfmt -o "${po%.po}.mo" "$po"; done
|
for po in languages/wp-bootstrap-*.po; do msgfmt -o "${po%.po}.mo" "$po"; done
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Updating Translations
|
||||||
|
|
||||||
|
When new strings are added to PHP sources, use the fast JSON workflow documented in
|
||||||
|
`wp-jobroom-theme/CLAUDE.md → Updating Translations (Fast JSON Workflow)`. That
|
||||||
|
document contains the full step-by-step process including the `patch-po.py` patcher script
|
||||||
|
(located in `wp-jobroom-theme/languages/patch-po.py`) which patches **both** `wp-bootstrap`
|
||||||
|
and `wp-jobroom-theme` `.po` files in a single pass.
|
||||||
|
|
||||||
|
**Quick reference for wp-bootstrap POT regeneration:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec jobroom-wordpress wp i18n make-pot \
|
||||||
|
/var/www/html/wp-content/themes/wp-bootstrap \
|
||||||
|
/var/www/html/wp-content/themes/wp-bootstrap/languages/wp-bootstrap.pot \
|
||||||
|
--allow-root
|
||||||
|
|
||||||
|
# Then merge into all .po files:
|
||||||
|
for locale in de_CH de_CH_informal de_DE de_DE_informal en_GB es_ES fr_CH fr_FR it_CH it_IT nl_NL pl_PL pt_PT; do
|
||||||
|
msgmerge --update --backup=none --no-fuzzy-matching \
|
||||||
|
languages/wp-bootstrap-${locale}.po languages/wp-bootstrap.pot
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
### Create Releases
|
### Create Releases
|
||||||
|
|
||||||
**Important Git Notes:**
|
**Important Git Notes:**
|
||||||
@@ -211,6 +234,20 @@ Build steps (in order):
|
|||||||
|
|
||||||
## Session History
|
## Session History
|
||||||
|
|
||||||
|
### Session 16 — v1.0.10 Title Double-Encoding Fix (2026-02-25)
|
||||||
|
|
||||||
|
**Completed:** Fixed double-encoding of HTML entities in page titles rendered through Twig.
|
||||||
|
|
||||||
|
**Root cause:** WordPress's `get_the_title()` returns titles with HTML entities pre-encoded (e.g. `&` → `&`). `ContextBuilder` passed these pre-encoded strings to Twig as template variables. Twig's autoescape then re-encoded the `&` in `&` to `&`, which browsers rendered as the literal text `&` instead of `&`. Affected all pages with `&` in their title (e.g. help pages "Bewerbungen & Nachrichten", "Konto & Sicherheit", "Abonnements & Abrechnung").
|
||||||
|
|
||||||
|
**Fix:** Wrapped all 6 `get_the_title()` calls in `ContextBuilder.php` with `wp_specialchars_decode()`. This decodes WordPress entities back to raw characters before Twig, allowing Twig autoescape to properly encode them once. XSS-safe because Twig still escapes all output.
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- `inc/Template/ContextBuilder.php` — `wp_specialchars_decode()` on all 6 `get_the_title()` calls
|
||||||
|
- `style.css` — version bump to 1.0.10
|
||||||
|
- `CHANGELOG.md` — v1.0.10 entry
|
||||||
|
|
||||||
### Session 15 — v1.0.9 Performance Optimization (2026-02-19)
|
### Session 15 — v1.0.9 Performance Optimization (2026-02-19)
|
||||||
|
|
||||||
**Completed:** Two targeted performance fixes for production environments.
|
**Completed:** Two targeted performance fixes for production environments.
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ class ContextBuilder
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $post->ID,
|
'id' => $post->ID,
|
||||||
'title' => get_the_title(),
|
'title' => wp_specialchars_decode( get_the_title() ),
|
||||||
'url' => get_permalink(),
|
'url' => get_permalink(),
|
||||||
'content' => apply_filters('the_content', get_the_content()),
|
'content' => apply_filters('the_content', get_the_content()),
|
||||||
'excerpt' => get_the_excerpt(),
|
'excerpt' => get_the_excerpt(),
|
||||||
@@ -184,7 +184,7 @@ class ContextBuilder
|
|||||||
$wp_query->the_post();
|
$wp_query->the_post();
|
||||||
$posts[] = [
|
$posts[] = [
|
||||||
'id' => get_the_ID(),
|
'id' => get_the_ID(),
|
||||||
'title' => get_the_title(),
|
'title' => wp_specialchars_decode( get_the_title() ),
|
||||||
'url' => get_permalink(),
|
'url' => get_permalink(),
|
||||||
'excerpt' => get_the_excerpt(),
|
'excerpt' => get_the_excerpt(),
|
||||||
'date' => get_the_date(),
|
'date' => get_the_date(),
|
||||||
@@ -349,14 +349,14 @@ class ContextBuilder
|
|||||||
|
|
||||||
if ($prev) {
|
if ($prev) {
|
||||||
$navigation['previous'] = [
|
$navigation['previous'] = [
|
||||||
'title' => get_the_title($prev),
|
'title' => wp_specialchars_decode( get_the_title($prev) ),
|
||||||
'url' => get_permalink($prev),
|
'url' => get_permalink($prev),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($next) {
|
if ($next) {
|
||||||
$navigation['next'] = [
|
$navigation['next'] = [
|
||||||
'title' => get_the_title($next),
|
'title' => wp_specialchars_decode( get_the_title($next) ),
|
||||||
'url' => get_permalink($next),
|
'url' => get_permalink($next),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,7 @@ class ContextBuilder
|
|||||||
$query->the_post();
|
$query->the_post();
|
||||||
$posts[] = [
|
$posts[] = [
|
||||||
'id' => get_the_ID(),
|
'id' => get_the_ID(),
|
||||||
'title' => get_the_title(),
|
'title' => wp_specialchars_decode( get_the_title() ),
|
||||||
'url' => get_permalink(),
|
'url' => get_permalink(),
|
||||||
'date' => get_the_date(),
|
'date' => get_the_date(),
|
||||||
'date_iso' => get_the_date('c'),
|
'date_iso' => get_the_date('c'),
|
||||||
@@ -438,7 +438,7 @@ class ContextBuilder
|
|||||||
while ($query->have_posts()) {
|
while ($query->have_posts()) {
|
||||||
$query->the_post();
|
$query->the_post();
|
||||||
$posts[] = [
|
$posts[] = [
|
||||||
'title' => get_the_title(),
|
'title' => wp_specialchars_decode( get_the_title() ),
|
||||||
'url' => get_permalink(),
|
'url' => get_permalink(),
|
||||||
'date' => get_the_date(),
|
'date' => get_the_date(),
|
||||||
];
|
];
|
||||||
|
|||||||
+1816
-792
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1817
-791
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1729
-765
File diff suppressed because it is too large.
Load diff
+1770
-790
File diff suppressed because it is too large.
Load diff
+1822
-790
File diff suppressed because it is too large.
Load diff
+1776
-790
File diff suppressed because it is too large.
Load diff
+1802
-790
File diff suppressed because it is too large.
Load diff
+1802
-790
File diff suppressed because it is too large.
Load diff
+1766
-790
File diff suppressed because it is too large.
Load diff
+1786
-792
File diff suppressed because it is too large.
Load diff
+1772
-790
File diff suppressed because it is too large.
Load diff
+1592
-706
File diff suppressed because it is too large.
Load diff
@@ -7,7 +7,7 @@ Description: A modern WordPress Block Theme built from scratch with Bootstrap 5.
|
|||||||
Requires at least: 6.7
|
Requires at least: 6.7
|
||||||
Tested up to: 6.7
|
Tested up to: 6.7
|
||||||
Requires PHP: 8.3
|
Requires PHP: 8.3
|
||||||
Version: 1.0.9
|
Version: 1.0.10
|
||||||
License: GNU General Public License v2 or later
|
License: GNU General Public License v2 or later
|
||||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||||
Text Domain: wp-bootstrap
|
Text Domain: wp-bootstrap
|
||||||
|
|||||||
Reference in new issue
Block a user