You've already forked wc-bootstrap
Add constraints section documenting that the woocommerce plugin is read-only and that the Docker environment is not yet set up. Track composer.lock. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
317 lines
14 KiB
Markdown
317 lines
14 KiB
Markdown
# WooCommerce Bootstrap
|
|
|
|
**Author:** Marco Grätsch
|
|
**Author URL:** <https://src.bundespruefstelle.ch/magdev>
|
|
**Author Email:** <magdev3.0@gmail.com>
|
|
**Repository URL:** <ssh://git@src.bundespruefstelle.ch:2022/magdev/wc-bootstrap.git>
|
|
**Issues URL:** <ssh://git@src.bundespruefstelle.ch:2022/magdev/wc-bootstrap.git/issues>
|
|
|
|
## Project Overview
|
|
|
|
This child theme of wp-bootstrap (`../wp-bootstrap/` or <https://src.bundespruefstelle.ch/magdev/wp-bootstrap>) extends wp-bootstrap and adds overrides for all theme files of the WooCommerce plugin (`../../plugins/woocommerce/` or <https://github.com/woocommerce/woocommerce.git>). All theme files from the plugin are converted to Bootstrap 5 structures and styles.
|
|
|
|
## Technical Stack
|
|
|
|
- **Language:** PHP 8.3.x
|
|
- **Framework:** Latest WordPress Theme API
|
|
- **Template Engine:** Twig 3.0 (via Composer)
|
|
- **WordPress Base Theme:** wp-bootstrap
|
|
- **Frontend:** Bootstrap 5 JavaScript & Vanilla JavaScript
|
|
- **Styling:** Bootstrap 5 & Custom CSS (if necessary)
|
|
- **Dependency Management:** Composer (PHP), npm (JS/CSS)
|
|
- **Internationalization:** WordPress i18n (.pot/.po/.mo files)
|
|
|
|
### Security Best Practices
|
|
|
|
- All user inputs are sanitized (integers for quantities/prices)
|
|
- Nonce verification on form submissions
|
|
- Output escaping in templates (`esc_attr`, `esc_html`, `esc_js`)
|
|
- Direct file access prevention via `ABSPATH` check
|
|
- XSS-safe DOM construction in JavaScript (no `innerHTML` with user data)
|
|
- `json_encode|raw` in JS context is correct (not XSS) -- Twig auto-escaping would break JSON
|
|
- `styles|raw` in PDF exports is backend-generated static CSS, documented with comments
|
|
|
|
### Translation Ready
|
|
|
|
All user-facing strings use:
|
|
|
|
```php
|
|
__('Text to translate', 'wc-bootstrap')
|
|
_e('Text to translate', 'wc-bootstrap')
|
|
```
|
|
|
|
Text domain: `wc-bootstrap`
|
|
|
|
#### Text Domain Strategy
|
|
|
|
<!-- Choose ONE of these strategies based on your project needs: -->
|
|
|
|
**Option A -- Plugin domain (recommended when plugin provides Twig functions):**
|
|
All strings in theme templates use the plugin's `'woocommerce'` domain. This is necessary when the plugin registers `__()` / `_n()` as Twig functions with a default domain, because `load_child_theme_textdomain()` does not resolve at Twig render time.
|
|
|
|
**Rule:** Always use `'woocommerce'` as the text domain in all Twig templates and PHP files.
|
|
|
|
**Option B -- Theme domain (when theme handles its own Twig rendering):**
|
|
Theme templates use the theme's own `'wc-bootstrap'` domain. Ensure `load_child_theme_textdomain()` is called before Twig rendering.
|
|
|
|
#### Available Translations
|
|
|
|
<!-- List your supported locales here -->
|
|
|
|
- `en_US` -- English (base language, .pot template)
|
|
- `de_DE` -- German (Germany, formal)
|
|
- `de_CH` -- German (Switzerland, formal)
|
|
- `fr_FR` -- French (France)
|
|
|
|
Translation file naming convention: `wc-bootstrap-{locale}.po` (e.g., `wc-bootstrap-de_CH.po`)
|
|
|
|
Compiled `.mo` files are built by the CI/CD pipeline during releases. For local development:
|
|
|
|
```bash
|
|
for po in languages/wc-bootstrap-*.po; do msgfmt -o "${po%.po}.mo" "$po"; done
|
|
```
|
|
|
|
#### Updating Translations (Fast JSON Workflow)
|
|
|
|
##### Step 1 -- Regenerate `.pot` files
|
|
|
|
wp-bootstrap (PHP sources only):
|
|
|
|
```bash
|
|
docker exec woocommerce-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
|
|
```
|
|
|
|
Child theme (PHP + Twig). Use a Twig extractor script that scans `.html.twig` files for `__()`, `_e()`, `_n()`, `_x()` calls, generates `twig-extracted.pot`, then merges with WP-CLI PHP extraction:
|
|
|
|
```bash
|
|
# Inside languages/ directory:
|
|
python3 twig-extractor.py # generates twig-extracted.pot
|
|
docker exec woocommerce-wordpress wp i18n make-pot \
|
|
/var/www/html/wp-content/themes/wc-bootstrap \
|
|
/var/www/html/wp-content/themes/wc-bootstrap/languages/php-extracted.pot \
|
|
--allow-root
|
|
msgcat --use-first php-extracted.pot twig-extracted.pot \
|
|
-o wc-bootstrap.pot
|
|
rm php-extracted.pot
|
|
```
|
|
|
|
##### Step 2 -- Merge new strings into all `.po` files
|
|
|
|
```bash
|
|
for locale in de_CH de_DE fr_FR; do
|
|
msgmerge --update --backup=none --no-fuzzy-matching \
|
|
wc-bootstrap-${locale}.po wc-bootstrap.pot
|
|
done
|
|
```
|
|
|
|
##### Step 3 -- Translate and apply
|
|
|
|
Extract untranslated strings per locale into JSON, translate (via AI or manual), then apply with `languages/patch-po.py`.
|
|
|
|
German variant derivation rules:
|
|
|
|
- `de_CH` from `de_DE`: replace `ss` where Swiss German uses `ss` instead of `ß`
|
|
- `de_DE_informal` from `de_DE`: `Sie` -> `du`, `Ihr` -> `dein`, etc.
|
|
- `de_CH_informal`: combine both transformations
|
|
|
|
##### Step 4 -- Validate and compile
|
|
|
|
```bash
|
|
for po in languages/wc-bootstrap-*.po; do msgfmt --statistics "$po" -o /dev/null; done
|
|
for po in languages/wc-bootstrap-*.po; do msgfmt -o "${po%.po}.mo" "$po"; done
|
|
```
|
|
|
|
### Important Git Notes
|
|
|
|
- Default branch while development is `dev`
|
|
- Create releases from branch `main` after merging branch `dev`
|
|
- Tags should use format `vX.X.X` (e.g., `v1.1.22`), start with v0.1.0
|
|
- Use annotated tags (`-a`) not lightweight tags
|
|
- **ALWAYS push tags to origin** -- CI/CD triggers on tag push
|
|
- Commit messages should follow the established format with Claude Code attribution
|
|
- `.claude/settings.local.json` changes are typically local-only (stash before rebasing)
|
|
|
|
### CRITICAL -- Release Workflow
|
|
|
|
On every new version, ALWAYS execute this complete workflow:
|
|
|
|
```bash
|
|
# 1. Commit changes to dev branch
|
|
git add <files>
|
|
git commit -m "Description of changes (vX.X.X)"
|
|
|
|
# 2. Merge dev to main
|
|
git checkout main
|
|
git merge dev --no-edit
|
|
|
|
# 3. Create annotated tag
|
|
git tag -a vX.X.X -m "Version X.X.X - Brief description"
|
|
|
|
# 4. Push everything to origin
|
|
git push origin dev main vX.X.X
|
|
|
|
# 5. Switch back to dev for continued development
|
|
git checkout dev
|
|
```
|
|
|
|
Never skip any of these steps. The release is not complete until all branches and the tag are pushed to origin.
|
|
|
|
### CRITICAL -- Cross-Project Release Order
|
|
|
|
When a release touches both the plugin and the theme, ALWAYS release in this order:
|
|
|
|
1. **Theme first** -- full release workflow (commit -> merge -> tag -> push)
|
|
2. **Plugin second** -- update plugin's Dockerfile/config to reference the new theme version, then full release workflow
|
|
|
|
Reason: the plugin's build references the theme version. If the plugin is released first with a new theme version number, the CI build will attempt to download a theme release that does not yet exist and fail.
|
|
|
|
---
|
|
|
|
## For AI Assistants
|
|
|
|
When starting a new session on this project:
|
|
|
|
1. Read this CLAUDE.md file first
|
|
2. Semantic versioning follows the `MAJOR.MINOR.BUGFIX` pattern
|
|
3. Check git log for recent changes
|
|
4. Verify you're on the `dev` branch before making changes
|
|
5. Run `git submodule update --init --recursive` if lib/ is empty (only if submodules present)
|
|
6. Run `composer install` if vendor/ is missing
|
|
7. Test changes before committing
|
|
8. Follow commit message format with Claude Code attribution
|
|
9. Update this session history section with learnings
|
|
10. Never commit backup files (`*.po~`, `*.bak`, etc.) - check `git status` before committing
|
|
11. Follow markdown linting rules (see below)
|
|
|
|
Always refer to this document when starting work on this project.
|
|
|
|
### Markdown Linting Rules
|
|
|
|
1. **MD031**: Blank lines before and after fenced code blocks
|
|
2. **MD056**: Table separators must have matching column counts
|
|
3. **MD009**: No trailing spaces
|
|
4. **MD012**: No multiple consecutive blank lines
|
|
5. **MD040**: Fenced code blocks should have a language specified
|
|
6. **MD032**: Lists surrounded by blank lines
|
|
7. **MD034**: Bare URLs in angle brackets or markdown link syntax
|
|
8. **MD013**: Disabled (line length)
|
|
9. **MD024**: `siblings_only` mode
|
|
|
|
## Known Pitfalls & Key Learnings
|
|
|
|
Recurring bugs and non-obvious behaviours discovered across sessions. **Read this before starting any task.**
|
|
|
|
### Template Override Mechanism
|
|
|
|
- Plugin's `Template` class uses Twig `FilesystemLoader`. The `inc/TemplateOverride.php` hooks `init` at priority 20 (after plugin init at 0) and uses `prependPath()` to give child theme templates priority.
|
|
- Plugin templates in `../../plugins/woocommerce/templates/` are overridden by matching files in `templates/`.
|
|
|
|
### Twig Compatibility
|
|
|
|
- **`|values` filter does NOT exist in Twig 3.x** -- use loop-based sum instead. Twig 4.x only.
|
|
- **Twig autoescape + WordPress escape filters = double encoding** -- register all `esc_*` filters with `['is_safe' => ['html']]` option in the plugin's `Template.php`.
|
|
- **`wp i18n make-pot` does NOT scan Twig templates** -- any string used exclusively in `.html.twig` files must be manually added to the `.pot` file.
|
|
- **`#, fuzzy` silently skips translations at runtime** -- always remove fuzzy flags after verifying translations.
|
|
|
|
### Bootstrap 5 vs Plugin CSS Conflicts
|
|
|
|
- Plugin CSS may define its own grid systems that override Bootstrap's flexbox `row row-cols-*`. Add theme CSS overrides as needed.
|
|
- **CSS dependency chain**: `woocommerce` -> child theme overrides. Ensures correct cascade.
|
|
- jQuery `.show()`/`.hide()` cannot override Bootstrap `!important` (`d-none`). Toggle both class and inline style.
|
|
- `overflow: visible !important` on `.wp-block-navigation__container` is essential for dropdowns inside block theme navigation.
|
|
|
|
### Double Heading Prevention
|
|
|
|
- Parent theme (`wp-bootstrap`) conditionally skips its `<h1>` when `post.title` is empty.
|
|
- Plugin passes empty `post.title` to parent theme's Twig system.
|
|
- Child theme layout templates always render their own `<h1>` with `page_title` context.
|
|
|
|
### Theme Wrapping (`_wrapped` / `_theme_wrapped`)
|
|
|
|
- `_wrapped` is set in `base.html.twig` when `_theme_wrapped` is true (parent theme provides page shell).
|
|
- **Structural blocks** (wrapper, breadcrumbs, sidebar, `<h1>`) are suppressed when wrapped.
|
|
- **Functional blocks** (`{% block scripts %}`) must ALWAYS render -- they contain AJAX handlers, JS initialization etc.
|
|
|
|
### Plugin JS Compatibility
|
|
|
|
- Theme must preserve plugin's JS-bound CSS class names (e.g., repeater fields, interactive widgets).
|
|
- Theme uses plugin's global JS objects for AJAX URLs, nonces, and i18n strings.
|
|
- Bootstrap 5 `data-bs-toggle` attributes replace plugin's custom dropdown mechanisms.
|
|
|
|
### Security
|
|
|
|
- Security audit checklist (OWASP Top-10): open redirect validation, `|esc_url`/`|esc_attr`/`|esc_js` on all dynamic output, `|wp_kses_post` for rich text, no `innerHTML` with dynamic data.
|
|
|
|
## Multi-Project Architecture
|
|
|
|
This child theme is part of a three-project ecosystem. Each project is a separate git repo with its own `CLAUDE.md` and should be worked on in **separate Claude Code sessions**.
|
|
|
|
### Projects
|
|
|
|
| Project | Type | Location | Repository |
|
|
| ------- | ---- | -------- | ---------- |
|
|
| woocommerce | Plugin (read-only) | `wp-content/plugins/woocommerce/` | <https://github.com/woocommerce/woocommerce.git> |
|
|
| wp-bootstrap | Parent Theme | `wp-content/themes/wp-bootstrap/` | <https://src.bundespruefstelle.ch/magdev/wp-bootstrap> |
|
|
| wc-bootstrap | Child Theme | `wp-content/themes/wc-bootstrap/` | <ssh://git@src.bundespruefstelle.ch:2022/magdev/wc-bootstrap.git> |
|
|
|
|
### Dependency Chain
|
|
|
|
```txt
|
|
wp-bootstrap (parent theme, Bootstrap 5 FSE + Twig rendering)
|
|
+-- wc-bootstrap (child theme, overrides plugin Twig templates with Bootstrap 5)
|
|
+-- woocommerce (plugin, provides post types, logic, base Twig templates)
|
|
```
|
|
|
|
### Important Constraints
|
|
|
|
- **WooCommerce plugin is read-only.** We have no control over its source code. All customizations happen in the child theme via template overrides and hooks.
|
|
- **Docker environment is not yet set up.** Commands referencing `docker exec` (e.g., in the translation workflow) are not currently available. Local alternatives or manual steps must be used until the container is configured.
|
|
|
|
### Cross-Project Workflow
|
|
|
|
1. **One session per project.** Each session reads its own `CLAUDE.md` and stays within its own git repo.
|
|
2. **Plugin changes first.** When a change affects templates consumed by the theme, make the plugin change first, then switch to the theme session.
|
|
3. **Communicate changes explicitly.** When switching sessions, describe what changed upstream (new variables, renamed classes, new templates, etc.).
|
|
4. **Shared Docker environment.** All three projects will be bind-mounted into the same Docker container once it is set up, so changes will be visible live without rebuilds.
|
|
|
|
### Template Contract (Plugin -> Theme)
|
|
|
|
The child theme overrides plugin Twig templates by prepending its own `templates/` directory to the Twig `FilesystemLoader` via `TemplateOverride` class (hooks `init` priority 20, after plugin init at priority 0).
|
|
|
|
#### Twig Template Locations
|
|
|
|
- **Plugin base templates:** `wp-content/plugins/woocommerce/templates/`
|
|
- **Theme overrides:** `wp-content/themes/wc-bootstrap/templates/` (mirrors plugin structure)
|
|
- **Resolution order:** Theme templates take priority over plugin templates (Twig `prependPath`)
|
|
|
|
### Theme Contract (Parent -> Child)
|
|
|
|
The child theme inherits from `wp-bootstrap` via WordPress `Template: wp-bootstrap` declaration.
|
|
|
|
- **Bootstrap 5:** CSS framework and JS loaded by parent theme
|
|
- **Bootstrap Icons:** Web font available via parent theme's SCSS build
|
|
- **Twig rendering:** Parent theme's `TwigService` handles frontend rendering
|
|
- **Dark mode:** Parent handles via `data-bs-theme` attribute; child theme inherits
|
|
- **Style variations:** Color palettes available from parent, bridged to Bootstrap CSS custom properties
|
|
|
|
## Architecture Decisions
|
|
|
|
- **Edit forms** use 3+9 column layout: `col-lg-3` sticky sidebar (progress indicator, section nav) + `col-lg-9` card-based sections.
|
|
- **Detail pages** use 8+4 column layout with sticky sidebar.
|
|
- **Cards** use `<article class="card h-100">` with `stretched-link`.
|
|
- **Form layout** uses centered `col-lg-8 col-xl-7` with card + shadow for auth forms.
|
|
- **Mobile patterns**: offcanvas for search filters; navbar uses Bootstrap `offcanvas-lg` responsive pattern.
|
|
- **Email templates**: use custom CSS class prefix (not Bootstrap) to avoid email client conflicts.
|
|
- **PDF exports**: inline styles aligned with Bootstrap color palette (no external CSS in PDF renderers).
|
|
|
|
## Version History
|
|
|
|
Current version: **v0.1.0**
|
|
|
|
## Session History
|
|
|
|
<!-- AI assistants: document key learnings and session outcomes here -->
|