Acontece que a resposta estava em wp_trim_excerpt()
.
Está definido em wp-includes/functions.php:1879
:
/**
* Generates an excerpt from the content, if needed.
*
* The excerpt word amount will be 55 words and if the amount is greater than
* that, then the string ' [...]' will be appended to the excerpt. If the string
* is less than 55 words, then the content will be returned as is.
*
* The 55 word limit can be modified by plugins/themes using the excerpt_length filter
* The ' [...]' string can be modified by plugins/themes using the excerpt_more filter
*
* @since 1.5.0
*
* @param string $text Optional. The excerpt. If set to empty, an excerpt is generated.
* @return string The excerpt.
*/
function wp_trim_excerpt($text = '') {
$raw_excerpt = $text;
if ( '' == $text ) {
$text = get_the_content('');
$text = strip_shortcodes( $text );
$text = apply_filters('the_content', $text);
$text = str_replace(']]>', ']]>', $text);
$excerpt_length = apply_filters('excerpt_length', 55);
$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
$text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
}
return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
}
Assim, qualquer texto passado não é processado; só funciona se for chamado com um parâmetro vazio.
Para resolver isso, adicionei um filtro rápido ao meu tema que resolve o problema:
/**
* Allows for excerpt generation outside the loop.
*
* @param string $text The text to be trimmed
* @return string The trimmed text
*/
function rw_trim_excerpt( $text='' )
{
$text = strip_shortcodes( $text );
$text = apply_filters('the_content', $text);
$text = str_replace(']]>', ']]>', $text);
$excerpt_length = apply_filters('excerpt_length', 55);
$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
return wp_trim_words( $text, $excerpt_length, $excerpt_more );
}
add_filter('wp_trim_excerpt', 'rw_trim_excerpt');
É um tanto redundante, mas eu gosto mais do que abrir novos loops toda vez que eu quero gerar um trecho.