Index: bb-admin/includes/functions.bb-admin.php
===================================================================
--- bb-admin/includes/functions.bb-admin.php	(revision 2442)
+++ bb-admin/includes/functions.bb-admin.php	(working copy)
@@ -68,6 +68,8 @@
 		$bb_submenu['topics.php'][5]   = array( __( 'Topics' ), 'moderate', 'topics.php' );
 	$bb_menu[160] = array( __( 'Posts' ), 'moderate', 'posts.php', '', 'bb-menu-posts' );
 		$bb_submenu['posts.php'][5]   = array( __( 'Posts' ), 'moderate', 'posts.php' );
+	$bb_menu[165] = array( __( 'Tags' ), 'manage_tags', 'tags.php', '', 'bb-menu-tags' );
+		$bb_submenu['tags.php'][5] = array( __( 'Tags' ), 'manage_tags', 'tags.php' );
 
 	// 200 < Plugin added menu items < 250
 
@@ -710,6 +712,289 @@
 
 }
 
+/* Tags */
+
+function bb_tag_row( $tag ) {
+	
+	$actions  = "<a href='" . esc_attr( bb_get_tag_link( (int) $tag['tag_id'] ) ) . "'>" . __( 'View' ) . "</a>";
+	$actions .= " | <a href='" . bb_get_tag_link( (int) $tag['tag_id'] ) . "#manage-tags'>" . __( 'Edit' ) . "</a>";
+	$actions .= " | <a href='" . esc_attr( bb_nonce_url( bb_get_uri( 'bb-admin/tags.php', array( 'action' => 'destroy', 'id' => $tag['tag_id'], 'tagsearch' => @$_GET['tagsearch'], 'page' => @$_GET['page'], 'orderby' => @$_GET['orderby'], 'order' => @$_GET['order'], 'per_page' => @$_GET['per_page'] ), BB_URI_CONTEXT_A_HREF + BB_URI_CONTEXT_BB_ADMIN ), 'destroy-tag_' . $tag['tag_id'] ) ) . "' onclick=\"return confirm('" . esc_js( sprintf(__( 'Are you sure you want to destroy the "%s" tag? This is permanent and cannot be undone.' ), $tag['name'] ) ) . "');\">" . __( 'Delete' ) . "</a>";
+	
+	$r  = "\t<tr id='tag-" . $tag['tag_id'] . "'" . get_alt_class( 'tag' ) . ">\n";
+	$r .= "\t<td class='check-column'><input type='checkbox' name='tag[]' value='" . $tag['tag_id'] . "' /></td>";
+	$r .= "\t\t<td class=\"tag\"><span class=\"row-title\">" . $tag['tag_id'] . "</td>\n";
+	$r .= "\t\t<td class=\"tag\"><span class=\"row-title\"><a href='" . bb_get_tag_link( (int) $tag['tag_id'] ) . "'>" . $tag['name'] . "</a></span><div><span class=\"row-actions\">$actions</span>&nbsp;</div></td>\n";
+	$r .= "\t\t<td>" . $tag['count'] . "</td>\n";
+	$r .= "\t</tr>\n";
+	
+	return $r;
+}
+
+// BB_Tag_Search class
+// Derived from BB_User_Search
+
+class BB_Tag_Search {
+	var $results;
+	var $search_term;
+	var $page;
+	var $raw_page;
+	var $tags_per_page = 25;
+	var $first_tag;
+	var $last_tag;
+	var $query_limit;
+	var $total_tags_for_query = 0;
+	var $search_errors;
+	var $paging_text;
+	var $paging_text_bottom;
+	var $order_by = 'name';
+	var $order = 'ASC';
+
+	function BB_Tag_Search ( $search_term = false, $page = 1, $getorder_by = 'name', $getorder = 'ASC', $get_per_page = 25 ) { // constructor
+		$this->search_term = $search_term ? stripslashes( $search_term ) : false;
+		$this->raw_page = ( '' == $page ) ? false : (int) $page;
+		$page = (int) $page;
+		$this->page = $page < 2 ? 1 : $page;
+		
+		$this->order_by = in_array( $getorder_by, array( 'id', 'name', 'count' ) ) ? $getorder_by : 'name';
+		$this->order = in_array( $getorder, array( 'ASC', 'DESC' ) ) ? $getorder : 'ASC';
+		$this->tags_per_page = in_array( $get_per_page, array( 25, 50, 100 ) ) ? (int)$get_per_page : 25;
+		
+		$this->prepare_query();
+		$this->query();
+		$this->prepare_vars_for_template_usage();
+		$this->do_paging();
+	}
+
+	function prepare_query() {
+		$this->first_tag = ( $this->page - 1 ) * $this->tags_per_page;
+	}
+
+	function query() {
+		global $wp_taxonomy_object;
+		
+		$terms = $wp_taxonomy_object->get_terms(
+				'bb_topic_tag',
+				array(
+				      'search' => $this->search_term,
+				      'offset' => $this->first_tag,
+				      'number' => $this->tags_per_page,
+				      'orderby' => $this->order_by,
+				      'order' => $this->order,
+				      'get' => 'all'
+				      )
+				);
+		if ( is_wp_error( $terms ) )
+			$this->search_errors = $terms;
+		
+		$tags = array();
+		
+		for ( $i = 0; isset( $terms[$i] ); $i++ ) {
+			$tags[$i]['tag_id']	= $terms[$i]->term_id;
+			$tags[$i]['name']	= $terms[$i]->name;
+			$tags[$i]['count']	= $terms[$i]->count;
+		}
+		
+		$this->results = $tags;
+
+		if ( $this->results )
+			$this->total_tags_for_query = bb_count_last_query();
+		elseif ( !is_wp_error( $this->search_errors ) )
+			$this->search_errors = new WP_Error( 'no_matching_users_found', '<strong>' . __( 'No matching tags were found!' ) . '</strong>' );
+
+		if ( is_wp_error( $this->search_errors ) )
+			bb_admin_notice( $this->search_errors );
+	}
+
+	function prepare_vars_for_template_usage() {
+		$this->search_term = stripslashes($this->search_term); // done with DB, from now on we want slashes gone
+	}
+
+	function do_paging() {
+		global $bb_current_submenu;
+		$displaying_num = sprintf(
+			__( '%1$s to %2$s of %3$s' ),
+			bb_number_format_i18n( ( $this->page - 1 ) * $this->tags_per_page + 1 ),
+			$this->page * $this->tags_per_page < $this->total_tags_for_query ? bb_number_format_i18n( $this->page * $this->tags_per_page ) : '<span class="total-type-count">' . bb_number_format_i18n( $this->total_tags_for_query ) . '</span>',
+			'<span class="total-type-count">' . bb_number_format_i18n( $this->total_tags_for_query ) . '</span>'
+		);
+		$page_number_links = $this->total_tags_for_query > $this->tags_per_page ? get_page_number_links( $this->page, $this->total_tags_for_query, $this->tags_per_page, false ) : '';
+		$this->paging_text = "<div class='tablenav-pages'><span class='displaying-num'>$displaying_num</span><span class=\"displaying-pages\">$page_number_links</span><div class=\"clear\"></div></div>\n";
+		$this->paging_text_bottom = "<div class='tablenav-pages'><span class=\"displaying-pages\">$page_number_links</span><div class=\"clear\"></div></div>\n";
+	}
+
+	function get_results() {
+		return (array) $this->results;
+	}
+
+	function page_links() {
+		echo $this->paging_text;
+	}
+
+	function results_are_paged() {
+		if ( isset($this->paging_text) && $this->paging_text )
+			return true;
+		return false;
+	}
+
+	function is_search() {
+		if ( $this->search_term )
+			return true;
+		return false;
+	}
+
+	function display( $show_extra = true ) {
+		$r = '';
+
+		$h2_search = $this->search_term ? ' ' . sprintf( __( 'matching &#8220;%s&#8221;' ), esc_html( $this->search_term ) ) : '';
+
+		$h2_span = '<span class="subtitle">';
+		$h2_span .= apply_filters( 'bb_tag_search_description', $h2_search, $this );
+		$h2_span .= '</span>';
+
+		echo "<h2 class=\"first\">" . apply_filters( 'bb_tag_search_title', __( 'Tags' ) ) . $h2_span . "</h2>\n";
+		do_action( 'bb_admin_notices' );
+
+		if ( $show_extra ) {
+			
+			$order_by = array( 'id' => __( 'Tag ID' ), 'name' => __( 'Tag Name' ), 'count' => __( 'Topic Count' ) );
+			$orders = array( 'ASC' => __( 'Ascending' ), 'DESC' => __( 'Descending' ) );
+			$per_pages = array( '25' => bb_number_format_i18n( '25' ), '50' => bb_number_format_i18n( '50' ), '100' => bb_number_format_i18n( '100' ) );
+			
+			$r .= "<form action='' method='get' id='search' class='search-form'>\n";
+			$r .= "<fieldset>\n";
+			
+			/* Search */
+			$r .= "<div>\n";
+			$r .= "\t\t<label for='tagsearch'>" . __( 'Search Term' ) . "</label>";
+			$r .= "\t\t<div><input type='text' name='tagsearch' id='tagsearch' class='text-input' value='" . esc_html( $this->search_term, 1 ) . "' /></div>\n";
+			$r .= "</div>\n";
+			
+			/* Order by */
+			$r .= "<div>\n";
+			$r .= "\t\t<label for='orderby'>" . __( 'Order By' ) . "</label>";
+			$r .= "\t\t<div><select name='orderby' id='orderby'>\n";
+			
+			foreach ( $order_by as $orderby => $display ) {
+				$selected = '';
+				if ( $this->order_by == $orderby )
+					$selected = ' selected="selected"';
+				$value = esc_attr( $orderby );
+				$display = esc_html( $display );
+				$r .= "\t\t\t<option value='$value'$selected>$display</option>\n";
+			}
+			
+			$r .= "\t\t</select></div>\n";
+			$r .= "</div>\n";
+			
+			/* Order */
+			$r .= "<div>\n";
+			$r .= "\t\t<label for='order'>" . __( 'Order' ) . "</label>";
+			$r .= "\t\t<div><select name='order' id='order'>\n";
+			
+			foreach ( $orders as $order => $display ) {
+				$selected = '';
+				if ( $this->order == $order )
+					$selected = ' selected="selected"';
+				$value = esc_attr( $order );
+				$display = esc_html( $display );
+				$r .= "\t\t\t<option value='$value'$selected>$display</option>\n";
+			}
+			
+			$r .= "\t\t</select></div>\n";
+			$r .= "</div>\n";
+			
+			/* Per Page */
+			$r .= "<div>\n";
+			$r .= "\t\t<label for='per_page'>" . __( 'Per Page' ) . "</label>";
+			$r .= "\t\t<div><select name='per_page' id='per_page'>\n";
+			
+			foreach ( $per_pages as $per_page => $display ) {
+				$selected = '';
+				if ( $this->tags_per_page == $per_page )
+					$selected = ' selected="selected"';
+				$value = esc_attr( $per_page );
+				$display = esc_html( $display );
+				$r .= "\t\t\t<option value='$value'$selected>$display</option>\n";
+			}
+			
+			$r .= "\t\t</select></div>\n";
+			$r .= "</div>\n";
+			
+			$r = apply_filters( 'bb_tag_search_form_inputs', $r, $this );
+			
+			$r .= "<div class=\"submit\">\n";
+			$r .= "\t\t<label class='hidden' for='submit'>" . __( 'Search' ) . "</label>";
+			$r .= "\t\t<div><input type='submit' id='submit' class='button submit-input' value='" . __( 'Filter' ) . "' /></div>\n";
+			$r .= "</div>\n";
+			$r .= "</fieldset>\n";
+			$r .= "</form>\n\n";
+			
+			/* Bulk Actions */
+			
+			$bulk_actions = array(
+				'destroy' => __( 'Destroy' ),
+				'merge' => __( 'Merge' )
+			);
+			
+			do_action_ref_array( 'bulk_tag_actions', array( &$bulk_actions ) );
+			
+			$r .= "<form class='table-form bulk-form' method='post'>\n";
+			$r .= "\t<fieldset>\n";
+			$r .= "\t\t<select name='action' onchange=\"if(this.value=='merge'){jQuery('#new-tag').css('display','inline');}else{jQuery('#new-tag').css('display','none');}\">\n";
+			$r .= "\t\t\t<option>" . __( 'Bulk Actions' ) . "</option>\n";
+			foreach ( $bulk_actions as $value => $label ) {
+				$r .= "\t\t\t<option value='" . esc_attr( $value ) . "'>" . esc_html( $label ) . "</option>\n";
+			}
+			$r .= "\t\t</select>\n";
+			$r .= "\t\t<input type='text' name='merge_new_tag' id='new-tag' class='text-input' value='" . __( 'New Tag Name' ) . "' style='display:none;' onblur='if(this.value==\"" . __( 'New Tag Name' ) . "\")this.value=\"\"';' onblur='if(this.value==\"\")this.value=\"" . __( 'New Tag Name' ) . "\"';' />\n";
+			$r .= "\t\t<input type='submit' value='" . __( 'Apply' ) . "' class='button submit-input' onclick=\"return confirm('" . esc_js( __( 'Are you sure you want to do this? This is permanent and cannot be undone.' ) ) . "');\" />\n";
+			$r .= bb_nonce_field( 'tags-bulk', '_wpnonce', true, false );
+			$r .= "\t</fieldset>\n";
+		}
+
+		if ( $this->get_results() ) {
+			if ( $this->results_are_paged() )
+				$r .= "<div class='tablenav'>\n" . $this->paging_text . "</div><div class=\"clear\"></div>\n\n";
+				
+			$r .= "<table class='widefat'>\n";
+			$r .= "<thead>\n";
+			$r .= "\t<tr>\n";
+			
+			$r .= "\t\t<th scope='col' class='check-column'><input type='checkbox' /></th>\n";
+			$r .= "\t\t<th style='width:20%;'>" . __( 'Tag ID' ) . "</th>\n";
+			$r .= "\t\t<th style='width:50%;'>" . __( 'Tag Name' ) . "</th>\n";
+			$r .= "\t\t<th style='width:30%;'>" . __( 'Topics' ) . "</th>\n";
+			
+			$r .= "\t</tr>\n";
+			$r .= "</thead>\n\n";
+			
+			$r .= "<tfoot>\n";
+			$r .= "\t<tr>\n";
+			
+			$r .= "\t\t<th scope='col' class='check-column'><input type='checkbox' /></th>\n";
+			$r .= "\t\t<th style='width:20%;'>" . __( 'Tag ID' ) . "</th>\n";
+			$r .= "\t\t<th style='width:50%;'>" . __( 'Tag Name' ) . "</th>\n";
+			$r .= "\t\t<th style='width:30%;'>" . __( 'Topics' ) . "</th>\n";
+			
+			$r .= "\t</tr>\n";
+			$r .= "</tfoot>\n\n";
+
+			$r .= "<tbody id='role-$role'>\n";
+			foreach ( (array) $this->get_results() as $tag )
+				$r .= bb_tag_row( $tag );
+			$r .= "</tbody>\n";
+			$r .= "</table>\n\n";
+			
+			$r .= "</form>\n";
+
+			if ( $this->results_are_paged() )
+				$r .= "<div class='tablenav bottom'>\n" . $this->paging_text_bottom . "</div><div class=\"clear\"></div>\n\n";
+		}
+		echo $r;
+	}
+
+}
+
 /* Forums */
 
 // Expects forum_name, forum_desc to be pre-escaped
