Making a Dynamic WordPress Menu Outside WordPress

Posted on Jun 1, 2009 in Wordpress | 3 comments


Imagine you have a blog which is a supplement to your site, such as a platform for company news.

Now imagine you want to add your blog to your main site’s navigation menu. Easy enough, just add a static link.

Now imagine you want to create an unordered list of the categories in your blog, so that each category can be easily accessed from any page on your website…. oops, it just got tricky.

One solution could be to load the core wordpress files and use their function to get your categories ordered and subcategorized nicely. However, although the upside is WordPress does the hard work for you, the downside is that you need to include a lot of extra and unneccessary code which will probably conflict with your website code.

Have no fear though… Here’s a little php5 class that you can use to access your wordpress database, extract all the categories, and print them out in an unordered list structure. Categories with no content are ignored (unless a subcategory within it has content).

class wpCategories {
	public $wpCategories;

	public function wpCategories($db, $wp_prefix = "wp_"){
		$conn = new mysqli($db['host'], $db['username'], $db['password'], $db['database']);
		$sql = "
			SELECT term_taxonomy_id, t.term_id, `name`, slug, `parent`, `count` FROM
			{$wp_prefix}terms t, {$wp_prefix}term_taxonomy tt
			WHERE t.term_id=tt.term_id
			AND taxonomy='category'
			ORDER BY `name`
		";
		/* check connection */
		if (mysqli_connect_errno()) {
			throw new Exception("Couldn't connect to database");
		}
		if($result = $conn->query($sql)){
			//Get the base categories
			$wpCategoryChildren = array();
			$wpCategories = array();
			while( $row = $result->fetch_assoc() ){
				if($row['parent'] != 0){
					//Save this record for later
					$wpCategoryChildren[$row['parent']][$row['term_taxonomy_id']] = $row;
				}else{
					//This has no parents, so add it to the categories list
					$wpCategories[$row['term_taxonomy_id']]['parent'] = $row;
					$wpCategories[$row['term_taxonomy_id']]['children'] = array();
				}
			}
			$this->wpGetCategories($wpCategories, $wpCategoryChildren);
			$this->wpCategories = $wpCategories;
		}else{
			throw new Exception('No Categories Found');
		}
	}

	//Get the categories from a list of parent categories and possible children
	public function wpGetCategories(&$categories, &$children){
		//Go through each parent category and find any children
		foreach($categories as $parentId => $childCategories){
			//Find immediate children
			$getChildren = array();
			if( array_key_exists($parentId, $children) ){
				foreach($children[$parentId] as $childKey => $childCategory){
					//Assign the category to the categories array and remove it from the children array
					$categories[$parentId]['children'][$childCategory['term_taxonomy_id']]['parent'] = $childCategory;
					$categories[$parentId]['children'][$childCategory['term_taxonomy_id']]['children'] = array();
					unset($children[$parentId][$childKey]);
					//Change the count so that if a parent has 0 entries but a subcategory has at least one, the whole tree isn't skipped
					$categories[$parentId]['parent']['count'] += $childCategory['count'];
					//Set flag if it has children
					$getChildren[] = array_key_exists($childKey, $children);
				}
				//If any of the children processed above have children of their own, then run this function on the array of children
				if( in_array(true, $getChildren) ){
					$this->wpGetCategories($categories[$parentId]['children'], $children);
				}
			}
		}
	}
	
	function printString($categories){
		$count = 0;
		if(is_array($categories)){
			foreach( $categories as $categoryArray ){
				//First print the category head, as long as it or it's children have at least 1 post
				if( $categoryArray['parent']['count']>0 ){
					if($count == 0){
						?><ul><?php
					}
					?>
					<li><a href='/news-events/category/<?= $categoryArray&#91;'parent'&#93;&#91;'slug'&#93; ?>/'><?= $categoryArray&#91;'parent'&#93;&#91;'name'&#93; ?></a>
					<?php
					//If this category has children, run this function again to print them.
					if( count($categoryArray&#91;'children'&#93;) > 0 ){
						$this->printString($categoryArray['children']);
					}
					?>
					</li>
					<?php
					$count++;
				}
			}
			if($count > 0){
				?></ul><?php
			}
		}
	}

	//Print a higherarchical array as a list
	function __toString(){
		$categories = $this->wpCategories;
		ob_start();
		$this->printString($categories);
		return ob_get_clean();
	}
}

To get this working, include the code above in your script, and then run the following:

try {
$wpCategories = new wpCategories(array(‘host’=>’xxxx’, ‘username’=>’xxxx’, ‘password’=> ‘xxxx’, ‘database’=>’xxxx’));
echo $wpCategories;
}catch(Exception $ex){
?>

have to wrap this in try/catch blocks, but in the event that something goes wrong with the WP database, you have a graceful failsafe method.