가장 긴 글 목록을 분할할 수 있는 제안과 함께 표시하는 기능

18.04.2025|

Tiempo de lectura Lectura: 7 min, 36 s
Número de palabras Palabras: 1409
Número de visitas Visitas: 70
Icono de traducción
가장 긴 글 목록을 분할할 수 있는 제안과 함께 표시하는 기능

며칠 전에 SEO에 영향을 주지 않고 워드프레스 글을 페이지로 분할하는 방법을 살펴보았다면, 오늘은 콘텐츠 유형, 길이 및 언어에 따라 긴 글을 쉽게 찾고 분류할 수 있는 기능을 추가합니다.

긴 항목이 몇 개만 있으면 거의 외우기 쉽습니다. 항목이 많고 다른 언어로 번역된 항목이 있는 경우에는 더 복잡해집니다. 이 코드는 글을 분할할 때(구텐베르크 "페이지 나누기" 또는 "페이지 나누기" 블록 사용) 선택 프로세스의 속도를 높이고 어떤 글을 분할해야 하는지, 현재 분할이 일관성이 있는지 빠르게 알려주는 데 목적이 있습니다.

이 코드는 정확히 어떤 기능을 하나요?

템플릿 또는 하위 테마의 functions.php에 다음 코드를 추가하면 단축 코드가 생성되며, 페이지 또는 글에서 이 단축 코드를 사용하면 다른 언어로 번역된 글을 포함하여 단어가 1500개 이상인 모든 글이 페이지별로 나열된 목록(페이지당 10개 항목)을 표시합니다. 이 쇼트코드는 폴리랑과 폴리랑 없이도 작동합니다.

이 값은 // 2. 설정에서 변경할 수 있습니다(쿼리로 인해 응답 속도가 느려지는 것을 원하지 않는다면 표시할 총 페이지 수를 너무 많이 늘리지 마세요). 초안 페이지나 비공개 페이지에 단축 코드를 사용하면 방문자가 몰려 성능에 영향을 미치고 리소스가 제한된 경우 서버의 CPU를 소모하는 위험을 피할 수 있습니다.)

이 코드를 사용하면 글에 몇 개의 나누기가 있는지(또는 전혀 없는지)뿐만 아니라 각 나누기에 포함된 단어 수를 표시하여 단어가 여러 섹션에 어떻게 분포되어 있는지 확인할 수 있으므로 현재 페이지 매김이 균형을 이루고 있는지 평가하는 데 매우 유용할 수 있습니다.

콘텐츠 유형 자동 감지

4가지 콘텐츠 유형에 대한 자동 감지 기능이 추가되며, 여기서 '나누기'는 x단어마다 나누기를 의미합니다. 계산은 정보 밀도를 기반으로 하며 최대 한도는 구성할 수 있습니다.

기술 (700단어/단락): 튜토리얼, 코드

내러티브 (1200단어/단락): 스토리, 내러티브

저널리즘 (900단어/단락): 뉴스, 기사

일반 (1000단어/휴식): 표준 콘텐츠

선택 기준

코드 기준에 대해서는 팁과 참고 자료를 검색해 보았습니다. 일부 매개 변수는 블로그에 맞게 조정했지만 이는 항상 탄력적이며 각 사이트에 맞게 미세 조정할 수 있으므로 언제든지 더 많은 신호를 추가하여 감지를 더 정확하게 만들 수 있습니다. 이를 출발점으로 삼아 글에서 유형에 따라 가장 자주 사용하는 요소를 조사하거나 코드가 식별할 수 있는 자체 브랜드와 가장 자주 사용하는 태그를 추가하세요.

현재 심사 기준은 다음과 같습니다:

A. 기술 콘텐츠 (⚙️ 700단어/단락)

  • 카테고리: 튜토리얼, 가이드, 기술, 코딩, 프로그래밍
  • 태그: 코드, 소프트웨어, 기술, 개발
  • 구조
    :폴리랑 플레이스홀더는 수정하지 않습니다.

B. 내러티브 콘텐츠 (📖 1200단어/단락)

  • 카테고리: 단편소설, 역사, 서사, 문학
  • 태그: 단편, 소설, 소설, 시, 시조
  • 구조
    :폴리랑 플레이스홀더는 수정하지 않습니다.

C. 저널리즘 콘텐츠 (📰 900단어/단락)

  • 카테고리: 뉴스, 시사, 리포트, 기사
  • Tags: 언론, 인터뷰, 의견
  • 구조
    :폴리랑 플레이스홀더는 수정하지 않습니다.

D. 일반 콘텐츠 (✍️ 1000단어/단락)

  • 위의 기준과 일치하지 않을 때 적용됩니다.
  • 표준 글의 기본값

코드는 다음 순서로 항목을 평가합니다:

  1. 게시물 카테고리
  2. 게시물 태그
  3. 콘텐츠의 구조
  4. 일치하는 항목이 없는 경우 '일반'을 지정합니다.

권장되는 최대 휴식 시간은 글당 5개입니다.

측면

CSS는 편의를 위해 코드에 포함되어 있으며 이 모양을 탭에 반환합니다. 표시되는 정보는 매우 명확합니다.

빠른 액세스가 더 편리하다고 생각되면 제목을 편집 페이지로 연결하도록 수정하거나 다른 개선 사항을 적용할 수 있습니다.

코드

// ======================================================================
//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' => __('&laquo;'),
                'next_text' => __('&raquo;'),
                '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');
관련 문서
브라우저가 곧 워드프레스입니다.

브라우저가 곧 워드프레스입니다.

속도 감사: 워드프레스의 발목을 잡는 요소 찾기

속도 감사: 워드프레스의 발목을 잡는 요소 찾기

생성블록 프로의 새로운 블록

생성블록 프로의 새로운 블록 "캐러셀"

Este blog se aloja en LucusHost

LucusHost, el mejor hosting

이메일 구독

기사가 게시되는 즉시 광고 없이 받은 편지함에서 전체 기사를 무료로 받아보세요. 피드의 전체 콘텐츠는 외부 서비스를 통해 광고 없이 전송됩니다.