Monthly Archive for September, 2008

Balance HTML Tags

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

Getting The Content From Wordpress

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(']]>', ']]&gt;', $content);
 
	if (!$passback) {
		echo $content;
	} else {
		return $content;
	}
}

Get Grandparent Pages in Wordpress

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