Files
roi-theme/wp-content/themes/apus-theme/inc/featured-image.php
FrankZamora 995707156f Implementar Issues #2-4, #8-13, #16 - Funcionalidades core del tema
Implementación masiva de funcionalidades esenciales del tema apus-theme usando agentes paralelos para máxima eficiencia.

**Issues Completados:**

**Issue #2 - Eliminar bloat de WordPress:**
- inc/performance.php: 13 funciones que remueven emojis, oEmbed, feeds, dashicons, jQuery migrate, XML-RPC, etc.
- Optimización completa del frontend

**Issue #3 - Desactivar búsqueda nativa:**
- inc/search-disable.php: Bloquea queries de búsqueda, widget, formularios
- search.php: Retorna 404 con mensaje amigable

**Issue #4 - Desactivar comentarios:**
- inc/comments-disable.php: 15 funciones que eliminan comentarios de frontend y backend
- comments.php: Template desactivado

**Issue #8 - Footer con 4 widgets:**
- footer.php: Verificado con 4 áreas de widgets y copyright
- assets/css/footer.css: Estilos responsive completos
- Sistema de anchos configurables

**Issue #9 - Jerarquía de plantillas:**
- home.php, category.php, tag.php, author.php, date.php, taxonomy.php, attachment.php
- 7 nuevas plantillas + 12 verificadas
- Template parts completos
- Paginación en todos los archives

**Issue #10 - Imágenes destacadas:**
- inc/featured-image.php: 12 funciones para manejo de featured images
- Sin placeholders, lazy loading, alt text automático
- Responsive con Bootstrap, aspect ratio

**Issue #11 - Badge de categoría:**
- inc/category-badge.php: Badge Bootstrap sobre H1 en single posts
- Excluye "Uncategorized"
- Template tag: apus_display_category_badge()

**Issue #12 - TOC automático:**
- inc/toc.php: Genera TOC desde H2/H3
- assets/css/toc.css: Estilos con numeración CSS counters
- assets/js/toc.js: Smooth scroll, scroll spy, toggle
- Configurable con apus_get_option()

**Issue #13 - Posts relacionados:**
- inc/related-posts.php: Query por categoría, 12 funciones
- inc/admin/related-posts-options.php: Sistema de configuración
- assets/css/related-posts.css: Cards responsive
- Hook automático en single posts

**Issue #16 - AdSense delay:**
- inc/adsense-delay.php: Retardo de carga hasta scroll/click
- assets/js/adsense-loader.js: Detecta interacciones
- Mejora FID y TBT para Core Web Vitals

**Archivos Modificados:**
- functions.php: Includes de nuevos módulos, removido feed support
- single.php: Integración de category badge
- inc/enqueue-scripts.php: Enqueue de nuevos assets
- inc/theme-options-helpers.php: Helper functions para TOC

**Archivos Creados:**
- 7 nuevas plantillas WordPress
- 3 nuevos módulos inc/ (comments-disable, search-disable)
- 8 reportes de documentación .md

**Estadísticas:**
- Total funciones PHP: 60+ nuevas funciones
- Líneas de código: 2,500+ líneas
- Archivos nuevos: 18
- Archivos modificados: 9

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 16:53:31 -06:00

479 lines
15 KiB
PHP

