Proyecto WordPress Bedrock con Docker y tema Block Theme (FSE). El tema vive en app/web/app/themes/__THEME_SLUG__/.
project/
├── docker-compose.yml # Docker: PHP-FPM, Nginx, MariaDB, MailHog, phpMyAdmin
├── docker/ # Dockerfiles y configs
├── setup.js # Interactive setup (run once, then deleted)
├── app/ # Bedrock application root
│ ├── composer.json # Bedrock deps (WP core, plugins via wpackagist)
│ ├── config/application.php # Main WP config (reads .env)
│ └── web/app/themes/<theme>/ # Block Theme (FSE)
app/web/app/themes/<theme>/
├── blocks/ # ACF Blocks v3 (block.json + render.php)
├── includes/ # PHP classes (PSR-4, namespace __NAMESPACE__\)
│ ├── ACF/ # ACF field groups
│ ├── Helpers/ # ViteHelper.php
│ └── Theme/ # ThemeSetup.php
├── parts/ # Template parts (header, footer)
├── templates/ # Block templates FSE (index.html, single.html, etc.)
├── resources/
│ ├── fonts/ # Custom fonts (copied to public/ by Vite)
│ ├── styles/ # SCSS: base/, components/, sections/, templates/, frontend/
│ └── scripts/ # TS: components/, frontend/
├── public/ # Generated by Vite (DO NOT edit)
├── functions.php
├── theme.json
├── vite.config.js
└── tsconfig.json
# Docker
docker compose up -d # Start services
docker compose down # Stop services
docker compose exec php sh # Shell into PHP container
# Bedrock (from app/)
cd app && composer install # Install WP core + plugins
composer require wpackagist-plugin/name # Add plugin
# Theme (from app/web/app/themes/<theme>/)
npm run dev # Vite dev server with HMR (localhost:5173)
npm run build # Build once
npm run production # Optimized build
composer install # Theme PHP deps
# Remote sync — powered by wp-dev-sync (from project root)
npm run sync # Watch + auto-sync to remote (wp-dev-sync watch)
npm run sync:push # Manual push (wp-dev-sync push)
npm run sync:pull # Manual pull (wp-dev-sync pull)
# WordPress CLI
docker compose exec php wp cache flush
docker compose exec php wp db exportdeclare(strict_types=1);ydefined('ABSPATH') || exit;al inicio de archivos- Clases: PascalCase, archivos PascalCase.php, namespace
__NAMESPACE__\ - Funciones: snake_case, Variables: snake_case o camelCase (consistente)
- Constantes: UPPER_SNAKE_CASE
- 4 espacios de indentacion, maximo 120 caracteres por linea
- Usar features de PHP 8.2: readonly classes, enums, constructor property promotion, named arguments, match expressions, nullsafe operator, union types
- Escapar salida:
esc_html(),esc_attr(),esc_url(),wp_kses_post() - Sanitizar entrada:
sanitize_email(),sanitize_text_field() - Verificar nonces y capabilities en formularios/AJAX
- Prefijo
__THEME_SLUG___para hooks y filters - Constantes del tema:
THEME_DIR,THEME_URI,THEME_VERSION,THEME_SITENAME
- Archivos: kebab-case.js/ts en
resources/scripts/ - Variables/Funciones: camelCase, Clases: PascalCase, Constantes: UPPER_SNAKE_CASE
- Usar
constpor defecto,letsolo cuando necesario, nuncavar - Modulos ES6 con import/export, path alias
@/pararesources/ - Preferir metodos inmutables:
toSorted(),toReversed(),toSpliced(),with() - Optional chaining (
?.) y nullish coalescing (??) - Sistema de inicializacion: clases con
static initializeAll()llamadas desdemain.tsenDOMContentLoaded - Entry:
resources/scripts/frontend/main.ts
strict: trueen tsconfig.json- Minimizar
any, usarunknowncuando tipo desconocido readonlypara propiedades inmutables- Tipos explicitos en APIs publicas, inferencia para lo obvio
- Composicion sobre herencia
- Archivos: kebab-case.scss en
resources/styles/ - BEM obligatorio:
.block,.block__element,.block--modifier - Maximo 3 niveles de nesting
- Entry:
resources/styles/frontend/main.scss(importa todo) - Media queries obligatorio con mixins (NO usar
@mediadirecto):@use '../../media-queries' as mq; @include mq.respond-above(sm); // > breakpoint @include mq.respond-below(md); // < breakpoint @include mq.respond-between(sm, md);
- Breakpoints: xs:576px, sm:768px, md:1200px, lg:1440px, xl:1600px
- Media queries anidadas dentro del selector, no en bloques separados
- Usar CSS moderno: container queries, cascade layers,
:has(), native nesting,oklch(),color-mix(),clamp() - Variables CSS para theming dinamico, variables SCSS para logica
- Mobile-first approach
Estructura: blocks/nombre/block.json + blocks/nombre/render.php
{
"acf": {
"mode": "preview",
"blockVersion": 3,
"autoInlineEditing": true,
"renderTemplate": "render.php"
}
}- Crear
blocks/mi-block/block.json+render.php - Campos ACF en
includes/ACF/MiBlock.php - Agregar
'MiBlock'al array$acf_filesenfunctions.php - Agregar
'mi-block'al array$blocksenThemeSetup.php - Estilos en
resources/styles/sections/_mi-block.scss - Importar en
resources/styles/frontend/main.scss - Ver
blocks/example-cta/como referencia completa
- HTML semantico:
<header>,<nav>,<main>,<article>,<section>,<aside>,<footer> - Jerarquia de encabezados h1-h6 sin saltar niveles
- ARIA labels en elementos interactivos,
aria-expanded,aria-controls,aria-live - Navegacion completa por teclado, indicadores de focus visibles
- Contraste minimo 4.5:1 (texto normal), 3:1 (texto grande y componentes UI)
alten todas las imagenes,aria-hidden="true"en decorativasprefers-reduced-motion: reducerespetado en animaciones- Skip links en header
- Labels asociados en formularios, mensajes de error con
aria-describedby
- HMR:
npm run devcreapublic/hot,ViteHelperdetecta y carga desde dev server host.docker.internalpermite al contenedor PHP alcanzar Vite en el host- Fuentes: Vite copia
resources/fonts/apublic/fonts/,theme.jsonusafile:./public/fonts/ - Produccion:
npm run production, WordPress carga desdepublic/via manifest.json - SCSS se importa desde el entry TS:
main.tsimporta../../styles/frontend/main.scss - Site Editor / wp-admin: no encolar
enqueue_asset()(JS + cliente Vite) enenqueue_block_assetscuandois_admin(). Usar soloViteHelper::enqueue_compiled_styles_only()para el iframe del editor.
.env, app/.env, app/vendor/, app/web/wp/, app/web/app/plugins/*, node_modules/, vendor/, public/hot, public/css/, public/js/, public/.vite/, public/manifest.json
- Bedrock: Content dir
/app, WordPress core via Composer, plugins via wpackagist - ACF Pro: Field groups en
includes/ACF/, blocks enblocks/ - Vite 5: Build tool con HMR,
vite-plugin-static-copypara fuentes - Composer PSR-4:
__NAMESPACE__\aincludes/ - Remote Sync: wp-dev-sync CLI para sync con servidor remoto (SSH/FTP)