* 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;
});
영화 – 페이지 5 – 마틴 시드 매거진
넷플릭스가 직업적 포부와 예상치 못한 인간관계 사이의 갈등을 그린 로맨틱 드라마 “망고”를 카탈로그에 추가한다. 코미디 요소도 가미된 이 영화는 제목을 단순한 이국적인 배경(과일 농장)을 넘어 갈등의 핵심 은유로 사용한다. 이 서사는 의무와 마음 사이의 딜레마를 제시하며, 주인공들에게 야망을…
새로운 초자연 스릴러 ‘바라물라’가 넷플릭스 공개를 앞두고 있다. 이 영화는 안개와 눈으로 뒤덮인 카슈미르의 ‘오싹할 만큼 아름다운’ 계곡을…
기예르모 델 토로 감독에게 <프랑켄슈타인>은 단순히 필모그래피에 추가되는 또 하나의 작품이 아니다. 이는 그의 존재와 예술을 정의해 온…
비에 젖은 마카오의 거리 위로 반사되는 네온사인의 눈부신 불빛 아래, 한 남자가 바카라 테이블에서 자신의 마지막 남은 모든…
고강도 스릴러를 맞이할 준비가 되었는가? 이 영화는 첫 순간부터 숨 막히는 경험을 약속한다. 영화는 태평양 불명의 위치에서 발사된…
우리는 좀비 영화에 질렸는가? 이에 대한 대답은 각자 다르겠지만, 아직 질리지 않은 사람들을 위해 넷플릭스가 인도네시아에서 제작된 새로운…
아르헨티나 영화가 독창적인 줄거리, 코미디와 드라마의 조화, 그리고 무엇보다 잘 짜인 캐릭터가 돋보이는 현실적인 이야기라는 최고의 무기를 들고…
넷플릭스가 스페인 현대사의 가장 어두운 장 중 하나인 테러 조직 ETA의 이야기를 과감하게 다룹니다. 저명한 후안 안토니오 바요나…
이제 누구에게도 놀라운 일이 아니다. 한국 엔터테인먼트 산업은 스트리밍 거인 넷플릭스와의 파트너십 덕분에 세계적인 강자로 우뚝 섰다. 한국…
넷플릭스가 드라마, 판타지, 로맨스 장르를 아우르는 필리핀 영화 “남아있는 시간”의 글로벌 공개를 준비하고 있습니다. 단순한 사랑 이야기를 넘어,…
폴란드 축구 훌리건들의 이야기를 다룬 화제작이 다시 한번 넷플릭스를 찾아옵니다. 전작과 동일한 강렬함과 도발적인 정신을 그대로 간직한 채…
넷플릭스가 우리를 태국으로 이끌어, 평범한 직장인이 상황에 내몰려 범죄의 길로 빠져드는 과정을 심도 있게 조명한다. 중산층의 열망이 고층…
넷플릭스에 공개되는 ‘스윔 투 미’는 권력, 의존, 애정의 복잡한 역학을 다루는 칠레 드라마다. 인물, 연출, 그리고 무엇보다 연기가…