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:
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