Created: 2017.04.09
A solution from Hacking at 0300
Created: 2017.04.09
A solution from Hacking at 0300
function query_re(){ | |
global $wp_query; | |
$terms = $wp_query->query_vars['search_terms']; | |
foreach ($terms as &$term) $term = preg_quote($term, '/'); | |
return '/'.implode('|', $terms).'/iu'; | |
} | |
add_filter('the_excerpt', function ($text){ | |
return preg_replace_text (query_re(), '<span class="searchterm">$0</span>', $text); | |
}); | |
remove_all_filters('get_the_excerpt'); // we want to take over handling the excerpt | |
add_filter( 'get_the_excerpt', function($excerpt){ | |
global $post; | |
$excerpt_length = apply_filters('excerpt_length', 55); | |
$excerpt_more = apply_filters('excerpt_more', '…'); | |
$query_re = query_re(); | |
// First choice: the author-composed excerpt | |
if ($excerpt && preg_match($query_re, $excerpt)) return $excerpt; | |
// Second choice: the start of the text | |
// get the actual text of the post | |
$text = wp_strip_all_tags(apply_filters('the_content', $post->post_content)); | |
// Create the default excerpt | |
$excerpted_text = wp_trim_words($text, $excerpt_length, $excerpt_more); | |
if (preg_match($query_re, $excerpted_text)) return $excerpted_text; | |
// Third choice: context of the search term | |
$text_matched = preg_match ($query_re, $text, $matches, PREG_OFFSET_CAPTURE); // save the matched terms with their offsets | |
if ($text_matched){ | |
$offset = $matches[0][1]+strlen($matches[0][0]); // the offset into the end of the text where the term was found | |
// hack: we want to add context for where the term was found, but we want it to use whole words. wp_trim_words will trim the end, | |
// but we want so many words (empirically, one third the excerpt length) in the beginning. So we reverse the text and use that. | |
$len = $excerpt_length/3; | |
// need to use a single character to indicate truncation since we are reversing the text | |
$reversetext = strrev_utf8(wp_trim_words(strrev_utf8(substr($text, 0, $offset)), $len, '…')); | |
$context = $reversetext.substr($text, $offset); // rebuild it | |
return wp_trim_words($context, $excerpt_length, $excerpt_more); | |
} | |
// No matches. Just use the usual excerpt | |
return $excerpt ? $excerpt : $excerpted_text; | |
}); |