feat: sitio CV completo v1.0.0
- 4 temas WordPress: persona-cv (activo), lumina, apex-cv, cvolio - Plugin pflores-cv-fields con CMB2 (100% gratuito) — admin editable - Generador PDF dinámico con Chromium headless (?cv_pdf=1) - Datos del CV de Patricia Flores cargados en CMB2 - URL dinámica con soporte proxy SSL (NPM/X-Forwarded-Proto) - WP Mail SMTP instalado (pendiente config SMTP) - Documentación completa: PROMPT_IA.md, DEPLOY_WEB.md, PRODUCCION.md, VERSIONADO.md
This commit is contained in:
@@ -0,0 +1,499 @@
|
||||
<?php
|
||||
/**
|
||||
* Generador de PDF del CV — replica el diseño del DOCX original.
|
||||
* Endpoint: /?cv_pdf=1 → descarga CV_Patricia_Flores_Sanchez.pdf
|
||||
*
|
||||
* Diseño fiel al DOCX:
|
||||
* - Columna única, A4
|
||||
* - Colores: #1B3A5C (navy), #3A3A3A (cuerpo), #666666 (secundario)
|
||||
* - Fuentes: nombre 19pt, cargos 10pt, cuerpo 9pt, secundario 8pt
|
||||
* - Secciones: MAYÚSCULAS + borde inferior navy
|
||||
* - Cargo + período en la misma línea (izq / der)
|
||||
* - Certificaciones: Título — Emisor Año
|
||||
* - Competencias: Grupo: habilidad · habilidad · ...
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
add_filter('query_vars', function (array $vars): array {
|
||||
$vars[] = 'cv_pdf';
|
||||
return $vars;
|
||||
});
|
||||
|
||||
add_action('template_redirect', 'pflores_handle_pdf_download');
|
||||
function pflores_handle_pdf_download(): void
|
||||
{
|
||||
if ((string) get_query_var('cv_pdf') !== '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
$chromium = pflores_find_chromium();
|
||||
if ($chromium === '') {
|
||||
wp_die('Chromium no disponible en el servidor.', 'Error PDF', ['response' => 500]);
|
||||
}
|
||||
|
||||
$cv = function_exists('pflores_get_cv_data') ? pflores_get_cv_data() : [];
|
||||
$html = pflores_build_cv_html($cv);
|
||||
$ts = time();
|
||||
$tmpDir = sys_get_temp_dir();
|
||||
$htmlFile = $tmpDir . '/cv_pf_' . $ts . '.html';
|
||||
$pdfFile = $tmpDir . '/cv_pf_' . $ts . '.pdf';
|
||||
|
||||
file_put_contents($htmlFile, $html);
|
||||
|
||||
$cmd = escapeshellcmd($chromium)
|
||||
. ' --headless --no-sandbox --disable-gpu'
|
||||
. ' --run-all-compositor-stages-before-draw'
|
||||
. ' --print-to-pdf=' . escapeshellarg($pdfFile)
|
||||
. ' --print-to-pdf-no-header'
|
||||
. ' "file://' . $htmlFile . '"'
|
||||
. ' 2>/dev/null';
|
||||
|
||||
exec($cmd);
|
||||
@unlink($htmlFile);
|
||||
|
||||
if (! file_exists($pdfFile) || filesize($pdfFile) < 1024) {
|
||||
@unlink($pdfFile);
|
||||
wp_die('No se pudo generar el PDF.', 'Error PDF', ['response' => 500]);
|
||||
}
|
||||
|
||||
header('Content-Type: application/pdf');
|
||||
header('Content-Disposition: attachment; filename="CV_Patricia_Flores_Sanchez.pdf"');
|
||||
header('Content-Length: ' . filesize($pdfFile));
|
||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
readfile($pdfFile);
|
||||
@unlink($pdfFile);
|
||||
exit;
|
||||
}
|
||||
|
||||
function pflores_find_chromium(): string
|
||||
{
|
||||
foreach (['chromium', 'chromium-browser', 'google-chrome', 'google-chrome-stable'] as $bin) {
|
||||
$path = trim((string) shell_exec('which ' . escapeshellarg($bin) . ' 2>/dev/null'));
|
||||
if ($path !== '' && file_exists($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
CONSTRUCTOR HTML — réplica fiel del DOCX
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
function pflores_build_cv_html(array $cv): string
|
||||
{
|
||||
/* ── datos ── */
|
||||
$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'] ?? [];
|
||||
|
||||
$name = $hero['name'] ?? '';
|
||||
$role = $hero['role'] ?? '';
|
||||
$role2 = $hero['role2'] ?? '';
|
||||
$location = $hero['location'] ?? '';
|
||||
$email = $hero['email'] ?? '';
|
||||
$phone = $hero['phone'] ?? '';
|
||||
$linkedin = $hero['linkedin'] ?? '';
|
||||
$avail = $hero['availability'] ?? '';
|
||||
$focus = $hero['focus'] ?? '';
|
||||
$langs = $hero['languages'] ?? '';
|
||||
$web = $hero['web'] ?? '';
|
||||
$intro = $hero['intro'] ?? '';
|
||||
|
||||
/* ── helpers ── */
|
||||
$h = fn(string $s): string => htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
$nl = "\n";
|
||||
|
||||
/* ── estilos (replica el DOCX) ── */
|
||||
$css = '
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 16mm 18mm 16mm 18mm;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 9pt;
|
||||
color: #3A3A3A;
|
||||
background: #ffffff;
|
||||
line-height: 1.45;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
|
||||
/* ── CABECERA ── */
|
||||
.cv-name {
|
||||
font-size: 19pt;
|
||||
font-weight: 700;
|
||||
color: #1B3A5C;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.cv-role {
|
||||
font-size: 10pt;
|
||||
font-weight: 700;
|
||||
color: #1B3A5C;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.cv-contact {
|
||||
font-size: 8pt;
|
||||
color: #666666;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cv-contact span { margin: 0 4px; }
|
||||
|
||||
/* ── SECCIONES ── */
|
||||
.sec {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.sec-title {
|
||||
font-size: 10pt;
|
||||
font-weight: 700;
|
||||
color: #1B3A5C;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .04em;
|
||||
border-bottom: 1.5px solid #1B3A5C;
|
||||
padding-bottom: 2px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* ── PERFIL ── */
|
||||
.profile-text {
|
||||
font-size: 9pt;
|
||||
color: #3A3A3A;
|
||||
line-height: 1.55;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/* ── EXPERIENCIA ── */
|
||||
.exp-item { margin-bottom: 8px; }
|
||||
.exp-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
.exp-title {
|
||||
font-size: 10pt;
|
||||
font-weight: 700;
|
||||
color: #1B3A5C;
|
||||
}
|
||||
.exp-period {
|
||||
font-size: 9pt;
|
||||
color: #3A3A3A;
|
||||
font-style: italic;
|
||||
white-space: nowrap;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.exp-company {
|
||||
font-size: 9pt;
|
||||
color: #666666;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.exp-desc {
|
||||
font-size: 9pt;
|
||||
color: #3A3A3A;
|
||||
margin-bottom: 3px;
|
||||
font-style: italic;
|
||||
}
|
||||
.exp-bullets {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.exp-bullets li {
|
||||
font-size: 9pt;
|
||||
color: #3A3A3A;
|
||||
padding-left: 12px;
|
||||
position: relative;
|
||||
margin-bottom: 2px;
|
||||
line-height: 1.45;
|
||||
text-align: justify;
|
||||
}
|
||||
.exp-bullets li::before {
|
||||
content: "•";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #1B3A5C;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ── FORMACIÓN ── */
|
||||
.edu-item {
|
||||
margin-bottom: 6px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.edu-left { flex: 1; }
|
||||
.edu-degree {
|
||||
font-size: 9pt;
|
||||
font-weight: 700;
|
||||
color: #1B3A5C;
|
||||
}
|
||||
.edu-institution {
|
||||
font-size: 8pt;
|
||||
color: #666666;
|
||||
margin-top: 1px;
|
||||
}
|
||||
.edu-detail {
|
||||
font-size: 8pt;
|
||||
color: #666666;
|
||||
font-style: italic;
|
||||
margin-top: 1px;
|
||||
}
|
||||
.edu-year {
|
||||
font-size: 9pt;
|
||||
font-weight: 700;
|
||||
color: #1B3A5C;
|
||||
white-space: nowrap;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* ── CERTIFICACIONES ── */
|
||||
.cert-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 8pt;
|
||||
color: #3A3A3A;
|
||||
margin-bottom: 2.5px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.cert-title { flex: 1; padding-right: 8px; }
|
||||
.cert-year { color: #1B3A5C; font-weight: 700; white-space: nowrap; }
|
||||
|
||||
/* ── COMPETENCIAS ── */
|
||||
.comp-line {
|
||||
font-size: 9pt;
|
||||
color: #3A3A3A;
|
||||
margin-bottom: 3px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.comp-line strong { color: #1B3A5C; }
|
||||
|
||||
/* ── VOLUNTARIADO / ADICIONAL ── */
|
||||
.vol-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
.vol-title { font-size: 9pt; font-weight: 700; color: #1B3A5C; }
|
||||
.vol-year { font-size: 9pt; font-weight: 700; color: #1B3A5C; }
|
||||
.vol-body { font-size: 9pt; color: #3A3A3A; line-height: 1.45; margin-top: 1px; }
|
||||
|
||||
.add-line {
|
||||
font-size: 9pt;
|
||||
color: #3A3A3A;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.add-line strong { color: #1B3A5C; }
|
||||
|
||||
.cv-footer-line {
|
||||
font-size: 8pt;
|
||||
color: #999999;
|
||||
text-align: right;
|
||||
margin-top: 8px;
|
||||
border-top: .5px solid #dddddd;
|
||||
padding-top: 4px;
|
||||
}
|
||||
';
|
||||
|
||||
/* ═══════════ SECCIÓN: PERFIL PROFESIONAL ═══════════ */
|
||||
|
||||
// Combina intro + summary (como el DOCX)
|
||||
$summaryBody = $summary['body'] ?? '';
|
||||
$profileFull = trim($intro);
|
||||
if ($summaryBody && $summaryBody !== $intro) {
|
||||
// Evitar duplicar si intro ya contiene el resumen
|
||||
if (strpos($profileFull, substr($summaryBody, 0, 30)) === false) {
|
||||
$profileFull .= ' ' . $summaryBody;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════ SECCIÓN: EXPERIENCIA ═══════════ */
|
||||
$expHtml = '';
|
||||
foreach ($experience as $job) {
|
||||
$expHtml .= '<div class="exp-item">';
|
||||
$expHtml .= '<div class="exp-header">';
|
||||
$expHtml .= '<span class="exp-title">' . $h($job['title'] ?? '') . '</span>';
|
||||
$expHtml .= '<span class="exp-period">' . $h($job['period'] ?? '') . '</span>';
|
||||
$expHtml .= '</div>';
|
||||
|
||||
$company = $h($job['company'] ?? '');
|
||||
$loc = $h($job['location'] ?? '');
|
||||
if ($company || $loc) {
|
||||
$expHtml .= '<p class="exp-company">' . $company . ($loc ? ' | ' . $loc : '') . '</p>';
|
||||
}
|
||||
|
||||
if (! empty($job['lead'])) {
|
||||
$expHtml .= '<p class="exp-desc">' . $h($job['lead']) . '</p>';
|
||||
}
|
||||
|
||||
if (! empty($job['bullets'])) {
|
||||
$expHtml .= '<ul class="exp-bullets">';
|
||||
foreach ($job['bullets'] as $bullet) {
|
||||
$expHtml .= '<li>' . $h($bullet) . '</li>';
|
||||
}
|
||||
$expHtml .= '</ul>';
|
||||
}
|
||||
$expHtml .= '</div>';
|
||||
}
|
||||
|
||||
/* ═══════════ SECCIÓN: FORMACIÓN ═══════════ */
|
||||
$eduHtml = '';
|
||||
foreach ($education as $edu) {
|
||||
$eduHtml .= '<div class="edu-item">';
|
||||
$eduHtml .= '<div class="edu-left">';
|
||||
$eduHtml .= '<p class="edu-degree">' . $h($edu['title'] ?? '') . '</p>';
|
||||
$eduHtml .= '<p class="edu-institution">' . $h($edu['institution'] ?? '') . '</p>';
|
||||
if (! empty($edu['detail'])) {
|
||||
$eduHtml .= '<p class="edu-detail">' . $h($edu['detail']) . '</p>';
|
||||
}
|
||||
$eduHtml .= '</div>';
|
||||
$eduHtml .= '<span class="edu-year">' . $h($edu['year'] ?? '') . '</span>';
|
||||
$eduHtml .= '</div>';
|
||||
}
|
||||
|
||||
/* ═══════════ SECCIÓN: CERTIFICACIONES ═══════════ */
|
||||
$certHtml = '';
|
||||
foreach ($certifications as $cert) {
|
||||
$title = $h($cert['title'] ?? '');
|
||||
$issuer = $h($cert['issuer'] ?? '');
|
||||
$year = $h($cert['year'] ?? '');
|
||||
$certHtml .= '<div class="cert-item">';
|
||||
$certHtml .= '<span class="cert-title">' . $title . ($issuer ? ' — ' . $issuer : '') . '</span>';
|
||||
$certHtml .= '<span class="cert-year">' . $year . '</span>';
|
||||
$certHtml .= '</div>';
|
||||
}
|
||||
|
||||
/* ═══════════ SECCIÓN: COMPETENCIAS ═══════════ */
|
||||
$compHtml = '';
|
||||
foreach ($competencies as $groupName => $items) {
|
||||
$skills = [];
|
||||
foreach ($items as $item) {
|
||||
$skills[] = is_array($item) ? ($item['name'] ?? '') : (string) $item;
|
||||
}
|
||||
$skillsStr = implode(' · ', array_filter($skills));
|
||||
$compHtml .= '<p class="comp-line"><strong>' . $h($groupName) . ':</strong> ' . $h($skillsStr) . '</p>';
|
||||
}
|
||||
|
||||
/* ═══════════ SECCIÓN: VOLUNTARIADO ═══════════ */
|
||||
$volHtml = '';
|
||||
if (! empty($volunteer['title'])) {
|
||||
$volHtml .= '<div class="vol-header">';
|
||||
$volHtml .= '<span class="vol-title">' . $h($volunteer['title']) . '</span>';
|
||||
$volHtml .= '<span class="vol-year">' . $h($volunteer['year'] ?? '') . '</span>';
|
||||
$volHtml .= '</div>';
|
||||
if (! empty($volunteer['body'])) {
|
||||
$volHtml .= '<p class="vol-body">' . $h($volunteer['body']) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════ SECCIÓN: INFORMACIÓN ADICIONAL ═══════════ */
|
||||
$addHtml = '';
|
||||
$addLines = [
|
||||
'Idiomas' => $langs,
|
||||
'Disponibilidad' => $avail,
|
||||
'Enfoque' => $focus,
|
||||
];
|
||||
// Añadir los del array additional filtrando redundancias
|
||||
foreach ($additional as $k => $v) {
|
||||
if ($v !== '' && ! in_array($k, ['Disponibilidad', 'Idiomas'], true)) {
|
||||
$addLines[$k] = $v;
|
||||
}
|
||||
}
|
||||
foreach ($addLines as $k => $v) {
|
||||
if ($v === '') continue;
|
||||
$addHtml .= '<p class="add-line"><strong>' . $h($k) . ':</strong> ' . $h($v) . '</p>';
|
||||
}
|
||||
if ($web) {
|
||||
$addHtml .= '<p class="add-line"><strong>Web:</strong> ' . $h($web) . '</p>';
|
||||
}
|
||||
|
||||
/* ═══════════ LÍNEA DE CONTACTO (cabecera) ═══════════ */
|
||||
$contactParts = [];
|
||||
if ($email) $contactParts[] = 'Correo: ' . $email;
|
||||
if ($phone) $contactParts[] = 'Tel.: ' . $phone;
|
||||
if ($linkedin) {
|
||||
// Mostrar URL limpia sin https://www.
|
||||
$lnDisplay = preg_replace('#^https?://(www\.)?#', '', urldecode($linkedin));
|
||||
$contactParts[] = 'LinkedIn: ' . $lnDisplay;
|
||||
}
|
||||
if ($location) $contactParts[] = $location;
|
||||
$contactLine = implode(' | ', $contactParts);
|
||||
|
||||
/* ═══════════ TÍTULO del documento ═══════════ */
|
||||
$fullRole = $role . ($role2 ? ' | ' . $role2 : '');
|
||||
$year = gmdate('Y');
|
||||
|
||||
/* ═══════════ HTML COMPLETO ═══════════ */
|
||||
return '<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>CV — ' . $h($name) . '</title>
|
||||
<style>' . $css . '</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- CABECERA -->
|
||||
<p class="cv-name">' . $h($name) . '</p>
|
||||
<p class="cv-role">' . $h($fullRole) . '</p>
|
||||
<p class="cv-contact">' . $h($contactLine) . '</p>
|
||||
|
||||
<!-- PERFIL PROFESIONAL -->
|
||||
<div class="sec">
|
||||
<p class="sec-title">Perfil profesional</p>
|
||||
<p class="profile-text">' . $h($profileFull) . '</p>
|
||||
</div>
|
||||
|
||||
<!-- EXPERIENCIA PROFESIONAL -->
|
||||
<div class="sec">
|
||||
<p class="sec-title">Experiencia profesional</p>
|
||||
' . $expHtml . '
|
||||
</div>
|
||||
|
||||
<!-- FORMACIÓN ACADÉMICA -->
|
||||
<div class="sec">
|
||||
<p class="sec-title">Formación académica</p>
|
||||
' . $eduHtml . '
|
||||
</div>
|
||||
|
||||
<!-- CERTIFICACIONES RELEVANTES -->
|
||||
<div class="sec">
|
||||
<p class="sec-title">Certificaciones relevantes</p>
|
||||
' . $certHtml . '
|
||||
</div>
|
||||
|
||||
<!-- COMPETENCIAS CLAVE -->
|
||||
' . ($compHtml ? '<div class="sec">
|
||||
<p class="sec-title">Competencias clave</p>
|
||||
' . $compHtml . '
|
||||
</div>' : '') . '
|
||||
|
||||
<!-- VOLUNTARIADO -->
|
||||
' . ($volHtml ? '<div class="sec">
|
||||
<p class="sec-title">Voluntariado</p>
|
||||
' . $volHtml . '
|
||||
</div>' : '') . '
|
||||
|
||||
<!-- INFORMACIÓN ADICIONAL -->
|
||||
' . ($addHtml ? '<div class="sec">
|
||||
<p class="sec-title">Información adicional</p>
|
||||
' . $addHtml . '
|
||||
</div>' : '') . '
|
||||
|
||||
<p class="cv-footer-line">' . $h($location) . ' — ' . $year . '</p>
|
||||
|
||||
</body>
|
||||
</html>';
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Pflores CV Fields
|
||||
* Description: Página de opciones y campos para el CV de Patricia Flores. Usa CMB2 (100 % gratuito, WordPress.org).
|
||||
* Version: 2.0.0
|
||||
* Author: mgonzalez
|
||||
* Text Domain: pflores-cv
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/pdf-generator.php';
|
||||
|
||||
/* ─────────────────────────────────────────────
|
||||
1. PÁGINAS DE OPCIONES (menú WP-Admin)
|
||||
────────────────────────────────────────────── */
|
||||
add_action('cmb2_admin_init', 'pflores_register_pages');
|
||||
function pflores_register_pages(): void
|
||||
{
|
||||
/* ── PERFIL Y CONTACTO ── */
|
||||
$perfil = new_cmb2_box([
|
||||
'id' => 'pflores_perfil',
|
||||
'title' => 'Perfil y contacto',
|
||||
'object_types' => ['options-page'],
|
||||
'option_key' => 'pflores_perfil',
|
||||
'menu_title' => 'CV Patricia Flores',
|
||||
'icon_url' => 'dashicons-id-alt',
|
||||
'position' => 3,
|
||||
'save_button' => 'Guardar cambios',
|
||||
'capability' => 'manage_options',
|
||||
]);
|
||||
|
||||
$perfil->add_field(['id' => 'pf_name', 'name' => 'Nombre completo', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_role', 'name' => 'Cargo principal', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_role2', 'name' => 'Sector / subtítulo', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_intro', 'name' => 'Introducción', 'type' => 'textarea', 'attributes' => ['rows' => 4]]);
|
||||
$perfil->add_field(['id' => 'pf_summary_title', 'name' => 'Título del perfil', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_summary_body', 'name' => 'Resumen profesional', 'type' => 'textarea', 'attributes' => ['rows' => 5]]);
|
||||
$perfil->add_field(['id' => 'pf_location', 'name' => 'Ubicación', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_email', 'name' => 'Correo electrónico', 'type' => 'text_email']);
|
||||
$perfil->add_field(['id' => 'pf_phone', 'name' => 'Teléfono', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_linkedin', 'name' => 'LinkedIn URL', 'type' => 'text_url']);
|
||||
$perfil->add_field(['id' => 'pf_availability', 'name' => 'Disponibilidad', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_focus', 'name' => 'Enfoque profesional', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_languages', 'name' => 'Idiomas', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_photo', 'name' => 'Foto de perfil', 'type' => 'file', 'options' => ['url' => false], 'text' => ['add_upload_file_text' => 'Seleccionar foto']]);
|
||||
$perfil->add_field(['id' => 'pf_born', 'name' => 'Fecha de nacimiento', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_ci', 'name' => 'Cédula de identidad', 'type' => 'text']);
|
||||
$perfil->add_field(['id' => 'pf_web', 'name' => 'Web profesional', 'type' => 'text']);
|
||||
|
||||
/* ── EXPERIENCIA ── */
|
||||
$exp = new_cmb2_box([
|
||||
'id' => 'pflores_experiencia',
|
||||
'title' => 'Experiencia profesional',
|
||||
'object_types' => ['options-page'],
|
||||
'option_key' => 'pflores_experiencia',
|
||||
'parent_slug' => 'pflores_perfil',
|
||||
'menu_title' => 'Experiencia',
|
||||
'save_button' => 'Guardar cambios',
|
||||
'capability' => 'manage_options',
|
||||
]);
|
||||
|
||||
$exp_group = $exp->add_field([
|
||||
'id' => 'pf_experience',
|
||||
'type' => 'group',
|
||||
'description' => 'Cargos del más reciente al más antiguo',
|
||||
'options' => [
|
||||
'group_title' => 'Cargo {#}',
|
||||
'add_button' => 'Añadir cargo',
|
||||
'remove_button' => 'Eliminar cargo',
|
||||
'sortable' => true,
|
||||
'closed' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$exp->add_group_field($exp_group, ['id' => 'period', 'name' => 'Período (ej: Abr. 2022 – Presente)', 'type' => 'text']);
|
||||
$exp->add_group_field($exp_group, ['id' => 'title', 'name' => 'Cargo', 'type' => 'text']);
|
||||
$exp->add_group_field($exp_group, ['id' => 'company', 'name' => 'Institución / Empresa', 'type' => 'text']);
|
||||
$exp->add_group_field($exp_group, ['id' => 'location', 'name' => 'Lugar', 'type' => 'text']);
|
||||
$exp->add_group_field($exp_group, ['id' => 'lead', 'name' => 'Descripción breve', 'type' => 'textarea_small']);
|
||||
$exp->add_group_field($exp_group, [
|
||||
'id' => 'bullets_text',
|
||||
'name' => 'Logros y actividades',
|
||||
'type' => 'textarea',
|
||||
'description' => 'Un punto por línea. Sin guiones ni asteriscos.',
|
||||
'attributes' => ['rows' => 8],
|
||||
]);
|
||||
|
||||
/* ── FORMACIÓN Y CERTIFICACIONES ── */
|
||||
$form = new_cmb2_box([
|
||||
'id' => 'pflores_formacion',
|
||||
'title' => 'Formación y certificaciones',
|
||||
'object_types' => ['options-page'],
|
||||
'option_key' => 'pflores_formacion',
|
||||
'parent_slug' => 'pflores_perfil',
|
||||
'menu_title' => 'Formación',
|
||||
'save_button' => 'Guardar cambios',
|
||||
'capability' => 'manage_options',
|
||||
]);
|
||||
|
||||
$edu_group = $form->add_field([
|
||||
'id' => 'pf_education',
|
||||
'type' => 'group',
|
||||
'options' => ['group_title' => 'Título {#}', 'add_button' => 'Añadir título', 'remove_button' => 'Eliminar', 'sortable' => true, 'closed' => true],
|
||||
]);
|
||||
$form->add_group_field($edu_group, ['id' => 'year', 'name' => 'Año', 'type' => 'text', 'attributes' => ['size' => 6]]);
|
||||
$form->add_group_field($edu_group, ['id' => 'title', 'name' => 'Título', 'type' => 'text']);
|
||||
$form->add_group_field($edu_group, ['id' => 'institution', 'name' => 'Institución','type' => 'text']);
|
||||
$form->add_group_field($edu_group, ['id' => 'detail', 'name' => 'Detalle / Nota de reconocimiento', 'type' => 'textarea_small']);
|
||||
|
||||
$cert_group = $form->add_field([
|
||||
'id' => 'pf_certifications',
|
||||
'type' => 'group',
|
||||
'description' => 'Certificaciones relevantes',
|
||||
'options' => ['group_title' => 'Certificación {#}', 'add_button' => 'Añadir certificación', 'remove_button' => 'Eliminar', 'sortable' => true, 'closed' => true],
|
||||
]);
|
||||
$form->add_group_field($cert_group, ['id' => 'year', 'name' => 'Año', 'type' => 'text', 'attributes' => ['size' => 6]]);
|
||||
$form->add_group_field($cert_group, ['id' => 'title', 'name' => 'Título', 'type' => 'text']);
|
||||
$form->add_group_field($cert_group, ['id' => 'issuer', 'name' => 'Emisor', 'type' => 'text']);
|
||||
|
||||
/* ── COMPETENCIAS ── */
|
||||
$comp = new_cmb2_box([
|
||||
'id' => 'pflores_competencias',
|
||||
'title' => 'Competencias y habilidades',
|
||||
'object_types' => ['options-page'],
|
||||
'option_key' => 'pflores_competencias',
|
||||
'parent_slug' => 'pflores_perfil',
|
||||
'menu_title' => 'Competencias',
|
||||
'save_button' => 'Guardar cambios',
|
||||
'capability' => 'manage_options',
|
||||
]);
|
||||
|
||||
$comp_group = $comp->add_field([
|
||||
'id' => 'pf_competencies',
|
||||
'type' => 'group',
|
||||
'options' => ['group_title' => 'Grupo {#}', 'add_button' => 'Añadir grupo', 'remove_button' => 'Eliminar', 'sortable' => true, 'closed' => true],
|
||||
]);
|
||||
$comp->add_group_field($comp_group, ['id' => 'group_name', 'name' => 'Nombre del grupo (ej: Finanzas y Operaciones)', 'type' => 'text']);
|
||||
$comp->add_group_field($comp_group, [
|
||||
'id' => 'skills_text',
|
||||
'name' => 'Habilidades',
|
||||
'type' => 'textarea',
|
||||
'description' => 'Una por línea. Formato: Nombre de la habilidad|85 (el número es el porcentaje 0-100).',
|
||||
'attributes' => ['rows' => 7],
|
||||
]);
|
||||
|
||||
/* ── MÉTRICAS, IMPACTO Y EXTRAS ── */
|
||||
$extra = new_cmb2_box([
|
||||
'id' => 'pflores_extras',
|
||||
'title' => 'Métricas, impacto y datos adicionales',
|
||||
'object_types' => ['options-page'],
|
||||
'option_key' => 'pflores_extras',
|
||||
'parent_slug' => 'pflores_perfil',
|
||||
'menu_title' => 'Métricas / Impacto',
|
||||
'save_button' => 'Guardar cambios',
|
||||
'capability' => 'manage_options',
|
||||
]);
|
||||
|
||||
$metrics_group = $extra->add_field([
|
||||
'id' => 'pf_metrics',
|
||||
'type' => 'group',
|
||||
'description' => 'Contadores principales del héroe',
|
||||
'options' => ['group_title' => 'Métrica {#}', 'add_button' => 'Añadir métrica', 'remove_button' => 'Eliminar', 'sortable' => true, 'closed' => false],
|
||||
]);
|
||||
$extra->add_group_field($metrics_group, ['id' => 'value', 'name' => 'Valor (ej: 22+, USD 5 M)', 'type' => 'text']);
|
||||
$extra->add_group_field($metrics_group, ['id' => 'suffix', 'name' => 'Sufijo (opcional)', 'type' => 'text', 'attributes' => ['size' => 8]]);
|
||||
$extra->add_group_field($metrics_group, ['id' => 'label', 'name' => 'Etiqueta descriptiva', 'type' => 'text']);
|
||||
|
||||
$hl_group = $extra->add_field([
|
||||
'id' => 'pf_highlights',
|
||||
'type' => 'group',
|
||||
'description' => 'Logros destacados con número grande',
|
||||
'options' => ['group_title' => 'Logro {#}', 'add_button' => 'Añadir logro', 'remove_button' => 'Eliminar', 'sortable' => true, 'closed' => false],
|
||||
]);
|
||||
$extra->add_group_field($hl_group, ['id' => 'value', 'name' => 'Valor (ej: 74 %, 9/10)', 'type' => 'text']);
|
||||
$extra->add_group_field($hl_group, ['id' => 'suffix', 'name' => 'Sufijo (opcional)', 'type' => 'text', 'attributes' => ['size' => 8]]);
|
||||
$extra->add_group_field($hl_group, ['id' => 'label', 'name' => 'Descripción', 'type' => 'text']);
|
||||
|
||||
$impact_group = $extra->add_field([
|
||||
'id' => 'pf_impact',
|
||||
'type' => 'group',
|
||||
'description' => 'Áreas de impacto ejecutivo',
|
||||
'options' => ['group_title' => 'Impacto {#}', 'add_button' => 'Añadir área', 'remove_button' => 'Eliminar', 'sortable' => true, 'closed' => false],
|
||||
]);
|
||||
$extra->add_group_field($impact_group, ['id' => 'title', 'name' => 'Título', 'type' => 'text']);
|
||||
$extra->add_group_field($impact_group, ['id' => 'body', 'name' => 'Descripción', 'type' => 'textarea_small']);
|
||||
|
||||
$extra->add_field(['id' => 'pf_volunteer_title', 'name' => 'Voluntariado — Título', 'type' => 'text']);
|
||||
$extra->add_field(['id' => 'pf_volunteer_year', 'name' => 'Voluntariado — Año', 'type' => 'text', 'attributes' => ['size' => 8]]);
|
||||
$extra->add_field(['id' => 'pf_volunteer_body', 'name' => 'Voluntariado — Descripción', 'type' => 'textarea_small']);
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────
|
||||
2. FUNCIÓN CENTRAL — lee de CMB2
|
||||
────────────────────────────────────────────── */
|
||||
function pflores_get_cv_data(): array
|
||||
{
|
||||
if (! function_exists('cmb2_get_option')) {
|
||||
return pflores_cv_fallback_data();
|
||||
}
|
||||
|
||||
$perfil = get_option('pflores_perfil', []);
|
||||
$experiencia = get_option('pflores_experiencia', []);
|
||||
$formacion = get_option('pflores_formacion', []);
|
||||
$competencias = get_option('pflores_competencias', []);
|
||||
$extras = get_option('pflores_extras', []);
|
||||
|
||||
// ── Experiencia ──
|
||||
$experience = [];
|
||||
foreach ((array) ($experiencia['pf_experience'] ?? []) as $job) {
|
||||
$bullets = array_values(array_filter(
|
||||
array_map('trim', explode("\n", (string) ($job['bullets_text'] ?? '')))
|
||||
));
|
||||
$experience[] = [
|
||||
'period' => $job['period'] ?? '',
|
||||
'title' => $job['title'] ?? '',
|
||||
'company' => $job['company'] ?? '',
|
||||
'location' => $job['location'] ?? '',
|
||||
'lead' => $job['lead'] ?? '',
|
||||
'bullets' => $bullets,
|
||||
];
|
||||
}
|
||||
|
||||
// ── Educación ──
|
||||
$education = [];
|
||||
foreach ((array) ($formacion['pf_education'] ?? []) as $edu) {
|
||||
$education[] = [
|
||||
'year' => $edu['year'] ?? '',
|
||||
'title' => $edu['title'] ?? '',
|
||||
'institution' => $edu['institution'] ?? '',
|
||||
'detail' => $edu['detail'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
// ── Certificaciones ──
|
||||
$certifications = [];
|
||||
foreach ((array) ($formacion['pf_certifications'] ?? []) as $cert) {
|
||||
$certifications[] = [
|
||||
'year' => $cert['year'] ?? '',
|
||||
'title' => $cert['title'] ?? '',
|
||||
'issuer' => $cert['issuer'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
// ── Competencias (nombre|porcentaje) ──
|
||||
$competencies = [];
|
||||
foreach ((array) ($competencias['pf_competencies'] ?? []) as $group) {
|
||||
$groupName = $group['group_name'] ?? '';
|
||||
if ($groupName === '') {
|
||||
continue;
|
||||
}
|
||||
$skills = [];
|
||||
foreach (array_filter(array_map('trim', explode("\n", (string) ($group['skills_text'] ?? '')))) as $line) {
|
||||
$parts = explode('|', $line, 2);
|
||||
$skills[] = ['name' => trim($parts[0]), 'pct' => isset($parts[1]) ? (int) trim($parts[1]) : 80];
|
||||
}
|
||||
$competencies[$groupName] = $skills;
|
||||
}
|
||||
|
||||
// ── Métricas ──
|
||||
$metrics = [];
|
||||
foreach ((array) ($extras['pf_metrics'] ?? []) as $m) {
|
||||
$metrics[] = ['value' => $m['value'] ?? '', 'suffix' => $m['suffix'] ?? '', 'label' => $m['label'] ?? ''];
|
||||
}
|
||||
|
||||
// ── Highlights ──
|
||||
$highlights = [];
|
||||
foreach ((array) ($extras['pf_highlights'] ?? []) as $h) {
|
||||
$highlights[] = ['value' => $h['value'] ?? '', 'suffix' => $h['suffix'] ?? '', 'label' => $h['label'] ?? ''];
|
||||
}
|
||||
|
||||
// ── Impacto ──
|
||||
$impact = [];
|
||||
foreach ((array) ($extras['pf_impact'] ?? []) as $item) {
|
||||
$impact[] = ['title' => $item['title'] ?? '', 'body' => $item['body'] ?? ''];
|
||||
}
|
||||
|
||||
// ── Foto (CMB2 file field devuelve ID; obtenemos la URL) ──
|
||||
$photoId = $perfil['pf_photo'] ?? '';
|
||||
$photoUrl = $photoId ? (string) wp_get_attachment_url((int) $photoId) : '';
|
||||
|
||||
return [
|
||||
'hero' => [
|
||||
'eyebrow' => 'Currículum ejecutivo',
|
||||
'name' => $perfil['pf_name'] ?? '',
|
||||
'role' => $perfil['pf_role'] ?? '',
|
||||
'role2' => $perfil['pf_role2'] ?? '',
|
||||
'intro' => $perfil['pf_intro'] ?? '',
|
||||
'location' => $perfil['pf_location'] ?? '',
|
||||
'email' => $perfil['pf_email'] ?? '',
|
||||
'phone' => $perfil['pf_phone'] ?? '',
|
||||
'linkedin' => $perfil['pf_linkedin'] ?? '',
|
||||
'availability' => $perfil['pf_availability'] ?? '',
|
||||
'focus' => $perfil['pf_focus'] ?? '',
|
||||
'languages' => $perfil['pf_languages'] ?? '',
|
||||
'born' => $perfil['pf_born'] ?? '',
|
||||
'id' => $perfil['pf_ci'] ?? '',
|
||||
'web' => $perfil['pf_web'] ?? '',
|
||||
],
|
||||
'photo' => $photoUrl,
|
||||
'metrics' => $metrics,
|
||||
'highlights' => $highlights,
|
||||
'summary' => [
|
||||
'title' => $perfil['pf_summary_title'] ?? '',
|
||||
'body' => $perfil['pf_summary_body'] ?? '',
|
||||
],
|
||||
'impact' => $impact,
|
||||
'experience' => $experience,
|
||||
'education' => $education,
|
||||
'certifications' => $certifications,
|
||||
'competencies' => $competencies,
|
||||
'volunteer' => [
|
||||
'title' => $extras['pf_volunteer_title'] ?? '',
|
||||
'year' => $extras['pf_volunteer_year'] ?? '',
|
||||
'body' => $extras['pf_volunteer_body'] ?? '',
|
||||
],
|
||||
'additional' => [
|
||||
'Idiomas' => $perfil['pf_languages'] ?? '',
|
||||
'Disponibilidad' => $perfil['pf_availability'] ?? '',
|
||||
'C.I.' => $perfil['pf_ci'] ?? '',
|
||||
'Fecha de nacimiento' => $perfil['pf_born'] ?? '',
|
||||
'Web profesional' => $perfil['pf_web'] ?? '',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────
|
||||
3. FALLBACK si CMB2 no está activo
|
||||
────────────────────────────────────────────── */
|
||||
function pflores_cv_fallback_data(): array
|
||||
{
|
||||
return [
|
||||
'hero' => ['eyebrow' => 'Currículum ejecutivo', 'name' => 'Patricia Soledad Flores Sánchez', 'role' => 'Gerente / Jefa de Operaciones Financieras', 'role2' => 'Sector financiero y microfinanzas', 'intro' => 'Ejecutiva financiera con más de 22 años de trayectoria en banca y microfinanzas.', 'location' => 'Loja, Ecuador', 'email' => 'patricflorsanchez@gmail.com', 'phone' => '+593 99 469 8405', 'linkedin' => 'https://www.linkedin.com/in/patricia-soledad-flores-s%C3%A1nchez-43b84418/', 'availability' => 'Inmediata | Presencial / Híbrida / Remota', 'focus' => 'Operaciones financieras, control interno y transformación digital', 'languages' => 'Español nativo | Inglés básico en formación activa', 'born' => '3 de agosto de 1980', 'id' => '1103591648', 'web' => 'pflores.linkedcorp.net'],
|
||||
'photo' => '',
|
||||
'metrics' => [],
|
||||
'highlights' => [],
|
||||
'summary' => ['title' => '', 'body' => ''],
|
||||
'impact' => [],
|
||||
'experience' => [],
|
||||
'education' => [],
|
||||
'certifications' => [],
|
||||
'competencies' => [],
|
||||
'volunteer' => ['title' => '', 'year' => '', 'body' => ''],
|
||||
'additional' => [],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
* Carga los datos iniciales del CV de Patricia Flores en CMB2.
|
||||
* URL: /wp-content/plugins/pflores-cv-fields/populate-data.php?key=pflores2024
|
||||
*/
|
||||
|
||||
if (($_GET['key'] ?? '') !== 'pflores2024') {
|
||||
http_response_code(403); exit('Acceso denegado.');
|
||||
}
|
||||
|
||||
require_once dirname(__DIR__, 3) . '/wp-load.php';
|
||||
|
||||
if (! function_exists('cmb2_get_option')) {
|
||||
exit('CMB2 no está activo.');
|
||||
}
|
||||
|
||||
$ok = [];
|
||||
|
||||
/* ════════════════════════════════════════════
|
||||
PERFIL Y CONTACTO → option: pflores_perfil
|
||||
════════════════════════════════════════════ */
|
||||
update_option('pflores_perfil', [
|
||||
'pf_name' => 'Patricia Soledad Flores Sánchez',
|
||||
'pf_role' => 'Gerente / Jefa de Operaciones Financieras',
|
||||
'pf_role2' => 'Sector financiero y microfinanzas',
|
||||
'pf_intro' => 'Ejecutiva financiera con más de 22 años de trayectoria en banca y microfinanzas. Máster en Dirección y Planificación Financiera, reconocido por la SENECYT en Ecuador, con especialización en gestión operativa, transformación digital de procesos, control interno y liderazgo de equipos multidisciplinarios.',
|
||||
'pf_summary_title' => 'Perfil estratégico con enfoque en eficiencia, control y ejecución sostenible',
|
||||
'pf_summary_body' => 'Actualmente lidera la operatividad de 26 agencias a nivel nacional y coordina aproximadamente 1.500 operaciones de microcrédito mensuales, por un monto cercano a USD 5 millones. También articula la recaudación de cerca de 28.000 clientes por canales internos y externos, integrando visión operativa, criterio financiero, disciplina de control y liderazgo sostenido del desempeño.',
|
||||
'pf_location' => 'Loja, Ecuador',
|
||||
'pf_email' => 'patricflorsanchez@gmail.com',
|
||||
'pf_phone' => '+593 99 469 8405',
|
||||
'pf_linkedin' => 'https://www.linkedin.com/in/patricia-soledad-flores-s%C3%A1nchez-43b84418/',
|
||||
'pf_availability' => 'Inmediata | Presencial / Híbrida / Remota',
|
||||
'pf_focus' => 'Operaciones financieras, control interno y transformación digital',
|
||||
'pf_languages' => 'Español nativo | Inglés básico en formación activa',
|
||||
'pf_born' => '3 de agosto de 1980',
|
||||
'pf_ci' => '1103591648',
|
||||
'pf_web' => 'pflores.linkedcorp.net',
|
||||
'pf_photo' => '',
|
||||
]);
|
||||
$ok[] = '✓ Perfil y contacto (17 campos)';
|
||||
|
||||
/* ════════════════════════════════════════════
|
||||
EXPERIENCIA → option: pflores_experiencia
|
||||
════════════════════════════════════════════ */
|
||||
update_option('pflores_experiencia', [
|
||||
'pf_experience' => [
|
||||
[
|
||||
'period' => 'Abr. 2022 – Presente',
|
||||
'title' => 'Jefa de Operaciones',
|
||||
'company' => 'Fundación FACES Microfinanzas',
|
||||
'location' => 'Loja, Ecuador',
|
||||
'lead' => 'Responsable del desempeño operativo nacional, cumplimiento del POA, control interno, digitalización de procesos y gestión de equipos.',
|
||||
'bullets_text' =>
|
||||
"Cumplimiento del POA: 98 % (Q2 2025), 96 % (Q3 2025), 100 % (Q4 2025) y 105 % (Q1 2026).\n" .
|
||||
"La transformación digital logró que los desembolsos por transferencia representen el 47,80 % del monto total en Q1 2026.\n" .
|
||||
"Redujo los requerimientos de soporte desde Dirección en un 74 %, de 1.489 a 382, mediante la descentralización de procesos hacia las agencias.\n" .
|
||||
"Automatizó el proceso del seguro de desgravamen con cálculo de prima, conciliación mensual, liquidación de siniestros y asientos contables automatizados.\n" .
|
||||
"Elevó el índice de cumplimiento operativo nacional del 65 % al 88 % con la matriz de supervisión y certificación por agencia.\n" .
|
||||
"Redujo el tiempo de atención del seguro de desgravamen de 17 a 10 días.\n" .
|
||||
"Redujo los tiempos de desembolso a 1,68 días en Q3 2025, mejor resultado del año frente a la meta institucional máxima de 2 días.\n" .
|
||||
"La efectividad de recuperación de mora alcanzó 90,60 % en Q1 2026, con USD 3,06 millones recuperados sobre USD 3,37 millones en mora.\n" .
|
||||
"Redujo el índice de rotación del área del 41,46 % al 10,24 % entre diciembre de 2022 y marzo de 2026 mediante mejoras salariales, remuneración variable, evaluación trimestral y un plan de carrera con certificación de 60 horas para asistentes de caja.\n" .
|
||||
"Participa en comités estratégicos, auditorías internas y externas, y en representación institucional ante organismos financieros internacionales de desarrollo.",
|
||||
],
|
||||
[
|
||||
'period' => 'Feb. 2021 – Mar. 2022',
|
||||
'title' => 'Supervisora de Operaciones',
|
||||
'company' => 'Fundación FACES Microfinanzas',
|
||||
'location' => 'Loja, Ecuador',
|
||||
'lead' => 'Supervisó operaciones de 18 agencias a nivel nacional y regularizó procesos críticos inexistentes o incompletos.',
|
||||
'bullets_text' =>
|
||||
"Reconstruyó desde cero las bases de cálculo del seguro de desgravamen y regularizó pagos pendientes desde enero de 2021.\n" .
|
||||
"Elaboró el instructivo de constitución de garantías hipotecarias, proceso que no existía previamente en la institución.\n" .
|
||||
"Inició el proyecto de automatización de pagos por depósitos y transferencias.",
|
||||
],
|
||||
[
|
||||
'period' => '2019 – 2021',
|
||||
'title' => 'Actualización y formación profesional',
|
||||
'company' => 'Formación independiente',
|
||||
'location' => 'Ecuador',
|
||||
'lead' => 'Etapa enfocada en fortalecimiento técnico y actualización profesional tras su salida de Mutualista Pichincha.',
|
||||
'bullets_text' => "SAP FI (30 h).\nExcel Empresarial (24 h).\nPrevención de Lavado de Activos — UAFE (5 h).",
|
||||
],
|
||||
[
|
||||
'period' => 'Ago. 2004 – May. 2019',
|
||||
'title' => 'Oficial Operativa Regional / Jefa Operativa',
|
||||
'company' => 'Mutualista Pichincha',
|
||||
'location' => 'Loja, Ecuador',
|
||||
'lead' => 'Trayectoria ascendente de 15 años desde Cajera hasta Jefa Operativa Regional.',
|
||||
'bullets_text' =>
|
||||
"Reconocida a nivel nacional por excelencia en control operativo.\n" .
|
||||
"La agencia se mantuvo consistentemente por encima del 80 % en gestión de excepciones de crédito hipotecario.\n" .
|
||||
"Administró proyecto inmobiliario institucional en Loja.\n" .
|
||||
"Gestionó alertas ALA/FT con 100 % de cumplimiento en comités trimestrales y auditorías internas sin observaciones significativas de forma sostenida.",
|
||||
],
|
||||
[
|
||||
'period' => 'Ene. 2002 – Nov. 2003',
|
||||
'title' => 'Cajera',
|
||||
'company' => 'Cooperativa de Ahorro y Crédito El Porvenir',
|
||||
'location' => 'Loja, Ecuador',
|
||||
'lead' => 'Inicio de carrera en el frente operativo financiero con disciplina de caja y apoyo contable.',
|
||||
'bullets_text' =>
|
||||
"Gestión de caja sin faltantes ni sobrantes.\n" .
|
||||
"Contrato renovado de forma anticipada a los tres meses.\n" .
|
||||
"Apoyo al área de Contabilidad y reemplazo temporal de la contadora durante vacaciones.",
|
||||
],
|
||||
],
|
||||
]);
|
||||
$ok[] = '✓ Experiencia (5 cargos, 23 bullets)';
|
||||
|
||||
/* ════════════════════════════════════════════
|
||||
FORMACIÓN Y CERTIFICACIONES → pflores_formacion
|
||||
════════════════════════════════════════════ */
|
||||
update_option('pflores_formacion', [
|
||||
'pf_education' => [
|
||||
['year' => '2021', 'title' => 'Máster Universitario en Dirección y Planificación Financiera', 'institution' => 'Universidad Europea Miguel de Cervantes — Valladolid, España', 'detail' => 'Título reconocido por la SENECYT — Ecuador, febrero de 2023 | Reg. 2021/394270.'],
|
||||
['year' => '2007', 'title' => 'Ingeniera en Administración en Banca y Finanzas', 'institution' => 'Universidad Técnica Particular de Loja (UTPL)', 'detail' => ''],
|
||||
],
|
||||
'pf_certifications' => [
|
||||
['year' => '2026', 'title' => 'Mujeres que Lideran: Alta Gerencia', 'issuer' => 'Foro UNIR — Universidad Internacional de La Rioja'],
|
||||
['year' => '2025', 'title' => 'Programa Internacional de Habilidades Gerenciales (48 h)', 'issuer' => 'IDEASGROUP — Ecuador / México'],
|
||||
['year' => '2025', 'title' => 'Transforma tu Trabajo con Inteligencia Artificial (12 h)', 'issuer' => 'Red de Instituciones Financieras de Desarrollo'],
|
||||
['year' => '2025', 'title' => 'Excel: Básico a Dashboard (40 h)', 'issuer' => 'DMARURI Training & Consulting'],
|
||||
['year' => '2024', 'title' => 'Administración por Procesos — BPM (64 h)', 'issuer' => 'Escuela Politécnica Nacional — CEC'],
|
||||
['year' => '2023', 'title' => 'Formación de Formadores (80 h)', 'issuer' => 'Ministerio del Trabajo del Ecuador | Certificación vigente hasta 2028'],
|
||||
['year' => '2023', 'title' => 'Power BI (40 h) | Indicadores Clave de Desempeño — KPI (12 h)', 'issuer' => 'Liderazgo Capacitación & Eventos'],
|
||||
['year' => '2020', 'title' => 'Gestión Financiera ERP SAP FI — Key User (30 h)', 'issuer' => 'Socio SAP certificado'],
|
||||
['year' => '2020', 'title' => 'Prevención de Lavado de Activos y Financiamiento de Delitos', 'issuer' => 'UAFE — Ecuador'],
|
||||
['year' => '2013', 'title' => 'Tributación Integral (36 h)', 'issuer' => 'Universidad Técnica Particular de Loja'],
|
||||
],
|
||||
]);
|
||||
$ok[] = '✓ Formación (2 títulos) + Certificaciones (10)';
|
||||
|
||||
/* ════════════════════════════════════════════
|
||||
COMPETENCIAS → pflores_competencias
|
||||
════════════════════════════════════════════ */
|
||||
update_option('pflores_competencias', [
|
||||
'pf_competencies' => [
|
||||
['group_name' => 'Finanzas y Operaciones', 'skills_text' => "Gestión de operaciones financieras|95\nControl interno y cumplimiento|95\nGestión de cartera y microfinanzas|90\nConciliación bancaria / Tesorería|90\nALA/FT y prevención de riesgos|88"],
|
||||
['group_name' => 'Tecnología y Procesos', 'skills_text' => "Transformación digital / BPM|85\nSAP FI|78\nExcel avanzado y dashboards|85\nPower BI|75\nIA aplicada al trabajo|70"],
|
||||
['group_name' => 'Liderazgo', 'skills_text' => "Equipos de hasta 48 personas|95\nGestión del cambio organizacional|90\nFormación de formadores|88\nRemuneración variable y plan de carrera|85\nDiversidad, equidad e inclusión|80"],
|
||||
],
|
||||
]);
|
||||
$ok[] = '✓ Competencias (3 grupos, 15 habilidades)';
|
||||
|
||||
/* ════════════════════════════════════════════
|
||||
MÉTRICAS, IMPACTO Y EXTRAS → pflores_extras
|
||||
════════════════════════════════════════════ */
|
||||
update_option('pflores_extras', [
|
||||
'pf_metrics' => [
|
||||
['value' => '22+', 'suffix' => '', 'label' => 'años de experiencia en banca y microfinanzas'],
|
||||
['value' => '26', 'suffix' => '', 'label' => 'agencias bajo liderazgo operativo nacional'],
|
||||
['value' => '48', 'suffix' => '', 'label' => 'personas a cargo en la estructura operativa'],
|
||||
['value' => 'USD 5 M','suffix' => '', 'label' => 'en operaciones mensuales de microcrédito'],
|
||||
['value' => '28.000', 'suffix' => '', 'label' => 'clientes coordinados en recaudación por canales internos y externos'],
|
||||
],
|
||||
'pf_highlights' => [
|
||||
['value' => '9/10', 'suffix' => '', 'label' => 'calificación de gestión con resultado excelente en cuatro trimestres consecutivos'],
|
||||
['value' => '74 %', 'suffix' => '', 'label' => 'reducción de requerimientos de soporte desde Dirección por descentralización de procesos'],
|
||||
['value' => '1,68 días','suffix' => '', 'label' => 'tiempo de desembolso logrado en Q3 2025, mejor resultado del año'],
|
||||
['value' => '75 %', 'suffix' => '', 'label' => 'reducción del índice de rotación del área entre 2022 y 2026'],
|
||||
],
|
||||
'pf_impact' => [
|
||||
['title' => 'Transformación digital', 'body' => 'Lideró desembolsos por transferencia bancaria, integración de APIs bancarias y digitalización de expedientes y pagarés en 13 agencias.'],
|
||||
['title' => 'Automatización crítica', 'body' => 'Automatizó el seguro de desgravamen, desde el cálculo de prima hasta la liquidación contable, reduciendo tiempos de 17 a 10 días.'],
|
||||
['title' => 'Supervisión nacional', 'body' => 'Implementó una matriz de supervisión y certificación por agencia, elevando el índice de cumplimiento operativo del 65 % al 88 %.'],
|
||||
],
|
||||
'pf_volunteer_title' => 'Voluntaria — Hogar San Camilo de Lellis',
|
||||
'pf_volunteer_year' => '2025',
|
||||
'pf_volunteer_body' => 'Hogar de niñas con discapacidad | Loja, Ecuador. Alineado a la visión y misión de responsabilidad social de la Fundación FACES Microfinanzas.',
|
||||
]);
|
||||
$ok[] = '✓ Métricas (5) + Highlights (4) + Impacto (3) + Voluntariado';
|
||||
|
||||
?>
|
||||
<!doctype html><html><head><meta charset="utf-8"><title>Datos CV cargados</title>
|
||||
<style>body{font-family:monospace;background:#0f1117;color:#e0e3ef;padding:2rem;line-height:1.8}h1{color:#22d3ee}li{color:#22c55e}.links a{color:#22d3ee;display:block;margin:.3rem 0}.warn{color:#f59e0b;margin-top:1.5rem}</style>
|
||||
</head><body>
|
||||
<h1>✅ CV de Patricia Flores — datos cargados con CMB2</h1>
|
||||
<ul><?php foreach ($ok as $r) echo "<li>$r</li>"; ?></ul>
|
||||
<div class="links" style="margin-top:1.5rem">
|
||||
<a href="/wp-admin">→ Ir al admin de WordPress</a>
|
||||
<a href="/wp-admin/admin.php?page=pflores_perfil">→ CV Patricia Flores → Perfil</a>
|
||||
<a href="/">→ Ver el CV en el sitio</a>
|
||||
</div>
|
||||
<p class="warn">⚠ Elimina este archivo una vez verificado.</p>
|
||||
</body></html>
|
||||
Reference in New Issue
Block a user