Theming WordPress excerpts and archives

WordPress

I run this blog on WordPress. One of the major advantages of WordPress is its support for customizable web themes. These themes contain the graphical markup (CSS, images) and PHP code to mangle the data that is displayed.

I’ve adapted some of the default functions to have the display of archives and blog excerpts behave differently to the default provided by WordPress.

Styling WordPress archives

WordPress archives are accessible via the wp_get_archives function. This function has a number of features and its HTML output can be styled.

<h3 class="widget-title"><?php _e( 'Archives' ); ?></h3>
	<select style='margin: 12px 0 24px 0;' id='archivedropdown' onchange='document.location.href=this.options[this.selectedIndex].value;'>
	  	<?php 
					$html = wp_get_archives( array( 'type' => 'monthly', 'format' => 'option', 'show_post_count' => true, 'echo' => false ) ); 
					$html = preg_replace( '~(&nbsp;)(\(\d++\))~', '$1&nbsp;&nbsp;&nbsp; $2', $html );
					echo $html;
			?>
	</select>

Initially you see the title of the archives between two header tags (h3). After the header there is an HTML select box with a Javascript call. Whenever the ‘option’ in the select box is changed, the current URL is changed to the selected value (which is the URL corresponding with the category).

The wp_get_archives function is called with a number of options:

  • type : The type of archive list to display;
  • format : Format for the archive list;
  • show_post_count : Display number of posts in an archive or do not;
  • echo : Display the output or return it.

Afterwards, a number of spaces are inserted (with preg_replace) before the post count.

Styling blog excerpts, keeping paragraphs and remove headers

The default excerpt of WordPress removes the paragraph and header tags. I’d like to keep the paragraph tags and remove the content of the header tags.

You can override the excerpt filtering options by adding your own custom function in functions.php. NEVER change anything in the core code of WordPress as all your changes will be overwritten with the next update.

The number of words displayed in the excerpt is controlled via excerpt_length. You can change it by adding a new filter. Similarly if you want to change the way the ‘read more’ link is displayed you have to change excerpt_more filter. An example is in the code below.

// Length of excerpt in words
function new_excerpt_length($length) {
	return 75;
}
add_filter('excerpt_length', 'new_excerpt_length');

// The 'read more' link in the excerpt
function new_excerpt_more($more) {
       global $post;
	return '<span style="white-space: pre;"> ... <a class="moretag" href="'. get_permalink($post->ID) . '">Read more</a>.</span>';
}
add_filter('excerpt_more', 'new_excerpt_more');

The next step covers keeping the paragraph styles in the excerpt. This is more tricky. The solution below works but I’m sure there are more elegant ways to accomplish this result.

// Override the function found in wp-includes/formatting.php
function new_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(']]>', ']]&gt;', $text);
		$excerpt_length = apply_filters('excerpt_length', 55);
		$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');

		$regex = '#(<h([1-6])[^>]*>)\s?(.*)?\s?(<\/h\2>)#';
    $text = preg_replace($regex,'', $text);

		$text = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $text );

		$text = strip_tags($text, '<p><strong><i><b>');
		
		// This is a copy of 'wp_trim_words' with removed strip_tags
		if ( null === $excerpt_more )
			$excerpt_more = __( '&hellip;' );

		/* translators: If your word count is based on single characters (East Asian characters),
		   enter 'characters'. Otherwise, enter 'words'. Do not translate into your own language. */
		if ( 'characters' == _x( 'words', 'word count: words or characters?' ) && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) {
			$text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
			preg_match_all( '/./u', $text, $words_array );
			$words_array = array_slice( $words_array[0], 0, $excerpt_length + 1 );
			$sep = '';
		} else {
			$words_array = preg_split( "/[\n\r\t ]+/", $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY );
			$sep = ' ';
		}
		if ( count( $words_array ) > $excerpt_length ) {
			array_pop( $words_array );
			$text = implode( $sep, $words_array );
			$text = $text . $excerpt_more;
		} else {
			$text = implode( $sep, $words_array );
		}

	}
	return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
}
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'new_trim_excerpt');

Essentially we override a function wp_trim_excerpt (that can be found in wp-includes/formatting.php) that trims the excerpt. The function starts with applying basic filters and looking up the length and the read more link for the excerpt.

Then there’s a regex function. This call removes the content from the header tags in the WordPress excerpt. In the default trim function there’s a call to wp_strip_all_tags. I replaced that with a custom call for stripping the HTML tags (via the PHP function) but keeping the paragraph (p), bold (strong), italic (i) and new line (br) tags.

Afterwards this function handles the splitting of the content. This is copied from the default function. At the end it returns the content of the string, applying any filters that are still pending.

You add the function by first remove the filter from the default queue (with remove_filter(‘get_the_excerpt’, ‘wp_trim_excerpt’) ) and then adding the new function.

Resources

Leave a Reply

Your email address will not be published. Required fields are marked *