*/ function apus_output_schema_jsonld() { $schemas = array(); // Siempre incluir Organization y WebSite $schemas[] = apus_get_organization_schema(); $schemas[] = apus_get_website_schema(); // Schemas específicos según el contexto if (is_singular('post')) { $schemas[] = apus_get_article_schema(); $schemas[] = apus_get_breadcrumb_schema(); // HowTo schema (Issue #42) $howto_schema = apus_get_howto_schema(); if ($howto_schema) { $schemas[] = $howto_schema; } // FAQPage schema (Issue #38) $faq_schema = apus_get_faqpage_schema(); if ($faq_schema) { $schemas[] = $faq_schema; } } elseif (is_page()) { $schemas[] = apus_get_webpage_schema(); $schemas[] = apus_get_breadcrumb_schema(); } elseif (is_front_page()) { // La página principal ya tiene WebSite schema $schemas[] = apus_get_breadcrumb_schema(); } else { // Para archives, categorías, etc. $schemas[] = apus_get_breadcrumb_schema(); } // Filtrar schemas vacíos $schemas = array_filter($schemas); // Crear graph con todos los schemas if (!empty($schemas)) { $graph = array( '@context' => 'https://schema.org', '@graph' => $schemas ); echo '' . "\n"; } } add_action('wp_head', 'apus_output_schema_jsonld', 5); /** * Genera el schema Organization * Información sobre la organización/empresa * * @return array Schema Organization */ function apus_get_organization_schema() { $logo = get_theme_mod('custom_logo'); $logo_url = ''; if ($logo) { $logo_data = wp_get_attachment_image_src($logo, 'full'); if ($logo_data) { $logo_url = $logo_data[0]; } } // Si no hay logo personalizado, usar un fallback if (empty($logo_url)) { $logo_url = get_template_directory_uri() . '/assets/images/logo.png'; } $schema = array( '@type' => 'Organization', '@id' => home_url('/#organization'), 'name' => get_bloginfo('name'), 'url' => home_url('/'), 'logo' => array( '@type' => 'ImageObject', 'url' => $logo_url, '@id' => home_url('/#logo') ), 'description' => get_bloginfo('description'), 'sameAs' => array() ); // Añadir redes sociales si están configuradas $social_profiles = array( 'facebook' => get_theme_mod('social_facebook', ''), 'twitter' => get_theme_mod('social_twitter', ''), 'linkedin' => get_theme_mod('social_linkedin', ''), 'instagram' => get_theme_mod('social_instagram', ''), 'youtube' => get_theme_mod('social_youtube', '') ); foreach ($social_profiles as $profile_url) { if (!empty($profile_url)) { $schema['sameAs'][] = $profile_url; } } // Eliminar array vacío si no hay redes sociales if (empty($schema['sameAs'])) { unset($schema['sameAs']); } return $schema; } /** * Genera el schema WebSite con SearchAction * Información del sitio web y funcionalidad de búsqueda * * @return array Schema WebSite */ function apus_get_website_schema() { $schema = array( '@type' => 'WebSite', '@id' => home_url('/#website'), 'url' => home_url('/'), 'name' => get_bloginfo('name'), 'description' => get_bloginfo('description'), 'publisher' => array( '@id' => home_url('/#organization') ), 'inLanguage' => 'es-MX' ); // Añadir SearchAction solo si la búsqueda está habilitada // (el tema desactiva la búsqueda por defecto en Issue #3) if (!get_option('apus_disable_search', false)) { $schema['potentialAction'] = array( '@type' => 'SearchAction', 'target' => array( '@type' => 'EntryPoint', 'urlTemplate' => home_url('/?s={search_term_string}') ), 'query-input' => 'required name=search_term_string' ); } return $schema; } /** * Genera el schema Article para posts * Información completa del artículo * * @return array|null Schema Article o null si no es un post */ function apus_get_article_schema() { if (!is_singular('post')) { return null; } global $post; $post_id = get_the_ID(); // Imagen destacada $image_url = ''; $image_width = 1200; $image_height = 630; if (has_post_thumbnail($post_id)) { $image_data = wp_get_attachment_image_src(get_post_thumbnail_id($post_id), 'full'); if ($image_data) { $image_url = $image_data[0]; $image_width = $image_data[1]; $image_height = $image_data[2]; } } // Autor $author_id = $post->post_author; $author_name = get_the_author_meta('display_name', $author_id); $author_url = get_author_posts_url($author_id); $author_description = get_the_author_meta('description', $author_id); // Categorías y palabras clave $categories = get_the_category($post_id); $category_names = array(); if (!empty($categories)) { foreach ($categories as $category) { $category_names[] = $category->name; } } // Extracto o descripción $description = get_the_excerpt($post_id); if (empty($description)) { $description = wp_trim_words(strip_tags($post->post_content), 55, '...'); } $schema = array( '@type' => 'Article', '@id' => get_permalink($post_id) . '#article', 'headline' => get_the_title($post_id), 'description' => $description, 'datePublished' => get_the_date('c', $post_id), 'dateModified' => get_the_modified_date('c', $post_id), 'author' => array( '@type' => 'Person', '@id' => $author_url . '#person', 'name' => $author_name, 'url' => $author_url ), 'publisher' => array( '@id' => home_url('/#organization') ), 'mainEntityOfPage' => array( '@type' => 'WebPage', '@id' => get_permalink($post_id) ), 'inLanguage' => 'es-MX', 'isPartOf' => array( '@id' => home_url('/#website') ) ); // Añadir imagen si existe if (!empty($image_url)) { $schema['image'] = array( '@type' => 'ImageObject', 'url' => $image_url, 'width' => $image_width, 'height' => $image_height ); } // Añadir categorías como articleSection if (!empty($category_names)) { $schema['articleSection'] = $category_names; $schema['keywords'] = implode(', ', $category_names); } // Añadir descripción del autor si existe if (!empty($author_description)) { $schema['author']['description'] = $author_description; } // Número de palabras $word_count = str_word_count(strip_tags($post->post_content)); if ($word_count > 0) { $schema['wordCount'] = $word_count; } return $schema; } /** * Genera el schema WebPage para páginas estáticas * Información de página genérica * * @return array|null Schema WebPage o null si no es una página */ function apus_get_webpage_schema() { if (!is_page()) { return null; } global $post; $page_id = get_the_ID(); // Imagen destacada $image_url = ''; if (has_post_thumbnail($page_id)) { $image_data = wp_get_attachment_image_src(get_post_thumbnail_id($page_id), 'full'); if ($image_data) { $image_url = $image_data[0]; } } // Extracto o descripción $description = get_the_excerpt($page_id); if (empty($description)) { $description = wp_trim_words(strip_tags($post->post_content), 55, '...'); } $schema = array( '@type' => 'WebPage', '@id' => get_permalink($page_id) . '#webpage', 'url' => get_permalink($page_id), 'name' => get_the_title($page_id), 'description' => $description, 'datePublished' => get_the_date('c', $page_id), 'dateModified' => get_the_modified_date('c', $page_id), 'isPartOf' => array( '@id' => home_url('/#website') ), 'inLanguage' => 'es-MX' ); // Añadir imagen si existe if (!empty($image_url)) { $schema['primaryImageOfPage'] = array( '@type' => 'ImageObject', 'url' => $image_url ); } // Breadcrumb reference $schema['breadcrumb'] = array( '@id' => get_permalink($page_id) . '#breadcrumb' ); return $schema; } /** * Genera el schema BreadcrumbList * Navegación de migas de pan * * @return array Schema BreadcrumbList */ function apus_get_breadcrumb_schema() { $items = array(); $position = 1; // Inicio (Home) $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => 'Inicio', 'item' => home_url('/') ); // Para posts if (is_singular('post')) { $post_id = get_the_ID(); $categories = get_the_category($post_id); // Añadir la primera categoría si existe if (!empty($categories)) { $category = $categories[0]; $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => $category->name, 'item' => get_category_link($category->term_id) ); } // Post actual (sin item ya que es la página actual) $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => get_the_title($post_id) ); } // Para páginas elseif (is_page()) { global $post; $page_id = get_the_ID(); // Si tiene páginas padre if ($post->post_parent) { $ancestors = array_reverse(get_post_ancestors($page_id)); foreach ($ancestors as $ancestor_id) { $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => get_the_title($ancestor_id), 'item' => get_permalink($ancestor_id) ); } } // Página actual $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => get_the_title($page_id) ); } // Para categorías elseif (is_category()) { $category = get_queried_object(); $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => $category->name ); } // Para archivos de autor elseif (is_author()) { $author = get_queried_object(); $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => $author->display_name ); } // Para archivos de fecha elseif (is_date()) { if (is_year()) { $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => get_the_date('Y') ); } elseif (is_month()) { $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => get_the_date('F Y') ); } elseif (is_day()) { $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => get_the_date('d F Y') ); } } // Para búsquedas elseif (is_search()) { $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => 'Resultados de búsqueda para: ' . get_search_query() ); } // Para 404 elseif (is_404()) { $items[] = array( '@type' => 'ListItem', 'position' => $position++, 'name' => 'Página no encontrada' ); } $schema = array( '@type' => 'BreadcrumbList', '@id' => get_permalink() . '#breadcrumb', 'itemListElement' => $items ); return $schema; } /** * Genera Schema HowTo para procesos paso a paso * Detecta sección con ID #proceso o heading que contenga "proceso" * * @return array|null Schema HowTo o null si no aplica */ function apus_get_howto_schema() { if (!is_single()) { return null; } global $post; $content = $post->post_content; // Verificar si el post tiene sección de proceso if (stripos($content, 'id="proceso"') === false && stripos($content, '>proceso<') === false && stripos($content, '>proceso de') === false) { return null; } // Usar DOMDocument para parsear libxml_use_internal_errors(true); $dom = new DOMDocument(); $dom->loadHTML('' . $content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); libxml_clear_errors(); $steps = array(); // Buscar listas ordenadas
como respuesta $next_element = $h3->nextSibling; while ($next_element && $next_element->nodeType !== 1) { $next_element = $next_element->nextSibling; } if ($next_element && $next_element->nodeName === 'p') { $answer_text = trim(strip_tags($next_element->textContent)); if (!empty($answer_text)) { $questions[] = array( '@type' => 'Question', 'name' => $question_text, 'acceptedAnswer' => array( '@type' => 'Answer', 'text' => $answer_text ) ); } } } // Mínimo 2 preguntas para generar schema if (count($questions) < 2) { return null; } // Limitar a 10 preguntas máximo if (count($questions) > 10) { $questions = array_slice($questions, 0, 10); } return array( '@type' => 'FAQPage', '@id' => get_permalink() . '#faqpage', 'mainEntity' => $questions ); } /** * Deshabilita los schemas de Rank Math si está activo * Para evitar duplicación de schemas */ function apus_disable_rankmath_schema() { // Deshabilitar schema de Rank Math si está activo if (class_exists('RankMath')) { add_filter('rank_math/json_ld', '__return_false'); } // Deshabilitar schema de Yoast SEO si está activo if (defined('WPSEO_VERSION')) { add_filter('wpseo_json_ld_output', '__return_false'); } } add_action('wp_head', 'apus_disable_rankmath_schema', 1);