Initial theme scaffolding (v0.0.1)

- Bootstrap 5 CSS/JS integration via Yarn (served locally)
- Dart Sass build pipeline with PostCSS, Autoprefixer, cssnano
- Twig 3.0 via Composer with PSR-4 autoloading
- FSE block theme templates (index, home, single, page, archive, search, 404)
- Template parts (header, footer) and block patterns
- theme.json with Bootstrap 5-aligned design tokens
- Gitea CI/CD workflow for automated release packages
- WordPress i18n support (en_US base, de_CH translation)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-02-08 02:25:33 +01:00
commit d7415b9747
51 changed files with 15596 additions and 0 deletions

12
.editorconfig Normal file
View File

@@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false

View File

@@ -0,0 +1,261 @@
name: Create Release Package
on:
push:
tags:
- 'v*'
jobs:
lint:
name: PHP Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, xml, zip
tools: composer:v2
- name: PHP Syntax Check
run: |
find . -name "*.php" -not -path "./vendor/*" -not -path "./node_modules/*" -print0 | xargs -0 -n1 php -l
build-release:
name: Build Release
runs-on: ubuntu-latest
needs: [lint]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, xml, zip, intl, gettext
tools: composer:v2
- name: Get version from tag
id: version
run: |
VERSION=${GITHUB_REF_NAME#v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Building version: $VERSION"
- name: Install Node dependencies
run: yarn install --frozen-lockfile
- name: Build assets
run: yarn build
- name: Validate composer.json
run: composer validate --no-check-lock --no-check-all
- name: Install Composer dependencies (production)
run: |
composer config platform.php 8.3.0
composer install --no-dev --optimize-autoloader --no-interaction
- name: Install gettext
run: apt-get update && apt-get install -y gettext
- name: Compile translations
run: |
for po in languages/*.po; do
if [ -f "$po" ]; then
mo="${po%.po}.mo"
echo "Compiling $po to $mo"
msgfmt -o "$mo" "$po"
fi
done
- name: Verify theme version matches tag
run: |
THEME_VERSION=$(grep -oP "Version:\s*\K[0-9]+\.[0-9]+\.[0-9]+" style.css | head -1)
TAG_VERSION=${{ steps.version.outputs.version }}
if [ "$THEME_VERSION" != "$TAG_VERSION" ]; then
echo "Error: Theme version ($THEME_VERSION) does not match tag version ($TAG_VERSION)"
exit 1
fi
echo "Version verified: $THEME_VERSION"
- name: Create release directory
run: mkdir -p releases
- name: Build release package
run: |
VERSION=${{ steps.version.outputs.version }}
THEME_NAME="wp-bootstrap"
RELEASE_FILE="releases/${THEME_NAME}-${VERSION}.zip"
cd ..
zip -r "${THEME_NAME}/${RELEASE_FILE}" "${THEME_NAME}" \
-x "${THEME_NAME}/.git/*" \
-x "${THEME_NAME}/.gitea/*" \
-x "${THEME_NAME}/.github/*" \
-x "${THEME_NAME}/.vscode/*" \
-x "${THEME_NAME}/.claude/*" \
-x "${THEME_NAME}/CLAUDE.md" \
-x "${THEME_NAME}/PLAN.md" \
-x "${THEME_NAME}/wp-core" \
-x "${THEME_NAME}/wp-core/*" \
-x "${THEME_NAME}/releases/*" \
-x "${THEME_NAME}/node_modules/*" \
-x "${THEME_NAME}/src/*" \
-x "${THEME_NAME}/package.json" \
-x "${THEME_NAME}/yarn.lock" \
-x "${THEME_NAME}/composer.json" \
-x "${THEME_NAME}/composer.lock" \
-x "${THEME_NAME}/.gitignore" \
-x "${THEME_NAME}/.editorconfig" \
-x "${THEME_NAME}/*.log" \
-x "${THEME_NAME}/*.po~" \
-x "${THEME_NAME}/*.bak" \
-x "${THEME_NAME}/views/.gitkeep" \
-x "${THEME_NAME}/assets/images/.gitkeep" \
-x "*.DS_Store"
cd "${THEME_NAME}"
echo "Created: ${RELEASE_FILE}"
ls -lh "${RELEASE_FILE}"
- name: Generate checksums
run: |
VERSION=${{ steps.version.outputs.version }}
THEME_NAME="wp-bootstrap"
cd releases
sha256sum "${THEME_NAME}-${VERSION}.zip" > "${THEME_NAME}-${VERSION}.zip.sha256"
echo "SHA256:"
cat "${THEME_NAME}-${VERSION}.zip.sha256"
- name: Verify package structure
run: |
set +o pipefail
VERSION=${{ steps.version.outputs.version }}
THEME_NAME="wp-bootstrap"
echo "Package contents (first 50 entries):"
unzip -l "releases/${THEME_NAME}-${VERSION}.zip" | head -50 || true
# Verify main style.css file exists
if unzip -l "releases/${THEME_NAME}-${VERSION}.zip" | grep -q "${THEME_NAME}/style.css"; then
echo "Main style.css file: OK"
else
echo "ERROR: Main style.css file not found!"
exit 1
fi
# Verify vendor directory included
if unzip -l "releases/${THEME_NAME}-${VERSION}.zip" | grep -q "${THEME_NAME}/vendor/"; then
echo "Vendor directory: OK"
else
echo "ERROR: Vendor directory not found!"
exit 1
fi
# Verify assets directory included
if unzip -l "releases/${THEME_NAME}-${VERSION}.zip" | grep -q "${THEME_NAME}/assets/"; then
echo "Assets directory: OK"
else
echo "ERROR: Assets directory not found!"
exit 1
fi
# Verify node_modules excluded
if unzip -l "releases/${THEME_NAME}-${VERSION}.zip" | grep -q "${THEME_NAME}/node_modules/"; then
echo "WARNING: node_modules/ directory should be excluded"
exit 1
else
echo "node_modules/ excluded: OK"
fi
# Verify src excluded
if unzip -l "releases/${THEME_NAME}-${VERSION}.zip" | grep -q "${THEME_NAME}/src/"; then
echo "WARNING: src/ directory should be excluded"
exit 1
else
echo "src/ excluded: OK"
fi
- name: Extract changelog for release notes
id: changelog
run: |
VERSION=${{ steps.version.outputs.version }}
NOTES=$(sed -n "/^## \[${VERSION}\]/,/^## \[/p" CHANGELOG.md | sed '$ d' | tail -n +2)
if [ -z "$NOTES" ]; then
NOTES="Release version ${VERSION}"
fi
echo "$NOTES" > release_notes.txt
echo "Release notes extracted"
- name: Create Gitea Release
env:
GITEA_TOKEN: ${{ secrets.SRC_GITEA_TOKEN }}
run: |
VERSION=${{ steps.version.outputs.version }}
TAG_NAME=${{ github.ref_name }}
THEME_NAME="wp-bootstrap"
PRERELEASE="false"
if [[ "$TAG_NAME" == *-* ]] || [[ "$VERSION" == 0.* ]]; then
PRERELEASE="true"
fi
BODY=$(cat release_notes.txt)
# Check if release already exists and delete it
EXISTING_RELEASE=$(curl -s \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG_NAME}")
EXISTING_ID=$(echo "$EXISTING_RELEASE" | jq -r '.id // empty')
if [ -n "$EXISTING_ID" ] && [ "$EXISTING_ID" != "null" ]; then
echo "Deleting existing release ID: $EXISTING_ID"
curl -s -X DELETE \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${EXISTING_ID}"
echo "Existing release deleted"
fi
# Create release via Gitea API
RELEASE_RESPONSE=$(curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"tag_name\": \"${TAG_NAME}\", \"name\": \"WP Bootstrap ${VERSION}\", \"body\": $(echo "$BODY" | jq -Rs .), \"draft\": false, \"prerelease\": ${PRERELEASE}}" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases")
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id')
if [ "$RELEASE_ID" == "null" ] || [ -z "$RELEASE_ID" ]; then
echo "Failed to create release:"
echo "$RELEASE_RESPONSE"
exit 1
fi
echo "Created release ID: $RELEASE_ID"
# Upload release assets
for file in "releases/${THEME_NAME}-${VERSION}.zip" "releases/${THEME_NAME}-${VERSION}.zip.sha256"; do
if [ -f "$file" ]; then
FILENAME=$(basename "$file")
echo "Uploading $FILENAME..."
curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/octet-stream" \
--data-binary "@$file" \
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=${FILENAME}"
echo "Uploaded $FILENAME"
fi
done
echo "Release created: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${TAG_NAME}"

29
.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
# Symlinks
wp-core
# Dependencies
node_modules/
vendor/
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Yarn
yarn-error.log
# Backup files
*.bak
*.po~
# Claude local settings
.claude/settings.local.json
# Build artifacts (releases directory)
releases/

19
CHANGELOG.md Normal file
View File

@@ -0,0 +1,19 @@
# Changelog
All notable changes to this project will be documented in this file.
## [0.0.1] - 2026-02-08
### Added
- Initial theme scaffolding
- Bootstrap 5 CSS and JS integration (served locally via Yarn)
- SASS build pipeline with Dart Sass, PostCSS, Autoprefixer, cssnano
- Twig 3.0 template engine integration via Composer
- FSE templates: index, home, single, page, archive, search, 404
- Template parts: header, footer
- Block patterns: header, footer, query loop, comments, post navigation, more posts, 404, search, blog heading, written by
- `theme.json` with Bootstrap 5-aligned design tokens (colors, typography, spacing)
- WordPress i18n support with `en_US` (base) and `de_CH` translations
- Gitea CI/CD workflow for automated release packages
- Editor styles for block editor compatibility

172
CLAUDE.md Normal file
View File

@@ -0,0 +1,172 @@
# WordPress Theme using Bootstrap 5
**Author:** Marco Graetsch
**Author URL:** <https://src.bundespruefstelle.ch/magdev>
**Author Email:** <magdev3.0@gmail.com>
**Repository URL:** <https://src.bundespruefstelle.ch/magdev/wp-bootstrap>
**Issues URL:** <https://src.bundespruefstelle.ch/magdev/wp-bootstrap/issues>
## 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.
### Getting started (v0.0.1)
- [ ] Create a new Theme, use `wp-core/wp-content/themes/twentytwentyfive/` as blueprint (but not as base-theme, we're building from scratch!).
- [ ] Include Bootstrap 5 (CSS/JS) (serve locally, not from CDN, use Yarn for install).
- [ ] Use SASS as Stylesheet language, use node-sass for compilation.
- [ ] Integrate custom stylesheets using SASS.
- [ ] Add Gitea CI/CD workflow to create WordPress compatible release packages. Perform as much as possible build tasks in the workflow.
- [ ] Create `PLAN.md` with a comprhensive plan to create the custom theme.
- [ ] Create `README.md` with current information.
- [ ] Create `CHANGELOG.md` with initial information
- [ ] Commit to `main` and `dev`, but don't tag yet. Push to `origin`.
Planning is moved to `PLAN.md`
## 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), Yarn (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 <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.
---
**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., `<https://example.com>`) 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.

99
PLAN.md Normal file
View File

@@ -0,0 +1,99 @@
# WP Bootstrap - Development Plan
## Project Vision
WP Bootstrap is a modern WordPress Block Theme built from scratch with Bootstrap 5. It provides a clean, responsive foundation for WordPress websites using the Full Site Editing (FSE) architecture with Bootstrap's design system.
## Architecture
### Theme Type
Full Site Editing (FSE) Block Theme following the WordPress 6.x template hierarchy:
- **Templates** (`templates/`): HTML files with WordPress block markup
- **Template Parts** (`parts/`): Reusable header/footer components
- **Patterns** (`patterns/`): PHP files with block markup and i18n support
- **Design Tokens** (`theme.json`): Colors, typography, spacing mapped to Bootstrap 5
### Technology Stack
- **PHP 8.3+** with PSR-4 autoloading
- **Twig 3.0** via Composer for custom block rendering
- **Bootstrap 5.3+** CSS & JS served locally
- **Dart Sass** for SCSS compilation
- **PostCSS** with Autoprefixer and cssnano for production CSS
### Build Pipeline
```txt
src/scss/style.scss → sass → assets/css/style.css → postcss → assets/css/style.min.css
src/scss/editor-style.scss → sass → assets/css/editor-style.css
node_modules/bootstrap/dist/js/ → copyfiles → assets/js/bootstrap.bundle.min.js
```
## Version Roadmap
### v0.0.1 - Getting Started (Current)
- Theme scaffolding and project setup
- Bootstrap 5 CSS/JS integration
- SASS build pipeline
- Basic FSE templates and patterns
- Twig infrastructure
- Gitea CI/CD workflow
- i18n support (en_US, de_CH)
### v0.1.0 - Core Theme
- Complete set of block patterns
- Dark mode toggle implementation
- Custom block styles for Bootstrap components
- Style variations (color schemes)
- Sidebar template part
- Enhanced typography settings
### v0.2.0 - Design Editor
- Full Design Editor compatibility
- Custom block categories
- Page-level patterns and templates
- Enhanced header/footer variations
- Custom navigation styles
### v0.3.0 - Polish
- Performance optimization (selective Bootstrap imports)
- Accessibility audit and fixes
- RTL language support
- Additional translations
- Documentation
### v1.0.0 - Release
- All features complete and tested
- WordPress.org theme review compliance
- Comprehensive documentation
- Full test coverage
## Bootstrap 5 Integration Strategy
### CSS
Bootstrap SCSS is imported into the theme's build pipeline with variable overrides applied before import. The compiled CSS contains the full Bootstrap framework plus WordPress-specific overrides.
### JavaScript
The Bootstrap JS bundle (including Popper.js) is served as a pre-built file copied from `node_modules` during the build step.
### Design Tokens
`theme.json` colors, typography, and spacing are aligned with Bootstrap's default SCSS variables to ensure visual consistency between the WordPress editor and the frontend.
## Dark Mode Plan
Bootstrap 5.3+ includes built-in dark mode via the `data-bs-theme="dark"` attribute. Implementation plan:
1. SCSS: `$enable-dark-mode: true` generates dark mode CSS custom properties
2. JavaScript: Toggle mechanism with `localStorage` persistence
3. WordPress: Integration with the Site Editor color scheme
4. Accessibility: Respect `prefers-color-scheme` media query

80
README.md Normal file
View File

@@ -0,0 +1,80 @@
# WP Bootstrap
A modern WordPress Block Theme built from scratch with Bootstrap 5.
## Features
- Full Site Editing (FSE) support
- Bootstrap 5 CSS and JavaScript
- Responsive design
- Dark mode ready (Bootstrap 5.3 dark mode variables)
- Twig 3.0 template engine
- WordPress i18n support
- Gitea CI/CD automated releases
## Requirements
- WordPress 6.7 or higher
- PHP 8.3 or higher
## Installation
### From Release Package
1. Download the latest `.zip` from [Releases](https://src.bundespruefstelle.ch/magdev/wp-bootstrap/releases)
2. Go to WordPress Admin > Appearance > Themes > Add New > Upload Theme
3. Upload the ZIP file and activate
### From Source
```bash
git clone ssh://git@src.bundespruefstelle.ch:2022/magdev/wp-bootstrap.git
cd wp-bootstrap
composer install
yarn install
yarn build
```
## Development
### Prerequisites
- Node.js 20+
- Yarn
- Composer
- PHP 8.3+
### Build Commands
| Command | Description |
| --- | --- |
| `yarn build` | Compile SCSS, minify CSS, copy Bootstrap JS |
| `yarn dev` | Watch SCSS files and recompile on changes |
| `yarn scss` | Compile SCSS only |
| `yarn postcss` | Minify CSS with Autoprefixer |
| `composer install` | Install PHP dependencies |
### Project Structure
```txt
wp-bootstrap/
├── assets/ Compiled CSS, JS, and images
├── inc/ PHP classes (PSR-4 autoloaded)
├── languages/ Translation files (.pot, .po)
├── parts/ FSE template parts (header, footer)
├── patterns/ Block patterns
├── src/scss/ SCSS source files
├── templates/ FSE page templates
├── views/ Twig templates
├── functions.php Theme bootstrap
├── style.css Theme metadata
└── theme.json Design tokens and settings
```
## License
GPL-2.0-or-later
## Author
Marco Graetsch - [src.bundespruefstelle.ch/magdev](https://src.bundespruefstelle.ch/magdev)

190
assets/css/editor-style.css Normal file
View File

@@ -0,0 +1,190 @@
/*!
* WP Bootstrap Theme - Editor Styles
*/
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000000;
--bs-white: #FFFFFF;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #343a40;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 52, 58, 64;
--bs-primary-text-emphasis: rgb(5.2, 44, 101.2);
--bs-secondary-text-emphasis: rgb(43.2, 46.8, 50);
--bs-success-text-emphasis: rgb(10, 54, 33.6);
--bs-info-text-emphasis: rgb(5.2, 80.8, 96);
--bs-warning-text-emphasis: rgb(102, 77.2, 2.8);
--bs-danger-text-emphasis: rgb(88, 21.2, 27.6);
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: rgb(206.6, 226, 254.6);
--bs-secondary-bg-subtle: rgb(225.6, 227.4, 229);
--bs-success-bg-subtle: rgb(209, 231, 220.8);
--bs-info-bg-subtle: rgb(206.6, 244.4, 252);
--bs-warning-bg-subtle: rgb(255, 242.6, 205.4);
--bs-danger-bg-subtle: rgb(248, 214.6, 217.8);
--bs-light-bg-subtle: rgb(251.5, 252, 252.5);
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: rgb(158.2, 197, 254.2);
--bs-secondary-border-subtle: rgb(196.2, 199.8, 203);
--bs-success-border-subtle: rgb(163, 207, 186.6);
--bs-info-border-subtle: rgb(158.2, 233.8, 249);
--bs-warning-border-subtle: rgb(255, 230.2, 155.8);
--bs-danger-border-subtle: rgb(241, 174.2, 180.6);
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #FFFFFF;
--bs-body-bg-rgb: 255, 255, 255;
--bs-emphasis-color: #000000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-heading-color: inherit;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: rgb(10.4, 88, 202.4);
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-color: #212529;
--bs-highlight-bg: rgb(255, 242.6, 205.4);
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-xxl: 2rem;
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
--bs-focus-ring-width: 0.25rem;
--bs-focus-ring-opacity: 0.25;
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
--bs-form-valid-color: #198754;
--bs-form-valid-border-color: #198754;
--bs-form-invalid-color: #dc3545;
--bs-form-invalid-border-color: #dc3545;
}
[data-bs-theme=dark] {
color-scheme: dark;
--bs-body-color: #dee2e6;
--bs-body-color-rgb: 222, 226, 230;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #FFFFFF;
--bs-emphasis-color-rgb: 255, 255, 255;
--bs-secondary-color: rgba(222, 226, 230, 0.75);
--bs-secondary-color-rgb: 222, 226, 230;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
--bs-tertiary-color-rgb: 222, 226, 230;
--bs-tertiary-bg: rgb(42.5, 47.5, 52.5);
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-primary-text-emphasis: rgb(109.8, 168, 253.8);
--bs-secondary-text-emphasis: rgb(166.8, 172.2, 177);
--bs-success-text-emphasis: rgb(117, 183, 152.4);
--bs-info-text-emphasis: rgb(109.8, 223.2, 246);
--bs-warning-text-emphasis: rgb(255, 217.8, 106.2);
--bs-danger-text-emphasis: rgb(234, 133.8, 143.4);
--bs-light-text-emphasis: #f8f9fa;
--bs-dark-text-emphasis: #dee2e6;
--bs-primary-bg-subtle: rgb(2.6, 22, 50.6);
--bs-secondary-bg-subtle: rgb(21.6, 23.4, 25);
--bs-success-bg-subtle: rgb(5, 27, 16.8);
--bs-info-bg-subtle: rgb(2.6, 40.4, 48);
--bs-warning-bg-subtle: rgb(51, 38.6, 1.4);
--bs-danger-bg-subtle: rgb(44, 10.6, 13.8);
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: rgb(7.8, 66, 151.8);
--bs-secondary-border-subtle: rgb(64.8, 70.2, 75);
--bs-success-border-subtle: rgb(15, 81, 50.4);
--bs-info-border-subtle: rgb(7.8, 121.2, 144);
--bs-warning-border-subtle: rgb(153, 115.8, 4.2);
--bs-danger-border-subtle: rgb(132, 31.8, 41.4);
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: inherit;
--bs-link-color: rgb(109.8, 168, 253.8);
--bs-link-hover-color: rgb(138.84, 185.4, 254.04);
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: rgb(230.4, 132.6, 181.2);
--bs-highlight-color: #dee2e6;
--bs-highlight-bg: rgb(102, 77.2, 2.8);
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: rgb(117, 183, 152.4);
--bs-form-valid-border-color: rgb(117, 183, 152.4);
--bs-form-invalid-color: rgb(234, 133.8, 143.4);
--bs-form-invalid-border-color: rgb(234, 133.8, 143.4);
}
.editor-styles-wrapper {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
line-height: 1.5;
}
.editor-styles-wrapper a {
text-decoration-thickness: 1px !important;
text-underline-offset: 0.1em;
}
/*# sourceMappingURL=editor-style.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["../../src/scss/editor-style.scss","../../node_modules/bootstrap/scss/_root.scss","../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../node_modules/bootstrap/scss/mixins/_color-mode.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;ACAA;AAAA;EASI;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAGF;EACA;EAMA;EACA;EACA;EAOA;EC2OI,qBALI;EDpOR;EACA;EAKA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAGA;EAEA;EACA;EACA;EAEA;EACA;EAMA;EACA;EACA;EAGA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EAIA;EACA;EACA;EAIA;EACA;EACA;EACA;;;AEhHE;EFsHA;EAGA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EAGE;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAIA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAGF;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;;;ADzKJ;EACI;EACA;;AAEA;EACI;EACA","file":"editor-style.css"}

11893
assets/css/style.css Normal file

File diff suppressed because it is too large Load Diff

1
assets/css/style.css.map Normal file

File diff suppressed because one or more lines are too long

10
assets/css/style.min.css vendored Normal file

File diff suppressed because one or more lines are too long

0
assets/images/.gitkeep Normal file
View File

7
assets/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

26
composer.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "magdev/wp-bootstrap",
"description": "WordPress Theme built with Bootstrap 5 and Twig",
"type": "wordpress-theme",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "Marco Graetsch",
"email": "magdev3.0@gmail.com",
"homepage": "https://src.bundespruefstelle.ch/magdev"
}
],
"require": {
"php": ">=8.3",
"twig/twig": "^3.0"
},
"autoload": {
"psr-4": {
"WPBootstrap\\": "inc/"
}
},
"config": {
"optimize-autoloader": true,
"sort-packages": true
}
}

335
composer.lock generated Normal file
View File

@@ -0,0 +1,335 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7f711ad3aa03001938265eb3bd2ad61c",
"packages": [
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-12-23T08:48:59+00:00"
},
{
"name": "twig/twig",
"version": "v3.23.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9",
"reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9",
"shasum": ""
},
"require": {
"php": ">=8.1.0",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"phpstan/phpstan": "^2.0",
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
},
"type": "library",
"autoload": {
"files": [
"src/Resources/core.php",
"src/Resources/debug.php",
"src/Resources/escaper.php",
"src/Resources/string_loader.php"
],
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.23.0"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2026-01-23T21:00:41+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=8.3"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

95
functions.php Normal file
View File

@@ -0,0 +1,95 @@
<?php
/**
* WP Bootstrap functions and definitions.
*
* @link https://developer.wordpress.org/themes/basics/theme-functions/
*
* @package WPBootstrap
* @since 0.0.1
*/
// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Load Composer autoloader.
if ( file_exists( get_template_directory() . '/vendor/autoload.php' ) ) {
require_once get_template_directory() . '/vendor/autoload.php';
}
/**
* Sets up theme defaults and registers support for various WordPress features.
*/
if ( ! function_exists( 'wp_bootstrap_setup' ) ) :
function wp_bootstrap_setup() {
// Add support for post formats.
add_theme_support( 'post-formats', array(
'aside', 'audio', 'chat', 'gallery', 'image',
'link', 'quote', 'status', 'video',
) );
// Make theme available for translation.
load_theme_textdomain( 'wp-bootstrap', get_template_directory() . '/languages' );
// Add editor styles.
add_editor_style( 'assets/css/editor-style.css' );
}
endif;
add_action( 'after_setup_theme', 'wp_bootstrap_setup' );
/**
* Enqueue theme scripts and styles.
*/
if ( ! function_exists( 'wp_bootstrap_enqueue_scripts' ) ) :
function wp_bootstrap_enqueue_scripts() {
$theme_version = wp_get_theme()->get( 'Version' );
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
// Enqueue the compiled Bootstrap + custom CSS.
wp_enqueue_style(
'wp-bootstrap-style',
get_template_directory_uri() . '/assets/css/style' . $suffix . '.css',
array(),
$theme_version
);
// Enqueue Bootstrap JS bundle (includes Popper).
wp_enqueue_script(
'wp-bootstrap-js',
get_template_directory_uri() . '/assets/js/bootstrap.bundle.min.js',
array(),
$theme_version,
true
);
}
endif;
add_action( 'wp_enqueue_scripts', 'wp_bootstrap_enqueue_scripts' );
/**
* Register block pattern categories.
*/
if ( ! function_exists( 'wp_bootstrap_pattern_categories' ) ) :
function wp_bootstrap_pattern_categories() {
register_block_pattern_category(
'wp-bootstrap_page',
array(
'label' => __( 'Pages', 'wp-bootstrap' ),
'description' => __( 'A collection of full page layouts.', 'wp-bootstrap' ),
)
);
}
endif;
add_action( 'init', 'wp_bootstrap_pattern_categories' );
/**
* Initialize Twig template engine.
*/
if ( ! function_exists( 'wp_bootstrap_init_twig' ) ) :
function wp_bootstrap_init_twig() {
if ( class_exists( '\\WPBootstrap\\Twig\\TwigService' ) ) {
\WPBootstrap\Twig\TwigService::getInstance();
}
}
endif;
add_action( 'after_setup_theme', 'wp_bootstrap_init_twig' );

