Permitir HTML en el extracto
GUÍA COMPLETA SOBRE EXTRACTOS
Recientemente he respondido algunas preguntas sobre extractos, así que voy a dar una explicación detallada cubriendo todo lo que pueda.
PREFACIO
Parece que hay un par de preguntas surgiendo de esta respuesta sobre dónde debería ir el código, y la respuesta es, realmente depende de ti y cómo lo veas conveniente. Hay un par de opciones donde puedes colocar el código (si no se indica explícitamente):
En el functions.php de tu tema o cualquier archivo usado como archivo de funciones. Solo recuerda que cuando hagas esto, si el tema no es tuyo, todos los cambios se perderán cuando actualices tu tema.
Una mejor manera sería usar el código en un tema hijo. Como arriba, en el functions.php o un archivo relacionado con funciones.
Usar el código en un plugin. Esta es la forma preferida ya que hace que el código esté disponible en todos los temas. Si cambias de tema, no tienes que preocuparte por reescribir el mismo código.
Espero que esto aclare un poco las cosas :-)
ETIQUETAS HTML/FORMATEO
the_excerpt()
antes que nada no acepta ningún parámetro, así que no se le puede pasar nada. Es un hecho que the_excerpt()
recorta el contenido a 55 palabras, y todas las etiquetas HTML son eliminadas antes de devolver el texto. the_excerpt()
se encuentra en wp-includes/post-template.php. Para permitir ciertas o todas las etiquetas HTML en el extracto, se debe crear un nuevo extracto.
Primero, la función original debe ser eliminada, y luego la nueva función debe ser enganchada a get_the_excerpt
. Por favor ten en cuenta, este nuevo extracto seguirá siendo invocable como the_excerpt()
en los archivos de plantilla, no hay necesidad de cambiar eso. get_the_excerpt()
se encuentra en wp-includes/post-template.php.
El extracto usa wp_trim_excerpt
para devolver el texto recortado, así que necesitamos eliminar wp_trim_excerpt
primero del filtro del extracto. wp_trim_excerpt()
se encuentra en wp-includes/formatting.php, línea 2355. Así es cómo:
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
Ahora puedes añadir tu nuevo extracto a get_the_excerpt
add_filter('get_the_excerpt', 'wpse_custom_wp_trim_excerpt');
Para permitir etiquetas HTML/formateo, necesitaremos especificar qué etiquetas necesitas permitir. Puedes usar la siguiente declaración strip_tags
para lograrlo
$wpse_excerpt = strip_tags($wpse_excerpt, wpse_allowedtags());
El segundo argumento wpse_allowedtags()
es una pequeña función que se usa para añadir las etiquetas que the_excerpt()
permitirá. Para una lista completa de etiquetas HTML 5 válidas, ve y échale un vistazo aquí. Aquí está la función, añade cualquier etiqueta HTML que necesites permitir/mantener
function wpse_allowedtags() {
// Añade etiquetas personalizadas a esta cadena
return '<script>,<style>,<br>,<em>,<i>,<ul>,<ol>,<li>,<a>,<p>,<img>,<video>,<audio>';
}
Si necesitas permitir todas las etiquetas HTML, es decir, no eliminar ninguna etiqueta, la función strips_tags()
puede ser omitida/eliminada completamente.
Un punto a tener en cuenta, sin embargo, cuando se permiten etiquetas HTML, estas etiquetas se cuentan como palabras, así que tu conteo de palabras para extractos con etiquetas y sin etiquetas no será el mismo. Para corregir eso, necesitarás eliminar estas etiquetas del conteo real de palabras primero para que solo se cuenten las palabras.
He escrito un extracto que permitirá todas las etiquetas, contará solo palabras como palabras, y completará una oración después de la cantidad establecida de palabras (para que el texto no se recorte a mitad de oración) y añadirá un texto de leer más después de la última palabra.
Aquí está el código completo
function wpse_allowedtags()
{
// Añade etiquetas personalizadas a esta cadena
return '<script>,<style>,<br>,<em>,<i>,<ul>,<ol>,<li>,<a>,<p>,<img>,<video>,<audio>';
}
if (!function_exists('wpse_custom_wp_trim_excerpt')) :
function wpse_custom_wp_trim_excerpt($wpse_excerpt)
{
$raw_excerpt = $wpse_excerpt;
if ('' == $wpse_excerpt) {
$wpse_excerpt = get_the_content('');
$wpse_excerpt = strip_shortcodes($wpse_excerpt);
$wpse_excerpt = apply_filters('the_content', $wpse_excerpt);
$wpse_excerpt = str_replace(']]>', ']]>', $wpse_excerpt);
$wpse_excerpt = strip_tags($wpse_excerpt, wpse_allowedtags()); /*SI necesitas permitir solo ciertas etiquetas. Elimina si todas las etiquetas están permitidas */
//Establece el conteo de palabras del extracto y solo corta después de que la oración esté completa.
$excerpt_word_count = 75;
$excerpt_length = apply_filters('excerpt_length', $excerpt_word_count);
$tokens = array();
$excerptOutput = '';
$count = 0;
// Divide la cadena en tokens; etiquetas HTML, o palabras, seguidas por cualquier espacio en blanco
preg_match_all('/(<[^>]+>|[^<>\s]+)\s*/u', $wpse_excerpt, $tokens);
foreach ($tokens[0] as $token) {
if ($count >= $excerpt_length && preg_match('/[\,\;\?\.\!]\s*$/uS', $token)) {
// Límite alcanzado, continúa hasta que , ; ? . o ! ocurran al final
$excerptOutput .= trim($token);
break;
}
// Añade palabras para completar la oración
$count++;
// Añade lo que queda del token
$excerptOutput .= $token;
}
$wpse_excerpt = trim(force_balance_tags($excerptOutput));
$excerpt_end = ' <a href="' . esc_url(get_permalink()) . '">' . ' » ' . sprintf(__('Leer más sobre: %s »', 'wpse'), get_the_title()) . '</a>';
$excerpt_more = apply_filters('excerpt_more', ' ' . $excerpt_end);
//$pos = strrpos($wpse_excerpt, '</');
//if ($pos !== false)
// Dentro de la última etiqueta HTML
//$wpse_excerpt = substr_replace($wpse_excerpt, $excerpt_end, $pos, 0); /* Añade leer más junto a la última palabra */
//else
// Después del contenido
$wpse_excerpt .= $excerpt_more; /*Añade leer más en un nuevo párrafo */
return $wpse_excerpt;
}
return apply_filters('wpse_custom_wp_trim_excerpt', $wpse_excerpt, $raw_excerpt);
}
endif;
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'wpse_custom_wp_trim_excerpt');
Puedes simplemente eliminar las '//' de las funciones que necesites adicionalmente.
LONGITUDES PERSONALIZADAS DE EXTRACTOS
A veces necesitas mostrar extractos simples de diferentes longitudes y no es viable escribir un extracto para cada post/función/página. Aquí hay una pequeña y bonita función usando wp_trim_words
function wpse_custom_excerpts($limit) {
return wp_trim_words(get_the_excerpt(), $limit, '<a href="'. esc_url( get_permalink() ) . '">' . ' …' . __( 'Leer más »', 'wpse' ) . '</a>');
}
Lo que hace esta pequeña función es tomar get_the_excerpt
, recortarlo al $limit
establecido por el usuario, y devolver el texto con un enlace de leer más al final.
Puedes invocar este extracto así en tu plantilla
echo wpse_custom_excerpts($limit);
donde $limit
será tu conteo de palabras, así que un extracto de 30 palabras sería
echo wpse_custom_excerpts(30);
Solo una cosa para recordar aquí, si estableces tu límite a más de 55 palabras, solo se devolverán 55 palabras ya que el extracto solo tiene 55 palabras de longitud. Si se necesitan extractos más largos, usa get_the_content
en su lugar.
LONGITUD PERSONALIZADA DE EXTRACTO
Si solo necesitas alterar la longitud de the_excerpt()
, puedes usar la siguiente función
function wpse_excerpt_length( $length ) {
return 20;
}
add_filter( 'excerpt_length', 'wpse_excerpt_length', 999 );
Recuerda, necesitarás establecer una prioridad mayor que 10 para que tu función personalizada se ejecute después de la predeterminada.
AÑADIR ENLACE LEER MÁS
Todos los textos devueltos por el extracto tienen el odiado [...]
al final que no es clickeable. Para añadir un texto de leer más en lugar de los puntos suspensivos, usa esta función
function wpse_excerpt_more( $more ) {
return ' <a class="read-more" href="'. get_permalink( get_the_ID() ) . '">' . __('Leer Más', 'your-text-domain') . '</a>';
}
add_filter( 'excerpt_more', 'wpse_excerpt_more' );
EDITAR
Extracto del primer párrafo
Quiero mantener esto completo, así que aquí está el extracto que recorta después del primer párrafo.
Aquí hay una función que mantiene las etiquetas HTML intactas, añade un enlace "Leer más" al final del extracto y recorta el extracto después del primer párrafo.
if ( ! function_exists( 'wpse0001_custom_wp_trim_excerpt' ) ) :
function wpse0001_custom_wp_trim_excerpt($wpse0001_excerpt) {
global $post;
$raw_excerpt = $wpse0001_excerpt;
if ( '' == $wpse0001_excerpt ) {
$wpse0001_excerpt = get_the_content('');
$wpse0001_excerpt = strip_shortcodes( $wpse0001_excerpt );
$wpse0001_excerpt = apply_filters('the_content', $wpse0001_excerpt);
$wpse0001_excerpt = substr( $wpse0001_excerpt, 0, strpos( $wpse0001_excerpt, '</p>' ) + 4 );
$wpse0001_excerpt = str_replace(']]>', ']]>', $wpse0001_excerpt);
$excerpt_end = ' <a href="'. esc_url( get_permalink() ) . '">' . ' » ' . sprintf(__( 'Leer más sobre: %s »', 'pietergoosen' ), get_the_title()) . '</a>';
$excerpt_more = apply_filters('excerpt_more', ' ' . $excerpt_end);
//$pos = strrpos($wpse0001_excerpt, '</');
//if ($pos !== false)
// Dentro de la última etiqueta HTML
//$wpse0001_excerpt = substr_replace($wpse0001_excerpt, $excerpt_end, $pos, 0);
//else
// Después del contenido
$wpse0001_excerpt .= $excerpt_more;
return $wpse0001_excerpt;
}
return apply_filters('wpse0001_custom_wp_trim_excerpt', $wpse0001_excerpt, $raw_excerpt);
}
endif;
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'wpse0001_custom_wp_trim_excerpt');
EDITAR 29-10-2015
Para cualquiera que necesite una solución para no mostrar el enlace de leer más después del extracto cuando el extracto es más corto que la cantidad de palabras establecida, por favor ve la siguiente pregunta y respuesta