Index: bb-admin/style.css
===================================================================
--- bb-admin/style.css	(revision 2442)
+++ bb-admin/style.css	(working copy)
@@ -451,6 +451,15 @@
 	background-position: -186px -7px;
 }
 
+ul#bbAdminMenu li#bb-menu-tags a div.bb-menu-icon {
+	background-position: -278px -39px;
+}
+
+ul#bbAdminMenu li#bb-menu-tags.bb-menu-current a div.bb-menu-icon,
+ul#bbAdminMenu li#bb-menu-tags a:hover div.bb-menu-icon {
+	background-position: -278px -7px;
+}
+
 ul#bbAdminMenu li#bb-menu-users a div.bb-menu-icon {
 	background-position: -308px -39px;
 }
@@ -847,7 +856,8 @@
 	color: rgb(70, 70, 70);
 }
 
-form.search-form fieldset div div input.text-input {
+form.search-form fieldset div div input.text-input,
+#new-tag {
 	width: 100px;
 	padding: 3px;
 	-moz-border-radius: 4px;
Index: bb-admin/tag-destroy.php
===================================================================
--- bb-admin/tag-destroy.php	(revision 2442)
+++ bb-admin/tag-destroy.php	(working copy)
@@ -1,22 +0,0 @@
-<?php
-require('admin.php');
-
-if ( !bb_current_user_can('manage_tags') )
-	bb_die(__('You are not allowed to manage tags.'));
-
-$tag_id = (int) $_POST['id' ];
-
-bb_check_admin_referer( 'destroy-tag_' . $tag_id );
-
-$old_tag = bb_get_tag( $tag_id );
-if ( !$old_tag )
-	bb_die(__('Tag not found.'));
-
-if ( $destroyed = bb_destroy_tag( $tag_id ) ) {
-	printf(__("Rows deleted from tags table: %d <br />\n"), $destroyed['tags']);
-	printf(__("Rows deleted from tagged table: %d <br />\n"), $destroyed['tagged']);
-	printf(__('<a href="%s">Home</a>'), bb_get_uri());
-} else {
-   die(printf(__("Something odd happened when attempting to destroy that tag.<br />\n<a href=\"%s\">Try Again?</a>"), wp_get_referer()));
-}
-?>
Index: bb-admin/tag-merge.php
===================================================================
--- bb-admin/tag-merge.php	(revision 2442)
+++ bb-admin/tag-merge.php	(working copy)
@@ -1,26 +0,0 @@
-<?php
-require('admin.php');
-
-if ( !bb_current_user_can('manage_tags') )
-	bb_die(__('You are not allowed to manage tags.'));
-
-$old_id = (int) $_POST['id' ];
-$tag = $_POST['tag'];
-
-bb_check_admin_referer( 'merge-tag_' . $old_id );
-
-if ( ! $tag = bb_get_tag( $tag ) )
-	bb_die(__('Tag specified not found.'));
-
-if ( ! bb_get_tag( $old_id ) )
-	bb_die(__('Tag to be merged not found.'));
-
-if ( $merged = bb_merge_tags( $old_id, $tag->tag_id ) ) {
-	printf(__("Number of topics from which the old tag was removed: %d <br />\n"),  $merged['old_count']);
-    printf(__("Number of topics to which the new tag was added: %d <br />\n"),$merged['diff_count']);
-	printf(__("Number of rows deleted from tags table:%d <br />\n"),$merged['destroyed']['tags']);
-	printf(__('<a href="%s">New Tag</a>'), bb_get_tag_link());
-} else {
-   die(printf(__("Something odd happened when attempting to merge those tags.<br />\n<a href=\"%s\">Try Again?</a>"), wp_get_referer()));
-}
-?>
Index: bb-admin/tag-rename.php
===================================================================
--- bb-admin/tag-rename.php	(revision 2442)
+++ bb-admin/tag-rename.php	(working copy)
@@ -1,22 +0,0 @@
-<?php
-require('admin.php');
-
-if ( !bb_current_user_can('manage_tags') )
-	bb_die(__('You are not allowed to manage tags.'));
-
-$tag_id = (int) $_POST['id' ];
-$tag    =       $_POST['tag'];
-
-bb_check_admin_referer( 'rename-tag_' . $tag_id );
-
-$old_tag = bb_get_tag( $tag_id );
-if ( !$old_tag )
-	bb_die(__('Tag not found.'));
-
-$tag = stripslashes( $tag );
-if ( $tag = bb_rename_tag( $tag_id, $tag ) )
-	wp_redirect( bb_get_tag_link() );
-else
-	die(printf(__('There already exists a tag by that name or the name is invalid. <a href="%s">Try Again</a>'), wp_get_referer()));
-exit;
-?>
Index: bb-admin/tags.php
===================================================================
--- bb-admin/tags.php	(revision 0)
+++ bb-admin/tags.php	(revision 0)
@@ -0,0 +1,107 @@
+<?php
+require_once( 'admin.php' );
+
+if ( 'post' == strtolower( $_SERVER['REQUEST_METHOD'] ) ) { /* Accepts multiple tags in array */
+	bb_check_admin_referer( 'tags-bulk' );
+
+	$tag_ids = array_map( 'absint', (array) $_POST['tag'] );
+	$count = 0;
+	$action = trim( $_POST['action'] );
+
+	switch ( $action ) {
+	case 'destroy' :
+		foreach ( $tag_ids as $tag_id )
+			$count += (int) (bool) bb_destroy_tag( $tag_id );
+		
+		$query_vars = array( 'message' => 'destroyed', 'count' => $count );
+		break;
+	case 'merge' :
+		if ( !$new_tag = (string) trim( $_POST['merge_new_tag'] ) )
+			break;
+		if ( !$new_tag_id = bb_create_tag( $new_tag ) ) /* The tag ID would be returned if tag is already there, else it would be created */
+			if ( !$new_tag_id = bb_get_tag_id( $new_tag ) ) /* Due to some problem, bb_create_tag doesn't return the term id so we need to try to get the id again */
+				break;
+		
+		foreach ( $tag_ids as $tag_id ) {
+			if ( $tag_id == $new_tag_id )
+				continue;
+			$count += (int) (bool) bb_merge_tags( $tag_id, $new_tag_id );
+		}
+		
+		$query_vars = array( 'message' => 'merged', 'count' => $count, 'new_id' => $new_tag_id );
+		break;
+	default :
+		if ( $action )
+			$query_vars = apply_filters( "bulk_tag__$action", array(), $tag_ids, $action );
+		break;
+	}
+
+	bb_safe_redirect( add_query_arg( $query_vars ) );
+	exit;
+}
+
+if ( !empty( $_GET['action'] ) && in_array( $_GET['action'], array( 'rename', 'merge', 'destroy' ) ) && $old_tag = bb_get_tag( (int) $_GET['id'] ) ) { /* Accepts only one tag */
+	$action = $_GET['action'];
+	$old_id = (int) $_GET['id'];
+	
+	bb_check_admin_referer( $action . '-tag_' . $old_id );
+	
+	switch ( $action ) {
+		case 'destroy':
+			$query_vars = ( (bool) bb_destroy_tag( $old_id ) ) ? array( 'message' => 'destroyed' ) : $query_vars = array( 'message' => 'error' );
+			break;
+		case 'merge':
+			if ( !$new_tag = bb_get_tag( $_GET['tag'] ) ) {
+				$query_vars = array( 'message' => 'error' );
+				break;
+			}
+			$query_vars = ( (bool) bb_merge_tags( $old_id, $new_tag->tag_id ) ) ? array( 'message' => 'merged', 'new_id' => $new_tag->tag_id ) : array( 'message' => 'error' );
+			break;
+		case 'rename':
+			$new_tag = stripslashes( $_GET['tag'] );
+			$query_vars = ( (bool) bb_rename_tag( $old_id, $new_tag ) ) ? array( 'message' => 'renamed', 'new_id' => $old_id ) : array( 'message' => 'error' );
+			break;
+	}
+	
+	bb_safe_redirect( remove_query_arg( array( 'action', 'tag', 'Submit', 'id', '_wpnonce' ), add_query_arg( $query_vars ) ) ); /* Just keep _wp_http_referer for messages (below) */
+	exit;
+}
+
+if ( !empty( $_GET['message'] ) ) {
+	$message_count = isset( $_GET['count'] ) ? (int) $_GET['count'] : 1;
+	
+	switch ( (string) $_GET['message'] ) {
+		case 'destroyed':
+			$back = isset( $_GET['_wp_http_referer'] ) ? ' <a href="' . bb_get_uri() . '">' . __( 'Back to forums.' ) . '</a>' : '';
+			bb_admin_notice( '<strong>' . sprintf( _n( 'Tag destroyed.', '%s tags destroyed.', $message_count ), bb_number_format_i18n( $message_count ) ) . '</strong>' . $back );
+			break;
+		case 'merged':
+			bb_admin_notice( '<strong>' . sprintf( _n( 'Tag merged into %2$s.', '%1$s tags merged into %2$s.', $message_count ), bb_number_format_i18n( $message_count ), '<a href="' . bb_get_tag_link( (int) $_GET['new_id'] ) . '">' . bb_get_tag_name( (int) $_GET['new_id'] )  . '</a>' ) . '</strong>' );
+			break;
+		case 'renamed':
+			bb_admin_notice( '<strong>' . sprintf( 'Tag renamed to %s.', '<a href="' . bb_get_tag_link( (int) $_GET['new_id'] ) . '">' . bb_get_tag_name( (int) $_GET['new_id'] ) . '</a>' ) . '</strong>' );
+			break;
+		case 'error':
+			$back = isset( $_GET['_wp_http_referer'] ) ? ' <a href="' . bb_get_uri() . '">' . __( 'Back to forums.' ) . '</a>' : '';
+			bb_admin_notice( '<strong>' . __( 'There was an error with your request! Please try again.' ) . '</strong>' . $back );
+			break;
+	}
+}
+
+$tag_query = new BB_Tag_Search( @$_GET['tagsearch'], @$_GET['page'], @$_GET['orderby'], @$_GET['order'], @$_GET['per_page'] );
+
+$bb_admin_body_class = ' bb-admin-tags';
+
+bb_get_admin_header();
+
+if ( !bb_current_user_can( 'manage_tags' ) )
+	die( __( "Now how'd you get here?  And what did you think you'd being doing?" ) ); //This should never happen.
+?>
+
+<div class="wrap">
+
+<?php $tag_query->display(); ?>
+
+</div>
+
+<?php bb_get_admin_footer(); ?>
Index: bb-includes/functions.bb-template.php
===================================================================
--- bb-includes/functions.bb-template.php	(revision 2442)
+++ bb-includes/functions.bb-template.php	(working copy)
@@ -3137,39 +3137,44 @@
 <?php
 }
 
