David Lohmeyer's Blog

Format Wordpress posts from the last week with better excerpts

At work we send a weekly newsletter that has a summary of our blog posts from the last week.  As our blog has grown, this task has started to take a lot more time to manually format each post title and excerpt.  Seeking to automate this process was a goal of mine, as our main post listing is not easily formattable into a newsletter text block without editing.

A customized Wordpress page with special code was in order.  Utilizing Wordpress page templates, one can query for posts in a specific time period and manipulate the text displayed for the post.  The following is my page template.  This is theme-sepcific, so you'll probably have to tweak it depending on what you have going for a theme.  The only extraneous code here is my closing div near the end.  I'm also filtering out posts with the words "PowerLinks" and Commentary:" in them since they're not as relevant to our newsletter:

<?php
/*
Template Name: Since last Wednesday
*/
?>

<?php get_header(); ?>

<?php
add_filter('posts_where', 'filter_where');
$query = 'posts_per_page=-1';
$queryObject = new WP_Query($query);
remove_filter('posts_where', 'filter_where');

// The Loop...
?>

<?php if ($queryObject->have_posts()) {
      while ($queryObject->have_posts()) {
        $queryObject->the_post();
        if(!strstr(get_the_title(), 'PowerLinks')
        && !strstr(get_the_title(), 'Commentary:')){
?>

      <h2><a href="<?php the_permalink() ?>" rel="bookmark"><?php the_title(); ?></a> </h2>
      <?php the_first_sentence(); ?>
<?php
        }
      } //end while
    }else{
?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php } ?>

</div>
<?php get_footer(); ?>

There are a few special functions in this template that need to be present in the functions.php file, notably the posts_where filter and the_first_sentence function.  Here's the filter, which should be in functions.php:

 

function filter_where( $where = '' ) {
    $where .= " AND post_date > '" . date('Y-m-d', strtotime('-6 days')) . "'";
    return $where;
}

Here's the set of functions for the_first_sentence.  These are relatively complex since they look for periods and filter out instances where the period is just an abbreviation for someone's title.  They also look for opening parentheses and make sure that they are closed in the sentence being pulled.  This is a relatively new function, so I'll probably be tweaking it in the future.  For now it seems to be working well for its purpose:

function the_first_sentence() {
     $content = get_the_content('',FALSE,'');
     $content = apply_filters('the_content', $content);
     $content = strip_tags($content);
     $pos = strpos($content, '.');
     $gotExcerpt = false;
     while($gotExcerpt == false){
         if(period_is_title($pos, $content) || parenthesis_is_open($pos, $content)){
             if(next_period_position($pos, $content) != false){
                $pos = next_period_position($pos, $content);
             }else{
                $gotExcerpt = true;
                echo excerpt_to_position($pos, $content);
             }
         }else{
            echo excerpt_to_position($pos, $content);
            $gotExcerpt = true;
         }
     }
}

 

function period_is_title($pos, $content) {
    $textBeforePeriod = substr($content,$pos-3,3);
    if((strpos($textBeforePeriod,' ') != false
        || substr($textBeforePeriod,0,1) == ' ')
        && preg_match("/([A-Za-z])+/", $textBeforePeriod)){
        return true;
    }else{
        return false;
    }
}
function parenthesis_is_open($pos, $content) {
     $stringToSearch = $content;
     $posOpen = strpos($stringToSearch, '(');
     $posClosed = strpos($stringToSearch, ')');
     $textToClosed = substr($stringToSearch,0,$pos);
     //Parentheses count is uneven, they're open.
     if(substr_count($textToClosed, '(') != substr_count($textToClosed, ')')){
        return true;
     }
     //Period position is inside a parenthesis.
     if($pos > $posOpen && ($pos < $posClosed || $posClosed == false)) {
        return true;
     }
     return false;
}

 

function next_period_position($pos, $content) {
    $nextPeriod = strpos($content,'.',$pos+1);
    if($nextPeriod != false && strpos(substr($content,0,$pos),'Related posts') == false){
        return $nextPeriod;
    }else{
        return false;
    }
}

If you're looking to do something similar I hope these are helpful.

Related Posts