72
inc/Twig/TwigService.php Normal file
View File

@@ -0,0 +1,72 @@
<?php
/**
* Twig Template Engine Service.
*
* @package WPBootstrap
* @since 0.0.1
*/
namespace WPBootstrap\Twig;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\TwigFunction;
class TwigService
{
private static ?TwigService $instance = null;
private Environment $twig;
private function __construct()
{
$viewsDir = get_template_directory() . '/views';
$cacheDir = WP_CONTENT_DIR . '/cache/twig';
$loader = new FilesystemLoader($viewsDir);
$this->twig = new Environment($loader, [
'cache' => WP_DEBUG ? false : $cacheDir,
'debug' => WP_DEBUG,
'auto_reload' => true,
]);
$this->registerWordPressFunctions();
}
public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function render(string $template, array $context = []): string
{
return $this->twig->render($template, $context);
}
public function display(string $template, array $context = []): void
{
$this->twig->display($template, $context);
}
public function getEnvironment(): Environment
{
return $this->twig;
}
private function registerWordPressFunctions(): void
{
$this->twig->addFunction(new TwigFunction('__', function (string $text, string $domain = 'wp-bootstrap'): string {
return __($text, $domain);
}));
$this->twig->addFunction(new TwigFunction('_e', function (string $text, string $domain = 'wp-bootstrap'): void {
_e($text, $domain);
}));
$this->twig->addFunction(new TwigFunction('esc_html', 'esc_html'));
$this->twig->addFunction(new TwigFunction('esc_attr', 'esc_attr'));
$this->twig->addFunction(new TwigFunction('esc_url', 'esc_url'));
}
}

