Today I was disappointed to find that Drupal does not automatically close HTML tags when it generates a teaser from the body text. So I wrote a function for us. It is not sophisticated. It is not classy. But it appears to work, ha ha.
/* this function closes any open tags
* in the correct order
*/
function balanceTags($html) {
// basically we're going to walk through the string and
// push open tags to the stack
// pop close tags from the stack
// return a nicer string
$stack = array();
$pointer = 0;
$len = strlen($html);
$mode = 0;
$tag = '';
$closetag = false;
while ($pointer < $len) {
$c = substr($html, $pointer, 1);
if ($c == '<') {
// this is the beginning of a tag
$mode = 1;
} else if ($c == '>') {
// this is the end of a tag
$mode = 0;
if ($closetag) {
// this is a closetag like </div>
if (count($stack)) {
$last_tag = array_pop($stack);
// let's strip off any atrributes
$space = strpos($last_tag, ' ');
if ($space !== false) {
$last_tag = substr($last_tag, 0, $space);
}
while ($last_tag != $tag && $last_tag != '') {
// they don't match, so we need to close the one we just popped
$newhtml .= '</' . $last_tag . '>';
$last_tag = array_pop($stack);
// let's strip off any atrributes
$space = strpos($last_tag, ' ');
if ($space !== false) {
$last_tag = substr($last_tag, 0, $space);
}
}
if ($last_tag) {
$newhtml .= '</' . $tag . '>';
}
} else {
}
$closetag = false;
$tag = '';
} else {
// okay, so we're going to push this tag on the stack
array_push($stack, $tag);
$newhtml .= '<' . $tag . '>';
$tag = '';
}
} else if ($c == '/' && $mode == 1) {
// this is the / part of a close tag
$closetag = true;
} else {
if ($mode == 0) {
// this is just text
$newhtml .= $c;
} else if ($mode == 1) {
// we're building a tag
$tag .= $c;
}
}
$pointer++;
}
// alright, so, do we have anything hanging around?
while (count($stack)) {
$last_tag = array_pop($stack);
// let's strip off any atrributes
$space = strpos($last_tag, ' ');
if ($space !== false) {
$last_tag = substr($last_tag, 0, $space);
}
$newhtml .= '</' . $last_tag . '>';
}
return $newhtml;
} // end balanceTags
Wordpress has all these neat functions for handling parts of a Post, like the_title() and the_exceprt(). Some of them are nice enough to return the value so that you can use it in your PHP code. the_content() is not one of them. But you can hack that function in /wp-includes/post-template.php
function the_content($more_link_text = '(more...)', $stripteaser = 0, $more_file = '', $passback = false) {
$content = get_the_content($more_link_text, $stripteaser, $more_file);
$content = apply_filters('the_content', $content);
$content = str_replace(']]>', ']]>', $content);
if (!$passback) {
echo $content;
} else {
return $content;
}
}
I copied these functions from the Fold Page List plug-in for Wordpress and modified them a little. They are very handy for building breadcrumbs.
/** get_parent_id
* get the id of the parent of a given page
* @param int page id
* @return int the id of the page's parent page
*/
function get_parent_id ( $child = 0 ) {
global $wpdb;
// Make sure there is a child ID to process
if ( $child > 0 ) {
$result = $wpdb->get_var("SELECT post_parent FROM $wpdb->posts WHERE ID = $child");
} else {
// ... or set a zero result.
$result = 0;
}
//
return $result;
}
/** get_ancestor_ids
* get an array of ancestor ids for a given page
* you get an array that looks something like
* [0] this page id
* [1] parent page id
* [2] grandparent page id
* @param int page you want the ancestry of
* @param boolean include this page in the tree (optional, default true)
* @param boolean results top down (optional, default true)
* @return an array of ancestor ids
*/
function get_ancestor_ids ( $child = 0, $inclusive=true, $topdown=true ) {
if ( $child && $inclusive ) $ancestors[] = $child;
while ($parent = get_parent_id ( $child ) ) {
$ancestors[] = $parent;
$child = $parent;
}
// If there are ancestors, test for resorting, and apply
if ($ancestors && $topdown) krsort($ancestors);
if ( !$ancestors ) $ancestors[] = 0;
//
return $ancestors;
}
Here’s my bread crumb function …
function buildBreadCrumbTrail($showThis = true) {
global $post;
echo '<a href="/">Home</a>' . chr(10);
$ancestors = get_ancestor_ids($post->ID, false);
$num_ancestors = count($ancestors);
foreach ($ancestors as $i => $ancestor_id) {
if ($ancestor_id > 0) {
echo ' > <a href="'.get_permalink($ancestor_id).'">'.get_the_title($ancestor_id).'</a>';
}
}
if ($showThis) {
echo ' > <a href="'; the_permalink(); echo '">'; the_title(); echo '</a>' . chr(10);
}
} // end buildBreadCrumbTrail