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

No comments

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

며칠 전에 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');

Suscríbete para recibir los post en tu email sin publicidad

관련 문서

SEO에 영향을 주지 않고 긴 워드프레스 글을 페이지로 분할하는 방법

SEO에 영향을 주지 않고 긴 워드프레스 글을 페이지로 분할하는 방법

워드프레스에서 플러그인 없이 모달 창을 여는 버튼

워드프레스에서 플러그인 없이 모달 창을 여는 버튼

워드프레스 6.8의 투기적 로딩

워드프레스 6.8의 투기적 로딩

Leave a Comment

Este blog se aloja en LucusHost

LucusHost, el mejor hosting