¿dónde exactamente coloco esta parte? function wpse_allowedtags() {
// Agrega etiquetas personalizadas a esta cadena
return '<script>,<style>,<br>,<em>,<i>,<ul>,<ol>,<li>,<a>,<p>,<img>,<video>,<audio>';
}
estoy confundido

Todo este código va en functions.php
. Puedes agregarlo justo encima de if ( ! function_exists( 'wpse_custom_wp_trim_excerpt' ) ) :
en tu archivo functions.php

Lo sé, pero hay ciertas etiquetas que quiero permitir y no sé cómo lograrlo. Coloqué el código en mi functions.php, pero ¿qué debo cambiar para permitir ciertas etiquetas @pieter goosen

¿Debería borrar esta línea y reemplazarla? $wpse_excerpt = strip_tags($wpse_excerpt, wpse_allowedtags());

No, mantén $wpse_excerpt = strip_tags($wpse_excerpt, wpse_allowedtags());
. Debes agregar tus etiquetas a estos return '<script>,<style>,<br>,<em>,<i>,<ul>,<ol>,<li>,<a>,<p>,<img>,<video>,<audio>';
También puedes eliminar todas estas etiquetas y solo agregar las tuyas

si esto va al archivo functions.php, ¿no se sobrescribirá cuando llegue una actualización?