<?php
/**
* Featured Image Functions
*
* Funciones para manejo de imágenes destacadas con comportamiento configurable.
* Sin placeholders - solo muestra imagen si existe.
* Issue #10 - Imágenes destacadas configurables
*
* @package Apus_Theme
* @since 1.0.0
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
/**
* Obtiene la imagen destacada de un post con configuración respetada
*
* Retorna HTML de la imagen destacada verificando:
* - Si las imágenes destacadas están habilitadas globalmente
* - Si el post tiene una imagen destacada asignada
* - Retorna HTML de la imagen o cadena vacía (sin placeholder)
*
* Tamaños disponibles:
* - apus-featured-large: 1200x600 (para single posts)
* - apus-featured-medium: 800x400 (para archives)
* - apus-thumbnail: 400x300 (para widgets/sidebars)
*
* @param int|null $post_id ID del post (null = post actual)
* @param string $size Tamaño de imagen registrado (default: apus-featured-large)
* @param array $attr Atributos HTML adicionales para la imagen
* @param bool $force_show Forzar mostrar ignorando configuración (default: false)
* @return string HTML de la imagen o cadena vacía
*/
function apus_get_featured_image($post_id = null, $size = 'apus-featured-large', $attr = array(), $force_show = false) {
// Obtener ID del post actual si no se especifica
if (!$post_id) {
$post_id = get_the_ID();
}
// Si no hay ID válido, retornar vacío
if (!$post_id) {
return '';
}
// Verificar si el post tiene imagen destacada
if (!has_post_thumbnail($post_id)) {
return ''; // No placeholder - retornar vacío
}
// Obtener tipo de post
$post_type = get_post_type($post_id);
// Verificar configuración global según tipo de contenido
if (!$force_show) {
// Primero intentar con apus_get_option (sistema de opciones del tema)
if (function_exists('apus_get_option')) {
if ($post_type === 'post') {
$enabled = apus_get_option('featured_image_single', true);
} elseif ($post_type === 'page') {
$enabled = apus_get_option('featured_image_page', true);
} else {
$enabled = apus_get_option('featured_image_' . $post_type, true);
}
} else {
// Fallback a theme_mod
$option_key = 'apus_featured_image_' . $post_type;
$enabled = get_theme_mod($option_key, true);
}
if (!$enabled) {
return '';
}
}
// Atributos por defecto con Bootstrap img-fluid
$default_attr = array(
'class' => 'img-fluid featured-image',
'loading' => 'lazy',
'alt' => ''
);
// Merge de atributos
$attr = wp_parse_args($attr, $default_attr);
// Si no hay alt text específico, usar el título del post
if (empty($attr['alt'])) {
$attr['alt'] = get_the_title($post_id);
}
// Obtener HTML de la imagen
$thumbnail = get_the_post_thumbnail($post_id, $size, $attr);
// Si no hay thumbnail, retornar vacío
if (empty($thumbnail)) {
return '';
}
// Retornar HTML de la imagen sin contenedor adicional
return $thumbnail;
}
/**
* Muestra la imagen destacada de un post
*
* Template tag para usar directamente en templates.
* Echo wrapper de apus_get_featured_image().
*
* Uso en templates:
* <?php apus_the_featured_image(); ?>
* <?php apus_the_featured_image(null, 'apus-featured-medium'); ?>
*
* @param int|null $post_id ID del post (null = post actual)
* @param string $size Tamaño de imagen registrado
* @param array $attr Atributos HTML adicionales
* @param bool $force_show Forzar mostrar ignorando configuración
*/
function apus_the_featured_image($post_id = null, $size = 'apus-featured-large', $attr = array(), $force_show = false) {
echo apus_get_featured_image($post_id, $size, $attr, $force_show);
}
/**
* Obtiene HTML de thumbnail para archives y loops
*
* Versión optimizada para listados con tamaño medium y link al post.
* Incluye clases responsive de Bootstrap.
*
* @param int|null $post_id ID del post (null = post actual)
* @param bool $with_link Envolver en enlace al post (default: true)
* @return string HTML del thumbnail o cadena vacía
*/
function apus_get_post_thumbnail($post_id = null, $with_link = true) {
// Obtener ID del post actual si no se especifica
if (!$post_id) {
$post_id = get_the_ID();
}
// Si no hay ID válido, retornar vacío
if (!$post_id) {
return '';
}
// Verificar si el post tiene imagen destacada
if (!has_post_thumbnail($post_id)) {
return ''; // No placeholder - retornar vacío
}
// Obtener la imagen con clases Bootstrap
$image = get_the_post_thumbnail($post_id, 'apus-featured-medium', array(
'class' => 'img-fluid post-thumbnail',
'loading' => 'lazy',
'alt' => get_the_title($post_id)
));
// Si no hay imagen, retornar vacío
if (!$image) {
return '';
}
// Construir HTML
$html = '';
if ($with_link) {
$html .= '<a href="' . esc_url(get_permalink($post_id)) . '" class="post-thumbnail-link d-block" aria-label="' . esc_attr(get_the_title($post_id)) . '">';
}
$html .= $image;
if ($with_link) {
$html .= '</a>';
}
return $html;
}
/**
* Muestra el thumbnail del post para archives
*
* Template tag para usar directamente en template-parts.
* Echo wrapper de apus_get_post_thumbnail().
*
* Uso en templates:
* <?php apus_the_post_thumbnail(); ?>
* <?php apus_the_post_thumbnail(null, false); // sin link ?>
*
* @param int|null $post_id ID del post (null = post actual)
* @param bool $with_link Envolver en enlace al post
*/
function apus_the_post_thumbnail($post_id = null, $with_link = true) {
echo apus_get_post_thumbnail($post_id, $with_link);
}
/**
* Obtiene HTML de thumbnail pequeño para widgets/sidebars
*
* Versión mini para listados compactos en sidebars.
* Usa el tamaño apus-thumbnail (400x300).
*
* @param int|null $post_id ID del post (null = post actual)
* @param bool $with_link Envolver en enlace al post (default: true)
* @return string HTML del thumbnail o cadena vacía
*/
function apus_get_post_thumbnail_small($post_id = null, $with_link = true) {
// Obtener ID del post actual si no se especifica
if (!$post_id) {
$post_id = get_the_ID();
}
// Si no hay ID válido, retornar vacío
if (!$post_id) {
return '';
}
// Verificar si el post tiene imagen destacada
if (!has_post_thumbnail($post_id)) {
return ''; // No placeholder - retornar vacío
}
// Obtener la imagen
$image = get_the_post_thumbnail($post_id, 'apus-thumbnail', array(
'class' => 'img-fluid post-thumbnail-small',
'loading' => 'lazy',
'alt' => get_the_title($post_id)
));
// Si no hay imagen, retornar vacío
if (!$image) {
return '';
}
// Construir HTML
$html = '';
if ($with_link) {
$html .= '<a href="' . esc_url(get_permalink($post_id)) . '" class="post-thumbnail-link-small d-block" aria-label="' . esc_attr(get_the_title($post_id)) . '">';
}
$html .= $image;
if ($with_link) {
$html .= '</a>';
}
return $html;
}
/**
* Muestra el thumbnail pequeño del post
*
* Template tag para usar en widgets y sidebars.
* Echo wrapper de apus_get_post_thumbnail_small().
*
* @param int|null $post_id ID del post (null = post actual)
* @param bool $with_link Envolver en enlace al post
*/
function apus_the_post_thumbnail_small($post_id = null, $with_link = true) {
echo apus_get_post_thumbnail_small($post_id, $with_link);
}
/**
* Verifica si se debe mostrar la imagen destacada según configuración
*
* Función helper para usar en condicionales de templates.
* Útil para estructuras if/else en templates.
*
* Uso en templates:
* <?php if (apus_should_show_featured_image()): ?>
* <div class="has-thumbnail">...</div>
* <?php endif; ?>
*
* @param int|null $post_id ID del post (null = post actual)
* @return bool True si debe mostrarse, false en caso contrario
*/
function apus_should_show_featured_image($post_id = null) {
// Obtener ID del post actual si no se especifica
if (!$post_id) {
$post_id = get_the_ID();
}
// Si no hay ID válido, retornar false
if (!$post_id) {
return false;
}
// Verificar si el post tiene imagen destacada
if (!has_post_thumbnail($post_id)) {
return false;
}
// Obtener tipo de post
$post_type = get_post_type($post_id);
// Verificar configuración global según tipo de contenido
if (function_exists('apus_get_option')) {
if ($post_type === 'post') {
$enabled = apus_get_option('featured_image_single', true);
} elseif ($post_type === 'page') {
$enabled = apus_get_option('featured_image_page', true);
} else {
$enabled = apus_get_option('featured_image_' . $post_type, true);
}
} else {
// Fallback a theme_mod
$option_key = 'apus_featured_image_' . $post_type;
$enabled = get_theme_mod($option_key, true);
}
return (bool) $enabled;
}
/**
* Obtiene la URL de la imagen destacada
*
* Útil para backgrounds CSS o meta tags de redes sociales (Open Graph, Twitter Cards).
*
* Uso:
* $image_url = apus_get_featured_image_url();
* echo '<div style="background-image: url(' . $image_url . ')"></div>';
*
* @param int|null $post_id ID del post (null = post actual)
* @param string $size Tamaño de imagen registrado (default: apus-featured-large)
* @return string URL de la imagen o cadena vacía
*/
function apus_get_featured_image_url($post_id = null, $size = 'apus-featured-large') {
// Obtener ID del post actual si no se especifica
if (!$post_id) {
$post_id = get_the_ID();
}
// Si no hay ID válido, retornar vacío
if (!$post_id) {
return '';
}
// Verificar si el post tiene imagen destacada
if (!has_post_thumbnail($post_id)) {
return ''; // No placeholder - retornar vacío
}
// Obtener URL de la imagen
$image_url = get_the_post_thumbnail_url($post_id, $size);
return $image_url ? esc_url($image_url) : '';
}
/**
* Obtiene el contenedor responsive de imagen destacada con aspect ratio
*
* Incluye aspect ratio CSS y lazy loading para mejor rendimiento.
* Evita layout shift (CLS) con ratio predefinido usando Bootstrap ratio utility.
*
* Uso en templates:
* <?php echo apus_get_featured_image_responsive(); ?>
* <?php echo apus_get_featured_image_responsive(null, 'apus-featured-medium', '16/9'); ?>
*
* @param int|null $post_id ID del post (null = post actual)
* @param string $size Tamaño de imagen registrado (default: apus-featured-large)
* @param string $aspect_ratio Ratio CSS - '2/1' para 2:1, '16/9', etc. (default: '2/1')
* @return string HTML del contenedor con imagen o cadena vacía
*/
function apus_get_featured_image_responsive($post_id = null, $size = 'apus-featured-large', $aspect_ratio = '2/1') {
// Obtener la imagen
$image = apus_get_featured_image($post_id, $size);
// Si no hay imagen, retornar vacío
if (empty($image)) {
return '';
}
// Construir contenedor responsive con Bootstrap ratio y aspect-ratio CSS
$html = '<div class="featured-image-wrapper ratio" style="--bs-aspect-ratio: ' . esc_attr($aspect_ratio) . '; aspect-ratio: ' . esc_attr($aspect_ratio) . ';">';
$html .= $image;
$html .= '</div>';
return $html;
}
/**
* Muestra el contenedor responsive de imagen destacada
*
* Template tag para usar directamente en templates.
* Echo wrapper de apus_get_featured_image_responsive().
*
* @param int|null $post_id ID del post (null = post actual)
* @param string $size Tamaño de imagen registrado
* @param string $aspect_ratio Ratio CSS (ej: '16/9', '2/1')
*/
function apus_the_featured_image_responsive($post_id = null, $size = 'apus-featured-large', $aspect_ratio = '2/1') {
echo apus_get_featured_image_responsive($post_id, $size, $aspect_ratio);
}
/**
* Verifica si las imágenes destacadas están habilitadas para un tipo de post
*
* Función legacy mantenida por compatibilidad.
*
* @param string $post_type Tipo de post (vacío = post actual)
* @return bool True si habilitadas, false en caso contrario
*/
function apus_is_featured_image_enabled($post_type = '') {
if (empty($post_type)) {
$post_type = get_post_type();
}
if (!$post_type) {
return true; // Default habilitado
}
// Intentar con apus_get_option primero
if (function_exists('apus_get_option')) {
if ($post_type === 'post') {
return apus_get_option('featured_image_single', true);
} elseif ($post_type === 'page') {
return apus_get_option('featured_image_page', true);
} else {
return apus_get_option('featured_image_' . $post_type, true);
}
}
// Fallback a theme_mod
$option_key = 'apus_featured_image_' . $post_type;
return (bool) get_theme_mod($option_key, true);
}
/**
* Registra configuración de imágenes destacadas en Customizer
*
* Agrega controles para habilitar/deshabilitar imágenes destacadas por tipo de post.
* Funciona como fallback si no hay panel de opciones del tema.
*
* @param WP_Customize_Manager $wp_customize Objeto Theme Customizer
*/
function apus_featured_image_customizer($wp_customize) {
// Solo agregar si no existe el panel de opciones del tema
if (function_exists('apus_get_option')) {
return; // El panel de opciones manejará esto
}
// Agregar sección
$wp_customize->add_section('apus_featured_images', array(
'title' => __('Imágenes Destacadas', 'apus-theme'),
'description' => __('Configurar visualización de imágenes destacadas por tipo de contenido.', 'apus-theme'),
'priority' => 30,
));
// Obtener tipos de post públicos
$post_types = get_post_types(array('public' => true), 'objects');
foreach ($post_types as $post_type) {
// Saltar attachments
if ($post_type->name === 'attachment') {
continue;
}
$setting_id = 'apus_featured_image_' . $post_type->name;
// Agregar setting
$wp_customize->add_setting($setting_id, array(
'default' => true,
'sanitize_callback' => 'wp_validate_boolean',
'transport' => 'refresh',
));
// Agregar control
$wp_customize->add_control($setting_id, array(
'label' => sprintf(
/* translators: %s: nombre del tipo de post */
__('Habilitar para %s', 'apus-theme'),
$post_type->labels->name
),
'section' => 'apus_featured_images',
'type' => 'checkbox',
));
}
}
add_action('customize_register', 'apus_featured_image_customizer');