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; | |
| }); |