@mcgrailm sí, así sería. Por eso es importante agregar esto al functions.php de tu tema hijo. Incluso puedes agregarlo como un plugin must-use

@PieterGoosen ¡Guau, esta es una gran explicación! Solo hay un detalle: la función va a agregar palabras hasta el siguiente . o ! (por ejemplo), pero ¿qué pasa si no hay más palabras después del último . o !? El enlace "Leer más" igual se mostrará... Sé que la función de extracto no se supone que muestre el contenido completo, pero eso puede ser difícil de controlar si un editor escribe un artículo pequeño. ¿Qué opinas de esta situación?

@Pipo Tienes razón. Revisaré este problema después del fin de semana, voy a estar un poco ocupado. Te mantendré informado. Gracias por tu respuesta

@PieterGoosen No hay problema, no hay prisa, solo estoy intentando aprender de tu código. Que tengas un buen domingo

¿Esto asegura que no queden etiquetas abiertas? Lo pregunto por esta pregunta.

Hay un problema con las etiquetas ul y li que conozco, pero en general, esto debería eliminarse de un extracto. @ialocin

¡Genial! Entonces, si tengo, digamos, 100 palabras y hay una etiqueta de apertura sin una de cierre, será eliminada.

@ialocin no, no lo hará. Puedes implementar algo como esto para eliminar etiquetas que quedan abiertas. Lo que quise decir es que, en realidad, se deberían eliminar etiquetas como ul y li del extracto. En una de las funciones anteriores puedes hacerlo.