85
languages/de_CH.po Normal file
View File

@@ -0,0 +1,85 @@
# German (Switzerland) translation for WP Bootstrap.
# Copyright (C) 2026 Marco Graetsch
# This file is distributed under the same license as the WP Bootstrap theme.
#
msgid ""
msgstr ""
"Project-Id-Version: WP Bootstrap 0.0.1\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-bootstrap/issues\n"
"POT-Creation-Date: 2026-02-08 00:00+0000\n"
"PO-Revision-Date: 2026-02-08 00:00+0000\n"
"Last-Translator: Marco Graetsch <magdev3.0@gmail.com>\n"
"Language-Team: German (Switzerland)\n"
"Language: de_CH\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. Theme Name of the theme
msgid "WP Bootstrap"
msgstr "WP Bootstrap"
#. Description of the theme
msgid "A modern WordPress Block Theme built from scratch with Bootstrap 5. Features responsive design, dark mode support, and full compatibility with the WordPress Site Editor."
msgstr "Ein modernes WordPress Block-Theme, erstellt mit Bootstrap 5. Mit responsivem Design, Darkmode-Unterstützung und voller Kompatibilität mit dem WordPress Site-Editor."
#: patterns/footer.php
msgid "Powered by %s"
msgstr "Betrieben mit %s"
#: patterns/footer.php
msgid "https://wordpress.org"
msgstr "https://de.wordpress.org"
#: patterns/hidden-404.php
msgid "Page not found"
msgstr "Seite nicht gefunden"
#: patterns/hidden-404.php
msgid "The page you are looking for does not exist, or it has been moved. Please try searching using the form below."
msgstr "Die gesuchte Seite existiert nicht oder wurde verschoben. Bitte verwenden Sie das untenstehende Suchformular."
#: patterns/hidden-search.php
msgid "Search"
msgstr "Suchen"
#: patterns/hidden-search.php
msgid "Search..."
msgstr "Suchen..."
#: patterns/hidden-blog-heading.php
msgid "Blog"
msgstr "Blog"
#: patterns/comments.php
msgid "Comments"
msgstr "Kommentare"
#: patterns/post-navigation.php
msgid "Previous"
msgstr "Zurück"
#: patterns/post-navigation.php
msgid "Next"
msgstr "Weiter"
#: patterns/more-posts.php
msgid "More posts"
msgstr "Weitere Beiträge"
#: patterns/template-query-loop.php
msgid "Read more"
msgstr "Weiterlesen"
#: patterns/template-query-loop.php
msgid "No posts were found."
msgstr "Es wurden keine Beiträge gefunden."
#: functions.php
msgid "Pages"
msgstr "Seiten"
#: functions.php
msgid "A collection of full page layouts."
msgstr "Eine Sammlung von ganzseitigen Layouts."

