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>
|
||||
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
BIN
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 535 B |
@@ -0,0 +1,10 @@
|
||||
<svg width="640" height="760" viewBox="0 0 640 760" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="640" height="760" rx="48" fill="#F7EFE4"/>
|
||||
<circle cx="320" cy="238" r="112" fill="#E6B596"/>
|
||||
<path d="M182 612C182 515.35 260.35 437 357 437H283C379.65 437 458 515.35 458 612V640H182V612Z" fill="#D4582B"/>
|
||||
<path d="M221 230C221 175.324 265.324 131 320 131C374.676 131 419 175.324 419 230V284C419 338.676 374.676 383 320 383C265.324 383 221 338.676 221 284V230Z" fill="#1F1D1A"/>
|
||||
<path d="M244 245C244 202.474 278.474 168 321 168C363.526 168 398 202.474 398 245V283C398 325.526 363.526 360 321 360C278.474 360 244 325.526 244 283V245Z" fill="#F5CBB2"/>
|
||||
<rect x="116" y="488" width="408" height="28" rx="14" fill="#F2DDCC"/>
|
||||
<rect x="116" y="536" width="332" height="24" rx="12" fill="#F2DDCC"/>
|
||||
<rect x="116" y="578" width="280" height="24" rx="12" fill="#F2DDCC"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 902 B |
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Apex CV — theme.js
|
||||
* Mobile sidebar toggle · Print button · Scroll spy
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
Helpers
|
||||
----------------------------------------------------------------------- */
|
||||
function qs(selector, ctx) {
|
||||
return (ctx || document).querySelector(selector);
|
||||
}
|
||||
function qsa(selector, ctx) {
|
||||
return Array.from((ctx || document).querySelectorAll(selector));
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
Mobile sidebar
|
||||
----------------------------------------------------------------------- */
|
||||
var sidebar = qs('#ax-sidebar');
|
||||
var toggle = qs('.ax-mobile-toggle');
|
||||
var overlay = null;
|
||||
|
||||
function createOverlay() {
|
||||
if (overlay) return overlay;
|
||||
overlay = document.createElement('div');
|
||||
overlay.className = 'ax-sidebar-overlay';
|
||||
overlay.setAttribute('aria-hidden', 'true');
|
||||
document.body.appendChild(overlay);
|
||||
overlay.addEventListener('click', closeSidebar);
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function openSidebar() {
|
||||
if (!sidebar || !toggle) return;
|
||||
sidebar.classList.add('is-open');
|
||||
toggle.setAttribute('aria-expanded', 'true');
|
||||
var ov = createOverlay();
|
||||
// force reflow before adding class for transition
|
||||
ov.offsetHeight; // eslint-disable-line no-unused-expressions
|
||||
ov.classList.add('is-visible');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeSidebar() {
|
||||
if (!sidebar || !toggle) return;
|
||||
sidebar.classList.remove('is-open');
|
||||
toggle.setAttribute('aria-expanded', 'false');
|
||||
if (overlay) overlay.classList.remove('is-visible');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
function isMobile() {
|
||||
return window.innerWidth <= 768;
|
||||
}
|
||||
|
||||
if (toggle) {
|
||||
toggle.addEventListener('click', function () {
|
||||
var isOpen = sidebar && sidebar.classList.contains('is-open');
|
||||
if (isOpen) {
|
||||
closeSidebar();
|
||||
} else {
|
||||
openSidebar();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Close sidebar when clicking outside on mobile */
|
||||
document.addEventListener('click', function (e) {
|
||||
if (!isMobile()) return;
|
||||
if (!sidebar || !sidebar.classList.contains('is-open')) return;
|
||||
if (sidebar.contains(e.target)) return;
|
||||
if (toggle && toggle.contains(e.target)) return;
|
||||
closeSidebar();
|
||||
});
|
||||
|
||||
/* Close sidebar on nav link click (mobile) */
|
||||
qsa('.ax-nav__link').forEach(function (link) {
|
||||
link.addEventListener('click', function () {
|
||||
if (isMobile()) {
|
||||
closeSidebar();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* Close sidebar on resize back to desktop */
|
||||
window.addEventListener('resize', function () {
|
||||
if (!isMobile() && sidebar && sidebar.classList.contains('is-open')) {
|
||||
closeSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
Print button
|
||||
----------------------------------------------------------------------- */
|
||||
qsa('[data-apex-print]').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
window.print();
|
||||
});
|
||||
});
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
Scroll spy via IntersectionObserver
|
||||
----------------------------------------------------------------------- */
|
||||
var navLinks = qsa('.ax-nav__link');
|
||||
|
||||
if ('IntersectionObserver' in window && navLinks.length > 0) {
|
||||
var activeSection = null;
|
||||
|
||||
function setActive(sectionId) {
|
||||
if (activeSection === sectionId) return;
|
||||
activeSection = sectionId;
|
||||
navLinks.forEach(function (link) {
|
||||
var target = link.getAttribute('data-section') || link.getAttribute('href').replace('#', '');
|
||||
if (target === sectionId) {
|
||||
link.classList.add('is-active');
|
||||
link.setAttribute('aria-current', 'true');
|
||||
} else {
|
||||
link.classList.remove('is-active');
|
||||
link.removeAttribute('aria-current');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Collect sections that correspond to nav links
|
||||
var sectionIds = navLinks.map(function (link) {
|
||||
return link.getAttribute('data-section') || link.getAttribute('href').replace('#', '');
|
||||
});
|
||||
|
||||
var sectionEls = sectionIds
|
||||
.map(function (id) { return document.getElementById(id); })
|
||||
.filter(Boolean);
|
||||
|
||||
// Track which sections are currently intersecting
|
||||
var visibleSections = new Set();
|
||||
|
||||
var observer = new IntersectionObserver(
|
||||
function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.isIntersecting) {
|
||||
visibleSections.add(entry.target.id);
|
||||
} else {
|
||||
visibleSections.delete(entry.target.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Activate the topmost visible section (matches reading order)
|
||||
var toActivate = null;
|
||||
sectionEls.forEach(function (el) {
|
||||
if (visibleSections.has(el.id) && toActivate === null) {
|
||||
toActivate = el.id;
|
||||
}
|
||||
});
|
||||
|
||||
if (toActivate) {
|
||||
setActive(toActivate);
|
||||
}
|
||||
},
|
||||
{
|
||||
rootMargin: '-10% 0px -60% 0px',
|
||||
threshold: 0
|
||||
}
|
||||
);
|
||||
|
||||
sectionEls.forEach(function (el) { observer.observe(el); });
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
Smooth scroll for anchor links (fallback for older browsers)
|
||||
----------------------------------------------------------------------- */
|
||||
qsa('a[href^="#"]').forEach(function (link) {
|
||||
link.addEventListener('click', function (e) {
|
||||
var href = link.getAttribute('href');
|
||||
if (!href || href === '#') return;
|
||||
var target = document.querySelector(href);
|
||||
if (!target) return;
|
||||
e.preventDefault();
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php declare(strict_types=1); ?>
|
||||
</div><!-- /.ax-layout -->
|
||||
<?php wp_footer(); ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,351 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
get_header();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Data source: plugin first, theme fallback
|
||||
// ---------------------------------------------------------------------------
|
||||
$cv = function_exists('pflores_get_cv_data') ? pflores_get_cv_data() : apex_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'];
|
||||
|
||||
$acfPhoto = $cv['photo'] ?? '';
|
||||
$profileImage = $acfPhoto ?: get_template_directory_uri() . '/assets/images/patricia-flores-profile.jpeg';
|
||||
$cvFile = get_template_directory_uri() . '/assets/docs/CV_Patricia_Flores_Sanchez_ES_FINAL.docx';
|
||||
$qrImage = get_template_directory_uri() . '/assets/images/patricia-flores-qr.png';
|
||||
$publicUrl = 'https://pflores.linkedcorp.net';
|
||||
|
||||
// Build flat skills list for sidebar pills
|
||||
$skillsFlat = [];
|
||||
foreach ($competencies as $groupItems) {
|
||||
foreach ((array) $groupItems as $item) {
|
||||
$skillsFlat[] = is_array($item) ? ($item['name'] ?? '') : (string) $item;
|
||||
}
|
||||
}
|
||||
$skills = array_filter($skillsFlat);
|
||||
?>
|
||||
|
||||
<?php /* ===================================================================
|
||||
SIDEBAR
|
||||
=================================================================== */ ?>
|
||||
<aside class="ax-sidebar" id="ax-sidebar" role="complementary" aria-label="<?php esc_attr_e('Perfil y navegación', 'apex'); ?>">
|
||||
|
||||
<?php /* --- Profile ------------------------------------------------ */ ?>
|
||||
<div class="ax-profile">
|
||||
<div class="ax-profile__avatar-wrap">
|
||||
<img
|
||||
class="ax-profile__avatar"
|
||||
src="<?php echo esc_url($profileImage); ?>"
|
||||
alt="<?php echo esc_attr($hero['name']); ?>"
|
||||
width="120"
|
||||
height="120"
|
||||
>
|
||||
<span class="ax-profile__status" aria-label="<?php esc_attr_e('Disponible', 'apex'); ?>"></span>
|
||||
</div>
|
||||
<h1 class="ax-profile__name"><?php echo esc_html($hero['name']); ?></h1>
|
||||
<p class="ax-profile__role"><?php echo esc_html($hero['role']); ?></p>
|
||||
<p class="ax-profile__role2"><?php echo esc_html($hero['role2'] ?? ''); ?></p>
|
||||
</div>
|
||||
|
||||
<?php /* --- Navigation --------------------------------------------- */ ?>
|
||||
<nav class="ax-nav" aria-label="<?php esc_attr_e('Secciones del CV', 'apex'); ?>">
|
||||
<?php echo wp_kses_post(apex_render_nav()); ?>
|
||||
</nav>
|
||||
|
||||
<?php /* --- Contact ------------------------------------------------ */ ?>
|
||||
<div class="ax-sidebar-section">
|
||||
<span class="ax-sidebar-label"><?php esc_html_e('Contacto', 'apex'); ?></span>
|
||||
<ul class="ax-contact-list">
|
||||
<li class="ax-contact-list__item">
|
||||
<svg class="ax-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
||||
<path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" fill="currentColor"/>
|
||||
<path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" fill="currentColor"/>
|
||||
</svg>
|
||||
<a href="mailto:<?php echo esc_attr(antispambot($hero['email'])); ?>">
|
||||
<?php echo esc_html($hero['email']); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="ax-contact-list__item">
|
||||
<svg class="ax-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
||||
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" fill="currentColor"/>
|
||||
</svg>
|
||||
<a href="tel:<?php echo esc_attr(preg_replace('/[^0-9+]/', '', $hero['phone'])); ?>">
|
||||
<?php echo esc_html($hero['phone']); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="ax-contact-list__item">
|
||||
<svg class="ax-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd" fill="currentColor"/>
|
||||
</svg>
|
||||
<span><?php echo esc_html($hero['location']); ?></span>
|
||||
</li>
|
||||
<?php if (! empty($hero['linkedin'])) : ?>
|
||||
<li class="ax-contact-list__item">
|
||||
<svg class="ax-icon" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
||||
<path d="M16.338 16.338H13.67V12.16c0-.995-.017-2.277-1.387-2.277-1.39 0-1.601 1.086-1.601 2.207v4.248H8.014V7.688h2.558v1.17h.036c.356-.675 1.227-1.387 2.526-1.387 2.703 0 3.203 1.778 3.203 4.092v4.774zM5.005 6.575a1.548 1.548 0 11-.003-3.096 1.548 1.548 0 01.003 3.096zm-1.337 9.763H6.34V7.688H3.667v8.65zM17.668 1H2.328C1.595 1 1 1.581 1 2.298v15.403C1 18.418 1.595 19 2.328 19h15.34c.734 0 1.332-.582 1.332-1.299V2.298C19 1.581 18.402 1 17.668 1z" fill="currentColor"/>
|
||||
</svg>
|
||||
<a href="<?php echo esc_url($hero['linkedin']); ?>" target="_blank" rel="noreferrer noopener">
|
||||
LinkedIn
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php /* --- Skills / Competencies ---------------------------------- */ ?>
|
||||
<div class="ax-sidebar-section">
|
||||
<span class="ax-sidebar-label"><?php esc_html_e('Competencias', 'apex'); ?></span>
|
||||
<div class="ax-skill-pills">
|
||||
<?php foreach ($competencies as $groupName => $groupItems) : ?>
|
||||
<p class="ax-skill-group-label"><?php echo esc_html($groupName); ?></p>
|
||||
<?php foreach ((array) $groupItems as $item) : ?>
|
||||
<?php $name = is_array($item) ? ($item['name'] ?? '') : (string) $item; ?>
|
||||
<?php if ($name !== '') : ?>
|
||||
<span class="ax-skill-pill"><?php echo esc_html($name); ?></span>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php /* --- Languages / Availability ------------------------------- */ ?>
|
||||
<div class="ax-sidebar-section">
|
||||
<span class="ax-sidebar-label"><?php esc_html_e('Idiomas', 'apex'); ?></span>
|
||||
<p class="ax-sidebar-text"><?php echo esc_html($additional['Idiomas'] ?? 'Español nativo | Inglés básico'); ?></p>
|
||||
<span class="ax-sidebar-label" style="margin-top:.75rem"><?php esc_html_e('Disponibilidad', 'apex'); ?></span>
|
||||
<p class="ax-sidebar-text"><?php echo esc_html($hero['availability']); ?></p>
|
||||
</div>
|
||||
|
||||
<?php /* --- Action buttons ----------------------------------------- */ ?>
|
||||
<div class="ax-sidebar-section ax-sidebar-section--actions">
|
||||
<a class="ax-btn ax-btn--primary" href="<?php echo esc_url(home_url('/?cv_pdf=1')); ?>">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
||||
<?php esc_html_e('Descargar CV PDF', 'apex'); ?>
|
||||
</a>
|
||||
<a class="ax-btn ax-btn--ghost" href="<?php echo esc_url(home_url('/?cv_pdf=1')); ?>" target="_blank">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
|
||||
<?php esc_html_e('Descargar PDF', 'apex'); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</aside><!-- /.ax-sidebar -->
|
||||
|
||||
<?php /* ===================================================================
|
||||
MAIN CONTENT
|
||||
=================================================================== */ ?>
|
||||
<main class="ax-main" id="main-content">
|
||||
<div class="ax-content-wrap">
|
||||
|
||||
<?php /* ── SOBRE MÍ ─────────────────────────────────────────── */ ?>
|
||||
<section id="sobre-mi" class="ax-section">
|
||||
<header class="ax-section__head">
|
||||
<span class="ax-section__eyebrow"><?php esc_html_e('Perfil profesional', 'apex'); ?></span>
|
||||
<h2 class="ax-section__title"><?php echo esc_html($summary['title']); ?></h2>
|
||||
</header>
|
||||
<p class="ax-lead"><?php echo esc_html($summary['body']); ?></p>
|
||||
|
||||
<?php /* Metrics grid — 5 columns */ ?>
|
||||
<div class="ax-metrics">
|
||||
<?php foreach ($metrics as $metric) : ?>
|
||||
<article class="ax-metric-card">
|
||||
<strong class="ax-metric-card__value"><?php echo esc_html($metric['value']); ?></strong>
|
||||
<span class="ax-metric-card__label"><?php echo esc_html($metric['label']); ?></span>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php /* ── IMPACTO ──────────────────────────────────────────── */ ?>
|
||||
<section id="impacto" class="ax-section">
|
||||
<header class="ax-section__head">
|
||||
<span class="ax-section__eyebrow"><?php esc_html_e('Impacto ejecutivo', 'apex'); ?></span>
|
||||
<h2 class="ax-section__title"><?php esc_html_e('Resultados concretos con alcance nacional', 'apex'); ?></h2>
|
||||
</header>
|
||||
|
||||
<?php /* Highlights — 2×2 grid */ ?>
|
||||
<div class="ax-highlights">
|
||||
<?php foreach ($highlights as $hl) : ?>
|
||||
<article class="ax-highlight-card">
|
||||
<strong class="ax-highlight-card__value"><?php echo esc_html($hl['value']); ?></strong>
|
||||
<span class="ax-highlight-card__label"><?php echo esc_html($hl['label']); ?></span>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php /* Impact cards — 3 columns */ ?>
|
||||
<div class="ax-impact-cards">
|
||||
<?php foreach ($impact as $item) : ?>
|
||||
<article class="ax-impact-card">
|
||||
<h3 class="ax-impact-card__title"><?php echo esc_html($item['title']); ?></h3>
|
||||
<p class="ax-impact-card__body"><?php echo esc_html($item['body']); ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php /* ── EXPERIENCIA ─────────────────────────────────────── */ ?>
|
||||
<section id="experiencia" class="ax-section">
|
||||
<header class="ax-section__head">
|
||||
<span class="ax-section__eyebrow"><?php esc_html_e('Experiencia profesional', 'apex'); ?></span>
|
||||
<h2 class="ax-section__title"><?php esc_html_e('Trayectoria sólida en banca, operaciones y microfinanzas', 'apex'); ?></h2>
|
||||
</header>
|
||||
|
||||
<div class="ax-timeline">
|
||||
<?php foreach ($experience as $job) : ?>
|
||||
<article class="ax-timeline__item">
|
||||
<div class="ax-timeline__period">
|
||||
<span class="ax-timeline__period-text"><?php echo esc_html($job['period']); ?></span>
|
||||
<span class="ax-timeline__dot" aria-hidden="true"></span>
|
||||
</div>
|
||||
<div class="ax-timeline__content">
|
||||
<h3 class="ax-timeline__job-title"><?php echo esc_html($job['title']); ?></h3>
|
||||
<p class="ax-timeline__meta">
|
||||
<?php echo esc_html($job['company']); ?>
|
||||
<span class="ax-timeline__sep" aria-hidden="true">·</span>
|
||||
<?php echo esc_html($job['location']); ?>
|
||||
</p>
|
||||
<p class="ax-timeline__lead"><?php echo esc_html($job['lead']); ?></p>
|
||||
<?php if (! empty($job['bullets'])) : ?>
|
||||
<ul class="ax-timeline__bullets">
|
||||
<?php foreach ($job['bullets'] as $bullet) : ?>
|
||||
<li><?php echo esc_html($bullet); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php /* ── FORMACIÓN ───────────────────────────────────────── */ ?>
|
||||
<section id="formacion" class="ax-section">
|
||||
<header class="ax-section__head">
|
||||
<span class="ax-section__eyebrow"><?php esc_html_e('Formación académica', 'apex'); ?></span>
|
||||
<h2 class="ax-section__title"><?php esc_html_e('Base técnica y formación ejecutiva de alto nivel', 'apex'); ?></h2>
|
||||
</header>
|
||||
|
||||
<div class="ax-edu-cards">
|
||||
<?php foreach ($education as $edu) : ?>
|
||||
<article class="ax-edu-card">
|
||||
<span class="ax-edu-card__year"><?php echo esc_html($edu['year']); ?></span>
|
||||
<div class="ax-edu-card__body">
|
||||
<h3 class="ax-edu-card__title"><?php echo esc_html($edu['title']); ?></h3>
|
||||
<p class="ax-edu-card__institution"><?php echo esc_html($edu['institution']); ?></p>
|
||||
<?php if (! empty($edu['detail'])) : ?>
|
||||
<p class="ax-edu-card__detail"><?php echo esc_html($edu['detail']); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php /* ── CERTIFICACIONES ─────────────────────────────────── */ ?>
|
||||
<section id="certificaciones" class="ax-section">
|
||||
<header class="ax-section__head">
|
||||
<span class="ax-section__eyebrow"><?php esc_html_e('Certificaciones relevantes', 'apex'); ?></span>
|
||||
<h2 class="ax-section__title"><?php esc_html_e('Actualización continua en gerencia, procesos y analítica', 'apex'); ?></h2>
|
||||
</header>
|
||||
|
||||
<div class="ax-cert-list">
|
||||
<?php foreach ($certifications as $cert) : ?>
|
||||
<article class="ax-cert-item">
|
||||
<span class="ax-cert-item__year"><?php echo esc_html($cert['year']); ?></span>
|
||||
<div class="ax-cert-item__body">
|
||||
<h3 class="ax-cert-item__title"><?php echo esc_html($cert['title']); ?></h3>
|
||||
<p class="ax-cert-item__issuer"><?php echo esc_html($cert['issuer']); ?></p>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php /* ── CONTACTO ────────────────────────────────────────── */ ?>
|
||||
<section id="contacto" class="ax-section">
|
||||
<header class="ax-section__head">
|
||||
<span class="ax-section__eyebrow"><?php esc_html_e('Información adicional', 'apex'); ?></span>
|
||||
<h2 class="ax-section__title"><?php esc_html_e('Datos clave, voluntariado y tarjeta de presentación', 'apex'); ?></h2>
|
||||
</header>
|
||||
|
||||
<div class="ax-extras-grid">
|
||||
|
||||
<?php /* Volunteer */ ?>
|
||||
<div class="ax-extras-grid__card">
|
||||
<span class="ax-sidebar-label"><?php esc_html_e('Voluntariado', 'apex'); ?></span>
|
||||
<h3 class="ax-extras__heading"><?php echo esc_html($volunteer['title']); ?></h3>
|
||||
<p class="ax-extras__year"><?php echo esc_html($volunteer['year']); ?></p>
|
||||
<p class="ax-extras__body"><?php echo esc_html($volunteer['body']); ?></p>
|
||||
</div>
|
||||
|
||||
<?php /* Additional data */ ?>
|
||||
<div class="ax-extras-grid__card">
|
||||
<span class="ax-sidebar-label"><?php esc_html_e('Datos personales', 'apex'); ?></span>
|
||||
<dl class="ax-data-list">
|
||||
<?php foreach ($additional as $label => $value) : ?>
|
||||
<div class="ax-data-list__row">
|
||||
<dt><?php echo esc_html($label); ?></dt>
|
||||
<dd><?php echo esc_html($value); ?></dd>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<?php /* Business card / QR */ ?>
|
||||
<div class="ax-extras-grid__card ax-extras-grid__card--bcard">
|
||||
<span class="ax-sidebar-label"><?php esc_html_e('Tarjeta de presentación', 'apex'); ?></span>
|
||||
<article class="ax-bcard">
|
||||
<div class="ax-bcard__header">
|
||||
<p class="ax-bcard__name"><?php echo esc_html($hero['name']); ?></p>
|
||||
<p class="ax-bcard__role"><?php echo esc_html($hero['role']); ?></p>
|
||||
</div>
|
||||
<div class="ax-bcard__body">
|
||||
<div class="ax-bcard__qr">
|
||||
<img
|
||||
src="<?php echo esc_url($qrImage); ?>"
|
||||
alt="<?php esc_attr_e('Código QR — perfil web de Patricia Flores', 'apex'); ?>"
|
||||
width="120"
|
||||
height="120"
|
||||
>
|
||||
</div>
|
||||
<div class="ax-bcard__info">
|
||||
<p><?php echo esc_html($hero['location']); ?></p>
|
||||
<p>
|
||||
<a href="tel:<?php echo esc_attr(preg_replace('/[^0-9+]/', '', $hero['phone'])); ?>">
|
||||
<?php echo esc_html($hero['phone']); ?>
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="mailto:<?php echo esc_attr(antispambot($hero['email'])); ?>">
|
||||
<?php echo esc_html($hero['email']); ?>
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="<?php echo esc_url($publicUrl); ?>" target="_blank" rel="noreferrer noopener">
|
||||
<?php echo esc_html($publicUrl); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
</div><!-- /.ax-extras-grid -->
|
||||
</section>
|
||||
|
||||
</div><!-- /.ax-content-wrap -->
|
||||
</main><!-- /.ax-main -->
|
||||
|
||||
<?php get_footer(); ?>
|
||||
@@ -0,0 +1,118 @@
|
||||
<?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';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Theme setup
|
||||
// ---------------------------------------------------------------------------
|
||||
function apex_setup(): void
|
||||
{
|
||||
add_theme_support('title-tag');
|
||||
add_theme_support('post-thumbnails');
|
||||
add_theme_support('editor-styles');
|
||||
add_theme_support('responsive-embeds');
|
||||
add_theme_support('wp-block-styles');
|
||||
add_theme_support('align-wide');
|
||||
|
||||
register_nav_menus([
|
||||
'primary' => __('Menú principal', 'apex'),
|
||||
]);
|
||||
}
|
||||
add_action('after_setup_theme', 'apex_setup');
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Enqueue assets
|
||||
// ---------------------------------------------------------------------------
|
||||
function apex_enqueue_assets(): void
|
||||
{
|
||||
wp_enqueue_style(
|
||||
'apex-fonts',
|
||||
'https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap',
|
||||
[],
|
||||
null
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'apex-theme',
|
||||
get_template_directory_uri() . '/assets/css/theme.css',
|
||||
['apex-fonts'],
|
||||
wp_get_theme()->get('Version')
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'apex-theme',
|
||||
get_template_directory_uri() . '/assets/js/theme.js',
|
||||
[],
|
||||
wp_get_theme()->get('Version'),
|
||||
true
|
||||
);
|
||||
}
|
||||
add_action('wp_enqueue_scripts', 'apex_enqueue_assets');
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Body classes
|
||||
// ---------------------------------------------------------------------------
|
||||
function apex_body_classes(array $classes): array
|
||||
{
|
||||
$classes[] = 'apex-shell';
|
||||
|
||||
if (is_front_page()) {
|
||||
$classes[] = 'apex-front-page';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
add_filter('body_class', 'apex_body_classes');
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Navigation: render sidebar nav list
|
||||
// ---------------------------------------------------------------------------
|
||||
function apex_render_nav(): string
|
||||
{
|
||||
$items = [
|
||||
'#sobre-mi' => __('Sobre mí', 'apex'),
|
||||
'#impacto' => __('Impacto', 'apex'),
|
||||
'#experiencia' => __('Experiencia', 'apex'),
|
||||
'#formacion' => __('Formación', 'apex'),
|
||||
'#certificaciones' => __('Certificaciones', 'apex'),
|
||||
'#contacto' => __('Contacto', 'apex'),
|
||||
];
|
||||
|
||||
$html = '<ul class="ax-nav__list">';
|
||||
foreach ($items as $href => $label) {
|
||||
$html .= sprintf(
|
||||
'<li class="ax-nav__item"><a class="ax-nav__link" href="%s" data-section="%s">%s</a></li>',
|
||||
esc_url($href),
|
||||
esc_attr(ltrim($href, '#')),
|
||||
esc_html($label)
|
||||
);
|
||||
}
|
||||
$html .= '</ul>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Redirect sample page
|
||||
// ---------------------------------------------------------------------------
|
||||
function apex_redirect_default_sample_page(): void
|
||||
{
|
||||
if (! is_page()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$page = get_queried_object();
|
||||
if (! $page instanceof WP_Post) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($page->post_name === 'pagina-ejemplo' || $page->post_name === 'sample-page') {
|
||||
wp_safe_redirect(home_url('/'), 301);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
add_action('template_redirect', 'apex_redirect_default_sample_page', 1);
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php declare(strict_types=1); ?>
|
||||
<!doctype html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<head>
|
||||
<meta charset="<?php bloginfo('charset'); ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
<body <?php body_class(); ?>>
|
||||
<?php wp_body_open(); ?>
|
||||
<button class="ax-mobile-toggle" type="button" aria-expanded="false" aria-controls="ax-sidebar" aria-label="<?php esc_attr_e('Menú', 'apex'); ?>">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
<div class="ax-layout">
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
// No customizer settings - data comes from pflores-cv-fields plugin.
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Fallback CV data for the Apex CV theme.
|
||||
* Primary data source: pflores_get_cv_data() from the pflores-cv-fields plugin.
|
||||
* This function is only called when that plugin is not active.
|
||||
*/
|
||||
function apex_cv_data(): array
|
||||
{
|
||||
return [
|
||||
'hero' => [
|
||||
'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. 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.',
|
||||
'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',
|
||||
],
|
||||
|
||||
'metrics' => [
|
||||
['value' => '22+', 'label' => 'años de experiencia en banca y microfinanzas'],
|
||||
['value' => '26', 'label' => 'agencias bajo liderazgo operativo nacional'],
|
||||
['value' => '48', 'label' => 'personas a cargo en la estructura operativa'],
|
||||
['value' => 'USD 5 M', 'label' => 'en operaciones mensuales de microcrédito'],
|
||||
['value' => '28.000', 'label' => 'clientes coordinados en recaudación por canales internos y externos'],
|
||||
],
|
||||
|
||||
'highlights' => [
|
||||
['value' => '9/10', 'label' => 'calificación de gestión con resultado excelente en cuatro trimestres consecutivos'],
|
||||
['value' => '74 %', 'label' => 'reducción de requerimientos de soporte desde Dirección por descentralización de procesos'],
|
||||
['value' => '1,68 días', 'label' => 'tiempo de desembolso logrado en Q3 2025, mejor resultado del año'],
|
||||
['value' => '75 %', 'label' => 'reducción del índice de rotación del área entre 2022 y 2026'],
|
||||
],
|
||||
|
||||
'summary' => [
|
||||
'title' => 'Perfil estratégico con enfoque en eficiencia, control y ejecución sostenible',
|
||||
'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.',
|
||||
],
|
||||
|
||||
'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 %.',
|
||||
],
|
||||
],
|
||||
|
||||
'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' => [
|
||||
'Cumplimiento del POA: 98 % (Q2 2025), 96 % (Q3 2025), 100 % (Q4 2025) y 105 % (Q1 2026).',
|
||||
'La transformación digital logró que los desembolsos por transferencia representen el 47,80 % del monto total en Q1 2026.',
|
||||
'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.',
|
||||
'Automatizó el proceso del seguro de desgravamen con cálculo de prima, conciliación mensual, liquidación de siniestros y asientos contables automatizados.',
|
||||
'Elevó el índice de cumplimiento operativo nacional del 65 % al 88 % con la matriz de supervisión y certificación por agencia.',
|
||||
'Redujo el tiempo de atención del seguro de desgravamen de 17 a 10 días.',
|
||||
'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.',
|
||||
'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.',
|
||||
'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.',
|
||||
'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' => [
|
||||
'Reconstruyó desde cero las bases de cálculo del seguro de desgravamen y regularizó pagos pendientes desde enero de 2021.',
|
||||
'Elaboró el instructivo de constitución de garantías hipotecarias, proceso que no existía previamente en la institució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' => [
|
||||
'SAP FI (30 h).',
|
||||
'Excel Empresarial (24 h).',
|
||||
'Prevenció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' => [
|
||||
'Reconocida a nivel nacional por excelencia en control operativo.',
|
||||
'La agencia se mantuvo consistentemente por encima del 80 % en gestión de excepciones de crédito hipotecario.',
|
||||
'Administró proyecto inmobiliario institucional en Loja.',
|
||||
'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' => [
|
||||
'Gestión de caja sin faltantes ni sobrantes.',
|
||||
'Contrato renovado de forma anticipada a los tres meses.',
|
||||
'Apoyo al área de Contabilidad y reemplazo temporal de la contadora durante vacaciones.',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'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' => '',
|
||||
],
|
||||
],
|
||||
|
||||
'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'],
|
||||
],
|
||||
|
||||
'competencies' => [
|
||||
'Finanzas y Operaciones' => [
|
||||
['name' => 'Gestión de operaciones financieras', 'pct' => 98],
|
||||
['name' => 'Conciliación bancaria', 'pct' => 97],
|
||||
['name' => 'Originación de crédito', 'pct' => 95],
|
||||
['name' => 'Gestión de cartera', 'pct' => 95],
|
||||
['name' => 'Control interno', 'pct' => 96],
|
||||
['name' => 'Tesorería operativa', 'pct' => 94],
|
||||
['name' => 'Microfinanzas', 'pct' => 97],
|
||||
['name' => 'ALA/FT', 'pct' => 95],
|
||||
],
|
||||
'Tecnología y Procesos' => [
|
||||
['name' => 'Transformación digital', 'pct' => 92],
|
||||
['name' => 'BPM', 'pct' => 88],
|
||||
['name' => 'Integración de APIs / Web Services','pct' => 82],
|
||||
['name' => 'SAP FI', 'pct' => 80],
|
||||
['name' => 'Excel avanzado y dashboards', 'pct' => 90],
|
||||
['name' => 'Power BI', 'pct' => 85],
|
||||
['name' => 'IA aplicada', 'pct' => 78],
|
||||
['name' => 'Core financiero', 'pct' => 93],
|
||||
],
|
||||
'Liderazgo' => [
|
||||
['name' => 'Equipos de hasta 48 personas', 'pct' => 95],
|
||||
['name' => 'Remuneración variable', 'pct' => 90],
|
||||
['name' => 'Gestión del cambio', 'pct' => 92],
|
||||
['name' => 'Formación de formadores', 'pct' => 88],
|
||||
['name' => 'Diversidad, equidad e inclusión', 'pct' => 87],
|
||||
],
|
||||
],
|
||||
|
||||
'volunteer' => [
|
||||
'title' => 'Voluntaria — Hogar San Camilo de Lellis',
|
||||
'year' => '2025',
|
||||
'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.',
|
||||
],
|
||||
|
||||
'additional' => [
|
||||
'Idiomas' => 'Español nativo | Inglés básico en formación activa',
|
||||
'Disponibilidad' => 'Inmediata | Presencial / Híbrida / Remota',
|
||||
'C.I.' => '1103591648',
|
||||
'Fecha de nacimiento'=> '3 de agosto de 1980',
|
||||
'Web profesional' => 'pflores.linkedcorp.net',
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Visit tracking — Apex CV theme
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function apex_should_track_visit(): bool
|
||||
{
|
||||
if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_user_logged_in() && current_user_can('manage_options')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_front_page() || is_home() || is_singular();
|
||||
}
|
||||
|
||||
function apex_track_visit(): void
|
||||
{
|
||||
if (! apex_should_track_visit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$requestUri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
|
||||
$visitorHash = md5($requestUri . '|' . apex_get_client_ip() . '|' . gmdate('Y-m-d-H'));
|
||||
$transientKey = 'apex_visit_' . $visitorHash;
|
||||
|
||||
if (get_transient($transientKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_transient($transientKey, '1', HOUR_IN_SECONDS);
|
||||
|
||||
$total = (int) get_option('apex_total_visits', 0);
|
||||
update_option('apex_total_visits', $total + 1, false);
|
||||
|
||||
if (is_front_page()) {
|
||||
$frontPage = (int) get_option('page_on_front');
|
||||
if ($frontPage > 0) {
|
||||
$views = (int) get_post_meta($frontPage, '_apex_views', true);
|
||||
update_post_meta($frontPage, '_apex_views', $views + 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$postId = get_queried_object_id();
|
||||
if ($postId > 0) {
|
||||
$views = (int) get_post_meta($postId, '_apex_views', true);
|
||||
update_post_meta($postId, '_apex_views', $views + 1);
|
||||
}
|
||||
}
|
||||
add_action('template_redirect', 'apex_track_visit');
|
||||
|
||||
function apex_get_client_ip(): string
|
||||
{
|
||||
$keys = [
|
||||
'HTTP_X_FORWARDED_FOR',
|
||||
'HTTP_CLIENT_IP',
|
||||
'REMOTE_ADDR',
|
||||
];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (! empty($_SERVER[$key])) {
|
||||
$value = explode(',', (string) $_SERVER[$key]);
|
||||
return trim($value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return '0.0.0.0';
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Dashboard widget
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function apex_register_visits_dashboard_widget(): void
|
||||
{
|
||||
wp_add_dashboard_widget(
|
||||
'apex_visits_widget',
|
||||
__('Apex CV: Visitas', 'apex'),
|
||||
'apex_render_visits_dashboard_widget'
|
||||
);
|
||||
}
|
||||
add_action('wp_dashboard_setup', 'apex_register_visits_dashboard_widget');
|
||||
|
||||
function apex_render_visits_dashboard_widget(): void
|
||||
{
|
||||
$total = (int) get_option('apex_total_visits', 0);
|
||||
$frontPage = (int) get_option('page_on_front');
|
||||
$frontViews = $frontPage > 0 ? (int) get_post_meta($frontPage, '_apex_views', true) : 0;
|
||||
?>
|
||||
<div class="apex-visits-widget">
|
||||
<p><strong><?php esc_html_e('Visitas totales registradas:', 'apex'); ?></strong> <?php echo esc_html((string) $total); ?></p>
|
||||
<p><strong><?php esc_html_e('Visitas a la portada:', 'apex'); ?></strong> <?php echo esc_html((string) $frontViews); ?></p>
|
||||
<p><?php esc_html_e('El contador evita duplicados del mismo visitante en la misma URL durante una hora.', 'apex'); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Post/page views column in admin
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function apex_add_views_column(array $columns): array
|
||||
{
|
||||
$columns['apex_views'] = __('Visitas', 'apex');
|
||||
return $columns;
|
||||
}
|
||||
add_filter('manage_pages_columns', 'apex_add_views_column');
|
||||
add_filter('manage_posts_columns', 'apex_add_views_column');
|
||||
|
||||
function apex_render_views_column(string $column, int $postId): void
|
||||
{
|
||||
if ($column !== 'apex_views') {
|
||||
return;
|
||||
}
|
||||
|
||||
echo esc_html((string) ((int) get_post_meta($postId, '_apex_views', true)));
|
||||
}
|
||||
add_action('manage_pages_custom_column', 'apex_render_views_column', 10, 2);
|
||||
add_action('manage_posts_custom_column', 'apex_render_views_column', 10, 2);
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
// Fallback template — the theme uses front-page.php for all CV content.
|
||||
get_header();
|
||||
?>
|
||||
<div class="ax-main">
|
||||
<div class="ax-content-wrap">
|
||||
<?php if (have_posts()) : ?>
|
||||
<?php while (have_posts()) : the_post(); ?>
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
||||
<h1><?php the_title(); ?></h1>
|
||||
<div class="entry-content">
|
||||
<?php the_content(); ?>
|
||||
</div>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e('No se encontró contenido.', 'apex'); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php get_footer(); ?>
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Theme Name: Apex CV
|
||||
Theme URI: https://pflores.linkedcorp.net
|
||||
Description: Tema oscuro y elegante. Sidebar fijo izquierdo, paleta dark con acento cian.
|
||||
Version: 1.0.0
|
||||
Requires at least: 6.8
|
||||
Requires PHP: 8.1
|
||||
Text Domain: apex
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
/home/mgonzalez/desarrollo/web/pflores.linkedcorp.net/frontend/lumina-cv-theme
|
||||
@@ -0,0 +1 @@
|
||||
/home/mgonzalez/desarrollo/web/pflores.linkedcorp.net/frontend/persona-cv-theme
|
||||
Reference in New Issue
Block a user