990 lines
37 KiB
Markdown
990 lines
37 KiB
Markdown
# PROMPT_IA — Guía completa del proyecto pflores.linkedcorp.net
|
|
|
|
> Documento de referencia para asistentes de IA. Léelo completo antes de cualquier tarea.
|
|
> Última actualización: junio 2026.
|
|
|
|
---
|
|
|
|
## 1. ¿Qué es este proyecto?
|
|
|
|
Sitio web personal de **hoja de vida / currículum ejecutivo** de **Patricia Soledad Flores Sánchez**, gerente de operaciones financieras con 22+ años en banca y microfinanzas (Ecuador).
|
|
|
|
- URL pública: `https://pflores.linkedcorp.net`
|
|
- Stack: **WordPress 6.x** + PHP 8.4 + MariaDB + **CMB2** (campos personalizados, 100 % gratuito)
|
|
- Se ejecuta con el servidor PHP incorporado (`php -S`) en el puerto **8081**
|
|
- SSL terminado por **Nginx Proxy Manager** → envía `X-Forwarded-Proto: https`
|
|
- IP local del servidor: `192.168.222.40`
|
|
|
|
---
|
|
|
|
## 2. Estructura de directorios
|
|
|
|
```
|
|
pflores.linkedcorp.net/
|
|
├── backend/
|
|
│ ├── start-wordpress.sh # Arrancar el servidor PHP (usa router.php)
|
|
│ ├── router.php # Router PHP — permite URLs tipo /politica-de-privacidad/
|
|
│ └── wordpress/ # Instalación WordPress 7.0
|
|
│ ├── wp-config.php # Config dinámica (URL, auto-updates OFF)
|
|
│ ├── favicon.ico # Foto de Patricia, circular, 16/32/48px
|
|
│ └── wp-content/
|
|
│ ├── plugins/
|
|
│ │ ├── cmb2/ # CMB2 — campos personalizados (GRATIS)
|
|
│ │ ├── wp-mail-smtp/ # Email SMTP (pendiente config)
|
|
│ │ └── pflores-cv-fields/
|
|
│ │ ├── pflores-cv-fields.php # Menú admin + campos CMB2
|
|
│ │ ├── pdf-generator.php # Generador PDF con Chromium
|
|
│ │ └── populate-data.php # Sembrador inicial (ejecutar 1 vez)
|
|
│ └── themes/
|
|
│ ├── apex-cv/ # Directorio REAL — Dark, cian, sidebar fijo
|
|
│ ├── persona-cv -> ../../../../frontend/persona-cv-theme # symlink relativo
|
|
│ ├── lumina -> ../../../../frontend/lumina-cv-theme # symlink relativo
|
|
│ └── cvolio -> ../../../../frontend/cvfolio-theme # symlink relativo
|
|
├── frontend/
|
|
│ ├── persona-cv-theme/ # ACTIVO — Personage-style, rojo, Raleway
|
|
│ │ ├── style.css
|
|
│ │ ├── functions.php
|
|
│ │ ├── header.php # Nav + botón "Descargar CV PDF"
|
|
│ │ ├── footer.php
|
|
│ │ ├── front-page.php # Plantilla principal del CV
|
|
│ │ ├── index.php
|
|
│ │ ├── assets/css/theme.css
|
|
│ │ ├── assets/js/theme.js
|
|
│ │ ├── assets/images/ # patricia-flores-profile.jpeg, qr.png
|
|
│ │ ├── assets/docs/ # CV_Patricia_Flores_Sanchez_ES_FINAL.docx
|
|
│ │ └── inc/
|
|
│ │ ├── cv-data.php # Fallback hardcodeado (función persona_cv_data())
|
|
│ │ ├── customizer.php
|
|
│ │ └── visits.php
|
|
│ ├── lumina-cv-theme/ # Claro, teal+ámbar, sidebar izquierdo
|
|
│ └── cvfolio-theme/ # Oscuro, glassmorphism original
|
|
├── otros/ # Archivos de referencia (foto, QR, docx original)
|
|
├── docs/
|
|
│ └── instalacion-wordpress.md
|
|
├── .env # Local, no versionado
|
|
├── .env.example
|
|
├── VERSION
|
|
├── CHANGELOG.md
|
|
├── VERSIONADO.md
|
|
├── PRODUCCION.md
|
|
├── DEPLOY_WEB.md
|
|
├── PROMPT_IA.md # ESTE ARCHIVO
|
|
└── README.md
|
|
```
|
|
|
|
> **Temas:** `apex-cv` vive en `wp-content/themes/apex-cv/` como directorio real (no symlink).
|
|
> Los otros 3 temas usan **symlinks con ruta relativa** (`../../../../frontend/...`)
|
|
> para funcionar tanto en desarrollo como en producción sin cambios.
|
|
|
|
---
|
|
|
|
## 3. Base de datos
|
|
|
|
### Desarrollo
|
|
|
|
```
|
|
Host: 192.168.222.20
|
|
DB: paty.wordpress
|
|
Usuario: paty.wordpress
|
|
Password: paty.wordpress
|
|
Prefijo: cv_ → tabla principal: cv_options
|
|
```
|
|
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0
|
|
```
|
|
|
|
### Producción
|
|
|
|
```
|
|
Host: 192.168.222.32
|
|
DB: paty.wordpress
|
|
Usuario: paty.wordpress
|
|
Password: (ver LOCAL_DEPLOY_CONTEXT.md)
|
|
Prefijo: cv_
|
|
```
|
|
|
|
> La BD de producción es una copia completa de la de desarrollo. Misma estructura, mismos datos del CV. Credenciales distintas.
|
|
|
|
---
|
|
|
|
## 4. Arrancar / reiniciar el servidor
|
|
|
|
```bash
|
|
# Ver si está corriendo
|
|
lsof -i tcp:8081
|
|
|
|
# Matar proceso existente
|
|
kill $(lsof -ti tcp:8081)
|
|
|
|
# Arrancar (lee variables de .env automáticamente)
|
|
bash backend/start-wordpress.sh &
|
|
```
|
|
|
|
El servidor escucha en `0.0.0.0:8081` (todas las interfaces) gracias a `WP_HOST=0.0.0.0` en `.env`.
|
|
|
|
---
|
|
|
|
## 5. Plugins activos y su función
|
|
|
|
| Plugin | Propósito | Gratuito |
|
|
|--------|-----------|----------|
|
|
| `cmb2/init.php` | Campos personalizados en el admin (repeaters, options pages) | ✓ GPL |
|
|
| `pflores-cv-fields/pflores-cv-fields.php` | Páginas de opciones + función `pflores_get_cv_data()` + PDF | ✓ propio |
|
|
|
|
**Activar / verificar plugins en la BD:**
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "SELECT option_value FROM cv_options WHERE option_name='active_plugins';"
|
|
```
|
|
|
|
El valor correcto debe ser:
|
|
```
|
|
a:2:{i:0;s:13:"cmb2/init.php";i:1;s:39:"pflores-cv-fields/pflores-cv-fields.php";}
|
|
```
|
|
|
|
Si no, corregirlo:
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "UPDATE cv_options SET option_value='a:2:{i:0;s:13:\"cmb2/init.php\";i:1;s:39:\"pflores-cv-fields/pflores-cv-fields.php\";}' WHERE option_name='active_plugins';"
|
|
```
|
|
|
|
> ⚠ La serialización PHP es estricta: `s:N:` donde N es la longitud exacta en bytes.
|
|
> Siempre genera el valor con `php -r "echo serialize(['cmb2/init.php','pflores-cv-fields/pflores-cv-fields.php']);"`.
|
|
|
|
---
|
|
|
|
## 6. Cambiar el tema activo
|
|
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "UPDATE cv_options SET option_value='SLUG_TEMA' WHERE option_name IN('template','stylesheet');"
|
|
```
|
|
|
|
| Slug | Tema |
|
|
|------|------|
|
|
| `persona-cv` | **Activo por defecto** — Personage-style, secciones alternas, rojo |
|
|
| `lumina` | Claro, teal+ámbar, sidebar izquierdo, foto circular |
|
|
| `apex-cv` | Oscuro, cian eléctrico, sidebar fijo |
|
|
| `cvolio` | Oscuro glassmorphism, paleta café/tostado |
|
|
|
|
---
|
|
|
|
## 7. Arquitectura de datos — CMB2
|
|
|
|
Todos los datos del CV se almacenan en `wp_options` (prefijo `cv_`) como arrays PHP serializados. Se acceden con `get_option('clave')`.
|
|
|
|
| Clave `wp_options` | Contenido |
|
|
|--------------------|-----------|
|
|
| `pflores_perfil` | Nombre, cargo, intro, resumen, contacto, foto |
|
|
| `pflores_experiencia` | Array de cargos con bullets |
|
|
| `pflores_formacion` | Títulos académicos + certificaciones |
|
|
| `pflores_competencias` | Grupos de habilidades con porcentajes |
|
|
| `pflores_extras` | Métricas, highlights, impacto, voluntariado |
|
|
|
|
**Función central de lectura:**
|
|
```php
|
|
pflores_get_cv_data(): array
|
|
// Retorna la misma estructura que todos los temas esperan.
|
|
// Si CMB2 no está disponible, devuelve pflores_cv_fallback_data().
|
|
```
|
|
|
|
**Estructura del array retornado:**
|
|
```php
|
|
[
|
|
'hero' => ['name','role','role2','intro','location','email',
|
|
'phone','linkedin','availability','focus','languages',
|
|
'born','id','web','eyebrow'],
|
|
'photo' => 'URL de la imagen de perfil (o vacío)',
|
|
'summary' => ['title','body'],
|
|
'metrics' => [['value','suffix','label'], ...], // 5 contadores
|
|
'highlights' => [['value','suffix','label'], ...], // 4 logros grandes
|
|
'impact' => [['title','body'], ...], // 3 áreas
|
|
'experience' => [['period','title','company','location','lead','bullets'=>[...]], ...],
|
|
'education' => [['year','title','institution','detail'], ...],
|
|
'certifications' => [['year','title','issuer'], ...],
|
|
'competencies' => ['Grupo' => [['name','pct'], ...], ...],
|
|
'volunteer' => ['title','year','body'],
|
|
'additional' => ['Idiomas'=>'...','Disponibilidad'=>'...','C.I.'=>'...', ...],
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Editar datos del CV desde el admin
|
|
|
|
URL del admin: `https://pflores.linkedcorp.net/wp-admin`
|
|
- Usuario: `pflores`
|
|
- Contraseña: en `.env` como `WP_ADMIN_PASSWORD`
|
|
|
|
En el menú lateral aparece **"CV Patricia Flores"** con sub-páginas:
|
|
- **Perfil** → datos personales, foto, disponibilidad
|
|
- **Experiencia** → cargos (repeater, arrastrable)
|
|
- **Formación** → títulos + certificaciones
|
|
- **Competencias** → grupos de habilidades con porcentajes
|
|
- **Métricas / Impacto** → contadores, logros, áreas de impacto, voluntariado
|
|
|
|
---
|
|
|
|
## 9. Agregar un nuevo campo al CV
|
|
|
|
### 9a. Campo simple (texto, email, URL)
|
|
|
|
**Paso 1** — Registrar el campo en `pflores-cv-fields.php` dentro de la función `pflores_register_pages()`:
|
|
|
|
```php
|
|
// Ejemplo: añadir "Twitter/X" al perfil
|
|
$perfil->add_field([
|
|
'id' => 'pf_twitter',
|
|
'name' => 'Twitter / X URL',
|
|
'type' => 'text_url',
|
|
]);
|
|
```
|
|
|
|
**Paso 2** — Añadir la lectura en `pflores_get_cv_data()`:
|
|
```php
|
|
'hero' => [
|
|
// ... campos existentes ...
|
|
'twitter' => $perfil['pf_twitter'] ?? '',
|
|
],
|
|
```
|
|
|
|
**Paso 3** — Usarlo en el `front-page.php` de cada tema:
|
|
```php
|
|
$twitter = $hero['twitter'] ?? '';
|
|
if ($twitter) : ?>
|
|
<a href="<?php echo esc_url($twitter); ?>">Twitter</a>
|
|
<?php endif; ?>
|
|
```
|
|
|
|
**Paso 4** — Si el campo debe aparecer en el PDF, añadirlo en `pdf-generator.php` dentro de `pflores_build_cv_html()`.
|
|
|
|
---
|
|
|
|
### 9b. Nuevo grupo repetible (como experiencia o certificaciones)
|
|
|
|
**Paso 1** — Registrar un nuevo CMB2 box con group en `pflores_register_pages()`:
|
|
|
|
```php
|
|
$premios = new_cmb2_box([
|
|
'id' => 'pflores_premios',
|
|
'title' => 'Premios y reconocimientos',
|
|
'object_types' => ['options-page'],
|
|
'option_key' => 'pflores_premios', // nombre de la opción en BD
|
|
'parent_slug' => 'pflores_perfil', // sub-menú bajo el menú principal
|
|
'menu_title' => 'Premios',
|
|
'save_button' => 'Guardar cambios',
|
|
'capability' => 'manage_options',
|
|
]);
|
|
|
|
$gr = $premios->add_field([
|
|
'id' => 'pf_awards',
|
|
'type' => 'group',
|
|
'options' => ['group_title' => 'Premio {#}', 'add_button' => 'Añadir premio',
|
|
'remove_button' => 'Eliminar', 'sortable' => true, 'closed' => true],
|
|
]);
|
|
$premios->add_group_field($gr, ['id' => 'year', 'name' => 'Año', 'type' => 'text']);
|
|
$premios->add_group_field($gr, ['id' => 'title', 'name' => 'Título', 'type' => 'text']);
|
|
$premios->add_group_field($gr, ['id' => 'org', 'name' => 'Organización','type' => 'text']);
|
|
```
|
|
|
|
**Paso 2** — Leer los datos en `pflores_get_cv_data()`:
|
|
```php
|
|
$premiosOpts = get_option('pflores_premios', []);
|
|
$awards = [];
|
|
foreach ((array) ($premiosOpts['pf_awards'] ?? []) as $item) {
|
|
$awards[] = ['year' => $item['year'] ?? '', 'title' => $item['title'] ?? '', 'org' => $item['org'] ?? ''];
|
|
}
|
|
// Agregar 'awards' => $awards al array retornado
|
|
```
|
|
|
|
**Paso 3** — Renderizarlo en `front-page.php` de cada tema.
|
|
|
|
**Paso 4** — Poblar datos iniciales añadiendo al `populate-data.php`:
|
|
```php
|
|
update_option('pflores_premios', [
|
|
'pf_awards' => [
|
|
['year' => '2025', 'title' => 'Premio Excelencia', 'org' => 'Fundación FACES'],
|
|
],
|
|
]);
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Modificar datos existentes
|
|
|
|
**Opción A** — Desde el admin de WordPress (recomendado):
|
|
- Ir a `wp-admin` → **CV Patricia Flores** → sub-página correspondiente → editar → Guardar.
|
|
|
|
**Opción B** — Directo en BD (para migraciones o correcciones masivas):
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 -e "
|
|
UPDATE cv_options SET option_value = 'Nuevo valor' WHERE option_name = 'pflores_perfil';
|
|
"
|
|
```
|
|
> Para campos dentro de arrays (repeaters), es más fácil editar desde el admin o re-ejecutar `populate-data.php`.
|
|
|
|
**Re-ejecutar el poblador de datos** (si se necesita resetear todo):
|
|
```
|
|
https://pflores.linkedcorp.net/wp-content/plugins/pflores-cv-fields/populate-data.php?key=pflores2024
|
|
```
|
|
> ⚠ Esto sobreescribe TODOS los datos con los valores del archivo `populate-data.php`.
|
|
|
|
---
|
|
|
|
## 11. Crear un nuevo tema
|
|
|
|
### Convenciones obligatorias
|
|
|
|
1. **Directorio**: Crear **directamente** en `backend/wordpress/wp-content/themes/NOMBRE-cv/` con subdirectorios `assets/{css,js,images,docs}` e `inc/`.
|
|
> ⚠ **No usar symlink** — el tema `apex-cv` demostró que los archivos en `frontend/` desaparecen cuando WordPress activa/desactiva temas. El directorio real dentro de `wp-content/themes/` es la única forma estable.
|
|
2. **Text Domain**: usar `nombre` (minúsculas, sin guiones).
|
|
3. **Prefijo de funciones**: `nombre_` (ej: `nova_setup()`, `nova_render_nav()`).
|
|
4. **Prefijo CSS**: `nv-` (2-3 letras, sin conflictos con `pn-`, `lm-`, `ax-`, `cv-`).
|
|
5. **Copiar assets**: copiar imágenes y docs desde cualquier tema existente:
|
|
```bash
|
|
cp frontend/persona-cv-theme/assets/images/* backend/wordpress/wp-content/themes/NOMBRE-cv/assets/images/
|
|
cp frontend/persona-cv-theme/assets/docs/* backend/wordpress/wp-content/themes/NOMBRE-cv/assets/docs/
|
|
```
|
|
|
|
### Archivos mínimos requeridos
|
|
|
|
```
|
|
NOMBRE-cv-theme/
|
|
├── style.css # Cabecera del tema (Theme Name, Text Domain, Version...)
|
|
├── functions.php # apex_setup, enqueue, nav helpers
|
|
├── header.php # <html><head> + nav + botón PDF
|
|
├── footer.php # </body></html>
|
|
├── front-page.php # TODA la lógica y HTML del CV
|
|
├── index.php # Fallback vacío o mínimo
|
|
└── inc/
|
|
├── cv-data.php # Función NOMBRE_cv_data() con fallback hardcodeado
|
|
├── customizer.php # Opcional, puede estar vacío
|
|
└── visits.php # Contador de visitas (copiar de otro tema y renombrar funciones)
|
|
```
|
|
|
|
### Estructura obligatoria de `functions.php`
|
|
|
|
```php
|
|
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once get_template_directory() . '/inc/customizer.php';
|
|
require_once get_template_directory() . '/inc/cv-data.php';
|
|
require_once get_template_directory() . '/inc/visits.php';
|
|
|
|
function NOMBRE_setup(): void { /* add_theme_support, register_nav_menus */ }
|
|
add_action('after_setup_theme', 'NOMBRE_setup');
|
|
|
|
function NOMBRE_enqueue_assets(): void {
|
|
// Cargar Google Font + CSS + JS
|
|
wp_enqueue_style('NOMBRE-fonts', 'https://fonts.googleapis.com/...', [], null);
|
|
wp_enqueue_style('NOMBRE-theme', get_template_directory_uri() . '/assets/css/theme.css', ['NOMBRE-fonts'], '1.0.0');
|
|
wp_enqueue_script('NOMBRE-theme', get_template_directory_uri() . '/assets/js/theme.js', [], '1.0.0', true);
|
|
}
|
|
add_action('wp_enqueue_scripts', 'NOMBRE_enqueue_assets');
|
|
|
|
function NOMBRE_render_nav(): string { /* nav links con IDs de sección */ }
|
|
```
|
|
|
|
### Estructura obligatoria de `front-page.php`
|
|
|
|
```php
|
|
<?php
|
|
declare(strict_types=1);
|
|
get_header();
|
|
|
|
// ► SIEMPRE usar esta línea para obtener los datos:
|
|
$cv = function_exists('pflores_get_cv_data') ? pflores_get_cv_data() : NOMBRE_cv_data();
|
|
|
|
$hero = $cv['hero'];
|
|
$metrics = $cv['metrics'];
|
|
$highlights = $cv['highlights'];
|
|
$summary = $cv['summary'];
|
|
$impact = $cv['impact'];
|
|
$experience = $cv['experience'];
|
|
$education = $cv['education'];
|
|
$certifications = $cv['certifications'];
|
|
$competencies = $cv['competencies'];
|
|
$volunteer = $cv['volunteer'];
|
|
$additional = $cv['additional'];
|
|
|
|
// Foto de perfil: CMB2 primero, si no la imagen local del tema
|
|
$acfPhoto = $cv['photo'] ?? '';
|
|
$profileImage = $acfPhoto ?: get_template_directory_uri() . '/assets/images/patricia-flores-profile.jpeg';
|
|
|
|
// QR y URL pública
|
|
$qrImage = get_template_directory_uri() . '/assets/images/patricia-flores-qr.png';
|
|
$publicUrl = 'https://pflores.linkedcorp.net';
|
|
// ► NO usar $cvFile para botones de descarga — usar siempre home_url('/?cv_pdf=1')
|
|
|
|
// Variables de conveniencia del hero
|
|
$heroName = $hero['name'];
|
|
$heroRole = $hero['role'];
|
|
$heroEmail = $hero['email'];
|
|
$heroPhone = $hero['phone'];
|
|
$heroLocation = $hero['location'];
|
|
$linkedin = $hero['linkedin'];
|
|
|
|
/* ... HTML del tema aquí ... */
|
|
|
|
get_footer();
|
|
```
|
|
|
|
### Iteración sobre competencias (compatibilidad CMB2 + fallback)
|
|
|
|
Los temas deben manejar ambos formatos de competencias:
|
|
|
|
```php
|
|
<?php foreach ($competencies as $group => $items) : ?>
|
|
<h3><?php echo esc_html($group); ?></h3>
|
|
<?php foreach ($items as $item) :
|
|
// ► SIEMPRE usar esta normalización:
|
|
$skillName = is_array($item) ? ($item['name'] ?? '') : (string) $item;
|
|
$skillPct = is_array($item) ? ($item['pct'] ?? 80) : 80;
|
|
?>
|
|
<span><?php echo esc_html($skillName); ?></span>
|
|
<?php // Si el tema muestra barras de progreso: ?>
|
|
<div style="width:<?php echo esc_attr((string)$skillPct); ?>%"></div>
|
|
<?php endforeach; ?>
|
|
<?php endforeach; ?>
|
|
```
|
|
|
|
### Botón de descarga PDF (obligatorio en todos los temas)
|
|
|
|
```php
|
|
<!-- En header.php o sidebar, reemplazar cualquier botón de "Imprimir" por: -->
|
|
<a class="btn-pdf" href="<?php echo esc_url(home_url('/?cv_pdf=1')); ?>" target="_blank">
|
|
Descargar CV PDF
|
|
</a>
|
|
```
|
|
|
|
### LOPDP — 3 requisitos obligatorios en todo tema nuevo
|
|
|
|
**1. Navegación con URLs absolutas** — en `functions.php`, la función que genera el menú debe usar `home_url('/')` como base cuando no se está en el front page:
|
|
|
|
```php
|
|
function NOMBRE_render_nav(): string {
|
|
// ...
|
|
$base = is_front_page() ? '' : home_url('/');
|
|
$items = [
|
|
$base . '#sobre-mi' => 'Sobre mí',
|
|
$base . '#experiencia' => 'Experiencia',
|
|
// ... resto de anclas igual
|
|
];
|
|
// ...
|
|
}
|
|
```
|
|
|
|
Sin esto, los links del menú quedan como `#sobre-mi` en la página de política de privacidad y no llevan de vuelta al CV.
|
|
|
|
**2. `index.php` estilizado** — reescribir con el estilo del tema, botón "Volver al CV" y tipografía coherente. Ver los existentes como referencia: `frontend/persona-cv-theme/index.php`.
|
|
|
|
**3. Link de privacidad en el footer** — en `footer.php` o en la sección del copyright de `front-page.php`:
|
|
|
|
```php
|
|
<a href="<?php echo esc_url(home_url('/politica-de-privacidad/')); ?>"
|
|
style="opacity:.5;text-decoration:underline;font-size:.75rem;color:inherit">
|
|
Política de Privacidad · LOPDP
|
|
</a>
|
|
```
|
|
|
|
> El banner LOPDP y la página de política son globales — están en el plugin `pflores-cv-fields.php`, no en cada tema. Solo el link del footer y el index.php deben adaptarse por tema.
|
|
|
|
### `inc/cv-data.php` — función de fallback
|
|
|
|
Debe contener **todos los datos reales** de Patricia Flores, idénticos a los que están en la BD. Copiar la función de otro tema y renombrar a `NOMBRE_cv_data()`.
|
|
|
|
> ⚠ Las competencias del fallback deben tener formato array:
|
|
> `['name' => 'Gestión operativa', 'pct' => 95]`
|
|
|
|
### Activar el nuevo tema
|
|
|
|
```bash
|
|
# El directorio ya existe en wp-content/themes/NOMBRE-cv/ — solo activar en la BD:
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "UPDATE cv_options SET option_value='NOMBRE-cv' WHERE option_name IN('template','stylesheet');"
|
|
```
|
|
|
|
### Versionar el nuevo tema
|
|
|
|
Al estar en `wp-content/themes/` directamente, añadir al staging explícitamente:
|
|
```bash
|
|
git add backend/wordpress/wp-content/themes/NOMBRE-cv/
|
|
git commit -m "feat: nuevo tema NOMBRE-cv"
|
|
```
|
|
|
|
> ⚠ **Evitar el slug `apex`** (existe un tema comercial con ese nombre en WordPress.org).
|
|
> Usar siempre slugs compuestos: `nova-cv`, `slate-cv`, `forma-cv`, etc.
|
|
|
|
---
|
|
|
|
## 12. Crear / modificar menús de navegación
|
|
|
|
Los menús de navegación son listas de anclas (`#seccion`) dentro del mismo tema. No se usan menús de WordPress por defecto.
|
|
|
|
### Modificar los ítems del menú en un tema
|
|
|
|
En `functions.php` de cada tema, hay una función `NOMBRE_render_nav()`:
|
|
|
|
```php
|
|
function persona_render_nav(): string {
|
|
$items = [
|
|
'#sobre-mi' => 'Sobre mí',
|
|
'#impacto' => 'Impacto',
|
|
'#experiencia' => 'Experiencia',
|
|
'#formacion' => 'Formación',
|
|
'#competencias' => 'Competencias',
|
|
'#certificaciones' => 'Certificaciones',
|
|
'#contacto' => 'Contacto',
|
|
];
|
|
// Para añadir un ítem: '#premios' => 'Premios',
|
|
// Para eliminar: quitar la línea correspondiente
|
|
// Para reordenar: cambiar el orden del array
|
|
...
|
|
}
|
|
```
|
|
|
|
El `href` debe coincidir con el `id` de la sección en `front-page.php`:
|
|
```html
|
|
<section id="premios"> <!-- El ID debe ser igual al href sin el # -->
|
|
```
|
|
|
|
### Usar menús de WordPress (avanzado)
|
|
|
|
Si se registra un menú en `functions.php`:
|
|
```php
|
|
register_nav_menus(['primary' => __('Menú principal', 'persona')]);
|
|
```
|
|
|
|
Se puede asignar desde `wp-admin` → **Apariencia → Menús** y el tema lo detectará automáticamente si `has_nav_menu('primary')` retorna `true`.
|
|
|
|
---
|
|
|
|
## 13. Generador de PDF
|
|
|
|
**Endpoint:** `https://pflores.linkedcorp.net/?cv_pdf=1`
|
|
|
|
**Cómo funciona** (`pdf-generator.php`):
|
|
1. Se activa con `get_query_var('cv_pdf') === '1'`
|
|
2. Llama a `pflores_get_cv_data()` para obtener todos los datos actuales
|
|
3. Genera HTML limpio con CSS embebido (formato A4, 2 columnas)
|
|
4. Escribe el HTML en un archivo temporal
|
|
5. Ejecuta Chromium headless: `chromium --headless --no-sandbox --print-to-pdf=... file://...`
|
|
6. Lee el PDF resultante y lo devuelve con headers de descarga
|
|
7. Limpia los archivos temporales
|
|
|
|
**Modificar el layout del PDF:**
|
|
|
|
Todo el diseño está en la función `pflores_build_cv_html()` dentro de `pdf-generator.php`. Modificar el CSS dentro de la variable `$css` o el HTML de cada sección.
|
|
|
|
**Añadir una nueva sección al PDF** (ej: Premios):
|
|
|
|
```php
|
|
// En pflores_build_cv_html(), después de certificaciones:
|
|
$awardsHtml = '';
|
|
foreach ($awards as $a) {
|
|
$awardsHtml .= '<div class="cert-item">...';
|
|
}
|
|
|
|
// Y en el HTML final:
|
|
'<p class="sec-title">Premios y reconocimientos</p>' . $awardsHtml .
|
|
```
|
|
|
|
---
|
|
|
|
## 14. Archivo `.env`
|
|
|
|
```
|
|
WP_ENV=local
|
|
WP_HOST=0.0.0.0
|
|
WP_PORT=8081
|
|
WP_URL=http://192.168.222.40:8081
|
|
|
|
DB_NAME=paty.wordpress
|
|
DB_USER=paty.wordpress
|
|
DB_PASSWORD=paty.wordpress
|
|
DB_HOST=192.168.222.20
|
|
DB_PREFIX=cv_
|
|
|
|
WP_ADMIN_USER=pflores
|
|
WP_ADMIN_PASSWORD=HXk4boxuI1QYum3jKL
|
|
```
|
|
|
|
---
|
|
|
|
## 15. Configuración `wp-config.php` clave
|
|
|
|
```php
|
|
// Auto-updates DESACTIVADAS (protege archivos de temas y plugins locales)
|
|
define('AUTOMATIC_UPDATER_DISABLED', true);
|
|
define('WP_AUTO_UPDATE_CORE', false);
|
|
|
|
// URL dinámica — funciona con cualquier IP o dominio, y detrás de proxy SSL (NPM)
|
|
$_wpIsHttps = /* detecta X-Forwarded-Proto: https */;
|
|
define('WP_HOME', $_wpProto . '://' . $_wpHost);
|
|
define('WP_SITEURL', $_wpProto . '://' . $_wpHost);
|
|
```
|
|
|
|
---
|
|
|
|
## 16. Convenciones de código
|
|
|
|
| Elemento | Convención |
|
|
|----------|-----------|
|
|
| PHP | `declare(strict_types=1)` en todos los archivos |
|
|
| Funciones WordPress | Usar `esc_html()`, `esc_url()`, `esc_attr()` en toda salida HTML |
|
|
| Prefijos | Funciones y opciones siempre con prefijo del plugin/tema para evitar conflictos |
|
|
| Comentarios | Solo cuando el "por qué" no es obvio. Sin comentarios de "qué hace" |
|
|
| Serialización PHP en SQL | Generar con `php -r "echo serialize([...]);"` — nunca manual |
|
|
| Auto-updates WP | **Siempre desactivadas** — no tocar `wp-config.php` en ese bloque |
|
|
|
|
---
|
|
|
|
## 17. Tareas comunes — referencia rápida
|
|
|
|
### Verificar que todo funciona
|
|
```bash
|
|
curl -s http://127.0.0.1:8081/ | grep -c "Patricia Soledad"
|
|
# Debe retornar >= 1
|
|
```
|
|
|
|
### Ver el tema activo
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "SELECT option_value FROM cv_options WHERE option_name='template';" 2>/dev/null
|
|
```
|
|
|
|
### Ver todos los datos del CV en BD
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "SELECT option_name, LENGTH(option_value) as bytes FROM cv_options WHERE option_name LIKE 'pflores_%' ORDER BY option_name;" 2>/dev/null
|
|
```
|
|
|
|
### Limpiar caché de WordPress (transients)
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "DELETE FROM cv_options WHERE option_name LIKE '_site_transient_%' OR option_name LIKE '_transient_%';" 2>/dev/null
|
|
```
|
|
|
|
### Verificar los 4 temas en un loop
|
|
```bash
|
|
for slug in persona-cv lumina apex-cv cvolio; do
|
|
mysql -u "paty.wordpress" -p"paty.wordpress" -h 192.168.222.20 "paty.wordpress" --ssl=0 \
|
|
-e "UPDATE cv_options SET option_value='$slug' WHERE option_name IN('template','stylesheet');" 2>/dev/null
|
|
sleep 0.4
|
|
count=$(curl -s http://127.0.0.1:8081/ | grep -c "Patricia Soledad" || true)
|
|
echo "[$slug] Patricia aparece: $count veces"
|
|
done
|
|
# Restaurar:
|
|
mysql ... -e "UPDATE cv_options SET option_value='persona-cv' WHERE option_name IN('template','stylesheet');"
|
|
```
|
|
|
|
### Probar la descarga del PDF
|
|
```bash
|
|
curl -sI http://127.0.0.1:8081/?cv_pdf=1 | grep -E "Content-Type|Content-Disposition"
|
|
# Debe mostrar: application/pdf y attachment; filename="CV_Patricia_Flores_Sanchez.pdf"
|
|
```
|
|
|
|
### Comprobar PHP syntax de un tema
|
|
```bash
|
|
php -l /ruta/al/tema/front-page.php
|
|
php -l /ruta/al/tema/functions.php
|
|
```
|
|
|
|
---
|
|
|
|
## 18. Errores frecuentes y soluciones
|
|
|
|
| Error | Causa probable | Solución |
|
|
|-------|---------------|----------|
|
|
| Página en blanco o "error crítico" | PHP fatal en el tema | Ver `debug.log`, buscar la línea del error |
|
|
| CSS sin cargar / página sin estilos | Mixed content (HTTP vs HTTPS) | Verificar `wp-config.php` — bloque de proxy SSL |
|
|
| CMB2 / plugin no carga | Serialización incorrecta en `active_plugins` | Regenerar con `php -r "echo serialize([...]);"` |
|
|
| `pflores_get_cv_data()` retorna vacío | Datos no guardados en BD | Re-ejecutar `populate-data.php?key=pflores2024` + limpiar caché |
|
|
| Apex-cv vacío o sin archivos | Tema apex-cv depende de directorio real, no symlink | Los archivos van en `wp-content/themes/apex-cv/`, no en `frontend/` |
|
|
| CSS/JS con 404 tras clonar en servidor nuevo | Symlinks corruptos o rotos | Los symlinks en git usan **ruta relativa** (`../../../../frontend/...`) — si están rotos, ver `PRODUCCION.md` → Problemas conocidos |
|
|
| 502 persistente en favicon u otros estáticos tras haberlo corregido | NPM **Cache Assets** cachéo la respuesta 502/404 anterior | En NPM: desactivar Cache Assets → guardar → reactivar → guardar. Para CV puede quedar desactivado. |
|
|
| PDF vacío o error 500 | Chromium no encontrado o falla | `which chromium chromium-browser google-chrome` |
|
|
| `update_option` no guarda | Caché de WordPress | Limpiar transients (ver sección 17) |
|
|
|
|
---
|
|
|
|
## 19. Acerca de los temas — resumen visual
|
|
|
|
| Tema | Estilo | Layout | Fuente | Acento |
|
|
|------|--------|--------|--------|--------|
|
|
| `persona-cv` | Personage/Pixflow, secciones alternas | Full-width, nav sticky top | Raleway + Open Sans | Rojo `#c0392b` |
|
|
| `lumina` | Claro, moderno, alegre | Sidebar IZQUIERDO fijo | Plus Jakarta Sans | Teal `#0d9488` + Ámbar |
|
|
| `apex-cv` | Oscuro, serio, editorial | Sidebar IZQUIERDO fijo | Space Grotesk | Cian `#22d3ee` + Dorado |
|
|
| `cvolio` | Oscuro glassmorphism | Hero dividido + sidebar DERECHO | Manrope + Cormorant | Café/tostado |
|
|
|
|
---
|
|
|
|
## 20. Notas importantes para la IA asistente
|
|
|
|
1. **No usar ACF** (Advanced Custom Fields). Tiene Repeater solo en versión de pago. Usar CMB2.
|
|
2. **No instalar plugins de pago**. Todo debe ser 100 % gratuito.
|
|
3. **No tocar el bloque de auto-updates** en `wp-config.php`.
|
|
4. **Verificar serialización PHP** antes de cualquier `UPDATE` en `active_plugins` o similar.
|
|
5. **Limpiar caché** después de modificar datos en BD directamente.
|
|
6. **La foto de perfil** es `assets/images/patricia-flores-profile.jpeg` en cada tema — NO usar el placeholder SVG como defecto.
|
|
7. **El CV en docx** (`CV_Patricia_Flores_Sanchez_ES_FINAL.docx`) es solo para descarga — el contenido de la web se gestiona por CMB2.
|
|
8. **El PDF** se genera dinámicamente con Chromium desde `/?cv_pdf=1` — no hay PDF estático.
|
|
9. **Los 4 temas leen de CMB2** mediante `pflores_get_cv_data()`. Si esa función no existe (plugin inactivo), cada tema usa su propio fallback hardcodeado.
|
|
10. **Siempre verificar** con `curl -s http://127.0.0.1:8081/ | grep -c "Patricia Soledad"` que el sitio responde correctamente después de cualquier cambio.
|
|
|
|
---
|
|
|
|
## 21. Git y Gitea — versionar y subir
|
|
|
|
### Repositorio
|
|
|
|
- **Remoto:** `https://gitea.linkedcorp.net/mgonzalez/pflores.linkedcorp.net.git`
|
|
- **Rama:** `main`
|
|
- **Credenciales:** archivo local `.token_gitea` (nunca versionado)
|
|
|
|
### Flujo estándar de commit + push
|
|
|
|
```bash
|
|
# 1. Revisar qué cambió
|
|
git status
|
|
git diff --stat
|
|
|
|
# 2. Agregar archivos — SELECTIVO (nunca git add -A sin revisar)
|
|
git add frontend/ # temas propios
|
|
git add backend/wordpress/wp-content/plugins/pflores-cv-fields/
|
|
git add backend/wordpress/wp-content/themes/apex-cv/
|
|
git add backend/wordpress/wp-config.php
|
|
git add CHANGELOG.md VERSION README.md PROMPT_IA.md
|
|
|
|
# 3. Confirmar que .env y .token_gitea NO están en staging
|
|
git status | grep -E "\.env|\.token" # debe retornar vacío
|
|
|
|
# 4. Commit
|
|
git commit -m "tipo: descripción corta"
|
|
# Prefijos: feat: / fix: / docs: / chore: / style:
|
|
|
|
# 5. Push
|
|
git push origin main
|
|
```
|
|
|
|
### Credenciales para push
|
|
|
|
Al hacer `git push` por primera vez pedirá usuario y contraseña:
|
|
- **Usuario:** `mgonzalez`
|
|
- **Contraseña:** Personal Access Token (NO la contraseña web de Gitea)
|
|
|
|
Crear token: `https://gitea.linkedcorp.net/user/settings/applications`
|
|
|
|
Para no escribir credenciales cada vez:
|
|
```bash
|
|
git config credential.helper store
|
|
# La primera vez las guarda; las siguientes son automáticas
|
|
```
|
|
|
|
Guardar también en `.token_gitea` (local, nunca versionar):
|
|
```text
|
|
# Token gitea
|
|
usuario: mgonzalez
|
|
token: [token de gitea.linkedcorp.net]
|
|
```
|
|
|
|
### Qué SE versiona vs qué NO
|
|
|
|
**SE versiona:**
|
|
- `frontend/` (todos los temas propios)
|
|
- `backend/wordpress/wp-content/plugins/pflores-cv-fields/`
|
|
- `backend/wordpress/wp-content/themes/apex-cv/`
|
|
- `backend/wordpress/wp-config.php`
|
|
- `backend/start-wordpress.sh`, `docs/`, `*.md`, `VERSION`
|
|
- `CV_Patricia_Flores_Sanchez_ES_FINAL.docx`, imágenes del CV
|
|
|
|
**NO se versiona:**
|
|
- `.env`, `.token_gitea`, `LOCAL_DEPLOY_CONTEXT.md`
|
|
- WordPress core (`wp-admin/`, `wp-includes/`)
|
|
- Plugins de terceros (`cmb2/`, `wp-mail-smtp/`)
|
|
- Temas por defecto de WP (`twenty*/`)
|
|
- `wp-content/debug.log`, `uploads/`, `languages/`
|
|
|
|
### Versionar antes de hacer push
|
|
|
|
Ver `VERSIONADO.md` para decidir si subir `X`, `Y` o `Z`:
|
|
```bash
|
|
# Actualizar VERSION
|
|
echo "1.0.1" > VERSION
|
|
|
|
# Anotar cambio en CHANGELOG.md
|
|
# Luego commit y push normal
|
|
```
|
|
|
|
---
|
|
|
|
## 22. Servidor de producción
|
|
|
|
### Datos del servidor
|
|
|
|
- Host: `192.168.222.3`
|
|
- SSH: `deploy@192.168.222.3 -p 2203`
|
|
- `deploy` tiene sudo NOPASSWD
|
|
- Ruta app: `/opt/apps/pflores.linkedcorp.net`
|
|
- Servicio systemd: `pflores-web.service`
|
|
- Puerto: `0.0.0.0:8081`
|
|
- NPM proxy: `pflores.linkedcorp.net` → `192.168.222.3:8081`
|
|
|
|
> ⚠ El servicio **debe** escuchar en `0.0.0.0:8081`, no en `127.0.0.1`. NPM llega desde fuera del loopback — si queda en `127.0.0.1` el resultado es **502 Bad Gateway**.
|
|
|
|
Credenciales SSH: ver `LOCAL_DEPLOY_CONTEXT.md`
|
|
|
|
### Estructura en producción
|
|
|
|
```
|
|
/opt/apps/pflores.linkedcorp.net/
|
|
├── backend/wordpress/ ← WordPress + temas + plugins
|
|
├── frontend/ ← temas (lumina, persona-cv, cvolio via symlink)
|
|
├── scripts/deploy_prod_web.sh ← script de deploy
|
|
└── .env ← config producción (local, nunca versionar)
|
|
```
|
|
|
|
### Deploy recurrente (flujo completo)
|
|
|
|
```bash
|
|
# 1. En desarrollo: commit + push a Gitea (ver sección 21)
|
|
|
|
# 2. En el servidor de producción:
|
|
ssh deploy@192.168.222.3 -p 2203
|
|
cd /opt/apps/pflores.linkedcorp.net
|
|
bash scripts/deploy_prod_web.sh
|
|
```
|
|
|
|
El script hace: `git reset --hard` + verificar plugins + `systemctl restart` + verificar HTTP 200.
|
|
|
|
### Comandos útiles en producción
|
|
|
|
```bash
|
|
sudo systemctl status pflores-web
|
|
sudo systemctl restart pflores-web
|
|
sudo journalctl -u pflores-web -n 50 --no-pager
|
|
curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:8081/
|
|
curl -sI http://127.0.0.1:8081/?cv_pdf=1 | grep Content-Type
|
|
```
|
|
|
|
### Plugins de terceros (no en git)
|
|
|
|
Si desaparecen tras un `git reset --hard`, el script de deploy los reinstala automáticamente. También se pueden instalar manualmente:
|
|
|
|
```bash
|
|
cd /opt/apps/pflores.linkedcorp.net/backend/wordpress/wp-content/plugins
|
|
# CMB2
|
|
wget -q https://downloads.wordpress.org/plugin/cmb2.latest-stable.zip -O cmb2.zip && python3 -c "import zipfile; zipfile.ZipFile('cmb2.zip').extractall('.')" && rm cmb2.zip
|
|
# WP Mail SMTP
|
|
wget -q https://downloads.wordpress.org/plugin/wp-mail-smtp.latest-stable.zip -O wpmail.zip && python3 -c "import zipfile; zipfile.ZipFile('wpmail.zip').extractall('.')" && rm wpmail.zip
|
|
```
|
|
|
|
### WordPress core (no en git)
|
|
|
|
Si hay que reinstalar el core de WordPress en el servidor:
|
|
```bash
|
|
cd /opt/apps/pflores.linkedcorp.net/backend/wordpress
|
|
wget -q https://wordpress.org/wordpress-7.0.zip -O /tmp/wp.zip
|
|
python3 -c "
|
|
import zipfile,shutil,os
|
|
z=zipfile.ZipFile('/tmp/wp.zip')
|
|
z.extractall('/tmp/wp_extract')
|
|
src='/tmp/wp_extract/wordpress'
|
|
for d in ['wp-admin','wp-includes']:
|
|
if not os.path.exists(d): shutil.copytree(os.path.join(src,d),d)
|
|
for f in os.listdir(src):
|
|
if os.path.isfile(os.path.join(src,f)): shutil.copy2(os.path.join(src,f),f)
|
|
"
|
|
rm -rf /tmp/wp.zip /tmp/wp_extract
|
|
```
|
|
|
|
---
|
|
|
|
## 23. LOPDP Ecuador — Implementación completa
|
|
|
|
### ¿Qué es y por qué existe?
|
|
|
|
La **Ley Orgánica de Protección de Datos Personales del Ecuador (LOPDP)** exige informar a los visitantes sobre el tratamiento de sus datos. Este sitio usa estadísticas anónimas de visitas (transients de WordPress, eliminados cada hora) con base legal en el **Art. 26 LOPDP — interés legítimo**.
|
|
|
|
### Componentes implementados
|
|
|
|
Todo el código LOPDP vive en `backend/wordpress/wp-content/plugins/pflores-cv-fields/pflores-cv-fields.php` (sección 3).
|
|
|
|
| Componente | Función | Dónde |
|
|
|---|---|---|
|
|
| `router.php` | Permite URLs bonitas (`/politica-de-privacidad/`) en el servidor PHP integrado | `backend/router.php` |
|
|
| Página de política | Creada automáticamente en `admin_init` con contenido completo | BD: `cv_posts`, `post_name = politica-de-privacidad` |
|
|
| Banner LOPDP | `wp_footer` — aparece en todos los temas, se acepta con `localStorage` | `pflores-cv-fields.php` función `pflores_lopd_banner()` |
|
|
| Widget dashboard | Estadísticas de visitas por tema + total | `pflores-cv-fields.php` función `pflores_visitas_widget()` |
|
|
| Link en footer | Cada tema tiene un enlace discreto "Política de Privacidad · LOPDP" | `footer.php` o `front-page.php` de cada tema |
|
|
| Nav con home_url | Menú funciona desde páginas internas | `functions.php` de cada tema |
|
|
| `index.php` estilizado | Páginas internas con estilo del tema + "Volver al CV" | `index.php` de cada tema |
|
|
|
|
### Infraestructura de URLs (router.php)
|
|
|
|
Sin el router, PHP built-in server devuelve 404 para `/politica-de-privacidad/`.
|
|
|
|
El archivo `backend/router.php`:
|
|
```php
|
|
<?php
|
|
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
|
$file = __DIR__ . '/wordpress' . $path;
|
|
if ($path !== '/' && file_exists($file) && !is_dir($file)) { return false; }
|
|
require_once __DIR__ . '/wordpress/index.php';
|
|
```
|
|
|
|
El `start-wordpress.sh` lo usa así:
|
|
```bash
|
|
exec php -S "${WP_HOST}:${WP_PORT}" -t "$WP_DIR" "$ROOT_DIR/backend/router.php"
|
|
```
|
|
|
|
Los permalinks en BD deben estar en `/%postname%/` (ya configurado en dev y prod).
|
|
|
|
### Bugs conocidos del banner — NO repetir
|
|
|
|
| Bug | Descripción | Fix correcto |
|
|
|---|---|---|
|
|
| `display:flex!important` en CSS | Impide que el JS pueda ocultar el banner (`style.display='none'` no funciona) | Usar `display:flex` sin `!important` |
|
|
| `banner.removeAttribute('hidden')` | No muestra el banner correctamente en todos los navegadores | Usar `banner.style.display = 'flex'` |
|
|
|
|
### Actualizar la página de política de privacidad
|
|
|
|
Desde el admin de WordPress: **Páginas → Política de Privacidad → Editar**.
|
|
|
|
O directamente en BD:
|
|
```bash
|
|
mysql -u "paty.wordpress" -p"PASSWORD" -h HOST "paty.wordpress" --ssl=0 -e "
|
|
UPDATE cv_posts SET post_content='NUEVO_CONTENIDO'
|
|
WHERE post_name='politica-de-privacidad' AND post_type='page';"
|
|
```
|
|
|
|
### Si la página de política no existe en producción
|
|
|
|
```bash
|
|
# Verificar
|
|
mysql -u "paty.wordpress" -p"gS0mFSQrdnhSDN2b" -h 192.168.222.32 "paty.wordpress" --ssl=0 \
|
|
-e "SELECT ID, post_name, post_status FROM cv_posts WHERE post_name='politica-de-privacidad';" 2>/dev/null
|
|
|
|
# Si no existe, forzar creación visitando el admin:
|
|
curl -s http://127.0.0.1:8081/wp-admin/admin.php > /dev/null
|
|
# O insertar directamente en BD (ver PRODUCCION.md sección "Problemas conocidos")
|
|
```
|
|
|
|
### Verificación rápida
|
|
|
|
```bash
|
|
# Banner presente en el HTML
|
|
curl -s http://127.0.0.1:8081/ | grep -c "pflores-lopd-banner" # debe ser 5
|
|
|
|
# Página de política accesible
|
|
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8081/politica-de-privacidad/ # debe ser 200
|
|
|
|
# Contenido correcto
|
|
curl -s http://127.0.0.1:8081/politica-de-privacidad/ | grep -c "Art. 26\|LOPDP" # debe ser >= 1
|
|
|
|
# Sin cédula en el HTML público
|
|
curl -s http://127.0.0.1:8081/ | grep "1103591648" # debe retornar vacío
|
|
```
|