View File

@@ -0,0 +1,81 @@
# Copyright (C) 2026 Marco Graetsch
# This file is distributed under the same license as the WP Bootstrap theme.
msgid ""
msgstr ""
"Project-Id-Version: WP Bootstrap 0.0.1\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wp-bootstrap/issues\n"
"POT-Creation-Date: 2026-02-08 00:00+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
#. Theme Name of the theme
msgid "WP Bootstrap"
msgstr ""
#. Description of the theme
msgid "A modern WordPress Block Theme built from scratch with Bootstrap 5. Features responsive design, dark mode support, and full compatibility with the WordPress Site Editor."
msgstr ""
#: patterns/footer.php
msgid "Powered by %s"
msgstr ""
#: patterns/footer.php
msgid "https://wordpress.org"
msgstr ""
#: patterns/hidden-404.php
msgid "Page not found"
msgstr ""
#: patterns/hidden-404.php
msgid "The page you are looking for does not exist, or it has been moved. Please try searching using the form below."
msgstr ""
#: patterns/hidden-search.php
msgid "Search"
msgstr ""
#: patterns/hidden-search.php
msgid "Search..."
msgstr ""
#: patterns/hidden-blog-heading.php
msgid "Blog"
msgstr ""
#: patterns/comments.php
msgid "Comments"
msgstr ""
#: patterns/post-navigation.php
msgid "Previous"
msgstr ""
#: patterns/post-navigation.php
msgid "Next"
msgstr ""
#: patterns/more-posts.php
msgid "More posts"
msgstr ""
#: patterns/template-query-loop.php
msgid "Read more"
msgstr ""
#: patterns/template-query-loop.php
msgid "No posts were found."
msgstr ""
#: functions.php
msgid "Pages"
msgstr ""
#: functions.php
msgid "A collection of full page layouts."
msgstr ""