-function manage_tags_forms()
-{
+function manage_tags_forms() {
+	if ( !bb_current_user_can( 'manage_tags' ) )
+		return false;
+	
 	global $tag;
-	if ( !bb_current_user_can( 'manage_tags' ) ) {
-		return false;
-	}
 
 	$form  = '<ul id="manage-tags">' . "\n";
-	$form .= '<li id="tag-rename">' . __('Rename tag:') . "\n\t";
-	$form .= '<form method="post" action="' . bb_get_uri( 'bb-admin/tag-rename.php', null, BB_URI_CONTEXT_FORM_ACTION + BB_URI_CONTEXT_BB_ADMIN ) . '"><div>' . "\n\t";
+	$form .= '<li id="tag-rename">' . __( 'Rename tag:' ) . "\n\t";
+	$form .= '<form method="get" action="' . bb_get_uri( 'bb-admin/tags.php', null, BB_URI_CONTEXT_FORM_ACTION + BB_URI_CONTEXT_BB_ADMIN ) . '"><div>' . "\n\t";
 	$form .= '<input type="text" name="tag" size="10" maxlength="30" />' . "\n\t";
 	$form .= '<input type="hidden" name="id" value="' . $tag->tag_id . '" />' . "\n\t";
-	$form .= "<input type='submit' name='Submit' value='" . __('Rename') . "' />\n\t";
+	$form .= '<input type="hidden" name="action" value="rename" />' . "\n\t";
+	$form .= "<input type='submit' name='Submit' value='" . __( 'Rename' ) . "' />\n\t";
 	echo $form;
 	bb_nonce_field( 'rename-tag_' . $tag->tag_id );
 	echo "\n\t</div></form>\n  </li>\n ";
-	$form  = "<li id='tag-merge'>" . __('Merge this tag into:') . "\n\t";
-	$form .= "<form method='post' action='" . bb_get_uri('bb-admin/tag-merge.php', null, BB_URI_CONTEXT_FORM_ACTION + BB_URI_CONTEXT_BB_ADMIN) . "'><div>\n\t";
+	
+	$form  = "<li id='tag-merge'>" . __( 'Merge this tag into:' ) . "\n\t";
+	$form .= "<form method='get' action='" . bb_get_uri( 'bb-admin/tags.php', null, BB_URI_CONTEXT_FORM_ACTION + BB_URI_CONTEXT_BB_ADMIN ) . "'><div>\n\t";
 	$form .= "<input type='text' name='tag' size='10' maxlength='30' />\n\t";
 	$form .= "<input type='hidden' name='id' value='$tag->tag_id' />\n\t";
-	$form .= "<input type='submit' name='Submit' value='" . __('Merge') . "' ";
-	$form .= 'onclick="return confirm(\'' . esc_js( sprintf(__('Are you sure you want to merge the "%s" tag into the tag you specified? This is permanent and cannot be undone.'), $tag->raw_tag) ) . "');\" />\n\t";
+	$form .= '<input type="hidden" name="action" value="merge" />' . "\n\t";
+	$form .= "<input type='submit' name='Submit' value='" . __( 'Merge' ) . "' ";
+	$form .= 'onclick="return confirm(\'' . esc_js( sprintf(__( 'Are you sure you want to merge the "%s" tag into the tag you specified? This is permanent and cannot be undone.' ), $tag->raw_tag ) ) . "');\" />\n\t";
 	echo $form;
 	bb_nonce_field( 'merge-tag_' . $tag->tag_id );
 	echo "\n\t</div></form>\n  </li>\n ";
-	$form  = "<li id='tag-destroy'>" . __('Destroy tag:') . "\n\t";
-	$form .= "<form method='post' action='" . bb_get_uri('bb-admin/tag-destroy.php', null, BB_URI_CONTEXT_FORM_ACTION + BB_URI_CONTEXT_BB_ADMIN) . "'><div>\n\t";
+	
+	$form  = "<li id='tag-destroy'>" . __( 'Destroy tag:' ) . "\n\t";
+	$form .= "<form method='get' action='" . bb_get_uri( 'bb-admin/tags.php', null, BB_URI_CONTEXT_FORM_ACTION + BB_URI_CONTEXT_BB_ADMIN ) . "'><div>\n\t";
 	$form .= "<input type='hidden' name='id' value='$tag->tag_id' />\n\t";
-	$form .= "<input type='submit' name='Submit' value='" . __('Destroy') . "' ";
-	$form .= 'onclick="return confirm(\'' . esc_js( sprintf(__('Are you sure you want to destroy the "%s" tag? This is permanent and cannot be undone.'), $tag->raw_tag) ) . "');\" />\n\t";
+	$form .= '<input type="hidden" name="action" value="destroy" />' . "\n\t";
+	$form .= "<input type='submit' name='Submit' value='" . __( 'Destroy' ) . "' ";
+	$form .= 'onclick="return confirm(\'' . esc_js( sprintf(__( 'Are you sure you want to destroy the "%s" tag? This is permanent and cannot be undone.' ), $tag->raw_tag ) ) . "');\" />\n\t";
 	echo $form;
 	bb_nonce_field( 'destroy-tag_' . $tag->tag_id );
 	echo "\n\t</div></form>\n  </li>\n</ul>";
+	
 }
 
 function bb_tag_remove_link( $args = null ) {
Index: bb-includes/functions.bb-topic-tags.php
===================================================================
--- bb-includes/functions.bb-topic-tags.php	(revision 2442)
+++ bb-includes/functions.bb-topic-tags.php	(working copy)
@@ -422,7 +422,7 @@
 
 	$tag_id = (int) $tag_id;
 	$raw_tag = bb_trim_for_db( $tag_name, 50 );
-	$tag_name = tag_sanitize( $tag_name ); 
+	$tag_name = bb_pre_term_slug( $tag_name ); 
 
 	if ( empty( $tag_name ) ) {
 		return false;
@@ -464,16 +464,16 @@
 	do_action( 'bb_pre_merge_tags', $old_id, $new_id );
 
 	// Get all topics tagged with old tag
-	$old_topics = bb_get_tagged_topic_ids( $old_id );
+	$old_topics = (array) bb_get_tagged_topic_ids( $old_id );
 
 	// Get all toics tagged with new tag
-	$new_topics = bb_get_tagged_topic_ids( $new_id );
+	$new_topics = (array) bb_get_tagged_topic_ids( $new_id );
 
 	// Get intersection of those topics
-	$both_topics = array_intersect( $old_topics, $new_topics );
+	$both_topics = (array) array_intersect( $old_topics, $new_topics );
 
 	// Discard the intersection from the old tags topics
-	$old_topics = array_diff( $old_topics, $both_topics );
+	$old_topics = (array) array_diff( $old_topics, $both_topics );
 
 	// Add the remainder of the old tag topics to the new tag
 	if ( count( $old_topics ) ) {

