# WordPress Theme using Bootstrap 5 **Author:** Marco Graetsch **Author URL:** **Author Email:** **Repository URL:** **Issues URL:** ## Project Overview This WordPress-Theme is built from scratch employing Bootstrap 5. Build modern Websites using the state-of-the-art Framework. All basic WordPress components are converted and are fully working. The theme uses Twig for rendering. It is also a good starting point as base theme for complex WordPress websites. ### Features - [ ] All native WordPress theme files converted to Boostrap 5 - [ ] Works seemlessly on default WordPress installations - [ ] Installable via WordPress admin #### Frontend - [ ] Fully responsive Design - [ ] Supports darkmode #### Administration - [ ] Compatible with the Gutenberg-Editor - [ ] Customizable with the Design-Editor ### Key Fact: 100% AI-Generated This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase was created through AI assistance. ## Temporary Roadmap **Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file. Current version is **v0.1.1** - Bootstrap Frontend Rendering. Next milestone is **v0.2.0 - Design Editor**. See `PLAN.md` for details. ## Technical Stack - **Language:** PHP 8.3.x - **PHP-Standards:** PSR-4 - **Framework:** Latest WordPress Theme API - **Template Engine:** Twig 3.0 (via Composer) - **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) - **Canonical Plugin Name:** `wp-bootstrap` ### 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) ### Translation Ready All user-facing strings use: ```php __('Text to translate', 'wp-bootstrap') _e('Text to translate', 'wp-bootstrap') ``` Text domain: `wp-bootstrap` #### Translation Template - Base `.pot` file created: `languages/wp-bootstrap.pot` - Ready for translation to any locale - All translatable strings properly marked with text domain #### Available Translations - `en_US` - English (United States) [base language - .pot template] - `de_CH` - German (Switzerland, formal) There is no need to compile translation to *.mo locally as it will be done in the Gitea CD/CI pipeline ### Create Releases **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 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. --- **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 When editing CLAUDE.md or other markdown files, follow these rules to avoid linting errors: 1. **MD031 - Blank lines around fenced code blocks**: Always add a blank line before and after fenced code blocks, even when they follow list items. Example of correct format: - **Item label**: (blank line here) \`\`\`php code example \`\`\` (blank line here) 2. **MD056 - Table column count**: Table separators must have matching column counts and proper spacing. Use consistent dash lengths that match column header widths. 3. **MD009 - No trailing spaces**: Remove trailing whitespace from lines 4. **MD012 - No multiple consecutive blank lines**: Use only single blank lines between sections 5. **MD040 - Fenced code blocks should have a language specified**: Always add a language identifier to code blocks (e.g., `txt`, `bash`, `php`). For shortcode examples, use `txt`. 6. **MD032 - Lists should be surrounded by blank lines**: Add a blank line before AND after list blocks, including after bold labels like `**Attributes:**`. 7. **MD034 - Bare URLs**: Wrap URLs in angle brackets (e.g., ``) or use markdown link syntax `[text](url)`. 8. **Author section formatting**: Use a heading (`### Name`) instead of bold (`**Name**`) for the author name to maintain consistent document structure. ### Build Pipeline The build uses npm scripts defined in `package.json`: ```bash # Full build (CI and local) npm run build # Development watch mode npm run dev ``` Build steps (in order): 1. `copy:js` — Copy Bootstrap JS bundle from `node_modules` to `assets/js/` 2. `copy:theme-js` — Copy theme JS (e.g., `dark-mode.js`) from `src/js/` to `assets/js/` 3. `scss` — Compile SCSS (`src/scss/`) to CSS (`assets/css/`) 4. `postcss` — Autoprefixer + cssnano minification → `assets/css/style.min.css` **CI/CD note:** The Gitea workflow uses `npm install` and `npm run build`. ### Architecture Notes - **Dark mode:** Uses Bootstrap 5.3 `data-bs-theme` attribute on ``. An inline anti-flash script runs synchronously in `` (via `wp_add_inline_script` with `'before'`), while the full `dark-mode.js` is deferred. Preference stored in `localStorage` key `wp-bootstrap-theme`. - **Block styles:** Registered via `register_block_style()` with `inline_style` parameter in `functions.php`. Dark mode overrides for alert/card styles are in `src/scss/_custom.scss`. - **Style variations:** JSON files in `styles/` directory. All 4 variations use the same 10 color slug names (base, contrast, primary, secondary, success, danger, warning, info, light, dark) to ensure patterns work across all schemes. - **Fonts:** Inter (sans-serif) and Lora (serif) variable fonts bundled as `.woff2` in `assets/fonts/`. Declared via `fontFace` in `theme.json` with `font-display: swap`. - **Patterns:** PHP files in `patterns/` with WordPress block markup and i18n. Hidden patterns (prefixed `hidden-`) are reusable components not shown in the pattern inserter. - **Twig frontend rendering:** `TemplateController` hooks `template_redirect` to intercept frontend requests and render Bootstrap 5 HTML via Twig, bypassing FSE block markup. FSE templates remain for the Site Editor. WordPress functions that produce output (`wp_head`, `wp_footer`, `body_class`, `language_attributes`) are captured via `ob_start()`/`ob_get_clean()` and passed to Twig as safe HTML strings. - **Navigation menus:** `NavWalker` converts flat `wp_get_nav_menu_items()` into a nested tree for Bootstrap dropdown rendering. Falls back to listing published pages when no menu is assigned. - **Docker development:** WordPress runs in Docker container `jobroom-wordpress`. The theme directory must be bind-mounted via `compose.override.yaml` (absolute path) for live changes to be visible. ## Session History ### Session 3 — v0.1.1 Bootstrap Frontend Rendering (2026-02-08) **Completed:** Full Twig-based Bootstrap 5 frontend rendering, replacing FSE block markup on the public-facing site. **What was built:** - `TemplateController` class hooking `template_redirect` to render Twig templates for all page types - `ContextBuilder` class gathering WordPress data (posts, menus, pagination, comments, sidebar, archive info) into structured arrays - `NavWalker` class converting flat menu items to nested tree for Bootstrap dropdown menus - 20 Twig templates: base layout, 5 page templates (index, single, page, archive, search, 404), 9 partials (header, footer, pagination, sidebar, comments, search form, dark mode toggle, meta, post navigation), 3 components (post card, grid card, post loop) - Enhanced `TwigService` with WordPress output-buffering functions, globals, and filters - Navigation menu locations (primary, footer) with pages fallback - Comment form Bootstrap styling filter - README.md project documentation **Key learnings:** - `template_redirect` + `exit()` cleanly bypasses FSE rendering on frontend while preserving Site Editor functionality - WordPress functions that produce output (`wp_head`, `wp_footer`, `body_class`, `language_attributes`) must be captured via `ob_start()`/`ob_get_clean()` for use in Twig, and marked with `is_safe => html` - With `optimize-autoloader: true` in `composer.json`, new PSR-4 classes require `composer dump-autoload` to regenerate the static classmap - Docker bind mounts require absolute paths in `compose.override.yaml` -- relative paths create empty directories - Post content is rendered via `apply_filters('the_content', get_the_content())` which processes Gutenberg blocks into standard HTML that Bootstrap CSS handles natively ### Session 2 — v0.1.0 Core Theme (2026-02-08) **Completed:** Full v0.1.0 milestone implementation. **What was built:** - 16 block patterns across 7 new categories (hero, features, CTA, testimonials, pricing, contact, text) - Dark mode toggle with SVG sun/moon icons, localStorage persistence, `prefers-color-scheme` detection - 17 custom block styles mapping Bootstrap components to WordPress blocks - 4 style variations: Ocean, Forest, Sunset, Midnight - Sidebar template part + "Blog with Sidebar" custom template - Inter + Lora variable web fonts with Display font size **Key learnings:** - CI uses `npm install` / `npm run build` — `yarn` is not available in the CI runner - Bootstrap 5 alert colors are hardcoded (not CSS variables), so explicit dark mode overrides are needed in SCSS - Anti-flash for dark mode requires a synchronous inline script via `wp_add_inline_script('handle', '...', 'before')` — the deferred JS alone causes a flash - Variable fonts use `fontWeight: "100 900"` range syntax in `theme.json` `fontFace` declarations - Style variation JSON files must maintain identical color slug names across all variations for patterns to work correctly - When re-tagging a release, delete the remote tag first (`git push origin :refs/tags/vX.X.X`) then recreate and push ### Session 1 — v0.0.1 Getting Started (2026-02-08) **Completed:** Initial theme scaffolding, Bootstrap 5 integration, SASS pipeline, Twig setup, CI/CD workflow, basic FSE templates and patterns, i18n support.