36
package.json Normal file
View File

@@ -0,0 +1,36 @@
{
"name": "wp-bootstrap",
"version": "0.0.1",
"description": "WordPress Theme built with Bootstrap 5",
"author": "Marco Graetsch <magdev3.0@gmail.com>",
"license": "GPL-2.0-or-later",
"repository": {
"type": "git",
"url": "https://src.bundespruefstelle.ch/magdev/wp-bootstrap"
},
"private": true,
"engines": {
"node": ">=20.0.0"
},
"dependencies": {
"bootstrap": "^5.3",
"@popperjs/core": "^2.11"
},
"devDependencies": {
"sass": "^1.97",
"postcss": "^8.5",
"postcss-cli": "^11",
"autoprefixer": "^10.4",
"cssnano": "^7.1",
"copyfiles": "^2.4"
},
"scripts": {
"scss": "sass src/scss/style.scss:assets/css/style.css src/scss/editor-style.scss:assets/css/editor-style.css --load-path=node_modules",
"scss:watch": "sass --watch src/scss/style.scss:assets/css/style.css src/scss/editor-style.scss:assets/css/editor-style.css --load-path=node_modules",
"postcss": "postcss assets/css/style.css --use autoprefixer cssnano -o assets/css/style.min.css --no-map",
"copy:js": "copyfiles -f node_modules/bootstrap/dist/js/bootstrap.bundle.min.js node_modules/bootstrap/dist/js/bootstrap.bundle.min.js.map assets/js/",
"build": "npm run copy:js && npm run scss && npm run postcss",
"watch": "npm run copy:js && npm run scss:watch",
"dev": "npm run watch"
}
}

1
parts/footer.html Normal file
View File

@@ -0,0 +1 @@
<!-- wp:pattern {"slug":"wp-bootstrap/footer"} /-->

1
parts/header.html Normal file
View File

@@ -0,0 +1 @@
<!-- wp:pattern {"slug":"wp-bootstrap/header"} /-->

44
patterns/comments.php Normal file
View File

@@ -0,0 +1,44 @@
<?php
/**
* Title: Comments
* Slug: wp-bootstrap/comments
* Categories: posts
* Description: Comments section with form.
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:comments {"style":{"spacing":{"padding":{"top":"var:preset|spacing|60"}}}} -->
<div class="wp-block-comments" style="padding-top:var(--wp--preset--spacing--60)">
<!-- wp:heading {"fontSize":"large"} -->
<h2 class="has-large-font-size"><?php esc_html_e( 'Comments', 'wp-bootstrap' ); ?></h2>
<!-- /wp:heading -->
<!-- wp:comment-template -->
<!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|20","padding":{"bottom":"var:preset|spacing|40"}}},"layout":{"type":"flex","flexWrap":"nowrap","verticalAlignment":"top"}} -->
<div class="wp-block-group" style="padding-bottom:var(--wp--preset--spacing--40)">
<!-- wp:avatar {"size":40} /-->
<!-- wp:group {"layout":{"type":"default"}} -->
<div class="wp-block-group">
<!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|10"}},"layout":{"type":"flex","flexWrap":"wrap"},"fontSize":"small"} -->
<div class="wp-block-group has-small-font-size">
<!-- wp:comment-author-name /-->
<!-- wp:comment-date /-->
<!-- wp:comment-edit-link /-->
</div>
<!-- /wp:group -->
<!-- wp:comment-content /-->
<!-- wp:comment-reply-link {"fontSize":"small"} /-->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
<!-- /wp:comment-template -->
<!-- wp:comments-pagination {"layout":{"type":"flex","justifyContent":"space-between"}} -->
<!-- wp:comments-pagination-previous /-->
<!-- wp:comments-pagination-numbers /-->
<!-- wp:comments-pagination-next /-->
<!-- /wp:comments-pagination -->
<!-- wp:post-comments-form /-->
</div>
<!-- /wp:comments -->

49
patterns/footer.php Normal file
View File

@@ -0,0 +1,49 @@
<?php
/**
* Title: Footer
* Slug: wp-bootstrap/footer
* Categories: footer
* Block Types: core/template-part/footer
* Description: Site footer with site title, tagline, and credits.
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|50"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--50)">
<!-- wp:group {"align":"wide","layout":{"type":"default"}} -->
<div class="wp-block-group alignwide">
<!-- wp:group {"align":"full","style":{"spacing":{"blockGap":"var:preset|spacing|20"}},"layout":{"type":"flex","flexWrap":"wrap","justifyContent":"space-between"}} -->
<div class="wp-block-group alignfull">
<!-- wp:site-title {"level":3} /-->
<!-- wp:site-tagline /-->
</div>
<!-- /wp:group -->
<!-- wp:spacer {"height":"var:preset|spacing|60"} -->
<div style="height:var(--wp--preset--spacing--60)" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->
<!-- wp:group {"align":"full","style":{"spacing":{"blockGap":"var:preset|spacing|20"}},"layout":{"type":"flex","flexWrap":"wrap","justifyContent":"space-between"}} -->
<div class="wp-block-group alignfull">
<!-- wp:paragraph {"fontSize":"small"} -->
<p class="has-small-font-size"><?php esc_html_e( 'WP Bootstrap', 'wp-bootstrap' ); ?></p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"fontSize":"small"} -->
<p class="has-small-font-size">
<?php
printf(
/* translators: Powered by WordPress. %s: WordPress link. */
esc_html__( 'Powered by %s', 'wp-bootstrap' ),
'<a href="' . esc_url( __( 'https://wordpress.org', 'wp-bootstrap' ) ) . '" rel="nofollow">WordPress</a>'
);
?>
</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->

