
Wenn wir vor ein paar Tagen gesehen haben, wie man lange WordPress-Beiträge in Seiten aufteilt, ohne die SEO zu beeinträchtigen, werden wir heute eine zusätzliche Funktion hinzufügen, die es Ihnen ermöglicht, diese langen Beiträge leicht zu finden und nach Inhaltstyp, Länge und Sprache zu kategorisieren.
Wenn Sie nur wenige lange Einträge haben, ist es leicht, sie fast auswendig zu kennen. Komplizierter wird es, wenn es viele davon gibt und sie auch ihre jeweiligen Übersetzungen in anderen Sprachen haben. Dieser Code soll den Auswahlprozess beim Aufteilen von Beiträgen (mit dem Gutenberg-Block "Seitenumbruch" oder "Seitenumbruch") beschleunigen und Sie schnell wissen lassen, welche Beiträge Sie noch aufteilen müssen und ob Ihre aktuellen Aufteilungen kohärent sind.
Was genau macht der Code?
Der folgende Code, der in die functions.php Ihres Templates oder Child-Themes eingefügt wird, generiert einen Shortcode. Wenn Sie diesen Shortcode auf einer beliebigen Seite oder einem beliebigen Beitrag verwenden, wird eine paginierte Liste (10 Einträge pro Seite) mit allen Beiträgen angezeigt, die mehr als 1500 Wörter enthalten, einschließlich der in andere Sprachen übersetzten. Es funktioniert sowohl mit Polylang als auch ohne Polylang.
Diese Werte können in // 2. Konfiguration geändert werden (erhöhen Sie nur nicht die Gesamtzahl der anzuzeigenden Seiten zu sehr, wenn Sie nicht wollen, dass die Abfrage die Antwort verlangsamt). Die Idee ist, dass Sie den Shortcode auf Entwurfs- oder privaten Seiten verwenden, damit Sie nicht riskieren, dass ein Besucheransturm die Leistung beeinträchtigt und die CPU Ihres Servers auslastet, wenn Sie nur über begrenzte Ressourcen verfügen).
Mit diesem Code können Sie nicht nur sehen, wie viele Umbrüche ein Beitrag hat (oder ob er überhaupt keine hat), sondern auch, wie die Wörter zwischen den verschiedenen Abschnitten verteilt sind, indem Sie sehen, wie viele Wörter jeder Umbruch enthält, was sehr nützlich sein kann, um zu beurteilen, ob Ihre aktuelle Paginierung ausgewogen ist.
Automatische Erkennung von Inhaltstypen
Es wurde eine automatische Erkennung für 4 Inhaltstypen hinzugefügt, wobei "Pause" eine Pause alle x Wörter bedeutet. Die Berechnung basiert auf der Informationsdichte, und die Höchstgrenze ist konfigurierbar.
Technisch (700 Wörter/Pause): Anleitungen, Code
Erzählung (1200 Wörter/Bruch): Geschichten, Erzählungen
Journalistisch (900 Wörter/Bruch): Nachrichten, Artikel
Allgemeines (1000 Wörter/Pause): Standard-Inhalt
Auswahlkriterien
Für die Code-Kriterien habe ich nach Tipps und Hinweisen gesucht. Einige Parameter habe ich an meinen Blog angepasst, aber das ist immer dehnbar und kann für jede Website feinabgestimmt werden, Sie können immer weitere Signale hinzufügen, um die Erkennung genauer zu machen. Nehmen Sie es als Ausgangspunkt und untersuchen Sie, welche Elemente Sie am häufigsten in Ihren Artikeln verwenden, je nach deren Typ, oder fügen Sie Ihre eigenen Marken hinzu, die der Code identifizieren kann, sowie einige der von Ihnen am häufigsten verwendeten Tags.
Die derzeitigen Kriterien für das Screening lauten wie folgt:
A. Technischer Inhalt (⚙️ 700 Wörter/Bruch)
- Kategorien: Tutorial, Anleitung, technisch, Kodierung, Programmierung
- Tags: Code, Software, Technologie, Entwicklung
- Struktur
:Polylang Platzhalter nicht ändern
B. Erzählerischer Inhalt (📖 1200 Wörter/Pause)
- Kategorien: Kurzgeschichte, Geschichte, Erzählung, Literatur
- Tags: Kurzgeschichte, Roman, Belletristik, Poesie
- Struktur
:Polylang Platzhalter nicht ändern
C. Journalistischer Inhalt (📰 900 Wörter/Bruch)
- Kategorien: Nachrichten, Zeitgeschehen, Bericht, Artikel
- Tags: Meinung, Interview, Presse
- Struktur
:Polylang Platzhalter nicht ändern
D. Allgemeiner Inhalt (✍️ 1000 Wörter/Bruch)
- Gilt, wenn sie nicht mit den oben genannten Kriterien übereinstimmt.
- Standardwert für Standardstellen
Der Code wertet die Elemente in der folgenden Reihenfolge aus:
- Beitragskategorien
- Tags eintragen
- Struktur des Inhalts
- Zuweisen von "Allgemein", wenn es keine Übereinstimmung gibt
Es werden maximal 5 Pausen pro Beitrag vorgeschlagen.
Aspekt
Das CSS ist der Einfachheit halber in den Code integriert und gibt den Registerkarten dieses Aussehen. Die Informationen, die angezeigt werden, sind ziemlich eindeutig.
Sie können es so ändern, dass der Titel mit der Bearbeitungsseite verknüpft wird, wenn Sie es für den schnellen Zugriff bequemer finden, oder andere Verbesserungen vornehmen, die Sie sich vorstellen können.
Code
// ======================================================================
//Displays a paginated list of long posts (ordered from most to least number of words) with suggestions for splitting them into pages according to content type
// Shortcode for Page Breaks analysis on long posts. Courtesy of /jrmora.com
// ======================================================================
function analizador_pagebreaks_completo() {
// 1. Protección contra ejecución en admin/AJAX
if (is_admin() || wp_doing_ajax() || (defined('REST_REQUEST') && REST_REQUEST)) {
return '';
}
// 2. Configuración
$config = [
'umbral_palabras' => 1500,
'posts_por_pagina' => 10,
'mostrar_todos_idiomas' => true
];
// 3. Detección de tipo de contenido
function detectar_tipo_contenido($post_id) {
$post = get_post($post_id);
$content = strip_tags($post->post_content);
// Por categorías
$categorias = wp_get_post_categories($post_id, ['fields' => 'slugs']);
if (array_intersect($categorias, ['tutorial', 'guia', 'tecnico', 'code', 'programacion'])) {
return ['tipo' => 'técnico', 'color' => '#e3f2fd', 'icono' => '⚙️'];
} elseif (array_intersect($categorias, ['relato', 'historia', 'narrativa', 'literatura'])) {
return ['tipo' => 'narrativo', 'color' => '#f3e5f5', 'icono' => '📖'];
} elseif (array_intersect($categorias, ['noticia', 'actualidad', 'reportaje', 'articulo'])) {
return ['tipo' => 'periodístico', 'color' => '#e8f5e9', 'icono' => '📰'];
}
// Por etiquetas
$etiquetas = wp_get_post_tags($post_id, ['fields' => 'slugs']);
if (array_intersect($etiquetas, ['codigo', 'software', 'tecnologia', 'dev'])) {
return ['tipo' => 'técnico', 'color' => '#e3f2fd', 'icono' => '⚙️'];
} elseif (array_intersect($etiquetas, ['cuento', 'novela', 'ficcion', 'poesia'])) {
return ['tipo' => 'narrativo', 'color' => '#f3e5f5', 'icono' => '📖'];
}
// Por estructura
if (preg_match_all('/```|<pre>|<code>/i', $content) > 2) {
return ['tipo' => 'técnico', 'color' => '#e3f2fd', 'icono' => '⚙️'];
} elseif (preg_match_all('/\n—|\n"|\n\d+\. /i', $content) > 3) {
return ['tipo' => 'narrativo', 'color' => '#f3e5f5', 'icono' => '📖'];
} elseif (preg_match_all('/\n### |\n#### |\*Nota:/i', $content) > 3) {
return ['tipo' => 'periodístico', 'color' => '#e8f5e9', 'icono' => '📰'];
}
return ['tipo' => 'general', 'color' => '#f5f5f5', 'icono' => '✍️'];
}
// 4. Cálculo de breaks por tipo
function calcular_breaks_por_tipo($palabras, $tipo) {
$config = [
'técnico' => 700,
'narrativo' => 1200,
'periodístico' => 900,
'general' => 1000
];
$breaks = max(1, floor($palabras / ($config[$tipo] ?? 1000)) - 1);
return min($breaks, 5); // Máximo 5 breaks
}
// 5. Función para calcular distribución de palabras entre breaks
function calcular_distribucion_palabras($content) {
$total_palabras = str_word_count(strip_tags($content));
$breaks = substr_count($content, '<!--nextpage-->');
if ($breaks === 0) {
return [];
}
// Dividir el contenido por los breaks
$secciones = explode('<!--nextpage-->', $content);
$distribucion = [];
foreach ($secciones as $seccion) {
$palabras_seccion = str_word_count(strip_tags($seccion));
$distribucion[] = $palabras_seccion;
}
return $distribucion;
}
// 6. Función para obtener todos los IDs de posts a procesar
function obtener_ids_posts_a_procesar($mostrar_todos_idiomas) {
$args = [
'post_type' => 'post',
'posts_per_page' => -1,
'fields' => 'ids',
'post_status' => 'publish'
];
// Si Polylang está activo y queremos mostrar todos los idiomas
if ($mostrar_todos_idiomas && function_exists('pll_get_post_translations')) {
$query = new WP_Query($args);
$all_post_ids = [];
foreach ($query->posts as $post_id) {
$translations = pll_get_post_translations($post_id);
$all_post_ids = array_merge($all_post_ids, array_values($translations));
}
return array_unique($all_post_ids);
}
// Caso normal (sin Polylang o no mostrar todos los idiomas)
$query = new WP_Query($args);
return $query->posts;
}
// 7. Obtener y procesar posts
$posts_procesados = [];
$post_ids = obtener_ids_posts_a_procesar($config['mostrar_todos_idiomas']);
foreach ($post_ids as $post_id) {
procesar_post_con_tipo($post_id, $config['umbral_palabras'], $posts_procesados);
}
// 8. Ordenar por palabras (mayor a menor)
usort($posts_procesados, function($a, $b) {
return $b['palabras'] - $a['palabras'];
});
// 9. Paginación manual
$paged = max(1, get_query_var('paged'));
$total_posts = count($posts_procesados);
$total_paginas = ceil($total_posts / $config['posts_por_pagina']);
$offset = ($paged - 1) * $config['posts_por_pagina'];
$posts_paginados = array_slice($posts_procesados, $offset, $config['posts_por_pagina']);
// 10. CSS con mejoras visuales
$output = '<style>
.pb-ultimate-container {
max-width: 800px;
margin: 0 auto;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.pb-ultimate-item {
background: #fff;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
border: 1px solid #e0e0e0;
}
.pb-ultimate-title {
font-size: 1.25rem;
margin: 0 0 10px 0;
line-height: 1.4;
}
.pb-ultimate-meta {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 12px;
font-size: 0.85rem;
}
.pb-ultimate-meta-item {
display: inline-flex;
align-items: center;
gap: 4px;
}
.pb-ultimate-type {
padding: 2px 10px;
border-radius: 10px;
font-size: 0.75rem;
font-weight: 500;
}
.pb-ultimate-suggestion {
background: #f5f5f5;
border-left: 3px solid #64b5f6;
padding: 10px 15px;
margin-top: 15px;
border-radius: 0 4px 4px 0;
font-size: 0.9rem;
}
.pb-ultimate-pagination {
display: flex;
justify-content: center;
margin: 30px 0;
flex-wrap: wrap;
gap: 8px;
}
.pb-ultimate-page {
padding: 8px 16px;
border-radius: 4px;
text-decoration: none;
}
.pb-ultimate-page-number {
border: 1px solid #e0e0e0;
color: #1976d2;
}
.pb-ultimate-page-number:hover {
background: #e3f2fd;
}
.pb-ultimate-page-current {
background: #1976d2;
color: white;
border: 1px solid #1976d2;
}
.pb-ultimate-wordcount {
font-weight: 600;
color: #212121;
}
.pb-ultimate-language {
background: #e3f2fd;
color: #1565c0;
padding: 2px 10px;
border-radius: 10px;
font-size: 0.75rem;
}
.pb-ultimate-warning {
color: #d32f2f;
font-weight: 500;
}
.pb-ultimate-distribution {
margin-left: 5px;
font-size: 0.95em; /* Aumentado de 0.8em a 0.95em */
font-weight: 600; /* Negrita añadida */
color: #444; /* Color más oscuro para mejor contraste */
background: #f8f8f8; /* Fondo sutil */
padding: 2px 6px;
border-radius: 4px;
border-left: 2px solid #64b5f6; /* Borde izquierdo azul */
}
.pb-ultimate-distribution-separator {
color: #999;
font-weight: normal;
margin: 0 3px;
}
</style>';
$output .= '<div class="pb-ultimate-container">';
if (!empty($posts_procesados)) {
foreach ($posts_paginados as $post) {
$breaks_sugeridos = calcular_breaks_por_tipo($post['palabras'], $post['tipo']['tipo']);
$palabras_por_seccion = ceil($post['palabras'] / ($breaks_sugeridos + 1));
$output .= '<div class="pb-ultimate-item">';
$output .= '<h3 class="pb-ultimate-title"><a href="' . esc_url($post['enlace']) . '">' . esc_html($post['titulo']) . '</a></h3>';
$output .= '<div class="pb-ultimate-meta">';
$output .= '<span class="pb-ultimate-meta-item pb-ultimate-wordcount">📝 ' . number_format($post['palabras']) . ' palabras</span>';
$output .= '<span class="pb-ultimate-meta-item pb-ultimate-type" style="background: ' . $post['tipo']['color'] . '">';
$output .= $post['tipo']['icono'] . ' ' . ucfirst($post['tipo']['tipo']);
$output .= '</span>';
$output .= '<span class="pb-ultimate-meta-item pb-ultimate-language">' . strtoupper($post['idioma']) . '</span>';
if ($post['tiene_break']) {
$distribucion = calcular_distribucion_palabras($post['contenido']);
$distribucion_text = '';
if (!empty($distribucion)) {
$distribucion_text = '<span class="pb-ultimate-distribution">(';
$distribucion_parts = [];
foreach ($distribucion as $index => $palabras) {
$distribucion_parts[] = ($index + 1) . 'º: ' . number_format($palabras);
}
$distribucion_text .= implode('<span class="pb-ultimate-distribution-separator"> · </span>', $distribucion_parts) . ')</span>';
}
$output .= '<span class="pb-ultimate-meta-item">✅ ' . $post['breaks_actuales'] . ' breaks ';
$output .= $distribucion_text;
$output .= '</span>';
} else {
$output .= '<span class="pb-ultimate-meta-item pb-ultimate-warning">⚠️ SIN PAGINAR</span>';
}
$output .= '</div>';
$output .= '<div class="pb-ultimate-suggestion">';
$output .= '<strong>Sugerencia:</strong> ' . $breaks_sugeridos . ' breaks (1 cada ~' . number_format($palabras_por_seccion) . ' palabras)';
$output .= '</div>';
$output .= '</div>';
}
// Paginación
if ($total_paginas > 1) {
$output .= '<div class="pb-ultimate-pagination">';
$output .= paginate_links([
'base' => str_replace(999999999, '%#%', esc_url(get_pagenum_link(999999999))),
'format' => '?paged=%#%',
'current' => $paged,
'total' => $total_paginas,
'prev_text' => __('«'),
'next_text' => __('»'),
'mid_size' => 1
]);
$output .= '</div>';
}
} else {
$output .= '<div class="pb-ultimate-item">No se encontraron posts que requieran paginación.</div>';
}
return $output . '</div>';
}
// Función auxiliar: Procesar post con tipo
function procesar_post_con_tipo($post_id, $umbral, &$posts) {
$post = get_post($post_id);
if (!$post) return;
$content = $post->post_content;
$word_count = str_word_count(strip_tags($content));
if ($word_count >= $umbral) {
$tipo = detectar_tipo_contenido($post_id);
$idioma = 'es'; // Valor por defecto
// Detectar idioma si Polylang está activo
if (function_exists('pll_get_post_language')) {
$idioma = pll_get_post_language($post_id) ?: 'es';
}
$posts[] = [
'ID' => $post_id,
'titulo' => $post->post_title,
'palabras' => $word_count,
'contenido' => $content,
'enlace' => get_permalink($post_id),
'tiene_break' => (strpos($content, '<!--nextpage-->') !== false),
'breaks_actuales' => substr_count($content, '<!--nextpage-->'),
'idioma' => $idioma,
'tipo' => $tipo
];
}
}
add_shortcode('analizador_pagebreaks_ultimate', 'analizador_pagebreaks_completo');