Lástima, entonces te malentendí, obviamente. Esto era más sobre, por ejemplo, la etiqueta <b>
.

Creo que esto necesita pruebas :-). Cuando construí esto, estaba más pensado para etiquetas "a", que en esa etapa era mi principal problema. Solo más tarde noté que las etiquetas "ul" y "li" se eliminaban a medias, por lo que te quedabas con la etiqueta de apertura pero no con la de cierre. Para ser honesto, este código tiene sus fallos :-)

@PieterGoosen Solo mencionar que enganchar la función excerpt_more no funcionará a menos que le des una prioridad más baja, ya que template-tags.php se carga después del functions.php del tema actual.

@PieterGoosen gracias por el post tan informativo - pregunta rápida: ¿sería posible modificar el extracto de esta manera solo para un tipo de entrada específico?

¿Puedes simplemente escribir una solución rápida que pueda copiar y pegar en mi código? Es verano y no quiero leer un libro.

Añade más etiquetas si lo necesitas en $allowed_tags = ...
function _20170529_excerpt($text) {
$raw_excerpt = $text;
if ( '' == $text ) {
// Obtener el contenido del post
$text = get_the_content('');
// Eliminar todos los shortcodes del contenido
$text = strip_shortcodes( $text );
$text = apply_filters('the_content', $text);
$text = str_replace(']]>', ']]>', $text);
$allowed_tags = '<a>,<b>,<br><i>';
$text = strip_tags($text, $allowed_tags);
$excerpt_word_count = 55; /*** MODIFICA ESTO. Cambia el número de palabras del extracto al entero que prefieras.***/
$excerpt_length = apply_filters('excerpt_length', $excerpt_word_count);
$excerpt_end = '[...]'; /*** MODIFICA ESTO. Cambia el final del extracto por otra cosa.***/
$excerpt_more = apply_filters('excerpt_more', ' ' . $excerpt_end);
$words = preg_split("/[\n\r\t ]+/", $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY);
if ( count($words) > $excerpt_length ) {
array_pop($words);
$text = implode(' ', $words);
$text = $text . $excerpt_more;
} else {
$text = implode(' ', $words);
}
}
return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
}

Puedes añadir un editor de texto enriquecido para los extractos también, agrega el siguiente código en el archivo de plugin o en el functions.php de tu tema y podrás ver el editor HTML para extractos. Además, renderizará los extractos en formato HTML también. #saludos
Copié esto de algún lugar pero no recuerdo la fuente. Lo uso en todos mis proyectos y funciona.
Edición: Esto fue copiado de Agregar un editor de texto enriquecido al extracto respuesta del 2012 por fuxia
/**
* Reemplaza el editor de extracto predeterminado con TinyMCE.
*/
add_action( 'add_meta_boxes', array ( 'T5_Richtext_Excerpt', 'switch_boxes' ) );
class T5_Richtext_Excerpt
{
/**
* Reemplaza las meta cajas.
*
* @return void
*/
public static function switch_boxes()
{
if ( ! post_type_supports( $GLOBALS['post']->post_type, 'excerpt' ) )
{
return;
}
remove_meta_box(
'postexcerpt', // ID
'', // Pantalla, vacío para soportar todos los tipos de post
'normal' // Contexto
);
add_meta_box(
'postexcerpt2', // Reutilizar solo 'postexcerpt' no funciona.
__( 'Extracto' ), // Título
array ( __CLASS__, 'show' ), // Función de visualización
null, // Pantalla, usamos todas las pantallas con meta cajas.
'normal', // Contexto
'core', // Prioridad
);
}
/**
* Salida para la meta caja.
*
* @param object $post
* @return void
*/
public static function show( $post )
{
?>
<label class="screen-reader-text" for="excerpt"><?php
_e( 'Extracto' )
?></label>
<?php
// Usamos el nombre predeterminado, 'excerpt', así no tenemos que preocuparnos
// por guardar, otros filtros, etc.
wp_editor(
self::unescape( $post->post_excerpt ),
'excerpt',
array (
'textarea_rows' => 15,
'media_buttons' => FALSE,
'teeny' => TRUE,
'tinymce' => TRUE
)
);
}
/**
* El extracto usualmente está escapado. Esto rompe el editor HTML.
*
* @param string $str
* @return string
*/
public static function unescape( $str )
{
return str_replace(
array ( '<', '>', '"', '&', ' ', '&nbsp;' ),
array ( '<', '>', '"', '&', ' ', ' ' ),
$str
);
}
}