30
patterns/header.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
/**
* Title: Header
* Slug: wp-bootstrap/header
* Categories: header
* Block Types: core/template-part/header
* Description: Site header with site title and navigation.
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:group {"align":"full","layout":{"type":"default"}} -->
<div class="wp-block-group alignfull">
<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:group {"align":"wide","style":{"spacing":{"padding":{"top":"var:preset|spacing|30","bottom":"var:preset|spacing|30"}}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div class="wp-block-group alignwide" style="padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30)">
<!-- wp:site-title {"level":0} /-->
<!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|10"}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"right"}} -->
<div class="wp-block-group">
<!-- wp:navigation {"overlayBackgroundColor":"base","overlayTextColor":"contrast","layout":{"type":"flex","justifyContent":"right","flexWrap":"wrap"}} /-->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->

23
patterns/hidden-404.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
/**
* Title: 404
* Slug: wp-bootstrap/hidden-404
* Inserter: no
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:heading {"level":1,"align":"wide"} -->
<h1 class="alignwide"><?php esc_html_e( 'Page not found', 'wp-bootstrap' ); ?></h1>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p><?php esc_html_e( 'The page you are looking for does not exist, or it has been moved. Please try searching using the form below.', 'wp-bootstrap' ); ?></p>
<!-- /wp:paragraph -->
<!-- wp:pattern {"slug":"wp-bootstrap/hidden-search"} /-->
</div>
<!-- /wp:group -->

View File

@@ -0,0 +1,13 @@
<?php
/**
* Title: Blog heading
* Slug: wp-bootstrap/hidden-blog-heading
* Inserter: no
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:heading {"level":1} -->
<h1><?php esc_html_e( 'Blog', 'wp-bootstrap' ); ?></h1>
<!-- /wp:heading -->

View File

@@ -0,0 +1,11 @@
<?php
/**
* Title: Search
* Slug: wp-bootstrap/hidden-search
* Inserter: no
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:search {"label":"<?php esc_attr_e( 'Search', 'wp-bootstrap' ); ?>","showLabel":false,"placeholder":"<?php esc_attr_e( 'Search...', 'wp-bootstrap' ); ?>","buttonText":"<?php esc_attr_e( 'Search', 'wp-bootstrap' ); ?>"} /-->

View File

@@ -0,0 +1,23 @@
<?php
/**
* Title: Written by
* Slug: wp-bootstrap/hidden-written-by
* Inserter: no
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|10"}},"layout":{"type":"flex","flexWrap":"wrap"},"fontSize":"small"} -->
<div class="wp-block-group has-small-font-size">
<!-- wp:post-date /-->
<!-- wp:paragraph -->
<p>·</p>
<!-- /wp:paragraph -->
<!-- wp:post-author-name {"isLink":true} /-->
<!-- wp:paragraph -->
<p>·</p>
<!-- /wp:paragraph -->
<!-- wp:post-terms {"term":"category"} /-->
</div>
<!-- /wp:group -->

29
patterns/more-posts.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
/**
* Title: More posts
* Slug: wp-bootstrap/more-posts
* Categories: posts
* Description: A section with more recent posts.
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)">
<!-- wp:heading {"fontSize":"large"} -->
<h2 class="has-large-font-size"><?php esc_html_e( 'More posts', 'wp-bootstrap' ); ?></h2>
<!-- /wp:heading -->
<!-- wp:query {"query":{"perPage":3,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","inherit":false},"layout":{"type":"constrained"}} -->
<!-- wp:post-template {"layout":{"type":"grid","columnCount":3}} -->
<!-- wp:group {"layout":{"type":"default"}} -->
<div class="wp-block-group">
<!-- wp:post-featured-image {"aspectRatio":"3/2","isLink":true} /-->
<!-- wp:post-title {"level":3,"isLink":true,"fontSize":"medium"} /-->
<!-- wp:post-date {"fontSize":"small"} /-->
</div>
<!-- /wp:group -->
<!-- /wp:post-template -->
<!-- /wp:query -->
</div>
<!-- /wp:group -->

View File

@@ -0,0 +1,20 @@
<?php
/**
* Title: Post navigation
* Slug: wp-bootstrap/post-navigation
* Categories: posts
* Description: Previous and next post links.
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)">
<!-- wp:separator {"className":"is-style-wide"} -->
<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>
<!-- /wp:separator -->
<!-- wp:post-navigation-link {"type":"previous","label":"<?php esc_attr_e( 'Previous', 'wp-bootstrap' ); ?>","arrow":"arrow"} /-->
<!-- wp:post-navigation-link {"label":"<?php esc_attr_e( 'Next', 'wp-bootstrap' ); ?>","arrow":"arrow"} /-->
</div>
<!-- /wp:group -->

View File

@@ -0,0 +1,42 @@
<?php
/**
* Title: Query loop
* Slug: wp-bootstrap/template-query-loop
* Inserter: no
*
* @package WPBootstrap
* @since 0.0.1
*/
?>
<!-- wp:query {"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","inherit":true},"align":"wide","layout":{"type":"constrained"}} -->
<!-- wp:post-template {"layout":{"type":"default"}} -->
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|40","bottom":"var:preset|spacing|40"}}},"layout":{"type":"default"}} -->
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40)">
<!-- wp:post-title {"level":2,"isLink":true} /-->
<!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|10"}},"layout":{"type":"flex","flexWrap":"wrap"},"fontSize":"small"} -->
<div class="wp-block-group has-small-font-size">
<!-- wp:post-date /-->
<!-- wp:paragraph -->
<p>·</p>
<!-- /wp:paragraph -->
<!-- wp:post-author-name {"isLink":true} /-->
</div>
<!-- /wp:group -->
<!-- wp:post-excerpt {"moreText":"<?php esc_attr_e( 'Read more', 'wp-bootstrap' ); ?>"} /-->
</div>
<!-- /wp:group -->
<!-- wp:separator {"className":"is-style-wide"} -->
<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>
<!-- /wp:separator -->
<!-- /wp:post-template -->
<!-- wp:query-pagination {"layout":{"type":"flex","justifyContent":"space-between"}} -->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- /wp:query-pagination -->
<!-- wp:query-no-results -->
<!-- wp:paragraph -->
<p><?php esc_html_e( 'No posts were found.', 'wp-bootstrap' ); ?></p>
<!-- /wp:paragraph -->
<!-- /wp:query-no-results -->
<!-- /wp:query -->

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

