* Plugin Name: MCM Master SEO & News Engine V3.2 * Description: Schema NewsArticle/AnalysisNewsArticle/NewsMediaOrganization, OG tags, robots consolidado y LLMS dinámico. * Version: 3.2 * * Changelog V3.2: * - Auto-derivation of analysis description from post_content (1024–1500 chars, * cut at last sentence boundary). Manual `_mcm_analysis_desc` still overrides. * - Auto-derivation of alternativeHeadline via Polylang for non-EN posts: * fetches the EN translation's title automatically. Manual override still * works via `_mcm_analysis_alt_headline`. * - Result: an analysis post requires ZERO manual meta to emit a complete * AnalysisNewsArticle schema. Only `_mcm_analysis_about` remains optional * for explicit semantic entities. * * Changelog V3.1: * - AnalysisNewsArticle support: detects analysis posts via category term_meta * `_mcm_is_analysis_category=1` and elevates @type from NewsArticle to * AnalysisNewsArticle for those posts only. * - Adds optional fields for analysis: alternativeHeadline, long description, * about[] entities, genre. All read from post_meta — never hardcoded. * - Single emission: still ONE JSON-LD block per page, no duplication. * - Backwards compatible: posts not in an analysis category behave identically * to V3.0. */ defined('ABSPATH') || exit; /* ------------------------------------------------------------------------- HELPER: is this post an analysis piece? Checks every category assigned to the post; if any has term_meta `_mcm_is_analysis_category = 1`, the post is treated as analysis. Falls back to post_meta `_mcm_is_analysis = 1` for cases where an analysis is published outside the dedicated category (rare but supported). ------------------------------------------------------------------------- */ if ( ! function_exists('mcm_is_analysis_post') ) { function mcm_is_analysis_post($post_id) { // Manual override: post-level meta wins. if ( get_post_meta($post_id, '_mcm_is_analysis', true) === '1' ) { return true; } // Category-level detection. $cats = get_the_category($post_id); if ( empty($cats) ) return false; foreach ( $cats as $cat ) { if ( get_term_meta($cat->term_id, '_mcm_is_analysis_category', true) === '1' ) { return true; } } return false; } } /* ------------------------------------------------------------------------- 1. MOTOR DE SCHEMA JSON-LD - Portada: NewsMediaOrganization (estilo NYT) - Artículos: NewsArticle por defecto, AnalysisNewsArticle si la categoría está marcada como análisis vía term_meta. ------------------------------------------------------------------------- */ add_action('wp_head', function() { global $post; $site_url = home_url('/'); $logo_url = 'https://www.martincid.com/wp-content/uploads/2024/02/mcm_logo_112_112.png'; $schema = []; // --- PORTADA: NewsMediaOrganization --- if ( is_front_page() ) { $schema = [ '@context' => 'https://schema.org', '@type' => 'NewsMediaOrganization', '@id' => $site_url . '#organization', 'name' => 'Martin Cid Magazine', 'url' => $site_url, 'logo' => [ '@type' => 'ImageObject', 'url' => $logo_url, 'width' => 112, 'height' => 112, ], 'sameAs' => [ 'https://www.facebook.com/martincidmagazinemcm', 'https://twitter.com/martincid', 'https://news.google.com/publications/CAAiEIv0h98T7G_9BD-jaLEyitEqFAgKIhCL9IffE-xv_QQ_o2ixMorR', ], 'publishingPrinciples' => $site_url . 'editorial-principles/', 'ethicsPolicy' => $site_url . 'ethics-policy/', 'masthead' => $site_url . 'team-members/', ]; } // --- ARTÍCULOS: NewsArticle / AnalysisNewsArticle --- elseif ( is_singular('post') && !empty($post) ) { // Idioma del artículo (Polylang) $lang_code = function_exists('pll_current_language') ? pll_current_language('locale') : 'en_US'; // Normalizar locale a BCP-47 para inLanguage (en_US → en-US) $in_language = str_replace('_', '-', $lang_code); // Categoría principal como articleSection $categories = get_the_category($post->ID); $article_section = !empty($categories) ? $categories[0]->name : 'News'; // Imagen destacada con dimensiones $thumb_id = get_post_thumbnail_id($post->ID); $img_data = wp_get_attachment_image_src($thumb_id, 'full'); $img_meta = $img_data ? wp_get_attachment_metadata($thumb_id) : null; $image_obj = [ '@type' => 'ImageObject', 'url' => $img_data ? $img_data[0] : $logo_url, ]; if ( $img_data && $img_data[1] ) $image_obj['width'] = (int)$img_data[1]; if ( $img_data && $img_data[2] ) $image_obj['height'] = (int)$img_data[2]; // Detectar si es análisis para elegir tipo y descripción adecuada $is_analysis = mcm_is_analysis_post($post->ID); $type = $is_analysis ? 'AnalysisNewsArticle' : 'NewsArticle'; // Descripción según tipo: // - Análisis: priority _mcm_analysis_desc (manual, 1024+) → autogen 1500 chars desde post_content (V3.2) // - Resto: priority _mcm_seo_desc → autogen 160 chars desde excerpt $description = ''; if ( $is_analysis ) { $description = get_post_meta($post->ID, '_mcm_analysis_desc', true); if ( !$description ) { // V3.2: auto-extraer ~1500 chars del cuerpo limpio. // Cubre el rango óptimo (1024-1800) que Discover y AI Overviews valoran. $clean = preg_replace('/\s+/', ' ', wp_strip_all_tags(strip_shortcodes($post->post_content))); $clean = trim($clean); if ( mb_strlen($clean) > 1500 ) { // Recortar en la última oración completa antes del límite para no cortar mid-sentence $cut = mb_substr($clean, 0, 1500); $last_period = max( mb_strrpos($cut, '. '), mb_strrpos($cut, '! '), mb_strrpos($cut, '? ') ); $description = ($last_period && $last_period > 1024) ? mb_substr($cut, 0, $last_period + 1) : $cut; } else { $description = $clean; } } } else { $description = get_post_meta($post->ID, '_mcm_seo_desc', true); if ( !$description ) { $raw = $post->post_excerpt ?: $post->post_content; $description = mb_substr(preg_replace('/\s+/', ' ', wp_strip_all_tags(strip_shortcodes($raw))), 0, 160); } } $schema = [ '@context' => 'https://schema.org', '@type' => $type, 'mainEntityOfPage' => [ '@type' => 'WebPage', '@id' => get_permalink(), ], 'headline' => get_the_title(), 'description' => $description, 'articleSection' => $article_section, 'inLanguage' => $in_language, 'image' => $image_obj, 'datePublished' => get_the_date('c'), 'dateModified' => get_the_modified_date('c'), 'author' => [ '@type' => 'Person', 'name' => get_the_author_meta('display_name', $post->post_author), 'url' => get_author_posts_url($post->post_author), ], 'publisher' => [ '@type' => 'Organization', 'name' => 'Martin Cid Magazine', 'url' => $site_url, 'logo' => [ '@type' => 'ImageObject', 'url' => $logo_url, 'width' => 112, 'height' => 112, ], ], 'isAccessibleForFree' => true, 'hasPart' => [ '@type' => 'WebPageElement', 'isAccessibleForFree' => true, 'cssSelector' => '.entry-content', ], 'speakable' => [ '@type' => 'SpeakableSpecification', 'cssSelector' => ['h1', '.entry-content p:first-of-type'], ], ]; // --- Campos adicionales solo para AnalysisNewsArticle --- if ( $is_analysis ) { // Alternative headline: manual override → autodeducir desde traducción EN via Polylang (V3.2) $alt_headline = get_post_meta($post->ID, '_mcm_analysis_alt_headline', true); if ( !$alt_headline && function_exists('pll_get_post') && $lang_code !== 'en_US' ) { $en_post_id = pll_get_post($post->ID, 'en'); if ( $en_post_id && $en_post_id != $post->ID ) { $en_title = get_the_title($en_post_id); if ( $en_title ) $alt_headline = $en_title; } } if ( $alt_headline ) { $schema['alternativeHeadline'] = $alt_headline; } // about[]: CSV of canonical English Wikipedia entity names // e.g. "Generative artificial intelligence,Higher education,Cognitive offloading" $about_csv = get_post_meta($post->ID, '_mcm_analysis_about', true); if ( $about_csv ) { $about_items = array_filter(array_map('trim', explode(',', $about_csv))); if ( !empty($about_items) ) { // Cap at 5 to avoid semantic dilution (Google penalises noise above ~5) $about_items = array_slice($about_items, 0, 5); $schema['about'] = array_map(function($name) { return ['@type' => 'Thing', 'name' => $name]; }, $about_items); } } // Genre: explicit "Analysis" tag for clearer Discover categorisation $schema['genre'] = 'Analysis'; } } if ( !empty($schema) ) { echo "\n" . '' . "\n"; } }, 1); /* ------------------------------------------------------------------------- 2. OG TAGS + TWITTER CARD og:locale dinámico por idioma (Polylang). Se emite solo en singulares y portada. El tema puede emitir sus propios OG básicos — este bloque los sobreescribe con valores más precisos gracias a la priority 5 (después del tema). ------------------------------------------------------------------------- */ add_action('wp_head', function() { global $post; // Detectar locale actual via Polylang $locale = function_exists('pll_current_language') ? pll_current_language('locale') : get_locale(); $og_locale = str_replace('-', '_', $locale); // BCP-47 → og:locale format (en_US) if ( is_front_page() ) { $og_title = function_exists('pll__') ? pll__('Martin Cid Magazine - Movies, TV, Art, Music & Tech') : get_bloginfo('name'); $og_desc = function_exists('pll__') ? pll__('International magazine dedicated to entertainment, cinema, art, music and tech.') : ''; $og_url = home_url('/'); $og_image = 'https://www.martincid.com/wp-content/uploads/2024/02/mcm_logo_112_112.png'; $og_type = 'website'; } elseif ( is_singular('post') && !empty($post) ) { $og_title = get_the_title(); $raw_desc = get_post_meta($post->ID, '_mcm_seo_desc', true); if ( !$raw_desc ) { $raw = $post->post_excerpt ?: $post->post_content; $raw_desc = mb_substr(preg_replace('/\s+/', ' ', wp_strip_all_tags(strip_shortcodes($raw))), 0, 160); } $og_desc = $raw_desc; $og_url = get_permalink(); $thumb_id = get_post_thumbnail_id($post->ID); $img_src = wp_get_attachment_image_src($thumb_id, 'full'); $og_image = $img_src ? $img_src[0] : 'https://www.martincid.com/wp-content/uploads/2024/02/mcm_logo_112_112.png'; $og_type = 'article'; } else { return; // No emitir OG en páginas de archivo, categoría, etc. } echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; // Twitter Card echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; }, 5); // Priority 5: después del tema (priority 10 por defecto) si el tema emite OG /* ------------------------------------------------------------------------- 3. ROBOTS CONSOLIDADO Un único punto de control para todos los meta robots del sitio. Incluye max-snippet e max-video-preview para Discover. NOTA: mcm-seo-bare-metal.php NO emite robots — solo este archivo. ------------------------------------------------------------------------- */ add_action('wp_head', function() { if ( is_tag() || is_search() || is_author() || is_date() || is_404() ) { echo '' . "\n"; } else { echo '' . "\n"; } }, 1); /* ------------------------------------------------------------------------- 4. MOTOR LLMS.TXT DINÁMICO (Multilingüe, Polylang-aware) Detecta idioma via Polylang en lugar de WPML. ------------------------------------------------------------------------- */ add_action('init', function() { $url_path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); if ($url_path !== '/llms.txt') return; // Detectar idioma con Polylang (no WPML) $lang = function_exists('pll_current_language') ? pll_current_language() : 'en'; header('Content-Type: text/plain; charset=utf-8'); $context = [ 'es' => [ 'title' => 'Martin Cid Magazine (Edición en Español)', 'desc' => 'Revista digital líder en arte, cultura contemporánea, tecnología y reseñas de cine.', 'about' => 'MCM es un hub cultural global que ofrece análisis profundos sobre las tendencias que definen nuestra era.', 'sections' => ['Noticias' => '/news/', 'Cine y TV' => '/movies/', 'Arte' => '/art/', 'Tecnología' => '/technology-sv/'], ], 'en' => [ 'title' => 'Martin Cid Magazine (English Edition)', 'desc' => 'Premier digital publication for art, contemporary culture, technology, and film reviews.', 'about' => 'MCM is a global cultural hub providing deep dives into the trends defining our era.', 'sections' => ['News' => '/news/', 'Movies & TV' => '/movies/', 'Art' => '/art/', 'Tech' => '/technology-sv/'], ], 'fr' => [ 'title' => 'Martin Cid Magazine (Édition Française)', 'desc' => "Magazine numérique de référence pour l'art, la culture contemporaine et le cinéma.", 'about' => 'MCM est un centre culturel mondial proposant des analyses approfondies sur les tendances actuelles.', 'sections' => ['Nouvelles' => '/news/', 'Cinéma' => '/movies/', 'Art' => '/art/', 'Tech' => '/technology-sv/'], ], 'de' => [ 'title' => 'Martin Cid Magazine (Deutsche Ausgabe)', 'desc' => 'Führendes digitales Magazin für Kunst, Kultur, Technologie und Filmkritiken.', 'about' => 'MCM ist ein globaler Kultur-Hub mit tiefgehenden Analysen zu den Trends unserer Zeit.', 'sections' => ['Nachrichten' => '/news/', 'Kino & TV' => '/movies/', 'Kunst' => '/art/', 'Tech' => '/technology-sv/'], ], 'ja' => [ 'title' => 'Martin Cid Magazine(日本語版)', 'desc' => 'アート、文化、テクノロジー、映画レビューを扱うデジタルマガジン。', 'about' => 'MCMは時代のトレンドを深く分析するグローバルな文化ハブです。', 'sections' => ['ニュース' => '/news/', '映画・TV' => '/movies/', 'アート' => '/art/', 'テック' => '/technology-sv/'], ], 'ko' => [ 'title' => 'Martin Cid Magazine(한국어판)', 'desc' => '예술, 문화, 기술 및 영화 리뷰를 다루는 디지털 매거진.', 'about' => 'MCM은 시대의 트렌드를 심층 분석하는 글로벌 문화 허브입니다.', 'sections' => ['뉴스' => '/news/', '영화·TV' => '/movies/', '예술' => '/art/', '테크' => '/technology-sv/'], ], ]; $current = isset($context[$lang]) ? $context[$lang] : $context['en']; $site_url = home_url('/'); echo '# ' . $current['title'] . "\n\n"; echo '> ' . $current['desc'] . "\n\n"; echo "## About\n"; echo $current['about'] . "\n\n"; echo "## Core Sections\n"; foreach ($current['sections'] as $name => $path) { echo '- ' . $name . ': ' . home_url($path) . "\n"; } echo "\n## Editorial Standards & Trust (E-E-A-T)\n"; echo '- Ethics Policy: ' . $site_url . "ethics-policy/\n"; echo '- Editorial Principles: ' . $site_url . "editorial-principles/\n"; echo '- Masthead: ' . $site_url . "team-members/\n"; echo "\n## Technical Data for AI Agents\n"; echo '- Primary Sitemap: ' . $site_url . "wp-sitemap.xml\n"; echo '- RSS Feed: ' . get_feed_link() . "\n"; echo '- Publisher: Martin Cid' . "\n"; exit; }); Curiosités – Martin Cid Magazine FR
Curiosités