2
src/scss/_custom.scss Normal file
View File

@@ -0,0 +1,2 @@
// Custom theme styles
// Add theme-specific styles here that go beyond Bootstrap defaults

42
src/scss/_variables.scss Normal file
View File

@@ -0,0 +1,42 @@
// Bootstrap variable overrides
// These MUST be defined BEFORE importing Bootstrap's variables
// Colors - matching theme.json palette
$white: #FFFFFF;
$gray-100: #f8f9fa;
$gray-200: #e9ecef;
$gray-300: #dee2e6;
$gray-400: #ced4da;
$gray-500: #adb5bd;
$gray-600: #6c757d;
$gray-700: #495057;
$gray-800: #343a40;
$gray-900: #212529;
$black: #000000;
$primary: #0d6efd;
$secondary: #6c757d;
$success: #198754;
$danger: #dc3545;
$warning: #ffc107;
$info: #0dcaf0;
$light: $gray-100;
$dark: $gray-800;
// Layout
$container-max-widths: (
sm: 540px,
md: 720px,
lg: 960px,
xl: 1140px,
xxl: 1320px
);
// Typography - using system fonts (matching theme.json)
$font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
// Enable dark mode
$enable-dark-mode: true;
// Enable reduced motion
$enable-reduced-motion: true;

37
src/scss/_wordpress.scss Normal file
View File

@@ -0,0 +1,37 @@
// WordPress FSE block compatibility with Bootstrap 5
// Ensures Bootstrap styles don't conflict with block editor styles
// Focus styles
:where(.wp-site-blocks *:focus) {
outline-width: 2px;
outline-style: solid;
}
// Prevent Bootstrap's reboot from conflicting with block editor
.wp-block-group,
.wp-block-columns,
.wp-block-column {
box-sizing: border-box;
}
// Navigation block compatibility
.wp-block-navigation {
.wp-block-navigation-item__content {
outline-offset: 4px;
}
}
// Text wrapping (progressive enhancement)
h1, h2, h3, h4, h5, h6, blockquote, caption, figcaption, p {
text-wrap: pretty;
}
// More block
.more-link {
display: block;
}
// Preformatted text
:where(pre) {
overflow-x: auto;
}

View File

@@ -0,0 +1,23 @@
/*!
* WP Bootstrap Theme - Editor Styles
*/
// Import Bootstrap functions and variables for consistency
@import "bootstrap/scss/functions";
@import "variables";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
// Editor-specific adjustments
.editor-styles-wrapper {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
line-height: 1.5;
a {
text-decoration-thickness: 1px !important;
text-underline-offset: 0.1em;
}
}

19
src/scss/style.scss Normal file
View File

@@ -0,0 +1,19 @@
/*!
* WP Bootstrap Theme
* Built with Bootstrap 5
*/
// 1. Import Bootstrap functions first (needed for variable manipulation)
@import "bootstrap/scss/functions";
// 2. Override Bootstrap variables BEFORE they're set
@import "variables";
// 3. Import all of Bootstrap
@import "bootstrap/scss/bootstrap";
// 4. WordPress block compatibility
@import "wordpress";
// 5. Custom styles
@import "custom";

15
style.css Normal file
View File

@@ -0,0 +1,15 @@
/*
Theme Name: WP Bootstrap
Theme URI: https://src.bundespruefstelle.ch/magdev/wp-bootstrap
Author: Marco Graetsch
Author URI: https://src.bundespruefstelle.ch/magdev
Description: A modern WordPress Block Theme built from scratch with Bootstrap 5. Features responsive design, dark mode support, and full compatibility with the WordPress Site Editor.
Requires at least: 6.7
Tested up to: 6.7
Requires PHP: 8.3
Version: 0.0.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: wp-bootstrap
Tags: one-column, custom-colors, custom-menu, custom-logo, editor-style, featured-images, full-site-editing, block-patterns, rtl-language-support, sticky-post, threaded-comments, translation-ready, wide-blocks, block-styles, accessibility-ready, blog
*/

9
templates/404.html Normal file
View File

@@ -0,0 +1,9 @@
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"padding":{"top":"var:preset|spacing|50","bottom":"var:preset|spacing|50","left":"var:preset|spacing|50","right":"var:preset|spacing|50"}}},"layout":{"type":"default"}} -->
<main class="wp-block-group" style="padding-top:var(--wp--preset--spacing--50);padding-right:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--50);padding-left:var(--wp--preset--spacing--50)">
<!-- wp:pattern {"slug":"wp-bootstrap/hidden-404"} /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

11
templates/archive.html Normal file
View File

@@ -0,0 +1,11 @@
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<main class="wp-block-group" style="margin-top:var(--wp--preset--spacing--60)">
<!-- wp:query-title {"type":"archive"} /-->
<!-- wp:term-description /-->
<!-- wp:pattern {"slug":"wp-bootstrap/template-query-loop"} /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

10
templates/home.html Normal file
View File

@@ -0,0 +1,10 @@
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<main class="wp-block-group" style="margin-top:var(--wp--preset--spacing--60)">
<!-- wp:pattern {"slug":"wp-bootstrap/hidden-blog-heading"} /-->
<!-- wp:pattern {"slug":"wp-bootstrap/template-query-loop"} /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

10
templates/index.html Normal file
View File

@@ -0,0 +1,10 @@
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<main class="wp-block-group" style="margin-top:var(--wp--preset--spacing--60)">
<!-- wp:pattern {"slug":"wp-bootstrap/hidden-blog-heading"} /-->
<!-- wp:pattern {"slug":"wp-bootstrap/template-query-loop"} /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

15
templates/page.html Normal file
View File

@@ -0,0 +1,15 @@
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<main class="wp-block-group" style="margin-top:var(--wp--preset--spacing--60)">
<!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)">
<!-- wp:post-featured-image {"style":{"spacing":{"margin":{"bottom":"var:preset|spacing|60"}}}} /-->
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-content {"align":"full","layout":{"type":"constrained"}} /-->
</div>
<!-- /wp:group -->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

11
templates/search.html Normal file
View File

@@ -0,0 +1,11 @@
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<main class="wp-block-group" style="margin-top:var(--wp--preset--spacing--60)">
<!-- wp:query-title {"type":"search"} /-->
<!-- wp:pattern {"slug":"wp-bootstrap/hidden-search"} /-->
<!-- wp:pattern {"slug":"wp-bootstrap/template-query-loop"} /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

24
templates/single.html Normal file
View File

@@ -0,0 +1,24 @@
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<main class="wp-block-group" style="margin-top:var(--wp--preset--spacing--60)">
<!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)">
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-featured-image {"aspectRatio":"16/9"} /-->
<!-- wp:pattern {"slug":"wp-bootstrap/hidden-written-by"} /-->
<!-- wp:post-content {"align":"full","layout":{"type":"constrained"}} /-->
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|60","bottom":"var:preset|spacing|60"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-group" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)">
<!-- wp:post-terms {"term":"post_tag","separator":" "} /-->
</div>
<!-- /wp:group -->
<!-- wp:pattern {"slug":"wp-bootstrap/post-navigation"} /-->
<!-- wp:pattern {"slug":"wp-bootstrap/comments"} /-->
</div>
<!-- /wp:group -->
<!-- wp:pattern {"slug":"wp-bootstrap/more-posts"} /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

398
theme.json Normal file
View File

@@ -0,0 +1,398 @@
{
"$schema": "https://schemas.wp.org/wp/6.7/theme.json",
"version": 3,
"settings": {
"appearanceTools": true,
"color": {
"defaultDuotone": false,
"defaultGradients": false,
"defaultPalette": false,
"palette": [
{
"color": "#FFFFFF",
"name": "Base",
"slug": "base"
},
{
"color": "#212529",
"name": "Contrast",
"slug": "contrast"
},
{
"color": "#0d6efd",
"name": "Primary",
"slug": "primary"
},
{
"color": "#6c757d",
"name": "Secondary",
"slug": "secondary"
},
{
"color": "#198754",
"name": "Success",
"slug": "success"
},
{
"color": "#dc3545",
"name": "Danger",
"slug": "danger"
},
{
"color": "#ffc107",
"name": "Warning",
"slug": "warning"
},
{
"color": "#0dcaf0",
"name": "Info",
"slug": "info"
},
{
"color": "#f8f9fa",
"name": "Light",
"slug": "light"
},
{
"color": "#343a40",
"name": "Dark",
"slug": "dark"
}
]
},
"layout": {
"contentSize": "720px",
"wideSize": "1140px"
},
"spacing": {
"defaultSpacingSizes": false,
"spacingSizes": [
{
"name": "3xs",
"size": "0.25rem",
"slug": "10"
},
{
"name": "2xs",
"size": "0.5rem",
"slug": "20"
},
{
"name": "xs",
"size": "1rem",
"slug": "30"
},
{
"name": "s",
"size": "1.5rem",
"slug": "40"
},
{
"name": "m",
"size": "clamp(1.5rem, 3vw, 3rem)",
"slug": "50"
},
{
"name": "l",
"size": "clamp(2rem, 5vw, 4rem)",
"slug": "60"
},
{
"name": "xl",
"size": "clamp(3rem, 7vw, 6rem)",
"slug": "70"
},
{
"name": "2xl",
"size": "clamp(4rem, 10vw, 8rem)",
"slug": "80"
}
],
"units": ["%", "px", "em", "rem", "vh", "vw"]
},
"typography": {
"writingMode": true,
"defaultFontSizes": false,
"fluid": true,
"fontSizes": [
{
"fluid": false,
"name": "Small",
"size": "0.875rem",
"slug": "small"
},
{
"fluid": {
"max": "1.125rem",
"min": "1rem"
},
"name": "Medium",
"size": "1rem",
"slug": "medium"
},
{
"fluid": {
"max": "1.25rem",
"min": "1.125rem"
},
"name": "Large",
"size": "1.25rem",
"slug": "large"
},
{
"fluid": {
"max": "1.75rem",
"min": "1.5rem"
},
"name": "Extra Large",
"size": "1.5rem",
"slug": "x-large"
},
{
"fluid": {
"max": "2.5rem",
"min": "2rem"
},
"name": "Huge",
"size": "2rem",
"slug": "xx-large"
}
],
"fontFamilies": [
{
"fontFamily": "system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', 'Liberation Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'",
"name": "System Sans Serif",
"slug": "system-sans-serif"
},
{
"fontFamily": "SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
"name": "System Monospace",
"slug": "system-monospace"
}
]
},
"useRootPaddingAwareAlignments": true
},
"styles": {
"color": {
"background": "var:preset|color|base",
"text": "var:preset|color|contrast"
},
"spacing": {
"blockGap": "1.5rem",
"padding": {
"left": "var:preset|spacing|50",
"right": "var:preset|spacing|50"
}
},
"typography": {
"fontFamily": "var:preset|font-family|system-sans-serif",
"fontSize": "var:preset|font-size|medium",
"fontWeight": "400",
"lineHeight": "1.5"
},
"elements": {
"button": {
"color": {
"background": "var:preset|color|primary",
"text": "var:preset|color|base"
},
"border": {
"radius": "0.375rem"
},
":hover": {
"color": {
"background": "#0b5ed7",
"text": "var:preset|color|base"
}
},
"spacing": {
"padding": {
"bottom": "0.5rem",
"left": "1rem",
"right": "1rem",
"top": "0.5rem"
}
},
"typography": {
"fontSize": "var:preset|font-size|medium"
}
},
"heading": {
"typography": {
"fontWeight": "500",
"lineHeight": "1.2"
}
},
"h1": {
"typography": {
"fontSize": "var:preset|font-size|xx-large"
}
},
"h2": {
"typography": {
"fontSize": "var:preset|font-size|x-large"
}
},
"h3": {
"typography": {
"fontSize": "var:preset|font-size|large"
}
},
"h4": {
"typography": {
"fontSize": "var:preset|font-size|medium"
}
},
"h5": {
"typography": {
"fontSize": "var:preset|font-size|small"
}
},
"h6": {
"typography": {
"fontSize": "var:preset|font-size|small",
"textTransform": "uppercase"
}
},
"link": {
"color": {
"text": "var:preset|color|primary"
},
":hover": {
"color": {
"text": "#0a58ca"
},
"typography": {
"textDecoration": "underline"
}
}
}
},
"blocks": {
"core/button": {
"variations": {
"outline": {
"border": {
"color": "var:preset|color|primary",
"width": "1px"
},
"color": {
"background": "transparent",
"text": "var:preset|color|primary"
}
}
}
},
"core/code": {
"typography": {
"fontFamily": "var:preset|font-family|system-monospace",
"fontSize": "var:preset|font-size|small"
},
"color": {
"background": "var:preset|color|light"
},
"spacing": {
"padding": {
"top": "var:preset|spacing|30",
"right": "var:preset|spacing|30",
"bottom": "var:preset|spacing|30",
"left": "var:preset|spacing|30"
}
}
},
"core/navigation": {
"typography": {
"fontSize": "var:preset|font-size|medium"
},
"elements": {
"link": {
":hover": {
"typography": {
"textDecoration": "underline"
}
},
"typography": {
"textDecoration": "none"
}
}
}
},
"core/post-title": {
"elements": {
"link": {
":hover": {
"typography": {
"textDecoration": "underline"
}
},
"typography": {
"textDecoration": "none"
}
}
}
},
"core/post-date": {
"color": {
"text": "var:preset|color|secondary"
},
"typography": {
"fontSize": "var:preset|font-size|small"
}
},
"core/site-title": {
"typography": {
"fontWeight": "700"
},
"elements": {
"link": {
"typography": {
"textDecoration": "none"
},
":hover": {
"typography": {
"textDecoration": "underline"
}
}
}
}
},
"core/separator": {
"border": {
"color": "currentColor",
"style": "solid",
"width": "0 0 1px 0"
},
"color": {
"text": "var:preset|color|secondary"
}
},
"core/quote": {
"border": {
"style": "solid",
"width": "0 0 0 4px",
"color": "var:preset|color|primary"
},
"spacing": {
"padding": {
"left": "var:preset|spacing|30",
"top": "var:preset|spacing|20",
"bottom": "var:preset|spacing|20"
}
}
}
}
},
"templateParts": [
{
"area": "header",
"name": "header",
"title": "Header"
},
{
"area": "footer",
"name": "footer",
"title": "Footer"
}
]
}

0
views/.gitkeep Normal file
View File

1179
yarn.lock Normal file

File diff suppressed because it is too large Load Diff