Index: /tags/2.5.4/bbpress.php
===================================================================
--- /tags/2.5.4/bbpress.php	(revision 5382)
+++ /tags/2.5.4/bbpress.php	(revision 5382)
@@ -0,0 +1,929 @@
+<?php
+
+/**
+ * The bbPress Plugin
+ *
+ * bbPress is forum software with a twist from the creators of WordPress.
+ *
+ * $Id$
+ *
+ * @package bbPress
+ * @subpackage Main
+ */
+
+/**
+ * Plugin Name: bbPress
+ * Plugin URI:  http://bbpress.org
+ * Description: bbPress is forum software with a twist from the creators of WordPress.
+ * Author:      The bbPress Community
+ * Author URI:  http://bbpress.org
+ * Version:     2.5.4
+ * Text Domain: bbpress
+ * Domain Path: /languages/
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'bbPress' ) ) :
+/**
+ * Main bbPress Class
+ *
+ * "How doth the little busy bee, improve each shining hour..."
+ *
+ * @since bbPress (r2464)
+ */
+final class bbPress {
+
+	/** Magic *****************************************************************/
+
+	/**
+	 * bbPress uses many variables, several of which can be filtered to
+	 * customize the way it operates. Most of these variables are stored in a
+	 * private array that gets updated with the help of PHP magic methods.
+	 *
+	 * This is a precautionary measure, to avoid potential errors produced by
+	 * unanticipated direct manipulation of bbPress's run-time data.
+	 *
+	 * @see bbPress::setup_globals()
+	 * @var array
+	 */
+	private $data;
+
+	/** Not Magic *************************************************************/
+
+	/**
+	 * @var mixed False when not logged in; WP_User object when logged in
+	 */
+	public $current_user = false;
+
+	/**
+	 * @var obj Add-ons append to this (Akismet, BuddyPress, etc...)
+	 */
+	public $extend;
+
+	/**
+	 * @var array Topic views
+	 */
+	public $views        = array();
+
+	/**
+	 * @var array Overloads get_option()
+	 */
+	public $options      = array();
+
+	/**
+	 * @var array Overloads get_user_meta()
+	 */
+	public $user_options = array();
+
+	/** Singleton *************************************************************/
+
+	/**
+	 * Main bbPress Instance
+	 *
+	 * bbPress is fun
+	 * Please load it only one time
+	 * For this, we thank you
+	 *
+	 * Insures that only one instance of bbPress exists in memory at any one
+	 * time. Also prevents needing to define globals all over the place.
+	 *
+	 * @since bbPress (r3757)
+	 * @staticvar object $instance
+	 * @uses bbPress::setup_globals() Setup the globals needed
+	 * @uses bbPress::includes() Include the required files
+	 * @uses bbPress::setup_actions() Setup the hooks and actions
+	 * @see bbpress()
+	 * @return The one true bbPress
+	 */
+	public static function instance() {
+
+		// Store the instance locally to avoid private static replication
+		static $instance = null;
+
+		// Only run these methods if they haven't been ran previously
+		if ( null === $instance ) {
+			$instance = new bbPress;
+			$instance->setup_globals();
+			$instance->includes();
+			$instance->setup_actions();
+		}
+
+		// Always return the instance
+		return $instance;
+	}
+
+	/** Magic Methods *********************************************************/
+
+	/**
+	 * A dummy constructor to prevent bbPress from being loaded more than once.
+	 *
+	 * @since bbPress (r2464)
+	 * @see bbPress::instance()
+	 * @see bbpress();
+	 */
+	private function __construct() { /* Do nothing here */ }
+
+	/**
+	 * A dummy magic method to prevent bbPress from being cloned
+	 *
+	 * @since bbPress (r2464)
+	 */
+	public function __clone() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'bbpress' ), '2.1' ); }
+
+	/**
+	 * A dummy magic method to prevent bbPress from being unserialized
+	 *
+	 * @since bbPress (r2464)
+	 */
+	public function __wakeup() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'bbpress' ), '2.1' ); }
+
+	/**
+	 * Magic method for checking the existence of a certain custom field
+	 *
+	 * @since bbPress (r3951)
+	 */
+	public function __isset( $key ) { return isset( $this->data[$key] ); }
+
+	/**
+	 * Magic method for getting bbPress variables
+	 *
+	 * @since bbPress (r3951)
+	 */
+	public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; }
+
+	/**
+	 * Magic method for setting bbPress variables
+	 *
+	 * @since bbPress (r3951)
+	 */
+	public function __set( $key, $value ) { $this->data[$key] = $value; }
+
+	/**
+	 * Magic method for unsetting bbPress variables
+	 *
+	 * @since bbPress (r4628)
+	 */
+	public function __unset( $key ) { if ( isset( $this->data[$key] ) ) unset( $this->data[$key] ); }
+
+	/**
+	 * Magic method to prevent notices and errors from invalid method calls
+	 *
+	 * @since bbPress (r4252)
+	 */
+	public function __call( $name = '', $args = array() ) { unset( $name, $args ); return null; }
+
+	/** Private Methods *******************************************************/
+
+	/**
+	 * Set some smart defaults to class variables. Allow some of them to be
+	 * filtered to allow for early overriding.
+	 *
+	 * @since bbPress (r2626)
+	 * @access private
+	 * @uses plugin_dir_path() To generate bbPress plugin path
+	 * @uses plugin_dir_url() To generate bbPress plugin url
+	 * @uses apply_filters() Calls various filters
+	 */
+	private function setup_globals() {
+
+		/** Versions **********************************************************/
+
+		$this->version    = '2.5.4-5380';
+		$this->db_version = '250';
+
+		/** Paths *************************************************************/
+
+		// Setup some base path and URL information
+		$this->file       = __FILE__;
+		$this->basename   = apply_filters( 'bbp_plugin_basenname', plugin_basename( $this->file ) );
+		$this->plugin_dir = apply_filters( 'bbp_plugin_dir_path',  plugin_dir_path( $this->file ) );
+		$this->plugin_url = apply_filters( 'bbp_plugin_dir_url',   plugin_dir_url ( $this->file ) );
+
+		// Includes
+		$this->includes_dir = apply_filters( 'bbp_includes_dir', trailingslashit( $this->plugin_dir . 'includes'  ) );
+		$this->includes_url = apply_filters( 'bbp_includes_url', trailingslashit( $this->plugin_url . 'includes'  ) );
+
+		// Languages
+		$this->lang_dir     = apply_filters( 'bbp_lang_dir',     trailingslashit( $this->plugin_dir . 'languages' ) );
+
+		// Templates
+		$this->themes_dir   = apply_filters( 'bbp_themes_dir',   trailingslashit( $this->plugin_dir . 'templates' ) );
+		$this->themes_url   = apply_filters( 'bbp_themes_url',   trailingslashit( $this->plugin_url . 'templates' ) );
+
+		/** Identifiers *******************************************************/
+
+		// Post type identifiers
+		$this->forum_post_type   = apply_filters( 'bbp_forum_post_type',  'forum'     );
+		$this->topic_post_type   = apply_filters( 'bbp_topic_post_type',  'topic'     );
+		$this->reply_post_type   = apply_filters( 'bbp_reply_post_type',  'reply'     );
+		$this->topic_tag_tax_id  = apply_filters( 'bbp_topic_tag_tax_id', 'topic-tag' );
+
+		// Status identifiers
+		$this->spam_status_id    = apply_filters( 'bbp_spam_post_status',    'spam'    );
+		$this->closed_status_id  = apply_filters( 'bbp_closed_post_status',  'closed'  );
+		$this->orphan_status_id  = apply_filters( 'bbp_orphan_post_status',  'orphan'  );
+		$this->public_status_id  = apply_filters( 'bbp_public_post_status',  'publish' );
+		$this->pending_status_id = apply_filters( 'bbp_pending_post_status', 'pending' );
+		$this->private_status_id = apply_filters( 'bbp_private_post_status', 'private' );
+		$this->hidden_status_id  = apply_filters( 'bbp_hidden_post_status',  'hidden'  );
+		$this->trash_status_id   = apply_filters( 'bbp_trash_post_status',   'trash'   );
+
+		// Other identifiers
+		$this->user_id           = apply_filters( 'bbp_user_id',   'bbp_user'   );
+		$this->tops_id           = apply_filters( 'bbp_tops_id',   'bbp_tops'   );
+		$this->reps_id           = apply_filters( 'bbp_reps_id',   'bbp_reps'   );
+		$this->favs_id           = apply_filters( 'bbp_favs_id',   'bbp_favs'   );
+		$this->subs_id           = apply_filters( 'bbp_subs_id',   'bbp_subs'   );
+		$this->view_id           = apply_filters( 'bbp_view_id',   'bbp_view'   );
+		$this->edit_id           = apply_filters( 'bbp_edit_id',   'edit'       );
+		$this->paged_id          = apply_filters( 'bbp_paged_id',  'paged'      );
+		$this->search_id         = apply_filters( 'bbp_search_id', 'bbp_search' );
+
+		/** Queries ***********************************************************/
+
+		$this->current_view_id      = 0; // Current view id
+		$this->current_forum_id     = 0; // Current forum id
+		$this->current_topic_id     = 0; // Current topic id
+		$this->current_reply_id     = 0; // Current reply id
+		$this->current_topic_tag_id = 0; // Current topic tag id
+
+		$this->forum_query    = new WP_Query(); // Main forum query
+		$this->topic_query    = new WP_Query(); // Main topic query
+		$this->reply_query    = new WP_Query(); // Main reply query
+		$this->search_query   = new WP_Query(); // Main search query
+
+		/** Theme Compat ******************************************************/
+
+		$this->theme_compat   = new stdClass(); // Base theme compatibility class
+		$this->filters        = new stdClass(); // Used when adding/removing filters
+
+		/** Users *************************************************************/
+
+		$this->current_user   = new WP_User(); // Currently logged in user
+		$this->displayed_user = new WP_User(); // Currently displayed user
+
+		/** Misc **************************************************************/
+
+		$this->domain         = 'bbpress';      // Unique identifier for retrieving translated strings
+		$this->extend         = new stdClass(); // Plugins add data here
+		$this->errors         = new WP_Error(); // Feedback
+		$this->tab_index      = apply_filters( 'bbp_default_tab_index', 100 );
+	}
+
+	/**
+	 * Include required files
+	 *
+	 * @since bbPress (r2626)
+	 * @access private
+	 * @uses is_admin() If in WordPress admin, load additional file
+	 */
+	private function includes() {
+
+		/** Core **************************************************************/
+
+		require( $this->includes_dir . 'core/sub-actions.php'        );
+		require( $this->includes_dir . 'core/functions.php'          );
+		require( $this->includes_dir . 'core/cache.php'              );
+		require( $this->includes_dir . 'core/options.php'            );
+		require( $this->includes_dir . 'core/capabilities.php'       );
+		require( $this->includes_dir . 'core/update.php'             );
+		require( $this->includes_dir . 'core/template-functions.php' );
+		require( $this->includes_dir . 'core/template-loader.php'    );
+		require( $this->includes_dir . 'core/theme-compat.php'       );
+
+		/** Components ********************************************************/
+
+		// Common
+		require( $this->includes_dir . 'common/ajax.php'          );
+		require( $this->includes_dir . 'common/classes.php'       );
+		require( $this->includes_dir . 'common/functions.php'     );
+		require( $this->includes_dir . 'common/formatting.php'    );
+		require( $this->includes_dir . 'common/template.php'      );
+		require( $this->includes_dir . 'common/widgets.php'       );
+		require( $this->includes_dir . 'common/shortcodes.php'    );
+
+		// Forums
+		require( $this->includes_dir . 'forums/capabilities.php'  );
+		require( $this->includes_dir . 'forums/functions.php'     );
+		require( $this->includes_dir . 'forums/template.php'      );
+
+		// Topics
+		require( $this->includes_dir . 'topics/capabilities.php'  );
+		require( $this->includes_dir . 'topics/functions.php'     );
+		require( $this->includes_dir . 'topics/template.php'      );
+
+		// Replies
+		require( $this->includes_dir . 'replies/capabilities.php' );
+		require( $this->includes_dir . 'replies/functions.php'    );
+		require( $this->includes_dir . 'replies/template.php'     );
+
+		// Search
+		require( $this->includes_dir . 'search/functions.php'     );
+		require( $this->includes_dir . 'search/template.php'      );
+
+		// Users
+		require( $this->includes_dir . 'users/capabilities.php'   );
+		require( $this->includes_dir . 'users/functions.php'      );
+		require( $this->includes_dir . 'users/template.php'       );
+		require( $this->includes_dir . 'users/options.php'        );
+
+		/** Hooks *************************************************************/
+
+		require( $this->includes_dir . 'core/extend.php'  );
+		require( $this->includes_dir . 'core/actions.php' );
+		require( $this->includes_dir . 'core/filters.php' );
+
+		/** Admin *************************************************************/
+
+		// Quick admin check and load if needed
+		if ( is_admin() ) {
+			require( $this->includes_dir . 'admin/admin.php'   );
+			require( $this->includes_dir . 'admin/actions.php' );
+		}
+	}
+
+	/**
+	 * Setup the default hooks and actions
+	 *
+	 * @since bbPress (r2644)
+	 * @access private
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_actions() {
+
+		// Add actions to plugin activation and deactivation hooks
+		add_action( 'activate_'   . $this->basename, 'bbp_activation'   );
+		add_action( 'deactivate_' . $this->basename, 'bbp_deactivation' );
+
+		// If bbPress is being deactivated, do not add any actions
+		if ( bbp_is_deactivation( $this->basename ) )
+			return;
+
+		// Array of bbPress core actions
+		$actions = array(
+			'setup_theme',              // Setup the default theme compat
+			'setup_current_user',       // Setup currently logged in user
+			'register_post_types',      // Register post types (forum|topic|reply)
+			'register_post_statuses',   // Register post statuses (closed|spam|orphan|hidden)
+			'register_taxonomies',      // Register taxonomies (topic-tag)
+			'register_shortcodes',      // Register shortcodes (bbp-login)
+			'register_views',           // Register the views (no-replies)
+			'register_theme_packages',  // Register bundled theme packages (bbp-theme-compat/bbp-themes)
+			'load_textdomain',          // Load textdomain (bbpress)
+			'add_rewrite_tags',         // Add rewrite tags (view|user|edit|search)
+			'add_rewrite_rules',        // Generate rewrite rules (view|edit|paged|search)
+			'add_permastructs'          // Add permalink structures (view|user|search)
+		);
+
+		// Add the actions
+		foreach ( $actions as $class_action )
+			add_action( 'bbp_' . $class_action, array( $this, $class_action ), 5 );
+
+		// All bbPress actions are setup (includes bbp-core-hooks.php)
+		do_action_ref_array( 'bbp_after_setup_actions', array( &$this ) );
+	}
+
+	/** Public Methods ********************************************************/
+
+	/**
+	 * Register bundled theme packages
+	 *
+	 * Note that since we currently have complete control over bbp-themes and
+	 * the bbp-theme-compat folders, it's fine to hardcode these here. If at a
+	 * later date we need to automate this, and API will need to be built.
+	 *
+	 * @since bbPress (r3829)
+	 */
+	public function register_theme_packages() {
+
+		// Register the default theme compatibility package
+		bbp_register_theme_package( array(
+			'id'      => 'default',
+			'name'    => __( 'bbPress Default', 'bbpress' ),
+			'version' => bbp_get_version(),
+			'dir'     => trailingslashit( $this->themes_dir . 'default' ),
+			'url'     => trailingslashit( $this->themes_url . 'default' )
+		) );
+
+		// Register the basic theme stack. This is really dope.
+		bbp_register_template_stack( 'get_stylesheet_directory', 10 );
+		bbp_register_template_stack( 'get_template_directory',   12 );
+		bbp_register_template_stack( 'bbp_get_theme_compat_dir', 14 );
+	}
+
+	/**
+	 * Setup the default bbPress theme compatibility location.
+	 *
+	 * @since bbPress (r3778)
+	 */
+	public function setup_theme() {
+
+		// Bail if something already has this under control
+		if ( ! empty( $this->theme_compat->theme ) )
+			return;
+
+		// Setup the theme package to use for compatibility
+		bbp_setup_theme_compat( bbp_get_theme_package_id() );
+	}
+
+	/**
+	 * Load the translation file for current language. Checks the languages
+	 * folder inside the bbPress plugin first, and then the default WordPress
+	 * languages folder.
+	 *
+	 * Note that custom translation files inside the bbPress plugin folder
+	 * will be removed on bbPress updates. If you're creating custom
+	 * translation files, please use the global language folder.
+	 *
+	 * @since bbPress (r2596)
+	 *
+	 * @uses apply_filters() Calls 'plugin_locale' with {@link get_locale()} value
+	 * @uses load_textdomain() To load the textdomain
+	 */
+	public function load_textdomain() {
+
+		// Traditional WordPress plugin locale filter
+		$locale        = apply_filters( 'plugin_locale', get_locale(), $this->domain );
+		$mofile        = sprintf( '%1$s-%2$s.mo', $this->domain, $locale );
+
+		// Setup paths to current locale file
+		$mofile_local  = $this->lang_dir . $mofile;
+		$mofile_global = WP_LANG_DIR . '/bbpress/' . $mofile;
+
+		// Look in global /wp-content/languages/bbpress folder
+		load_textdomain( $this->domain, $mofile_global );
+
+		// Look in local /wp-content/plugins/bbpress/bbp-languages/ folder
+		load_textdomain( $this->domain, $mofile_local );
+
+		// Look in global /wp-content/languages/plugins/
+		load_plugin_textdomain( $this->domain );
+	}
+
+	/**
+	 * Setup the post types for forums, topics and replies
+	 *
+	 * @since bbPress (r2597)
+	 * @uses register_post_type() To register the post types
+	 * @uses apply_filters() Calls various filters to modify the arguments
+	 *                        sent to register_post_type()
+	 */
+	public static function register_post_types() {
+
+		/** Forums ************************************************************/
+
+		// Register Forum content type
+		register_post_type(
+			bbp_get_forum_post_type(),
+			apply_filters( 'bbp_register_forum_post_type', array(
+				'labels'              => bbp_get_forum_post_type_labels(),
+				'rewrite'             => bbp_get_forum_post_type_rewrite(),
+				'supports'            => bbp_get_forum_post_type_supports(),
+				'description'         => __( 'bbPress Forums', 'bbpress' ),
+				'capabilities'        => bbp_get_forum_caps(),
+				'capability_type'     => array( 'forum', 'forums' ),
+				'menu_position'       => 555555,
+				'has_archive'         => bbp_get_root_slug(),
+				'exclude_from_search' => true,
+				'show_in_nav_menus'   => true,
+				'public'              => true,
+				'show_ui'             => current_user_can( 'bbp_forums_admin' ),
+				'can_export'          => true,
+				'hierarchical'        => true,
+				'query_var'           => true,
+				'menu_icon'           => ''
+			) )
+		);
+
+		/** Topics ************************************************************/
+
+		// Register Topic content type
+		register_post_type(
+			bbp_get_topic_post_type(),
+			apply_filters( 'bbp_register_topic_post_type', array(
+				'labels'              => bbp_get_topic_post_type_labels(),
+				'rewrite'             => bbp_get_topic_post_type_rewrite(),
+				'supports'            => bbp_get_topic_post_type_supports(),
+				'description'         => __( 'bbPress Topics', 'bbpress' ),
+				'capabilities'        => bbp_get_topic_caps(),
+				'capability_type'     => array( 'topic', 'topics' ),
+				'menu_position'       => 555555,
+				'has_archive'         => ( 'forums' === bbp_show_on_root() ) ? bbp_get_topic_archive_slug() : false,
+				'exclude_from_search' => true,
+				'show_in_nav_menus'   => false,
+				'public'              => true,
+				'show_ui'             => current_user_can( 'bbp_topics_admin' ),
+				'can_export'          => true,
+				'hierarchical'        => false,
+				'query_var'           => true,
+				'menu_icon'           => ''
+			)
+		) );
+
+		/** Replies ***********************************************************/
+
+		// Register reply content type
+		register_post_type(
+			bbp_get_reply_post_type(),
+			apply_filters( 'bbp_register_reply_post_type', array(
+				'labels'              => bbp_get_reply_post_type_labels(),
+				'rewrite'             => bbp_get_reply_post_type_rewrite(),
+				'supports'            => bbp_get_reply_post_type_supports(),
+				'description'         => __( 'bbPress Replies', 'bbpress' ),
+				'capabilities'        => bbp_get_reply_caps(),
+				'capability_type'     => array( 'reply', 'replies' ),
+				'menu_position'       => 555555,
+				'exclude_from_search' => true,
+				'has_archive'         => false,
+				'show_in_nav_menus'   => false,
+				'public'              => true,
+				'show_ui'             => current_user_can( 'bbp_replies_admin' ),
+				'can_export'          => true,
+				'hierarchical'        => false,
+				'query_var'           => true,
+				'menu_icon'           => ''
+			) )
+		);
+	}
+
+	/**
+	 * Register the post statuses used by bbPress
+	 *
+	 * We do some manipulation of the 'trash' status so trashed topics and
+	 * replies can be viewed from within the theme.
+	 *
+	 * @since bbPress (r2727)
+	 * @uses register_post_status() To register post statuses
+	 * @uses $wp_post_statuses To modify trash and private statuses
+	 * @uses current_user_can() To check if the current user is capable &
+	 *                           modify $wp_post_statuses accordingly
+	 */
+	public static function register_post_statuses() {
+
+		// Closed
+		register_post_status(
+			bbp_get_closed_status_id(),
+			apply_filters( 'bbp_register_closed_post_status', array(
+				'label'             => _x( 'Closed', 'post', 'bbpress' ),
+				'label_count'       => _nx_noop( 'Closed <span class="count">(%s)</span>', 'Closed <span class="count">(%s)</span>', 'post', 'bbpress' ),
+				'public'            => true,
+				'show_in_admin_all' => true
+			) )
+		);
+
+		// Spam
+		register_post_status(
+			bbp_get_spam_status_id(),
+			apply_filters( 'bbp_register_spam_post_status', array(
+				'label'                     => _x( 'Spam', 'post', 'bbpress' ),
+				'label_count'               => _nx_noop( 'Spam <span class="count">(%s)</span>', 'Spam <span class="count">(%s)</span>', 'post', 'bbpress' ),
+				'protected'                 => true,
+				'exclude_from_search'       => true,
+				'show_in_admin_status_list' => true,
+				'show_in_admin_all_list'    => false
+			) )
+		 );
+
+		// Orphan
+		register_post_status(
+			bbp_get_orphan_status_id(),
+			apply_filters( 'bbp_register_orphan_post_status', array(
+				'label'                     => _x( 'Orphan', 'post', 'bbpress' ),
+				'label_count'               => _nx_noop( 'Orphan <span class="count">(%s)</span>', 'Orphans <span class="count">(%s)</span>', 'post', 'bbpress' ),
+				'protected'                 => true,
+				'exclude_from_search'       => true,
+				'show_in_admin_status_list' => true,
+				'show_in_admin_all_list'    => false
+			) )
+		);
+
+		// Hidden
+		register_post_status(
+			bbp_get_hidden_status_id(),
+			apply_filters( 'bbp_register_hidden_post_status', array(
+				'label'                     => _x( 'Hidden', 'post', 'bbpress' ),
+				'label_count'               => _nx_noop( 'Hidden <span class="count">(%s)</span>', 'Hidden <span class="count">(%s)</span>', 'post', 'bbpress' ),
+				'private'                   => true,
+				'exclude_from_search'       => true,
+				'show_in_admin_status_list' => true,
+				'show_in_admin_all_list'    => true
+			) )
+		);
+
+		/**
+		 * Trash fix
+		 *
+		 * We need to remove the internal arg and change that to
+		 * protected so that the users with 'view_trash' cap can view
+		 * single trashed topics/replies in the front-end as wp_query
+		 * doesn't allow any hack for the trashed topics to be viewed.
+		 */
+		global $wp_post_statuses;
+
+		if ( !empty( $wp_post_statuses['trash'] ) ) {
+
+			// User can view trash so set internal to false
+			if ( current_user_can( 'view_trash' ) ) {
+				$wp_post_statuses['trash']->internal  = false;
+				$wp_post_statuses['trash']->protected = true;
+
+			// User cannot view trash so set internal to true
+			} else {
+				$wp_post_statuses['trash']->internal = true;
+			}
+		}
+	}
+
+	/**
+	 * Register the topic tag taxonomy
+	 *
+	 * @since bbPress (r2464)
+	 * @uses register_taxonomy() To register the taxonomy
+	 */
+	public static function register_taxonomies() {
+
+		// Register the topic-tag taxonomy
+		register_taxonomy(
+			bbp_get_topic_tag_tax_id(),
+			bbp_get_topic_post_type(),
+			apply_filters( 'bbp_register_topic_taxonomy', array(
+				'labels'                => bbp_get_topic_tag_tax_labels(),
+				'rewrite'               => bbp_get_topic_tag_tax_rewrite(),
+				'capabilities'          => bbp_get_topic_tag_caps(),
+				'update_count_callback' => '_update_post_term_count',
+				'query_var'             => true,
+				'show_tagcloud'         => true,
+				'hierarchical'          => false,
+				'show_in_nav_menus'     => false,
+				'public'                => true,
+				'show_ui'               => bbp_allow_topic_tags() && current_user_can( 'bbp_topic_tags_admin' )
+			)
+		) );
+	}
+
+	/**
+	 * Register the bbPress views
+	 *
+	 * @since bbPress (r2789)
+	 * @uses bbp_register_view() To register the views
+	 */
+	public static function register_views() {
+
+		// Popular topics
+		bbp_register_view(
+			'popular',
+			__( 'Most popular topics', 'bbpress' ),
+			apply_filters( 'bbp_register_view_popular', array(
+				'meta_key'      => '_bbp_reply_count',
+				'max_num_pages' => 1,
+				'orderby'       => 'meta_value_num',
+				'show_stickies' => false
+			)
+		) );
+
+		// Topics with no replies
+		bbp_register_view(
+			'no-replies',
+			__( 'Topics with no replies', 'bbpress' ),
+			apply_filters( 'bbp_register_view_no_replies', array(
+				'meta_key'      => '_bbp_reply_count',
+				'meta_value'    => 1,
+				'meta_compare'  => '<',
+				'orderby'       => '',
+				'show_stickies' => false
+			)
+		) );
+	}
+
+	/**
+	 * Register the bbPress shortcodes
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @uses BBP_Shortcodes
+	 */
+	public function register_shortcodes() {
+		$this->shortcodes = new BBP_Shortcodes();
+	}
+
+	/**
+	 * Setup the currently logged-in user
+	 *
+	 * Do not to call this prematurely, I.E. before the 'init' action has
+	 * started. This function is naturally hooked into 'init' to ensure proper
+	 * execution. get_currentuserinfo() is used to check for XMLRPC_REQUEST to
+	 * avoid xmlrpc errors.
+	 *
+	 * @since bbPress (r2697)
+	 * @uses wp_get_current_user()
+	 */
+	public function setup_current_user() {
+		$this->current_user = wp_get_current_user();
+	}
+
+	/** Custom Rewrite Rules **************************************************/
+
+	/**
+	 * Add the bbPress-specific rewrite tags
+	 *
+	 * @since bbPress (r2753)
+	 * @uses add_rewrite_tag() To add the rewrite tags
+	 */
+	public static function add_rewrite_tags() {
+		add_rewrite_tag( '%' . bbp_get_view_rewrite_id()               . '%', '([^/]+)'   ); // View Page tag
+		add_rewrite_tag( '%' . bbp_get_edit_rewrite_id()               . '%', '([1]{1,})' ); // Edit Page tag
+		add_rewrite_tag( '%' . bbp_get_search_rewrite_id()             . '%', '([^/]+)'   ); // Search Results tag
+		add_rewrite_tag( '%' . bbp_get_user_rewrite_id()               . '%', '([^/]+)'   ); // User Profile tag
+		add_rewrite_tag( '%' . bbp_get_user_favorites_rewrite_id()     . '%', '([1]{1,})' ); // User Favorites tag
+		add_rewrite_tag( '%' . bbp_get_user_subscriptions_rewrite_id() . '%', '([1]{1,})' ); // User Subscriptions tag
+		add_rewrite_tag( '%' . bbp_get_user_topics_rewrite_id()        . '%', '([1]{1,})' ); // User Topics Tag
+		add_rewrite_tag( '%' . bbp_get_user_replies_rewrite_id()       . '%', '([1]{1,})' ); // User Replies Tag
+	}
+
+	/**
+	 * Add bbPress-specific rewrite rules for uri's that are not
+	 * setup for us by way of custom post types or taxonomies. This includes:
+	 * - Front-end editing
+	 * - Topic views
+	 * - User profiles
+	 *
+	 * @since bbPress (r2688)
+	 * @todo Extract into an API
+	 */
+	public static function add_rewrite_rules() {
+
+		/** Setup *************************************************************/
+
+		// Add rules to top or bottom?
+		$priority           = 'top';
+
+		// Single Slugs
+		$forum_slug         = bbp_get_forum_slug();
+		$topic_slug         = bbp_get_topic_slug();
+		$reply_slug         = bbp_get_reply_slug();
+		$ttag_slug          = bbp_get_topic_tag_tax_slug();
+
+		// Archive Slugs
+		$user_slug          = bbp_get_user_slug();
+		$view_slug          = bbp_get_view_slug();
+		$search_slug        = bbp_get_search_slug();
+		$topic_archive_slug = bbp_get_topic_archive_slug();
+		$reply_archive_slug = bbp_get_reply_archive_slug();
+
+		// Tertiary Slugs
+		$feed_slug          = 'feed';
+		$edit_slug          = 'edit';
+		$paged_slug         = bbp_get_paged_slug();
+		$user_favs_slug     = bbp_get_user_favorites_slug();
+		$user_subs_slug     = bbp_get_user_subscriptions_slug();
+
+		// Unique rewrite ID's
+		$feed_id            = 'feed';
+		$edit_id            = bbp_get_edit_rewrite_id();
+		$view_id            = bbp_get_view_rewrite_id();
+		$paged_id           = bbp_get_paged_rewrite_id();
+		$search_id          = bbp_get_search_rewrite_id();
+		$user_id            = bbp_get_user_rewrite_id();
+		$user_favs_id       = bbp_get_user_favorites_rewrite_id();
+		$user_subs_id       = bbp_get_user_subscriptions_rewrite_id();
+		$user_tops_id       = bbp_get_user_topics_rewrite_id();
+		$user_reps_id       = bbp_get_user_replies_rewrite_id();
+
+		// Rewrite rule matches used repeatedly below
+		$root_rule    = '/([^/]+)/?$';
+		$feed_rule    = '/([^/]+)/' . $feed_slug  . '/?$';
+		$edit_rule    = '/([^/]+)/' . $edit_slug  . '/?$';
+		$paged_rule   = '/([^/]+)/' . $paged_slug . '/?([0-9]{1,})/?$';
+
+		// Search rules (without slug check)
+		$search_root_rule  = '/?$';
+		$search_paged_rule = '/' . $paged_slug . '/?([0-9]{1,})/?$';
+
+		/** Add ***************************************************************/
+
+		// User profile rules
+		$tops_rule       = '/([^/]+)/' . $topic_archive_slug . '/?$';
+		$reps_rule       = '/([^/]+)/' . $reply_archive_slug . '/?$';
+		$favs_rule       = '/([^/]+)/' . $user_favs_slug     . '/?$';
+		$subs_rule       = '/([^/]+)/' . $user_subs_slug     . '/?$';
+		$tops_paged_rule = '/([^/]+)/' . $topic_archive_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
+		$reps_paged_rule = '/([^/]+)/' . $reply_archive_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
+		$favs_paged_rule = '/([^/]+)/' . $user_favs_slug     . '/' . $paged_slug . '/?([0-9]{1,})/?$';
+		$subs_paged_rule = '/([^/]+)/' . $user_subs_slug     . '/' . $paged_slug . '/?([0-9]{1,})/?$';
+
+		// Edit Forum|Topic|Reply|Topic-tag
+		add_rewrite_rule( $forum_slug . $edit_rule, 'index.php?' . bbp_get_forum_post_type()  . '=$matches[1]&' . $edit_id . '=1', $priority );
+		add_rewrite_rule( $topic_slug . $edit_rule, 'index.php?' . bbp_get_topic_post_type()  . '=$matches[1]&' . $edit_id . '=1', $priority );
+		add_rewrite_rule( $reply_slug . $edit_rule, 'index.php?' . bbp_get_reply_post_type()  . '=$matches[1]&' . $edit_id . '=1', $priority );
+		add_rewrite_rule( $ttag_slug  . $edit_rule, 'index.php?' . bbp_get_topic_tag_tax_id() . '=$matches[1]&' . $edit_id . '=1', $priority );
+
+		// User Pagination|Edit|View
+		add_rewrite_rule( $user_slug . $tops_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_tops_id . '=1&' . $paged_id . '=$matches[2]', $priority );
+		add_rewrite_rule( $user_slug . $reps_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_reps_id . '=1&' . $paged_id . '=$matches[2]', $priority );
+		add_rewrite_rule( $user_slug . $favs_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_favs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
+		add_rewrite_rule( $user_slug . $subs_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_subs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
+		add_rewrite_rule( $user_slug . $tops_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_tops_id . '=1',                               $priority );
+		add_rewrite_rule( $user_slug . $reps_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_reps_id . '=1',                               $priority );
+		add_rewrite_rule( $user_slug . $favs_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_favs_id . '=1',                               $priority );
+		add_rewrite_rule( $user_slug . $subs_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_subs_id . '=1',                               $priority );
+		add_rewrite_rule( $user_slug . $edit_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $edit_id      . '=1',                               $priority );
+		add_rewrite_rule( $user_slug . $root_rule,       'index.php?' . $user_id  . '=$matches[1]',                                                       $priority );
+
+		// Topic-View Pagination|Feed|View
+		add_rewrite_rule( $view_slug . $paged_rule, 'index.php?' . $view_id . '=$matches[1]&' . $paged_id . '=$matches[2]', $priority );
+		add_rewrite_rule( $view_slug . $feed_rule,  'index.php?' . $view_id . '=$matches[1]&' . $feed_id  . '=$matches[2]', $priority );
+		add_rewrite_rule( $view_slug . $root_rule,  'index.php?' . $view_id . '=$matches[1]',                               $priority );
+
+		// Search All
+		add_rewrite_rule( $search_slug . $search_paged_rule, 'index.php?' . $paged_id .'=$matches[1]', $priority );
+		add_rewrite_rule( $search_slug . $search_root_rule,  'index.php?' . $search_id,                $priority );
+	}
+
+	/**
+	 * Add permalink structures for new archive-style destinations.
+	 *
+	 * - Users
+	 * - Topic Views
+	 * - Search
+	 *
+	 * @since bbPress (r4930)
+	 */
+	public static function add_permastructs() {
+
+		// Get unique ID's
+		$user_id     = bbp_get_user_rewrite_id();
+		$view_id     = bbp_get_view_rewrite_id();
+		$search_id   = bbp_get_search_rewrite_id();
+
+		// Get root slugs
+		$user_slug   = bbp_get_user_slug();
+		$view_slug   = bbp_get_view_slug();
+		$search_slug = bbp_get_search_slug();
+
+		// User Permastruct
+		add_permastruct( $user_id, $user_slug . '/%' . $user_id . '%', array(
+			'with_front'  => false,
+			'ep_mask'     => EP_NONE,
+			'paged'       => false,
+			'feed'        => false,
+			'forcomments' => false,
+			'walk_dirs'   => true,
+			'endpoints'   => false,
+		) );
+
+		// Topic View Permastruct
+		add_permastruct( $view_id, $view_slug . '/%' . $view_id . '%', array(
+			'with_front'  => false,
+			'ep_mask'     => EP_NONE,
+			'paged'       => false,
+			'feed'        => false,
+			'forcomments' => false,
+			'walk_dirs'   => true,
+			'endpoints'   => false,
+		) );
+
+		// Search Permastruct
+		add_permastruct( $user_id, $search_slug . '/%' . $search_id . '%', array(
+			'with_front'  => false,
+			'ep_mask'     => EP_NONE,
+			'paged'       => true,
+			'feed'        => false,
+			'forcomments' => false,
+			'walk_dirs'   => true,
+			'endpoints'   => false,
+		) );
+	}
+}
+
+/**
+ * The main function responsible for returning the one true bbPress Instance
+ * to functions everywhere.
+ *
+ * Use this function like you would a global variable, except without needing
+ * to declare the global.
+ *
+ * Example: <?php $bbp = bbpress(); ?>
+ *
+ * @return The one true bbPress Instance
+ */
+function bbpress() {
+	return bbpress::instance();
+}
+
+/**
+ * Hook bbPress early onto the 'plugins_loaded' action.
+ *
+ * This gives all other plugins the chance to load before bbPress, to get their
+ * actions, filters, and overrides setup without bbPress being in the way.
+ */
+if ( defined( 'BBPRESS_LATE_LOAD' ) ) {
+	add_action( 'plugins_loaded', 'bbpress', (int) BBPRESS_LATE_LOAD );
+
+// "And now here's something we hope you'll really like!"
+} else {
+	bbpress();
+}
+
+endif; // class_exists check
Index: /tags/2.5.4/humans.txt
===================================================================
--- /tags/2.5.4/humans.txt	(revision 5382)
+++ /tags/2.5.4/humans.txt	(revision 5382)
@@ -0,0 +1,54 @@
+                ..=OO$,
+            ~OO=. . . . .Z88
+        .78..  .,OOOOOOO    .7O
+       IO.  7OOOOOOOOOOOOOOO.   8..
+      O. .OOOOOOOOOOOOOOOOOOOOO   O.
+    7O  OOOOOOOOOOOOOOOOOOOOOOOO8  O.
+   ,O.      OOOOOOO..     OOOOOOOO. O,
+  IO  OO    OOOOOOOOO.   OOOOOOOOOO..O
+ .O .8OO    OOOOOOOOO.   OOOOOOOOOOO  O
+ O  OOOO   8OOOOOOOOO.   OOOOOOOOOOOZ ,O
+ O .OOO.  .OOOOOOOOOO   OOOOOOOOOOOOO .8
+.Z 7OOO   .OOOOOOOOO   .OOOOOOOOOOOOO  8.
+.O OOOO.  OOO~..ZOOO.  .OOO. +OOOOOOO: O.
+.O OOO.     .OI.  .$   Z..7O.  .OOOOO~ O.
+.Z $OO   .ZOOOOOO     ..OOOOOO   OOOO  O.
+ O  O7   OOOOOOOO     .OOOOOOO   IOOO  O
+ O  8   .OOOOOOOO     OOOOOOOO   OOOZ .O
+  8     .OOOOOOOO     OOOOOOOO   OOO .O.
+  ?O    OOOOOOOO      OOOOOOO.  .OO..O.
+   O+   OOOOOOO      +OOOOOO? ..OO  O,
+    78   OOOOI .,O8   OOOO8. .OO8 .O
+      O.  . . OOOOOO7..  ..OOOO  .8
+      .?O  .7OOOOOOOOOOOOOOO.. .8.
+         78    .,OOOOOOO.    7O..
+            :OO+.       .ZO8.
+                ..=OO$,
+
+    We are the humans behind bbPress
+
+/* TEAM */
+Name: Matt Mullenweg
+Title: Founding Developer
+Twitter: photomatt
+Favorite Food: BBQ
+
+Name: John James Jacoby
+Title: Lead Developer
+Twitter: jjj
+Favorite Food: Truffle Lasagna
+
+Name: Jennifer M. Dodd
+Title: Core Contributor
+Twitter: jmdodd
+
+Name: Stephen Edgar
+Title: Core Contributor
+Twitter: netweb
+
+/* THANKS */
+Mike Adams, Gautam Gupta, Ben L, Justin Tadlock, cnorris23, anointed, andy, nacin
+
+/* META */
+Updated: 2013/11/25
+See: http://humanstxt.org/
Index: /tags/2.5.4/includes/admin/actions.php
===================================================================
--- /tags/2.5.4/includes/admin/actions.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/actions.php	(revision 5382)
@@ -0,0 +1,185 @@
+<?php
+
+/**
+ * bbPress Admin Actions
+ *
+ * @package bbPress
+ * @subpackage Admin
+ *
+ * This file contains the actions that are used through-out bbPress Admin. They
+ * are consolidated here to make searching for them easier, and to help developers
+ * understand at a glance the order in which things occur.
+ *
+ * There are a few common places that additional actions can currently be found
+ *
+ *  - bbPress: In {@link bbPress::setup_actions()} in bbpress.php
+ *  - Admin: More in {@link BBP_Admin::setup_actions()} in admin.php
+ *
+ * @see bbp-core-actions.php
+ * @see bbp-core-filters.php
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Attach bbPress to WordPress
+ *
+ * bbPress uses its own internal actions to help aid in third-party plugin
+ * development, and to limit the amount of potential future code changes when
+ * updates to WordPress core occur.
+ *
+ * These actions exist to create the concept of 'plugin dependencies'. They
+ * provide a safe way for plugins to execute code *only* when bbPress is
+ * installed and activated, without needing to do complicated guesswork.
+ *
+ * For more information on how this works, see the 'Plugin Dependency' section
+ * near the bottom of this file.
+ *
+ *           v--WordPress Actions       v--bbPress Sub-actions
+ */
+add_action( 'admin_menu',              'bbp_admin_menu'                    );
+add_action( 'admin_init',              'bbp_admin_init'                    );
+add_action( 'admin_head',              'bbp_admin_head'                    );
+add_action( 'admin_notices',           'bbp_admin_notices'                 );
+add_action( 'custom_menu_order',       'bbp_admin_custom_menu_order'       );
+add_action( 'menu_order',              'bbp_admin_menu_order'              );
+add_action( 'wpmu_new_blog',           'bbp_new_site',               10, 6 );
+
+// Hook on to admin_init
+add_action( 'bbp_admin_init', 'bbp_admin_forums'                );
+add_action( 'bbp_admin_init', 'bbp_admin_topics'                );
+add_action( 'bbp_admin_init', 'bbp_admin_replies'               );
+add_action( 'bbp_admin_init', 'bbp_setup_updater',          999 );
+add_action( 'bbp_admin_init', 'bbp_register_importers'          );
+add_action( 'bbp_admin_init', 'bbp_register_admin_style'        );
+add_action( 'bbp_admin_init', 'bbp_register_admin_settings'     );
+add_action( 'bbp_admin_init', 'bbp_do_activation_redirect', 1   );
+
+// Initialize the admin area
+add_action( 'bbp_init', 'bbp_admin' );
+
+// Reset the menu order
+add_action( 'bbp_admin_menu', 'bbp_admin_separator' );
+
+// Activation
+add_action( 'bbp_activation', 'bbp_delete_rewrite_rules'        );
+add_action( 'bbp_activation', 'bbp_make_current_user_keymaster' );
+
+// Deactivation
+add_action( 'bbp_deactivation', 'bbp_remove_caps'          );
+add_action( 'bbp_deactivation', 'bbp_delete_rewrite_rules' );
+
+// New Site
+add_action( 'bbp_new_site', 'bbp_create_initial_content', 8 );
+
+// Contextual Helpers
+add_action( 'load-settings_page_bbpress', 'bbp_admin_settings_help' );
+
+// Handle submission of Tools pages
+add_action( 'load-tools_page_bbp-repair', 'bbp_admin_repair_handler' );
+add_action( 'load-tools_page_bbp-reset',  'bbp_admin_reset_handler'  );
+
+// Add sample permalink filter
+add_filter( 'post_type_link', 'bbp_filter_sample_permalink', 10, 4 );
+
+/**
+ * When a new site is created in a multisite installation, run the activation
+ * routine on that site
+ *
+ * @since bbPress (r3283)
+ *
+ * @param int $blog_id
+ * @param int $user_id
+ * @param string $domain
+ * @param string $path
+ * @param int $site_id
+ * @param array() $meta
+ */
+function bbp_new_site( $blog_id, $user_id, $domain, $path, $site_id, $meta ) {
+
+	// Bail if plugin is not network activated
+	if ( ! is_plugin_active_for_network( bbpress()->basename ) )
+		return;
+
+	// Switch to the new blog
+	switch_to_blog( $blog_id );
+
+	// Do the bbPress activation routine
+	do_action( 'bbp_new_site', $blog_id, $user_id, $domain, $path, $site_id, $meta );
+
+	// restore original blog
+	restore_current_blog();
+}
+
+/** Sub-Actions ***************************************************************/
+
+/**
+ * Piggy back admin_init action
+ *
+ * @since bbPress (r3766)
+ * @uses do_action() Calls 'bbp_admin_init'
+ */
+function bbp_admin_init() {
+	do_action( 'bbp_admin_init' );
+}
+
+/**
+ * Piggy back admin_menu action
+ *
+ * @since bbPress (r3766)
+ * @uses do_action() Calls 'bbp_admin_menu'
+ */
+function bbp_admin_menu() {
+	do_action( 'bbp_admin_menu' );
+}
+
+/**
+ * Piggy back admin_head action
+ *
+ * @since bbPress (r3766)
+ * @uses do_action() Calls 'bbp_admin_head'
+ */
+function bbp_admin_head() {
+	do_action( 'bbp_admin_head' );
+}
+
+/**
+ * Piggy back admin_notices action
+ *
+ * @since bbPress (r3766)
+ * @uses do_action() Calls 'bbp_admin_notices'
+ */
+function bbp_admin_notices() {
+	do_action( 'bbp_admin_notices' );
+}
+
+/**
+ * Dedicated action to register bbPress importers
+ *
+ * @since bbPress (r3766)
+ * @uses do_action() Calls 'bbp_admin_notices'
+ */
+function bbp_register_importers() {
+	do_action( 'bbp_register_importers' );
+}
+
+/**
+ * Dedicated action to register admin styles
+ *
+ * @since bbPress (r3766)
+ * @uses do_action() Calls 'bbp_admin_notices'
+ */
+function bbp_register_admin_style() {
+	do_action( 'bbp_register_admin_style' );
+}
+
+/**
+ * Dedicated action to register admin settings
+ *
+ * @since bbPress (r3766)
+ * @uses do_action() Calls 'bbp_register_admin_settings'
+ */
+function bbp_register_admin_settings() {
+	do_action( 'bbp_register_admin_settings' );
+}
Index: /tags/2.5.4/includes/admin/admin.php
===================================================================
--- /tags/2.5.4/includes/admin/admin.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/admin.php	(revision 5382)
@@ -0,0 +1,1095 @@
+<?php
+
+/**
+ * Main bbPress Admin Class
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Admin' ) ) :
+/**
+ * Loads bbPress plugin admin area
+ *
+ * @package bbPress
+ * @subpackage Administration
+ * @since bbPress (r2464)
+ */
+class BBP_Admin {
+
+	/** Directory *************************************************************/
+
+	/**
+	 * @var string Path to the bbPress admin directory
+	 */
+	public $admin_dir = '';
+
+	/** URLs ******************************************************************/
+
+	/**
+	 * @var string URL to the bbPress admin directory
+	 */
+	public $admin_url = '';
+
+	/**
+	 * @var string URL to the bbPress images directory
+	 */
+	public $images_url = '';
+
+	/**
+	 * @var string URL to the bbPress admin styles directory
+	 */
+	public $styles_url = '';
+
+	/**
+	 * @var string URL to the bbPress admin css directory
+	 */
+	public $css_url = '';
+
+	/**
+	 * @var string URL to the bbPress admin js directory
+	 */
+	public $js_url = '';
+
+	/** Capability ************************************************************/
+
+	/**
+	 * @var bool Minimum capability to access Tools and Settings
+	 */
+	public $minimum_capability = 'keep_gate';
+
+	/** Separator *************************************************************/
+
+	/**
+	 * @var bool Whether or not to add an extra top level menu separator
+	 */
+	public $show_separator = false;
+
+	/** Functions *************************************************************/
+
+	/**
+	 * The main bbPress admin loader
+	 *
+	 * @since bbPress (r2515)
+	 *
+	 * @uses BBP_Admin::setup_globals() Setup the globals needed
+	 * @uses BBP_Admin::includes() Include the required files
+	 * @uses BBP_Admin::setup_actions() Setup the hooks and actions
+	 */
+	public function __construct() {
+		$this->setup_globals();
+		$this->includes();
+		$this->setup_actions();
+	}
+
+	/**
+	 * Admin globals
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 */
+	private function setup_globals() {
+		$bbp = bbpress();
+		$this->admin_dir  = trailingslashit( $bbp->includes_dir . 'admin'  ); // Admin path
+		$this->admin_url  = trailingslashit( $bbp->includes_url . 'admin'  ); // Admin url
+		$this->images_url = trailingslashit( $this->admin_url   . 'images' ); // Admin images URL
+		$this->styles_url = trailingslashit( $this->admin_url   . 'styles' ); // Admin styles URL
+		$this->css_url    = trailingslashit( $this->admin_url   . 'css'    ); // Admin css URL
+		$this->js_url     = trailingslashit( $this->admin_url   . 'js'     ); // Admin js URL
+	}
+
+	/**
+	 * Include required files
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 */
+	private function includes() {
+		require( $this->admin_dir . 'tools.php'     );
+		require( $this->admin_dir . 'converter.php' );
+		require( $this->admin_dir . 'settings.php'  );
+		require( $this->admin_dir . 'functions.php' );
+		require( $this->admin_dir . 'metaboxes.php' );
+		require( $this->admin_dir . 'forums.php'    );
+		require( $this->admin_dir . 'topics.php'    );
+		require( $this->admin_dir . 'replies.php'   );
+		require( $this->admin_dir . 'users.php'     );
+	}
+
+	/**
+	 * Setup the admin hooks, actions and filters
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 *
+	 * @uses add_action() To add various actions
+	 * @uses add_filter() To add various filters
+	 */
+	private function setup_actions() {
+
+		// Bail to prevent interfering with the deactivation process
+		if ( bbp_is_deactivation() )
+			return;
+
+		/** General Actions ***************************************************/
+
+		add_action( 'bbp_admin_menu',              array( $this, 'admin_menus'                )     ); // Add menu item to settings menu
+		add_action( 'bbp_admin_head',              array( $this, 'admin_head'                 )     ); // Add some general styling to the admin area
+		add_action( 'bbp_admin_notices',           array( $this, 'activation_notice'          )     ); // Add notice if not using a bbPress theme
+		add_action( 'bbp_register_admin_style',    array( $this, 'register_admin_style'       )     ); // Add green admin style
+		add_action( 'bbp_register_admin_settings', array( $this, 'register_admin_settings'    )     ); // Add settings
+		add_action( 'bbp_activation',              array( $this, 'new_install'                )     ); // Add menu item to settings menu
+		add_action( 'admin_enqueue_scripts',       array( $this, 'enqueue_styles'             )     ); // Add enqueued CSS
+		add_action( 'admin_enqueue_scripts',       array( $this, 'enqueue_scripts'            )     ); // Add enqueued JS
+		add_action( 'wp_dashboard_setup',          array( $this, 'dashboard_widget_right_now' )     ); // Forums 'Right now' Dashboard widget
+		add_action( 'admin_bar_menu',              array( $this, 'admin_bar_about_link'       ), 15 ); // Add a link to bbPress about page to the admin bar
+
+		/** Ajax **************************************************************/
+
+		add_action( 'wp_ajax_bbp_suggest_topic',        array( $this, 'suggest_topic' ) );
+		add_action( 'wp_ajax_nopriv_bbp_suggest_topic', array( $this, 'suggest_topic' ) );
+
+		add_action( 'wp_ajax_bbp_suggest_user',         array( $this, 'suggest_user'  ) );
+		add_action( 'wp_ajax_nopriv_bbp_suggest_user',  array( $this, 'suggest_user'  ) );
+
+		/** Filters ***********************************************************/
+
+		// Modify bbPress's admin links
+		add_filter( 'plugin_action_links', array( $this, 'modify_plugin_action_links' ), 10, 2 );
+
+		// Map settings capabilities
+		add_filter( 'bbp_map_meta_caps',   array( $this, 'map_settings_meta_caps' ), 10, 4 );
+
+		// Hide the theme compat package selection
+		add_filter( 'bbp_admin_get_settings_sections', array( $this, 'hide_theme_compat_packages' ) );
+
+		// Allow keymasters to save forums settings
+		add_filter( 'option_page_capability_bbpress',  array( $this, 'option_page_capability_bbpress' ) );
+
+		/** Network Admin *****************************************************/
+
+		// Add menu item to settings menu
+		add_action( 'network_admin_menu',  array( $this, 'network_admin_menus' ) );
+
+		/** Dependencies ******************************************************/
+
+		// Allow plugins to modify these actions
+		do_action_ref_array( 'bbp_admin_loaded', array( &$this ) );
+	}
+
+	/**
+	 * Add the admin menus
+	 *
+	 * @since bbPress (r2646)
+	 *
+	 * @uses add_management_page() To add the Recount page in Tools section
+	 * @uses add_options_page() To add the Forums settings page in Settings
+	 *                           section
+	 */
+	public function admin_menus() {
+
+		$hooks = array();
+
+		// These are later removed in admin_head
+		if ( current_user_can( 'bbp_tools_page' ) ) {
+			if ( current_user_can( 'bbp_tools_repair_page' ) ) {
+				$hooks[] = add_management_page(
+					__( 'Repair Forums', 'bbpress' ),
+					__( 'Forum Repair',  'bbpress' ),
+					$this->minimum_capability,
+					'bbp-repair',
+					'bbp_admin_repair'
+				);
+			}
+
+			if ( current_user_can( 'bbp_tools_import_page' ) ) {
+				$hooks[] = add_management_page(
+					__( 'Import Forums', 'bbpress' ),
+					__( 'Forum Import',  'bbpress' ),
+					$this->minimum_capability,
+					'bbp-converter',
+					'bbp_converter_settings'
+				);
+			}
+
+			if ( current_user_can( 'bbp_tools_reset_page' ) ) {
+				$hooks[] = add_management_page(
+					__( 'Reset Forums', 'bbpress' ),
+					__( 'Forum Reset',  'bbpress' ),
+					$this->minimum_capability,
+					'bbp-reset',
+					'bbp_admin_reset'
+				);
+			}
+
+			// Fudge the highlighted subnav item when on a bbPress admin page
+			foreach ( $hooks as $hook ) {
+				add_action( "admin_head-$hook", 'bbp_tools_modify_menu_highlight' );
+			}
+
+			// Forums Tools Root
+			add_management_page(
+				__( 'Forums', 'bbpress' ),
+				__( 'Forums', 'bbpress' ),
+				$this->minimum_capability,
+				'bbp-repair',
+				'bbp_admin_repair'
+			);
+		}
+
+		// Are settings enabled?
+		if ( ! bbp_settings_integration() && current_user_can( 'bbp_settings_page' ) ) {
+			add_options_page(
+				__( 'Forums',  'bbpress' ),
+				__( 'Forums',  'bbpress' ),
+				$this->minimum_capability,
+				'bbpress',
+				'bbp_admin_settings'
+			);
+		}
+
+		// These are later removed in admin_head
+		if ( current_user_can( 'bbp_about_page' ) ) {
+
+			// About
+			add_dashboard_page(
+				__( 'Welcome to bbPress',  'bbpress' ),
+				__( 'Welcome to bbPress',  'bbpress' ),
+				$this->minimum_capability,
+				'bbp-about',
+				array( $this, 'about_screen' )
+			);
+
+			// Credits
+			add_dashboard_page(
+				__( 'Welcome to bbPress',  'bbpress' ),
+				__( 'Welcome to bbPress',  'bbpress' ),
+				$this->minimum_capability,
+				'bbp-credits',
+				array( $this, 'credits_screen' )
+			);
+		}
+
+		// Bail if plugin is not network activated
+		if ( ! is_plugin_active_for_network( bbpress()->basename ) )
+			return;
+
+		add_submenu_page(
+			'index.php',
+			__( 'Update Forums', 'bbpress' ),
+			__( 'Update Forums', 'bbpress' ),
+			'manage_network',
+			'bbp-update',
+			array( $this, 'update_screen' )
+		);
+	}
+
+	/**
+	 * Add the network admin menus
+	 *
+	 * @since bbPress (r3689)
+	 * @uses add_submenu_page() To add the Update Forums page in Updates
+	 */
+	public function network_admin_menus() {
+
+		// Bail if plugin is not network activated
+		if ( ! is_plugin_active_for_network( bbpress()->basename ) )
+			return;
+
+		add_submenu_page(
+			'upgrade.php',
+			__( 'Update Forums', 'bbpress' ),
+			__( 'Update Forums', 'bbpress' ),
+			'manage_network',
+			'bbpress-update',
+			array( $this, 'network_update_screen' )
+		);
+	}
+
+	/**
+	 * If this is a new installation, create some initial forum content.
+	 *
+	 * @since bbPress (r3767)
+	 * @return type
+	 */
+	public static function new_install() {
+		if ( !bbp_is_install() )
+			return;
+
+		bbp_create_initial_content();
+	}
+
+	/**
+	 * Register the settings
+	 *
+	 * @since bbPress (r2737)
+	 *
+	 * @uses add_settings_section() To add our own settings section
+	 * @uses add_settings_field() To add various settings fields
+	 * @uses register_setting() To register various settings
+	 * @todo Put fields into multidimensional array
+	 */
+	public static function register_admin_settings() {
+
+		// Bail if no sections available
+		$sections = bbp_admin_get_settings_sections();
+		if ( empty( $sections ) )
+			return false;
+
+		// Are we using settings integration?
+		$settings_integration = bbp_settings_integration();
+
+		// Loop through sections
+		foreach ( (array) $sections as $section_id => $section ) {
+
+			// Only proceed if current user can see this section
+			if ( ! current_user_can( $section_id ) )
+				continue;
+
+			// Only add section and fields if section has fields
+			$fields = bbp_admin_get_settings_fields_for_section( $section_id );
+			if ( empty( $fields ) )
+				continue;
+
+			// Toggle the section if core integration is on
+			if ( ( true === $settings_integration ) && !empty( $section['page'] ) ) {
+				$page = $section['page'];
+			} else {
+				$page = 'bbpress';
+			}
+
+			// Add the section
+			add_settings_section( $section_id, $section['title'], $section['callback'], $page );
+
+			// Loop through fields for this section
+			foreach ( (array) $fields as $field_id => $field ) {
+
+				// Add the field
+				if ( ! empty( $field['callback'] ) && !empty( $field['title'] ) ) {
+					add_settings_field( $field_id, $field['title'], $field['callback'], $page, $section_id, $field['args'] );
+				}
+
+				// Register the setting
+				register_setting( $page, $field_id, $field['sanitize_callback'] );
+			}
+		}
+	}
+
+	/**
+	 * Maps settings capabilities
+	 *
+	 * @since bbPress (r4242)
+	 *
+	 * @param array $caps Capabilities for meta capability
+	 * @param string $cap Capability name
+	 * @param int $user_id User id
+	 * @param mixed $args Arguments
+	 * @uses get_post() To get the post
+	 * @uses apply_filters() Calls 'bbp_map_meta_caps' with caps, cap, user id and
+	 *                        args
+	 * @return array Actual capabilities for meta capability
+	 */
+	public static function map_settings_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+
+		// What capability is being checked?
+		switch ( $cap ) {
+
+			// BuddyPress
+			case 'bbp_settings_buddypress' :
+				if ( ( is_plugin_active( 'buddypress/bp-loader.php' ) && defined( 'BP_VERSION' ) && bp_is_root_blog() ) && is_super_admin() ) {
+					$caps = array( bbpress()->admin->minimum_capability );
+				} else {
+					$caps = array( 'do_not_allow' );
+				}
+
+				break;
+
+			// Akismet
+			case 'bbp_settings_akismet' :
+				if ( ( is_plugin_active( 'akismet/akismet.php' ) && defined( 'AKISMET_VERSION' ) ) && is_super_admin() ) {
+					$caps = array( bbpress()->admin->minimum_capability );
+				} else {
+					$caps = array( 'do_not_allow' );
+				}
+
+				break;
+
+			// bbPress
+			case 'bbp_about_page'            : // About and Credits
+			case 'bbp_tools_page'            : // Tools Page
+			case 'bbp_tools_repair_page'     : // Tools - Repair Page
+			case 'bbp_tools_import_page'     : // Tools - Import Page
+			case 'bbp_tools_reset_page'      : // Tools - Reset Page
+			case 'bbp_settings_page'         : // Settings Page
+			case 'bbp_settings_users'        : // Settings - Users
+			case 'bbp_settings_features'     : // Settings - Features
+			case 'bbp_settings_theme_compat' : // Settings - Theme compat
+			case 'bbp_settings_root_slugs'   : // Settings - Root slugs
+			case 'bbp_settings_single_slugs' : // Settings - Single slugs
+			case 'bbp_settings_user_slugs'   : // Settings - User slugs
+			case 'bbp_settings_per_page'     : // Settings - Per page
+			case 'bbp_settings_per_rss_page' : // Settings - Per RSS page
+				$caps = array( bbpress()->admin->minimum_capability );
+				break;
+		}
+
+		return apply_filters( 'bbp_map_settings_meta_caps', $caps, $cap, $user_id, $args );
+	}
+
+	/**
+	 * Register the importers
+	 *
+	 * @since bbPress (r2737)
+	 *
+	 * @uses apply_filters() Calls 'bbp_importer_path' filter to allow plugins
+	 *                        to customize the importer script locations.
+	 */
+	public function register_importers() {
+
+		// Leave if we're not in the import section
+		if ( !defined( 'WP_LOAD_IMPORTERS' ) )
+			return;
+
+		// Load Importer API
+		require_once( ABSPATH . 'wp-admin/includes/import.php' );
+
+		// Load our importers
+		$importers = apply_filters( 'bbp_importers', array( 'bbpress' ) );
+
+		// Loop through included importers
+		foreach ( $importers as $importer ) {
+
+			// Allow custom importer directory
+			$import_dir  = apply_filters( 'bbp_importer_path', $this->admin_dir . 'importers', $importer );
+
+			// Compile the importer path
+			$import_file = trailingslashit( $import_dir ) . $importer . '.php';
+
+			// If the file exists, include it
+			if ( file_exists( $import_file ) ) {
+				require( $import_file );
+			}
+		}
+	}
+
+	/**
+	 * Admin area activation notice
+	 *
+	 * Shows a nag message in admin area about the theme not supporting bbPress
+	 *
+	 * @since bbPress (r2743)
+	 *
+	 * @uses current_user_can() To check notice should be displayed.
+	 */
+	public function activation_notice() {
+		// @todo - something fun
+	}
+
+	/**
+	 * Add Settings link to plugins area
+	 *
+	 * @since bbPress (r2737)
+	 *
+	 * @param array $links Links array in which we would prepend our link
+	 * @param string $file Current plugin basename
+	 * @return array Processed links
+	 */
+	public static function modify_plugin_action_links( $links, $file ) {
+
+		// Return normal links if not bbPress
+		if ( plugin_basename( bbpress()->file ) !== $file ) {
+			return $links;
+		}
+
+		// New links to merge into existing links
+		$new_links = array();
+
+		// Settings page link
+		if ( current_user_can( 'bbp_settings_page' ) ) {
+			$new_links['settings'] = '<a href="' . add_query_arg( array( 'page' => 'bbpress'   ), admin_url( 'options-general.php' ) ) . '">' . esc_html__( 'Settings', 'bbpress' ) . '</a>';
+		}
+
+		// About page link
+		if ( current_user_can( 'bbp_about_page' ) ) {
+			$new_links['about']    = '<a href="' . add_query_arg( array( 'page' => 'bbp-about' ), admin_url( 'index.php'           ) ) . '">' . esc_html__( 'About',    'bbpress' ) . '</a>';
+		}
+
+		// Add a few links to the existing links array
+		return array_merge( $links, $new_links );
+	}
+
+	/**
+	 * Add the 'Right now in Forums' dashboard widget
+	 *
+	 * @since bbPress (r2770)
+	 *
+	 * @uses wp_add_dashboard_widget() To add the dashboard widget
+	 */
+	public static function dashboard_widget_right_now() {
+		wp_add_dashboard_widget( 'bbp-dashboard-right-now', __( 'Right Now in Forums', 'bbpress' ), 'bbp_dashboard_widget_right_now' );
+	}
+
+	/**
+	 * Add a link to bbPress about page to the admin bar
+	 *
+	 * @since bbPress (r5136)
+	 *
+	 * @param WP_Admin_Bar $wp_admin_bar
+	 */
+	public function admin_bar_about_link( $wp_admin_bar ) {
+
+		if ( is_user_logged_in() ) {
+
+			$wp_admin_bar->add_menu( array(
+				'parent' => 'wp-logo',
+				'id'     => 'bbp-about',
+				'title'  => esc_html__( 'About bbPress', 'bbpress' ),
+				'href'   => add_query_arg( array( 'page' => 'bbp-about' ), admin_url( 'index.php' ) )
+			) );
+		}
+	}
+
+	/**
+	 * Enqueue any admin scripts we might need
+	 *
+	 * @since bbPress (r4260)
+	 */
+	public function enqueue_scripts() {
+		wp_enqueue_script( 'suggest' );
+
+		// Get the version to use for JS
+		$version = bbp_get_version();
+
+		// Post type checker (only topics and replies)
+		if ( 'post' === get_current_screen()->base ) {
+			switch( get_current_screen()->post_type ) {
+				case bbp_get_reply_post_type() :
+				case bbp_get_topic_post_type() :
+
+					// Enqueue the common JS
+					wp_enqueue_script( 'bbp-admin-common-js', $this->js_url . 'common.js', array( 'jquery' ), $version );
+
+					// Topics admin
+					if ( bbp_get_topic_post_type() === get_current_screen()->post_type ) {
+						wp_enqueue_script( 'bbp-admin-topics-js', $this->js_url . 'topics.js', array( 'jquery' ), $version );
+
+					// Replies admin
+					} elseif ( bbp_get_reply_post_type() === get_current_screen()->post_type ) {
+						wp_enqueue_script( 'bbp-admin-replies-js', $this->js_url . 'replies.js', array( 'jquery' ), $version );
+					}
+
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Enqueue any admin scripts we might need
+	 *
+	 * @since bbPress (r5224)
+	 */
+	public function enqueue_styles() {
+		wp_enqueue_style( 'bbp-admin-css', $this->css_url . 'admin.css', array( 'dashicons' ), bbp_get_version() );
+	}
+
+	/**
+	 * Remove the individual recount and converter menus.
+	 * They are grouped together by h2 tabs
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @uses remove_submenu_page() To remove menu items with alternat navigation
+	 */
+	public function admin_head() {
+		remove_submenu_page( 'tools.php', 'bbp-repair'    );
+		remove_submenu_page( 'tools.php', 'bbp-converter' );
+		remove_submenu_page( 'tools.php', 'bbp-reset'     );
+		remove_submenu_page( 'index.php', 'bbp-about'     );
+		remove_submenu_page( 'index.php', 'bbp-credits'   );
+	}
+
+	/**
+	 * Registers the bbPress admin color scheme
+	 *
+	 * Because wp-content can exist outside of the WordPress root there is no
+	 * way to be certain what the relative path of the admin images is.
+	 * We are including the two most common configurations here, just in case.
+	 *
+	 * @since bbPress (r2521)
+	 *
+	 * @uses wp_admin_css_color() To register the color scheme
+	 */
+	public function register_admin_style () {
+
+		// RTL and/or minified
+		$suffix = is_rtl() ? '-rtl' : '';
+		//$suffix .= defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+		// Mint
+		wp_admin_css_color(
+			'bbp-mint',
+			esc_html_x( 'Mint',      'admin color scheme', 'bbpress' ),
+			$this->styles_url . 'mint' . $suffix . '.css',
+			array( '#4f6d59', '#33834e', '#5FB37C', '#81c498' ),
+			array( 'base' => '#f1f3f2', 'focus' => '#fff', 'current' => '#fff' )
+		);
+
+		// Evergreen
+		wp_admin_css_color(
+			'bbp-evergreen',
+			esc_html_x( 'Evergreen', 'admin color scheme', 'bbpress' ),
+			$this->styles_url . 'evergreen' . $suffix . '.css',
+			array( '#324d3a', '#446950', '#56b274', '#324d3a' ),
+			array( 'base' => '#f1f3f2', 'focus' => '#fff', 'current' => '#fff' )
+		);
+
+		// Bail if already using the fresh color scheme
+		if ( 'fresh' === get_user_option( 'admin_color' ) ) {
+			return;
+		}
+
+		// Force 'colors-fresh' dependency
+		global $wp_styles;
+		$wp_styles->registered[ 'colors' ]->deps[] = 'colors-fresh';
+	}
+
+	/**
+	 * Hide theme compat package selection if only 1 package is registered
+	 *
+	 * @since bbPress (r4315)
+	 *
+	 * @param array $sections Forums settings sections
+	 * @return array
+	 */
+	public function hide_theme_compat_packages( $sections = array() ) {
+		if ( count( bbpress()->theme_compat->packages ) <= 1 )
+			unset( $sections['bbp_settings_theme_compat'] );
+
+		return $sections;
+	}
+
+	/**
+	 * Allow keymaster role to save Forums settings
+	 *
+	 * @since bbPress (r4678)
+	 *
+	 * @param string $capability
+	 * @return string Return 'keep_gate' capability
+	 */
+	public function option_page_capability_bbpress( $capability = 'manage_options' ) {
+		$capability = 'keep_gate';
+		return $capability;
+	}
+
+	/** Ajax ******************************************************************/
+
+	/**
+	 * Ajax action for facilitating the forum auto-suggest
+	 *
+	 * @since bbPress (r4261)
+	 *
+	 * @uses get_posts()
+	 * @uses bbp_get_topic_post_type()
+	 * @uses bbp_get_topic_id()
+	 * @uses bbp_get_topic_title()
+	 */
+	public function suggest_topic() {
+
+		// Try to get some topics
+		$topics = get_posts( array(
+			's'         => like_escape( $_REQUEST['q'] ),
+			'post_type' => bbp_get_topic_post_type()
+		) );
+
+		// If we found some topics, loop through and display them
+		if ( ! empty( $topics ) ) {
+			foreach ( (array) $topics as $post ) {
+				printf( esc_html__( '%s - %s', 'bbpress' ), bbp_get_topic_id( $post->ID ), bbp_get_topic_title( $post->ID ) . "\n" );
+			}
+		}
+		die();
+	}
+
+	/**
+	 * Ajax action for facilitating the topic and reply author auto-suggest
+	 *
+	 * @since bbPress (r5014)
+	 */
+	public function suggest_user() {
+
+		// Try to get some users
+		$users_query = new WP_User_Query( array(
+			'search'         => '*' . like_escape( $_REQUEST['q'] ) . '*',
+			'fields'         => array( 'ID', 'user_nicename' ),
+			'search_columns' => array( 'ID', 'user_nicename', 'user_email' ),
+			'orderby'        => 'ID'
+		) );
+
+		// If we found some users, loop through and display them
+		if ( ! empty( $users_query->results ) ) {
+			foreach ( (array) $users_query->results as $user ) {
+				printf( esc_html__( '%s - %s', 'bbpress' ), bbp_get_user_id( $user->ID ), bbp_get_user_nicename( $user->ID, array( 'force' => $user->user_nicename ) ) . "\n" );
+			}
+		}
+		die();
+	}
+
+	/** About *****************************************************************/
+
+	/**
+	 * Output the about screen
+	 *
+	 * @since bbPress (r4159)
+	 */
+	public function about_screen() {
+
+		list( $display_version ) = explode( '-', bbp_get_version() ); ?>
+
+		<div class="wrap about-wrap">
+			<h1><?php printf( esc_html__( 'Welcome to bbPress %s', 'bbpress' ), $display_version ); ?></h1>
+			<div class="about-text"><?php printf( esc_html__( 'Thank you for updating! bbPress %s is bundled up and ready to weather the storm of users in your community!', 'bbpress' ), $display_version ); ?></div>
+			<div class="bbp-badge"><?php printf( esc_html__( 'Version %s', 'bbpress' ), $display_version ); ?></div>
+
+			<h2 class="nav-tab-wrapper">
+				<a class="nav-tab nav-tab-active" href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'bbp-about' ), 'index.php' ) ) ); ?>">
+					<?php esc_html_e( 'What&#8217;s New', 'bbpress' ); ?>
+				</a><a class="nav-tab" href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'bbp-credits' ), 'index.php' ) ) ); ?>">
+					<?php esc_html_e( 'Credits', 'bbpress' ); ?>
+				</a>
+			</h2>
+
+			<div class="changelog">
+				<h3><?php esc_html_e( 'Forum Subscriptions', 'bbpress' ); ?></h3>
+
+				<div class="feature-section col two-col">
+					<div class="last-feature">
+						<h4><?php esc_html_e( 'Subscribe to Forums', 'bbpress' ); ?></h4>
+						<p><?php esc_html_e( 'Now your users can subscribe to new topics in specific forums.', 'bbpress' ); ?></p>
+					</div>
+
+					<div>
+						<h4><?php esc_html_e( 'Manage Subscriptions', 'bbpress' ); ?></h4>
+						<p><?php esc_html_e( 'Your users can manage all of their subscriptions in one convenient location.', 'bbpress' ); ?></p>
+					</div>
+				</div>
+			</div>
+
+			<div class="changelog">
+				<h3><?php esc_html_e( 'Converters', 'bbpress' ); ?></h3>
+
+				<div class="feature-section col one-col">
+					<div class="last-feature">
+						<p><?php esc_html_e( 'We&#8217;re all abuzz about the hive of new importers, AEF, Drupal, FluxBB, Kunena Forums for Joomla, MyBB, Phorum, PHPFox, PHPWind, PunBB, SMF, Xenforo and XMB. Existing importers are now sweeter than honey with improved importing stickies, topic tags, forum categories and the sting is now gone if you need to remove imported users.', 'bbpress' ); ?></p>
+					</div>
+				</div>
+
+				<div class="feature-section col three-col">
+					<div>
+						<h4><?php esc_html_e( 'Theme Compatibility', 'bbpress' ); ?></h4>
+						<p><?php esc_html_e( 'Better handling of styles and scripts in the template stack.', 'bbpress' ); ?></p>
+					</div>
+
+					<div>
+						<h4><?php esc_html_e( 'Polyglot support', 'bbpress' ); ?></h4>
+						<p><?php esc_html_e( 'bbPress fully supports automatic translation updates.', 'bbpress' ); ?></p>
+					</div>
+
+					<div class="last-feature">
+						<h4><?php esc_html_e( 'User capabilities', 'bbpress' ); ?></h4>
+						<p><?php esc_html_e( 'Roles and capabilities have been swept through, cleaned up, and simplified.', 'bbpress' ); ?></p>
+					</div>
+				</div>
+			</div>
+
+			<div class="return-to-dashboard">
+				<a href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'bbpress' ), 'options-general.php' ) ) ); ?>"><?php esc_html_e( 'Go to Forum Settings', 'bbpress' ); ?></a>
+			</div>
+
+		</div>
+
+		<?php
+	}
+
+	/**
+	 * Output the credits screen
+	 *
+	 * Hardcoding this in here is pretty janky. It's fine for 2.2, but we'll
+	 * want to leverage api.wordpress.org eventually.
+	 *
+	 * @since bbPress (r4159)
+	 */
+	public function credits_screen() {
+
+		list( $display_version ) = explode( '-', bbp_get_version() ); ?>
+
+		<div class="wrap about-wrap">
+			<h1><?php printf( esc_html__( 'Welcome to bbPress %s', 'bbpress' ), $display_version ); ?></h1>
+			<div class="about-text"><?php printf( esc_html__( 'Thank you for updating! bbPress %s is waxed, polished, and ready for you to take it for a lap or two around the block!', 'bbpress' ), $display_version ); ?></div>
+			<div class="bbp-badge"><?php printf( esc_html__( 'Version %s', 'bbpress' ), $display_version ); ?></div>
+
+			<h2 class="nav-tab-wrapper">
+				<a href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'bbp-about' ), 'index.php' ) ) ); ?>" class="nav-tab">
+					<?php esc_html_e( 'What&#8217;s New', 'bbpress' ); ?>
+				</a><a href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'bbp-credits' ), 'index.php' ) ) ); ?>" class="nav-tab nav-tab-active">
+					<?php esc_html_e( 'Credits', 'bbpress' ); ?>
+				</a>
+			</h2>
+
+			<p class="about-description"><?php esc_html_e( 'bbPress is created by a worldwide swarm of busy, busy bees.', 'bbpress' ); ?></p>
+
+			<h4 class="wp-people-group"><?php esc_html_e( 'Project Leaders', 'bbpress' ); ?></h4>
+			<ul class="wp-people-group " id="wp-people-group-project-leaders">
+				<li class="wp-person" id="wp-person-matt">
+					<a href="http://profiles.wordpress.org/matt"><img src="http://0.gravatar.com/avatar/767fc9c115a1b989744c755db47feb60?s=60" class="gravatar" alt="Matt Mullenweg" /></a>
+					<a class="web" href="http://profiles.wordpress.org/matt">Matt Mullenweg</a>
+					<span class="title"><?php esc_html_e( 'Founding Developer', 'bbpress' ); ?></span>
+				</li>
+				<li class="wp-person" id="wp-person-johnjamesjacoby">
+					<a href="http://profiles.wordpress.org/johnjamesjacoby"><img src="http://0.gravatar.com/avatar/81ec16063d89b162d55efe72165c105f?s=60" class="gravatar" alt="John James Jacoby" /></a>
+					<a class="web" href="http://profiles.wordpress.org/johnjamesjacoby">John James Jacoby</a>
+					<span class="title"><?php esc_html_e( 'Lead Developer', 'bbpress' ); ?></span>
+				</li>
+				<li class="wp-person" id="wp-person-jmdodd">
+					<a href="http://profiles.wordpress.org/jmdodd"><img src="http://0.gravatar.com/avatar/6a7c997edea340616bcc6d0fe03f65dd?s=60" class="gravatar" alt="Jennifer M. Dodd" /></a>
+					<a class="web" href="http://profiles.wordpress.org/jmdodd">Jennifer M. Dodd</a>
+					<span class="title"><?php esc_html_e( 'Feature Developer', 'bbpress' ); ?></span>
+				</li>
+				<li class="wp-person" id="wp-person-netweb">
+					<a href="http://profiles.wordpress.org/netweb"><img src="http://0.gravatar.com/avatar/97e1620b501da675315ba7cfb740e80f?s=60" class="gravatar" alt="Stephen Edgar" /></a>
+					<a class="web" href="http://profiles.wordpress.org/netweb">Stephen Edgar</a>
+					<span class="title"><?php esc_html_e( 'Converter Specialist', 'bbpress' ); ?></span>
+				</li>
+			</ul>
+
+			<h4 class="wp-people-group"><?php esc_html_e( 'Contributing Developers', 'bbpress' ); ?></h4>
+			<ul class="wp-people-group " id="wp-people-group-contributing-developers">
+				<li class="wp-person" id="wp-person-jaredatch">
+					<a href="http://profiles.wordpress.org/jaredatch"><img src="http://0.gravatar.com/avatar/e341eca9e1a85dcae7127044301b4363?s=60" class="gravatar" alt="Jared Atchison" /></a>
+					<a class="web" href="http://profiles.wordpress.org/jaredatch">Jared Atchison</a>
+					<span class="title"><?php esc_html_e( 'Bug Testing', 'bbpress' ); ?></span>
+				</li>
+				<li class="wp-person" id="wp-person-gautamgupta">
+					<a href="http://profiles.wordpress.org/gautamgupta"><img src="http://0.gravatar.com/avatar/b0810422cbe6e4eead4def5ae7a90b34?s=60" class="gravatar" alt="Gautam Gupta" /></a>
+					<a class="web" href="http://profiles.wordpress.org/gautamgupta">Gautam Gupta</a>
+					<span class="title"><?php esc_html_e( 'Feature Developer', 'bbpress' ); ?></span>
+				</li>
+			</ul>
+
+			<h4 class="wp-people-group"><?php esc_html_e( 'Core Contributors to bbPress 2.5', 'bbpress' ); ?></h4>
+			<p class="wp-credits-list">
+				<a href="http://profiles.wordpress.org/alex-ye">alex-ye</a>,
+				<a href="http://profiles.wordpress.org/alexvorn2">alexvorn2</a>,
+				<a href="http://profiles.wordpress.org/aliso">aliso</a>,
+				<a href="http://profiles.wordpress.org/boonebgorges">boonebgorges</a>,
+				<a href="http://profiles.wordpress.org/daveshine">daveshine</a>,
+				<a href="http://profiles.wordpress.org/DJPaul">DJPaul</a>,
+				<a href="http://profiles.wordpress.org/ethitter">ethitter</a>,
+				<a href="http://profiles.wordpress.org/fanquake">fanquake</a>,
+				<a href="http://profiles.wordpress.org/GargajCNS">GargajCNS</a>,
+				<a href="http://profiles.wordpress.org/GautamGupta">GautamGupta</a>,
+				<a href="http://profiles.wordpress.org/imath">imath</a>,
+				<a href="http://profiles.wordpress.org/jkudish">jkudish</a>,
+				<a href="http://profiles.wordpress.org/kobenland">kobenland</a>,
+				<a href="http://profiles.wordpress.org/lakrisgubben">lakrisgubben</a>,
+				<a href="http://profiles.wordpress.org/loki_racer">loki_racer</a>,
+				<a href="http://profiles.wordpress.org/mamaduka">mamaduka</a>,
+				<a href="http://profiles.wordpress.org/Maty">Maty</a>,
+				<a href="http://profiles.wordpress.org/mercime">mercime</a>,
+				<a href="http://profiles.wordpress.org/mordauk">mordauk</a>,
+				<a href="http://profiles.wordpress.org/mrcl">mrcl</a>,
+				<a href="http://profiles.wordpress.org/MZAWeb">MZAWeb</a>,
+				<a href="http://profiles.wordpress.org/r-a-y">r-a-y</a>,
+				<a href="http://profiles.wordpress.org/strangerstudios">strangerstudios</a>,
+				<a href="http://profiles.wordpress.org/thebrandonallen">thebrandonallen</a>,
+				<a href="http://profiles.wordpress.org/tlovett1">tlovett1</a>,
+				<a href="http://profiles.wordpress.org/wpdennis">wpdennis</a>,
+			</p>
+
+			<div class="return-to-dashboard">
+				<a href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'bbpress' ), 'options-general.php' ) ) ); ?>"><?php esc_html_e( 'Go to Forum Settings', 'bbpress' ); ?></a>
+			</div>
+
+		</div>
+
+		<?php
+	}
+
+	/** Updaters **************************************************************/
+
+	/**
+	 * Update all bbPress forums across all sites
+	 *
+	 * @since bbPress (r3689)
+	 *
+	 * @global WPDB $wpdb
+	 * @uses get_blog_option()
+	 * @uses wp_remote_get()
+	 */
+	public static function update_screen() {
+
+		// Get action
+		$action = isset( $_GET['action'] ) ? $_GET['action'] : ''; ?>
+
+		<div class="wrap">
+			<div id="icon-edit" class="icon32 icon32-posts-topic"><br /></div>
+			<h2><?php esc_html_e( 'Update Forum', 'bbpress' ); ?></h2>
+
+		<?php
+
+		// Taking action
+		switch ( $action ) {
+			case 'bbp-update' :
+
+				// Run the full updater
+				bbp_version_updater(); ?>
+
+				<p><?php esc_html_e( 'All done!', 'bbpress' ); ?></p>
+				<a class="button" href="index.php?page=bbp-update"><?php esc_html_e( 'Go Back', 'bbpress' ); ?></a>
+
+				<?php
+
+				break;
+
+			case 'show' :
+			default : ?>
+
+				<p><?php esc_html_e( 'You can update your forum through this page. Hit the link below to update.', 'bbpress' ); ?></p>
+				<p><a class="button" href="index.php?page=bbp-update&amp;action=bbp-update"><?php esc_html_e( 'Update Forum', 'bbpress' ); ?></a></p>
+
+			<?php break;
+
+		} ?>
+
+		</div><?php
+	}
+
+	/**
+	 * Update all bbPress forums across all sites
+	 *
+	 * @since bbPress (r3689)
+	 *
+	 * @global WPDB $wpdb
+	 * @uses get_blog_option()
+	 * @uses wp_remote_get()
+	 */
+	public static function network_update_screen() {
+		global $wpdb;
+
+		// Get action
+		$action = isset( $_GET['action'] ) ? $_GET['action'] : ''; ?>
+
+		<div class="wrap">
+			<div id="icon-edit" class="icon32 icon32-posts-topic"><br /></div>
+			<h2><?php esc_html_e( 'Update Forums', 'bbpress' ); ?></h2>
+
+		<?php
+
+		// Taking action
+		switch ( $action ) {
+			case 'bbpress-update' :
+
+				// Site counter
+				$n = isset( $_GET['n'] ) ? intval( $_GET['n'] ) : 0;
+
+				// Get blogs 5 at a time
+				$blogs = $wpdb->get_results( "SELECT * FROM {$wpdb->blogs} WHERE site_id = '{$wpdb->siteid}' AND spam = '0' AND deleted = '0' AND archived = '0' ORDER BY registered DESC LIMIT {$n}, 5", ARRAY_A );
+
+				// No blogs so all done!
+				if ( empty( $blogs ) ) : ?>
+
+					<p><?php esc_html_e( 'All done!', 'bbpress' ); ?></p>
+					<a class="button" href="update-core.php?page=bbpress-update"><?php esc_html_e( 'Go Back', 'bbpress' ); ?></a>
+
+				<?php
+
+				// Still have sites to loop through
+				else : ?>
+
+					<ul>
+
+						<?php foreach ( (array) $blogs as $details ) :
+
+							$siteurl = get_blog_option( $details['blog_id'], 'siteurl' ); ?>
+
+							<li><?php echo $siteurl; ?></li>
+
+							<?php
+
+							// Get the response of the bbPress update on this site
+							$response = wp_remote_get(
+								trailingslashit( $siteurl ) . 'wp-admin/index.php?page=bbp-update&action=bbp-update',
+								array( 'timeout' => 30, 'httpversion' => '1.1' )
+							);
+
+							// Site errored out, no response?
+							if ( is_wp_error( $response ) )
+								wp_die( sprintf( __( 'Warning! Problem updating %1$s. Your server may not be able to connect to sites running on it. Error message: <em>%2$s</em>', 'bbpress' ), $siteurl, $response->get_error_message() ) );
+
+							// Switch to the new blog
+							switch_to_blog( $details[ 'blog_id' ] );
+
+							$basename = bbpress()->basename;
+
+							// Run the updater on this site
+							if ( is_plugin_active_for_network( $basename ) || is_plugin_active( $basename ) ) {
+								bbp_version_updater();
+							}
+
+							// restore original blog
+							restore_current_blog();
+
+							// Do some actions to allow plugins to do things too
+							do_action( 'after_bbpress_upgrade', $response             );
+							do_action( 'bbp_upgrade_site',      $details[ 'blog_id' ] );
+
+						endforeach; ?>
+
+					</ul>
+
+					<p>
+						<?php esc_html_e( 'If your browser doesn&#8217;t start loading the next page automatically, click this link:', 'bbpress' ); ?>
+						<a class="button" href="update-core.php?page=bbpress-update&amp;action=bbpress-update&amp;n=<?php echo ( $n + 5 ); ?>"><?php esc_html_e( 'Next Forums', 'bbpress' ); ?></a>
+					</p>
+					<script type='text/javascript'>
+						<!--
+						function nextpage() {
+							location.href = 'update-core.php?page=bbpress-update&action=bbpress-update&n=<?php echo ( $n + 5 ) ?>';
+						}
+						setTimeout( 'nextpage()', 250 );
+						//-->
+					</script><?php
+
+				endif;
+
+				break;
+
+			case 'show' :
+			default : ?>
+
+				<p><?php esc_html_e( 'You can update all the forums on your network through this page. It works by calling the update script of each site automatically. Hit the link below to update.', 'bbpress' ); ?></p>
+				<p><a class="button" href="update-core.php?page=bbpress-update&amp;action=bbpress-update"><?php esc_html_e( 'Update Forums', 'bbpress' ); ?></a></p>
+
+			<?php break;
+
+		} ?>
+
+		</div><?php
+	}
+}
+endif; // class_exists check
+
+/**
+ * Setup bbPress Admin
+ *
+ * @since bbPress (r2596)
+ *
+ * @uses BBP_Admin
+ */
+function bbp_admin() {
+	bbpress()->admin = new BBP_Admin();
+
+	bbpress()->admin->converter = new BBP_Converter();
+}
Index: /tags/2.5.4/includes/admin/converter.php
===================================================================
--- /tags/2.5.4/includes/admin/converter.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converter.php	(revision 5382)
@@ -0,0 +1,1479 @@
+<?php
+
+/**
+ * bbPress Converter
+ *
+ * Based on the hard work of Adam Ellis at http://bbconverter.com
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Main BBP_Converter Class
+ */
+class BBP_Converter {
+
+	/**
+	 * The main bbPress Converter loader
+	 *
+	 * @since bbPress (r3813)
+	 * @uses BBP_Converter::includes() Include the required files
+	 * @uses BBP_Converter::setup_actions() Setup the actions
+	 */
+	public function __construct() {
+
+		// "I wonder where I'll float next."
+		if ( empty( $_SERVER['REQUEST_METHOD'] ) )
+			return;
+
+		// Bail if request is not correct
+		switch ( strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
+
+			// Converter is converting
+			case 'POST' :
+				if ( ( empty( $_POST['action'] ) || ( 'bbconverter_process' !=  $_POST['action'] ) ) )
+					return;
+
+				break;
+
+			// Some other admin page
+			case 'GET'  :
+				if ( ( empty( $_GET['page'] ) || ( 'bbp-converter' !=  $_GET['page'] ) ) )
+					return;
+
+				break;
+		}
+
+		// Proceed with the actions
+		$this->setup_actions();
+	}
+
+	/**
+	 * Setup the default actions
+	 *
+	 * @since bbPress (r3813)
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_actions() {
+
+		// Attach to the admin head with our ajax requests cycle and css
+		add_action( 'bbp_admin_head',              array( $this, 'admin_head'              ) );
+
+		// Attach the bbConverter admin settings action to the WordPress admin init action.
+		add_action( 'bbp_register_admin_settings', array( $this, 'register_admin_settings' ) );
+
+		// Attach to the admin ajax request to process cycles
+		add_action( 'wp_ajax_bbconverter_process', array( $this, 'process_callback'        ) );
+	}
+
+	/**
+	 * Register the settings
+	 *
+	 * @since bbPress (r3813)
+	 * @uses add_settings_section() To add our own settings section
+	 * @uses add_settings_field() To add various settings fields
+	 * @uses register_setting() To register various settings
+	 */
+	public function register_admin_settings() {
+
+		// Add the main section
+		add_settings_section( 'bbpress_converter_main',     __( 'Database Settings', 'bbpress' ),  'bbp_converter_setting_callback_main_section', 'bbpress_converter' );
+
+		// System Select
+		add_settings_field( '_bbp_converter_platform',      __( 'Select Platform',   'bbpress' ),  'bbp_converter_setting_callback_platform', 'bbpress_converter', 'bbpress_converter_main' );
+		register_setting  ( 'bbpress_converter_main',       '_bbp_converter_platform',           'sanitize_title' );
+
+		// Database Server
+		add_settings_field( '_bbp_converter_db_server',     __( 'Database Server',   'bbpress' ),  'bbp_converter_setting_callback_dbserver', 'bbpress_converter', 'bbpress_converter_main' );
+		register_setting  ( 'bbpress_converter_main',       '_bbp_converter_db_server',          'sanitize_title' );
+
+		// Database Server Port
+		add_settings_field( '_bbp_converter_db_port',       __( 'Database Port',     'bbpress' ),  'bbp_converter_setting_callback_dbport', 'bbpress_converter', 'bbpress_converter_main' );
+		register_setting  ( 'bbpress_converter_main',       '_bbp_converter_db_port',            'sanitize_title' );
+
+		// Database Name
+		add_settings_field( '_bbp_converter_db_name',       __( 'Database Name',     'bbpress' ),  'bbp_converter_setting_callback_dbname', 'bbpress_converter', 'bbpress_converter_main' );
+		register_setting  ( 'bbpress_converter_main',       '_bbp_converter_db_name',            'sanitize_title' );
+
+		// Database User
+		add_settings_field( '_bbp_converter_db_user',       __( 'Database User',     'bbpress' ),  'bbp_converter_setting_callback_dbuser', 'bbpress_converter', 'bbpress_converter_main' );
+		register_setting  ( 'bbpress_converter_main',       '_bbp_converter_db_user',            'sanitize_title' );
+
+		// Database Pass
+		add_settings_field( '_bbp_converter_db_pass',       __( 'Database Password', 'bbpress' ),  'bbp_converter_setting_callback_dbpass', 'bbpress_converter', 'bbpress_converter_main' );
+		register_setting  ( 'bbpress_converter_main',       '_bbp_converter_db_pass',            'sanitize_title' );
+
+		// Database Prefix
+		add_settings_field( '_bbp_converter_db_prefix',     __( 'Table Prefix',      'bbpress' ),  'bbp_converter_setting_callback_dbprefix', 'bbpress_converter', 'bbpress_converter_main' );
+		register_setting  ( 'bbpress_converter_main',       '_bbp_converter_db_prefix',          'sanitize_title' );
+
+		// Add the options section
+		add_settings_section( 'bbpress_converter_opt',      __( 'Options',           'bbpress' ),  'bbp_converter_setting_callback_options_section', 'bbpress_converter' );
+
+		// Rows Limit
+		add_settings_field( '_bbp_converter_rows',          __( 'Rows Limit',        'bbpress' ),  'bbp_converter_setting_callback_rows', 'bbpress_converter', 'bbpress_converter_opt' );
+		register_setting  ( 'bbpress_converter_opt',        '_bbp_converter_rows',               'intval' );
+
+		// Delay Time
+		add_settings_field( '_bbp_converter_delay_time',    __( 'Delay Time',        'bbpress' ), 'bbp_converter_setting_callback_delay_time', 'bbpress_converter', 'bbpress_converter_opt' );
+		register_setting  ( 'bbpress_converter_opt',        '_bbp_converter_delay_time',        'intval' );
+
+		// Convert Users ?
+		add_settings_field( '_bbp_converter_convert_users', __( 'Convert Users',     'bbpress' ), 'bbp_converter_setting_callback_convert_users', 'bbpress_converter', 'bbpress_converter_opt' );
+		register_setting  ( 'bbpress_converter_opt',        '_bbp_converter_convert_users',     'intval' );
+
+		// Restart
+		add_settings_field( '_bbp_converter_restart',       __( 'Start Over',        'bbpress' ), 'bbp_converter_setting_callback_restart', 'bbpress_converter', 'bbpress_converter_opt' );
+		register_setting  ( 'bbpress_converter_opt',        '_bbp_converter_restart',           'intval' );
+
+		// Clean
+		add_settings_field( '_bbp_converter_clean',         __( 'Purge Previous Import', 'bbpress' ), 'bbp_converter_setting_callback_clean', 'bbpress_converter', 'bbpress_converter_opt' );
+		register_setting  ( 'bbpress_converter_opt',        '_bbp_converter_clean',             'intval' );
+	}
+
+	/**
+	 * Admin scripts
+	 *
+	 * @since bbPress (r3813)
+	 */
+	public function admin_head() { ?>
+
+		<style type="text/css" media="screen">
+			/*<![CDATA[*/
+
+			div.bbp-converter-updated,
+			div.bbp-converter-warning {
+				border-radius: 3px 3px 3px 3px;
+				border-style: solid;
+				border-width: 1px;
+				padding: 5px 5px 5px 5px;
+			}
+
+			div.bbp-converter-updated {
+				height: 300px;
+				overflow: auto;
+				display: none;
+				background-color: #FFFFE0;
+				border-color: #E6DB55;
+				font-family: monospace;
+				font-weight: bold;
+			}
+
+			div.bbp-converter-updated p {
+				margin: 0.5em 0;
+				padding: 2px;
+				float: left;
+				clear: left;
+			}
+
+			div.bbp-converter-updated p.loading {
+				padding: 2px 20px 2px 2px;
+				background-image: url('<?php echo admin_url(); ?>images/wpspin_light.gif');
+				background-repeat: no-repeat;
+				background-position: center right;
+			}
+
+			#bbp-converter-stop {
+				display:none;
+			}
+
+			#bbp-converter-progress {
+				display:none;
+			}
+
+			/*]]>*/
+		</style>
+
+		<script language="javascript">
+
+			var bbconverter_is_running = false;
+			var bbconverter_run_timer;
+			var bbconverter_delay_time = 0;
+
+			function bbconverter_grab_data() {
+				var values = {};
+				jQuery.each(jQuery('#bbp-converter-settings').serializeArray(), function(i, field) {
+					values[field.name] = field.value;
+				});
+
+				if( values['_bbp_converter_restart'] ) {
+					jQuery('#_bbp_converter_restart').removeAttr("checked");
+				}
+
+				if( values['_bbp_converter_delay_time'] ) {
+					bbconverter_delay_time = values['_bbp_converter_delay_time'] * 1000;
+				}
+
+				values['action'] = 'bbconverter_process';
+				values['_ajax_nonce'] = '<?php echo  wp_create_nonce( 'bbp_converter_process' ); ?>';
+
+				return values;
+			}
+
+			function bbconverter_start() {
+				if( false == bbconverter_is_running ) {
+					bbconverter_is_running = true;
+					jQuery('#bbp-converter-start').hide();
+					jQuery('#bbp-converter-stop').show();
+					jQuery('#bbp-converter-progress').show();
+					bbconverter_log( '<p class="loading"><?php esc_html_e( 'Starting Conversion', 'bbpress' ); ?></p>' );
+					bbconverter_run();
+				}
+			}
+
+			function bbconverter_run() {
+				jQuery.post(ajaxurl, bbconverter_grab_data(), function(response) {
+					var response_length = response.length - 1;
+					response = response.substring(0,response_length);
+					bbconverter_success(response);
+				});
+			}
+
+			function bbconverter_stop() {
+				jQuery('#bbp-converter-start').show();
+				jQuery('#bbp-converter-stop').hide();
+				jQuery('#bbp-converter-progress').hide();
+				jQuery('#bbp-converter-message p').removeClass( 'loading' );
+				bbconverter_is_running = false;
+				clearTimeout( bbconverter_run_timer );
+			}
+
+			function bbconverter_success(response) {
+				bbconverter_log(response);
+
+				if ( response == '<p class="loading"><?php esc_html_e( 'Conversion Complete', 'bbpress' ); ?></p>' || response.indexOf('error') > -1 ) {
+					bbconverter_log('<p>Repair any missing information: <a href="<?php echo admin_url(); ?>tools.php?page=bbp-repair">Continue</a></p>');
+					bbconverter_stop();
+				} else if( bbconverter_is_running ) { // keep going
+					jQuery('#bbp-converter-progress').show();
+					clearTimeout( bbconverter_run_timer );
+					bbconverter_run_timer = setTimeout( 'bbconverter_run()', bbconverter_delay_time );
+				} else {
+					bbconverter_stop();
+				}
+			}
+
+			function bbconverter_log(text) {
+				if ( jQuery('#bbp-converter-message').css('display') == 'none' ) {
+					jQuery('#bbp-converter-message').show();
+				}
+				if ( text ) {
+					jQuery('#bbp-converter-message p').removeClass( 'loading' );
+					jQuery('#bbp-converter-message').prepend( text );
+				}
+			}
+
+		</script>
+
+		<?php
+	}
+
+	/**
+	 * Wrap the converter output in paragraph tags, so styling can be applied
+	 *
+	 * @since bbPress (r4052)
+	 *
+	 * @param string $output
+	 */
+	private static function converter_output( $output = '' ) {
+
+		// Get the last query
+		$before = '<p class="loading">';
+		$after  = '</p>';
+		$query  = get_option( '_bbp_converter_query' );
+
+		if ( ! empty( $query ) )
+			$before = '<p class="loading" title="' . esc_attr( $query ) . '">';
+
+		echo $before . $output . $after;
+	}
+
+	/**
+	 * Callback processor
+	 *
+	 * @since bbPress (r3813)
+	 */
+	public function process_callback() {
+
+		// Verify intent
+		check_ajax_referer( 'bbp_converter_process' );
+
+		if ( ! ini_get( 'safe_mode' ) ) {
+			set_time_limit( 0 );
+			ini_set( 'memory_limit',   '256M' );
+			ini_set( 'implicit_flush', '1'    );
+			ignore_user_abort( true );
+		}
+
+		// Save step and count so that it can be restarted.
+		if ( ! get_option( '_bbp_converter_step' ) || ( !empty( $_POST['_bbp_converter_restart'] ) ) ) {
+			update_option( '_bbp_converter_step',  1 );
+			update_option( '_bbp_converter_start', 0 );
+		}
+
+		$step  = (int) get_option( '_bbp_converter_step',  1 );
+		$min   = (int) get_option( '_bbp_converter_start', 0 );
+		$count = (int) ! empty( $_POST['_bbp_converter_rows'] ) ? $_POST['_bbp_converter_rows'] : 100;
+		$max   = ( $min + $count ) - 1;
+		$start = $min;
+
+		// Bail if platform did not get saved
+		$platform = !empty( $_POST['_bbp_converter_platform' ] ) ? $_POST['_bbp_converter_platform' ] : get_option( '_bbp_converter_platform' );
+		if ( empty( $platform ) )
+			return;
+
+		// Include the appropriate converter.
+		$converter = bbp_new_converter( $platform );
+
+		switch ( $step ) {
+
+			// STEP 1. Clean all tables.
+			case 1 :
+				if ( !empty( $_POST['_bbp_converter_clean'] ) ) {
+					if ( $converter->clean( $start ) ) {
+						update_option( '_bbp_converter_step',  $step + 1 );
+						update_option( '_bbp_converter_start', 0         );
+						$this->sync_table( true );
+						if ( empty( $start ) ) {
+							$this->converter_output( __( 'No data to clean', 'bbpress' ) );
+						}
+					} else {
+						update_option( '_bbp_converter_start', $max + 1 );
+						$this->converter_output( sprintf( __( 'Deleting previously converted data (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+					}
+				} else {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+				}
+
+				break;
+
+			// STEP 2. Convert users.
+			case 2 :
+				if ( !empty( $_POST['_bbp_converter_convert_users'] ) ) {
+					if ( $converter->convert_users( $start ) ) {
+						update_option( '_bbp_converter_step',  $step + 1 );
+						update_option( '_bbp_converter_start', 0         );
+						if ( empty( $start ) ) {
+							$this->converter_output( __( 'No users to convert', 'bbpress' ) );
+						}
+					} else {
+						update_option( '_bbp_converter_start', $max + 1 );
+						$this->converter_output( sprintf(  __( 'Converting users (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+					}
+				} else {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+				}
+
+				break;
+
+			// STEP 3. Clean passwords.
+			case 3 :
+				if ( !empty( $_POST['_bbp_converter_convert_users'] ) ) {
+					if ( $converter->clean_passwords( $start ) ) {
+						update_option( '_bbp_converter_step',  $step + 1 );
+						update_option( '_bbp_converter_start', 0         );
+						if ( empty( $start ) ) {
+							$this->converter_output( __( 'No passwords to clear', 'bbpress' ) );
+						}
+					} else {
+						update_option( '_bbp_converter_start', $max + 1 );
+						$this->converter_output( sprintf( __( 'Delete users WordPress default passwords (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+					}
+				} else {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+				}
+
+				break;
+
+			// STEP 4. Convert forums.
+			case 4 :
+				if ( $converter->convert_forums( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No forums to convert', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Converting forums (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			// STEP 5. Convert forum parents.
+			case 5 :
+				if ( $converter->convert_forum_parents( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No forum parents to convert', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Calculating forum hierarchy (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			// STEP 6. Convert topics.
+			case 6 :
+				if ( $converter->convert_topics( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No topics to convert', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Converting topics (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			// STEP 7. Stick topics.
+			case 7 :
+				if ( $converter->convert_topic_stickies( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No stickies to stick', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Calculating topic stickies (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			// STEP 8. Stick to front topics (Super Sicky).
+			case 8 :
+				if ( $converter->convert_topic_super_stickies( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No super stickies to stick', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Calculating topic super stickies (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			// STEP 9. Convert tags.
+			case 9 :
+				if ( $converter->convert_tags( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No tags to convert', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Converting topic tags (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			// STEP 10. Convert replies.
+			case 10 :
+				if ( $converter->convert_replies( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No replies to convert', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Converting replies (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			// STEP 11. Convert reply_to parents.
+			case 11 :
+				if ( $converter->convert_reply_to_parents( $start ) ) {
+					update_option( '_bbp_converter_step',  $step + 1 );
+					update_option( '_bbp_converter_start', 0         );
+					if ( empty( $start ) ) {
+						$this->converter_output( __( 'No reply_to parents to convert', 'bbpress' ) );
+					}
+				} else {
+					update_option( '_bbp_converter_start', $max + 1 );
+					$this->converter_output( sprintf( __( 'Calculating reply_to parents (%1$s - %2$s)', 'bbpress' ), $min, $max ) );
+				}
+
+				break;
+
+			default :
+				delete_option( '_bbp_converter_step'  );
+				delete_option( '_bbp_converter_start' );
+				delete_option( '_bbp_converter_query' );
+
+				$this->converter_output( __( 'Conversion Complete', 'bbpress' ) );
+
+				break;
+		}
+	}
+
+	/**
+	 * Create Tables for fast syncing
+	 *
+	 * @since bbPress (r3813)
+	 */
+	public function sync_table( $drop = false ) {
+		global $wpdb;
+
+		$table_name = $wpdb->prefix . 'bbp_converter_translator';
+		if ( ! empty( $drop ) && $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" ) == $table_name )
+			$wpdb->query( "DROP TABLE {$table_name}" );
+
+		require_once( ABSPATH . '/wp-admin/includes/upgrade.php' );
+
+		if ( !empty( $wpdb->charset ) ) {
+			$charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
+		}
+
+		if ( !empty( $wpdb->collate ) ) {
+			$charset_collate .= " COLLATE $wpdb->collate";
+		}
+
+		/** Translator ****************************************************/
+
+		$sql = "CREATE TABLE {$table_name} (
+					meta_id mediumint(8) unsigned not null auto_increment,
+					value_type varchar(25) null,
+					value_id bigint(20) unsigned not null default '0',
+					meta_key varchar(25) null,
+					meta_value varchar(25) null,
+				PRIMARY KEY  (meta_id),
+					KEY value_id (value_id),
+					KEY meta_join (meta_key, meta_value) ) {$charset_collate};";
+
+		dbDelta( $sql );
+	}
+}
+
+/**
+ * Base class to be extended by specific individual importers
+ *
+ * @since bbPress (r3813)
+ */
+abstract class BBP_Converter_Base {
+
+	/**
+	 * @var array() This is the field mapping array to process.
+	 */
+	protected $field_map = array();
+
+	/**
+	 * @var object This is the connection to the WordPress datbase.
+	 */
+	protected $wpdb;
+
+	/**
+	 * @var object This is the connection to the other platforms database.
+	 */
+	protected $opdb;
+
+	/**
+	 * @var int This is the max rows to process at a time.
+	 */
+	public $max_rows;
+
+	/**
+	 * @var array() Map of topic to forum.  It is for optimization.
+	 */
+	private $map_topicid_to_forumid = array();
+
+	/**
+	 * @var array() Map of from old forum ids to new forum ids.  It is for optimization.
+	 */
+	private $map_forumid = array();
+
+	/**
+	 * @var array() Map of from old topic ids to new topic ids.  It is for optimization.
+	 */
+	private $map_topicid = array();
+
+	/**
+	 * @var array() Map of from old reply_to ids to new reply_to ids.  It is for optimization.
+	 */
+	private $map_reply_to = array();
+
+	/**
+	 * @var array() Map of from old user ids to new user ids.  It is for optimization.
+	 */
+	private $map_userid = array();
+
+	/**
+	 * @var str This is the charset for your wp database.
+	 */
+	public $charset;
+
+	/**
+	 * @var boolean Sync table available.
+	 */
+	public $sync_table = false;
+
+	/**
+	 * @var str Sync table name.
+	 */
+	public $sync_table_name;
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * This is the constructor and it connects to the platform databases.
+	 */
+	public function __construct() {
+		$this->setup_globals();
+	}
+
+	private function setup_globals() {
+		global $wpdb;
+
+		/** Get database connections ******************************************/
+
+		$this->wpdb         = $wpdb;
+		$this->max_rows     = (int) $_POST['_bbp_converter_rows'];
+		$this->opdb         = new wpdb( $_POST['_bbp_converter_db_user'], $_POST['_bbp_converter_db_pass'], $_POST['_bbp_converter_db_name'], $_POST['_bbp_converter_db_server'] );
+		$this->opdb->prefix = $_POST['_bbp_converter_db_prefix'];
+
+		/**
+		 * Error Reporting
+		 */
+		$this->wpdb->show_errors();
+		$this->opdb->show_errors();
+
+		/**
+		 * Syncing
+		 */
+		$this->sync_table_name = $this->wpdb->prefix . 'bbp_converter_translator';
+		if ( $this->wpdb->get_var( "SHOW TABLES LIKE '" . $this->sync_table_name . "'" ) == $this->sync_table_name ) {
+			$this->sync_table = true;
+		} else {
+			$this->sync_table = false;
+		}
+
+		/**
+		 * Charset
+		 */
+		if ( empty( $this->wpdb->charset ) ) {
+			$this->charset = 'UTF8';
+		} else {
+			$this->charset = $this->wpdb->charset;
+		}
+
+		/**
+		 * Default mapping.
+		 */
+
+		/** Forum Section *****************************************************/
+
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_status',
+			'default'      => 'publish'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'comment_status',
+			'default'      => 'closed'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'ping_status',
+			'default'      => 'closed'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_type',
+			'default'      => 'forum'
+		);
+
+		/** Topic Section *****************************************************/
+
+		$this->field_map[] = array(
+			'to_type'      => 'topic',
+			'to_fieldname' => 'post_status',
+			'default'      => 'publish'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'topic',
+			'to_fieldname' => 'comment_status',
+			'default'      => 'closed'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'topic',
+			'to_fieldname' => 'ping_status',
+			'default'      => 'closed'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'topic',
+			'to_fieldname' => 'post_type',
+			'default'      => 'topic'
+		);
+
+		/** Post Section ******************************************************/
+
+		$this->field_map[] = array(
+			'to_type'      => 'reply',
+			'to_fieldname' => 'post_status',
+			'default'      => 'publish'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'reply',
+			'to_fieldname' => 'comment_status',
+			'default'      => 'closed'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'reply',
+			'to_fieldname' => 'ping_status',
+			'default'      => 'closed'
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'reply',
+			'to_fieldname' => 'post_type',
+			'default'      => 'reply'
+		);
+
+		/** User Section ******************************************************/
+
+		$this->field_map[] = array(
+			'to_type'      => 'user',
+			'to_fieldname' => 'role',
+			'default'      => get_option( 'default_role' )
+		);
+	}
+
+	/**
+	 * Convert Forums
+	 */
+	public function convert_forums( $start = 1 ) {
+		return $this->convert_table( 'forum', $start );
+	}
+
+	/**
+	 * Convert Topics / Threads
+	 */
+	public function convert_topics( $start = 1 ) {
+		return $this->convert_table( 'topic', $start );
+	}
+
+	/**
+	 * Convert Posts
+	 */
+	public function convert_replies( $start = 1 ) {
+		return $this->convert_table( 'reply', $start );
+	}
+
+	/**
+	 * Convert Users
+	 */
+	public function convert_users( $start = 1 ) {
+		return $this->convert_table( 'user', $start );
+	}
+
+	/**
+	 * Convert Tags
+	 */
+	public function convert_tags( $start = 1 ) {
+		return $this->convert_table( 'tags', $start );
+	}
+
+	/**
+	 * Convert Table
+	 *
+	 * @param string to type
+	 * @param int Start row
+	 */
+	public function convert_table( $to_type, $start ) {
+
+		// Are we usig a sync table, or postmeta?
+		if ( $this->wpdb->get_var( "SHOW TABLES LIKE '" . $this->sync_table_name . "'" ) == $this->sync_table_name ) {
+			$this->sync_table = true;
+		} else {
+			$this->sync_table = false;
+		}
+
+		// Set some defaults
+		$has_insert     = false;
+		$from_tablename = '';
+		$field_list     = $from_tables = $tablefield_array = array();
+
+		// Toggle Table Name based on $to_type (destination)
+		switch ( $to_type ) {
+			case 'user' :
+				$tablename = $this->wpdb->users;
+				break;
+
+			case 'tags' :
+				$tablename = '';
+				break;
+
+			default :
+				$tablename = $this->wpdb->posts;
+		}
+
+		// Get the fields from the destination table
+		if ( !empty( $tablename ) ) {
+			$tablefield_array = $this->get_fields( $tablename );
+		}
+
+		/** Step 1 ************************************************************/
+
+		// Loop through the field maps, and look for to_type matches
+		foreach ( $this->field_map as $item ) {
+
+			// Yay a match, and we have a from table, too
+			if ( ( $item['to_type'] == $to_type ) && !empty( $item['from_tablename'] ) ) {
+
+				// $from_tablename was set from a previous loop iteration
+				if ( ! empty( $from_tablename ) ) {
+
+					// Doing some joining
+					if ( !in_array( $item['from_tablename'], $from_tables ) && in_array( $item['join_tablename'], $from_tables ) ) {
+						$from_tablename .= ' ' . $item['join_type'] . ' JOIN ' . $this->opdb->prefix . $item['from_tablename'] . ' AS ' . $item['from_tablename'] . ' ' . $item['join_expression'];
+					}
+
+				// $from_tablename needs to be set
+				} else {
+					$from_tablename = $item['from_tablename'] . ' AS ' . $item['from_tablename'];
+				}
+
+				// Specific FROM expression data used
+				if ( !empty( $item['from_expression'] ) ) {
+
+					// No 'WHERE' in expression
+					if ( stripos( $from_tablename, "WHERE" ) === false ) {
+						$from_tablename .= ' ' . $item['from_expression'];
+
+					// 'WHERE' in expression, so replace with 'AND'
+					} else {
+						$from_tablename .= ' ' . str_replace( "WHERE", "AND", $item['from_expression'] );
+					}
+				}
+
+				// Add tablename and fieldname to arrays, formatted for querying
+				$from_tables[] = $item['from_tablename'];
+				$field_list[]  = 'convert(' . $item['from_tablename'] . '.' . $item['from_fieldname'] . ' USING "' . $this->charset . '") AS ' . $item['from_fieldname'];
+			}
+		}
+
+		/** Step 2 ************************************************************/
+
+		// We have a $from_tablename, so we want to get some data to convert
+		if ( !empty( $from_tablename ) ) {
+
+			// Get some data from the old forums
+			$field_list  = array_unique( $field_list );
+			$forum_query = 'SELECT ' . implode( ',', $field_list ) . ' FROM ' . $this->opdb->prefix . $from_tablename . ' LIMIT ' . $start . ', ' . $this->max_rows;
+			$forum_array = $this->opdb->get_results( $forum_query, ARRAY_A );
+
+			// Set this query as the last one ran
+			update_option( '_bbp_converter_query', $forum_query );
+
+			// Query returned some results
+			if ( !empty( $forum_array ) ) {
+
+				// Loop through results
+				foreach ( (array) $forum_array as $forum ) {
+
+					// Reset some defaults
+					$insert_post = $insert_postmeta = $insert_data = array();
+
+					// Loop through field map, again...
+					foreach ( $this->field_map as $row ) {
+
+						// Types matchand to_fieldname is present. This means
+						// we have some work to do here.
+						if ( ( $row['to_type'] == $to_type ) && ! is_null( $row['to_fieldname'] ) ) {
+
+							// This row has a destination that matches one of the
+							// columns in this table.
+							if ( in_array( $row['to_fieldname'], $tablefield_array ) ) {
+
+								// Allows us to set default fields.
+								if ( isset( $row['default'] ) ) {
+									$insert_post[$row['to_fieldname']] = $row['default'];
+
+								// Translates a field from the old forum.
+								} elseif ( isset( $row['callback_method'] ) ) {
+									if ( ( 'callback_userid' == $row['callback_method'] ) && empty( $_POST['_bbp_converter_convert_users'] ) ) {
+										$insert_post[$row['to_fieldname']] = $forum[$row['from_fieldname']];
+									} else {
+										$insert_post[$row['to_fieldname']] = call_user_func_array( array( $this, $row['callback_method'] ), array( $forum[$row['from_fieldname']], $forum ) );
+									}
+
+								// Maps the field from the old forum.
+								} else {
+									$insert_post[$row['to_fieldname']] = $forum[$row['from_fieldname']];
+								}
+
+							// Destination field is not empty, so we might need
+							// to do some extra work or set a default.
+							} elseif ( !empty( $row['to_fieldname'] ) ) {
+
+								// Allows us to set default fields.
+								if ( isset( $row['default'] ) ) {
+									$insert_postmeta[$row['to_fieldname']] = $row['default'];
+
+								// Translates a field from the old forum.
+								} elseif ( isset( $row['callback_method'] ) ) {
+									if ( ( $row['callback_method'] == 'callback_userid' ) && ( 0 == $_POST['_bbp_converter_convert_users'] ) ) {
+										$insert_postmeta[$row['to_fieldname']] = $forum[$row['from_fieldname']];
+									} else {
+										$insert_postmeta[$row['to_fieldname']] = call_user_func_array( array( $this, $row['callback_method'] ), array( $forum[$row['from_fieldname']], $forum ) );
+									}
+
+								// Maps the field from the old forum.
+								} else {
+									$insert_postmeta[$row['to_fieldname']] = $forum[$row['from_fieldname']];
+								}
+							}
+						}
+					}
+
+					/** Step 3 ************************************************/
+
+					// Something to insert into the destination field
+					if ( count( $insert_post ) > 0 || ( $to_type == 'tags' && count( $insert_postmeta ) > 0 ) ) {
+
+						switch ( $to_type ) {
+
+							/** New user **************************************/
+
+							case 'user':
+								if ( username_exists( $insert_post['user_login'] ) ) {
+									$insert_post['user_login'] = 'imported_' . $insert_post['user_login'];
+								}
+
+								if ( email_exists( $insert_post['user_email'] ) ) {
+									$insert_post['user_email'] = 'imported_' . $insert_post['user_email'];
+								}
+
+								$post_id = wp_insert_user( $insert_post );
+
+								if ( is_numeric( $post_id ) ) {
+
+									foreach ( $insert_postmeta as $key => $value ) {
+
+										add_user_meta( $post_id, $key, $value, true );
+
+										if ( '_id' == substr( $key, -3 ) && ( true === $this->sync_table ) ) {
+											$this->wpdb->insert( $this->sync_table_name, array( 'value_type' => 'user', 'value_id' => $post_id, 'meta_key' => $key, 'meta_value' => $value ) );
+										}
+									}
+								}
+								break;
+
+							/** New Topic-Tag *********************************/
+
+							case 'tags':
+								$post_id = wp_set_object_terms( $insert_postmeta['objectid'], $insert_postmeta['name'], 'topic-tag', true );
+								$term = get_term_by( 'name', $insert_postmeta['name'], 'topic-tag');
+								if ( false !== $term ) {
+									wp_update_term( $term->term_id, 'topic-tag', array(
+										'description' => $insert_postmeta['description'],
+										'slug'        => $insert_postmeta['slug']
+									) );
+								}
+ 								break;
+
+							/** Forum, Topic, Reply ***************************/
+
+							default:
+								$post_id = wp_insert_post( $insert_post );
+
+								if ( is_numeric( $post_id ) ) {
+
+									foreach ( $insert_postmeta as $key => $value ) {
+
+										add_post_meta( $post_id, $key, $value, true );
+
+										// Forums need to save their old ID for group forum association
+										if ( ( 'forum' == $to_type ) && ( '_bbp_forum_id' == $key ) )
+											add_post_meta( $post_id, '_bbp_old_forum_id', $value );
+
+										// Topics need an extra bit of metadata
+										// to be keyed to the new post_id
+										if ( ( 'topic' == $to_type ) && ( '_bbp_topic_id' == $key ) ) {
+
+											// Update the live topic ID
+											update_post_meta( $post_id, $key, $post_id );
+
+											// Save the old topic ID
+											add_post_meta( $post_id, '_bbp_old_topic_id', $value );
+											if ( '_id' == substr( $key, -3 ) && ( true === $this->sync_table ) ) {
+												$this->wpdb->insert( $this->sync_table_name, array( 'value_type' => 'post', 'value_id' => $post_id, 'meta_key' => '_bbp_topic_id',     'meta_value' => $post_id ) );
+												$this->wpdb->insert( $this->sync_table_name, array( 'value_type' => 'post', 'value_id' => $post_id, 'meta_key' => '_bbp_old_topic_id', 'meta_value' => $value   ) );
+											}
+
+										} elseif ( '_id' == substr( $key, -3 ) && ( true === $this->sync_table ) ) {
+											$this->wpdb->insert( $this->sync_table_name, array( 'value_type' => 'post', 'value_id' => $post_id, 'meta_key' => $key, 'meta_value' => $value ) );
+										}
+
+										// Replies need to save their old reply_to ID for hierarchical replies association
+										if ( ( 'reply' == $to_type ) && ( '_bbp_reply_to' == $key ) ) {
+											add_post_meta( $post_id, '_bbp_old_reply_to', $value );
+										}
+									}
+								}
+								break;
+						}
+						$has_insert = true;
+					}
+				}
+			}
+		}
+
+		return ! $has_insert;
+	}
+
+	/**
+	 * This method converts old forum heirarchy to new bbPress heirarchy.
+	 */
+	public function convert_forum_parents( $start ) {
+
+		$has_update = false;
+
+		if ( !empty( $this->sync_table ) ) {
+			$query = 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_forum_parent_id" AND meta_value > 0 LIMIT ' . $start . ', ' . $this->max_rows;
+		} else {
+			$query = 'SELECT post_id AS value_id, meta_value FROM ' . $this->wpdb->postmeta . ' WHERE meta_key = "_bbp_forum_parent_id" AND meta_value > 0 LIMIT ' . $start . ', ' . $this->max_rows;
+		}
+
+		update_option( '_bbp_converter_query', $query );
+
+		$forum_array = $this->wpdb->get_results( $query );
+
+		foreach ( (array) $forum_array as $row ) {
+			$parent_id = $this->callback_forumid( $row->meta_value );
+			$this->wpdb->query( 'UPDATE ' . $this->wpdb->posts . ' SET post_parent = "' . $parent_id . '" WHERE ID = "' . $row->value_id . '" LIMIT 1' );
+			$has_update = true;
+		}
+
+		return ! $has_update;
+	}
+
+	/**
+	 * This method converts old topic stickies to new bbPress stickies.
+	 *
+	 * @since bbPress (r)
+	 *
+	 * @uses WPDB $wpdb
+	 * @uses bbp_stick_topic() to set the imported topic as sticky
+	 *
+	 */
+	public function convert_topic_stickies( $start ) {
+
+		$has_update = false;
+
+		if ( !empty( $this->sync_table ) ) {
+			$query = 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_old_sticky_status" AND meta_value = "sticky" LIMIT ' . $start . ', ' . $this->max_rows;
+		} else {
+			$query = 'SELECT post_id AS value_id, meta_value FROM ' . $this->wpdb->postmeta . ' WHERE meta_key = "_bbp_old_sticky_status" AND meta_value = "sticky" LIMIT ' . $start . ', ' . $this->max_rows;
+		}
+
+		update_option( '_bbp_converter_query', $query );
+
+		$sticky_array = $this->wpdb->get_results( $query );
+
+		foreach ( (array) $sticky_array as $row ) {
+			bbp_stick_topic( $row->value_id );
+			$has_update = true;
+		}
+
+		return ! $has_update;
+	}
+
+	/**
+	 * This method converts old topic super stickies to new bbPress super stickies.
+	 *
+	 * @since bbPress (r)
+	 *
+	 * @uses WPDB $wpdb
+	 * @uses bbp_stick_topic() to set the imported topic as super sticky
+	 *
+	 */
+	public function convert_topic_super_stickies( $start ) {
+
+		$has_update = false;
+
+		if ( !empty( $this->sync_table ) ) {
+			$query = 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_old_sticky_status" AND meta_value = "super-sticky" LIMIT ' . $start . ', ' . $this->max_rows;
+		} else {
+			$query = 'SELECT post_id AS value_id, meta_value FROM ' . $this->wpdb->postmeta . ' WHERE meta_key = "_bbp_old_sticky_status" AND meta_value = "super-sticky" LIMIT ' . $start . ', ' . $this->max_rows;
+		}
+
+		update_option( '_bbp_converter_query', $query );
+
+		$sticky_array = $this->wpdb->get_results( $query );
+
+		foreach ( (array) $sticky_array as $row ) {
+			$super = true;
+			bbp_stick_topic( $row->value_id, $super );
+			$has_update = true;
+		}
+
+		return ! $has_update;
+	}
+
+	/**
+	 * This method converts old reply_to post id to new bbPress reply_to post id.
+	 */
+	public function convert_reply_to_parents( $start ) {
+
+		$has_update = false;
+
+		if ( !empty( $this->sync_table ) ) {
+			$query = 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_old_reply_to" AND meta_value > 0 LIMIT ' . $start . ', ' . $this->max_rows;
+		} else {
+			$query = 'SELECT post_id AS value_id, meta_value FROM ' . $this->wpdb->postmeta . ' WHERE meta_key = "_bbp_old_reply_to" AND meta_value > 0 LIMIT ' . $start . ', ' . $this->max_rows;
+		}
+
+		update_option( '_bbp_converter_query', $query );
+
+		$reply_to_array = $this->wpdb->get_results( $query );
+
+		foreach ( (array) $reply_to_array as $row ) {
+			$reply_to = $this->callback_reply_to( $row->meta_value );
+			$this->wpdb->query( 'UPDATE ' . $this->wpdb->postmeta . ' SET meta_value = "' . $reply_to . '" WHERE meta_key = "_bbp_reply_to" AND post_id = "' . $row->value_id . '" LIMIT 1' );
+			$has_update = true;
+		}
+
+		return ! $has_update;
+	}
+
+	/**
+	 * This method deletes data from the wp database.
+	 */
+	public function clean( $start ) {
+
+		$start      = 0;
+		$has_delete = false;
+
+		/** Delete bbconverter topics/forums/posts ****************************/
+
+		if ( true === $this->sync_table ) {
+			$query = 'SELECT value_id FROM ' . $this->sync_table_name . ' INNER JOIN ' . $this->wpdb->posts . ' ON(value_id = ID) WHERE meta_key LIKE "_bbp_%" AND value_type = "post" GROUP BY value_id ORDER BY value_id DESC LIMIT ' . $this->max_rows;
+		} else {
+			$query = 'SELECT post_id AS value_id FROM ' . $this->wpdb->postmeta . ' WHERE meta_key LIKE "_bbp_%" GROUP BY post_id ORDER BY post_id DESC LIMIT ' . $this->max_rows;
+		}
+
+		update_option( '_bbp_converter_query', $query );
+
+		$posts = $this->wpdb->get_results( $query, ARRAY_A );
+
+		if ( isset( $posts[0] ) && ! empty( $posts[0]['value_id'] ) ) {
+			foreach ( (array) $posts as $value ) {
+				wp_delete_post( $value['value_id'], true );
+			}
+			$has_delete = true;
+		}
+
+		/** Delete bbconverter users ******************************************/
+
+		if ( true === $this->sync_table ) {
+			$query = 'SELECT value_id FROM ' . $this->sync_table_name . ' INNER JOIN ' . $this->wpdb->users . ' ON(value_id = ID) WHERE meta_key = "_bbp_user_id" AND value_type = "user" LIMIT ' . $this->max_rows;
+		} else {
+			$query = 'SELECT user_id AS value_id FROM ' . $this->wpdb->usermeta . ' WHERE meta_key = "_bbp_user_id" LIMIT ' . $this->max_rows;
+		}
+
+		update_option( '_bbp_converter_query', $query );
+
+		$users = $this->wpdb->get_results( $query, ARRAY_A );
+
+		if ( !empty( $users ) ) {
+			foreach ( $users as $value ) {
+				wp_delete_user( $value['value_id'] );
+			}
+			$has_delete = true;
+		}
+
+		unset( $posts );
+		unset( $users );
+
+		return ! $has_delete;
+	}
+
+	/**
+	 * This method deletes passwords from the wp database.
+	 *
+	 * @param int Start row
+	 */
+	public function clean_passwords( $start ) {
+
+		$has_delete = false;
+
+		/** Delete bbconverter passwords **************************************/
+
+		$query       = 'SELECT user_id, meta_value FROM ' . $this->wpdb->usermeta . ' WHERE meta_key = "_bbp_password" LIMIT ' . $start . ', ' . $this->max_rows;
+		update_option( '_bbp_converter_query', $query );
+
+		$bbconverter = $this->wpdb->get_results( $query, ARRAY_A );
+
+		if ( !empty( $bbconverter ) ) {
+
+			foreach ( $bbconverter as $value ) {
+				if ( is_serialized( $value['meta_value'] ) ) {
+					$this->wpdb->query( 'UPDATE ' . $this->wpdb->users . ' ' . 'SET user_pass = "" ' . 'WHERE ID = "' . $value['user_id'] . '"' );
+				} else {
+					$this->wpdb->query( 'UPDATE ' . $this->wpdb->users . ' ' . 'SET user_pass = "' . $value['meta_value'] . '" ' . 'WHERE ID = "' . $value['user_id'] . '"' );
+					$this->wpdb->query( 'DELETE FROM ' . $this->wpdb->usermeta . ' WHERE meta_key = "_bbp_password" AND user_id = "' . $value['user_id'] . '"' );
+				}
+			}
+			$has_delete = true;
+		}
+
+		return ! $has_delete;
+	}
+
+	/**
+	 * This method implements the authentication for the different forums.
+	 *
+	 * @param string Unencoded password.
+	 */
+	abstract protected function authenticate_pass( $password, $hash );
+
+	/**
+	 * Info
+	 */
+	abstract protected function info();
+
+	/**
+	 * This method grabs appropriate fields from the table specified
+	 *
+	 * @param string The table name to grab fields from
+	 */
+	private function get_fields( $tablename ) {
+		$rval        = array();
+		$field_array = $this->wpdb->get_results( 'DESCRIBE ' . $tablename, ARRAY_A );
+
+		foreach ( $field_array as $field ) {
+			$rval[] = $field['Field'];
+		}
+
+		if ( $tablename == $this->wpdb->users ) {
+			$rval[] = 'role';
+			$rval[] = 'yim';
+			$rval[] = 'aim';
+			$rval[] = 'jabber';
+		}
+		return $rval;
+	}
+
+	/** Callbacks *************************************************************/
+
+	/**
+	 * Run password through wp_hash_password()
+	 *
+	 * @param string $username
+	 * @param string $password
+	 */
+	public function callback_pass( $username, $password ) {
+		$user = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT * FROM ' . $this->wpdb->users . ' WHERE user_login = "%s" AND user_pass = "" LIMIT 1', $username ) );
+		if ( !empty( $user ) ) {
+			$usermeta = $this->wpdb->get_row( 'SELECT * FROM ' . $this->wpdb->usermeta . ' WHERE meta_key = "_bbp_password" AND user_id = "' . $user->ID . '" LIMIT 1' );
+
+			if ( !empty( $usermeta ) ) {
+				if ( $this->authenticate_pass( $password, $usermeta->meta_value ) ) {
+					$this->wpdb->query( 'UPDATE ' . $this->wpdb->users . ' ' . 'SET user_pass = "' . wp_hash_password( $password ) . '" ' . 'WHERE ID = "' . $user->ID . '"' );
+					$this->wpdb->query( 'DELETE FROM ' . $this->wpdb->usermeta . ' WHERE meta_key = "_bbp_password" AND user_id = "' . $user->ID . '"' );
+				}
+			}
+		}
+	}
+
+	/**
+	 * A mini cache system to reduce database calls to forum ID's
+	 *
+	 * @param string $field
+	 * @return string
+	 */
+	private function callback_forumid( $field ) {
+		if ( !isset( $this->map_forumid[$field] ) ) {
+			if ( !empty( $this->sync_table ) ) {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_forum_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			} else {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT post_id AS value_id FROM ' . $this->wpdb->postmeta . ' WHERE meta_key = "_bbp_forum_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			}
+
+			if ( !is_null( $row ) ) {
+				$this->map_forumid[$field] = $row->value_id;
+			} else {
+				$this->map_forumid[$field] = 0;
+			}
+		}
+		return $this->map_forumid[$field];
+	}
+
+	/**
+	 * A mini cache system to reduce database calls to topic ID's
+	 *
+	 * @param string $field
+	 * @return string
+	 */
+	private function callback_topicid( $field ) {
+		if ( !isset( $this->map_topicid[$field] ) ) {
+			if ( !empty( $this->sync_table ) ) {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_old_topic_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			} else {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT post_id AS value_id FROM ' . $this->wpdb->postmeta . ' WHERE meta_key = "_bbp_old_topic_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			}
+
+			if ( !is_null( $row ) ) {
+				$this->map_topicid[$field] = $row->value_id;
+			} else {
+				$this->map_topicid[$field] = 0;
+			}
+		}
+		return $this->map_topicid[$field];
+	}
+
+	/**
+	 * A mini cache system to reduce database calls to reply_to post id.
+	 *
+	 * @param string $field
+	 * @return string
+	 */
+	private function callback_reply_to( $field ) {
+		if ( !isset( $this->map_reply_to[$field] ) ) {
+			if ( !empty( $this->sync_table ) ) {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_post_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			} else {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT post_id AS value_id FROM ' . $this->wpdb->postmeta . ' WHERE meta_key = "_bbp_post_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			}
+
+			if ( !is_null( $row ) ) {
+				$this->map_reply_to[$field] = $row->value_id;
+			} else {
+				$this->map_reply_to[$field] = 0;
+			}
+		}
+		return $this->map_reply_to[$field];
+	}
+
+	/**
+	 * A mini cache system to reduce database calls to user ID's
+	 *
+	 * @param string $field
+	 * @return string
+	 */
+	private function callback_userid( $field ) {
+		if ( !isset( $this->map_userid[$field] ) ) {
+			if ( !empty( $this->sync_table ) ) {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT value_id, meta_value FROM ' . $this->sync_table_name . ' WHERE meta_key = "_bbp_user_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			} else {
+				$row = $this->wpdb->get_row( $this->wpdb->prepare( 'SELECT user_id AS value_id FROM ' . $this->wpdb->usermeta . ' WHERE meta_key = "_bbp_user_id" AND meta_value = "%s" LIMIT 1', $field ) );
+			}
+
+			if ( !is_null( $row ) ) {
+				$this->map_userid[$field] = $row->value_id;
+			} else {
+				if ( !empty( $_POST['_bbp_converter_convert_users'] ) && ( $_POST['_bbp_converter_convert_users'] == 1 ) ) {
+					$this->map_userid[$field] = 0;
+				} else {
+					$this->map_userid[$field] = $field;
+				}
+			}
+		}
+		return $this->map_userid[$field];
+	}
+
+	/**
+	 * A mini cache system to reduce database calls map topics ID's to forum ID's
+	 *
+	 * @param string $field
+	 * @return string
+	 */
+	private function callback_topicid_to_forumid( $field ) {
+		$topicid = $this->callback_topicid( $field );
+		if ( empty( $topicid ) ) {
+			$this->map_topicid_to_forumid[$topicid] = 0;
+		} elseif ( ! isset( $this->map_topicid_to_forumid[$topicid] ) ) {
+			$row = $this->wpdb->get_row( 'SELECT post_parent FROM ' . $this->wpdb->posts . ' WHERE ID = "' . $topicid . '" LIMIT 1' );
+
+			if ( !is_null( $row ) ) {
+				$this->map_topicid_to_forumid[$topicid] = $row->post_parent;
+			} else {
+				$this->map_topicid_to_forumid[$topicid] = 0;
+			}
+		}
+
+		return $this->map_topicid_to_forumid[$topicid];
+	}
+
+	protected function callback_slug( $field ) {
+		return sanitize_title( $field );
+	}
+
+	protected function callback_negative( $field ) {
+		if ( $field < 0 ) {
+			return 0;
+		} else {
+			return $field;
+		}
+	}
+
+	protected function callback_html( $field ) {
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+
+	protected function callback_null( $field ) {
+		if ( is_null( $field ) ) {
+			return '';
+		} else {
+			return $field;
+		}
+	}
+
+	protected function callback_datetime( $field ) {
+		if ( is_numeric( $field ) ) {
+			return date( 'Y-m-d H:i:s', $field );
+		} else {
+			return date( 'Y-m-d H:i:s', strtotime( $field ) );
+		}
+	}
+}
+
+/**
+ * This is a function that is purposely written to look like a "new" statement.
+ * It is basically a dynamic loader that will load in the platform conversion
+ * of your choice.
+ *
+ * @param string $platform Name of valid platform class.
+ */
+function bbp_new_converter( $platform ) {
+	$found = false;
+
+	if ( $curdir = opendir( bbpress()->admin->admin_dir . 'converters/' ) ) {
+		while ( $file = readdir( $curdir ) ) {
+			if ( stristr( $file, '.php' ) && stristr( $file, 'index' ) === FALSE ) {
+				$file = preg_replace( '/.php/', '', $file );
+				if ( $platform == $file ) {
+					$found = true;
+					continue;
+				}
+			}
+		}
+		closedir( $curdir );
+	}
+
+	if ( true === $found ) {
+		require_once( bbpress()->admin->admin_dir . 'converters/' . $platform . '.php' );
+		return new $platform;
+	} else {
+		return null;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/AEF.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/AEF.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/AEF.php	(revision 5382)
@@ -0,0 +1,691 @@
+<?php
+
+/**
+ * Implementation of AEF Forum converter.
+ *
+ * @since bbPress (r5139)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/aef
+ */
+class AEF extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses AEF::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'fid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'par_board_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'ntopic',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'nposts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'ntopic',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'nposts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'fname',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'fname',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_order',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum status (Unlocked = 1 or Locked = 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'status',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_status',
+			'callback_method' => 'callback_forum_status'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'tid',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'n_posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'n_posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 't_bid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		// Note: We join the 'posts' table because 'topics' table does not include author id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'posts' table because 'topics' table does not include author ip.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_ip',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'posts' table because 'topics' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 't_bid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 't_sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		// Note: We join the 'posts' table because 'topics' table does not include topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.pid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open = 1 or Closed = 0, AEF v1.0.9)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 't_status',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * AEF v1.0.9 Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'pid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_fid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'poster_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'topics' table because 'posts' table does not include reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.tid = posts.post_tid WHERE topics.first_post_id != posts.pid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the 'topics' table because 'posts' table does not include reply slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.tid = posts.post_tid WHERE topics.first_post_id != posts.pid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ptime',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'salt',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'users',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'AEF'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'www',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'r_time',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'yim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_aef_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_aef_user_msn'
+		);
+
+		// Store Gmail (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'gmail',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_aef_user_gmail'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'sig',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_aef_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Location (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'location',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_aef_user_location'
+		);
+
+		// Store PrivateText (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'users_text',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_aef_user_private_text'
+		);
+
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum status from AEF v1.0.9 numeric's to WordPress's strings.
+	 *
+	 * @param int $status AEF v1.0.9 numeric forum status
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_status( $status = 1 ) {
+		switch ( $status ) {
+			case 0 :
+				$status = 'closed';
+				break;
+
+			case 1 :
+			default :
+				$status = 'open';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from AEF v1.0.9 numeric's to WordPress's strings.
+	 *
+	 * @param int $status AEF v1.0.9 numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 1 ) {
+		switch ( $status ) {
+			case 0 :
+				$status = 'closed';
+				break;
+
+			case 1  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from AEF 1.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status AEF 1.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // AEF Sticky 't_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // AEF normal topic 't_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count AEF v1.0.9 topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title AEF v1.0.9 topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Drupal7.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Drupal7.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Drupal7.php	(revision 5382)
@@ -0,0 +1,587 @@
+<?php
+
+/**
+ * Implementation of Drupal v7.x Forum converter.
+ *
+ * @since bbPress (r5138)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/drupal
+ */
+class Drupal7 extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Drupal7::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'taxonomy_term_data',
+			'from_fieldname' => 'tid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'taxonomy_term_hierarchy',
+			'from_fieldname'  => 'parent',
+			'join_tablename'  => 'taxonomy_term_data',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid)',
+			'from_expression' => 'LEFT JOIN taxonomy_vocabulary AS taxonomy_vocabulary USING (vid) WHERE module = "forum"',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'taxonomy_term_data',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'taxonomy_term_data',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'taxonomy_term_data',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'taxonomy_term_data',
+			'from_fieldname' => 'weight',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_index',
+			'from_fieldname' => 'nid',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'comment_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'comment_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		// Note: We join the 'node' table because 'forum_index' table does not include author id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'node',
+			'from_fieldname'  => 'uid',
+			'join_tablename'  => 'forum_index',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON node.nid = forum_index.nid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic content.
+		// Note: We join the 'field_data_body' table because 'node' or 'forum_index' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'field_data_body',
+			'from_fieldname'  => 'body_value',
+			'join_tablename'  => 'node',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON field_data_body.revision_id = node.vid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_index',
+			'from_fieldname' => 'title',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'created',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'created',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'last_comment_timestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'last_comment_timestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_index',
+			'from_fieldname'  => 'last_comment_timestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Drupal v7.x Comments Enabled no = 0, closed = 1 & open = 2)
+		$this->field_map[] = array(
+			'from_tablename'  => 'node',
+			'from_fieldname'  => 'comment',
+			'join_tablename'  => 'forum_index',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON node.nid = forum_index.nid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'field_data_field_tags',
+			'from_fieldname'  => 'entity_id',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Taxonomy ID.
+		$this->field_map[] = array(
+			'from_tablename'  => 'field_data_field_tags',
+			'from_fieldname'  => 'field_tags_tid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'taxonomy'
+		);
+
+		// Term name.
+		$this->field_map[] = array(
+			'from_tablename'  => 'taxonomy_term_data',
+			'from_fieldname'  => 'name',
+			'join_tablename'  => 'field_data_field_tags',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON field_tags_tid = taxonomy_term_data.tid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		// Term slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'taxonomy_term_data',
+			'from_fieldname'  => 'name',
+			'join_tablename'  => 'field_data_field_tags',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON field_tags_tid = taxonomy_term_data.tid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'slug',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Term description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'taxonomy_term_data',
+			'from_fieldname'  => 'description',
+			'join_tablename'  => 'field_data_field_tags',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON field_tags_tid = taxonomy_term_data.tid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'description'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'comment',
+			'from_fieldname' => 'cid',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		// Note: We join the 'forum' table because 'comment' table does not include parent forum id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'tid',
+			'join_tablename'  => 'comment',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON forum.nid = comment.nid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'nid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply parent reply id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'pid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_reply_to'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'comment',
+			'from_fieldname' => 'hostname',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'uid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename' => 'comment',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		// Note: We join the 'field_data_comment_body' table because 'comment' table does not include reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'field_data_comment_body',
+			'from_fieldname'  => 'comment_body_value',
+			'join_tablename'  => 'comment',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON field_data_comment_body.entity_id = comment.cid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'nid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'created',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'created',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'changed',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'comment',
+			'from_fieldname'  => 'changed',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'uid',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'pass',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password'
+//			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'pass',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'users',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'Drupal7'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'mail',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'created',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'signature',
+			'to_fieldname'    => '_bbp_drupal7_user_sig',
+			'to_type'         => 'user',
+			'callback_method' => 'callback_html'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the post status from Drupal v7.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Drupal v7.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 2 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 2  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from Drupal v7.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Drupal v7.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky'; // Drupal Sticky 'topic_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal'; // Drupal Normal Topic 'sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count Drupal v7.x topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Example.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Example.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Example.php	(revision 5382)
@@ -0,0 +1,635 @@
+<?php
+
+/**
+ * Example converter base impoprter template for bbPress
+ *
+ * @since bbPress (r4689)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/custom-import
+ */
+class Example extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Example_Converter::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Setup table joins for the forum section at the base of this section
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums_table',
+			'from_fieldname'  => 'the_forum_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums_table',
+			'from_fieldname'  => 'the_parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums_table',
+			'from_fieldname' => 'the_topic_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums_table',
+			'from_fieldname' => 'the_reply_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums_table',
+			'from_fieldname' => 'the_total_topic_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums_table',
+			'from_fieldname' => 'the_total_reply_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums_table',
+			'from_fieldname'  => 'the_forum_title',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums_table',
+			'from_fieldname'  => 'the_forum_slug',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums_table',
+			'from_fieldname'  => 'the_forum_description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums_table',
+			'from_fieldname'  => 'the_forum_order',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_date',
+			'default' => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_date_gmt',
+			'default' => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_modified',
+			'default' => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_modified_gmt',
+			'default' => date('Y-m-d H:i:s')
+		);
+
+		// Setup the table joins for the forum section
+		$this->field_map[] = array(
+			'from_tablename'  => 'groups_table',
+			'from_fieldname'  => 'forum_id',
+			'join_tablename'  => 'forums_table',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING groups_table.forum_id = forums_table.forum_id',
+		//	'from_expression' => 'WHERE forums_table.forum_id != 1',
+			'to_type'         => 'forum'
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Setup table joins for the topic section at the base of this section
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_reply_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_total_topic_reply_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_parent_forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_author_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_author_ip_address',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_content',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_slug',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_parent_forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_sticky_status',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_creation_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_creation_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_modified_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_modified_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_modified_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Setup any table joins needed for the topic section
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_topic_id',
+			'join_tablename'  => 'topics_table',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING replies_table.the_topic_id = topics_table.the_topic_id',
+			'from_expression' => 'WHERE forums_table.the_topic_id = 0',
+			'to_type'         => 'topic'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Setup table joins for the tag section at the base of this section
+		// Setup any table joins needed for the tags section
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag_table',
+			'from_fieldname'  => 'the_topic_id',
+			'join_tablename'  => 'tagcontent_table',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING tagcontent_table.tag_id = tags_table.tag_id',
+			'from_expression' => 'WHERE tagcontent_table.tag_id = tag_table.tag_id',
+			'to_type'         => 'tags'
+		);
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tagcontent_table',
+			'from_fieldname'  => 'contentid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Taxonomy ID.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tagcontent_table',
+			'from_fieldname'  => 'tagid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'taxonomy'
+		);
+
+		// Term text.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag_table',
+			'from_fieldname'  => 'tagtext',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		// Term slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag_table',
+			'from_fieldname'  => 'tagslug',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'slug',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Term description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag_table',
+			'from_fieldname'  => 'tagdescription',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'description'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Setup table joins for the reply section at the base of this section
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_parent_forum_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_parent_topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_author_ip_address',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_author_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_title',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_slug',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_content',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply order.
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_order',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'menu_order'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_parent_topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_creation_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_creation_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_modified_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'replies_table',
+			'from_fieldname'  => 'the_reply_modified_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Setup any table joins needed for the reply section
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics_table',
+			'from_fieldname'  => 'the_topic_id',
+			'join_tablename'  => 'replies_table',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING topics_table.the_topic_id = replies_table.the_topic_id',
+			'from_expression' => 'WHERE topics_table.first_post != 0',
+			'to_type'         => 'reply'
+		);
+
+		/** User Section ******************************************************/
+
+		// Setup table joins for the user section at the base of this section
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_password_salt',
+			'to_type'         => 'user',
+			'to_fieldname'    => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_class',
+			'default' => 'Example'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_username',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users_table',
+			'from_fieldname' => 'the_users_nicename',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_email_address',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_homepage_url',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_registration_date',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User status.
+		$this->field_map[] = array(
+			'from_tablename' => 'users_table',
+			'from_fieldname' => 'the_users_status',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_status'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users_table',
+			'from_fieldname' => 'the_users_display_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_aim',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_table',
+			'from_fieldname'  => 'the_users_yahoo',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'yim'
+		);
+
+		// User Jabber (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users_table',
+			'from_fieldname' => 'the_users_jabber',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'jabber'
+		);
+
+		// Setup any table joins needed for the user section
+		$this->field_map[] = array(
+			'from_tablename'  => 'users_profile_table',
+			'from_fieldname'  => 'the_users_id',
+			'join_tablename'  => 'users_table',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING users_profile_table.the_user_id = users_table.the_user_id',
+			'from_expression' => 'WHERE users_table.the_user_id != -1',
+			'to_type'         => 'user'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/FluxBB.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/FluxBB.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/FluxBB.php	(revision 5382)
@@ -0,0 +1,646 @@
+<?php
+
+/**
+ * Implementation of FluxBB Forum converter.
+ *
+ * @since bbPress (r5138)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/fluxbb
+ */
+class FluxBB extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses FluxBB::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_desc',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'disp_position',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'num_replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'num_replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		// Note: We join the 'posts' table because 'topics' table does include numeric user id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'posts' table because 'topics' table does not include author IP addresses.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_ip',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'posts' table because 'topics' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.first_post_id = posts.id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open = 0 or Closed = 1, FluxBB v1.5.3)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * FluxBB v1.5.3 Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'poster_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'topics' table because 'posts' table does not include reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.id = posts.topic_id WHERE topics.first_post_id != posts.id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the 'topics' table because 'posts' table does not include slug title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON topics.id = posts.topic_id WHERE topics.first_post_id != posts.id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+//		$this->field_map[] = array(
+//			'from_tablename' => 'users',
+//			'from_fieldname' => 'salt',
+//			'to_type'        => 'user',
+//			'to_fieldname'   => ''
+//		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'users',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'FluxBB'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'url',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'registered',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'realname',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'yahoo',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+	// Store Jabber
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'jabber',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'jabber'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_fluxbb_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_fluxbb_user_msn'
+		);
+
+		// Store Location (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'location',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_fluxbb_user_location'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'signature',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_fluxbb_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Admin Note (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'admin_note',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_fluxbb_user_admin_note'
+		);
+
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the post status from FluxBB v1.5.3 numeric's to WordPress's strings.
+	 *
+	 * @param int $status FluxBB v1.5.3 numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from FluxBB v1.5.3 numeric's to WordPress's strings.
+	 *
+	 * @param int $status FluxBB v1.5.3 numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // FluxBB Sticky 'sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // FluxBB Normal Topic 'sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count FluxBB v1.5.3 topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title FluxBB v1.5.3 topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Invision.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Invision.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Invision.php	(revision 5382)
@@ -0,0 +1,646 @@
+<?php
+
+/**
+ * Implementation of Invision Power Board v3.x converter.
+ *
+ * @since bbPress (r4713)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/invision
+ */
+class Invision extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Invision::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals()	{
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'name_seo',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'position',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'menu_order'
+		);
+
+		// Forum type (Forum = 0 or Category = -1, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_date',
+			'default' => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_date_gmt',
+			'default' => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_modified',
+			'default' => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_modified_gmt',
+			'default' => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'starter_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic content.
+		// Note: We join the posts table because topics do not have content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON(topics.tid = posts.topic_id) WHERE posts.new_topic = 1',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'pinned',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'start_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'start_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'last_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'last_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'last_post',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'core_tags',
+			'from_fieldname'  => 'tag_meta_id',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Term text.
+		$this->field_map[] = array(
+			'from_tablename'  => 'core_tags',
+			'from_fieldname'  => 'tag_text',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'pid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ip_address',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'author_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the topics table because post table does not include topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'title',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON (topics.tid = posts.topic_id) WHERE posts.new_topic = 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'edit_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'edit_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'member_id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'members_pass_hash',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'members_pass_salt',
+			'to_type'         => 'user',
+			'to_fieldname'    => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_class',
+			'default' => 'Invision'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'email',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_email'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'joined',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'members_display_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * Translate the forum type from Invision numeric's to WordPress's strings.
+	 *
+	 * @param int $status Invision numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		if ( $status == -1 ) {
+			$status = 'category';
+		} else {
+			$status = 'forum';
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from Invision numeric's to WordPress's strings.
+	 *
+	 * @param int $status Invision numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // Invision Pinned Topic 'pinned = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // Invision Normal Topic 'pinned = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count Invision reply count
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title Invision topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		return array( 'hash' => $field, 'salt' => $row['members_pass_salt'] );
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $pass_array['salt'] ) . md5( $this->to_char( $password ) ) ) );
+	}
+
+	private function to_char( $input ) {
+		$output = "";
+		for ( $i = 0; $i < strlen( $input ); $i++ ) {
+			$j = ord( $input{$i} );
+			if ( ( $j >= 65 && $j <= 90 )
+				|| ( $j >= 97 && $j <= 122 )
+				|| ( $j >= 48 && $j <= 57 ) )
+			{
+				$output .= $input{$i};
+			} else {
+				$output .= "&#" . ord( $input{$i} ) . ";";
+			}
+		}
+		return $output;
+	}
+
+	/**
+	* This callback processes any custom BBCodes with parser.php
+	*/
+	protected function callback_html( $field ) {
+
+		// Strips Invision custom HTML first from $field before parsing $field to parser.php
+		$invision_markup = $field;
+		$invision_markup = html_entity_decode( $invision_markup );
+
+		// Replace '[html]' with '<pre><code>'
+		$invision_markup = preg_replace( '/\[html\]/', '<pre><code>',     $invision_markup );
+		// Replace '[/html]' with '</code></pre>'
+		$invision_markup = preg_replace( '/\[\/html\]/', '</code></pre>', $invision_markup );
+		// Replace '[sql]' with '<pre><code>'
+		$invision_markup = preg_replace( '/\[sql\]/', '<pre><code>',      $invision_markup );
+		// Replace '[/sql]' with '</code></pre>'
+		$invision_markup = preg_replace( '/\[\/sql\]/', '</code></pre>',  $invision_markup );
+		// Replace '[php]' with '<pre><code>'
+		$invision_markup = preg_replace( '/\[php\]/', '<pre><code>',      $invision_markup );
+		// Replace '[/php]' with '</code></pre>'
+		$invision_markup = preg_replace( '/\[\/php\]/', '</code></pre>',  $invision_markup );
+		// Replace '[xml]' with '<pre><code>'
+		$invision_markup = preg_replace( '/\[xml\]/', '<pre><code>',      $invision_markup );
+		// Replace '[/xml]' with '</code></pre>'
+		$invision_markup = preg_replace( '/\[\/xml\]/', '</code></pre>',  $invision_markup );
+		// Replace '[CODE]' with '<pre><code>'
+		$invision_markup = preg_replace( '/\[CODE\]/', '<pre><code>',     $invision_markup );
+		// Replace '[/CODE]' with '</code></pre>'
+		$invision_markup = preg_replace( '/\[\/CODE\]/', '</code></pre>', $invision_markup );
+
+		// Replace '[quote:XXXXXXX]' with '<blockquote>'
+		$invision_markup = preg_replace( '/\[quote:(.*?)\]/', '<blockquote>',                            $invision_markup );
+		// Replace '[quote="$1"]' with '<em>@$1 wrote:</em><blockquote>'
+		$invision_markup = preg_replace( '/\[quote="(.*?)":(.*?)\]/', '<em>@$1 wrote:</em><blockquote>', $invision_markup );
+		// Replace '[/quote:XXXXXXX]' with '</blockquote>'
+		$invision_markup = preg_replace( '/\[\/quote:(.*?)\]/', '</blockquote>',                         $invision_markup );
+
+		// Replace '[twitter]$1[/twitter]' with '<a href="https://twitter.com/$1">@$1</a>"
+		$invision_markup = preg_replace( '/\[twitter\](.*?)\[\/twitter\]/', '<a href="https://twitter.com/$1">@$1</a>', $invision_markup );
+
+		// Replace '[member='username']' with '@username"
+		$invision_markup = preg_replace( '/\[member=\'(.*?)\'\]/', '@$1 ', $invision_markup );
+
+		// Replace '[media]' with ''
+		$invision_markup = preg_replace( '/\[media\]/', '',   $invision_markup );
+		// Replace '[/media]' with ''
+		$invision_markup = preg_replace( '/\[\/media\]/', '', $invision_markup );
+
+		// Replace '[list:XXXXXXX]' with '<ul>'
+		$invision_markup = preg_replace( '/\[list\]/', '<ul>',                    $invision_markup );
+		// Replace '[list=1:XXXXXXX]' with '<ul>'
+		$invision_markup = preg_replace( '/\[list=1\]/', '<ul>',                  $invision_markup );
+		// Replace '[*:XXXXXXX]' with '<li>'
+		$invision_markup = preg_replace( '/\[\*\](.*?)\<br \/\>/', '<li>$1</li>', $invision_markup );
+		// Replace '[/list:u:XXXXXXX]' with '</ul>'
+		$invision_markup = preg_replace( '/\[\/list\]/', '</ul>',                 $invision_markup );
+
+		// Replace '[hr]' with '<hr>"
+		$invision_markup = preg_replace( '/\[hr\]/', '<hr>',     $invision_markup );
+
+		// Replace '[font=XXXXXXX]' with ''
+		$invision_markup = preg_replace( '/\[font=(.*?)\]/', '', $invision_markup );
+		// Replace '[/font]' with ''
+		$invision_markup = preg_replace( '/\[\/font\]/', '',     $invision_markup );
+
+		// Replace any Invision smilies from path '/sp-resources/forum-smileys/sf-smily.gif' with the equivelant WordPress Smilie
+		$invision_markup = preg_replace( '/\<img src=(.*?)EMO\_DIR(.*?)bbc_emoticon(.*?)alt=\'(.*?)\' \/\>/', '$4', $invision_markup );
+		$invision_markup = preg_replace( '/\:angry\:/',    ':mad:',     $invision_markup );
+		$invision_markup = preg_replace( '/\:mellow\:/',   ':neutral:', $invision_markup );
+		$invision_markup = preg_replace( '/\:blink\:/',    ':eek:',     $invision_markup );
+		$invision_markup = preg_replace( '/B\)/',          ':cool:',    $invision_markup );
+		$invision_markup = preg_replace( '/\:rolleyes\:/', ':roll:',    $invision_markup );
+		$invision_markup = preg_replace( '/\:unsure\:/',   ':???:',     $invision_markup );
+
+		// Now that Invision custom HTML has been stripped put the cleaned HTML back in $field
+		$field = $invision_markup;
+
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Kunena1.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Kunena1.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Kunena1.php	(revision 5382)
@@ -0,0 +1,546 @@
+<?php
+
+/**
+ * Implementation of Kunena v1.x Forums for Joomla Forum converter.
+ *
+ * @since bbPress (r5144)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/kunena/
+ */
+class Kunena1 extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Kunena1::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+    public function setup_globals() {
+
+        /** Forum Section *****************************************************/
+
+        // Forum id (Stored in postmeta)
+        $this->field_map[] = array(
+        	'from_tablename' => 'kunena_categories',
+        	'from_fieldname' => 'id',
+        	'to_type'        => 'forum',
+        	'to_fieldname'   => '_bbp_forum_id'
+		);
+
+        // Forum parent id (If no parent, then 0, Stored in postmeta)
+        $this->field_map[] = array(
+        	'from_tablename' => 'kunena_categories',
+        	'from_fieldname' => 'parent',
+        	'to_type'        => 'forum',
+        	'to_fieldname'   => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'numTopics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'numPosts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'numTopics',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'numPosts',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_reply_count'
+		);
+
+        // Forum title.
+        $this->field_map[] = array(
+        	'from_tablename' => 'kunena_categories',
+        	'from_fieldname' => 'name',
+        	'to_type'        => 'forum',
+        	'to_fieldname'   => 'post_title'
+		);
+
+        // Forum slug (Clean name to avoid conflicts)
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_categories',
+        	'from_fieldname'  => 'name',
+        	'to_type'         => 'forum',
+        	'to_fieldname'    => 'post_name',
+        	'callback_method' => 'callback_slug'
+		);
+
+        // Forum description.
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_categories',
+        	'from_fieldname'  => 'description',
+        	'to_type'         => 'forum',
+        	'to_fieldname'    => 'post_content',
+        	'callback_method' => 'callback_null'
+		);
+
+        // Forum display order (Starts from 1)
+        $this->field_map[] = array(
+        	'from_tablename' => 'kunena_categories',
+        	'from_fieldname' => 'ordering',
+        	'to_type'        => 'forum',
+        	'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = 0 or Forum > 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'parent',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum status (Open = 0 or Closed = 1, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'locked',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_status',
+			'callback_method' => 'callback_forum_status'
+		);
+
+        // Forum dates.
+        $this->field_map[] = array(
+        	'to_type'      => 'forum',
+        	'to_fieldname' => 'post_date',
+        	'default'      => date('Y-m-d H:i:s')
+		);
+        $this->field_map[] = array(
+        	'to_type'      => 'forum',
+        	'to_fieldname' => 'post_date_gmt',
+        	'default'      => date('Y-m-d H:i:s')
+		);
+        $this->field_map[] = array(
+        	'to_type'      => 'forum',
+        	'to_fieldname' => 'post_modified',
+        	'default'      => date('Y-m-d H:i:s')
+		);
+        $this->field_map[] = array(
+        	'to_type'      => 'forum',
+        	'to_fieldname' => 'post_modified_gmt',
+        	'default'      => date('Y-m-d H:i:s')
+		);
+
+        /** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_messages',
+			'from_fieldname' => 'thread',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'catid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'userid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'ip',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages_text',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'kunena_messages',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON kunena_messages_text.mesid = kunena_messages.id WHERE kunena_messages.parent = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_messages',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'catid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open or Closed, Kunena v3.x 0=open & 1=closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'locked',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+        /** Tags Section ******************************************************/
+
+		/**
+		 * Kunena v1.x Forums do not support topic tags out of the box
+		 */
+
+        /** Reply Section *****************************************************/
+
+        // Reply id (Stored in postmeta)
+        $this->field_map[] = array(
+        	'from_tablename' => 'kunena_messages',
+        	'from_fieldname' => 'id',
+        	'to_type'        => 'reply',
+        	'to_fieldname'   => '_bbp_post_id'
+		);
+
+        // Reply parent forum id (If no parent, then 0. Stored in postmeta)
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'catid',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => '_bbp_forum_id',
+        	'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+        // Reply parent topic id (If no parent, then 0. Stored in postmeta)
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'thread',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => '_bbp_topic_id',
+        	'callback_method' => 'callback_topicid'
+		);
+
+        // Reply author ip (Stored in postmeta)
+        $this->field_map[] = array(
+        	'from_tablename' => 'kunena_messages',
+        	'from_fieldname' => 'ip',
+        	'to_type'        => 'reply',
+        	'to_fieldname'   => '_bbp_author_ip'
+		);
+
+        // Reply author.
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'userid',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_author',
+        	'callback_method' => 'callback_userid'
+		);
+
+        // Reply title.
+        $this->field_map[] = array(
+        	'from_tablename' => 'kunena_messages',
+        	'from_fieldname' => 'subject',
+        	'to_type'        => 'reply',
+        	'to_fieldname'   => 'post_title',
+        	'callback_method' => 'callback_reply_title'
+		);
+
+        // Reply slug (Clean name to avoid conflicts)
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'subject',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_name',
+        	'callback_method' => 'callback_slug'
+		);
+
+        // Reply content.
+        // Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include reply content.
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages_text',
+        	'from_fieldname'  => 'message',
+        	'join_tablename'  => 'kunena_messages',
+        	'join_type'       => 'INNER',
+        	'join_expression' => 'ON kunena_messages.id = kunena_messages_text.mesid WHERE kunena_messages.parent != 0',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_content',
+        	'callback_method' => 'callback_html'
+		);
+
+        // Reply parent topic id (If no parent, then 0)
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'thread',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_parent',
+        	'callback_method' => 'callback_topicid'
+		);
+
+        // Reply dates.
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'time',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_date',
+        	'callback_method' => 'callback_datetime'
+		);
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'time',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_date_gmt',
+        	'callback_method' => 'callback_datetime'
+		);
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'time',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_modified',
+        	'callback_method' => 'callback_datetime'
+		);
+        $this->field_map[] = array(
+        	'from_tablename'  => 'kunena_messages',
+        	'from_fieldname'  => 'time',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_modified_gmt',
+        	'callback_method' => 'callback_datetime'
+		);
+
+        /** User Section ******************************************************/
+
+        //Note: We are importing the Joomla User details and the Kunena v1.x user profile details.
+
+        // Store old User id (Stored in usermeta)
+        $this->field_map[] = array(
+        	'from_tablename' => 'users',
+        	'from_fieldname' => 'id',
+        	'to_type'        => 'user',
+        	'to_fieldname'   => '_bbp_user_id'
+		);
+
+        // Store old User password (Stored in usermeta serialized with salt)
+        $this->field_map[] = array(
+        	'from_tablename'  => 'users',
+        	'from_fieldname'  => 'password',
+        	'to_type'         => 'user',
+        	'to_fieldname'    => '_bbp_password',
+        	'callback_method' => 'callback_savepass'
+		);
+
+        // Store old User Salt (This is only used for the SELECT row info for the above password save)
+//        $this->field_map[] = array(
+//        	'from_tablename' => 'user',
+//        	'from_fieldname' => 'salt',
+//        	'to_type'        => 'user',
+//        	'to_fieldname'   => ''
+//		);
+
+        // User password verify class (Stored in usermeta for verifying password)
+//        $this->field_map[] = array(
+//        	'to_type'      => 'user',
+//        	'to_fieldname' => '_bbp_class',
+//        	'default'      => 'Kunena1'
+//		);
+
+        // User name.
+        $this->field_map[] = array(
+        	'from_tablename' => 'users',
+        	'from_fieldname' => 'username',
+        	'to_type'        => 'user',
+        	'to_fieldname'   => 'user_login'
+		);
+
+        // User email.
+        $this->field_map[] = array(
+        	'from_tablename' => 'users',
+        	'from_fieldname' => 'email',
+        	'to_type'        => 'user',
+        	'to_fieldname'   => 'user_email'
+		);
+
+        // User registered.
+        $this->field_map[] = array(
+        	'from_tablename'  => 'users',
+        	'from_fieldname'  => 'registerDate',
+        	'to_type'         => 'user',
+        	'to_fieldname'    => 'user_registered',
+        	'callback_method' => 'callback_datetime'
+		);
+    }
+
+    /**
+     * This method allows us to indicates what is or is not converted for each
+     * converter.
+     */
+    public function info() {
+        return '';
+    }
+
+    /**
+     * This method is to save the salt and password together.  That
+     * way when we authenticate it we can get it out of the database
+     * as one value. Array values are auto sanitized by WordPress.
+     */
+    public function callback_savepass($field, $row) {
+        $pass_array = array('hash' => $field, 'salt' => $row['salt']);
+        return $pass_array;
+    }
+
+    /**
+     * This method is to take the pass out of the database and compare
+     * to a pass the user has typed in.
+     */
+    public function authenticate_pass($password, $serialized_pass) {
+        $pass_array = unserialize($serialized_pass);
+        return ( $pass_array['hash'] == md5(md5($password) . $pass_array['salt']) );
+    }
+
+	/**
+	 * Translate the forum type from Kunena v1.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v1.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		if ( $status == 0 ) {
+			$status = 'category';
+		} else {
+			$status = 'forum';
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the forum status from Kunena v1.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v1.x numeric forum status
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'open';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from Kunena v1.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v1.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title Kunena v1.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Kunena2.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Kunena2.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Kunena2.php	(revision 5382)
@@ -0,0 +1,588 @@
+<?php
+
+/**
+ * Implementation of Kunena v2.x Forums for Joomla Forum converter.
+ *
+ * @since bbPress (r5144)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/kunena/
+ */
+class Kunena2 extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Kunena2::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+    public function setup_globals() {
+
+    	/** Forum Section *****************************************************/
+
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'numTopics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'numPosts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'numTopics',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'numPosts',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'alias',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'ordering',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = 0 or Forum = >0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum status (Open = 0 or Closed = 1, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'locked',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_status',
+			'callback_method' => 'callback_forum_status'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_topics',
+			'from_fieldname' => 'id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'category_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_userid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'kunena_messages' table because 'kunena_topics' table does not include author ip.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'ip',
+			'join_tablename'  => 'kunena_topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (id)',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_message',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_topics',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'category_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'last_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'last_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'last_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open or Closed, Kunena v2.x 0=open & 1=closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'locked',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+        /** Tags Section ******************************************************/
+
+		/**
+		 * Kunena v2.x Forums do not support topic tags out of the box
+		 */
+
+ 		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'catid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'thread',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_messages',
+			'from_fieldname' => 'ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'userid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		// Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages_text',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'kunena_messages',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_messages_text.mesid = kunena_messages.id LEFT JOIN jos_kunena_topics AS kunena_topics ON kunena_messages.thread = kunena_topics.id WHERE kunena_messages.parent != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'thread',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+        /** User Section ******************************************************/
+
+        //Note: We are importing the Joomla User details and the Kunena v2.x user profile details.
+
+        // Store old User id (Stored in usermeta)
+        $this->field_map[] = array(
+            'from_tablename' => 'users',
+            'from_fieldname' => 'id',
+            'to_type'        => 'user',
+            'to_fieldname'   => '_bbp_user_id'
+        );
+
+        // Store old User password (Stored in usermeta serialized with salt)
+        $this->field_map[] = array(
+            'from_tablename'  => 'users',
+            'from_fieldname'  => 'password',
+            'to_type'         => 'user',
+            'to_fieldname'    => '_bbp_password',
+            'callback_method' => 'callback_savepass'
+        );
+
+        // Store old User Salt. This is only used for the SELECT row info for the above password save
+        /*
+        $this->field_map[] = array(
+            'from_tablename' => 'users',
+            'from_fieldname' => 'salt',
+            'to_type' => 'user',
+            'to_fieldname' => ''
+        );
+         */
+
+        // User password verify class. Stores in usermeta for verifying password.
+        /*
+        $this->field_map[] = array(
+            'to_type' => 'user',
+            'to_fieldname' => '_bbp_class',
+            'default' => 'Kunena2'
+        );
+         */
+
+        // User name.
+        $this->field_map[] = array(
+            'from_tablename' => 'users',
+            'from_fieldname' => 'username',
+            'to_type'        => 'user',
+            'to_fieldname'   => 'user_login'
+        );
+
+        // User email.
+        $this->field_map[] = array(
+            'from_tablename' => 'users',
+            'from_fieldname' => 'email',
+            'to_type'        => 'user',
+            'to_fieldname'   => 'user_email'
+        );
+
+        // User registered.
+        $this->field_map[] = array(
+            'from_tablename'  => 'users',
+            'from_fieldname'  => 'registerDate',
+            'to_type'         => 'user',
+            'to_fieldname'    => 'user_registered',
+            'callback_method' => 'callback_datetime'
+        );
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+    }
+
+    /**
+     * This method allows us to indicates what is or is not converted for each
+     * converter.
+     */
+    public function info() {
+        return '';
+    }
+
+    /**
+     * This method is to save the salt and password together.  That
+     * way when we authenticate it we can get it out of the database
+     * as one value. Array values are auto sanitized by WordPress.
+     */
+    public function callback_savepass($field, $row) {
+        $pass_array = array('hash' => $field, 'salt' => $row['salt']);
+        return $pass_array;
+    }
+
+    /**
+     * This method is to take the pass out of the database and compare
+     * to a pass the user has typed in.
+     */
+    public function authenticate_pass($password, $serialized_pass) {
+        $pass_array = unserialize($serialized_pass);
+        return ( $pass_array['hash'] == md5(md5($password) . $pass_array['salt']) );
+    }
+	/**
+	 * Translate the forum type from Kunena v2.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v2.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		if ( $status == 0 ) {
+			$status = 'category';
+		} else {
+			$status = 'forum';
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the forum status from Kunena v2.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v2.x numeric forum status
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'open';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from Kunena v2.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v2.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count Kunena v2.x topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title Kunena v2.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Kunena3.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Kunena3.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Kunena3.php	(revision 5382)
@@ -0,0 +1,815 @@
+<?php
+
+/**
+ * Implementation of Kunena v3.x Forums for Joomla Forum converter.
+ *
+ * @since bbPress (r5144)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/kunena/
+ */
+class Kunena3 extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Kunena3::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'numTopics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'numPosts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'numTopics',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'numPosts',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'alias',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_categories',
+			'from_fieldname' => 'ordering',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = 0 or Forum = >0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum status (Open = 0 or Closed = 1, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_categories',
+			'from_fieldname'  => 'locked',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_status',
+			'callback_method' => 'callback_forum_status'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_topics',
+			'from_fieldname' => 'id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'category_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_userid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'kunena_messages' table because 'kunena_topics' table does not include author ip.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'ip',
+			'join_tablename'  => 'kunena_topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (id)',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_message',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_topics',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'category_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'first_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'last_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'last_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'last_post_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open or Closed, Kunena v3.x 0=open & 1=closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_topics',
+			'from_fieldname'  => 'locked',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * Kunena v3.x Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section ******************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'catid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'thread',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_messages',
+			'from_fieldname' => 'ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'userid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename' => 'kunena_messages',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		// Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages_text',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'kunena_messages',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_messages_text.mesid = kunena_messages.id LEFT JOIN jos_kunena_topics AS kunena_topics ON kunena_messages.thread = kunena_topics.id WHERE kunena_messages.parent != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'thread',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_messages',
+			'from_fieldname'  => 'time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		//Note: We are importing the Joomla User details and the Kunena v3.x user profile details.
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+//		$this->field_map[] = array(
+//			'from_tablename' => 'users',
+//			'from_fieldname' => 'salt',
+//			'to_type'        => 'user',
+//			'to_fieldname'   => ''
+//		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'users',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'Kunena3'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'websiteurl',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'registerDate',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'aim',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'yim',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'yim'
+		);
+
+		// Store Google Tak (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'gtalk',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'jabber'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'icq',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'msn',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_msn'
+		);
+
+		// Store Skype (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'skype',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_skype'
+		);
+
+		// Store Twitter (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'twitter',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_twitter'
+		);
+
+		// Store Facebook (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'facebook',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_facebook'
+		);
+
+		// Store myspace (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'myspace',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_myspace'
+		);
+
+		// Store linkedin (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'linkedin',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_linkedin'
+		);
+
+		// Store delicious (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'delicious',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_delicious'
+		);
+
+		// Store friendfeed (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'friendfeed',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_friendfeed'
+		);
+
+		// Store digg (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'digg',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_digg'
+		);
+
+		// Store blogspot (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'blogspot',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_blogspot'
+		);
+
+		// Store flickr (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'flickr',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_flickr'
+		);
+
+		// Store bebo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'bebo',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_bebo'
+		);
+
+		// Store websitename (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'websitename',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_websitename'
+		);
+
+		// Store location (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'location',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_location'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'kunena_users',
+			'from_fieldname'  => 'signature',
+			'join_tablename'  => 'users',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON kunena_users.userid = users.id',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_kunena3_user_sig',
+			'callback_method' => 'callback_html'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum type from Kunena v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v3.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		if ( $status == 0 ) {
+			$status = 'category';
+		} else {
+			$status = 'forum';
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the forum status from Kunena v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v3.x numeric forum status
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'open';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from Kunena v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Kunena v3.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count Kunena v3.x topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title Kunena v3.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Mingle.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Mingle.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Mingle.php	(revision 5382)
@@ -0,0 +1,483 @@
+<?php
+
+/**
+ * Implementation of Mingle Forums converter.
+ *
+ * @since bbPress (r4691)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/mingle
+ */
+class Mingle extends BBP_Converter_Base {
+
+	/**
+	 * Main constructor
+	 *
+	 * @uses Mingle::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals()	{
+
+		/** Forum Section ******************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_forums',
+			'from_fieldname' => 'id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_forums',
+			'from_fieldname' => 'parent_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_parent_id'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_forums',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_forums',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_forums',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_forums',
+			'from_fieldname' => 'sort',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_date',
+			'default'        => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_date_gmt',
+			'default'        => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_modified',
+			'default'        => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_modified_gmt',
+			'default'        => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section ******************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_threads',
+			'from_fieldname' => 'id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'starter',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic content.
+		// Note: We join the forum_posts table because forum_topics do not have topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'text',
+			'join_tablename'  => 'forum_threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON forum_posts.parent_id = forum_threads.id GROUP BY forum_threads.id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_threads',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'status',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'last_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'last_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_threads',
+			'from_fieldname' => 'last_post',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_last_active_time'
+		);
+
+		// Topic status (Open or Closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * Mingle Forums do not support topic tags
+         */
+
+		/** Reply Section ******************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_posts',
+			'from_fieldname' => 'id',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_post_id'
+		);
+
+		// Setup reply section table joins
+		// We need join the 'forum_threads' table to only import replies
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_threads',
+			'from_fieldname'  => 'date',
+			'join_tablename'  => 'forum_posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON forum_posts.parent_id = forum_threads.id',
+			'from_expression' => 'WHERE forum_threads.subject != forum_posts.subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_last_active_time'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'author_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_posts',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'text',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_posts',
+			'from_fieldname'  => 'date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'ID',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_pass',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_password'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_login',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_nicename',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_url',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_registered',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_registered'
+		);
+
+		// User status.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_status',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_status'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'display_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together. That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		return false;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		return false;
+	}
+
+	/**
+	 * Translate the topic status from Mingle numeric's to WordPress's strings.
+	 *
+	 * @param int $status Mingle v1.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from Mingle numeric's to WordPress's strings.
+	 *
+	 * @param int $status Mingle numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 'sticky' :
+				$status = 'sticky';       // Mingle Sticky 'status = sticky'
+				break;
+
+			case 'open'  :
+			default :
+				$status = 'normal';       // Mingle Normal Topic 'status = open'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	* This callback processes any custom BBCodes with parser.php
+	*/
+	protected function callback_html( $field ) {
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+
+}
Index: /tags/2.5.4/includes/admin/converters/MyBB.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/MyBB.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/MyBB.php	(revision 5382)
@@ -0,0 +1,591 @@
+<?php
+
+/**
+ * Implementation of MyBB Forum converter.
+ *
+ * @since bbPress (r5140)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/mybb
+ */
+class MyBB extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses MyBB::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'fid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'pid',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'threads',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'disporder',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'threads',
+			'from_fieldname' => 'tid',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'uid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'ipaddress',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE replyto = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'posts' table because 'threads' table does not have content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE replyto = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'threads',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'lastpost',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'lastpost',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'lastpost',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open or Closed, MyBB v1.6.10 open = null & closed = 1)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * MyBB v1.6.10 Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'pid',
+			'from_expression' => 'WHERE replyto != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'ipaddress',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'uid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'edittime',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'edittime',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'uid',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'salt',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'users',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'MyBB'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'website',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'regdate',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'usertitle',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'yahoo',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_mybb_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_mybb_user_msn'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'signature',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_mybb_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the post status from MyBB v1.6.10 numeric's to WordPress's strings.
+	 *
+	 * @param int $status MyBB v1.6.10 numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from MyBB v1.6.10 numeric's to WordPress's strings.
+	 *
+	 * @param int $status MyBB v1.6.10 numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // MyBB Sticky 'topic_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // MyBB Normal Topic 'topic_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count MyBB v1.6.10 topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+}
Index: /tags/2.5.4/includes/admin/converters/PHPFox3.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/PHPFox3.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/PHPFox3.php	(revision 5382)
@@ -0,0 +1,652 @@
+<?php
+
+/**
+ * Implementation of PHPFox v3.x Forum converter.
+ *
+ * @since bbPress (r5146)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/phpfox
+ */
+class PHPFox3 extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses PHPFox3::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'forum_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'total_thread',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'total_post',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'total_thread',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'total_post',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'name_url',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'ordering',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Forum = 0 or Category = 1, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'is_category',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum status (0=Open or 1=Closed, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'is_closed',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_status',
+			'callback_method' => 'callback_forum_status'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_thread',
+			'from_fieldname' => 'thread_id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'total_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'total_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic content.
+		// Note: We join the 'forum_post_text' table because 'forum_thread' table does not include content.
+		// Note: We can use 'text' for original text OR 'text_parsed' for pre-parsed text output
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post_text',
+			'from_fieldname'  => 'text_parsed',
+			'join_tablename'  => 'forum_thread',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON forum_thread.start_id = forum_post_text.post_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum_thread',
+			'from_fieldname' => 'title',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'title_url',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic status (Open or Closed, PHPFox v3.5.x 0=open & 1=closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'is_closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'order_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'time_stamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'time_stamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'time_update',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'time_update',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'time_update',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'item_id',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Taxonomy ID.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'tag_id',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'taxonomy'
+		);
+
+		// Term text.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'tag_text',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		// Term slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'tag_url',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'slug',
+			'callback_method' => 'callback_slug'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'post_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'forum_id',
+			'join_tablename'  => 'forum_post',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (thread_id)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'thread_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'title',
+			'join_tablename'  => 'forum_post',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (thread_id)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_thread',
+			'from_fieldname'  => 'title_url',
+			'join_tablename'  => 'forum_post',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (thread_id)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		// Note: We join the 'forum_post_text' table because 'forum_post' table does not include content.
+		// Note: We can use 'text' for original text OR 'text_parsed' for pre-parsed text output
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post_text',
+			'from_fieldname'  => 'text_parsed',
+			'join_tablename'  => 'forum_post',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON forum_post_text.post_id = forum_post.post_id WHERE forum_thread.start_id != forum_post.post_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'thread_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'time_stamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'time_stamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'time_stamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum_post',
+			'from_fieldname'  => 'time_stamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'user_id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'password_salt',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'user',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'PHPFox3'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'user_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'user_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'joined',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'full_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum type from PHPFox v3.5.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status PHPFox v3.5.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'category';
+				break;
+
+			case 0  :
+			default :
+				$status = 'forum';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the forum status from PHPFox v3.5.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status PHPFox v3.5.x numeric forum status
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'open';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from PHPFox v3.5.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status PHPFox v3.5.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from PHPFox v3.5.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status PHPFox v3.5.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // PHPFox Sticky 'topic_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // PHPFox Normal Topic 'topic_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count PHPFox v3.5.x topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title PHPFox v3.5.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/PHPWind.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/PHPWind.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/PHPWind.php	(revision 5382)
@@ -0,0 +1,585 @@
+<?php
+
+/**
+ * Implementation of PHPWind Forum converter.
+ *
+ * @since bbPress (r5142)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/phpwind
+ */
+class PHPWind extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses PHPWind::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'bbs_forum',
+			'from_fieldname' => 'fid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum',
+			'from_fieldname'  => 'parentid',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum_statistics',
+			'from_fieldname'  => 'threads',
+			'join_tablename'  => 'bbs_forum',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (fid)',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum_statistics',
+			'from_fieldname'  => 'posts',
+			'join_tablename'  => 'bbs_forum',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (fid)',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum_statistics',
+			'from_fieldname'  => 'threads',
+			'join_tablename'  => 'bbs_forum',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (fid)',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum_statistics',
+			'from_fieldname'  => 'posts',
+			'join_tablename'  => 'bbs_forum',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (fid)',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'bbs_forum',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum',
+			'from_fieldname'  => 'descrip',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'bbs_forum',
+			'from_fieldname' => 'vieworder',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = category or Forum = forum, sub or sub2,  Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_forum',
+			'from_fieldname'  => 'type',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'bbs_forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'bbs_forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'bbs_forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'bbs_forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'bbs_threads',
+			'from_fieldname' => 'tid',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'created_userid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'created_ip',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'bbs_threads_content' table because 'bbs_threads' table does not have content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads_content',
+			'from_fieldname'  => 'content',
+			'join_tablename'  => 'bbs_threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid)',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'bbs_threads',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'created_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'created_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'lastpost_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'lastpost_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'lastpost_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open or Closed, PHPWind v9.x 0=no, 1=closed & 2=open)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'tpcstatus',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * PHPWind v9.x Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'bbs_posts',
+			'from_fieldname' => 'pid',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'bbs_posts',
+			'from_fieldname' => 'created_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'created_userid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'bbs_threads' table because 'bbs_posts' table does not include reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'bbs_posts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (tid)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the 'bbs_threads' table because 'bbs_posts' table does not include reply slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_threads',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'bbs_posts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (tid)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'content',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'created_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'created_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'created_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'bbs_posts',
+			'from_fieldname'  => 'created_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'uid',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password'
+//			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+/*		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'pass',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+*/
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'user',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'PHPWind'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'regdate',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'realname',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum type from PHPWind v9.x Capitalised case to WordPress's non-capatilise case strings.
+	 *
+	 * @param int $status PHPWind v9.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 1 ) {
+		switch ( $status ) {
+			case 'category' :
+				$status = 'category';
+				break;
+
+			case 'sub' :
+				$status = 'forum';
+				break;
+
+			case 'sub2' :
+				$status = 'forum';
+				break;
+
+			case 'forum' :
+			default :
+				$status = 'forum';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from PHPWind v9.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status PHPWind v9.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 2 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 2  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count PHPWind v9.x topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+}
Index: /tags/2.5.4/includes/admin/converters/Phorum.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Phorum.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Phorum.php	(revision 5382)
@@ -0,0 +1,545 @@
+<?php
+
+/**
+ * Implementation of Phorum Forum converter.
+ *
+ * @since bbPress (r5141)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/phorum
+ */
+class Phorum extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Phorum::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'parent_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'thread_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'message_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'display_order',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = 1 or Forum = 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'folder_flag',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'thread',
+			'from_expression' => 'WHERE parent_id = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'thread_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'thread_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'ip',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'body',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'messages',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// Topic status (Open = 0 or Closed = 1)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * Phorum v5.2.19 Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'message_id',
+			'from_expression' => 'WHERE parent_id != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'thread',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'messages',
+			'from_fieldname' => 'ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename' => 'messages',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'body',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'thread',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'datestamp',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+//		$this->field_map[] = array(
+//			'from_tablename' => 'users',
+//			'from_fieldname' => 'salt',
+//			'to_type'        => 'user',
+//			'to_fieldname'   => ''
+//		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'users',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'Phorum'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'display_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'date_added',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'real_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'signature',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phorum_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum type from Phorum v5.2.19 numeric's to WordPress's strings.
+	 *
+	 * @param int $status Phorum v5.2.19 numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'category';
+				break;
+
+			case 0  :
+			default :
+				$status = 'forum';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from Phorum v5.2.19 numeric's to WordPress's strings.
+	 *
+	 * @param int $status Phorum v5.2.19 numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count Phorum v5.2.19 topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+}
Index: /tags/2.5.4/includes/admin/converters/PunBB.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/PunBB.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/PunBB.php	(revision 5382)
@@ -0,0 +1,680 @@
+<?php
+
+/**
+ * Implementation of PunBB v1.4.2 Forum converter.
+ *
+ * @since bbPress (r5153)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/punbb
+ */
+class PunBB extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses PunBB::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'num_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_desc',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'disp_position',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'num_replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'num_replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		// Note: We join the 'posts' table because 'topics' table does not have user id's.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.first_post_id = posts.id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'posts' table because 'topics' table does not have author ip.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_ip',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.first_post_id = posts.id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'posts' table because 'topics' table does not have content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.first_post_id = posts.id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic status (Open or Closed, PunBB v1.4.2 0=open & 1=closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'last_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'last_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'last_post',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * PunBB v1.4.2 Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		// Note: We join the 'topics' table because 'posts' table does not have parent forum id's.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id = posts.topic_id WHERE topics.first_post_id != posts.id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'poster_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'topics' table because 'posts' table does not have topic subject.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id = posts.topic_id WHERE topics.first_post_id != posts.id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the 'topics' table because 'posts' table does not have topic subject.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id = posts.topic_id WHERE topics.first_post_id != posts.id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'posted',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'edited',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'edited',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'salt',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'users',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'PunBB'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'url',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'registered',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'realname',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'yahoo',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// Store Jabber
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'jabber',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'jabber'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_msn'
+		);
+
+		// Store Facebook (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'facebook',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_facebook'
+		);
+
+		// Store Twitter (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'twitter',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_twitter'
+		);
+
+		// Store LinkedIn (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'linkedin',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_linkedin'
+		);
+
+		// Store Skype (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'skype',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_skype'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'signature',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Location (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'location',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_from'
+		);
+
+		// Store Admin Note (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'admin_note',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_punbb_user_admin_note'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the post status from PunBB v1.4.2 numeric's to WordPress's strings.
+	 *
+	 * @param int $status PunBB v1.4.2 numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from PunBB v1.4.2 numeric's to WordPress's strings.
+	 *
+	 * @param int $status PunBB v1.4.2 numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // PunBB Sticky 'topic_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // PunBB Normal Topic 'topic_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count PunBB v1.4.2 topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title PunBB v1.4.2 topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/SMF.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/SMF.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/SMF.php	(revision 5382)
@@ -0,0 +1,740 @@
+<?php
+
+/**
+ * Implementation of SMF Forum converter.
+ *
+ * @since bbPress (r5189)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/smf
+ */
+class SMF extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses SMF::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section ******************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'boards',
+			'from_fieldname' => 'id_board',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'boards',
+			'from_fieldname'  => 'id_parent',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'boards',
+			'from_fieldname' => 'num_topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'boards',
+			'from_fieldname' => 'num_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'boards',
+			'from_fieldname' => 'num_topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'boards',
+			'from_fieldname' => 'num_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'boards',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'boards',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'boards',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'boards',
+			'from_fieldname' => 'board_order',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section ******************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'id_topic',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'num_replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'num_replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'id_board',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'id_member_started',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_ip',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'messages' table because 'topics' table does not have content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'body',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'id_board',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic status (Open or Closed, SMF v2.0.4 0=open & 1=closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'locked',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'is_sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * SMF v2.0.4 Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section ******************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'id_msg',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'id_board',
+			'join_tablename'  => 'messages',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (id_topic) WHERE topics.id_first_msg != messages.id_msg',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'id_topic',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'messages',
+			'from_fieldname' => 'poster_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'id_member',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename' => 'messages',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'body',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'id_topic',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'messages',
+			'from_fieldname'  => 'poster_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'id_member',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'passwd',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'user',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'SMF'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'member_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'member_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'email_address',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'website_url',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'date_registered',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'real_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'yim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_smf_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_smf_user_msn'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'signature',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_smf_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Avatar (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'avatar',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_smf_user_avatar',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Location (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'location',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_smf_user_location',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Personal Text (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'personal_text',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_smf_user_personal_text',
+			'callback_method' => 'callback_html'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'username' => $row['member_name'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] === sha1( strtolower( $pass_array['username'] ) . $password ) ? true : false );
+	}
+
+	/**
+	 * Translate the post status from SMF v2.0.4 numeric's to WordPress's strings.
+	 *
+	 * @param int $status SMF v2.0.4 numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from SMF v2.0.4 numeric's to WordPress's strings.
+	 *
+	 * @param int $status SMF v2.0.4 numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky'; // SMF Sticky 'is_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal'; // SMF normal topic 'is_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count SMF v2.0.4 topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title SMF v2.0.4 topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * This callback processes any custom parser.php attributes and custom code with preg_replace
+	 */
+	protected function callback_html( $field ) {
+
+		// Strips SMF custom HTML first from $field before parsing $field to parser.php
+		$SMF_markup = $field;
+		$SMF_markup = html_entity_decode( $SMF_markup );
+
+		// Replace '[quote]' with '<blockquote>'
+		$SMF_markup = preg_replace( '/\[quote\]/',        '<blockquote>',  $SMF_markup );
+		// Replace '[quote ($1)]' with '<blockquote>"
+		$SMF_markup = preg_replace( '/\[quote (.*?)\]/' , '<blockquote>',  $SMF_markup );
+		// Replace '[/quote]' with '</blockquote>'
+		$SMF_markup = preg_replace( '/\[\/quote\]/',      '</blockquote>', $SMF_markup );
+
+		// Replace '[glow]' with ''
+		$SMF_markup = preg_replace( '/\[glow\]/',   '',       $SMF_markup );
+		// Replace '[glow]' with ''
+		$SMF_markup = preg_replace( '/\[glow=(.*?)\]/',   '', $SMF_markup );
+		// Replace '[/glow]' with ''
+		$SMF_markup = preg_replace( '/\[\/glow\]/', '',       $SMF_markup );
+
+		// Replace '[shadow]' with ''
+		$SMF_markup = preg_replace( '/\[shadow\]/',   '',       $SMF_markup );
+		// Replace '[shadow]' with ''
+		$SMF_markup = preg_replace( '/\[shadow=(.*?)\]/',   '', $SMF_markup );
+		// Replace '[/shadow]' with ''
+		$SMF_markup = preg_replace( '/\[\/shadow\]/', '',       $SMF_markup );
+
+		// Replace '[move]' with ''
+		$SMF_markup = preg_replace( '/\[move\]/',   '', $SMF_markup );
+		// Replace '[/move]' with ''
+		$SMF_markup = preg_replace( '/\[\/move\]/', '', $SMF_markup );
+
+		// Replace '[table]' with '<table>'
+		$SMF_markup = preg_replace( '/\[table\]/',   '<table>',  $SMF_markup );
+		// Replace '[/table]' with '</table>'
+		$SMF_markup = preg_replace( '/\[\/table\]/', '</table>', $SMF_markup );
+		// Replace '[tr]' with '<tr>'
+		$SMF_markup = preg_replace( '/\[tr\]/',   '<tr>',  $SMF_markup );
+		// Replace '[/tr]' with '</tr>'
+		$SMF_markup = preg_replace( '/\[\/tr\]/', '</tr>', $SMF_markup );
+		// Replace '[td]' with '<td>'
+		$SMF_markup = preg_replace( '/\[td\]/',   '<td>',  $SMF_markup );
+		// Replace '[/td]' with '</td>'
+		$SMF_markup = preg_replace( '/\[\/td\]/', '</td>', $SMF_markup );
+
+		// Replace '[list]' with '<ul>'
+		$phpbb_uid = preg_replace( '/\[list\]/',     '<ul>',          $phpbb_uid );
+		// Replace '[liist type=decimal]' with '<ol type="a">'
+		$phpbb_uid = preg_replace( '/\[list\ type=decimal\]/',   '<ol type="a">', $phpbb_uid );
+		// Replace '[li]' with '<li>'
+		$SMF_markup = preg_replace( '/\[li\]/',   '<li>',  $SMF_markup );
+		// Replace '[/li]' with '</li>'
+		$SMF_markup = preg_replace( '/\[\/li\]/', '</li>', $SMF_markup );
+
+		// Replace '[tt]' with '<tt>'
+		$SMF_markup = preg_replace( '/\[tt\]/',   '<tt>',  $SMF_markup );
+		// Replace '[/tt]' with '</tt>'
+		$SMF_markup = preg_replace( '/\[\/tt\]/', '</tt>', $SMF_markup );
+
+		// Replace '<br />' with ''
+		$SMF_markup = preg_replace( '/\<br \/\>/',   '<tt>',  $SMF_markup );
+
+		// Replace '[size=$1]' with '<span style="font-size:$1%;">$3</span>'
+		$SMF_markup = preg_replace( '/\[size=(.*?)\]/', '<span style="font-size:$1">', $SMF_markup );
+		// Replace '[/size]' with '</span>'
+		$SMF_markup = preg_replace( '/\[\/size\]/',     '</span>',                     $SMF_markup );
+
+		// Now that SMF custom HTML has been stripped put the cleaned HTML back in $field
+		$field = $SMF_markup;
+
+		// Parse out any bbCodes in $field with the BBCode 'parser.php'
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/SimplePress5.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/SimplePress5.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/SimplePress5.php	(revision 5382)
@@ -0,0 +1,582 @@
+<?php
+
+/**
+ * Implementation of SimplePress v5 converter.
+ *
+ * @since bbPress (r4638)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/simplepress/
+ */
+class SimplePress5 extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses SimplePress5::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'forum_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'parent',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'topic_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'post_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'topic_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'post_count',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'forum_name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfforums',
+			'from_fieldname'  => 'forum_name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfforums',
+			'from_fieldname'  => 'forum_desc',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfforums',
+			'from_fieldname' => 'forum_seq',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forums',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forums',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forums',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forums',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sftopics',
+			'from_fieldname' => 'topic_id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sftopics',
+			'from_fieldname' => 'post_count',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic content.
+		// Note: We join the sfposts table because sftopics do not have content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'post_content',
+			'join_tablename'  => 'sftopics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE sfposts.post_index = 1',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'sftopics',
+			'from_fieldname' => 'topic_name',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_name',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic status (Open or Closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_status',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_status'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_pinned',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * SimplePress Forums do not support topic tags without paid extensions
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfposts',
+			'from_fieldname' => 'post_id',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'sfposts',
+			'from_fieldname' => 'poster_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the sftopics table because sfposts table does not include topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_name',
+			'join_tablename'  => 'sfposts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (topic_id) WHERE sfposts.post_index != 1',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the sftopics table because sfposts table does not include topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sftopics',
+			'from_fieldname'  => 'topic_name',
+			'join_tablename'  => 'sfposts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (topic_id) WHERE sfposts.post_index != 1',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'post_content',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'sfposts',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'ID',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_pass',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_password'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_login',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_nicename',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_url',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_registered',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_registered'
+		);
+
+		// User status.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_status',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_status'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'display_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together. That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		return false;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		return false;
+	}
+
+	/**
+	 * Translate the post status from Simple:Press v5.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Simple:Press numeric status
+	 * @return string WordPress safe
+	 */
+	public function callback_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from Simple:Press v5.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Simple:Press v5.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // Simple:Press Sticky 'topic_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // Simple:Press Normal Topic 'topic_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count Simple:Press v5.x reply count
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title Simple:Press v5.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * This callback processes any custom parser.php attributes and custom HTML code with preg_replace
+	 */
+	protected function callback_html( $field ) {
+
+		// Strip any custom HTML not supported by parser.php first from $field before parsing $field to parser.php
+		$simplepress_markup = $field;
+		$simplepress_markup = html_entity_decode( $simplepress_markup );
+
+		// Replace any SimplePress smilies from path '/sp-resources/forum-smileys/sf-smily.gif' with the equivelant WordPress Smilie
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-confused\.gif(.*?)\" \/>/',     ':?' ,     $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-cool\.gif(.*?)\" \/>/',        ':cool:',   $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-cry\.gif(.*?)\" \/>/',         ':cry:',    $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-embarassed\.gif(.*?)\" \/>/' , ':oops:',   $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-frown\.gif(.*?)\" \/>/',       ':(',       $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-kiss\.gif(.*?)\" \/>/',        ':P',       $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-laugh\.gif(.*?)\" \/>/',       ':D',       $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-smile\.gif(.*?)\" \/>/',       ':smile:',  $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-surprised\.gif(.*?)\" \/>/',   ':o',       $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-wink\.gif(.*?)\" \/>/',        ':wink:',   $simplepress_markup );
+		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-yell\.gif(.*?)\" \/>/',         ':x',      $simplepress_markup );
+
+		// Replace '<div class="sfcode">example code</div>' with '<code>*</code>'
+		$simplepress_markup = preg_replace( '/\<div class\=\"sfcode\"\>(.*?)\<\/div\>/' , '<code>$1</code>' , $simplepress_markup );
+
+		// Replace '<strong>username said </strong>' with '@username said:'
+		$simplepress_markup = preg_replace ( '/\<strong\>(.*?)\ said\ \<\/strong\>/',     '@$1 said:',        $simplepress_markup );
+
+		// Replace '<p>&nbsp;</p>' with '<p>&nbsp;</p>'
+		$simplepress_markup = preg_replace ( '/\n(&nbsp;|[\s\p{Z}\xA0\x{00A0}]+)\r/', '<br>', $simplepress_markup );
+
+		// Now that SimplePress' custom HTML codes have been stripped put the cleaned HTML back in $field
+		$field = $simplepress_markup;
+
+		// Parse out any bbCodes with the BBCode 'parser.php'
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/Vanilla.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/Vanilla.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/Vanilla.php	(revision 5382)
@@ -0,0 +1,566 @@
+<?php
+
+/**
+ * Implementation of Vanilla 2.0.18.1 Converter
+ *
+ * @since bbPress (r4717)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/vanilla
+ */
+class Vanilla extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses Vanilla::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Category',
+			'from_fieldname'  => 'CategoryID',
+			'from_expression' => 'WHERE Category.CategoryID > 0',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Category',
+			'from_fieldname'  => 'ParentCategoryID',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id',
+			'callback_method' => 'callback_forum_parent'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'CountDiscussions',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'CountComments',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'CountDiscussions',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'CountComments',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'Name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Category',
+			'from_fieldname'  => 'Name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Category',
+			'from_fieldname'  => 'Description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'Sort',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'DateInserted',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_date',
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'DateInserted',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_date_gmt',
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'DateUpdated',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_modified',
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Category',
+			'from_fieldname' => 'DateUpdated',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_modified_gmt',
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'Discussion',
+			'from_fieldname' => 'DiscussionID',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'CountComments',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'CountComments',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'CategoryID',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'InsertUserID',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'Discussion',
+			'from_fieldname' => 'Name',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'Name',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'Body',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic status (Open or Closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Topic author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'InsertIPAddress',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'CategoryID',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename' => 'Discussion',
+			'from_fieldname' => 'DateInserted',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Discussion',
+			'from_fieldname' => 'DateInserted',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Discussion',
+			'from_fieldname' => 'DateUpdated',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Discussion',
+			'from_fieldname' => 'DateUpdated',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_modified_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Discussion',
+			'from_fieldname' => 'DateLastComment',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_last_active_time'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'TagDiscussion',
+			'from_fieldname'  => 'DiscussionID',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Taxonomy ID.
+		$this->field_map[] = array(
+			'from_tablename'  => 'TagDiscussion',
+			'from_fieldname'  => 'TagID',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'taxonomy'
+		);
+
+		// Term text.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Tag',
+			'from_fieldname'  => 'Name',
+			'join_tablename'  => 'TagDiscussion',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tagid)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Comment',
+			'from_fieldname'  => 'CommentID',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Comment',
+			'from_fieldname'  => 'DiscussionID',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'CategoryID',
+			'join_tablename'  => 'Comment',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (DiscussionID)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply title.
+		// Note: We join the Discussion table because Comment table does not include topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'Name',
+			'join_tablename'  => 'Comment',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (DiscussionID)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the Discussion table because Comment table does not include topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Discussion',
+			'from_fieldname'  => 'Name',
+			'join_tablename'  => 'Comment',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (DiscussionID)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'Comment',
+			'from_fieldname' => 'InsertIPAddress',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Comment',
+			'from_fieldname'  => 'InsertUserID',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'Comment',
+			'from_fieldname'  => 'Body',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'Comment',
+			'from_fieldname'  => 'DiscussionID',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename' => 'Comment',
+			'from_fieldname' => 'DateInserted',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Comment',
+			'from_fieldname' => 'DateInserted',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Comment',
+			'from_fieldname' => 'DateUpdated',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'Comment',
+			'from_fieldname' => 'DateUpdated',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_modified_gmt'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'User',
+			'from_fieldname'  => 'UserID',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'User',
+			'from_fieldname' => 'Password',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_password'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'User',
+			'from_fieldname' => 'Name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'User',
+			'from_fieldname' => 'Name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'User',
+			'from_fieldname' => 'Email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename' => 'User',
+			'from_fieldname' => 'DateInserted',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_registered'
+		);
+
+		// Display Name
+		$this->field_map[] = array(
+			'from_tablename' => 'User',
+			'from_fieldname' => 'Name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * Translate the topic status from Vanilla v2.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status Vanilla v2.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Clean Root Parent ID -1 to 0
+	 *
+	 * @param int $parent Vanilla v2.x Parent ID
+	 * @return int
+	 */
+	public function callback_forum_parent( $parent = 0 ) {
+		if ( $parent == -1 ) {
+			return 0;
+		} else {
+			return $parent;
+		}
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count Vanilla v2.x reply count
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title Vanilla v2.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * This method is to save the salt and password together. That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		return false;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		return false;
+	}
+
+	/**
+	* This callback processes any custom BBCodes with parser.php
+	*/
+	protected function callback_html( $field ) {
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/XMB.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/XMB.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/XMB.php	(revision 5382)
@@ -0,0 +1,709 @@
+<?php
+
+/**
+ * Implementation of XMB Forum converter.
+ *
+ * @since bbPress (r5143)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/xmb
+ */
+class XMB extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses XMB::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'fid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'fup',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'threads',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'threads',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'displayorder',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = 'group', Forum = 'forum' or 'sub', Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'type',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'threads',
+			'from_fieldname' => 'tid',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		// Note: We join the 'members' table because 'threads' table does not have numerical author id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'uid',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON threads.author = members.username',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'posts' table because 'threads' table does not have author ip.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'useip',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'posts' table because 'threads' table does not have content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'threads',
+			'from_fieldname' => 'subject',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'subject',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic status (Open or Closed, XMB v1.9.11.13 ''=open & 'yes'=closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'closed',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'topped',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		// Note: We join the 'posts' table because 'threads' table does not include dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'join_tablename'  => 'threads',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * XMB v1.9.11.13 Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'pid',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'fid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'useip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		// Note: We join the 'members' table because 'posts' table does not have numerical author id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'uid',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON posts.author = members.username',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'threads' table because 'posts' table does not have topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject = ""',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the 'threads' table because 'posts' table does not have topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'threads',
+			'from_fieldname'  => 'subject',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tid) WHERE posts.subject = ""',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'message',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'tid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'uid',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+//		$this->field_map[] = array(
+//			'from_tablename' => 'members',
+//			'from_fieldname' => 'salt',
+//			'to_type'        => 'user',
+//			'to_fieldname'   => ''
+//		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'members',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'XMB'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'site',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'regdate',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'yahoo',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_xmb_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_xmb_user_msn'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'sig',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_xmb_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Bio (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'members',
+			'from_fieldname'  => 'bio',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_xmb_user_bio',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Location (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'location',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_xmb_user_location'
+		);
+
+		// Store Avatar (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'avatar',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_xmb_user_avatar'
+		);
+
+		// Store Mood (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'members',
+			'from_fieldname' => 'mood',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_xmb_user_mood'
+		);
+
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info()
+	{
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum type from XMB v1.9.11.13 Capitalised case to WordPress's non-capatilise case strings.
+	 *
+	 * @param int $status XMB v1.9.11.13 numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 1 ) {
+		switch ( $status ) {
+			case 'group' :
+				$status = 'category';
+				break;
+
+			case 'sub' :
+				$status = 'forum';
+				break;
+
+			case 'forum' :
+			default :
+				$status = 'forum';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the post status from XMB v1.9.11.13 numeric's to WordPress's strings.
+	 *
+	 * @param int $status XMB v1.9.11.13 numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = '' ) {
+		switch ( $status ) {
+			case 'yes' :
+				$status = 'closed';
+				break;
+
+			case ''  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from XMB v1.9.11.13 numeric's to WordPress's strings.
+	 *
+	 * @param int $status XMB v1.9.11.13 numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // XMB Sticky 'topped = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // XMB Normal Topic 'topped = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic/reply count.
+	 *
+	 * @param int $count XMB v1.9.11.13 topic/reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title XMB v1.9.11.13 topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+}
Index: /tags/2.5.4/includes/admin/converters/XenForo.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/XenForo.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/XenForo.php	(revision 5382)
@@ -0,0 +1,725 @@
+<?php
+
+/**
+ *  Implementation of XenForo converter.
+ *
+ * @since bbPress (r5145)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/xenforo
+ */
+class XenForo extends BBP_Converter_Base {
+
+	/**
+	 * Main constructor
+	 *
+	 * @uses XenForo::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'node',
+			'from_fieldname'  => 'node_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'node',
+			'from_fieldname'  => 'parent_node_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		// Note: We join the 'forum' table because 'node' does not include topic counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'discussion_count',
+			'join_tablename'  => 'node',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		// Note: We join the 'forum' table because 'node' does not include reply counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'message_count',
+			'join_tablename'  => 'node',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		// Note: We join the 'forum' table because 'node' does not include topic counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'discussion_count',
+			'join_tablename'  => 'node',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		// Note: We join the 'forum' table because 'node' does not include reply counts.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'message_count',
+			'join_tablename'  => 'node',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'node',
+			'from_fieldname' => 'title',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		// 'node_name' only has slug for explictly named forums
+		$this->field_map[] = array(
+			'from_tablename'  => 'node',
+			'from_fieldname'  => 'node_name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'node',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'node',
+			'from_fieldname' => 'display_order',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = Category or Forum = Forum, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'node',
+			'from_fieldname'  => 'node_type_id',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum status (Unlocked = 1 or Locked = 0, Stored in postmeta)
+		// Note: We join the 'forum' table because 'node' does not include forum status.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'allow_posting',
+			'join_tablename'  => 'node',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_status',
+			'callback_method' => 'callback_forum_status'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'thread_id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'reply_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'reply_count',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'node_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'title',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic content.
+		// Note: We join the 'post' table because 'thread' table does not include content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'message',
+			'join_tablename'  => 'thread',
+			'join_type'       => 'INNER',
+			'join_expression' => 'ON thread.first_post_id = post.post_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic status (Open = 1 or Closed = 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'discussion_open',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'node_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'last_post_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'last_post_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'last_post_date',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * XenForo Forums do not support topic tags out of the box
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'post',
+			'from_fieldname' => 'post_id',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'thread_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'thread_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'user_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'thread' table because 'post' do not have titles.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'join_tablename'  => 'post',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (thread_id) WHERE thread.first_post_id != post.post_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the 'thread' table because 'post' do not have titles.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'join_tablename'  => 'post',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (thread_id) WHERE thread.first_post_id != post.post_id',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'message',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'thread_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'post_date',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'user_id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+/*		// User password.
+		// Note: We join the 'user_authenticate' table because 'user' does not include password.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user_authenticate',
+			'from_fieldname'  => 'data',
+			'join_tablename'  => 'user',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (user_id)',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_converter_password'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'salt',
+			'to_type'        => 'user',
+			'to_fieldname'   =>   ''
+		);
+*/
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_class',
+			'default'        => 'XenForo'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		// Note: We join the 'user_profile' table because 'user' does not include user homepage.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user_profile',
+			'from_fieldname'  => 'homepage',
+			'join_tablename'  => 'user',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (user_id)',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'register_date',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+
+		// Store Custom Title (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'custom_title',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_xenforo_user_custom_title'
+		);
+
+		// Store Status (Stored in usermeta)
+		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user status.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user_profile',
+			'from_fieldname'  => 'status',
+			'join_tablename'  => 'user',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (user_id)',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_xenforo_user_status'
+		);
+
+		// Store Signature (Stored in usermeta)
+		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user signature.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user_profile',
+			'from_fieldname'  => 'signature',
+			'join_tablename'  => 'user',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (user_id)',
+			'to_fieldname'    => '_bbp_xenforo_user_sig',
+			'to_type'         => 'user',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Location (Stored in usermeta)
+		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user location.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user_profile',
+			'from_fieldname'  => 'location',
+			'join_tablename'  => 'user',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (user_id)',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_xenforo_user_location'
+		);
+
+		// Store Occupation (Stored in usermeta)
+		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user occupation.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user_profile',
+			'from_fieldname'  => 'occupation',
+			'join_tablename'  => 'user',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (user_id)',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_xenforo_user_occupation'
+		);
+
+		// Store About (Stored in usermeta)
+		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user about.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user_profile',
+			'from_fieldname'  => 'about',
+			'join_tablename'  => 'user',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (user_id)',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_xenforo_user_about',
+			'callback_method' => 'callback_html'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by wordpress.
+	 */
+	public function translate_savepass( $field, $row )
+	{
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass )
+	{
+		$pass_array = unserialize( $serialized_pass );
+		switch( $pass_array['hashFunc'] )
+		{
+			case 'sha256':
+				return ( $pass_array['hash'] == hash( 'sha256', hash( 'sha256', $password ) . $pass_array['salt'] ) );
+			case 'sha1':
+				return ( $pass_array['hash'] == sha1( sha1( $password ) . $pass_array['salt'] ) );
+		}
+	}
+
+	/**
+	 * Translate the forum type from XenForo Capitalised case to WordPress's non-capatilise case strings.
+	 *
+	 * @param int $status XenForo numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 1 ) {
+		switch ( $status ) {
+			case 'Category' :
+				$status = 'category';
+				break;
+
+			case 'Forum' :
+			default :
+				$status = 'forum';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the forum status from XenForo numeric's to WordPress's strings.
+	 *
+	 * @param int $status XenForo numeric forum status
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_status( $status = 1 ) {
+		switch ( $status ) {
+			case 0 :
+				$status = 'closed';
+				break;
+
+			case 1 :
+			default :
+				$status = 'open';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic status from XenForo numeric's to WordPress's strings.
+	 *
+	 * @param int $status XenForo numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 1 ) {
+		switch ( $status ) {
+			case 0 :
+				$status = 'closed';
+				break;
+
+			case 1 :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from XenForo numeric's to WordPress's strings.
+	 *
+	 * @param int $status XenForo numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // XenForo Sticky 'sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // XenForo Normal Topic 'sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count XenForo reply count
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title XenForo topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/bbPress1.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/bbPress1.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/bbPress1.php	(revision 5382)
@@ -0,0 +1,671 @@
+<?php
+
+/**
+ * bbPress 1.1 Converter
+ *
+ * @since bbPress (r3816)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/bbpress-1-x-buddypress-group-forums
+ */
+class bbPress1 extends BBP_Converter_Base {
+
+	/**
+	 * Main constructor
+	 *
+	 * @uses bbPress1::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_parent',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		$this->field_map[] = array(
+			'from_tablename'   => 'forums',
+			'from_fieldname'   => 'forum_slug',
+			'to_type'          => 'forum',
+			'to_fieldname'     => 'post_name',
+			'callback_method'  => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'   => 'forums',
+			'from_fieldname'   => 'forum_desc',
+			'to_type'          => 'forum',
+			'to_fieldname'     => 'post_content',
+			'callback_method'  => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_order',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (bbPress v1.x Forum > 0 or Category = 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'meta',
+			'from_fieldname'  => 'meta_value',
+			'join_tablename'  => 'forums',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'ON meta.object_id = forums.forum_id AND meta.meta_key = "forum_is_category"',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_posts',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_poster',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_title',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_slug',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic content.
+		// Note: We join the 'posts' table because 'topics' table does not include content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_text',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_position IN (0,1)',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic status (Spam, Trash or Publish, bbPress v1.x publish = 0, trash = 1 & spam = 2)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_status',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_position IN (0,1)',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_status'
+		);
+
+		// Topic author ip (Stored in postmeta)
+		// Note: We join the 'posts' table because 'topics' table does not include author ip.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_ip',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_position IN (0,1)',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_start_time',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_start_time',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_time',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_time',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_modified_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_time',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_last_active_time'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'term_relationships',
+			'from_fieldname'  => 'object_id',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Taxonomy ID.
+		$this->field_map[] = array(
+			'from_tablename'  => 'term_taxonomy',
+			'from_fieldname'  => 'term_taxonomy_id',
+			'join_tablename'  => 'term_relationships',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (term_taxonomy_id)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'taxonomy'
+		);
+
+		// Term text.
+		$this->field_map[] = array(
+			'from_tablename'  => 'terms',
+			'from_fieldname'  => 'name',
+			'join_tablename'  => 'term_taxonomy',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (term_id)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		// Term slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'terms',
+			'from_fieldname'  => 'slug',
+			'join_tablename'  => 'term_taxonomy',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (term_id)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'slug',
+			'callback_method' => 'callback_slug'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Reply title.
+		// Note: We join the 'topics' table because 'posts' table does not include topic title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_title',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_position NOT IN (0,1)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		// Note: We join the 'topics' table because 'posts' table does not include topic slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_slug',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_position NOT IN (0,1)',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'poster_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply status (Spam, Trash or Publish, bbPress v1.x publish = 0, trash = 1 & spam = 2)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_status',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_status'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_text',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply order.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_position',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'menu_order'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'post_time',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_date'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'post_time',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_date_gmt'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'post_time',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_modified'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'post_time',
+			'to_type'        => 'reply',
+			'to_fieldname'   => 'post_modified_gmt'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'ID',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_pass',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_password'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_login',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User nice name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_nicename',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_nicename'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_url',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_registered',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_registered'
+		);
+
+		// User status.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_status',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_status'
+		);
+
+		// User display name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'display_name',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'display_name'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * Translate the post status from bbPress 1's numeric's to WordPress's
+	 * strings.
+	 *
+	 * @param int $status bbPress 1.x numeric post status
+	 * @return string WordPress safe
+	 */
+	public function callback_status( $status = 0 ) {
+		switch ( $status ) {
+			case 2 :
+				$status = 'spam';    // bbp_get_spam_status_id()
+				break;
+
+			case 1 :
+				$status = 'trash';   // bbp_get_trash_status_id()
+				break;
+
+			case 0  :
+			default :
+				$status = 'publish'; // bbp_get_public_status_id()
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the forum type from bbPress 1.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status bbPress 1.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		if ( $status == 1 ) {
+			$status = 'category';
+		} else {
+			$status = 'forum';
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from bbPress 1.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status bbPress 1.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 2 :
+				$status = 'super-sticky'; // bbPress Super Sticky 'topic_sticky = 2'
+				break;
+
+			case 1 :
+				$status = 'sticky';       // bbPress Sticky 'topic_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // bbPress Normal Topic 'topic_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count bbPress 1.x topic and reply counts
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title bbPress 1.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * This method is to save the salt and password together. That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		return false;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		return false;
+	}
+
+	/**
+	 * This callback:
+	 *
+	 * - turns off smiley parsing
+	 * - processes any custom parser.php attributes
+	 * - decodes necessary HTML entities
+	 */
+	protected function callback_html( $field ) {
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/index.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/index.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/admin/converters/phpBB.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/phpBB.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/phpBB.php	(revision 5382)
@@ -0,0 +1,914 @@
+<?php
+
+/**
+ * Implementation of phpBB v3 Converter.
+ *
+ * @since bbPress (r4689)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/phpbb
+ */
+class phpBB extends BBP_Converter_Base {
+
+	/**
+	 * Main Constructor
+	 *
+	 * @uses phpBB::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	public function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'parent_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_topics',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_topics_real',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_posts',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'forum_name',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_name',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_desc',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forums',
+			'from_fieldname' => 'left_id',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = 0 or Forum = 1, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_type',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum status (Unlocked = 0 or Locked = 1, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forums',
+			'from_fieldname'  => 'forum_status',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_status',
+			'callback_method' => 'callback_forum_status'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date('Y-m-d H:i:s')
+		);
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date('Y-m-d H:i:s')
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_id',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_replies',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_replies_real',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_poster',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_ip',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_id = topics.topic_first_post_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic content.
+		// Note: We join the 'posts' table because 'topics' does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_text',
+			'join_tablename'  => 'topics',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_id = topics.topic_first_post_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_title',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic status (Open or Closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_status',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_type',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_time',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'topics',
+			'from_fieldname' => 'topic_last_post_time',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		/**
+		 * phpBB Forums do not support topic tags
+		 */
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'post_id',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_post_id'
+		);
+
+		// Setup reply section table joins
+		$this->field_map[] = array(
+			'from_tablename'  => 'topics',
+			'from_fieldname'  => 'topic_id',
+			'join_tablename'  => 'posts',
+			'join_type'       => 'LEFT',
+			'join_expression' => 'USING (topic_id) WHERE posts.post_id != topics.topic_first_post_id',
+			'to_type'         => 'reply'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'forum_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'posts',
+			'from_fieldname' => 'poster_ip',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'poster_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+		// Reply slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_subject',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_text',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'topic_id',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'posts',
+			'from_fieldname'  => 'post_time',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_id',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'user_password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_form_salt',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'user',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'phpBB'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_website',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'users',
+			'from_fieldname'  => 'user_regdate',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_yim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// Store ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phpbb_user_icq'
+		);
+
+		// Store MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_msnm',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phpbb_user_msnm'
+		);
+
+		// Store Jabber
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_jabber',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'jabber'
+		);
+
+		// Store Occupation (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_occ',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phpbb_user_occ'
+		);
+
+		// Store Interests (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_interests',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phpbb_user_interests'
+		);
+
+		// Store Signature (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_sig',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phpbb_user_sig',
+			'callback_method' => 'callback_html'
+		);
+
+		// Store Location (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_from',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phpbb_user_from'
+		);
+
+		// Store Avatar Filename (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'users',
+			'from_fieldname' => 'user_avatar',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_phpbb_user_avatar'
+		);
+
+		// Store old role (Stored in usermeta)
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when it is authenticate it we can get it out of the database
+	 * as one value.
+	 */
+	public function callback_savepass( $field, $row ) {
+		return array(
+			'hash' => $field,
+			'salt' => $row['salt']
+		);
+	}
+
+	/**
+	 * Check for correct password
+	 *
+	 * @param string $password The password in plain text
+	 * @param string $hash The stored password hash
+	 *
+	 * @link Original source for password functions http://openwall.com/phpass/
+	 * @link phpass is now included in WP Core http://core.trac.wordpress.org/browser/trunk/wp-includes/class-phpass.php
+	 *
+	 * @return bool Returns true if the password is correct, false if not.
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+		$pass_array = unserialize( $serialized_pass );
+		if ( strlen( $pass_array['hash'] ) == 34 ) {
+			return ( $this->_hash_crypt_private( $password, $pass_array['hash'], $itoa64 ) === $pass_array['hash'] ) ? true : false;
+		}
+
+		return ( md5( $password ) === $pass_array['hash'] ) ? true : false;
+	}
+
+	/**
+	 * The crypt function/replacement
+	 */
+	private function _hash_crypt_private( $password, $setting, &$itoa64 ) {
+		$output = '*';
+
+		// Check for correct hash
+		if ( substr( $setting, 0, 3 ) != '$H$' ) {
+			return $output;
+		}
+
+		$count_log2 = strpos( $itoa64, $setting[3] );
+
+		if ( $count_log2 < 7 || $count_log2 > 30 ) {
+			return $output;
+		}
+
+		$count = 1 << $count_log2;
+		$salt  = substr( $setting, 4, 8 );
+
+		if ( strlen( $salt ) != 8 ) {
+			return $output;
+		}
+
+		/**
+		 * We're kind of forced to use MD5 here since it's the only
+		 * cryptographic primitive available in all versions of PHP
+		 * currently in use.  To implement our own low-level crypto
+		 * in PHP would result in much worse performance and
+		 * consequently in lower iteration counts and hashes that are
+		 * quicker to crack (by non-PHP code).
+		 */
+		if ( floatval( phpversion() ) >= 5 ) {
+			$hash = md5( $salt . $password, true );
+			do
+			{
+				$hash = md5( $hash . $password, true );
+			}
+			while ( --$count );
+		} else {
+			$hash = pack( 'H*', md5( $salt . $password ) );
+			do {
+				$hash = pack( 'H*', md5( $hash . $password ) );
+			}
+			while ( --$count );
+		}
+
+		$output = substr($setting, 0, 12);
+		$output .= $this->_hash_encode64($hash, 16, $itoa64);
+
+		return $output;
+	}
+
+	/**
+	 * Encode hash
+	 */
+	private function _hash_encode64( $input, $count, &$itoa64 ) {
+		$output = '';
+		$i = 0;
+
+		do {
+			$value = ord( $input[$i++] );
+			$output .= $itoa64[$value & 0x3f];
+
+			if ($i < $count) {
+				$value |= ord( $input[$i] ) << 8;
+			}
+
+			$output .= $itoa64[( $value >> 6 ) & 0x3f];
+
+			if ( $i++ >= $count ) {
+				break;
+			}
+
+			if ( $i < $count ) {
+				$value |= ord( $input[$i] ) << 16;
+			}
+
+			$output .= $itoa64[( $value >> 12 ) & 0x3f];
+
+			if ( $i++ >= $count ) {
+				break;
+			}
+
+			$output .= $itoa64[($value >> 18) & 0x3f];
+		} while ( $i < $count );
+
+		return $output;
+	}
+
+	/**
+	 * Translate the forum type from phpBB v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status phpBB v3.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 1 ) {
+		switch ( $status ) {
+			case 0 :
+				$status = 'category';
+				break;
+
+			case 1  :
+			default :
+				$status = 'forum';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the forum status from phpBB v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status phpBB v3.x numeric forum status
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0  :
+			default :
+				$status = 'open';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic status from phpBB v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status phpBB v3.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'closed';
+				break;
+
+			case 0 :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from phpBB 3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status phpBB 3.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 3 :
+				$status = 'super-sticky'; // phpBB Global Sticky 'topic_type = 3'
+				break;
+
+			case 2 :
+				$status = 'super-sticky'; // phpBB Announcement Sticky 'topic_type = 2'
+				break;
+
+			case 1 :
+				$status = 'sticky';       // phpBB Sticky 'topic_type = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // phpBB normal topic 'topic_type = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count phpBB v3.x reply count
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title phpBB v3.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * This callback processes any custom parser.php attributes and custom code with preg_replace
+	 */
+	protected function callback_html( $field ) {
+
+		// Strips custom phpBB 'magic_url' and 'bbcode_uid' first from $field before parsing $field to parser.php
+		$phpbb_uid = $field;
+		$phpbb_uid = html_entity_decode( $phpbb_uid );
+
+		// Replace '[b:XXXXXXX]' with '<strong>'
+		$phpbb_uid = preg_replace( '/\[b:(.*?)\]/',   '<strong>',  $phpbb_uid );
+		// Replace '[/b:XXXXXXX]' with '</strong>'
+		$phpbb_uid = preg_replace( '/\[\/b:(.*?)\]/', '</strong>', $phpbb_uid );
+
+		// Replace '[i:XXXXXXX]' with '<em>'
+		$phpbb_uid = preg_replace( '/\[i:(.*?)\]/',   '<em>',      $phpbb_uid );
+		// Replace '[/i:XXXXXXX]' with '</em>'
+		$phpbb_uid = preg_replace( '/\[\/i:(.*?)\]/', '</em>',     $phpbb_uid );
+
+		// Replace '[u:XXXXXXX]' with '<u>'
+		$phpbb_uid = preg_replace( '/\[u:(.*?)\]/',   '<u>',       $phpbb_uid );
+		// Replace '[/u:XXXXXXX]' with '</u>'
+		$phpbb_uid = preg_replace( '/\[\/u:(.*?)\]/', '</u>',      $phpbb_uid );
+
+		// Replace '[quote:XXXXXXX]' with '<blockquote>'
+		$phpbb_uid = preg_replace( '/\[quote:(.*?)\]/',          '<blockquote>',                   $phpbb_uid );
+		// Replace '[quote="$1"]' with '<em>$1 wrote:</em><blockquote>"
+		$phpbb_uid = preg_replace( '/\[quote="(.*?)":(.*?)\]/', '<em>@$1 wrote:</em><blockquote>', $phpbb_uid );
+		// Replace '[/quote:XXXXXXX]' with '</blockquote>'
+		$phpbb_uid = preg_replace( '/\[\/quote:(.*?)\]/',       '</blockquote>',                   $phpbb_uid );
+
+		// Replace '[img:XXXXXXX]' with '<img src="'
+		$phpbb_uid = preg_replace( '/\[img:(.*?)\]/',   '<img src="', $phpbb_uid );
+		// Replace '[/img:XXXXXXX]' with ' alt="">'
+		$phpbb_uid = preg_replace( '/\[\/img:(.*?)\]/', '" alt="">',  $phpbb_uid );
+
+		// Replace '<!-- s$1 --><img src=\"{SMILIES_PATH}$2 -->' with '$1'
+		$phpbb_uid = preg_replace( '/<!-- s(.*?) --><img src=\"{SMILIES_PATH}(.*?)-->/', '$1', $phpbb_uid );
+
+		// Replace '<!-- m --><a class="postlink" href="$1">$1</a><!-- m -->' with '$1'
+		$phpbb_uid = preg_replace( '/\<!-- m --\>\<a class="postlink" href="([^\[]+?)"\>([^\[]+?)\<\/a\>\<!-- m --\>/', '$1', $phpbb_uid );
+
+		// Replace '[url:XXXXXXX]$1[/url:XXXXXXX]' with '<a href="http://$1">$1</a>'
+		$phpbb_uid = preg_replace( '/\[url:(?:[^\]]+)\]([^\[]+?)\[\/url:(?:[^\]]+)\]/',       '<a href="http://$1">$1</a>',  $phpbb_uid );
+		// Replace '[url=http://$1:XXXXXXX]$3[/url:XXXXXXX]' with '<a href="http://$1">$3</a>'
+		$phpbb_uid = preg_replace( '/\[url\=http\:\/\/(.*?)\:(.*?)\](.*?)\[\/url:(.*?)\]/i',  '<a href="http://$1">$3</a>',  $phpbb_uid );
+		// Replace '[url=https://$1:XXXXXXX]$3[/url:XXXXXXX]' with '<a href="http://$1">$3</a>'
+		$phpbb_uid = preg_replace( '/\[url\=https\:\/\/(.*?)\:(.*?)\](.*?)\[\/url:(.*?)\]/i', '<a href="https://$1">$3</a>', $phpbb_uid );
+
+		// Replace '[email:XXXXXXX]' with '<a href="mailto:$2">$2</a>'
+		$phpbb_uid = preg_replace( '/\[email:(.*?)\](.*?)\[\/email:(.*?)\]/', '<a href="mailto:$2">$2</a>', $phpbb_uid );
+		// Replace '<!-- e -->no.one@domain.adr<!-- e -->' with '$1'
+		$phpbb_uid = preg_replace( '/\<!-- e --\>(.*?)\<!-- e --\>/', '$1', $phpbb_uid );
+
+		// Replace '[code:XXXXXXX]' with '<pre><code>'
+		$phpbb_uid = preg_replace( '/\[code:(.*?)\]/',   '<pre><code>',   $phpbb_uid );
+		// Replace '[/code:XXXXXXX]' with '</code></pre>'
+		$phpbb_uid = preg_replace( '/\[\/code:(.*?)\]/', '</code></pre>', $phpbb_uid );
+
+		// Replace '[color=$1:XXXXXXXX]' with '<span style="color:$1">'
+		$phpbb_uid = preg_replace( '/\[color=(.*?)\:(.*?)\]/', '<span style="color: $1">', $phpbb_uid );
+		// Replace '[/color:XXXXXXX]' with '</span>'
+		$phpbb_uid = preg_replace( '/\[\/color:(.*?)\]/',      '</span>',                  $phpbb_uid );
+
+		// Replace '[size=$1:XXXXXXXX]' with '<span style="font-size:$1%;">$3</span>'
+		$phpbb_uid = preg_replace( '/\[size=(.*?):(.*?)\]/', '<span style="font-size:$1%;">', $phpbb_uid );
+		// Replace '[/size:XXXXXXX]' with ''
+		$phpbb_uid = preg_replace( '/\[\/size:(.*?)\]/',     '</span>',                       $phpbb_uid );
+
+		// Replace '[list:XXXXXXX]' with '<ul>'
+		$phpbb_uid = preg_replace( '/\[list:(.*?)\]/',     '<ul>',          $phpbb_uid );
+		// Replace '[list=a:XXXXXXX]' with '<ol type="a">'
+		$phpbb_uid = preg_replace( '/\[list=a:(.*?)\]/',   '<ol type="a">', $phpbb_uid );
+		// Replace '[list=1:XXXXXXX]' with '<ol>'
+		$phpbb_uid = preg_replace( '/\[list=1:(.*?)\]/',   '<ol>',          $phpbb_uid );
+		// Replace '[*:XXXXXXX]' with '<li>'
+		$phpbb_uid = preg_replace( '/\[\*:(.*?)\]/',       '<li>',          $phpbb_uid );
+		// Replace '[/*:m:XXXXXXX]' with '</li>'
+		$phpbb_uid = preg_replace( '/\[\/\*:m:(.*?)\]/',   '</li>',         $phpbb_uid );
+		// Replace '[/list:u:XXXXXXX]' with '</ul>'
+		$phpbb_uid = preg_replace( '/\[\/list:u:(.*?)\]/', '</ul>',         $phpbb_uid );
+		// Replace '[/list:o:XXXXXXX]' with '</ol>'
+		$phpbb_uid = preg_replace( '/\[\/list:o:(.*?)\]/', '</ol>',         $phpbb_uid );
+
+		// Now that phpBB's 'magic_url' and 'bbcode_uid' have been stripped put the cleaned HTML back in $field
+		$field = $phpbb_uid;
+
+		// Parse out any bbCodes in $field with the BBCode 'parser.php'
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/vBulletin.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/vBulletin.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/vBulletin.php	(revision 5382)
@@ -0,0 +1,707 @@
+<?php
+
+/**
+ * Implementation of vBulletin v4.x Converter.
+ *
+ * @since bbPress (r4724)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/vbulletin
+ */
+class vBulletin extends BBP_Converter_Base {
+
+	/**
+	 * Main constructor
+	 *
+	 * @uses vBulletin::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	private function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'forumid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'parentid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'threadcount',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'replycount',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'threadcount',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'replycount',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'title',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'title_clean',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'displayorder',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = -1 or Forum > 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'parentid',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+		$this->field_map[]	 = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+		$this->field_map[]	 = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+		$this->field_map[]	 = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'threadid',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'forumid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'replycount',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'replycount',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'postuserid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'post' table because 'thread' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'ipaddress',
+			'join_tablename'  => 'thread',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'title',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'forumid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic content.
+		// Note: We join the 'post' table because 'thread' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'pagetext',
+			'join_tablename'  => 'thread',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic status (Open or Closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'open',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'lastpost',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tagcontent',
+			'from_fieldname'  => 'contentid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Taxonomy ID.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tagcontent',
+			'from_fieldname'  => 'tagid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'taxonomy'
+		);
+
+		// Term text.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'tagtext',
+			'join_tablename'  => 'tagcontent',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tagid)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		// Term slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'tagtext',
+			'join_tablename'  => 'tagcontent',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tagid)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'slug',
+			'callback_method' => 'callback_slug'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'postid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		// Note: We join the 'thread' table because 'post' table does not include forum id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'forumid',
+			'join_tablename'  => 'post',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'threadid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'post',
+			'from_fieldname' => 'ipaddress',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'userid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'thread' table because 'post' table does not include reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'join_tablename'  => 'post',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+        // Reply slug (Clean name to avoid conflicts)
+        // Note: We join the 'thread' table because 'post' table does not include reply slug.
+        $this->field_map[] = array(
+        	'from_tablename'  => 'thread',
+        	'from_fieldname'  => 'title',
+        	'join_tablename'  => 'post',
+        	'join_type'       => 'INNER',
+        	'join_expression' => 'USING (threadid) WHERE post.parentid != 0',
+        	'to_type'         => 'reply',
+        	'to_fieldname'    => 'post_name',
+        	'callback_method' => 'callback_slug'
+        );
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'pagetext',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'threadid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[]	 = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'userid',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'salt',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_salt'
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'user',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'vBulletin'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'homepage',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'joindate',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'yahoo',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// User ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_vbulletin_user_icq'
+		);
+
+		// User MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_vbulletin_user_msn'
+		);
+
+		// User Skype (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'skype',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_vbulletin_user_skype'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 *
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ) . $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum type from vBulletin v4.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status vBulletin v4.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		if ( $status == -1 ) {
+			$status = 'category';
+		} else {
+			$status = 'forum';
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from vBulletin v4.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status vBulletin v4.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 2 :
+				$status = 'super-sticky'; // vBulletin Super Sticky 'sticky = 2'
+				break;
+
+			case 1 :
+				$status = 'sticky';       // vBulletin Sticky 'sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // vBulletin Normal Topic 'sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count vBulletin v4.x reply count
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title vBulletin v4.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * Translate the post status from vBulletin numeric's to WordPress's strings.
+	 *
+	 * @param int $status vBulletin v4.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 1 ) {
+		switch ( $status ) {
+			case 0 :
+				$status = 'closed';
+				break;
+
+			case 1  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * This callback processes any custom parser.php attributes and custom code with preg_replace
+	 */
+	protected function callback_html( $field ) {
+
+		// Strips vBulletin custom HTML first from $field before parsing $field to parser.php
+		$vbulletin_markup = $field;
+		$vbulletin_markup = html_entity_decode( $vbulletin_markup );
+
+		// Replace '[QUOTE]' with '<blockquote>'
+		$vbulletin_markup = preg_replace( '/\[QUOTE\]/', '<blockquote>', $vbulletin_markup );
+		// Replace '[QUOTE=User Name($1);PostID($2)]' with '<em>@$1 $2 wrote:</em><blockquote>"
+		$vbulletin_markup = preg_replace( '/\[QUOTE=(.*?);(.*?)\]/' , '<em>@$1 $2 wrote:</em><blockquote>', $vbulletin_markup );
+		// Replace '[/QUOTE]' with '</blockquote>'
+		$vbulletin_markup = preg_replace( '/\[\/QUOTE\]/', '</blockquote>', $vbulletin_markup );
+		// Replace '[MENTION=###($1)]User Name($2)[/MENTION]' with '@$2"
+		$vbulletin_markup = preg_replace( '/\[MENTION=(.*?)\](.*?)\[\/MENTION\]/', '@$2', $vbulletin_markup );
+
+		// Replace '[video=youtube;$1]$2[/video]' with '$2"
+		$vbulletin_markup = preg_replace( '/\[video\=youtube;(.*?)\](.*?)\[\/video\]/', '$2', $vbulletin_markup );
+
+		// Now that vBulletin custom HTML has been stripped put the cleaned HTML back in $field
+		$field = $vbulletin_markup;
+
+		// Parse out any bbCodes in $field with the BBCode 'parser.php'
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/converters/vBulletin3.php
===================================================================
--- /tags/2.5.4/includes/admin/converters/vBulletin3.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/converters/vBulletin3.php	(revision 5382)
@@ -0,0 +1,707 @@
+<?php
+
+/**
+ * Implementation of vBulletin v3.x Converter.
+ *
+ * @since bbPress (r5151)
+ * @link Codex Docs http://codex.bbpress.org/import-forums/vbulletin
+ */
+class vBulletin3 extends BBP_Converter_Base {
+
+	/**
+	 * Main constructor
+	 *
+	 * @uses vBulletin::setup_globals()
+	 */
+	function __construct() {
+		parent::__construct();
+		$this->setup_globals();
+	}
+
+	/**
+	 * Sets up the field mappings
+	 */
+	private function setup_globals() {
+
+		/** Forum Section *****************************************************/
+
+		// Forum id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'forumid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_id'
+		);
+
+		// Forum parent id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'parentid',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_forum_parent_id'
+		);
+
+		// Forum topic count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'threadcount',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_topic_count'
+		);
+
+		// Forum reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'replycount',
+			'to_type'        => 'forum',
+			'to_fieldname'   => '_bbp_reply_count'
+		);
+
+		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'threadcount',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_topic_count'
+		);
+
+		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'replycount',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_total_reply_count'
+		);
+
+		// Forum title.
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'title',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Forum slug (Clean name to avoid confilcts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'title_clean',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Forum description.
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'description',
+			'to_type'         => 'forum',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_null'
+		);
+
+		// Forum display order (Starts from 1)
+		$this->field_map[] = array(
+			'from_tablename' => 'forum',
+			'from_fieldname' => 'displayorder',
+			'to_type'        => 'forum',
+			'to_fieldname'   => 'menu_order'
+		);
+
+		// Forum type (Category = -1 or Forum > 0, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'forum',
+			'from_fieldname'  => 'parentid',
+			'to_type'         => 'forum',
+			'to_fieldname'    => '_bbp_forum_type',
+			'callback_method' => 'callback_forum_type'
+		);
+
+		// Forum dates.
+		$this->field_map[] = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+		$this->field_map[]	 = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_date_gmt',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+		$this->field_map[]	 = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+		$this->field_map[]	 = array(
+			'to_type'      => 'forum',
+			'to_fieldname' => 'post_modified_gmt',
+			'default'      => date( 'Y-m-d H:i:s' )
+		);
+
+		/** Topic Section *****************************************************/
+
+		// Topic id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'threadid',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_topic_id'
+		);
+
+		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'forumid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic reply count (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'replycount',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'replycount',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_total_reply_count',
+			'callback_method' => 'callback_topic_reply_count'
+		);
+
+		// Topic author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'postuserid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Topic Author ip (Stored in postmeta)
+		// Note: We join the 'post' table because 'thread' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'ipaddress',
+			'join_tablename'  => 'thread',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_author_ip'
+		);
+
+		// Topic title.
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'title',
+			'to_type'        => 'topic',
+			'to_fieldname'   => 'post_title'
+		);
+
+		// Topic slug (Clean name to avoid conflicts)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Topic parent forum id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'forumid',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_forumid'
+		);
+
+		// Topic content.
+		// Note: We join the 'post' table because 'thread' table does not include topic content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'pagetext',
+			'join_tablename'  => 'thread',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Topic status (Open or Closed)
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'open',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_status',
+			'callback_method' => 'callback_topic_status'
+		);
+
+		// Sticky status (Stored in postmeta))
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'sticky',
+			'to_type'         => 'topic',
+			'to_fieldname'    => '_bbp_old_sticky_status',
+			'callback_method' => 'callback_sticky_status'
+		);
+
+		// Topic dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'topic',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename' => 'thread',
+			'from_fieldname' => 'lastpost',
+			'to_type'        => 'topic',
+			'to_fieldname'   => '_bbp_last_active_time',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** Tags Section ******************************************************/
+
+		// Topic id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tagthread',
+			'from_fieldname'  => 'threadid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'objectid',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Taxonomy ID.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tagthread',
+			'from_fieldname'  => 'tagid',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'taxonomy'
+		);
+
+		// Term text.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'tagtext',
+			'join_tablename'  => 'tagthread',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tagid)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'name'
+		);
+
+		// Term slug.
+		$this->field_map[] = array(
+			'from_tablename'  => 'tag',
+			'from_fieldname'  => 'tagtext',
+			'join_tablename'  => 'tagthread',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (tagid)',
+			'to_type'         => 'tags',
+			'to_fieldname'    => 'slug',
+			'callback_method' => 'callback_slug'
+		);
+
+		/** Reply Section *****************************************************/
+
+		// Reply id (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'postid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_post_id'
+		);
+
+		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
+		// Note: We join the 'thread' table because 'post' table does not include forum id.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'forumid',
+			'join_tablename'  => 'post',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_forum_id',
+			'callback_method' => 'callback_topicid_to_forumid'
+		);
+
+		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'threadid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => '_bbp_topic_id',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply author ip (Stored in postmeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'post',
+			'from_fieldname' => 'ipaddress',
+			'to_type'        => 'reply',
+			'to_fieldname'   => '_bbp_author_ip'
+		);
+
+		// Reply author.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'userid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_author',
+			'callback_method' => 'callback_userid'
+		);
+
+		// Reply title.
+		// Note: We join the 'thread' table because 'post' table does not include reply title.
+		$this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'join_tablename'  => 'post',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_title',
+			'callback_method' => 'callback_reply_title'
+		);
+
+        // Reply slug (Clean name to avoid conflicts)
+        // Note: We join the 'thread' table because 'post' table does not include reply slug.
+        $this->field_map[] = array(
+			'from_tablename'  => 'thread',
+			'from_fieldname'  => 'title',
+			'join_tablename'  => 'post',
+			'join_type'       => 'INNER',
+			'join_expression' => 'USING (threadid) WHERE post.parentid != 0',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_name',
+			'callback_method' => 'callback_slug'
+		);
+
+		// Reply content.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'pagetext',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_content',
+			'callback_method' => 'callback_html'
+		);
+
+		// Reply parent topic id (If no parent, then 0)
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'threadid',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_parent',
+			'callback_method' => 'callback_topicid'
+		);
+
+		// Reply dates.
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_date_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[] = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified',
+			'callback_method' => 'callback_datetime'
+		);
+		$this->field_map[]	 = array(
+			'from_tablename'  => 'post',
+			'from_fieldname'  => 'dateline',
+			'to_type'         => 'reply',
+			'to_fieldname'    => 'post_modified_gmt',
+			'callback_method' => 'callback_datetime'
+		);
+
+		/** User Section ******************************************************/
+
+		// Store old User id (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'userid',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_user_id'
+		);
+
+		// Store old User password (Stored in usermeta serialized with salt)
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'password',
+			'to_type'         => 'user',
+			'to_fieldname'    => '_bbp_password',
+			'callback_method' => 'callback_savepass'
+		);
+
+		// Store old User Salt (This is only used for the SELECT row info for the above password save)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'salt',
+			'to_type'        => 'user',
+			'to_fieldname'   => ''
+		);
+
+		// User password verify class (Stored in usermeta for verifying password)
+		$this->field_map[] = array(
+			'to_type'      => 'user',
+			'to_fieldname' => '_bbp_class',
+			'default'      => 'vBulletin3'
+		);
+
+		// User name.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'username',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_login'
+		);
+
+		// User email.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'email',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_email'
+		);
+
+		// User homepage.
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'homepage',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'user_url'
+		);
+
+		// User registered.
+		$this->field_map[] = array(
+			'from_tablename'  => 'user',
+			'from_fieldname'  => 'joindate',
+			'to_type'         => 'user',
+			'to_fieldname'    => 'user_registered',
+			'callback_method' => 'callback_datetime'
+		);
+
+		// User AIM (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'aim',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'aim'
+		);
+
+		// User Yahoo (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'yahoo',
+			'to_type'        => 'user',
+			'to_fieldname'   => 'yim'
+		);
+
+		// User ICQ (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'icq',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_vbulletin3_user_icq'
+		);
+
+		// User MSN (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'msn',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_vbulletin3_user_msn'
+		);
+
+		// User Skype (Stored in usermeta)
+		$this->field_map[] = array(
+			'from_tablename' => 'user',
+			'from_fieldname' => 'skype',
+			'to_type'        => 'user',
+			'to_fieldname'   => '_bbp_vbulletin3_user_skype'
+		);
+	}
+
+	/**
+	 * This method allows us to indicates what is or is not converted for each
+	 * converter.
+	 */
+	public function info() {
+		return '';
+	}
+
+
+	/**
+	 * This method is to save the salt and password together.  That
+	 * way when we authenticate it we can get it out of the database
+	 * as one value. Array values are auto sanitized by WordPress.
+	 */
+	public function callback_savepass( $field, $row ) {
+		$pass_array = array( 'hash'	 => $field, 'salt'	 => $row['salt'] );
+		return $pass_array;
+	}
+
+	/**
+	 * This method is to take the pass out of the database and compare
+	 * to a pass the user has typed in.
+	 *
+	 * vBulletin passwords do not work. Maybe use the below plugin's approach?
+	 *
+	 * @link http://wordpress.org/extend/plugins/vb-user-copy/
+	 * @link http://plugins.trac.wordpress.org/browser/vb-user-copy/trunk/vb_user_copy.php
+	 */
+	public function authenticate_pass( $password, $serialized_pass ) {
+		$pass_array = unserialize( $serialized_pass );
+		return ( $pass_array['hash'] == md5( md5( $password ) . $pass_array['salt'] ) );
+	}
+
+	/**
+	 * Translate the forum type from vBulletin v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status vBulletin v3.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_forum_type( $status = 0 ) {
+		if ( $status == -1 ) {
+			$status = 'category';
+		} else {
+			$status = 'forum';
+		}
+		return $status;
+	}
+
+	/**
+	 * Translate the topic sticky status type from vBulletin v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status vBulletin v3.x numeric forum type
+	 * @return string WordPress safe
+	 */
+	public function callback_sticky_status( $status = 0 ) {
+		switch ( $status ) {
+			case 1 :
+				$status = 'sticky';       // vBulletin Sticky 'topic_sticky = 1'
+				break;
+
+			case 0  :
+			default :
+				$status = 'normal';       // vBulletin Normal Topic 'topic_sticky = 0'
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * Verify the topic reply count.
+	 *
+	 * @param int $count vBulletin v3.x reply count
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_reply_count( $count = 1 ) {
+		$count = absint( (int) $count - 1 );
+		return $count;
+	}
+
+	/**
+	 * Set the reply title
+	 *
+	 * @param string $title vBulletin v3.x topic title of this reply
+	 * @return string Prefixed topic title, or empty string
+	 */
+	public function callback_reply_title( $title = '' ) {
+		$title = !empty( $title ) ? __( 'Re: ', 'bbpress' ) . html_entity_decode( $title ) : '';
+		return $title;
+	}
+
+	/**
+	 * Translate the post status from vBulletin v3.x numeric's to WordPress's strings.
+	 *
+	 * @param int $status vBulletin v3.x numeric topic status
+	 * @return string WordPress safe
+	 */
+	public function callback_topic_status( $status = 1 ) {
+		switch ( $status ) {
+			case 0 :
+				$status = 'closed';
+				break;
+
+			case 1  :
+			default :
+				$status = 'publish';
+				break;
+		}
+		return $status;
+	}
+
+	/**
+	 * This callback processes any custom parser.php attributes and custom code with preg_replace
+	 */
+	protected function callback_html( $field ) {
+
+		// Strips vBulletin custom HTML first from $field before parsing $field to parser.php
+		$vbulletin_markup = $field;
+		$vbulletin_markup = html_entity_decode( $vbulletin_markup );
+
+		// Replace '[QUOTE]' with '<blockquote>'
+		$vbulletin_markup = preg_replace( '/\[QUOTE\]/', '<blockquote>', $vbulletin_markup );
+		// Replace '[QUOTE=User Name($1);PostID($2)]' with '<em>@$1 $2 wrote:</em><blockquote>"
+		$vbulletin_markup = preg_replace( '/\[QUOTE=(.*?);(.*?)\]/' , '<em>@$1 $2 wrote:</em><blockquote>', $vbulletin_markup );
+		// Replace '[/QUOTE]' with '</blockquote>'
+		$vbulletin_markup = preg_replace( '/\[\/QUOTE\]/', '</blockquote>', $vbulletin_markup );
+		// Replace '[MENTION=###($1)]User Name($2)[/MENTION]' with '@$2"
+		$vbulletin_markup = preg_replace( '/\[MENTION=(.*?)\](.*?)\[\/MENTION\]/', '@$2', $vbulletin_markup );
+
+		// Replace '[video=youtube;$1]$2[/video]' with '$2"
+		$vbulletin_markup = preg_replace( '/\[video\=youtube;(.*?)\](.*?)\[\/video\]/', '$2', $vbulletin_markup );
+
+		// Now that vBulletin custom HTML has been stripped put the cleaned HTML back in $field
+		$field = $vbulletin_markup;
+
+		// Parse out any bbCodes in $field with the BBCode 'parser.php'
+		require_once( bbpress()->admin->admin_dir . 'parser.php' );
+		$bbcode = BBCode::getInstance();
+		$bbcode->enable_smileys = false;
+		$bbcode->smiley_regex   = false;
+		return html_entity_decode( $bbcode->Parse( $field ) );
+	}
+}
Index: /tags/2.5.4/includes/admin/css/admin.css
===================================================================
--- /tags/2.5.4/includes/admin/css/admin.css	(revision 5382)
+++ /tags/2.5.4/includes/admin/css/admin.css	(revision 5382)
@@ -0,0 +1,177 @@
+
+/* Kludge for too-wide forums dropdown */
+#poststuff #bbp_forum_attributes select#parent_id,
+#poststuff #bbp_topic_attributes select#parent_id,
+#poststuff #bbp_reply_attributes select#bbp_forum_id {
+	max-width: 170px;
+}
+
+/* Version Badge */
+
+.bbp-badge {
+	padding-top: 142px;
+	height: 50px;
+	width: 173px;
+	color: #fafafa;
+	font-weight: bold;
+	font-size: 14px;
+	text-align: center;
+	margin: 0 -5px;
+	background: url('../images/badge.png') no-repeat;
+}
+
+.about-wrap .bbp-badge {
+	position: absolute;
+	top: 0;
+	right: 0;
+}
+	body.rtl .about-wrap .bbp-badge {
+		right: auto;
+		left: 0;
+	}
+
+#bbp-dashboard-right-now p.sub,
+#bbp-dashboard-right-now .table,
+#bbp-dashboard-right-now .versions {
+	margin: -12px;
+}
+
+#bbp-dashboard-right-now .inside {
+	font-size: 12px;
+	padding-top: 20px;
+	margin-bottom: 0;
+}
+
+#bbp-dashboard-right-now p.sub {
+	padding: 5px 0 15px;
+	color: #8f8f8f;
+	font-size: 14px;
+	position: absolute;
+	top: -17px;
+	left: 15px;
+}
+	body.rtl #bbp-dashboard-right-now p.sub {
+		right: 15px;
+		left: 0;
+	}
+
+#bbp-dashboard-right-now .table {
+	margin: 0;
+	padding: 0;
+	position: relative;
+}
+
+#bbp-dashboard-right-now .table_content {
+	float: left;
+	border-top: #ececec 1px solid;
+	width: 45%;
+}
+	body.rtl #bbp-dashboard-right-now .table_content {
+		float: right;
+	}
+
+#bbp-dashboard-right-now .table_discussion {
+	float: right;
+	border-top: #ececec 1px solid;
+	width: 45%;
+}
+	body.rtl #bbp-dashboard-right-now .table_discussion {
+		float: left;
+	}
+
+#bbp-dashboard-right-now table td {
+	padding: 3px 0;
+	white-space: nowrap;
+}
+
+#bbp-dashboard-right-now table tr.first td {
+	border-top: none;
+}
+
+#bbp-dashboard-right-now td.b {
+	padding-right: 6px;
+	text-align: right;
+	font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
+	font-size: 14px;
+	width: 1%;
+}
+	body.rtl #bbp-dashboard-right-now td.b {
+		padding-left: 6px;
+		padding-right: 0;
+	}
+
+#bbp-dashboard-right-now td.b a {
+	font-size: 18px;
+}
+
+#bbp-dashboard-right-now td.b a:hover {
+	color: #d54e21;
+}
+
+#bbp-dashboard-right-now .t {
+	font-size: 12px;
+	padding-right: 12px;
+	padding-top: 6px;
+	color: #777;
+}
+	body.rtl #bbp-dashboard-right-now .t {
+		padding-left: 12px;
+		padding-right: 0;
+	}
+
+#bbp-dashboard-right-now .t a {
+	white-space: nowrap;
+}
+
+#bbp-dashboard-right-now .spam {
+	color: red;
+}
+
+#bbp-dashboard-right-now .waiting {
+	color: #e66f00;
+}
+
+#bbp-dashboard-right-now .approved {
+	color: green;
+}
+
+#bbp-dashboard-right-now .versions {
+	padding: 6px 10px 12px;
+	clear: both;
+}
+
+#bbp-dashboard-right-now .versions .b {
+	font-weight: bold;
+}
+
+#bbp-dashboard-right-now a.button {
+	float: right;
+	clear: right;
+	position: relative;
+	top: -5px;
+}
+	body.rtl #bbp-dashboard-right-now a.button {
+		float: left;
+		clear: left;
+	}
+
+/* Dashicons */
+#adminmenu #menu-posts-forum .wp-menu-image:before {
+	content: "\f449";
+}
+
+#adminmenu #menu-posts-topic .wp-menu-image:before {
+	content: "\f450";
+}
+
+#adminmenu #menu-posts-reply .wp-menu-image:before {
+	content: "\f451";
+}
+
+/* Ratio 2x */
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5) {
+	.bbp-badge {
+		background-image: url('../images/badge-2x.png');
+		background-size: 173px 194px;
+	}
+}
Index: /tags/2.5.4/includes/admin/forums.php
===================================================================
--- /tags/2.5.4/includes/admin/forums.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/forums.php	(revision 5382)
@@ -0,0 +1,583 @@
+<?php
+
+/**
+ * bbPress Forum Admin Class
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Forums_Admin' ) ) :
+/**
+ * Loads bbPress forums admin area
+ *
+ * @package bbPress
+ * @subpackage Administration
+ * @since bbPress (r2464)
+ */
+class BBP_Forums_Admin {
+
+	/** Variables *************************************************************/
+
+	/**
+	 * @var The post type of this admin component
+	 */
+	private $post_type = '';
+
+	/** Functions *************************************************************/
+
+	/**
+	 * The main bbPress forums admin loader
+	 *
+	 * @since bbPress (r2515)
+	 *
+	 * @uses BBP_Forums_Admin::setup_globals() Setup the globals needed
+	 * @uses BBP_Forums_Admin::setup_actions() Setup the hooks and actions
+	 * @uses BBP_Forums_Admin::setup_help() Setup the help text
+	 */
+	public function __construct() {
+		$this->setup_globals();
+		$this->setup_actions();
+	}
+
+	/**
+	 * Setup the admin hooks, actions and filters
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 *
+	 * @uses add_action() To add various actions
+	 * @uses add_filter() To add various filters
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 */
+	private function setup_actions() {
+
+		// Add some general styling to the admin area
+		add_action( 'bbp_admin_head',        array( $this, 'admin_head'       ) );
+
+		// Messages
+		add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
+
+		// Metabox actions
+		add_action( 'add_meta_boxes',        array( $this, 'attributes_metabox'      ) );
+		add_action( 'save_post',             array( $this, 'attributes_metabox_save' ) );
+
+		// Column headers.
+		add_filter( 'manage_' . $this->post_type . '_posts_columns',        array( $this, 'column_headers' )        );
+
+		// Columns (in page row)
+		add_action( 'manage_' . $this->post_type . '_posts_custom_column',  array( $this, 'column_data'    ), 10, 2 );
+		add_filter( 'page_row_actions',                                     array( $this, 'row_actions'    ), 10, 2 );
+
+		// Contextual Help
+		add_action( 'load-edit.php',     array( $this, 'edit_help' ) );
+		add_action( 'load-post.php',     array( $this, 'new_help'  ) );
+		add_action( 'load-post-new.php', array( $this, 'new_help'  ) );
+	}
+
+	/**
+	 * Should we bail out of this method?
+	 *
+	 * @since bbPress (r4067)
+	 * @return boolean
+	 */
+	private function bail() {
+		if ( !isset( get_current_screen()->post_type ) || ( $this->post_type != get_current_screen()->post_type ) )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Admin globals
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 */
+	private function setup_globals() {
+		$this->post_type = bbp_get_forum_post_type();
+	}
+
+	/** Contextual Help *******************************************************/
+
+	/**
+	 * Contextual help for bbPress forum edit page
+	 *
+	 * @since bbPress (r3119)
+	 * @uses get_current_screen()
+	 */
+	public function edit_help() {
+
+		if ( $this->bail() ) return;
+
+		// Overview
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'overview',
+			'title'		=> __( 'Overview', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'This screen displays the individual forums on your site. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
+		) );
+
+		// Screen Content
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'screen-content',
+			'title'		=> __( 'Screen Content', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( 'You can hide/display columns based on your needs and decide how many forums to list per screen using the Screen Options tab.',                                                                                                                                'bbpress' ) . '</li>' .
+					'<li>' . __( 'You can filter the list of forums by forum status using the text links in the upper left to show All, Published, or Trashed forums. The default view is to show all forums.',                                                                                 'bbpress' ) . '</li>' .
+					'<li>' . __( 'You can refine the list to show only forums from a specific month by using the dropdown menus above the forums list. Click the Filter button after making your selection. You also can refine the list by clicking on the forum creator in the forums list.', 'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		// Available Actions
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'action-links',
+			'title'		=> __( 'Available Actions', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'Hovering over a row in the forums list will display action links that allow you to manage your forum. You can perform the following actions:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that forum. You can also reach that screen by clicking on the forum title.',                                                                              'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Trash</strong> removes your forum from this list and places it in the trash, from which you can permanently delete it.',                                                                                    'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>View</strong> will show you what your draft forum will look like if you publish it. View will take you to your live site to view the forum. Which link is available depends on your forum&#8217;s status.', 'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		// Bulk Actions
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'bulk-actions',
+			'title'		=> __( 'Bulk Actions', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'You can also edit or move multiple forums to the trash at once. Select the forums you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.',           'bbpress' ) . '</p>' .
+				'<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected forums at once. To remove a forum from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
+		) );
+
+		// Help Sidebar
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
+			'<p>' . __( '<a href="http://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
+		);
+	}
+
+	/**
+	 * Contextual help for bbPress forum edit page
+	 *
+	 * @since bbPress (r3119)
+	 * @uses get_current_screen()
+	 */
+	public function new_help() {
+
+		if ( $this->bail() ) return;
+
+		$customize_display = '<p>' . __( 'The title field and the big forum editing Area are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.', 'bbpress' ) . '</p>';
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'customize-display',
+			'title'   => __( 'Customizing This Display', 'bbpress' ),
+			'content' => $customize_display,
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'title-forum-editor',
+			'title'   => __( 'Title and Forum Editor', 'bbpress' ),
+			'content' =>
+				'<p>' . __( '<strong>Title</strong> - Enter a title for your forum. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
+				'<p>' . __( '<strong>Forum Editor</strong> - Enter the text for your forum. There are two modes of editing: Visual and HTML. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The HTML mode allows you to enter raw HTML along with your forum text. You can insert media files by clicking the icons above the forum editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in HTML mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular forum editor.', 'bbpress' ) . '</p>'
+		) );
+
+		$publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your forum in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a forum or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a forum to be published in the future or backdate a forum.', 'bbpress' ) . '</p>';
+
+		if ( current_theme_supports( 'forum-thumbnails' ) && post_type_supports( 'forum', 'thumbnail' ) ) {
+			$publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your forum without inserting it. This is usually useful only if your theme makes use of the featured image as a forum thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
+		}
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'forum-attributes',
+			'title'   => __( 'Forum Attributes', 'bbpress' ),
+			'content' =>
+				'<p>' . __( 'Select the attributes that your forum should have:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( '<strong>Type</strong> indicates if the forum is a category or forum. Categories generally contain other forums.',                                                                                'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Status</strong> allows you to close a forum to new topics and forums.',                                                                                                                  'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Visibility</strong> lets you pick the scope of each forum and what users are allowed to access it.',                                                                                     'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Parent</strong> dropdown determines the parent forum. Select the forum or category from the dropdown, or leave the default (No Parent) to create the forum at the root of your forums.', 'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Order</strong> allows you to order your forums numerically.',                                                                                                                            'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'publish-box',
+			'title'   => __( 'Publish Box', 'bbpress' ),
+			'content' => $publish_box,
+		) );
+
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
+			'<p>' . __( '<a href="http://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
+		);
+	}
+
+	/**
+	 * Add the forum attributes metabox
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses add_meta_box() To add the metabox
+	 * @uses do_action() Calls 'bbp_forum_attributes_metabox'
+	 */
+	public function attributes_metabox() {
+
+		if ( $this->bail() ) return;
+
+		add_meta_box (
+			'bbp_forum_attributes',
+			__( 'Forum Attributes', 'bbpress' ),
+			'bbp_forum_metabox',
+			$this->post_type,
+			'side',
+			'high'
+		);
+
+		do_action( 'bbp_forum_attributes_metabox' );
+	}
+
+	/**
+	 * Pass the forum attributes for processing
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @param int $forum_id Forum id
+	 * @uses current_user_can() To check if the current user is capable of
+	 *                           editing the forum
+	 * @uses bbp_get_forum() To get the forum
+	 * @uses bbp_is_forum_closed() To check if the forum is closed
+	 * @uses bbp_is_forum_category() To check if the forum is a category
+	 * @uses bbp_is_forum_private() To check if the forum is private
+	 * @uses bbp_close_forum() To close the forum
+	 * @uses bbp_open_forum() To open the forum
+	 * @uses bbp_categorize_forum() To make the forum a category
+	 * @uses bbp_normalize_forum() To make the forum normal (not category)
+	 * @uses bbp_privatize_forum() To mark the forum as private
+	 * @uses bbp_publicize_forum() To mark the forum as public
+	 * @uses do_action() Calls 'bbp_forum_attributes_metabox_save' with the
+	 *                    forum id
+	 * @return int Forum id
+	 */
+	public function attributes_metabox_save( $forum_id ) {
+
+		if ( $this->bail() ) return $forum_id;
+
+		// Bail if doing an autosave
+		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
+			return $forum_id;
+
+		// Bail if not a post request
+		if ( ! bbp_is_post_request() )
+			return $forum_id;
+
+		// Nonce check
+		if ( empty( $_POST['bbp_forum_metabox'] ) || !wp_verify_nonce( $_POST['bbp_forum_metabox'], 'bbp_forum_metabox_save' ) )
+			return $forum_id;
+
+		// Only save for forum post-types
+		if ( ! bbp_is_forum( $forum_id ) )
+			return $forum_id;
+
+		// Bail if current user cannot edit this forum
+		if ( !current_user_can( 'edit_forum', $forum_id ) )
+			return $forum_id;
+
+		// Parent ID
+		$parent_id = ( !empty( $_POST['parent_id'] ) && is_numeric( $_POST['parent_id'] ) ) ? (int) $_POST['parent_id'] : 0;
+
+		// Update the forum meta bidness
+		bbp_update_forum( array(
+			'forum_id'    => $forum_id,
+			'post_parent' => (int) $parent_id
+		) );
+
+		do_action( 'bbp_forum_attributes_metabox_save', $forum_id );
+
+		return $forum_id;
+	}
+
+	/**
+	 * Add some general styling to the admin area
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses sanitize_html_class() To sanitize the classes
+	 * @uses do_action() Calls 'bbp_admin_head'
+	 */
+	public function admin_head() {
+
+		if ( $this->bail() ) return;
+
+		?>
+
+		<style type="text/css" media="screen">
+		/*<![CDATA[*/
+
+			#misc-publishing-actions,
+			#save-post {
+				display: none;
+			}
+
+			strong.label {
+				display: inline-block;
+				width: 60px;
+			}
+
+			#bbp_forum_attributes hr {
+				border-style: solid;
+				border-width: 1px;
+				border-color: #ccc #fff #fff #ccc;
+			}
+
+			.column-bbp_forum_topic_count,
+			.column-bbp_forum_reply_count,
+			.column-bbp_topic_reply_count,
+			.column-bbp_topic_voice_count {
+				width: 8% !important;
+			}
+
+			.column-author,
+			.column-bbp_reply_author,
+			.column-bbp_topic_author {
+				width: 10% !important;
+			}
+
+			.column-bbp_topic_forum,
+			.column-bbp_reply_forum,
+			.column-bbp_reply_topic {
+				width: 10% !important;
+			}
+
+			.column-bbp_forum_freshness,
+			.column-bbp_topic_freshness {
+				width: 10% !important;
+			}
+
+			.column-bbp_forum_created,
+			.column-bbp_topic_created,
+			.column-bbp_reply_created {
+				width: 15% !important;
+			}
+
+			.status-closed {
+				background-color: #eaeaea;
+			}
+
+			.status-spam {
+				background-color: #faeaea;
+			}
+
+		/*]]>*/
+		</style>
+
+		<?php
+	}
+
+	/**
+	 * Manage the column headers for the forums page
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param array $columns The columns
+	 * @uses apply_filters() Calls 'bbp_admin_forums_column_headers' with
+	 *                        the columns
+	 * @return array $columns bbPress forum columns
+	 */
+	public function column_headers( $columns ) {
+
+		if ( $this->bail() ) return $columns;
+
+		$columns = array (
+			'cb'                    => '<input type="checkbox" />',
+			'title'                 => __( 'Forum',     'bbpress' ),
+			'bbp_forum_topic_count' => __( 'Topics',    'bbpress' ),
+			'bbp_forum_reply_count' => __( 'Replies',   'bbpress' ),
+			'author'                => __( 'Creator',   'bbpress' ),
+			'bbp_forum_created'     => __( 'Created' ,  'bbpress' ),
+			'bbp_forum_freshness'   => __( 'Freshness', 'bbpress' )
+		);
+
+		return apply_filters( 'bbp_admin_forums_column_headers', $columns );
+	}
+
+	/**
+	 * Print extra columns for the forums page
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param string $column Column
+	 * @param int $forum_id Forum id
+	 * @uses bbp_forum_topic_count() To output the forum topic count
+	 * @uses bbp_forum_reply_count() To output the forum reply count
+	 * @uses get_the_date() Get the forum creation date
+	 * @uses get_the_time() Get the forum creation time
+	 * @uses esc_attr() To sanitize the forum creation time
+	 * @uses bbp_get_forum_last_active_time() To get the time when the forum was
+	 *                                    last active
+	 * @uses do_action() Calls 'bbp_admin_forums_column_data' with the
+	 *                    column and forum id
+	 */
+	public function column_data( $column, $forum_id ) {
+
+		if ( $this->bail() ) return;
+
+		switch ( $column ) {
+			case 'bbp_forum_topic_count' :
+				bbp_forum_topic_count( $forum_id );
+				break;
+
+			case 'bbp_forum_reply_count' :
+				bbp_forum_reply_count( $forum_id );
+				break;
+
+			case 'bbp_forum_created':
+				printf( '%1$s <br /> %2$s',
+					get_the_date(),
+					esc_attr( get_the_time() )
+				);
+
+				break;
+
+			case 'bbp_forum_freshness' :
+				$last_active = bbp_get_forum_last_active_time( $forum_id, false );
+				if ( !empty( $last_active ) )
+					echo esc_html( $last_active );
+				else
+					esc_html_e( 'No Topics', 'bbpress' );
+
+				break;
+
+			default:
+				do_action( 'bbp_admin_forums_column_data', $column, $forum_id );
+				break;
+		}
+	}
+
+	/**
+	 * Forum Row actions
+	 *
+	 * Remove the quick-edit action link and display the description under
+	 * the forum title
+	 *
+	 * @since bbPress (r2577)
+	 *
+	 * @param array $actions Actions
+	 * @param array $forum Forum object
+	 * @uses bbp_forum_content() To output forum description
+	 * @return array $actions Actions
+	 */
+	public function row_actions( $actions, $forum ) {
+
+		if ( $this->bail() ) return $actions;
+
+		unset( $actions['inline hide-if-no-js'] );
+
+		// simple hack to show the forum description under the title
+		bbp_forum_content( $forum->ID );
+
+		return $actions;
+	}
+
+	/**
+	 * Custom user feedback messages for forum post type
+	 *
+	 * @since bbPress (r3080)
+	 *
+	 * @global int $post_ID
+	 * @uses bbp_get_forum_permalink()
+	 * @uses wp_post_revision_title()
+	 * @uses esc_url()
+	 * @uses add_query_arg()
+	 *
+	 * @param array $messages
+	 *
+	 * @return array
+	 */
+	public function updated_messages( $messages ) {
+		global $post_ID;
+
+		if ( $this->bail() ) return $messages;
+
+		// URL for the current forum
+		$forum_url = bbp_get_forum_permalink( $post_ID );
+
+		// Current forum's post_date
+		$post_date = bbp_get_global_post_field( 'post_date', 'raw' );
+
+		// Messages array
+		$messages[$this->post_type] = array(
+			0 =>  '', // Left empty on purpose
+
+			// Updated
+			1 =>  sprintf( __( 'Forum updated. <a href="%s">View forum</a>', 'bbpress' ), $forum_url ),
+
+			// Custom field updated
+			2 => __( 'Custom field updated.', 'bbpress' ),
+
+			// Custom field deleted
+			3 => __( 'Custom field deleted.', 'bbpress' ),
+
+			// Forum updated
+			4 => __( 'Forum updated.', 'bbpress' ),
+
+			// Restored from revision
+			// translators: %s: date and time of the revision
+			5 => isset( $_GET['revision'] )
+					? sprintf( __( 'Forum restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
+					: false,
+
+			// Forum created
+			6 => sprintf( __( 'Forum created. <a href="%s">View forum</a>', 'bbpress' ), $forum_url ),
+
+			// Forum saved
+			7 => __( 'Forum saved.', 'bbpress' ),
+
+			// Forum submitted
+			8 => sprintf( __( 'Forum submitted. <a target="_blank" href="%s">Preview forum</a>', 'bbpress' ), esc_url( add_query_arg( 'preview', 'true', $forum_url ) ) ),
+
+			// Forum scheduled
+			9 => sprintf( __( 'Forum scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview forum</a>', 'bbpress' ),
+					// translators: Publish box date format, see http://php.net/date
+					date_i18n( __( 'M j, Y @ G:i', 'bbpress' ),
+					strtotime( $post_date ) ),
+					$forum_url ),
+
+			// Forum draft updated
+			10 => sprintf( __( 'Forum draft updated. <a target="_blank" href="%s">Preview forum</a>', 'bbpress' ), esc_url( add_query_arg( 'preview', 'true', $forum_url ) ) ),
+		);
+
+		return $messages;
+	}
+}
+endif; // class_exists check
+
+/**
+ * Setup bbPress Forums Admin
+ *
+ * This is currently here to make hooking and unhooking of the admin UI easy.
+ * It could use dependency injection in the future, but for now this is easier.
+ *
+ * @since bbPress (r2596)
+ *
+ * @uses BBP_Forums_Admin
+ */
+function bbp_admin_forums() {
+	bbpress()->admin->forums = new BBP_Forums_Admin();
+}
Index: /tags/2.5.4/includes/admin/functions.php
===================================================================
--- /tags/2.5.4/includes/admin/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/functions.php	(revision 5382)
@@ -0,0 +1,294 @@
+<?php
+
+/**
+ * bbPress Admin Functions
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Admin Menus ***************************************************************/
+
+/**
+ * Add a separator to the WordPress admin menus
+ *
+ * @since bbPress (r2957)
+ */
+function bbp_admin_separator() {
+
+	// Caps necessary where a separator is necessary
+	$caps = array(
+		'bbp_forums_admin',
+		'bbp_topics_admin',
+		'bbp_replies_admin',
+	);
+
+	// Loop through caps, and look for a reason to show the separator
+	foreach ( $caps as $cap ) {
+		if ( current_user_can( $cap ) ) {
+			bbpress()->admin->show_separator = true;
+			break;
+		}
+	}
+
+	// Bail if no separator
+	if ( false === bbpress()->admin->show_separator ) {
+		return;
+	}
+
+	global $menu;
+
+	$menu[] = array( '', 'read', 'separator-bbpress', '', 'wp-menu-separator bbpress' );
+}
+
+/**
+ * Tell WordPress we have a custom menu order
+ *
+ * @since bbPress (r2957)
+ *
+ * @param bool $menu_order Menu order
+ * @return mixed True if separator, false if not
+ */
+function bbp_admin_custom_menu_order( $menu_order = false ) {
+	if ( false === bbpress()->admin->show_separator )
+		return $menu_order;
+
+	return true;
+}
+
+/**
+ * Move our custom separator above our custom post types
+ *
+ * @since bbPress (r2957)
+ *
+ * @param array $menu_order Menu Order
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @return array Modified menu order
+ */
+function bbp_admin_menu_order( $menu_order ) {
+
+	// Bail if user cannot see any top level bbPress menus
+	if ( empty( $menu_order ) || ( false === bbpress()->admin->show_separator ) )
+		return $menu_order;
+
+	// Initialize our custom order array
+	$bbp_menu_order = array();
+
+	// Menu values
+	$second_sep   = 'separator2';
+	$custom_menus = array(
+		'separator-bbpress',                               // Separator
+		'edit.php?post_type=' . bbp_get_forum_post_type(), // Forums
+		'edit.php?post_type=' . bbp_get_topic_post_type(), // Topics
+		'edit.php?post_type=' . bbp_get_reply_post_type()  // Replies
+	);
+
+	// Loop through menu order and do some rearranging
+	foreach ( $menu_order as $item ) {
+
+		// Position bbPress menus above appearance
+		if ( $second_sep == $item ) {
+
+			// Add our custom menus
+			foreach ( $custom_menus as $custom_menu ) {
+				if ( array_search( $custom_menu, $menu_order ) ) {
+					$bbp_menu_order[] = $custom_menu;
+				}
+			}
+
+			// Add the appearance separator
+			$bbp_menu_order[] = $second_sep;
+
+		// Skip our menu items
+		} elseif ( ! in_array( $item, $custom_menus ) ) {
+			$bbp_menu_order[] = $item;
+		}
+	}
+
+	// Return our custom order
+	return $bbp_menu_order;
+}
+
+/**
+ * Filter sample permalinks so that certain languages display properly.
+ *
+ * @since bbPress (r3336)
+ *
+ * @param string $post_link Custom post type permalink
+ * @param object $_post Post data object
+ * @param bool $leavename Optional, defaults to false. Whether to keep post name or page name.
+ * @param bool $sample Optional, defaults to false. Is it a sample permalink.
+ *
+ * @uses is_admin() To make sure we're on an admin page
+ * @uses bbp_is_custom_post_type() To get the forum post type
+ *
+ * @return string The custom post type permalink
+ */
+function bbp_filter_sample_permalink( $post_link, $_post, $leavename = false, $sample = false ) {
+
+	// Bail if not on an admin page and not getting a sample permalink
+	if ( !empty( $sample ) && is_admin() && bbp_is_custom_post_type() )
+		return urldecode( $post_link );
+
+	// Return post link
+	return $post_link;
+}
+
+/**
+ * Sanitize permalink slugs when saving the settings page.
+ *
+ * @since bbPress (r5364)
+ *
+ * @param string $slug
+ * @return string
+ */
+function bbp_sanitize_slug( $slug = '' ) {
+
+	// Don't allow multiple slashes in a row
+	$value = preg_replace( '#/+#', '/', str_replace( '#', '', $slug ) );
+
+	// Strip out unsafe or unusable chars
+	$value = esc_url_raw( $value );
+
+	// esc_url_raw() adds a scheme via esc_url(), so let's remove it
+	$value = str_replace( 'http://', '', $value );
+
+	// Trim off first and last slashes.
+	//
+	// We already prevent double slashing elsewhere, but let's prevent
+	// accidental poisoning of options values where we can.
+	$value = ltrim( $value, '/' );
+	$value = rtrim( $value, '/' );
+
+	// Filter the result and return
+	return apply_filters( 'bbp_sanitize_slug', $value, $slug );
+}
+
+/**
+ * Uninstall all bbPress options and capabilities from a specific site.
+ *
+ * @since bbPress (r3765)
+ * @param type $site_id
+ */
+function bbp_do_uninstall( $site_id = 0 ) {
+	if ( empty( $site_id ) )
+		$site_id = get_current_blog_id();
+
+	switch_to_blog( $site_id );
+	bbp_delete_options();
+	bbp_remove_caps();
+	flush_rewrite_rules();
+	restore_current_blog();
+}
+
+/**
+ * Redirect user to bbPress's What's New page on activation
+ *
+ * @since bbPress (r4389)
+ *
+ * @internal Used internally to redirect bbPress to the about page on activation
+ *
+ * @uses get_transient() To see if transient to redirect exists
+ * @uses delete_transient() To delete the transient if it exists
+ * @uses is_network_admin() To bail if being network activated
+ * @uses wp_safe_redirect() To redirect
+ * @uses add_query_arg() To help build the URL to redirect to
+ * @uses admin_url() To get the admin URL to index.php
+ *
+ * @return If no transient, or in network admin, or is bulk activation
+ */
+function bbp_do_activation_redirect() {
+
+	// Bail if no activation redirect
+    if ( ! get_transient( '_bbp_activation_redirect' ) ) {
+		return;
+	}
+
+	// Delete the redirect transient
+	delete_transient( '_bbp_activation_redirect' );
+
+	// Bail if activating from network, or bulk
+	if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
+		return;
+	}
+
+	// Bail if the current user cannot see the about page
+	if ( ! current_user_can( 'bbp_about_page' ) ) {
+		return;
+	}
+
+	// Redirect to bbPress about page
+	wp_safe_redirect( add_query_arg( array( 'page' => 'bbp-about' ), admin_url( 'index.php' ) ) );
+}
+
+/**
+ * This tells WP to highlight the Tools > Forums menu item,
+ * regardless of which actual bbPress Tools screen we are on.
+ *
+ * The conditional prevents the override when the user is viewing settings or
+ * any third-party plugins.
+ *
+ * @since bbPress (r3888)
+ * @global string $plugin_page
+ * @global array $submenu_file
+ */
+function bbp_tools_modify_menu_highlight() {
+	global $plugin_page, $submenu_file;
+
+	// This tweaks the Tools subnav menu to only show one bbPress menu item
+	if ( ! in_array( $plugin_page, array( 'bbp-settings' ) ) )
+		$submenu_file = 'bbp-repair';
+}
+
+/**
+ * Output the tabs in the admin area
+ *
+ * @since bbPress (r3872)
+ * @param string $active_tab Name of the tab that is active
+ */
+function bbp_tools_admin_tabs( $active_tab = '' ) {
+	echo bbp_get_tools_admin_tabs( $active_tab );
+}
+
+	/**
+	 * Output the tabs in the admin area
+	 *
+	 * @since bbPress (r3872)
+	 * @param string $active_tab Name of the tab that is active
+	 */
+	function bbp_get_tools_admin_tabs( $active_tab = '' ) {
+
+		// Declare local variables
+		$tabs_html    = '';
+		$idle_class   = 'nav-tab';
+		$active_class = 'nav-tab nav-tab-active';
+
+		// Setup core admin tabs
+		$tabs = apply_filters( 'bbp_tools_admin_tabs', array(
+			'0' => array(
+				'href' => get_admin_url( '', add_query_arg( array( 'page' => 'bbp-repair'    ), 'tools.php' ) ),
+				'name' => __( 'Repair Forums', 'bbpress' )
+			),
+			'1' => array(
+				'href' => get_admin_url( '', add_query_arg( array( 'page' => 'bbp-converter' ), 'tools.php' ) ),
+				'name' => __( 'Import Forums', 'bbpress' )
+			),
+			'2' => array(
+				'href' => get_admin_url( '', add_query_arg( array( 'page' => 'bbp-reset'     ), 'tools.php' ) ),
+				'name' => __( 'Reset Forums', 'bbpress' )
+			)
+		) );
+
+		// Loop through tabs and build navigation
+		foreach ( array_values( $tabs ) as $tab_data ) {
+			$is_current = (bool) ( $tab_data['name'] == $active_tab );
+			$tab_class  = $is_current ? $active_class : $idle_class;
+			$tabs_html .= '<a href="' . esc_url( $tab_data['href'] ) . '" class="' . esc_attr( $tab_class ) . '">' . esc_html( $tab_data['name'] ) . '</a>';
+		}
+
+		// Output the tabs
+		return $tabs_html;
+	}
Index: /tags/2.5.4/includes/admin/images/index.php
===================================================================
--- /tags/2.5.4/includes/admin/images/index.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/images/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/admin/index.php
===================================================================
--- /tags/2.5.4/includes/admin/index.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/admin/js/common.js
===================================================================
--- /tags/2.5.4/includes/admin/js/common.js	(revision 5382)
+++ /tags/2.5.4/includes/admin/js/common.js	(revision 5382)
@@ -0,0 +1,11 @@
+jQuery( document ).ready( function() {
+
+	var bbp_author_id = jQuery( '#bbp_author_id' );
+
+	bbp_author_id.suggest( ajaxurl + '?action=bbp_suggest_user', {
+		onSelect: function() {
+			var value = this.value;
+			bbp_author_id.val( value.substr( 0, value.indexOf( ' ' ) ) );
+		}
+	} );
+} );
Index: /tags/2.5.4/includes/admin/js/replies.js
===================================================================
--- /tags/2.5.4/includes/admin/js/replies.js	(revision 5382)
+++ /tags/2.5.4/includes/admin/js/replies.js	(revision 5382)
@@ -0,0 +1,11 @@
+jQuery( document ).ready(function() {
+
+	var bbp_topic_id = jQuery( '#bbp_topic_id' );
+
+	bbp_topic_id.suggest( ajaxurl + '?action=bbp_suggest_topic', {
+		onSelect: function() {
+			var value = this.value;
+			bbp_topic_id.val( value.substr( 0, value.indexOf( ' ' ) ) );
+		}
+	} );
+} );
Index: /tags/2.5.4/includes/admin/js/topics.js
===================================================================
--- /tags/2.5.4/includes/admin/js/topics.js	(revision 5382)
+++ /tags/2.5.4/includes/admin/js/topics.js	(revision 5382)
@@ -0,0 +1,4 @@
+jQuery( document ).ready( function() {
+	jQuery( '#misc-publishing-actions' ).find( '.misc-pub-section' ).first().remove();
+	jQuery( '#save-action' ).remove();
+} );
Index: /tags/2.5.4/includes/admin/metaboxes.php
===================================================================
--- /tags/2.5.4/includes/admin/metaboxes.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/metaboxes.php	(revision 5382)
@@ -0,0 +1,532 @@
+<?php
+
+/**
+ * bbPress Admin Metaboxes
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+/** Dashboard *****************************************************************/
+
+/**
+ * bbPress Dashboard Right Now Widget
+ *
+ * Adds a dashboard widget with forum statistics
+ *
+ * @since bbPress (r2770)
+ *
+ * @uses bbp_get_version() To get the current bbPress version
+ * @uses bbp_get_statistics() To get the forum statistics
+ * @uses current_user_can() To check if the user is capable of doing things
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses get_admin_url() To get the administration url
+ * @uses add_query_arg() To add custom args to the url
+ * @uses do_action() Calls 'bbp_dashboard_widget_right_now_content_table_end'
+ *                    below the content table
+ * @uses do_action() Calls 'bbp_dashboard_widget_right_now_table_end'
+ *                    below the discussion table
+ * @uses do_action() Calls 'bbp_dashboard_widget_right_now_discussion_table_end'
+ *                    below the discussion table
+ * @uses do_action() Calls 'bbp_dashboard_widget_right_now_end' below the widget
+ */
+function bbp_dashboard_widget_right_now() {
+
+	// Get the statistics
+	$r = bbp_get_statistics(); ?>
+
+	<div class="table table_content">
+
+		<p class="sub"><?php esc_html_e( 'Discussion', 'bbpress' ); ?></p>
+
+		<table>
+
+			<tr class="first">
+
+				<?php
+					$num  = $r['forum_count'];
+					$text = _n( 'Forum', 'Forums', $r['forum_count'], 'bbpress' );
+					if ( current_user_can( 'publish_forums' ) ) {
+						$link = add_query_arg( array( 'post_type' => bbp_get_forum_post_type() ), get_admin_url( null, 'edit.php' ) );
+						$num  = '<a href="' . $link . '">' . $num  . '</a>';
+						$text = '<a href="' . $link . '">' . $text . '</a>';
+					}
+				?>
+
+				<td class="first b b-forums"><?php echo $num; ?></td>
+				<td class="t forums"><?php echo $text; ?></td>
+
+			</tr>
+
+			<tr>
+
+				<?php
+					$num  = $r['topic_count'];
+					$text = _n( 'Topic', 'Topics', $r['topic_count'], 'bbpress' );
+					if ( current_user_can( 'publish_topics' ) ) {
+						$link = add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), get_admin_url( null, 'edit.php' ) );
+						$num  = '<a href="' . $link . '">' . $num  . '</a>';
+						$text = '<a href="' . $link . '">' . $text . '</a>';
+					}
+				?>
+
+				<td class="first b b-topics"><?php echo $num; ?></td>
+				<td class="t topics"><?php echo $text; ?></td>
+
+			</tr>
+
+			<tr>
+
+				<?php
+					$num  = $r['reply_count'];
+					$text = _n( 'Reply', 'Replies', $r['reply_count'], 'bbpress' );
+					if ( current_user_can( 'publish_replies' ) ) {
+						$link = add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), get_admin_url( null, 'edit.php' ) );
+						$num  = '<a href="' . $link . '">' . $num  . '</a>';
+						$text = '<a href="' . $link . '">' . $text . '</a>';
+					}
+				?>
+
+				<td class="first b b-replies"><?php echo $num; ?></td>
+				<td class="t replies"><?php echo $text; ?></td>
+
+			</tr>
+
+			<?php if ( bbp_allow_topic_tags() ) : ?>
+
+				<tr>
+
+					<?php
+						$num  = $r['topic_tag_count'];
+						$text = _n( 'Topic Tag', 'Topic Tags', $r['topic_tag_count'], 'bbpress' );
+						if ( current_user_can( 'manage_topic_tags' ) ) {
+							$link = add_query_arg( array( 'taxonomy' => bbp_get_topic_tag_tax_id(), 'post_type' => bbp_get_topic_post_type() ), get_admin_url( null, 'edit-tags.php' ) );
+							$num  = '<a href="' . $link . '">' . $num  . '</a>';
+							$text = '<a href="' . $link . '">' . $text . '</a>';
+						}
+					?>
+
+					<td class="first b b-topic_tags"><span class="total-count"><?php echo $num; ?></span></td>
+					<td class="t topic_tags"><?php echo $text; ?></td>
+
+				</tr>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bbp_dashboard_widget_right_now_content_table_end' ); ?>
+
+		</table>
+
+	</div>
+
+
+	<div class="table table_discussion">
+
+		<p class="sub"><?php esc_html_e( 'Users &amp; Moderation', 'bbpress' ); ?></p>
+
+		<table>
+
+			<tr class="first">
+
+				<?php
+					$num  = $r['user_count'];
+					$text = _n( 'User', 'Users', $r['user_count'], 'bbpress' );
+					if ( current_user_can( 'edit_users' ) ) {
+						$link = get_admin_url( null, 'users.php' );
+						$num  = '<a href="' . $link . '">' . $num  . '</a>';
+						$text = '<a href="' . $link . '">' . $text . '</a>';
+					}
+				?>
+
+				<td class="b b-users"><span class="total-count"><?php echo $num; ?></span></td>
+				<td class="last t users"><?php echo $text; ?></td>
+
+			</tr>
+
+			<?php if ( isset( $r['topic_count_hidden'] ) ) : ?>
+
+				<tr>
+
+					<?php
+						$num  = $r['topic_count_hidden'];
+						$text = _n( 'Hidden Topic', 'Hidden Topics', $r['topic_count_hidden'], 'bbpress' );
+						$link = add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), get_admin_url( null, 'edit.php' ) );
+						if ( '0' !== $num ) {
+							$link = add_query_arg( array( 'post_status' => bbp_get_spam_status_id() ), $link );
+						}
+                        $num  = '<a href="' . $link . '" title="' . esc_attr( $r['hidden_topic_title'] ) . '">' . $num  . '</a>';
+						$text = '<a class="waiting" href="' . $link . '" title="' . esc_attr( $r['hidden_topic_title'] ) . '">' . $text . '</a>';
+					?>
+
+					<td class="b b-hidden-topics"><?php echo $num; ?></td>
+					<td class="last t hidden-replies"><?php echo $text; ?></td>
+
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( isset( $r['reply_count_hidden'] ) ) : ?>
+
+				<tr>
+
+					<?php
+						$num  = $r['reply_count_hidden'];
+						$text = _n( 'Hidden Reply', 'Hidden Replies', $r['reply_count_hidden'], 'bbpress' );
+						$link = add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), get_admin_url( null, 'edit.php' ) );
+						if ( '0' !== $num ) {
+							$link = add_query_arg( array( 'post_status' => bbp_get_spam_status_id() ), $link );
+						}
+                        $num  = '<a href="' . $link . '" title="' . esc_attr( $r['hidden_reply_title'] ) . '">' . $num  . '</a>';
+						$text = '<a class="waiting" href="' . $link . '" title="' . esc_attr( $r['hidden_reply_title'] ) . '">' . $text . '</a>';
+					?>
+
+					<td class="b b-hidden-replies"><?php echo $num; ?></td>
+					<td class="last t hidden-replies"><?php echo $text; ?></td>
+
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( bbp_allow_topic_tags() && isset( $r['empty_topic_tag_count'] ) ) : ?>
+
+				<tr>
+
+					<?php
+						$num  = $r['empty_topic_tag_count'];
+						$text = _n( 'Empty Topic Tag', 'Empty Topic Tags', $r['empty_topic_tag_count'], 'bbpress' );
+						$link = add_query_arg( array( 'taxonomy' => bbp_get_topic_tag_tax_id(), 'post_type' => bbp_get_topic_post_type() ), get_admin_url( null, 'edit-tags.php' ) );
+						$num  = '<a href="' . $link . '">' . $num  . '</a>';
+						$text = '<a class="waiting" href="' . $link . '">' . $text . '</a>';
+					?>
+
+					<td class="b b-hidden-topic-tags"><?php echo $num; ?></td>
+					<td class="last t hidden-topic-tags"><?php echo $text; ?></td>
+
+				</tr>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bbp_dashboard_widget_right_now_discussion_table_end' ); ?>
+
+		</table>
+
+	</div>
+
+	<?php do_action( 'bbp_dashboard_widget_right_now_table_end' ); ?>
+
+	<div class="versions">
+
+		<span id="wp-version-message">
+			<?php printf( __( 'You are using <span class="b">bbPress %s</span>.', 'bbpress' ), bbp_get_version() ); ?>
+		</span>
+
+	</div>
+
+	<br class="clear" />
+
+	<?php
+
+	do_action( 'bbp_dashboard_widget_right_now_end' );
+}
+
+/** Forums ********************************************************************/
+
+/**
+ * Forum metabox
+ *
+ * The metabox that holds all of the additional forum information
+ *
+ * @since bbPress (r2744)
+ *
+ * @uses bbp_is_forum_closed() To check if a forum is closed or not
+ * @uses bbp_is_forum_category() To check if a forum is a category or not
+ * @uses bbp_is_forum_private() To check if a forum is private or not
+ * @uses bbp_dropdown() To show a dropdown of the forums for forum parent
+ * @uses do_action() Calls 'bbp_forum_metabox'
+ */
+function bbp_forum_metabox() {
+
+	// Post ID
+	$post_id     = get_the_ID();
+	$post_parent = bbp_get_global_post_field( 'post_parent', 'raw'  );
+	$menu_order  = bbp_get_global_post_field( 'menu_order',  'edit' );
+
+	/** Type ******************************************************************/
+
+	?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Type:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="bbp_forum_type_select"><?php esc_html_e( 'Type:', 'bbpress' ) ?></label>
+		<?php bbp_form_forum_type_dropdown( array( 'forum_id' => $post_id ) ); ?>
+	</p>
+
+	<?php
+
+	/** Status ****************************************************************/
+
+	?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Status:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="bbp_forum_status_select"><?php esc_html_e( 'Status:', 'bbpress' ) ?></label>
+		<?php bbp_form_forum_status_dropdown( array( 'forum_id' => $post_id ) ); ?>
+	</p>
+
+	<?php
+
+	/** Visibility ************************************************************/
+
+	?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Visibility:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="bbp_forum_visibility_select"><?php esc_html_e( 'Visibility:', 'bbpress' ) ?></label>
+		<?php bbp_form_forum_visibility_dropdown( array( 'forum_id' => $post_id ) ); ?>
+	</p>
+
+	<hr />
+
+	<?php
+
+	/** Parent ****************************************************************/
+
+	?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Parent:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="parent_id"><?php esc_html_e( 'Forum Parent', 'bbpress' ); ?></label>
+		<?php bbp_dropdown( array(
+			'post_type'          => bbp_get_forum_post_type(),
+			'selected'           => $post_parent,
+			'numberposts'        => -1,
+			'orderby'            => 'title',
+			'order'              => 'ASC',
+			'walker'             => '',
+			'exclude'            => $post_id,
+
+			// Output-related
+			'select_id'          => 'parent_id',
+			'tab'                => bbp_get_tab_index(),
+			'options_only'       => false,
+			'show_none'          => __( '&mdash; No parent &mdash;', 'bbpress' ),
+			'disable_categories' => false,
+			'disabled'           => ''
+		) ); ?>
+	</p>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Order:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="menu_order"><?php esc_html_e( 'Forum Order', 'bbpress' ); ?></label>
+		<input name="menu_order" type="number" step="1" size="4" id="menu_order" value="<?php echo esc_attr( $menu_order ); ?>" />
+	</p>
+
+	<input name="ping_status" type="hidden" id="ping_status" value="open" />
+
+	<?php
+	wp_nonce_field( 'bbp_forum_metabox_save', 'bbp_forum_metabox' );
+	do_action( 'bbp_forum_metabox', $post_id );
+}
+
+/** Topics ********************************************************************/
+
+/**
+ * Topic metabox
+ *
+ * The metabox that holds all of the additional topic information
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses do_action() Calls 'bbp_topic_metabox'
+ */
+function bbp_topic_metabox() {
+
+	// Post ID
+	$post_id = get_the_ID();
+
+	/** Type ******************************************************************/
+
+	?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Type:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="bbp_stick_topic"><?php esc_html_e( 'Topic Type', 'bbpress' ); ?></label>
+		<?php bbp_form_topic_type_dropdown( array( 'topic_id' => $post_id ) ); ?>
+	</p>
+
+	<?php
+
+	/** Status ****************************************************************/
+
+	?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Status:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="bbp_open_close_topic"><?php esc_html_e( 'Select whether to open or close the topic.', 'bbpress' ); ?></label>
+		<?php bbp_form_topic_status_dropdown( array( 'select_id' => 'post_status', 'topic_id' => $post_id ) ); ?>
+	</p>
+
+	<?php
+
+	/** Parent *****************************************************************/
+
+	?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Forum:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="parent_id"><?php esc_html_e( 'Forum', 'bbpress' ); ?></label>
+		<?php bbp_dropdown( array(
+			'post_type'          => bbp_get_forum_post_type(),
+			'selected'           => bbp_get_topic_forum_id( $post_id ),
+			'numberposts'        => -1,
+			'orderby'            => 'title',
+			'order'              => 'ASC',
+			'walker'             => '',
+			'exclude'            => '',
+
+			// Output-related
+			'select_id'          => 'parent_id',
+			'tab'                => bbp_get_tab_index(),
+			'options_only'       => false,
+			'show_none'          => __( '&mdash; No parent &mdash;', 'bbpress' ),
+			'disable_categories' => current_user_can( 'edit_forums' ),
+			'disabled'           => ''
+		) ); ?>
+	</p>
+
+	<input name="ping_status" type="hidden" id="ping_status" value="open" />
+
+	<?php
+	wp_nonce_field( 'bbp_topic_metabox_save', 'bbp_topic_metabox' );
+	do_action( 'bbp_topic_metabox', $post_id );
+}
+
+/** Replies *******************************************************************/
+
+/**
+ * Reply metabox
+ *
+ * The metabox that holds all of the additional reply information
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses do_action() Calls 'bbp_reply_metabox'
+ */
+function bbp_reply_metabox() {
+
+	// Post ID
+	$post_id = get_the_ID();
+
+	// Get some meta
+	$reply_topic_id = bbp_get_reply_topic_id( $post_id );
+	$reply_forum_id = bbp_get_reply_forum_id( $post_id );
+	$reply_to       = bbp_get_reply_to(       $post_id );
+
+	// Allow individual manipulation of reply forum
+	if ( current_user_can( 'edit_others_replies' ) || current_user_can( 'moderate' ) ) : ?>
+
+		<p>
+			<strong class="label"><?php esc_html_e( 'Forum:', 'bbpress' ); ?></strong>
+			<label class="screen-reader-text" for="bbp_forum_id"><?php esc_html_e( 'Forum', 'bbpress' ); ?></label>
+			<?php bbp_dropdown( array(
+				'post_type'          => bbp_get_forum_post_type(),
+				'selected'           => $reply_forum_id,
+				'numberposts'        => -1,
+				'orderby'            => 'title',
+				'order'              => 'ASC',
+				'walker'             => '',
+				'exclude'            => '',
+
+				// Output-related
+				'select_id'          => 'bbp_forum_id',
+				'tab'                => bbp_get_tab_index(),
+				'options_only'       => false,
+				'show_none'          => __( '&mdash; No parent &mdash;', 'bbpress' ),
+				'disable_categories' => current_user_can( 'edit_forums' ),
+				'disabled'           => ''
+			) ); ?>
+		</p>
+
+	<?php endif; ?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Topic:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="parent_id"><?php esc_html_e( 'Topic', 'bbpress' ); ?></label>
+		<input name="parent_id" id="bbp_topic_id" type="text" value="<?php echo esc_attr( $reply_topic_id ); ?>" />
+	</p>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'Reply To:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="bbp_reply_to"><?php esc_html_e( 'Reply To', 'bbpress' ); ?></label>
+		<input name="bbp_reply_to" id="bbp_reply_to" type="text" value="<?php echo esc_attr( $reply_to ); ?>" />
+	</p>
+
+	<input name="ping_status" type="hidden" id="ping_status" value="open" />
+
+	<?php
+	wp_nonce_field( 'bbp_reply_metabox_save', 'bbp_reply_metabox' );
+	do_action( 'bbp_reply_metabox', $post_id );
+}
+
+/** Users *********************************************************************/
+
+/**
+ * Anonymous user information metabox
+ *
+ * @since bbPress (r2828)
+ *
+ * @uses bbp_is_reply_anonymous() To check if reply is anonymous
+ * @uses bbp_is_topic_anonymous() To check if topic is anonymous
+ * @uses get_the_ID() To get the global post ID
+ * @uses get_post_meta() To get the author user information
+ */
+function bbp_author_metabox() {
+
+	// Post ID
+	$post_id = get_the_ID();
+
+	// Show extra bits if topic/reply is anonymous
+	if ( bbp_is_reply_anonymous( $post_id ) || bbp_is_topic_anonymous( $post_id ) ) : ?>
+
+		<p>
+			<strong class="label"><?php esc_html_e( 'Name:', 'bbpress' ); ?></strong>
+			<label class="screen-reader-text" for="bbp_anonymous_name"><?php esc_html_e( 'Name', 'bbpress' ); ?></label>
+			<input type="text" id="bbp_anonymous_name" name="bbp_anonymous_name" value="<?php echo esc_attr( get_post_meta( $post_id, '_bbp_anonymous_name', true ) ); ?>" />
+		</p>
+
+		<p>
+			<strong class="label"><?php esc_html_e( 'Email:', 'bbpress' ); ?></strong>
+			<label class="screen-reader-text" for="bbp_anonymous_email"><?php esc_html_e( 'Email', 'bbpress' ); ?></label>
+			<input type="text" id="bbp_anonymous_email" name="bbp_anonymous_email" value="<?php echo esc_attr( get_post_meta( $post_id, '_bbp_anonymous_email', true ) ); ?>" />
+		</p>
+
+		<p>
+			<strong class="label"><?php esc_html_e( 'Website:', 'bbpress' ); ?></strong>
+			<label class="screen-reader-text" for="bbp_anonymous_website"><?php esc_html_e( 'Website', 'bbpress' ); ?></label>
+			<input type="text" id="bbp_anonymous_website" name="bbp_anonymous_website" value="<?php echo esc_attr( get_post_meta( $post_id, '_bbp_anonymous_website', true ) ); ?>" />
+		</p>
+
+	<?php else : ?>
+
+		<p>
+			<strong class="label"><?php esc_html_e( 'ID:', 'bbpress' ); ?></strong>
+			<label class="screen-reader-text" for="bbp_author_id"><?php esc_html_e( 'ID', 'bbpress' ); ?></label>
+			<input type="text" id="bbp_author_id" name="post_author_override" value="<?php echo esc_attr( bbp_get_global_post_field( 'post_author' ) ); ?>" />
+		</p>
+
+	<?php endif; ?>
+
+	<p>
+		<strong class="label"><?php esc_html_e( 'IP:', 'bbpress' ); ?></strong>
+		<label class="screen-reader-text" for="bbp_author_ip_address"><?php esc_html_e( 'IP Address', 'bbpress' ); ?></label>
+		<input type="text" id="bbp_author_ip_address" name="bbp_author_ip_address" value="<?php echo esc_attr( get_post_meta( $post_id, '_bbp_author_ip', true ) ); ?>" disabled="disabled" />
+	</p>
+
+	<?php
+
+	do_action( 'bbp_author_metabox', $post_id );
+}
Index: /tags/2.5.4/includes/admin/parser.php
===================================================================
--- /tags/2.5.4/includes/admin/parser.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/parser.php	(revision 5382)
@@ -0,0 +1,2073 @@
+<?php
+/*
+This is a compressed copy of NBBC. Do not edit!
+
+Copyright (c) 2008-9, the Phantom Inker.  All rights reserved.
+Portions Copyright (c) 2004-2008 AddedBytes.com
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in
+  the documentation and/or other materials provided with the
+  distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE PHANTOM INKER "AS IS" AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+define("BBCODE_VERSION", "1.4.5");
+define("BBCODE_RELEASE", "2010-09-17");
+define("BBCODE_VERBATIM", 2);
+define("BBCODE_REQUIRED", 1);
+define("BBCODE_OPTIONAL", 0);
+define("BBCODE_PROHIBIT", -1);
+define("BBCODE_CHECK", 1);
+define("BBCODE_OUTPUT", 2);
+define("BBCODE_ENDTAG", 5);
+define("BBCODE_TAG", 4);
+define("BBCODE_TEXT", 3);
+define("BBCODE_NL", 2);
+define("BBCODE_WS", 1);
+define("BBCODE_EOI", 0);
+define("BBCODE_LEXSTATE_TEXT", 0);
+define("BBCODE_LEXSTATE_TAG", 1);
+define("BBCODE_MODE_SIMPLE", 0);
+define("BBCODE_MODE_CALLBACK", 1);
+define("BBCODE_MODE_INTERNAL", 2);
+define("BBCODE_MODE_LIBRARY", 3);
+define("BBCODE_MODE_ENHANCED", 4);
+define("BBCODE_STACK_TOKEN", 0);
+define("BBCODE_STACK_TEXT", 1);
+define("BBCODE_STACK_TAG", 2);
+define("BBCODE_STACK_CLASS", 3);
+if (!function_exists('str_split')) {
+function str_split($string, $split_length = 1) {
+$array = explode("\r\n", chunk_split($string, $split_length));
+array_pop($array);
+return $array;
+}
+}
+$BBCode_SourceDir = dirname(__FILE__);
+
+class BBCodeLexer {
+var $token;
+var $text;
+var $tag;
+var $state;
+var $input;
+var $ptr;
+var $unget;
+var $verbatim;
+var $debug;
+var $tagmarker;
+var $end_tagmarker;
+var $pat_main;
+var $pat_comment;
+var $pat_comment2;
+var $pat_wiki;
+function BBCodeLexer($string, $tagmarker = '[') {
+$regex_beginmarkers = Array( '[' => '\[', '<' => '<', '{' => '\{', '(' => '\(' );
+$regex_endmarkers = Array( '[' => '\]', '<' => '>', '{' => '\}', '(' => '\)' );
+$endmarkers = Array( '[' => ']', '<' => '>', '{' => '}', '(' => ')' );
+if (!isset($regex_endmarkers[$tagmarker])) $tagmarker = '[';
+$e = $regex_endmarkers[$tagmarker];
+$b = $regex_beginmarkers[$tagmarker];
+$this->tagmarker = $tagmarker;
+$this->end_tagmarker = $endmarkers[$tagmarker];
+$this->pat_main = "/( "
+. "{$b}"
+. "(?! -- | ' | !-- | {$b}{$b} )"
+. "(?: [^\\n\\r{$b}{$e}] | \\\" [^\\\"\\n\\r]* \\\" | \\' [^\\'\\n\\r]* \\' )*"
+. "{$e}"
+. "| {$b}{$b} (?: [^{$e}\\r\\n] | {$e}[^{$e}\\r\\n] )* {$e}{$e}"
+. "| {$b} (?: -- | ' ) (?: [^{$e}\\n\\r]* ) {$e}"
+. "| {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e}"
+. "| -----+"
+. "| \\x0D\\x0A | \\x0A\\x0D | \\x0D | \\x0A"
+. "| [\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+(?=[\\x0D\\x0A{$b}]|-----|$)"
+. "| (?<=[\\x0D\\x0A{$e}]|-----|^)[\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+"
+. " )/Dx";
+$this->input = preg_split($this->pat_main, $string, -1, PREG_SPLIT_DELIM_CAPTURE);
+$this->pat_comment = "/^ {$b} (?: -- | ' ) /Dx";
+$this->pat_comment2 = "/^ {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e} $/Dx";
+$this->pat_wiki = "/^ {$b}{$b} ([^\\|]*) (?:\\|(.*))? {$e}{$e} $/Dx";
+$this->ptr = 0;
+$this->unget = false;
+$this->state = BBCODE_LEXSTATE_TEXT;
+$this->verbatim = false;
+$this->token = BBCODE_EOI;
+$this->tag = false;
+$this->text = "";
+}
+function GuessTextLength() {
+$length = 0;
+$ptr = 0;
+$state = BBCODE_LEXSTATE_TEXT;
+while ($ptr < count($this->input)) {
+$text = $this->input[$ptr++];
+if ($state == BBCODE_LEXSTATE_TEXT) {
+$state = BBCODE_LEXSTATE_TAG;
+$length += strlen($text);
+}
+else {
+switch (ord(substr($this->text, 0, 1))) {
+case 10:
+case 13:
+$state = BBCODE_LEXSTATE_TEXT;
+$length++;
+break;
+default:
+$state = BBCODE_LEXSTATE_TEXT;
+$length += strlen($text);
+break;
+case 40:
+case 60:
+case 91:
+case 123:
+$state = BBCODE_LEXSTATE_TEXT;
+break;
+}
+}
+}
+return $length;
+}
+function NextToken() {
+if ($this->unget) {
+$this->unget = false;
+return $this->token;
+}
+while (true) {
+if ($this->ptr >= count($this->input)) {
+$this->text = "";
+$this->tag = false;
+return $this->token = BBCODE_EOI;
+}
+$this->text = preg_replace("/[\\x00-\\x08\\x0B-\\x0C\\x0E-\\x1F]/", "",
+$this->input[$this->ptr++]);
+if ($this->verbatim) {
+$this->tag = false;
+if ($this->state == BBCODE_LEXSTATE_TEXT) {
+$this->state = BBCODE_LEXSTATE_TAG;
+$token_type = BBCODE_TEXT;
+}
+else {
+$this->state = BBCODE_LEXSTATE_TEXT;
+switch (ord(substr($this->text, 0, 1))) {
+case 10:
+case 13:
+$token_type = BBCODE_NL;
+break;
+default:
+$token_type = BBCODE_WS;
+break;
+case 45:
+case 40:
+case 60:
+case 91:
+case 123:
+$token_type = BBCODE_TEXT;
+break;
+}
+}
+if (strlen($this->text) > 0)
+return $this->token = $token_type;
+}
+else if ($this->state == BBCODE_LEXSTATE_TEXT) {
+$this->state = BBCODE_LEXSTATE_TAG;
+$this->tag = false;
+if (strlen($this->text) > 0)
+return $this->token = BBCODE_TEXT;
+}
+else {
+switch (ord(substr($this->text, 0, 1))) {
+case 10:
+case 13:
+$this->tag = false;
+$this->state = BBCODE_LEXSTATE_TEXT;
+return $this->token = BBCODE_NL;
+case 45:
+if (preg_match("/^-----/", $this->text)) {
+$this->tag = Array('_name' => 'rule', '_endtag' => false, '_default' => '');
+$this->state = BBCODE_LEXSTATE_TEXT;
+return $this->token = BBCODE_TAG;
+}
+else {
+$this->tag = false;
+$this->state = BBCODE_LEXSTATE_TEXT;
+if (strlen($this->text) > 0)
+return $this->token = BBCODE_TEXT;
+continue;
+}
+default:
+$this->tag = false;
+$this->state = BBCODE_LEXSTATE_TEXT;
+return $this->token = BBCODE_WS;
+case 40:
+case 60:
+case 91:
+case 123:
+if (preg_match($this->pat_comment, $this->text)) {
+$this->state = BBCODE_LEXSTATE_TEXT;
+continue;
+}
+if (preg_match($this->pat_comment2, $this->text)) {
+$this->state = BBCODE_LEXSTATE_TEXT;
+continue;
+}
+if (preg_match($this->pat_wiki, $this->text, $matches)) {
+$this->tag = Array('_name' => 'wiki', '_endtag' => false,
+'_default' => @$matches[1], 'title' => @$matches[2]);
+$this->state = BBCODE_LEXSTATE_TEXT;
+return $this->token = BBCODE_TAG;
+}
+$this->tag = $this->Internal_DecodeTag($this->text);
+$this->state = BBCODE_LEXSTATE_TEXT;
+return $this->token = ($this->tag['_end'] ? BBCODE_ENDTAG : BBCODE_TAG);
+}
+}
+}
+}
+function UngetToken() {
+if ($this->token !== BBCODE_EOI)
+$this->unget = true;
+}
+function PeekToken() {
+$result = $this->NextToken();
+if ($this->token !== BBCODE_EOI)
+$this->unget = true;
+return $result;
+}
+function SaveState() {
+return Array(
+'token' => $this->token,
+'text' => $this->text,
+'tag' => $this->tag,
+'state' => $this->state,
+'input' => $this->input,
+'ptr' => $this->ptr,
+'unget' => $this->unget,
+'verbatim' => $this->verbatim
+);
+}
+function RestoreState($state) {
+if (!is_array($state)) return;
+$this->token = @$state['token'];
+$this->text = @$state['text'];
+$this->tag = @$state['tag'];
+$this->state = @$state['state'];
+$this->input = @$state['input'];
+$this->ptr = @$state['ptr'];
+$this->unget = @$state['unget'];
+$this->verbatim = @$state['verbatim'];
+}
+function Internal_StripQuotes($string) {
+if (preg_match("/^\\\"(.*)\\\"$/", $string, $matches))
+return $matches[1];
+else if (preg_match("/^\\'(.*)\\'$/", $string, $matches))
+return $matches[1];
+else return $string;
+}
+function Internal_ClassifyPiece($ptr, $pieces) {
+if ($ptr >= count($pieces)) return -1;
+$piece = $pieces[$ptr];
+if ($piece == '=') return '=';
+else if (preg_match("/^[\\'\\\"]/", $piece)) return '"';
+else if (preg_match("/^[\\x00-\\x20]+$/", $piece)) return ' ';
+else return 'A';
+}
+function Internal_DecodeTag($tag) {
+$result = Array('_tag' => $tag, '_endtag' => '', '_name' => '',
+'_hasend' => false, '_end' => false, '_default' => false);
+$tag = substr($tag, 1, strlen($tag)-2);
+$ch = ord(substr($tag, 0, 1));
+if ($ch >= 0 && $ch <= 32) return $result;
+$pieces = preg_split("/(\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|=|[\\x00-\\x20]+)/",
+$tag, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
+$ptr = 0;
+if (count($pieces) < 1) return $result;
+if (@substr($pieces[$ptr], 0, 1) == '/') {
+$result['_name'] = strtolower(substr($pieces[$ptr++], 1));
+$result['_end'] = true;
+}
+else {
+$result['_name'] = strtolower($pieces[$ptr++]);
+$result['_end'] = false;
+}
+while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
+$ptr++;
+$params = Array();
+if ($type != '=') {
+$result['_default'] = false;
+$params[] = Array('key' => '', 'value' => '');
+}
+else {
+$ptr++;
+while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
+$ptr++;
+if ($type == "\"")
+$value = $this->Internal_StripQuotes($pieces[$ptr++]);
+else {
+$after_space = false;
+$start = $ptr;
+while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) {
+if ($type == ' ') $after_space = true;
+if ($type == '=' && $after_space) break;
+$ptr++;
+}
+if ($type == -1) $ptr--;
+if ($type == '=') {
+$ptr--;
+while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) == ' ')
+$ptr--;
+while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) != ' ')
+$ptr--;
+}
+$value = "";
+for (; $start <= $ptr; $start++) {
+if ($this->Internal_ClassifyPiece($start, $pieces) == ' ')
+$value .= " ";
+else $value .= $this->Internal_StripQuotes($pieces[$start]);
+}
+$value = trim($value);
+$ptr++;
+}
+$result['_default'] = $value;
+$params[] = Array('key' => '', 'value' => $value);
+}
+while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) {
+while ($type == ' ') {
+$ptr++;
+$type = $this->Internal_ClassifyPiece($ptr, $pieces);
+}
+if ($type == 'A' || $type == '"')
+$key = strtolower($this->Internal_StripQuotes(@$pieces[$ptr++]));
+else if ($type == '=') {
+$ptr++;
+continue;
+}
+else if ($type == -1) break;
+while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
+$ptr++;
+if ($type != '=')
+$value = $this->Internal_StripQuotes($key);
+else {
+$ptr++;
+while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
+$ptr++;
+if ($type == '"') {
+$value = $this->Internal_StripQuotes($pieces[$ptr++]);
+}
+else if ($type != -1) {
+$value = $pieces[$ptr++];
+while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1
+&& $type != ' ')
+$value .= $pieces[$ptr++];
+}
+else $value = "";
+}
+if (substr($key, 0, 1) != '_')
+$result[$key] = $value;
+$params[] = Array('key' => $key, 'value' => $value);
+}
+$result['_params'] = $params;
+return $result;
+}
+}
+
+class BBCodeLibrary {
+var $default_smileys = Array(
+':)' => 'smile.gif', ':-)' => 'smile.gif',
+'=)' => 'smile.gif', '=-)' => 'smile.gif',
+':(' => 'frown.gif', ':-(' => 'frown.gif',
+'=(' => 'frown.gif', '=-(' => 'frown.gif',
+':D' => 'bigsmile.gif', ':-D' => 'bigsmile.gif',
+'=D' => 'bigsmile.gif', '=-D' => 'bigsmile.gif',
+'>:('=> 'angry.gif', '>:-('=> 'angry.gif',
+'>=('=> 'angry.gif', '>=-('=> 'angry.gif',
+'D:' => 'angry.gif', 'D-:' => 'angry.gif',
+'D=' => 'angry.gif', 'D-=' => 'angry.gif',
+'>:)'=> 'evil.gif', '>:-)'=> 'evil.gif',
+'>=)'=> 'evil.gif', '>=-)'=> 'evil.gif',
+'>:D'=> 'evil.gif', '>:-D'=> 'evil.gif',
+'>=D'=> 'evil.gif', '>=-D'=> 'evil.gif',
+'>;)'=> 'sneaky.gif', '>;-)'=> 'sneaky.gif',
+'>;D'=> 'sneaky.gif', '>;-D'=> 'sneaky.gif',
+'O:)' => 'saint.gif', 'O:-)' => 'saint.gif',
+'O=)' => 'saint.gif', 'O=-)' => 'saint.gif',
+':O' => 'surprise.gif', ':-O' => 'surprise.gif',
+'=O' => 'surprise.gif', '=-O' => 'surprise.gif',
+':?' => 'confuse.gif', ':-?' => 'confuse.gif',
+'=?' => 'confuse.gif', '=-?' => 'confuse.gif',
+':s' => 'worry.gif', ':-S' => 'worry.gif',
+'=s' => 'worry.gif', '=-S' => 'worry.gif',
+':|' => 'neutral.gif', ':-|' => 'neutral.gif',
+'=|' => 'neutral.gif', '=-|' => 'neutral.gif',
+':I' => 'neutral.gif', ':-I' => 'neutral.gif',
+'=I' => 'neutral.gif', '=-I' => 'neutral.gif',
+':/' => 'irritated.gif', ':-/' => 'irritated.gif',
+'=/' => 'irritated.gif', '=-/' => 'irritated.gif',
+':\\' => 'irritated.gif', ':-\\' => 'irritated.gif',
+'=\\' => 'irritated.gif', '=-\\' => 'irritated.gif',
+':P' => 'tongue.gif', ':-P' => 'tongue.gif',
+'=P' => 'tongue.gif', '=-P' => 'tongue.gif',
+'X-P' => 'tongue.gif',
+'8)' => 'bigeyes.gif', '8-)' => 'bigeyes.gif',
+'B)' => 'cool.gif', 'B-)' => 'cool.gif',
+';)' => 'wink.gif', ';-)' => 'wink.gif',
+';D' => 'bigwink.gif', ';-D' => 'bigwink.gif',
+'^_^'=> 'anime.gif', '^^;' => 'sweatdrop.gif',
+'>_>'=> 'lookright.gif', '>.>' => 'lookright.gif',
+'<_<'=> 'lookleft.gif', '<.<' => 'lookleft.gif',
+'XD' => 'laugh.gif', 'X-D' => 'laugh.gif',
+';D' => 'bigwink.gif', ';-D' => 'bigwink.gif',
+':3' => 'smile3.gif', ':-3' => 'smile3.gif',
+'=3' => 'smile3.gif', '=-3' => 'smile3.gif',
+';3' => 'wink3.gif', ';-3' => 'wink3.gif',
+'<g>' => 'teeth.gif', '<G>' => 'teeth.gif',
+'o.O' => 'boggle.gif', 'O.o' => 'boggle.gif',
+':blue:' => 'blue.gif',
+':zzz:' => 'sleepy.gif',
+'<3' => 'heart.gif',
+':star:' => 'star.gif',
+);
+var $default_tag_rules = Array(
+'b' => Array(
+'simple_start' => "<b>",
+'simple_end' => "</b>",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+'plain_start' => "<b>",
+'plain_end' => "</b>",
+),
+'i' => Array(
+'simple_start' => "<i>",
+'simple_end' => "</i>",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+'plain_start' => "<i>",
+'plain_end' => "</i>",
+),
+'u' => Array(
+'simple_start' => "<u>",
+'simple_end' => "</u>",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+'plain_start' => "<u>",
+'plain_end' => "</u>",
+),
+'s' => Array(
+'simple_start' => "<strike>",
+'simple_end' => "</strike>",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+'plain_start' => "<i>",
+'plain_end' => "</i>",
+),
+'font' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'allow' => Array('_default' => '/^[a-zA-Z0-9._ -]+$/'),
+'method' => 'DoFont',
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+),
+'color' => Array(
+'mode' => BBCODE_MODE_ENHANCED,
+'allow' => Array('_default' => '/^#?[a-zA-Z0-9._ -]+$/'),
+'template' => '<span style="color:{$_default/tw}">{$_content/v}</span>',
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+),
+'size' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'allow' => Array('_default' => '/^[0-9.]+$/D'),
+'method' => 'DoSize',
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+),
+'sup' => Array(
+'simple_start' => "<sup>",
+'simple_end' => "</sup>",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+),
+'sub' => Array(
+'simple_start' => "<sub>",
+'simple_end' => "</sub>",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+),
+'spoiler' => Array(
+'simple_start' => "<span class=\"bbcode_spoiler\">",
+'simple_end' => "</span>",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+),
+'acronym' => Array(
+'mode' => BBCODE_MODE_ENHANCED,
+'template' => '<span class="bbcode_acronym" title="{$_default/e}">{$_content/v}</span>',
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+),
+'url' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'method' => 'DoURL',
+'class' => 'link',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
+'content' => BBCODE_REQUIRED,
+'plain_start' => "<a href=\"{\$link}\">",
+'plain_end' => "</a>",
+'plain_content' => Array('_content', '_default'),
+'plain_link' => Array('_default', '_content'),
+),
+'email' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'method' => 'DoEmail',
+'class' => 'link',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
+'content' => BBCODE_REQUIRED,
+'plain_start' => "<a href=\"mailto:{\$link}\">",
+'plain_end' => "</a>",
+'plain_content' => Array('_content', '_default'),
+'plain_link' => Array('_default', '_content'),
+),
+'wiki' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'method' => "DoWiki",
+'class' => 'link',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
+'end_tag' => BBCODE_PROHIBIT,
+'content' => BBCODE_PROHIBIT,
+'plain_start' => "<b>[",
+'plain_end' => "]</b>",
+'plain_content' => Array('title', '_default'),
+'plain_link' => Array('_default', '_content'),
+),
+'img' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'method' => "DoImage",
+'class' => 'image',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+'end_tag' => BBCODE_REQUIRED,
+'content' => BBCODE_REQUIRED,
+'plain_start' => "[image]",
+'plain_content' => Array(),
+),
+'rule' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'method' => "DoRule",
+'class' => 'block',
+'allow_in' => Array('listitem', 'block', 'columns'),
+'end_tag' => BBCODE_PROHIBIT,
+'content' => BBCODE_PROHIBIT,
+'before_tag' => "sns",
+'after_tag' => "sns",
+'plain_start' => "\n-----\n",
+'plain_end' => "",
+'plain_content' => Array(),
+),
+'br' => Array(
+'mode' => BBCODE_MODE_SIMPLE,
+'simple_start' => "<br />\n",
+'simple_end' => "",
+'class' => 'inline',
+'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
+'end_tag' => BBCODE_PROHIBIT,
+'content' => BBCODE_PROHIBIT,
+'before_tag' => "s",
+'after_tag' => "s",
+'plain_start' => "\n",
+'plain_end' => "",
+'plain_content' => Array(),
+),
+'left' => Array(
+'simple_start' => "\n<div class=\"bbcode_left\" style=\"text-align:left\">\n",
+'simple_end' => "\n</div>\n",
+'allow_in' => Array('listitem', 'block', 'columns'),
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n",
+'plain_end' => "\n",
+),
+'right' => Array(
+'simple_start' => "\n<div class=\"bbcode_right\" style=\"text-align:right\">\n",
+'simple_end' => "\n</div>\n",
+'allow_in' => Array('listitem', 'block', 'columns'),
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n",
+'plain_end' => "\n",
+),
+'center' => Array(
+'simple_start' => "\n<div class=\"bbcode_center\" style=\"text-align:center\">\n",
+'simple_end' => "\n</div>\n",
+'allow_in' => Array('listitem', 'block', 'columns'),
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n",
+'plain_end' => "\n",
+),
+'indent' => Array(
+'simple_start' => "\n<div class=\"bbcode_indent\" style=\"margin-left:4em\">\n",
+'simple_end' => "\n</div>\n",
+'allow_in' => Array('listitem', 'block', 'columns'),
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n",
+'plain_end' => "\n",
+),
+'columns' => Array(
+'simple_start' => "\n<table class=\"bbcode_columns\"><tbody><tr><td class=\"bbcode_column bbcode_firstcolumn\">\n",
+'simple_end' => "\n</td></tr></tbody></table>\n",
+'class' => 'columns',
+'allow_in' => Array('listitem', 'block', 'columns'),
+'end_tag' => BBCODE_REQUIRED,
+'content' => BBCODE_REQUIRED,
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n",
+'plain_end' => "\n",
+),
+'nextcol' => Array(
+'simple_start' => "\n</td><td class=\"bbcode_column\">\n",
+'class' => 'nextcol',
+'allow_in' => Array('columns'),
+'end_tag' => BBCODE_PROHIBIT,
+'content' => BBCODE_PROHIBIT,
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n",
+'plain_end' => "",
+),
+'code' => Array(
+'mode' => BBCODE_MODE_ENHANCED,
+'template' => "\n<div class=\"bbcode_code\">\n<div class=\"bbcode_code_head\">Code:</div>\n<div class=\"bbcode_code_body\" style=\"white-space:pre\">{\$_content/v}</div>\n</div>\n",
+'class' => 'code',
+'allow_in' => Array('listitem', 'block', 'columns'),
+'content' => BBCODE_VERBATIM,
+'before_tag' => "sns",
+'after_tag' => "sn",
+'before_endtag' => "sn",
+'after_endtag' => "sns",
+'plain_start' => "\n<b>Code:</b>\n",
+'plain_end' => "\n",
+),
+'quote' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'method' => "DoQuote",
+'allow_in' => Array('listitem', 'block', 'columns'),
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n<b>Quote:</b>\n",
+'plain_end' => "\n",
+),
+'list' => Array(
+'mode' => BBCODE_MODE_LIBRARY,
+'method' => 'DoList',
+'class' => 'list',
+'allow_in' => Array('listitem', 'block', 'columns'),
+'before_tag' => "sns",
+'after_tag' => "sns",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n",
+'plain_end' => "\n",
+),
+'*' => Array(
+'simple_start' => "<li>",
+'simple_end' => "</li>\n",
+'class' => 'listitem',
+'allow_in' => Array('list'),
+'end_tag' => BBCODE_OPTIONAL,
+'before_tag' => "s",
+'after_tag' => "s",
+'before_endtag' => "sns",
+'after_endtag' => "sns",
+'plain_start' => "\n * ",
+'plain_end' => "\n",
+),
+);
+function DoURL($bbcode, $action, $name, $default, $params, $content) {
+if ($action == BBCODE_CHECK) return true;
+$url = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content));
+if ($bbcode->IsValidURL($url)) {
+if ($bbcode->debug)
+print "ISVALIDURL<br />";
+if ($bbcode->url_targetable !== false && isset($params['target']))
+$target = " target=\"" . htmlspecialchars($params['target']) . "\"";
+else $target = "";
+if ($bbcode->url_target !== false)
+if (!($bbcode->url_targetable == 'override' && isset($params['target'])))
+$target = " target=\"" . htmlspecialchars($bbcode->url_target) . "\"";
+return '<a href="' . htmlspecialchars($url) . '" class="bbcode_url"' . $target . '>' . $content . '</a>';
+}
+else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']);
+}
+function DoEmail($bbcode, $action, $name, $default, $params, $content) {
+if ($action == BBCODE_CHECK) return true;
+$email = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content));
+if ($bbcode->IsValidEmail($email))
+return '<a href="mailto:' . htmlspecialchars($email) . '" class="bbcode_email">' . $content . '</a>';
+else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']);
+}
+function DoSize($bbcode, $action, $name, $default, $params, $content) {
+switch ($default) {
+case '0': $size = '.5em'; break;
+case '1': $size = '.67em'; break;
+case '2': $size = '.83em'; break;
+default:
+case '3': $size = '1.0em'; break;
+case '4': $size = '1.17em'; break;
+case '5': $size = '1.5em'; break;
+case '6': $size = '2.0em'; break;
+case '7': $size = '2.5em'; break;
+}
+return "<span style=\"font-size:$size\">$content</span>";
+}
+function DoFont($bbcode, $action, $name, $default, $params, $content) {
+$fonts = explode(",", $default);
+$result = "";
+$special_fonts = Array(
+'serif' => 'serif',
+'sans-serif' => 'sans-serif',
+'sans serif' => 'sans-serif',
+'sansserif' => 'sans-serif',
+'sans' => 'sans-serif',
+'cursive' => 'cursive',
+'fantasy' => 'fantasy',
+'monospace' => 'monospace',
+'mono' => 'monospace',
+);
+foreach ($fonts as $font) {
+$font = trim($font);
+if (isset($special_fonts[$font])) {
+if (strlen($result) > 0) $result .= ",";
+$result .= $special_fonts[$font];
+}
+else if (strlen($font) > 0) {
+if (strlen($result) > 0) $result .= ",";
+$result .= "'$font'";
+}
+}
+return "<span style=\"font-family:$result\">$content</span>";
+}
+function DoWiki($bbcode, $action, $name, $default, $params, $content) {
+$name = $bbcode->Wikify($default);
+if ($action == BBCODE_CHECK)
+return strlen($name) > 0;
+$title = trim(@$params['title']);
+if (strlen($title) <= 0) $title = trim($default);
+return "<a href=\"{$bbcode->wiki_url}$name\" class=\"bbcode_wiki\">"
+. htmlspecialchars($title) . "</a>";
+}
+function DoImage($bbcode, $action, $name, $default, $params, $content) {
+if ($action == BBCODE_CHECK) return true;
+$content = trim($bbcode->UnHTMLEncode(strip_tags($content)));
+if (preg_match("/\\.(?:gif|jpeg|jpg|jpe|png)$/", $content)) {
+if (preg_match("/^[a-zA-Z0-9_][^:]+$/", $content)) {
+if (!preg_match("/(?:\\/\\.\\.\\/)|(?:^\\.\\.\\/)|(?:^\\/)/", $content)) {
+$info = @getimagesize("{$bbcode->local_img_dir}/{$content}");
+if ($info[2] == IMAGETYPE_GIF || $info[2] == IMAGETYPE_JPEG || $info[2] == IMAGETYPE_PNG) {
+return "<img src=\""
+. htmlspecialchars("{$bbcode->local_img_url}/{$content}") . "\" alt=\""
+. htmlspecialchars(basename($content)) . "\" width=\""
+. htmlspecialchars($info[0]) . "\" height=\""
+. htmlspecialchars($info[1]) . "\" class=\"bbcode_img\" />";
+}
+}
+}
+else if ($bbcode->IsValidURL($content, false)) {
+return "<img src=\"" . htmlspecialchars($content) . "\" alt=\""
+. htmlspecialchars(basename($content)) . "\" class=\"bbcode_img\" />";
+}
+}
+return htmlspecialchars($params['_tag']) . htmlspecialchars($content) . htmlspecialchars($params['_endtag']);
+}
+function DoRule($bbcode, $action, $name, $default, $params, $content) {
+if ($action == BBCODE_CHECK) return true;
+else return $bbcode->rule_html;
+}
+function DoQuote($bbcode, $action, $name, $default, $params, $content) {
+if ($action == BBCODE_CHECK) return true;
+if (isset($params['name'])) {
+$title = htmlspecialchars(trim($params['name'])) . " wrote";
+if (isset($params['date']))
+$title .= " on " . htmlspecialchars(trim($params['date']));
+$title .= ":";
+if (isset($params['url'])) {
+$url = trim($params['url']);
+if ($bbcode->IsValidURL($url))
+$title = "<a href=\"" . htmlspecialchars($params['url']) . "\">" . $title . "</a>";
+}
+}
+else if (!is_string($default))
+$title = "Quote:";
+else $title = htmlspecialchars(trim($default)) . " wrote:";
+return "\n<div class=\"bbcode_quote\">\n<div class=\"bbcode_quote_head\">"
+. $title . "</div>\n<div class=\"bbcode_quote_body\">"
+. $content . "</div>\n</div>\n";
+}
+function DoList($bbcode, $action, $name, $default, $params, $content) {
+$list_styles = Array(
+'1' => 'decimal',
+'01' => 'decimal-leading-zero',
+'i' => 'lower-roman',
+'I' => 'upper-roman',
+'a' => 'lower-alpha',
+'A' => 'upper-alpha',
+);
+$ci_list_styles = Array(
+'circle' => 'circle',
+'disc' => 'disc',
+'square' => 'square',
+'greek' => 'lower-greek',
+'armenian' => 'armenian',
+'georgian' => 'georgian',
+);
+$ul_types = Array(
+'circle' => 'circle',
+'disc' => 'disc',
+'square' => 'square',
+);
+$default = trim($default);
+if ($action == BBCODE_CHECK) {
+if (!is_string($default) || strlen($default) == "") return true;
+else if (isset($list_styles[$default])) return true;
+else if (isset($ci_list_styles[strtolower($default)])) return true;
+else return false;
+}
+if (!is_string($default) || strlen($default) == "") {
+$elem = 'ul';
+$type = '';
+}
+else if ($default == '1') {
+$elem = 'ol';
+$type = '';
+}
+else if (isset($list_styles[$default])) {
+$elem = 'ol';
+$type = $list_styles[$default];
+}
+else {
+$default = strtolower($default);
+if (isset($ul_types[$default])) {
+$elem = 'ul';
+$type = $ul_types[$default];
+}
+else if (isset($ci_list_styles[$default])) {
+$elem = 'ol';
+$type = $ci_list_styles[$default];
+}
+}
+if (strlen($type))
+return "\n<$elem class=\"bbcode_list\" style=\"list-style-type:$type\">\n$content</$elem>\n";
+else return "\n<$elem class=\"bbcode_list\">\n$content</$elem>\n";
+}
+}
+
+class BBCodeEmailAddressValidator {
+function check_email_address($strEmailAddress) {
+if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) {
+return false;
+}
+$intAtSymbol = strrpos($strEmailAddress, '@');
+if ($intAtSymbol === false) {
+return false;
+}
+$arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol);
+$arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1);
+$arrTempAddress[0] = preg_replace('/"[^"]+"/'
+,''
+,$arrEmailAddress[0]);
+$arrTempAddress[1] = $arrEmailAddress[1];
+$strTempAddress = $arrTempAddress[0] . $arrTempAddress[1];
+if (strrpos($strTempAddress, '@') !== false) {
+return false;
+}
+if (!$this->check_local_portion($arrEmailAddress[0])) {
+return false;
+}
+if (!$this->check_domain_portion($arrEmailAddress[1])) {
+return false;
+}
+return true;
+}
+function check_local_portion($strLocalPortion) {
+if (!$this->check_text_length($strLocalPortion, 1, 64)) {
+return false;
+}
+$arrLocalPortion = explode('.', $strLocalPortion);
+for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) {
+if (!preg_match('.^('
+. '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]'
+. '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})'
+.'|'
+. '("[^\\\"]{0,62}")'
+.')$.'
+,$arrLocalPortion[$i])) {
+return false;
+}
+}
+return true;
+}
+function check_domain_portion($strDomainPortion) {
+if (!$this->check_text_length($strDomainPortion, 1, 255)) {
+return false;
+}
+if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
+.'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/'
+,$strDomainPortion) ||
+preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
+.'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/'
+,$strDomainPortion)) {
+return true;
+} else {
+$arrDomainPortion = explode('.', $strDomainPortion);
+if (sizeof($arrDomainPortion) < 2) {
+return false;
+}
+for ($i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) {
+if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) {
+return false;
+}
+if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|'
+.'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) {
+return false;
+}
+}
+}
+return true;
+}
+function check_text_length($strText, $intMinimum, $intMaximum) {
+$intTextLength = strlen($strText);
+if (($intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) {
+return false;
+} else {
+return true;
+}
+}
+}
+
+class BBCode {
+var $tag_rules;
+var $defaults;
+var $current_class;
+var $root_class;
+var $lost_start_tags;
+var $start_tags;
+var $allow_ampersand;
+var $tag_marker;
+var $ignore_newlines;
+var $plain_mode;
+var $detect_urls;
+var $url_pattern;
+var $output_limit;
+var $text_length;
+var $was_limited;
+var $limit_tail;
+var $limit_precision;
+var $smiley_dir;
+var $smiley_url;
+var $smileys;
+var $smiley_regex;
+var $enable_smileys;
+var $wiki_url;
+var $local_img_dir;
+var $local_img_url;
+var $url_targetable;
+var $url_target;
+var $rule_html;
+var $pre_trim;
+var $post_trim;
+var $debug;
+
+
+/* ADDED */
+// singleton instance
+private static $instance;
+
+// private constructor function
+// to prevent external instantiation
+private function __construct()
+{
+	$this->defaults = new BBCodeLibrary;
+	$this->tag_rules = $this->defaults->default_tag_rules;
+	$this->smileys = $this->defaults->default_smileys;
+	$this->enable_smileys = true;
+	$this->smiley_regex = false;
+	$this->smiley_dir = $this->GetDefaultSmileyDir();
+	$this->smiley_url = $this->GetDefaultSmileyURL();
+	$this->wiki_url = $this->GetDefaultWikiURL();
+	$this->local_img_dir = $this->GetDefaultLocalImgDir();
+	$this->local_img_url = $this->GetDefaultLocalImgURL();
+	$this->rule_html = $this->GetDefaultRuleHTML();
+	$this->pre_trim = "";
+	$this->post_trim = "";
+	$this->root_class = 'block';
+	$this->lost_start_tags = Array();
+	$this->start_tags = Array();
+	$this->tag_marker = '[';
+	$this->allow_ampsersand = false;
+	$this->current_class = $this->root_class;
+	$this->debug = false;
+	$this->ignore_newlines = false;
+	$this->output_limit = 0;
+	$this->plain_mode = false;
+	$this->was_limited = false;
+	$this->limit_tail = "...";
+	$this->limit_precision = 0.15;
+	$this->detect_urls = false;
+	$this->url_pattern = '<a href="{$url/h}">{$text/h}</a>';
+	$this->url_targetable = false;
+	$this->url_target = false;
+}
+
+// getInstance method
+public static function getInstance()
+{
+    if(!self::$instance)
+    {
+      self::$instance = new self();
+    }
+
+    return self::$instance;
+}
+/* ADDED */
+
+
+function SetPreTrim($trim = "a") { $this->pre_trim = $trim; }
+function GetPreTrim() { return $this->pre_trim; }
+function SetPostTrim($trim = "a") { $this->post_trim = $trim; }
+function GetPostTrim() { return $this->post_trim; }
+function SetRoot($class = 'block') { $this->root_class = $class; }
+function SetRootInline() { $this->root_class = 'inline'; }
+function SetRootBlock() { $this->root_class = 'block'; }
+function GetRoot() { return $this->root_class; }
+function SetDebug($enable = true) { $this->debug = $enable; }
+function GetDebug() { return $this->debug; }
+function SetAllowAmpersand($enable = true) { $this->allow_ampersand = $enable; }
+function GetAllowAmpersand() { return $this->allow_ampersand; }
+function SetTagMarker($marker = '[') { $this->tag_marker = $marker; }
+function GetTagMarker() { return $this->tag_marker; }
+function SetIgnoreNewlines($ignore = true) { $this->ignore_newlines = $ignore; }
+function GetIgnoreNewlines() { return $this->ignore_newlines; }
+function SetLimit($limit = 0) { $this->output_limit = $limit; }
+function GetLimit() { return $this->output_limit; }
+function SetLimitTail($tail = "...") { $this->limit_tail = $tail; }
+function GetLimitTail() { return $this->limit_tail; }
+function SetLimitPrecision($prec = 0.15) { $this->limit_precision = $prec; }
+function GetLimitPrecision() { return $this->limit_precision; }
+function WasLimited() { return $this->was_limited; }
+function SetPlainMode($enable = true) { $this->plain_mode = $enable; }
+function GetPlainMode() { return $this->plain_mode; }
+function SetDetectURLs($enable = true) { $this->detect_urls = $enable; }
+function GetDetectURLs() { return $this->detect_urls; }
+function SetURLPattern($pattern) { $this->url_pattern = $pattern; }
+function GetURLPattern() { return $this->url_pattern; }
+function SetURLTargetable($enable) { $this->url_targetable = $enable; }
+function GetURLTargetable() { return $this->url_targetable; }
+function SetURLTarget($target) { $this->url_target = $target; }
+function GetURLTarget() { return $this->url_target; }
+function AddRule($name, $rule) { $this->tag_rules[$name] = $rule; }
+function RemoveRule($name) { unset($this->tag_rules[$name]); }
+function GetRule($name) { return isset($this->tag_rules[$name])
+? $this->tag_rules[$name] : false; }
+function ClearRules() { $this->tag_rules = Array(); }
+function GetDefaultRule($name) { return isset($this->defaults->default_tag_rules[$name])
+? $this->defaults->default_tag_rules[$name] : false; }
+function SetDefaultRule($name) { if (isset($this->defaults->default_tag_rules[$name]))
+$this->AddRule($name, $this->defaults->default_tag_rules[$name]);
+else $this->RemoveRule($name); }
+function GetDefaultRules() { return $this->defaults->default_tag_rules; }
+function SetDefaultRules() { $this->tag_rules = $this->defaults->default_tag_rules; }
+function SetWikiURL($url) { $this->wiki_url = $url; }
+function GetWikiURL($url) { return $this->wiki_url; }
+function GetDefaultWikiURL() { return '/?page='; }
+function SetLocalImgDir($path) { $this->local_img_dir = $path; }
+function GetLocalImgDir() { return $this->local_img_dir; }
+function GetDefaultLocalImgDir() { return "img"; }
+function SetLocalImgURL($path) { $this->local_img_url = $path; }
+function GetLocalImgURL() { return $this->local_img_url; }
+function GetDefaultLocalImgURL() { return "img"; }
+function SetRuleHTML($html) { $this->rule_html = $html; }
+function GetRuleHTML() { return $this->rule_html; }
+function GetDefaultRuleHTML() { return "\n<hr class=\"bbcode_rule\" />\n"; }
+function AddSmiley($code, $image) { $this->smileys[$code] = $image; $this->smiley_regex = false; }
+function RemoveSmiley($code) { unset($this->smileys[$code]); $this->smiley_regex = false; }
+function GetSmiley($code) { return isset($this->smileys[$code])
+? $this->smileys[$code] : false; }
+function ClearSmileys() { $this->smileys = Array(); $this->smiley_regex = false; }
+function GetDefaultSmiley($code) { return isset($this->defaults->default_smileys[$code])
+? $this->defaults->default_smileys[$code] : false; }
+function SetDefaultSmiley($code) { $this->smileys[$code] = @$this->defaults->default_smileys[$code];
+$this->smiley_regex = false; }
+function GetDefaultSmileys() { return $this->defaults->default_smileys; }
+function SetDefaultSmileys() { $this->smileys = $this->defaults->default_smileys;
+$this->smiley_regex = false; }
+function SetSmileyDir($path) { $this->smiley_dir = $path; }
+function GetSmileyDir() { return $this->smiley_dir; }
+function GetDefaultSmileyDir() { return "smileys"; }
+function SetSmileyURL($path) { $this->smiley_url = $path; }
+function GetSmileyURL() { return $this->smiley_url; }
+function GetDefaultSmileyURL() { return "smileys"; }
+function SetEnableSmileys($enable = true) { $this->enable_smileys = $enable; }
+function GetEnableSmileys() { return $this->enable_smileys; }
+function nl2br($string) {
+return preg_replace("/\\x0A|\\x0D|\\x0A\\x0D|\\x0D\\x0A/", "<br />\n", $string);
+}
+function UnHTMLEncode($string) {
+if (function_exists("html_entity_decode"))
+return html_entity_decode($string);
+$string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
+$string = preg_replace('~&#([0-9]+);~e', 'chr("\\1")', $string);
+$trans_tbl = get_html_translation_table(HTML_ENTITIES);
+$trans_tbl = array_flip($trans_tbl);
+return strtr($string, $trans_tbl);
+}
+function Wikify($string) {
+return rawurlencode(str_replace(" ", "_",
+trim(preg_replace("/[!?;@#\$%\\^&*<>=+`~\\x00-\\x20_-]+/", " ", $string))));
+}
+function IsValidURL($string, $email_too = true) {
+if (preg_match("/^
+(?:https?|ftp):\\/\\/
+(?:
+(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+
+[a-zA-Z0-9]
+(?:[a-zA-Z0-9-]*[a-zA-Z0-9])?
+|
+\\[
+(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}
+(?:
+25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:
+(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F]
+|\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+
+)
+\\]
+)
+(?::[0-9]{1,5})?
+(?:[\\/\\?\\#][^\\n\\r]*)?
+$/Dx", $string)) return true;
+if (preg_match("/^[^:]+([\\/\\\\?#][^\\r\\n]*)?$/D", $string))
+return true;
+if ($email_too)
+if (substr($string, 0, 7) == "mailto:")
+return $this->IsValidEmail(substr($string, 7));
+return false;
+}
+function IsValidEmail($string) {
+$validator = new BBCodeEmailAddressValidator;
+return $validator->check_email_address($string);
+/*
+return preg_match("/^
+(?:
+[a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+
+(?:\.[a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+)*
+|
+\"(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]
+|\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])*\"
+)
+@
+(?:
+(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+
+[a-z0-9]
+(?:[a-z0-9-]*[a-z0-9])?
+|
+\\[
+(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}
+(?:
+25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:
+(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F]
+|\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+
+)
+\\]
+)
+$/Dx", $string);
+*/
+}
+function HTMLEncode($string) {
+if (!$this->allow_ampersand)
+return htmlspecialchars($string);
+else return str_replace(Array('<', '>', '"'),
+Array('&lt;', '&gt;', '&quot;'), $string);
+}
+function FixupOutput($string) {
+if (!$this->detect_urls) {
+$output = $this->Internal_ProcessSmileys($string);
+}
+else {
+$chunks = $this->Internal_AutoDetectURLs($string);
+$output = Array();
+if (count($chunks)) {
+$is_a_url = false;
+foreach ($chunks as $index => $chunk) {
+if (!$is_a_url) {
+$chunk = $this->Internal_ProcessSmileys($chunk);
+}
+$output[] = $chunk;
+$is_a_url = !$is_a_url;
+}
+}
+$output = implode("", $output);
+}
+return $output;
+}
+function Internal_ProcessSmileys($string) {
+if (!$this->enable_smileys || $this->plain_mode) {
+$output = $this->HTMLEncode($string);
+}
+else {
+if ($this->smiley_regex === false) {
+$this->Internal_RebuildSmileys();
+}
+$tokens = preg_split($this->smiley_regex, $string, -1, PREG_SPLIT_DELIM_CAPTURE);
+if (count($tokens) <= 1) {
+$output = $this->HTMLEncode($string);
+}
+else {
+$output = "";
+$is_a_smiley = false;
+foreach ($tokens as $token) {
+if (!$is_a_smiley) {
+$output .= $this->HTMLEncode($token);
+}
+else {
+if (isset($this->smiley_info[$token])) {
+$info = $this->smiley_info[$token];
+}
+else {
+$info = @getimagesize($this->smiley_dir . '/' . $this->smileys[$token]);
+$this->smiley_info[$token] = $info;
+}
+$alt = htmlspecialchars($token);
+$output .= "<img src=\"" . htmlspecialchars($this->smiley_url . '/' . $this->smileys[$token])
+. "\" width=\"{$info[0]}\" height=\"{$info[1]}\""
+. " alt=\"$alt\" title=\"$alt\" class=\"bbcode_smiley\" />";
+}
+$is_a_smiley = !$is_a_smiley;
+}
+}
+}
+return $output;
+}
+function Internal_RebuildSmileys() {
+$regex = Array("/(?<![\\w])(");
+$first = true;
+foreach ($this->smileys as $code => $filename) {
+if (!$first) $regex[] = "|";
+$regex[] = preg_quote("$code", '/');
+$first = false;
+}
+$regex[] = ")(?![\\w])/";
+$this->smiley_regex = implode("", $regex);
+}
+function Internal_AutoDetectURLs($string) {
+$output = preg_split("/( (?:
+(?:https?|ftp) : \\/*
+(?:
+(?: (?: [a-zA-Z0-9-]{2,} \\. )+
+(?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
+| aero | biz | coop | info | museum | name | pro
+| example | invalid | localhost | test | local | onion | swift ) )
+| (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
+| (?: [0-9A-Fa-f:]+ : [0-9A-Fa-f]{1,4} )
+)
+(?: : [0-9]+ )?
+(?! [a-zA-Z0-9.:-] )
+(?:
+\\/
+[^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]*
+)?
+(?:
+[?#]
+[^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+
+)?
+) | (?:
+(?:
+(?: (?: [a-zA-Z0-9-]{2,} \\. )+
+(?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
+| aero | biz | coop | info | museum | name | pro
+| example | invalid | localhost | test | local | onion | swift ) )
+| (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
+)
+(?: : [0-9]+ )?
+(?! [a-zA-Z0-9.:-] )
+(?:
+\\/
+[^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]*
+)?
+(?:
+[?#]
+[^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+
+)?
+) | (?:
+[a-zA-Z0-9._-]{2,} @
+(?:
+(?: (?: [a-zA-Z0-9-]{2,} \\. )+
+(?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
+| aero | biz | coop | info | museum | name | pro
+| example | invalid | localhost | test | local | onion | swift ) )
+| (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
+)
+) )/Dx", $string, -1, PREG_SPLIT_DELIM_CAPTURE);
+if (count($output) > 1) {
+$is_a_url = false;
+foreach ($output as $index => $token) {
+if ($is_a_url) {
+if (preg_match("/^[a-zA-Z0-9._-]{2,}@/", $token)) {
+$url = "mailto:" . $token;
+}
+else if (preg_match("/^(https?:|ftp:)\\/*([^\\/&?#]+)\\/*(.*)\$/", $token, $matches)) {
+$url = $matches[1] . '/' . '/' . $matches[2] . "/" . $matches[3];
+}
+else {
+preg_match("/^([^\\/&?#]+)\\/*(.*)\$/", $token, $matches);
+$url = "http:/" . "/" . $matches[1] . "/" . $matches[2];
+}
+$params = @parse_url($url);
+if (!is_array($params)) $params = Array();
+$params['url'] = $url;
+$params['link'] = $url;
+$params['text'] = $token;
+$output[$index] = $this->FillTemplate($this->url_pattern, $params);
+}
+$is_a_url = !$is_a_url;
+}
+}
+return $output;
+}
+function FillTemplate($template, $insert_array, $default_array = Array()) {
+$pieces = preg_split('/(\{\$[a-zA-Z0-9_.:\/-]+\})/', $template,
+-1, PREG_SPLIT_DELIM_CAPTURE);
+if (count($pieces) <= 1)
+return $template;
+$result = Array();
+$is_an_insert = false;
+foreach ($pieces as $piece) {
+if (!$is_an_insert) {
+$result[] = $piece;
+}
+else if (!preg_match('/\{\$([a-zA-Z0-9_:-]+)((?:\\.[a-zA-Z0-9_:-]+)*)(?:\/([a-zA-Z0-9_:-]+))?\}/', $piece, $matches)) {
+$result[] = $piece;
+}
+else {
+if (isset($insert_array[$matches[1]]))
+$value = @$insert_array[$matches[1]];
+else $value = @$default_array[$matches[1]];
+if (strlen(@$matches[2])) {
+foreach (split(".", substr($matches[2], 1)) as $index) {
+if (is_array($value))
+$value = @$value[$index];
+else if (is_object($value)) {
+$value = (array)$value;
+$value = @$value[$index];
+}
+else $value = "";
+}
+}
+switch (gettype($value)) {
+case 'boolean': $value = $value ? "true" : "false"; break;
+case 'integer': $value = (string)$value; break;
+case 'double': $value = (string)$value; break;
+case 'string': break;
+default: $value = ""; break;
+}
+if (strlen(@$matches[3]))
+$flags = array_flip(str_split($matches[3]));
+else $flags = Array();
+if (!isset($flags['v'])) {
+if (isset($flags['w']))
+$value = preg_replace("/[\\x00-\\x09\\x0B-\x0C\x0E-\\x20]+/", " ", $value);
+if (isset($flags['t'])) $value = trim($value);
+if (isset($flags['b'])) $value = basename($value);
+if (isset($flags['e'])) $value = $this->HTMLEncode($value);
+else if (isset($flags['k'])) $value = $this->Wikify($value);
+else if (isset($flags['h'])) $value = htmlspecialchars($value);
+else if (isset($flags['u'])) $value = urlencode($value);
+if (isset($flags['n'])) $value = $this->nl2br($value);
+}
+$result[] = $value;
+}
+$is_an_insert = !$is_an_insert;
+}
+return implode("", $result);
+}
+function Internal_CollectText($array, $start = 0) {
+ob_start();
+for ($start = intval($start), $end = count($array); $start < $end; $start++)
+print $array[$start][BBCODE_STACK_TEXT];
+$output = ob_get_contents();
+ob_end_clean();
+return $output;
+}
+function Internal_CollectTextReverse($array, $start = 0, $end = 0) {
+ob_start();
+for ($start = intval($start); $start >= $end; $start--)
+print $array[$start][BBCODE_STACK_TEXT];
+$output = ob_get_contents();
+ob_end_clean();
+return $output;
+}
+function Internal_GenerateOutput($pos) {
+$output = Array();
+while (count($this->stack) > $pos) {
+$token = array_pop($this->stack);
+if ($token[BBCODE_STACK_TOKEN] != BBCODE_TAG) {
+$output[] = $token;
+}
+else {
+$name = @$token[BBCODE_STACK_TAG]['_name'];
+$rule = @$this->tag_rules[$name];
+$end_tag = @$rule['end_tag'];
+if (!isset($rule['end_tag'])) $end_tag = BBCODE_REQUIRED;
+else $end_tag = $rule['end_tag'];
+array_pop($this->start_tags[$name]);
+if ($end_tag == BBCODE_PROHIBIT) {
+$output[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_TEXT => $token[BBCODE_STACK_TEXT],
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+else {
+if ($end_tag == BBCODE_REQUIRED)
+@$this->lost_start_tags[$name] += 1;
+$end = $this->Internal_CleanupWSByIteratingPointer(@$rule['before_endtag'], 0, $output);
+$this->Internal_CleanupWSByPoppingStack(@$rule['after_tag'], $output);
+$tag_body = $this->Internal_CollectTextReverse($output, count($output)-1, $end);
+$this->Internal_CleanupWSByPoppingStack(@$rule['before_tag'], $this->stack);
+$this->Internal_UpdateParamsForMissingEndTag(@$token[BBCODE_STACK_TAG]);
+$tag_output = $this->DoTag(BBCODE_OUTPUT, $name,
+@$token[BBCODE_STACK_TAG]['_default'], @$token[BBCODE_STACK_TAG], $tag_body);
+$output = Array(Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_TEXT => $tag_output,
+BBCODE_STACK_CLASS => $this->current_class
+));
+}
+}
+}
+$this->Internal_ComputeCurrentClass();
+return $output;
+}
+function Internal_RewindToClass($class_list) {
+$pos = count($this->stack) - 1;
+while ($pos >= 0 && !in_array($this->stack[$pos][BBCODE_STACK_CLASS], $class_list))
+$pos--;
+if ($pos < 0) {
+if (!in_array($this->root_class, $class_list))
+return false;
+}
+$output = $this->Internal_GenerateOutput($pos+1);
+while (count($output)) {
+$token = array_pop($output);
+$token[BBCODE_STACK_CLASS] = $this->current_class;
+$this->stack[] = $token;
+}
+return true;
+}
+function Internal_FinishTag($tag_name) {
+if (strlen($tag_name) <= 0)
+return false;
+if (isset($this->start_tags[$tag_name])
+&& count($this->start_tags[$tag_name]))
+$pos = array_pop($this->start_tags[$tag_name]);
+else $pos = -1;
+if ($pos < 0) return false;
+$newpos = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['after_tag'],
+$pos+1, $this->stack);
+$delta = $newpos - ($pos+1);
+$output = $this->Internal_GenerateOutput($newpos);
+$newend = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['before_endtag'],
+0, $output);
+$output = $this->Internal_CollectTextReverse($output, count($output) - 1, $newend);
+while ($delta-- > 0)
+array_pop($this->stack);
+$this->Internal_ComputeCurrentClass();
+return $output;
+}
+function Internal_ComputeCurrentClass() {
+if (count($this->stack) > 0)
+$this->current_class = $this->stack[count($this->stack)-1][BBCODE_STACK_CLASS];
+else $this->current_class = $this->root_class;
+}
+function Internal_DumpStack($array = false, $raw = false) {
+if (!$raw) $string = "<span style='color: #00C;'>";
+else $string = "";
+if ($array === false)
+$array = $this->stack;
+foreach ($array as $item) {
+switch (@$item[BBCODE_STACK_TOKEN]) {
+case BBCODE_TEXT:
+$string .= "\"" . htmlspecialchars(@$item[BBCODE_STACK_TEXT]) . "\" ";
+break;
+case BBCODE_WS:
+$string .= "WS ";
+break;
+case BBCODE_NL:
+$string .= "NL ";
+break;
+case BBCODE_TAG:
+$string .= "[" . htmlspecialchars(@$item[BBCODE_STACK_TAG]['_name']) . "] ";
+break;
+default:
+$string .= "unknown ";
+break;
+}
+}
+if (!$raw) $string .= "</span>";
+return $string;
+}
+function Internal_CleanupWSByPoppingStack($pattern, &$array) {
+if (strlen($pattern) <= 0) return;
+$oldlen = count($array);
+foreach (str_split($pattern) as $char) {
+switch ($char) {
+case 's':
+while (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_WS)
+array_pop($array);
+break;
+case 'n':
+if (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_NL)
+array_pop($array);
+break;
+case 'a':
+while (count($array) > 0
+&& (($token = $array[count($array)-1][BBCODE_STACK_TOKEN]) == BBCODE_WS
+|| $token == BBCODE_NL))
+array_pop($array);
+break;
+}
+}
+if (count($array) != $oldlen) {
+$this->Internal_ComputeCurrentClass();
+}
+}
+function Internal_CleanupWSByEatingInput($pattern) {
+if (strlen($pattern) <= 0) return;
+foreach (str_split($pattern) as $char) {
+switch ($char) {
+case 's':
+$token_type = $this->lexer->NextToken();
+while ($token_type == BBCODE_WS) {
+$token_type = $this->lexer->NextToken();
+}
+$this->lexer->UngetToken();
+break;
+case 'n':
+$token_type = $this->lexer->NextToken();
+if ($token_type != BBCODE_NL)
+$this->lexer->UngetToken();
+break;
+case 'a':
+$token_type = $this->lexer->NextToken();
+while ($token_type == BBCODE_WS || $token_type == BBCODE_NL) {
+$token_type = $this->lexer->NextToken();
+}
+$this->lexer->UngetToken();
+break;
+}
+}
+}
+function Internal_CleanupWSByIteratingPointer($pattern, $pos, $array) {
+if (strlen($pattern) <= 0) return $pos;
+foreach (str_split($pattern) as $char) {
+switch ($char) {
+case 's':
+while ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_WS)
+$pos++;
+break;
+case 'n':
+if ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_NL)
+$pos++;
+break;
+case 'a':
+while ($pos < count($array)
+&& (($token = $array[$pos][BBCODE_STACK_TOKEN]) == BBCODE_WS || $token == BBCODE_NL))
+$pos++;
+break;
+}
+}
+return $pos;
+}
+function Internal_LimitText($string, $limit) {
+$chunks = preg_split("/([\\x00-\\x20]+)/", $string, -1, PREG_SPLIT_DELIM_CAPTURE);
+$output = "";
+foreach ($chunks as $chunk) {
+if (strlen($output) + strlen($chunk) > $limit)
+break;
+$output .= $chunk;
+}
+$output = rtrim($output);
+return $output;
+}
+function Internal_DoLimit() {
+$this->Internal_CleanupWSByPoppingStack("a", $this->stack);
+if (strlen($this->limit_tail) > 0) {
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->limit_tail,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+$this->was_limited = true;
+}
+function DoTag($action, $tag_name, $default_value, $params, $contents) {
+$tag_rule = @$this->tag_rules[$tag_name];
+switch ($action) {
+case BBCODE_CHECK:
+if (isset($tag_rule['allow'])) {
+foreach ($tag_rule['allow'] as $param => $pattern) {
+if ($param == '_content') $value = $contents;
+else if ($param == '_defaultcontent') {
+if (strlen($default_value))
+$value = $default_value;
+else $value = $contents;
+}
+else {
+if (isset($params[$param]))
+$value = $params[$param];
+else $value = @$tag_rule['default'][$param];
+}
+if (!preg_match($pattern, $value)) {
+return false;
+}
+}
+return true;
+}
+switch (@$tag_rule['mode']) {
+default:
+case BBCODE_MODE_SIMPLE:
+$result = true;
+break;
+case BBCODE_MODE_ENHANCED:
+$result = true;
+break;
+case BBCODE_MODE_INTERNAL:
+$result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_CHECK,
+$tag_name, $default_value, $params, $contents);
+break;
+case BBCODE_MODE_LIBRARY:
+$result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_CHECK,
+$tag_name, $default_value, $params, $contents);
+break;
+case BBCODE_MODE_CALLBACK:
+$result = @call_user_func(@$tag_rule['method'], $this, BBCODE_CHECK,
+$tag_name, $default_value, $params, $contents);
+break;
+}
+return $result;
+case BBCODE_OUTPUT:
+if ($this->plain_mode) {
+if (!isset($tag_rule['plain_content']))
+$plain_content = Array('_content');
+else $plain_content = $tag_rule['plain_content'];
+$result = $possible_content = "";
+foreach ($plain_content as $possible_content) {
+if ($possible_content == '_content'
+&& strlen($contents) > 0) {
+$result = $contents;
+break;
+}
+if (isset($params[$possible_content])
+&& strlen($params[$possible_content]) > 0) {
+$result = htmlspecialchars($params[$possible_content]);
+break;
+}
+}
+$start = @$tag_rule['plain_start'];
+$end = @$tag_rule['plain_end'];
+if (isset($tag_rule['plain_link'])) {
+$link = $possible_content = "";
+foreach ($tag_rule['plain_link'] as $possible_content) {
+if ($possible_content == '_content'
+&& strlen($contents) > 0) {
+$link = $this->UnHTMLEncode(strip_tags($contents));
+break;
+}
+if (isset($params[$possible_content])
+&& strlen($params[$possible_content]) > 0) {
+$link = $params[$possible_content];
+break;
+}
+}
+$params = @parse_url($link);
+if (!is_array($params)) $params = Array();
+$params['link'] = $link;
+$params['url'] = $link;
+$start = $this->FillTemplate($start, $params);
+$end = $this->FillTemplate($end, $params);
+}
+return $start . $result . $end;
+}
+switch (@$tag_rule['mode']) {
+default:
+case BBCODE_MODE_SIMPLE:
+$result = @$tag_rule['simple_start'] . $contents . @$tag_rule['simple_end'];
+break;
+case BBCODE_MODE_ENHANCED:
+$result = $this->Internal_DoEnhancedTag($tag_rule, $params, $contents);
+break;
+case BBCODE_MODE_INTERNAL:
+$result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_OUTPUT,
+$tag_name, $default_value, $params, $contents);
+break;
+case BBCODE_MODE_LIBRARY:
+$result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_OUTPUT,
+$tag_name, $default_value, $params, $contents);
+break;
+case BBCODE_MODE_CALLBACK:
+$result = @call_user_func(@$tag_rule['method'], $this, BBCODE_OUTPUT,
+$tag_name, $default_value, $params, $contents);
+break;
+}
+return $result;
+default:
+return false;
+}
+}
+function Internal_DoEnhancedTag($tag_rule, $params, $contents) {
+$params['_content'] = $contents;
+$params['_defaultcontent'] = strlen(@$params['_default']) ? $params['_default'] : $contents;
+return $this->FillTemplate(@$tag_rule['template'], $params, @$tag_rule['default']);
+}
+function Internal_UpdateParamsForMissingEndTag(&$params) {
+switch ($this->tag_marker) {
+case '[': $tail_marker = ']'; break;
+case '<': $tail_marker = '>'; break;
+case '{': $tail_marker = '}'; break;
+case '(': $tail_marker = ')'; break;
+default: $tail_marker = $this->tag_marker; break;
+}
+$params['_endtag'] = $this->tag_marker . '/' . $params['_name'] . $tail_marker;
+}
+function Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule) {
+if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) {
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+return;
+}
+$this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack);
+$output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$tag_params['_default'], $tag_params, "");
+$this->Internal_CleanupWSByEatingInput(@$tag_rule['after_tag']);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $output,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+function Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule) {
+$state = $this->lexer->SaveState();
+$end_tag = $this->lexer->tagmarker . "/" . $tag_name . $this->lexer->end_tagmarker;
+$start = count($this->stack);
+$this->lexer->verbatim = true;
+while (($token_type = $this->lexer->NextToken()) != BBCODE_EOI) {
+if ($this->lexer->text == $end_tag) {
+$end_tag_params = $this->lexer->tag;
+break;
+}
+if ($this->output_limit > 0
+&& $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
+$text = $this->Internal_LimitText($this->lexer->text,
+$this->output_limit - $this->text_length);
+if (strlen($text) > 0) {
+$this->text_length += strlen($text);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+$this->Internal_DoLimit();
+break;
+}
+$this->text_length += strlen($this->lexer->text);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => $token_type,
+BBCODE_STACK_TEXT => htmlspecialchars($this->lexer->text),
+BBCODE_STACK_TAG => $this->lexer->tag,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+$this->lexer->verbatim = false;
+if ($token_type == BBCODE_EOI) {
+$this->lexer->RestoreState($state);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+return;
+}
+$newstart = $this->Internal_CleanupWSByIteratingPointer(@$tag_rule['after_tag'], $start, $this->stack);
+$this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_endtag'], $this->stack);
+$this->Internal_CleanupWSByEatingInput(@$tag_rule['after_endtag']);
+$content = $this->Internal_CollectText($this->stack, $newstart);
+array_splice($this->stack, $start);
+$this->Internal_ComputeCurrentClass();
+$this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack);
+$tag_params['_endtag'] = $end_tag_params['_tag'];
+$tag_params['_hasend'] = true;
+$output = $this->DoTag(BBCODE_OUTPUT, $tag_name,
+@$tag_params['_default'], $tag_params, $content);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $output,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+function Internal_ParseStartTagToken() {
+$tag_params = $this->lexer->tag;
+$tag_name = @$tag_params['_name'];
+if (!isset($this->tag_rules[$tag_name])) {
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+return;
+}
+$tag_rule = $this->tag_rules[$tag_name];
+$allow_in = is_array($tag_rule['allow_in'])
+? $tag_rule['allow_in'] : Array($this->root_class);
+if (!in_array($this->current_class, $allow_in)) {
+if (!$this->Internal_RewindToClass($allow_in)) {
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+return;
+}
+}
+$end_tag = isset($tag_rule['end_tag']) ? $tag_rule['end_tag'] : BBCODE_REQUIRED;
+if ($end_tag == BBCODE_PROHIBIT) {
+$this->Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule);
+return;
+}
+if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) {
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+return;
+}
+if (@$tag_rule['content'] == BBCODE_VERBATIM) {
+$this->Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule);
+return;
+}
+if (isset($tag_rule['class']))
+$newclass = $tag_rule['class'];
+else $newclass = $this->root_class;
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => $this->lexer->token,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => $this->lexer->tag,
+BBCODE_STACK_CLASS => ($this->current_class = $newclass),
+);
+if (!isset($this->start_tags[$tag_name]))
+$this->start_tags[$tag_name] = Array(count($this->stack)-1);
+else $this->start_tags[$tag_name][] = count($this->stack)-1;
+}
+function Internal_ParseEndTagToken() {
+$tag_params = $this->lexer->tag;
+$tag_name = @$tag_params['_name'];
+$contents = $this->Internal_FinishTag($tag_name);
+if ($contents === false) {
+if (@$this->lost_start_tags[$tag_name] > 0) {
+$this->lost_start_tags[$tag_name]--;
+}
+else {
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+return;
+}
+$start_tag_node = array_pop($this->stack);
+$start_tag_params = $start_tag_node[BBCODE_STACK_TAG];
+$this->Internal_ComputeCurrentClass();
+$this->Internal_CleanupWSByPoppingStack(@$this->tag_rules[$tag_name]['before_tag'], $this->stack);
+$start_tag_params['_endtag'] = $tag_params['_tag'];
+$start_tag_params['_hasend'] = true;
+$output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$start_tag_params['_default'],
+$start_tag_params, $contents);
+$this->Internal_CleanupWSByEatingInput(@$this->tag_rules[$tag_name]['after_endtag']);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $output,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+function Parse($string) {
+$this->lexer = new BBCodeLexer($string, $this->tag_marker);
+$this->lexer->debug = $this->debug;
+$old_output_limit = $this->output_limit;
+if ($this->output_limit > 0) {
+if (strlen($string) < $this->output_limit) {
+$this->output_limit = 0;
+}
+else if ($this->limit_precision > 0) {
+$guess_length = $this->lexer->GuessTextLength();
+if ($guess_length < $this->output_limit * ($this->limit_precision + 1.0)) {
+$this->output_limit = 0;
+}
+else {
+}
+}
+}
+$this->stack = Array();
+$this->start_tags = Array();
+$this->lost_start_tags = Array();
+$this->text_length = 0;
+$this->was_limited = false;
+if (strlen($this->pre_trim) > 0)
+$this->Internal_CleanupWSByEatingInput($this->pre_trim);
+$newline = $this->plain_mode ? "\n" : "<br />\n";
+while (true) {
+if (($token_type = $this->lexer->NextToken()) == BBCODE_EOI) {
+break;
+}
+switch ($token_type) {
+case BBCODE_TEXT:
+if ($this->output_limit > 0
+&& $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
+$text = $this->Internal_LimitText($this->lexer->text,
+$this->output_limit - $this->text_length);
+if (strlen($text) > 0) {
+$this->text_length += strlen($text);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+$this->Internal_DoLimit();
+break 2;
+}
+$this->text_length += strlen($this->lexer->text);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_TEXT,
+BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+break;
+case BBCODE_WS:
+if ($this->output_limit > 0
+&& $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
+$this->Internal_DoLimit();
+break 2;
+}
+$this->text_length += strlen($this->lexer->text);
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_WS,
+BBCODE_STACK_TEXT => $this->lexer->text,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+break;
+case BBCODE_NL:
+if ($this->ignore_newlines) {
+if ($this->output_limit > 0
+&& $this->text_length + 1 >= $this->output_limit) {
+$this->Internal_DoLimit();
+break 2;
+}
+$this->text_length += 1;
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_WS,
+BBCODE_STACK_TEXT => "\n",
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+}
+else {
+$this->Internal_CleanupWSByPoppingStack("s", $this->stack);
+if ($this->output_limit > 0
+&& $this->text_length + 1 >= $this->output_limit) {
+$this->Internal_DoLimit();
+break 2;
+}
+$this->text_length += 1;
+$this->stack[] = Array(
+BBCODE_STACK_TOKEN => BBCODE_NL,
+BBCODE_STACK_TEXT => $newline,
+BBCODE_STACK_TAG => false,
+BBCODE_STACK_CLASS => $this->current_class,
+);
+$this->Internal_CleanupWSByEatingInput("s");
+}
+break;
+case BBCODE_TAG:
+$this->Internal_ParseStartTagToken();
+break;
+case BBCODE_ENDTAG:
+$this->Internal_ParseEndTagToken();
+break;
+default:
+break;
+}
+}
+if (strlen($this->post_trim) > 0)
+$this->Internal_CleanupWSByPoppingStack($this->post_trim, $this->stack);
+$result = $this->Internal_GenerateOutput(0);
+$result = $this->Internal_CollectTextReverse($result, count($result) - 1);
+$this->output_limit = $old_output_limit;
+if ($this->plain_mode) {
+$result = preg_replace("/[\\x00-\\x09\\x0B-\\x20]+/", " ", $result);
+$result = preg_replace("/(?:[\\x20]*\\n){2,}[\\x20]*/", "\n\n", $result);
+$result = trim($result);
+}
+return $result;
+}
+}
+
Index: /tags/2.5.4/includes/admin/replies.php
===================================================================
--- /tags/2.5.4/includes/admin/replies.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/replies.php	(revision 5382)
@@ -0,0 +1,904 @@
+<?php
+
+/**
+ * bbPress Replies Admin Class
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Replies_Admin' ) ) :
+/**
+ * Loads bbPress replies admin area
+ *
+ * @package bbPress
+ * @subpackage Administration
+ * @since bbPress (r2464)
+ */
+class BBP_Replies_Admin {
+
+	/** Variables *************************************************************/
+
+	/**
+	 * @var The post type of this admin component
+	 */
+	private $post_type = '';
+
+	/** Functions *************************************************************/
+
+	/**
+	 * The main bbPress admin loader
+	 *
+	 * @since bbPress (r2515)
+	 *
+	 * @uses BBP_Replies_Admin::setup_globals() Setup the globals needed
+	 * @uses BBP_Replies_Admin::setup_actions() Setup the hooks and actions
+	 * @uses BBP_Replies_Admin::setup_actions() Setup the help text
+	 */
+	public function __construct() {
+		$this->setup_globals();
+		$this->setup_actions();
+	}
+
+	/**
+	 * Setup the admin hooks, actions and filters
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 *
+	 * @uses add_action() To add various actions
+	 * @uses add_filter() To add various filters
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 */
+	private function setup_actions() {
+
+		// Add some general styling to the admin area
+		add_action( 'bbp_admin_head',        array( $this, 'admin_head'       ) );
+
+		// Messages
+		add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
+
+		// Reply column headers.
+		add_filter( 'manage_' . $this->post_type . '_posts_columns',  array( $this, 'column_headers' ) );
+
+		// Reply columns (in post row)
+		add_action( 'manage_' . $this->post_type . '_posts_custom_column',  array( $this, 'column_data' ), 10, 2 );
+		add_filter( 'post_row_actions',                                     array( $this, 'row_actions' ), 10, 2 );
+
+		// Reply metabox actions
+		add_action( 'add_meta_boxes', array( $this, 'attributes_metabox'      ) );
+		add_action( 'save_post',      array( $this, 'attributes_metabox_save' ) );
+
+		// Check if there are any bbp_toggle_reply_* requests on admin_init, also have a message displayed
+		add_action( 'load-edit.php',  array( $this, 'toggle_reply'        ) );
+		add_action( 'admin_notices',  array( $this, 'toggle_reply_notice' ) );
+
+		// Anonymous metabox actions
+		add_action( 'add_meta_boxes', array( $this, 'author_metabox'      ) );
+
+		// Add ability to filter topics and replies per forum
+		add_filter( 'restrict_manage_posts', array( $this, 'filter_dropdown'  ) );
+		add_filter( 'bbp_request',           array( $this, 'filter_post_rows' ) );
+
+		// Contextual Help
+		add_action( 'load-edit.php',     array( $this, 'edit_help' ) );
+		add_action( 'load-post.php',     array( $this, 'new_help'  ) );
+		add_action( 'load-post-new.php', array( $this, 'new_help'  ) );
+	}
+
+	/**
+	 * Should we bail out of this method?
+	 *
+	 * @since bbPress (r4067)
+	 * @return boolean
+	 */
+	private function bail() {
+		if ( !isset( get_current_screen()->post_type ) || ( $this->post_type !== get_current_screen()->post_type ) )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Admin globals
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 */
+	private function setup_globals() {
+		$this->post_type = bbp_get_reply_post_type();
+	}
+
+	/** Contextual Help *******************************************************/
+
+	/**
+	 * Contextual help for bbPress reply edit page
+	 *
+	 * @since bbPress (r3119)
+	 * @uses get_current_screen()
+	 */
+	public function edit_help() {
+
+		if ( $this->bail() ) return;
+
+		// Overview
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'overview',
+			'title'		=> __( 'Overview', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'This screen provides access to all of your replies. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
+		) );
+
+		// Screen Content
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'screen-content',
+			'title'		=> __( 'Screen Content', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( 'You can hide/display columns based on your needs and decide how many replies to list per screen using the Screen Options tab.',                                                                                                                                                                          'bbpress' ) . '</li>' .
+					'<li>' . __( 'You can filter the list of replies by reply status using the text links in the upper left to show All, Published, Draft, or Trashed replies. The default view is to show all replies.',                                                                                                                   'bbpress' ) . '</li>' .
+					'<li>' . __( 'You can view replies in a simple title list or with an excerpt. Choose the view you prefer by clicking on the icons at the top of the list on the right.',                                                                                                                                             'bbpress' ) . '</li>' .
+					'<li>' . __( 'You can refine the list to show only replies in a specific category or from a specific month by using the dropdown menus above the replies list. Click the Filter button after making your selection. You also can refine the list by clicking on the reply author, category or tag in the replies list.', 'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		// Available Actions
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'action-links',
+			'title'		=> __( 'Available Actions', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'Hovering over a row in the replies list will display action links that allow you to manage your reply. You can perform the following actions:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that reply. You can also reach that screen by clicking on the reply title.',                                                                                 'bbpress' ) . '</li>' .
+					//'<li>' . __( '<strong>Quick Edit</strong> provides inline access to the metadata of your reply, allowing you to update reply details without leaving this screen.',                                                                  'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Trash</strong> removes your reply from this list and places it in the trash, from which you can permanently delete it.',                                                                                       'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Spam</strong> removes your reply from this list and places it in the spam queue, from which you can permanently delete it.',                                                                                   'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Preview</strong> will show you what your draft reply will look like if you publish it. View will take you to your live site to view the reply. Which link is available depends on your reply&#8217;s status.', 'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		// Bulk Actions
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'bulk-actions',
+			'title'		=> __( 'Bulk Actions', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'You can also edit or move multiple replies to the trash at once. Select the replies you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.',           'bbpress' ) . '</p>' .
+				'<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected replies at once. To remove a reply from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
+		) );
+
+		// Help Sidebar
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
+			'<p>' . __( '<a href="http://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
+		);
+	}
+
+	/**
+	 * Contextual help for bbPress reply edit page
+	 *
+	 * @since bbPress (r3119)
+	 * @uses get_current_screen()
+	 */
+	public function new_help() {
+
+		if ( $this->bail() ) return;
+
+		$customize_display = '<p>' . __( 'The title field and the big reply editing Area are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.', 'bbpress' ) . '</p>';
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'customize-display',
+			'title'   => __( 'Customizing This Display', 'bbpress' ),
+			'content' => $customize_display,
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'title-reply-editor',
+			'title'   => __( 'Title and Reply Editor', 'bbpress' ),
+			'content' =>
+				'<p>' . __( '<strong>Title</strong> - Enter a title for your reply. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
+				'<p>' . __( '<strong>Reply Editor</strong> - Enter the text for your reply. There are two modes of editing: Visual and HTML. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The HTML mode allows you to enter raw HTML along with your reply text. You can insert media files by clicking the icons above the reply editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in HTML mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular reply editor.', 'bbpress' ) . '</p>'
+		) );
+
+		$publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your reply in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a reply or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a reply to be published in the future or backdate a reply.', 'bbpress' ) . '</p>';
+
+		if ( current_theme_supports( 'reply-thumbnails' ) && post_type_supports( 'reply', 'thumbnail' ) ) {
+			$publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your reply without inserting it. This is usually useful only if your theme makes use of the featured image as a reply thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
+		}
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'reply-attributes',
+			'title'   => __( 'Reply Attributes', 'bbpress' ),
+			'content' =>
+				'<p>' . __( 'Select the attributes that your reply should have:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( '<strong>Forum</strong> dropdown determines the parent forum that the reply belongs to. Select the forum, or leave the default (Use Forum of Topic) to post the reply in forum of the topic.', 'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Topic</strong> determines the parent topic that the reply belongs to.', 'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Reply To</strong> determines the threading of the reply.', 'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'publish-box',
+			'title'   => __( 'Publish Box', 'bbpress' ),
+			'content' => $publish_box,
+		) );
+
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
+			'<p>' . __( '<a href="http://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
+		);
+	}
+
+	/**
+	 * Add the reply attributes metabox
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses add_meta_box() To add the metabox
+	 * @uses do_action() Calls 'bbp_reply_attributes_metabox'
+	 */
+	public function attributes_metabox() {
+
+		if ( $this->bail() ) return;
+
+		add_meta_box (
+			'bbp_reply_attributes',
+			__( 'Reply Attributes', 'bbpress' ),
+			'bbp_reply_metabox',
+			$this->post_type,
+			'side',
+			'high'
+		);
+
+		do_action( 'bbp_reply_attributes_metabox' );
+	}
+
+	/**
+	 * Pass the reply attributes for processing
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @param int $reply_id Reply id
+	 * @uses current_user_can() To check if the current user is capable of
+	 *                           editing the reply
+	 * @uses do_action() Calls 'bbp_reply_attributes_metabox_save' with the
+	 *                    reply id and parent id
+	 * @return int Parent id
+	 */
+	public function attributes_metabox_save( $reply_id ) {
+
+		if ( $this->bail() ) return $reply_id;
+
+		// Bail if doing an autosave
+		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
+			return $reply_id;
+
+		// Bail if not a post request
+		if ( ! bbp_is_post_request() )
+			return $reply_id;
+
+		// Check action exists
+		if ( empty( $_POST['action'] ) )
+			return $reply_id;
+
+		// Nonce check
+		if ( empty( $_POST['bbp_reply_metabox'] ) || !wp_verify_nonce( $_POST['bbp_reply_metabox'], 'bbp_reply_metabox_save' ) )
+			return $reply_id;
+
+		// Current user cannot edit this reply
+		if ( !current_user_can( 'edit_reply', $reply_id ) )
+			return $reply_id;
+
+		// Get the reply meta post values
+		$topic_id = !empty( $_POST['parent_id']    ) ? (int) $_POST['parent_id']    : 0;
+		$forum_id = !empty( $_POST['bbp_forum_id'] ) ? (int) $_POST['bbp_forum_id'] : bbp_get_topic_forum_id( $topic_id );
+		$reply_to = !empty( $_POST['bbp_reply_to'] ) ? (int) $_POST['bbp_reply_to'] : 0;
+
+		// Get reply author data
+		$anonymous_data = bbp_filter_anonymous_post_data();
+		$author_id      = bbp_get_reply_author_id( $reply_id );
+		$is_edit        = (bool) isset( $_POST['save'] );
+
+		// Formally update the reply
+		bbp_update_reply( $reply_id, $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit, $reply_to );
+
+		// Allow other fun things to happen
+		do_action( 'bbp_reply_attributes_metabox_save', $reply_id, $topic_id, $forum_id, $reply_to );
+		do_action( 'bbp_author_metabox_save',           $reply_id, $anonymous_data                 );
+
+		return $reply_id;
+	}
+
+	/**
+	 * Add the author info metabox
+	 *
+	 * Allows editing of information about an author
+	 *
+	 * @since bbPress (r2828)
+	 *
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses add_meta_box() To add the metabox
+	 * @uses do_action() Calls 'bbp_author_metabox' with the topic/reply
+	 *                    id
+	 */
+	public function author_metabox() {
+
+		if ( $this->bail() ) return;
+
+		// Bail if post_type is not a reply
+		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) )
+			return;
+
+		// Add the metabox
+		add_meta_box(
+			'bbp_author_metabox',
+			__( 'Author Information', 'bbpress' ),
+			'bbp_author_metabox',
+			$this->post_type,
+			'side',
+			'high'
+		);
+
+		do_action( 'bbp_author_metabox', get_the_ID() );
+	}
+
+	/**
+	 * Add some general styling to the admin area
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses sanitize_html_class() To sanitize the classes
+	 * @uses do_action() Calls 'bbp_admin_head'
+	 */
+	public function admin_head() {
+
+		if ( $this->bail() ) return;
+
+		?>
+
+		<style type="text/css" media="screen">
+		/*<![CDATA[*/
+
+			strong.label {
+				display: inline-block;
+				width: 60px;
+			}
+
+			.column-bbp_forum_topic_count,
+			.column-bbp_forum_reply_count,
+			.column-bbp_topic_reply_count,
+			.column-bbp_topic_voice_count {
+				width: 8% !important;
+			}
+
+			.column-author,
+			.column-bbp_reply_author,
+			.column-bbp_topic_author {
+				width: 10% !important;
+			}
+
+			.column-bbp_topic_forum,
+			.column-bbp_reply_forum,
+			.column-bbp_reply_topic {
+				width: 10% !important;
+			}
+
+			.column-bbp_forum_freshness,
+			.column-bbp_topic_freshness {
+				width: 10% !important;
+			}
+
+			.column-bbp_forum_created,
+			.column-bbp_topic_created,
+			.column-bbp_reply_created {
+				width: 15% !important;
+			}
+
+			.status-closed {
+				background-color: #eaeaea;
+			}
+
+			.status-spam {
+				background-color: #faeaea;
+			}
+
+		/*]]>*/
+		</style>
+
+		<?php
+	}
+
+	/**
+	 * Toggle reply
+	 *
+	 * Handles the admin-side spamming/unspamming of replies
+	 *
+	 * @since bbPress (r2740)
+	 *
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses current_user_can() To check if the user is capable of editing
+	 *                           the reply
+	 * @uses wp_die() To die if the user isn't capable or the post wasn't
+	 *                 found
+	 * @uses check_admin_referer() To verify the nonce and check referer
+	 * @uses bbp_is_reply_spam() To check if the reply is marked as spam
+	 * @uses bbp_unspam_reply() To unmark the reply as spam
+	 * @uses bbp_spam_reply() To mark the reply as spam
+	 * @uses do_action() Calls 'bbp_toggle_reply_admin' with success, post
+	 *                    data, action and message
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_safe_redirect() Redirect the page to custom url
+	 */
+	public function toggle_reply() {
+
+		if ( $this->bail() ) return;
+
+		// Only proceed if GET is a reply toggle action
+		if ( bbp_is_get_request() && !empty( $_GET['action'] ) && in_array( $_GET['action'], array( 'bbp_toggle_reply_spam' ) ) && !empty( $_GET['reply_id'] ) ) {
+			$action    = $_GET['action'];            // What action is taking place?
+			$reply_id  = (int) $_GET['reply_id'];    // What's the reply id?
+			$success   = false;                      // Flag
+			$post_data = array( 'ID' => $reply_id ); // Prelim array
+
+			// Get reply and die if empty
+			$reply = bbp_get_reply( $reply_id );
+			if ( empty( $reply ) ) // Which reply?
+				wp_die( __( 'The reply was not found!', 'bbpress' ) );
+
+			if ( !current_user_can( 'moderate', $reply->ID ) ) // What is the user doing here?
+				wp_die( __( 'You do not have the permission to do that!', 'bbpress' ) );
+
+			switch ( $action ) {
+				case 'bbp_toggle_reply_spam' :
+					check_admin_referer( 'spam-reply_' . $reply_id );
+
+					$is_spam = bbp_is_reply_spam( $reply_id );
+					$message = $is_spam ? 'unspammed' : 'spammed';
+					$success = $is_spam ? bbp_unspam_reply( $reply_id ) : bbp_spam_reply( $reply_id );
+
+					break;
+			}
+
+			$success = wp_update_post( $post_data );
+			$message = array( 'bbp_reply_toggle_notice' => $message, 'reply_id' => $reply->ID );
+
+			if ( false === $success || is_wp_error( $success ) )
+				$message['failed'] = '1';
+
+			// Do additional reply toggle actions (admin side)
+			do_action( 'bbp_toggle_reply_admin', $success, $post_data, $action, $message );
+
+			// Redirect back to the reply
+			$redirect = add_query_arg( $message, remove_query_arg( array( 'action', 'reply_id' ) ) );
+			wp_safe_redirect( $redirect );
+
+			// For good measure
+			exit();
+		}
+	}
+
+	/**
+	 * Toggle reply notices
+	 *
+	 * Display the success/error notices from
+	 * {@link BBP_Admin::toggle_reply()}
+	 *
+	 * @since bbPress (r2740)
+	 *
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses bbp_get_reply_title() To get the reply title of the reply
+	 * @uses esc_html() To sanitize the reply title
+	 * @uses apply_filters() Calls 'bbp_toggle_reply_notice_admin' with
+	 *                        message, reply id, notice and is it a failure
+	 */
+	public function toggle_reply_notice() {
+
+		if ( $this->bail() ) return;
+
+		// Only proceed if GET is a reply toggle action
+		if ( bbp_is_get_request() && !empty( $_GET['bbp_reply_toggle_notice'] ) && in_array( $_GET['bbp_reply_toggle_notice'], array( 'spammed', 'unspammed' ) ) && !empty( $_GET['reply_id'] ) ) {
+			$notice     = $_GET['bbp_reply_toggle_notice'];         // Which notice?
+			$reply_id   = (int) $_GET['reply_id'];                  // What's the reply id?
+			$is_failure = !empty( $_GET['failed'] ) ? true : false; // Was that a failure?
+
+			// Empty? No reply?
+			if ( empty( $notice ) || empty( $reply_id ) )
+				return;
+
+			// Get reply and bail if empty
+			$reply = bbp_get_reply( $reply_id );
+			if ( empty( $reply ) )
+				return;
+
+			$reply_title = bbp_get_reply_title( $reply->ID );
+
+			switch ( $notice ) {
+				case 'spammed' :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem marking the reply "%1$s" as spam.', 'bbpress' ), $reply_title ) : sprintf( __( 'Reply "%1$s" successfully marked as spam.', 'bbpress' ), $reply_title );
+					break;
+
+				case 'unspammed' :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem unmarking the reply "%1$s" as spam.', 'bbpress' ), $reply_title ) : sprintf( __( 'Reply "%1$s" successfully unmarked as spam.', 'bbpress' ), $reply_title );
+					break;
+			}
+
+			// Do additional reply toggle notice filters (admin side)
+			$message = apply_filters( 'bbp_toggle_reply_notice_admin', $message, $reply->ID, $notice, $is_failure );
+
+			?>
+
+			<div id="message" class="<?php echo $is_failure === true ? 'error' : 'updated'; ?> fade">
+				<p style="line-height: 150%"><?php echo esc_html( $message ); ?></p>
+			</div>
+
+			<?php
+		}
+	}
+
+	/**
+	 * Manage the column headers for the replies page
+	 *
+	 * @since bbPress (r2577)
+	 *
+	 * @param array $columns The columns
+	 * @uses apply_filters() Calls 'bbp_admin_replies_column_headers' with
+	 *                        the columns
+	 * @return array $columns bbPress reply columns
+	 */
+	public function column_headers( $columns ) {
+
+		if ( $this->bail() ) return $columns;
+
+		$columns = array(
+			'cb'                => '<input type="checkbox" />',
+			'title'             => __( 'Title',   'bbpress' ),
+			'bbp_reply_forum'   => __( 'Forum',   'bbpress' ),
+			'bbp_reply_topic'   => __( 'Topic',   'bbpress' ),
+			'bbp_reply_author'  => __( 'Author',  'bbpress' ),
+			'bbp_reply_created' => __( 'Created', 'bbpress' ),
+		);
+
+		return apply_filters( 'bbp_admin_replies_column_headers', $columns );
+	}
+
+	/**
+	 * Print extra columns for the replies page
+	 *
+	 * @since bbPress (r2577)
+	 *
+	 * @param string $column Column
+	 * @param int $reply_id reply id
+	 * @uses bbp_get_reply_topic_id() To get the topic id of the reply
+	 * @uses bbp_topic_title() To output the reply's topic title
+	 * @uses apply_filters() Calls 'reply_topic_row_actions' with an array
+	 *                        of reply topic actions
+	 * @uses bbp_get_topic_permalink() To get the topic permalink
+	 * @uses bbp_get_topic_forum_id() To get the forum id of the topic of
+	 *                                 the reply
+	 * @uses bbp_get_forum_permalink() To get the forum permalink
+	 * @uses admin_url() To get the admin url of post.php
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses apply_filters() Calls 'reply_topic_forum_row_actions' with an
+	 *                        array of reply topic forum actions
+	 * @uses bbp_reply_author_display_name() To output the reply author name
+	 * @uses get_the_date() Get the reply creation date
+	 * @uses get_the_time() Get the reply creation time
+	 * @uses esc_attr() To sanitize the reply creation time
+	 * @uses bbp_get_reply_last_active_time() To get the time when the reply was
+	 *                                    last active
+	 * @uses do_action() Calls 'bbp_admin_replies_column_data' with the
+	 *                    column and reply id
+	 */
+	public function column_data( $column, $reply_id ) {
+
+		if ( $this->bail() ) return;
+
+		// Get topic ID
+		$topic_id = bbp_get_reply_topic_id( $reply_id );
+
+		// Populate Column Data
+		switch ( $column ) {
+
+			// Topic
+			case 'bbp_reply_topic' :
+
+				// Output forum name
+				if ( !empty( $topic_id ) ) {
+
+					// Topic Title
+					$topic_title = bbp_get_topic_title( $topic_id );
+					if ( empty( $topic_title ) ) {
+						$topic_title = esc_html__( 'No Topic', 'bbpress' );
+					}
+
+					// Output the title
+					echo $topic_title;
+
+				// Reply has no topic
+				} else {
+					esc_html_e( 'No Topic', 'bbpress' );
+				}
+
+				break;
+
+			// Forum
+			case 'bbp_reply_forum' :
+
+				// Get Forum ID's
+				$reply_forum_id = bbp_get_reply_forum_id( $reply_id );
+				$topic_forum_id = bbp_get_topic_forum_id( $topic_id );
+
+				// Output forum name
+				if ( !empty( $reply_forum_id ) ) {
+
+					// Forum Title
+					$forum_title = bbp_get_forum_title( $reply_forum_id );
+					if ( empty( $forum_title ) ) {
+						$forum_title = esc_html__( 'No Forum', 'bbpress' );
+					}
+
+					// Alert capable users of reply forum mismatch
+					if ( $reply_forum_id !== $topic_forum_id ) {
+						if ( current_user_can( 'edit_others_replies' ) || current_user_can( 'moderate' ) ) {
+							$forum_title .= '<div class="attention">' . esc_html__( '(Mismatch)', 'bbpress' ) . '</div>';
+						}
+					}
+
+					// Output the title
+					echo $forum_title;
+
+				// Reply has no forum
+				} else {
+					_e( 'No Forum', 'bbpress' );
+				}
+
+				break;
+
+			// Author
+			case 'bbp_reply_author' :
+				bbp_reply_author_display_name ( $reply_id );
+				break;
+
+			// Freshness
+			case 'bbp_reply_created':
+
+				// Output last activity time and date
+				printf( '%1$s <br /> %2$s',
+					get_the_date(),
+					esc_attr( get_the_time() )
+				);
+
+				break;
+
+			// Do action for anything else
+			default :
+				do_action( 'bbp_admin_replies_column_data', $column, $reply_id );
+				break;
+		}
+	}
+
+	/**
+	 * Reply Row actions
+	 *
+	 * Remove the quick-edit action link under the reply title and add the
+	 * content and spam link
+	 *
+	 * @since bbPress (r2577)
+	 *
+	 * @param array $actions Actions
+	 * @param array $reply Reply object
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses bbp_reply_content() To output reply content
+	 * @uses bbp_get_reply_permalink() To get the reply link
+	 * @uses bbp_get_reply_title() To get the reply title
+	 * @uses current_user_can() To check if the current user can edit or
+	 *                           delete the reply
+	 * @uses bbp_is_reply_spam() To check if the reply is marked as spam
+	 * @uses get_post_type_object() To get the reply post type object
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses remove_query_arg() To remove custom args from the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses get_delete_post_link() To get the delete post link of the reply
+	 * @return array $actions Actions
+	 */
+	public function row_actions( $actions, $reply ) {
+
+		if ( $this->bail() ) return $actions;
+
+		unset( $actions['inline hide-if-no-js'] );
+
+		// Reply view links to topic
+		$actions['view'] = '<a href="' . esc_url( bbp_get_reply_url( $reply->ID ) ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;', 'bbpress' ), bbp_get_reply_title( $reply->ID ) ) ) . '" rel="permalink">' . esc_html__( 'View', 'bbpress' ) . '</a>';
+
+		// User cannot view replies in trash
+		if ( ( bbp_get_trash_status_id() === $reply->post_status ) && !current_user_can( 'view_trash' ) )
+			unset( $actions['view'] );
+
+		// Only show the actions if the user is capable of viewing them
+		if ( current_user_can( 'moderate', $reply->ID ) ) {
+			if ( in_array( $reply->post_status, array( bbp_get_public_status_id(), bbp_get_spam_status_id() ) ) ) {
+				$spam_uri  = wp_nonce_url( add_query_arg( array( 'reply_id' => $reply->ID, 'action' => 'bbp_toggle_reply_spam' ), remove_query_arg( array( 'bbp_reply_toggle_notice', 'reply_id', 'failed', 'super' ) ) ), 'spam-reply_'  . $reply->ID );
+				if ( bbp_is_reply_spam( $reply->ID ) ) {
+					$actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark the reply as not spam', 'bbpress' ) . '">' . esc_html__( 'Not spam', 'bbpress' ) . '</a>';
+				} else {
+					$actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark this reply as spam',    'bbpress' ) . '">' . esc_html__( 'Spam',     'bbpress' ) . '</a>';
+				}
+			}
+		}
+
+		// Trash
+		if ( current_user_can( 'delete_reply', $reply->ID ) ) {
+			if ( bbp_get_trash_status_id() === $reply->post_status ) {
+				$post_type_object   = get_post_type_object( bbp_get_reply_post_type() );
+				$actions['untrash'] = "<a title='" . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . "' href='" . add_query_arg( array( '_wp_http_referer' => add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), admin_url( 'edit.php' ) ) ), wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $reply->ID ) ), 'untrash-' . $reply->post_type . '_' . $reply->ID ) ) . "'>" . esc_html__( 'Restore', 'bbpress' ) . "</a>";
+			} elseif ( EMPTY_TRASH_DAYS ) {
+				$actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash', 'bbpress' ) . "' href='" . add_query_arg( array( '_wp_http_referer' => add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), admin_url( 'edit.php' ) ) ), get_delete_post_link( $reply->ID ) ) . "'>" . esc_html__( 'Trash', 'bbpress' ) . "</a>";
+			}
+
+			if ( bbp_get_trash_status_id() === $reply->post_status || !EMPTY_TRASH_DAYS ) {
+				$actions['delete'] = "<a class='submitdelete' title='" . esc_attr__( 'Delete this item permanently', 'bbpress' ) . "' href='" . add_query_arg( array( '_wp_http_referer' => add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), admin_url( 'edit.php' ) ) ), get_delete_post_link( $reply->ID, '', true ) ) . "'>" . esc_html__( 'Delete Permanently', 'bbpress' ) . "</a>";
+			} elseif ( bbp_get_spam_status_id() === $reply->post_status ) {
+				unset( $actions['trash'] );
+			}
+		}
+
+		return $actions;
+	}
+
+	/**
+	 * Add forum dropdown to topic and reply list table filters
+	 *
+	 * @since bbPress (r2991)
+	 *
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_dropdown() To generate a forum dropdown
+	 * @return bool False. If post type is not topic or reply
+	 */
+	public function filter_dropdown() {
+
+		if ( $this->bail() ) return;
+
+		// Add Empty Spam button
+		if ( !empty( $_GET['post_status'] ) && ( bbp_get_spam_status_id() === $_GET['post_status'] ) && current_user_can( 'moderate' ) ) {
+			wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
+			$title = esc_attr__( 'Empty Spam', 'bbpress' );
+			submit_button( $title, 'button-secondary apply', 'delete_all', false );
+		}
+
+		// Get which forum is selected
+		$selected = !empty( $_GET['bbp_forum_id'] ) ? $_GET['bbp_forum_id'] : '';
+
+		// Show the forums dropdown
+		bbp_dropdown( array(
+			'selected'  => $selected,
+			'show_none' => __( 'In all forums', 'bbpress' )
+		) );
+	}
+
+	/**
+	 * Adjust the request query and include the forum id
+	 *
+	 * @since bbPress (r2991)
+	 *
+	 * @param array $query_vars Query variables from {@link WP_Query}
+	 * @uses is_admin() To check if it's the admin section
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @return array Processed Query Vars
+	 */
+	public function filter_post_rows( $query_vars ) {
+
+		if ( $this->bail() ) return $query_vars;
+
+		// Add post_parent query_var if one is present
+		if ( !empty( $_GET['bbp_forum_id'] ) ) {
+			$query_vars['meta_key']   = '_bbp_forum_id';
+			$query_vars['meta_value'] = $_GET['bbp_forum_id'];
+		}
+
+		// Return manipulated query_vars
+		return $query_vars;
+	}
+
+	/**
+	 * Custom user feedback messages for reply post type
+	 *
+	 * @since bbPress (r3080)
+	 *
+	 * @global int $post_ID
+	 * @uses bbp_get_topic_permalink()
+	 * @uses wp_post_revision_title()
+	 * @uses esc_url()
+	 * @uses add_query_arg()
+	 *
+	 * @param array $messages
+	 *
+	 * @return array
+	 */
+	public function updated_messages( $messages ) {
+		global $post_ID;
+
+		if ( $this->bail() ) return $messages;
+
+		// URL for the current topic
+		$topic_url = bbp_get_topic_permalink( bbp_get_reply_topic_id( $post_ID ) );
+
+		// Current reply's post_date
+		$post_date = bbp_get_global_post_field( 'post_date', 'raw' );
+
+		// Messages array
+		$messages[$this->post_type] = array(
+			0 =>  '', // Left empty on purpose
+
+			// Updated
+			1 =>  sprintf( __( 'Reply updated. <a href="%s">View topic</a>', 'bbpress' ), $topic_url ),
+
+			// Custom field updated
+			2 => __( 'Custom field updated.', 'bbpress' ),
+
+			// Custom field deleted
+			3 => __( 'Custom field deleted.', 'bbpress' ),
+
+			// Reply updated
+			4 => __( 'Reply updated.', 'bbpress' ),
+
+			// Restored from revision
+			// translators: %s: date and time of the revision
+			5 => isset( $_GET['revision'] )
+					? sprintf( __( 'Reply restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
+					: false,
+
+			// Reply created
+			6 => sprintf( __( 'Reply created. <a href="%s">View topic</a>', 'bbpress' ), $topic_url ),
+
+			// Reply saved
+			7 => __( 'Reply saved.', 'bbpress' ),
+
+			// Reply submitted
+			8 => sprintf( __( 'Reply submitted. <a target="_blank" href="%s">Preview topic</a>', 'bbpress' ), esc_url( add_query_arg( 'preview', 'true', $topic_url ) ) ),
+
+			// Reply scheduled
+			9 => sprintf( __( 'Reply scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview topic</a>', 'bbpress' ),
+					// translators: Publish box date format, see http://php.net/date
+					date_i18n( __( 'M j, Y @ G:i', 'bbpress' ),
+					strtotime( $post_date ) ),
+					$topic_url ),
+
+			// Reply draft updated
+			10 => sprintf( __( 'Reply draft updated. <a target="_blank" href="%s">Preview topic</a>', 'bbpress' ), esc_url( add_query_arg( 'preview', 'true', $topic_url ) ) ),
+		);
+
+		return $messages;
+	}
+}
+endif; // class_exists check
+
+/**
+ * Setup bbPress Replies Admin
+ *
+ * This is currently here to make hooking and unhooking of the admin UI easy.
+ * It could use dependency injection in the future, but for now this is easier.
+ *
+ * @since bbPress (r2596)
+ *
+ * @uses BBP_Replies_Admin
+ */
+function bbp_admin_replies() {
+	bbpress()->admin->replies = new BBP_Replies_Admin();
+}
Index: /tags/2.5.4/includes/admin/settings.php
===================================================================
--- /tags/2.5.4/includes/admin/settings.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/settings.php	(revision 5382)
@@ -0,0 +1,1759 @@
+<?php
+
+/**
+ * bbPress Admin Settings
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Sections ******************************************************************/
+
+/**
+ * Get the Forums settings sections.
+ *
+ * @since bbPress (r4001)
+ * @return array
+ */
+function bbp_admin_get_settings_sections() {
+	return (array) apply_filters( 'bbp_admin_get_settings_sections', array(
+		'bbp_settings_users' => array(
+			'title'    => __( 'Forum User Settings', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_user_section',
+			'page'     => 'discussion'
+		),
+		'bbp_settings_features' => array(
+			'title'    => __( 'Forum Features', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_features_section',
+			'page'     => 'discussion'
+		),
+		'bbp_settings_theme_compat' => array(
+			'title'    => __( 'Forum Theme Packages', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_subtheme_section',
+			'page'     => 'general'
+		),
+		'bbp_settings_per_page' => array(
+			'title'    => __( 'Topics and Replies Per Page', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_per_page_section',
+			'page'     => 'reading'
+		),
+		'bbp_settings_per_rss_page' => array(
+			'title'    => __( 'Topics and Replies Per RSS Page', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_per_rss_page_section',
+			'page'     => 'reading',
+		),
+		'bbp_settings_root_slugs' => array(
+			'title'    => __( 'Forum Root Slug', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_root_slug_section',
+			'page'     => 'permalink'
+		),
+		'bbp_settings_single_slugs' => array(
+			'title'    => __( 'Single Forum Slugs', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_single_slug_section',
+			'page'     => 'permalink',
+		),
+		'bbp_settings_user_slugs' => array(
+			'title'    => __( 'Forum User Slugs', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_user_slug_section',
+			'page'     => 'permalink',
+		),
+		'bbp_settings_buddypress' => array(
+			'title'    => __( 'BuddyPress Integration', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_buddypress_section',
+			'page'     => 'buddypress',
+		),
+		'bbp_settings_akismet' => array(
+			'title'    => __( 'Akismet Integration', 'bbpress' ),
+			'callback' => 'bbp_admin_setting_callback_akismet_section',
+			'page'     => 'discussion'
+		)
+	) );
+}
+
+/**
+ * Get all of the settings fields.
+ *
+ * @since bbPress (r4001)
+ * @return type
+ */
+function bbp_admin_get_settings_fields() {
+	return (array) apply_filters( 'bbp_admin_get_settings_fields', array(
+
+		/** User Section ******************************************************/
+
+		'bbp_settings_users' => array(
+
+			// Edit lock setting
+			'_bbp_edit_lock' => array(
+				'title'             => __( 'Disallow editing after', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_editlock',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Throttle setting
+			'_bbp_throttle_time' => array(
+				'title'             => __( 'Throttle posting every', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_throttle',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow anonymous posting setting
+			'_bbp_allow_anonymous' => array(
+				'title'             => __( 'Anonymous posting', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_anonymous',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow global access (on multisite)
+			'_bbp_allow_global_access' => array(
+				'title'             => __( 'Auto role', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_global_access',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow global access (on multisite)
+			'_bbp_default_role' => array(
+				'sanitize_callback' => 'sanitize_text_field',
+				'args'              => array()
+			)
+		),
+
+		/** Features Section **************************************************/
+
+		'bbp_settings_features' => array(
+
+			// Allow topic and reply revisions
+			'_bbp_allow_revisions' => array(
+				'title'             => __( 'Revisions', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_revisions',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow favorites setting
+			'_bbp_enable_favorites' => array(
+				'title'             => __( 'Favorites', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_favorites',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow subscriptions setting
+			'_bbp_enable_subscriptions' => array(
+				'title'             => __( 'Subscriptions', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_subscriptions',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow topic tags
+			'_bbp_allow_topic_tags' => array(
+				'title'             => __( 'Topic tags', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_topic_tags',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow topic tags
+			'_bbp_allow_search' => array(
+				'title'             => __( 'Search', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_search',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow fancy editor setting
+			'_bbp_use_wp_editor' => array(
+				'title'             => __( 'Post Formatting', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_use_wp_editor',
+				'args'              => array(),
+				'sanitize_callback' => 'intval'
+			),
+
+			// Allow auto embedding setting
+			'_bbp_use_autoembed' => array(
+				'title'             => __( 'Auto-embed links', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_use_autoembed',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Set reply threading level
+			'_bbp_thread_replies_depth' => array(
+				'title'             => __( 'Reply Threading', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_thread_replies_depth',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Allow threaded replies
+			'_bbp_allow_threaded_replies' => array(
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			)
+		),
+
+		/** Theme Packages ****************************************************/
+
+		'bbp_settings_theme_compat' => array(
+
+			// Theme package setting
+			'_bbp_theme_package_id' => array(
+				'title'             => __( 'Current Package', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_subtheme_id',
+				'sanitize_callback' => 'esc_sql',
+				'args'              => array()
+			)
+		),
+
+		/** Per Page Section **************************************************/
+
+		'bbp_settings_per_page' => array(
+
+			// Replies per page setting
+			'_bbp_topics_per_page' => array(
+				'title'             => __( 'Topics', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_topics_per_page',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Replies per page setting
+			'_bbp_replies_per_page' => array(
+				'title'             => __( 'Replies', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_replies_per_page',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			)
+		),
+
+		/** Per RSS Page Section **********************************************/
+
+		'bbp_settings_per_rss_page' => array(
+
+			// Replies per page setting
+			'_bbp_topics_per_rss_page' => array(
+				'title'             => __( 'Topics', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_topics_per_rss_page',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Replies per page setting
+			'_bbp_replies_per_rss_page' => array(
+				'title'             => __( 'Replies', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_replies_per_rss_page',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			)
+		),
+
+		/** Front Slugs *******************************************************/
+
+		'bbp_settings_root_slugs' => array(
+
+			// Root slug setting
+			'_bbp_root_slug' => array(
+				'title'             => __( 'Forum Root', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_root_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Include root setting
+			'_bbp_include_root' => array(
+				'title'             => __( 'Forum Prefix', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_include_root',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// What to show on Forum Root
+			'_bbp_show_on_root' => array(
+				'title'             => __( 'Forum root should show', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_show_on_root',
+				'sanitize_callback' => 'sanitize_text_field',
+				'args'              => array()
+			),
+		),
+
+		/** Single Slugs ******************************************************/
+
+		'bbp_settings_single_slugs' => array(
+
+			// Forum slug setting
+			'_bbp_forum_slug' => array(
+				'title'             => __( 'Forum', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_forum_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Topic slug setting
+			'_bbp_topic_slug' => array(
+				'title'             => __( 'Topic', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_topic_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Topic tag slug setting
+			'_bbp_topic_tag_slug' => array(
+				'title'             => __( 'Topic Tag', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_topic_tag_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// View slug setting
+			'_bbp_view_slug' => array(
+				'title'             => __( 'Topic View', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_view_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Reply slug setting
+			'_bbp_reply_slug' => array(
+				'title'             => __( 'Reply', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_reply_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Search slug setting
+			'_bbp_search_slug' => array(
+				'title'             => __( 'Search', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_search_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			)
+		),
+
+		/** User Slugs ********************************************************/
+
+		'bbp_settings_user_slugs' => array(
+
+			// User slug setting
+			'_bbp_user_slug' => array(
+				'title'             => __( 'User Base', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_user_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Topics slug setting
+			'_bbp_topic_archive_slug' => array(
+				'title'             => __( 'Topics Started', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_topic_archive_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Replies slug setting
+			'_bbp_reply_archive_slug' => array(
+				'title'             => __( 'Replies Created', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_reply_archive_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Favorites slug setting
+			'_bbp_user_favs_slug' => array(
+				'title'             => __( 'Favorite Topics', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_user_favs_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			),
+
+			// Subscriptions slug setting
+			'_bbp_user_subs_slug' => array(
+				'title'             => __( 'Topic Subscriptions', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_user_subs_slug',
+				'sanitize_callback' => 'bbp_sanitize_slug',
+				'args'              => array()
+			)
+		),
+
+		/** BuddyPress ********************************************************/
+
+		'bbp_settings_buddypress' => array(
+
+			// Are group forums enabled?
+			'_bbp_enable_group_forums' => array(
+				'title'             => __( 'Enable Group Forums', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_group_forums',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			),
+
+			// Group forums parent forum ID
+			'_bbp_group_forums_root_id' => array(
+				'title'             => __( 'Group Forums Parent', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_group_forums_root_id',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			)
+		),
+
+		/** Akismet ***********************************************************/
+
+		'bbp_settings_akismet' => array(
+
+			// Should we use Akismet
+			'_bbp_enable_akismet' => array(
+				'title'             => __( 'Use Akismet', 'bbpress' ),
+				'callback'          => 'bbp_admin_setting_callback_akismet',
+				'sanitize_callback' => 'intval',
+				'args'              => array()
+			)
+		)
+	) );
+}
+
+/**
+ * Get settings fields by section.
+ *
+ * @since bbPress (r4001)
+ * @param string $section_id
+ * @return mixed False if section is invalid, array of fields otherwise.
+ */
+function bbp_admin_get_settings_fields_for_section( $section_id = '' ) {
+
+	// Bail if section is empty
+	if ( empty( $section_id ) )
+		return false;
+
+	$fields = bbp_admin_get_settings_fields();
+	$retval = isset( $fields[$section_id] ) ? $fields[$section_id] : false;
+
+	return (array) apply_filters( 'bbp_admin_get_settings_fields_for_section', $retval, $section_id );
+}
+
+/** User Section **************************************************************/
+
+/**
+ * User settings section description for the settings page
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_user_section() {
+?>
+
+	<p><?php esc_html_e( 'Setting time limits and other user posting capabilities', 'bbpress' ); ?></p>
+
+<?php
+}
+
+
+/**
+ * Edit lock setting field
+ *
+ * @since bbPress (r2737)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_editlock() {
+?>
+
+	<input name="_bbp_edit_lock" id="_bbp_edit_lock" type="number" min="0" step="1" value="<?php bbp_form_option( '_bbp_edit_lock', '5' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_edit_lock' ); ?> />
+	<label for="_bbp_edit_lock"><?php esc_html_e( 'minutes', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Throttle setting field
+ *
+ * @since bbPress (r2737)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_throttle() {
+?>
+
+	<input name="_bbp_throttle_time" id="_bbp_throttle_time" type="number" min="0" step="1" value="<?php bbp_form_option( '_bbp_throttle_time', '10' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_throttle_time' ); ?> />
+	<label for="_bbp_throttle_time"><?php esc_html_e( 'seconds', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow anonymous posting setting field
+ *
+ * @since bbPress (r2737)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_anonymous() {
+?>
+
+	<input name="_bbp_allow_anonymous" id="_bbp_allow_anonymous" type="checkbox" value="1" <?php checked( bbp_allow_anonymous( false ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_anonymous' ); ?> />
+	<label for="_bbp_allow_anonymous"><?php esc_html_e( 'Allow guest users without accounts to create topics and replies', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow global access setting field
+ *
+ * @since bbPress (r3378)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_global_access() {
+
+	// Get the default role once rather than loop repeatedly below
+	$default_role = bbp_get_default_role();
+
+	// Start the output buffer for the select dropdown
+	ob_start(); ?>
+
+	</label>
+	<label for="_bbp_default_role">
+		<select name="_bbp_default_role" id="_bbp_default_role" <?php bbp_maybe_admin_setting_disabled( '_bbp_default_role' ); ?>>
+		<?php foreach ( bbp_get_dynamic_roles() as $role => $details ) : ?>
+
+			<option <?php selected( $default_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo translate_user_role( $details['name'] ); ?></option>
+
+		<?php endforeach; ?>
+		</select>
+
+	<?php $select = ob_get_clean(); ?>
+
+	<label for="_bbp_allow_global_access">
+		<input name="_bbp_allow_global_access" id="_bbp_allow_global_access" type="checkbox" value="1" <?php checked( bbp_allow_global_access( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_global_access' ); ?> />
+		<?php printf( esc_html__( 'Automatically give registered visitors the %s forum role', 'bbpress' ), $select ); ?>
+	</label>
+
+<?php
+}
+
+/** Features Section **********************************************************/
+
+/**
+ * Features settings section description for the settings page
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_features_section() {
+?>
+
+	<p><?php esc_html_e( 'Forum features that can be toggled on and off', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Allow favorites setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_favorites() {
+?>
+
+	<input name="_bbp_enable_favorites" id="_bbp_enable_favorites" type="checkbox" value="1" <?php checked( bbp_is_favorites_active( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_enable_favorites' ); ?> />
+	<label for="_bbp_enable_favorites"><?php esc_html_e( 'Allow users to mark topics as favorites', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow subscriptions setting field
+ *
+ * @since bbPress (r2737)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_subscriptions() {
+?>
+
+	<input name="_bbp_enable_subscriptions" id="_bbp_enable_subscriptions" type="checkbox" value="1" <?php checked( bbp_is_subscriptions_active( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_enable_subscriptions' ); ?> />
+	<label for="_bbp_enable_subscriptions"><?php esc_html_e( 'Allow users to subscribe to forums and topics', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow topic tags setting field
+ *
+ * @since bbPress (r4944)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_topic_tags() {
+?>
+
+	<input name="_bbp_allow_topic_tags" id="_bbp_allow_topic_tags" type="checkbox" value="1" <?php checked( bbp_allow_topic_tags( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_topic_tags' ); ?> />
+	<label for="_bbp_allow_topic_tags"><?php esc_html_e( 'Allow topics to have tags', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow forum wide search
+ *
+ * @since bbPress (r4970)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_search() {
+?>
+
+	<input name="_bbp_allow_search" id="_bbp_allow_search" type="checkbox" value="1" <?php checked( bbp_allow_search( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_search' ); ?> />
+	<label for="_bbp_allow_search"><?php esc_html_e( 'Allow forum wide search', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Hierarchical reply maximum depth level setting field
+ *
+ * Replies will be threaded if depth is 2 or greater
+ *
+ * @since bbPress (r4944)
+ *
+ * @uses apply_filters() Calls 'bbp_thread_replies_depth_max' to set a
+ *                        maximum displayed level
+ * @uses selected() To display the selected attribute
+ */
+function bbp_admin_setting_callback_thread_replies_depth() {
+
+	// Set maximum depth for dropdown
+	$max_depth     = (int) apply_filters( 'bbp_thread_replies_depth_max', 10 );
+	$current_depth = bbp_thread_replies_depth();
+
+	// Start an output buffer for the select dropdown
+	ob_start(); ?>
+
+	</label>
+	<label for="_bbp_thread_replies_depth">
+		<select name="_bbp_thread_replies_depth" id="_bbp_thread_replies_depth" <?php bbp_maybe_admin_setting_disabled( '_bbp_thread_replies_depth' ); ?>>
+		<?php for ( $i = 2; $i <= $max_depth; $i++ ) : ?>
+
+			<option value="<?php echo esc_attr( $i ); ?>" <?php selected( $i, $current_depth ); ?>><?php echo esc_html( $i ); ?></option>
+
+		<?php endfor; ?>
+		</select>
+
+	<?php $select = ob_get_clean(); ?>
+
+	<label for="_bbp_allow_threaded_replies">
+		<input name="_bbp_allow_threaded_replies" id="_bbp_allow_threaded_replies" type="checkbox" value="1" <?php checked( '1', bbp_allow_threaded_replies( false ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_threaded_replies' ); ?> />
+		<?php printf( esc_html__( 'Enable threaded (nested) replies %s levels deep', 'bbpress' ), $select ); ?>
+	</label>
+
+<?php
+}
+
+/**
+ * Allow topic and reply revisions
+ *
+ * @since bbPress (r3412)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_revisions() {
+?>
+
+	<input name="_bbp_allow_revisions" id="_bbp_allow_revisions" type="checkbox" value="1" <?php checked( bbp_allow_revisions( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_revisions' ); ?> />
+	<label for="_bbp_allow_revisions"><?php esc_html_e( 'Allow topic and reply revision logging', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Use the WordPress editor setting field
+ *
+ * @since bbPress (r3586)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_use_wp_editor() {
+?>
+
+	<input name="_bbp_use_wp_editor" id="_bbp_use_wp_editor" type="checkbox" value="1" <?php checked( bbp_use_wp_editor( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_use_wp_editor' ); ?> />
+	<label for="_bbp_use_wp_editor"><?php esc_html_e( 'Add toolbar & buttons to textareas to help with HTML formatting', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Main subtheme section
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_subtheme_section() {
+?>
+
+	<p><?php esc_html_e( 'How your forum content is displayed within your existing theme.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Use the WordPress editor setting field
+ *
+ * @since bbPress (r3586)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_subtheme_id() {
+
+	// Declare locale variable
+	$theme_options   = '';
+	$current_package = bbp_get_theme_package_id( 'default' );
+
+	// Note: This should never be empty. /templates/ is the
+	// canonical backup if no other packages exist. If there's an error here,
+	// something else is wrong.
+	//
+	// @see bbPress::register_theme_packages()
+	foreach ( (array) bbpress()->theme_compat->packages as $id => $theme ) {
+		$theme_options .= '<option value="' . esc_attr( $id ) . '"' . selected( $theme->id, $current_package, false ) . '>' . sprintf( esc_html__( '%1$s - %2$s', 'bbpress' ), esc_html( $theme->name ), esc_html( str_replace( WP_CONTENT_DIR, '', $theme->dir ) ) )  . '</option>';
+	}
+
+	if ( !empty( $theme_options ) ) : ?>
+
+		<select name="_bbp_theme_package_id" id="_bbp_theme_package_id" <?php bbp_maybe_admin_setting_disabled( '_bbp_theme_package_id' ); ?>><?php echo $theme_options ?></select>
+		<label for="_bbp_theme_package_id"><?php esc_html_e( 'will serve all bbPress templates', 'bbpress' ); ?></label>
+
+	<?php else : ?>
+
+		<p><?php esc_html_e( 'No template packages available.', 'bbpress' ); ?></p>
+
+	<?php endif;
+}
+
+/**
+ * Allow oEmbed in replies
+ *
+ * @since bbPress (r3752)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_use_autoembed() {
+?>
+
+	<input name="_bbp_use_autoembed" id="_bbp_use_autoembed" type="checkbox" value="1" <?php checked( bbp_use_autoembed( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_use_autoembed' ); ?> />
+	<label for="_bbp_use_autoembed"><?php esc_html_e( 'Embed media (YouTube, Twitter, Flickr, etc...) directly into topics and replies', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/** Per Page Section **********************************************************/
+
+/**
+ * Per page settings section description for the settings page
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_per_page_section() {
+?>
+
+	<p><?php esc_html_e( 'How many topics and replies to show per page', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Topics per page setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_topics_per_page() {
+?>
+
+	<input name="_bbp_topics_per_page" id="_bbp_topics_per_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_topics_per_page', '15' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_topics_per_page' ); ?> />
+	<label for="_bbp_topics_per_page"><?php esc_html_e( 'per page', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Replies per page setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_replies_per_page() {
+?>
+
+	<input name="_bbp_replies_per_page" id="_bbp_replies_per_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_replies_per_page', '15' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_replies_per_page' ); ?> />
+	<label for="_bbp_replies_per_page"><?php esc_html_e( 'per page', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/** Per RSS Page Section ******************************************************/
+
+/**
+ * Per page settings section description for the settings page
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_per_rss_page_section() {
+?>
+
+	<p><?php esc_html_e( 'How many topics and replies to show per RSS page', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Topics per RSS page setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_topics_per_rss_page() {
+?>
+
+	<input name="_bbp_topics_per_rss_page" id="_bbp_topics_per_rss_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_topics_per_rss_page', '25' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_topics_per_rss_page' ); ?> />
+	<label for="_bbp_topics_per_rss_page"><?php esc_html_e( 'per page', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Replies per RSS page setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_replies_per_rss_page() {
+?>
+
+	<input name="_bbp_replies_per_rss_page" id="_bbp_replies_per_rss_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_replies_per_rss_page', '25' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_replies_per_rss_page' ); ?> />
+	<label for="_bbp_replies_per_rss_page"><?php esc_html_e( 'per page', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/** Slug Section **************************************************************/
+
+/**
+ * Slugs settings section description for the settings page
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_root_slug_section() {
+
+	// Flush rewrite rules when this section is saved
+	if ( isset( $_GET['settings-updated'] ) && isset( $_GET['page'] ) )
+		flush_rewrite_rules(); ?>
+
+	<p><?php esc_html_e( 'Customize your Forums root. Partner with a WordPress Page and use Shortcodes for more flexibility.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Root slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_root_slug() {
+?>
+
+        <input name="_bbp_root_slug" id="_bbp_root_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_root_slug', 'forums', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_root_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_root_slug', 'forums' );
+}
+
+/**
+ * Include root slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_include_root() {
+?>
+
+	<input name="_bbp_include_root" id="_bbp_include_root" type="checkbox" value="1" <?php checked( bbp_include_root_slug() ); bbp_maybe_admin_setting_disabled( '_bbp_include_root' ); ?> />
+	<label for="_bbp_include_root"><?php esc_html_e( 'Prefix all forum content with the Forum Root slug (Recommended)', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Include root slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_show_on_root() {
+
+	// Current setting
+	$show_on_root = bbp_show_on_root();
+
+	// Options for forum root output
+	$root_options = array(
+		'forums' => array(
+			'name' => __( 'Forum Index', 'bbpress' )
+		),
+		'topics' => array(
+			'name' => __( 'Topics by Freshness', 'bbpress' )
+		)
+	); ?>
+
+	<select name="_bbp_show_on_root" id="_bbp_show_on_root" <?php bbp_maybe_admin_setting_disabled( '_bbp_show_on_root' ); ?>>
+
+		<?php foreach ( $root_options as $option_id => $details ) : ?>
+
+			<option <?php selected( $show_on_root, $option_id ); ?> value="<?php echo esc_attr( $option_id ); ?>"><?php echo esc_html( $details['name'] ); ?></option>
+
+		<?php endforeach; ?>
+
+	</select>
+
+<?php
+}
+
+/** User Slug Section *********************************************************/
+
+/**
+ * Slugs settings section description for the settings page
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_user_slug_section() {
+?>
+
+	<p><?php esc_html_e( 'Customize your user profile slugs.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * User slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_user_slug() {
+?>
+
+	<input name="_bbp_user_slug" id="_bbp_user_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_user_slug', 'users', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_user_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_user_slug', 'users' );
+}
+
+/**
+ * Topic archive slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_topic_archive_slug() {
+?>
+
+	<input name="_bbp_topic_archive_slug" id="_bbp_topic_archive_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_topic_archive_slug', 'topics', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_topic_archive_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_topic_archive_slug', 'topics' );
+}
+
+/**
+ * Reply archive slug setting field
+ *
+ * @since bbPress (r4932)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_reply_archive_slug() {
+?>
+
+	<input name="_bbp_reply_archive_slug" id="_bbp_reply_archive_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_reply_archive_slug', 'replies', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_reply_archive_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_reply_archive_slug', 'replies' );
+}
+
+/**
+ * Favorites slug setting field
+ *
+ * @since bbPress (r4932)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_user_favs_slug() {
+?>
+
+	<input name="_bbp_user_favs_slug" id="_bbp_user_favs_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_user_favs_slug', 'favorites', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_user_favs_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_reply_archive_slug', 'favorites' );
+}
+
+/**
+ * Favorites slug setting field
+ *
+ * @since bbPress (r4932)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_user_subs_slug() {
+?>
+
+	<input name="_bbp_user_subs_slug" id="_bbp_user_subs_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_user_subs_slug', 'subscriptions', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_user_subs_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_user_subs_slug', 'subscriptions' );
+}
+
+/** Single Slugs **************************************************************/
+
+/**
+ * Slugs settings section description for the settings page
+ *
+ * @since bbPress (r2786)
+ */
+function bbp_admin_setting_callback_single_slug_section() {
+?>
+
+	<p><?php printf( esc_html__( 'Custom slugs for single forums, topics, replies, tags, views, and search.', 'bbpress' ), get_admin_url( null, 'options-permalink.php' ) ); ?></p>
+
+<?php
+}
+
+/**
+ * Forum slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_forum_slug() {
+?>
+
+	<input name="_bbp_forum_slug" id="_bbp_forum_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_forum_slug', 'forum', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_forum_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_forum_slug', 'forum' );
+}
+
+/**
+ * Topic slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_topic_slug() {
+?>
+
+	<input name="_bbp_topic_slug" id="_bbp_topic_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_topic_slug', 'topic', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_topic_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_topic_slug', 'topic' );
+}
+
+/**
+ * Reply slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_reply_slug() {
+?>
+
+	<input name="_bbp_reply_slug" id="_bbp_reply_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_reply_slug', 'reply', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_reply_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_reply_slug', 'reply' );
+}
+
+/**
+ * Topic tag slug setting field
+ *
+ * @since bbPress (r2786)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_topic_tag_slug() {
+?>
+
+	<input name="_bbp_topic_tag_slug" id="_bbp_topic_tag_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_topic_tag_slug', 'topic-tag', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_topic_tag_slug' ); ?> />
+
+<?php
+
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_topic_tag_slug', 'topic-tag' );
+}
+
+/**
+ * View slug setting field
+ *
+ * @since bbPress (r2789)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_view_slug() {
+?>
+
+	<input name="_bbp_view_slug" id="_bbp_view_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_view_slug', 'view', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_view_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_view_slug', 'view' );
+}
+
+/**
+ * Search slug setting field
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_search_slug() {
+?>
+
+	<input name="_bbp_search_slug" id="_bbp_search_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_search_slug', 'search', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_search_slug' ); ?> />
+
+<?php
+	// Slug Check
+	bbp_form_slug_conflict_check( '_bbp_search_slug', 'search' );
+}
+
+/** BuddyPress ****************************************************************/
+
+/**
+ * Extension settings section description for the settings page
+ *
+ * @since bbPress (r3575)
+ */
+function bbp_admin_setting_callback_buddypress_section() {
+?>
+
+	<p><?php esc_html_e( 'Forum settings for BuddyPress', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Allow BuddyPress group forums setting field
+ *
+ * @since bbPress (r3575)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_group_forums() {
+?>
+
+	<input name="_bbp_enable_group_forums" id="_bbp_enable_group_forums" type="checkbox" value="1" <?php checked( bbp_is_group_forums_active( true ) );  bbp_maybe_admin_setting_disabled( '_bbp_enable_group_forums' ); ?> />
+	<label for="_bbp_enable_group_forums"><?php esc_html_e( 'Allow BuddyPress Groups to have their own forums', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Replies per page setting field
+ *
+ * @since bbPress (r3575)
+ *
+ * @uses bbp_form_option() To output the option value
+ */
+function bbp_admin_setting_callback_group_forums_root_id() {
+
+	// Output the dropdown for all forums
+	bbp_dropdown( array(
+		'selected'           => bbp_get_group_forums_root_id(),
+		'show_none'          => __( '&mdash; Forum root &mdash;', 'bbpress' ),
+		'orderby'            => 'title',
+		'order'              => 'ASC',
+		'select_id'          => '_bbp_group_forums_root_id',
+		'disable_categories' => false,
+		'disabled'           => '_bbp_group_forums_root_id'
+	) ); ?>
+
+	<label for="_bbp_group_forums_root_id"><?php esc_html_e( 'is the parent for all group forums', 'bbpress' ); ?></label>
+	<p class="description"><?php esc_html_e( 'Using the Forum Root is not recommended. Changing this does not move existing forums.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/** Akismet *******************************************************************/
+
+/**
+ * Extension settings section description for the settings page
+ *
+ * @since bbPress (r3575)
+ */
+function bbp_admin_setting_callback_akismet_section() {
+?>
+
+	<p><?php esc_html_e( 'Forum settings for Akismet', 'bbpress' ); ?></p>
+
+<?php
+}
+
+
+/**
+ * Allow Akismet setting field
+ *
+ * @since bbPress (r3575)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bbp_admin_setting_callback_akismet() {
+?>
+
+	<input name="_bbp_enable_akismet" id="_bbp_enable_akismet" type="checkbox" value="1" <?php checked( bbp_is_akismet_active( true ) );  bbp_maybe_admin_setting_disabled( '_bbp_enable_akismet' ); ?> />
+	<label for="_bbp_enable_akismet"><?php esc_html_e( 'Allow Akismet to actively prevent forum spam.', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/** Settings Page *************************************************************/
+
+/**
+ * The main settings page
+ *
+ * @since bbPress (r2643)
+ *
+ * @uses screen_icon() To display the screen icon
+ * @uses settings_fields() To output the hidden fields for the form
+ * @uses do_settings_sections() To output the settings sections
+ */
+function bbp_admin_settings() {
+?>
+
+	<div class="wrap">
+
+		<?php screen_icon(); ?>
+
+		<h2><?php esc_html_e( 'Forums Settings', 'bbpress' ) ?></h2>
+
+		<form action="options.php" method="post">
+
+			<?php settings_fields( 'bbpress' ); ?>
+
+			<?php do_settings_sections( 'bbpress' ); ?>
+
+			<p class="submit">
+				<input type="submit" name="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes', 'bbpress' ); ?>" />
+			</p>
+		</form>
+	</div>
+
+<?php
+}
+
+
+/** Converter Section *********************************************************/
+
+/**
+ * Main settings section description for the settings page
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_main_section() {
+?>
+
+	<p><?php _e( 'Information about your previous forums database so that they can be converted. <strong>Backup your database before proceeding.</strong>', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Edit Platform setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_platform() {
+
+	$platform_options = '';
+	$curdir           = opendir( bbpress()->admin->admin_dir . 'converters/' );
+
+	// Bail if no directory was found (how did this happen?)
+	if ( empty( $curdir ) )
+		return;
+
+	// Loop through files in the converters folder and assemble some options
+	while ( $file = readdir( $curdir ) ) {
+		if ( ( stristr( $file, '.php' ) ) && ( stristr( $file, 'index' ) === false ) ) {
+			$file              = preg_replace( '/.php/', '', $file );
+			$platform_options .= '<option value="' . $file . '">' . esc_html( $file ) . '</option>';
+		}
+	}
+
+	closedir( $curdir ); ?>
+
+	<select name="_bbp_converter_platform" id="_bbp_converter_platform" /><?php echo $platform_options ?></select>
+	<label for="_bbp_converter_platform"><?php esc_html_e( 'is the previous forum software', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Edit Database Server setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_dbserver() {
+?>
+
+	<input name="_bbp_converter_db_server" id="_bbp_converter_db_server" type="text" value="<?php bbp_form_option( '_bbp_converter_db_server', 'localhost' ); ?>" class="medium-text" />
+	<label for="_bbp_converter_db_server"><?php esc_html_e( 'IP or hostname', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Edit Database Server Port setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_dbport() {
+?>
+
+	<input name="_bbp_converter_db_port" id="_bbp_converter_db_port" type="text" value="<?php bbp_form_option( '_bbp_converter_db_port', '3306' ); ?>" class="small-text" />
+	<label for="_bbp_converter_db_port"><?php esc_html_e( 'Use default 3306 if unsure', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Edit Database User setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_dbuser() {
+?>
+
+	<input name="_bbp_converter_db_user" id="_bbp_converter_db_user" type="text" value="<?php bbp_form_option( '_bbp_converter_db_user' ); ?>" class="medium-text" />
+	<label for="_bbp_converter_db_user"><?php esc_html_e( 'User for your database connection', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Edit Database Pass setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_dbpass() {
+?>
+
+	<input name="_bbp_converter_db_pass" id="_bbp_converter_db_pass" type="password" value="<?php bbp_form_option( '_bbp_converter_db_pass' ); ?>" class="medium-text" />
+	<label for="_bbp_converter_db_pass"><?php esc_html_e( 'Password to access the database', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Edit Database Name setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_dbname() {
+?>
+
+	<input name="_bbp_converter_db_name" id="_bbp_converter_db_name" type="text" value="<?php bbp_form_option( '_bbp_converter_db_name' ); ?>" class="medium-text" />
+	<label for="_bbp_converter_db_name"><?php esc_html_e( 'Name of the database with your old forum data', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Main settings section description for the settings page
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_options_section() {
+?>
+
+	<p><?php esc_html_e( 'Some optional parameters to help tune the conversion process.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Edit Table Prefix setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_dbprefix() {
+?>
+
+	<input name="_bbp_converter_db_prefix" id="_bbp_converter_db_prefix" type="text" value="<?php bbp_form_option( '_bbp_converter_db_prefix' ); ?>" class="medium-text" />
+	<label for="_bbp_converter_db_prefix"><?php esc_html_e( '(If converting from BuddyPress Forums, use "wp_bb_" or your custom prefix)', 'bbpress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Edit Rows Limit setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_rows() {
+?>
+
+	<input name="_bbp_converter_rows" id="_bbp_converter_rows" type="text" value="<?php bbp_form_option( '_bbp_converter_rows', '100' ); ?>" class="small-text" />
+	<label for="_bbp_converter_rows"><?php esc_html_e( 'rows to process at a time', 'bbpress' ); ?></label>
+	<p class="description"><?php esc_html_e( 'Keep this low if you experience out-of-memory issues.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Edit Delay Time setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_delay_time() {
+?>
+
+	<input name="_bbp_converter_delay_time" id="_bbp_converter_delay_time" type="text" value="<?php bbp_form_option( '_bbp_converter_delay_time', '1' ); ?>" class="small-text" />
+	<label for="_bbp_converter_delay_time"><?php esc_html_e( 'second(s) delay between each group of rows', 'bbpress' ); ?></label>
+	<p class="description"><?php esc_html_e( 'Keep this high to prevent too-many-connection issues.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Edit Restart setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_restart() {
+?>
+
+	<input name="_bbp_converter_restart" id="_bbp_converter_restart" type="checkbox" value="1" <?php checked( get_option( '_bbp_converter_restart', false ) ); ?> />
+	<label for="_bbp_converter_restart"><?php esc_html_e( 'Start a fresh conversion from the beginning', 'bbpress' ); ?></label>
+	<p class="description"><?php esc_html_e( 'You should clean old conversion information before starting over.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Edit Clean setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_clean() {
+?>
+
+	<input name="_bbp_converter_clean" id="_bbp_converter_clean" type="checkbox" value="1" <?php checked( get_option( '_bbp_converter_clean', false ) ); ?> />
+	<label for="_bbp_converter_clean"><?php esc_html_e( 'Purge all information from a previously attempted import', 'bbpress' ); ?></label>
+	<p class="description"><?php esc_html_e( 'Use this if an import failed and you want to remove that incomplete data.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Edit Convert Users setting field
+ *
+ * @since bbPress (r3813)
+ */
+function bbp_converter_setting_callback_convert_users() {
+?>
+
+	<input name="_bbp_converter_convert_users" id="_bbp_converter_convert_users" type="checkbox" value="1" <?php checked( get_option( '_bbp_converter_convert_users', false ) ); ?> />
+	<label for="_bbp_converter_convert_users"><?php esc_html_e( 'Attempt to import user accounts from previous forums', 'bbpress' ); ?></label>
+	<p class="description"><?php esc_html_e( 'Non-bbPress passwords cannot be automatically converted. They will be converted as each user logs in.', 'bbpress' ); ?></p>
+
+<?php
+}
+
+/** Converter Page ************************************************************/
+
+/**
+ * The main settings page
+ *
+ * @uses screen_icon() To display the screen icon
+ * @uses settings_fields() To output the hidden fields for the form
+ * @uses do_settings_sections() To output the settings sections
+ */
+function bbp_converter_settings() {
+?>
+
+	<div class="wrap">
+
+		<?php screen_icon( 'tools' ); ?>
+
+		<h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( esc_html__( 'Import Forums', 'bbpress' ) ); ?></h2>
+
+		<form action="#" method="post" id="bbp-converter-settings">
+
+			<?php settings_fields( 'bbpress_converter' ); ?>
+
+			<?php do_settings_sections( 'bbpress_converter' ); ?>
+
+			<p class="submit">
+				<input type="button" name="submit" class="button-primary" id="bbp-converter-start" value="<?php esc_attr_e( 'Start', 'bbpress' ); ?>" onclick="bbconverter_start();" />
+				<input type="button" name="submit" class="button-primary" id="bbp-converter-stop" value="<?php esc_attr_e( 'Stop', 'bbpress' ); ?>" onclick="bbconverter_stop();" />
+				<img id="bbp-converter-progress" src="">
+			</p>
+
+			<div class="bbp-converter-updated" id="bbp-converter-message"></div>
+		</form>
+	</div>
+
+<?php
+}
+
+/** Helpers *******************************************************************/
+
+/**
+ * Contextual help for Forums settings page
+ *
+ * @since bbPress (r3119)
+ * @uses get_current_screen()
+ */
+function bbp_admin_settings_help() {
+
+	$current_screen = get_current_screen();
+
+	// Bail if current screen could not be found
+	if ( empty( $current_screen ) )
+		return;
+
+	// Overview
+	$current_screen->add_help_tab( array(
+		'id'      => 'overview',
+		'title'   => __( 'Overview', 'bbpress' ),
+		'content' => '<p>' . __( 'This screen provides access to all of the Forums settings.',                          'bbpress' ) . '</p>' .
+					 '<p>' . __( 'Please see the additional help tabs for more information on each indiviual section.', 'bbpress' ) . '</p>'
+	) );
+
+	// Main Settings
+	$current_screen->add_help_tab( array(
+		'id'      => 'main_settings',
+		'title'   => __( 'Main Settings', 'bbpress' ),
+		'content' => '<p>' . __( 'In the Main Settings you have a number of options:', 'bbpress' ) . '</p>' .
+					 '<p>' .
+						'<ul>' .
+							'<li>' . __( 'You can choose to lock a post after a certain number of minutes. "Locking post editing" will prevent the author from editing some amount of time after saving a post.',              'bbpress' ) . '</li>' .
+							'<li>' . __( '"Throttle time" is the amount of time required between posts from a single author. The higher the throttle time, the longer a user will need to wait between posting to the forum.', 'bbpress' ) . '</li>' .
+							'<li>' . __( 'Favorites are a way for users to save and later return to topics they favor. This is enabled by default.',                                                                           'bbpress' ) . '</li>' .
+							'<li>' . __( 'Subscriptions allow users to subscribe for notifications to topics that interest them. This is enabled by default.',                                                                 'bbpress' ) . '</li>' .
+							'<li>' . __( 'Topic-Tags allow users to filter topics between forums. This is enabled by default.',                                                                                                'bbpress' ) . '</li>' .
+							'<li>' . __( '"Anonymous Posting" allows guest users who do not have accounts on your site to both create topics as well as replies.',                                                             'bbpress' ) . '</li>' .
+							'<li>' . __( 'The Fancy Editor brings the luxury of the Visual editor and HTML editor from the traditional WordPress dashboard into your theme.',                                                  'bbpress' ) . '</li>' .
+							'<li>' . __( 'Auto-embed will embed the media content from a URL directly into the replies. For example: links to Flickr and YouTube.',                                                            'bbpress' ) . '</li>' .
+						'</ul>' .
+					'</p>' .
+					'<p>' . __( 'You must click the Save Changes button at the bottom of the screen for new settings to take effect.', 'bbpress' ) . '</p>'
+	) );
+
+	// Per Page
+	$current_screen->add_help_tab( array(
+		'id'      => 'per_page',
+		'title'   => __( 'Per Page', 'bbpress' ),
+		'content' => '<p>' . __( 'Per Page settings allow you to control the number of topics and replies appear on each page.',                                                    'bbpress' ) . '</p>' .
+					 '<p>' . __( 'This is comparable to the WordPress "Reading Settings" page, where you can set the number of posts that should show on blog pages and in feeds.', 'bbpress' ) . '</p>' .
+					 '<p>' . __( 'These are broken up into two separate groups: one for what appears in your theme, another for RSS feeds.',                                        'bbpress' ) . '</p>'
+	) );
+
+	// Slugs
+	$current_screen->add_help_tab( array(
+		'id'      => 'slus',
+		'title'   => __( 'Slugs', 'bbpress' ),
+		'content' => '<p>' . __( 'The Slugs section allows you to control the permalink structure for your forums.',                                                                                                            'bbpress' ) . '</p>' .
+					 '<p>' . __( '"Archive Slugs" are used as the "root" for your forums and topics. If you combine these values with existing page slugs, bbPress will attempt to output the most correct title and content.', 'bbpress' ) . '</p>' .
+					 '<p>' . __( '"Single Slugs" are used as a prefix when viewing an individual forum, topic, reply, user, or view.',                                                                                          'bbpress' ) . '</p>' .
+					 '<p>' . __( 'In the event of a slug collision with WordPress or BuddyPress, a warning will appear next to the problem slug(s).', 'bbpress' ) . '</p>'
+	) );
+
+	// Help Sidebar
+	$current_screen->set_help_sidebar(
+		'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
+		'<p>' . __( '<a href="http://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
+		'<p>' . __( '<a href="http://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
+	);
+}
+
+/**
+ * Disable a settings field if the value is forcibly set in bbPress's global
+ * options array.
+ *
+ * @since bbPress (r4347)
+ *
+ * @param string $option_key
+ */
+function bbp_maybe_admin_setting_disabled( $option_key = '' ) {
+	disabled( isset( bbpress()->options[$option_key] ) );
+}
+
+/**
+ * Output settings API option
+ *
+ * @since bbPress (r3203)
+ *
+ * @uses bbp_get_bbp_form_option()
+ *
+ * @param string $option
+ * @param string $default
+ * @param bool $slug
+ */
+function bbp_form_option( $option, $default = '' , $slug = false ) {
+	echo bbp_get_form_option( $option, $default, $slug );
+}
+	/**
+	 * Return settings API option
+	 *
+	 * @since bbPress (r3203)
+	 *
+	 * @uses get_option()
+	 * @uses esc_attr()
+	 * @uses apply_filters()
+	 *
+	 * @param string $option
+	 * @param string $default
+	 * @param bool $slug
+	 */
+	function bbp_get_form_option( $option, $default = '', $slug = false ) {
+
+		// Get the option and sanitize it
+		$value = get_option( $option, $default );
+
+		// Slug?
+		if ( true === $slug ) {
+			$value = esc_attr( apply_filters( 'editable_slug', $value ) );
+
+		// Not a slug
+		} else {
+			$value = esc_attr( $value );
+		}
+
+		// Fallback to default
+		if ( empty( $value ) )
+			$value = $default;
+
+		// Allow plugins to further filter the output
+		return apply_filters( 'bbp_get_form_option', $value, $option );
+	}
+
+/**
+ * Used to check if a bbPress slug conflicts with an existing known slug.
+ *
+ * @since bbPress (r3306)
+ *
+ * @param string $slug
+ * @param string $default
+ *
+ * @uses bbp_get_form_option() To get a sanitized slug string
+ */
+function bbp_form_slug_conflict_check( $slug, $default ) {
+
+	// Only set the slugs once ver page load
+	static $the_core_slugs = array();
+
+	// Get the form value
+	$this_slug = bbp_get_form_option( $slug, $default, true );
+
+	if ( empty( $the_core_slugs ) ) {
+
+		// Slugs to check
+		$core_slugs = apply_filters( 'bbp_slug_conflict_check', array(
+
+			/** WordPress Core ****************************************************/
+
+			// Core Post Types
+			'post_base'       => array( 'name' => __( 'Posts',         'bbpress' ), 'default' => 'post',          'context' => 'WordPress' ),
+			'page_base'       => array( 'name' => __( 'Pages',         'bbpress' ), 'default' => 'page',          'context' => 'WordPress' ),
+			'revision_base'   => array( 'name' => __( 'Revisions',     'bbpress' ), 'default' => 'revision',      'context' => 'WordPress' ),
+			'attachment_base' => array( 'name' => __( 'Attachments',   'bbpress' ), 'default' => 'attachment',    'context' => 'WordPress' ),
+			'nav_menu_base'   => array( 'name' => __( 'Menus',         'bbpress' ), 'default' => 'nav_menu_item', 'context' => 'WordPress' ),
+
+			// Post Tags
+			'tag_base'        => array( 'name' => __( 'Tag base',      'bbpress' ), 'default' => 'tag',           'context' => 'WordPress' ),
+
+			// Post Categories
+			'category_base'   => array( 'name' => __( 'Category base', 'bbpress' ), 'default' => 'category',      'context' => 'WordPress' ),
+
+			/** bbPress Core ******************************************************/
+
+			// Forum archive slug
+			'_bbp_root_slug'          => array( 'name' => __( 'Forums base', 'bbpress' ), 'default' => 'forums', 'context' => 'bbPress' ),
+
+			// Topic archive slug
+			'_bbp_topic_archive_slug' => array( 'name' => __( 'Topics base', 'bbpress' ), 'default' => 'topics', 'context' => 'bbPress' ),
+
+			// Forum slug
+			'_bbp_forum_slug'         => array( 'name' => __( 'Forum slug',  'bbpress' ), 'default' => 'forum',  'context' => 'bbPress' ),
+
+			// Topic slug
+			'_bbp_topic_slug'         => array( 'name' => __( 'Topic slug',  'bbpress' ), 'default' => 'topic',  'context' => 'bbPress' ),
+
+			// Reply slug
+			'_bbp_reply_slug'         => array( 'name' => __( 'Reply slug',  'bbpress' ), 'default' => 'reply',  'context' => 'bbPress' ),
+
+			// User profile slug
+			'_bbp_user_slug'          => array( 'name' => __( 'User base',   'bbpress' ), 'default' => 'users',  'context' => 'bbPress' ),
+
+			// View slug
+			'_bbp_view_slug'          => array( 'name' => __( 'View base',   'bbpress' ), 'default' => 'view',   'context' => 'bbPress' ),
+
+			// Topic tag slug
+			'_bbp_topic_tag_slug'     => array( 'name' => __( 'Topic tag slug', 'bbpress' ), 'default' => 'topic-tag', 'context' => 'bbPress' ),
+		) );
+
+		/** BuddyPress Core *******************************************************/
+
+		if ( defined( 'BP_VERSION' ) ) {
+			$bp = buddypress();
+
+			// Loop through root slugs and check for conflict
+			if ( !empty( $bp->pages ) ) {
+				foreach ( $bp->pages as $page => $page_data ) {
+					$page_base    = $page . '_base';
+					$page_title   = sprintf( __( '%s page', 'bbpress' ), $page_data->title );
+					$core_slugs[$page_base] = array( 'name' => $page_title, 'default' => $page_data->slug, 'context' => 'BuddyPress' );
+				}
+			}
+		}
+
+		// Set the static
+		$the_core_slugs = apply_filters( 'bbp_slug_conflict', $core_slugs );
+	}
+
+	// Loop through slugs to check
+	foreach ( $the_core_slugs as $key => $value ) {
+
+		// Get the slug
+		$slug_check = bbp_get_form_option( $key, $value['default'], true );
+
+		// Compare
+		if ( ( $slug !== $key ) && ( $slug_check === $this_slug ) ) : ?>
+
+			<span class="attention"><?php printf( esc_html__( 'Possible %1$s conflict: %2$s', 'bbpress' ), $value['context'], '<strong>' . $value['name'] . '</strong>' ); ?></span>
+
+		<?php endif;
+	}
+}
Index: /tags/2.5.4/includes/admin/styles/evergreen-rtl.css
===================================================================
--- /tags/2.5.4/includes/admin/styles/evergreen-rtl.css	(revision 5382)
+++ /tags/2.5.4/includes/admin/styles/evergreen-rtl.css	(revision 5382)
@@ -0,0 +1,168 @@
+/* Dashicons mixin use: @include dashicons( '\f140' ); */
+/* Button mixin- creates 3d-ish button effect with correct  highlights/shadows, based on a base color. */
+html { background: #f2f2f2; }
+
+/* Links */
+a { color: #0074a2; }
+a:hover, a:active, a:focus { color: #0099d5; }
+
+#rightnow a:hover, #media-upload a.del-link:hover, div.dashboard-widget-submit input:hover, .subsubsub a:hover, .subsubsub a.current:hover, .ui-tabs-nav a:hover { color: #0099d5; }
+
+/* Forms */
+input[type=checkbox]:checked:before { color: #56b274; }
+
+input[type=radio]:checked:before { background: #56b274; }
+
+.wp-core-ui input[type="reset"]:hover, .wp-core-ui input[type="reset"]:active { color: #0099d5; }
+
+/* Core UI */
+.wp-core-ui .button-primary { background: #56b274; border-color: #43925d; color: white; -webkit-box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus { background: #469961; border-color: #3b8152; color: white; -webkit-box-shadow: inset 0 1px 0 #79c291, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #79c291, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:active { background: #469961; border-color: #3b8152; color: white; -webkit-box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); }
+.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled { color: #c7d1ca !important; background: #469961 !important; border-color: #3b8152 !important; text-shadow: none !important; }
+.wp-core-ui .wp-ui-primary { color: white; background-color: #446950; }
+.wp-core-ui .wp-ui-text-primary { color: #446950; }
+.wp-core-ui .wp-ui-highlight { color: white; background-color: #56b274; }
+.wp-core-ui .wp-ui-text-highlight { color: #56b274; }
+.wp-core-ui .wp-ui-notification { color: white; background-color: #36b360; }
+.wp-core-ui .wp-ui-text-notification { color: #36b360; }
+.wp-core-ui .wp-ui-text-icon { color: #f1f3f2; }
+
+/* List tables */
+.wrap .add-new-h2:hover, #add-new-comment a:hover, .tablenav .tablenav-pages a:hover, .tablenav .tablenav-pages a:focus { color: white; background-color: #446950; }
+
+.view-switch a.current:before { color: #446950; }
+
+.view-switch a:hover:before { color: #36b360; }
+
+.post-com-count:hover:after { border-top-color: #446950; }
+
+.post-com-count:hover span { color: white; background-color: #446950; }
+
+strong .post-com-count:after { border-top-color: #36b360; }
+
+strong .post-com-count span { background-color: #36b360; }
+
+/* Admin Menu */
+#adminmenuback, #adminmenuwrap, #adminmenu { background: #446950; }
+
+#adminmenu a { color: white; }
+
+#adminmenu div.wp-menu-image:before { color: #f1f3f2; }
+
+#adminmenu a:hover, #adminmenu li.menu-top:hover, #adminmenu li.opensub > a.menu-top, #adminmenu li > a.menu-top:focus { color: white; background-color: #56b274; }
+
+#adminmenu li.menu-top:hover div.wp-menu-image:before, #adminmenu li.opensub > a.menu-top div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: submenu */
+#adminmenu .wp-submenu, #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu .wp-has-current-submenu.opensub .wp-submenu, .folded #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu { background: #36533f; }
+
+#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after { border-left-color: #36533f; }
+
+#adminmenu .wp-submenu .wp-submenu-head { color: #c6d2ca; }
+
+#adminmenu .wp-submenu a, #adminmenu .wp-has-current-submenu .wp-submenu a, .folded #adminmenu .wp-has-current-submenu .wp-submenu a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a { color: #c6d2ca; }
+#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover, #adminmenu .wp-has-current-submenu .wp-submenu a:focus, #adminmenu .wp-has-current-submenu .wp-submenu a:hover, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover { color: #56b274; }
+
+/* Admin Menu: current */
+#adminmenu .wp-submenu li.current a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a { color: white; }
+#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus { color: #56b274; }
+
+ul#adminmenu a.wp-has-current-submenu:after, ul#adminmenu > li.current > a.current:after { border-left-color: #eeeeee; }
+
+#adminmenu li.current a.menu-top, #adminmenu li.wp-has-current-submenu a.wp-has-current-submenu, #adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head, .folded #adminmenu li.current.menu-top { color: white; background: #56b274; }
+
+#adminmenu li.wp-has-current-submenu div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: bubble */
+#adminmenu .awaiting-mod, #adminmenu .update-plugins { color: white; background: #36b360; }
+
+#adminmenu li.current a .awaiting-mod, #adminmenu li a.wp-has-current-submenu .update-plugins, #adminmenu li:hover a .awaiting-mod, #adminmenu li.menu-top:hover > a .update-plugins { color: white; background: #36533f; }
+
+/* Admin Menu: collapse button */
+#collapse-menu { color: #f1f3f2; }
+
+#collapse-menu:hover { color: white; }
+
+#collapse-button div:after { color: #f1f3f2; }
+
+#collapse-menu:hover #collapse-button div:after { color: white; }
+
+/* Admin Bar */
+#wpadminbar { color: white; background: #446950; }
+
+#wpadminbar .ab-item, #wpadminbar a.ab-item, #wpadminbar > #wp-toolbar span.ab-label, #wpadminbar > #wp-toolbar span.noticon { color: white; }
+
+#wpadminbar .ab-icon, #wpadminbar .ab-icon:before, #wpadminbar .ab-item:before, #wpadminbar .ab-item:after { color: #f1f3f2; }
+
+#wpadminbar .ab-top-menu > li:hover > .ab-item, #wpadminbar .ab-top-menu > li.hover > .ab-item, #wpadminbar .ab-top-menu > li > .ab-item:focus, #wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus, #wpadminbar-nojs .ab-top-menu > li.menupop:hover > .ab-item, #wpadminbar .ab-top-menu > li.menupop.hover > .ab-item { color: #56b274; background: #36533f; }
+
+#wpadminbar > #wp-toolbar li:hover span.ab-label, #wpadminbar > #wp-toolbar li.hover span.ab-label, #wpadminbar > #wp-toolbar a:focus span.ab-label { color: #56b274; }
+
+#wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: white; }
+
+/* Admin Bar: submenu */
+#wpadminbar .menupop .ab-sub-wrapper { background: #36533f; }
+
+#wpadminbar .quicklinks .menupop ul.ab-sub-secondary, #wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu { background: #597763; }
+
+#wpadminbar .ab-submenu .ab-item, #wpadminbar .quicklinks .menupop ul li a, #wpadminbar .quicklinks .menupop.hover ul li a, #wpadminbar-nojs .quicklinks .menupop:hover ul li a { color: #c6d2ca; }
+
+#wpadminbar .quicklinks li .blavatar, #wpadminbar .menupop .menupop > .ab-item:before { color: #f1f3f2; }
+
+#wpadminbar .quicklinks .menupop ul li a:hover, #wpadminbar .quicklinks .menupop ul li a:focus, #wpadminbar .quicklinks .menupop ul li a:hover strong, #wpadminbar .quicklinks .menupop ul li a:focus strong, #wpadminbar .quicklinks .menupop.hover ul li a:hover, #wpadminbar .quicklinks .menupop.hover ul li a:focus, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus, #wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li a:focus .ab-icon:before, #wpadminbar li .ab-item:focus:before, #wpadminbar li.hover .ab-icon:before, #wpadminbar li.hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li.hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: #56b274; }
+
+#wpadminbar .quicklinks li a:hover .blavatar, #wpadminbar .menupop .menupop > .ab-item:hover:before { color: #56b274; }
+
+/* Admin Bar: search */
+#wpadminbar #adminbarsearch:before { color: #f1f3f2; }
+
+#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus { color: white; background: #527f61; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-webkit-input-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-ms-input-placeholder { color: white; opacity: .7; }
+
+/* Admin Bar: my account */
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img { border-color: #527f61; background-color: #527f61; }
+
+#wpadminbar #wp-admin-bar-user-info .display-name { color: white; }
+
+#wpadminbar #wp-admin-bar-user-info a:hover .display-name { color: #56b274; }
+
+#wpadminbar #wp-admin-bar-user-info .username { color: #c6d2ca; }
+
+/* Pointers */
+.wp-pointer .wp-pointer-content h3 { background-color: #56b274; }
+
+.wp-pointer.wp-pointer-top .wp-pointer-arrow, .wp-pointer.wp-pointer-undefined .wp-pointer-arrow { border-bottom-color: #56b274; }
+
+/* Media Uploader */
+.media-item .bar, .media-progress-bar div { background-color: #56b274; }
+
+.details.attachment { box-shadow: 0 0 0 1px white, 0 0 0 5px #56b274; }
+
+.attachment.details .check { background-color: #56b274; box-shadow: 0 0 0 1px white, 0 0 0 2px #56b274; }
+
+/* Themes */
+.theme-browser .theme.active .theme-name, .theme-browser .theme.add-new-theme:hover:after { background: #56b274; }
+
+.theme-browser .theme.add-new-theme:hover span:after { color: #56b274; }
+
+.theme-overlay .theme-header .close:hover, .theme-overlay .theme-header .right:hover, .theme-overlay .theme-header .left:hover { background: #56b274; }
+
+/* jQuery UI Slider */
+.wp-slider .ui-slider-handle, .wp-slider .ui-slider-handle.ui-state-hover, .wp-slider .ui-slider-handle.focus { background: #56b274; border-color: #43925d; -webkit-box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); }
+
+/* Responsive Component */
+div#wp-responsive-toggle a:before { color: #f1f3f2; }
+
+.wp-responsive-open div#wp-responsive-toggle a { border-color: transparent; background: #56b274; }
+
+.star-rating .star { color: #56b274; }
+
+.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a { background: #36533f; }
Index: /tags/2.5.4/includes/admin/styles/evergreen.css
===================================================================
--- /tags/2.5.4/includes/admin/styles/evergreen.css	(revision 5382)
+++ /tags/2.5.4/includes/admin/styles/evergreen.css	(revision 5382)
@@ -0,0 +1,168 @@
+/* Dashicons mixin use: @include dashicons( '\f140' ); */
+/* Button mixin- creates 3d-ish button effect with correct  highlights/shadows, based on a base color. */
+html { background: #f2f2f2; }
+
+/* Links */
+a { color: #0074a2; }
+a:hover, a:active, a:focus { color: #0099d5; }
+
+#rightnow a:hover, #media-upload a.del-link:hover, div.dashboard-widget-submit input:hover, .subsubsub a:hover, .subsubsub a.current:hover, .ui-tabs-nav a:hover { color: #0099d5; }
+
+/* Forms */
+input[type=checkbox]:checked:before { color: #56b274; }
+
+input[type=radio]:checked:before { background: #56b274; }
+
+.wp-core-ui input[type="reset"]:hover, .wp-core-ui input[type="reset"]:active { color: #0099d5; }
+
+/* Core UI */
+.wp-core-ui .button-primary { background: #56b274; border-color: #43925d; color: white; -webkit-box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus { background: #469961; border-color: #3b8152; color: white; -webkit-box-shadow: inset 0 1px 0 #79c291, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #79c291, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:active { background: #469961; border-color: #3b8152; color: white; -webkit-box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); }
+.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled { color: #c7d1ca !important; background: #469961 !important; border-color: #3b8152 !important; text-shadow: none !important; }
+.wp-core-ui .wp-ui-primary { color: white; background-color: #446950; }
+.wp-core-ui .wp-ui-text-primary { color: #446950; }
+.wp-core-ui .wp-ui-highlight { color: white; background-color: #56b274; }
+.wp-core-ui .wp-ui-text-highlight { color: #56b274; }
+.wp-core-ui .wp-ui-notification { color: white; background-color: #36b360; }
+.wp-core-ui .wp-ui-text-notification { color: #36b360; }
+.wp-core-ui .wp-ui-text-icon { color: #f1f3f2; }
+
+/* List tables */
+.wrap .add-new-h2:hover, #add-new-comment a:hover, .tablenav .tablenav-pages a:hover, .tablenav .tablenav-pages a:focus { color: white; background-color: #446950; }
+
+.view-switch a.current:before { color: #446950; }
+
+.view-switch a:hover:before { color: #36b360; }
+
+.post-com-count:hover:after { border-top-color: #446950; }
+
+.post-com-count:hover span { color: white; background-color: #446950; }
+
+strong .post-com-count:after { border-top-color: #36b360; }
+
+strong .post-com-count span { background-color: #36b360; }
+
+/* Admin Menu */
+#adminmenuback, #adminmenuwrap, #adminmenu { background: #446950; }
+
+#adminmenu a { color: white; }
+
+#adminmenu div.wp-menu-image:before { color: #f1f3f2; }
+
+#adminmenu a:hover, #adminmenu li.menu-top:hover, #adminmenu li.opensub > a.menu-top, #adminmenu li > a.menu-top:focus { color: white; background-color: #56b274; }
+
+#adminmenu li.menu-top:hover div.wp-menu-image:before, #adminmenu li.opensub > a.menu-top div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: submenu */
+#adminmenu .wp-submenu, #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu .wp-has-current-submenu.opensub .wp-submenu, .folded #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu { background: #36533f; }
+
+#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after { border-right-color: #36533f; }
+
+#adminmenu .wp-submenu .wp-submenu-head { color: #c6d2ca; }
+
+#adminmenu .wp-submenu a, #adminmenu .wp-has-current-submenu .wp-submenu a, .folded #adminmenu .wp-has-current-submenu .wp-submenu a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a { color: #c6d2ca; }
+#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover, #adminmenu .wp-has-current-submenu .wp-submenu a:focus, #adminmenu .wp-has-current-submenu .wp-submenu a:hover, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover { color: #56b274; }
+
+/* Admin Menu: current */
+#adminmenu .wp-submenu li.current a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a { color: white; }
+#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus { color: #56b274; }
+
+ul#adminmenu a.wp-has-current-submenu:after, ul#adminmenu > li.current > a.current:after { border-right-color: #eeeeee; }
+
+#adminmenu li.current a.menu-top, #adminmenu li.wp-has-current-submenu a.wp-has-current-submenu, #adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head, .folded #adminmenu li.current.menu-top { color: white; background: #56b274; }
+
+#adminmenu li.wp-has-current-submenu div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: bubble */
+#adminmenu .awaiting-mod, #adminmenu .update-plugins { color: white; background: #36b360; }
+
+#adminmenu li.current a .awaiting-mod, #adminmenu li a.wp-has-current-submenu .update-plugins, #adminmenu li:hover a .awaiting-mod, #adminmenu li.menu-top:hover > a .update-plugins { color: white; background: #36533f; }
+
+/* Admin Menu: collapse button */
+#collapse-menu { color: #f1f3f2; }
+
+#collapse-menu:hover { color: white; }
+
+#collapse-button div:after { color: #f1f3f2; }
+
+#collapse-menu:hover #collapse-button div:after { color: white; }
+
+/* Admin Bar */
+#wpadminbar { color: white; background: #446950; }
+
+#wpadminbar .ab-item, #wpadminbar a.ab-item, #wpadminbar > #wp-toolbar span.ab-label, #wpadminbar > #wp-toolbar span.noticon { color: white; }
+
+#wpadminbar .ab-icon, #wpadminbar .ab-icon:before, #wpadminbar .ab-item:before, #wpadminbar .ab-item:after { color: #f1f3f2; }
+
+#wpadminbar .ab-top-menu > li:hover > .ab-item, #wpadminbar .ab-top-menu > li.hover > .ab-item, #wpadminbar .ab-top-menu > li > .ab-item:focus, #wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus, #wpadminbar-nojs .ab-top-menu > li.menupop:hover > .ab-item, #wpadminbar .ab-top-menu > li.menupop.hover > .ab-item { color: #56b274; background: #36533f; }
+
+#wpadminbar > #wp-toolbar li:hover span.ab-label, #wpadminbar > #wp-toolbar li.hover span.ab-label, #wpadminbar > #wp-toolbar a:focus span.ab-label { color: #56b274; }
+
+#wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: white; }
+
+/* Admin Bar: submenu */
+#wpadminbar .menupop .ab-sub-wrapper { background: #36533f; }
+
+#wpadminbar .quicklinks .menupop ul.ab-sub-secondary, #wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu { background: #597763; }
+
+#wpadminbar .ab-submenu .ab-item, #wpadminbar .quicklinks .menupop ul li a, #wpadminbar .quicklinks .menupop.hover ul li a, #wpadminbar-nojs .quicklinks .menupop:hover ul li a { color: #c6d2ca; }
+
+#wpadminbar .quicklinks li .blavatar, #wpadminbar .menupop .menupop > .ab-item:before { color: #f1f3f2; }
+
+#wpadminbar .quicklinks .menupop ul li a:hover, #wpadminbar .quicklinks .menupop ul li a:focus, #wpadminbar .quicklinks .menupop ul li a:hover strong, #wpadminbar .quicklinks .menupop ul li a:focus strong, #wpadminbar .quicklinks .menupop.hover ul li a:hover, #wpadminbar .quicklinks .menupop.hover ul li a:focus, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus, #wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li a:focus .ab-icon:before, #wpadminbar li .ab-item:focus:before, #wpadminbar li.hover .ab-icon:before, #wpadminbar li.hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li.hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: #56b274; }
+
+#wpadminbar .quicklinks li a:hover .blavatar, #wpadminbar .menupop .menupop > .ab-item:hover:before { color: #56b274; }
+
+/* Admin Bar: search */
+#wpadminbar #adminbarsearch:before { color: #f1f3f2; }
+
+#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus { color: white; background: #527f61; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-webkit-input-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-ms-input-placeholder { color: white; opacity: .7; }
+
+/* Admin Bar: my account */
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img { border-color: #527f61; background-color: #527f61; }
+
+#wpadminbar #wp-admin-bar-user-info .display-name { color: white; }
+
+#wpadminbar #wp-admin-bar-user-info a:hover .display-name { color: #56b274; }
+
+#wpadminbar #wp-admin-bar-user-info .username { color: #c6d2ca; }
+
+/* Pointers */
+.wp-pointer .wp-pointer-content h3 { background-color: #56b274; }
+
+.wp-pointer.wp-pointer-top .wp-pointer-arrow, .wp-pointer.wp-pointer-undefined .wp-pointer-arrow { border-bottom-color: #56b274; }
+
+/* Media Uploader */
+.media-item .bar, .media-progress-bar div { background-color: #56b274; }
+
+.details.attachment { box-shadow: 0 0 0 1px white, 0 0 0 5px #56b274; }
+
+.attachment.details .check { background-color: #56b274; box-shadow: 0 0 0 1px white, 0 0 0 2px #56b274; }
+
+/* Themes */
+.theme-browser .theme.active .theme-name, .theme-browser .theme.add-new-theme:hover:after { background: #56b274; }
+
+.theme-browser .theme.add-new-theme:hover span:after { color: #56b274; }
+
+.theme-overlay .theme-header .close:hover, .theme-overlay .theme-header .right:hover, .theme-overlay .theme-header .left:hover { background: #56b274; }
+
+/* jQuery UI Slider */
+.wp-slider .ui-slider-handle, .wp-slider .ui-slider-handle.ui-state-hover, .wp-slider .ui-slider-handle.focus { background: #56b274; border-color: #43925d; -webkit-box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #8bca9f, 0 1px 0 rgba(0, 0, 0, 0.15); }
+
+/* Responsive Component */
+div#wp-responsive-toggle a:before { color: #f1f3f2; }
+
+.wp-responsive-open div#wp-responsive-toggle a { border-color: transparent; background: #56b274; }
+
+.star-rating .star { color: #56b274; }
+
+.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a { background: #36533f; }
Index: /tags/2.5.4/includes/admin/styles/index.php
===================================================================
--- /tags/2.5.4/includes/admin/styles/index.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/styles/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/admin/styles/mint-rtl.css
===================================================================
--- /tags/2.5.4/includes/admin/styles/mint-rtl.css	(revision 5382)
+++ /tags/2.5.4/includes/admin/styles/mint-rtl.css	(revision 5382)
@@ -0,0 +1,168 @@
+/* Dashicons mixin use: @include dashicons( '\f140' ); */
+/* Button mixin- creates 3d-ish button effect with correct  highlights/shadows, based on a base color. */
+html { background: #f2f2f2; }
+
+/* Links */
+a { color: #0074a2; }
+a:hover, a:active, a:focus { color: #0099d5; }
+
+#rightnow a:hover, #media-upload a.del-link:hover, div.dashboard-widget-submit input:hover, .subsubsub a:hover, .subsubsub a.current:hover, .ui-tabs-nav a:hover { color: #0099d5; }
+
+/* Forms */
+input[type=checkbox]:checked:before { color: #4f6d59; }
+
+input[type=radio]:checked:before { background: #4f6d59; }
+
+.wp-core-ui input[type="reset"]:hover, .wp-core-ui input[type="reset"]:active { color: #0099d5; }
+
+/* Core UI */
+.wp-core-ui .button-primary { background: #4f6d59; border-color: #3a4f41; color: white; -webkit-box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus { background: #3e5546; border-color: #2f4035; color: white; -webkit-box-shadow: inset 0 1px 0 #658a71, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #658a71, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:active { background: #3e5546; border-color: #2f4035; color: white; -webkit-box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); }
+.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled { color: #c7d1ca !important; background: #3e5546 !important; border-color: #2f4035 !important; text-shadow: none !important; }
+.wp-core-ui .wp-ui-primary { color: white; background-color: #5fb37c; }
+.wp-core-ui .wp-ui-text-primary { color: #5fb37c; }
+.wp-core-ui .wp-ui-highlight { color: white; background-color: #4f6d59; }
+.wp-core-ui .wp-ui-text-highlight { color: #4f6d59; }
+.wp-core-ui .wp-ui-notification { color: white; background-color: #33834e; }
+.wp-core-ui .wp-ui-text-notification { color: #33834e; }
+.wp-core-ui .wp-ui-text-icon { color: #f1f3f2; }
+
+/* List tables */
+.wrap .add-new-h2:hover, #add-new-comment a:hover, .tablenav .tablenav-pages a:hover, .tablenav .tablenav-pages a:focus { color: white; background-color: #5fb37c; }
+
+.view-switch a.current:before { color: #5fb37c; }
+
+.view-switch a:hover:before { color: #33834e; }
+
+.post-com-count:hover:after { border-top-color: #5fb37c; }
+
+.post-com-count:hover span { color: white; background-color: #5fb37c; }
+
+strong .post-com-count:after { border-top-color: #33834e; }
+
+strong .post-com-count span { background-color: #33834e; }
+
+/* Admin Menu */
+#adminmenuback, #adminmenuwrap, #adminmenu { background: #5fb37c; }
+
+#adminmenu a { color: white; }
+
+#adminmenu div.wp-menu-image:before { color: #f1f3f2; }
+
+#adminmenu a:hover, #adminmenu li.menu-top:hover, #adminmenu li.opensub > a.menu-top, #adminmenu li > a.menu-top:focus { color: white; background-color: #4f6d59; }
+
+#adminmenu li.menu-top:hover div.wp-menu-image:before, #adminmenu li.opensub > a.menu-top div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: submenu */
+#adminmenu .wp-submenu, #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu .wp-has-current-submenu.opensub .wp-submenu, .folded #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu { background: #4ca26a; }
+
+#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after { border-left-color: #4ca26a; }
+
+#adminmenu .wp-submenu .wp-submenu-head { color: #cfe8d7; }
+
+#adminmenu .wp-submenu a, #adminmenu .wp-has-current-submenu .wp-submenu a, .folded #adminmenu .wp-has-current-submenu .wp-submenu a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a { color: #cfe8d7; }
+#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover, #adminmenu .wp-has-current-submenu .wp-submenu a:focus, #adminmenu .wp-has-current-submenu .wp-submenu a:hover, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover { color: #4f6d59; }
+
+/* Admin Menu: current */
+#adminmenu .wp-submenu li.current a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a { color: white; }
+#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus { color: #4f6d59; }
+
+ul#adminmenu a.wp-has-current-submenu:after, ul#adminmenu > li.current > a.current:after { border-left-color: #eeeeee; }
+
+#adminmenu li.current a.menu-top, #adminmenu li.wp-has-current-submenu a.wp-has-current-submenu, #adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head, .folded #adminmenu li.current.menu-top { color: white; background: #4f6d59; }
+
+#adminmenu li.wp-has-current-submenu div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: bubble */
+#adminmenu .awaiting-mod, #adminmenu .update-plugins { color: white; background: #33834e; }
+
+#adminmenu li.current a .awaiting-mod, #adminmenu li a.wp-has-current-submenu .update-plugins, #adminmenu li:hover a .awaiting-mod, #adminmenu li.menu-top:hover > a .update-plugins { color: white; background: #4ca26a; }
+
+/* Admin Menu: collapse button */
+#collapse-menu { color: #f1f3f2; }
+
+#collapse-menu:hover { color: white; }
+
+#collapse-button div:after { color: #f1f3f2; }
+
+#collapse-menu:hover #collapse-button div:after { color: white; }
+
+/* Admin Bar */
+#wpadminbar { color: white; background: #5fb37c; }
+
+#wpadminbar .ab-item, #wpadminbar a.ab-item, #wpadminbar > #wp-toolbar span.ab-label, #wpadminbar > #wp-toolbar span.noticon { color: white; }
+
+#wpadminbar .ab-icon, #wpadminbar .ab-icon:before, #wpadminbar .ab-item:before, #wpadminbar .ab-item:after { color: #f1f3f2; }
+
+#wpadminbar .ab-top-menu > li:hover > .ab-item, #wpadminbar .ab-top-menu > li.hover > .ab-item, #wpadminbar .ab-top-menu > li > .ab-item:focus, #wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus, #wpadminbar-nojs .ab-top-menu > li.menupop:hover > .ab-item, #wpadminbar .ab-top-menu > li.menupop.hover > .ab-item { color: #4f6d59; background: #4ca26a; }
+
+#wpadminbar > #wp-toolbar li:hover span.ab-label, #wpadminbar > #wp-toolbar li.hover span.ab-label, #wpadminbar > #wp-toolbar a:focus span.ab-label { color: #4f6d59; }
+
+#wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: white; }
+
+/* Admin Bar: submenu */
+#wpadminbar .menupop .ab-sub-wrapper { background: #4ca26a; }
+
+#wpadminbar .quicklinks .menupop ul.ab-sub-secondary, #wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu { background: #7eb892; }
+
+#wpadminbar .ab-submenu .ab-item, #wpadminbar .quicklinks .menupop ul li a, #wpadminbar .quicklinks .menupop.hover ul li a, #wpadminbar-nojs .quicklinks .menupop:hover ul li a { color: #cfe8d7; }
+
+#wpadminbar .quicklinks li .blavatar, #wpadminbar .menupop .menupop > .ab-item:before { color: #f1f3f2; }
+
+#wpadminbar .quicklinks .menupop ul li a:hover, #wpadminbar .quicklinks .menupop ul li a:focus, #wpadminbar .quicklinks .menupop ul li a:hover strong, #wpadminbar .quicklinks .menupop ul li a:focus strong, #wpadminbar .quicklinks .menupop.hover ul li a:hover, #wpadminbar .quicklinks .menupop.hover ul li a:focus, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus, #wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li a:focus .ab-icon:before, #wpadminbar li .ab-item:focus:before, #wpadminbar li.hover .ab-icon:before, #wpadminbar li.hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li.hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: #4f6d59; }
+
+#wpadminbar .quicklinks li a:hover .blavatar, #wpadminbar .menupop .menupop > .ab-item:hover:before { color: #4f6d59; }
+
+/* Admin Bar: search */
+#wpadminbar #adminbarsearch:before { color: #f1f3f2; }
+
+#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus { color: white; background: #77bf8f; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-webkit-input-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-ms-input-placeholder { color: white; opacity: .7; }
+
+/* Admin Bar: my account */
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img { border-color: #77bf8f; background-color: #77bf8f; }
+
+#wpadminbar #wp-admin-bar-user-info .display-name { color: white; }
+
+#wpadminbar #wp-admin-bar-user-info a:hover .display-name { color: #4f6d59; }
+
+#wpadminbar #wp-admin-bar-user-info .username { color: #cfe8d7; }
+
+/* Pointers */
+.wp-pointer .wp-pointer-content h3 { background-color: #4f6d59; }
+
+.wp-pointer.wp-pointer-top .wp-pointer-arrow, .wp-pointer.wp-pointer-undefined .wp-pointer-arrow { border-bottom-color: #4f6d59; }
+
+/* Media Uploader */
+.media-item .bar, .media-progress-bar div { background-color: #4f6d59; }
+
+.details.attachment { box-shadow: 0 0 0 1px white, 0 0 0 5px #4f6d59; }
+
+.attachment.details .check { background-color: #4f6d59; box-shadow: 0 0 0 1px white, 0 0 0 2px #4f6d59; }
+
+/* Themes */
+.theme-browser .theme.active .theme-name, .theme-browser .theme.add-new-theme:hover:after { background: #4f6d59; }
+
+.theme-browser .theme.add-new-theme:hover span:after { color: #4f6d59; }
+
+.theme-overlay .theme-header .close:hover, .theme-overlay .theme-header .right:hover, .theme-overlay .theme-header .left:hover { background: #4f6d59; }
+
+/* jQuery UI Slider */
+.wp-slider .ui-slider-handle, .wp-slider .ui-slider-handle.ui-state-hover, .wp-slider .ui-slider-handle.focus { background: #4f6d59; border-color: #3a4f41; -webkit-box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); }
+
+/* Responsive Component */
+div#wp-responsive-toggle a:before { color: #f1f3f2; }
+
+.wp-responsive-open div#wp-responsive-toggle a { border-color: transparent; background: #4f6d59; }
+
+.star-rating .star { color: #4f6d59; }
+
+.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a { background: #4ca26a; }
Index: /tags/2.5.4/includes/admin/styles/mint.css
===================================================================
--- /tags/2.5.4/includes/admin/styles/mint.css	(revision 5382)
+++ /tags/2.5.4/includes/admin/styles/mint.css	(revision 5382)
@@ -0,0 +1,168 @@
+/* Dashicons mixin use: @include dashicons( '\f140' ); */
+/* Button mixin- creates 3d-ish button effect with correct  highlights/shadows, based on a base color. */
+html { background: #f2f2f2; }
+
+/* Links */
+a { color: #0074a2; }
+a:hover, a:active, a:focus { color: #0099d5; }
+
+#rightnow a:hover, #media-upload a.del-link:hover, div.dashboard-widget-submit input:hover, .subsubsub a:hover, .subsubsub a.current:hover, .ui-tabs-nav a:hover { color: #0099d5; }
+
+/* Forms */
+input[type=checkbox]:checked:before { color: #4f6d59; }
+
+input[type=radio]:checked:before { background: #4f6d59; }
+
+.wp-core-ui input[type="reset"]:hover, .wp-core-ui input[type="reset"]:active { color: #0099d5; }
+
+/* Core UI */
+.wp-core-ui .button-primary { background: #4f6d59; border-color: #3a4f41; color: white; -webkit-box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus { background: #3e5546; border-color: #2f4035; color: white; -webkit-box-shadow: inset 0 1px 0 #658a71, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #658a71, 0 1px 0 rgba(0, 0, 0, 0.15); }
+.wp-core-ui .button-primary:active { background: #3e5546; border-color: #2f4035; color: white; -webkit-box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); }
+.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled { color: #c7d1ca !important; background: #3e5546 !important; border-color: #2f4035 !important; text-shadow: none !important; }
+.wp-core-ui .wp-ui-primary { color: white; background-color: #5fb37c; }
+.wp-core-ui .wp-ui-text-primary { color: #5fb37c; }
+.wp-core-ui .wp-ui-highlight { color: white; background-color: #4f6d59; }
+.wp-core-ui .wp-ui-text-highlight { color: #4f6d59; }
+.wp-core-ui .wp-ui-notification { color: white; background-color: #33834e; }
+.wp-core-ui .wp-ui-text-notification { color: #33834e; }
+.wp-core-ui .wp-ui-text-icon { color: #f1f3f2; }
+
+/* List tables */
+.wrap .add-new-h2:hover, #add-new-comment a:hover, .tablenav .tablenav-pages a:hover, .tablenav .tablenav-pages a:focus { color: white; background-color: #5fb37c; }
+
+.view-switch a.current:before { color: #5fb37c; }
+
+.view-switch a:hover:before { color: #33834e; }
+
+.post-com-count:hover:after { border-top-color: #5fb37c; }
+
+.post-com-count:hover span { color: white; background-color: #5fb37c; }
+
+strong .post-com-count:after { border-top-color: #33834e; }
+
+strong .post-com-count span { background-color: #33834e; }
+
+/* Admin Menu */
+#adminmenuback, #adminmenuwrap, #adminmenu { background: #5fb37c; }
+
+#adminmenu a { color: white; }
+
+#adminmenu div.wp-menu-image:before { color: #f1f3f2; }
+
+#adminmenu a:hover, #adminmenu li.menu-top:hover, #adminmenu li.opensub > a.menu-top, #adminmenu li > a.menu-top:focus { color: white; background-color: #4f6d59; }
+
+#adminmenu li.menu-top:hover div.wp-menu-image:before, #adminmenu li.opensub > a.menu-top div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: submenu */
+#adminmenu .wp-submenu, #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu .wp-has-current-submenu.opensub .wp-submenu, .folded #adminmenu .wp-has-current-submenu .wp-submenu, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu { background: #4ca26a; }
+
+#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after { border-right-color: #4ca26a; }
+
+#adminmenu .wp-submenu .wp-submenu-head { color: #cfe8d7; }
+
+#adminmenu .wp-submenu a, #adminmenu .wp-has-current-submenu .wp-submenu a, .folded #adminmenu .wp-has-current-submenu .wp-submenu a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a { color: #cfe8d7; }
+#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover, #adminmenu .wp-has-current-submenu .wp-submenu a:focus, #adminmenu .wp-has-current-submenu .wp-submenu a:hover, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus, .folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover { color: #4f6d59; }
+
+/* Admin Menu: current */
+#adminmenu .wp-submenu li.current a, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a { color: white; }
+#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover, #adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover, #adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus { color: #4f6d59; }
+
+ul#adminmenu a.wp-has-current-submenu:after, ul#adminmenu > li.current > a.current:after { border-right-color: #eeeeee; }
+
+#adminmenu li.current a.menu-top, #adminmenu li.wp-has-current-submenu a.wp-has-current-submenu, #adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head, .folded #adminmenu li.current.menu-top { color: white; background: #4f6d59; }
+
+#adminmenu li.wp-has-current-submenu div.wp-menu-image:before { color: white; }
+
+/* Admin Menu: bubble */
+#adminmenu .awaiting-mod, #adminmenu .update-plugins { color: white; background: #33834e; }
+
+#adminmenu li.current a .awaiting-mod, #adminmenu li a.wp-has-current-submenu .update-plugins, #adminmenu li:hover a .awaiting-mod, #adminmenu li.menu-top:hover > a .update-plugins { color: white; background: #4ca26a; }
+
+/* Admin Menu: collapse button */
+#collapse-menu { color: #f1f3f2; }
+
+#collapse-menu:hover { color: white; }
+
+#collapse-button div:after { color: #f1f3f2; }
+
+#collapse-menu:hover #collapse-button div:after { color: white; }
+
+/* Admin Bar */
+#wpadminbar { color: white; background: #5fb37c; }
+
+#wpadminbar .ab-item, #wpadminbar a.ab-item, #wpadminbar > #wp-toolbar span.ab-label, #wpadminbar > #wp-toolbar span.noticon { color: white; }
+
+#wpadminbar .ab-icon, #wpadminbar .ab-icon:before, #wpadminbar .ab-item:before, #wpadminbar .ab-item:after { color: #f1f3f2; }
+
+#wpadminbar .ab-top-menu > li:hover > .ab-item, #wpadminbar .ab-top-menu > li.hover > .ab-item, #wpadminbar .ab-top-menu > li > .ab-item:focus, #wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus, #wpadminbar-nojs .ab-top-menu > li.menupop:hover > .ab-item, #wpadminbar .ab-top-menu > li.menupop.hover > .ab-item { color: #4f6d59; background: #4ca26a; }
+
+#wpadminbar > #wp-toolbar li:hover span.ab-label, #wpadminbar > #wp-toolbar li.hover span.ab-label, #wpadminbar > #wp-toolbar a:focus span.ab-label { color: #4f6d59; }
+
+#wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: white; }
+
+/* Admin Bar: submenu */
+#wpadminbar .menupop .ab-sub-wrapper { background: #4ca26a; }
+
+#wpadminbar .quicklinks .menupop ul.ab-sub-secondary, #wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu { background: #7eb892; }
+
+#wpadminbar .ab-submenu .ab-item, #wpadminbar .quicklinks .menupop ul li a, #wpadminbar .quicklinks .menupop.hover ul li a, #wpadminbar-nojs .quicklinks .menupop:hover ul li a { color: #cfe8d7; }
+
+#wpadminbar .quicklinks li .blavatar, #wpadminbar .menupop .menupop > .ab-item:before { color: #f1f3f2; }
+
+#wpadminbar .quicklinks .menupop ul li a:hover, #wpadminbar .quicklinks .menupop ul li a:focus, #wpadminbar .quicklinks .menupop ul li a:hover strong, #wpadminbar .quicklinks .menupop ul li a:focus strong, #wpadminbar .quicklinks .menupop.hover ul li a:hover, #wpadminbar .quicklinks .menupop.hover ul li a:focus, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover, #wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus, #wpadminbar li:hover .ab-icon:before, #wpadminbar li:hover .ab-item:before, #wpadminbar li a:focus .ab-icon:before, #wpadminbar li .ab-item:focus:before, #wpadminbar li.hover .ab-icon:before, #wpadminbar li.hover .ab-item:before, #wpadminbar li:hover .ab-item:after, #wpadminbar li.hover .ab-item:after, #wpadminbar li:hover #adminbarsearch:before { color: #4f6d59; }
+
+#wpadminbar .quicklinks li a:hover .blavatar, #wpadminbar .menupop .menupop > .ab-item:hover:before { color: #4f6d59; }
+
+/* Admin Bar: search */
+#wpadminbar #adminbarsearch:before { color: #f1f3f2; }
+
+#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus { color: white; background: #77bf8f; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-webkit-input-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input::-moz-placeholder { color: white; opacity: .7; }
+
+#wpadminbar #adminbarsearch .adminbar-input:-ms-input-placeholder { color: white; opacity: .7; }
+
+/* Admin Bar: my account */
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img { border-color: #77bf8f; background-color: #77bf8f; }
+
+#wpadminbar #wp-admin-bar-user-info .display-name { color: white; }
+
+#wpadminbar #wp-admin-bar-user-info a:hover .display-name { color: #4f6d59; }
+
+#wpadminbar #wp-admin-bar-user-info .username { color: #cfe8d7; }
+
+/* Pointers */
+.wp-pointer .wp-pointer-content h3 { background-color: #4f6d59; }
+
+.wp-pointer.wp-pointer-top .wp-pointer-arrow, .wp-pointer.wp-pointer-undefined .wp-pointer-arrow { border-bottom-color: #4f6d59; }
+
+/* Media Uploader */
+.media-item .bar, .media-progress-bar div { background-color: #4f6d59; }
+
+.details.attachment { box-shadow: 0 0 0 1px white, 0 0 0 5px #4f6d59; }
+
+.attachment.details .check { background-color: #4f6d59; box-shadow: 0 0 0 1px white, 0 0 0 2px #4f6d59; }
+
+/* Themes */
+.theme-browser .theme.active .theme-name, .theme-browser .theme.add-new-theme:hover:after { background: #4f6d59; }
+
+.theme-browser .theme.add-new-theme:hover span:after { color: #4f6d59; }
+
+.theme-overlay .theme-header .close:hover, .theme-overlay .theme-header .right:hover, .theme-overlay .theme-header .left:hover { background: #4f6d59; }
+
+/* jQuery UI Slider */
+.wp-slider .ui-slider-handle, .wp-slider .ui-slider-handle.ui-state-hover, .wp-slider .ui-slider-handle.focus { background: #4f6d59; border-color: #3a4f41; -webkit-box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 1px 0 #71977e, 0 1px 0 rgba(0, 0, 0, 0.15); }
+
+/* Responsive Component */
+div#wp-responsive-toggle a:before { color: #f1f3f2; }
+
+.wp-responsive-open div#wp-responsive-toggle a { border-color: transparent; background: #4f6d59; }
+
+.star-rating .star { color: #4f6d59; }
+
+.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a { background: #4ca26a; }
Index: /tags/2.5.4/includes/admin/tools.php
===================================================================
--- /tags/2.5.4/includes/admin/tools.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/tools.php	(revision 5382)
@@ -0,0 +1,1383 @@
+<?php
+
+/**
+ * bbPress Admin Tools Page
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Repair ********************************************************************/
+
+/**
+ * Admin repair page
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses bbp_admin_repair_list() To get the recount list
+ * @uses check_admin_referer() To verify the nonce and the referer
+ * @uses wp_cache_flush() To flush the cache
+ * @uses do_action() Calls 'admin_notices' to display the notices
+ * @uses screen_icon() To display the screen icon
+ * @uses wp_nonce_field() To add a hidden nonce field
+ */
+function bbp_admin_repair() {
+?>
+
+	<div class="wrap">
+
+		<?php screen_icon( 'tools' ); ?>
+
+		<h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( __( 'Repair Forums', 'bbpress' ) ); ?></h2>
+
+		<p><?php esc_html_e( 'bbPress keeps track of relationships between forums, topics, replies, and topic tags, and users. Occasionally these relationships become out of sync, most often after an import or migration. Use the tools below to manually recalculate these relationships.', 'bbpress' ); ?></p>
+		<p class="description"><?php esc_html_e( 'Some of these tools create substantial database overhead. Avoid running more than 1 repair job at a time.', 'bbpress' ); ?></p>
+
+		<form class="settings" method="post" action="">
+			<table class="form-table">
+				<tbody>
+					<tr valign="top">
+						<th scope="row"><?php esc_html_e( 'Relationships to Repair:', 'bbpress' ) ?></th>
+						<td>
+							<fieldset>
+								<legend class="screen-reader-text"><span><?php esc_html_e( 'Repair', 'bbpress' ) ?></span></legend>
+
+								<?php foreach ( bbp_admin_repair_list() as $item ) : ?>
+
+									<label><input type="checkbox" class="checkbox" name="<?php echo esc_attr( $item[0] ) . '" id="' . esc_attr( str_replace( '_', '-', $item[0] ) ); ?>" value="1" /> <?php echo esc_html( $item[1] ); ?></label><br />
+
+								<?php endforeach; ?>
+
+							</fieldset>
+						</td>
+					</tr>
+				</tbody>
+			</table>
+
+			<fieldset class="submit">
+				<input class="button-primary" type="submit" name="submit" value="<?php esc_attr_e( 'Repair Items', 'bbpress' ); ?>" />
+				<?php wp_nonce_field( 'bbpress-do-counts' ); ?>
+			</fieldset>
+		</form>
+	</div>
+
+<?php
+}
+
+/**
+ * Handle the processing and feedback of the admin tools page
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses bbp_admin_repair_list() To get the recount list
+ * @uses check_admin_referer() To verify the nonce and the referer
+ * @uses wp_cache_flush() To flush the cache
+ * @uses do_action() Calls 'admin_notices' to display the notices
+ */
+function bbp_admin_repair_handler() {
+
+	if ( ! bbp_is_post_request() )
+		return;
+
+	check_admin_referer( 'bbpress-do-counts' );
+
+	// Stores messages
+	$messages = array();
+
+	wp_cache_flush();
+
+	foreach ( (array) bbp_admin_repair_list() as $item ) {
+		if ( isset( $item[2] ) && isset( $_POST[$item[0]] ) && 1 === absint( $_POST[$item[0]] ) && is_callable( $item[2] ) ) {
+			$messages[] = call_user_func( $item[2] );
+		}
+	}
+
+	if ( count( $messages ) ) {
+		foreach ( $messages as $message ) {
+			bbp_admin_tools_feedback( $message[1] );
+		}
+	}
+}
+
+/**
+ * Assemble the admin notices
+ *
+ * @since bbPress (r2613)
+ *
+ * @param string|WP_Error $message A message to be displayed or {@link WP_Error}
+ * @param string $class Optional. A class to be added to the message div
+ * @uses WP_Error::get_error_messages() To get the error messages of $message
+ * @uses add_action() Adds the admin notice action with the message HTML
+ * @return string The message HTML
+ */
+function bbp_admin_tools_feedback( $message, $class = false ) {
+	if ( is_string( $message ) ) {
+		$message = '<p>' . $message . '</p>';
+		$class = $class ? $class : 'updated';
+	} elseif ( is_wp_error( $message ) ) {
+		$errors = $message->get_error_messages();
+
+		switch ( count( $errors ) ) {
+			case 0:
+				return false;
+				break;
+
+			case 1:
+				$message = '<p>' . $errors[0] . '</p>';
+				break;
+
+			default:
+				$message = '<ul>' . "\n\t" . '<li>' . implode( '</li>' . "\n\t" . '<li>', $errors ) . '</li>' . "\n" . '</ul>';
+				break;
+		}
+
+		$class = $class ? $class : 'error';
+	} else {
+		return false;
+	}
+
+	$message = '<div id="message" class="' . esc_attr( $class ) . '">' . $message . '</div>';
+	$message = str_replace( "'", "\'", $message );
+	$lambda  = create_function( '', "echo '$message';" );
+
+	add_action( 'admin_notices', $lambda );
+
+	return $lambda;
+}
+
+/**
+ * Get the array of the repair list
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses apply_filters() Calls 'bbp_repair_list' with the list array
+ * @return array Repair list of options
+ */
+function bbp_admin_repair_list() {
+	$repair_list = array(
+		0  => array( 'bbp-sync-topic-meta',          __( 'Recalculate the parent topic for each post',        'bbpress' ), 'bbp_admin_repair_topic_meta'               ),
+		5  => array( 'bbp-sync-forum-meta',          __( 'Recalculate the parent forum for each post',        'bbpress' ), 'bbp_admin_repair_forum_meta'               ),
+		10 => array( 'bbp-sync-forum-visibility',    __( 'Recalculate private and hidden forums',             'bbpress' ), 'bbp_admin_repair_forum_visibility'         ),
+		15 => array( 'bbp-sync-all-topics-forums',   __( 'Recalculate last activity in each topic and forum', 'bbpress' ), 'bbp_admin_repair_freshness'                ),
+		20 => array( 'bbp-sync-all-topics-sticky',   __( 'Recalculate the sticky relationship of each topic', 'bbpress' ), 'bbp_admin_repair_sticky'                   ),
+		25 => array( 'bbp-sync-all-reply-positions', __( 'Recalculate the position of each reply',            'bbpress' ), 'bbp_admin_repair_reply_menu_order'         ),
+		30 => array( 'bbp-group-forums',             __( 'Repair BuddyPress Group Forum relationships',       'bbpress' ), 'bbp_admin_repair_group_forum_relationship' ),
+		35 => array( 'bbp-forum-topics',             __( 'Count topics in each forum',                        'bbpress' ), 'bbp_admin_repair_forum_topic_count'        ),
+		40 => array( 'bbp-forum-replies',            __( 'Count replies in each forum',                       'bbpress' ), 'bbp_admin_repair_forum_reply_count'        ),
+		45 => array( 'bbp-topic-replies',            __( 'Count replies in each topic',                       'bbpress' ), 'bbp_admin_repair_topic_reply_count'        ),
+		50 => array( 'bbp-topic-voices',             __( 'Count voices in each topic',                        'bbpress' ), 'bbp_admin_repair_topic_voice_count'        ),
+		55 => array( 'bbp-topic-hidden-replies',     __( 'Count spammed & trashed replies in each topic',     'bbpress' ), 'bbp_admin_repair_topic_hidden_reply_count' ),
+		60 => array( 'bbp-user-topics',              __( 'Count topics for each user',                        'bbpress' ), 'bbp_admin_repair_user_topic_count'         ),
+		65 => array( 'bbp-user-replies',             __( 'Count replies for each user',                       'bbpress' ), 'bbp_admin_repair_user_reply_count'         ),
+		70 => array( 'bbp-user-favorites',           __( 'Remove trashed topics from user favorites',         'bbpress' ), 'bbp_admin_repair_user_favorites'           ),
+		75 => array( 'bbp-user-topic-subscriptions', __( 'Remove trashed topics from user subscriptions',     'bbpress' ), 'bbp_admin_repair_user_topic_subscriptions' ),
+		80 => array( 'bbp-user-forum-subscriptions', __( 'Remove trashed forums from user subscriptions',     'bbpress' ), 'bbp_admin_repair_user_forum_subscriptions' ),
+		85 => array( 'bbp-user-role-map',            __( 'Remap existing users to default forum roles',       'bbpress' ), 'bbp_admin_repair_user_roles'               )
+	);
+	ksort( $repair_list );
+
+	return (array) apply_filters( 'bbp_repair_list', $repair_list );
+}
+
+/**
+ * Recount topic replies
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_topic_reply_count() {
+	global $wpdb;
+
+	$statement = __( 'Counting the number of replies in each topic&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	// Post types and status
+	$tpt = bbp_get_topic_post_type();
+	$rpt = bbp_get_reply_post_type();
+	$pps = bbp_get_public_status_id();
+	$cps = bbp_get_closed_status_id();
+
+	// Delete the meta key _bbp_reply_count for each topic
+	$sql_delete = "DELETE `postmeta` FROM `{$wpdb->postmeta}` AS `postmeta`
+						LEFT JOIN `{$wpdb->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
+						WHERE `posts`.`post_type` = '{$tpt}'
+						AND `postmeta`.`meta_key` = '_bbp_reply_count'";
+
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) ) {
+		return array( 1, sprintf( $statement, $result ) );
+	}
+
+	// Recalculate the meta key _bbp_reply_count for each topic
+	$sql = "INSERT INTO `{$wpdb->postmeta}` (`post_id`, `meta_key`, `meta_value`) (
+			SELECT `topics`.`ID` AS `post_id`, '_bbp_reply_count' AS `meta_key`, COUNT(`replies`.`ID`) As `meta_value`
+				FROM `{$wpdb->posts}` AS `topics`
+					LEFT JOIN `{$wpdb->posts}` as `replies`
+						ON  `replies`.`post_parent` = `topics`.`ID`
+						AND `replies`.`post_status` = '{$pps}'
+						AND `replies`.`post_type`   = '{$rpt}'
+				WHERE `topics`.`post_type` = '{$tpt}'
+					AND `topics`.`post_status` IN ( '{$pps}', '{$cps}' )
+				GROUP BY `topics`.`ID`);";
+
+	if ( is_wp_error( $wpdb->query( $sql ) ) ) {
+		return array( 2, sprintf( $statement, $result ) );
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recount topic voices
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_topic_voice_count() {
+	global $wpdb;
+
+	$statement = __( 'Counting the number of voices in each topic&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	$sql_delete = "DELETE FROM `{$wpdb->postmeta}` WHERE `meta_key` = '_bbp_voice_count';";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	// Post types and status
+	$tpt = bbp_get_topic_post_type();
+	$rpt = bbp_get_reply_post_type();
+	$pps = bbp_get_public_status_id();
+	$cps = bbp_get_closed_status_id();
+
+	$sql = "INSERT INTO `{$wpdb->postmeta}` (`post_id`, `meta_key`, `meta_value`) (
+			SELECT `postmeta`.`meta_value`, '_bbp_voice_count', COUNT(DISTINCT `post_author`) as `meta_value`
+				FROM `{$wpdb->posts}` AS `posts`
+				LEFT JOIN `{$wpdb->postmeta}` AS `postmeta`
+					ON `posts`.`ID` = `postmeta`.`post_id`
+					AND `postmeta`.`meta_key` = '_bbp_topic_id'
+				WHERE `posts`.`post_type` IN ( '{$tpt}', '{$rpt}' )
+					AND `posts`.`post_status` IN ( '{$pps}', '{$cps}' )
+					AND `posts`.`post_author` != '0'
+				GROUP BY `postmeta`.`meta_value`);";
+
+	if ( is_wp_error( $wpdb->query( $sql ) ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recount topic hidden replies (spammed/trashed)
+ *
+ * @since bbPress (r2747)
+ *
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_topic_hidden_reply_count() {
+	global $wpdb;
+
+	$statement = __( 'Counting the number of spammed and trashed replies in each topic&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	$sql_delete = "DELETE FROM `{$wpdb->postmeta}` WHERE `meta_key` = '_bbp_reply_count_hidden';";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	$sql = "INSERT INTO `{$wpdb->postmeta}` (`post_id`, `meta_key`, `meta_value`) (SELECT `post_parent`, '_bbp_reply_count_hidden', COUNT(`post_status`) as `meta_value` FROM `{$wpdb->posts}` WHERE `post_type` = '" . bbp_get_reply_post_type() . "' AND `post_status` IN ( '" . implode( "','", array( bbp_get_trash_status_id(), bbp_get_spam_status_id() ) ) . "') GROUP BY `post_parent`);";
+	if ( is_wp_error( $wpdb->query( $sql ) ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Repair group forum ID mappings after a bbPress 1.1 to bbPress 2.2 conversion
+ *
+ * @since bbPress (r4395)
+ *
+ * @global WPDB $wpdb
+ * @return If a wp_error() occurs and no converted forums are found
+ */
+function bbp_admin_repair_group_forum_relationship() {
+	global $wpdb;
+
+	$statement = __( 'Repairing BuddyPress group-forum relationships&hellip; %s', 'bbpress' );
+	$g_count     = 0;
+	$f_count     = 0;
+	$s_count     = 0;
+
+	// Copy the BuddyPress filter here, incase BuddyPress is not active
+	$prefix            = apply_filters( 'bp_core_get_table_prefix', $wpdb->base_prefix );
+	$groups_table      = $prefix . 'bp_groups';
+	$groups_meta_table = $prefix . 'bp_groups_groupmeta';
+
+	// Get the converted forum IDs
+	$forum_ids = $wpdb->query( "SELECT `forum`.`ID`, `forummeta`.`meta_value`
+								FROM `{$wpdb->posts}` AS `forum`
+									LEFT JOIN `{$wpdb->postmeta}` AS `forummeta`
+										ON `forum`.`ID` = `forummeta`.`post_id`
+										AND `forummeta`.`meta_key` = '_bbp_old_forum_id'
+								WHERE `forum`.`post_type` = 'forum'
+								GROUP BY `forum`.`ID`;" );
+
+	// Bail if forum IDs returned an error
+	if ( is_wp_error( $forum_ids ) || empty( $wpdb->last_result ) )
+		return array( 2, sprintf( $statement, __( 'Failed!', 'bbpress' ) ) );
+
+	// Stash the last results
+	$results = $wpdb->last_result;
+
+	// Update each group forum
+	foreach ( $results as $group_forums ) {
+
+		// Only update if is a converted forum
+		if ( ! isset( $group_forums->meta_value ) )
+			continue;
+
+		// Attempt to update group meta
+		$updated = $wpdb->query( "UPDATE `{$groups_meta_table}` SET `meta_value` = '{$group_forums->ID}' WHERE `meta_key` = 'forum_id' AND `meta_value` = '{$group_forums->meta_value}';" );
+
+		// Bump the count
+		if ( !empty( $updated ) && ! is_wp_error( $updated ) ) {
+			++$g_count;
+		}
+
+		// Update group to forum relationship data
+		$group_id = (int) $wpdb->get_var( "SELECT `group_id` FROM `{$groups_meta_table}` WHERE `meta_key` = 'forum_id' AND `meta_value` = '{$group_forums->ID}';" );
+		if ( !empty( $group_id ) ) {
+
+			// Update the group to forum meta connection in forums
+			update_post_meta( $group_forums->ID, '_bbp_group_ids', array( $group_id ) );
+
+			// Get the group status
+			$group_status = $wpdb->get_var( "SELECT `status` FROM `{$groups_table}` WHERE `id` = '{$group_id}';" );
+
+			// Sync up forum visibility based on group status
+			switch ( $group_status ) {
+
+				// Public groups have public forums
+				case 'public' :
+					bbp_publicize_forum( $group_forums->ID );
+
+					// Bump the count for output later
+					++$s_count;
+					break;
+
+				// Private/hidden groups have hidden forums
+				case 'private' :
+				case 'hidden'  :
+					bbp_hide_forum( $group_forums->ID );
+
+					// Bump the count for output later
+					++$s_count;
+					break;
+			}
+
+			// Bump the count for output later
+			++$f_count;
+		}
+	}
+
+	// Make some logical guesses at the old group root forum
+	if ( function_exists( 'bp_forums_parent_forum_id' ) ) {
+		$old_default_forum_id = bp_forums_parent_forum_id();
+	} elseif ( defined( 'BP_FORUMS_PARENT_FORUM_ID' ) ) {
+		$old_default_forum_id = (int) BP_FORUMS_PARENT_FORUM_ID;
+	} else {
+		$old_default_forum_id = 1;
+	}
+
+	// Try to get the group root forum
+	$posts = get_posts( array(
+		'post_type'   => bbp_get_forum_post_type(),
+		'meta_key'    => '_bbp_old_forum_id',
+		'meta_value'  => $old_default_forum_id,
+		'numberposts' => 1
+	) );
+
+	// Found the group root forum
+	if ( ! empty( $posts ) ) {
+
+		// Rename 'Default Forum'  since it's now visible in sitewide forums
+		if ( 'Default Forum' === $posts[0]->post_title ) {
+			wp_update_post( array(
+				'ID'         => $posts[0]->ID,
+				'post_title' => __( 'Group Forums', 'bbpress' ),
+				'post_name'  => __( 'group-forums', 'bbpress' ),
+			) );
+		}
+
+		// Update the group forums root metadata
+		update_option( '_bbp_group_forums_root_id', $posts[0]->ID );
+	}
+
+	// Remove old bbPress 1.1 roles (BuddyPress)
+	remove_role( 'member'    );
+	remove_role( 'inactive'  );
+	remove_role( 'blocked'   );
+	remove_role( 'moderator' );
+	remove_role( 'keymaster' );
+
+	// Complete results
+	$result = sprintf( __( 'Complete! %s groups updated; %s forums updated; %s forum statuses synced.', 'bbpress' ), bbp_number_format( $g_count ), bbp_number_format( $f_count ), bbp_number_format( $s_count ) );
+	return array( 0, sprintf( $statement, $result ) );
+}
+
+/**
+ * Recount forum topics
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses get_posts() To get the forums
+ * @uses bbp_update_forum_topic_count() To update the forum topic count
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_forum_topic_count() {
+	global $wpdb;
+
+	$statement = __( 'Counting the number of topics in each forum&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	$sql_delete = "DELETE FROM {$wpdb->postmeta} WHERE meta_key IN ( '_bbp_topic_count', '_bbp_total_topic_count' );";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	$forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
+	if ( !empty( $forums ) ) {
+		foreach ( $forums as $forum ) {
+			bbp_update_forum_topic_count( $forum->ID );
+		}
+	} else {
+		return array( 2, sprintf( $statement, $result ) );
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recount forum replies
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses get_posts() To get the forums
+ * @uses bbp_update_forum_reply_count() To update the forum reply count
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_forum_reply_count() {
+	global $wpdb;
+
+	$statement = __( 'Counting the number of replies in each forum&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	// Post type
+	$fpt = bbp_get_forum_post_type();
+
+	// Delete the meta keys _bbp_reply_count and _bbp_total_reply_count for each forum
+	$sql_delete = "DELETE `postmeta` FROM `{$wpdb->postmeta}` AS `postmeta`
+						LEFT JOIN `{$wpdb->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
+						WHERE `posts`.`post_type` = '{$fpt}'
+						AND `postmeta`.`meta_key` = '_bbp_reply_count'
+						OR `postmeta`.`meta_key` = '_bbp_total_reply_count'";
+
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) ) {
+ 		return array( 1, sprintf( $statement, $result ) );
+	}
+ 
+	// Recalculate the metas key _bbp_reply_count and _bbp_total_reply_count for each forum
+	$forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
+	if ( !empty( $forums ) ) {
+		foreach ( $forums as $forum ) {
+			bbp_update_forum_reply_count( $forum->ID );
+		}
+	} else {
+		return array( 2, sprintf( $statement, $result ) );
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recount topics by the users
+ *
+ * @since bbPress (r3889)
+ *
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_user_topic_count() {
+	global $wpdb;
+
+	$statement   = __( 'Counting the number of topics each user has created&hellip; %s', 'bbpress' );
+	$result      = __( 'Failed!', 'bbpress' );
+	$sql_select  = "SELECT `post_author`, COUNT(DISTINCT `ID`) as `_count` FROM `{$wpdb->posts}` WHERE `post_type` = '" . bbp_get_topic_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "' GROUP BY `post_author`;";
+	$insert_rows = $wpdb->get_results( $sql_select );
+
+	if ( is_wp_error( $insert_rows ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	$key           = $wpdb->prefix . '_bbp_topic_count';
+	$insert_values = array();
+	foreach ( $insert_rows as $insert_row )
+		$insert_values[] = "('{$insert_row->post_author}', '{$key}', '{$insert_row->_count}')";
+
+	if ( !count( $insert_values ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	$sql_delete = "DELETE FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 3, sprintf( $statement, $result ) );
+
+	foreach ( array_chunk( $insert_values, 10000 ) as $chunk ) {
+		$chunk = "\n" . implode( ",\n", $chunk );
+		$sql_insert = "INSERT INTO `{$wpdb->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES $chunk;";
+
+		if ( is_wp_error( $wpdb->query( $sql_insert ) ) ) {
+			return array( 4, sprintf( $statement, $result ) );
+		}
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recount topic replied by the users
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_user_reply_count() {
+	global $wpdb;
+
+	$statement   = __( 'Counting the number of topics to which each user has replied&hellip; %s', 'bbpress' );
+	$result      = __( 'Failed!', 'bbpress' );
+	$sql_select  = "SELECT `post_author`, COUNT(DISTINCT `ID`) as `_count` FROM `{$wpdb->posts}` WHERE `post_type` = '" . bbp_get_reply_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "' GROUP BY `post_author`;";
+	$insert_rows = $wpdb->get_results( $sql_select );
+
+	if ( is_wp_error( $insert_rows ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	$key           = $wpdb->prefix . '_bbp_reply_count';
+	$insert_values = array();
+	foreach ( $insert_rows as $insert_row )
+		$insert_values[] = "('{$insert_row->post_author}', '{$key}', '{$insert_row->_count}')";
+
+	if ( !count( $insert_values ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	$sql_delete = "DELETE FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 3, sprintf( $statement, $result ) );
+
+	foreach ( array_chunk( $insert_values, 10000 ) as $chunk ) {
+		$chunk = "\n" . implode( ",\n", $chunk );
+		$sql_insert = "INSERT INTO `{$wpdb->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES $chunk;";
+
+		if ( is_wp_error( $wpdb->query( $sql_insert ) ) ) {
+			return array( 4, sprintf( $statement, $result ) );
+		}
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Clean the users' favorites
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_user_favorites() {
+	global $wpdb;
+
+	$statement = __( 'Removing trashed topics from user favorites&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+	$key       = $wpdb->prefix . '_bbp_favorites';
+	$users     = $wpdb->get_results( "SELECT `user_id`, `meta_value` AS `favorites` FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';" );
+
+	if ( is_wp_error( $users ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	$topics = $wpdb->get_col( "SELECT `ID` FROM `{$wpdb->posts}` WHERE `post_type` = '" . bbp_get_topic_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "';" );
+
+	if ( is_wp_error( $topics ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	$values = array();
+	foreach ( $users as $user ) {
+		if ( empty( $user->favorites ) || !is_string( $user->favorites ) )
+			continue;
+
+		$favorites = array_intersect( $topics, explode( ',', $user->favorites ) );
+		if ( empty( $favorites ) || !is_array( $favorites ) )
+			continue;
+
+		$favorites_joined = implode( ',', $favorites );
+		$values[]         = "('{$user->user_id}', '{$key}, '{$favorites_joined}')";
+
+		// Cleanup
+		unset( $favorites, $favorites_joined );
+	}
+
+	if ( !count( $values ) ) {
+		$result = __( 'Nothing to remove!', 'bbpress' );
+		return array( 0, sprintf( $statement, $result ) );
+	}
+
+	$sql_delete = "DELETE FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 4, sprintf( $statement, $result ) );
+
+	foreach ( array_chunk( $values, 10000 ) as $chunk ) {
+		$chunk = "\n" . implode( ",\n", $chunk );
+		$sql_insert = "INSERT INTO `$wpdb->usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES $chunk;";
+		if ( is_wp_error( $wpdb->query( $sql_insert ) ) ) {
+			return array( 5, sprintf( $statement, $result ) );
+		}
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Clean the users' topic subscriptions
+ *
+ * @since bbPress (r2668)
+ *
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_user_topic_subscriptions() {
+	global $wpdb;
+
+	$statement = __( 'Removing trashed topics from user subscriptions&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+	$key       = $wpdb->prefix . '_bbp_subscriptions';
+	$users     = $wpdb->get_results( "SELECT `user_id`, `meta_value` AS `subscriptions` FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';" );
+
+	if ( is_wp_error( $users ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	$topics = $wpdb->get_col( "SELECT `ID` FROM `{$wpdb->posts}` WHERE `post_type` = '" . bbp_get_topic_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "';" );
+	if ( is_wp_error( $topics ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	$values = array();
+	foreach ( $users as $user ) {
+		if ( empty( $user->subscriptions ) || !is_string( $user->subscriptions ) )
+			continue;
+
+		$subscriptions = array_intersect( $topics, explode( ',', $user->subscriptions ) );
+		if ( empty( $subscriptions ) || !is_array( $subscriptions ) )
+			continue;
+
+		$subscriptions_joined = implode( ',', $subscriptions );
+		$values[]             = "('{$user->user_id}', '{$key}', '{$subscriptions_joined}')";
+
+		// Cleanup
+		unset( $subscriptions, $subscriptions_joined );
+	}
+
+	if ( !count( $values ) ) {
+		$result = __( 'Nothing to remove!', 'bbpress' );
+		return array( 0, sprintf( $statement, $result ) );
+	}
+
+	$sql_delete = "DELETE FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 4, sprintf( $statement, $result ) );
+
+	foreach ( array_chunk( $values, 10000 ) as $chunk ) {
+		$chunk = "\n" . implode( ",\n", $chunk );
+		$sql_insert = "INSERT INTO `{$wpdb->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES $chunk;";
+		if ( is_wp_error( $wpdb->query( $sql_insert ) ) ) {
+			return array( 5, sprintf( $statement, $result ) );
+		}
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Clean the users' forum subscriptions
+ *
+ * @since bbPress (r5155)
+ *
+ * @uses bbp_get_forum_post_type() To get the topic post type
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_user_forum_subscriptions() {
+	global $wpdb;
+
+	$statement = __( 'Removing trashed forums from user subscriptions&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+	$key       = $wpdb->prefix . '_bbp_forum_subscriptions';
+	$users     = $wpdb->get_results( "SELECT `user_id`, `meta_value` AS `subscriptions` FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';" );
+
+	if ( is_wp_error( $users ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	$forums = $wpdb->get_col( "SELECT `ID` FROM `{$wpdb->posts}` WHERE `post_type` = '" . bbp_get_forum_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "';" );
+	if ( is_wp_error( $forums ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	$values = array();
+	foreach ( $users as $user ) {
+		if ( empty( $user->subscriptions ) || !is_string( $user->subscriptions ) )
+			continue;
+
+		$subscriptions = array_intersect( $forums, explode( ',', $user->subscriptions ) );
+		if ( empty( $subscriptions ) || !is_array( $subscriptions ) )
+			continue;
+
+		$subscriptions_joined = implode( ',', $subscriptions );
+		$values[]             = "('{$user->user_id}', '{$key}', '{$subscriptions_joined}')";
+
+		// Cleanup
+		unset( $subscriptions, $subscriptions_joined );
+	}
+
+	if ( !count( $values ) ) {
+		$result = __( 'Nothing to remove!', 'bbpress' );
+		return array( 0, sprintf( $statement, $result ) );
+	}
+
+	$sql_delete = "DELETE FROM `{$wpdb->usermeta}` WHERE `meta_key` = '{$key}';";
+	if ( is_wp_error( $wpdb->query( $sql_delete ) ) )
+		return array( 4, sprintf( $statement, $result ) );
+
+	foreach ( array_chunk( $values, 10000 ) as $chunk ) {
+		$chunk = "\n" . implode( ",\n", $chunk );
+		$sql_insert = "INSERT INTO `{$wpdb->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES $chunk;";
+		if ( is_wp_error( $wpdb->query( $sql_insert ) ) ) {
+			return array( 5, sprintf( $statement, $result ) );
+		}
+	}
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * This repair tool will map each user of the current site to their respective
+ * forums role. By default, Admins will be Key Masters, and every other role
+ * will be the default role defined in Settings > Forums (Participant).
+ *
+ * @since bbPress (r4340)
+ *
+ * @uses bbp_get_user_role_map() To get the map of user roles
+ * @uses get_editable_roles() To get the current WordPress roles
+ * @uses get_users() To get the users of each role (limited to ID field)
+ * @uses bbp_set_user_role() To set each user's forums role
+ */
+function bbp_admin_repair_user_roles() {
+
+	$statement    = __( 'Remapping forum role for each user on this site&hellip; %s', 'bbpress' );
+	$changed      = 0;
+	$role_map     = bbp_get_user_role_map();
+	$default_role = bbp_get_default_role();
+
+	// Bail if no role map exists
+	if ( empty( $role_map ) )
+		return array( 1, sprintf( $statement, __( 'Failed!', 'bbpress' ) ) );
+
+	// Iterate through each role...
+	foreach ( array_keys( bbp_get_blog_roles() ) as $role ) {
+
+		// Reset the offset
+		$offset = 0;
+
+		// If no role map exists, give the default forum role (bbp-participant)
+		$new_role = isset( $role_map[$role] ) ? $role_map[$role] : $default_role;
+
+		// Get users of this site, limited to 1000
+		while ( $users = get_users( array(
+				'role'   => $role,
+				'fields' => 'ID',
+				'number' => 1000,
+				'offset' => $offset
+			) ) ) {
+
+			// Iterate through each user of $role and try to set it
+			foreach ( (array) $users as $user_id ) {
+				if ( bbp_set_user_role( $user_id, $new_role ) ) {
+					++$changed; // Keep a count to display at the end
+				}
+			}
+
+			// Bump the offset for the next query iteration
+			$offset = $offset + 1000;
+		}
+	}
+
+	$result = sprintf( __( 'Complete! %s users updated.', 'bbpress' ), bbp_number_format( $changed ) );
+	return array( 0, sprintf( $statement, $result ) );
+}
+
+/**
+ * Recaches the last post in every topic and forum
+ *
+ * @since bbPress (r3040)
+ *
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_freshness() {
+	global $wpdb;
+
+	$statement = __( 'Recomputing latest post in every topic and forum&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	// First, delete everything.
+	if ( is_wp_error( $wpdb->query( "DELETE FROM `$wpdb->postmeta` WHERE `meta_key` IN ( '_bbp_last_reply_id', '_bbp_last_topic_id', '_bbp_last_active_id', '_bbp_last_active_time' );" ) ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	// Next, give all the topics with replies the ID their last reply.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `topic`.`ID`, '_bbp_last_reply_id', MAX( `reply`.`ID` )
+			FROM `$wpdb->posts` AS `topic` INNER JOIN `$wpdb->posts` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
+			WHERE `reply`.`post_status` IN ( '" . bbp_get_public_status_id() . "' ) AND `topic`.`post_type` = 'topic' AND `reply`.`post_type` = 'reply'
+			GROUP BY `topic`.`ID` );" ) ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	// For any remaining topics, give a reply ID of 0.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `ID`, '_bbp_last_reply_id', 0
+			FROM `$wpdb->posts` AS `topic` LEFT JOIN `$wpdb->postmeta` AS `reply`
+			ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_reply_id'
+			WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = 'topic' );" ) ) )
+		return array( 3, sprintf( $statement, $result ) );
+
+	// Now we give all the forums with topics the ID their last topic.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `forum`.`ID`, '_bbp_last_topic_id', `topic`.`ID`
+			FROM `$wpdb->posts` AS `forum` INNER JOIN `$wpdb->posts` AS `topic` ON `forum`.`ID` = `topic`.`post_parent`
+			WHERE `topic`.`post_status` IN ( '" . bbp_get_public_status_id() . "' ) AND `forum`.`post_type` = 'forum' AND `topic`.`post_type` = 'topic'
+			GROUP BY `forum`.`ID` );" ) ) )
+		return array( 4, sprintf( $statement, $result ) );
+
+	// For any remaining forums, give a topic ID of 0.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `ID`, '_bbp_last_topic_id', 0
+			FROM `$wpdb->posts` AS `forum` LEFT JOIN `$wpdb->postmeta` AS `topic`
+			ON `forum`.`ID` = `topic`.`post_id` AND `topic`.`meta_key` = '_bbp_last_topic_id'
+			WHERE `topic`.`meta_id` IS NULL AND `forum`.`post_type` = 'forum' );" ) ) )
+		return array( 5, sprintf( $statement, $result ) );
+
+	// After that, we give all the topics with replies the ID their last reply (again, this time for a different reason).
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `topic`.`ID`, '_bbp_last_active_id', MAX( `reply`.`ID` )
+			FROM `$wpdb->posts` AS `topic` INNER JOIN `$wpdb->posts` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
+			WHERE `reply`.`post_status` IN ( '" . bbp_get_public_status_id() . "' ) AND `topic`.`post_type` = 'topic' AND `reply`.`post_type` = 'reply'
+			GROUP BY `topic`.`ID` );" ) ) )
+		return array( 6, sprintf( $statement, $result ) );
+
+	// For any remaining topics, give a reply ID of themself.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `ID`, '_bbp_last_active_id', `ID`
+			FROM `$wpdb->posts` AS `topic` LEFT JOIN `$wpdb->postmeta` AS `reply`
+			ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_active_id'
+			WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = 'topic' );" ) ) )
+		return array( 7, sprintf( $statement, $result ) );
+
+	// Give topics with replies their last update time.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `topic`.`ID`, '_bbp_last_active_time', MAX( `reply`.`post_date` )
+			FROM `$wpdb->posts` AS `topic` INNER JOIN `$wpdb->posts` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
+			WHERE `reply`.`post_status` IN ( '" . bbp_get_public_status_id() . "' ) AND `topic`.`post_type` = 'topic' AND `reply`.`post_type` = 'reply'
+			GROUP BY `topic`.`ID` );" ) ) )
+		return array( 8, sprintf( $statement, $result ) );
+
+	// Give topics without replies their last update time.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `ID`, '_bbp_last_active_time', `post_date`
+			FROM `$wpdb->posts` AS `topic` LEFT JOIN `$wpdb->postmeta` AS `reply`
+			ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_active_time'
+			WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = 'topic' );" ) ) )
+		return array( 9, sprintf( $statement, $result ) );
+
+	// Forums need to know what their last active item is as well. Now it gets a bit more complex to do in the database.
+	$forums = $wpdb->get_col( "SELECT `ID` FROM `$wpdb->posts` WHERE `post_type` = 'forum' and `post_status` != 'auto-draft';" );
+	if ( is_wp_error( $forums ) )
+		return array( 10, sprintf( $statement, $result ) );
+
+ 	// Loop through forums
+ 	foreach ( $forums as $forum_id ) {
+		if ( !bbp_is_forum_category( $forum_id ) ) {
+			bbp_update_forum( array( 'forum_id' => $forum_id ) );
+		}
+	}
+
+	// Loop through categories when forums are done
+	foreach ( $forums as $forum_id ) {
+		if ( bbp_is_forum_category( $forum_id ) ) {
+			bbp_update_forum( array( 'forum_id' => $forum_id ) );
+		}
+	}
+
+	// Complete results
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Repairs the relationship of sticky topics to the actual parent forum
+ *
+ * @since bbPress (r4695)
+ *
+ * @uses wpdb::get_col() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_sticky() {
+	global $wpdb;
+
+	$statement = __( 'Repairing the sticky topic to the parent forum relationships&hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+	$forums    = $wpdb->get_col( "SELECT ID FROM `{$wpdb->posts}` WHERE `post_type` = 'forum';" );
+
+	// Bail if no forums found
+	if ( empty( $forums ) || is_wp_error( $forums ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	// Loop through forums and get their sticky topics
+	foreach ( $forums as $forum ) {
+		$forum_stickies[$forum] = get_post_meta( $forum, '_bbp_sticky_topics', true );
+	}
+
+	// Cleanup
+	unset( $forums, $forum );
+
+	// Loop through each forum with sticky topics
+	foreach ( $forum_stickies as $forum_id => $stickies ) {
+
+		// Skip if no stickies
+		if ( empty( $stickies ) ) {
+			continue;
+		}
+
+		// Loop through each sticky topic
+		foreach ( $stickies as $id => $topic_id ) {
+
+			// If the topic is not a super sticky, and the forum ID does not
+			// match the topic's forum ID, unset the forum's sticky meta.
+			if ( ! bbp_is_topic_super_sticky( $topic_id ) && $forum_id !== bbp_get_topic_forum_id( $topic_id ) ) {
+				unset( $forum_stickies[$forum_id][$id] );
+			}
+		}
+
+		// Get sticky topic ID's, or use empty string
+		$stickers = empty( $forum_stickies[$forum_id] ) ? '' : array_values( $forum_stickies[$forum_id] );
+
+		// Update the forum's sticky topics meta
+		update_post_meta( $forum_id, '_bbp_sticky_topics', $stickers );
+	}
+
+	// Complete results
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recaches the private and hidden forums
+ *
+ * @since bbPress (r4104)
+ *
+ * @uses delete_option() to delete private and hidden forum pointers
+ * @uses WP_Query() To query post IDs
+ * @uses is_wp_error() To return if error occurred
+ * @uses update_option() To update the private and hidden post ID pointers
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_forum_visibility() {
+	$statement = __( 'Recalculating forum visibility &hellip; %s', 'bbpress' );
+
+	// Bail if queries returned errors
+	if ( ! bbp_repair_forum_visibility() ) {
+		return array( 2, sprintf( $statement, __( 'Failed!',   'bbpress' ) ) );
+
+	// Complete results
+	} else {
+		return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+	}
+}
+
+/**
+ * Recaches the forum for each post
+ *
+ * @since bbPress (r3876)
+ *
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_forum_meta() {
+	global $wpdb;
+
+	$statement = __( 'Recalculating the forum for each post &hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	// First, delete everything.
+	if ( is_wp_error( $wpdb->query( "DELETE FROM `$wpdb->postmeta` WHERE `meta_key` = '_bbp_forum_id';" ) ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	// Next, give all the topics with replies the ID their last reply.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `forum`.`ID`, '_bbp_forum_id', `forum`.`post_parent`
+			FROM `$wpdb->posts`
+				AS `forum`
+			WHERE `forum`.`post_type` = 'forum'
+			GROUP BY `forum`.`ID` );" ) ) )
+		return array( 2, sprintf( $statement, $result ) );
+
+	// Next, give all the topics with replies the ID their last reply.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `topic`.`ID`, '_bbp_forum_id', `topic`.`post_parent`
+			FROM `$wpdb->posts`
+				AS `topic`
+			WHERE `topic`.`post_type` = 'topic'
+			GROUP BY `topic`.`ID` );" ) ) )
+		return array( 3, sprintf( $statement, $result ) );
+
+	// Next, give all the topics with replies the ID their last reply.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `reply`.`ID`, '_bbp_forum_id', `topic`.`post_parent`
+			FROM `$wpdb->posts`
+				AS `reply`
+			INNER JOIN `$wpdb->posts`
+				AS `topic`
+				ON `reply`.`post_parent` = `topic`.`ID`
+			WHERE `topic`.`post_type` = 'topic'
+				AND `reply`.`post_type` = 'reply'
+			GROUP BY `reply`.`ID` );" ) ) )
+		return array( 4, sprintf( $statement, $result ) );
+
+	// Complete results
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recaches the topic for each post
+ *
+ * @since bbPress (r3876)
+ *
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_topic_meta() {
+	global $wpdb;
+
+	$statement = __( 'Recalculating the topic for each post &hellip; %s', 'bbpress' );
+	$result    = __( 'Failed!', 'bbpress' );
+
+	// First, delete everything.
+	if ( is_wp_error( $wpdb->query( "DELETE FROM `$wpdb->postmeta` WHERE `meta_key` = '_bbp_topic_id';" ) ) )
+		return array( 1, sprintf( $statement, $result ) );
+
+	// Next, give all the topics with replies the ID their last reply.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `topic`.`ID`, '_bbp_topic_id', `topic`.`ID`
+			FROM `$wpdb->posts`
+				AS `topic`
+			WHERE `topic`.`post_type` = 'topic'
+			GROUP BY `topic`.`ID` );" ) ) )
+		return array( 3, sprintf( $statement, $result ) );
+
+	// Next, give all the topics with replies the ID their last reply.
+	if ( is_wp_error( $wpdb->query( "INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`)
+			( SELECT `reply`.`ID`, '_bbp_topic_id', `topic`.`ID`
+			FROM `$wpdb->posts`
+				AS `reply`
+			INNER JOIN `$wpdb->posts`
+				AS `topic`
+				ON `reply`.`post_parent` = `topic`.`ID`
+			WHERE `topic`.`post_type` = 'topic'
+				AND `reply`.`post_type` = 'reply'
+			GROUP BY `reply`.`ID` );" ) ) )
+		return array( 4, sprintf( $statement, $result ) );
+
+	// Complete results
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/**
+ * Recalculate reply menu order
+ *
+ * @since bbPress (r5367)
+ *
+ * @uses wpdb::query() To run our recount sql queries
+ * @uses is_wp_error() To check if the executed query returned {@link WP_Error}
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_update_reply_position() To update the reply position
+ * @return array An array of the status code and the message
+ */
+function bbp_admin_repair_reply_menu_order() {
+	global $wpdb;
+
+	$statement = __( 'Recalculating reply menu order &hellip; %s', 'bbpress' );
+	$result    = __( 'No reply positions to recalculate!',         'bbpress' );
+
+	// Delete cases where `_bbp_reply_to` was accidentally set to itself
+	if ( is_wp_error( $wpdb->query( "DELETE FROM `{$wpdb->postmeta}` WHERE `meta_key` = '_bbp_reply_to' AND `post_id` = `meta_value`;" ) ) ) {
+		return array( 1, sprintf( $statement, $result ) ); 
+	}
+
+	// Post type
+	$rpt = bbp_get_reply_post_type();
+
+	// Get an array of reply id's to update the menu oder for each reply
+	$replies = $wpdb->get_results( "SELECT `a`.`ID` FROM `{$wpdb->posts}` AS `a`
+										INNER JOIN (
+											SELECT `menu_order`, `post_parent`
+											FROM `{$wpdb->posts}`
+											GROUP BY `menu_order`, `post_parent`
+											HAVING COUNT( * ) >1
+										)`b`
+										ON `a`.`menu_order` = `b`.`menu_order`
+										AND `a`.`post_parent` = `b`.`post_parent`
+										WHERE `post_type` = '{$rpt}';", OBJECT_K );
+
+	// Bail if no replies returned
+	if ( empty( $replies ) ) {
+		return array( 1, sprintf( $statement, $result ) );
+	}
+
+	// Recalculate the menu order position for each reply
+	foreach ( $replies as $reply ) {
+		bbp_update_reply_position( $reply->ID );
+	}
+
+	// Cleanup
+	unset( $replies, $reply );
+
+	// Flush the cache; things are about to get ugly.
+	wp_cache_flush();
+
+	return array( 0, sprintf( $statement, __( 'Complete!', 'bbpress' ) ) );
+}
+
+/** Reset ********************************************************************/
+
+/**
+ * Admin reset page
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses check_admin_referer() To verify the nonce and the referer
+ * @uses do_action() Calls 'admin_notices' to display the notices
+ * @uses screen_icon() To display the screen icon
+ * @uses wp_nonce_field() To add a hidden nonce field
+ */
+function bbp_admin_reset() {
+?>
+
+	<div class="wrap">
+
+		<?php screen_icon( 'tools' ); ?>
+
+		<h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( __( 'Reset Forums', 'bbpress' ) ); ?></h2>
+		<p><?php esc_html_e( 'Revert your forums back to a brand new installation. This process cannot be undone.', 'bbpress' ); ?></p>
+		<p><strong><?php esc_html_e( 'Backup your database before proceeding.', 'bbpress' ); ?></strong></p>
+
+		<form class="settings" method="post" action="">
+			<table class="form-table">
+				<tbody>
+					<tr valign="top">
+						<th scope="row"><?php esc_html_e( 'The following data will be removed:', 'bbpress' ) ?></th>
+						<td>
+							<?php esc_html_e( 'All Forums',           'bbpress' ); ?><br />
+							<?php esc_html_e( 'All Topics',           'bbpress' ); ?><br />
+							<?php esc_html_e( 'All Replies',          'bbpress' ); ?><br />
+							<?php esc_html_e( 'All Topic Tags',       'bbpress' ); ?><br />
+							<?php esc_html_e( 'Related Meta Data',    'bbpress' ); ?><br />
+							<?php esc_html_e( 'Forum Settings',       'bbpress' ); ?><br />
+							<?php esc_html_e( 'Forum Activity',       'bbpress' ); ?><br />
+							<?php esc_html_e( 'Forum User Roles',     'bbpress' ); ?><br />
+							<?php esc_html_e( 'Importer Helper Data', 'bbpress' ); ?><br />
+						</td>
+					</tr>
+					<tr valign="top">
+						<th scope="row"><?php esc_html_e( 'Delete imported users?', 'bbpress' ); ?></th>
+						<td>
+							<fieldset>
+								<legend class="screen-reader-text"><span><?php esc_html_e( "Say it ain't so!", 'bbpress' ); ?></span></legend>
+								<label><input type="checkbox" class="checkbox" name="bbpress-delete-imported-users" id="bbpress-delete-imported-users" value="1" /> <?php esc_html_e( 'This option will delete all previously imported users, and cannot be undone.', 'bbpress' ); ?></label>
+								<p class="description"><?php esc_html_e( 'Note: Resetting without this checked will delete the meta-data necessary to delete these users.', 'bbpress' ); ?></p>
+							</fieldset>
+						</td>
+					</tr>
+					<tr valign="top">
+						<th scope="row"><?php esc_html_e( 'Are you sure you want to do this?', 'bbpress' ); ?></th>
+						<td>
+							<fieldset>
+								<legend class="screen-reader-text"><span><?php esc_html_e( "Say it ain't so!", 'bbpress' ); ?></span></legend>
+								<label><input type="checkbox" class="checkbox" name="bbpress-are-you-sure" id="bbpress-are-you-sure" value="1" /> <?php esc_html_e( 'This process cannot be undone.', 'bbpress' ); ?></label>
+								<p class="description"><?php esc_html_e( 'Human sacrifice, dogs and cats living together... mass hysteria!', 'bbpress' ); ?></p>
+							</fieldset>
+						</td>
+					</tr>
+				</tbody>
+			</table>
+
+			<fieldset class="submit">
+				<input class="button-primary" type="submit" name="submit" value="<?php esc_attr_e( 'Reset bbPress', 'bbpress' ); ?>" />
+				<?php wp_nonce_field( 'bbpress-reset' ); ?>
+			</fieldset>
+		</form>
+	</div>
+
+<?php
+}
+
+/**
+ * Handle the processing and feedback of the admin tools page
+ *
+ * @since bbPress (r2613)
+ *
+ * @uses check_admin_referer() To verify the nonce and the referer
+ * @uses wp_cache_flush() To flush the cache
+ */
+function bbp_admin_reset_handler() {
+
+	// Bail if not resetting
+	if ( ! bbp_is_post_request() || empty( $_POST['bbpress-are-you-sure'] ) )
+		return;
+
+	// Only keymasters can proceed
+	if ( ! bbp_is_user_keymaster() )
+		return;
+
+	check_admin_referer( 'bbpress-reset' );
+
+	global $wpdb;
+
+	// Stores messages
+	$messages = array();
+	$failed   = __( 'Failed',   'bbpress' );
+	$success  = __( 'Success!', 'bbpress' );
+
+	// Flush the cache; things are about to get ugly.
+	wp_cache_flush();
+
+	/** Posts *****************************************************************/
+
+	$statement  = __( 'Deleting Posts&hellip; %s', 'bbpress' );
+	$sql_posts  = $wpdb->get_results( "SELECT `ID` FROM `{$wpdb->posts}` WHERE `post_type` IN ('forum', 'topic', 'reply')", OBJECT_K );
+	$sql_delete = "DELETE FROM `{$wpdb->posts}` WHERE `post_type` IN ('forum', 'topic', 'reply')";
+	$result     = is_wp_error( $wpdb->query( $sql_delete ) ) ? $failed : $success;
+	$messages[] = sprintf( $statement, $result );
+
+	/** Post Meta *************************************************************/
+
+	if ( !empty( $sql_posts ) ) {
+		$sql_meta = array();
+		foreach ( $sql_posts as $key => $value ) {
+			$sql_meta[] = $key;
+		}
+		$statement  = __( 'Deleting Post Meta&hellip; %s', 'bbpress' );
+		$sql_meta   = implode( "', '", $sql_meta );
+		$sql_delete = "DELETE FROM `{$wpdb->postmeta}` WHERE `post_id` IN ('{$sql_meta}');";
+		$result     = is_wp_error( $wpdb->query( $sql_delete ) ) ? $failed : $success;
+		$messages[] = sprintf( $statement, $result );
+	}
+
+	/** Topic Tags ************************************************************/
+
+	$statement  = __( 'Deleting Topic Tags&hellip; %s', 'bbpress' );
+	$sql_delete = "DELETE a,b,c FROM `{$wpdb->terms}` AS a LEFT JOIN `{$wpdb->term_taxonomy}` AS c ON a.term_id = c.term_id LEFT JOIN `{$wpdb->term_relationships}` AS b ON b.term_taxonomy_id = c.term_taxonomy_id WHERE c.taxonomy = 'topic-tag';";
+	$result     = is_wp_error( $wpdb->query( $sql_delete ) ) ? $failed : $success;
+	$messages[] = sprintf( $statement, $result );
+
+	/** User ******************************************************************/
+
+	// Delete users
+	if ( !empty( $_POST['bbpress-delete-imported-users'] ) ) {
+		$sql_users  = $wpdb->get_results( "SELECT `user_id` FROM `{$wpdb->usermeta}` WHERE `meta_key` = '_bbp_user_id'", OBJECT_K );
+		if ( !empty( $sql_users ) ) {
+			$sql_meta = array();
+			foreach ( $sql_users as $key => $value ) {
+				$sql_meta[] = $key;
+			}
+			$statement  = __( 'Deleting User&hellip; %s', 'bbpress' );
+			$sql_meta   = implode( "', '", $sql_meta );
+			$sql_delete = "DELETE FROM `{$wpdb->users}` WHERE `ID` IN ('{$sql_meta}');";
+			$result     = is_wp_error( $wpdb->query( $sql_delete ) ) ? $failed : $success;
+			$messages[] = sprintf( $statement, $result );
+			$statement  = __( 'Deleting User Meta&hellip; %s', 'bbpress' );
+			$sql_delete = "DELETE FROM `{$wpdb->usermeta}` WHERE `user_id` IN ('{$sql_meta}');";
+			$result     = is_wp_error( $wpdb->query( $sql_delete ) ) ? $failed : $success;
+			$messages[] = sprintf( $statement, $result );
+		}
+
+	// Delete imported user metadata
+	} else {
+		$statement  = __( 'Deleting User Meta&hellip; %s', 'bbpress' );
+		$sql_delete = "DELETE FROM `{$wpdb->usermeta}` WHERE `meta_key` LIKE '%%_bbp_%%';";
+		$result     = is_wp_error( $wpdb->query( $sql_delete ) ) ? $failed : $success;
+		$messages[] = sprintf( $statement, $result );
+	}
+
+	/** Converter *************************************************************/
+
+	$statement  = __( 'Deleting Conversion Table&hellip; %s', 'bbpress' );
+	$table_name = $wpdb->prefix . 'bbp_converter_translator';
+	if ( $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" ) === $table_name ) {
+		$wpdb->query( "DROP TABLE {$table_name}" );
+		$result = $success;
+	} else {
+		$result = $failed;
+	}
+	$messages[] = sprintf( $statement, $result );
+
+	/** Options ***************************************************************/
+
+	$statement  = __( 'Deleting Settings&hellip; %s', 'bbpress' );
+	bbp_delete_options();
+	$messages[] = sprintf( $statement, $success );
+
+	/** Roles *****************************************************************/
+
+	$statement  = __( 'Deleting Roles and Capabilities&hellip; %s', 'bbpress' );
+	remove_role( bbp_get_moderator_role() );
+	remove_role( bbp_get_participant_role() );
+	bbp_remove_caps();
+	$messages[] = sprintf( $statement, $success );
+
+	/** Output ****************************************************************/
+
+	if ( count( $messages ) ) {
+		foreach ( $messages as $message ) {
+			bbp_admin_tools_feedback( $message );
+		}
+	}
+}
Index: /tags/2.5.4/includes/admin/topics.php
===================================================================
--- /tags/2.5.4/includes/admin/topics.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/topics.php	(revision 5382)
@@ -0,0 +1,974 @@
+<?php
+
+/**
+ * bbPress Topics Admin Class
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Topics_Admin' ) ) :
+/**
+ * Loads bbPress topics admin area
+ *
+ * @package bbPress
+ * @subpackage Administration
+ * @since bbPress (r2464)
+ */
+class BBP_Topics_Admin {
+
+	/** Variables *************************************************************/
+
+	/**
+	 * @var The post type of this admin component
+	 */
+	private $post_type = '';
+
+	/** Functions *************************************************************/
+
+	/**
+	 * The main bbPress topics admin loader
+	 *
+	 * @since bbPress (r2515)
+	 *
+	 * @uses BBP_Topics_Admin::setup_globals() Setup the globals needed
+	 * @uses BBP_Topics_Admin::setup_actions() Setup the hooks and actions
+	 * @uses BBP_Topics_Admin::setup_help() Setup the help text
+	 */
+	public function __construct() {
+		$this->setup_globals();
+		$this->setup_actions();
+	}
+
+	/**
+	 * Setup the admin hooks, actions and filters
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 *
+	 * @uses add_action() To add various actions
+	 * @uses add_filter() To add various filters
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 */
+	private function setup_actions() {
+
+		// Add some general styling to the admin area
+		add_action( 'bbp_admin_head',        array( $this, 'admin_head'       ) );
+
+		// Messages
+		add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
+
+		// Topic column headers.
+		add_filter( 'manage_' . $this->post_type . '_posts_columns',        array( $this, 'column_headers' ) );
+
+		// Topic columns (in post row)
+		add_action( 'manage_' . $this->post_type . '_posts_custom_column',  array( $this, 'column_data' ), 10, 2 );
+		add_filter( 'post_row_actions',                                     array( $this, 'row_actions' ), 10, 2 );
+
+		// Topic metabox actions
+		add_action( 'add_meta_boxes', array( $this, 'attributes_metabox'      ) );
+		add_action( 'save_post',      array( $this, 'attributes_metabox_save' ) );
+
+		// Check if there are any bbp_toggle_topic_* requests on admin_init, also have a message displayed
+		add_action( 'load-edit.php',  array( $this, 'toggle_topic'        ) );
+		add_action( 'admin_notices',  array( $this, 'toggle_topic_notice' ) );
+
+		// Anonymous metabox actions
+		add_action( 'add_meta_boxes', array( $this, 'author_metabox'      ) );
+
+		// Add ability to filter topics and replies per forum
+		add_filter( 'restrict_manage_posts', array( $this, 'filter_dropdown'  ) );
+		add_filter( 'bbp_request',           array( $this, 'filter_post_rows' ) );
+
+		// Contextual Help
+		add_action( 'load-edit.php',     array( $this, 'edit_help' ) );
+		add_action( 'load-post.php',     array( $this, 'new_help'  ) );
+		add_action( 'load-post-new.php', array( $this, 'new_help'  ) );
+	}
+
+	/**
+	 * Should we bail out of this method?
+	 *
+	 * @since bbPress (r4067)
+	 * @return boolean
+	 */
+	private function bail() {
+		if ( !isset( get_current_screen()->post_type ) || ( $this->post_type !== get_current_screen()->post_type ) )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Admin globals
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 */
+	private function setup_globals() {
+		$this->post_type = bbp_get_topic_post_type();
+	}
+
+	/** Contextual Help *******************************************************/
+
+	/**
+	 * Contextual help for bbPress topic edit page
+	 *
+	 * @since bbPress (r3119)
+	 * @uses get_current_screen()
+	 */
+	public function edit_help() {
+
+		if ( $this->bail() ) return;
+
+		// Overview
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'overview',
+			'title'		=> __( 'Overview', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'This screen displays the individual topics on your site. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
+		) );
+
+		// Screen Content
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'screen-content',
+			'title'		=> __( 'Screen Content', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( 'You can hide/display columns based on your needs and decide how many topics to list per screen using the Screen Options tab.',                                                                                                                                'bbpress' ) . '</li>' .
+					'<li>' . __( 'You can filter the list of topics by topic status using the text links in the upper left to show All, Published, or Trashed topics. The default view is to show all topics.',                                                                                 'bbpress' ) . '</li>' .
+					'<li>' . __( 'You can refine the list to show only topics from a specific month by using the dropdown menus above the topics list. Click the Filter button after making your selection. You also can refine the list by clicking on the topic creator in the topics list.', 'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		// Available Actions
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'action-links',
+			'title'		=> __( 'Available Actions', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'Hovering over a row in the topics list will display action links that allow you to manage your topic. You can perform the following actions:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that topic. You can also reach that screen by clicking on the topic title.',                                                                                 'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Trash</strong> removes your topic from this list and places it in the trash, from which you can permanently delete it.',                                                                                       'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Spam</strong> removes your topic from this list and places it in the spam queue, from which you can permanently delete it.',                                                                                   'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Preview</strong> will show you what your draft topic will look like if you publish it. View will take you to your live site to view the topic. Which link is available depends on your topic&#8217;s status.', 'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Close</strong> will mark the selected topic as &#8217;closed&#8217; and disable the option to post new replies to the topic.',                                                                                 'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Stick</strong> will keep the selected topic &#8217;pinned&#8217; to the top the parent forum topic list.',                                                                                                     'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Stick <em>(to front)</em></strong> will keep the selected topic &#8217;pinned&#8217; to the top of ALL forums and be visable in any forums topics list.',                                                      'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		// Bulk Actions
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'bulk-actions',
+			'title'		=> __( 'Bulk Actions', 'bbpress' ),
+			'content'	=>
+				'<p>' . __( 'You can also edit or move multiple topics to the trash at once. Select the topics you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.',           'bbpress' ) . '</p>' .
+				'<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected topics at once. To remove a topic from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
+		) );
+
+		// Help Sidebar
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://codex.bbpress.org" target="_blank">bbPress Documentation</a>',     'bbpress' ) . '</p>' .
+			'<p>' . __( '<a href="http://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>',  'bbpress' ) . '</p>'
+		);
+	}
+
+	/**
+	 * Contextual help for bbPress topic edit page
+	 *
+	 * @since bbPress (r3119)
+	 * @uses get_current_screen()
+	 */
+	public function new_help() {
+
+		if ( $this->bail() ) return;
+
+		$customize_display = '<p>' . __( 'The title field and the big topic editing Area are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.', 'bbpress' ) . '</p>';
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'customize-display',
+			'title'   => __( 'Customizing This Display', 'bbpress' ),
+			'content' => $customize_display,
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'title-topic-editor',
+			'title'   => __( 'Title and Topic Editor', 'bbpress' ),
+			'content' =>
+				'<p>' . __( '<strong>Title</strong> - Enter a title for your topic. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
+				'<p>' . __( '<strong>Topic Editor</strong> - Enter the text for your topic. There are two modes of editing: Visual and HTML. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The HTML mode allows you to enter raw HTML along with your topic text. You can insert media files by clicking the icons above the topic editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in HTML mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular topic editor.', 'bbpress' ) . '</p>'
+		) );
+
+		$publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your topic in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a topic or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a topic to be published in the future or backdate a topic.', 'bbpress' ) . '</p>';
+
+		if ( current_theme_supports( 'topic-thumbnails' ) && post_type_supports( 'topic', 'thumbnail' ) ) {
+			$publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your topic without inserting it. This is usually useful only if your theme makes use of the featured image as a topic thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
+		}
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'topic-attributes',
+			'title'   => __( 'Topic Attributes', 'bbpress' ),
+			'content' =>
+				'<p>' . __( 'Select the attributes that your topic should have:', 'bbpress' ) . '</p>' .
+				'<ul>' .
+					'<li>' . __( '<strong>Forum</strong> dropdown determines the parent forum that the topic belongs to. Select the forum or category from the dropdown, or leave the default (No Forum) to post the topic without an assigned forum.', 'bbpress' ) . '</li>' .
+					'<li>' . __( '<strong>Topic Type</strong> dropdown indicates the sticky status of the topic. Selecting the super sticky option would stick the topic to the front of your forums, i.e. the topic index, sticky option would stick the topic to its respective forum. Selecting normal would not stick the topic anywhere.', 'bbpress' ) . '</li>' .
+				'</ul>'
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'publish-box',
+			'title'   => __( 'Publish Box', 'bbpress' ),
+			'content' => $publish_box,
+		) );
+
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
+			'<p>' . __( '<a href="http://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
+		);
+	}
+
+	/**
+	 * Add the topic attributes metabox
+	 *
+	 * @since bbPress (r2744)
+	 *
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses add_meta_box() To add the metabox
+	 * @uses do_action() Calls 'bbp_topic_attributes_metabox'
+	 */
+	public function attributes_metabox() {
+
+		if ( $this->bail() ) return;
+
+		add_meta_box (
+			'bbp_topic_attributes',
+			__( 'Topic Attributes', 'bbpress' ),
+			'bbp_topic_metabox',
+			$this->post_type,
+			'side',
+			'high'
+		);
+
+		do_action( 'bbp_topic_attributes_metabox' );
+	}
+
+	/**
+	 * Pass the topic attributes for processing
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @param int $topic_id Topic id
+	 * @uses current_user_can() To check if the current user is capable of
+	 *                           editing the topic
+	 * @uses do_action() Calls 'bbp_topic_attributes_metabox_save' with the
+	 *                    topic id and parent id
+	 * @return int Parent id
+	 */
+	public function attributes_metabox_save( $topic_id ) {
+
+		if ( $this->bail() ) return $topic_id;
+
+		// Bail if doing an autosave
+		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
+			return $topic_id;
+
+		// Bail if not a post request
+		if ( ! bbp_is_post_request() )
+			return $topic_id;
+
+		// Nonce check
+		if ( empty( $_POST['bbp_topic_metabox'] ) || !wp_verify_nonce( $_POST['bbp_topic_metabox'], 'bbp_topic_metabox_save' ) )
+			return $topic_id;
+
+		// Bail if current user cannot edit this topic
+		if ( !current_user_can( 'edit_topic', $topic_id ) )
+			return $topic_id;
+
+		// Get the forum ID
+		$forum_id = !empty( $_POST['parent_id'] ) ? (int) $_POST['parent_id'] : 0;
+
+		// Get topic author data
+		$anonymous_data = bbp_filter_anonymous_post_data();
+		$author_id      = bbp_get_topic_author_id( $topic_id );
+		$is_edit        = (bool) isset( $_POST['save'] );
+
+		// Formally update the topic
+		bbp_update_topic( $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit );
+
+		// Stickies
+		if ( !empty( $_POST['bbp_stick_topic'] ) && in_array( $_POST['bbp_stick_topic'], array( 'stick', 'super', 'unstick' ) ) ) {
+
+			// What's the haps?
+			switch ( $_POST['bbp_stick_topic'] ) {
+
+				// Sticky in this forum
+				case 'stick'   :
+					bbp_stick_topic( $topic_id );
+					break;
+
+				// Super sticky in all forums
+				case 'super'   :
+					bbp_stick_topic( $topic_id, true );
+					break;
+
+				// Normal
+				case 'unstick' :
+				default        :
+					bbp_unstick_topic( $topic_id );
+					break;
+			}
+		}
+
+		// Allow other fun things to happen
+		do_action( 'bbp_topic_attributes_metabox_save', $topic_id, $forum_id       );
+		do_action( 'bbp_author_metabox_save',           $topic_id, $anonymous_data );
+
+		return $topic_id;
+	}
+
+	/**
+	 * Add the author info metabox
+	 *
+	 * @since bbPress (r2828)
+	 *
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses add_meta_box() To add the metabox
+	 * @uses do_action() Calls 'bbp_author_metabox' with the topic/reply
+	 *                    id
+	 */
+	public function author_metabox() {
+
+		if ( $this->bail() ) return;
+
+		// Bail if post_type is not a topic
+		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) )
+			return;
+
+		// Add the metabox
+		add_meta_box(
+			'bbp_author_metabox',
+			__( 'Author Information', 'bbpress' ),
+			'bbp_author_metabox',
+			$this->post_type,
+			'side',
+			'high'
+		);
+
+		do_action( 'bbp_author_metabox', get_the_ID() );
+	}
+
+	/**
+	 * Add some general styling to the admin area
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses sanitize_html_class() To sanitize the classes
+	 * @uses do_action() Calls 'bbp_admin_head'
+	 */
+	public function admin_head() {
+
+		if ( $this->bail() ) return;
+
+		?>
+
+		<style type="text/css" media="screen">
+		/*<![CDATA[*/
+
+			strong.label {
+				display: inline-block;
+				width: 60px;
+			}
+
+			.column-bbp_forum_topic_count,
+			.column-bbp_forum_reply_count,
+			.column-bbp_topic_reply_count,
+			.column-bbp_topic_voice_count {
+				width: 8% !important;
+			}
+
+			.column-author,
+			.column-bbp_reply_author,
+			.column-bbp_topic_author {
+				width: 10% !important;
+			}
+
+			.column-bbp_topic_forum,
+			.column-bbp_reply_forum,
+			.column-bbp_reply_topic {
+				width: 10% !important;
+			}
+
+			.column-bbp_forum_freshness,
+			.column-bbp_topic_freshness {
+				width: 10% !important;
+			}
+
+			.column-bbp_forum_created,
+			.column-bbp_topic_created,
+			.column-bbp_reply_created {
+				width: 15% !important;
+			}
+
+			.status-closed {
+				background-color: #eaeaea;
+			}
+
+			.status-spam {
+				background-color: #faeaea;
+			}
+
+		/*]]>*/
+		</style>
+
+		<?php
+	}
+
+	/**
+	 * Toggle topic
+	 *
+	 * Handles the admin-side opening/closing, sticking/unsticking and
+	 * spamming/unspamming of topics
+	 *
+	 * @since bbPress (r2727)
+	 *
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses current_user_can() To check if the user is capable of editing
+	 *                           the topic
+	 * @uses wp_die() To die if the user isn't capable or the post wasn't
+	 *                 found
+	 * @uses check_admin_referer() To verify the nonce and check referer
+	 * @uses bbp_is_topic_open() To check if the topic is open
+	 * @uses bbp_close_topic() To close the topic
+	 * @uses bbp_open_topic() To open the topic
+	 * @uses bbp_is_topic_sticky() To check if the topic is a sticky or
+	 *                              super sticky
+	 * @uses bbp_unstick_topic() To unstick the topic
+	 * @uses bbp_stick_topic() To stick the topic
+	 * @uses bbp_is_topic_spam() To check if the topic is marked as spam
+	 * @uses bbp_unspam_topic() To unmark the topic as spam
+	 * @uses bbp_spam_topic() To mark the topic as spam
+	 * @uses do_action() Calls 'bbp_toggle_topic_admin' with success, post
+	 *                    data, action and message
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_safe_redirect() Redirect the page to custom url
+	 */
+	public function toggle_topic() {
+
+		if ( $this->bail() ) return;
+
+		// Only proceed if GET is a topic toggle action
+		if ( bbp_is_get_request() && !empty( $_GET['action'] ) && in_array( $_GET['action'], array( 'bbp_toggle_topic_close', 'bbp_toggle_topic_stick', 'bbp_toggle_topic_spam' ) ) && !empty( $_GET['topic_id'] ) ) {
+			$action    = $_GET['action'];            // What action is taking place?
+			$topic_id  = (int) $_GET['topic_id'];    // What's the topic id?
+			$success   = false;                      // Flag
+			$post_data = array( 'ID' => $topic_id ); // Prelim array
+			$topic     = bbp_get_topic( $topic_id );
+
+			// Bail if topic is missing
+			if ( empty( $topic ) )
+				wp_die( __( 'The topic was not found!', 'bbpress' ) );
+
+			if ( !current_user_can( 'moderate', $topic->ID ) ) // What is the user doing here?
+				wp_die( __( 'You do not have the permission to do that!', 'bbpress' ) );
+
+			switch ( $action ) {
+				case 'bbp_toggle_topic_close' :
+					check_admin_referer( 'close-topic_' . $topic_id );
+
+					$is_open = bbp_is_topic_open( $topic_id );
+					$message = true === $is_open ? 'closed' : 'opened';
+					$success = true === $is_open ? bbp_close_topic( $topic_id ) : bbp_open_topic( $topic_id );
+
+					break;
+
+				case 'bbp_toggle_topic_stick' :
+					check_admin_referer( 'stick-topic_' . $topic_id );
+
+					$is_sticky = bbp_is_topic_sticky( $topic_id );
+					$is_super  = false === $is_sticky && !empty( $_GET['super'] ) && ( "1" === $_GET['super'] ) ? true : false;
+					$message   = true  === $is_sticky ? 'unsticked'     : 'sticked';
+					$message   = true  === $is_super  ? 'super_sticked' : $message;
+					$success   = true  === $is_sticky ? bbp_unstick_topic( $topic_id ) : bbp_stick_topic( $topic_id, $is_super );
+
+					break;
+
+				case 'bbp_toggle_topic_spam'  :
+					check_admin_referer( 'spam-topic_' . $topic_id );
+
+					$is_spam = bbp_is_topic_spam( $topic_id );
+					$message = true === $is_spam ? 'unspammed' : 'spammed';
+					$success = true === $is_spam ? bbp_unspam_topic( $topic_id ) : bbp_spam_topic( $topic_id );
+
+					break;
+			}
+
+			$message = array( 'bbp_topic_toggle_notice' => $message, 'topic_id' => $topic->ID );
+
+			if ( false === $success || is_wp_error( $success ) )
+				$message['failed'] = '1';
+
+			// Do additional topic toggle actions (admin side)
+			do_action( 'bbp_toggle_topic_admin', $success, $post_data, $action, $message );
+
+			// Redirect back to the topic
+			$redirect = add_query_arg( $message, remove_query_arg( array( 'action', 'topic_id' ) ) );
+			wp_safe_redirect( $redirect );
+
+			// For good measure
+			exit();
+		}
+	}
+
+	/**
+	 * Toggle topic notices
+	 *
+	 * Display the success/error notices from
+	 * {@link BBP_Admin::toggle_topic()}
+	 *
+	 * @since bbPress (r2727)
+	 *
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses bbp_get_topic_title() To get the topic title of the topic
+	 * @uses esc_html() To sanitize the topic title
+	 * @uses apply_filters() Calls 'bbp_toggle_topic_notice_admin' with
+	 *                        message, topic id, notice and is it a failure
+	 */
+	public function toggle_topic_notice() {
+
+		if ( $this->bail() ) return;
+
+		// Only proceed if GET is a topic toggle action
+		if ( bbp_is_get_request() && !empty( $_GET['bbp_topic_toggle_notice'] ) && in_array( $_GET['bbp_topic_toggle_notice'], array( 'opened', 'closed', 'super_sticked', 'sticked', 'unsticked', 'spammed', 'unspammed' ) ) && !empty( $_GET['topic_id'] ) ) {
+			$notice     = $_GET['bbp_topic_toggle_notice'];         // Which notice?
+			$topic_id   = (int) $_GET['topic_id'];                  // What's the topic id?
+			$is_failure = !empty( $_GET['failed'] ) ? true : false; // Was that a failure?
+
+			// Bais if no topic_id or notice
+			if ( empty( $notice ) || empty( $topic_id ) )
+				return;
+
+			// Bail if topic is missing
+			$topic = bbp_get_topic( $topic_id );
+			if ( empty( $topic ) )
+				return;
+
+			$topic_title = bbp_get_topic_title( $topic->ID );
+
+			switch ( $notice ) {
+				case 'opened'    :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem opening the topic "%1$s".',           'bbpress' ), $topic_title ) : sprintf( __( 'Topic "%1$s" successfully opened.',           'bbpress' ), $topic_title );
+					break;
+
+				case 'closed'    :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem closing the topic "%1$s".',           'bbpress' ), $topic_title ) : sprintf( __( 'Topic "%1$s" successfully closed.',           'bbpress' ), $topic_title );
+					break;
+
+				case 'super_sticked' :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem sticking the topic "%1$s" to front.', 'bbpress' ), $topic_title ) : sprintf( __( 'Topic "%1$s" successfully sticked to front.', 'bbpress' ), $topic_title );
+					break;
+
+				case 'sticked'   :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem sticking the topic "%1$s".',          'bbpress' ), $topic_title ) : sprintf( __( 'Topic "%1$s" successfully sticked.',          'bbpress' ), $topic_title );
+					break;
+
+				case 'unsticked' :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem unsticking the topic "%1$s".',        'bbpress' ), $topic_title ) : sprintf( __( 'Topic "%1$s" successfully unsticked.',        'bbpress' ), $topic_title );
+					break;
+
+				case 'spammed'   :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem marking the topic "%1$s" as spam.',   'bbpress' ), $topic_title ) : sprintf( __( 'Topic "%1$s" successfully marked as spam.',   'bbpress' ), $topic_title );
+					break;
+
+				case 'unspammed' :
+					$message = $is_failure === true ? sprintf( __( 'There was a problem unmarking the topic "%1$s" as spam.', 'bbpress' ), $topic_title ) : sprintf( __( 'Topic "%1$s" successfully unmarked as spam.', 'bbpress' ), $topic_title );
+					break;
+			}
+
+			// Do additional topic toggle notice filters (admin side)
+			$message = apply_filters( 'bbp_toggle_topic_notice_admin', $message, $topic->ID, $notice, $is_failure );
+
+			?>
+
+			<div id="message" class="<?php echo $is_failure === true ? 'error' : 'updated'; ?> fade">
+				<p style="line-height: 150%"><?php echo esc_html( $message ); ?></p>
+			</div>
+
+			<?php
+		}
+	}
+
+	/**
+	 * Manage the column headers for the topics page
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param array $columns The columns
+	 * @uses apply_filters() Calls 'bbp_admin_topics_column_headers' with
+	 *                        the columns
+	 * @return array $columns bbPress topic columns
+	 */
+	public function column_headers( $columns ) {
+
+		if ( $this->bail() ) return $columns;
+
+		$columns = array(
+			'cb'                    => '<input type="checkbox" />',
+			'title'                 => __( 'Topics',    'bbpress' ),
+			'bbp_topic_forum'       => __( 'Forum',     'bbpress' ),
+			'bbp_topic_reply_count' => __( 'Replies',   'bbpress' ),
+			'bbp_topic_voice_count' => __( 'Voices',    'bbpress' ),
+			'bbp_topic_author'      => __( 'Author',    'bbpress' ),
+			'bbp_topic_created'     => __( 'Created',   'bbpress' ),
+			'bbp_topic_freshness'   => __( 'Freshness', 'bbpress' )
+		);
+
+		return apply_filters( 'bbp_admin_topics_column_headers', $columns );
+	}
+
+	/**
+	 * Print extra columns for the topics page
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param string $column Column
+	 * @param int $topic_id Topic id
+	 * @uses bbp_get_topic_forum_id() To get the forum id of the topic
+	 * @uses bbp_forum_title() To output the topic's forum title
+	 * @uses apply_filters() Calls 'topic_forum_row_actions' with an array
+	 *                        of topic forum actions
+	 * @uses bbp_get_forum_permalink() To get the forum permalink
+	 * @uses admin_url() To get the admin url of post.php
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses bbp_topic_reply_count() To output the topic reply count
+	 * @uses bbp_topic_voice_count() To output the topic voice count
+	 * @uses bbp_topic_author_display_name() To output the topic author name
+	 * @uses get_the_date() Get the topic creation date
+	 * @uses get_the_time() Get the topic creation time
+	 * @uses esc_attr() To sanitize the topic creation time
+	 * @uses bbp_get_topic_last_active_time() To get the time when the topic was
+	 *                                    last active
+	 * @uses do_action() Calls 'bbp_admin_topics_column_data' with the
+	 *                    column and topic id
+	 */
+	public function column_data( $column, $topic_id ) {
+
+		if ( $this->bail() ) return;
+
+		// Get topic forum ID
+		$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+		// Populate column data
+		switch ( $column ) {
+
+			// Forum
+			case 'bbp_topic_forum' :
+
+				// Output forum name
+				if ( !empty( $forum_id ) ) {
+
+					// Forum Title
+					$forum_title = bbp_get_forum_title( $forum_id );
+					if ( empty( $forum_title ) ) {
+						$forum_title = esc_html__( 'No Forum', 'bbpress' );
+					}
+
+					// Output the title
+					echo $forum_title;
+
+				} else {
+					esc_html_e( '(No Forum)', 'bbpress' );
+				}
+
+				break;
+
+			// Reply Count
+			case 'bbp_topic_reply_count' :
+				bbp_topic_reply_count( $topic_id );
+				break;
+
+			// Reply Count
+			case 'bbp_topic_voice_count' :
+				bbp_topic_voice_count( $topic_id );
+				break;
+
+			// Author
+			case 'bbp_topic_author' :
+				bbp_topic_author_display_name( $topic_id );
+				break;
+
+			// Freshness
+			case 'bbp_topic_created':
+				printf( '%1$s <br /> %2$s',
+					get_the_date(),
+					esc_attr( get_the_time() )
+				);
+
+				break;
+
+			// Freshness
+			case 'bbp_topic_freshness' :
+				$last_active = bbp_get_topic_last_active_time( $topic_id, false );
+				if ( !empty( $last_active ) ) {
+					echo esc_html( $last_active );
+				} else {
+					esc_html_e( 'No Replies', 'bbpress' ); // This should never happen
+				}
+
+				break;
+
+			// Do an action for anything else
+			default :
+				do_action( 'bbp_admin_topics_column_data', $column, $topic_id );
+				break;
+		}
+	}
+
+	/**
+	 * Topic Row actions
+	 *
+	 * Remove the quick-edit action link under the topic title and add the
+	 * content and close/stick/spam links
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param array $actions Actions
+	 * @param array $topic Topic object
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_topic_content() To output topic content
+	 * @uses bbp_get_topic_permalink() To get the topic link
+	 * @uses bbp_get_topic_title() To get the topic title
+	 * @uses current_user_can() To check if the current user can edit or
+	 *                           delete the topic
+	 * @uses bbp_is_topic_open() To check if the topic is open
+	 * @uses bbp_is_topic_spam() To check if the topic is marked as spam
+	 * @uses bbp_is_topic_sticky() To check if the topic is a sticky or a
+	 *                              super sticky
+	 * @uses get_post_type_object() To get the topic post type object
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses remove_query_arg() To remove custom args from the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses get_delete_post_link() To get the delete post link of the topic
+	 * @return array $actions Actions
+	 */
+	public function row_actions( $actions, $topic ) {
+
+		if ( $this->bail() ) return $actions;
+
+		unset( $actions['inline hide-if-no-js'] );
+
+		// Show view link if it's not set, the topic is trashed and the user can view trashed topics
+		if ( empty( $actions['view'] ) && ( bbp_get_trash_status_id() === $topic->post_status ) && current_user_can( 'view_trash' ) )
+			$actions['view'] = '<a href="' . esc_url( bbp_get_topic_permalink( $topic->ID ) ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;', 'bbpress' ), bbp_get_topic_title( $topic->ID ) ) ) . '" rel="permalink">' . esc_html__( 'View', 'bbpress' ) . '</a>';
+
+		// Only show the actions if the user is capable of viewing them :)
+		if ( current_user_can( 'moderate', $topic->ID ) ) {
+
+			// Close
+			// Show the 'close' and 'open' link on published and closed posts only
+			if ( in_array( $topic->post_status, array( bbp_get_public_status_id(), bbp_get_closed_status_id() ) ) ) {
+				$close_uri = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_close' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'close-topic_' . $topic->ID );
+				if ( bbp_is_topic_open( $topic->ID ) )
+					$actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Close this topic', 'bbpress' ) . '">' . _x( 'Close', 'Close a Topic', 'bbpress' ) . '</a>';
+				else
+					$actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Open this topic',  'bbpress' ) . '">' . _x( 'Open',  'Open a Topic',  'bbpress' ) . '</a>';
+			}
+
+			// Dont show sticky if topic links is spam or trash
+			if ( !bbp_is_topic_spam( $topic->ID ) && !bbp_is_topic_trash( $topic->ID ) ) {
+
+				// Sticky
+				$stick_uri  = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_stick' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'stick-topic_'  . $topic->ID );
+				if ( bbp_is_topic_sticky( $topic->ID ) ) {
+					$actions['stick'] = '<a href="' . esc_url( $stick_uri ) . '" title="' . esc_attr__( 'Unstick this topic', 'bbpress' ) . '">' . esc_html__( 'Unstick', 'bbpress' ) . '</a>';
+				} else {
+					$super_uri        = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_stick', 'super' => '1' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'stick-topic_'  . $topic->ID );
+					$actions['stick'] = '<a href="' . esc_url( $stick_uri ) . '" title="' . esc_attr__( 'Stick this topic to its forum', 'bbpress' ) . '">' . esc_html__( 'Stick', 'bbpress' ) . '</a> <a href="' . esc_url( $super_uri ) . '" title="' . esc_attr__( 'Stick this topic to front', 'bbpress' ) . '">' . esc_html__( '(to front)', 'bbpress' ) . '</a>';
+				}
+			}
+
+			// Spam
+			$spam_uri  = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_spam' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'spam-topic_'  . $topic->ID );
+			if ( bbp_is_topic_spam( $topic->ID ) )
+				$actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark the topic as not spam', 'bbpress' ) . '">' . esc_html__( 'Not spam', 'bbpress' ) . '</a>';
+			else
+				$actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark this topic as spam',    'bbpress' ) . '">' . esc_html__( 'Spam',     'bbpress' ) . '</a>';
+
+		}
+
+		// Do not show trash links for spam topics, or spam links for trashed topics
+		if ( current_user_can( 'delete_topic', $topic->ID ) ) {
+			if ( bbp_get_trash_status_id() === $topic->post_status ) {
+				$post_type_object   = get_post_type_object( bbp_get_topic_post_type() );
+				$actions['untrash'] = "<a title='" . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . "' href='" . wp_nonce_url( add_query_arg( array( '_wp_http_referer' => add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit.php' ) ) ), admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $topic->ID ) ) ), 'untrash-' . $topic->post_type . '_' . $topic->ID ) . "'>" . esc_html__( 'Restore', 'bbpress' ) . "</a>";
+			} elseif ( EMPTY_TRASH_DAYS ) {
+				$actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash', 'bbpress' ) . "' href='" . add_query_arg( array( '_wp_http_referer' => add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit.php' ) ) ), get_delete_post_link( $topic->ID ) ) . "'>" . esc_html__( 'Trash', 'bbpress' ) . "</a>";
+			}
+
+			if ( bbp_get_trash_status_id() === $topic->post_status || !EMPTY_TRASH_DAYS ) {
+				$actions['delete'] = "<a class='submitdelete' title='" . esc_attr__( 'Delete this item permanently', 'bbpress' ) . "' href='" . add_query_arg( array( '_wp_http_referer' => add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit.php' ) ) ), get_delete_post_link( $topic->ID, '', true ) ) . "'>" . esc_html__( 'Delete Permanently', 'bbpress' ) . "</a>";
+			} elseif ( bbp_get_spam_status_id() === $topic->post_status ) {
+				unset( $actions['trash'] );
+			}
+		}
+
+		return $actions;
+	}
+
+	/**
+	 * Add forum dropdown to topic and reply list table filters
+	 *
+	 * @since bbPress (r2991)
+	 *
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_dropdown() To generate a forum dropdown
+	 * @return bool False. If post type is not topic or reply
+	 */
+	public function filter_dropdown() {
+
+		if ( $this->bail() ) return;
+
+		// Add Empty Spam button
+		if ( !empty( $_GET['post_status'] ) && ( bbp_get_spam_status_id() === $_GET['post_status'] ) && current_user_can( 'moderate' ) ) {
+			wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
+			$title = esc_attr__( 'Empty Spam', 'bbpress' );
+			submit_button( $title, 'button-secondary apply', 'delete_all', false );
+		}
+
+		// Get which forum is selected
+		$selected = !empty( $_GET['bbp_forum_id'] ) ? $_GET['bbp_forum_id'] : '';
+
+		// Show the forums dropdown
+		bbp_dropdown( array(
+			'selected'  => $selected,
+			'show_none' => __( 'In all forums', 'bbpress' )
+		) );
+	}
+
+	/**
+	 * Adjust the request query and include the forum id
+	 *
+	 * @since bbPress (r2991)
+	 *
+	 * @param array $query_vars Query variables from {@link WP_Query}
+	 * @uses is_admin() To check if it's the admin section
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @return array Processed Query Vars
+	 */
+	function filter_post_rows( $query_vars ) {
+
+		if ( $this->bail() ) return $query_vars;
+
+		// Add post_parent query_var if one is present
+		if ( !empty( $_GET['bbp_forum_id'] ) ) {
+			$query_vars['meta_key']   = '_bbp_forum_id';
+			$query_vars['meta_value'] = $_GET['bbp_forum_id'];
+		}
+
+		// Return manipulated query_vars
+		return $query_vars;
+	}
+
+	/**
+	 * Custom user feedback messages for topic post type
+	 *
+	 * @since bbPress (r3080)
+	 *
+	 * @global int $post_ID
+	 * @uses bbp_get_topic_permalink()
+	 * @uses wp_post_revision_title()
+	 * @uses esc_url()
+	 * @uses add_query_arg()
+	 *
+	 * @param array $messages
+	 *
+	 * @return array
+	 */
+	public function updated_messages( $messages ) {
+		global $post_ID;
+
+		if ( $this->bail() ) return $messages;
+
+		// URL for the current topic
+		$topic_url = bbp_get_topic_permalink( $post_ID );
+
+		// Current topic's post_date
+		$post_date = bbp_get_global_post_field( 'post_date', 'raw' );
+
+		// Messages array
+		$messages[$this->post_type] = array(
+			0 =>  '', // Left empty on purpose
+
+			// Updated
+			1 =>  sprintf( __( 'Topic updated. <a href="%s">View topic</a>', 'bbpress' ), $topic_url ),
+
+			// Custom field updated
+			2 => __( 'Custom field updated.', 'bbpress' ),
+
+			// Custom field deleted
+			3 => __( 'Custom field deleted.', 'bbpress' ),
+
+			// Topic updated
+			4 => __( 'Topic updated.', 'bbpress' ),
+
+			// Restored from revision
+			// translators: %s: date and time of the revision
+			5 => isset( $_GET['revision'] )
+					? sprintf( __( 'Topic restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
+					: false,
+
+			// Topic created
+			6 => sprintf( __( 'Topic created. <a href="%s">View topic</a>', 'bbpress' ), $topic_url ),
+
+			// Topic saved
+			7 => __( 'Topic saved.', 'bbpress' ),
+
+			// Topic submitted
+			8 => sprintf( __( 'Topic submitted. <a target="_blank" href="%s">Preview topic</a>', 'bbpress' ), esc_url( add_query_arg( 'preview', 'true', $topic_url ) ) ),
+
+			// Topic scheduled
+			9 => sprintf( __( 'Topic scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview topic</a>', 'bbpress' ),
+					// translators: Publish box date format, see http://php.net/date
+					date_i18n( __( 'M j, Y @ G:i', 'bbpress' ),
+					strtotime( $post_date ) ),
+					$topic_url ),
+
+			// Topic draft updated
+			10 => sprintf( __( 'Topic draft updated. <a target="_blank" href="%s">Preview topic</a>', 'bbpress' ), esc_url( add_query_arg( 'preview', 'true', $topic_url ) ) ),
+		);
+
+		return $messages;
+	}
+}
+endif; // class_exists check
+
+/**
+ * Setup bbPress Topics Admin
+ *
+ * This is currently here to make hooking and unhooking of the admin UI easy.
+ * It could use dependency injection in the future, but for now this is easier.
+ *
+ * @since bbPress (r2596)
+ *
+ * @uses BBP_Forums_Admin
+ */
+function bbp_admin_topics() {
+	bbpress()->admin->topics = new BBP_Topics_Admin();
+}
Index: /tags/2.5.4/includes/admin/users.php
===================================================================
--- /tags/2.5.4/includes/admin/users.php	(revision 5382)
+++ /tags/2.5.4/includes/admin/users.php	(revision 5382)
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * bbPress Users Admin Class
+ *
+ * @package bbPress
+ * @subpackage Administration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Users_Admin' ) ) :
+/**
+ * Loads bbPress users admin area
+ *
+ * @package bbPress
+ * @subpackage Administration
+ * @since bbPress (r2464)
+ */
+class BBP_Users_Admin {
+
+	/**
+	 * The bbPress users admin loader
+	 *
+	 * @since bbPress (r2515)
+	 *
+	 * @uses BBP_Users_Admin::setup_globals() Setup the globals needed
+	 * @uses BBP_Users_Admin::setup_actions() Setup the hooks and actions
+	 */
+	public function __construct() {
+		$this->setup_actions();
+	}
+
+	/**
+	 * Setup the admin hooks, actions and filters
+	 *
+	 * @since bbPress (r2646)
+	 * @access private
+	 *
+	 * @uses add_action() To add various actions
+	 */
+	function setup_actions() {
+
+		// Bail if in network admin
+		if ( is_network_admin() )
+			return;
+
+		// User profile edit/display actions
+		add_action( 'edit_user_profile', array( $this, 'secondary_role_display' ) );
+
+		// WordPress user screen
+		add_action( 'restrict_manage_users',      array( $this, 'user_role_bulk_dropdown' )        );
+		add_filter( 'manage_users_columns',       array( $this, 'user_role_column'        )        );
+		add_filter( 'manage_users_custom_column', array( $this, 'user_role_row'           ), 10, 3 );
+
+		// Process bulk role change
+		add_action( 'load-users.php',             array( $this, 'user_role_bulk_change'   )        );
+	}
+
+	/**
+	 * Default interface for setting a forum role
+	 *
+	 * @since bbPress (r4285)
+	 *
+	 * @param WP_User $profileuser User data
+	 * @return bool Always false
+	 */
+	public static function secondary_role_display( $profileuser ) {
+
+		// Bail if current user cannot edit users
+		if ( ! current_user_can( 'edit_user', $profileuser->ID ) )
+			return;
+
+		// Get the roles
+		$dynamic_roles = bbp_get_dynamic_roles();
+
+		// Only keymasters can set other keymasters
+		if ( ! bbp_is_user_keymaster() )
+			unset( $dynamic_roles[ bbp_get_keymaster_role() ] ); ?>
+
+		<h3><?php esc_html_e( 'Forums', 'bbpress' ); ?></h3>
+
+		<table class="form-table">
+			<tbody>
+				<tr>
+					<th><label for="bbp-forums-role"><?php esc_html_e( 'Forum Role', 'bbpress' ); ?></label></th>
+					<td>
+
+						<?php $user_role = bbp_get_user_role( $profileuser->ID ); ?>
+
+						<select name="bbp-forums-role" id="bbp-forums-role">
+
+							<?php if ( ! empty( $user_role ) ) : ?>
+
+								<option value=""><?php esc_html_e( '&mdash; No role for these forums &mdash;', 'bbpress' ); ?></option>
+
+							<?php else : ?>
+
+								<option value="" selected="selected"><?php esc_html_e( '&mdash; No role for these forums &mdash;', 'bbpress' ); ?></option>
+
+							<?php endif; ?>
+
+							<?php foreach ( $dynamic_roles as $role => $details ) : ?>
+
+								<option <?php selected( $user_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo translate_user_role( $details['name'] ); ?></option>
+
+							<?php endforeach; ?>
+
+						</select>
+					</td>
+				</tr>
+
+			</tbody>
+		</table>
+
+		<?php
+	}
+
+	/**
+	 * Add bulk forums role dropdown to the WordPress users table
+	 *
+	 * @since bbPress (r4360)
+	 */
+	public static function user_role_bulk_dropdown() {
+
+		// Bail if current user cannot promote users 
+		if ( !current_user_can( 'promote_users' ) )
+			return;
+
+		// Get the roles
+		$dynamic_roles = bbp_get_dynamic_roles();
+
+		// Only keymasters can set other keymasters
+		if ( ! bbp_is_user_keymaster() )
+			unset( $dynamic_roles[ bbp_get_keymaster_role() ] ); ?>
+
+		<label class="screen-reader-text" for="bbp-new-role"><?php esc_html_e( 'Change forum role to&hellip;', 'bbpress' ) ?></label>
+		<select name="bbp-new-role" id="bbp-new-role" style="display:inline-block; float:none;">
+			<option value=''><?php esc_html_e( 'Change forum role to&hellip;', 'bbpress' ) ?></option>
+			<?php foreach ( $dynamic_roles as $role => $details ) : ?>
+				<option value="<?php echo esc_attr( $role ); ?>"><?php echo translate_user_role( $details['name'] ); ?></option>
+			<?php endforeach; ?>
+		</select><?php submit_button( __( 'Change', 'bbpress' ), 'secondary', 'bbp-change-role', false );
+	}
+
+	/**
+	 * Process bulk dropdown form submission from the WordPress Users
+	 * Table
+	 *
+	 * @uses current_user_can() to check for 'promote users' capability
+	 * @uses bbp_get_dynamic_roles() to get forum roles
+	 * @uses bbp_get_user_role() to get a user's current forums role
+	 * @uses bbp_set_user_role() to set the user's new forums role
+	 * @return bool Always false
+	 */
+	public function user_role_bulk_change() {
+
+		// Bail if current user cannot promote users 
+		if ( !current_user_can( 'promote_users' ) )
+			return;
+
+		// Bail if no users specified
+		if ( empty( $_REQUEST['users'] ) )
+			return;
+
+		// Bail if this isn't a bbPress action
+		if ( empty( $_REQUEST['bbp-new-role'] ) || empty( $_REQUEST['bbp-change-role'] ) )
+			return;
+
+		// Check that the new role exists
+		$dynamic_roles = bbp_get_dynamic_roles();
+		if ( empty( $dynamic_roles[ $_REQUEST['bbp-new-role'] ] ) )
+			return;
+
+		// Get the current user ID
+		$current_user_id = (int) bbp_get_current_user_id();
+
+		// Run through user ids
+		foreach ( (array) $_REQUEST['users'] as $user_id ) {
+			$user_id = (int) $user_id;
+
+			// Don't let a user change their own role
+			if ( $user_id === $current_user_id )
+				continue;
+
+			// Set up user and role data
+			$user_role = bbp_get_user_role( $user_id );			
+			$new_role  = sanitize_text_field( $_REQUEST['bbp-new-role'] );
+
+			// Only keymasters can set other keymasters
+			if ( in_array( bbp_get_keymaster_role(), array( $user_role, $new_role ) ) && ! bbp_is_user_keymaster() )
+				continue;
+
+			// Set the new forums role
+			if ( $new_role !== $user_role ) {
+				bbp_set_user_role( $user_id, $new_role );
+			}
+		}
+	}
+
+	/**
+	 * Add Forum Role column to the WordPress Users table, and change the
+	 * core role title to "Site Role"
+	 *
+	 * @since bbPress (r4337)
+	 *
+	 * @param array $columns Users table columns
+	 * @return array $columns
+	 */
+	public static function user_role_column( $columns = array() ) {
+		$columns['role']          = __( 'Site Role',  'bbpress' );
+		$columns['bbp_user_role'] = __( 'Forum Role', 'bbpress' );
+
+		return $columns;
+	}
+
+	/**
+	 * Return user's forums role for display in the WordPress Users list table
+	 *
+	 * @since bbPress (r4337)
+	 *
+	 * @param string $retval
+	 * @param string $column_name
+	 * @param int $user_id
+	 *
+	 * @return string Displayable bbPress user role
+	 */
+	public static function user_role_row( $retval = '', $column_name = '', $user_id = 0 ) {
+
+		// Only looking for bbPress's user role column
+		if ( 'bbp_user_role' === $column_name ) {
+
+			// Get the users role
+			$user_role = bbp_get_user_role( $user_id );
+			$retval    = false;
+
+			// Translate user role for display
+			if ( ! empty( $user_role ) ) {
+				$roles  = bbp_get_dynamic_roles();
+				$retval = translate_user_role( $roles[$user_role]['name'] );
+			}
+		}
+
+		// Pass retval through
+		return $retval;
+	}
+}
+new BBP_Users_Admin();
+endif; // class exists
Index: /tags/2.5.4/includes/common/ajax.php
===================================================================
--- /tags/2.5.4/includes/common/ajax.php	(revision 5382)
+++ /tags/2.5.4/includes/common/ajax.php	(revision 5382)
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * bbPress Common AJAX Functions
+ *
+ * Common AJAX functions are ones that are used to setup and/or use during
+ * bbPress specific, theme-side  AJAX requests.
+ *
+ * @package bbPress
+ * @subpackage Ajax
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the URL to use for theme-side bbPress AJAX requests
+ *
+ * @since bbPress (r4543)
+ *
+ * @uses bbp_get_ajax_url() To get the URL to use for AJAX requests
+ */
+function bbp_ajax_url() {
+	echo esc_url( bbp_get_ajax_url() );
+}
+	/**
+	 * Return the URL to use for theme-side bbPress AJAX requests
+	 *
+	 * @since bbPress (r4543)
+	 *
+	 * @global WP $wp
+	 * @return string
+	 */
+	function bbp_get_ajax_url() {
+		global $wp;
+
+		$base_url = home_url( trailingslashit( $wp->request ), ( is_ssl() ? 'https' : 'http' ) );
+		$ajaxurl  = add_query_arg( array( 'bbp-ajax' => 'true' ), $base_url );
+
+		return apply_filters( 'bbp_get_ajax_url', $ajaxurl );
+	}
+
+/**
+ * Is this a bbPress AJAX request?
+ *
+ * @since bbPress (r4543)
+ *
+ * @return bool Looking for bbp-ajax
+ */
+function bbp_is_ajax() {
+	return (bool) ( ( isset( $_GET['bbp-ajax'] ) || isset( $_POST['bbp-ajax'] ) ) && ! empty( $_REQUEST['action'] ) );
+}
+
+/**
+ * Hooked to the 'bbp_template_redirect' action, this is bbPress's custom
+ * theme-side ajax handler.
+ *
+ * @since bbPress (r4543)
+ *
+ * @return If not a bbPress ajax request
+ */
+function bbp_do_ajax() {
+
+	// Bail if not an ajax request
+	if ( ! bbp_is_ajax() )
+		return;
+
+	// Set WordPress core ajax constant
+	define( 'DOING_AJAX', true );
+
+	// Set the header content type
+	@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
+
+	// Disable content sniffing in browsers that support it
+	send_nosniff_header();
+
+	// Perform custom bbPress ajax
+	do_action( 'bbp_ajax_' . $_REQUEST['action'] );
+
+	// All done
+	die( '0' );
+}
+
+/**
+ * Helper method to return JSON response for the ajax calls
+ *
+ * @since bbPress (r4542)
+ *
+ * @param bool $success
+ * @param string $content
+ * @param array $extras
+ */
+function bbp_ajax_response( $success = false, $content = '', $status = -1, $extras = array() ) {
+
+	// Set status to 200 if setting response as successful
+	if ( ( true === $success ) && ( -1 === $status ) )
+		$status = 200;
+
+	// Setup the response array
+	$response = array(
+		'success' => $success,
+		'status'  => $status,
+		'content' => $content
+	);
+
+	// Merge extra response parameters in
+	if ( !empty( $extras ) && is_array( $extras ) ) {
+		$response = array_merge( $response, $extras );
+	}
+
+	// Send back the JSON
+	@header( 'Content-type: application/json' );
+	echo json_encode( $response );
+	die();
+}
Index: /tags/2.5.4/includes/common/classes.php
===================================================================
--- /tags/2.5.4/includes/common/classes.php	(revision 5382)
+++ /tags/2.5.4/includes/common/classes.php	(revision 5382)
@@ -0,0 +1,417 @@
+<?php
+
+/**
+ * bbPress Classes
+ *
+ * @package bbPress
+ * @subpackage Classes
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Component' ) ) :
+/**
+ * bbPress Component Class
+ *
+ * The bbPress component class is responsible for simplifying the creation
+ * of components that share similar behaviors and routines. It is used
+ * internally by bbPress to create forums, topics and replies, but can be
+ * extended to create other really neat things.
+ *
+ * @package bbPress
+ * @subpackage Classes
+ *
+ * @since bbPress (r2688)
+ */
+class BBP_Component {
+
+	/**
+	 * @var string Unique name (for internal identification)
+	 * @internal
+	 */
+	var $name;
+
+	/**
+	 * @var Unique ID (normally for custom post type)
+	 */
+	var $id;
+
+	/**
+	 * @var string Unique slug (used in query string and permalinks)
+	 */
+	var $slug;
+
+	/**
+	 * @var WP_Query The loop for this component
+	 */
+	var $query;
+
+	/**
+	 * @var string The current ID of the queried object
+	 */
+	var $current_id;
+
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * bbPress Component loader
+	 *
+	 * @since bbPress (r2700)
+	 *
+	 * @param mixed $args Required. Supports these args:
+	 *  - name: Unique name (for internal identification)
+	 *  - id: Unique ID (normally for custom post type)
+	 *  - slug: Unique slug (used in query string and permalinks)
+	 *  - query: The loop for this component (WP_Query)
+	 *  - current_id: The current ID of the queried object
+	 * @uses BBP_Component::setup_globals() Setup the globals needed
+	 * @uses BBP_Component::includes() Include the required files
+	 * @uses BBP_Component::setup_actions() Setup the hooks and actions
+	 */
+	public function __construct( $args = '' ) {
+		if ( empty( $args ) )
+			return;
+
+		$this->setup_globals( $args );
+		$this->includes();
+		$this->setup_actions();
+	}
+
+	/**
+	 * Component global variables
+	 *
+	 * @since bbPress (r2700)
+	 * @access private
+	 *
+	 * @uses apply_filters() Calls 'bbp_{@link BBP_Component::name}_id'
+	 * @uses apply_filters() Calls 'bbp_{@link BBP_Component::name}_slug'
+	 */
+	private function setup_globals( $args = '' ) {
+		$this->name = $args['name'];
+		$this->id   = apply_filters( 'bbp_' . $this->name . '_id',   $args['id']   );
+		$this->slug = apply_filters( 'bbp_' . $this->name . '_slug', $args['slug'] );
+	}
+
+	/**
+	 * Include required files
+	 *
+	 * @since bbPress (r2700)
+	 * @access private
+	 *
+	 * @uses do_action() Calls 'bbp_{@link BBP_Component::name}includes'
+	 */
+	private function includes() {
+		do_action( 'bbp_' . $this->name . 'includes' );
+	}
+
+	/**
+	 * Setup the actions
+	 *
+	 * @since bbPress (r2700)
+	 * @access private
+	 *
+	 * @uses add_action() To add various actions
+	 * @uses do_action() Calls
+	 *                    'bbp_{@link BBP_Component::name}setup_actions'
+	 */
+	private function setup_actions() {
+		add_action( 'bbp_register_post_types',    array( $this, 'register_post_types'    ), 10, 2 ); // Register post types
+		add_action( 'bbp_register_taxonomies',    array( $this, 'register_taxonomies'    ), 10, 2 ); // Register taxonomies
+		add_action( 'bbp_add_rewrite_tags',       array( $this, 'add_rewrite_tags'       ), 10, 2 ); // Add the rewrite tags
+		add_action( 'bbp_generate_rewrite_rules', array( $this, 'generate_rewrite_rules' ), 10, 2 ); // Generate rewrite rules
+
+		// Additional actions can be attached here
+		do_action( 'bbp_' . $this->name . 'setup_actions' );
+	}
+
+	/**
+	 * Setup the component post types
+	 *
+	 * @since bbPress (r2700)
+	 *
+	 * @uses do_action() Calls 'bbp_{@link BBP_Component::name}_register_post_types'
+	 */
+	public function register_post_types() {
+		do_action( 'bbp_' . $this->name . '_register_post_types' );
+	}
+
+	/**
+	 * Register component specific taxonomies
+	 *
+	 * @since bbPress (r2700)
+	 *
+	 * @uses do_action() Calls 'bbp_{@link BBP_Component::name}_register_taxonomies'
+	 */
+	public function register_taxonomies() {
+		do_action( 'bbp_' . $this->name . '_register_taxonomies' );
+	}
+
+	/**
+	 * Add any additional rewrite tags
+	 *
+	 * @since bbPress (r2700)
+	 *
+	 * @uses do_action() Calls 'bbp_{@link BBP_Component::name}_add_rewrite_tags'
+	 */
+	public function add_rewrite_tags() {
+		do_action( 'bbp_' . $this->name . '_add_rewrite_tags' );
+	}
+
+	/**
+	 * Generate any additional rewrite rules
+	 *
+	 * @since bbPress (r2700)
+	 *
+	 * @uses do_action() Calls 'bbp_{@link BBP_Component::name}_generate_rewrite_rules'
+	 */
+	public function generate_rewrite_rules( $wp_rewrite ) {
+		do_action_ref_array( 'bbp_' . $this->name . '_generate_rewrite_rules', $wp_rewrite );
+	}
+}
+endif; // BBP_Component
+
+if ( class_exists( 'Walker' ) ) :
+/**
+ * Create HTML dropdown list of bbPress forums/topics.
+ *
+ * @package bbPress
+ * @subpackage Classes
+ *
+ * @since bbPress (r2746)
+ * @uses Walker
+ */
+class BBP_Walker_Dropdown extends Walker {
+
+	/**
+	 * @see Walker::$tree_type
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @var string
+	 */
+	var $tree_type;
+
+	/**
+	 * @see Walker::$db_fields
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @var array
+	 */
+	var $db_fields = array( 'parent' => 'post_parent', 'id' => 'ID' );
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * Set the tree_type
+	 *
+	 * @since bbPress (r2746)
+	 */
+	public function __construct() {
+		$this->tree_type = bbp_get_forum_post_type();
+	}
+
+	/**
+	 * @see Walker::start_el()
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @param string $output Passed by reference. Used to append additional
+	 *                        content.
+	 * @param object $_post Post data object.
+	 * @param int $depth Depth of post in reference to parent posts. Used
+	 *                    for padding.
+	 * @param array $args Uses 'selected' argument for selected post to set
+	 *                     selected HTML attribute for option element.
+	 * @param int $current_object_id
+	 * @uses bbp_is_forum_category() To check if the forum is a category
+	 * @uses current_user_can() To check if the current user can post in
+	 *                           closed forums
+	 * @uses bbp_is_forum_closed() To check if the forum is closed
+	 * @uses apply_filters() Calls 'bbp_walker_dropdown_post_title' with the
+	 *                        title, output, post, depth and args
+	 */
+	public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
+		$pad     = str_repeat( '&nbsp;', (int) $depth * 3 );
+		$output .= '<option class="level-' . (int) $depth . '"';
+
+		// Disable the <option> if:
+		// - we're told to do so
+		// - the post type is a forum
+		// - the forum is a category
+		// - forum is closed
+		if (	( true === $args['disable_categories'] )
+				&& ( bbp_get_forum_post_type() === $object->post_type )
+				&& ( bbp_is_forum_category( $object->ID )
+					|| ( !current_user_can( 'edit_forum', $object->ID ) && bbp_is_forum_closed( $object->ID )
+				)
+			) ) {
+			$output .= ' disabled="disabled" value=""';
+		} else {
+			$output .= ' value="' . (int) $object->ID .'"' . selected( $args['selected'], $object->ID, false );
+		}
+
+		$output .= '>';
+		$title   = apply_filters( 'bbp_walker_dropdown_post_title', $object->post_title, $output, $object, $depth, $args );
+		$output .= $pad . esc_html( $title );
+		$output .= "</option>\n";
+	}
+}
+
+/**
+ * Create hierarchical list of bbPress replies.
+ *
+ * @package bbPress
+ * @subpackage Classes
+ *
+ * @since bbPress (r4944)
+ */
+class BBP_Walker_Reply extends Walker {
+
+	/**
+	 * @see Walker::$tree_type
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @var string
+	 */
+	var $tree_type = 'reply';
+
+	/**
+	 * @see Walker::$db_fields
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @var array
+	 */
+	var $db_fields = array(
+		'parent' => 'reply_to',
+		'id'     => 'ID'
+	);
+
+	/**
+	 * @see Walker::start_lvl()
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @param string $output Passed by reference. Used to append additional content
+	 * @param int $depth Depth of reply
+	 * @param array $args Uses 'style' argument for type of HTML list
+	 */
+	public function start_lvl( &$output = '', $depth = 0, $args = array() ) {
+		bbpress()->reply_query->reply_depth = $depth + 1;
+
+		switch ( $args['style'] ) {
+			case 'div':
+				break;
+			case 'ol':
+				echo "<ol class='bbp-threaded-replies'>\n";
+				break;
+			case 'ul':
+			default:
+				echo "<ul class='bbp-threaded-replies'>\n";
+				break;
+		}
+	}
+
+	/**
+	 * @see Walker::end_lvl()
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @param string $output Passed by reference. Used to append additional content
+	 * @param int $depth Depth of reply
+	 * @param array $args Will only append content if style argument value is 'ol' or 'ul'
+	 */
+	public function end_lvl( &$output = '', $depth = 0, $args = array() ) {
+		bbpress()->reply_query->reply_depth = (int) $depth + 1;
+
+		switch ( $args['style'] ) {
+			case 'div':
+				break;
+			case 'ol':
+				echo "</ol>\n";
+				break;
+			case 'ul':
+			default:
+				echo "</ul>\n";
+				break;
+		}
+	}
+
+	/**
+	 * @since bbPress (r4944)
+	 */
+	public function display_element( $element = false, &$children_elements = array(), $max_depth = 0, $depth = 0, $args = array(), &$output = '' ) {
+
+		if ( empty( $element ) )
+			return;
+
+		// Get element's id
+		$id_field = $this->db_fields['id'];
+		$id       = $element->$id_field;
+
+		// Display element
+		parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
+
+		// If we're at the max depth and the current element still has children, loop over those
+		// and display them at this level to prevent them being orphaned to the end of the list.
+		if ( ( $max_depth <= (int) $depth + 1 ) && isset( $children_elements[$id] ) ) {
+			foreach ( $children_elements[$id] as $child ) {
+				$this->display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
+			}
+			unset( $children_elements[$id] );
+		}
+	}
+
+	/**
+	 * @see Walker:start_el()
+	 *
+	 * @since bbPress (r4944)
+	 */
+	public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
+
+		// Set up reply
+		$depth++;
+		bbpress()->reply_query->reply_depth = $depth;
+		bbpress()->reply_query->post        = $object;
+		bbpress()->current_reply_id         = $object->ID;
+
+		// Check for a callback and use it if specified
+		if ( !empty( $args['callback'] ) ) {
+			call_user_func( $args['callback'], $object, $args, $depth );
+			return;
+		}
+
+		// Style for div or list element
+		if ( !empty( $args['style'] ) && ( 'div' === $args['style'] ) ) {
+			echo "<div>\n";
+		} else {
+			echo "<li>\n";
+		}
+
+		bbp_get_template_part( 'loop', 'single-reply' );
+	}
+
+	/**
+	 * @since bbPress (r4944)
+	 */
+	public function end_el( &$output = '', $object = false, $depth = 0, $args = array() ) {
+
+		// Check for a callback and use it if specified
+		if ( !empty( $args['end-callback'] ) ) {
+			call_user_func( $args['end-callback'], $object, $args, $depth );
+			return;
+		}
+
+		// Style for div or list element
+		if ( !empty( $args['style'] ) && ( 'div' === $args['style'] ) ) {
+			echo "</div>\n";
+		} else {
+			echo "</li>\n";
+		}
+	}
+}
+endif; // class_exists check
Index: /tags/2.5.4/includes/common/formatting.php
===================================================================
--- /tags/2.5.4/includes/common/formatting.php	(revision 5382)
+++ /tags/2.5.4/includes/common/formatting.php	(revision 5382)
@@ -0,0 +1,382 @@
+<?php
+
+/**
+ * bbPress Formatting
+ *
+ * @package bbPress
+ * @subpackage Formatting
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Kses **********************************************************************/
+
+/**
+ * Custom allowed tags for forum topics and replies
+ *
+ * Allows all users to post links, quotes, code, formatting, lists, and images
+ *
+ * @since bbPress (r4603)
+ *
+ * @return array Associative array of allowed tags and attributes
+ */
+function bbp_kses_allowed_tags() {
+	return apply_filters( 'bbp_kses_allowed_tags', array(
+
+		// Links
+		'a' => array(
+			'href'     => array(),
+			'title'    => array(),
+			'rel'      => array(),
+			'target'   => array()
+		),
+
+		// Quotes
+		'blockquote'   => array(
+			'cite'     => array()
+		),
+
+		// Code
+		'code'         => array(),
+		'pre'          => array(),
+
+		// Formatting
+		'em'           => array(),
+		'strong'       => array(),
+		'del'          => array(
+			'datetime' => true,
+		),
+
+		// Lists
+		'ul'           => array(),
+		'ol'           => array(
+			'start'    => true,
+		),
+		'li'           => array(),
+
+		// Images
+		'img'          => array(
+			'src'      => true,
+			'border'   => true,
+			'alt'      => true,
+			'height'   => true,
+			'width'    => true,
+		)
+	) );
+}
+
+/**
+ * Custom kses filter for forum topics and replies, for filtering incoming data
+ *
+ * @since bbPress (r4603)
+ *
+ * @param string $data Content to filter, expected to be escaped with slashes
+ * @return string Filtered content
+ */
+function bbp_filter_kses( $data = '' ) {
+	return addslashes( wp_kses( stripslashes( $data ), bbp_kses_allowed_tags() ) );
+}
+
+/**
+ * Custom kses filter for forum topics and replies, for raw data
+ *
+ * @since bbPress (r4603)
+ *
+ * @param string $data Content to filter, expected to not be escaped
+ * @return string Filtered content
+ */
+function bbp_kses_data( $data = '' ) {
+	return wp_kses( $data , bbp_kses_allowed_tags() );
+}
+
+/** Formatting ****************************************************************/
+
+/**
+ * Filter the topic or reply content and output code and pre tags
+ *
+ * @since bbPress (r4641)
+ *
+ * @param string $content Topic and reply content
+ * @return string Partially encodedd content
+ */
+function bbp_code_trick( $content = '' ) {
+	$content = str_replace( array( "\r\n", "\r" ), "\n", $content );
+	$content = preg_replace_callback( "|(`)(.*?)`|",      'bbp_encode_callback', $content );
+	$content = preg_replace_callback( "!(^|\n)`(.*?)`!s", 'bbp_encode_callback', $content );
+
+	return $content;
+}
+
+/**
+ * When editing a topic or reply, reverse the code trick so the textarea
+ * contains the correct editable content.
+ *
+ * @since bbPress (r4641)
+ *
+ * @param string $content Topic and reply content
+ * @return string Partially encodedd content
+ */
+function bbp_code_trick_reverse( $content = '' ) {
+
+	// Setup variables
+	$openers = array( '<p>', '<br />' );
+	$content = preg_replace_callback( "!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", 'bbp_decode_callback', $content );
+
+	// Do the do
+	$content = str_replace( $openers,       '',       $content );
+	$content = str_replace( '</p>',         "\n",     $content );
+	$content = str_replace( '<coded_br />', '<br />', $content );
+	$content = str_replace( '<coded_p>',    '<p>',    $content );
+	$content = str_replace( '</coded_p>',   '</p>',   $content );
+
+	return $content;
+}
+
+/**
+ * Filter the content and encode any bad HTML tags
+ *
+ * @since bbPress (r4641)
+ *
+ * @param string $content Topic and reply content
+ * @return string Partially encodedd content
+ */
+function bbp_encode_bad( $content = '' ) {
+
+	// Setup variables
+	$content = _wp_specialchars( $content, ENT_NOQUOTES );
+	$content = preg_split( '@(`[^`]*`)@m', $content, -1, PREG_SPLIT_NO_EMPTY + PREG_SPLIT_DELIM_CAPTURE );
+	$allowed = bbp_kses_allowed_tags();
+	$empty   = array(
+		'br'    => true,
+		'hr'    => true,
+		'img'   => true,
+		'input' => true,
+		'param' => true,
+		'area'  => true,
+		'col'   => true,
+		'embed' => true
+	);
+
+	// Loop through allowed tags and compare for empty and normal tags
+	foreach ( $allowed as $tag => $args ) {
+		$preg = $args ? "{$tag}(?:\s.*?)?" : $tag;
+
+		// Which walker to use based on the tag and arguments
+		if ( isset( $empty[$tag] ) ) {
+			array_walk( $content, 'bbp_encode_empty_callback',  $preg );
+		} else {
+			array_walk( $content, 'bbp_encode_normal_callback', $preg );
+		}
+	}
+
+	// Return the joined content array
+	return implode( '', $content );
+}
+
+/** Code Callbacks ************************************************************/
+
+/**
+ * Callback to encode the tags in topic or reply content
+ *
+ * @since bbPress (r4641)
+ *
+ * @param array $matches
+ * @return string
+ */
+function bbp_encode_callback( $matches = array() ) {
+
+	// Trim inline code, not pre blocks (to prevent removing indentation)
+	if ( "`" === $matches[1] ) {
+		$content = trim( $matches[2] );
+	} else {
+		$content = $matches[2];
+	}
+
+	// Do some replacing
+	$content = htmlspecialchars( $content, ENT_QUOTES );
+	$content = str_replace( array( "\r\n", "\r" ), "\n", $content );
+	$content = preg_replace( "|\n\n\n+|", "\n\n", $content );
+	$content = str_replace( '&amp;amp;', '&amp;', $content );
+	$content = str_replace( '&amp;lt;',  '&lt;',  $content );
+	$content = str_replace( '&amp;gt;',  '&gt;',  $content );
+
+	// Wrap in code tags
+	$content = '<code>' . $content . '</code>';
+
+	// Wrap blocks in pre tags
+	if ( "`" !== $matches[1] ) {
+		$content = "\n<pre>" . $content . "</pre>\n";
+	}
+
+	return $content;
+}
+
+/**
+ * Callback to decode the tags in topic or reply content
+ *
+ * @since bbPress (r4641)
+ *
+ * @param array $matches
+ * @todo Experiment with _wp_specialchars()
+ * @return string
+ */
+function bbp_decode_callback( $matches = array() ) {
+
+	// Setup variables
+	$trans_table = array_flip( get_html_translation_table( HTML_ENTITIES ) );
+	$amps        = array( '&#38;','&#038;', '&amp;' );
+	$single      = array( '&#39;','&#039;'          );
+	$content     = $matches[2];
+	$content     = strtr( $content, $trans_table );
+
+	// Do the do
+	$content = str_replace( '<br />', '<coded_br />', $content );
+	$content = str_replace( '<p>',    '<coded_p>',    $content );
+	$content = str_replace( '</p>',   '</coded_p>',   $content );
+	$content = str_replace( $amps,    '&',            $content );
+	$content = str_replace( $single,  "'",            $content );
+
+	// Return content wrapped in code tags
+	return '`' . $content . '`';
+}
+
+/**
+ * Callback to replace empty HTML tags in a content string
+ *
+ * @since bbPress (r4641)
+ *
+ * @internal Used by bbp_encode_bad()
+ * @param string $content
+ * @param string $key Not used
+ * @param string $preg
+ */
+function bbp_encode_empty_callback( &$content = '', $key = '', $preg = '' ) {
+	if ( strpos( $content, '`' ) !== 0 ) {
+		$content = preg_replace( "|&lt;({$preg})\s*?/*?&gt;|i", '<$1 />', $content );
+	}
+}
+
+/**
+ * Callback to replace normal HTML tags in a content string
+ *
+ * @since bbPress (r4641)
+ *
+ * @internal Used by bbp_encode_bad()
+ * @param type $content
+ * @param type $key
+ * @param type $preg
+ */
+function bbp_encode_normal_callback( &$content = '', $key = '', $preg = '') {
+	if ( strpos( $content, '`' ) !== 0 ) {
+		$content = preg_replace( "|&lt;(/?{$preg})&gt;|i", '<$1>', $content );
+	}
+}
+
+/** No Follow *****************************************************************/
+
+/**
+ * Catches links so rel=nofollow can be added (on output, not save)
+ *
+ * @since bbPress (r4865)
+ * @param string $text Post text
+ * @return string $text Text with rel=nofollow added to any links
+ */
+function bbp_rel_nofollow( $text = '' ) {
+	return preg_replace_callback( '|<a (.+?)>|i', 'bbp_rel_nofollow_callback', $text );
+}
+
+/**
+ * Adds rel=nofollow to a link
+ *
+ * @since bbPress (r4865)
+ * @param array $matches
+ * @return string $text Link with rel=nofollow added
+ */
+function bbp_rel_nofollow_callback( $matches = array() ) {
+	$text = $matches[1];
+	$text = str_replace( array( ' rel="nofollow"', " rel='nofollow'" ), '', $text );
+	return "<a $text rel=\"nofollow\">";
+}
+
+/** Make Clickable ************************************************************/
+
+/**
+ * Convert plaintext URI to HTML links.
+ *
+ * Converts URI, www and ftp, and email addresses. Finishes by fixing links
+ * within links.
+ *
+ * This custom version of WordPress's make_clickable() skips links inside of
+ * pre and code tags.
+ *
+ * @since bbPress (r4941)
+ *
+ * @param string $text Content to convert URIs.
+ * @return string Content with converted URIs.
+ */
+function bbp_make_clickable( $text ) {
+	$r       = '';
+	$in_code = false;
+	$textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
+
+	foreach ( $textarr as $piece ) {
+
+		switch ( $piece ) {
+			case '<code>' :
+			case '<pre>'  :
+				$in_code = true;
+				break;
+			case '</code>' :
+			case '</pre>'  :
+				$in_code = false;
+				break;
+		}
+
+		if ( $in_code || empty( $piece ) || ( $piece[0] === '<' && ! preg_match('|^<\s*[\w]{1,20}+://|', $piece) ) ) {
+			$r .= $piece;
+			continue;
+		}
+
+		// Long strings might contain expensive edge cases ...
+		if ( 10000 < strlen( $piece ) ) {
+			// ... break it up
+			foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
+				if ( 2101 < strlen( $chunk ) ) {
+					$r .= $chunk; // Too big, no whitespace: bail.
+				} else {
+					$r .= make_clickable( $chunk );
+				}
+			}
+		} else {
+			$ret = " $piece "; // Pad with whitespace to simplify the regexes
+
+			$url_clickable = '~
+				([\\s(<.,;:!?])                                        # 1: Leading whitespace, or punctuation
+				(                                                      # 2: URL
+					[\\w]{1,20}+://                                # Scheme and hier-part prefix
+					(?=\S{1,2000}\s)                               # Limit to URLs less than about 2000 characters long
+					[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+         # Non-punctuation URL character
+					(?:                                            # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
+						[\'.,;:!?)]                            # Punctuation URL character
+						[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
+					)*
+				)
+				(\)?)                                                  # 3: Trailing closing parenthesis (for parethesis balancing post processing)
+			~xS'; // The regex is a non-anchored pattern and does not have a single fixed starting character.
+			      // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
+
+			$ret = preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $ret );
+
+			$ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret );
+			$ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret );
+
+			$ret = substr( $ret, 1, -1 ); // Remove our whitespace padding.
+			$r .= $ret;
+		}
+	}
+
+	// Cleanup of accidental links within links
+	$r = preg_replace( '#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r );
+	return $r;
+}
Index: /tags/2.5.4/includes/common/functions.php
===================================================================
--- /tags/2.5.4/includes/common/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/common/functions.php	(revision 5382)
@@ -0,0 +1,1954 @@
+<?php
+
+/**
+ * bbPress Common Functions
+ *
+ * Common functions are ones that are used by more than one component, like
+ * forums, topics, replies, users, topic tags, etc...
+ *
+ * @package bbPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Formatting ****************************************************************/
+
+/**
+ * A bbPress specific method of formatting numeric values
+ *
+ * @since bbPress (r2486)
+ *
+ * @param string $number Number to format
+ * @param string $decimals Optional. Display decimals
+ * @uses apply_filters() Calls 'bbp_number_format' with the formatted values,
+ *                        number and display decimals bool
+ * @return string Formatted string
+ */
+function bbp_number_format( $number = 0, $decimals = false, $dec_point = '.', $thousands_sep = ',' ) {
+
+	// If empty, set $number to (int) 0
+	if ( ! is_numeric( $number ) )
+		$number = 0;
+
+	return apply_filters( 'bbp_number_format', number_format( $number, $decimals, $dec_point, $thousands_sep ), $number, $decimals, $dec_point, $thousands_sep );
+}
+
+/**
+ * A bbPress specific method of formatting numeric values
+ *
+ * @since bbPress (r3857)
+ *
+ * @param string $number Number to format
+ * @param string $decimals Optional. Display decimals
+ * @uses apply_filters() Calls 'bbp_number_format' with the formatted values,
+ *                        number and display decimals bool
+ * @return string Formatted string
+ */
+function bbp_number_format_i18n( $number = 0, $decimals = false ) {
+
+	// If empty, set $number to (int) 0
+	if ( ! is_numeric( $number ) )
+		$number = 0;
+
+	return apply_filters( 'bbp_number_format_i18n', number_format_i18n( $number, $decimals ), $number, $decimals );
+}
+
+/**
+ * Convert time supplied from database query into specified date format.
+ *
+ * @since bbPress (r2455)
+ *
+ * @param int|object $post Optional. Default is global post object. A post_id or
+ *                          post object
+ * @param string $d Optional. Default is 'U'. Either 'G', 'U', or php date
+ *                             format
+ * @param bool $translate Optional. Default is false. Whether to translate the
+ *                                   result
+ * @uses mysql2date() To convert the format
+ * @uses apply_filters() Calls 'bbp_convert_date' with the time, date format
+ *                        and translate bool
+ * @return string Returns timestamp
+ */
+function bbp_convert_date( $time, $d = 'U', $translate = false ) {
+	$time = mysql2date( $d, $time, $translate );
+
+	return apply_filters( 'bbp_convert_date', $time, $d, $translate );
+}
+
+/**
+ * Output formatted time to display human readable time difference.
+ *
+ * @since bbPress (r2544)
+ *
+ * @param string $older_date Unix timestamp from which the difference begins.
+ * @param string $newer_date Optional. Unix timestamp from which the
+ *                            difference ends. False for current time.
+ * @param int $gmt Optional. Whether to use GMT timezone. Default is false.
+ * @uses bbp_get_time_since() To get the formatted time
+ */
+function bbp_time_since( $older_date, $newer_date = false, $gmt = false ) {
+	echo bbp_get_time_since( $older_date, $newer_date, $gmt );
+}
+	/**
+	 * Return formatted time to display human readable time difference.
+	 *
+	 * @since bbPress (r2544)
+	 *
+	 * @param string $older_date Unix timestamp from which the difference begins.
+	 * @param string $newer_date Optional. Unix timestamp from which the
+	 *                            difference ends. False for current time.
+	 * @param int $gmt Optional. Whether to use GMT timezone. Default is false.
+	 * @uses current_time() To get the current time in mysql format
+	 * @uses human_time_diff() To get the time differene in since format
+	 * @uses apply_filters() Calls 'bbp_get_time_since' with the time
+	 *                        difference and time
+	 * @return string Formatted time
+	 */
+	function bbp_get_time_since( $older_date, $newer_date = false, $gmt = false ) {
+
+		// Setup the strings
+		$unknown_text   = apply_filters( 'bbp_core_time_since_unknown_text',   __( 'sometime',  'bbpress' ) );
+		$right_now_text = apply_filters( 'bbp_core_time_since_right_now_text', __( 'right now', 'bbpress' ) );
+		$ago_text       = apply_filters( 'bbp_core_time_since_ago_text',       __( '%s ago',    'bbpress' ) );
+
+		// array of time period chunks
+		$chunks = array(
+			array( 60 * 60 * 24 * 365 , __( 'year',   'bbpress' ), __( 'years',   'bbpress' ) ),
+			array( 60 * 60 * 24 * 30 ,  __( 'month',  'bbpress' ), __( 'months',  'bbpress' ) ),
+			array( 60 * 60 * 24 * 7,    __( 'week',   'bbpress' ), __( 'weeks',   'bbpress' ) ),
+			array( 60 * 60 * 24 ,       __( 'day',    'bbpress' ), __( 'days',    'bbpress' ) ),
+			array( 60 * 60 ,            __( 'hour',   'bbpress' ), __( 'hours',   'bbpress' ) ),
+			array( 60 ,                 __( 'minute', 'bbpress' ), __( 'minutes', 'bbpress' ) ),
+			array( 1,                   __( 'second', 'bbpress' ), __( 'seconds', 'bbpress' ) )
+		);
+
+		if ( !empty( $older_date ) && !is_numeric( $older_date ) ) {
+			$time_chunks = explode( ':', str_replace( ' ', ':', $older_date ) );
+			$date_chunks = explode( '-', str_replace( ' ', '-', $older_date ) );
+			$older_date  = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
+		}
+
+		// $newer_date will equal false if we want to know the time elapsed
+		// between a date and the current time. $newer_date will have a value if
+		// we want to work out time elapsed between two known dates.
+		$newer_date = ( !$newer_date ) ? strtotime( current_time( 'mysql', $gmt ) ) : $newer_date;
+
+		// Difference in seconds
+		$since = $newer_date - $older_date;
+
+		// Something went wrong with date calculation and we ended up with a negative date.
+		if ( 0 > $since ) {
+			$output = $unknown_text;
+
+		// We only want to output two chunks of time here, eg:
+		//     x years, xx months
+		//     x days, xx hours
+		// so there's only two bits of calculation below:
+		} else {
+
+			// Step one: the first chunk
+			for ( $i = 0, $j = count( $chunks ); $i < $j; ++$i ) {
+				$seconds = $chunks[$i][0];
+
+				// Finding the biggest chunk (if the chunk fits, break)
+				$count = floor( $since / $seconds );
+				if ( 0 != $count ) {
+					break;
+				}
+			}
+
+			// If $i iterates all the way to $j, then the event happened 0 seconds ago
+			if ( !isset( $chunks[$i] ) ) {
+				$output = $right_now_text;
+
+			} else {
+
+				// Set output var
+				$output = ( 1 == $count ) ? '1 '. $chunks[$i][1] : $count . ' ' . $chunks[$i][2];
+
+				// Step two: the second chunk
+				if ( $i + 2 < $j ) {
+					$seconds2 = $chunks[$i + 1][0];
+					$name2    = $chunks[$i + 1][1];
+					$count2   = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
+
+					// Add to output var
+					if ( 0 != $count2 ) {
+						$output .= ( 1 == $count2 ) ? _x( ',', 'Separator in time since', 'bbpress' ) . ' 1 '. $name2 : _x( ',', 'Separator in time since', 'bbpress' ) . ' ' . $count2 . ' ' . $chunks[$i + 1][2];
+					}
+				}
+
+				// No output, so happened right now
+				if ( ! (int) trim( $output ) ) {
+					$output = $right_now_text;
+				}
+			}
+		}
+
+		// Append 'ago' to the end of time-since if not 'right now'
+		if ( $output != $right_now_text ) {
+			$output = sprintf( $ago_text, $output );
+		}
+
+		return apply_filters( 'bbp_get_time_since', $output, $older_date, $newer_date );
+	}
+
+/**
+ * Formats the reason for editing the topic/reply.
+ *
+ * Does these things:
+ *  - Trimming
+ *  - Removing periods from the end of the string
+ *  - Trimming again
+ *
+ * @since bbPress (r2782)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @return string Status of topic
+ */
+function bbp_format_revision_reason( $reason = '' ) {
+	$reason = (string) $reason;
+
+	// Format reason for proper display
+	if ( empty( $reason ) )
+		return $reason;
+
+	// Trimming
+	$reason = trim( $reason );
+
+	// We add our own full stop.
+	while ( substr( $reason, -1 ) === '.' )
+		$reason = substr( $reason, 0, -1 );
+
+	// Trim again
+	$reason = trim( $reason );
+
+	return $reason;
+}
+
+/** Misc **********************************************************************/
+
+/**
+ * Return the unescaped redirect_to request value
+ *
+ * @bbPress (r4655)
+ *
+ * @return string The URL to redirect to, if set
+ */
+function bbp_get_redirect_to() {
+	$retval = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
+
+	return apply_filters( 'bbp_get_redirect_to', $retval );
+}
+
+/**
+ * Append 'view=all' to query string if it's already there from referer
+ *
+ * @since bbPress (r3325)
+ *
+ * @param string $original_link Original Link to be modified
+ * @param bool $force Override bbp_get_view_all() check
+ * @uses current_user_can() To check if the current user can moderate
+ * @uses add_query_arg() To add args to the url
+ * @uses apply_filters() Calls 'bbp_add_view_all' with the link and original link
+ * @return string The link with 'view=all' appended if necessary
+ */
+function bbp_add_view_all( $original_link = '', $force = false ) {
+
+	// Are we appending the view=all vars?
+	if ( bbp_get_view_all() || !empty( $force ) ) {
+		$link = add_query_arg( array( 'view' => 'all' ), $original_link );
+	} else {
+		$link = $original_link;
+	}
+
+	return apply_filters( 'bbp_add_view_all', $link, $original_link );
+}
+
+/**
+ * Remove 'view=all' from query string
+ *
+ * @since bbPress (r3325)
+ *
+ * @param string $original_link Original Link to be modified
+ * @uses current_user_can() To check if the current user can moderate
+ * @uses add_query_arg() To add args to the url
+ * @uses apply_filters() Calls 'bbp_add_view_all' with the link and original link
+ * @return string The link with 'view=all' appended if necessary
+ */
+function bbp_remove_view_all( $original_link = '' ) {
+	return apply_filters( 'bbp_add_view_all', remove_query_arg( 'view', $original_link ), $original_link );
+}
+
+/**
+ * If current user can and is vewing all topics/replies
+ *
+ * @since bbPress (r3325)
+ *
+ * @uses current_user_can() To check if the current user can moderate
+ * @uses apply_filters() Calls 'bbp_get_view_all' with the link and original link
+ * @return bool Whether current user can and is viewing all
+ */
+function bbp_get_view_all( $cap = 'moderate' ) {
+	$retval = ( ( !empty( $_GET['view'] ) && ( 'all' === $_GET['view'] ) && current_user_can( $cap ) ) );
+	return apply_filters( 'bbp_get_view_all', (bool) $retval );
+}
+
+/**
+ * Assist pagination by returning correct page number
+ *
+ * @since bbPress (r2628)
+ *
+ * @uses get_query_var() To get the 'paged' value
+ * @return int Current page number
+ */
+function bbp_get_paged() {
+	global $wp_query;
+
+	// Check the query var
+	if ( get_query_var( 'paged' ) ) {
+		$paged = get_query_var( 'paged' );
+
+	// Check query paged
+	} elseif ( !empty( $wp_query->query['paged'] ) ) {
+		$paged = $wp_query->query['paged'];
+	}
+
+	// Paged found
+	if ( !empty( $paged ) )
+		return (int) $paged;
+
+	// Default to first page
+	return 1;
+}
+
+/**
+ * Fix post author id on post save
+ *
+ * When a logged in user changes the status of an anonymous reply or topic, or
+ * edits it, the post_author field is set to the logged in user's id. This
+ * function fixes that.
+ *
+ * @since bbPress (r2734)
+ *
+ * @param array $data Post data
+ * @param array $postarr Original post array (includes post id)
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_is_topic_anonymous() To check if the topic is by an anonymous user
+ * @uses bbp_is_reply_anonymous() To check if the reply is by an anonymous user
+ * @return array Data
+ */
+function bbp_fix_post_author( $data = array(), $postarr = array() ) {
+
+	// Post is not being updated or the post_author is already 0, return
+	if ( empty( $postarr['ID'] ) || empty( $data['post_author'] ) )
+		return $data;
+
+	// Post is not a topic or reply, return
+	if ( !in_array( $data['post_type'], array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ) ) )
+		return $data;
+
+	// Is the post by an anonymous user?
+	if ( ( bbp_get_topic_post_type() === $data['post_type'] && !bbp_is_topic_anonymous( $postarr['ID'] ) ) ||
+	     ( bbp_get_reply_post_type() === $data['post_type'] && !bbp_is_reply_anonymous( $postarr['ID'] ) ) )
+		return $data;
+
+	// The post is being updated. It is a topic or a reply and is written by an anonymous user.
+	// Set the post_author back to 0
+	$data['post_author'] = 0;
+
+	return $data;
+}
+
+/**
+ * Check the date against the _bbp_edit_lock setting.
+ *
+ * @since bbPress (r3133)
+ *
+ * @param string $post_date_gmt
+ *
+ * @uses get_option() Get the edit lock time
+ * @uses current_time() Get the current time
+ * @uses strtotime() Convert strings to time
+ * @uses apply_filters() Allow output to be manipulated
+ *
+ * @return bool
+ */
+function bbp_past_edit_lock( $post_date_gmt ) {
+
+	// Assume editing is allowed
+	$retval = false;
+
+	// Bail if empty date
+	if ( ! empty( $post_date_gmt ) ) {
+
+		// Period of time
+		$lockable  = '+' . get_option( '_bbp_edit_lock', '5' ) . ' minutes';
+
+		// Now
+		$cur_time  = current_time( 'timestamp', true );
+
+		// Add lockable time to post time
+		$lock_time = strtotime( $lockable, strtotime( $post_date_gmt ) );
+
+		// Compare
+		if ( $cur_time >= $lock_time ) {
+			$retval = true;
+		}
+	}
+
+	return apply_filters( 'bbp_past_edit_lock', (bool) $retval, $cur_time, $lock_time, $post_date_gmt );
+}
+
+/** Statistics ****************************************************************/
+
+/**
+ * Get the forum statistics
+ *
+ * @since bbPress (r2769)
+ *
+ * @param mixed $args Optional. The function supports these arguments (all
+ *                     default to true):
+ *  - count_users: Count users?
+ *  - count_forums: Count forums?
+ *  - count_topics: Count topics? If set to false, private, spammed and trashed
+ *                   topics are also not counted.
+ *  - count_private_topics: Count private topics? (only counted if the current
+ *                           user has read_private_topics cap)
+ *  - count_spammed_topics: Count spammed topics? (only counted if the current
+ *                           user has edit_others_topics cap)
+ *  - count_trashed_topics: Count trashed topics? (only counted if the current
+ *                           user has view_trash cap)
+ *  - count_replies: Count replies? If set to false, private, spammed and
+ *                   trashed replies are also not counted.
+ *  - count_private_replies: Count private replies? (only counted if the current
+ *                           user has read_private_replies cap)
+ *  - count_spammed_replies: Count spammed replies? (only counted if the current
+ *                           user has edit_others_replies cap)
+ *  - count_trashed_replies: Count trashed replies? (only counted if the current
+ *                           user has view_trash cap)
+ *  - count_tags: Count tags? If set to false, empty tags are also not counted
+ *  - count_empty_tags: Count empty tags?
+ * @uses bbp_count_users() To count the number of registered users
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wp_count_posts() To count the number of forums, topics and replies
+ * @uses wp_count_terms() To count the number of topic tags
+ * @uses current_user_can() To check if the user is capable of doing things
+ * @uses number_format_i18n() To format the number
+ * @uses apply_filters() Calls 'bbp_get_statistics' with the statistics and args
+ * @return object Walked forum tree
+ */
+function bbp_get_statistics( $args = '' ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'count_users'           => true,
+		'count_forums'          => true,
+		'count_topics'          => true,
+		'count_private_topics'  => true,
+		'count_spammed_topics'  => true,
+		'count_trashed_topics'  => true,
+		'count_replies'         => true,
+		'count_private_replies' => true,
+		'count_spammed_replies' => true,
+		'count_trashed_replies' => true,
+		'count_tags'            => true,
+		'count_empty_tags'      => true
+	), 'get_statistics' );
+
+	// Defaults
+	$user_count            = 0;
+	$forum_count           = 0;
+	$topic_count           = 0;
+	$topic_count_hidden    = 0;
+	$reply_count           = 0;
+	$reply_count_hidden    = 0;
+	$topic_tag_count       = 0;
+	$empty_topic_tag_count = 0;
+
+	// Users
+	if ( !empty( $r['count_users'] ) ) {
+		$user_count = bbp_get_total_users();
+	}
+
+	// Forums
+	if ( !empty( $r['count_forums'] ) ) {
+		$forum_count = wp_count_posts( bbp_get_forum_post_type() )->publish;
+	}
+
+	// Post statuses
+	$private = bbp_get_private_status_id();
+	$spam    = bbp_get_spam_status_id();
+	$trash   = bbp_get_trash_status_id();
+	$closed  = bbp_get_closed_status_id();
+
+	// Topics
+	if ( !empty( $r['count_topics'] ) ) {
+		$all_topics  = wp_count_posts( bbp_get_topic_post_type() );
+
+		// Published (publish + closed)
+		$topic_count = $all_topics->publish + $all_topics->{$closed};
+
+		if ( current_user_can( 'read_private_topics' ) || current_user_can( 'edit_others_topics' ) || current_user_can( 'view_trash' ) ) {
+
+			// Private
+			$topics['private'] = ( !empty( $r['count_private_topics'] ) && current_user_can( 'read_private_topics' ) ) ? (int) $all_topics->{$private} : 0;
+
+			// Spam
+			$topics['spammed'] = ( !empty( $r['count_spammed_topics'] ) && current_user_can( 'edit_others_topics'  ) ) ? (int) $all_topics->{$spam}    : 0;
+
+			// Trash
+			$topics['trashed'] = ( !empty( $r['count_trashed_topics'] ) && current_user_can( 'view_trash'          ) ) ? (int) $all_topics->{$trash}   : 0;
+
+			// Total hidden (private + spam + trash)
+			$topic_count_hidden = $topics['private'] + $topics['spammed'] + $topics['trashed'];
+
+			// Generate the hidden topic count's title attribute
+			$topic_titles[] = !empty( $topics['private'] ) ? sprintf( __( 'Private: %s', 'bbpress' ), number_format_i18n( $topics['private'] ) ) : '';
+			$topic_titles[] = !empty( $topics['spammed'] ) ? sprintf( __( 'Spammed: %s', 'bbpress' ), number_format_i18n( $topics['spammed'] ) ) : '';
+			$topic_titles[] = !empty( $topics['trashed'] ) ? sprintf( __( 'Trashed: %s', 'bbpress' ), number_format_i18n( $topics['trashed'] ) ) : '';
+
+			// Compile the hidden topic title
+			$hidden_topic_title = implode( ' | ', array_filter( $topic_titles ) );
+		}
+	}
+
+	// Replies
+	if ( !empty( $r['count_replies'] ) ) {
+
+		$all_replies = wp_count_posts( bbp_get_reply_post_type() );
+
+		// Published
+		$reply_count = $all_replies->publish;
+
+		if ( current_user_can( 'read_private_replies' ) || current_user_can( 'edit_others_replies' ) || current_user_can( 'view_trash' ) ) {
+
+			// Private
+			$replies['private'] = ( !empty( $r['count_private_replies'] ) && current_user_can( 'read_private_replies' ) ) ? (int) $all_replies->{$private} : 0;
+
+			// Spam
+			$replies['spammed'] = ( !empty( $r['count_spammed_replies'] ) && current_user_can( 'edit_others_replies'  ) ) ? (int) $all_replies->{$spam}    : 0;
+
+			// Trash
+			$replies['trashed'] = ( !empty( $r['count_trashed_replies'] ) && current_user_can( 'view_trash'           ) ) ? (int) $all_replies->{$trash}   : 0;
+
+			// Total hidden (private + spam + trash)
+			$reply_count_hidden = $replies['private'] + $replies['spammed'] + $replies['trashed'];
+
+			// Generate the hidden topic count's title attribute
+			$reply_titles[] = !empty( $replies['private'] ) ? sprintf( __( 'Private: %s', 'bbpress' ), number_format_i18n( $replies['private'] ) ) : '';
+			$reply_titles[] = !empty( $replies['spammed'] ) ? sprintf( __( 'Spammed: %s', 'bbpress' ), number_format_i18n( $replies['spammed'] ) ) : '';
+			$reply_titles[] = !empty( $replies['trashed'] ) ? sprintf( __( 'Trashed: %s', 'bbpress' ), number_format_i18n( $replies['trashed'] ) ) : '';
+
+			// Compile the hidden replies title
+			$hidden_reply_title = implode( ' | ', array_filter( $reply_titles ) );
+
+		}
+	}
+
+	// Topic Tags
+	if ( !empty( $r['count_tags'] ) && bbp_allow_topic_tags() ) {
+
+		// Get the count
+		$topic_tag_count = wp_count_terms( bbp_get_topic_tag_tax_id(), array( 'hide_empty' => true ) );
+
+		// Empty tags
+		if ( !empty( $r['count_empty_tags'] ) && current_user_can( 'edit_topic_tags' ) ) {
+			$empty_topic_tag_count = wp_count_terms( bbp_get_topic_tag_tax_id() ) - $topic_tag_count;
+		}
+	}
+
+	// Tally the tallies
+	$statistics = array_map( 'number_format_i18n', array_map( 'absint', compact(
+		'user_count',
+		'forum_count',
+		'topic_count',
+		'topic_count_hidden',
+		'reply_count',
+		'reply_count_hidden',
+		'topic_tag_count',
+		'empty_topic_tag_count'
+	) ) );
+
+	// Add the hidden (topic/reply) count title attribute strings because we
+	// don't need to run the math functions on these (see above)
+	$statistics['hidden_topic_title'] = isset( $hidden_topic_title ) ? $hidden_topic_title : '';
+	$statistics['hidden_reply_title'] = isset( $hidden_reply_title ) ? $hidden_reply_title : '';
+
+	return apply_filters( 'bbp_get_statistics', $statistics, $r );
+}
+
+/** New/edit topic/reply helpers **********************************************/
+
+/**
+ * Filter anonymous post data
+ *
+ * We use REMOTE_ADDR here directly. If you are behind a proxy, you should
+ * ensure that it is properly set, such as in wp-config.php, for your
+ * environment. See {@link http://core.trac.wordpress.org/ticket/9235}
+ *
+ * Note that bbp_pre_anonymous_filters() is responsible for sanitizing each
+ * of the filtered core anonymous values here.
+ *
+ * If there are any errors, those are directly added to {@link bbPress:errors}
+ *
+ * @since bbPress (r2734)
+ *
+ * @param mixed $args Optional. If no args are there, then $_POST values are
+ *                     used.
+ * @uses apply_filters() Calls 'bbp_pre_anonymous_post_author_name' with the
+ *                        anonymous user name
+ * @uses apply_filters() Calls 'bbp_pre_anonymous_post_author_email' with the
+ *                        anonymous user email
+ * @uses apply_filters() Calls 'bbp_pre_anonymous_post_author_website' with the
+ *                        anonymous user website
+ * @return bool|array False on errors, values in an array on success
+ */
+function bbp_filter_anonymous_post_data( $args = '' ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array (
+		'bbp_anonymous_name'    => !empty( $_POST['bbp_anonymous_name']    ) ? $_POST['bbp_anonymous_name']    : false,
+		'bbp_anonymous_email'   => !empty( $_POST['bbp_anonymous_email']   ) ? $_POST['bbp_anonymous_email']   : false,
+		'bbp_anonymous_website' => !empty( $_POST['bbp_anonymous_website'] ) ? $_POST['bbp_anonymous_website'] : false,
+	), 'filter_anonymous_post_data' );
+
+	// Filter variables and add errors if necessary
+	$r['bbp_anonymous_name'] = apply_filters( 'bbp_pre_anonymous_post_author_name',  $r['bbp_anonymous_name']  );
+	if ( empty( $r['bbp_anonymous_name'] ) )
+		bbp_add_error( 'bbp_anonymous_name',  __( '<strong>ERROR</strong>: Invalid author name submitted!',   'bbpress' ) );
+
+	$r['bbp_anonymous_email'] = apply_filters( 'bbp_pre_anonymous_post_author_email', $r['bbp_anonymous_email'] );
+	if ( empty( $r['bbp_anonymous_email'] ) )
+		bbp_add_error( 'bbp_anonymous_email', __( '<strong>ERROR</strong>: Invalid email address submitted!', 'bbpress' ) );
+
+	// Website is optional
+	$r['bbp_anonymous_website'] = apply_filters( 'bbp_pre_anonymous_post_author_website', $r['bbp_anonymous_website'] );
+
+	// Return false if we have any errors
+	$retval = bbp_has_errors() ? false : $r;
+
+	// Finally, return sanitized data or false
+	return apply_filters( 'bbp_filter_anonymous_post_data', $retval, $r );
+}
+
+/**
+ * Check for duplicate topics/replies
+ *
+ * Check to make sure that a user is not making a duplicate post
+ *
+ * @since bbPress (r2763)
+ *
+ * @param array $post_data Contains information about the comment
+ * @uses current_user_can() To check if the current user can throttle
+ * @uses get_meta_sql() To generate the meta sql for checking anonymous email
+ * @uses apply_filters() Calls 'bbp_check_for_duplicate_query' with the
+ *                        duplicate check query and post data
+ * @uses wpdb::get_var() To execute our query and get the var back
+ * @uses get_post_meta() To get the anonymous user email post meta
+ * @uses do_action() Calls 'bbp_post_duplicate_trigger' with the post data when
+ *                    it is found that it is a duplicate
+ * @return bool True if it is not a duplicate, false if it is
+ */
+function bbp_check_for_duplicate( $post_data = array() ) {
+
+	// No duplicate checks for those who can throttle
+	if ( current_user_can( 'throttle' ) )
+		return true;
+
+	// Define global to use get_meta_sql() and get_var() methods
+	global $wpdb;
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $post_data, array(
+		'post_author'    => 0,
+		'post_type'      => array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ),
+		'post_parent'    => 0,
+		'post_content'   => '',
+		'post_status'    => bbp_get_trash_status_id(),
+		'anonymous_data' => false
+	), 'check_for_duplicate' );
+
+	// Check for anonymous post
+	if ( empty( $r['post_author'] ) && ( !empty( $r['anonymous_data'] ) && !empty( $r['anonymous_data']['bbp_anonymous_email'] ) ) ) {
+		$clauses = get_meta_sql( array( array(
+			'key'   => '_bbp_anonymous_email',
+			'value' => $r['anonymous_data']['bbp_anonymous_email']
+		) ), 'post', $wpdb->posts, 'ID' );
+
+		$join    = $clauses['join'];
+		$where   = $clauses['where'];
+	} else {
+		$join    = $where = '';
+	}
+
+	// Unslash $r to pass through $wpdb->prepare()
+	//
+	// @see: http://bbpress.trac.wordpress.org/ticket/2185/
+	// @see: http://core.trac.wordpress.org/changeset/23973/
+	$r = function_exists( 'wp_unslash' ) ? wp_unslash( $r ) : stripslashes_deep( $r );
+
+	// Prepare duplicate check query
+	$query  = $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} {$join} WHERE post_type = %s AND post_status != %s AND post_author = %d AND post_content = %s {$where}", $r['post_type'], $r['post_status'], $r['post_author'], $r['post_content'] );
+	$query .= !empty( $r['post_parent'] ) ? $wpdb->prepare( " AND post_parent = %d", $r['post_parent'] ) : '';
+	$query .= " LIMIT 1";
+	$dupe   = apply_filters( 'bbp_check_for_duplicate_query', $query, $r );
+
+	if ( $wpdb->get_var( $dupe ) ) {
+		do_action( 'bbp_check_for_duplicate_trigger', $post_data );
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * Check for flooding
+ *
+ * Check to make sure that a user is not making too many posts in a short amount
+ * of time.
+ *
+ * @since bbPress (r2734)
+ *
+ * @param false|array $anonymous_data Optional - if it's an anonymous post. Do
+ *                                     not supply if supplying $author_id.
+ *                                     Should have key 'bbp_author_ip'.
+ *                                     Should be sanitized (see
+ *                                     {@link bbp_filter_anonymous_post_data()}
+ *                                     for sanitization)
+ * @param int $author_id Optional. Supply if it's a post by a logged in user.
+ *                        Do not supply if supplying $anonymous_data.
+ * @uses get_option() To get the throttle time
+ * @uses get_transient() To get the last posted transient of the ip
+ * @uses bbp_get_user_last_posted() To get the last posted time of the user
+ * @uses current_user_can() To check if the current user can throttle
+ * @return bool True if there is no flooding, false if there is
+ */
+function bbp_check_for_flood( $anonymous_data = false, $author_id = 0 ) {
+
+	// Option disabled. No flood checks.
+	$throttle_time = get_option( '_bbp_throttle_time' );
+	if ( empty( $throttle_time ) )
+		return true;
+
+	// User is anonymous, so check a transient based on the IP
+	if ( !empty( $anonymous_data ) && is_array( $anonymous_data ) ) {
+		$last_posted = get_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted' );
+
+		if ( !empty( $last_posted ) && time() < $last_posted + $throttle_time ) {
+			return false;
+		}
+
+	// User is logged in, so check their last posted time
+	} elseif ( !empty( $author_id ) ) {
+		$author_id   = (int) $author_id;
+		$last_posted = bbp_get_user_last_posted( $author_id );
+
+		if ( isset( $last_posted ) && time() < $last_posted + $throttle_time && !current_user_can( 'throttle' ) ) {
+			return false;
+		}
+	} else {
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * Checks topics and replies against the discussion moderation of blocked keys
+ *
+ * @since bbPress (r3581)
+ *
+ * @param array $anonymous_data Anonymous user data
+ * @param int $author_id Topic or reply author ID
+ * @param string $title The title of the content
+ * @param string $content The content being posted
+ * @uses bbp_is_user_keymaster() Allow keymasters to bypass blacklist
+ * @uses bbp_current_author_ip() To get current user IP address
+ * @uses bbp_current_author_ua() To get current user agent
+ * @return bool True if test is passed, false if fail
+ */
+function bbp_check_for_moderation( $anonymous_data = false, $author_id = 0, $title = '', $content = '' ) {
+
+	// Allow for moderation check to be skipped
+	if ( apply_filters( 'bbp_bypass_check_for_moderation', false, $anonymous_data, $author_id, $title, $content ) )
+		return true;
+
+	// Bail if keymaster is author
+	if ( !empty( $author_id ) && bbp_is_user_keymaster( $author_id ) )
+		return true;
+
+	// Define local variable(s)
+	$_post     = array();
+	$match_out = '';
+
+	/** Blacklist *************************************************************/
+
+	// Get the moderation keys
+	$blacklist = trim( get_option( 'moderation_keys' ) );
+
+	// Bail if blacklist is empty
+	if ( empty( $blacklist ) )
+		return true;
+
+	/** User Data *************************************************************/
+
+	// Map anonymous user data
+	if ( !empty( $anonymous_data ) ) {
+		$_post['author'] = $anonymous_data['bbp_anonymous_name'];
+		$_post['email']  = $anonymous_data['bbp_anonymous_email'];
+		$_post['url']    = $anonymous_data['bbp_anonymous_website'];
+
+	// Map current user data
+	} elseif ( !empty( $author_id ) ) {
+
+		// Get author data
+		$user = get_userdata( $author_id );
+
+		// If data exists, map it
+		if ( !empty( $user ) ) {
+			$_post['author'] = $user->display_name;
+			$_post['email']  = $user->user_email;
+			$_post['url']    = $user->user_url;
+		}
+	}
+
+	// Current user IP and user agent
+	$_post['user_ip'] = bbp_current_author_ip();
+	$_post['user_ua'] = bbp_current_author_ua();
+
+	// Post title and content
+	$_post['title']   = $title;
+	$_post['content'] = $content;
+
+	/** Max Links *************************************************************/
+
+	$max_links = get_option( 'comment_max_links' );
+	if ( !empty( $max_links ) ) {
+
+		// How many links?
+		$num_links = preg_match_all( '/<a [^>]*href/i', $content, $match_out );
+
+		// Allow for bumping the max to include the user's URL
+		$num_links = apply_filters( 'comment_max_links_url', $num_links, $_post['url'] );
+
+		// Das ist zu viele links!
+		if ( $num_links >= $max_links ) {
+			return false;
+		}
+	}
+
+	/** Words *****************************************************************/
+
+	// Get words separated by new lines
+	$words = explode( "\n", $blacklist );
+
+	// Loop through words
+	foreach ( (array) $words as $word ) {
+
+		// Trim the whitespace from the word
+		$word = trim( $word );
+
+		// Skip empty lines
+		if ( empty( $word ) ) { continue; }
+
+		// Do some escaping magic so that '#' chars in the
+		// spam words don't break things:
+		$word    = preg_quote( $word, '#' );
+		$pattern = "#$word#i";
+
+		// Loop through post data
+		foreach ( $_post as $post_data ) {
+
+			// Check each user data for current word
+			if ( preg_match( $pattern, $post_data ) ) {
+
+				// Post does not pass
+				return false;
+			}
+		}
+	}
+
+	// Check passed successfully
+	return true;
+}
+
+/**
+ * Checks topics and replies against the discussion blacklist of blocked keys
+ *
+ * @since bbPress (r3446)
+ *
+ * @param array $anonymous_data Anonymous user data
+ * @param int $author_id Topic or reply author ID
+ * @param string $title The title of the content
+ * @param string $content The content being posted
+ * @uses bbp_is_user_keymaster() Allow keymasters to bypass blacklist
+ * @uses bbp_current_author_ip() To get current user IP address
+ * @uses bbp_current_author_ua() To get current user agent
+ * @return bool True if test is passed, false if fail
+ */
+function bbp_check_for_blacklist( $anonymous_data = false, $author_id = 0, $title = '', $content = '' ) {
+
+	// Allow for blacklist check to be skipped
+	if ( apply_filters( 'bbp_bypass_check_for_blacklist', false, $anonymous_data, $author_id, $title, $content ) )
+		return true;
+
+	// Bail if keymaster is author
+	if ( !empty( $author_id ) && bbp_is_user_keymaster( $author_id ) )
+		return true;
+
+	// Define local variable
+	$_post = array();
+
+	/** Blacklist *************************************************************/
+
+	// Get the moderation keys
+	$blacklist = trim( get_option( 'blacklist_keys' ) );
+
+	// Bail if blacklist is empty
+	if ( empty( $blacklist ) )
+		return true;
+
+	/** User Data *************************************************************/
+
+	// Map anonymous user data
+	if ( !empty( $anonymous_data ) ) {
+		$_post['author'] = $anonymous_data['bbp_anonymous_name'];
+		$_post['email']  = $anonymous_data['bbp_anonymous_email'];
+		$_post['url']    = $anonymous_data['bbp_anonymous_website'];
+
+	// Map current user data
+	} elseif ( !empty( $author_id ) ) {
+
+		// Get author data
+		$user = get_userdata( $author_id );
+
+		// If data exists, map it
+		if ( !empty( $user ) ) {
+			$_post['author'] = $user->display_name;
+			$_post['email']  = $user->user_email;
+			$_post['url']    = $user->user_url;
+		}
+	}
+
+	// Current user IP and user agent
+	$_post['user_ip'] = bbp_current_author_ip();
+	$_post['user_ua'] = bbp_current_author_ua();
+
+	// Post title and content
+	$_post['title']   = $title;
+	$_post['content'] = $content;
+
+	/** Words *****************************************************************/
+
+	// Get words separated by new lines
+	$words = explode( "\n", $blacklist );
+
+	// Loop through words
+	foreach ( (array) $words as $word ) {
+
+		// Trim the whitespace from the word
+		$word = trim( $word );
+
+		// Skip empty lines
+		if ( empty( $word ) ) { continue; }
+
+		// Do some escaping magic so that '#' chars in the
+		// spam words don't break things:
+		$word    = preg_quote( $word, '#' );
+		$pattern = "#$word#i";
+
+		// Loop through post data
+		foreach ( $_post as $post_data ) {
+
+			// Check each user data for current word
+			if ( preg_match( $pattern, $post_data ) ) {
+
+				// Post does not pass
+				return false;
+			}
+		}
+	}
+
+	// Check passed successfully
+	return true;
+}
+
+/** Subscriptions *************************************************************/
+
+/**
+ * Sends notification emails for new replies to subscribed topics
+ *
+ * Gets new post's ID and check if there are subscribed users to that topic, and
+ * if there are, send notifications
+ *
+ * Note: in bbPress 2.6, we've moved away from 1 email per subscriber to 1 email
+ * with everyone BCC'd. This may have negative repercussions for email services
+ * that limit the number of addresses in a BCC field (often to around 500.) In
+ * those cases, we recommend unhooking this function and creating your own
+ * custom emailer script.
+ * 
+ * @since bbPress (r2668)
+ *
+ * @param int $reply_id ID of the newly made reply
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+ * @uses bbp_get_reply_id() To validate the reply ID
+ * @uses bbp_get_topic_id() To validate the topic ID
+ * @uses bbp_get_forum_id() To validate the forum ID
+ * @uses bbp_get_reply() To get the reply
+ * @uses bbp_is_reply_published() To make sure the reply is published
+ * @uses bbp_get_topic_id() To validate the topic ID
+ * @uses bbp_get_topic() To get the reply's topic
+ * @uses bbp_is_topic_published() To make sure the topic is published
+ * @uses bbp_get_reply_author_display_name() To get the reply author's display name
+ * @uses do_action() Calls 'bbp_pre_notify_subscribers' with the reply id,
+ *                    topic id and user id
+ * @uses bbp_get_topic_subscribers() To get the topic subscribers
+ * @uses apply_filters() Calls 'bbp_subscription_mail_message' with the
+ *                    message, reply id, topic id and user id
+ * @uses apply_filters() Calls 'bbp_subscription_mail_title' with the
+ *                    topic title, reply id, topic id and user id
+ * @uses apply_filters() Calls 'bbp_subscription_mail_headers'
+ * @uses get_userdata() To get the user data
+ * @uses wp_mail() To send the mail
+ * @uses do_action() Calls 'bbp_post_notify_subscribers' with the reply id,
+ *                    topic id and user id
+ * @return bool True on success, false on failure
+ */
+function bbp_notify_subscribers( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = false, $reply_author = 0 ) {
+
+	// Bail if subscriptions are turned off
+	if ( !bbp_is_subscriptions_active() ) {
+		return false;
+	}
+
+	/** Validation ************************************************************/
+
+	$reply_id = bbp_get_reply_id( $reply_id );
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	/** Topic *****************************************************************/
+
+	// Bail if topic is not published
+	if ( !bbp_is_topic_published( $topic_id ) ) {
+		return false;
+	}
+
+	/** Reply *****************************************************************/
+
+	// Bail if reply is not published
+	if ( !bbp_is_reply_published( $reply_id ) ) {
+		return false;
+	}
+
+	// Poster name
+	$reply_author_name = bbp_get_reply_author_display_name( $reply_id );
+
+	/** Mail ******************************************************************/
+
+	// Remove filters from reply content and topic title to prevent content
+	// from being encoded with HTML entities, wrapped in paragraph tags, etc...
+	remove_all_filters( 'bbp_get_reply_content' );
+	remove_all_filters( 'bbp_get_topic_title'   );
+
+	// Strip tags from text and setup mail data
+	$topic_title   = strip_tags( bbp_get_topic_title( $topic_id ) );
+	$reply_content = strip_tags( bbp_get_reply_content( $reply_id ) );
+	$reply_url     = bbp_get_reply_url( $reply_id );
+	$blog_name     = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
+	$do_not_reply  = '<noreply@' . ltrim( get_home_url(), '^(http|https)://' ) . '>';
+
+	// For plugins to filter messages per reply/topic/user
+	$message = sprintf( __( '%1$s wrote:
+
+%2$s
+
+Post Link: %3$s
+
+-----------
+
+You are receiving this email because you subscribed to a forum topic.
+
+Login and visit the topic to unsubscribe from these emails.', 'bbpress' ),
+
+		$reply_author_name,
+		$reply_content,
+		$reply_url
+	);
+
+	$message = apply_filters( 'bbp_subscription_mail_message', $message, $reply_id, $topic_id );
+	if ( empty( $message ) ) {
+		return;
+	}
+
+	// For plugins to filter titles per reply/topic/user
+	$subject = apply_filters( 'bbp_subscription_mail_title', '[' . $blog_name . '] ' . $topic_title, $reply_id, $topic_id );
+	if ( empty( $subject ) ) {
+		return;
+	}
+
+	/** Users *****************************************************************/
+
+	// Array to hold BCC's
+	$headers = array();
+
+	// Setup the From header
+	$headers[] = 'From: ' . get_bloginfo( 'name' ) . ' ' . $do_not_reply;
+	
+	// Get topic subscribers and bail if empty
+	$user_ids = bbp_get_topic_subscribers( $topic_id, true );
+	if ( empty( $user_ids ) ) {
+		return false;
+	}
+
+	// Loop through users
+	foreach ( (array) $user_ids as $user_id ) {
+
+		// Don't send notifications to the person who made the post
+		if ( !empty( $reply_author ) && (int) $user_id === (int) $reply_author ) {
+			continue;
+		}
+
+		// Get email address of subscribed user
+		$headers[] = 'Bcc: ' . get_userdata( $user_id )->user_email;
+	}
+
+	/** Send it ***************************************************************/
+
+	// Custom headers
+	$headers = apply_filters( 'bbp_subscription_mail_headers', $headers );
+
+	do_action( 'bbp_pre_notify_subscribers', $reply_id, $topic_id, $user_ids );
+
+	// Send notification email
+	wp_mail( $do_not_reply, $subject, $message, $headers );
+
+	do_action( 'bbp_post_notify_subscribers', $reply_id, $topic_id, $user_ids );
+
+	return true;
+}
+
+/**
+ * Sends notification emails for new topics to subscribed forums
+ *
+ * Gets new post's ID and check if there are subscribed users to that forum, and
+ * if there are, send notifications
+ *
+ * Note: in bbPress 2.6, we've moved away from 1 email per subscriber to 1 email
+ * with everyone BCC'd. This may have negative repercussions for email services
+ * that limit the number of addresses in a BCC field (often to around 500.) In
+ * those cases, we recommend unhooking this function and creating your own
+ * custom emailer script.
+ * 
+ * @since bbPress (r5156)
+ *
+ * @param int $topic_id ID of the newly made reply
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+ * @uses bbp_get_topic_id() To validate the topic ID
+ * @uses bbp_get_forum_id() To validate the forum ID
+ * @uses bbp_is_topic_published() To make sure the topic is published
+ * @uses bbp_get_forum_subscribers() To get the forum subscribers
+ * @uses bbp_get_topic_author_display_name() To get the topic author's display name
+ * @uses do_action() Calls 'bbp_pre_notify_forum_subscribers' with the topic id,
+ *                    forum id and user id
+ * @uses apply_filters() Calls 'bbp_forum_subscription_mail_message' with the
+ *                    message, topic id, forum id and user id
+ * @uses apply_filters() Calls 'bbp_forum_subscription_mail_title' with the
+ *                    topic title, topic id, forum id and user id
+ * @uses apply_filters() Calls 'bbp_forum_subscription_mail_headers'
+ * @uses get_userdata() To get the user data
+ * @uses wp_mail() To send the mail
+ * @uses do_action() Calls 'bbp_post_notify_forum_subscribers' with the topic,
+ *                    id, forum id and user id
+ * @return bool True on success, false on failure
+ */
+function bbp_notify_forum_subscribers( $topic_id = 0, $forum_id = 0, $anonymous_data = false, $topic_author = 0 ) {
+
+	// Bail if subscriptions are turned off
+	if ( !bbp_is_subscriptions_active() ) {
+		return false;
+	}
+
+	/** Validation ************************************************************/
+
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	/** Topic *****************************************************************/
+
+	// Bail if topic is not published
+	if ( ! bbp_is_topic_published( $topic_id ) ) {
+		return false;
+	}
+
+	// Poster name
+	$topic_author_name = bbp_get_topic_author_display_name( $topic_id );
+
+	/** Mail ******************************************************************/
+
+	// Remove filters from reply content and topic title to prevent content
+	// from being encoded with HTML entities, wrapped in paragraph tags, etc...
+	remove_all_filters( 'bbp_get_topic_content' );
+	remove_all_filters( 'bbp_get_topic_title'   );
+
+	// Strip tags from text and setup mail data
+	$topic_title   = strip_tags( bbp_get_topic_title( $topic_id ) );
+	$topic_content = strip_tags( bbp_get_topic_content( $topic_id ) );
+	$topic_url     = get_permalink( $topic_id );
+	$blog_name     = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
+	$do_not_reply  = '<noreply@' . ltrim( get_home_url(), '^(http|https)://' ) . '>';
+
+	// For plugins to filter messages per reply/topic/user
+	$message = sprintf( __( '%1$s wrote:
+
+%2$s
+
+Topic Link: %3$s
+
+-----------
+
+You are receiving this email because you subscribed to a forum.
+
+Login and visit the topic to unsubscribe from these emails.', 'bbpress' ),
+
+		$topic_author_name,
+		$topic_content,
+		$topic_url
+	);
+
+	$message = apply_filters( 'bbp_forum_subscription_mail_message', $message, $topic_id, $forum_id, $user_id );
+	if ( empty( $message ) ) {
+		return;
+	}
+
+	// For plugins to filter titles per reply/topic/user
+	$subject = apply_filters( 'bbp_forum_subscription_mail_title', '[' . $blog_name . '] ' . $topic_title, $topic_id, $forum_id, $user_id );
+	if ( empty( $subject ) ) {
+		return;
+	}
+
+	/** User ******************************************************************/
+
+	// Array to hold BCC's
+	$headers = array();
+
+	// Setup the From header
+	$headers[] = 'From: ' . get_bloginfo( 'name' ) . ' ' . $do_not_reply;
+	
+	// Get topic subscribers and bail if empty
+	$user_ids = bbp_get_forum_subscribers( $forum_id, true );
+	if ( empty( $user_ids ) ) {
+		return false;
+	}
+
+	// Loop through users
+	foreach ( (array) $user_ids as $user_id ) {
+
+		// Don't send notifications to the person who made the post
+		if ( !empty( $topic_author ) && (int) $user_id === (int) $topic_author ) {
+			continue;
+		}
+
+		// Get email address of subscribed user
+		$headers[] = 'Bcc: ' . get_userdata( $user_id )->user_email;
+	}
+
+	/** Send it ***************************************************************/
+
+	// Custom headers
+	$headers = apply_filters( 'bbp_subscription_mail_headers', $headers );
+
+	do_action( 'bbp_pre_notify_forum_subscribers', $topic_id, $forum_id, $user_ids );
+
+	// Send notification email
+	wp_mail( $do_not_reply, $subject, $message, $headers );
+
+	do_action( 'bbp_post_notify_forum_subscribers', $topic_id, $forum_id, $user_ids );
+
+	return true;
+}
+
+/** Login *********************************************************************/
+
+/**
+ * Return a clean and reliable logout URL
+ *
+ * @param string $url URL
+ * @param string $redirect_to Where to redirect to?
+ * @uses add_query_arg() To add args to the url
+ * @uses apply_filters() Calls 'bbp_logout_url' with the url and redirect to
+ * @return string The url
+ */
+function bbp_logout_url( $url = '', $redirect_to = '' ) {
+
+	// Make sure we are directing somewhere
+	if ( empty( $redirect_to ) && !strstr( $url, 'redirect_to' ) ) {
+
+		// Rejig the $redirect_to
+		if ( !isset( $_SERVER['REDIRECT_URL'] ) || ( $redirect_to !== home_url( $_SERVER['REDIRECT_URL'] ) ) ) {
+			$redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
+		}
+
+		$redirect_to = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+
+		// Sanitize $redirect_to and add it to full $url
+		$redirect_to = add_query_arg( array( 'loggedout'   => 'true'                    ), esc_url( $redirect_to ) );
+		$url         = add_query_arg( array( 'redirect_to' => urlencode( $redirect_to ) ), $url                    );
+	}
+
+	// Filter and return
+	return apply_filters( 'bbp_logout_url', $url, $redirect_to );
+}
+
+/** Queries *******************************************************************/
+
+/**
+ * Merge user defined arguments into defaults array.
+ *
+ * This function is used throughout bbPress to allow for either a string or array
+ * to be merged into another array. It is identical to wp_parse_args() except
+ * it allows for arguments to be passively or aggressively filtered using the
+ * optional $filter_key parameter.
+ *
+ * @since bbPress (r3839)
+ *
+ * @param string|array $args Value to merge with $defaults
+ * @param array $defaults Array that serves as the defaults.
+ * @param string $filter_key String to key the filters from
+ * @return array Merged user defined values with defaults.
+ */
+function bbp_parse_args( $args, $defaults = array(), $filter_key = '' ) {
+
+	// Setup a temporary array from $args
+	if ( is_object( $args ) ) {
+		$r = get_object_vars( $args );
+	} elseif ( is_array( $args ) ) {
+		$r =& $args;
+	} else {
+		wp_parse_str( $args, $r );
+	}
+
+	// Passively filter the args before the parse
+	if ( !empty( $filter_key ) ) {
+		$r = apply_filters( 'bbp_before_' . $filter_key . '_parse_args', $r );
+	}
+
+	// Parse
+	if ( is_array( $defaults ) && !empty( $defaults ) ) {
+		$r = array_merge( $defaults, $r );
+	}
+
+	// Aggressively filter the args after the parse
+	if ( !empty( $filter_key ) ) {
+		$r = apply_filters( 'bbp_after_' . $filter_key . '_parse_args', $r );
+	}
+
+	// Return the parsed results
+	return $r;
+}
+
+/**
+ * Adds ability to include or exclude specific post_parent ID's
+ *
+ * @since bbPress (r2996)
+ *
+ * @global DB $wpdb
+ * @global WP $wp
+ * @param string $where
+ * @param WP_Query $object
+ * @return string
+ */
+function bbp_query_post_parent__in( $where, $object = '' ) {
+	global $wpdb, $wp;
+
+	// Noop if WP core supports this already
+	if ( in_array( 'post_parent__in', $wp->private_query_vars ) )
+		return $where;
+
+	// Bail if no object passed
+	if ( empty( $object ) )
+		return $where;
+
+	// Only 1 post_parent so return $where
+	if ( is_numeric( $object->query_vars['post_parent'] ) )
+		return $where;
+
+	// Including specific post_parent's
+	if ( ! empty( $object->query_vars['post_parent__in'] ) ) {
+		$ids    = implode( ',', wp_parse_id_list( $object->query_vars['post_parent__in'] ) );
+		$where .= " AND {$wpdb->posts}.post_parent IN ($ids)";
+
+	// Excluding specific post_parent's
+	} elseif ( ! empty( $object->query_vars['post_parent__not_in'] ) ) {
+		$ids    = implode( ',', wp_parse_id_list( $object->query_vars['post_parent__not_in'] ) );
+		$where .= " AND {$wpdb->posts}.post_parent NOT IN ($ids)";
+	}
+
+	// Return possibly modified $where
+	return $where;
+}
+
+/**
+ * Query the DB and get the last public post_id that has parent_id as post_parent
+ *
+ * @param int $parent_id Parent id
+ * @param string $post_type Post type. Defaults to 'post'
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wp_cache_get() To check if there is a cache of the last child id
+ * @uses wpdb::prepare() To prepare the query
+ * @uses wpdb::get_var() To get the result of the query in a variable
+ * @uses wp_cache_set() To set the cache for future use
+ * @uses apply_filters() Calls 'bbp_get_public_child_last_id' with the child
+ *                        id, parent id and post type
+ * @return int The last active post_id
+ */
+function bbp_get_public_child_last_id( $parent_id = 0, $post_type = 'post' ) {
+	global $wpdb;
+
+	// Bail if nothing passed
+	if ( empty( $parent_id ) )
+		return false;
+
+	// The ID of the cached query
+	$cache_id = 'bbp_parent_' . $parent_id . '_type_' . $post_type . '_child_last_id';
+
+	// Check for cache and set if needed
+	$child_id = wp_cache_get( $cache_id, 'bbpress_posts' );
+	if ( false === $child_id ) {
+		$post_status = array( bbp_get_public_status_id() );
+
+		// Add closed status if topic post type
+		if ( $post_type === bbp_get_topic_post_type() ) {
+			$post_status[] = bbp_get_closed_status_id();
+		}
+
+		// Join post statuses together
+		$post_status = "'" . implode( "', '", $post_status ) . "'";
+
+		$child_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s' ORDER BY ID DESC LIMIT 1;", $parent_id, $post_type ) );
+		wp_cache_set( $cache_id, $child_id, 'bbpress_posts' );
+	}
+
+	// Filter and return
+	return apply_filters( 'bbp_get_public_child_last_id', (int) $child_id, $parent_id, $post_type );
+}
+
+/**
+ * Query the DB and get a count of public children
+ *
+ * @param int $parent_id Parent id
+ * @param string $post_type Post type. Defaults to 'post'
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wp_cache_get() To check if there is a cache of the children count
+ * @uses wpdb::prepare() To prepare the query
+ * @uses wpdb::get_var() To get the result of the query in a variable
+ * @uses wp_cache_set() To set the cache for future use
+ * @uses apply_filters() Calls 'bbp_get_public_child_count' with the child
+ *                        count, parent id and post type
+ * @return int The number of children
+ */
+function bbp_get_public_child_count( $parent_id = 0, $post_type = 'post' ) {
+	global $wpdb;
+
+	// Bail if nothing passed
+	if ( empty( $parent_id ) )
+		return false;
+
+	// The ID of the cached query
+	$cache_id    = 'bbp_parent_' . $parent_id . '_type_' . $post_type . '_child_count';
+
+	// Check for cache and set if needed
+	$child_count = wp_cache_get( $cache_id, 'bbpress_posts' );
+	if ( false === $child_count ) {
+		$post_status = array( bbp_get_public_status_id() );
+
+		// Add closed status if topic post type
+		if ( $post_type === bbp_get_topic_post_type() ) {
+			$post_status[] = bbp_get_closed_status_id();
+		}
+
+		// Join post statuses together
+		$post_status = "'" . implode( "', '", $post_status ) . "'";
+
+		$child_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s';", $parent_id, $post_type ) );
+		wp_cache_set( $cache_id, $child_count, 'bbpress_posts' );
+	}
+
+	// Filter and return
+	return apply_filters( 'bbp_get_public_child_count', (int) $child_count, $parent_id, $post_type );
+}
+
+/**
+ * Query the DB and get a the child id's of public children
+ *
+ * @param int $parent_id Parent id
+ * @param string $post_type Post type. Defaults to 'post'
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wp_cache_get() To check if there is a cache of the children
+ * @uses wpdb::prepare() To prepare the query
+ * @uses wpdb::get_col() To get the result of the query in an array
+ * @uses wp_cache_set() To set the cache for future use
+ * @uses apply_filters() Calls 'bbp_get_public_child_ids' with the child ids,
+ *                        parent id and post type
+ * @return array The array of children
+ */
+function bbp_get_public_child_ids( $parent_id = 0, $post_type = 'post' ) {
+	global $wpdb;
+
+	// Bail if nothing passed
+	if ( empty( $parent_id ) )
+		return false;
+
+	// The ID of the cached query
+	$cache_id  = 'bbp_parent_public_' . $parent_id . '_type_' . $post_type . '_child_ids';
+
+	// Check for cache and set if needed
+	$child_ids = wp_cache_get( $cache_id, 'bbpress_posts' );
+	if ( false === $child_ids ) {
+		$post_status = array( bbp_get_public_status_id() );
+
+		// Add closed status if topic post type
+		if ( $post_type === bbp_get_topic_post_type() ) {
+			$post_status[] = bbp_get_closed_status_id();
+		}
+
+		// Join post statuses together
+		$post_status = "'" . implode( "', '", $post_status ) . "'";
+
+		$child_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s' ORDER BY ID DESC;", $parent_id, $post_type ) );
+		wp_cache_set( $cache_id, $child_ids, 'bbpress_posts' );
+	}
+
+	// Filter and return
+	return apply_filters( 'bbp_get_public_child_ids', $child_ids, $parent_id, $post_type );
+}
+
+/**
+ * Query the DB and get a the child id's of all children
+ *
+ * @param int $parent_id Parent id
+ * @param string $post_type Post type. Defaults to 'post'
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wp_cache_get() To check if there is a cache of the children
+ * @uses wpdb::prepare() To prepare the query
+ * @uses wpdb::get_col() To get the result of the query in an array
+ * @uses wp_cache_set() To set the cache for future use
+ * @uses apply_filters() Calls 'bbp_get_public_child_ids' with the child ids,
+ *                        parent id and post type
+ * @return array The array of children
+ */
+function bbp_get_all_child_ids( $parent_id = 0, $post_type = 'post' ) {
+	global $wpdb;
+
+	// Bail if nothing passed
+	if ( empty( $parent_id ) )
+		return false;
+
+	// The ID of the cached query
+	$cache_id  = 'bbp_parent_all_' . $parent_id . '_type_' . $post_type . '_child_ids';
+
+	// Check for cache and set if needed
+	$child_ids = wp_cache_get( $cache_id, 'bbpress_posts' );
+	if ( false === $child_ids ) {
+		$post_status = array( bbp_get_public_status_id() );
+
+		// Extra post statuses based on post type
+		switch ( $post_type ) {
+
+			// Forum
+			case bbp_get_forum_post_type() :
+				$post_status[] = bbp_get_private_status_id();
+				$post_status[] = bbp_get_hidden_status_id();
+				break;
+
+			// Topic
+			case bbp_get_topic_post_type() :
+				$post_status[] = bbp_get_closed_status_id();
+				$post_status[] = bbp_get_trash_status_id();
+				$post_status[] = bbp_get_spam_status_id();
+				break;
+
+			// Reply
+			case bbp_get_reply_post_type() :
+				$post_status[] = bbp_get_trash_status_id();
+				$post_status[] = bbp_get_spam_status_id();
+				break;
+		}
+
+		// Join post statuses together
+		$post_status = "'" . implode( "', '", $post_status ) . "'";
+
+		$child_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s' ORDER BY ID DESC;", $parent_id, $post_type ) );
+		wp_cache_set( $cache_id, $child_ids, 'bbpress_posts' );
+	}
+
+	// Filter and return
+	return apply_filters( 'bbp_get_all_child_ids', $child_ids, (int) $parent_id, $post_type );
+}
+
+/** Globals *******************************************************************/
+
+/**
+ * Get the unfiltered value of a global $post's key
+ *
+ * Used most frequently when editing a forum/topic/reply
+ *
+ * @since bbPress (r3694)
+ *
+ * @global WP_Query $post
+ * @param string $field Name of the key
+ * @param string $context How to sanitize - raw|edit|db|display|attribute|js
+ * @return string Field value
+ */
+function bbp_get_global_post_field( $field = 'ID', $context = 'edit' ) {
+	global $post;
+
+	$retval = isset( $post->$field ) ? $post->$field : '';
+	$retval = sanitize_post_field( $field, $retval, $post->ID, $context );
+
+	return apply_filters( 'bbp_get_global_post_field', $retval, $post );
+}
+
+/** Nonces ********************************************************************/
+
+/**
+ * Makes sure the user requested an action from another page on this site.
+ *
+ * To avoid security exploits within the theme.
+ *
+ * @since bbPress (r4022)
+ *
+ * @uses do_action() Calls 'bbp_check_referer' on $action.
+ * @param string $action Action nonce
+ * @param string $query_arg where to look for nonce in $_REQUEST
+ */
+function bbp_verify_nonce_request( $action = '', $query_arg = '_wpnonce' ) {
+
+	/** Home URL **************************************************************/
+
+	// Parse home_url() into pieces to remove query-strings, strange characters,
+	// and other funny things that plugins might to do to it.
+	$parsed_home = parse_url( home_url( '/', ( is_ssl() ? 'https' : 'http' ) ) );
+
+	// Maybe include the port, if it's included
+	if ( isset( $parsed_home['port'] ) ) {
+		$parsed_host = $parsed_home['host'] . ':' . $parsed_home['port'];
+	} else {
+		$parsed_host = $parsed_home['host'];
+	}
+
+	// Set the home URL for use in comparisons
+	$home_url = trim( strtolower( $parsed_home['scheme'] . '://' . $parsed_host . $parsed_home['path'] ), '/' );
+
+	/** Requested URL *********************************************************/
+
+	// Maybe include the port, if it's included in home_url()
+	if ( isset( $parsed_home['port'] ) ) {
+		$request_host = $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'];
+	} else {
+		$request_host = $_SERVER['HTTP_HOST'];
+	}
+
+	// Build the currently requested URL
+	$scheme        = is_ssl() ? 'https://' : 'http://';
+	$requested_url = strtolower( $scheme . $request_host . $_SERVER['REQUEST_URI'] );
+
+	/** Look for match ********************************************************/
+
+	// Filter the requested URL, for configurations like reverse proxying
+	$matched_url = apply_filters( 'bbp_verify_nonce_request_url', $requested_url );
+
+	// Check the nonce
+	$result = isset( $_REQUEST[$query_arg] ) ? wp_verify_nonce( $_REQUEST[$query_arg], $action ) : false;
+
+	// Nonce check failed
+	if ( empty( $result ) || empty( $action ) || ( strpos( $matched_url, $home_url ) !== 0 ) ) {
+		$result = false;
+	}
+
+	// Do extra things
+	do_action( 'bbp_verify_nonce_request', $action, $result );
+
+	return $result;
+}
+
+/** Feeds *********************************************************************/
+
+/**
+ * This function is hooked into the WordPress 'request' action and is
+ * responsible for sniffing out the query vars and serving up RSS2 feeds if
+ * the stars align and the user has requested a feed of any bbPress type.
+ *
+ * @since bbPress (r3171)
+ *
+ * @param array $query_vars
+ * @return array
+ */
+function bbp_request_feed_trap( $query_vars = array() ) {
+
+	// Looking at a feed
+	if ( isset( $query_vars['feed'] ) ) {
+
+		// Forum/Topic/Reply Feed
+		if ( isset( $query_vars['post_type'] ) ) {
+
+			// Matched post type
+			$post_type = false;
+
+			// Post types to check
+			$post_types = array(
+				bbp_get_forum_post_type(),
+				bbp_get_topic_post_type(),
+				bbp_get_reply_post_type()
+			);
+
+			// Cast query vars as array outside of foreach loop
+			$qv_array = (array) $query_vars['post_type'];
+
+			// Check if this query is for a bbPress post type
+			foreach ( $post_types as $bbp_pt ) {
+			    if ( in_array( $bbp_pt, $qv_array, true ) ) {
+				    $post_type = $bbp_pt;
+				    break;
+			    }
+			}
+
+			// Looking at a bbPress post type
+			if ( ! empty( $post_type ) ) {
+
+				// Supported select query vars
+				$select_query_vars = array(
+					'p'        => false,
+					'name'     => false,
+					$post_type => false,
+				);
+
+				// Setup matched variables to select
+				foreach ( $query_vars as $key => $value ) {
+					if ( isset( $select_query_vars[$key] ) ) {
+						$select_query_vars[$key] = $value;
+					}
+				}
+
+				// Remove any empties
+				$select_query_vars = array_filter( $select_query_vars );
+
+				// What bbPress post type are we looking for feeds on?
+				switch ( $post_type ) {
+
+					// Forum
+					case bbp_get_forum_post_type() :
+
+						// Define local variable(s)
+						$meta_query = array();
+
+						// Single forum
+						if ( !empty( $select_query_vars ) ) {
+
+							// Load up our own query
+							query_posts( array_merge( array(
+								'post_type' => bbp_get_forum_post_type(),
+								'feed'      => true
+							), $select_query_vars ) );
+
+							// Restrict to specific forum ID
+							$meta_query = array( array(
+								'key'     => '_bbp_forum_id',
+								'value'   => bbp_get_forum_id(),
+								'type'    => 'numeric',
+								'compare' => '='
+							) );
+						}
+
+						// Only forum replies
+						if ( !empty( $_GET['type'] ) && ( bbp_get_reply_post_type() === $_GET['type'] ) ) {
+
+							// The query
+							$the_query = array(
+								'author'         => 0,
+								'feed'           => true,
+								'post_type'      => bbp_get_reply_post_type(),
+								'post_parent'    => 'any',
+								'post_status'    => array( bbp_get_public_status_id(), bbp_get_closed_status_id() ),
+								'posts_per_page' => bbp_get_replies_per_rss_page(),
+								'order'          => 'DESC',
+								'meta_query'     => $meta_query
+							);
+
+							// Output the feed
+							bbp_display_replies_feed_rss2( $the_query );
+
+						// Only forum topics
+						} elseif ( !empty( $_GET['type'] ) && ( bbp_get_topic_post_type() === $_GET['type'] ) ) {
+
+							// The query
+							$the_query = array(
+								'author'         => 0,
+								'feed'           => true,
+								'post_type'      => bbp_get_topic_post_type(),
+								'post_parent'    => bbp_get_forum_id(),
+								'post_status'    => array( bbp_get_public_status_id(), bbp_get_closed_status_id() ),
+								'posts_per_page' => bbp_get_topics_per_rss_page(),
+								'order'          => 'DESC'
+							);
+
+							// Output the feed
+							bbp_display_topics_feed_rss2( $the_query );
+
+						// All forum topics and replies
+						} else {
+
+							// Exclude private/hidden forums if not looking at single
+							if ( empty( $select_query_vars ) )
+								$meta_query = array( bbp_exclude_forum_ids( 'meta_query' ) );
+
+							// The query
+							$the_query = array(
+								'author'         => 0,
+								'feed'           => true,
+								'post_type'      => array( bbp_get_reply_post_type(), bbp_get_topic_post_type() ),
+								'post_parent'    => 'any',
+								'post_status'    => array( bbp_get_public_status_id(), bbp_get_closed_status_id() ),
+								'posts_per_page' => bbp_get_replies_per_rss_page(),
+								'order'          => 'DESC',
+								'meta_query'     => $meta_query
+							);
+
+							// Output the feed
+							bbp_display_replies_feed_rss2( $the_query );
+						}
+
+						break;
+
+					// Topic feed - Show replies
+					case bbp_get_topic_post_type() :
+
+						// Single topic
+						if ( !empty( $select_query_vars ) ) {
+
+							// Load up our own query
+							query_posts( array_merge( array(
+								'post_type' => bbp_get_topic_post_type(),
+								'feed'      => true
+							), $select_query_vars ) );
+
+							// Output the feed
+							bbp_display_replies_feed_rss2( array( 'feed' => true ) );
+
+						// All topics
+						} else {
+
+							// The query
+							$the_query = array(
+								'author'         => 0,
+								'feed'           => true,
+								'post_parent'    => 'any',
+								'posts_per_page' => bbp_get_topics_per_rss_page(),
+								'show_stickies'  => false
+							);
+
+							// Output the feed
+							bbp_display_topics_feed_rss2( $the_query );
+						}
+
+						break;
+
+					// Replies
+					case bbp_get_reply_post_type() :
+
+						// The query
+						$the_query = array(
+							'posts_per_page' => bbp_get_replies_per_rss_page(),
+							'meta_query'     => array( array( ) ),
+							'feed'           => true
+						);
+
+						// All replies
+						if ( empty( $select_query_vars ) ) {
+							bbp_display_replies_feed_rss2( $the_query );
+						}
+
+						break;
+				}
+			}
+
+		// Single Topic Vview
+		} elseif ( isset( $query_vars[ bbp_get_view_rewrite_id() ] ) ) {
+
+			// Get the view
+			$view = $query_vars[ bbp_get_view_rewrite_id() ];
+
+			// We have a view to display a feed
+			if ( !empty( $view ) ) {
+
+				// Get the view query
+				$the_query = bbp_get_view_query_args( $view );
+
+				// Output the feed
+				bbp_display_topics_feed_rss2( $the_query );
+			}
+		}
+
+		// @todo User profile feeds
+	}
+
+	// No feed so continue on
+	return $query_vars;
+}
+
+/** Templates ******************************************************************/
+
+/**
+ * Used to guess if page exists at requested path
+ *
+ * @since bbPress (r3304)
+ *
+ * @uses get_option() To see if pretty permalinks are enabled
+ * @uses get_page_by_path() To see if page exists at path
+ *
+ * @param string $path
+ * @return mixed False if no page, Page object if true
+ */
+function bbp_get_page_by_path( $path = '' ) {
+
+	// Default to false
+	$retval = false;
+
+	// Path is not empty
+	if ( !empty( $path ) ) {
+
+		// Pretty permalinks are on so path might exist
+		if ( get_option( 'permalink_structure' ) ) {
+			$retval = get_page_by_path( $path );
+		}
+	}
+
+	return apply_filters( 'bbp_get_page_by_path', $retval, $path );
+}
+
+/**
+ * Sets the 404 status.
+ *
+ * Used primarily with topics/replies inside hidden forums.
+ *
+ * @since bbPress (r3051)
+ *
+ * @global WP_Query $wp_query
+ * @uses WP_Query::set_404()
+ */
+function bbp_set_404() {
+	global $wp_query;
+
+	if ( ! isset( $wp_query ) ) {
+		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.', 'bbpress' ), '3.1' );
+		return false;
+	}
+
+	$wp_query->set_404();
+}
Index: /tags/2.5.4/includes/common/index.php
===================================================================
--- /tags/2.5.4/includes/common/index.php	(revision 5382)
+++ /tags/2.5.4/includes/common/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/common/shortcodes.php
===================================================================
--- /tags/2.5.4/includes/common/shortcodes.php	(revision 5382)
+++ /tags/2.5.4/includes/common/shortcodes.php	(revision 5382)
@@ -0,0 +1,872 @@
+<?php
+
+/**
+ * bbPress Shortcodes
+ *
+ * @package bbPress
+ * @subpackage Shortcodes
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Shortcodes' ) ) :
+/**
+ * bbPress Shortcode Class
+ *
+ * @since bbPress (r3031)
+ */
+class BBP_Shortcodes {
+
+	/** Vars ******************************************************************/
+
+	/**
+	 * @var array Shortcode => function
+	 */
+	public $codes = array();
+
+	/** Functions *************************************************************/
+
+	/**
+	 * Add the register_shortcodes action to bbp_init
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @uses setup_globals()
+	 * @uses add_shortcodes()
+	 */
+	public function __construct() {
+		$this->setup_globals();
+		$this->add_shortcodes();
+	}
+
+	/**
+	 * Shortcode globals
+	 *
+	 * @since bbPress (r3143)
+	 * @access private
+	 *
+	 * @uses apply_filters()
+	 */
+	private function setup_globals() {
+
+		// Setup the shortcodes
+		$this->codes = apply_filters( 'bbp_shortcodes', array(
+
+			/** Forums ********************************************************/
+
+			'bbp-forum-index'      => array( $this, 'display_forum_index'   ), // Forum Index
+			'bbp-forum-form'       => array( $this, 'display_forum_form'    ), // Topic form
+			'bbp-single-forum'     => array( $this, 'display_forum'         ), // Specific forum - pass an 'id' attribute
+
+			/** Topics ********************************************************/
+
+			'bbp-topic-index'      => array( $this, 'display_topic_index'   ), // Topic index
+			'bbp-topic-form'       => array( $this, 'display_topic_form'    ), // Topic form
+			'bbp-single-topic'     => array( $this, 'display_topic'         ), // Specific topic - pass an 'id' attribute
+
+			/** Topic Tags ****************************************************/
+
+			'bbp-topic-tags'       => array( $this, 'display_topic_tags'    ), // All topic tags in a cloud
+			'bbp-single-tag'       => array( $this, 'display_topics_of_tag' ), // Topics of Tag
+
+			/** Replies *******************************************************/
+
+			'bbp-reply-form'       => array( $this, 'display_reply_form'    ), // Reply form
+			'bbp-single-reply'     => array( $this, 'display_reply'         ), // Specific reply - pass an 'id' attribute
+
+			/** Views *********************************************************/
+
+			'bbp-single-view'      => array( $this, 'display_view'          ), // Single view
+
+			/** Search ********************************************************/
+
+			'bbp-search-form'      => array( $this, 'display_search_form'   ), // Search form
+			'bbp-search'           => array( $this, 'display_search'        ), // Search
+
+			/** Account *******************************************************/
+
+			'bbp-login'            => array( $this, 'display_login'         ), // Login
+			'bbp-register'         => array( $this, 'display_register'      ), // Register
+			'bbp-lost-pass'        => array( $this, 'display_lost_pass'     ), // Lost Password
+
+			/** Others *******************************************************/
+
+			'bbp-stats'            => array( $this, 'display_stats'         ), // Stats
+		) );
+	}
+
+	/**
+	 * Register the bbPress shortcodes
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @uses add_shortcode()
+	 * @uses do_action()
+	 */
+	private function add_shortcodes() {
+		foreach ( (array) $this->codes as $code => $function ) {
+			add_shortcode( $code, $function );
+		}
+	}
+
+	/**
+	 * Unset some globals in the $bbp object that hold query related info
+	 *
+	 * @since bbPress (r3034)
+	 */
+	private function unset_globals() {
+		$bbp = bbpress();
+
+		// Unset global queries
+		$bbp->forum_query  = new WP_Query();
+		$bbp->topic_query  = new WP_Query();
+		$bbp->reply_query  = new WP_Query();
+		$bbp->search_query = new WP_Query();
+
+		// Unset global ID's
+		$bbp->current_view_id      = 0;
+		$bbp->current_forum_id     = 0;
+		$bbp->current_topic_id     = 0;
+		$bbp->current_reply_id     = 0;
+		$bbp->current_topic_tag_id = 0;
+
+		// Reset the post data
+		wp_reset_postdata();
+	}
+
+	/** Output Buffers ********************************************************/
+
+	/**
+	 * Start an output buffer.
+	 *
+	 * This is used to put the contents of the shortcode into a variable rather
+	 * than outputting the HTML at run-time. This allows shortcodes to appear
+	 * in the correct location in the_content() instead of when it's created.
+	 *
+	 * @since bbPress (r3079)
+	 *
+	 * @param string $query_name
+	 *
+	 * @uses bbp_set_query_name()
+	 * @uses ob_start()
+	 */
+	private function start( $query_name = '' ) {
+
+		// Set query name
+		bbp_set_query_name( $query_name );
+
+		// Start output buffer
+		ob_start();
+	}
+
+	/**
+	 * Return the contents of the output buffer and flush its contents.
+	 *
+	 * @since bbPress( r3079)
+	 *
+	 * @uses BBP_Shortcodes::unset_globals() Cleans up global values
+	 * @return string Contents of output buffer.
+	 */
+	private function end() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Reset the query name
+		bbp_reset_query_name();
+
+		// Return and flush the output buffer
+		return ob_get_clean();
+	}
+
+	/** Forum shortcodes ******************************************************/
+
+	/**
+	 * Display an index of all visible root level forums in an output buffer
+	 * and return to ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses bbp_has_forums()
+	 * @uses get_template_part()
+	 * @return string
+	 */
+	public function display_forum_index() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start( 'bbp_forum_archive' );
+
+		bbp_get_template_part( 'content', 'archive-forum' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the contents of a specific forum ID in an output buffer
+	 * and return to ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses get_template_part()
+	 * @uses bbp_single_forum_description()
+	 * @return string
+	 */
+	public function display_forum( $attr, $content = '' ) {
+
+		// Sanity check required info
+		if ( !empty( $content ) || ( empty( $attr['id'] ) || !is_numeric( $attr['id'] ) ) )
+			return $content;
+
+		// Set passed attribute to $forum_id for clarity
+		$forum_id = bbpress()->current_forum_id = $attr['id'];
+
+		// Bail if ID passed is not a forum
+		if ( !bbp_is_forum( $forum_id ) )
+			return $content;
+
+		// Start output buffer
+		$this->start( 'bbp_single_forum' );
+
+		// Check forum caps
+		if ( bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
+			bbp_get_template_part( 'content',  'single-forum' );
+
+		// Forum is private and user does not have caps
+		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
+			bbp_get_template_part( 'feedback', 'no-access'    );
+		}
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the forum form in an output buffer and return to ensure
+	 * post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3566)
+	 *
+	 * @uses get_template_part()
+	 */
+	public function display_forum_form() {
+
+		// Start output buffer
+		$this->start( 'bbp_forum_form' );
+
+		// Output templates
+		bbp_get_template_part( 'form', 'forum' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Topic shortcodes ******************************************************/
+
+	/**
+	 * Display an index of all visible root level topics in an output buffer
+	 * and return to ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses bbp_get_hidden_forum_ids()
+	 * @uses get_template_part()
+	 * @return string
+	 */
+	public function display_topic_index() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Filter the query
+		if ( ! bbp_is_topic_archive() ) {
+			add_filter( 'bbp_before_has_topics_parse_args', array( $this, 'display_topic_index_query' ) );
+		}
+
+		// Start output buffer
+		$this->start( 'bbp_topic_archive' );
+
+		// Output template
+		bbp_get_template_part( 'content', 'archive-topic' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the contents of a specific topic ID in an output buffer
+	 * and return to ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses get_template_part()
+	 * @return string
+	 */
+	public function display_topic( $attr, $content = '' ) {
+
+		// Sanity check required info
+		if ( !empty( $content ) || ( empty( $attr['id'] ) || !is_numeric( $attr['id'] ) ) )
+			return $content;
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Set passed attribute to $forum_id for clarity
+		$topic_id = bbpress()->current_topic_id = $attr['id'];
+		$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+		// Bail if ID passed is not a topic
+		if ( !bbp_is_topic( $topic_id ) )
+			return $content;
+
+		// Reset the queries if not in theme compat
+		if ( !bbp_is_theme_compat_active() ) {
+
+			$bbp = bbpress();
+
+			// Reset necessary forum_query attributes for topics loop to function
+			$bbp->forum_query->query_vars['post_type'] = bbp_get_forum_post_type();
+			$bbp->forum_query->in_the_loop             = true;
+			$bbp->forum_query->post                    = get_post( $forum_id );
+
+			// Reset necessary topic_query attributes for topics loop to function
+			$bbp->topic_query->query_vars['post_type'] = bbp_get_topic_post_type();
+			$bbp->topic_query->in_the_loop             = true;
+			$bbp->topic_query->post                    = get_post( $topic_id );
+		}
+
+		// Start output buffer
+		$this->start( 'bbp_single_topic' );
+
+		// Check forum caps
+		if ( bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
+			bbp_get_template_part( 'content', 'single-topic' );
+
+		// Forum is private and user does not have caps
+		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
+			bbp_get_template_part( 'feedback', 'no-access'    );
+		}
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the topic form in an output buffer and return to ensure
+	 * post/page contents are displayed first.
+	 *
+	 * Supports 'forum_id' attribute to display the topic form for a particular
+	 * forum. This currently has styling issues from not being wrapped in
+	 * <div id="bbpress-forums"></div> which will need to be sorted out later.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses get_template_part()
+	 * @return string
+	 */
+	public function display_topic_form( $attr = array(), $content = '' ) {
+
+		// Sanity check supplied info
+		if ( !empty( $content ) || ( !empty( $attr['forum_id'] ) && ( !is_numeric( $attr['forum_id'] ) || !bbp_is_forum( $attr['forum_id'] ) ) ) )
+			return $content;
+
+		// Unset globals
+		$this->unset_globals();
+
+		// If forum id is set, use the 'bbp_single_forum' query name
+		if ( !empty( $attr['forum_id'] ) ) {
+
+			// Set the global current_forum_id for future requests
+			bbpress()->current_forum_id = $forum_id = bbp_get_forum_id( $attr['forum_id'] );
+
+			// Start output buffer
+			$this->start( 'bbp_single_forum' );
+
+		// No forum id was passed
+		} else {
+
+			// Set the $forum_id variable to satisfy checks below
+			$forum_id = 0;
+
+			// Start output buffer
+			$this->start( 'bbp_topic_form' );
+		}
+
+		// If the forum id is set, check forum caps else display normal topic form
+		if ( empty( $forum_id ) || bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
+			bbp_get_template_part( 'form', 'topic' );
+
+		// Forum is private and user does not have caps
+		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
+			bbp_get_template_part( 'feedback', 'no-access' );
+		}
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Replies ***************************************************************/
+
+	/**
+	 * Display the contents of a specific reply ID in an output buffer
+	 * and return to ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses get_template_part()
+	 * @return string
+	 */
+	public function display_reply( $attr, $content = '' ) {
+
+		// Sanity check required info
+		if ( !empty( $content ) || ( empty( $attr['id'] ) || !is_numeric( $attr['id'] ) ) )
+			return $content;
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Set passed attribute to $reply_id for clarity
+		$reply_id = bbpress()->current_reply_id = $attr['id'];
+		$forum_id = bbp_get_reply_forum_id( $reply_id );
+
+		// Bail if ID passed is not a reply
+		if ( !bbp_is_reply( $reply_id ) )
+			return $content;
+
+		// Reset the queries if not in theme compat
+		if ( !bbp_is_theme_compat_active() ) {
+
+			$bbp = bbpress();
+
+			// Reset necessary forum_query attributes for replys loop to function
+			$bbp->forum_query->query_vars['post_type'] = bbp_get_forum_post_type();
+			$bbp->forum_query->in_the_loop             = true;
+			$bbp->forum_query->post                    = get_post( $forum_id );
+
+			// Reset necessary reply_query attributes for replys loop to function
+			$bbp->reply_query->query_vars['post_type'] = bbp_get_reply_post_type();
+			$bbp->reply_query->in_the_loop             = true;
+			$bbp->reply_query->post                    = get_post( $reply_id );
+		}
+
+		// Start output buffer
+		$this->start( 'bbp_single_reply' );
+
+		// Check forum caps
+		if ( bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
+			bbp_get_template_part( 'content',  'single-reply' );
+
+		// Forum is private and user does not have caps
+		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
+			bbp_get_template_part( 'feedback', 'no-access'    );
+		}
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the reply form in an output buffer and return to ensure
+	 * post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @uses get_template_part()
+	 */
+	public function display_reply_form() {
+
+		// Start output buffer
+		$this->start( 'bbp_reply_form' );
+
+		// Output templates
+		bbp_get_template_part( 'form', 'reply' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Topic Tags ************************************************************/
+
+	/**
+	 * Display a tag cloud of all topic tags in an output buffer and return to
+	 * ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3110)
+	 *
+	 * @return string
+	 */
+	public function display_topic_tags() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start( 'bbp_topic_tags' );
+
+		// Output the topic tags
+		wp_tag_cloud( array(
+			'smallest' => 9,
+			'largest'  => 38,
+			'number'   => 80,
+			'taxonomy' => bbp_get_topic_tag_tax_id()
+		) );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the contents of a specific topic tag in an output buffer
+	 * and return to ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3110)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses get_template_part()
+	 * @return string
+	 */
+	public function display_topics_of_tag( $attr, $content = '' ) {
+
+		// Sanity check required info
+		if ( !empty( $content ) || ( empty( $attr['id'] ) || !is_numeric( $attr['id'] ) ) )
+			return $content;
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Filter the query
+		if ( ! bbp_is_topic_tag() ) {
+			add_filter( 'bbp_before_has_topics_parse_args', array( $this, 'display_topics_of_tag_query' ) );
+		}
+
+		// Start output buffer
+		$this->start( 'bbp_topic_tag' );
+
+		// Set passed attribute to $ag_id for clarity
+		bbpress()->current_topic_tag_id = $tag_id = $attr['id'];
+
+		// Output template
+		bbp_get_template_part( 'content', 'archive-topic' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the contents of a specific topic tag in an output buffer
+	 * and return to ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3346)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses get_template_part()
+	 * @return string
+	 */
+	public function display_topic_tag_form() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start( 'bbp_topic_tag_edit' );
+
+		// Output template
+		bbp_get_template_part( 'content', 'topic-tag-edit' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Views *****************************************************************/
+
+	/**
+	 * Display the contents of a specific view in an output buffer and return to
+	 * ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r3031)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses get_template_part()
+	 * @uses bbp_single_forum_description()
+	 * @return string
+	 */
+	public function display_view( $attr, $content = '' ) {
+
+		// Sanity check required info
+		if ( empty( $attr['id'] ) )
+			return $content;
+
+		// Set passed attribute to $view_id for clarity
+		$view_id = $attr['id'];
+
+		// Start output buffer
+		$this->start( 'bbp_single_view' );
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Set the current view ID
+		bbpress()->current_view_id = $view_id;
+
+		// Load the view
+		bbp_view_query( $view_id );
+
+		// Output template
+		bbp_get_template_part( 'content', 'single-view' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Search ****************************************************************/
+
+	/**
+	 * Display the search form in an output buffer and return to ensure
+	 * post/page contents are displayed first.
+	 *
+	 * @since bbPress (r4585)
+	 *
+	 * @uses get_template_part()
+	 */
+	public function display_search_form() {
+
+		// Bail if search is disabled
+		if ( ! bbp_allow_search() ) {
+			return;
+		}
+
+		// Start output buffer
+		$this->start( 'bbp_search_form' );
+
+		// Output templates
+		bbp_get_template_part( 'form', 'search' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display the contents of search results in an output buffer and return to
+	 * ensure that post/page contents are displayed first.
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @param array $attr
+	 * @param string $content
+	 * @uses bbp_search_query()
+	 * @uses get_template_part()
+	 */
+	public function display_search( $attr, $content = '' ) {
+
+		// Sanity check required info
+		if ( !empty( $content ) ) {
+			return $content;
+		}
+
+		// Bail if search is disabled
+		if ( ! bbp_allow_search() ) {
+			return;
+		}
+
+		// Trim search attribute if it's set
+		if ( isset( $attr['search'] ) ) {
+			$attr['search'] = trim( $attr['search'] );
+		}
+
+		// Set passed attribute to $search_terms for clarity
+		$search_terms = empty( $attr['search'] ) ? bbp_get_search_terms() : $attr['search'];
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Set terms for query
+		set_query_var( bbp_get_search_rewrite_id(), $search_terms );
+
+		// Start output buffer
+		$this->start( bbp_get_search_rewrite_id() );
+
+		// Output template
+		bbp_get_template_part( 'content', 'search' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Account ***************************************************************/
+
+	/**
+	 * Display a login form
+	 *
+	 * @since bbPress (r3302)
+	 *
+	 * @return string
+	 */
+	public function display_login() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start( 'bbp_login' );
+
+		// Output templates
+		if ( !is_user_logged_in() )
+			bbp_get_template_part( 'form',     'user-login' );
+		else
+			bbp_get_template_part( 'feedback', 'logged-in'  );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display a register form
+	 *
+	 * @since bbPress (r3302)
+	 *
+	 * @return string
+	 */
+	public function display_register() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start( 'bbp_register' );
+
+		// Output templates
+		if ( !is_user_logged_in() )
+			bbp_get_template_part( 'form',     'user-register' );
+		else
+			bbp_get_template_part( 'feedback', 'logged-in'     );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display a lost password form
+	 *
+	 * @since bbPress (r3302)
+	 *
+	 * @return string
+	 */
+	public function display_lost_pass() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start( 'bbp_lost_pass' );
+
+		// Output templates
+		if ( !is_user_logged_in() )
+			bbp_get_template_part( 'form',     'user-lost-pass' );
+		else
+			bbp_get_template_part( 'feedback', 'logged-in'      );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Other *****************************************************************/
+
+	/**
+	 * Display forum statistics
+	 *
+	 * @since bbPress (r4509)
+	 *
+	 * @return shring
+	 */
+	public function display_stats() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start();
+
+		// Output statistics
+		bbp_get_template_part( 'content', 'statistics' );
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/**
+	 * Display a breadcrumb
+	 *
+	 * @since bbPress (r3302)
+	 *
+	 * @return string
+	 */
+	public function display_breadcrumb() {
+
+		// Unset globals
+		$this->unset_globals();
+
+		// Start output buffer
+		$this->start();
+
+		// Output breadcrumb
+		bbp_breadcrumb();
+
+		// Return contents of output buffer
+		return $this->end();
+	}
+
+	/** Query Filters *********************************************************/
+
+	/**
+	 * Filter the query for the topic index
+	 *
+	 * @since bbPress (r3637)
+	 *
+	 * @param array $args
+	 * @return array
+	 */
+	public function display_topic_index_query( $args = array() ) {
+		$args['author']        = 0;
+		$args['show_stickies'] = true;
+		$args['order']         = 'DESC';
+		return $args;
+	}
+
+	/**
+	 * Filter the query for topic tags
+	 *
+	 * @since bbPress (r3637)
+	 *
+	 * @param array $args
+	 * @return array
+	 */
+	public function display_topics_of_tag_query( $args = array() ) {
+		$args['tax_query'] = array( array(
+			'taxonomy' => bbp_get_topic_tag_tax_id(),
+			'field'    => 'id',
+			'terms'    => bbpress()->current_topic_tag_id
+		) );
+
+		return $args;
+	}
+}
+endif;
Index: /tags/2.5.4/includes/common/template.php
===================================================================
--- /tags/2.5.4/includes/common/template.php	(revision 5382)
+++ /tags/2.5.4/includes/common/template.php	(revision 5382)
@@ -0,0 +1,2678 @@
+<?php
+
+/**
+ * bbPress Common Template Tags
+ *
+ * Common template tags are ones that are used by more than one component, like
+ * forums, topics, replies, users, topic tags, etc...
+ *
+ * @package bbPress
+ * @subpackage TemplateTags
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** URLs **********************************************************************/
+
+/**
+ * Ouput the forum URL
+ *
+ * @since bbPress (r3979)
+ *
+ * @uses bbp_get_forums_url() To get the forums URL
+ * @param string $path Additional path with leading slash
+ */
+function bbp_forums_url( $path = '/' ) {
+	echo esc_url( bbp_get_forums_url( $path ) );
+}
+	/**
+	 * Return the forum URL
+	 *
+	 * @since bbPress (r3979)
+	 *
+	 * @uses home_url() To get the home URL
+	 * @uses bbp_get_root_slug() To get the forum root location
+	 * @param string $path Additional path with leading slash
+	 */
+	function bbp_get_forums_url( $path = '/' ) {
+		return home_url( bbp_get_root_slug() . $path );
+	}
+
+/**
+ * Ouput the forum URL
+ *
+ * @since bbPress (r3979)
+ *
+ * @uses bbp_get_topics_url() To get the topics URL
+ * @param string $path Additional path with leading slash
+ */
+function bbp_topics_url( $path = '/' ) {
+	echo esc_url( bbp_get_topics_url( $path ) );
+}
+	/**
+	 * Return the forum URL
+	 *
+	 * @since bbPress (r3979)
+	 *
+	 * @uses home_url() To get the home URL
+	 * @uses bbp_get_topic_archive_slug() To get the topics archive location
+	 * @param string $path Additional path with leading slash
+	 * @return The URL to the topics archive
+	 */
+	function bbp_get_topics_url( $path = '/' ) {
+		return home_url( bbp_get_topic_archive_slug() . $path );
+	}
+
+/** Add-on Actions ************************************************************/
+
+/**
+ * Add our custom head action to wp_head
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses do_action() Calls 'bbp_head'
+*/
+function bbp_head() {
+	do_action( 'bbp_head' );
+}
+
+/**
+ * Add our custom head action to wp_head
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses do_action() Calls 'bbp_footer'
+ */
+function bbp_footer() {
+	do_action( 'bbp_footer' );
+}
+
+/** is_ ***********************************************************************/
+
+/**
+ * Check if current site is public
+ *
+ * @since bbPress (r3398)
+ *
+ * @param int $site_id
+ * @uses get_current_blog_id()
+ * @uses get_blog_option()
+ * @uses apply_filters()
+ * @return bool True if site is public, false if private
+ */
+function bbp_is_site_public( $site_id = 0 ) {
+
+	// Get the current site ID
+	if ( empty( $site_id ) )
+		$site_id = get_current_blog_id();
+
+	// Get the site visibility setting
+	$public = get_blog_option( $site_id, 'blog_public', 1 );
+
+	return (bool) apply_filters( 'bbp_is_site_public', $public, $site_id );
+}
+
+/**
+ * Check if current page is a bbPress forum
+ *
+ * @since bbPress (r2549)
+ *
+ * @param int $post_id Possible post_id to check
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @return bool True if it's a forum page, false if not
+ */
+function bbp_is_forum( $post_id = 0 ) {
+
+	// Assume false
+	$retval = false;
+
+	// Supplied ID is a forum
+	if ( !empty( $post_id ) && ( bbp_get_forum_post_type() === get_post_type( $post_id ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_forum', $retval, $post_id );
+}
+
+/**
+ * Check if we are viewing a forum archive.
+ *
+ * @since bbPress (r3251)
+ *
+ * @uses is_post_type_archive() To check if we are looking at the forum archive
+ * @uses bbp_get_forum_post_type() To get the forum post type ID
+ *
+ * @return bool
+ */
+function bbp_is_forum_archive() {
+	global $wp_query;
+
+	// Default to false
+	$retval = false;
+
+	// In forum archive
+	if ( is_post_type_archive( bbp_get_forum_post_type() ) || bbp_is_query_name( 'bbp_forum_archive' ) || !empty( $wp_query->bbp_show_topics_on_root ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_forum_archive', $retval );
+}
+
+/**
+ * Viewing a single forum
+ *
+ * @since bbPress (r3338)
+ *
+ * @uses is_single()
+ * @uses bbp_get_forum_post_type()
+ * @uses get_post_type()
+ * @uses apply_filters()
+ *
+ * @return bool
+ */
+function bbp_is_single_forum() {
+
+	// Assume false
+	$retval = false;
+
+	// Edit is not a single forum
+	if ( bbp_is_forum_edit() )
+		return false;
+
+	// Single and a match
+	if ( is_singular( bbp_get_forum_post_type() ) || bbp_is_query_name( 'bbp_single_forum' ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_forum', $retval );
+}
+
+/**
+ * Check if current page is a forum edit page
+ *
+ * @since bbPress (r3553)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_forum_edit is true
+ * @return bool True if it's the forum edit page, false if not
+ */
+function bbp_is_forum_edit() {
+	global $wp_query, $pagenow;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_forum_edit ) && ( $wp_query->bbp_is_forum_edit === true ) )
+		$retval = true;
+
+	// Editing in admin
+	elseif ( is_admin() && ( 'post.php' === $pagenow ) && ( get_post_type() === bbp_get_forum_post_type() ) && ( !empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_forum_edit', $retval );
+}
+
+/**
+ * Check if current page is a bbPress topic
+ *
+ * @since bbPress (r2549)
+ *
+ * @param int $post_id Possible post_id to check
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses get_post_type() To get the post type of the post id
+ * @return bool True if it's a topic page, false if not
+ */
+function bbp_is_topic( $post_id = 0 ) {
+
+	// Assume false
+	$retval = false;
+
+	// Supplied ID is a topic
+	if ( !empty( $post_id ) && ( bbp_get_topic_post_type() === get_post_type( $post_id ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_topic', $retval, $post_id );
+}
+
+/**
+ * Viewing a single topic
+ *
+ * @since bbPress (r3338)
+ *
+ * @uses is_single()
+ * @uses bbp_get_topic_post_type()
+ * @uses get_post_type()
+ * @uses apply_filters()
+ *
+ * @return bool
+ */
+function bbp_is_single_topic() {
+
+	// Assume false
+	$retval = false;
+
+	// Edit is not a single topic
+	if ( bbp_is_topic_edit() )
+		return false;
+
+	// Single and a match
+	if ( is_singular( bbp_get_topic_post_type() ) || bbp_is_query_name( 'bbp_single_topic' ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_topic', $retval );
+}
+
+/**
+ * Check if we are viewing a topic archive.
+ *
+ * @since bbPress (r3251)
+ *
+ * @uses is_post_type_archive() To check if we are looking at the topic archive
+ * @uses bbp_get_topic_post_type() To get the topic post type ID
+ *
+ * @return bool
+ */
+function bbp_is_topic_archive() {
+
+	// Default to false
+	$retval = false;
+
+	// In topic archive
+	if ( is_post_type_archive( bbp_get_topic_post_type() ) || bbp_is_query_name( 'bbp_topic_archive' ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_topic_archive', $retval );
+}
+
+/**
+ * Check if current page is a topic edit page
+ *
+ * @since bbPress (r2753)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_topic_edit is true
+ * @return bool True if it's the topic edit page, false if not
+ */
+function bbp_is_topic_edit() {
+	global $wp_query, $pagenow;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_topic_edit ) && ( $wp_query->bbp_is_topic_edit === true ) )
+		$retval = true;
+
+	// Editing in admin
+	elseif ( is_admin() && ( 'post.php' === $pagenow ) && ( get_post_type() === bbp_get_topic_post_type() ) && ( !empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_topic_edit', $retval );
+}
+
+/**
+ * Check if current page is a topic merge page
+ *
+ * @since bbPress (r2756)
+ *
+ * @uses bbp_is_topic_edit() To check if it's a topic edit page
+ * @return bool True if it's the topic merge page, false if not
+ */
+function bbp_is_topic_merge() {
+
+	// Assume false
+	$retval = false;
+
+	// Check topic edit and GET params
+	if ( bbp_is_topic_edit() && !empty( $_GET['action'] ) && ( 'merge' === $_GET['action'] ) )
+		return true;
+
+	return (bool) apply_filters( 'bbp_is_topic_merge', $retval );
+}
+
+/**
+ * Check if current page is a topic split page
+ *
+ * @since bbPress (r2756)
+ *
+ * @uses bbp_is_topic_edit() To check if it's a topic edit page
+ * @return bool True if it's the topic split page, false if not
+ */
+function bbp_is_topic_split() {
+
+	// Assume false
+	$retval = false;
+
+	// Check topic edit and GET params
+	if ( bbp_is_topic_edit() && !empty( $_GET['action'] ) && ( 'split' === $_GET['action'] ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_topic_split', $retval );
+}
+
+/**
+ * Check if the current page is a topic tag
+ *
+ * @since bbPress (r3311)
+ *
+ * @return bool True if it's a topic tag, false if not
+ */
+function bbp_is_topic_tag() {
+
+	// Bail if topic-tags are off
+	if ( ! bbp_allow_topic_tags() )
+		return false;
+
+	// Return false if editing a topic tag
+	if ( bbp_is_topic_tag_edit() )
+		return false;
+
+	// Assume false
+	$retval = false;
+
+	// Check tax and query vars
+	if ( is_tax( bbp_get_topic_tag_tax_id() ) || !empty( bbpress()->topic_query->is_tax ) || get_query_var( 'bbp_topic_tag' ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_topic_tag', $retval );
+}
+
+/**
+ * Check if the current page is editing a topic tag
+ *
+ * @since bbPress (r3346)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_topic_tag_edit is true
+ * @return bool True if editing a topic tag, false if not
+ */
+function bbp_is_topic_tag_edit() {
+	global $wp_query, $pagenow, $taxnow;
+
+	// Bail if topic-tags are off
+	if ( ! bbp_allow_topic_tags() )
+		return false;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_topic_tag_edit ) && ( true === $wp_query->bbp_is_topic_tag_edit ) )
+		$retval = true;
+
+	// Editing in admin
+	elseif ( is_admin() && ( 'edit-tags.php' === $pagenow ) && ( bbp_get_topic_tag_tax_id() === $taxnow ) && ( !empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_topic_tag_edit', $retval );
+}
+
+/**
+ * Check if the current post type is one of bbPress's
+ *
+ * @since bbPress (r3311)
+ *
+ * @param mixed $the_post Optional. Post object or post ID.
+ * @uses get_post_type()
+ * @uses bbp_get_forum_post_type()
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_reply_post_type()
+ *
+ * @return bool
+ */
+function bbp_is_custom_post_type( $the_post = false ) {
+
+	// Assume false
+	$retval = false;
+
+	// Viewing one of the bbPress post types
+	if ( in_array( get_post_type( $the_post ), array(
+		bbp_get_forum_post_type(),
+		bbp_get_topic_post_type(),
+		bbp_get_reply_post_type()
+	) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_custom_post_type', $retval, $the_post );
+}
+
+/**
+ * Check if current page is a bbPress reply
+ *
+ * @since bbPress (r2549)
+ *
+ * @param int $post_id Possible post_id to check
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses get_post_type() To get the post type of the post id
+ * @return bool True if it's a reply page, false if not
+ */
+function bbp_is_reply( $post_id = 0 ) {
+
+	// Assume false
+	$retval = false;
+
+	// Supplied ID is a reply
+	if ( !empty( $post_id ) && ( bbp_get_reply_post_type() === get_post_type( $post_id ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_reply', $retval, $post_id );
+}
+
+/**
+ * Check if current page is a reply edit page
+ *
+ * @since bbPress (r2753)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_reply_edit is true
+ * @return bool True if it's the reply edit page, false if not
+ */
+function bbp_is_reply_edit() {
+	global $wp_query, $pagenow;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_reply_edit ) && ( true === $wp_query->bbp_is_reply_edit ) )
+		$retval = true;
+
+	// Editing in admin
+	elseif ( is_admin() && ( 'post.php' === $pagenow ) && ( get_post_type() === bbp_get_reply_post_type() ) && ( !empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_reply_edit', $retval );
+}
+
+/**
+ * Check if current page is a reply move page
+ *
+ * @uses bbp_is_reply_move() To check if it's a reply move page
+ * @return bool True if it's the reply move page, false if not
+ */
+function bbp_is_reply_move() {
+
+	// Assume false
+	$retval = false;
+
+	// Check reply edit and GET params
+	if ( bbp_is_reply_edit() && !empty( $_GET['action'] ) && ( 'move' === $_GET['action'] ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_reply_move', $retval );
+}
+
+/**
+ * Viewing a single reply
+ *
+ * @since bbPress (r3344)
+ *
+ * @uses is_single()
+ * @uses bbp_get_reply_post_type()
+ * @uses get_post_type()
+ * @uses apply_filters()
+ *
+ * @return bool
+ */
+function bbp_is_single_reply() {
+
+	// Assume false
+	$retval = false;
+
+	// Edit is not a single reply
+	if ( bbp_is_reply_edit() )
+		return false;
+
+	// Single and a match
+	if ( is_singular( bbp_get_reply_post_type() ) || ( bbp_is_query_name( 'bbp_single_reply' ) ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_reply', $retval );
+}
+
+/**
+ * Check if current page is a bbPress user's favorites page (profile page)
+ *
+ * @since bbPress (r2652)
+ *
+ * @return bool True if it's the favorites page, false if not
+ */
+function bbp_is_favorites() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_favs ) && ( true === $wp_query->bbp_is_single_user_favs ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_favorites', $retval );
+}
+
+/**
+ * Check if current page is a bbPress user's subscriptions page (profile page)
+ *
+ * @since bbPress (r2652)
+ *
+ * @return bool True if it's the subscriptions page, false if not
+ */
+function bbp_is_subscriptions() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_subs ) && ( true === $wp_query->bbp_is_single_user_subs ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_subscriptions', $retval );
+}
+
+/**
+ * Check if current page shows the topics created by a bbPress user (profile
+ * page)
+ *
+ * @since bbPress (r2688)
+ *
+ * @return bool True if it's the topics created page, false if not
+ */
+function bbp_is_topics_created() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_topics ) && ( true === $wp_query->bbp_is_single_user_topics ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_topics_created', $retval );
+}
+
+/**
+ * Check if current page shows the topics created by a bbPress user (profile
+ * page)
+ *
+ * @since bbPress (r4225)
+ *
+ * @return bool True if it's the topics created page, false if not
+ */
+function bbp_is_replies_created() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_replies ) && ( true === $wp_query->bbp_is_single_user_replies ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_replies_created', $retval );
+}
+
+/**
+ * Check if current page is the currently logged in users author page
+ *
+ * @since bbPress (r2688)
+ * @uses bbp_is_single_user() Check query variable
+ * @uses is_user_logged_in() Must be logged in to be home
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_get_current_user_id()
+ * @return bool True if it's the user's home, false if not
+ */
+function bbp_is_user_home() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_home ) && ( true === $wp_query->bbp_is_single_user_home ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_user_home', $retval );
+}
+
+/**
+ * Check if current page is the currently logged in users author edit page
+ *
+ * @since bbPress (r3918)
+ * @uses bbp_is_single_user_edit() Check query variable
+ * @uses is_user_logged_in() Must be logged in to be home
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_get_current_user_id()
+ * @return bool True if it's the user's home, false if not
+ */
+function bbp_is_user_home_edit() {
+
+	// Assume false
+	$retval = false;
+
+	if ( bbp_is_user_home() && bbp_is_single_user_edit() )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_user_home_edit', $retval );
+}
+
+/**
+ * Check if current page is a user profile page
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_single_user is set to true
+ * @return bool True if it's a user's profile page, false if not
+ */
+function bbp_is_single_user() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user ) && ( true === $wp_query->bbp_is_single_user ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_user', $retval );
+}
+
+/**
+ * Check if current page is a user profile edit page
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_single_user_edit is set to true
+ * @return bool True if it's a user's profile edit page, false if not
+ */
+function bbp_is_single_user_edit() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_edit ) && ( true === $wp_query->bbp_is_single_user_edit ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_user_edit', $retval );
+}
+
+/**
+ * Check if current page is a user profile page
+ *
+ * @since bbPress (r4225)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_single_user_profile is set to true
+ * @return bool True if it's a user's profile page, false if not
+ */
+function bbp_is_single_user_profile() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_profile ) && ( true === $wp_query->bbp_is_single_user_profile ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_user_profile', $retval );
+}
+
+/**
+ * Check if current page is a user topics created page
+ *
+ * @since bbPress (r4225)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_single_user_topics is set to true
+ * @return bool True if it's a user's topics page, false if not
+ */
+function bbp_is_single_user_topics() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_topics ) && ( true === $wp_query->bbp_is_single_user_topics ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_user_topics', $retval );
+}
+
+/**
+ * Check if current page is a user replies created page
+ *
+ * @since bbPress (r4225)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_single_user_replies is set to true
+ * @return bool True if it's a user's replies page, false if not
+ */
+function bbp_is_single_user_replies() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_single_user_replies ) && ( true === $wp_query->bbp_is_single_user_replies ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_user_replies', $retval );
+}
+
+/**
+ * Check if current page is a view page
+ *
+ * @since bbPress (r2789)
+ *
+ * @global WP_Query $wp_query To check if WP_Query::bbp_is_view is true
+ * @uses bbp_is_query_name() To get the query name
+ * @return bool Is it a view page?
+ */
+function bbp_is_single_view() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_view ) && ( true === $wp_query->bbp_is_view ) )
+		$retval = true;
+
+	// Check query name
+	if ( empty( $retval ) && bbp_is_query_name( 'bbp_single_view' ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_single_view', $retval );
+}
+
+/**
+ * Check if current page is a search page
+ *
+ * @since bbPress (r4579)
+ *
+ * @global WP_Query $wp_query To check if WP_Query::bbp_is_search is true
+ * @uses bbp_is_query_name() To get the query name
+ * @return bool Is it a search page?
+ */
+function bbp_is_search() {
+	global $wp_query;
+
+	// Bail if search is disabled
+	if ( ! bbp_allow_search() )
+		return false;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_search ) && ( true === $wp_query->bbp_is_search ) )
+		$retval = true;
+
+	// Check query name
+	if ( empty( $retval ) && bbp_is_query_name( bbp_get_search_rewrite_id() ) )
+		$retval = true;
+
+	// Check $_GET
+	if ( empty( $retval ) && isset( $_REQUEST[ bbp_get_search_rewrite_id() ] ) && empty( $_REQUEST[ bbp_get_search_rewrite_id() ] ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_search', $retval );
+}
+
+/**
+ * Check if current page is a search results page
+ *
+ * @since bbPress (r4919)
+ *
+ * @global WP_Query $wp_query To check if WP_Query::bbp_is_search is true
+ * @uses bbp_is_query_name() To get the query name
+ * @return bool Is it a search page?
+ */
+function bbp_is_search_results() {
+	global $wp_query;
+
+	// Bail if search is disabled
+	if ( ! bbp_allow_search() )
+		return false;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_search_terms ) )
+		$retval = true;
+
+	// Check query name
+	if ( empty( $retval ) && bbp_is_query_name( 'bbp_search_results' ) )
+		$retval = true;
+
+	// Check $_REQUEST
+	if ( empty( $retval ) && !empty( $_REQUEST[ bbp_get_search_rewrite_id() ] ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_search_results', $retval );
+}
+
+/**
+ * Check if current page is an edit page
+ *
+ * @since bbPress (r3585)
+ *
+ * @uses WP_Query Checks if WP_Query::bbp_is_edit is true
+ * @return bool True if it's the edit page, false if not
+ */
+function bbp_is_edit() {
+	global $wp_query;
+
+	// Assume false
+	$retval = false;
+
+	// Check query
+	if ( !empty( $wp_query->bbp_is_edit ) && ( $wp_query->bbp_is_edit === true ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_edit', $retval );
+}
+
+/**
+ * Use the above is_() functions to output a body class for each scenario
+ *
+ * @since bbPress (r2926)
+ *
+ * @param array $wp_classes
+ * @param array $custom_classes
+ * @uses bbp_is_single_forum()
+ * @uses bbp_is_single_topic()
+ * @uses bbp_is_topic_edit()
+ * @uses bbp_is_topic_merge()
+ * @uses bbp_is_topic_split()
+ * @uses bbp_is_single_reply()
+ * @uses bbp_is_reply_edit()
+ * @uses bbp_is_reply_move()
+ * @uses bbp_is_single_view()
+ * @uses bbp_is_single_user_edit()
+ * @uses bbp_is_single_user()
+ * @uses bbp_is_user_home()
+ * @uses bbp_is_subscriptions()
+ * @uses bbp_is_favorites()
+ * @uses bbp_is_topics_created()
+ * @uses bbp_is_forum_archive()
+ * @uses bbp_is_topic_archive()
+ * @uses bbp_is_topic_tag()
+ * @uses bbp_is_topic_tag_edit()
+ * @uses bbp_get_topic_tag_tax_id()
+ * @uses bbp_get_topic_tag_slug()
+ * @uses bbp_get_topic_tag_id()
+ * @return array Body Classes
+ */
+function bbp_body_class( $wp_classes, $custom_classes = false ) {
+
+	$bbp_classes = array();
+
+	/** Archives **************************************************************/
+
+	if ( bbp_is_forum_archive() ) {
+		$bbp_classes[] = bbp_get_forum_post_type() . '-archive';
+
+	} elseif ( bbp_is_topic_archive() ) {
+		$bbp_classes[] = bbp_get_topic_post_type() . '-archive';
+
+	/** Topic Tags ************************************************************/
+
+	} elseif ( bbp_is_topic_tag() ) {
+		$bbp_classes[] = bbp_get_topic_tag_tax_id();
+		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_slug();
+		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_id();
+	} elseif ( bbp_is_topic_tag_edit() ) {
+		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-edit';
+		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_slug() . '-edit';
+		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_id()   . '-edit';
+
+	/** Components ************************************************************/
+
+	} elseif ( bbp_is_single_forum() ) {
+		$bbp_classes[] = bbp_get_forum_post_type();
+
+	} elseif ( bbp_is_single_topic() ) {
+		$bbp_classes[] = bbp_get_topic_post_type();
+
+	} elseif ( bbp_is_single_reply() ) {
+		$bbp_classes[] = bbp_get_reply_post_type();
+
+	} elseif ( bbp_is_topic_edit() ) {
+		$bbp_classes[] = bbp_get_topic_post_type() . '-edit';
+
+	} elseif ( bbp_is_topic_merge() ) {
+		$bbp_classes[] = bbp_get_topic_post_type() . '-merge';
+
+	} elseif ( bbp_is_topic_split() ) {
+		$bbp_classes[] = bbp_get_topic_post_type() . '-split';
+
+	} elseif ( bbp_is_reply_edit() ) {
+		$bbp_classes[] = bbp_get_reply_post_type() . '-edit';
+
+	} elseif ( bbp_is_reply_move() ) {
+		$bbp_classes[] = bbp_get_reply_post_type() . '-move';
+
+	} elseif ( bbp_is_single_view() ) {
+		$bbp_classes[] = 'bbp-view';
+
+	/** User ******************************************************************/
+
+	} elseif ( bbp_is_single_user_edit() ) {
+		$bbp_classes[] = 'bbp-user-edit';
+		$bbp_classes[] = 'single';
+		$bbp_classes[] = 'singular';
+
+	} elseif ( bbp_is_single_user() ) {
+		$bbp_classes[] = 'bbp-user-page';
+		$bbp_classes[] = 'single';
+		$bbp_classes[] = 'singular';
+
+	} elseif ( bbp_is_user_home() ) {
+		$bbp_classes[] = 'bbp-user-home';
+		$bbp_classes[] = 'single';
+		$bbp_classes[] = 'singular';
+
+	} elseif ( bbp_is_user_home_edit() ) {
+		$bbp_classes[] = 'bbp-user-home-edit';
+		$bbp_classes[] = 'single';
+		$bbp_classes[] = 'singular';
+
+	} elseif ( bbp_is_topics_created() ) {
+		$bbp_classes[] = 'bbp-topics-created';
+		$bbp_classes[] = 'single';
+		$bbp_classes[] = 'singular';
+
+	} elseif ( bbp_is_favorites() ) {
+		$bbp_classes[] = 'bbp-favorites';
+		$bbp_classes[] = 'single';
+		$bbp_classes[] = 'singular';
+
+	} elseif ( bbp_is_subscriptions() ) {
+		$bbp_classes[] = 'bbp-subscriptions';
+		$bbp_classes[] = 'single';
+		$bbp_classes[] = 'singular';
+
+	/** Search ****************************************************************/
+
+	} elseif ( bbp_is_search() ) {
+		$bbp_classes[] = 'bbp-search';
+		$bbp_classes[] = 'forum-search';
+
+	} elseif ( bbp_is_search_results() ) {
+		$bbp_classes[] = 'bbp-search-results';
+		$bbp_classes[] = 'forum-search-results';
+	}
+
+	/** Clean up **************************************************************/
+
+	// Add bbPress class if we are within a bbPress page
+	if ( !empty( $bbp_classes ) ) {
+		$bbp_classes[] = 'bbpress';
+	}
+
+	// Merge WP classes with bbPress classes and remove any duplicates
+	$classes = array_unique( array_merge( (array) $bbp_classes, (array) $wp_classes ) );
+
+	// Deprecated filter (do not use)
+	$classes = apply_filters( 'bbp_get_the_body_class', $classes, $bbp_classes, $wp_classes, $custom_classes );
+
+	return apply_filters( 'bbp_body_class', $classes, $bbp_classes, $wp_classes, $custom_classes );
+}
+
+/**
+ * Use the above is_() functions to return if in any bbPress page
+ *
+ * @since bbPress (r3344)
+ *
+ * @uses bbp_is_single_forum()
+ * @uses bbp_is_single_topic()
+ * @uses bbp_is_topic_edit()
+ * @uses bbp_is_topic_merge()
+ * @uses bbp_is_topic_split()
+ * @uses bbp_is_single_reply()
+ * @uses bbp_is_reply_edit()
+ * @uses bbp_is_reply_move()
+ * @uses bbp_is_single_view()
+ * @uses bbp_is_single_user_edit()
+ * @uses bbp_is_single_user()
+ * @uses bbp_is_user_home()
+ * @uses bbp_is_subscriptions()
+ * @uses bbp_is_favorites()
+ * @uses bbp_is_topics_created()
+ * @return bool In a bbPress page
+ */
+function is_bbpress() {
+
+	// Defalt to false
+	$retval = false;
+
+	/** Archives **************************************************************/
+
+	if ( bbp_is_forum_archive() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_topic_archive() ) {
+		$retval = true;
+
+	/** Topic Tags ************************************************************/
+
+	} elseif ( bbp_is_topic_tag() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_topic_tag_edit() ) {
+		$retval = true;
+
+	/** Components ************************************************************/
+
+	} elseif ( bbp_is_single_forum() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_single_topic() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_single_reply() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_topic_edit() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_topic_merge() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_topic_split() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_reply_edit() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_reply_move() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_single_view() ) {
+		$retval = true;
+
+	/** User ******************************************************************/
+
+	} elseif ( bbp_is_single_user_edit() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_single_user() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_user_home() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_user_home_edit() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_topics_created() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_favorites() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_subscriptions() ) {
+		$retval = true;
+
+	/** Search ****************************************************************/
+
+	} elseif ( bbp_is_search() ) {
+		$retval = true;
+
+	} elseif ( bbp_is_search_results() ) {
+		$retval = true;
+	}
+
+	/** Done ******************************************************************/
+
+	return (bool) apply_filters( 'is_bbpress', $retval );
+}
+
+/** Forms *********************************************************************/
+
+/**
+ * Output the login form action url
+ *
+ * @since bbPress (r2815)
+ *
+ * @param string $url Pass a URL to redirect to
+ * @uses add_query_arg() To add a arg to the url
+ * @uses site_url() Toget the site url
+ * @uses apply_filters() Calls 'bbp_wp_login_action' with the url and args
+ */
+function bbp_wp_login_action( $args = '' ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'action'  => '',
+		'context' => ''
+	), 'login_action' );
+
+	// Add action as query arg
+	if ( !empty( $r['action'] ) ) {
+		$login_url = add_query_arg( array( 'action' => $r['action'] ), 'wp-login.php' );
+
+	// No query arg
+	} else {
+		$login_url = 'wp-login.php';
+	}
+
+	$login_url = site_url( $login_url, $r['context'] );
+
+	echo apply_filters( 'bbp_wp_login_action', $login_url, $r );
+}
+
+/**
+ * Output hidden request URI field for user forms.
+ *
+ * The referer link is the current Request URI from the server super global. To
+ * check the field manually, use bbp_get_redirect_to().
+ *
+ * @since bbPress (r2815)
+ *
+ * @param string $redirect_to Pass a URL to redirect to
+ *
+ * @uses wp_get_referer() To get the referer
+ * @uses esc_attr() To escape the url
+ * @uses apply_filters() Calls 'bbp_redirect_to_field', passes field and to
+ */
+function bbp_redirect_to_field( $redirect_to = '' ) {
+
+	// Make sure we are directing somewhere
+	if ( empty( $redirect_to ) ) {
+		if ( isset( $_SERVER['REQUEST_URI'] ) ) {
+			$redirect_to = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+		} else {
+			$redirect_to = wp_get_referer();
+		}
+	}
+
+	// Remove loggedout query arg if it's there
+	$redirect_to    = (string) esc_attr( remove_query_arg( 'loggedout', $redirect_to ) );
+	$redirect_field = '<input type="hidden" id="bbp_redirect_to" name="redirect_to" value="' . $redirect_to . '" />';
+
+	echo apply_filters( 'bbp_redirect_to_field', $redirect_field, $redirect_to );
+}
+
+/**
+ * Echo sanitized $_REQUEST value.
+ *
+ * Use the $input_type parameter to properly process the value. This
+ * ensures correct sanitization of the value for the receiving input.
+ *
+ * @since bbPress (r2815)
+ *
+ * @param string $request Name of $_REQUEST to look for
+ * @param string $input_type Type of input. Default: text. Accepts:
+ *                            textarea|password|select|radio|checkbox
+ * @uses bbp_get_sanitize_val() To sanitize the value.
+ */
+function bbp_sanitize_val( $request = '', $input_type = 'text' ) {
+	echo bbp_get_sanitize_val( $request, $input_type );
+}
+	/**
+	 * Return sanitized $_REQUEST value.
+	 *
+	 * Use the $input_type parameter to properly process the value. This
+	 * ensures correct sanitization of the value for the receiving input.
+	 *
+	 * @since bbPress (r2815)
+	 *
+	 * @param string $request Name of $_REQUEST to look for
+	 * @param string $input_type Type of input. Default: text. Accepts:
+	 *                            textarea|password|select|radio|checkbox
+	 * @uses esc_attr() To escape the string
+	 * @uses apply_filters() Calls 'bbp_get_sanitize_val' with the sanitized
+	 *                        value, request and input type
+	 * @return string Sanitized value ready for screen display
+	 */
+	function bbp_get_sanitize_val( $request = '', $input_type = 'text' ) {
+
+		// Check that requested
+		if ( empty( $_REQUEST[$request] ) )
+			return false;
+
+		// Set request varaible
+		$pre_ret_val = $_REQUEST[$request];
+
+		// Treat different kinds of fields in different ways
+		switch ( $input_type ) {
+			case 'text'     :
+			case 'textarea' :
+				$retval = esc_attr( stripslashes( $pre_ret_val ) );
+				break;
+
+			case 'password' :
+			case 'select'   :
+			case 'radio'    :
+			case 'checkbox' :
+			default :
+				$retval = esc_attr( $pre_ret_val );
+				break;
+		}
+
+		return apply_filters( 'bbp_get_sanitize_val', $retval, $request, $input_type );
+	}
+
+/**
+ * Output the current tab index of a given form
+ *
+ * Use this function to handle the tab indexing of user facing forms within a
+ * template file. Calling this function will automatically increment the global
+ * tab index by default.
+ *
+ * @since bbPress (r2810)
+ *
+ * @param int $auto_increment Optional. Default true. Set to false to prevent
+ *                             increment
+ */
+function bbp_tab_index( $auto_increment = true ) {
+	echo bbp_get_tab_index( $auto_increment );
+}
+
+	/**
+	 * Output the current tab index of a given form
+	 *
+	 * Use this function to handle the tab indexing of user facing forms
+	 * within a template file. Calling this function will automatically
+	 * increment the global tab index by default.
+	 *
+	 * @since bbPress (r2810)
+	 *
+	 * @uses apply_filters Allows return value to be filtered
+	 * @param int $auto_increment Optional. Default true. Set to false to
+	 *                             prevent the increment
+	 * @return int $bbp->tab_index The global tab index
+	 */
+	function bbp_get_tab_index( $auto_increment = true ) {
+		$bbp = bbpress();
+
+		if ( true === $auto_increment )
+			++$bbp->tab_index;
+
+		return apply_filters( 'bbp_get_tab_index', (int) $bbp->tab_index );
+	}
+
+/**
+ * Output a select box allowing to pick which forum/topic a new topic/reply
+ * belongs in.
+ *
+ * Can be used for any post type, but is mostly used for topics and forums.
+ *
+ * @since bbPress (r2746)
+ *
+ * @param mixed $args See {@link bbp_get_dropdown()} for arguments
+ */
+function bbp_dropdown( $args = '' ) {
+	echo bbp_get_dropdown( $args );
+}
+	/**
+	 * Output a select box allowing to pick which forum/topic a new
+	 * topic/reply belongs in.
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @param mixed $args The function supports these args:
+	 *  - post_type: Post type, defaults to bbp_get_forum_post_type() (bbp_forum)
+	 *  - selected: Selected ID, to not have any value as selected, pass
+	 *               anything smaller than 0 (due to the nature of select
+	 *               box, the first value would of course be selected -
+	 *               though you can have that as none (pass 'show_none' arg))
+	 *  - orderby: Defaults to 'menu_order title'
+	 *  - post_parent: Post parent. Defaults to 0
+	 *  - post_status: Which all post_statuses to find in? Can be an array
+	 *                  or CSV of publish, category, closed, private, spam,
+	 *                  trash (based on post type) - if not set, these are
+	 *                  automatically determined based on the post_type
+	 *  - posts_per_page: Retrieve all forums/topics. Defaults to -1 to get
+	 *                     all posts
+	 *  - walker: Which walker to use? Defaults to
+	 *             {@link BBP_Walker_Dropdown}
+	 *  - select_id: ID of the select box. Defaults to 'bbp_forum_id'
+	 *  - tab: Tabindex value. False or integer
+	 *  - options_only: Show only <options>? No <select>?
+	 *  - show_none: Boolean or String __( '(No Forum)', 'bbpress' )
+	 *  - disable_categories: Disable forum categories and closed forums?
+	 *                         Defaults to true. Only for forums and when
+	 *                         the category option is displayed.
+	 * @uses BBP_Walker_Dropdown() As the default walker to generate the
+	 *                              dropdown
+	 * @uses current_user_can() To check if the current user can read
+	 *                           private forums
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses walk_page_dropdown_tree() To generate the dropdown using the
+	 *                                  walker
+	 * @uses apply_filters() Calls 'bbp_get_dropdown' with the dropdown
+	 *                        and args
+	 * @return string The dropdown
+	 */
+	function bbp_get_dropdown( $args = '' ) {
+
+		/** Arguments *********************************************************/
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'post_type'          => bbp_get_forum_post_type(),
+			'post_parent'        => null,
+			'post_status'        => null,
+			'selected'           => 0,
+			'exclude'            => array(),
+			'numberposts'        => -1,
+			'orderby'            => 'menu_order title',
+			'order'              => 'ASC',
+			'walker'             => '',
+
+			// Output-related
+			'select_id'          => 'bbp_forum_id',
+			'tab'                => bbp_get_tab_index(),
+			'options_only'       => false,
+			'show_none'          => false,
+			'disable_categories' => true,
+			'disabled'           => ''
+		), 'get_dropdown' );
+
+		if ( empty( $r['walker'] ) ) {
+			$r['walker']            = new BBP_Walker_Dropdown();
+			$r['walker']->tree_type = $r['post_type'];
+		}
+
+		// Force 0
+		if ( is_numeric( $r['selected'] ) && $r['selected'] < 0 ) {
+			$r['selected'] = 0;
+		}
+
+		// Force array
+		if ( !empty( $r['exclude'] ) && !is_array( $r['exclude'] ) ) {
+			$r['exclude'] = explode( ',', $r['exclude'] );
+		}
+
+		/** Setup variables ***************************************************/
+
+		$retval = '';
+		$posts  = get_posts( array(
+			'post_type'          => $r['post_type'],
+			'post_status'        => $r['post_status'],
+			'exclude'            => $r['exclude'],
+			'post_parent'        => $r['post_parent'],
+			'numberposts'        => $r['numberposts'],
+			'orderby'            => $r['orderby'],
+			'order'              => $r['order'],
+			'walker'             => $r['walker'],
+			'disable_categories' => $r['disable_categories']
+		) );
+
+		/** Drop Down *********************************************************/
+
+		// Build the opening tag for the select element
+		if ( empty( $r['options_only'] ) ) {
+
+			// Should this select appear disabled?
+			$disabled  = disabled( isset( bbpress()->options[ $r['disabled'] ] ), true, false );
+
+			// Setup the tab index attribute
+			$tab       = !empty( $r['tab'] ) ? ' tabindex="' . intval( $r['tab'] ) . '"' : '';
+
+			// Open the select tag
+			$retval   .= '<select name="' . esc_attr( $r['select_id'] ) . '" id="' . esc_attr( $r['select_id'] ) . '"' . $disabled . $tab . '>' . "\n";
+		}
+
+		// Display a leading 'no-value' option, with or without custom text
+		if ( !empty( $r['show_none'] ) || !empty( $r['none_found'] ) ) {
+
+			// Open the 'no-value' option tag
+			$retval .= "\t<option value=\"\" class=\"level-0\">";
+
+			// Use deprecated 'none_found' first for backpat
+			if ( ! empty( $r['none_found'] ) && is_string( $r['none_found'] ) ) {
+				$retval .= esc_html( $r['none_found'] );
+
+			// Use 'show_none' second
+			} elseif ( ! empty( $r['show_none'] ) && is_string( $r['show_none'] ) ) {
+				$retval .= esc_html( $r['show_none'] );
+
+			// Otherwise, make some educated guesses
+			} else {
+
+				// Switch the response based on post type
+				switch ( $r['post_type'] ) {
+
+					// Topics
+					case bbp_get_topic_post_type() :
+						$retval .= esc_html__( 'No topics available', 'bbpress' );
+						break;
+
+					// Forums
+					case bbp_get_forum_post_type() :
+						$retval .= esc_html__( 'No forums available', 'bbpress' );
+						break;
+
+					// Any other
+					default :
+						$retval .= esc_html__( 'None available', 'bbpress' );
+						break;
+				}
+			}
+
+			// Close the 'no-value' option tag
+			$retval .= '</option>';
+		}
+
+		// Items found so walk the tree
+		if ( !empty( $posts ) ) {
+			$retval .= walk_page_dropdown_tree( $posts, 0, $r );
+		}
+
+		// Close the selecet tag
+		if ( empty( $r['options_only'] ) ) {
+			$retval .= '</select>';
+		}
+
+		return apply_filters( 'bbp_get_dropdown', $retval, $r );
+	}
+
+/**
+ * Output the required hidden fields when creating/editing a forum
+ *
+ * @since bbPress (r3553)
+ *
+ * @uses bbp_is_forum_edit() To check if it's the forum edit page
+ * @uses wp_nonce_field() To generate hidden nonce fields
+ * @uses bbp_forum_id() To output the forum id
+ * @uses bbp_is_single_forum() To check if it's a forum page
+ * @uses bbp_forum_id() To output the forum id
+ */
+function bbp_forum_form_fields() {
+
+	if ( bbp_is_forum_edit() ) : ?>
+
+		<input type="hidden" name="action"       id="bbp_post_action" value="bbp-edit-forum" />
+		<input type="hidden" name="bbp_forum_id" id="bbp_forum_id"    value="<?php bbp_forum_id(); ?>" />
+
+		<?php
+
+		if ( current_user_can( 'unfiltered_html' ) )
+			wp_nonce_field( 'bbp-unfiltered-html-forum_' . bbp_get_forum_id(), '_bbp_unfiltered_html_forum', false );
+
+		?>
+
+		<?php wp_nonce_field( 'bbp-edit-forum_' . bbp_get_forum_id() );
+
+	else :
+
+		if ( bbp_is_single_forum() ) : ?>
+
+			<input type="hidden" name="bbp_forum_parent_id" id="bbp_forum_parent_id" value="<?php bbp_forum_parent_id(); ?>" />
+
+		<?php endif; ?>
+
+		<input type="hidden" name="action" id="bbp_post_action" value="bbp-new-forum" />
+
+		<?php
+
+		if ( current_user_can( 'unfiltered_html' ) )
+			wp_nonce_field( 'bbp-unfiltered-html-forum_new', '_bbp_unfiltered_html_forum', false );
+
+		?>
+
+		<?php wp_nonce_field( 'bbp-new-forum' );
+
+	endif;
+}
+
+/**
+ * Output the required hidden fields when creating/editing a topic
+ *
+ * @since bbPress (r2753)
+ *
+ * @uses bbp_is_topic_edit() To check if it's the topic edit page
+ * @uses wp_nonce_field() To generate hidden nonce fields
+ * @uses bbp_topic_id() To output the topic id
+ * @uses bbp_is_single_forum() To check if it's a forum page
+ * @uses bbp_forum_id() To output the forum id
+ */
+function bbp_topic_form_fields() {
+
+	if ( bbp_is_topic_edit() ) : ?>
+
+		<input type="hidden" name="action"       id="bbp_post_action" value="bbp-edit-topic" />
+		<input type="hidden" name="bbp_topic_id" id="bbp_topic_id"    value="<?php bbp_topic_id(); ?>" />
+
+		<?php
+
+		if ( current_user_can( 'unfiltered_html' ) )
+			wp_nonce_field( 'bbp-unfiltered-html-topic_' . bbp_get_topic_id(), '_bbp_unfiltered_html_topic', false );
+
+		?>
+
+		<?php wp_nonce_field( 'bbp-edit-topic_' . bbp_get_topic_id() );
+
+	else :
+
+		if ( bbp_is_single_forum() ) : ?>
+
+			<input type="hidden" name="bbp_forum_id" id="bbp_forum_id" value="<?php bbp_forum_id(); ?>" />
+
+		<?php endif; ?>
+
+		<input type="hidden" name="action" id="bbp_post_action" value="bbp-new-topic" />
+
+		<?php if ( current_user_can( 'unfiltered_html' ) )
+			wp_nonce_field( 'bbp-unfiltered-html-topic_new', '_bbp_unfiltered_html_topic', false ); ?>
+
+		<?php wp_nonce_field( 'bbp-new-topic' );
+
+	endif;
+}
+
+/**
+ * Output the required hidden fields when creating/editing a reply
+ *
+ * @since bbPress (r2753)
+ *
+ * @uses bbp_is_reply_edit() To check if it's the reply edit page
+ * @uses wp_nonce_field() To generate hidden nonce fields
+ * @uses bbp_reply_id() To output the reply id
+ * @uses bbp_topic_id() To output the topic id
+ * @uses bbp_forum_id() To output the forum id
+ */
+function bbp_reply_form_fields() {
+
+	if ( bbp_is_reply_edit() ) : ?>
+
+		<input type="hidden" name="bbp_reply_id"    id="bbp_reply_id"    value="<?php bbp_reply_id(); ?>" />
+		<input type="hidden" name="bbp_reply_to"    id="bbp_reply_to"    value="<?php bbp_form_reply_to(); ?>" />
+		<input type="hidden" name="action"          id="bbp_post_action" value="bbp-edit-reply" />
+
+		<?php if ( current_user_can( 'unfiltered_html' ) )
+			wp_nonce_field( 'bbp-unfiltered-html-reply_' . bbp_get_reply_id(), '_bbp_unfiltered_html_reply', false ); ?>
+
+		<?php wp_nonce_field( 'bbp-edit-reply_' . bbp_get_reply_id() );
+
+	else : ?>
+
+		<input type="hidden" name="bbp_topic_id"    id="bbp_topic_id"    value="<?php bbp_topic_id(); ?>" />
+		<input type="hidden" name="bbp_reply_to"    id="bbp_reply_to"    value="<?php bbp_form_reply_to(); ?>" />
+		<input type="hidden" name="action"          id="bbp_post_action" value="bbp-new-reply" />
+
+		<?php if ( current_user_can( 'unfiltered_html' ) )
+			wp_nonce_field( 'bbp-unfiltered-html-reply_' . bbp_get_topic_id(), '_bbp_unfiltered_html_reply', false ); ?>
+
+		<?php wp_nonce_field( 'bbp-new-reply' );
+
+		// Show redirect field if not viewing a specific topic
+		if ( bbp_is_query_name( 'bbp_single_topic' ) ) :
+			bbp_redirect_to_field( get_permalink() );
+
+		endif;
+	endif;
+}
+
+/**
+ * Output the required hidden fields when editing a user
+ *
+ * @since bbPress (r2690)
+ *
+ * @uses bbp_displayed_user_id() To output the displayed user id
+ * @uses wp_nonce_field() To generate a hidden referer field
+ */
+function bbp_edit_user_form_fields() {
+?>
+
+	<input type="hidden" name="action"  id="bbp_post_action" value="bbp-update-user" />
+	<input type="hidden" name="user_id" id="user_id"         value="<?php bbp_displayed_user_id(); ?>" />
+
+	<?php wp_nonce_field( 'update-user_' . bbp_get_displayed_user_id() );
+}
+
+/**
+ * Merge topic form fields
+ *
+ * Output the required hidden fields when merging a topic
+ *
+ * @since bbPress (r2756)
+ *
+ * @uses wp_nonce_field() To generate a hidden nonce field
+ * @uses bbp_topic_id() To output the topic id
+ */
+function bbp_merge_topic_form_fields() {
+?>
+
+	<input type="hidden" name="action"       id="bbp_post_action" value="bbp-merge-topic" />
+	<input type="hidden" name="bbp_topic_id" id="bbp_topic_id"    value="<?php bbp_topic_id(); ?>" />
+
+	<?php wp_nonce_field( 'bbp-merge-topic_' . bbp_get_topic_id() );
+}
+
+/**
+ * Split topic form fields
+ *
+ * Output the required hidden fields when splitting a topic
+ *
+ * @since bbPress (r2756)
+ *
+ * @uses wp_nonce_field() To generate a hidden nonce field
+ */
+function bbp_split_topic_form_fields() {
+?>
+
+	<input type="hidden" name="action"       id="bbp_post_action" value="bbp-split-topic" />
+	<input type="hidden" name="bbp_reply_id" id="bbp_reply_id"    value="<?php echo absint( $_GET['reply_id'] ); ?>" />
+
+	<?php wp_nonce_field( 'bbp-split-topic_' . bbp_get_topic_id() );
+}
+
+/**
+ * Move reply form fields
+ *
+ * Output the required hidden fields when moving a reply
+ *
+ * @uses wp_nonce_field() To generate a hidden nonce field
+ */
+function bbp_move_reply_form_fields() {
+?>
+
+	<input type="hidden" name="action"       id="bbp_post_action" value="bbp-move-reply" />
+	<input type="hidden" name="bbp_reply_id" id="bbp_reply_id"    value="<?php echo absint( $_GET['reply_id'] ); ?>" />
+
+	<?php wp_nonce_field( 'bbp-move-reply_' . bbp_get_reply_id() );
+}
+
+/**
+ * Output a textarea or TinyMCE if enabled
+ *
+ * @since bbPress (r3586)
+ *
+ * @param array $args
+ * @uses bbp_get_the_content() To return the content to output
+ */
+function bbp_the_content( $args = array() ) {
+	echo bbp_get_the_content( $args );
+}
+	/**
+	 * Return a textarea or TinyMCE if enabled
+	 *
+	 * @since bbPress (r3586)
+	 *
+	 * @param array $args
+	 *
+	 * @uses apply_filter() To filter args and output
+	 * @uses wp_parse_pargs() To compare args
+	 * @uses bbp_use_wp_editor() To see if WP editor is in use
+	 * @uses bbp_is_edit() To see if we are editing something
+	 * @uses wp_editor() To output the WordPress editor
+	 *
+	 * @return string HTML from output buffer
+	 */
+	function bbp_get_the_content( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'context'           => 'topic',
+			'before'            => '<div class="bbp-the-content-wrapper">',
+			'after'             => '</div>',
+			'wpautop'           => true,
+			'media_buttons'     => false,
+			'textarea_rows'     => '12',
+			'tabindex'          => bbp_get_tab_index(),
+			'tabfocus_elements' => 'bbp_topic_title,bbp_topic_tags',
+			'editor_class'      => 'bbp-the-content',
+			'tinymce'           => false,
+			'teeny'             => true,
+			'quicktags'         => true,
+			'dfw'               => false
+		), 'get_the_content' );
+
+		// If using tinymce, remove our escaping and trust tinymce
+		if ( bbp_use_wp_editor() && ( false !== $r['tinymce'] ) ) {
+			remove_filter( 'bbp_get_form_forum_content', 'esc_textarea' );
+			remove_filter( 'bbp_get_form_topic_content', 'esc_textarea' );
+			remove_filter( 'bbp_get_form_reply_content', 'esc_textarea' );
+		}
+
+		// Assume we are not editing
+		$post_content = call_user_func( 'bbp_get_form_' . $r['context'] . '_content' );
+
+		// Start an output buffor
+		ob_start();
+
+		// Output something before the editor
+		if ( !empty( $r['before'] ) ) {
+			echo $r['before'];
+		}
+
+		// Use TinyMCE if available
+		if ( bbp_use_wp_editor() ) :
+
+			// Enable additional TinyMCE plugins before outputting the editor
+			add_filter( 'tiny_mce_plugins',   'bbp_get_tiny_mce_plugins'   );
+			add_filter( 'teeny_mce_plugins',  'bbp_get_tiny_mce_plugins'   );
+			add_filter( 'teeny_mce_buttons',  'bbp_get_teeny_mce_buttons'  );
+			add_filter( 'quicktags_settings', 'bbp_get_quicktags_settings' );
+
+			// Output the editor
+			wp_editor( $post_content, 'bbp_' . $r['context'] . '_content', array(
+				'wpautop'           => $r['wpautop'],
+				'media_buttons'     => $r['media_buttons'],
+				'textarea_rows'     => $r['textarea_rows'],
+				'tabindex'          => $r['tabindex'],
+				'tabfocus_elements' => $r['tabfocus_elements'],
+				'editor_class'      => $r['editor_class'],
+				'tinymce'           => $r['tinymce'],
+				'teeny'             => $r['teeny'],
+				'quicktags'         => $r['quicktags'],
+				'dfw'               => $r['dfw'],
+			) );
+
+			// Remove additional TinyMCE plugins after outputting the editor
+			remove_filter( 'tiny_mce_plugins',   'bbp_get_tiny_mce_plugins'   );
+			remove_filter( 'teeny_mce_plugins',  'bbp_get_tiny_mce_plugins'   );
+			remove_filter( 'teeny_mce_buttons',  'bbp_get_teeny_mce_buttons'  );
+			remove_filter( 'quicktags_settings', 'bbp_get_quicktags_settings' );
+
+		/**
+		 * Fallback to normal textarea.
+		 *
+		 * Note that we do not use esc_textarea() here to prevent double
+		 * escaping the editable output, mucking up existing content.
+		 */
+		else : ?>
+
+			<textarea id="bbp_<?php echo esc_attr( $r['context'] ); ?>_content" class="<?php echo esc_attr( $r['editor_class'] ); ?>" name="bbp_<?php echo esc_attr( $r['context'] ); ?>_content" cols="60" rows="<?php echo esc_attr( $r['textarea_rows'] ); ?>" tabindex="<?php echo esc_attr( $r['tabindex'] ); ?>"><?php echo $post_content; ?></textarea>
+
+		<?php endif;
+
+		// Output something after the editor
+		if ( !empty( $r['after'] ) ) {
+			echo $r['after'];
+		}
+
+		// Put the output into a usable variable
+		$output = ob_get_clean();
+
+		return apply_filters( 'bbp_get_the_content', $output, $args, $post_content );
+	}
+
+/**
+ * Edit TinyMCE plugins to match core behaviour
+ *
+ * @since bbPress (r4574)
+ *
+ * @param array $plugins
+ * @see tiny_mce_plugins, teeny_mce_plugins
+ * @return array
+ */
+function bbp_get_tiny_mce_plugins( $plugins = array() ) {
+
+	// Unset fullscreen
+	foreach ( $plugins as $key => $value ) {
+		if ( 'fullscreen' === $value ) {
+			unset( $plugins[$key] );
+			break;
+		}
+	}
+
+	// Add the tabfocus plugin
+	$plugins[] = 'tabfocus';
+
+	return apply_filters( 'bbp_get_tiny_mce_plugins', $plugins );
+}
+
+/**
+ * Edit TeenyMCE buttons to match allowedtags
+ *
+ * @since bbPress (r4605)
+ *
+ * @param array $buttons
+ * @see teeny_mce_buttons
+ * @return array
+ */
+function bbp_get_teeny_mce_buttons( $buttons = array() ) {
+
+	// Remove some buttons from TeenyMCE
+	$buttons = array_diff( $buttons, array(
+		'underline',
+		'justifyleft',
+		'justifycenter',
+		'justifyright'
+	) );
+
+	// Images
+	array_push( $buttons, 'image' );
+
+	return apply_filters( 'bbp_get_teeny_mce_buttons', $buttons );
+}
+
+/**
+ * Edit TinyMCE quicktags buttons to match allowedtags
+ *
+ * @since bbPress (r4606)
+ *
+ * @param array $buttons
+ * @see quicktags_settings
+ * @return array Quicktags settings
+ */
+function bbp_get_quicktags_settings( $settings = array() ) {
+
+	// Get buttons out of settings
+	$buttons_array = explode( ',', $settings['buttons'] );
+
+	// Diff the ones we don't want out
+	$buttons = array_diff( $buttons_array, array(
+		'ins',
+		'more',
+		'spell'
+	) );
+
+	// Put them back into a string in the $settings array
+	$settings['buttons'] = implode( ',', $buttons );
+
+	return apply_filters( 'bbp_get_quicktags_settings', $settings );
+}
+
+/** Views *********************************************************************/
+
+/**
+ * Output the view id
+ *
+ * @since bbPress (r2789)
+ *
+ * @param string $view Optional. View id
+ * @uses bbp_get_view_id() To get the view id
+ */
+function bbp_view_id( $view = '' ) {
+	echo bbp_get_view_id( $view );
+}
+
+	/**
+	 * Get the view id
+	 *
+	 * Use view id if supplied, otherwise bbp_get_view_rewrite_id() query var.
+	 *
+	 * @since bbPress (r2789)
+	 *
+	 * @param string $view Optional. View id.
+	 * @uses sanitize_title() To sanitize the view id
+	 * @uses get_query_var() To get the view id query variable
+	 * @uses bbp_get_view_rewrite_id() To get the view rewrite ID
+	 * @return bool|string ID on success, false on failure
+	 */
+	function bbp_get_view_id( $view = '' ) {
+		$bbp = bbpress();
+
+		if ( !empty( $view ) ) {
+			$view = sanitize_title( $view );
+		} elseif ( ! empty( $bbp->current_view_id ) ) {
+			$view = $bbp->current_view_id;
+		} else {
+			$view = get_query_var( bbp_get_view_rewrite_id() );
+		}
+
+		if ( array_key_exists( $view, $bbp->views ) ) {
+			return $view;
+		}
+
+		return false;
+	}
+
+/**
+ * Output the view name aka title
+ *
+ * @since bbPress (r2789)
+ *
+ * @param string $view Optional. View id
+ * @uses bbp_get_view_title() To get the view title
+ */
+function bbp_view_title( $view = '' ) {
+	echo bbp_get_view_title( $view );
+}
+
+	/**
+	 * Get the view name aka title
+	 *
+	 * If a view id is supplied, that is used. Otherwise the bbp_view
+	 * query var is checked for.
+	 *
+	 * @since bbPress (r2789)
+	 *
+	 * @param string $view Optional. View id
+	 * @uses bbp_get_view_id() To get the view id
+	 * @return bool|string Title on success, false on failure
+	 */
+	function bbp_get_view_title( $view = '' ) {
+		$bbp = bbpress();
+
+		$view = bbp_get_view_id( $view );
+		if ( empty( $view ) )
+			return false;
+
+		return $bbp->views[$view]['title'];
+	}
+
+/**
+ * Output the view url
+ *
+ * @since bbPress (r2789)
+ *
+ * @param string $view Optional. View id
+ * @uses bbp_get_view_url() To get the view url
+ */
+function bbp_view_url( $view = false ) {
+	echo esc_url( bbp_get_view_url( $view ) );
+}
+	/**
+	 * Return the view url
+	 *
+	 * @since bbPress (r2789)
+	 *
+	 * @param string $view Optional. View id
+	 * @uses sanitize_title() To sanitize the view id
+	 * @uses home_url() To get blog home url
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses apply_filters() Calls 'bbp_get_view_url' with the view url,
+	 *                        used view id
+	 * @return string View url (or home url if the view was not found)
+	 */
+	function bbp_get_view_url( $view = false ) {
+		global $wp_rewrite;
+
+		$view = bbp_get_view_id( $view );
+		if ( empty( $view ) )
+			return home_url();
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url = $wp_rewrite->root . bbp_get_view_slug() . '/' . $view;
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array( bbp_get_view_rewrite_id() => $view ), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_view_link', $url, $view );
+	}
+
+/** Query *********************************************************************/
+
+/**
+ * Check the passed parameter against the current _bbp_query_name
+ *
+ * @since bbPress (r2980)
+ *
+ * @uses bbp_get_query_name() Get the query var '_bbp_query_name'
+ * @return bool True if match, false if not
+ */
+function bbp_is_query_name( $name = '' )  {
+	return (bool) ( bbp_get_query_name() === $name );
+}
+
+/**
+ * Get the '_bbp_query_name' setting
+ *
+ * @since bbPress (r2695)
+ *
+ * @uses get_query_var() To get the query var '_bbp_query_name'
+ * @return string To return the query var value
+ */
+function bbp_get_query_name()  {
+	return get_query_var( '_bbp_query_name' );
+}
+
+/**
+ * Set the '_bbp_query_name' setting to $name
+ *
+ * @since bbPress (r2692)
+ *
+ * @param string $name What to set the query var to
+ * @uses set_query_var() To set the query var '_bbp_query_name'
+ */
+function bbp_set_query_name( $name = '' )  {
+	set_query_var( '_bbp_query_name', $name );
+}
+
+/**
+ * Used to clear the '_bbp_query_name' setting
+ *
+ * @since bbPress (r2692)
+ *
+ * @uses bbp_set_query_name() To set the query var '_bbp_query_name' value to ''
+ */
+function bbp_reset_query_name() {
+	bbp_set_query_name();
+}
+
+/** Breadcrumbs ***************************************************************/
+
+/**
+ * Output the page title as a breadcrumb
+ *
+ * @since bbPress (r2589)
+ *
+ * @param string $sep Separator. Defaults to '&larr;'
+ * @param bool $current_page Include the current item
+ * @param bool $root Include the root page if one exists
+ * @uses bbp_get_breadcrumb() To get the breadcrumb
+ */
+function bbp_title_breadcrumb( $args = array() ) {
+	echo bbp_get_breadcrumb( $args );
+}
+
+/**
+ * Output a breadcrumb
+ *
+ * @since bbPress (r2589)
+ *
+ * @param string $sep Separator. Defaults to '&larr;'
+ * @param bool $current_page Include the current item
+ * @param bool $root Include the root page if one exists
+ * @uses bbp_get_breadcrumb() To get the breadcrumb
+ */
+function bbp_breadcrumb( $args = array() ) {
+	echo bbp_get_breadcrumb( $args );
+}
+	/**
+	 * Return a breadcrumb ( forum -> topic -> reply )
+	 *
+	 * @since bbPress (r2589)
+	 *
+	 * @param string $sep Separator. Defaults to '&larr;'
+	 * @param bool $current_page Include the current item
+	 * @param bool $root Include the root page if one exists
+	 *
+	 * @uses get_post() To get the post
+	 * @uses bbp_get_forum_permalink() To get the forum link
+	 * @uses bbp_get_topic_permalink() To get the topic link
+	 * @uses bbp_get_reply_permalink() To get the reply link
+	 * @uses get_permalink() To get the permalink
+	 * @uses bbp_get_forum_post_type() To get the forum post type
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses bbp_get_forum_title() To get the forum title
+	 * @uses bbp_get_topic_title() To get the topic title
+	 * @uses bbp_get_reply_title() To get the reply title
+	 * @uses get_the_title() To get the title
+	 * @uses apply_filters() Calls 'bbp_get_breadcrumb' with the crumbs
+	 * @return string Breadcrumbs
+	 */
+	function bbp_get_breadcrumb( $args = array() ) {
+
+		// Turn off breadcrumbs
+		if ( apply_filters( 'bbp_no_breadcrumb', is_front_page() ) )
+			return;
+
+		// Define variables
+		$front_id         = $root_id                                 = 0;
+		$ancestors        = $crumbs           = $tag_data            = array();
+		$pre_root_text    = $pre_front_text   = $pre_current_text    = '';
+		$pre_include_root = $pre_include_home = $pre_include_current = true;
+
+		/** Home Text *********************************************************/
+
+		// No custom home text
+		if ( empty( $args['home_text'] ) ) {
+
+			$front_id = get_option( 'page_on_front' );
+
+			// Set home text to page title
+			if ( !empty( $front_id ) ) {
+				$pre_front_text = get_the_title( $front_id );
+
+			// Default to 'Home'
+			} else {
+				$pre_front_text = __( 'Home', 'bbpress' );
+			}
+		}
+
+		/** Root Text *********************************************************/
+
+		// No custom root text
+		if ( empty( $args['root_text'] ) ) {
+			$page = bbp_get_page_by_path( bbp_get_root_slug() );
+			if ( !empty( $page ) ) {
+				$root_id = $page->ID;
+			}
+			$pre_root_text = bbp_get_forum_archive_title();
+		}
+
+		/** Includes **********************************************************/
+
+		// Root slug is also the front page
+		if ( !empty( $front_id ) && ( $front_id === $root_id ) ) {
+			$pre_include_root = false;
+		}
+
+		// Don't show root if viewing forum archive
+		if ( bbp_is_forum_archive() ) {
+			$pre_include_root = false;
+		}
+
+		// Don't show root if viewing page in place of forum archive
+		if ( !empty( $root_id ) && ( ( is_single() || is_page() ) && ( $root_id === get_the_ID() ) ) ) {
+			$pre_include_root = false;
+		}
+
+		/** Current Text ******************************************************/
+
+		// Search page
+		if ( bbp_is_search() ) {
+			$pre_current_text = bbp_get_search_title();
+
+		// Forum archive
+		} elseif ( bbp_is_forum_archive() ) {
+			$pre_current_text = bbp_get_forum_archive_title();
+
+		// Topic archive
+		} elseif ( bbp_is_topic_archive() ) {
+			$pre_current_text = bbp_get_topic_archive_title();
+
+		// View
+		} elseif ( bbp_is_single_view() ) {
+			$pre_current_text = bbp_get_view_title();
+
+		// Single Forum
+		} elseif ( bbp_is_single_forum() ) {
+			$pre_current_text = bbp_get_forum_title();
+
+		// Single Topic
+		} elseif ( bbp_is_single_topic() ) {
+			$pre_current_text = bbp_get_topic_title();
+
+		// Single Topic
+		} elseif ( bbp_is_single_reply() ) {
+			$pre_current_text = bbp_get_reply_title();
+
+		// Topic Tag (or theme compat topic tag)
+		} elseif ( bbp_is_topic_tag() || ( get_query_var( 'bbp_topic_tag' ) && !bbp_is_topic_tag_edit() ) ) {
+
+			// Always include the tag name
+			$tag_data[] = bbp_get_topic_tag_name();
+
+			// If capable, include a link to edit the tag
+			if ( current_user_can( 'manage_topic_tags' ) ) {
+				$tag_data[] = '<a href="' . esc_url( bbp_get_topic_tag_edit_link() ) . '" class="bbp-edit-topic-tag-link">' . esc_html__( '(Edit)', 'bbpress' ) . '</a>';
+			}
+
+			// Implode the results of the tag data
+			$pre_current_text = sprintf( __( 'Topic Tag: %s', 'bbpress' ), implode( ' ', $tag_data ) );
+
+		// Edit Topic Tag
+		} elseif ( bbp_is_topic_tag_edit() ) {
+			$pre_current_text = __( 'Edit', 'bbpress' );
+
+		// Single
+		} else {
+			$pre_current_text = get_the_title();
+		}
+
+		/** Parse Args ********************************************************/
+
+		// Parse args
+		$r = bbp_parse_args( $args, array(
+
+			// HTML
+			'before'          => '<div class="bbp-breadcrumb"><p>',
+			'after'           => '</p></div>',
+
+			// Separator
+			'sep'             => is_rtl() ? __( '&lsaquo;', 'bbpress' ) : __( '&rsaquo;', 'bbpress' ),
+			'pad_sep'         => 1,
+			'sep_before'      => '<span class="bbp-breadcrumb-sep">',
+			'sep_after'       => '</span>',
+
+			// Crumbs
+			'crumb_before'    => '',
+			'crumb_after'     => '',
+
+			// Home
+			'include_home'    => $pre_include_home,
+			'home_text'       => $pre_front_text,
+
+			// Forum root
+			'include_root'    => $pre_include_root,
+			'root_text'       => $pre_root_text,
+
+			// Current
+			'include_current' => $pre_include_current,
+			'current_text'    => $pre_current_text,
+			'current_before'  => '<span class="bbp-breadcrumb-current">',
+			'current_after'   => '</span>',
+		), 'get_breadcrumb' );
+
+		/** Ancestors *********************************************************/
+
+		// Get post ancestors
+		if ( is_singular() || bbp_is_forum_edit() || bbp_is_topic_edit() || bbp_is_reply_edit() ) {
+			$ancestors = array_reverse( (array) get_post_ancestors( get_the_ID() ) );
+		}
+
+		// Do we want to include a link to home?
+		if ( !empty( $r['include_home'] ) || empty( $r['home_text'] ) ) {
+			$crumbs[] = '<a href="' . trailingslashit( home_url() ) . '" class="bbp-breadcrumb-home">' . $r['home_text'] . '</a>';
+		}
+
+		// Do we want to include a link to the forum root?
+		if ( !empty( $r['include_root'] ) || empty( $r['root_text'] ) ) {
+
+			// Page exists at root slug path, so use its permalink
+			$page = bbp_get_page_by_path( bbp_get_root_slug() );
+			if ( !empty( $page ) ) {
+				$root_url = get_permalink( $page->ID );
+
+			// Use the root slug
+			} else {
+				$root_url = get_post_type_archive_link( bbp_get_forum_post_type() );
+			}
+
+			// Add the breadcrumb
+			$crumbs[] = '<a href="' . esc_url( $root_url ) . '" class="bbp-breadcrumb-root">' . $r['root_text'] . '</a>';
+		}
+
+		// Ancestors exist
+		if ( !empty( $ancestors ) ) {
+
+			// Loop through parents
+			foreach ( (array) $ancestors as $parent_id ) {
+
+				// Parents
+				$parent = get_post( $parent_id );
+
+				// Skip parent if empty or error
+				if ( empty( $parent ) || is_wp_error( $parent ) )
+					continue;
+
+				// Switch through post_type to ensure correct filters are applied
+				switch ( $parent->post_type ) {
+
+					// Forum
+					case bbp_get_forum_post_type() :
+						$crumbs[] = '<a href="' . esc_url( bbp_get_forum_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-forum">' . bbp_get_forum_title( $parent->ID ) . '</a>';
+						break;
+
+					// Topic
+					case bbp_get_topic_post_type() :
+						$crumbs[] = '<a href="' . esc_url( bbp_get_topic_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-topic">' . bbp_get_topic_title( $parent->ID ) . '</a>';
+						break;
+
+					// Reply (Note: not in most themes)
+					case bbp_get_reply_post_type() :
+						$crumbs[] = '<a href="' . esc_url( bbp_get_reply_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-reply">' . bbp_get_reply_title( $parent->ID ) . '</a>';
+						break;
+
+					// WordPress Post/Page/Other
+					default :
+						$crumbs[] = '<a href="' . esc_url( get_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-item">' . get_the_title( $parent->ID ) . '</a>';
+						break;
+				}
+			}
+
+		// Edit topic tag
+		} elseif ( bbp_is_topic_tag_edit() ) {
+			$crumbs[] = '<a href="' . esc_url( get_term_link( bbp_get_topic_tag_id(), bbp_get_topic_tag_tax_id() ) ) . '" class="bbp-breadcrumb-topic-tag">' . sprintf( __( 'Topic Tag: %s', 'bbpress' ), bbp_get_topic_tag_name() ) . '</a>';
+
+		// Search
+		} elseif ( bbp_is_search() && bbp_get_search_terms() ) {
+			$crumbs[] = '<a href="' . esc_url( bbp_get_search_url() ) . '" class="bbp-breadcrumb-search">' . esc_html__( 'Search', 'bbpress' ) . '</a>';
+		}
+
+		/** Current ***********************************************************/
+
+		// Add current page to breadcrumb
+		if ( !empty( $r['include_current'] ) || empty( $r['current_text'] ) ) {
+			$crumbs[] = $r['current_before'] . $r['current_text'] . $r['current_after'];
+		}
+
+		/** Separator *********************************************************/
+
+		// Wrap the separator in before/after before padding and filter
+		if ( ! empty( $r['sep'] ) ) {
+			$sep = $r['sep_before'] . $r['sep'] . $r['sep_after'];
+		}
+
+		// Pad the separator
+		if ( !empty( $r['pad_sep'] ) ) {
+			if ( function_exists( 'mb_strlen' ) ) {
+				$sep = str_pad( $sep, mb_strlen( $sep ) + ( (int) $r['pad_sep'] * 2 ), ' ', STR_PAD_BOTH );
+			} else {
+				$sep = str_pad( $sep, strlen( $sep ) + ( (int) $r['pad_sep'] * 2 ), ' ', STR_PAD_BOTH );
+			}
+		}
+
+		/** Finish Up *********************************************************/
+
+		// Filter the separator and breadcrumb
+		$sep    = apply_filters( 'bbp_breadcrumb_separator', $sep    );
+		$crumbs = apply_filters( 'bbp_breadcrumbs',          $crumbs );
+
+		// Build the trail
+		$trail  = !empty( $crumbs ) ? ( $r['before'] . $r['crumb_before'] . implode( $sep . $r['crumb_after'] . $r['crumb_before'] , $crumbs ) . $r['crumb_after'] . $r['after'] ) : '';
+
+		return apply_filters( 'bbp_get_breadcrumb', $trail, $crumbs, $r );
+	}
+
+/** Topic Tags ***************************************************************/
+
+/**
+ * Output all of the allowed tags in HTML format with attributes.
+ *
+ * This is useful for displaying in the post area, which elements and
+ * attributes are supported. As well as any plugins which want to display it.
+ *
+ * @since bbPress (r2780)
+ *
+ * @uses bbp_get_allowed_tags()
+ */
+function bbp_allowed_tags() {
+	echo bbp_get_allowed_tags();
+}
+	/**
+	 * Display all of the allowed tags in HTML format with attributes.
+	 *
+	 * This is useful for displaying in the post area, which elements and
+	 * attributes are supported. As well as any plugins which want to display it.
+	 *
+	 * @since bbPress (r2780)
+	 *
+	 * @uses bbp_kses_allowed_tags() To get the allowed tags
+	 * @uses apply_filters() Calls 'bbp_allowed_tags' with the tags
+	 * @return string HTML allowed tags entity encoded.
+	 */
+	function bbp_get_allowed_tags() {
+
+		$allowed = '';
+
+		foreach ( (array) bbp_kses_allowed_tags() as $tag => $attributes ) {
+			$allowed .= '<' . $tag;
+			if ( 0 < count( $attributes ) ) {
+				foreach ( array_keys( $attributes ) as $attribute ) {
+					$allowed .= ' ' . $attribute . '=""';
+				}
+			}
+			$allowed .= '> ';
+		}
+
+		return apply_filters( 'bbp_get_allowed_tags', htmlentities( $allowed ) );
+	}
+
+/** Errors & Messages *********************************************************/
+
+/**
+ * Display possible errors & messages inside a template file
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses WP_Error bbPress::errors::get_error_codes() To get the error codes
+ * @uses WP_Error bbPress::errors::get_error_data() To get the error data
+ * @uses WP_Error bbPress::errors::get_error_messages() To get the error
+ *                                                       messages
+ * @uses is_wp_error() To check if it's a {@link WP_Error}
+ */
+function bbp_template_notices() {
+
+	// Bail if no notices or errors
+	if ( !bbp_has_errors() )
+		return;
+
+	// Define local variable(s)
+	$errors = $messages = array();
+
+	// Get bbPress
+	$bbp = bbpress();
+
+	// Loop through notices
+	foreach ( $bbp->errors->get_error_codes() as $code ) {
+
+		// Get notice severity
+		$severity = $bbp->errors->get_error_data( $code );
+
+		// Loop through notices and separate errors from messages
+		foreach ( $bbp->errors->get_error_messages( $code ) as $error ) {
+			if ( 'message' === $severity ) {
+				$messages[] = $error;
+			} else {
+				$errors[]   = $error;
+			}
+		}
+	}
+
+	// Display errors first...
+	if ( !empty( $errors ) ) : ?>
+
+		<div class="bbp-template-notice error">
+			<p>
+				<?php echo implode( "</p>\n<p>", $errors ); ?>
+			</p>
+		</div>
+
+	<?php endif;
+
+	// ...and messages last
+	if ( !empty( $messages ) ) : ?>
+
+		<div class="bbp-template-notice">
+			<p>
+				<?php echo implode( "</p>\n<p>", $messages ); ?>
+			</p>
+		</div>
+
+	<?php endif;
+}
+
+/** Login/logout/register/lost pass *******************************************/
+
+/**
+ * Output the logout link
+ *
+ * @since bbPress (r2827)
+ *
+ * @param string $redirect_to Redirect to url
+ * @uses bbp_get_logout_link() To get the logout link
+ */
+function bbp_logout_link( $redirect_to = '' ) {
+	echo bbp_get_logout_link( $redirect_to );
+}
+	/**
+	 * Return the logout link
+	 *
+	 * @since bbPress (r2827)
+	 *
+	 * @param string $redirect_to Redirect to url
+	 * @uses wp_logout_url() To get the logout url
+	 * @uses apply_filters() Calls 'bbp_get_logout_link' with the logout link and
+	 *                        redirect to url
+	 * @return string The logout link
+	 */
+	function bbp_get_logout_link( $redirect_to = '' ) {
+		return apply_filters( 'bbp_get_logout_link', '<a href="' . wp_logout_url( $redirect_to ) . '" class="button logout-link">' . esc_html__( 'Log Out', 'bbpress' ) . '</a>', $redirect_to );
+	}
+
+/** Title *********************************************************************/
+
+/**
+ * Custom page title for bbPress pages
+ *
+ * @since bbPress (r2788)
+ *
+ * @param string $title Optional. The title (not used).
+ * @param string $sep Optional, default is '&raquo;'. How to separate the
+ *                     various items within the page title.
+ * @param string $seplocation Optional. Direction to display title, 'right'.
+ * @uses bbp_is_single_user() To check if it's a user profile page
+ * @uses bbp_is_single_user_edit() To check if it's a user profile edit page
+ * @uses bbp_is_user_home() To check if the profile page is of the current user
+ * @uses get_query_var() To get the user id
+ * @uses get_userdata() To get the user data
+ * @uses bbp_is_single_forum() To check if it's a forum
+ * @uses bbp_get_forum_title() To get the forum title
+ * @uses bbp_is_single_topic() To check if it's a topic
+ * @uses bbp_get_topic_title() To get the topic title
+ * @uses bbp_is_single_reply() To check if it's a reply
+ * @uses bbp_get_reply_title() To get the reply title
+ * @uses is_tax() To check if it's the tag page
+ * @uses get_queried_object() To get the queried object
+ * @uses bbp_is_single_view() To check if it's a view
+ * @uses bbp_get_view_title() To get the view title
+ * @uses apply_filters() Calls 'bbp_raw_title' with the title
+ * @uses apply_filters() Calls 'bbp_profile_page_wp_title' with the title,
+ *                        separator and separator location
+ * @return string The tite
+ */
+function bbp_title( $title = '', $sep = '&raquo;', $seplocation = '' ) {
+
+	// Title array
+	$new_title = array();
+
+	/** Archives **************************************************************/
+
+	// Forum Archive
+	if ( bbp_is_forum_archive() ) {
+		$new_title['text'] = bbp_get_forum_archive_title();
+
+	// Topic Archive
+	} elseif ( bbp_is_topic_archive() ) {
+		$new_title['text'] = bbp_get_topic_archive_title();
+
+	/** Edit ******************************************************************/
+
+	// Forum edit page
+	} elseif ( bbp_is_forum_edit() ) {
+		$new_title['text']   = bbp_get_forum_title();
+		$new_title['format'] = esc_attr__( 'Forum Edit: %s', 'bbpress' );
+
+	// Topic edit page
+	} elseif ( bbp_is_topic_edit() ) {
+		$new_title['text']   = bbp_get_topic_title();
+		$new_title['format'] = esc_attr__( 'Topic Edit: %s', 'bbpress' );
+
+	// Reply edit page
+	} elseif ( bbp_is_reply_edit() ) {
+		$new_title['text']   = bbp_get_reply_title();
+		$new_title['format'] = esc_attr__( 'Reply Edit: %s', 'bbpress' );
+
+	// Topic tag edit page
+	} elseif ( bbp_is_topic_tag_edit() ) {
+		$new_title['text']   = bbp_get_topic_tag_name();
+		$new_title['format'] = esc_attr__( 'Topic Tag Edit: %s', 'bbpress' );
+
+	/** Singles ***************************************************************/
+
+	// Forum page
+	} elseif ( bbp_is_single_forum() ) {
+		$new_title['text']   = bbp_get_forum_title();
+		$new_title['format'] = esc_attr__( 'Forum: %s', 'bbpress' );
+
+	// Topic page
+	} elseif ( bbp_is_single_topic() ) {
+		$new_title['text']   = bbp_get_topic_title();
+		$new_title['format'] = esc_attr__( 'Topic: %s', 'bbpress' );
+
+	// Replies
+	} elseif ( bbp_is_single_reply() ) {
+		$new_title['text']   = bbp_get_reply_title();
+
+	// Topic tag page
+	} elseif ( bbp_is_topic_tag() || get_query_var( 'bbp_topic_tag' ) ) {
+		$new_title['text']   = bbp_get_topic_tag_name();
+		$new_title['format'] = esc_attr__( 'Topic Tag: %s', 'bbpress' );
+
+	/** Users *****************************************************************/
+
+	// Profile page
+	} elseif ( bbp_is_single_user() ) {
+
+		// User is viewing their own profile
+		if ( bbp_is_user_home() ) {
+			$new_title['text'] = esc_attr_x( 'Your', 'User viewing his/her own profile', 'bbpress' );
+
+		// User is viewing someone else's profile (so use their display name)
+		} else {
+			$new_title['text'] = sprintf( esc_attr_x( "%s's", 'User viewing another users profile', 'bbpress' ), get_userdata( bbp_get_user_id() )->display_name );
+		}
+
+		// User topics created
+		if ( bbp_is_single_user_topics() ) {
+			$new_title['format'] = esc_attr__( "%s Topics",        'bbpress' );
+
+		// User rueplies created
+		} elseif ( bbp_is_single_user_replies() ) {
+			$new_title['format'] = esc_attr__( "%s Replies",       'bbpress' );
+
+		// User favorites
+		} elseif ( bbp_is_favorites() ) {
+			$new_title['format'] = esc_attr__( "%s Favorites",     'bbpress' );
+
+		// User subscriptions
+		} elseif ( bbp_is_subscriptions() ) {
+			$new_title['format'] = esc_attr__( "%s Subscriptions", 'bbpress' );
+
+		// User "home"
+		} else {
+			$new_title['format'] = esc_attr__( "%s Profile",       'bbpress' );
+		}
+
+	// Profile edit page
+	} elseif ( bbp_is_single_user_edit() ) {
+
+		// Current user
+		if ( bbp_is_user_home_edit() ) {
+			$new_title['text']   = esc_attr__( 'Edit Your Profile', 'bbpress' );
+
+		// Other user
+		} else {
+			$new_title['text']   = get_userdata( bbp_get_user_id() )->display_name;
+			$new_title['format'] = esc_attr__( "Edit %s's Profile", 'bbpress' );
+		}
+
+	/** Views *****************************************************************/
+
+	// Views
+	} elseif ( bbp_is_single_view() ) {
+		$new_title['text']   = bbp_get_view_title();
+		$new_title['format'] = esc_attr__( 'View: %s', 'bbpress' );
+
+	/** Search ****************************************************************/
+
+	// Search
+	} elseif ( bbp_is_search() ) {
+		$new_title['text'] = bbp_get_search_title();
+	}
+
+	// This filter is deprecated. Use 'bbp_before_title_parse_args' instead.
+	$new_title = apply_filters( 'bbp_raw_title_array', $new_title );
+
+	// Set title array defaults
+	$new_title = bbp_parse_args( $new_title, array(
+		'text'   => $title,
+		'format' => '%s'
+	), 'title' );
+
+	// Get the formatted raw title
+	$new_title = sprintf( $new_title['format'], $new_title['text'] );
+
+	// Filter the raw title
+	$new_title = apply_filters( 'bbp_raw_title', $new_title, $sep, $seplocation );
+
+	// Compare new title with original title
+	if ( $new_title === $title )
+		return $title;
+
+	// Temporary separator, for accurate flipping, if necessary
+	$t_sep  = '%WP_TITILE_SEP%';
+	$prefix = '';
+
+	if ( !empty( $new_title ) )
+		$prefix = " $sep ";
+
+	// sep on right, so reverse the order
+	if ( 'right' === $seplocation ) {
+		$new_title_array = array_reverse( explode( $t_sep, $new_title ) );
+		$new_title       = implode( " $sep ", $new_title_array ) . $prefix;
+
+	// sep on left, do not reverse
+	} else {
+		$new_title_array = explode( $t_sep, $new_title );
+		$new_title       = $prefix . implode( " $sep ", $new_title_array );
+	}
+
+	// Filter and return
+	return apply_filters( 'bbp_title', $new_title, $sep, $seplocation );
+}
Index: /tags/2.5.4/includes/common/widgets.php
===================================================================
--- /tags/2.5.4/includes/common/widgets.php	(revision 5382)
+++ /tags/2.5.4/includes/common/widgets.php	(revision 5382)
@@ -0,0 +1,1259 @@
+<?php
+
+/**
+ * bbPress Widgets
+ *
+ * Contains the forum list, topic list, reply list and login form widgets.
+ *
+ * @package bbPress
+ * @subpackage Widgets
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * bbPress Login Widget
+ *
+ * Adds a widget which displays the login form
+ *
+ * @since bbPress (r2827)
+ *
+ * @uses WP_Widget
+ */
+class BBP_Login_Widget extends WP_Widget {
+
+	/**
+	 * bbPress Login Widget
+	 *
+	 * Registers the login widget
+	 *
+	 * @since bbPress (r2827)
+	 *
+	 * @uses apply_filters() Calls 'bbp_login_widget_options' with the
+	 *                        widget options
+	 */
+	public function __construct() {
+		$widget_ops = apply_filters( 'bbp_login_widget_options', array(
+			'classname'   => 'bbp_widget_login',
+			'description' => __( 'A simple login form with optional links to sign-up and lost password pages.', 'bbpress' )
+		) );
+
+		parent::__construct( false, __( '(bbPress) Login Widget', 'bbpress' ), $widget_ops );
+	}
+
+	/**
+	 * Register the widget
+	 *
+	 * @since bbPress (r3389)
+	 *
+	 * @uses register_widget()
+	 */
+	public static function register_widget() {
+		register_widget( 'BBP_Login_Widget' );
+	}
+
+	/**
+	 * Displays the output, the login form
+	 *
+	 * @since bbPress (r2827)
+	 *
+	 * @param mixed $args Arguments
+	 * @param array $instance Instance
+	 * @uses apply_filters() Calls 'bbp_login_widget_title' with the title
+	 * @uses get_template_part() To get the login/logged in form
+	 */
+	public function widget( $args = array(), $instance = array() ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance );
+
+		// Typical WordPress filter
+		$settings['title'] = apply_filters( 'widget_title', $settings['title'], $instance, $this->id_base );
+
+		// bbPress filters
+		$settings['title']    = apply_filters( 'bbp_login_widget_title',    $settings['title'],    $instance, $this->id_base );
+		$settings['register'] = apply_filters( 'bbp_login_widget_register', $settings['register'], $instance, $this->id_base );
+		$settings['lostpass'] = apply_filters( 'bbp_login_widget_lostpass', $settings['lostpass'], $instance, $this->id_base );
+
+		echo $args['before_widget'];
+
+		if ( !empty( $settings['title'] ) ) {
+			echo $args['before_title'] . $settings['title'] . $args['after_title'];
+		}
+
+		if ( !is_user_logged_in() ) : ?>
+
+			<form method="post" action="<?php bbp_wp_login_action( array( 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
+				<fieldset>
+					<legend><?php _e( 'Log In', 'bbpress' ); ?></legend>
+
+					<div class="bbp-username">
+						<label for="user_login"><?php _e( 'Username', 'bbpress' ); ?>: </label>
+						<input type="text" name="log" value="<?php bbp_sanitize_val( 'user_login', 'text' ); ?>" size="20" id="user_login" tabindex="<?php bbp_tab_index(); ?>" />
+					</div>
+
+					<div class="bbp-password">
+						<label for="user_pass"><?php _e( 'Password', 'bbpress' ); ?>: </label>
+						<input type="password" name="pwd" value="<?php bbp_sanitize_val( 'user_pass', 'password' ); ?>" size="20" id="user_pass" tabindex="<?php bbp_tab_index(); ?>" />
+					</div>
+
+					<div class="bbp-remember-me">
+						<input type="checkbox" name="rememberme" value="forever" <?php checked( bbp_get_sanitize_val( 'rememberme', 'checkbox' ), true, true ); ?> id="rememberme" tabindex="<?php bbp_tab_index(); ?>" />
+						<label for="rememberme"><?php _e( 'Remember Me', 'bbpress' ); ?></label>
+					</div>
+
+					<div class="bbp-submit-wrapper">
+
+						<?php do_action( 'login_form' ); ?>
+
+						<button type="submit" name="user-submit" id="user-submit" tabindex="<?php bbp_tab_index(); ?>" class="button submit user-submit"><?php _e( 'Log In', 'bbpress' ); ?></button>
+
+						<?php bbp_user_login_fields(); ?>
+
+					</div>
+
+					<?php if ( !empty( $settings['register'] ) || !empty( $settings['lostpass'] ) ) : ?>
+
+						<div class="bbp-login-links">
+
+							<?php if ( !empty( $settings['register'] ) ) : ?>
+
+								<a href="<?php echo esc_url( $settings['register'] ); ?>" title="<?php esc_attr_e( 'Register', 'bbpress' ); ?>" class="bbp-register-link"><?php _e( 'Register', 'bbpress' ); ?></a>
+
+							<?php endif; ?>
+
+							<?php if ( !empty( $settings['lostpass'] ) ) : ?>
+
+								<a href="<?php echo esc_url( $settings['lostpass'] ); ?>" title="<?php esc_attr_e( 'Lost Password', 'bbpress' ); ?>" class="bbp-lostpass-link"><?php _e( 'Lost Password', 'bbpress' ); ?></a>
+
+							<?php endif; ?>
+
+						</div>
+
+					<?php endif; ?>
+
+				</fieldset>
+			</form>
+
+		<?php else : ?>
+
+			<div class="bbp-logged-in">
+				<a href="<?php bbp_user_profile_url( bbp_get_current_user_id() ); ?>" class="submit user-submit"><?php echo get_avatar( bbp_get_current_user_id(), '40' ); ?></a>
+				<h4><?php bbp_user_profile_link( bbp_get_current_user_id() ); ?></h4>
+
+				<?php bbp_logout_link(); ?>
+			</div>
+
+		<?php endif;
+
+		echo $args['after_widget'];
+	}
+
+	/**
+	 * Update the login widget options
+	 *
+	 * @since bbPress (r2827)
+	 *
+	 * @param array $new_instance The new instance options
+	 * @param array $old_instance The old instance options
+	 */
+	public function update( $new_instance, $old_instance ) {
+		$instance             = $old_instance;
+		$instance['title']    = strip_tags( $new_instance['title'] );
+		$instance['register'] = esc_url_raw( $new_instance['register'] );
+		$instance['lostpass'] = esc_url_raw( $new_instance['lostpass'] );
+
+		return $instance;
+	}
+
+	/**
+	 * Output the login widget options form
+	 *
+	 * @since bbPress (r2827)
+	 *
+	 * @param $instance Instance
+	 * @uses BBP_Login_Widget::get_field_id() To output the field id
+	 * @uses BBP_Login_Widget::get_field_name() To output the field name
+	 */
+	public function form( $instance = array() ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance ); ?>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'bbpress' ); ?>
+			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" /></label>
+		</p>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'register' ); ?>"><?php _e( 'Register URI:', 'bbpress' ); ?>
+			<input class="widefat" id="<?php echo $this->get_field_id( 'register' ); ?>" name="<?php echo $this->get_field_name( 'register' ); ?>" type="text" value="<?php echo esc_url( $settings['register'] ); ?>" /></label>
+		</p>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'lostpass' ); ?>"><?php _e( 'Lost Password URI:', 'bbpress' ); ?>
+			<input class="widefat" id="<?php echo $this->get_field_id( 'lostpass' ); ?>" name="<?php echo $this->get_field_name( 'lostpass' ); ?>" type="text" value="<?php echo esc_url( $settings['lostpass'] ); ?>" /></label>
+		</p>
+
+		<?php
+	}
+
+	/**
+	 * Merge the widget settings into defaults array.
+	 *
+	 * @since bbPress (r4802)
+	 *
+	 * @param $instance Instance
+	 * @uses bbp_parse_args() To merge widget settings into defaults
+	 */
+	public function parse_settings( $instance = array() ) {
+		return bbp_parse_args( $instance, array(
+			'title'    => '',
+			'register' => '',
+			'lostpass' => ''
+		), 'login_widget_settings' );
+	}
+}
+
+/**
+ * bbPress Views Widget
+ *
+ * Adds a widget which displays the view list
+ *
+ * @since bbPress (r3020)
+ *
+ * @uses WP_Widget
+ */
+class BBP_Views_Widget extends WP_Widget {
+
+	/**
+	 * bbPress View Widget
+	 *
+	 * Registers the view widget
+	 *
+	 * @since bbPress (r3020)
+	 *
+	 * @uses apply_filters() Calls 'bbp_views_widget_options' with the
+	 *                        widget options
+	 */
+	public function __construct() {
+		$widget_ops = apply_filters( 'bbp_views_widget_options', array(
+			'classname'   => 'widget_display_views',
+			'description' => __( 'A list of registered optional topic views.', 'bbpress' )
+		) );
+
+		parent::__construct( false, __( '(bbPress) Topic Views List', 'bbpress' ), $widget_ops );
+	}
+
+	/**
+	 * Register the widget
+	 *
+	 * @since bbPress (r3389)
+	 *
+	 * @uses register_widget()
+	 */
+	public static function register_widget() {
+		register_widget( 'BBP_Views_Widget' );
+	}
+
+	/**
+	 * Displays the output, the view list
+	 *
+	 * @since bbPress (r3020)
+	 *
+	 * @param mixed $args Arguments
+	 * @param array $instance Instance
+	 * @uses apply_filters() Calls 'bbp_view_widget_title' with the title
+	 * @uses bbp_get_views() To get the views
+	 * @uses bbp_view_url() To output the view url
+	 * @uses bbp_view_title() To output the view title
+	 */
+	public function widget( $args = array(), $instance = array() ) {
+
+		// Only output widget contents if views exist
+		if ( ! bbp_get_views() ) {
+			return;
+		}
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance );
+
+		// Typical WordPress filter
+		$settings['title'] = apply_filters( 'widget_title',          $settings['title'], $instance, $this->id_base );
+
+		// bbPress filter
+		$settings['title'] = apply_filters( 'bbp_view_widget_title', $settings['title'], $instance, $this->id_base );
+
+		echo $args['before_widget'];
+
+		if ( !empty( $settings['title'] ) ) {
+			echo $args['before_title'] . $settings['title'] . $args['after_title'];
+		} ?>
+
+		<ul>
+
+			<?php foreach ( array_keys( bbp_get_views() ) as $view ) : ?>
+
+				<li><a class="bbp-view-title" href="<?php bbp_view_url( $view ); ?>"><?php bbp_view_title( $view ); ?></a></li>
+
+			<?php endforeach; ?>
+
+		</ul>
+
+		<?php echo $args['after_widget'];
+	}
+
+	/**
+	 * Update the view widget options
+	 *
+	 * @since bbPress (r3020)
+	 *
+	 * @param array $new_instance The new instance options
+	 * @param array $old_instance The old instance options
+	 */
+	public function update( $new_instance = array(), $old_instance = array() ) {
+		$instance          = $old_instance;
+		$instance['title'] = strip_tags( $new_instance['title'] );
+
+		return $instance;
+	}
+
+	/**
+	 * Output the view widget options form
+	 *
+	 * @since bbPress (r3020)
+	 *
+	 * @param $instance Instance
+	 * @uses BBP_Views_Widget::get_field_id() To output the field id
+	 * @uses BBP_Views_Widget::get_field_name() To output the field name
+	 */
+	public function form( $instance = array() ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance ); ?>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'bbpress' ); ?>
+				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" />
+			</label>
+		</p>
+
+		<?php
+	}
+
+	/**
+	 * Merge the widget settings into defaults array.
+	 *
+	 * @since bbPress (r4802)
+	 *
+	 * @param $instance Instance
+	 * @uses bbp_parse_args() To merge widget settings into defaults
+	 */
+	public function parse_settings( $instance = array() ) {
+		return bbp_parse_args( $instance, array(
+			'title' => ''
+		), 'view_widget_settings' );
+	}
+}
+
+/**
+ * bbPress Search Widget
+ *
+ * Adds a widget which displays the forum search form
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses WP_Widget
+ */
+class BBP_Search_Widget extends WP_Widget {
+
+	/**
+	 * bbPress Search Widget
+	 *
+	 * Registers the search widget
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @uses apply_filters() Calls 'bbp_search_widget_options' with the
+	 *                        widget options
+	 */
+	public function __construct() {
+		$widget_ops = apply_filters( 'bbp_search_widget_options', array(
+			'classname'   => 'widget_display_search',
+			'description' => __( 'The bbPress forum search form.', 'bbpress' )
+		) );
+
+		parent::__construct( false, __( '(bbPress) Forum Search Form', 'bbpress' ), $widget_ops );
+	}
+
+	/**
+	 * Register the widget
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @uses register_widget()
+	 */
+	public static function register_widget() {
+		register_widget( 'BBP_Search_Widget' );
+	}
+
+	/**
+	 * Displays the output, the search form
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @uses apply_filters() Calls 'bbp_search_widget_title' with the title
+	 * @uses get_template_part() To get the search form
+	 */
+	public function widget( $args, $instance ) {
+
+		// Bail if search is disabled
+		if ( ! bbp_allow_search() )
+			return;
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance );
+
+		// Typical WordPress filter
+		$settings['title'] = apply_filters( 'widget_title',            $settings['title'], $instance, $this->id_base );
+
+		// bbPress filter
+		$settings['title'] = apply_filters( 'bbp_search_widget_title', $settings['title'], $instance, $this->id_base );
+
+		echo $args['before_widget'];
+
+		if ( !empty( $settings['title'] ) ) {
+			echo $args['before_title'] . $settings['title'] . $args['after_title'];
+		}
+
+		bbp_get_template_part( 'form', 'search' );
+
+		echo $args['after_widget'];
+	}
+
+	/**
+	 * Update the widget options
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @param array $new_instance The new instance options
+	 * @param array $old_instance The old instance options
+	 */
+	public function update( $new_instance, $old_instance ) {
+		$instance          = $old_instance;
+		$instance['title'] = strip_tags( $new_instance['title'] );
+
+		return $instance;
+	}
+
+	/**
+	 * Output the search widget options form
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @param $instance Instance
+	 * @uses BBP_Search_Widget::get_field_id() To output the field id
+	 * @uses BBP_Search_Widget::get_field_name() To output the field name
+	 */
+	public function form( $instance ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance ); ?>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'bbpress' ); ?>
+				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" />
+			</label>
+		</p>
+
+		<?php
+	}
+
+	/**
+	 * Merge the widget settings into defaults array.
+	 *
+	 * @since bbPress (r4802)
+	 *
+	 * @param $instance Instance
+	 * @uses bbp_parse_args() To merge widget settings into defaults
+	 */
+	public function parse_settings( $instance = array() ) {
+		return bbp_parse_args( $instance, array(
+			'title' => __( 'Search Forums', 'bbpress' )
+		), 'search_widget_settings' );
+	}
+}
+
+/**
+ * bbPress Forum Widget
+ *
+ * Adds a widget which displays the forum list
+ *
+ * @since bbPress (r2653)
+ *
+ * @uses WP_Widget
+ */
+class BBP_Forums_Widget extends WP_Widget {
+
+	/**
+	 * bbPress Forum Widget
+	 *
+	 * Registers the forum widget
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @uses apply_filters() Calls 'bbp_forums_widget_options' with the
+	 *                        widget options
+	 */
+	public function __construct() {
+		$widget_ops = apply_filters( 'bbp_forums_widget_options', array(
+			'classname'   => 'widget_display_forums',
+			'description' => __( 'A list of forums with an option to set the parent.', 'bbpress' )
+		) );
+
+		parent::__construct( false, __( '(bbPress) Forums List', 'bbpress' ), $widget_ops );
+	}
+
+	/**
+	 * Register the widget
+	 *
+	 * @since bbPress (r3389)
+	 *
+	 * @uses register_widget()
+	 */
+	public static function register_widget() {
+		register_widget( 'BBP_Forums_Widget' );
+	}
+
+	/**
+	 * Displays the output, the forum list
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param mixed $args Arguments
+	 * @param array $instance Instance
+	 * @uses apply_filters() Calls 'bbp_forum_widget_title' with the title
+	 * @uses get_option() To get the forums per page option
+	 * @uses current_user_can() To check if the current user can read
+	 *                           private() To resety name
+	 * @uses bbp_has_forums() The main forum loop
+	 * @uses bbp_forums() To check whether there are more forums available
+	 *                     in the loop
+	 * @uses bbp_the_forum() Loads up the current forum in the loop
+	 * @uses bbp_forum_permalink() To display the forum permalink
+	 * @uses bbp_forum_title() To display the forum title
+	 */
+	public function widget( $args, $instance ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance );
+
+		// Typical WordPress filter
+		$settings['title'] = apply_filters( 'widget_title',           $settings['title'], $instance, $this->id_base );
+
+		// bbPress filter
+		$settings['title'] = apply_filters( 'bbp_forum_widget_title', $settings['title'], $instance, $this->id_base );
+
+		// Note: private and hidden forums will be excluded via the
+		// bbp_pre_get_posts_normalize_forum_visibility action and function.
+		$widget_query = new WP_Query( array(
+			'post_type'           => bbp_get_forum_post_type(),
+			'post_parent'         => $settings['parent_forum'],
+			'post_status'         => bbp_get_public_status_id(),
+			'posts_per_page'      => get_option( '_bbp_forums_per_page', 50 ),
+			'ignore_sticky_posts' => true,
+			'no_found_rows'       => true,
+			'orderby'             => 'menu_order title',
+			'order'               => 'ASC'
+		) );
+
+		// Bail if no posts
+		if ( ! $widget_query->have_posts() ) {
+			return;
+		}
+
+		echo $args['before_widget'];
+
+		if ( !empty( $settings['title'] ) ) {
+			echo $args['before_title'] . $settings['title'] . $args['after_title'];
+		} ?>
+
+		<ul>
+
+			<?php while ( $widget_query->have_posts() ) : $widget_query->the_post(); ?>
+
+				<li><a class="bbp-forum-title" href="<?php bbp_forum_permalink( $widget_query->post->ID ); ?>"><?php bbp_forum_title( $widget_query->post->ID ); ?></a></li>
+
+			<?php endwhile; ?>
+
+		</ul>
+
+		<?php echo $args['after_widget'];
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	/**
+	 * Update the forum widget options
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param array $new_instance The new instance options
+	 * @param array $old_instance The old instance options
+	 */
+	public function update( $new_instance, $old_instance ) {
+		$instance                 = $old_instance;
+		$instance['title']        = strip_tags( $new_instance['title'] );
+		$instance['parent_forum'] = sanitize_text_field( $new_instance['parent_forum'] );
+
+		// Force to any
+		if ( !empty( $instance['parent_forum'] ) && !is_numeric( $instance['parent_forum'] ) ) {
+			$instance['parent_forum'] = 'any';
+		}
+
+		return $instance;
+	}
+
+	/**
+	 * Output the forum widget options form
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param $instance Instance
+	 * @uses BBP_Forums_Widget::get_field_id() To output the field id
+	 * @uses BBP_Forums_Widget::get_field_name() To output the field name
+	 */
+	public function form( $instance ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance ); ?>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'bbpress' ); ?>
+				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" />
+			</label>
+		</p>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'parent_forum' ); ?>"><?php _e( 'Parent Forum ID:', 'bbpress' ); ?>
+				<input class="widefat" id="<?php echo $this->get_field_id( 'parent_forum' ); ?>" name="<?php echo $this->get_field_name( 'parent_forum' ); ?>" type="text" value="<?php echo esc_attr( $settings['parent_forum'] ); ?>" />
+			</label>
+
+			<br />
+
+			<small><?php _e( '"0" to show only root - "any" to show all', 'bbpress' ); ?></small>
+		</p>
+
+		<?php
+	}
+
+	/**
+	 * Merge the widget settings into defaults array.
+	 *
+	 * @since bbPress (r4802)
+	 *
+	 * @param $instance Instance
+	 * @uses bbp_parse_args() To merge widget settings into defaults
+	 */
+	public function parse_settings( $instance = array() ) {
+		return bbp_parse_args( $instance, array(
+			'title'        => __( 'Forums', 'bbpress' ),
+			'parent_forum' => 0
+		), 'forum_widget_settings' );
+	}
+}
+
+/**
+ * bbPress Topic Widget
+ *
+ * Adds a widget which displays the topic list
+ *
+ * @since bbPress (r2653)
+ *
+ * @uses WP_Widget
+ */
+class BBP_Topics_Widget extends WP_Widget {
+
+	/**
+	 * bbPress Topic Widget
+	 *
+	 * Registers the topic widget
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @uses apply_filters() Calls 'bbp_topics_widget_options' with the
+	 *                        widget options
+	 */
+	public function __construct() {
+		$widget_ops = apply_filters( 'bbp_topics_widget_options', array(
+			'classname'   => 'widget_display_topics',
+			'description' => __( 'A list of recent topics, sorted by popularity or freshness.', 'bbpress' )
+		) );
+
+		parent::__construct( false, __( '(bbPress) Recent Topics', 'bbpress' ), $widget_ops );
+	}
+
+	/**
+	 * Register the widget
+	 *
+	 * @since bbPress (r3389)
+	 *
+	 * @uses register_widget()
+	 */
+	public static function register_widget() {
+		register_widget( 'BBP_Topics_Widget' );
+	}
+
+	/**
+	 * Displays the output, the topic list
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param mixed $args
+	 * @param array $instance
+	 * @uses apply_filters() Calls 'bbp_topic_widget_title' with the title
+	 * @uses bbp_topic_permalink() To display the topic permalink
+	 * @uses bbp_topic_title() To display the topic title
+	 * @uses bbp_get_topic_last_active_time() To get the topic last active
+	 *                                         time
+	 * @uses bbp_get_topic_id() To get the topic id
+	 */
+	public function widget( $args = array(), $instance = array() ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance );
+
+		// Typical WordPress filter
+		$settings['title'] = apply_filters( 'widget_title',           $settings['title'], $instance, $this->id_base );
+
+		// bbPress filter
+		$settings['title'] = apply_filters( 'bbp_topic_widget_title', $settings['title'], $instance, $this->id_base );
+
+		// How do we want to order our results?
+		switch ( $settings['order_by'] ) {
+
+			// Order by most recent replies
+			case 'freshness' :
+				$topics_query = array(
+					'post_type'           => bbp_get_topic_post_type(),
+					'post_parent'         => $settings['parent_forum'],
+					'posts_per_page'      => (int) $settings['max_shown'],
+					'post_status'         => array( bbp_get_public_status_id(), bbp_get_closed_status_id() ),
+					'ignore_sticky_posts' => true,
+					'no_found_rows'       => true,
+					'meta_key'            => '_bbp_last_active_time',
+					'orderby'             => 'meta_value',
+					'order'               => 'DESC',
+				);
+				break;
+
+			// Order by total number of replies
+			case 'popular' :
+				$topics_query = array(
+					'post_type'           => bbp_get_topic_post_type(),
+					'post_parent'         => $settings['parent_forum'],
+					'posts_per_page'      => (int) $settings['max_shown'],
+					'post_status'         => array( bbp_get_public_status_id(), bbp_get_closed_status_id() ),
+					'ignore_sticky_posts' => true,
+					'no_found_rows'       => true,
+					'meta_key'            => '_bbp_reply_count',
+					'orderby'             => 'meta_value',
+					'order'               => 'DESC'
+				);
+				break;
+
+			// Order by which topic was created most recently
+			case 'newness' :
+			default :
+				$topics_query = array(
+					'post_type'           => bbp_get_topic_post_type(),
+					'post_parent'         => $settings['parent_forum'],
+					'posts_per_page'      => (int) $settings['max_shown'],
+					'post_status'         => array( bbp_get_public_status_id(), bbp_get_closed_status_id() ),
+					'ignore_sticky_posts' => true,
+					'no_found_rows'       => true,
+					'order'               => 'DESC'
+				);
+				break;
+		}
+
+		// Note: private and hidden forums will be excluded via the
+		// bbp_pre_get_posts_normalize_forum_visibility action and function.
+		$widget_query = new WP_Query( $topics_query );
+
+		// Bail if no topics are found
+		if ( ! $widget_query->have_posts() ) {
+			return;
+		}
+
+		echo $args['before_widget'];
+
+		if ( !empty( $settings['title'] ) ) {
+			echo $args['before_title'] . $settings['title'] . $args['after_title'];
+		} ?>
+
+		<ul>
+
+			<?php while ( $widget_query->have_posts() ) :
+
+				$widget_query->the_post();
+				$topic_id    = bbp_get_topic_id( $widget_query->post->ID );
+				$author_link = '';
+
+				// Maybe get the topic author
+				if ( ! empty( $settings['show_user'] ) ) :
+					$author_link = bbp_get_topic_author_link( array( 'post_id' => $topic_id, 'type' => 'both', 'size' => 14 ) );
+				endif; ?>
+
+				<li>
+					<a class="bbp-forum-title" href="<?php bbp_topic_permalink( $topic_id ); ?>"><?php bbp_topic_title( $topic_id ); ?></a>
+
+					<?php if ( ! empty( $author_link ) ) : ?>
+
+						<?php printf( _x( 'by %1$s', 'widgets', 'bbpress' ), '<span class="topic-author">' . $author_link . '</span>' ); ?>
+
+					<?php endif; ?>
+
+					<?php if ( ! empty( $settings['show_date'] ) ) : ?>
+
+						<div><?php bbp_topic_last_active_time( $topic_id ); ?></div>
+
+					<?php endif; ?>
+
+				</li>
+
+			<?php endwhile; ?>
+
+		</ul>
+
+		<?php echo $args['after_widget'];
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	/**
+	 * Update the topic widget options
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param array $new_instance The new instance options
+	 * @param array $old_instance The old instance options
+	 */
+	public function update( $new_instance = array(), $old_instance = array() ) {
+		$instance                 = $old_instance;
+		$instance['title']        = strip_tags( $new_instance['title'] );
+		$instance['order_by']     = strip_tags( $new_instance['order_by'] );
+		$instance['parent_forum'] = sanitize_text_field( $new_instance['parent_forum'] );
+		$instance['show_date']    = (bool) $new_instance['show_date'];
+		$instance['show_user']    = (bool) $new_instance['show_user'];
+		$instance['max_shown']    = (int) $new_instance['max_shown'];
+
+		// Force to any
+		if ( !empty( $instance['parent_forum'] ) && !is_numeric( $instance['parent_forum'] ) ) {
+			$instance['parent_forum'] = 'any';
+		}
+
+		return $instance;
+	}
+
+	/**
+	 * Output the topic widget options form
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param $instance Instance
+	 * @uses BBP_Topics_Widget::get_field_id() To output the field id
+	 * @uses BBP_Topics_Widget::get_field_name() To output the field name
+	 */
+	public function form( $instance = array() ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance ); ?>
+
+		<p><label for="<?php echo $this->get_field_id( 'title'     ); ?>"><?php _e( 'Title:',                  'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title'     ); ?>" name="<?php echo $this->get_field_name( 'title'     ); ?>" type="text" value="<?php echo esc_attr( $settings['title']     ); ?>" /></label></p>
+		<p><label for="<?php echo $this->get_field_id( 'max_shown' ); ?>"><?php _e( 'Maximum topics to show:', 'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_shown' ); ?>" name="<?php echo $this->get_field_name( 'max_shown' ); ?>" type="text" value="<?php echo esc_attr( $settings['max_shown'] ); ?>" /></label></p>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'parent_forum' ); ?>"><?php _e( 'Parent Forum ID:', 'bbpress' ); ?>
+				<input class="widefat" id="<?php echo $this->get_field_id( 'parent_forum' ); ?>" name="<?php echo $this->get_field_name( 'parent_forum' ); ?>" type="text" value="<?php echo esc_attr( $settings['parent_forum'] ); ?>" />
+			</label>
+
+			<br />
+
+			<small><?php _e( '"0" to show only root - "any" to show all', 'bbpress' ); ?></small>
+		</p>
+
+		<p><label for="<?php echo $this->get_field_id( 'show_date' ); ?>"><?php _e( 'Show post date:',    'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_date' ); ?>" name="<?php echo $this->get_field_name( 'show_date' ); ?>" <?php checked( true, $settings['show_date'] ); ?> value="1" /></label></p>
+		<p><label for="<?php echo $this->get_field_id( 'show_user' ); ?>"><?php _e( 'Show topic author:', 'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_user' ); ?>" name="<?php echo $this->get_field_name( 'show_user' ); ?>" <?php checked( true, $settings['show_user'] ); ?> value="1" /></label></p>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'order_by' ); ?>"><?php _e( 'Order By:',        'bbpress' ); ?></label>
+			<select name="<?php echo $this->get_field_name( 'order_by' ); ?>" id="<?php echo $this->get_field_name( 'order_by' ); ?>">
+				<option <?php selected( $settings['order_by'], 'newness' );   ?> value="newness"><?php _e( 'Newest Topics',                'bbpress' ); ?></option>
+				<option <?php selected( $settings['order_by'], 'popular' );   ?> value="popular"><?php _e( 'Popular Topics',               'bbpress' ); ?></option>
+				<option <?php selected( $settings['order_by'], 'freshness' ); ?> value="freshness"><?php _e( 'Topics With Recent Replies', 'bbpress' ); ?></option>
+			</select>
+		</p>
+
+		<?php
+	}
+
+	/**
+	 * Merge the widget settings into defaults array.
+	 *
+	 * @since bbPress (r4802)
+	 *
+	 * @param $instance Instance
+	 * @uses bbp_parse_args() To merge widget options into defaults
+	 */
+	public function parse_settings( $instance = array() ) {
+		return bbp_parse_args( $instance, array(
+			'title'        => __( 'Recent Topics', 'bbpress' ),
+			'max_shown'    => 5,
+			'show_date'    => false,
+			'show_user'    => false,
+			'parent_forum' => 'any',
+			'order_by'     => false
+		), 'topic_widget_settings' );
+	}
+}
+
+/**
+ * bbPress Stats Widget
+ *
+ * Adds a widget which displays the forum statistics
+ *
+ * @since bbPress (r4509)
+ *
+ * @uses WP_Widget
+ */
+class BBP_Stats_Widget extends WP_Widget {
+
+	/**
+	 * bbPress Stats Widget
+	 *
+	 * Registers the stats widget
+	 *
+	 * @since bbPress (r4509)
+	 *
+	 * @uses  apply_filters() Calls 'bbp_stats_widget_options' with the
+	 *        widget options
+	 */
+	public function __construct() {
+		$widget_ops = apply_filters( 'bbp_stats_widget_options', array(
+			'classname'   => 'widget_display_stats',
+			'description' => __( 'Some statistics from your forum.', 'bbpress' )
+		) );
+
+		parent::__construct( false, __( '(bbPress) Statistics', 'bbpress' ), $widget_ops );
+	}
+
+	/**
+	 * Register the widget
+	 *
+	 * @since bbPress (r4509)
+	 *
+	 * @uses register_widget()
+	 */
+	public static function register_widget() {
+		register_widget( 'BBP_Stats_Widget' );
+	}
+
+	/**
+	 * Displays the output, the statistics
+	 *
+	 * @since bbPress (r4509)
+	 *
+	 * @param mixed $args     Arguments
+	 * @param array $instance Instance
+	 *
+	 * @uses apply_filters() Calls 'bbp_stats_widget_title' with the title
+	 * @uses bbp_get_template_part() To get the content-forum-statistics template
+	 */
+	public function widget( $args = array(), $instance = array() ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance );
+
+		// Typical WordPress filter
+		$settings['title'] = apply_filters( 'widget_title',           $settings['title'], $instance, $this->id_base );
+
+		// bbPress widget title filter
+		$settings['title'] = apply_filters( 'bbp_stats_widget_title', $settings['title'], $instance, $this->id_base );
+
+		echo $args['before_widget'];
+
+		if ( !empty( $settings['title'] ) ) {
+			echo $args['before_title'] . $settings['title'] . $args['after_title'];
+		}
+
+		bbp_get_template_part( 'content', 'statistics' );
+
+		echo $args['after_widget'];
+	}
+
+	/**
+	 * Update the stats widget options
+	 *
+	 * @since bbPress (r4509)
+	 *
+	 * @param array $new_instance The new instance options
+	 * @param array $old_instance The old instance options
+	 *
+	 * @return array
+	 */
+	public function update( $new_instance, $old_instance ) {
+		$instance          = $old_instance;
+		$instance['title'] = strip_tags( $new_instance['title'] );
+
+		return $instance;
+	}
+
+	/**
+	 * Output the stats widget options form
+	 *
+	 * @since bbPress (r4509)
+	 *
+	 * @param $instance
+	 *
+	 * @return string|void
+	 */
+	public function form( $instance ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance ); ?>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'bbpress' ); ?>
+				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>"/>
+			</label>
+		</p>
+
+	<?php
+	}
+
+	/**
+	 * Merge the widget settings into defaults array.
+	 *
+	 * @since bbPress (r4802)
+	 *
+	 * @param $instance Instance
+	 * @uses bbp_parse_args() To merge widget settings into defaults
+	 */
+	public function parse_settings( $instance = array() ) {
+		return bbp_parse_args( $instance, array(
+			'title' => __( 'Forum Statistics', 'bbpress' )
+		),
+		'stats_widget_settings' );
+	}
+}
+
+/**
+ * bbPress Replies Widget
+ *
+ * Adds a widget which displays the replies list
+ *
+ * @since bbPress (r2653)
+ *
+ * @uses WP_Widget
+ */
+class BBP_Replies_Widget extends WP_Widget {
+
+	/**
+	 * bbPress Replies Widget
+	 *
+	 * Registers the replies widget
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @uses apply_filters() Calls 'bbp_replies_widget_options' with the
+	 *                        widget options
+	 */
+	public function __construct() {
+		$widget_ops = apply_filters( 'bbp_replies_widget_options', array(
+			'classname'   => 'widget_display_replies',
+			'description' => __( 'A list of the most recent replies.', 'bbpress' )
+		) );
+
+		parent::__construct( false, __( '(bbPress) Recent Replies', 'bbpress' ), $widget_ops );
+	}
+
+	/**
+	 * Register the widget
+	 *
+	 * @since bbPress (r3389)
+	 *
+	 * @uses register_widget()
+	 */
+	public static function register_widget() {
+		register_widget( 'BBP_Replies_Widget' );
+	}
+
+	/**
+	 * Displays the output, the replies list
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param mixed $args
+	 * @param array $instance
+	 * @uses apply_filters() Calls 'bbp_reply_widget_title' with the title
+	 * @uses bbp_get_reply_author_link() To get the reply author link
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply_url() To get the reply url
+	 * @uses bbp_get_reply_excerpt() To get the reply excerpt
+	 * @uses bbp_get_reply_topic_title() To get the reply topic title
+	 * @uses get_the_date() To get the date of the reply
+	 * @uses get_the_time() To get the time of the reply
+	 */
+	public function widget( $args, $instance ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance );
+
+		// Typical WordPress filter
+		$settings['title'] = apply_filters( 'widget_title',             $settings['title'], $instance, $this->id_base );
+
+		// bbPress filter
+		$settings['title'] = apply_filters( 'bbp_replies_widget_title', $settings['title'], $instance, $this->id_base );
+
+		// Note: private and hidden forums will be excluded via the
+		// bbp_pre_get_posts_normalize_forum_visibility action and function.
+		$widget_query = new WP_Query( array(
+			'post_type'           => bbp_get_reply_post_type(),
+			'post_status'         => array( bbp_get_public_status_id(), bbp_get_closed_status_id() ),
+			'posts_per_page'      => (int) $settings['max_shown'],
+			'ignore_sticky_posts' => true,
+			'no_found_rows'       => true,
+		) );
+
+		// Bail if no replies
+		if ( ! $widget_query->have_posts() ) {
+			return;
+		}
+
+		echo $args['before_widget'];
+
+		if ( !empty( $settings['title'] ) ) {
+			echo $args['before_title'] . $settings['title'] . $args['after_title'];
+		} ?>
+
+		<ul>
+
+			<?php while ( $widget_query->have_posts() ) : $widget_query->the_post(); ?>
+
+				<li>
+
+					<?php
+
+					// Verify the reply ID
+					$reply_id   = bbp_get_reply_id( $widget_query->post->ID );
+					$reply_link = '<a class="bbp-reply-topic-title" href="' . esc_url( bbp_get_reply_url( $reply_id ) ) . '" title="' . esc_attr( bbp_get_reply_excerpt( $reply_id, 50 ) ) . '">' . bbp_get_reply_topic_title( $reply_id ) . '</a>';
+
+					// Only query user if showing them
+					if ( ! empty( $settings['show_user'] ) ) :
+						$author_link = bbp_get_reply_author_link( array( 'post_id' => $reply_id, 'type' => 'both', 'size' => 14 ) );
+					else :
+						$author_link = false;
+					endif;
+
+					// Reply author, link, and timestamp
+					if ( ! empty( $settings['show_date'] ) && !empty( $author_link ) ) :
+
+						// translators: 1: reply author, 2: reply link, 3: reply timestamp
+						printf( _x( '%1$s on %2$s %3$s', 'widgets', 'bbpress' ), $author_link, $reply_link, '<div>' . bbp_get_time_since( get_the_time( 'U' ) ) . '</div>' );
+
+					// Reply link and timestamp
+					elseif ( ! empty( $settings['show_date'] ) ) :
+
+						// translators: 1: reply link, 2: reply timestamp
+						printf( _x( '%1$s %2$s',         'widgets', 'bbpress' ), $reply_link,  '<div>' . bbp_get_time_since( get_the_time( 'U' ) ) . '</div>'              );
+
+					// Reply author and title
+					elseif ( !empty( $author_link ) ) :
+
+						// translators: 1: reply author, 2: reply link
+						printf( _x( '%1$s on %2$s',      'widgets', 'bbpress' ), $author_link, $reply_link                                                                 );
+
+					// Only the reply title
+					else :
+
+						// translators: 1: reply link
+						printf( _x( '%1$s',              'widgets', 'bbpress' ), $reply_link                                                                               );
+
+					endif;
+
+					?>
+
+				</li>
+
+			<?php endwhile; ?>
+
+		</ul>
+
+		<?php echo $args['after_widget'];
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	/**
+	 * Update the reply widget options
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param array $new_instance The new instance options
+	 * @param array $old_instance The old instance options
+	 */
+	public function update( $new_instance = array(), $old_instance = array() ) {
+		$instance              = $old_instance;
+		$instance['title']     = strip_tags( $new_instance['title'] );
+		$instance['show_date'] = (bool) $new_instance['show_date'];
+		$instance['show_user'] = (bool) $new_instance['show_user'];
+		$instance['max_shown'] = (int) $new_instance['max_shown'];
+
+		return $instance;
+	}
+
+	/**
+	 * Output the reply widget options form
+	 *
+	 * @since bbPress (r2653)
+	 *
+	 * @param $instance Instance
+	 * @uses BBP_Replies_Widget::get_field_id() To output the field id
+	 * @uses BBP_Replies_Widget::get_field_name() To output the field name
+	 */
+	public function form( $instance = array() ) {
+
+		// Get widget settings
+		$settings = $this->parse_settings( $instance ); ?>
+
+		<p><label for="<?php echo $this->get_field_id( 'title'     ); ?>"><?php _e( 'Title:',                   'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title'     ); ?>" name="<?php echo $this->get_field_name( 'title'     ); ?>" type="text" value="<?php echo esc_attr( $settings['title']     ); ?>" /></label></p>
+		<p><label for="<?php echo $this->get_field_id( 'max_shown' ); ?>"><?php _e( 'Maximum replies to show:', 'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_shown' ); ?>" name="<?php echo $this->get_field_name( 'max_shown' ); ?>" type="text" value="<?php echo esc_attr( $settings['max_shown'] ); ?>" /></label></p>
+		<p><label for="<?php echo $this->get_field_id( 'show_date' ); ?>"><?php _e( 'Show post date:',          'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_date' ); ?>" name="<?php echo $this->get_field_name( 'show_date' ); ?>" <?php checked( true, $settings['show_date'] ); ?> value="1" /></label></p>
+		<p><label for="<?php echo $this->get_field_id( 'show_user' ); ?>"><?php _e( 'Show reply author:',       'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_user' ); ?>" name="<?php echo $this->get_field_name( 'show_user' ); ?>" <?php checked( true, $settings['show_user'] ); ?> value="1" /></label></p>
+
+		<?php
+	}
+
+	/**
+	 * Merge the widget settings into defaults array.
+	 *
+	 * @since bbPress (r4802)
+	 *
+	 * @param $instance Instance
+	 * @uses bbp_parse_args() To merge widget settings into defaults
+	 */
+	public function parse_settings( $instance = array() ) {
+		return bbp_parse_args( $instance, array(
+			'title'     => __( 'Recent Replies', 'bbpress' ),
+			'max_shown' => 5,
+			'show_date' => false,
+			'show_user' => false
+		),
+		'replies_widget_settings' );
+	}
+}
Index: /tags/2.5.4/includes/core/actions.php
===================================================================
--- /tags/2.5.4/includes/core/actions.php	(revision 5382)
+++ /tags/2.5.4/includes/core/actions.php	(revision 5382)
@@ -0,0 +1,313 @@
+<?php
+
+/**
+ * bbPress Actions
+ *
+ * @package bbPress
+ * @subpackage Core
+ *
+ * This file contains the actions that are used through-out bbPress. They are
+ * consolidated here to make searching for them easier, and to help developers
+ * understand at a glance the order in which things occur.
+ *
+ * There are a few common places that additional actions can currently be found
+ *
+ *  - bbPress: In {@link bbPress::setup_actions()} in bbpress.php
+ *  - Admin: More in {@link BBP_Admin::setup_actions()} in admin.php
+ *
+ * @see /core/filters.php
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Attach bbPress to WordPress
+ *
+ * bbPress uses its own internal actions to help aid in third-party plugin
+ * development, and to limit the amount of potential future code changes when
+ * updates to WordPress core occur.
+ *
+ * These actions exist to create the concept of 'plugin dependencies'. They
+ * provide a safe way for plugins to execute code *only* when bbPress is
+ * installed and activated, without needing to do complicated guesswork.
+ *
+ * For more information on how this works, see the 'Plugin Dependency' section
+ * near the bottom of this file.
+ *
+ *           v--WordPress Actions        v--bbPress Sub-actions
+ */
+add_action( 'plugins_loaded',           'bbp_loaded',                 10    );
+add_action( 'init',                     'bbp_init',                   0     ); // Early for bbp_register
+add_action( 'parse_query',              'bbp_parse_query',            2     ); // Early for overrides
+add_action( 'widgets_init',             'bbp_widgets_init',           10    );
+add_action( 'generate_rewrite_rules',   'bbp_generate_rewrite_rules', 10    );
+add_action( 'wp_enqueue_scripts',       'bbp_enqueue_scripts',        10    );
+add_action( 'wp_head',                  'bbp_head',                   10    );
+add_action( 'wp_footer',                'bbp_footer',                 10    );
+add_action( 'set_current_user',         'bbp_setup_current_user',     10    );
+add_action( 'setup_theme',              'bbp_setup_theme',            10    );
+add_action( 'after_setup_theme',        'bbp_after_setup_theme',      10    );
+add_action( 'template_redirect',        'bbp_template_redirect',      8     ); // Before BuddyPress's 10 [BB2225]
+add_action( 'login_form_login',         'bbp_login_form_login',       10    );
+add_action( 'profile_update',           'bbp_profile_update',         10, 2 ); // user_id and old_user_data
+add_action( 'user_register',            'bbp_user_register',          10    );
+
+/**
+ * bbp_loaded - Attached to 'plugins_loaded' above
+ *
+ * Attach various loader actions to the bbp_loaded action.
+ * The load order helps to execute code at the correct time.
+ *                                                         v---Load order
+ */
+add_action( 'bbp_loaded', 'bbp_constants',                 2  );
+add_action( 'bbp_loaded', 'bbp_boot_strap_globals',        4  );
+add_action( 'bbp_loaded', 'bbp_includes',                  6  );
+add_action( 'bbp_loaded', 'bbp_setup_globals',             8  );
+add_action( 'bbp_loaded', 'bbp_setup_option_filters',      10 );
+add_action( 'bbp_loaded', 'bbp_setup_user_option_filters', 12 );
+add_action( 'bbp_loaded', 'bbp_register_theme_packages',   14 );
+add_action( 'bbp_loaded', 'bbp_filter_user_roles_option',  16 );
+
+/**
+ * bbp_init - Attached to 'init' above
+ *
+ * Attach various initialization actions to the init action.
+ * The load order helps to execute code at the correct time.
+ *                                               v---Load order
+ */
+add_action( 'bbp_init', 'bbp_load_textdomain',   0   );
+add_action( 'bbp_init', 'bbp_register',          0   );
+add_action( 'bbp_init', 'bbp_add_rewrite_tags',  20  );
+add_action( 'bbp_init', 'bbp_add_rewrite_rules', 30  );
+add_action( 'bbp_init', 'bbp_add_permastructs',  40  );
+add_action( 'bbp_init', 'bbp_ready',             999 );
+
+/**
+ * There is no action API for roles to use, so hook in immediately after
+ * everything is included (including the theme's functions.php. This is after
+ * the $wp_roles global is set but before $wp->init().
+ *
+ * If it's hooked in any sooner, role names may not be translated correctly.
+ *
+ * @link http://bbpress.trac.wordpress.org/ticket/2219
+ *
+ * This is kind of lame, but is all we have for now.
+ */
+add_action( 'bbp_after_setup_theme', 'bbp_add_forums_roles', 1 );
+
+/**
+ * When setting up the current user, make sure they have a role for the forums.
+ *
+ * This is multisite aware, thanks to bbp_filter_user_roles_option(), hooked to
+ * the 'bbp_loaded' action above.
+ */
+add_action( 'bbp_setup_current_user', 'bbp_set_current_user_default_role' );
+
+/**
+ * bbp_register - Attached to 'init' above on 0 priority
+ *
+ * Attach various initialization actions early to the init action.
+ * The load order helps to execute code at the correct time.
+ *                                                         v---Load order
+ */
+add_action( 'bbp_register', 'bbp_register_post_types',     2  );
+add_action( 'bbp_register', 'bbp_register_post_statuses',  4  );
+add_action( 'bbp_register', 'bbp_register_taxonomies',     6  );
+add_action( 'bbp_register', 'bbp_register_views',          8  );
+add_action( 'bbp_register', 'bbp_register_shortcodes',     10 );
+
+// Autoembeds
+add_action( 'bbp_init', 'bbp_reply_content_autoembed', 8 );
+add_action( 'bbp_init', 'bbp_topic_content_autoembed', 8 );
+
+/**
+ * bbp_ready - attached to end 'bbp_init' above
+ *
+ * Attach actions to the ready action after bbPress has fully initialized.
+ * The load order helps to execute code at the correct time.
+ *                                                v---Load order
+ */
+add_action( 'bbp_ready',  'bbp_setup_akismet',    2  ); // Spam prevention for topics and replies
+add_action( 'bp_include', 'bbp_setup_buddypress', 10 ); // Social network integration
+
+// Try to load the bbpress-functions.php file from the active themes
+add_action( 'bbp_after_setup_theme', 'bbp_load_theme_functions', 10 );
+
+// Widgets
+add_action( 'bbp_widgets_init', array( 'BBP_Login_Widget',   'register_widget' ), 10 );
+add_action( 'bbp_widgets_init', array( 'BBP_Views_Widget',   'register_widget' ), 10 );
+add_action( 'bbp_widgets_init', array( 'BBP_Search_Widget',  'register_widget' ), 10 );
+add_action( 'bbp_widgets_init', array( 'BBP_Forums_Widget',  'register_widget' ), 10 );
+add_action( 'bbp_widgets_init', array( 'BBP_Topics_Widget',  'register_widget' ), 10 );
+add_action( 'bbp_widgets_init', array( 'BBP_Replies_Widget', 'register_widget' ), 10 );
+add_action( 'bbp_widgets_init', array( 'BBP_Stats_Widget',   'register_widget' ), 10 );
+
+// Notices (loaded after bbp_init for translations)
+add_action( 'bbp_head',             'bbp_login_notices'    );
+add_action( 'bbp_head',             'bbp_topic_notices'    );
+add_action( 'bbp_template_notices', 'bbp_template_notices' );
+
+// Always exclude private/hidden forums if needed
+add_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );
+
+// Profile Page Messages
+add_action( 'bbp_template_notices', 'bbp_notice_edit_user_success'           );
+add_action( 'bbp_template_notices', 'bbp_notice_edit_user_is_super_admin', 2 );
+
+// Before Delete/Trash/Untrash Topic
+add_action( 'wp_trash_post', 'bbp_trash_forum'   );
+add_action( 'trash_post',    'bbp_trash_forum'   );
+add_action( 'untrash_post',  'bbp_untrash_forum' );
+add_action( 'delete_post',   'bbp_delete_forum'  );
+
+// After Deleted/Trashed/Untrashed Topic
+add_action( 'trashed_post',   'bbp_trashed_forum'   );
+add_action( 'untrashed_post', 'bbp_untrashed_forum' );
+add_action( 'deleted_post',   'bbp_deleted_forum'   );
+
+// Auto trash/untrash/delete a forums topics
+add_action( 'bbp_delete_forum',  'bbp_delete_forum_topics',  10 );
+add_action( 'bbp_trash_forum',   'bbp_trash_forum_topics',   10 );
+add_action( 'bbp_untrash_forum', 'bbp_untrash_forum_topics', 10 );
+
+// New/Edit Forum
+add_action( 'bbp_new_forum',  'bbp_update_forum', 10 );
+add_action( 'bbp_edit_forum', 'bbp_update_forum', 10 );
+
+// Save forum extra metadata
+add_action( 'bbp_new_forum_post_extras',         'bbp_save_forum_extras', 2 );
+add_action( 'bbp_edit_forum_post_extras',        'bbp_save_forum_extras', 2 );
+add_action( 'bbp_forum_attributes_metabox_save', 'bbp_save_forum_extras', 2 );
+
+// New/Edit Reply
+add_action( 'bbp_new_reply',  'bbp_update_reply', 10, 7 );
+add_action( 'bbp_edit_reply', 'bbp_update_reply', 10, 7 );
+
+// Before Delete/Trash/Untrash Reply
+add_action( 'wp_trash_post', 'bbp_trash_reply'   );
+add_action( 'trash_post',    'bbp_trash_reply'   );
+add_action( 'untrash_post',  'bbp_untrash_reply' );
+add_action( 'delete_post',   'bbp_delete_reply'  );
+
+// After Deleted/Trashed/Untrashed Reply
+add_action( 'trashed_post',   'bbp_trashed_reply'   );
+add_action( 'untrashed_post', 'bbp_untrashed_reply' );
+add_action( 'deleted_post',   'bbp_deleted_reply'   );
+
+// New/Edit Topic
+add_action( 'bbp_new_topic',  'bbp_update_topic', 10, 5 );
+add_action( 'bbp_edit_topic', 'bbp_update_topic', 10, 5 );
+
+// Split/Merge Topic
+add_action( 'bbp_merged_topic',     'bbp_merge_topic_count', 1, 3 );
+add_action( 'bbp_post_split_topic', 'bbp_split_topic_count', 1, 3 );
+
+// Move Reply
+add_action( 'bbp_post_move_reply', 'bbp_move_reply_count', 1, 3 );
+
+// Before Delete/Trash/Untrash Topic
+add_action( 'wp_trash_post', 'bbp_trash_topic'   );
+add_action( 'trash_post',    'bbp_trash_topic'   );
+add_action( 'untrash_post',  'bbp_untrash_topic' );
+add_action( 'delete_post',   'bbp_delete_topic'  );
+
+// After Deleted/Trashed/Untrashed Topic
+add_action( 'trashed_post',   'bbp_trashed_topic'   );
+add_action( 'untrashed_post', 'bbp_untrashed_topic' );
+add_action( 'deleted_post',   'bbp_deleted_topic'   );
+
+// Favorites
+add_action( 'bbp_trash_topic',  'bbp_remove_topic_from_all_favorites' );
+add_action( 'bbp_delete_topic', 'bbp_remove_topic_from_all_favorites' );
+
+// Subscriptions
+add_action( 'bbp_trash_topic',  'bbp_remove_topic_from_all_subscriptions'       );
+add_action( 'bbp_delete_topic', 'bbp_remove_topic_from_all_subscriptions'       );
+add_action( 'bbp_trash_forum',  'bbp_remove_forum_from_all_subscriptions'       );
+add_action( 'bbp_delete_forum', 'bbp_remove_forum_from_all_subscriptions'       );
+add_action( 'bbp_new_reply',    'bbp_notify_subscribers',                 11, 5 );
+add_action( 'bbp_new_topic',    'bbp_notify_forum_subscribers',           11, 4 );
+
+// Sticky
+add_action( 'bbp_trash_topic',  'bbp_unstick_topic' );
+add_action( 'bbp_delete_topic', 'bbp_unstick_topic' );
+
+// Update topic branch
+add_action( 'bbp_trashed_topic',   'bbp_update_topic_walker' );
+add_action( 'bbp_untrashed_topic', 'bbp_update_topic_walker' );
+add_action( 'bbp_deleted_topic',   'bbp_update_topic_walker' );
+add_action( 'bbp_spammed_topic',   'bbp_update_topic_walker' );
+add_action( 'bbp_unspammed_topic', 'bbp_update_topic_walker' );
+
+// Update reply branch
+add_action( 'bbp_trashed_reply',   'bbp_update_reply_walker' );
+add_action( 'bbp_untrashed_reply', 'bbp_update_reply_walker' );
+add_action( 'bbp_deleted_reply',   'bbp_update_reply_walker' );
+add_action( 'bbp_spammed_reply',   'bbp_update_reply_walker' );
+add_action( 'bbp_unspammed_reply', 'bbp_update_reply_walker' );
+
+// User status
+// @todo make these sub-actions
+add_action( 'make_ham_user',  'bbp_make_ham_user'  );
+add_action( 'make_spam_user', 'bbp_make_spam_user' );
+
+// User role
+add_action( 'bbp_profile_update', 'bbp_profile_update_role' );
+
+// Hook WordPress admin actions to bbPress profiles on save
+add_action( 'bbp_user_edit_after', 'bbp_user_edit_after' );
+
+// Caches
+add_action( 'bbp_new_forum_pre_extras',  'bbp_clean_post_cache' );
+add_action( 'bbp_new_forum_post_extras', 'bbp_clean_post_cache' );
+add_action( 'bbp_new_topic_pre_extras',  'bbp_clean_post_cache' );
+add_action( 'bbp_new_topic_post_extras', 'bbp_clean_post_cache' );
+add_action( 'bbp_new_reply_pre_extras',  'bbp_clean_post_cache' );
+add_action( 'bbp_new_reply_post_extras', 'bbp_clean_post_cache' );
+
+/**
+ * bbPress needs to redirect the user around in a few different circumstances:
+ *
+ * 1. POST and GET requests
+ * 2. Accessing private or hidden content (forums/topics/replies)
+ * 3. Editing forums, topics, replies, users, and tags
+ * 4. bbPress specific AJAX requests
+ */
+add_action( 'bbp_template_redirect', 'bbp_forum_enforce_blocked', 1  );
+add_action( 'bbp_template_redirect', 'bbp_forum_enforce_hidden',  1  );
+add_action( 'bbp_template_redirect', 'bbp_forum_enforce_private', 1  );
+add_action( 'bbp_template_redirect', 'bbp_post_request',          10 );
+add_action( 'bbp_template_redirect', 'bbp_get_request',           10 );
+add_action( 'bbp_template_redirect', 'bbp_check_user_edit',       10 );
+add_action( 'bbp_template_redirect', 'bbp_check_forum_edit',      10 );
+add_action( 'bbp_template_redirect', 'bbp_check_topic_edit',      10 );
+add_action( 'bbp_template_redirect', 'bbp_check_reply_edit',      10 );
+add_action( 'bbp_template_redirect', 'bbp_check_topic_tag_edit',  10 );
+
+// Theme-side POST requests
+add_action( 'bbp_post_request', 'bbp_do_ajax',                1  );
+add_action( 'bbp_post_request', 'bbp_edit_topic_tag_handler', 1  );
+add_action( 'bbp_post_request', 'bbp_edit_user_handler',      1  );
+add_action( 'bbp_post_request', 'bbp_edit_forum_handler',     1  );
+add_action( 'bbp_post_request', 'bbp_edit_reply_handler',     1  );
+add_action( 'bbp_post_request', 'bbp_edit_topic_handler',     1  );
+add_action( 'bbp_post_request', 'bbp_merge_topic_handler',    1  );
+add_action( 'bbp_post_request', 'bbp_split_topic_handler',    1  );
+add_action( 'bbp_post_request', 'bbp_move_reply_handler',     1  );
+add_action( 'bbp_post_request', 'bbp_new_forum_handler',      10 );
+add_action( 'bbp_post_request', 'bbp_new_reply_handler',      10 );
+add_action( 'bbp_post_request', 'bbp_new_topic_handler',      10 );
+
+// Theme-side GET requests
+add_action( 'bbp_get_request', 'bbp_toggle_topic_handler',        1  );
+add_action( 'bbp_get_request', 'bbp_toggle_reply_handler',        1  );
+add_action( 'bbp_get_request', 'bbp_favorites_handler',           1  );
+add_action( 'bbp_get_request', 'bbp_subscriptions_handler',       1  );
+add_action( 'bbp_get_request', 'bbp_forum_subscriptions_handler', 1  );
+add_action( 'bbp_get_request', 'bbp_search_results_redirect',     10 );
+
+// Maybe convert the users password
+add_action( 'bbp_login_form_login', 'bbp_user_maybe_convert_pass' );
+
+add_action( 'bbp_activation', 'bbp_add_activation_redirect' );
Index: /tags/2.5.4/includes/core/cache.php
===================================================================
--- /tags/2.5.4/includes/core/cache.php	(revision 5382)
+++ /tags/2.5.4/includes/core/cache.php	(revision 5382)
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * bbPress Cache Helpers
+ *
+ * Helper functions used to communicate with WordPress's various caches. Many
+ * of these functions are used to work around specific WordPress nuances. They
+ * are subject to changes, tweaking, and will need iteration as performance
+ * improvements are made to WordPress core.
+ *
+ * @package bbPress
+ * @subpackage Cache
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Helpers *******************************************************************/
+
+/**
+ * Skip invalidation of child post content when editing a parent.
+ *
+ * This prevents invalidating caches for topics and replies when editing a forum
+ * or a topic. Without this in place, WordPress will attempt to invalidate all
+ * child posts whenever a parent post is modified. This can cause thousands of
+ * cache invalidations to occur on a single edit, which is no good for anyone.
+ *
+ * @since bbPress (r4011)
+ *
+ * @package bbPress
+ * @subpackage Cache
+ */
+class BBP_Skip_Children {
+
+	/**
+	 * @var int Post ID being updated
+	 */
+	private $updating_post = 0;
+
+	/**
+	 * @var bool The original value of $_wp_suspend_cache_invalidation global
+	 */
+	private $original_cache_invalidation = false;
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * Hook into the 'pre_post_update' action.
+	 *
+	 * @since bbPress (r4011)
+	 */
+	public function __construct() {
+		add_action( 'pre_post_update', array( $this, 'pre_post_update' ) );
+	}
+
+	/**
+	 * Only clean post caches for main bbPress posts.
+	 *
+	 * Check that the post being updated is a bbPress post type, saves the
+	 * post ID to be used later, and adds an action to 'clean_post_cache' that
+	 * prevents child post caches from being cleared.
+	 *
+	 * @since bbPress (r4011)
+	 *
+	 * @param int $post_id The post ID being updated
+	 * @return If invalid post data
+	 */
+	public function pre_post_update( $post_id = 0 ) {
+
+		// Bail if post ID is not a bbPress post type
+		if ( empty( $post_id ) || ! bbp_is_custom_post_type( $post_id ) )
+			return;
+
+		// Store the $post_id
+		$this->updating_post = $post_id;
+
+		// Skip related post cache invalidation. This prevents invalidating the
+		// caches of the child posts when there is no reason to do so.
+		add_action( 'clean_post_cache', array( $this, 'skip_related_posts' ) );
+	}
+
+	/**
+	 * Skip cache invalidation of related posts if the post ID being invalidated
+	 * is not the one that was just updated.
+	 *
+	 * @since bbPress (r4011)
+	 *
+	 * @param int $post_id The post ID of the cache being invalidated
+	 * @return If invalid post data
+	 */
+	public function skip_related_posts( $post_id = 0 ) {
+
+		// Bail if this post is not the current bbPress post
+		if ( empty( $post_id ) || ( $this->updating_post !== $post_id ) )
+			return;
+
+		// Stash the current cache invalidation value in a variable, so we can
+		// restore back to it nicely in the future.
+		global $_wp_suspend_cache_invalidation;
+
+		$this->original_cache_invalidation = $_wp_suspend_cache_invalidation;
+
+		// Turn off cache invalidation
+		wp_suspend_cache_invalidation( true );
+
+		// Restore cache invalidation
+		add_action( 'wp_insert_post', array( $this, 'restore_cache_invalidation' ) );
+	}
+
+	/**
+	 * Restore the cache invalidation to its previous value.
+	 *
+	 * @since bbPress (r4011)
+	 * @uses wp_suspend_cache_invalidation()
+	 */
+	public function restore_cache_invalidation() {
+		wp_suspend_cache_invalidation( $this->original_cache_invalidation );
+	}
+}
+new BBP_Skip_Children();
+
+/** General *******************************************************************/
+
+/**
+ * Will clean a post in the cache.
+ *
+ * Will call to clean the term object cache associated with the post ID.
+ *
+ * @since bbPress (r4040)
+ *
+ * @uses do_action() Calls 'bbp_clean_post_cache' on $id
+ * @param object|int $_post The post object or ID to remove from the cache
+ */
+function bbp_clean_post_cache( $_post = '' ) {
+
+	// Bail if no post
+	$_post = get_post( $_post );
+	if ( empty( $_post ) )
+		return;
+
+	wp_cache_delete( $_post->ID, 'posts'     );
+	wp_cache_delete( $_post->ID, 'post_meta' );
+
+	clean_object_term_cache( $_post->ID, $_post->post_type );
+
+	do_action( 'bbp_clean_post_cache', $_post->ID, $_post );
+
+	// Child query types to clean
+	$post_types = array(
+		bbp_get_topic_post_type(),
+		bbp_get_forum_post_type(),
+		bbp_get_reply_post_type()
+	);
+
+	// Loop through query types and clean caches
+	foreach ( $post_types as $post_type ) {
+		wp_cache_delete( 'bbp_get_forum_'     . $_post->ID . '_reply_id',                              'bbpress_posts' );
+		wp_cache_delete( 'bbp_parent_'        . $_post->ID . '_type_' . $post_type . '_child_last_id', 'bbpress_posts' );
+		wp_cache_delete( 'bbp_parent_'        . $_post->ID . '_type_' . $post_type . '_child_count',   'bbpress_posts' );
+		wp_cache_delete( 'bbp_parent_public_' . $_post->ID . '_type_' . $post_type . '_child_ids',     'bbpress_posts' );
+		wp_cache_delete( 'bbp_parent_all_'    . $_post->ID . '_type_' . $post_type . '_child_ids',     'bbpress_posts' );
+	}
+
+	// Invalidate parent caches
+	if ( ! empty( $_post->post_parent ) ) {
+		bbp_clean_post_cache( $_post->post_parent );
+	}
+}
Index: /tags/2.5.4/includes/core/capabilities.php
===================================================================
--- /tags/2.5.4/includes/core/capabilities.php	(revision 5382)
+++ /tags/2.5.4/includes/core/capabilities.php	(revision 5382)
@@ -0,0 +1,542 @@
+<?php
+
+/**
+ * bbPress Capabilites
+ *
+ * The functions in this file are used primarily as convenient wrappers for
+ * capability output in user profiles. This includes mapping capabilities and
+ * groups to human readable strings,
+ *
+ * @package bbPress
+ * @subpackage Capabilities
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Mapping *******************************************************************/
+
+/**
+ * Returns an array of capabilities based on the role that is being requested.
+ *
+ * @since bbPress (r2994)
+ *
+ * @todo Map all of these and deprecate
+ *
+ * @param string $role Optional. Defaults to The role to load caps for
+ * @uses apply_filters() Allow return value to be filtered
+ *
+ * @return array Capabilities for $role
+ */
+function bbp_get_caps_for_role( $role = '' ) {
+
+	// Which role are we looking for?
+	switch ( $role ) {
+
+		// Keymaster
+		case bbp_get_keymaster_role() :
+			$caps = array(
+
+				// Keymasters only
+				'keep_gate'             => true,
+
+				// Primary caps
+				'spectate'              => true,
+				'participate'           => true,
+				'moderate'              => true,
+				'throttle'              => true,
+				'view_trash'            => true,
+
+				// Forum caps
+				'publish_forums'        => true,
+				'edit_forums'           => true,
+				'edit_others_forums'    => true,
+				'delete_forums'         => true,
+				'delete_others_forums'  => true,
+				'read_private_forums'   => true,
+				'read_hidden_forums'    => true,
+
+				// Topic caps
+				'publish_topics'        => true,
+				'edit_topics'           => true,
+				'edit_others_topics'    => true,
+				'delete_topics'         => true,
+				'delete_others_topics'  => true,
+				'read_private_topics'   => true,
+
+				// Reply caps
+				'publish_replies'       => true,
+				'edit_replies'          => true,
+				'edit_others_replies'   => true,
+				'delete_replies'        => true,
+				'delete_others_replies' => true,
+				'read_private_replies'  => true,
+
+				// Topic tag caps
+				'manage_topic_tags'     => true,
+				'edit_topic_tags'       => true,
+				'delete_topic_tags'     => true,
+				'assign_topic_tags'     => true
+			);
+
+			break;
+
+		// Moderator
+		case bbp_get_moderator_role() :
+			$caps = array(
+
+				// Primary caps
+				'spectate'              => true,
+				'participate'           => true,
+				'moderate'              => true,
+				'throttle'              => true,
+				'view_trash'            => true,
+
+				// Forum caps
+				'publish_forums'        => true,
+				'edit_forums'           => true,
+				'read_private_forums'   => true,
+				'read_hidden_forums'    => true,
+
+				// Topic caps
+				'publish_topics'        => true,
+				'edit_topics'           => true,
+				'edit_others_topics'    => true,
+				'delete_topics'         => true,
+				'delete_others_topics'  => true,
+				'read_private_topics'   => true,
+
+				// Reply caps
+				'publish_replies'       => true,
+				'edit_replies'          => true,
+				'edit_others_replies'   => true,
+				'delete_replies'        => true,
+				'delete_others_replies' => true,
+				'read_private_replies'  => true,
+
+				// Topic tag caps
+				'manage_topic_tags'     => true,
+				'edit_topic_tags'       => true,
+				'delete_topic_tags'     => true,
+				'assign_topic_tags'     => true,
+			);
+
+			break;
+
+		// Spectators can only read
+		case bbp_get_spectator_role()   :
+			$caps = array(
+
+				// Primary caps
+				'spectate'              => true,
+			);
+
+			break;
+
+		// Explicitly blocked
+		case bbp_get_blocked_role() :
+			$caps = array(
+
+				// Primary caps
+				'spectate'              => false,
+				'participate'           => false,
+				'moderate'              => false,
+				'throttle'              => false,
+				'view_trash'            => false,
+
+				// Forum caps
+				'publish_forums'        => false,
+				'edit_forums'           => false,
+				'edit_others_forums'    => false,
+				'delete_forums'         => false,
+				'delete_others_forums'  => false,
+				'read_private_forums'   => false,
+				'read_hidden_forums'    => false,
+
+				// Topic caps
+				'publish_topics'        => false,
+				'edit_topics'           => false,
+				'edit_others_topics'    => false,
+				'delete_topics'         => false,
+				'delete_others_topics'  => false,
+				'read_private_topics'   => false,
+
+				// Reply caps
+				'publish_replies'       => false,
+				'edit_replies'          => false,
+				'edit_others_replies'   => false,
+				'delete_replies'        => false,
+				'delete_others_replies' => false,
+				'read_private_replies'  => false,
+
+				// Topic tag caps
+				'manage_topic_tags'     => false,
+				'edit_topic_tags'       => false,
+				'delete_topic_tags'     => false,
+				'assign_topic_tags'     => false,
+			);
+
+			break;
+
+		// Participant/Default
+		case bbp_get_participant_role() :
+		default :
+			$caps = array(
+
+				// Primary caps
+				'spectate'              => true,
+				'participate'           => true,
+
+				// Forum caps
+				'read_private_forums'   => true,
+
+				// Topic caps
+				'publish_topics'        => true,
+				'edit_topics'           => true,
+
+				// Reply caps
+				'publish_replies'       => true,
+				'edit_replies'          => true,
+
+				// Topic tag caps
+				'assign_topic_tags'     => true,
+			);
+
+			break;
+	}
+
+	return apply_filters( 'bbp_get_caps_for_role', $caps, $role );
+}
+
+/**
+ * Adds capabilities to WordPress user roles.
+ *
+ * @since bbPress (r2608)
+ */
+function bbp_add_caps() {
+
+	// Loop through available roles and add caps
+	foreach ( bbp_get_wp_roles()->role_objects as $role ) {
+		foreach ( bbp_get_caps_for_role( $role->name ) as $cap => $value ) {
+			$role->add_cap( $cap, $value );
+		}
+	}
+
+	do_action( 'bbp_add_caps' );
+}
+
+/**
+ * Removes capabilities from WordPress user roles.
+ *
+ * @since bbPress (r2608)
+ */
+function bbp_remove_caps() {
+
+	// Loop through available roles and remove caps
+	foreach ( bbp_get_wp_roles()->role_objects as $role ) {
+		foreach ( array_keys( bbp_get_caps_for_role( $role->name ) ) as $cap ) {
+			$role->remove_cap( $cap );
+		}
+	}
+
+	do_action( 'bbp_remove_caps' );
+}
+
+/**
+ * Get the $wp_roles global without needing to declare it everywhere
+ *
+ * @since bbPress (r4293)
+ *
+ * @global WP_Roles $wp_roles
+ * @return WP_Roles
+ */
+function bbp_get_wp_roles() {
+	global $wp_roles;
+
+	// Load roles if not set
+	if ( ! isset( $wp_roles ) )
+		$wp_roles = new WP_Roles();
+
+	return $wp_roles;
+}
+
+/**
+ * Get the available roles minus bbPress's dynamic roles
+ *
+ * @since bbPress (r5064)
+ *
+ * @uses bbp_get_wp_roles() To load and get the $wp_roles global
+ * @return array
+ */
+function bbp_get_blog_roles() {
+
+	// Get WordPress's roles (returns $wp_roles global)
+	$wp_roles  = bbp_get_wp_roles();
+
+	// Apply the WordPress 'editable_roles' filter to let plugins ride along.
+	//
+	// We use this internally via bbp_filter_blog_editable_roles() to remove
+	// any custom bbPress roles that are added to the global.
+	$the_roles = isset( $wp_roles->roles ) ? $wp_roles->roles : false;
+	$all_roles = apply_filters( 'editable_roles', $the_roles );
+
+	return apply_filters( 'bbp_get_blog_roles', $all_roles, $wp_roles );
+}
+
+/** Forum Roles ***************************************************************/
+
+/**
+ * Add the bbPress roles to the $wp_roles global.
+ *
+ * We do this to avoid adding these values to the database.
+ *
+ * @since bbPress (r4290)
+ *
+ * @uses bbp_get_wp_roles() To load and get the $wp_roles global
+ * @uses bbp_get_dynamic_roles() To get and add bbPress's roles to $wp_roles
+ * @return WP_Roles The main $wp_roles global
+ */
+function bbp_add_forums_roles() {
+	$wp_roles = bbp_get_wp_roles();
+
+	foreach ( bbp_get_dynamic_roles() as $role_id => $details ) {
+		$wp_roles->roles[$role_id]        = $details;
+		$wp_roles->role_objects[$role_id] = new WP_Role( $role_id, $details['capabilities'] );
+		$wp_roles->role_names[$role_id]   = $details['name'];
+	}
+
+	return $wp_roles;
+}
+
+/**
+ * Helper function to add filter to option_wp_user_roles
+ *
+ * @since bbPress (r4363)
+ *
+ * @see _bbp_reinit_dynamic_roles()
+ *
+ * @global WPDB $wpdb Used to get the database prefix
+ */
+function bbp_filter_user_roles_option() {
+	global $wpdb;
+
+	$role_key = $wpdb->prefix . 'user_roles';
+
+	add_filter( 'option_' . $role_key, '_bbp_reinit_dynamic_roles' );
+}
+
+/**
+ * This is necessary because in a few places (noted below) WordPress initializes
+ * a blog's roles directly from the database option. When this happens, the
+ * $wp_roles global gets flushed, causing a user to magically lose any
+ * dynamically assigned roles or capabilities when $current_user in refreshed.
+ *
+ * Because dynamic multiple roles is a new concept in WordPress, we work around
+ * it here for now, knowing that improvements will come to WordPress core later.
+ *
+ * Also note that if using the $wp_user_roles global non-database approach,
+ * bbPress does not have an intercept point to add its dynamic roles.
+ *
+ * @see switch_to_blog()
+ * @see restore_current_blog()
+ * @see WP_Roles::_init()
+ *
+ * @since bbPress (r4363)
+ *
+ * @internal Used by bbPress to reinitialize dynamic roles on blog switch
+ *
+ * @param array $roles
+ * @return array Combined array of database roles and dynamic bbPress roles
+ */
+function _bbp_reinit_dynamic_roles( $roles = array() ) {
+	foreach ( bbp_get_dynamic_roles() as $role_id => $details ) {
+		$roles[$role_id] = $details;
+	}
+	return $roles;
+}
+
+/**
+ * Fetch a filtered list of forum roles that the current user is
+ * allowed to have.
+ *
+ * Simple function who's main purpose is to allow filtering of the
+ * list of forum roles so that plugins can remove inappropriate ones depending
+ * on the situation or user making edits.
+ *
+ * Specifically because without filtering, anyone with the edit_users
+ * capability can edit others to be administrators, even if they are
+ * only editors or authors. This filter allows admins to delegate
+ * user management.
+ *
+ * @since bbPress (r4284)
+ *
+ * @return array
+ */
+function bbp_get_dynamic_roles() {
+	return (array) apply_filters( 'bbp_get_dynamic_roles', array(
+
+		// Keymaster
+		bbp_get_keymaster_role() => array(
+			'name'         => __( 'Keymaster', 'bbpress' ),
+			'capabilities' => bbp_get_caps_for_role( bbp_get_keymaster_role() )
+		),
+
+		// Moderator
+		bbp_get_moderator_role() => array(
+			'name'         => __( 'Moderator', 'bbpress' ),
+			'capabilities' => bbp_get_caps_for_role( bbp_get_moderator_role() )
+		),
+
+		// Participant
+		bbp_get_participant_role() => array(
+			'name'         => __( 'Participant', 'bbpress' ),
+			'capabilities' => bbp_get_caps_for_role( bbp_get_participant_role() )
+		),
+
+		// Spectator
+		bbp_get_spectator_role() => array(
+			'name'         => __( 'Spectator', 'bbpress' ),
+			'capabilities' => bbp_get_caps_for_role( bbp_get_spectator_role() )
+		),
+
+		// Blocked
+		bbp_get_blocked_role() => array(
+			'name'         => __( 'Blocked', 'bbpress' ),
+			'capabilities' => bbp_get_caps_for_role( bbp_get_blocked_role() )
+		)
+	) );
+}
+
+/**
+ * Gets a translated role name from a role ID
+ *
+ * @since bbPress (r4792)
+ *
+ * @param string $role_id
+ * @return string Translated role name
+ */
+function bbp_get_dynamic_role_name( $role_id = '' ) {
+	$roles = bbp_get_dynamic_roles();
+	$role  = isset( $roles[$role_id] ) ? $roles[$role_id]['name'] : '';
+
+	return apply_filters( 'bbp_get_dynamic_role_name', $role, $role_id, $roles );
+}
+
+/**
+ * Removes the bbPress roles from the editable roles array
+ *
+ * This used to use array_diff_assoc() but it randomly broke before 2.2 release.
+ * Need to research what happened, and if there's a way to speed this up.
+ *
+ * @since bbPress (r4303)
+ *
+ * @param array $all_roles All registered roles
+ * @return array 
+ */
+function bbp_filter_blog_editable_roles( $all_roles = array() ) {
+
+	// Loop through bbPress roles
+	foreach ( array_keys( bbp_get_dynamic_roles() ) as $bbp_role ) {
+
+		// Loop through WordPress roles
+		foreach ( array_keys( $all_roles ) as $wp_role ) {
+
+			// If keys match, unset
+			if ( $wp_role === $bbp_role ) {
+				unset( $all_roles[$wp_role] );
+			}
+		}
+	}
+
+	return $all_roles;
+}
+
+/**
+ * The keymaster role for bbPress users
+ *
+ * @since bbPress (r4284)
+ *
+ * @uses apply_filters() Allow override of hardcoded keymaster role
+ * @return string
+ */
+function bbp_get_keymaster_role() {
+	return apply_filters( 'bbp_get_keymaster_role', 'bbp_keymaster' );
+}
+
+/**
+ * The moderator role for bbPress users
+ *
+ * @since bbPress (r3410)
+ *
+ * @uses apply_filters() Allow override of hardcoded moderator role
+ * @return string
+ */
+function bbp_get_moderator_role() {
+	return apply_filters( 'bbp_get_moderator_role', 'bbp_moderator' );
+}
+
+/**
+ * The participant role for registered user that can participate in forums
+ *
+ * @since bbPress (r3410)
+ *
+ * @uses apply_filters() Allow override of hardcoded participant role
+ * @return string
+ */
+function bbp_get_participant_role() {
+	return apply_filters( 'bbp_get_participant_role', 'bbp_participant' );
+}
+
+/**
+ * The spectator role is for registered users without any capabilities
+ *
+ * @since bbPress (r3860)
+ *
+ * @uses apply_filters() Allow override of hardcoded spectator role
+ * @return string
+ */
+function bbp_get_spectator_role() {
+	return apply_filters( 'bbp_get_spectator_role', 'bbp_spectator' );
+}
+
+/**
+ * The blocked role is for registered users that cannot spectate or participate
+ *
+ * @since bbPress (r4284)
+ *
+ * @uses apply_filters() Allow override of hardcoded blocked role
+ * @return string
+ */
+function bbp_get_blocked_role() {
+	return apply_filters( 'bbp_get_blocked_role', 'bbp_blocked' );
+}
+
+/** Deprecated ****************************************************************/
+
+/**
+ * Adds bbPress-specific user roles.
+ *
+ * @since bbPress (r2741)
+ * @deprecated since version 2.2
+ */
+function bbp_add_roles() {
+	_doing_it_wrong( 'bbp_add_roles', __( 'Editable forum roles no longer exist.', 'bbpress' ), '2.2' );
+}
+
+/**
+ * Removes bbPress-specific user roles.
+ *
+ * @since bbPress (r2741)
+ * @deprecated since version 2.2
+ */
+function bbp_remove_roles() {
+
+	// Remove the bbPress roles
+	foreach ( array_keys( bbp_get_dynamic_roles() ) as $bbp_role ) {
+		remove_role( $bbp_role );
+	}
+
+	// Some early adopters may have a deprecated visitor role. It was later
+	// replaced by the Spectator role.
+	remove_role( 'bbp_visitor' );
+}
Index: /tags/2.5.4/includes/core/extend.php
===================================================================
--- /tags/2.5.4/includes/core/extend.php	(revision 5382)
+++ /tags/2.5.4/includes/core/extend.php	(revision 5382)
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * bbPress Extentions
+ *
+ * There's a world of really cool plugins out there, and bbPress comes with
+ * support for some of the most popular ones.
+ *
+ * @package bbPress
+ * @subpackage Extend
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Loads Akismet inside the bbPress global class
+ *
+ * @since bbPress (r3277)
+ *
+ * @return If bbPress is not active
+ */
+function bbp_setup_akismet() {
+
+	// Bail if no akismet
+	if ( !defined( 'AKISMET_VERSION' ) ) return;
+
+	// Bail if Akismet is turned off
+	if ( !bbp_is_akismet_active() ) return;
+
+	// Include the Akismet Component
+	require( bbpress()->includes_dir . 'extend/akismet.php' );
+
+	// Instantiate Akismet for bbPress
+	bbpress()->extend->akismet = new BBP_Akismet();
+}
+
+/**
+ * Requires and creates the BuddyPress extension, and adds component creation
+ * action to bp_init hook. @see bbp_setup_buddypress_component()
+ *
+ * @since bbPress (r3395)
+ * @return If BuddyPress is not active
+ */
+function bbp_setup_buddypress() {
+
+	if ( ! function_exists( 'buddypress' ) ) {
+
+		/**
+		 * Helper for BuddyPress 1.6 and earlier
+		 *
+		 * @since bbPress (r4395)
+		 * @return BuddyPress
+		 */
+		function buddypress() {
+			return isset( $GLOBALS['bp'] ) ? $GLOBALS['bp'] : false;
+		}
+	}
+
+	// Bail if in maintenance mode
+	if ( ! buddypress() || buddypress()->maintenance_mode )
+		return;
+
+	// Include the BuddyPress Component
+	require( bbpress()->includes_dir . 'extend/buddypress/loader.php' );
+
+	// Instantiate BuddyPress for bbPress
+	bbpress()->extend->buddypress = new BBP_Forums_Component();
+}
Index: /tags/2.5.4/includes/core/filters.php
===================================================================
--- /tags/2.5.4/includes/core/filters.php	(revision 5382)
+++ /tags/2.5.4/includes/core/filters.php	(revision 5382)
@@ -0,0 +1,310 @@
+<?php
+
+/**
+ * bbPress Filters
+ *
+ * @package bbPress
+ * @subpackage Core
+ *
+ * This file contains the filters that are used through-out bbPress. They are
+ * consolidated here to make searching for them easier, and to help developers
+ * understand at a glance the order in which things occur.
+ *
+ * There are a few common places that additional filters can currently be found
+ *
+ *  - bbPress: In {@link bbPress::setup_actions()} in bbpress.php
+ *  - Admin: More in {@link BBP_Admin::setup_actions()} in admin.php
+ *
+ * @see /core/actions.php
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Attach bbPress to WordPress
+ *
+ * bbPress uses its own internal actions to help aid in third-party plugin
+ * development, and to limit the amount of potential future code changes when
+ * updates to WordPress core occur.
+ *
+ * These actions exist to create the concept of 'plugin dependencies'. They
+ * provide a safe way for plugins to execute code *only* when bbPress is
+ * installed and activated, without needing to do complicated guesswork.
+ *
+ * For more information on how this works, see the 'Plugin Dependency' section
+ * near the bottom of this file.
+ *
+ *           v--WordPress Actions       v--bbPress Sub-actions
+ */
+add_filter( 'request',                 'bbp_request',            10    );
+add_filter( 'template_include',        'bbp_template_include',   10    );
+add_filter( 'wp_title',                'bbp_title',              10, 3 );
+add_filter( 'body_class',              'bbp_body_class',         10, 2 );
+add_filter( 'map_meta_cap',            'bbp_map_meta_caps',      10, 4 );
+add_filter( 'allowed_themes',          'bbp_allowed_themes',     10    );
+add_filter( 'redirect_canonical',      'bbp_redirect_canonical', 10    );
+add_filter( 'login_redirect',          'bbp_redirect_login',     2,  3 );
+add_filter( 'logout_url',              'bbp_logout_url',         2,  2 );
+add_filter( 'plugin_locale',           'bbp_plugin_locale',      10, 2 );
+
+// Fix post author id for anonymous posts (set it back to 0) when the post status is changed
+add_filter( 'wp_insert_post_data', 'bbp_fix_post_author', 30, 2 );
+
+// Force comments_status on bbPress post types
+add_filter( 'comments_open', 'bbp_force_comment_status' );
+
+// Add post_parent__in to posts_where
+add_filter( 'posts_where', 'bbp_query_post_parent__in', 10, 2 );
+
+// Remove forums roles from list of all roles
+add_filter( 'editable_roles', 'bbp_filter_blog_editable_roles' );
+
+// Reply title fallback
+add_filter( 'the_title', 'bbp_get_reply_title_fallback', 2, 2 );
+
+/**
+ * Feeds
+ *
+ * bbPress comes with a number of custom RSS2 feeds that get handled outside
+ * the normal scope of feeds that WordPress would normally serve. To do this,
+ * we filter every page request, listen for a feed request, and trap it.
+ */
+add_filter( 'bbp_request', 'bbp_request_feed_trap' );
+
+/**
+ * Template Compatibility
+ *
+ * If you want to completely bypass this and manage your own custom bbPress
+ * template hierarchy, start here by removing this filter, then look at how
+ * bbp_template_include() works and do something similar. :)
+ */
+add_filter( 'bbp_template_include',   'bbp_template_include_theme_supports', 2, 1 );
+add_filter( 'bbp_template_include',   'bbp_template_include_theme_compat',   4, 2 );
+
+// Filter bbPress template locations
+add_filter( 'bbp_get_template_stack', 'bbp_add_template_stack_locations'          );
+
+// Links
+add_filter( 'paginate_links',          'bbp_add_view_all' );
+add_filter( 'bbp_get_topic_permalink', 'bbp_add_view_all' );
+add_filter( 'bbp_get_reply_permalink', 'bbp_add_view_all' );
+add_filter( 'bbp_get_forum_permalink', 'bbp_add_view_all' );
+
+// wp_filter_kses on new/edit topic/reply title
+add_filter( 'bbp_new_reply_pre_title',  'wp_filter_kses'  );
+add_filter( 'bbp_new_topic_pre_title',  'wp_filter_kses'  );
+add_filter( 'bbp_edit_reply_pre_title', 'wp_filter_kses'  );
+add_filter( 'bbp_edit_topic_pre_title', 'wp_filter_kses'  );
+
+// Prevent posting malicious or malformed content on new/edit topic/reply
+add_filter( 'bbp_new_reply_pre_content',  'bbp_encode_bad',  10 );
+add_filter( 'bbp_new_reply_pre_content',  'bbp_code_trick',  20 );
+add_filter( 'bbp_new_reply_pre_content',  'bbp_filter_kses', 30 );
+add_filter( 'bbp_new_reply_pre_content',  'balanceTags',     40 );
+add_filter( 'bbp_new_topic_pre_content',  'bbp_encode_bad',  10 );
+add_filter( 'bbp_new_topic_pre_content',  'bbp_code_trick',  20 );
+add_filter( 'bbp_new_topic_pre_content',  'bbp_filter_kses', 30 );
+add_filter( 'bbp_new_topic_pre_content',  'balanceTags',     40 );
+add_filter( 'bbp_new_forum_pre_content',  'bbp_encode_bad',  10 );
+add_filter( 'bbp_new_forum_pre_content',  'bbp_code_trick',  20 );
+add_filter( 'bbp_new_forum_pre_content',  'bbp_filter_kses', 30 );
+add_filter( 'bbp_new_forum_pre_content',  'balanceTags',     40 );
+add_filter( 'bbp_edit_reply_pre_content', 'bbp_encode_bad',  10 );
+add_filter( 'bbp_edit_reply_pre_content', 'bbp_code_trick',  20 );
+add_filter( 'bbp_edit_reply_pre_content', 'bbp_filter_kses', 30 );
+add_filter( 'bbp_edit_reply_pre_content', 'balanceTags',     40 );
+add_filter( 'bbp_edit_topic_pre_content', 'bbp_encode_bad',  10 );
+add_filter( 'bbp_edit_topic_pre_content', 'bbp_code_trick',  20 );
+add_filter( 'bbp_edit_topic_pre_content', 'bbp_filter_kses', 30 );
+add_filter( 'bbp_edit_topic_pre_content', 'balanceTags',     40 );
+add_filter( 'bbp_edit_forum_pre_content', 'bbp_encode_bad',  10 );
+add_filter( 'bbp_edit_forum_pre_content', 'bbp_code_trick',  20 );
+add_filter( 'bbp_edit_forum_pre_content', 'bbp_filter_kses', 30 );
+add_filter( 'bbp_edit_forum_pre_content', 'balanceTags',     40 );
+
+// No follow and stripslashes on user profile links
+add_filter( 'bbp_get_reply_author_link',      'bbp_rel_nofollow' );
+add_filter( 'bbp_get_reply_author_link',      'stripslashes'     );
+add_filter( 'bbp_get_topic_author_link',      'bbp_rel_nofollow' );
+add_filter( 'bbp_get_topic_author_link',      'stripslashes'     );
+add_filter( 'bbp_get_user_favorites_link',    'bbp_rel_nofollow' );
+add_filter( 'bbp_get_user_favorites_link',    'stripslashes'     );
+add_filter( 'bbp_get_user_subscribe_link',    'bbp_rel_nofollow' );
+add_filter( 'bbp_get_user_subscribe_link',    'stripslashes'     );
+add_filter( 'bbp_get_user_profile_link',      'bbp_rel_nofollow' );
+add_filter( 'bbp_get_user_profile_link',      'stripslashes'     );
+add_filter( 'bbp_get_user_profile_edit_link', 'bbp_rel_nofollow' );
+add_filter( 'bbp_get_user_profile_edit_link', 'stripslashes'     );
+
+// Run filters on reply content
+add_filter( 'bbp_get_reply_content', 'bbp_make_clickable', 4    );
+add_filter( 'bbp_get_reply_content', 'bbp_mention_filter', 5    );
+add_filter( 'bbp_get_reply_content', 'wptexturize',        6    );
+add_filter( 'bbp_get_reply_content', 'convert_chars',      8    );
+add_filter( 'bbp_get_reply_content', 'capital_P_dangit',   10   );
+add_filter( 'bbp_get_reply_content', 'convert_smilies',    20   );
+add_filter( 'bbp_get_reply_content', 'force_balance_tags', 30   );
+add_filter( 'bbp_get_reply_content', 'wpautop',            40   );
+add_filter( 'bbp_get_reply_content', 'bbp_rel_nofollow',   50   );
+
+// Run filters on topic content
+add_filter( 'bbp_get_topic_content', 'bbp_make_clickable', 4    );
+add_filter( 'bbp_get_topic_content', 'bbp_mention_filter', 5    );
+add_filter( 'bbp_get_topic_content', 'wptexturize',        6    );
+add_filter( 'bbp_get_topic_content', 'convert_chars',      8    );
+add_filter( 'bbp_get_topic_content', 'capital_P_dangit',   10   );
+add_filter( 'bbp_get_topic_content', 'convert_smilies',    20   );
+add_filter( 'bbp_get_topic_content', 'force_balance_tags', 30   );
+add_filter( 'bbp_get_topic_content', 'wpautop',            40   );
+add_filter( 'bbp_get_topic_content', 'bbp_rel_nofollow',   50   );
+
+// Form textarea output - undo the code-trick done pre-save, and sanitize
+add_filter( 'bbp_get_form_forum_content', 'bbp_code_trick_reverse' );
+add_filter( 'bbp_get_form_forum_content', 'esc_textarea'           );
+add_filter( 'bbp_get_form_forum_content', 'trim'                   );
+add_filter( 'bbp_get_form_topic_content', 'bbp_code_trick_reverse' );
+add_filter( 'bbp_get_form_topic_content', 'esc_textarea'           );
+add_filter( 'bbp_get_form_topic_content', 'trim'                   );
+add_filter( 'bbp_get_form_reply_content', 'bbp_code_trick_reverse' );
+add_filter( 'bbp_get_form_reply_content', 'esc_textarea'           );
+add_filter( 'bbp_get_form_reply_content', 'trim'                   );
+
+// Add number format filter to functions requiring numeric output
+add_filter( 'bbp_get_user_topic_count',     'bbp_number_format', 10 );
+add_filter( 'bbp_get_user_reply_count',     'bbp_number_format', 10 );
+add_filter( 'bbp_get_user_post_count',      'bbp_number_format', 10 );
+add_filter( 'bbp_get_forum_subforum_count', 'bbp_number_format', 10 );
+add_filter( 'bbp_get_forum_topic_count',    'bbp_number_format', 10 );
+add_filter( 'bbp_get_forum_reply_count',    'bbp_number_format', 10 );
+add_filter( 'bbp_get_forum_post_count',     'bbp_number_format', 10 );
+add_filter( 'bbp_get_topic_voice_count',    'bbp_number_format', 10 );
+add_filter( 'bbp_get_topic_reply_count',    'bbp_number_format', 10 );
+add_filter( 'bbp_get_topic_post_count',     'bbp_number_format', 10 );
+
+// Sanitize displayed user data
+add_filter( 'bbp_get_displayed_user_field', 'bbp_sanitize_displayed_user_field', 10, 3 );
+
+// Run wp_kses_data on topic/reply content in admin section
+if ( is_admin() ) {
+	add_filter( 'bbp_get_reply_content', 'bbp_kses_data' );
+	add_filter( 'bbp_get_topic_content', 'bbp_kses_data' );
+
+// Revisions (only when not in admin)
+} else {
+	add_filter( 'bbp_get_reply_content', 'bbp_reply_content_append_revisions',  99,  2 );
+	add_filter( 'bbp_get_topic_content', 'bbp_topic_content_append_revisions',  99,  2 );
+}
+
+// Suppress private forum details
+add_filter( 'bbp_get_forum_topic_count',    'bbp_suppress_private_forum_meta',  10, 2 );
+add_filter( 'bbp_get_forum_reply_count',    'bbp_suppress_private_forum_meta',  10, 2 );
+add_filter( 'bbp_get_forum_post_count',     'bbp_suppress_private_forum_meta',  10, 2 );
+add_filter( 'bbp_get_forum_freshness_link', 'bbp_suppress_private_forum_meta',  10, 2 );
+add_filter( 'bbp_get_author_link',          'bbp_suppress_private_author_link', 10, 2 );
+add_filter( 'bbp_get_topic_author_link',    'bbp_suppress_private_author_link', 10, 2 );
+add_filter( 'bbp_get_reply_author_link',    'bbp_suppress_private_author_link', 10, 2 );
+
+// Topic and reply author display names
+add_filter( 'bbp_get_topic_author_display_name', 'wptexturize'   );
+add_filter( 'bbp_get_topic_author_display_name', 'convert_chars' );
+add_filter( 'bbp_get_topic_author_display_name', 'esc_html'      );
+add_filter( 'bbp_get_reply_author_display_name', 'wptexturize'   );
+add_filter( 'bbp_get_reply_author_display_name', 'convert_chars' );
+add_filter( 'bbp_get_reply_author_display_name', 'esc_html'      );
+
+/**
+ * Add filters to anonymous post author data
+ */
+// Post author name
+add_filter( 'bbp_pre_anonymous_post_author_name',    'trim',                10 );
+add_filter( 'bbp_pre_anonymous_post_author_name',    'sanitize_text_field', 10 );
+add_filter( 'bbp_pre_anonymous_post_author_name',    'wp_filter_kses',      10 );
+add_filter( 'bbp_pre_anonymous_post_author_name',    '_wp_specialchars',    30 );
+
+// Save email
+add_filter( 'bbp_pre_anonymous_post_author_email',   'trim',                10 );
+add_filter( 'bbp_pre_anonymous_post_author_email',   'sanitize_email',      10 );
+add_filter( 'bbp_pre_anonymous_post_author_email',   'wp_filter_kses',      10 );
+
+// Save URL
+add_filter( 'bbp_pre_anonymous_post_author_website', 'trim',                10 );
+add_filter( 'bbp_pre_anonymous_post_author_website', 'wp_strip_all_tags',   10 );
+add_filter( 'bbp_pre_anonymous_post_author_website', 'esc_url_raw',         10 );
+add_filter( 'bbp_pre_anonymous_post_author_website', 'wp_filter_kses',      10 );
+
+// Queries
+add_filter( 'posts_request', '_bbp_has_replies_where', 10, 2 );
+
+// Capabilities
+add_filter( 'bbp_map_meta_caps', 'bbp_map_primary_meta_caps',   10, 4 ); // Primary caps
+add_filter( 'bbp_map_meta_caps', 'bbp_map_forum_meta_caps',     10, 4 ); // Forums
+add_filter( 'bbp_map_meta_caps', 'bbp_map_topic_meta_caps',     10, 4 ); // Topics
+add_filter( 'bbp_map_meta_caps', 'bbp_map_reply_meta_caps',     10, 4 ); // Replies
+add_filter( 'bbp_map_meta_caps', 'bbp_map_topic_tag_meta_caps', 10, 4 ); // Topic tags
+
+/** Deprecated ****************************************************************/
+
+/**
+ * The following filters are deprecated.
+ *
+ * These filters were most likely replaced by bbp_parse_args(), which includes
+ * both passive and aggressive filters anywhere parse_args is used to compare
+ * default arguments to passed arguments, without needing to litter the
+ * codebase with _before_ and _after_ filters everywhere.
+ */
+
+/**
+ * Deprecated locale filter
+ *
+ * @since bbPress (r4213)
+ *
+ * @param string $locale
+ * @return string  $domain
+ */
+function _bbp_filter_locale( $locale = '', $domain = '' ) {
+
+	// Only apply to the bbPress text-domain
+	if ( bbpress()->domain !== $domain ) {
+		return $locale;
+	}
+
+	return apply_filters( 'bbpress_locale', $locale, $domain );
+}
+add_filter( 'bbp_plugin_locale', '_bbp_filter_locale', 10, 1 );
+
+/**
+ * Deprecated forums query filter
+ *
+ * @since bbPress (r3961)
+ * @param array $args
+ * @return array
+ */
+function _bbp_has_forums_query( $args = array() ) {
+	return apply_filters( 'bbp_has_forums_query', $args );
+}
+add_filter( 'bbp_after_has_forums_parse_args', '_bbp_has_forums_query' );
+
+/**
+ * Deprecated topics query filter
+ *
+ * @since bbPress (r3961)
+ * @param array $args
+ * @return array
+ */
+function _bbp_has_topics_query( $args = array() ) {
+	return apply_filters( 'bbp_has_topics_query', $args );
+}
+add_filter( 'bbp_after_has_topics_parse_args', '_bbp_has_topics_query' );
+
+/**
+ * Deprecated replies query filter
+ *
+ * @since bbPress (r3961)
+ * @param array $args
+ * @return array
+ */
+function _bbp_has_replies_query( $args = array() ) {
+	return apply_filters( 'bbp_has_replies_query', $args );
+}
+add_filter( 'bbp_after_has_replies_parse_args', '_bbp_has_replies_query' );
Index: /tags/2.5.4/includes/core/functions.php
===================================================================
--- /tags/2.5.4/includes/core/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/core/functions.php	(revision 5382)
@@ -0,0 +1,579 @@
+<?php
+
+/**
+ * bbPress Core Functions
+ *
+ * @package bbPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Versions ******************************************************************/
+
+/**
+ * Output the bbPress version
+ *
+ * @since bbPress (r3468)
+ * @uses bbp_get_version() To get the bbPress version
+ */
+function bbp_version() {
+	echo bbp_get_version();
+}
+	/**
+	 * Return the bbPress version
+	 *
+	 * @since bbPress (r3468)
+	 * @retrun string The bbPress version
+	 */
+	function bbp_get_version() {
+		return bbpress()->version;
+	}
+
+/**
+ * Output the bbPress database version
+ *
+ * @since bbPress (r3468)
+ * @uses bbp_get_version() To get the bbPress version
+ */
+function bbp_db_version() {
+	echo bbp_get_db_version();
+}
+	/**
+	 * Return the bbPress database version
+	 *
+	 * @since bbPress (r3468)
+	 * @retrun string The bbPress version
+	 */
+	function bbp_get_db_version() {
+		return bbpress()->db_version;
+	}
+
+/**
+ * Output the bbPress database version directly from the database
+ *
+ * @since bbPress (r3468)
+ * @uses bbp_get_version() To get the current bbPress version
+ */
+function bbp_db_version_raw() {
+	echo bbp_get_db_version_raw();
+}
+	/**
+	 * Return the bbPress database version directly from the database
+	 *
+	 * @since bbPress (r3468)
+	 * @retrun string The current bbPress version
+	 */
+	function bbp_get_db_version_raw() {
+		return get_option( '_bbp_db_version', '' );
+	}
+
+/** Post Meta *****************************************************************/
+
+/**
+ * Update a posts forum meta ID
+ *
+ * @since bbPress (r3181)
+ *
+ * @param int $post_id The post to update
+ * @param int $forum_id The forum
+ */
+function bbp_update_forum_id( $post_id, $forum_id ) {
+
+	// Allow the forum ID to be updated 'just in time' before save
+	$forum_id = apply_filters( 'bbp_update_forum_id', $forum_id, $post_id );
+
+	// Update the post meta forum ID
+	update_post_meta( $post_id, '_bbp_forum_id', (int) $forum_id );
+}
+
+/**
+ * Update a posts topic meta ID
+ *
+ * @since bbPress (r3181)
+ *
+ * @param int $post_id The post to update
+ * @param int $forum_id The forum
+ */
+function bbp_update_topic_id( $post_id, $topic_id ) {
+
+	// Allow the topic ID to be updated 'just in time' before save
+	$topic_id = apply_filters( 'bbp_update_topic_id', $topic_id, $post_id );
+
+	// Update the post meta topic ID
+	update_post_meta( $post_id, '_bbp_topic_id', (int) $topic_id );
+}
+
+/**
+ * Update a posts reply meta ID
+ *
+ * @since bbPress (r3181)
+ *
+ * @param int $post_id The post to update
+ * @param int $forum_id The forum
+ */
+function bbp_update_reply_id( $post_id, $reply_id ) {
+
+	// Allow the reply ID to be updated 'just in time' before save
+	$reply_id = apply_filters( 'bbp_update_reply_id', $reply_id, $post_id );
+
+	// Update the post meta reply ID
+	update_post_meta( $post_id, '_bbp_reply_id',(int) $reply_id );
+}
+
+/** Views *********************************************************************/
+
+/**
+ * Get the registered views
+ *
+ * Does nothing much other than return the {@link $bbp->views} variable
+ *
+ * @since bbPress (r2789)
+ *
+ * @return array Views
+ */
+function bbp_get_views() {
+	return bbpress()->views;
+}
+
+/**
+ * Register a bbPress view
+ *
+ * @todo Implement feeds - See {@link http://trac.bbpress.org/ticket/1422}
+ *
+ * @since bbPress (r2789)
+ *
+ * @param string $view View name
+ * @param string $title View title
+ * @param mixed $query_args {@link bbp_has_topics()} arguments.
+ * @param bool $feed Have a feed for the view? Defaults to true. NOT IMPLEMENTED
+ * @param string $capability Capability that the current user must have
+ * @uses sanitize_title() To sanitize the view name
+ * @uses esc_html() To sanitize the view title
+ * @return array The just registered (but processed) view
+ */
+function bbp_register_view( $view, $title, $query_args = '', $feed = true, $capability = '' ) {
+
+	// Bail if user does not have capability
+	if ( ! empty( $capability ) && ! current_user_can( $capability ) )
+		return false;
+
+	$bbp   = bbpress();
+	$view  = sanitize_title( $view );
+	$title = esc_html( $title );
+
+	if ( empty( $view ) || empty( $title ) )
+		return false;
+
+	$query_args = bbp_parse_args( $query_args, '', 'register_view' );
+
+	// Set show_stickies to false if it wasn't supplied
+	if ( !isset( $query_args['show_stickies'] ) )
+		$query_args['show_stickies'] = false;
+
+	$bbp->views[$view] = array(
+		'title'  => $title,
+		'query'  => $query_args,
+		'feed'   => $feed
+	);
+
+	return $bbp->views[$view];
+}
+
+/**
+ * Deregister a bbPress view
+ *
+ * @since bbPress (r2789)
+ *
+ * @param string $view View name
+ * @uses sanitize_title() To sanitize the view name
+ * @return bool False if the view doesn't exist, true on success
+ */
+function bbp_deregister_view( $view ) {
+	$bbp  = bbpress();
+	$view = sanitize_title( $view );
+
+	if ( !isset( $bbp->views[$view] ) )
+		return false;
+
+	unset( $bbp->views[$view] );
+
+	return true;
+}
+
+/**
+ * Run the view's query
+ *
+ * @since bbPress (r2789)
+ *
+ * @param string $view Optional. View id
+ * @param mixed $new_args New arguments. See {@link bbp_has_topics()}
+ * @uses bbp_get_view_id() To get the view id
+ * @uses bbp_get_view_query_args() To get the view query args
+ * @uses sanitize_title() To sanitize the view name
+ * @uses bbp_has_topics() To make the topics query
+ * @return bool False if the view doesn't exist, otherwise if topics are there
+ */
+function bbp_view_query( $view = '', $new_args = '' ) {
+
+	$view = bbp_get_view_id( $view );
+	if ( empty( $view ) )
+		return false;
+
+	$query_args = bbp_get_view_query_args( $view );
+
+	if ( !empty( $new_args ) ) {
+		$new_args   = bbp_parse_args( $new_args, '', 'view_query' );
+		$query_args = array_merge( $query_args, $new_args );
+	}
+
+	return bbp_has_topics( $query_args );
+}
+
+/**
+ * Return the view's query arguments
+ *
+ * @since bbPress (r2789)
+ *
+ * @param string $view View name
+ * @uses bbp_get_view_id() To get the view id
+ * @return array Query arguments
+ */
+function bbp_get_view_query_args( $view ) {
+	$view   = bbp_get_view_id( $view );
+	$retval = !empty( $view ) ? bbpress()->views[$view]['query'] : false;
+
+	return apply_filters( 'bbp_get_view_query_args', $retval, $view );
+}
+
+/** Errors ********************************************************************/
+
+/**
+ * Adds an error message to later be output in the theme
+ *
+ * @since bbPress (r3381)
+ *
+ * @see WP_Error()
+ * @uses WP_Error::add();
+ *
+ * @param string $code Unique code for the error message
+ * @param string $message Translated error message
+ * @param string $data Any additional data passed with the error message
+ */
+function bbp_add_error( $code = '', $message = '', $data = '' ) {
+	bbpress()->errors->add( $code, $message, $data );
+}
+
+/**
+ * Check if error messages exist in queue
+ *
+ * @since bbPress (r3381)
+ *
+ * @see WP_Error()
+ *
+ * @uses is_wp_error()
+ * @usese WP_Error::get_error_codes()
+ */
+function bbp_has_errors() {
+	$has_errors = bbpress()->errors->get_error_codes() ? true : false;
+
+	return apply_filters( 'bbp_has_errors', $has_errors, bbpress()->errors );
+}
+
+/** Mentions ******************************************************************/
+
+/**
+ * Set the pattern used for matching usernames for mentions.
+ *
+ * Moved into its own function to allow filtering of the regex pattern
+ * anywhere mentions might be used.
+ *
+ * @since bbPress (r4997)
+ * @return string Pattern to match usernames with
+ */
+function bbp_find_mentions_pattern() {
+	return apply_filters( 'bbp_find_mentions_pattern', '/[@]+([A-Za-z0-9-_\.@]+)\b/' );
+}
+
+/**
+ * Searches through the content to locate usernames, designated by an @ sign.
+ *
+ * @since bbPress (r4323)
+ *
+ * @param string $content The content
+ * @return bool|array $usernames Existing usernames. False if no matches.
+ */
+function bbp_find_mentions( $content = '' ) {
+	$pattern   = bbp_find_mentions_pattern();
+	preg_match_all( $pattern, $content, $usernames );
+	$usernames = array_unique( array_filter( $usernames[1] ) );
+
+	// Bail if no usernames
+	if ( empty( $usernames ) ) {
+		$usernames = false;
+	}
+
+	return apply_filters( 'bbp_find_mentions', $usernames, $pattern, $content );
+}
+
+/**
+ * Finds and links @-mentioned users in the content
+ *
+ * @since bbPress (r4323)
+ *
+ * @uses bbp_find_mentions() To get usernames in content areas
+ * @return string $content Content filtered for mentions
+ */
+function bbp_mention_filter( $content = '' ) {
+
+	// Get Usernames and bail if none exist
+	$usernames = bbp_find_mentions( $content );
+	if ( empty( $usernames ) )
+		return $content;
+
+	// Loop through usernames and link to profiles
+	foreach ( (array) $usernames as $username ) {
+
+		// Skip if username does not exist or user is not active
+		$user = get_user_by( 'slug', $username );
+		if ( empty( $user->ID ) || bbp_is_user_inactive( $user->ID ) )
+			continue;
+
+		// Replace name in content
+		$content = preg_replace( '/(@' . $username . '\b)/', sprintf( '<a href="%1$s" rel="nofollow">@%2$s</a>', bbp_get_user_profile_url( $user->ID ), $username ), $content );
+	}
+
+	// Return modified content
+	return $content;
+}
+
+/** Post Statuses *************************************************************/
+
+/**
+ * Return the public post status ID
+ *
+ * @since bbPress (r3504)
+ *
+ * @return string
+ */
+function bbp_get_public_status_id() {
+	return bbpress()->public_status_id;
+}
+
+/**
+ * Return the pending post status ID
+ *
+ * @since bbPress (r3581)
+ *
+ * @return string
+ */
+function bbp_get_pending_status_id() {
+	return bbpress()->pending_status_id;
+}
+
+/**
+ * Return the private post status ID
+ *
+ * @since bbPress (r3504)
+ *
+ * @return string
+ */
+function bbp_get_private_status_id() {
+	return bbpress()->private_status_id;
+}
+
+/**
+ * Return the hidden post status ID
+ *
+ * @since bbPress (r3504)
+ *
+ * @return string
+ */
+function bbp_get_hidden_status_id() {
+	return bbpress()->hidden_status_id;
+}
+
+/**
+ * Return the closed post status ID
+ *
+ * @since bbPress (r3504)
+ *
+ * @return string
+ */
+function bbp_get_closed_status_id() {
+	return bbpress()->closed_status_id;
+}
+
+/**
+ * Return the spam post status ID
+ *
+ * @since bbPress (r3504)
+ *
+ * @return string
+ */
+function bbp_get_spam_status_id() {
+	return bbpress()->spam_status_id;
+}
+
+/**
+ * Return the trash post status ID
+ *
+ * @since bbPress (r3504)
+ *
+ * @return string
+ */
+function bbp_get_trash_status_id() {
+	return bbpress()->trash_status_id;
+}
+
+/**
+ * Return the orphan post status ID
+ *
+ * @since bbPress (r3504)
+ *
+ * @return string
+ */
+function bbp_get_orphan_status_id() {
+	return bbpress()->orphan_status_id;
+}
+
+/** Rewrite IDs ***************************************************************/
+
+/**
+ * Return the unique ID for user profile rewrite rules
+ *
+ * @since bbPress (r3762)
+ * @return string
+ */
+function bbp_get_user_rewrite_id() {
+	return bbpress()->user_id;
+}
+
+/**
+ * Return the unique ID for all edit rewrite rules (forum|topic|reply|tag|user)
+ *
+ * @since bbPress (r3762)
+ * @return string
+ */
+function bbp_get_edit_rewrite_id() {
+	return bbpress()->edit_id;
+}
+
+/**
+ * Return the unique ID for all search rewrite rules
+ *
+ * @since bbPress (r4579)
+ *
+ * @return string
+ */
+function bbp_get_search_rewrite_id() {
+	return bbpress()->search_id;
+}
+
+/**
+ * Return the unique ID for user topics rewrite rules
+ *
+ * @since bbPress (r4321)
+ * @return string
+ */
+function bbp_get_user_topics_rewrite_id() {
+	return bbpress()->tops_id;
+}
+
+/**
+ * Return the unique ID for user replies rewrite rules
+ *
+ * @since bbPress (r4321)
+ * @return string
+ */
+function bbp_get_user_replies_rewrite_id() {
+	return bbpress()->reps_id;
+}
+
+/**
+ * Return the unique ID for user caps rewrite rules
+ *
+ * @since bbPress (r4181)
+ * @return string
+ */
+function bbp_get_user_favorites_rewrite_id() {
+	return bbpress()->favs_id;
+}
+
+/**
+ * Return the unique ID for user caps rewrite rules
+ *
+ * @since bbPress (r4181)
+ * @return string
+ */
+function bbp_get_user_subscriptions_rewrite_id() {
+	return bbpress()->subs_id;
+}
+
+/**
+ * Return the unique ID for topic view rewrite rules
+ *
+ * @since bbPress (r3762)
+ * @return string
+ */
+function bbp_get_view_rewrite_id() {
+	return bbpress()->view_id;
+}
+
+/** Rewrite Extras ************************************************************/
+
+/**
+ * Get the id used for paginated requests
+ *
+ * @since bbPress (r4926)
+ * @return string
+ */
+function bbp_get_paged_rewrite_id() {
+	return bbpress()->paged_id;
+}
+
+/**
+ * Get the slug used for paginated requests
+ *
+ * @since bbPress (r4926)
+ * @global object $wp_rewrite The WP_Rewrite object
+ * @return string
+ */
+function bbp_get_paged_slug() {
+	global $wp_rewrite;
+	return $wp_rewrite->pagination_base;
+}
+
+/**
+ * Delete a blogs rewrite rules, so that they are automatically rebuilt on
+ * the subsequent page load.
+ *
+ * @since bbPress (r4198)
+ */
+function bbp_delete_rewrite_rules() {
+	delete_option( 'rewrite_rules' );
+}
+
+/** Requests ******************************************************************/
+
+/**
+ * Return true|false if this is a POST request
+ *
+ * @since bbPress (r4790)
+ * @return bool
+ */
+function bbp_is_post_request() {
+	return (bool) ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) );
+}
+
+/**
+ * Return true|false if this is a GET request
+ *
+ * @since bbPress (r4790)
+ * @return bool
+ */
+function bbp_is_get_request() {
+	return (bool) ( 'GET' === strtoupper( $_SERVER['REQUEST_METHOD'] ) );
+}
+
Index: /tags/2.5.4/includes/core/index.php
===================================================================
--- /tags/2.5.4/includes/core/index.php	(revision 5382)
+++ /tags/2.5.4/includes/core/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/core/options.php
===================================================================
--- /tags/2.5.4/includes/core/options.php	(revision 5382)
+++ /tags/2.5.4/includes/core/options.php	(revision 5382)
@@ -0,0 +1,624 @@
+<?php
+
+/**
+ * bbPress Options
+ *
+ * @package bbPress
+ * @subpackage Options
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Get the default site options and their values.
+ * 
+ * These option
+ *
+ * @since bbPress (r3421)
+ * @return array Filtered option names and values
+ */
+function bbp_get_default_options() {
+
+	// Default options
+	return apply_filters( 'bbp_get_default_options', array(
+
+		/** DB Version ********************************************************/
+
+		'_bbp_db_version'           => bbpress()->db_version,
+
+		/** Settings **********************************************************/
+
+		'_bbp_edit_lock'              => 5,                          // Lock post editing after 5 minutes
+		'_bbp_throttle_time'          => 10,                         // Throttle post time to 10 seconds
+		'_bbp_enable_favorites'       => 1,                          // Favorites
+		'_bbp_enable_subscriptions'   => 1,                          // Subscriptions
+		'_bbp_allow_anonymous'        => 0,                          // Allow anonymous posting
+		'_bbp_allow_global_access'    => 1,                          // Users from all sites can post
+		'_bbp_allow_revisions'        => 1,                          // Allow revisions
+		'_bbp_allow_topic_tags'       => 1,                          // Allow topic tagging
+		'_bbp_allow_threaded_replies' => 0,                          // Allow threaded replies
+		'_bbp_allow_search'           => 1,                          // Allow forum-wide search
+		'_bbp_thread_replies_depth'   => 2,                          // Thread replies depth
+		'_bbp_use_wp_editor'          => 1,                          // Use the WordPress editor if available
+		'_bbp_use_autoembed'          => 0,                          // Allow oEmbed in topics and replies
+		'_bbp_theme_package_id'       => 'default',                  // The ID for the current theme package
+		'_bbp_default_role'           => bbp_get_participant_role(), // Default forums role
+		'_bbp_settings_integration'   => 0,                          // Put settings into existing admin pages
+
+		/** Per Page **********************************************************/
+
+		'_bbp_topics_per_page'      => 15,          // Topics per page
+		'_bbp_replies_per_page'     => 15,          // Replies per page
+		'_bbp_forums_per_page'      => 50,          // Forums per page
+		'_bbp_topics_per_rss_page'  => 25,          // Topics per RSS page
+		'_bbp_replies_per_rss_page' => 25,          // Replies per RSS page
+
+		/** Page For **********************************************************/
+
+		'_bbp_page_for_forums'      => 0,           // Page for forums
+		'_bbp_page_for_topics'      => 0,           // Page for forums
+		'_bbp_page_for_login'       => 0,           // Page for login
+		'_bbp_page_for_register'    => 0,           // Page for register
+		'_bbp_page_for_lost_pass'   => 0,           // Page for lost-pass
+
+		/** Forum Root ********************************************************/
+
+		'_bbp_root_slug'            => 'forums',    // Forum archive slug
+		'_bbp_show_on_root'         => 'forums',    // What to show on root (forums|topics)
+		'_bbp_include_root'         => 1,           // Include forum-archive before single slugs
+
+		/** Single Slugs ******************************************************/
+
+		'_bbp_forum_slug'           => 'forum',     // Forum slug
+		'_bbp_topic_slug'           => 'topic',     // Topic slug
+		'_bbp_reply_slug'           => 'reply',     // Reply slug
+		'_bbp_topic_tag_slug'       => 'topic-tag', // Topic tag slug
+
+		/** User Slugs ********************************************************/
+
+		'_bbp_user_slug'            => 'users',         // User profile slug
+		'_bbp_user_favs_slug'       => 'favorites',     // User favorites slug
+		'_bbp_user_subs_slug'       => 'subscriptions', // User subscriptions slug
+		'_bbp_topic_archive_slug'   => 'topics',        // Topic archive slug
+		'_bbp_reply_archive_slug'   => 'replies',       // Reply archive slug
+
+		/** Other Slugs *******************************************************/
+
+		'_bbp_view_slug'            => 'view',      // View slug
+		'_bbp_search_slug'          => 'search',    // Search slug
+
+		/** Topics ************************************************************/
+
+		'_bbp_title_max_length'     => 80,          // Title Max Length
+		'_bbp_super_sticky_topics'  => '',          // Super stickies
+
+		/** Forums ************************************************************/
+
+		'_bbp_private_forums'       => '',          // Private forums
+		'_bbp_hidden_forums'        => '',          // Hidden forums
+
+		/** BuddyPress ********************************************************/
+
+		'_bbp_enable_group_forums'  => 1,           // Enable BuddyPress Group Extension
+		'_bbp_group_forums_root_id' => 0,           // Group Forums parent forum id
+
+		/** Akismet ***********************************************************/
+
+		'_bbp_enable_akismet'       => 1            // Users from all sites can post
+
+	) );
+}
+
+/**
+ * Add default options
+ *
+ * Hooked to bbp_activate, it is only called once when bbPress is activated.
+ * This is non-destructive, so existing settings will not be overridden.
+ *
+ * @since bbPress (r3421)
+ * @uses bbp_get_default_options() To get default options
+ * @uses add_option() Adds default options
+ * @uses do_action() Calls 'bbp_add_options'
+ */
+function bbp_add_options() {
+
+	// Add default options
+	foreach ( bbp_get_default_options() as $key => $value )
+		add_option( $key, $value );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bbp_add_options' );
+}
+
+/**
+ * Delete default options
+ *
+ * Hooked to bbp_uninstall, it is only called once when bbPress is uninstalled.
+ * This is destructive, so existing settings will be destroyed.
+ *
+ * @since bbPress (r3421)
+ * @uses bbp_get_default_options() To get default options
+ * @uses delete_option() Removes default options
+ * @uses do_action() Calls 'bbp_delete_options'
+ */
+function bbp_delete_options() {
+
+	// Add default options
+	foreach ( array_keys( bbp_get_default_options() ) as $key )
+		delete_option( $key );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bbp_delete_options' );
+}
+
+/**
+ * Add filters to each bbPress option and allow them to be overloaded from
+ * inside the $bbp->options array.
+ *
+ * @since bbPress (r3451)
+ * @uses bbp_get_default_options() To get default options
+ * @uses add_filter() To add filters to 'pre_option_{$key}'
+ * @uses do_action() Calls 'bbp_add_option_filters'
+ */
+function bbp_setup_option_filters() {
+
+	// Add filters to each bbPress option
+	foreach ( array_keys( bbp_get_default_options() ) as $key )
+		add_filter( 'pre_option_' . $key, 'bbp_pre_get_option' );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bbp_setup_option_filters' );
+}
+
+/**
+ * Filter default options and allow them to be overloaded from inside the
+ * $bbp->options array.
+ *
+ * @since bbPress (r3451)
+ * @param bool $value Optional. Default value false
+ * @return mixed false if not overloaded, mixed if set
+ */
+function bbp_pre_get_option( $value = '' ) {
+
+	// Remove the filter prefix
+	$option = str_replace( 'pre_option_', '', current_filter() );
+
+	// Check the options global for preset value
+	if ( isset( bbpress()->options[$option] ) )
+		$value = bbpress()->options[$option];
+
+	// Always return a value, even if false
+	return $value;
+}
+
+/** Active? *******************************************************************/
+
+/**
+ * Checks if favorites feature is enabled.
+ *
+ * @since bbPress (r2658)
+ * @param $default bool Optional.Default value true
+ * @uses get_option() To get the favorites option
+ * @return bool Is favorites enabled or not
+ */
+function bbp_is_favorites_active( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_is_favorites_active', (bool) get_option( '_bbp_enable_favorites', $default ) );
+}
+
+/**
+ * Checks if subscription feature is enabled.
+ *
+ * @since bbPress (r2658)
+ * @param $default bool Optional.Default value true
+ * @uses get_option() To get the subscriptions option
+ * @return bool Is subscription enabled or not
+ */
+function bbp_is_subscriptions_active( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_is_subscriptions_active', (bool) get_option( '_bbp_enable_subscriptions', $default ) );
+}
+
+/**
+ * Are topic tags allowed
+ *
+ * @since bbPress (r4097)
+ * @param $default bool Optional. Default value true
+ * @uses get_option() To get the allow tags
+ * @return bool Are tags allowed?
+ */
+function bbp_allow_topic_tags( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_allow_topic_tags', (bool) get_option( '_bbp_allow_topic_tags', $default ) );
+}
+
+/**
+ * Is forum-wide searching allowed
+ *
+ * @since bbPress (r4970)
+ * @param $default bool Optional. Default value true
+ * @uses get_option() To get the forum-wide search setting
+ * @return bool Is forum-wide searching allowed?
+ */
+function bbp_allow_search( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_allow_search', (bool) get_option( '_bbp_allow_search', $default ) );
+}
+
+/**
+ * Are replies threaded
+ *
+ * @since bbPress (r4944)
+ *
+ * @param bool $default Optional. Default value true
+ * @uses apply_filters() Calls 'bbp_thread_replies' with the calculated value and
+ *                        the thread replies depth
+ * @uses get_option() To get thread replies option
+ * @return bool Are replies threaded?
+ */
+function bbp_thread_replies() {
+	$depth  = bbp_thread_replies_depth();
+	$allow  = bbp_allow_threaded_replies();
+	$retval = (bool) ( ( $depth >= 2 ) && ( true === $allow ) );
+
+	return (bool) apply_filters( 'bbp_thread_replies', $retval, $depth, $allow );
+}
+
+/**
+ * Are threaded replies allowed
+ *
+ * @since bbPress (r4964)
+ * @param $default bool Optional. Default value false
+ * @uses get_option() To get the threaded replies setting
+ * @return bool Are threaded replies allowed?
+ */
+function bbp_allow_threaded_replies( $default = 0 ) {
+	return (bool) apply_filters( '_bbp_allow_threaded_replies', (bool) get_option( '_bbp_allow_threaded_replies', $default ) );
+}
+
+/**
+ * Maximum reply thread depth
+ *
+ * @since bbPress (r4944)
+ *
+ * @param int $default Thread replies depth
+ * @uses apply_filters() Calls 'bbp_thread_replies_depth' with the option value and
+ *                       the default depth
+ * @uses get_option() To get the thread replies depth
+ * @return int Thread replies depth
+ */
+function bbp_thread_replies_depth( $default = 2 ) {
+	return (int) apply_filters( 'bbp_thread_replies_depth', (int) get_option( '_bbp_thread_replies_depth', $default ) );
+}
+
+/**
+ * Are topic and reply revisions allowed
+ *
+ * @since bbPress (r3412)
+ * @param $default bool Optional. Default value true
+ * @uses get_option() To get the allow revisions
+ * @return bool Are revisions allowed?
+ */
+function bbp_allow_revisions( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_allow_revisions', (bool) get_option( '_bbp_allow_revisions', $default ) );
+}
+
+/**
+ * Is the anonymous posting allowed?
+ *
+ * @since bbPress (r2659)
+ * @param $default bool Optional. Default value
+ * @uses get_option() To get the allow anonymous option
+ * @return bool Is anonymous posting allowed?
+ */
+function bbp_allow_anonymous( $default = 0 ) {
+	return apply_filters( 'bbp_allow_anonymous', (bool) get_option( '_bbp_allow_anonymous', $default ) );
+}
+
+/**
+ * Is this forum available to all users on all sites in this installation?
+ *
+ * @since bbPress (r3378)
+ * @param $default bool Optional. Default value false
+ * @uses get_option() To get the global access option
+ * @return bool Is global access allowed?
+ */
+function bbp_allow_global_access( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_allow_global_access', (bool) get_option( '_bbp_allow_global_access', $default ) );
+}
+
+/**
+ * Is this forum available to all users on all sites in this installation?
+ *
+ * @since bbPress (r4294)
+ * @param $default string Optional. Default value empty
+ * @uses get_option() To get the default forums role option
+ * @return string The default forums user role
+ */
+function bbp_get_default_role( $default = 'bbp_participant' ) {
+	return apply_filters( 'bbp_get_default_role', get_option( '_bbp_default_role', $default ) );
+}
+
+/**
+ * Use the WordPress editor if available
+ *
+ * @since bbPress (r3386)
+ * @param $default bool Optional. Default value true
+ * @uses get_option() To get the WP editor option
+ * @return bool Use WP editor?
+ */
+function bbp_use_wp_editor( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_use_wp_editor', (bool) get_option( '_bbp_use_wp_editor', $default ) );
+}
+
+/**
+ * Use WordPress's oEmbed API
+ *
+ * @since bbPress (r3752)
+ * @param $default bool Optional. Default value true
+ * @uses get_option() To get the oEmbed option
+ * @return bool Use oEmbed?
+ */
+function bbp_use_autoembed( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_use_autoembed', (bool) get_option( '_bbp_use_autoembed', $default ) );
+}
+
+/**
+ * Get the current theme package ID
+ *
+ * @since bbPress (r3829)
+ * @param $default string Optional. Default value 'default'
+ * @uses get_option() To get the subtheme option
+ * @return string ID of the subtheme
+ */
+function bbp_get_theme_package_id( $default = 'default' ) {
+	return apply_filters( 'bbp_get_theme_package_id', get_option( '_bbp_theme_package_id', $default ) );
+}
+
+/**
+ * Output the maximum length of a title
+ *
+ * @since bbPress (r3246)
+ * @param $default bool Optional. Default value 80
+ */
+function bbp_title_max_length( $default = 80 ) {
+	echo bbp_get_title_max_length( $default );
+}
+	/**
+	 * Return the maximum length of a title
+	 *
+	 * @since bbPress (r3246)
+	 * @param $default bool Optional. Default value 80
+	 * @uses get_option() To get the maximum title length
+	 * @return int Is anonymous posting allowed?
+	 */
+	function bbp_get_title_max_length( $default = 80 ) {
+		return (int) apply_filters( 'bbp_get_title_max_length', (int) get_option( '_bbp_title_max_length', $default ) );
+	}
+
+/**
+ * Output the grop forums root parent forum id
+ *
+ * @since bbPress (r3575)
+ * @param $default int Optional. Default value
+ */
+function bbp_group_forums_root_id( $default = 0 ) {
+	echo bbp_get_group_forums_root_id( $default );
+}
+	/**
+	 * Return the grop forums root parent forum id
+	 *
+	 * @since bbPress (r3575)
+	 * @param $default bool Optional. Default value 0
+	 * @uses get_option() To get the root group forum ID
+	 * @return int The post ID for the root forum
+	 */
+	function bbp_get_group_forums_root_id( $default = 0 ) {
+		return (int) apply_filters( 'bbp_get_group_forums_root_id', (int) get_option( '_bbp_group_forums_root_id', $default ) );
+	}
+
+/**
+ * Checks if BuddyPress Group Forums are enabled
+ *
+ * @since bbPress (r3575)
+ * @param $default bool Optional. Default value true
+ * @uses get_option() To get the group forums option
+ * @return bool Is group forums enabled or not
+ */
+function bbp_is_group_forums_active( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_is_group_forums_active', (bool) get_option( '_bbp_enable_group_forums', $default ) );
+}
+
+/**
+ * Checks if Akismet is enabled
+ *
+ * @since bbPress (r3575)
+ * @param $default bool Optional. Default value true
+ * @uses get_option() To get the Akismet option
+ * @return bool Is Akismet enabled or not
+ */
+function bbp_is_akismet_active( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_is_akismet_active', (bool) get_option( '_bbp_enable_akismet', $default ) );
+}
+
+/**
+ * Integrate settings into existing WordPress pages
+ *
+ * @since bbPress (r4932)
+ * @param $default bool Optional. Default value false
+ * @uses get_option() To get the admin integration setting
+ * @return bool To deeply integrate settings, or not
+ */
+function bbp_settings_integration( $default = 0 ) {
+	return (bool) apply_filters( 'bbp_settings_integration', (bool) get_option( '_bbp_settings_integration', $default ) );
+}
+
+/** Slugs *********************************************************************/
+
+/**
+ * Return the root slug
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_root_slug( $default = 'forums' ) {
+	return apply_filters( 'bbp_get_root_slug', get_option( '_bbp_root_slug', $default ) );
+}
+
+/**
+ * Are we including the root slug in front of forum pages?
+ *
+ * @since bbPress (r3759)
+ * @return bool
+ */
+function bbp_include_root_slug( $default = 1 ) {
+	return (bool) apply_filters( 'bbp_include_root_slug', (bool) get_option( '_bbp_include_root', $default ) );
+}
+
+/**
+ * Return the search slug
+ *
+ * @since bbPress (r4932)
+ *
+ * @return string
+ */
+function bbp_show_on_root( $default = 'forums' ) {
+	return apply_filters( 'bbp_show_on_root', get_option( '_bbp_show_on_root', $default ) );
+}
+
+/**
+ * Maybe return the root slug, based on whether or not it's included in the url
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_maybe_get_root_slug() {
+	$retval = '';
+
+	if ( bbp_get_root_slug() && bbp_include_root_slug() )
+		$retval = trailingslashit( bbp_get_root_slug() );
+
+	return apply_filters( 'bbp_maybe_get_root_slug', $retval );
+}
+
+/**
+ * Return the single forum slug
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_forum_slug( $default = 'forum' ) {;
+	return apply_filters( 'bbp_get_root_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_forum_slug', $default ) );
+}
+
+/**
+ * Return the topic archive slug
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_topic_archive_slug( $default = 'topics' ) {
+	return apply_filters( 'bbp_get_topic_archive_slug', get_option( '_bbp_topic_archive_slug', $default ) );
+}
+
+/**
+ * Return the reply archive slug
+ *
+ * @since bbPress (r4925)
+ * @return string
+ */
+function bbp_get_reply_archive_slug( $default = 'replies' ) {
+	return apply_filters( 'bbp_get_reply_archive_slug', get_option( '_bbp_reply_archive_slug', $default ) );
+}
+
+/**
+ * Return the single topic slug
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_topic_slug( $default = 'topic' ) {
+	return apply_filters( 'bbp_get_topic_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_topic_slug', $default ) );
+}
+
+/**
+ * Return the topic-tag taxonomy slug
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_topic_tag_tax_slug( $default = 'topic-tag' ) {
+	return apply_filters( 'bbp_get_topic_tag_tax_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_topic_tag_slug', $default ) );
+}
+
+/**
+ * Return the single reply slug (used mostly for editing)
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_reply_slug( $default = 'reply' ) {
+	return apply_filters( 'bbp_get_reply_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_reply_slug', $default ) );
+}
+
+/**
+ * Return the single user slug
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_user_slug( $default = 'user' ) {
+	return apply_filters( 'bbp_get_user_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_user_slug', $default ) );
+}
+
+/**
+ * Return the single user favorites slug
+ *
+ * @since bbPress (r4187)
+ * @return string
+ */
+function bbp_get_user_favorites_slug( $default = 'favorites' ) {
+	return apply_filters( 'bbp_get_user_favorites_slug', get_option( '_bbp_user_favs_slug', $default ) );
+}
+
+/**
+ * Return the single user subscriptions slug
+ *
+ * @since bbPress (r4187)
+ * @return string
+ */
+function bbp_get_user_subscriptions_slug( $default = 'subscriptions' ) {
+	return apply_filters( 'bbp_get_user_subscriptions_slug', get_option( '_bbp_user_subs_slug', $default ) );
+}
+
+/**
+ * Return the topic view slug
+ *
+ * @since bbPress (r3759)
+ * @return string
+ */
+function bbp_get_view_slug( $default = 'view' ) {
+	return apply_filters( 'bbp_get_view_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_view_slug', $default ) );
+}
+
+/**
+ * Return the search slug
+ *
+ * @since bbPress (r4579)
+ *
+ * @return string
+ */
+function bbp_get_search_slug( $default = 'search' ) {
+	return apply_filters( 'bbp_get_search_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_search_slug', $default ) );
+}
+
+/** Legacy ********************************************************************/
+
+/**
+ * Checks if there is a previous BuddyPress Forum configuration
+ *
+ * @since bbPress (r3790)
+ * @param $default string Optional. Default empty string
+ * @uses get_option() To get the old bb-config.php location
+ * @return string The location of the bb-config.php file, if any
+ */
+function bbp_get_config_location( $default = '' ) {
+	return apply_filters( 'bbp_get_config_location', get_option( 'bb-config-location', $default ) );
+}
Index: /tags/2.5.4/includes/core/sub-actions.php
===================================================================
--- /tags/2.5.4/includes/core/sub-actions.php	(revision 5382)
+++ /tags/2.5.4/includes/core/sub-actions.php	(revision 5382)
@@ -0,0 +1,468 @@
+<?php
+
+/**
+ * Plugin Dependency
+ *
+ * The purpose of the following hooks is to mimic the behavior of something
+ * called 'plugin dependency' which enables a plugin to have plugins of their
+ * own in a safe and reliable way.
+ *
+ * We do this in bbPress by mirroring existing WordPress hookss in many places
+ * allowing dependant plugins to hook into the bbPress specific ones, thus
+ * guaranteeing proper code execution only when bbPress is active.
+ *
+ * The following functions are wrappers for hookss, allowing them to be
+ * manually called and/or piggy-backed on top of other hooks if needed.
+ *
+ * @todo use anonymous functions when PHP minimun requirement allows (5.3)
+ */
+
+/** Activation Actions ********************************************************/
+
+/**
+ * Runs on bbPress activation
+ *
+ * @since bbPress (r2509)
+ * @uses register_uninstall_hook() To register our own uninstall hook
+ * @uses do_action() Calls 'bbp_activation' hook
+ */
+function bbp_activation() {
+	do_action( 'bbp_activation' );
+}
+
+/**
+ * Runs on bbPress deactivation
+ *
+ * @since bbPress (r2509)
+ * @uses do_action() Calls 'bbp_deactivation' hook
+ */
+function bbp_deactivation() {
+	do_action( 'bbp_deactivation' );
+}
+
+/**
+ * Runs when uninstalling bbPress
+ *
+ * @since bbPress (r2509)
+ * @uses do_action() Calls 'bbp_uninstall' hook
+ */
+function bbp_uninstall() {
+	do_action( 'bbp_uninstall' );
+}
+
+/** Main Actions **************************************************************/
+
+/**
+ * Main action responsible for constants, globals, and includes
+ *
+ * @since bbPress (r2599)
+ * @uses do_action() Calls 'bbp_loaded'
+ */
+function bbp_loaded() {
+	do_action( 'bbp_loaded' );
+}
+
+/**
+ * Setup constants
+ *
+ * @since bbPress (r2599)
+ * @uses do_action() Calls 'bbp_constants'
+ */
+function bbp_constants() {
+	do_action( 'bbp_constants' );
+}
+
+/**
+ * Setup globals BEFORE includes
+ *
+ * @since bbPress (r2599)
+ * @uses do_action() Calls 'bbp_boot_strap_globals'
+ */
+function bbp_boot_strap_globals() {
+	do_action( 'bbp_boot_strap_globals' );
+}
+
+/**
+ * Include files
+ *
+ * @since bbPress (r2599)
+ * @uses do_action() Calls 'bbp_includes'
+ */
+function bbp_includes() {
+	do_action( 'bbp_includes' );
+}
+
+/**
+ * Setup globals AFTER includes
+ *
+ * @since bbPress (r2599)
+ * @uses do_action() Calls 'bbp_setup_globals'
+ */
+function bbp_setup_globals() {
+	do_action( 'bbp_setup_globals' );
+}
+
+/**
+ * Register any objects before anything is initialized
+ *
+ * @since bbPress (r4180)
+ * @uses do_action() Calls 'bbp_register'
+ */
+function bbp_register() {
+	do_action( 'bbp_register' );
+}
+
+/**
+ * Initialize any code after everything has been loaded
+ *
+ * @since bbPress (r2599)
+ * @uses do_action() Calls 'bbp_init'
+ */
+function bbp_init() {
+	do_action( 'bbp_init' );
+}
+
+/**
+ * Initialize widgets
+ *
+ * @since bbPress (r3389)
+ * @uses do_action() Calls 'bbp_widgets_init'
+ */
+function bbp_widgets_init() {
+	do_action( 'bbp_widgets_init' );
+}
+
+/**
+ * Setup the currently logged-in user
+ *
+ * @since bbPress (r2695)
+ * @uses did_action() To make sure the user isn't loaded out of order
+ * @uses do_action() Calls 'bbp_setup_current_user'
+ */
+function bbp_setup_current_user() {
+
+	// If the current user is being setup before the "init" action has fired,
+	// strange (and difficult to debug) role/capability issues will occur.
+	if ( ! did_action( 'after_setup_theme' ) ) {
+		_doing_it_wrong( __FUNCTION__, __( 'The current user is being initialized without using $wp->init().', 'bbpress' ), '2.3' );
+	}
+
+	do_action( 'bbp_setup_current_user' );
+}
+
+/** Supplemental Actions ******************************************************/
+
+/**
+ * Load translations for current language
+ *
+ * @since bbPress (r2599)
+ * @uses do_action() Calls 'bbp_load_textdomain'
+ */
+function bbp_load_textdomain() {
+	do_action( 'bbp_load_textdomain' );
+}
+
+/**
+ * Setup the post types
+ *
+ * @since bbPress (r2464)
+ * @uses do_action() Calls 'bbp_register_post_type'
+ */
+function bbp_register_post_types() {
+	do_action( 'bbp_register_post_types' );
+}
+
+/**
+ * Setup the post statuses
+ *
+ * @since bbPress (r2727)
+ * @uses do_action() Calls 'bbp_register_post_statuses'
+ */
+function bbp_register_post_statuses() {
+	do_action( 'bbp_register_post_statuses' );
+}
+
+/**
+ * Register the built in bbPress taxonomies
+ *
+ * @since bbPress (r2464)
+ * @uses do_action() Calls 'bbp_register_taxonomies'
+ */
+function bbp_register_taxonomies() {
+	do_action( 'bbp_register_taxonomies' );
+}
+
+/**
+ * Register the default bbPress views
+ *
+ * @since bbPress (r2789)
+ * @uses do_action() Calls 'bbp_register_views'
+ */
+function bbp_register_views() {
+	do_action( 'bbp_register_views' );
+}
+
+/**
+ * Register the default bbPress shortcodes
+ *
+ * @since bbPress (r4211)
+ * @uses do_action() Calls 'bbp_register_shortcodes'
+ */
+function bbp_register_shortcodes() {
+	do_action( 'bbp_register_shortcodes' );
+}
+
+/**
+ * Enqueue bbPress specific CSS and JS
+ *
+ * @since bbPress (r3373)
+ * @uses do_action() Calls 'bbp_enqueue_scripts'
+ */
+function bbp_enqueue_scripts() {
+	do_action( 'bbp_enqueue_scripts' );
+}
+
+/**
+ * Add the bbPress-specific rewrite tags
+ *
+ * @since bbPress (r2753)
+ * @uses do_action() Calls 'bbp_add_rewrite_tags'
+ */
+function bbp_add_rewrite_tags() {
+	do_action( 'bbp_add_rewrite_tags' );
+}
+
+/**
+ * Add the bbPress-specific rewrite rules
+ *
+ * @since bbPress (r4918)
+ * @uses do_action() Calls 'bbp_add_rewrite_rules'
+ */
+function bbp_add_rewrite_rules() {
+	do_action( 'bbp_add_rewrite_rules' );
+}
+
+/**
+ * Add the bbPress-specific permalink structures
+ *
+ * @since bbPress (r4918)
+ * @uses do_action() Calls 'bbp_add_permastructs'
+ */
+function bbp_add_permastructs() {
+	do_action( 'bbp_add_permastructs' );
+}
+
+/**
+ * Add the bbPress-specific login forum action
+ *
+ * @since bbPress (r2753)
+ * @uses do_action() Calls 'bbp_login_form_login'
+ */
+function bbp_login_form_login() {
+	do_action( 'bbp_login_form_login' );
+}
+
+/** User Actions **************************************************************/
+
+/**
+ * The main action for hooking into when a user account is updated
+ *
+ * @since bbPress (r4304)
+ *
+ * @param int $user_id ID of user being edited
+ * @param array $old_user_data The old, unmodified user data
+ * @uses do_action() Calls 'bbp_profile_update'
+ */
+function bbp_profile_update( $user_id = 0, $old_user_data = array() ) {
+	do_action( 'bbp_profile_update', $user_id, $old_user_data );
+}
+
+/**
+ * The main action for hooking into a user being registered
+ *
+ * @since bbPress (r4304)
+ * @param int $user_id ID of user being edited
+ * @uses do_action() Calls 'bbp_user_register'
+ */
+function bbp_user_register( $user_id = 0 ) {
+	do_action( 'bbp_user_register', $user_id );
+}
+
+/** Final Action **************************************************************/
+
+/**
+ * bbPress has loaded and initialized everything, and is okay to go
+ *
+ * @since bbPress (r2618)
+ * @uses do_action() Calls 'bbp_ready'
+ */
+function bbp_ready() {
+	do_action( 'bbp_ready' );
+}
+
+/** Theme Permissions *********************************************************/
+
+/**
+ * The main action used for redirecting bbPress theme actions that are not
+ * permitted by the current_user
+ *
+ * @since bbPress (r3605)
+ * @uses do_action()
+ */
+function bbp_template_redirect() {
+	do_action( 'bbp_template_redirect' );
+}
+
+/** Theme Helpers *************************************************************/
+
+/**
+ * The main action used for executing code before the theme has been setup
+ *
+ * @since bbPress (r3829)
+ * @uses do_action()
+ */
+function bbp_register_theme_packages() {
+	do_action( 'bbp_register_theme_packages' );
+}
+
+/**
+ * The main action used for executing code before the theme has been setup
+ *
+ * @since bbPress (r3732)
+ * @uses do_action()
+ */
+function bbp_setup_theme() {
+	do_action( 'bbp_setup_theme' );
+}
+
+/**
+ * The main action used for executing code after the theme has been setup
+ *
+ * @since bbPress (r3732)
+ * @uses do_action()
+ */
+function bbp_after_setup_theme() {
+	do_action( 'bbp_after_setup_theme' );
+}
+
+/**
+ * The main action used for handling theme-side POST requests
+ *
+ * @since bbPress (r4550)
+ * @uses do_action()
+ */
+function bbp_post_request() {
+
+	// Bail if not a POST action
+	if ( ! bbp_is_post_request() )
+		return;
+
+	// Bail if no action
+	if ( empty( $_POST['action'] ) )
+		return;
+
+	// This dynamic action is probably the one you want to use. It narrows down
+	// the scope of the 'action' without needing to check it in your function.
+	do_action( 'bbp_post_request_' . $_POST['action'] );
+
+	// Use this static action if you don't mind checking the 'action' yourself.
+	do_action( 'bbp_post_request',   $_POST['action'] );
+}
+
+/**
+ * The main action used for handling theme-side GET requests
+ *
+ * @since bbPress (r4550)
+ * @uses do_action()
+ */
+function bbp_get_request() {
+
+	// Bail if not a POST action
+	if ( ! bbp_is_get_request() )
+		return;
+
+	// Bail if no action
+	if ( empty( $_GET['action'] ) )
+		return;
+
+	// This dynamic action is probably the one you want to use. It narrows down
+	// the scope of the 'action' without needing to check it in your function.
+	do_action( 'bbp_get_request_' . $_GET['action'] );
+
+	// Use this static action if you don't mind checking the 'action' yourself.
+	do_action( 'bbp_get_request',   $_GET['action'] );
+}
+
+/** Filters *******************************************************************/
+
+/**
+ * Filter the plugin locale and domain.
+ *
+ * @since bbPress (r4213)
+ *
+ * @param string $locale
+ * @param string $domain
+ */
+function bbp_plugin_locale( $locale = '', $domain = '' ) {
+	return apply_filters( 'bbp_plugin_locale', $locale, $domain );
+}
+
+/**
+ * Piggy back filter for WordPress's 'request' filter
+ *
+ * @since bbPress (r3758)
+ * @param array $query_vars
+ * @return array
+ */
+function bbp_request( $query_vars = array() ) {
+	return apply_filters( 'bbp_request', $query_vars );
+}
+
+/**
+ * The main filter used for theme compatibility and displaying custom bbPress
+ * theme files.
+ *
+ * @since bbPress (r3311)
+ * @uses apply_filters()
+ * @param string $template
+ * @return string Template file to use
+ */
+function bbp_template_include( $template = '' ) {
+	return apply_filters( 'bbp_template_include', $template );
+}
+
+/**
+ * Generate bbPress-specific rewrite rules
+ *
+ * @since bbPress (r2688)
+ * @deprecated since bbPress (r4918)
+ * @param WP_Rewrite $wp_rewrite
+ * @uses do_action() Calls 'bbp_generate_rewrite_rules' with {@link WP_Rewrite}
+ */
+function bbp_generate_rewrite_rules( $wp_rewrite ) {
+	do_action_ref_array( 'bbp_generate_rewrite_rules', array( &$wp_rewrite ) );
+}
+
+/**
+ * Filter the allowed themes list for bbPress specific themes
+ *
+ * @since bbPress (r2944)
+ * @uses apply_filters() Calls 'bbp_allowed_themes' with the allowed themes list
+ */
+function bbp_allowed_themes( $themes ) {
+	return apply_filters( 'bbp_allowed_themes', $themes );
+}
+
+/**
+ * Maps forum/topic/reply caps to built in WordPress caps
+ *
+ * @since bbPress (r2593)
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ */
+function bbp_map_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+	return apply_filters( 'bbp_map_meta_caps', $caps, $cap, $user_id, $args );
+}
Index: /tags/2.5.4/includes/core/template-functions.php
===================================================================
--- /tags/2.5.4/includes/core/template-functions.php	(revision 5382)
+++ /tags/2.5.4/includes/core/template-functions.php	(revision 5382)
@@ -0,0 +1,679 @@
+<?php
+
+/**
+ * bbPress Template Functions
+ *
+ * This file contains functions necessary to mirror the WordPress core template
+ * loading process. Many of those functions are not filterable, and even then
+ * would not be robust enough to predict where bbPress templates might exist.
+ *
+ * @package bbPress
+ * @subpackage TemplateFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Adds bbPress theme support to any active WordPress theme
+ *
+ * @since bbPress (r3032)
+ *
+ * @param string $slug
+ * @param string $name Optional. Default null
+ * @uses bbp_locate_template()
+ * @uses load_template()
+ * @uses get_template_part()
+ */
+function bbp_get_template_part( $slug, $name = null ) {
+
+	// Execute code for this part
+	do_action( 'get_template_part_' . $slug, $slug, $name );
+
+	// Setup possible parts
+	$templates = array();
+	if ( isset( $name ) )
+		$templates[] = $slug . '-' . $name . '.php';
+	$templates[] = $slug . '.php';
+
+	// Allow template parst to be filtered
+	$templates = apply_filters( 'bbp_get_template_part', $templates, $slug, $name );
+
+	// Return the part that is found
+	return bbp_locate_template( $templates, true, false );
+}
+
+/**
+ * Retrieve the name of the highest priority template file that exists.
+ *
+ * Searches in the child theme before parent theme so that themes which
+ * inherit from a parent theme can just overload one file. If the template is
+ * not found in either of those, it looks in the theme-compat folder last.
+ *
+ * @since bbPress (r3618)
+ *
+ * @param string|array $template_names Template file(s) to search for, in order.
+ * @param bool $load If true the template file will be loaded if it is found.
+ * @param bool $require_once Whether to require_once or require. Default true.
+ *                            Has no effect if $load is false.
+ * @return string The template filename if one is located.
+ */
+function bbp_locate_template( $template_names, $load = false, $require_once = true ) {
+
+	// No file found yet
+	$located            = false;
+	$template_locations = bbp_get_template_stack();
+
+	// Try to find a template file
+	foreach ( (array) $template_names as $template_name ) {
+
+		// Continue if template is empty
+		if ( empty( $template_name ) ) {
+			continue;
+		}
+
+		// Trim off any slashes from the template name
+		$template_name  = ltrim( $template_name, '/' );
+
+		// Loop through template stack
+		foreach ( (array) $template_locations as $template_location ) {
+
+			// Continue if $template_location is empty
+			if ( empty( $template_location ) ) {
+				continue;
+			}
+
+			// Check child theme first
+			if ( file_exists( trailingslashit( $template_location ) . $template_name ) ) {
+				$located = trailingslashit( $template_location ) . $template_name;
+				break 2;
+			}
+		}
+	}
+
+	/**
+	 * This action exists only to follow the standard bbPress coding convention,
+	 * and should not be used to short-circuit any part of the template locator.
+	 *
+	 * If you want to override a specific template part, please either filter
+	 * 'bbp_get_template_part' or add a new location to the template stack.
+	 */
+	do_action( 'bbp_locate_template', $located, $template_name, $template_names, $template_locations, $load, $require_once );
+
+	// Maybe load the template if one was located
+	if ( ( true === $load ) && !empty( $located ) ) {
+		load_template( $located, $require_once );
+	}
+
+	return $located;
+}
+
+/**
+ * Enqueue a script from the highest priority location in the template stack.
+ *
+ * Registers the style if file provided (does NOT overwrite) and enqueues.
+ *
+ * @since bbPress (r5180)
+ *
+ * @param string      $handle Name of the stylesheet.
+ * @param string|bool $file   Relative path to stylesheet. Example: '/css/mystyle.css'.
+ * @param array       $deps   An array of registered style handles this stylesheet depends on. Default empty array.
+ * @param string|bool $ver    String specifying the stylesheet version number, if it has one. This parameter is used
+ *                            to ensure that the correct version is sent to the client regardless of caching, and so
+ *                            should be included if a version number is available and makes sense for the stylesheet.
+ * @param string      $media  Optional. The media for which this stylesheet has been defined.
+ *                            Default 'all'. Accepts 'all', 'aural', 'braille', 'handheld', 'projection', 'print',
+ *                            'screen', 'tty', or 'tv'.
+ *
+ * @return string The style filename if one is located.
+ */
+function bbp_enqueue_style( $handle = '', $file = '', $dependencies = array(), $version = false, $media = 'all' ) {
+
+	// No file found yet
+	$located = false;
+
+	// Trim off any slashes from the template name
+	$file = ltrim( $file, '/' );
+
+	// Make sure there is always a version
+	if ( empty( $version ) ) {
+		$version = bbp_get_version();
+	}
+
+	// Loop through template stack
+	foreach ( (array) bbp_get_template_stack() as $template_location ) {
+
+		// Continue if $template_location is empty
+		if ( empty( $template_location ) ) {
+			continue;
+		}
+
+		// Check child theme first
+		if ( file_exists( trailingslashit( $template_location ) . $file ) ) {
+			$located = trailingslashit( $template_location ) . $file;
+			break;
+		}
+	}
+
+	// Enqueue if located
+	if ( !empty( $located ) ) {
+
+		$content_dir = constant( 'WP_CONTENT_DIR' );
+ 
+		// IIS (Windows) here
+		// Replace back slashes with forward slash
+		if ( strpos( $located, '\\' ) !== false ) {
+			$located     = str_replace( '\\', '/', $located     );
+			$content_dir = str_replace( '\\', '/', $content_dir );
+		}
+
+ 		// Make path to file relative to site URL
+		$located = str_replace( $content_dir, content_url(), $located );
+
+		// Enqueue the style
+		wp_enqueue_style( $handle, $located, $dependencies, $version, $media );
+	}
+
+	return $located;
+}
+
+/**
+ * Enqueue a script from the highest priority location in the template stack.
+ *
+ * Registers the style if file provided (does NOT overwrite) and enqueues.
+ *
+ * @since bbPress (r5180)
+ *
+ * @param string      $handle    Name of the script.
+ * @param string|bool $file      Relative path to the script. Example: '/js/myscript.js'.
+ * @param array       $deps      An array of registered handles this script depends on. Default empty array.
+ * @param string|bool $ver       Optional. String specifying the script version number, if it has one. This parameter
+ *                               is used to ensure that the correct version is sent to the client regardless of caching,
+ *                               and so should be included if a version number is available and makes sense for the script.
+ * @param bool        $in_footer Optional. Whether to enqueue the script before </head> or before </body>.
+ *                               Default 'false'. Accepts 'false' or 'true'.
+ *
+ * @return string The script filename if one is located.
+ */
+function bbp_enqueue_script( $handle = '', $file = '', $dependencies = array(), $version = false, $in_footer = 'all' ) {
+
+	// No file found yet
+	$located = false;
+
+	// Trim off any slashes from the template name
+	$file = ltrim( $file, '/' );
+
+	// Make sure there is always a version
+	if ( empty( $version ) ) {
+		$version = bbp_get_version();
+	}
+
+	// Loop through template stack
+	foreach ( (array) bbp_get_template_stack() as $template_location ) {
+
+		// Continue if $template_location is empty
+		if ( empty( $template_location ) ) {
+			continue;
+		}
+
+		// Check child theme first
+		if ( file_exists( trailingslashit( $template_location ) . $file ) ) {
+			$located = trailingslashit( $template_location ) . $file;
+			break;
+		}
+	}
+
+	// Enqueue if located
+	if ( !empty( $located ) ) {
+
+		$content_dir = constant( 'WP_CONTENT_DIR' );
+ 
+		// IIS (Windows) here
+		// Replace back slashes with forward slash
+		if ( strpos( $located, '\\' ) !== false ) {
+			$located     = str_replace( '\\', '/', $located     );
+			$content_dir = str_replace( '\\', '/', $content_dir );
+		}
+
+ 		// Make path to file relative to site URL
+		$located = str_replace( $content_dir, content_url(), $located );
+
+		// Enqueue the style
+		wp_enqueue_script( $handle, $located, $dependencies, $version, $in_footer );
+	}
+
+	return $located;
+}
+
+/**
+ * This is really cool. This function registers a new template stack location,
+ * using WordPress's built in filters API.
+ *
+ * This allows for templates to live in places beyond just the parent/child
+ * relationship, to allow for custom template locations. Used in conjunction
+ * with bbp_locate_template(), this allows for easy template overrides.
+ *
+ * @since bbPress (r4323)
+ *
+ * @param string $location Callback function that returns the
+ * @param int $priority
+ */
+function bbp_register_template_stack( $location_callback = '', $priority = 10 ) {
+
+	// Bail if no location, or function does not exist
+	if ( empty( $location_callback ) || ! function_exists( $location_callback ) )
+		return false;
+
+	// Add location callback to template stack
+	return add_filter( 'bbp_template_stack', $location_callback, (int) $priority );
+}
+
+/**
+ * Deregisters a previously registered template stack location.
+ *
+ * @since bbPress (r4652)
+ *
+ * @param string $location Callback function that returns the
+ * @param int $priority
+ * @see bbp_register_template_stack()
+ */
+function bbp_deregister_template_stack( $location_callback = '', $priority = 10 ) {
+
+	// Bail if no location, or function does not exist
+	if ( empty( $location_callback ) || ! function_exists( $location_callback ) )
+		return false;
+
+	// Remove location callback to template stack
+	return remove_filter( 'bbp_template_stack', $location_callback, (int) $priority );
+}
+
+/**
+ * Call the functions added to the 'bbp_template_stack' filter hook, and return
+ * an array of the template locations.
+ *
+ * @see bbp_register_template_stack()
+ *
+ * @since bbPress (r4323)
+ *
+ * @global array $wp_filter Stores all of the filters
+ * @global array $merged_filters Merges the filter hooks using this function.
+ * @global array $wp_current_filter stores the list of current filters with the current one last
+ *
+ * @return array The filtered value after all hooked functions are applied to it.
+ */
+function bbp_get_template_stack() {
+	global $wp_filter, $merged_filters, $wp_current_filter;
+
+	// Setup some default variables
+	$tag  = 'bbp_template_stack';
+	$args = $stack = array();
+
+	// Add 'bbp_template_stack' to the current filter array
+	$wp_current_filter[] = $tag;
+
+	// Sort
+	if ( ! isset( $merged_filters[ $tag ] ) ) {
+		ksort( $wp_filter[$tag] );
+		$merged_filters[ $tag ] = true;
+	}
+
+	// Ensure we're always at the beginning of the filter array
+	reset( $wp_filter[ $tag ] );
+
+	// Loop through 'bbp_template_stack' filters, and call callback functions
+	do {
+		foreach ( (array) current( $wp_filter[$tag] ) as $the_ ) {
+			if ( ! is_null( $the_['function'] ) ) {
+				$args[1] = $stack;
+				$stack[] = call_user_func_array( $the_['function'], array_slice( $args, 1, (int) $the_['accepted_args'] ) );
+			}
+		}
+	} while ( next( $wp_filter[$tag] ) !== false );
+
+	// Remove 'bbp_template_stack' from the current filter array
+	array_pop( $wp_current_filter );
+
+	// Remove empties and duplicates
+	$stack = array_unique( array_filter( $stack ) );
+
+	return (array) apply_filters( 'bbp_get_template_stack', $stack ) ;
+}
+
+/**
+ * Get a template part in an output buffer, and return it
+ *
+ * @since bbPress (r5043)
+ *
+ * @param string $slug
+ * @param string $name
+ * @return string
+ */
+function bbp_buffer_template_part( $slug, $name = null, $echo = true ) {
+	ob_start();
+
+	bbp_get_template_part( $slug, $name );
+
+	// Get the output buffer contents
+	$output = ob_get_clean();
+
+	// Echo or return the output buffer contents
+	if ( true === $echo ) {
+		echo $output;
+	} else {
+		return $output;
+	}
+}
+
+/**
+ * Retrieve path to a template
+ *
+ * Used to quickly retrieve the path of a template without including the file
+ * extension. It will also check the parent theme and theme-compat theme with
+ * the use of {@link bbp_locate_template()}. Allows for more generic template
+ * locations without the use of the other get_*_template() functions.
+ *
+ * @since bbPress (r3629)
+ *
+ * @param string $type Filename without extension.
+ * @param array $templates An optional list of template candidates
+ * @uses bbp_set_theme_compat_templates()
+ * @uses bbp_locate_template()
+ * @uses bbp_set_theme_compat_template()
+ * @return string Full path to file.
+ */
+function bbp_get_query_template( $type, $templates = array() ) {
+	$type = preg_replace( '|[^a-z0-9-]+|', '', $type );
+
+	if ( empty( $templates ) )
+		$templates = array( "{$type}.php" );
+
+	// Filter possible templates, try to match one, and set any bbPress theme
+	// compat properties so they can be cross-checked later.
+	$templates = apply_filters( "bbp_get_{$type}_template", $templates );
+	$templates = bbp_set_theme_compat_templates( $templates );
+	$template  = bbp_locate_template( $templates );
+	$template  = bbp_set_theme_compat_template( $template );
+
+	return apply_filters( "bbp_{$type}_template", $template );
+}
+
+/**
+ * Get the possible subdirectories to check for templates in
+ *
+ * @since bbPress (r3738)
+ * @param array $templates Templates we are looking for
+ * @return array Possible subfolders to look in
+ */
+function bbp_get_template_locations( $templates = array() ) {
+	$locations = array(
+		'bbpress',
+		'forums',
+		''
+	);
+	return apply_filters( 'bbp_get_template_locations', $locations, $templates );
+}
+
+/**
+ * Add template locations to template files being searched for
+ *
+ * @since bbPress (r3738)
+ *
+ * @param array $templates
+ * @return array()
+ */
+function bbp_add_template_stack_locations( $stacks = array() ) {
+	$retval = array();
+
+	// Get alternate locations
+	$locations = bbp_get_template_locations();
+
+	// Loop through locations and stacks and combine
+	foreach ( (array) $stacks as $stack )
+		foreach ( (array) $locations as $custom_location )
+			$retval[] = untrailingslashit( trailingslashit( $stack ) . $custom_location );
+
+	return apply_filters( 'bbp_add_template_stack_locations', array_unique( $retval ), $stacks );
+}
+
+/**
+ * Add checks for bbPress conditions to parse_query action
+ *
+ * If it's a user page, WP_Query::bbp_is_single_user is set to true.
+ * If it's a user edit page, WP_Query::bbp_is_single_user_edit is set to true
+ * and the the 'wp-admin/includes/user.php' file is included.
+ * In addition, on user/user edit pages, WP_Query::home is set to false & query
+ * vars 'bbp_user_id' with the displayed user id and 'author_name' with the
+ * displayed user's nicename are added.
+ *
+ * If it's a forum edit, WP_Query::bbp_is_forum_edit is set to true
+ * If it's a topic edit, WP_Query::bbp_is_topic_edit is set to true
+ * If it's a reply edit, WP_Query::bbp_is_reply_edit is set to true.
+ *
+ * If it's a view page, WP_Query::bbp_is_view is set to true
+ * If it's a search page, WP_Query::bbp_is_search is set to true
+ *
+ * @since bbPress (r2688)
+ *
+ * @param WP_Query $posts_query
+ *
+ * @uses get_query_var() To get {@link WP_Query} query var
+ * @uses is_email() To check if the string is an email
+ * @uses get_user_by() To try to get the user by email and nicename
+ * @uses get_userdata() to get the user data
+ * @uses current_user_can() To check if the current user can edit the user
+ * @uses is_user_member_of_blog() To check if user profile page exists
+ * @uses WP_Query::set_404() To set a 404 status
+ * @uses apply_filters() Calls 'enable_edit_any_user_configuration' with true
+ * @uses bbp_get_view_query_args() To get the view query args
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses remove_action() To remove the auto save post revision action
+ */
+function bbp_parse_query( $posts_query ) {
+
+	// Bail if $posts_query is not the main loop
+	if ( ! $posts_query->is_main_query() )
+		return;
+
+	// Bail if filters are suppressed on this query
+	if ( true === $posts_query->get( 'suppress_filters' ) )
+		return;
+
+	// Bail if in admin
+	if ( is_admin() )
+		return;
+
+	// Get query variables
+	$bbp_view = $posts_query->get( bbp_get_view_rewrite_id() );
+	$bbp_user = $posts_query->get( bbp_get_user_rewrite_id() );
+	$is_edit  = $posts_query->get( bbp_get_edit_rewrite_id() );
+
+	// It is a user page - We'll also check if it is user edit
+	if ( !empty( $bbp_user ) ) {
+
+		/** Find User *********************************************************/
+
+		// Setup the default user variable
+		$the_user = false;
+
+		// If using pretty permalinks, use the email or slug
+		if ( get_option( 'permalink_structure' ) ) {
+
+			// Email was passed
+			if ( is_email( $bbp_user ) ) {
+				$the_user = get_user_by( 'email', $bbp_user );
+
+			// Try nicename
+			} else {
+				$the_user = get_user_by( 'slug', $bbp_user );
+			}
+		}
+
+		// No user found by slug/email, so try the ID if it's numeric
+		if ( empty( $the_user ) && is_numeric( $bbp_user ) ) {
+			$the_user = get_user_by( 'id', $bbp_user );
+		}
+
+		// 404 and bail if user does not have a profile
+		if ( empty( $the_user->ID ) || ! bbp_user_has_profile( $the_user->ID ) ) {
+			$posts_query->set_404();
+			return;
+		}
+
+		/** User Exists *******************************************************/
+
+		$is_favs    = $posts_query->get( bbp_get_user_favorites_rewrite_id()     );
+		$is_subs    = $posts_query->get( bbp_get_user_subscriptions_rewrite_id() );
+		$is_topics  = $posts_query->get( bbp_get_user_topics_rewrite_id()        );
+		$is_replies = $posts_query->get( bbp_get_user_replies_rewrite_id()       );
+
+		// View or edit?
+		if ( !empty( $is_edit ) ) {
+
+			// We are editing a profile
+			$posts_query->bbp_is_single_user_edit = true;
+
+			// Load the core WordPress contact methods
+			if ( !function_exists( '_wp_get_user_contactmethods' ) ) {
+				include_once( ABSPATH . 'wp-includes/registration.php' );
+			}
+
+			// Load the edit_user functions
+			if ( !function_exists( 'edit_user' ) ) {
+				require_once( ABSPATH . 'wp-admin/includes/user.php' );
+			}
+
+			// Load the grant/revoke super admin functions
+			if ( is_multisite() && !function_exists( 'revoke_super_admin' ) ) {
+				require_once( ABSPATH . 'wp-admin/includes/ms.php' );
+			}
+
+			// Editing a user
+			$posts_query->bbp_is_edit = true;
+
+		// User favorites
+		} elseif ( ! empty( $is_favs ) ) {
+			$posts_query->bbp_is_single_user_favs = true;
+
+		// User subscriptions
+		} elseif ( ! empty( $is_subs ) ) {
+			$posts_query->bbp_is_single_user_subs = true;
+
+		// User topics
+		} elseif ( ! empty( $is_topics ) ) {
+			$posts_query->bbp_is_single_user_topics = true;
+
+		// User topics
+		} elseif ( ! empty( $is_replies ) ) {
+			$posts_query->bbp_is_single_user_replies = true;
+
+		// User profile
+		} else {
+			$posts_query->bbp_is_single_user_profile = true;
+		}
+
+		// Looking at a single user
+		$posts_query->bbp_is_single_user = true;
+
+		// Make sure 404 is not set
+		$posts_query->is_404  = false;
+
+		// Correct is_home variable
+		$posts_query->is_home = false;
+
+		// User is looking at their own profile
+		if ( get_current_user_id() === $the_user->ID ) {
+			$posts_query->bbp_is_single_user_home = true;
+		}
+
+		// Set bbp_user_id for future reference
+		$posts_query->set( 'bbp_user_id', $the_user->ID );
+
+		// Set author_name as current user's nicename to get correct posts
+		$posts_query->set( 'author_name', $the_user->user_nicename );
+
+		// Set the displayed user global to this user
+		bbpress()->displayed_user = $the_user;
+
+	// View Page
+	} elseif ( !empty( $bbp_view ) ) {
+
+		// Check if the view exists by checking if there are query args are set
+		$view_args = bbp_get_view_query_args( $bbp_view );
+
+		// Bail if view args is false (view isn't registered)
+		if ( false === $view_args ) {
+			$posts_query->set_404();
+			return;
+		}
+
+		// Correct is_home variable
+		$posts_query->is_home     = false;
+
+		// We are in a custom topic view
+		$posts_query->bbp_is_view = true;
+
+	// Search Page
+	} elseif ( isset( $posts_query->query_vars[ bbp_get_search_rewrite_id() ] ) ) {
+
+		// Check if there are search query args set
+		$search_terms = bbp_get_search_terms();
+		if ( !empty( $search_terms ) )
+			$posts_query->bbp_search_terms = $search_terms;
+
+		// Correct is_home variable
+		$posts_query->is_home = false;
+
+		// We are in a search query
+		$posts_query->bbp_is_search = true;
+
+	// Forum/Topic/Reply Edit Page
+	} elseif ( !empty( $is_edit ) ) {
+
+		// Get the post type from the main query loop
+		$post_type = $posts_query->get( 'post_type' );
+
+		// Check which post_type we are editing, if any
+		if ( !empty( $post_type ) ) {
+			switch( $post_type ) {
+
+				// We are editing a forum
+				case bbp_get_forum_post_type() :
+					$posts_query->bbp_is_forum_edit = true;
+					$posts_query->bbp_is_edit       = true;
+					break;
+
+				// We are editing a topic
+				case bbp_get_topic_post_type() :
+					$posts_query->bbp_is_topic_edit = true;
+					$posts_query->bbp_is_edit       = true;
+					break;
+
+				// We are editing a reply
+				case bbp_get_reply_post_type() :
+					$posts_query->bbp_is_reply_edit = true;
+					$posts_query->bbp_is_edit       = true;
+					break;
+			}
+
+		// We are editing a topic tag
+		} elseif ( bbp_is_topic_tag() ) {
+			$posts_query->bbp_is_topic_tag_edit = true;
+			$posts_query->bbp_is_edit           = true;
+		}
+
+		// We save post revisions on our own
+		remove_action( 'pre_post_update', 'wp_save_post_revision' );
+
+	// Topic tag page
+	} elseif ( bbp_is_topic_tag() ) {
+		$posts_query->set( 'bbp_topic_tag',  get_query_var( 'term' )   );
+		$posts_query->set( 'post_type',      bbp_get_topic_post_type() );
+		$posts_query->set( 'posts_per_page', bbp_get_topics_per_page() );
+
+	// Do topics on forums root
+	} elseif ( is_post_type_archive( array( bbp_get_forum_post_type(), bbp_get_topic_post_type() ) ) && ( 'topics' === bbp_show_on_root() ) ) {
+		$posts_query->bbp_show_topics_on_root = true;
+	}
+}
Index: /tags/2.5.4/includes/core/template-loader.php
===================================================================
--- /tags/2.5.4/includes/core/template-loader.php	(revision 5382)
+++ /tags/2.5.4/includes/core/template-loader.php	(revision 5382)
@@ -0,0 +1,529 @@
+<?php
+
+/**
+ * bbPress Template Loader
+ *
+ * @package bbPress
+ * @subpackage TemplateLoader
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Possibly intercept the template being loaded
+ *
+ * Listens to the 'template_include' filter and waits for any bbPress specific
+ * template condition to be met. If one is met and the template file exists,
+ * it will be used; otherwise 
+ *
+ * Note that the _edit() checks are ahead of their counterparts, to prevent them
+ * from being stomped on accident.
+ *
+ * @since bbPress (r3032)
+ *
+ * @param string $template
+ *
+ * @uses bbp_is_single_user() To check if page is single user
+ * @uses bbp_get_single_user_template() To get user template
+ * @uses bbp_is_single_user_edit() To check if page is single user edit
+ * @uses bbp_get_single_user_edit_template() To get user edit template
+ * @uses bbp_is_single_view() To check if page is single view
+ * @uses bbp_get_single_view_template() To get view template
+ * @uses bbp_is_search() To check if page is search
+ * @uses bbp_get_search_template() To get search template
+ * @uses bbp_is_forum_edit() To check if page is forum edit
+ * @uses bbp_get_forum_edit_template() To get forum edit template
+ * @uses bbp_is_topic_merge() To check if page is topic merge
+ * @uses bbp_get_topic_merge_template() To get topic merge template
+ * @uses bbp_is_topic_split() To check if page is topic split
+ * @uses bbp_get_topic_split_template() To get topic split template
+ * @uses bbp_is_topic_edit() To check if page is topic edit
+ * @uses bbp_get_topic_edit_template() To get topic edit template
+ * @uses bbp_is_reply_move() To check if page is reply move
+ * @uses bbp_get_reply_move_template() To get reply move template
+ * @uses bbp_is_reply_edit() To check if page is reply edit
+ * @uses bbp_get_reply_edit_template() To get reply edit template
+ * @uses bbp_set_theme_compat_template() To set the global theme compat template
+ *
+ * @return string The path to the template file that is being used
+ */
+function bbp_template_include_theme_supports( $template = '' ) {
+
+	// Editing a user
+	if     ( bbp_is_single_user_edit() && ( $new_template = bbp_get_single_user_edit_template() ) ) :
+
+	// User favorites
+	elseif ( bbp_is_favorites()        && ( $new_template = bbp_get_favorites_template()        ) ) :
+
+	// User favorites
+	elseif ( bbp_is_subscriptions()    && ( $new_template = bbp_get_subscriptions_template()    ) ) :
+
+	// Viewing a user
+	elseif ( bbp_is_single_user()      && ( $new_template = bbp_get_single_user_template()      ) ) :
+
+	// Single View
+	elseif ( bbp_is_single_view()      && ( $new_template = bbp_get_single_view_template()      ) ) :
+
+	// Search
+	elseif ( bbp_is_search()           && ( $new_template = bbp_get_search_template()           ) ) :
+
+	// Forum edit
+	elseif ( bbp_is_forum_edit()       && ( $new_template = bbp_get_forum_edit_template()       ) ) :
+
+	// Single Forum
+	elseif ( bbp_is_single_forum()     && ( $new_template = bbp_get_single_forum_template()     ) ) :
+
+	// Forum Archive
+	elseif ( bbp_is_forum_archive()    && ( $new_template = bbp_get_forum_archive_template()    ) ) :
+
+	// Topic merge
+	elseif ( bbp_is_topic_merge()      && ( $new_template = bbp_get_topic_merge_template()      ) ) :
+
+	// Topic split
+	elseif ( bbp_is_topic_split()      && ( $new_template = bbp_get_topic_split_template()      ) ) :
+
+	// Topic edit
+	elseif ( bbp_is_topic_edit()       && ( $new_template = bbp_get_topic_edit_template()       ) ) :
+
+	// Single Topic
+	elseif ( bbp_is_single_topic()     && ( $new_template = bbp_get_single_topic_template()     ) ) :
+
+	// Topic Archive
+	elseif ( bbp_is_topic_archive()    && ( $new_template = bbp_get_topic_archive_template()    ) ) :
+
+	// Reply move
+	elseif ( bbp_is_reply_move()       && ( $new_template = bbp_get_reply_move_template()       ) ) :
+
+	// Editing a reply
+	elseif ( bbp_is_reply_edit()       && ( $new_template = bbp_get_reply_edit_template()       ) ) :
+
+	// Single Reply
+	elseif ( bbp_is_single_reply()     && ( $new_template = bbp_get_single_reply_template()     ) ) :
+
+	// Editing a topic tag
+	elseif ( bbp_is_topic_tag_edit()   && ( $new_template = bbp_get_topic_tag_edit_template()   ) ) :
+
+	// Viewing a topic tag
+	elseif ( bbp_is_topic_tag()        && ( $new_template = bbp_get_topic_tag_template()        ) ) :
+	endif;
+
+	// A bbPress template file was located, so override the WordPress template
+	// and use it to switch off bbPress's theme compatibility.
+	if ( !empty( $new_template ) ) {
+		$template = bbp_set_template_included( $new_template );
+	}
+
+	return apply_filters( 'bbp_template_include_theme_supports', $template );
+}
+
+/**
+ * Set the included template
+ *
+ * @since bbPress (r4975)
+ * @param mixed $template Default false
+ * @return mixed False if empty. Template name if template included
+ */
+function bbp_set_template_included( $template = false ) {
+	bbpress()->theme_compat->bbpress_template = $template;
+
+	return bbpress()->theme_compat->bbpress_template;
+}
+
+/**
+ * Is a bbPress template being included?
+ *
+ * @since bbPress (r4975)
+ * @return bool True if yes, false if no
+ */
+function bbp_is_template_included() {
+	return ! empty( bbpress()->theme_compat->bbpress_template );
+}
+
+/** Custom Functions **********************************************************/
+
+/**
+ * Attempt to load a custom bbPress functions file, similar to each themes
+ * functions.php file.
+ *
+ * @since bbPress (r3732)
+ *
+ * @global string $pagenow
+ * @uses bbp_locate_template()
+ */
+function bbp_load_theme_functions() {
+	global $pagenow;
+
+	// If bbPress is being deactivated, do not load any more files
+	if ( bbp_is_deactivation() )
+		return;
+
+	if ( ! defined( 'WP_INSTALLING' ) || ( !empty( $pagenow ) && ( 'wp-activate.php' !== $pagenow ) ) ) {
+		bbp_locate_template( 'bbpress-functions.php', true );
+	}
+}
+
+/** Individual Templates ******************************************************/
+
+/**
+ * Get the user profile template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_single_user_template() {
+	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
+	$user_id   = bbp_get_displayed_user_id();
+	$templates = array(
+		'single-user-' . $nicename . '.php', // Single User nicename
+		'single-user-' . $user_id  . '.php', // Single User ID
+		'single-user.php',                   // Single User
+		'user.php',                          // User
+	);
+	return bbp_get_query_template( 'profile', $templates );
+}
+
+/**
+ * Get the user profile edit template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_single_user_edit_template() {
+	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
+	$user_id   = bbp_get_displayed_user_id();
+	$templates = array(
+		'single-user-edit-' . $nicename . '.php', // Single User Edit nicename
+		'single-user-edit-' . $user_id  . '.php', // Single User Edit ID
+		'single-user-edit.php',                   // Single User Edit
+		'user-edit.php',                          // User Edit
+		'user.php',                               // User
+	);
+	return bbp_get_query_template( 'profile_edit', $templates );
+}
+
+/**
+ * Get the user favorites template
+ *
+ * @since bbPress (r4225)
+ *
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_favorites_template() {
+	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
+	$user_id   = bbp_get_displayed_user_id();
+	$templates = array(
+		'single-user-favorites-' . $nicename . '.php', // Single User Favs nicename
+		'single-user-favorites-' . $user_id  . '.php', // Single User Favs ID
+		'favorites-' . $nicename  . '.php',            // Favorites nicename
+		'favorites-' . $user_id   . '.php',            // Favorites ID
+		'favorites.php',                               // Favorites
+		'user.php',                                    // User
+	);
+	return bbp_get_query_template( 'favorites', $templates );
+}
+
+/**
+ * Get the user subscriptions template
+ *
+ * @since bbPress (r4225)
+ *
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_subscriptions_template() {
+	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
+	$user_id   = bbp_get_displayed_user_id();
+	$templates = array(
+		'single-user-subscriptions-' . $nicename . '.php', // Single User Subs nicename
+		'single-user-subscriptions-' . $user_id  . '.php', // Single User Subs ID
+		'subscriptions-' . $nicename  . '.php',            // Subscriptions nicename
+		'subscriptions-' . $user_id   . '.php',            // Subscriptions ID
+		'subscriptions.php',                               // Subscriptions
+		'user.php',                                        // User
+	);
+	return bbp_get_query_template( 'subscriptions', $templates );
+}
+
+/**
+ * Get the view template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_view_id()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_single_view_template() {
+	$view_id   = bbp_get_view_id();
+	$templates = array(
+		'single-view-' . $view_id . '.php', // Single View ID
+		'view-'        . $view_id . '.php', // View ID
+		'single-view.php',                  // Single View
+		'view.php',                         // View
+	);
+	return bbp_get_query_template( 'single_view', $templates );
+}
+
+/**
+ * Get the search template
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_search_template() {
+	$templates = array(
+		'page-forum-search.php', // Single Search
+		'forum-search.php',      // Search
+	);
+	return bbp_get_query_template( 'single_search', $templates );
+}
+
+/**
+ * Get the single forum template
+ *
+ * @since bbPress (r3922)
+ *
+ * @uses bbp_get_forum_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_single_forum_template() {
+	$templates = array(
+		'single-' . bbp_get_forum_post_type() . '.php' // Single Forum
+	);
+	return bbp_get_query_template( 'single_forum', $templates );
+}
+
+/**
+ * Get the forum archive template
+ *
+ * @since bbPress (r3922)
+ *
+ * @uses bbp_get_forum_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_forum_archive_template() {
+	$templates = array(
+		'archive-' . bbp_get_forum_post_type() . '.php' // Forum Archive
+	);
+	return bbp_get_query_template( 'forum_archive', $templates );
+}
+
+/**
+ * Get the forum edit template
+ *
+ * @since bbPress (r3566)
+ *
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_forum_edit_template() {
+	$templates = array(
+		'single-' . bbp_get_forum_post_type() . '-edit.php' // Single Forum Edit
+	);
+	return bbp_get_query_template( 'forum_edit', $templates );
+}
+
+/**
+ * Get the single topic template
+ *
+ * @since bbPress (r3922)
+ *
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_single_topic_template() {
+	$templates = array(
+		'single-' . bbp_get_topic_post_type() . '.php'
+	);
+	return bbp_get_query_template( 'single_topic', $templates );
+}
+
+/**
+ * Get the topic archive template
+ *
+ * @since bbPress (r3922)
+ *
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_topic_archive_template() {
+	$templates = array(
+		'archive-' . bbp_get_topic_post_type() . '.php' // Topic Archive
+	);
+	return bbp_get_query_template( 'topic_archive', $templates );
+}
+
+/**
+ * Get the topic edit template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_topic_edit_template() {
+	$templates = array(
+		'single-' . bbp_get_topic_post_type() . '-edit.php' // Single Topic Edit
+	);
+	return bbp_get_query_template( 'topic_edit', $templates );
+}
+
+/**
+ * Get the topic split template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_topic_split_template() {
+	$templates = array(
+		'single-' . bbp_get_topic_post_type() . '-split.php', // Topic Split
+	);
+	return bbp_get_query_template( 'topic_split', $templates );
+}
+
+/**
+ * Get the topic merge template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_topic_merge_template() {
+	$templates = array(
+		'single-' . bbp_get_topic_post_type() . '-merge.php', // Topic Merge
+	);
+	return bbp_get_query_template( 'topic_merge', $templates );
+}
+
+/**
+ * Get the single reply template
+ *
+ * @since bbPress (r3922)
+ *
+ * @uses bbp_get_reply_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_single_reply_template() {
+	$templates = array(
+		'single-' . bbp_get_reply_post_type() . '.php'
+	);
+	return bbp_get_query_template( 'single_reply', $templates );
+}
+
+/**
+ * Get the reply edit template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_reply_post_type()
+ * @uses bbp_get_query_template()
+* @return string Path to template file
+ */
+function bbp_get_reply_edit_template() {
+	$templates = array(
+		'single-' . bbp_get_reply_post_type() . '-edit.php' // Single Reply Edit
+	);
+	return bbp_get_query_template( 'reply_edit', $templates );
+}
+
+/**
+ * Get the reply move template
+ *
+ * @since bbPress (r4521)
+ *
+ * @uses bbp_get_reply_post_type()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_reply_move_template() {
+	$templates = array(
+		'single-' . bbp_get_reply_post_type() . '-move.php', // Reply move
+	);
+	return bbp_get_query_template( 'reply_move', $templates );
+}
+
+/**
+ * Get the topic template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_topic_tag_tax_id()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_topic_tag_template() {
+	$tt_slug   = bbp_get_topic_tag_slug();
+	$tt_id     = bbp_get_topic_tag_tax_id();
+	$templates = array(
+		'taxonomy-' . $tt_slug . '.php', // Single Topic Tag slug
+		'taxonomy-' . $tt_id   . '.php', // Single Topic Tag ID
+	);
+	return bbp_get_query_template( 'topic_tag', $templates );
+}
+
+/**
+ * Get the topic edit template
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses bbp_get_topic_tag_tax_id()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_topic_tag_edit_template() {
+	$tt_slug   = bbp_get_topic_tag_slug();
+	$tt_id     = bbp_get_topic_tag_tax_id();
+	$templates = array(
+		'taxonomy-' . $tt_slug . '-edit.php', // Single Topic Tag Edit slug
+		'taxonomy-' . $tt_id   . '-edit.php'  // Single Topic Tag Edit ID
+	);
+	return bbp_get_query_template( 'topic_tag_edit', $templates );
+}
+
+/**
+ * Get the templates to use as the endpoint for bbPress template parts
+ *
+ * @since bbPress (r3311)
+ *
+ * @uses apply_filters()
+ * @uses bbp_set_theme_compat_templates()
+ * @uses bbp_get_query_template()
+ * @return string Path to template file
+ */
+function bbp_get_theme_compat_templates() {
+	$templates = array(
+		'plugin-bbpress.php',
+		'bbpress.php',
+		'forums.php',
+		'forum.php',
+		'generic.php',
+		'page.php',
+		'single.php',
+		'index.php'
+	);
+	return bbp_get_query_template( 'bbpress', $templates );
+}
Index: /tags/2.5.4/includes/core/theme-compat.php
===================================================================
--- /tags/2.5.4/includes/core/theme-compat.php	(revision 5382)
+++ /tags/2.5.4/includes/core/theme-compat.php	(revision 5382)
@@ -0,0 +1,974 @@
+<?php
+
+/**
+ * bbPress Core Theme Compatibility
+ *
+ * @package bbPress
+ * @subpackage ThemeCompatibility
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Theme Compat **************************************************************/
+
+/**
+ * What follows is an attempt at intercepting the natural page load process
+ * to replace the_content() with the appropriate bbPress content.
+ *
+ * To do this, bbPress does several direct manipulations of global variables
+ * and forces them to do what they are not supposed to be doing.
+ *
+ * Don't try anything you're about to witness here, at home. Ever.
+ */
+
+/** Base Class ****************************************************************/
+
+/**
+ * Theme Compatibility base class
+ *
+ * This is only intended to be extended, and is included here as a basic guide
+ * for future Theme Packs to use. @link BBP_Twenty_Ten is a good example of
+ * extending this class, as is @link bbp_setup_theme_compat()
+ *
+ * @since bbPress (r3506)
+ */
+class BBP_Theme_Compat {
+
+	/**
+	 * Should be like:
+	 *
+	 * array(
+	 *     'id'      => ID of the theme (should be unique)
+	 *     'name'    => Name of the theme (should match style.css)
+	 *     'version' => Theme version for cache busting scripts and styling
+	 *     'dir'     => Path to theme
+	 *     'url'     => URL to theme
+	 * );
+	 * @var array
+	 */
+	private $_data = array();
+
+	/**
+	 * Pass the $properties to the object on creation.
+	 *
+	 * @since bbPress (r3926)
+	 * @param array $properties
+	 */
+    public function __construct( Array $properties = array() ) {
+		$this->_data = $properties;
+	}
+
+	/**
+	 * Set a theme's property.
+	 *
+	 * @since bbPress (r3926)
+	 * @param string $property
+	 * @param mixed $value
+	 * @return mixed
+	 */
+	public function __set( $property, $value ) {
+		return $this->_data[$property] = $value;
+	}
+
+	/**
+	 * Get a theme's property.
+	 *
+	 * @since bbPress (r3926)
+	 * @param string $property
+	 * @param mixed $value
+	 * @return mixed
+	 */
+	public function __get( $property ) {
+		return array_key_exists( $property, $this->_data ) ? $this->_data[$property] : '';
+	}
+}
+
+/** Functions *****************************************************************/
+
+/**
+ * Setup the default theme compat theme
+ *
+ * @since bbPress (r3311)
+ * @param BBP_Theme_Compat $theme
+ */
+function bbp_setup_theme_compat( $theme = '' ) {
+	$bbp = bbpress();
+
+	// Make sure theme package is available, set to default if not
+	if ( ! isset( $bbp->theme_compat->packages[$theme] ) || ! is_a( $bbp->theme_compat->packages[$theme], 'BBP_Theme_Compat' ) ) {
+		$theme = 'default';
+	}
+
+	// Set the active theme compat theme
+	$bbp->theme_compat->theme = $bbp->theme_compat->packages[$theme];
+}
+
+/**
+ * Gets the name of the bbPress compatable theme used, in the event the
+ * currently active WordPress theme does not explicitly support bbPress.
+ * This can be filtered or set manually. Tricky theme authors can override the
+ * default and include their own bbPress compatibility layers for their themes.
+ *
+ * @since bbPress (r3506)
+ * @uses apply_filters()
+ * @return string
+ */
+function bbp_get_theme_compat_id() {
+	return apply_filters( 'bbp_get_theme_compat_id', bbpress()->theme_compat->theme->id );
+}
+
+/**
+ * Gets the name of the bbPress compatable theme used, in the event the
+ * currently active WordPress theme does not explicitly support bbPress.
+ * This can be filtered or set manually. Tricky theme authors can override the
+ * default and include their own bbPress compatibility layers for their themes.
+ *
+ * @since bbPress (r3506)
+ * @uses apply_filters()
+ * @return string
+ */
+function bbp_get_theme_compat_name() {
+	return apply_filters( 'bbp_get_theme_compat_name', bbpress()->theme_compat->theme->name );
+}
+
+/**
+ * Gets the version of the bbPress compatable theme used, in the event the
+ * currently active WordPress theme does not explicitly support bbPress.
+ * This can be filtered or set manually. Tricky theme authors can override the
+ * default and include their own bbPress compatibility layers for their themes.
+ *
+ * @since bbPress (r3506)
+ * @uses apply_filters()
+ * @return string
+ */
+function bbp_get_theme_compat_version() {
+	return apply_filters( 'bbp_get_theme_compat_version', bbpress()->theme_compat->theme->version );
+}
+
+/**
+ * Gets the bbPress compatable theme used in the event the currently active
+ * WordPress theme does not explicitly support bbPress. This can be filtered,
+ * or set manually. Tricky theme authors can override the default and include
+ * their own bbPress compatibility layers for their themes.
+ *
+ * @since bbPress (r3032)
+ * @uses apply_filters()
+ * @return string
+ */
+function bbp_get_theme_compat_dir() {
+	return apply_filters( 'bbp_get_theme_compat_dir', bbpress()->theme_compat->theme->dir );
+}
+
+/**
+ * Gets the bbPress compatable theme used in the event the currently active
+ * WordPress theme does not explicitly support bbPress. This can be filtered,
+ * or set manually. Tricky theme authors can override the default and include
+ * their own bbPress compatibility layers for their themes.
+ *
+ * @since bbPress (r3032)
+ * @uses apply_filters()
+ * @return string
+ */
+function bbp_get_theme_compat_url() {
+	return apply_filters( 'bbp_get_theme_compat_url', bbpress()->theme_compat->theme->url );
+}
+
+/**
+ * Gets true/false if page is currently inside theme compatibility
+ *
+ * @since bbPress (r3265)
+ * @return bool
+ */
+function bbp_is_theme_compat_active() {
+	$bbp = bbpress();
+
+	if ( empty( $bbp->theme_compat->active ) )
+		return false;
+
+	return $bbp->theme_compat->active;
+}
+
+/**
+ * Sets true/false if page is currently inside theme compatibility
+ *
+ * @since bbPress (r3265)
+ * @param bool $set
+ * @return bool
+ */
+function bbp_set_theme_compat_active( $set = true ) {
+	bbpress()->theme_compat->active = $set;
+
+	return (bool) bbpress()->theme_compat->active;
+}
+
+/**
+ * Set the theme compat templates global
+ *
+ * Stash possible template files for the current query. Useful if plugins want
+ * to override them, or see what files are being scanned for inclusion.
+ *
+ * @since bbPress (r3311)
+ */
+function bbp_set_theme_compat_templates( $templates = array() ) {
+	bbpress()->theme_compat->templates = $templates;
+
+	return bbpress()->theme_compat->templates;
+}
+
+/**
+ * Set the theme compat template global
+ *
+ * Stash the template file for the current query. Useful if plugins want
+ * to override it, or see what file is being included.
+ *
+ * @since bbPress (r3311)
+ */
+function bbp_set_theme_compat_template( $template = '' ) {
+	bbpress()->theme_compat->template = $template;
+
+	return bbpress()->theme_compat->template;
+}
+
+/**
+ * Set the theme compat original_template global
+ *
+ * Stash the original template file for the current query. Useful for checking
+ * if bbPress was able to find a more appropriate template.
+ *
+ * @since bbPress (r3926)
+ */
+function bbp_set_theme_compat_original_template( $template = '' ) {
+	bbpress()->theme_compat->original_template = $template;
+
+	return bbpress()->theme_compat->original_template;
+}
+
+/**
+ * Set the theme compat original_template global
+ *
+ * Stash the original template file for the current query. Useful for checking
+ * if bbPress was able to find a more appropriate template.
+ *
+ * @since bbPress (r3926)
+ */
+function bbp_is_theme_compat_original_template( $template = '' ) {
+	$bbp = bbpress();
+
+	if ( empty( $bbp->theme_compat->original_template ) )
+		return false;
+
+	return (bool) ( $bbp->theme_compat->original_template === $template );
+}
+
+/**
+ * Register a new bbPress theme package to the active theme packages array
+ *
+ * @since bbPress (r3829)
+ * @param array $theme
+ */
+function bbp_register_theme_package( $theme = array(), $override = true ) {
+
+	// Create new BBP_Theme_Compat object from the $theme array
+	if ( is_array( $theme ) )
+		$theme = new BBP_Theme_Compat( $theme );
+
+	// Bail if $theme isn't a proper object
+	if ( ! is_a( $theme, 'BBP_Theme_Compat' ) )
+		return;
+
+	// Load up bbPress
+	$bbp = bbpress();
+
+	// Only override if the flag is set and not previously registered
+	if ( empty( $bbp->theme_compat->packages[$theme->id] ) || ( true === $override ) ) {
+		$bbp->theme_compat->packages[$theme->id] = $theme;
+	}
+}
+/**
+ * This fun little function fills up some WordPress globals with dummy data to
+ * stop your average page template from complaining about it missing.
+ *
+ * @since bbPress (r3108)
+ * @global WP_Query $wp_query
+ * @global object $post
+ * @param array $args
+ */
+function bbp_theme_compat_reset_post( $args = array() ) {
+	global $wp_query, $post;
+
+	// Switch defaults if post is set
+	if ( isset( $wp_query->post ) ) {
+		$dummy = bbp_parse_args( $args, array(
+			'ID'                    => $wp_query->post->ID,
+			'post_status'           => $wp_query->post->post_status,
+			'post_author'           => $wp_query->post->post_author,
+			'post_parent'           => $wp_query->post->post_parent,
+			'post_type'             => $wp_query->post->post_type,
+			'post_date'             => $wp_query->post->post_date,
+			'post_date_gmt'         => $wp_query->post->post_date_gmt,
+			'post_modified'         => $wp_query->post->post_modified,
+			'post_modified_gmt'     => $wp_query->post->post_modified_gmt,
+			'post_content'          => $wp_query->post->post_content,
+			'post_title'            => $wp_query->post->post_title,
+			'post_excerpt'          => $wp_query->post->post_excerpt,
+			'post_content_filtered' => $wp_query->post->post_content_filtered,
+			'post_mime_type'        => $wp_query->post->post_mime_type,
+			'post_password'         => $wp_query->post->post_password,
+			'post_name'             => $wp_query->post->post_name,
+			'guid'                  => $wp_query->post->guid,
+			'menu_order'            => $wp_query->post->menu_order,
+			'pinged'                => $wp_query->post->pinged,
+			'to_ping'               => $wp_query->post->to_ping,
+			'ping_status'           => $wp_query->post->ping_status,
+			'comment_status'        => $wp_query->post->comment_status,
+			'comment_count'         => $wp_query->post->comment_count,
+			'filter'                => $wp_query->post->filter,
+
+			'is_404'                => false,
+			'is_page'               => false,
+			'is_single'             => false,
+			'is_archive'            => false,
+			'is_tax'                => false,
+		), 'theme_compat_reset_post' );
+	} else {
+		$dummy = bbp_parse_args( $args, array(
+			'ID'                    => -9999,
+			'post_status'           => bbp_get_public_status_id(),
+			'post_author'           => 0,
+			'post_parent'           => 0,
+			'post_type'             => 'page',
+			'post_date'             => 0,
+			'post_date_gmt'         => 0,
+			'post_modified'         => 0,
+			'post_modified_gmt'     => 0,
+			'post_content'          => '',
+			'post_title'            => '',
+			'post_excerpt'          => '',
+			'post_content_filtered' => '',
+			'post_mime_type'        => '',
+			'post_password'         => '',
+			'post_name'             => '',
+			'guid'                  => '',
+			'menu_order'            => 0,
+			'pinged'                => '',
+			'to_ping'               => '',
+			'ping_status'           => '',
+			'comment_status'        => 'closed',
+			'comment_count'         => 0,
+			'filter'                => 'raw',
+
+			'is_404'                => false,
+			'is_page'               => false,
+			'is_single'             => false,
+			'is_archive'            => false,
+			'is_tax'                => false,
+		), 'theme_compat_reset_post' );
+	}
+
+	// Bail if dummy post is empty
+	if ( empty( $dummy ) ) {
+		return;
+	}
+
+	// Set the $post global
+	$post = new WP_Post( (object) $dummy );
+
+	// Copy the new post global into the main $wp_query
+	$wp_query->post       = $post;
+	$wp_query->posts      = array( $post );
+
+	// Prevent comments form from appearing
+	$wp_query->post_count = 1;
+	$wp_query->is_404     = $dummy['is_404'];
+	$wp_query->is_page    = $dummy['is_page'];
+	$wp_query->is_single  = $dummy['is_single'];
+	$wp_query->is_archive = $dummy['is_archive'];
+	$wp_query->is_tax     = $dummy['is_tax'];
+
+	// Clean up the dummy post
+	unset( $dummy );
+
+	/**
+	 * Force the header back to 200 status if not a deliberate 404
+	 *
+	 * @see http://bbpress.trac.wordpress.org/ticket/1973
+	 */
+	if ( ! $wp_query->is_404() ) {
+		status_header( 200 );
+	}
+
+	// If we are resetting a post, we are in theme compat
+	bbp_set_theme_compat_active( true );
+}
+
+/**
+ * Reset main query vars and filter 'the_content' to output a bbPress
+ * template part as needed.
+ *
+ * @since bbPress (r3032)
+ * @param string $template
+ * @uses bbp_is_single_user() To check if page is single user
+ * @uses bbp_get_single_user_template() To get user template
+ * @uses bbp_is_single_user_edit() To check if page is single user edit
+ * @uses bbp_get_single_user_edit_template() To get user edit template
+ * @uses bbp_is_single_view() To check if page is single view
+ * @uses bbp_get_single_view_template() To get view template
+ * @uses bbp_is_search() To check if page is search
+ * @uses bbp_get_search_template() To get search template
+ * @uses bbp_is_forum_edit() To check if page is forum edit
+ * @uses bbp_get_forum_edit_template() To get forum edit template
+ * @uses bbp_is_topic_merge() To check if page is topic merge
+ * @uses bbp_get_topic_merge_template() To get topic merge template
+ * @uses bbp_is_topic_split() To check if page is topic split
+ * @uses bbp_get_topic_split_template() To get topic split template
+ * @uses bbp_is_topic_edit() To check if page is topic edit
+ * @uses bbp_get_topic_edit_template() To get topic edit template
+ * @uses bbp_is_reply_move() To check if page is reply move
+ * @uses bbp_get_reply_move_template() To get reply move template
+ * @uses bbp_is_reply_edit() To check if page is reply edit
+ * @uses bbp_get_reply_edit_template() To get reply edit template
+ * @uses bbp_set_theme_compat_template() To set the global theme compat template
+ */
+function bbp_template_include_theme_compat( $template = '' ) {
+	
+	/**
+	 * Bail if a root template was already found. This prevents unintended
+	 * recursive filtering of 'the_content'.
+	 *
+	 * @link http://bbpress.trac.wordpress.org/ticket/2429
+	 */
+	if ( bbp_is_template_included() ) {
+		return $template;
+	}
+
+	/**
+	 * If BuddyPress is activated at a network level, the action order is
+	 * reversed, which causes the template integration to fail. If we're looking
+	 * at a BuddyPress page here, bail to prevent the extra processing.
+	 *
+	 * This is a bit more brute-force than is probably necessary, but gets the
+	 * job done while we work towards something more elegant.
+	 */
+	if ( function_exists( 'is_buddypress' ) && is_buddypress() )
+		return $template;
+
+	// Define local variable(s)
+	$bbp_shortcodes = bbpress()->shortcodes;
+
+	// Bail if shortcodes are unset somehow
+	if ( !is_a( $bbp_shortcodes, 'BBP_Shortcodes' ) )
+		return $template;
+
+	/** Users *************************************************************/
+
+	if ( bbp_is_single_user_edit() || bbp_is_single_user() ) {
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => bbp_buffer_template_part( 'content', 'single-user', false ),
+			'post_type'      => '',
+			'post_title'     => bbp_get_displayed_user_field( 'display_name' ),
+			'post_status'    => bbp_get_public_status_id(),
+			'is_archive'     => false,
+			'comment_status' => 'closed'
+		) );
+
+	/** Forums ************************************************************/
+
+	// Forum archive
+	} elseif ( bbp_is_forum_archive() ) {
+
+		// Page exists where this archive should be
+		$page = bbp_get_page_by_path( bbp_get_root_slug() );
+
+		// Should we replace the content...
+		if ( empty( $page->post_content ) ) {
+
+			// Use the topics archive
+			if ( 'topics' === bbp_show_on_root() ) {
+				$new_content = $bbp_shortcodes->display_topic_index();
+
+			// No page so show the archive
+			} else {
+				$new_content = $bbp_shortcodes->display_forum_index();
+			}
+
+		// ...or use the existing page content?
+		} else {
+			$new_content = apply_filters( 'the_content', $page->post_content );
+		}
+
+		// Should we replace the title...
+		if ( empty( $page->post_title ) ) {
+
+			// Use the topics archive
+			if ( 'topics' === bbp_show_on_root() ) {
+				$new_title = bbp_get_topic_archive_title();
+
+			// No page so show the archive
+			} else {
+				$new_title = bbp_get_forum_archive_title();
+			}
+
+		// ...or use the existing page title?
+		} else {
+			$new_title = apply_filters( 'the_title',   $page->post_title   );
+		}
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => !empty( $page->ID ) ? $page->ID : 0,
+			'post_title'     => $new_title,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => $new_content,
+			'post_type'      => bbp_get_forum_post_type(),
+			'post_status'    => bbp_get_public_status_id(),
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+
+	// Single Forum
+	} elseif ( bbp_is_forum_edit() ) {
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => bbp_get_forum_id(),
+			'post_title'     => bbp_get_forum_title(),
+			'post_author'    => bbp_get_forum_author_id(),
+			'post_date'      => 0,
+			'post_content'   => $bbp_shortcodes->display_forum_form(),
+			'post_type'      => bbp_get_forum_post_type(),
+			'post_status'    => bbp_get_forum_visibility(),
+			'is_single'      => true,
+			'comment_status' => 'closed'
+		) );
+
+	} elseif ( bbp_is_single_forum() ) {
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => bbp_get_forum_id(),
+			'post_title'     => bbp_get_forum_title(),
+			'post_author'    => bbp_get_forum_author_id(),
+			'post_date'      => 0,
+			'post_content'   => $bbp_shortcodes->display_forum( array( 'id' => bbp_get_forum_id() ) ),
+			'post_type'      => bbp_get_forum_post_type(),
+			'post_status'    => bbp_get_forum_visibility(),
+			'is_single'      => true,
+			'comment_status' => 'closed'
+		) );
+
+	/** Topics ************************************************************/
+
+	// Topic archive
+	} elseif ( bbp_is_topic_archive() ) {
+
+		// Page exists where this archive should be
+		$page = bbp_get_page_by_path( bbp_get_topic_archive_slug() );
+
+		// Should we replace the content...
+		if ( empty( $page->post_content ) ) {
+			$new_content = $bbp_shortcodes->display_topic_index();
+
+		// ...or use the existing page content?
+		} else {
+			$new_content = apply_filters( 'the_content', $page->post_content );
+		}
+
+		// Should we replace the title...
+		if ( empty( $page->post_title ) ) {
+			$new_title = bbp_get_topic_archive_title();
+
+		// ...or use the existing page title?
+		} else {
+			$new_title = apply_filters( 'the_title',   $page->post_title   );
+		}
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => !empty( $page->ID ) ? $page->ID : 0,
+			'post_title'     => bbp_get_topic_archive_title(),
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => $new_content,
+			'post_type'      => bbp_get_topic_post_type(),
+			'post_status'    => bbp_get_public_status_id(),
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+
+	// Single Topic
+	} elseif ( bbp_is_topic_edit() || bbp_is_single_topic() ) {
+
+		// Split
+		if ( bbp_is_topic_split() ) {
+			$new_content = bbp_buffer_template_part( 'form', 'topic-split', false );
+
+		// Merge
+		} elseif ( bbp_is_topic_merge() ) {
+			$new_content = bbp_buffer_template_part( 'form', 'topic-merge', false );
+
+		// Edit
+		} elseif ( bbp_is_topic_edit() ) {
+			$new_content = $bbp_shortcodes->display_topic_form();
+
+		// Single
+		} else {
+			$new_content = $bbp_shortcodes->display_topic( array( 'id' => bbp_get_topic_id() ) );
+		}
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => bbp_get_topic_id(),
+			'post_title'     => bbp_get_topic_title(),
+			'post_author'    => bbp_get_topic_author_id(),
+			'post_date'      => 0,
+			'post_content'   => $new_content,
+			'post_type'      => bbp_get_topic_post_type(),
+			'post_status'    => bbp_get_topic_status(),
+			'is_single'      => true,
+			'comment_status' => 'closed'
+		) );
+
+	/** Replies ***********************************************************/
+
+	// Reply archive
+	} elseif ( is_post_type_archive( bbp_get_reply_post_type() ) ) {
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => __( 'Replies', 'bbpress' ),
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => $bbp_shortcodes->display_reply_index(),
+			'post_type'      => bbp_get_reply_post_type(),
+			'post_status'    => bbp_get_public_status_id(),
+			'comment_status' => 'closed'
+		) );
+
+	// Single Reply
+	} elseif ( bbp_is_reply_edit() || bbp_is_single_reply() ) {
+
+		// Move
+		if ( bbp_is_reply_move() ) {
+			$new_content = bbp_buffer_template_part( 'form', 'reply-move', false );
+
+		// Edit
+		} elseif ( bbp_is_reply_edit() ) {
+			$new_content = $bbp_shortcodes->display_reply_form();
+
+		// Single
+		} else {
+			$new_content = $bbp_shortcodes->display_reply( array( 'id' => get_the_ID() ) );
+		}
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => bbp_get_reply_id(),
+			'post_title'     => bbp_get_reply_title(),
+			'post_author'    => bbp_get_reply_author_id(),
+			'post_date'      => 0,
+			'post_content'   => $new_content,
+			'post_type'      => bbp_get_reply_post_type(),
+			'post_status'    => bbp_get_reply_status(),
+			'comment_status' => 'closed'
+		) );
+
+	/** Views *************************************************************/
+
+	} elseif ( bbp_is_single_view() ) {
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => bbp_get_view_title(),
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => $bbp_shortcodes->display_view( array( 'id' => get_query_var( bbp_get_view_rewrite_id() ) ) ),
+			'post_type'      => '',
+			'post_status'    => bbp_get_public_status_id(),
+			'comment_status' => 'closed'
+		) );
+
+	/** Search ************************************************************/
+
+	} elseif ( bbp_is_search() ) {
+
+		// Reset post
+		bbp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => bbp_get_search_title(),
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => $bbp_shortcodes->display_search( array( 'search' => get_query_var( bbp_get_search_rewrite_id() ) ) ),
+			'post_type'      => '',
+			'post_status'    => bbp_get_public_status_id(),
+			'comment_status' => 'closed'
+		) );
+
+	/** Topic Tags ********************************************************/
+
+	// Topic Tag Edit
+	} elseif ( bbp_is_topic_tag_edit() || bbp_is_topic_tag() ) {
+
+		// Stash the current term in a new var
+		set_query_var( 'bbp_topic_tag', get_query_var( 'term' ) );
+
+		// Show topics of tag
+		if ( bbp_is_topic_tag() ) {
+			$new_content = $bbp_shortcodes->display_topics_of_tag( array( 'id' => bbp_get_topic_tag_id() ) );
+
+		// Edit topic tag
+		} elseif ( bbp_is_topic_tag_edit() ) {
+			$new_content = $bbp_shortcodes->display_topic_tag_form();
+		}
+
+		// Reset the post with our new title
+		bbp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => $new_content,
+			'post_type'      => '',
+			'post_title'     => sprintf( __( 'Topic Tag: %s', 'bbpress' ), '<span>' . bbp_get_topic_tag_name() . '</span>' ),
+			'post_status'    => bbp_get_public_status_id(),
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Bail if the template already matches a bbPress template. This includes
+	 * archive-* and single-* WordPress post_type matches (allowing
+	 * themes to use the expected format) as well as all bbPress-specific
+	 * template files for users, topics, forums, etc...
+	 *
+	 * We do this after the above checks to prevent incorrect 404 body classes
+	 * and header statuses, as well as to set the post global as needed.
+	 *
+	 * @see http://bbpress.trac.wordpress.org/ticket/1478/
+	 */
+	if ( bbp_is_template_included() ) {
+		return $template;
+
+	/**
+	 * If we are relying on bbPress's built in theme compatibility to load
+	 * the proper content, we need to intercept the_content, replace the
+	 * output, and display ours instead.
+	 *
+	 * To do this, we first remove all filters from 'the_content' and hook
+	 * our own function into it, which runs a series of checks to determine
+	 * the context, and then uses the built in shortcodes to output the
+	 * correct results from inside an output buffer.
+	 *
+	 * Uses bbp_get_theme_compat_templates() to provide fall-backs that
+	 * should be coded without superfluous mark-up and logic (prev/next
+	 * navigation, comments, date/time, etc...)
+	 *
+	 * Hook into the 'bbp_get_bbpress_template' to override the array of
+	 * possible templates, or 'bbp_bbpress_template' to override the result.
+	 */
+	} elseif ( bbp_is_theme_compat_active() ) {
+		bbp_remove_all_filters( 'the_content' );
+
+		$template = bbp_get_theme_compat_templates();
+	}
+
+	return apply_filters( 'bbp_template_include_theme_compat', $template );
+}
+
+/** Helpers *******************************************************************/
+
+/**
+ * Remove the canonical redirect to allow pretty pagination
+ *
+ * @since bbPress (r2628)
+ * @param string $redirect_url Redirect url
+ * @uses WP_Rewrite::using_permalinks() To check if the blog is using permalinks
+ * @uses bbp_get_paged() To get the current page number
+ * @uses bbp_is_single_topic() To check if it's a topic page
+ * @uses bbp_is_single_forum() To check if it's a forum page
+ * @return bool|string False if it's a topic/forum and their first page,
+ *                      otherwise the redirect url
+ */
+function bbp_redirect_canonical( $redirect_url ) {
+	global $wp_rewrite;
+
+	// Canonical is for the beautiful
+	if ( $wp_rewrite->using_permalinks() ) {
+
+		// If viewing beyond page 1 of several
+		if ( 1 < bbp_get_paged() ) {
+
+			// Only on single topics...
+			if ( bbp_is_single_topic() ) {
+				$redirect_url = false;
+
+			// ...and single forums...
+			} elseif ( bbp_is_single_forum() ) {
+				$redirect_url = false;
+
+			// ...and single replies...
+			} elseif ( bbp_is_single_reply() ) {
+				$redirect_url = false;
+
+			// ...and any single anything else...
+			//
+			// @todo - Find a more accurate way to disable paged canonicals for
+			//          paged shortcode usage within other posts.
+			} elseif ( is_page() || is_singular() ) {
+				$redirect_url = false;
+			}
+
+		// If editing a topic
+		} elseif ( bbp_is_topic_edit() ) {
+			$redirect_url = false;
+
+		// If editing a reply
+		} elseif ( bbp_is_reply_edit() ) {
+			$redirect_url = false;
+		}
+	}
+
+	return $redirect_url;
+}
+
+/** Filters *******************************************************************/
+
+/**
+ * Removes all filters from a WordPress filter, and stashes them in the $bbp
+ * global in the event they need to be restored later.
+ *
+ * @since bbPress (r3251)
+ * @global WP_filter $wp_filter
+ * @global array $merged_filters
+ * @param string $tag
+ * @param int $priority
+ * @return bool
+ */
+function bbp_remove_all_filters( $tag, $priority = false ) {
+	global $wp_filter, $merged_filters;
+
+	$bbp = bbpress();
+
+	// Filters exist
+	if ( isset( $wp_filter[$tag] ) ) {
+
+		// Filters exist in this priority
+		if ( !empty( $priority ) && isset( $wp_filter[$tag][$priority] ) ) {
+
+			// Store filters in a backup
+			$bbp->filters->wp_filter[$tag][$priority] = $wp_filter[$tag][$priority];
+
+			// Unset the filters
+			unset( $wp_filter[$tag][$priority] );
+
+		// Priority is empty
+		} else {
+
+			// Store filters in a backup
+			$bbp->filters->wp_filter[$tag] = $wp_filter[$tag];
+
+			// Unset the filters
+			unset( $wp_filter[$tag] );
+		}
+	}
+
+	// Check merged filters
+	if ( isset( $merged_filters[$tag] ) ) {
+
+		// Store filters in a backup
+		$bbp->filters->merged_filters[$tag] = $merged_filters[$tag];
+
+		// Unset the filters
+		unset( $merged_filters[$tag] );
+	}
+
+	return true;
+}
+
+/**
+ * Restores filters from the $bbp global that were removed using
+ * bbp_remove_all_filters()
+ *
+ * @since bbPress (r3251)
+ * @global WP_filter $wp_filter
+ * @global array $merged_filters
+ * @param string $tag
+ * @param int $priority
+ * @return bool
+ */
+function bbp_restore_all_filters( $tag, $priority = false ) {
+	global $wp_filter, $merged_filters;
+
+	$bbp = bbpress();
+
+	// Filters exist
+	if ( isset( $bbp->filters->wp_filter[$tag] ) ) {
+
+		// Filters exist in this priority
+		if ( !empty( $priority ) && isset( $bbp->filters->wp_filter[$tag][$priority] ) ) {
+
+			// Store filters in a backup
+			$wp_filter[$tag][$priority] = $bbp->filters->wp_filter[$tag][$priority];
+
+			// Unset the filters
+			unset( $bbp->filters->wp_filter[$tag][$priority] );
+
+		// Priority is empty
+		} else {
+
+			// Store filters in a backup
+			$wp_filter[$tag] = $bbp->filters->wp_filter[$tag];
+
+			// Unset the filters
+			unset( $bbp->filters->wp_filter[$tag] );
+		}
+	}
+
+	// Check merged filters
+	if ( isset( $bbp->filters->merged_filters[$tag] ) ) {
+
+		// Store filters in a backup
+		$merged_filters[$tag] = $bbp->filters->merged_filters[$tag];
+
+		// Unset the filters
+		unset( $bbp->filters->merged_filters[$tag] );
+	}
+
+	return true;
+}
+
+/**
+ * Force comments_status to 'closed' for bbPress post types
+ *
+ * @since bbPress (r3589)
+ * @param bool $open True if open, false if closed
+ * @param int $post_id ID of the post to check
+ * @return bool True if open, false if closed
+ */
+function bbp_force_comment_status( $open, $post_id = 0 ) {
+
+	// Get the post type of the post ID
+	$post_type = get_post_type( $post_id );
+
+	// Default return value is what is passed in $open
+	$retval = $open;
+
+	// Only force for bbPress post types
+	switch ( $post_type ) {
+		case bbp_get_forum_post_type() :
+		case bbp_get_topic_post_type() :
+		case bbp_get_reply_post_type() :
+			$retval = false;
+			break;
+	}
+
+	// Allow override of the override
+	return apply_filters( 'bbp_force_comment_status', $retval, $open, $post_id, $post_type );
+}
Index: /tags/2.5.4/includes/core/update.php
===================================================================
--- /tags/2.5.4/includes/core/update.php	(revision 5382)
+++ /tags/2.5.4/includes/core/update.php	(revision 5382)
@@ -0,0 +1,364 @@
+<?php
+
+/**
+ * bbPress Updater
+ *
+ * @package bbPress
+ * @subpackage Updater
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * If there is no raw DB version, this is the first installation
+ *
+ * @since bbPress (r3764)
+ *
+ * @uses get_option()
+ * @uses bbp_get_db_version() To get bbPress's database version
+ * @return bool True if update, False if not
+ */
+function bbp_is_install() {
+	return ! bbp_get_db_version_raw();
+}
+
+/**
+ * Compare the bbPress version to the DB version to determine if updating
+ *
+ * @since bbPress (r3421)
+ *
+ * @uses get_option()
+ * @uses bbp_get_db_version() To get bbPress's database version
+ * @return bool True if update, False if not
+ */
+function bbp_is_update() {
+	$raw    = (int) bbp_get_db_version_raw();
+	$cur    = (int) bbp_get_db_version();
+	$retval = (bool) ( $raw < $cur );
+	return $retval;
+}
+
+/**
+ * Determine if bbPress is being activated
+ *
+ * Note that this function currently is not used in bbPress core and is here
+ * for third party plugins to use to check for bbPress activation.
+ *
+ * @since bbPress (r3421)
+ *
+ * @return bool True if activating bbPress, false if not
+ */
+function bbp_is_activation( $basename = '' ) {
+	global $pagenow;
+
+	$bbp    = bbpress();
+	$action = false;
+
+	// Bail if not in admin/plugins
+	if ( ! ( is_admin() && ( 'plugins.php' === $pagenow ) ) ) {
+		return false;
+	}
+
+	if ( ! empty( $_REQUEST['action'] ) && ( '-1' !== $_REQUEST['action'] ) ) {
+		$action = $_REQUEST['action'];
+	} elseif ( ! empty( $_REQUEST['action2'] ) && ( '-1' !== $_REQUEST['action2'] ) ) {
+		$action = $_REQUEST['action2'];
+	}
+
+	// Bail if not activating
+	if ( empty( $action ) || !in_array( $action, array( 'activate', 'activate-selected' ) ) ) {
+		return false;
+	}
+
+	// The plugin(s) being activated
+	if ( $action === 'activate' ) {
+		$plugins = isset( $_GET['plugin'] ) ? array( $_GET['plugin'] ) : array();
+	} else {
+		$plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+	}
+
+	// Set basename if empty
+	if ( empty( $basename ) && !empty( $bbp->basename ) ) {
+		$basename = $bbp->basename;
+	}
+
+	// Bail if no basename
+	if ( empty( $basename ) ) {
+		return false;
+	}
+
+	// Is bbPress being activated?
+	return in_array( $basename, $plugins );
+}
+
+/**
+ * Determine if bbPress is being deactivated
+ *
+ * @since bbPress (r3421)
+ * @return bool True if deactivating bbPress, false if not
+ */
+function bbp_is_deactivation( $basename = '' ) {
+	global $pagenow;
+
+	$bbp    = bbpress();
+	$action = false;
+
+	// Bail if not in admin/plugins
+	if ( ! ( is_admin() && ( 'plugins.php' === $pagenow ) ) ) {
+		return false;
+	}
+
+	if ( ! empty( $_REQUEST['action'] ) && ( '-1' !== $_REQUEST['action'] ) ) {
+		$action = $_REQUEST['action'];
+	} elseif ( ! empty( $_REQUEST['action2'] ) && ( '-1' !== $_REQUEST['action2'] ) ) {
+		$action = $_REQUEST['action2'];
+	}
+
+	// Bail if not deactivating
+	if ( empty( $action ) || !in_array( $action, array( 'deactivate', 'deactivate-selected' ) ) ) {
+		return false;
+	}
+
+	// The plugin(s) being deactivated
+	if ( $action === 'deactivate' ) {
+		$plugins = isset( $_GET['plugin'] ) ? array( $_GET['plugin'] ) : array();
+	} else {
+		$plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+	}
+
+	// Set basename if empty
+	if ( empty( $basename ) && !empty( $bbp->basename ) ) {
+		$basename = $bbp->basename;
+	}
+
+	// Bail if no basename
+	if ( empty( $basename ) ) {
+		return false;
+	}
+
+	// Is bbPress being deactivated?
+	return in_array( $basename, $plugins );
+}
+
+/**
+ * Update the DB to the latest version
+ *
+ * @since bbPress (r3421)
+ * @uses update_option()
+ * @uses bbp_get_db_version() To get bbPress's database version
+ */
+function bbp_version_bump() {
+	update_option( '_bbp_db_version', bbp_get_db_version() );
+}
+
+/**
+ * Setup the bbPress updater
+ *
+ * @since bbPress (r3419)
+ *
+ * @uses bbp_version_updater()
+ * @uses bbp_version_bump()
+ * @uses flush_rewrite_rules()
+ */
+function bbp_setup_updater() {
+
+	// Bail if no update needed
+	if ( ! bbp_is_update() )
+		return;
+
+	// Call the automated updater
+	bbp_version_updater();
+}
+
+/**
+ * Create a default forum, topic, and reply
+ *
+ * @since bbPress (r3767)
+ * @param array $args Array of arguments to override default values
+ */
+function bbp_create_initial_content( $args = array() ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'forum_parent'  => 0,
+		'forum_status'  => 'publish',
+		'forum_title'   => __( 'General',                                  'bbpress' ),
+		'forum_content' => __( 'General chit-chat',                        'bbpress' ),
+		'topic_title'   => __( 'Hello World!',                             'bbpress' ),
+		'topic_content' => __( 'I am the first topic in your new forums.', 'bbpress' ),
+		'reply_title'   => __( 'Re: Hello World!',                         'bbpress' ),
+		'reply_content' => __( 'Oh, and this is what a reply looks like.', 'bbpress' ),
+	), 'create_initial_content' );
+
+	// Create the initial forum
+	$forum_id = bbp_insert_forum( array(
+		'post_parent'  => $r['forum_parent'],
+		'post_status'  => $r['forum_status'],
+		'post_title'   => $r['forum_title'],
+		'post_content' => $r['forum_content']
+	) );
+
+	// Create the initial topic
+	$topic_id = bbp_insert_topic(
+		array(
+			'post_parent'  => $forum_id,
+			'post_title'   => $r['topic_title'],
+			'post_content' => $r['topic_content']
+		),
+		array( 'forum_id'  => $forum_id )
+	);
+
+	// Create the initial reply
+	$reply_id = bbp_insert_reply(
+		array(
+			'post_parent'  => $topic_id,
+			'post_title'   => $r['reply_title'],
+			'post_content' => $r['reply_content']
+		),
+		array(
+			'forum_id'     => $forum_id,
+			'topic_id'     => $topic_id
+		)
+	);
+
+	return array(
+		'forum_id' => $forum_id,
+		'topic_id' => $topic_id,
+		'reply_id' => $reply_id
+	);
+}
+
+/**
+ * bbPress's version updater looks at what the current database version is, and
+ * runs whatever other code is needed.
+ *
+ * This is most-often used when the data schema changes, but should also be used
+ * to correct issues with bbPress meta-data silently on software update.
+ *
+ * @since bbPress (r4104)
+ */
+function bbp_version_updater() {
+
+	// Get the raw database version
+	$raw_db_version = (int) bbp_get_db_version_raw();
+
+	/** 2.0 Branch ************************************************************/
+
+	// 2.0, 2.0.1, 2.0.2, 2.0.3
+	if ( $raw_db_version < 200 ) {
+		// No changes
+	}
+
+	/** 2.1 Branch ************************************************************/
+
+	// 2.1, 2.1.1
+	if ( $raw_db_version < 211 ) {
+
+		/**
+		 * Repair private and hidden forum data
+		 *
+		 * @link http://bbpress.trac.wordpress.org/ticket/1891
+		 */
+		bbp_admin_repair_forum_visibility();
+	}
+
+	/** 2.2 Branch ************************************************************/
+
+	// 2.2
+	if ( $raw_db_version < 220 ) {
+
+		// Remove the Moderator role from the database
+		remove_role( bbp_get_moderator_role() );
+
+		// Remove the Participant role from the database
+		remove_role( bbp_get_participant_role() );
+
+		// Remove capabilities
+		bbp_remove_caps();
+	}
+
+	/** 2.3 Branch ************************************************************/
+
+	// 2.3
+	if ( $raw_db_version < 230 ) {
+		// No changes
+	}
+
+	/** All done! *************************************************************/
+
+	// Bump the version
+	bbp_version_bump();
+
+	// Delete rewrite rules to force a flush
+	bbp_delete_rewrite_rules();
+}
+
+/**
+ * Redirect user to bbPress's What's New page on activation
+ *
+ * @since bbPress (r4389)
+ *
+ * @internal Used internally to redirect bbPress to the about page on activation
+ *
+ * @uses is_network_admin() To bail if being network activated
+ * @uses set_transient() To drop the activation transient for 30 seconds
+ *
+ * @return If network admin or bulk activation
+ */
+function bbp_add_activation_redirect() {
+
+	// Bail if activating from network, or bulk
+	if ( is_network_admin() || isset( $_GET['activate-multi'] ) )
+		return;
+
+	// Add the transient to redirect
+    set_transient( '_bbp_activation_redirect', true, 30 );
+}
+
+/**
+ * Hooked to the 'bbp_activate' action, this helper function automatically makes
+ * the current user a Key Master in the forums if they just activated bbPress,
+ * regardless of the bbp_allow_global_access() setting.
+ *
+ * @since bbPress (r4910)
+ *
+ * @internal Used to internally make the current user a keymaster on activation
+ *
+ * @uses current_user_can() to bail if user cannot activate plugins
+ * @uses get_current_user_id() to get the current user ID
+ * @uses get_current_blog_id() to get the current blog ID
+ * @uses is_user_member_of_blog() to bail if the current user does not have a role
+ * @uses bbp_is_user_keymaster() to bail if the user is already a keymaster
+ * @uses bbp_set_user_role() to make the current user a keymaster
+ *
+ * @return If user can't activate plugins or is already a keymaster
+ */
+function bbp_make_current_user_keymaster() {
+
+	// Bail if the current user can't activate plugins since previous pageload
+	if ( ! current_user_can( 'activate_plugins' ) ) {
+		return;
+	}
+
+	// Get the current user ID
+	$user_id = get_current_user_id();
+	$blog_id = get_current_blog_id();
+
+	// Bail if user is not actually a member of this site
+	if ( ! is_user_member_of_blog( $user_id, $blog_id ) ) {
+		return;
+	}
+
+	// Bail if the current user already has a forum role to prevent
+	// unexpected role and capability escalation.
+	if ( bbp_get_user_role( $user_id ) ) {
+		return;
+	}
+
+	// Make the current user a keymaster
+	bbp_set_user_role( $user_id, bbp_get_keymaster_role() );
+
+	// Reload the current user so caps apply immediately
+	wp_get_current_user();
+}
Index: /tags/2.5.4/includes/extend/akismet.php
===================================================================
--- /tags/2.5.4/includes/extend/akismet.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/akismet.php	(revision 5382)
@@ -0,0 +1,802 @@
+<?php
+
+/**
+ * Main bbPress Akismet Class
+ *
+ * @package bbPress
+ * @subpackage Akismet
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Akismet' ) ) :
+/**
+ * Loads Akismet extension
+ *
+ * @since bbPress (r3277)
+ *
+ * @package bbPress
+ * @subpackage Akismet
+ */
+class BBP_Akismet {
+
+	/**
+	 * The main bbPress Akismet loader
+	 *
+	 * @since bbPress (r3277)
+	 *
+	 * @uses add_filter()
+	 */
+	public function __construct() {
+		$this->setup_actions();
+	}
+
+	/**
+	 * Setup the admin hooks
+	 *
+	 * @since bbPress (r3277)
+	 * @access private
+	 *
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_actions() {
+
+		// Prevent debug notices
+		$checks = array();
+
+		// bbPress functions to check for spam
+		$checks['check']  = array(
+			'bbp_new_topic_pre_insert'  => 1,  // New topic check
+			'bbp_new_reply_pre_insert'  => 1,  // New reply check
+			'bbp_edit_topic_pre_insert' => 1,  // Edit topic check
+			'bbp_edit_reply_pre_insert' => 1   // Edit reply check
+		);
+
+		// bbPress functions for spam and ham submissions
+		$checks['submit'] = array(
+			'bbp_spammed_topic'   => 10, // Spammed topic
+			'bbp_unspammed_topic' => 10, // Unspammed reply
+			'bbp_spammed_reply'   => 10, // Spammed reply
+			'bbp_unspammed_reply' => 10, // Unspammed reply
+		);
+
+		// Add the checks
+		foreach ( $checks as $type => $functions )
+			foreach ( $functions as $function => $priority )
+				add_filter( $function, array( $this, $type . '_post'  ), $priority );
+
+		// Update post meta
+		add_action( 'wp_insert_post', array( $this, 'update_post_meta' ), 10, 2 );
+
+		// Admin
+		if ( is_admin() ) {
+			add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) );
+		}
+	}
+
+	/**
+	 * Converts topic/reply data into Akismet comment checking format
+	 *
+	 * @since bbPress (r3277)
+	 *
+	 * @param string $post_data
+	 *
+	 * @uses get_userdata() To get the user data
+	 * @uses bbp_filter_anonymous_user_data() To get anonymous user data
+	 * @uses bbp_get_topic_permalink() To get the permalink of the topic
+	 * @uses bbp_get_reply_url() To get the permalink of the reply
+	 * @uses bbp_current_author_ip() To get the IP address of the current user
+	 * @uses BBP_Akismet::maybe_spam() To check if post is spam
+	 * @uses BBP_Akismet::get_user_roles() To get the role(s) of the current user
+	 * @uses do_action() To call the 'bbp_akismet_spam_caught' hook
+	 * @uses add_filter() To call the 'bbp_new_reply_pre_set_terms' hook
+	 *
+	 * @return array Array of post data
+	 */
+	public function check_post( $post_data ) {
+
+		// Define local variables
+		$user_data = array();
+		$post_permalink = '';
+
+		// Post is not published
+		if ( bbp_get_public_status_id() !== $post_data['post_status'] )
+			return $post_data;
+
+		// Cast the post_author to 0 if it's empty
+		if ( empty( $post_data['post_author'] ) )
+			$post_data['post_author'] = 0;
+
+		/** Author ************************************************************/
+
+		// Get user data
+		$userdata       = get_userdata( $post_data['post_author'] );
+		$anonymous_data = bbp_filter_anonymous_post_data();
+
+		// Author is anonymous
+		if ( !empty( $anonymous_data ) ) {
+			$user_data['name']    = $anonymous_data['bbp_anonymous_name'];
+			$user_data['email']   = $anonymous_data['bbp_anonymous_email'];
+			$user_data['website'] = $anonymous_data['bbp_anonymous_website'];
+
+		// Author is logged in
+		} elseif ( !empty( $userdata ) ) {
+			$user_data['name']    = $userdata->display_name;
+			$user_data['email']   = $userdata->user_email;
+			$user_data['website'] = $userdata->user_url;
+
+		// Missing author data, so set some empty strings
+		} else {
+			$user_data['name']    = '';
+			$user_data['email']   = '';
+			$user_data['website'] = '';
+		}
+
+		/** Post **************************************************************/
+
+		// Use post parent for permalink
+		if ( !empty( $post_data['post_parent'] ) )
+			$post_permalink = get_permalink( $post_data['post_parent'] );
+
+		// Put post_data back into usable array
+		$_post = array(
+			'comment_author'       => $user_data['name'],
+			'comment_author_email' => $user_data['email'],
+			'comment_author_url'   => $user_data['website'],
+			'comment_content'      => $post_data['post_content'],
+			'comment_post_ID'      => $post_data['post_parent'],
+			'comment_type'         => $post_data['post_type'],
+			'permalink'            => $post_permalink,
+			'referrer'             => $_SERVER['HTTP_REFERER'],
+			'user_agent'           => $_SERVER['HTTP_USER_AGENT'],
+			'user_ID'              => $post_data['post_author'],
+			'user_ip'              => bbp_current_author_ip(),
+			'user_role'            => $this->get_user_roles( $post_data['post_author'] ),
+		);
+
+		// Check the post_data
+		$_post = $this->maybe_spam( $_post );
+
+		// Get the result
+		$post_data['bbp_akismet_result'] = $_post['bbp_akismet_result'];
+		unset( $_post['bbp_akismet_result'] );
+
+		// Store the data as submitted
+		$post_data['bbp_post_as_submitted'] = $_post;
+
+		// Allow post_data to be manipulated
+		do_action_ref_array( 'bbp_akismet_check_post', $post_data );
+
+		// Spam
+		if ( 'true' === $post_data['bbp_akismet_result'] ) {
+
+			// Let plugins do their thing
+			do_action( 'bbp_akismet_spam_caught' );
+
+			// This is spam
+			$post_data['post_status'] = bbp_get_spam_status_id();
+
+			// We don't want your spam tags here
+			add_filter( 'bbp_new_reply_pre_set_terms', array( $this, 'filter_post_terms' ), 1, 3 );
+
+			// @todo Spam counter?
+		}
+
+		// @todo Topic/reply moderation? No true/false response - 'pending' or 'draft'
+		// @todo Auto-delete old spam?
+
+		// Log the last post
+		$this->last_post = $post_data;
+
+		// Pass the data back to the filter
+		return $post_data;
+	}
+
+	/**
+	 * Submit a post for spamming or hamming
+	 *
+	 * @since bbPress (r3277)
+	 *
+	 * @param int $post_id
+	 *
+	 * @global WP_Query $wpdb
+	 * @global string $akismet_api_host
+	 * @global string $akismet_api_port
+	 * @global object $current_user
+	 * @global object $current_site
+	 *
+	 * @uses current_filter() To get the reply_id
+	 * @uses get_post() To get the post object
+	 * @uses get_the_author_meta() To get the author meta
+	 * @uses get_post_meta() To get the post meta
+	 * @uses bbp_get_user_profile_url() To get a user's profile url
+	 * @uses get_permalink() To get the permalink of the post_parent
+	 * @uses BBP_Akismet::get_user_roles() To get the role(s) of the post_author
+	 * @uses bbp_current_author_ip() To get the IP address of the current user
+	 * @uses BBP_Akismet::maybe_spam() To submit the post as ham or spam
+	 * @uses update_post_meta() To update the post meta with some Akismet data
+	 * @uses do_action() To call the 'bbp_akismet_submit_spam_post' and 'bbp_akismet_submit_ham_post' hooks
+	 *
+	 * @return array Array of existing topic terms
+	 */
+	public function submit_post( $post_id = 0 ) {
+		global $current_user, $current_site;
+
+		// Innocent until proven guilty
+		$request_type   = 'ham';
+		$current_filter = current_filter();
+
+		// Check this filter and adjust the $request_type accordingly
+		switch ( $current_filter ) {
+
+			// Mysterious, and straight from the can
+			case 'bbp_spammed_topic' :
+			case 'bbp_spammed_reply' :
+				$request_type = 'spam';
+				break;
+
+			// Honey-glazed, a straight off the bone
+			case 'bbp_unspammed_topic' :
+			case 'bbp_unspammed_reply' :
+				$request_type = 'ham';
+				break;
+
+			// Possibly poison...
+			default :
+				return;
+		}
+
+		// Setup some variables
+		$post_id = (int) $post_id;
+
+		// Make sure we have a post
+		$_post = get_post( $post_id );
+
+		// Bail if get_post() fails
+		if ( empty( $_post ) )
+			return;
+
+		// Bail if we're spamming, but the post_status isn't spam
+		if ( ( 'spam' === $request_type ) && ( bbp_get_spam_status_id() !== $_post->post_status ) )
+			return;
+
+		// Set some default post_data
+		$post_data = array(
+			'comment_approved'     => $_post->post_status,
+			'comment_author'       => $_post->post_author ? get_the_author_meta( 'display_name', $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_name',    true ),
+			'comment_author_email' => $_post->post_author ? get_the_author_meta( 'email',        $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_email',   true ),
+			'comment_author_url'   => $_post->post_author ? bbp_get_user_profile_url(            $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_website', true ),
+			'comment_content'      => $_post->post_content,
+			'comment_date'         => $_post->post_date,
+			'comment_ID'           => $post_id,
+			'comment_post_ID'      => $_post->post_parent,
+			'comment_type'         => $_post->post_type,
+			'permalink'            => get_permalink( $post_id ),
+			'user_ID'              => $_post->post_author,
+			'user_ip'              => get_post_meta( $post_id, '_bbp_author_ip', true ),
+			'user_role'            => $this->get_user_roles( $_post->post_author ),
+		);
+
+		// Use the original version stored in post_meta if available
+		$as_submitted = get_post_meta( $post_id, '_bbp_akismet_as_submitted', true );
+		if ( $as_submitted && is_array( $as_submitted ) && isset( $as_submitted['comment_content'] ) )
+			$post_data = array_merge( $post_data, $as_submitted );
+
+		// Add the reporter IP address
+		$post_data['reporter_ip']  = bbp_current_author_ip();
+
+		// Add some reporter info
+		if ( is_object( $current_user ) )
+		    $post_data['reporter'] = $current_user->user_login;
+
+		// Add the current site domain
+		if ( is_object( $current_site ) )
+			$post_data['site_domain'] = $current_site->domain;
+
+		// Place your slide beneath the microscope
+		$post_data = $this->maybe_spam( $post_data, 'submit', $request_type );
+
+		// Manual user action
+		if ( isset( $post_data['reporter'] ) ) {
+
+			// What kind of action
+			switch ( $request_type ) {
+
+				// Spammy
+				case 'spam' :
+					$this->update_post_history( $post_id, sprintf( esc_html__( '%1$s reported this %2$s as spam', 'bbpress' ),     $post_data['reporter'], $post_data['comment_type'] ), 'report-spam' );
+					update_post_meta( $post_id, '_bbp_akismet_user_result', 'true'                 );
+					update_post_meta( $post_id, '_bbp_akismet_user',        $post_data['reporter'] );
+					break;
+
+				// Hammy
+				case 'ham'  :
+					$this->update_post_history( $post_id, sprintf( esc_html__( '%1$s reported this %2$s as not spam', 'bbpress' ), $post_data['reporter'], $post_data['comment_type'] ), 'report-ham'  );
+					update_post_meta( $post_id, '_bbp_akismet_user_result', 'false'                 );
+					update_post_meta( $post_id, '_bbp_akismet_user',         $post_data['reporter'] );
+
+					// @todo Topic term revision history
+					break;
+
+				// Possible other actions
+				default :
+					break;
+			}
+		}
+
+		do_action( 'bbp_akismet_submit_' . $request_type . '_post', $post_id, $post_data['bbp_akismet_result'] );
+	}
+
+	/**
+	 * Ping Akismet service and check for spam/ham response
+	 *
+	 * @since bbPress (r3277)
+	 *
+	 * @param array $post_data
+	 * @param string $check Accepts check|submit
+	 * @param string $spam Accepts spam|ham
+	 *
+	 * @global string $akismet_api_host
+	 * @global string $akismet_api_port
+	 *
+	 * @uses akismet_test_mode() To determine if Akismet is in test mode
+	 * @uses akismet_http_post() To send data to the mothership for processing
+	 *
+	 * @return array Array of post data
+	 */
+	private function maybe_spam( $post_data, $check = 'check', $spam = 'spam' ) {
+		global $akismet_api_host, $akismet_api_port;
+
+		// Define variables
+		$query_string = $path = $response = '';
+
+		// Populate post data
+		$post_data['blog']         = get_option( 'home' );
+		$post_data['blog_charset'] = get_option( 'blog_charset' );
+		$post_data['blog_lang']    = get_locale();
+		$post_data['referrer']     = $_SERVER['HTTP_REFERER'];
+		$post_data['user_agent']   = $_SERVER['HTTP_USER_AGENT'];
+
+		// Akismet Test Mode
+		if ( akismet_test_mode() )
+			$post_data['is_test'] = 'true';
+
+		// Loop through _POST args and rekey strings
+		foreach ( $_POST as $key => $value )
+			if ( is_string( $value ) )
+				$post_data['POST_' . $key] = $value;
+
+		// Keys to ignore
+		$ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );
+
+		// Loop through _SERVER args and remove whitelisted keys
+		foreach ( $_SERVER as $key => $value ) {
+
+			// Key should not be ignored
+			if ( !in_array( $key, $ignore ) && is_string( $value ) ) {
+				$post_data[$key] = $value;
+
+			// Key should be ignored
+			} else {
+				$post_data[$key] = '';
+			}
+		}
+
+		// Ready...
+		foreach ( $post_data as $key => $data )
+			$query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';
+
+		// Aim...
+		if ( 'check' === $check ) {
+			$path = '/1.1/comment-check';
+		} elseif ( 'submit' === $check ) {
+			$path = '/1.1/submit-' . $spam;
+		}
+
+		// Fire!
+		$response = $this->http_post( $query_string, $akismet_api_host, $path, $akismet_api_port );
+
+		// Check the high-speed cam
+		if ( !empty( $response[1] ) ) {
+			$post_data['bbp_akismet_result'] = $response[1];
+		} else {
+			$post_data['bbp_akismet_result'] = esc_html__( 'No response', 'bbpress' );
+		}
+
+		// This is ham
+		return $post_data;
+	}
+
+	/**
+	 * Update post meta after a spam check
+	 *
+	 * @since bbPress (r3308)
+	 *
+	 * @param int $post_id
+	 * @param object $_post
+	 *
+	 * @global object $this->last_post
+	 *
+	 * @uses get_post() To get the post object
+	 * @uses get_userdata() To get the user data
+	 * @uses bbp_filter_anonymous_user_data() To get anonymous user data
+	 * @uses update_post_meta() To update post meta with Akismet data
+	 * @uses BBP_Akismet::update_post_history() To update post Akismet history
+	 */
+	public function update_post_meta( $post_id = 0, $_post = false ) {
+
+		// Define local variable(s)
+		$as_submitted = false;
+
+		// Setup some variables
+		$post_id = (int) $post_id;
+
+		// Ensure we have a post object
+		if ( empty( $_post ) )
+			$_post = get_post( $post_id );
+
+		// Set up Akismet last post data
+		if ( !empty( $this->last_post ) )
+			$as_submitted = $this->last_post['bbp_post_as_submitted'];
+
+		// wp_insert_post() might be called in other contexts. Ensure this is
+		// the same topic/reply as was checked by BBP_Akismet::check_post()
+		if ( is_object( $_post ) && !empty( $this->last_post ) && is_array( $as_submitted ) ) {
+
+			// Get user data
+			$userdata       = get_userdata( $_post->post_author );
+			$anonymous_data = bbp_filter_anonymous_post_data();
+
+			// More checks
+			if (	intval( $as_submitted['comment_post_ID'] )    === intval( $_post->post_parent )
+					&&      $as_submitted['comment_author']       === ( $anonymous_data ? $anonymous_data['bbp_anonymous_name']  : $userdata->display_name )
+					&&      $as_submitted['comment_author_email'] === ( $anonymous_data ? $anonymous_data['bbp_anonymous_email'] : $userdata->user_email   )
+				) {
+
+				// Normal result: true
+				if ( $this->last_post['bbp_akismet_result'] === 'true' ) {
+
+					// Leave a trail so other's know what we did
+					update_post_meta( $post_id, '_bbp_akismet_result', 'true' );
+					$this->update_post_history( $post_id, esc_html__( 'Akismet caught this post as spam', 'bbpress' ), 'check-spam' );
+
+					// If post_status isn't the spam status, as expected, leave a note
+					if ( bbp_get_spam_status_id() !== $_post->post_status ) {
+						$this->update_post_history( $post_id, sprintf( esc_html__( 'Post status was changed to %s', 'bbpress' ), $_post->post_status ), 'status-changed-' . $_post->post_status );
+					}
+
+				// Normal result: false
+				} elseif ( $this->last_post['bbp_akismet_result'] === 'false' ) {
+
+					// Leave a trail so other's know what we did
+					update_post_meta( $post_id, '_bbp_akismet_result', 'false' );
+					$this->update_post_history( $post_id, esc_html__( 'Akismet cleared this post as not spam', 'bbpress' ), 'check-ham' );
+
+					// If post_status is the spam status, which isn't expected, leave a note
+					if ( bbp_get_spam_status_id() === $_post->post_status ) {
+
+						// @todo Use wp_blacklist_check()
+
+						$this->update_post_history( $post_id, sprintf( esc_html__( 'Post status was changed to %s', 'bbpress' ), $_post->post_status ), 'status-changed-' . $_post->post_status );
+					}
+
+				// Abnormal result: error
+				} else {
+					// Leave a trail so other's know what we did
+					update_post_meta( $post_id, '_bbp_akismet_error', time() );
+					$this->update_post_history( $post_id, sprintf( esc_html__( 'Akismet was unable to check this post (response: %s), will automatically retry again later.', 'bbpress' ), $this->last_post['bbp_akismet_result'] ), 'check-error' );
+				}
+
+				// Record the complete original data as submitted for checking
+				if ( isset( $this->last_post['bbp_post_as_submitted'] ) ) {
+					update_post_meta( $post_id, '_bbp_akismet_as_submitted', $this->last_post['bbp_post_as_submitted'] );
+				}
+			}
+		}
+	}
+
+	/**
+	 * Update a post's Akismet history
+	 *
+	 * @since bbPress (r3308)
+	 *
+	 * @param int $post_id
+	 * @param string $message
+	 * @param string $event
+	 *
+	 * @uses wp_get_current_user() To get the current_user object
+	 * @uses add_post_meta() Add Akismet post history
+	 */
+	private function update_post_history( $post_id = 0, $message = null, $event = null ) {
+
+		// Define local variable(s)
+		$user = '';
+
+		// Get the current user
+		$current_user = wp_get_current_user();
+
+		// Get the user's login name if possible
+		if ( is_object( $current_user ) && isset( $current_user->user_login ) )
+			$user = $current_user->user_login;
+
+		// Setup the event to be saved
+		$event = array(
+			'time'    => akismet_microtime(),
+			'message' => $message,
+			'event'   => $event,
+			'user'    => $user,
+		);
+
+		// Save the event data
+		add_post_meta( $post_id, '_bbp_akismet_history', $event );
+	}
+
+	/**
+	 * Get a post's Akismet history
+	 *
+	 * @since bbPress (r3308)
+	 *
+	 * @param int $post_id
+	 *
+	 * @uses wp_get_current_user() To get the current_user object
+	 * @uses get_post_meta() Get a post's Akismet history
+	 *
+	 * @return array Array of a post's Akismet history
+	 */
+	public function get_post_history( $post_id = 0 ) {
+
+		// Retrieve any previous history
+		$history = get_post_meta( $post_id, '_bbp_akismet_history' );
+
+		// Sort it by the time recorded
+		usort( $history, 'akismet_cmp_time' );
+
+		return $history;
+	}
+
+	/**
+	 * Handle any terms submitted with a post flagged as spam
+	 *
+	 * @since bbPress (r3308)
+	 *
+	 * @param string $terms Comma-separated list of terms
+	 * @param int $topic_id
+	 * @param int $reply_id
+	 *
+	 * @uses bbp_get_reply_id() To get the reply_id
+	 * @uses bbp_get_topic_id() To get the topic_id
+	 * @uses wp_get_object_terms() To a post's current terms
+	 * @uses update_post_meta() To add spam terms to post meta
+	 *
+	 * @return array Array of existing topic terms
+	 */
+	public function filter_post_terms( $terms = '', $topic_id = 0, $reply_id = 0 ) {
+
+		// Validate the reply_id and topic_id
+		$reply_id = bbp_get_reply_id( $reply_id );
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Get any pre-existing terms
+		$existing_terms = wp_get_object_terms( $topic_id, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );
+
+		// Save the terms for later in case the reply gets hammed
+		if ( !empty( $terms ) )
+			update_post_meta( $reply_id, '_bbp_akismet_spam_terms', $terms );
+
+		// Keep the topic tags the same for now
+		return $existing_terms;
+	}
+
+	/**
+	 * Submit data to Akismet service with unique bbPress User Agent
+	 *
+	 * This code is directly taken from the akismet_http_post() function and
+	 * documented to bbPress 2.0 standard.
+	 *
+	 * @since bbPress (r3466)
+	 *
+	 * @param string $request The request we are sending
+	 * @param string $host The host to send our request to
+	 * @param string $path The path from the host
+	 * @param string $port The port to use
+	 * @param string $ip Optional Override $host with an IP address
+	 * @uses bbp_get_version() To get the current bbPress version
+	 * @return mixed WP_Error on error, array on success, empty on failure
+	 */
+	private function http_post( $request, $host, $path, $port = 80, $ip = '' ) {
+
+		// Preload required variables
+		$bbp_version    = bbp_get_version();
+		$content_length = strlen( $request );
+		$http_host      = $host;
+		$blog_charset   = get_option( 'blog_charset' );
+		$response       = '';
+		$errno          = null;
+		$errstr         = null;
+
+		// Untque User Agent
+		$akismet_ua     = "bbPress/{$bbp_version} | ";
+		$akismet_ua    .= 'Akismet/' . constant( 'AKISMET_VERSION' );
+
+		// Use specific IP (if provided)
+		if ( !empty( $ip ) && long2ip( ip2long( $ip ) ) )
+			$http_host = $ip;
+
+		// WP HTTP class is available
+		if ( function_exists( 'wp_remote_post' ) ) {
+
+			// Setup the arguments
+			$http_args = array(
+				'body'             => $request,
+				'headers'          => array(
+					'Content-Type' => 'application/x-www-form-urlencoded; charset=' . $blog_charset,
+					'Host'         => $host,
+					'User-Agent'   => $akismet_ua
+				),
+				'httpversion'      => '1.0',
+				'timeout'          => 15
+			);
+
+			// Where we are sending our request
+			$akismet_url = 'http://' . $http_host . $path;
+
+			// Send the request
+			$response    = wp_remote_post( $akismet_url, $http_args );
+
+			// Bail if the response is an error
+			if ( is_wp_error( $response ) )
+				return '';
+
+			// No errors so return response
+			return array( $response['headers'], $response['body'] );
+
+		// WP HTTP class is not available (Why not?)
+		} else {
+
+			// Header info to use with our socket
+			$http_request  = "POST {$path} HTTP/1.0\r\n";
+			$http_request .= "Host: {$host}\r\n";
+			$http_request .= "Content-Type: application/x-www-form-urlencoded; charset={$blog_charset}\r\n";
+			$http_request .= "Content-Length: {$content_length}\r\n";
+			$http_request .= "User-Agent: {$akismet_ua}\r\n";
+			$http_request .= "\r\n";
+			$http_request .= $request;
+
+			// Open a socket connection
+			if ( false !== ( $fs = @fsockopen( $http_host, $port, $errno, $errstr, 10 ) ) ) {
+
+				// Write our request to the pointer
+				fwrite( $fs, $http_request );
+
+				// Loop through pointer and compile a response
+				while ( !feof( $fs ) ) {
+					// One TCP-IP packet at a time
+					$response .= fgets( $fs, 1160 );
+				}
+
+				// Close our socket
+				fclose( $fs );
+
+				// Explode the response into usable data
+				$response = explode( "\r\n\r\n", $response, 2 );
+			}
+
+			// Return the response ('' if error/empty)
+			return $response;
+		}
+	}
+
+	/**
+	 * Return a user's roles on this site (including super_admin)
+	 *
+	 * @since bbPress (r4812)
+	 *
+	 * @param type $user_id
+	 * @return boolean
+	 */
+	private function get_user_roles( $user_id = 0 ) {
+
+		// Default return value
+		$roles = array();
+
+		// Bail if cannot query the user
+		if ( ! class_exists( 'WP_User' ) || empty( $user_id ) ) {
+			return false;
+		}
+
+		// User ID
+		$user = new WP_User( $user_id );
+		if ( isset( $user->roles ) ) {
+			$roles = (array) $user->roles;
+		}
+
+		// Super admin
+		if ( is_multisite() && is_super_admin( $user_id ) ) {
+			$roles[] = 'super_admin';
+		}
+
+		return implode( ',', $roles );
+	}
+
+	/** Admin *****************************************************************/
+
+	/**
+	 * Add Aksimet History metaboxes to topics and replies
+	 *
+	 * @since bbPress (r5049)
+	 */
+	public function add_metaboxes() {
+
+		// Topics
+		add_meta_box(
+			'bbp_akismet_topic_history',
+			__( 'Akismet History', 'bbpress' ),
+			array( $this, 'history_metabox' ),
+			bbp_get_topic_post_type(),
+			'normal',
+			'core'
+		);
+
+		// Replies
+		add_meta_box(
+			'bbp_akismet_reply_history',
+			__( 'Akismet History', 'bbpress' ),
+			array( $this, 'history_metabox' ),
+			bbp_get_reply_post_type(),
+			'normal',
+			'core'
+		);
+	}
+
+	/**
+	 * Output for Akismet History metabox
+	 *
+	 * @since bbPress (r5049)
+	 *
+	 * @uses get_post_history() To get the Akismet history for the post
+	 * @uses get_the_ID() To get the post ID
+	 * @uses bbp_time_since() To get the human readable time
+	 */
+	public function history_metabox() {
+
+		// Post ID
+		$history = $this->get_post_history( get_the_ID() ); ?>
+
+		<div class="akismet-history" style="margin: 13px 0;">
+
+			<?php if ( !empty( $history ) ) : ?>
+
+				<table>
+					<tbody>
+
+						<?php foreach ( $history as $row ) : ?>
+
+							<tr>
+								<td style="color: #999; text-align: right; white-space: nowrap;">
+									<span title="<?php echo esc_attr( date( 'D d M Y @ h:i:m a', $row['time'] ) . ' GMT' ); ?>">
+										<?php bbp_time_since( $row['time'], false, true ); ?>
+									</span>
+								</td>
+								<td style="padding-left: 5px;">
+									<?php echo esc_html( $row['message'] ); ?>
+								</td>
+							</tr>
+
+						<?php endforeach; ?>
+					</tbody>
+				</table>
+
+			<?php else : ?>
+
+				<p><?php esc_html_e( 'No recorded history. Akismet has not checked this post.', 'bbpress' ); ?></p>
+
+			<?php endif; ?>
+
+		</div>
+
+		<?php
+	}
+}
+endif;
Index: /tags/2.5.4/includes/extend/buddypress/activity.php
===================================================================
--- /tags/2.5.4/includes/extend/buddypress/activity.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/buddypress/activity.php	(revision 5382)
@@ -0,0 +1,647 @@
+<?php
+
+/**
+ * bbPress BuddyPress Activity Class
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_BuddyPress_Activity' ) ) :
+/**
+ * Loads BuddyPress Activity extension
+ *
+ * @since bbPress (r3395)
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ */
+class BBP_BuddyPress_Activity {
+
+	/** Variables *************************************************************/
+
+	/**
+	 * The name of the BuddyPress component, used in activity streams
+	 *
+	 * @var string
+	 */
+	private $component = '';
+
+	/**
+	 * Forum Create Activity Action
+	 *
+	 * @var string
+	 */
+	private $forum_create = '';
+
+	/**
+	 * Topic Create Activity Action
+	 *
+	 * @var string
+	 */
+	private $topic_create = '';
+
+	/**
+	 * Topic Close Activity Action
+	 *
+	 * @var string
+	 */
+	private $topic_close = '';
+
+	/**
+	 * Topic Edit Activity Action
+	 *
+	 * @var string
+	 */
+	private $topic_edit = '';
+
+	/**
+	 * Topic Open Activity Action
+	 *
+	 * @var string
+	 */
+	private $topic_open = '';
+
+	/**
+	 * Reply Create Activity Action
+	 *
+	 * @var string
+	 */
+	private $reply_create = '';
+
+	/**
+	 * Reply Edit Activity Action
+	 *
+	 * @var string
+	 */
+	private $reply_edit = '';
+
+	/** Setup Methods *********************************************************/
+
+	/**
+	 * The bbPress BuddyPress Activity loader
+	 *
+	 * @since bbPress (r3395)
+	 */
+	public function __construct() {
+		$this->setup_globals();
+		$this->setup_actions();
+		$this->setup_filters();
+		$this->fully_loaded();
+	}
+
+	/**
+	 * Extension variables
+	 *
+	 * @since bbPress (r3395)
+	 * @access private
+	 * @uses apply_filters() Calls various filters
+	 */
+	private function setup_globals() {
+
+		// The name of the BuddyPress component, used in activity streams
+		$this->component    = 'bbpress';
+
+		// Forums
+		$this->forum_create = 'bbp_forum_create';
+
+		// Topics
+		$this->topic_create = 'bbp_topic_create';
+		$this->topic_edit   = 'bbp_topic_edit';
+		$this->topic_close  = 'bbp_topic_close';
+		$this->topic_open   = 'bbp_topic_open';
+
+		// Replies
+		$this->reply_create = 'bbp_reply_create';
+		$this->reply_edit   = 'bbp_reply_edit';
+	}
+
+	/**
+	 * Setup the actions
+	 *
+	 * @since bbPress (r3395)
+	 * @access private
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_actions() {
+
+		// Register the activity stream actions
+		add_action( 'bp_register_activity_actions',      array( $this, 'register_activity_actions' )        );
+
+		// Hook into topic and reply creation
+		add_action( 'bbp_new_topic',                     array( $this, 'topic_create'              ), 10, 4 );
+		add_action( 'bbp_new_reply',                     array( $this, 'reply_create'              ), 10, 5 );
+
+		// Hook into topic and reply status changes
+		add_action( 'edit_post',                         array( $this, 'topic_update'              ), 10, 2 );
+		add_action( 'edit_post',                         array( $this, 'reply_update'              ), 10, 2 );
+
+		// Hook into topic and reply deletion
+		add_action( 'bbp_delete_topic',                  array( $this, 'topic_delete'              ), 10, 1 );
+		add_action( 'bbp_delete_reply',                  array( $this, 'reply_delete'              ), 10, 1 );
+
+		// Append forum filters in site wide activity streams
+		add_action( 'bp_activity_filter_options',        array( $this, 'activity_filter_options'   ), 10    );
+
+		// Append forum filters in single member activity streams
+		add_action( 'bp_member_activity_filter_options', array( $this, 'activity_filter_options'   ), 10    );
+
+		// Append forum filters in single group activity streams
+		add_action( 'bp_group_activity_filter_options',  array( $this, 'activity_filter_options'   ), 10    );
+	}
+
+	/**
+	 * Setup the filters
+	 *
+	 * @since bbPress (r3395)
+	 * @access private
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_filters() {
+
+		// Obey BuddyPress commenting rules
+		add_filter( 'bp_activity_can_comment',   array( $this, 'activity_can_comment'   )        );
+
+		// Link directly to the topic or reply
+		add_filter( 'bp_activity_get_permalink', array( $this, 'activity_get_permalink' ), 10, 2 );
+	}
+
+	/**
+	 * Allow the variables, actions, and filters to be modified by third party
+	 * plugins and themes.
+	 *
+	 * @since bbPress (r3902)
+	 */
+	private function fully_loaded() {
+		do_action_ref_array( 'bbp_buddypress_activity_loaded', array( $this ) );
+	}
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * Register our activity actions with BuddyPress
+	 *
+	 * @since bbPress (r3395)
+	 * @uses bp_activity_set_action()
+	 */
+	public function register_activity_actions() {
+
+		// Sitewide activity stream items
+		bp_activity_set_action( $this->component, $this->topic_create, esc_html__( 'New forum topic', 'bbpress' ) );
+		bp_activity_set_action( $this->component, $this->reply_create, esc_html__( 'New forum reply', 'bbpress' ) );
+	}
+
+	/**
+	 * Wrapper for recoding bbPress actions to the BuddyPress activity stream
+	 *
+	 * @since bbPress (r3395)
+	 * @param type $args Array of arguments for bp_activity_add()
+	 * @uses bbp_get_current_user_id()
+	 * @uses bp_core_current_time()
+	 * @uses bbp_parse_args()
+	 * @uses aplly_filters()
+	 * @uses bp_activity_add()
+	 * @return type Activity ID if successful, false if not
+	 */
+	private function record_activity( $args = array() ) {
+
+		// Default activity args
+		$activity = bbp_parse_args( $args, array(
+			'id'                => null,
+			'user_id'           => bbp_get_current_user_id(),
+			'type'              => '',
+			'action'            => '',
+			'item_id'           => '',
+			'secondary_item_id' => '',
+			'content'           => '',
+			'primary_link'      => '',
+			'component'         => $this->component,
+			'recorded_time'     => bp_core_current_time(),
+			'hide_sitewide'     => false
+		), 'record_activity' );
+
+		// Add the activity
+		return bp_activity_add( $activity );
+	}
+
+	/**
+	 * Wrapper for deleting bbPress actions from BuddyPress activity stream
+	 *
+	 * @since bbPress (r3395)
+	 * @param type $args Array of arguments for bp_activity_add()
+	 * @uses bbp_get_current_user_id()
+	 * @uses bp_core_current_time()
+	 * @uses bbp_parse_args()
+	 * @uses aplly_filters()
+	 * @uses bp_activity_add()
+	 * @return type Activity ID if successful, false if not
+	 */
+	public function delete_activity( $args = '' ) {
+
+		// Default activity args
+		$activity = bbp_parse_args( $args, array(
+			'item_id'           => false,
+			'component'         => $this->component,
+			'type'              => false,
+			'user_id'           => false,
+			'secondary_item_id' => false
+		), 'delete_activity' );
+
+		// Delete the activity
+		bp_activity_delete_by_item_id( $activity );
+	}
+
+	/**
+	 * Check for an existing activity stream entry for a given post_id
+	 *
+	 * @param int $post_id ID of the topic or reply
+	 * @uses get_post_meta()
+	 * @uses bp_activity_get_specific()
+	 * @return int if an activity id is verified, false if not
+	 */
+	private static function get_activity_id( $post_id = 0 ) {
+
+		// Try to get the activity ID of the post
+		$activity_id = (int) get_post_meta( $post_id, '_bbp_activity_id', true );
+
+		// Bail if no activity ID is in post meta
+		if ( empty( $activity_id ) )
+			return null;
+
+		// Get the activity stream item, bail if it doesn't exist
+		$existing = bp_activity_get_specific( array( 'activity_ids' => $activity_id, 'show_hidden' => true, 'spam' => 'all', ) );
+		if ( empty( $existing['total'] ) || ( 1 !== (int) $existing['total'] ) )
+			return null;
+
+		// Return the activity ID since we've verified the connection
+		return $activity_id;
+	}
+
+	/**
+	 * Maybe disable activity stream comments on select actions
+	 *
+	 * @since bbPress (r3399)
+	 * @global BP_Activity_Template $activities_template
+	 * @param boolean $can_comment
+	 * @uses bp_get_activity_action_name()
+	 * @return boolean
+	 */
+	public function activity_can_comment( $can_comment = true ) {
+		global $activities_template;
+
+		// Already forced off, so comply
+		if ( false === $can_comment )
+			return $can_comment;
+
+		// Check if blog & forum activity stream commenting is off
+		if ( ( false === $activities_template->disable_blogforum_replies ) || (int) $activities_template->disable_blogforum_replies ) {
+
+			// Get the current action name
+			$action_name = bp_get_activity_action_name();
+
+			// Setup the array of possibly disabled actions
+			$disabled_actions = array(
+				$this->topic_create,
+				$this->reply_create
+			);
+
+			// Check if this activity stream action is disabled
+			if ( in_array( $action_name, $disabled_actions ) ) {
+				$can_comment = false;
+			}
+		}
+
+		return $can_comment;
+	}
+
+	/**
+	 * Maybe link directly to topics and replies in activity stream entries
+	 *
+	 * @since bbPress (r3399)
+	 * @param string $link
+	 * @param mixed $activity_object
+	 * @return string The link to the activity stream item
+	 */
+	public function activity_get_permalink( $link = '', $activity_object = false ) {
+
+		// Setup the array of actions to link directly to
+		$disabled_actions = array(
+			$this->topic_create,
+			$this->reply_create
+		);
+
+		// Check if this activity stream action is directly linked
+		if ( in_array( $activity_object->type, $disabled_actions ) ) {
+			$link = $activity_object->primary_link;
+		}
+
+		return $link;
+	}
+
+	/**
+	 * Append forum options to activity filter select box
+	 *
+	 * @since bbPress (r3653)
+	 */
+	function activity_filter_options() {
+	?>
+
+		<option value="<?php echo $this->topic_create; ?>"><?php esc_html_e( 'Topics',  'bbpress' ); ?></option>
+		<option value="<?php echo $this->reply_create; ?>"><?php esc_html_e( 'Replies', 'bbpress' ); ?></option>
+
+	<?php
+	}
+
+	/** Topics ****************************************************************/
+
+	/**
+	 * Record an activity stream entry when a topic is created or updated
+	 *
+	 * @since bbPress (r3395)
+	 * @param int $topic_id
+	 * @param int $forum_id
+	 * @param array $anonymous_data
+	 * @param int $topic_author_id
+	 * @uses bbp_get_topic_id()
+	 * @uses bbp_get_forum_id()
+	 * @uses bbp_get_user_profile_link()
+	 * @uses bbp_get_topic_permalink()
+	 * @uses bbp_get_topic_title()
+	 * @uses bbp_get_topic_content()
+	 * @uses bbp_get_forum_permalink()
+	 * @uses bbp_get_forum_title()
+	 * @uses bp_create_excerpt()
+	 * @uses apply_filters()
+	 * @return Bail early if topic is by anonymous user
+	 */
+	public function topic_create( $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $topic_author_id = 0 ) {
+
+		// Bail early if topic is by anonymous user
+		if ( !empty( $anonymous_data ) )
+			return;
+
+		// Bail if site is private
+		if ( !bbp_is_site_public() )
+			return;
+
+		// Validate activity data
+		$user_id  = (int) $topic_author_id;
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		// Bail if user is not active
+		if ( bbp_is_user_inactive( $user_id ) )
+			return;
+
+		// Bail if topic is not published
+		if ( !bbp_is_topic_published( $topic_id ) )
+			return;
+
+		// User link for topic author
+		$user_link = bbp_get_user_profile_link( $user_id  );
+
+		// Topic
+		$topic_permalink = bbp_get_topic_permalink( $topic_id );
+		$topic_title     = get_post_field( 'post_title',   $topic_id, 'raw' );
+		$topic_content   = get_post_field( 'post_content', $topic_id, 'raw' );
+		$topic_link      = '<a href="' . $topic_permalink . '">' . $topic_title . '</a>';
+
+		// Forum
+		$forum_permalink = bbp_get_forum_permalink( $forum_id );
+		$forum_title     = get_post_field( 'post_title', $forum_id, 'raw' );
+		$forum_link      = '<a href="' . $forum_permalink . '">' . $forum_title . '</a>';
+
+		// Activity action & text
+		$activity_text    = sprintf( esc_html__( '%1$s started the topic %2$s in the forum %3$s', 'bbpress' ), $user_link, $topic_link, $forum_link );
+		$activity_action  = apply_filters( 'bbp_activity_topic_create',         $activity_text, $user_id,   $topic_id,   $forum_id );
+		$activity_content = apply_filters( 'bbp_activity_topic_create_excerpt', $topic_content                                     );
+
+		// Compile and record the activity stream results
+		$activity_id = $this->record_activity( array(
+			'id'                => $this->get_activity_id( $topic_id ),
+			'user_id'           => $user_id,
+			'action'            => $activity_action,
+			'content'           => $activity_content,
+			'primary_link'      => $topic_permalink,
+			'type'              => $this->topic_create,
+			'item_id'           => $topic_id,
+			'secondary_item_id' => $forum_id,
+			'recorded_time'     => get_post_time( 'Y-m-d H:i:s', true, $topic_id ),
+			'hide_sitewide'     => ! bbp_is_forum_public( $forum_id, false )
+		) );
+
+		// Add the activity entry ID as a meta value to the topic
+		if ( !empty( $activity_id ) ) {
+			update_post_meta( $topic_id, '_bbp_activity_id', $activity_id );
+		}
+	}
+
+	/**
+	 * Delete the activity stream entry when a topic is spammed, trashed, or deleted
+	 *
+	 * @param int $topic_id
+	 * @uses bp_activity_delete()
+	 */
+	public function topic_delete( $topic_id = 0 ) {
+
+		// Get activity ID, bail if it doesn't exist
+		if ( $activity_id = $this->get_activity_id( $topic_id ) )
+			return bp_activity_delete( array( 'id' => $activity_id ) );
+
+		return false;
+	}
+
+	/**
+	 * Update the activity stream entry when a topic status changes
+	 *
+	 * @param int $post_id
+	 * @param obj $post
+	 * @uses get_post_type()
+	 * @uses bbp_get_topic_post_type()
+	 * @uses bbp_get_topic_id()
+	 * @uses bbp_is_topic_anonymous()
+	 * @uses bbp_get_public_status_id()
+	 * @uses bbp_get_closed_status_id()
+	 * @uses bbp_get_topic_forum_id()
+	 * @uses bbp_get_topic_author_id()
+	 * @return Bail early if not a topic, or topic is by anonymous user
+	 */
+	public function topic_update( $topic_id = 0, $post = null ) {
+
+		// Bail early if not a topic
+		if ( get_post_type( $post ) !== bbp_get_topic_post_type() )
+			return;
+
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Bail early if topic is by anonymous user
+		if ( bbp_is_topic_anonymous( $topic_id ) )
+			return;
+
+		// Action based on new status
+		if ( in_array( $post->post_status, array( bbp_get_public_status_id(), bbp_get_closed_status_id() ) ) ) {
+
+			// Validate topic data
+			$forum_id        = bbp_get_topic_forum_id( $topic_id );
+			$topic_author_id = bbp_get_topic_author_id( $topic_id );
+
+			$this->topic_create( $topic_id, $forum_id, array(), $topic_author_id );
+		} else {
+			$this->topic_delete( $topic_id );
+		}
+	}
+
+	/** Replies ***************************************************************/
+
+	/**
+	 * Record an activity stream entry when a reply is created
+	 *
+	 * @since bbPress (r3395)
+	 * @param int $topic_id
+	 * @param int $forum_id
+	 * @param array $anonymous_data
+	 * @param int $topic_author_id
+	 * @uses bbp_get_reply_id()
+	 * @uses bbp_get_topic_id()
+	 * @uses bbp_get_forum_id()
+	 * @uses bbp_get_user_profile_link()
+	 * @uses bbp_get_reply_url()
+	 * @uses bbp_get_reply_content()
+	 * @uses bbp_get_topic_permalink()
+	 * @uses bbp_get_topic_title()
+	 * @uses bbp_get_forum_permalink()
+	 * @uses bbp_get_forum_title()
+	 * @uses bp_create_excerpt()
+	 * @uses apply_filters()
+	 * @return Bail early if topic is by anonywous user
+	 */
+	public function reply_create( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $reply_author_id = 0 ) {
+
+		// Do not log activity of anonymous users
+		if ( !empty( $anonymous_data ) )
+			return;
+
+		// Bail if site is private
+		if ( !bbp_is_site_public() )
+			return;
+
+		// Validate activity data
+		$user_id  = (int) $reply_author_id;
+		$reply_id = bbp_get_reply_id( $reply_id );
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		// Bail if user is not active
+		if ( bbp_is_user_inactive( $user_id ) )
+			return;
+
+		// Bail if reply is not published
+		if ( !bbp_is_reply_published( $reply_id ) )
+			return;
+
+		// Setup links for activity stream
+		$user_link = bbp_get_user_profile_link( $user_id  );
+
+		// Reply
+		$reply_url     = bbp_get_reply_url( $reply_id );
+		$reply_content = get_post_field( 'post_content', $reply_id, 'raw' );
+
+		// Topic
+		$topic_permalink = bbp_get_topic_permalink( $topic_id );
+		$topic_title     = get_post_field( 'post_title', $topic_id, 'raw' );
+		$topic_link      = '<a href="' . $topic_permalink . '">' . $topic_title . '</a>';
+
+		// Forum
+		$forum_permalink = bbp_get_forum_permalink( $forum_id );
+		$forum_title     = get_post_field( 'post_title', $forum_id, 'raw' );
+		$forum_link      = '<a href="' . $forum_permalink . '">' . $forum_title . '</a>';
+
+		// Activity action & text
+		$activity_text    = sprintf( esc_html__( '%1$s replied to the topic %2$s in the forum %3$s', 'bbpress' ), $user_link, $topic_link, $forum_link );
+		$activity_action  = apply_filters( 'bbp_activity_reply_create',         $activity_text, $user_id, $reply_id,  $topic_id );
+		$activity_content = apply_filters( 'bbp_activity_reply_create_excerpt', $reply_content                                  );
+
+		// Compile and record the activity stream results
+		$activity_id = $this->record_activity( array(
+			'id'                => $this->get_activity_id( $reply_id ),
+			'user_id'           => $user_id,
+			'action'            => $activity_action,
+			'content'           => $activity_content,
+			'primary_link'      => $reply_url,
+			'type'              => $this->reply_create,
+			'item_id'           => $reply_id,
+			'secondary_item_id' => $topic_id,
+			'recorded_time'     => get_post_time( 'Y-m-d H:i:s', true, $reply_id ),
+			'hide_sitewide'     => ! bbp_is_forum_public( $forum_id, false )
+		) );
+
+		// Add the activity entry ID as a meta value to the reply
+		if ( !empty( $activity_id ) ) {
+			update_post_meta( $reply_id, '_bbp_activity_id', $activity_id );
+		}
+	}
+
+ 	/**
+	 * Delete the activity stream entry when a reply is spammed, trashed, or deleted
+	 *
+	 * @param int $reply_id
+	 * @uses get_post_meta()
+	 * @uses bp_activity_delete()
+	 */
+	public function reply_delete( $reply_id ) {
+
+		// Get activity ID, bail if it doesn't exist
+		if ( $activity_id = $this->get_activity_id( $reply_id ) )
+			return bp_activity_delete( array( 'id' => $activity_id ) );
+
+		return false;
+	}
+
+	/**
+	 * Update the activity stream entry when a reply status changes
+	 *
+	 * @param int $post_id
+	 * @param obj $post
+	 * @uses get_post_type()
+	 * @uses bbp_get_reply_post_type()
+	 * @uses bbp_get_reply_id()
+	 * @uses bbp_is_reply_anonymous()
+	 * @uses bbp_get_public_status_id()
+	 * @uses bbp_get_closed_status_id()
+	 * @uses bbp_get_reply_topic_id()
+	 * @uses bbp_get_reply_forum_id()
+	 * @uses bbp_get_reply_author_id()
+	 * @return Bail early if not a reply, or reply is by anonymous user
+	 */
+	public function reply_update( $reply_id, $post ) {
+
+		// Bail early if not a reply
+		if ( get_post_type( $post ) !== bbp_get_reply_post_type() )
+			return;
+
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// Bail early if reply is by anonymous user
+		if ( bbp_is_reply_anonymous( $reply_id ) )
+			return;
+
+		// Action based on new status
+		if ( bbp_get_public_status_id() === $post->post_status ) {
+
+			// Validate reply data
+			$topic_id        = bbp_get_reply_topic_id( $reply_id );
+			$forum_id        = bbp_get_reply_forum_id( $reply_id );
+			$reply_author_id = bbp_get_reply_author_id( $reply_id );
+
+			$this->reply_create( $reply_id, $topic_id, $forum_id, array(), $reply_author_id );
+		} else {
+			$this->reply_delete( $reply_id );
+		}
+	}
+}
+endif;
Index: /tags/2.5.4/includes/extend/buddypress/functions.php
===================================================================
--- /tags/2.5.4/includes/extend/buddypress/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/buddypress/functions.php	(revision 5382)
@@ -0,0 +1,685 @@
+<?php
+
+/**
+ * Main bbPress BuddyPress Class
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ * @todo maybe move to BuddyPress Forums once bbPress 1.1 can be removed
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** BuddyPress Helpers ********************************************************/
+
+/**
+ * Return bbPress's component name/ID ('forums' by default)
+ *
+ * This is used primarily for Notifications integration.
+ *
+ * @since bbPress (r5232)
+ * @return string
+ */
+function bbp_get_component_name() {
+
+	// Use existing ID
+	if ( !empty( bbpress()->extend->buddypress->id ) ) {
+		$retval = bbpress()->extend->buddypress->id;
+
+	// Use default
+	} else {
+		$retval = 'forums';
+	}
+
+	return apply_filters( 'bbp_get_component_name', $retval );
+}
+
+/**
+ * Filter the current bbPress user ID with the current BuddyPress user ID
+ *
+ * @since bbPress (r3552)
+ *
+ * @param int $user_id
+ * @param bool $displayed_user_fallback
+ * @param bool $current_user_fallback
+ *
+ * @return int User ID
+ */
+function bbp_filter_user_id( $user_id = 0, $displayed_user_fallback = true, $current_user_fallback = false ) {
+
+	// Define local variable
+	$bbp_user_id = 0;
+
+	// Get possible user ID's
+	$did = bp_displayed_user_id();
+	$lid = bp_loggedin_user_id();
+
+	// Easy empty checking
+	if ( !empty( $user_id ) && is_numeric( $user_id ) )
+		$bbp_user_id = $user_id;
+
+	// Currently viewing or editing a user
+	elseif ( ( true === $displayed_user_fallback ) && !empty( $did ) )
+		$bbp_user_id = $did;
+
+	// Maybe fallback on the current_user ID
+	elseif ( ( true === $current_user_fallback ) && !empty( $lid ) )
+		$bbp_user_id = $lid;
+
+	return $bbp_user_id;
+}
+add_filter( 'bbp_get_user_id', 'bbp_filter_user_id', 10, 3 );
+
+/**
+ * Filter the bbPress is_single_user function with BuddyPress eqivalent
+ *
+ * @since bbPress (r3552)
+ *
+ * @param bool $is Optional. Default false
+ * @return bool True if viewing single user, false if not
+ */
+function bbp_filter_is_single_user( $is = false ) {
+	if ( !empty( $is ) )
+		return $is;
+
+	return bp_is_user();
+}
+add_filter( 'bbp_is_single_user', 'bbp_filter_is_single_user', 10, 1 );
+
+/**
+ * Filter the bbPress is_user_home function with BuddyPress eqivalent
+ *
+ * @since bbPress (r3552)
+ *
+ * @param bool $is Optional. Default false
+ * @return bool True if viewing single user, false if not
+ */
+function bbp_filter_is_user_home( $is = false ) {
+	if ( !empty( $is ) )
+		return $is;
+
+	return bp_is_my_profile();
+}
+add_filter( 'bbp_is_user_home', 'bbp_filter_is_user_home', 10, 1 );
+
+/**
+ * Add the topic title to the <title> if viewing a single group forum topic
+ *
+ * @since bbPress (r5161)
+ *
+ * @param string $new_title The title to filter
+ * @param string $old_title (Not used)
+ * @param string $sep The separator to use
+ * @return string The possibly modified title
+ */
+function bbp_filter_modify_page_title( $new_title = '', $old_title = '', $sep = '' ) {
+
+	// Only filter if group forums are active
+	if ( bbp_is_group_forums_active() ) {
+
+		// Only filter for single group forum topics
+		if ( bp_is_group_forum_topic() || bp_is_group_forum_topic_edit() ) {
+
+			// Get the topic
+			$topic = get_posts( array(
+				'name'        => bp_action_variable( 1 ),
+				'post_status' => 'publish',
+				'post_type'   => bbp_get_topic_post_type(),
+				'numberposts' => 1
+			) );
+
+			// Add the topic title to the <title>
+			$new_title .= bbp_get_topic_title( $topic[0]->ID ) . ' ' . $sep . ' ';
+		}
+	}
+
+	// Return the title
+	return $new_title;
+}
+add_action( 'bp_modify_page_title', 'bbp_filter_modify_page_title', 10, 3 );
+
+/** BuddyPress Screens ********************************************************/
+
+/**
+ * Hook bbPress topics template into plugins template
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses add_action() To add the content hook
+ * @uses bp_core_load_template() To load the plugins template
+ */
+function bbp_member_forums_screen_topics() {
+	add_action( 'bp_template_content', 'bbp_member_forums_topics_content' );
+	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_topics', 'members/single/plugins' ) );
+}
+
+/**
+ * Hook bbPress replies template into plugins template
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses add_action() To add the content hook
+ * @uses bp_core_load_template() To load the plugins template
+ */
+function bbp_member_forums_screen_replies() {
+	add_action( 'bp_template_content', 'bbp_member_forums_replies_content' );
+	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_replies', 'members/single/plugins' ) );
+}
+
+/**
+ * Hook bbPress favorites template into plugins template
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses add_action() To add the content hook
+ * @uses bp_core_load_template() To load the plugins template
+ */
+function bbp_member_forums_screen_favorites() {
+	add_action( 'bp_template_content', 'bbp_member_forums_favorites_content' );
+	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_favorites', 'members/single/plugins' ) );
+}
+
+/**
+ * Hook bbPress subscriptions template into plugins template
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses add_action() To add the content hook
+ * @uses bp_core_load_template() To load the plugins template
+ */
+function bbp_member_forums_screen_subscriptions() {
+	add_action( 'bp_template_content', 'bbp_member_forums_subscriptions_content' );
+	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_subscriptions', 'members/single/plugins' ) );
+}
+
+/** BuddyPress Templates ******************************************************/
+
+/**
+ * Get the topics created template part
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses bbp_get_template_part()s
+ */
+function bbp_member_forums_topics_content() {
+?>
+
+	<div id="bbpress-forums">
+
+		<?php bbp_get_template_part( 'user', 'topics-created' ); ?>
+
+	</div>
+
+<?php
+}
+
+/**
+ * Get the topics replied to template part
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses bbp_get_template_part()
+ */
+function bbp_member_forums_replies_content() {
+?>
+
+	<div id="bbpress-forums">
+
+		<?php bbp_get_template_part( 'user', 'replies-created' ); ?>
+
+	</div>
+
+<?php
+}
+
+/**
+ * Get the topics favorited template part
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses bbp_get_template_part()
+ */
+function bbp_member_forums_favorites_content() {
+?>
+
+	<div id="bbpress-forums">
+
+		<?php bbp_get_template_part( 'user', 'favorites' ); ?>
+
+	</div>
+
+<?php
+}
+
+/**
+ * Get the topics subscribed template part
+ *
+ * @since bbPress (r3552)
+ *
+ * @uses bbp_get_template_part()
+ */
+function bbp_member_forums_subscriptions_content() {
+?>
+
+	<div id="bbpress-forums">
+
+		<?php bbp_get_template_part( 'user', 'subscriptions' ); ?>
+
+	</div>
+
+<?php
+}
+
+/** Forum/Group Sync **********************************************************/
+
+/**
+ * These functions are used to keep the many-to-many relationships between
+ * groups and forums synchronized. Each forum and group stores ponters to each
+ * other in their respective meta. This way if a group or forum is deleted
+ * their associattions can be updated without much effort.
+ */
+
+/**
+ * Get forum ID's for a group
+ *
+ * @param type $group_id
+ * @since bbPress (r3653)
+ */
+function bbp_get_group_forum_ids( $group_id = 0 ) {
+
+	// Assume no forums
+	$forum_ids = array();
+
+	// Use current group if none is set
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	// Get the forums
+	if ( !empty( $group_id ) )
+		$forum_ids = groups_get_groupmeta( $group_id, 'forum_id' );
+
+	// Make sure result is an array
+	if ( !is_array( $forum_ids ) )
+		$forum_ids = (array) $forum_ids;
+
+	// Trim out any empty array items
+	$forum_ids = array_filter( $forum_ids );
+
+	return (array) apply_filters( 'bbp_get_group_forum_ids', $forum_ids, $group_id );
+}
+
+/**
+ * Get group ID's for a forum
+ *
+ * @param type $forum_id
+ * @since bbPress (r3653)
+ */
+function bbp_get_forum_group_ids( $forum_id = 0 ) {
+
+	// Assume no forums
+	$group_ids = array();
+
+	// Use current group if none is set
+	if ( empty( $forum_id ) )
+		$forum_id = bbp_get_forum_id();
+
+	// Get the forums
+	if ( !empty( $forum_id ) )
+		$group_ids = get_post_meta( $forum_id, '_bbp_group_ids', true );
+
+	// Make sure result is an array
+	if ( !is_array( $group_ids ) )
+		$group_ids = (array) $group_ids;
+
+	// Trim out any empty array items
+	$group_ids = array_filter( $group_ids );
+
+	return (array) apply_filters( 'bbp_get_forum_group_ids', $group_ids, $forum_id );
+}
+
+/**
+ * Get forum ID's for a group
+ *
+ * @param type $group_id
+ * @since bbPress (r3653)
+ */
+function bbp_update_group_forum_ids( $group_id = 0, $forum_ids = array() ) {
+
+	// Use current group if none is set
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	// Trim out any empties
+	$forum_ids = array_filter( $forum_ids );
+
+	// Get the forums
+	return groups_update_groupmeta( $group_id, 'forum_id', $forum_ids );
+}
+
+/**
+ * Update group ID's for a forum
+ *
+ * @param type $forum_id
+ * @since bbPress (r3653)
+ */
+function bbp_update_forum_group_ids( $forum_id = 0, $group_ids = array() ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Trim out any empties
+	$group_ids = array_filter( $group_ids );
+
+	// Get the forums
+	return update_post_meta( $forum_id, '_bbp_group_ids', $group_ids );
+}
+
+/**
+ * Add a group to a forum
+ *
+ * @param type $group_id
+ * @since bbPress (r3653)
+ */
+function bbp_add_group_id_to_forum( $forum_id = 0, $group_id = 0 ) {
+
+	// Validate forum_id
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Use current group if none is set
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	// Get current group IDs
+	$group_ids = bbp_get_forum_group_ids( $forum_id );
+
+	// Maybe update the groups forums
+	if ( !in_array( $group_id, $group_ids ) ) {
+		$group_ids[] = $group_id;
+		return bbp_update_forum_group_ids( $forum_id, $group_ids );
+	}
+}
+
+/**
+ * Remove a forum from a group
+ *
+ * @param type $group_id
+ * @since bbPress (r3653)
+ */
+function bbp_add_forum_id_to_group( $group_id = 0, $forum_id = 0 ) {
+
+	// Validate forum_id
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Use current group if none is set
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	// Get current group IDs
+	$forum_ids = bbp_get_group_forum_ids( $group_id );
+
+	// Maybe update the groups forums
+	if ( !in_array( $forum_id, $forum_ids ) ) {
+		$forum_ids[] = $forum_id;
+		return bbp_update_group_forum_ids( $group_id, $forum_ids );
+	}
+}
+
+/**
+ * Remove a group from a forum
+ *
+ * @param type $group_id
+ * @since bbPress (r3653)
+ */
+function bbp_remove_group_id_from_forum( $forum_id = 0, $group_id = 0 ) {
+
+	// Validate forum_id
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Use current group if none is set
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	// Get current group IDs
+	$group_ids = bbp_get_forum_group_ids( $forum_id );
+
+	// Maybe update the groups forums
+	if ( in_array( $group_id, $group_ids ) ) {
+		$group_ids = array_diff( array_values( $group_ids ), (array) $group_id );
+		return bbp_update_forum_group_ids( $forum_id, $group_ids );
+	}
+}
+
+/**
+ * Remove a forum from a group
+ *
+ * @param type $group_id
+ * @since bbPress (r3653)
+ */
+function bbp_remove_forum_id_from_group( $group_id = 0, $forum_id = 0 ) {
+
+	// Validate forum_id
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Use current group if none is set
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	// Get current group IDs
+	$forum_ids = bbp_get_group_forum_ids( $group_id );
+
+	// Maybe update the groups forums
+	if ( in_array( $forum_id, $forum_ids ) ) {
+		$forum_ids = array_diff( array_values( $forum_ids ), (array) $forum_id );
+		return bbp_update_group_forum_ids( $group_id, $forum_ids );
+	}
+}
+
+/**
+ * Remove a group from aall forums
+ *
+ * @param type $group_id
+ * @since bbPress (r3653)
+ */
+function bbp_remove_group_id_from_all_forums( $group_id = 0 ) {
+
+	// Use current group if none is set
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	// Get current group IDs
+	$forum_ids = bbp_get_group_forum_ids( $group_id );
+
+	// Loop through forums and remove this group from each one
+	foreach ( (array) $forum_ids as $forum_id ) {
+		bbp_remove_group_id_from_forum( $group_id, $forum_id );
+	}
+}
+
+/**
+ * Remove a forum from all groups
+ *
+ * @param type $forum_id
+ * @since bbPress (r3653)
+ */
+function bbp_remove_forum_id_from_all_groups( $forum_id = 0 ) {
+
+	// Validate
+	$forum_id  = bbp_get_forum_id( $forum_id );
+	$group_ids = bbp_get_forum_group_ids( $forum_id );
+
+	// Loop through groups and remove this forum from each one
+	foreach ( (array) $group_ids as $group_id ) {
+		bbp_remove_forum_id_from_group( $forum_id, $group_id );
+	}
+}
+
+/**
+ * Return true if a forum is a group forum
+ *
+ * @since bbPress (r4571)
+ *
+ * @param int $forum_id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_forum_group_ids() To get the forum's group ids
+ * @uses apply_filters() Calls 'bbp_forum_is_group_forum' with the forum id 
+ * @return bool True if it is a group forum, false if not
+ */
+function bbp_is_forum_group_forum( $forum_id = 0 ) {
+
+	// Validate
+	$forum_id  = bbp_get_forum_id( $forum_id );
+
+	// Check for group ID's
+	$group_ids = bbp_get_forum_group_ids( $forum_id );
+
+	// Check if the forum has groups
+	$retval    = (bool) !empty( $group_ids );
+
+	return (bool) apply_filters( 'bbp_is_forum_group_forum', $retval, $forum_id, $group_ids );
+}
+
+/*** Group Member Status ******************************************************/
+
+/**
+ * Is the current user an admin of the current group
+ *
+ * @since bbPress (r4632)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_group()
+ * @uses bbpress()
+ * @uses get_current_user_id()
+ * @uses bp_get_current_group_id()
+ * @uses groups_is_user_admin()
+ * @return bool If current user is an admin of the current group
+ */
+function bbp_group_is_admin() {
+
+	// Bail if user is not logged in or not looking at a group
+	if ( ! is_user_logged_in() || ! bp_is_group() )
+		return false;
+
+	$bbp = bbpress();
+
+	// Set the global if not set
+	if ( ! isset( $bbp->current_user->is_group_admin ) )
+		$bbp->current_user->is_group_admin = groups_is_user_admin( get_current_user_id(), bp_get_current_group_id() );
+
+	// Return the value
+	return (bool) $bbp->current_user->is_group_admin;
+}
+
+/**
+ * Is the current user a moderator of the current group
+ *
+ * @since bbPress (r4632)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_group()
+ * @uses bbpress()
+ * @uses get_current_user_id()
+ * @uses bp_get_current_group_id()
+ * @uses groups_is_user_admin()
+ * @return bool If current user is a moderator of the current group
+ */
+function bbp_group_is_mod() {
+
+	// Bail if user is not logged in or not looking at a group
+	if ( ! is_user_logged_in() || ! bp_is_group() )
+		return false;
+
+	$bbp = bbpress();
+
+	// Set the global if not set
+	if ( ! isset( $bbp->current_user->is_group_mod ) )
+		$bbp->current_user->is_group_mod = groups_is_user_mod( get_current_user_id(), bp_get_current_group_id() );
+
+	// Return the value
+	return (bool) $bbp->current_user->is_group_mod;
+}
+
+/**
+ * Is the current user a member of the current group
+ *
+ * @since bbPress (r4632)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_group()
+ * @uses bbpress()
+ * @uses get_current_user_id()
+ * @uses bp_get_current_group_id()
+ * @uses groups_is_user_admin()
+ * @return bool If current user is a member of the current group
+ */
+function bbp_group_is_member() {
+
+	// Bail if user is not logged in or not looking at a group
+	if ( ! is_user_logged_in() || ! bp_is_group() )
+		return false;
+
+	$bbp = bbpress();
+
+	// Set the global if not set
+	if ( ! isset( $bbp->current_user->is_group_member ) )
+		$bbp->current_user->is_group_member = groups_is_user_member( get_current_user_id(), bp_get_current_group_id() );
+
+	// Return the value
+	return (bool) $bbp->current_user->is_group_member;
+}
+
+/**
+ * Is the current user banned from the current group
+ *
+ * @since bbPress (r4632)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_group()
+ * @uses bbpress()
+ * @uses get_current_user_id()
+ * @uses bp_get_current_group_id()
+ * @uses groups_is_user_admin()
+ * @return bool If current user is banned from the current group
+ */
+function bbp_group_is_banned() {
+
+	// Bail if user is not logged in or not looking at a group
+	if ( ! is_user_logged_in() || ! bp_is_group() )
+		return false;
+
+	$bbp = bbpress();
+
+	// Set the global if not set
+	if ( ! isset( $bbp->current_user->is_group_banned ) )
+		$bbp->current_user->is_group_banned = groups_is_user_banned( get_current_user_id(), bp_get_current_group_id() );
+
+	// Return the value
+	return (bool) $bbp->current_user->is_group_banned;
+}
+
+/**
+ * Is the current user the creator of the current group
+ *
+ * @since bbPress (r4632)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_group()
+ * @uses bbpress()
+ * @uses get_current_user_id()
+ * @uses bp_get_current_group_id()
+ * @uses groups_is_user_admin()
+ * @return bool If current user the creator of the current group
+ */
+function bbp_group_is_creator() {
+
+	// Bail if user is not logged in or not looking at a group
+	if ( ! is_user_logged_in() || ! bp_is_group() )
+		return false;
+
+	$bbp = bbpress();
+
+	// Set the global if not set
+	if ( ! isset( $bbp->current_user->is_group_creator ) )
+		$bbp->current_user->is_group_creator = groups_is_user_creator( get_current_user_id(), bp_get_current_group_id() );
+
+	// Return the value
+	return (bool) $bbp->current_user->is_group_creator;
+}
Index: /tags/2.5.4/includes/extend/buddypress/groups.php
===================================================================
--- /tags/2.5.4/includes/extend/buddypress/groups.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/buddypress/groups.php	(revision 5382)
@@ -0,0 +1,1398 @@
+<?php
+
+/**
+ * bbPress BuddyPress Group Extension Class
+ *
+ * This file is responsible for connecting bbPress to BuddyPress's Groups
+ * Component. It's a great example of how to perform both simple and advanced
+ * techniques to manipulate bbPress's default output.
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ * @todo maybe move to BuddyPress Forums once bbPress 1.1 can be removed
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Forums_Group_Extension' ) && class_exists( 'BP_Group_Extension' ) ) :
+/**
+ * Loads Group Extension for Forums Component
+ *
+ * @since bbPress (r3552)
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ * @todo Everything
+ */
+class BBP_Forums_Group_Extension extends BP_Group_Extension {
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * Setup bbPress group extension variables
+	 *
+	 * @since bbPress (r3552)
+	 */
+	public function __construct() {
+		$this->setup_variables();
+		$this->setup_actions();
+		$this->setup_filters();
+		$this->maybe_unset_forum_menu();
+	}
+
+	/**
+	 * Setup the group forums class variables
+	 *
+	 * @since bbPress ()
+	 */
+	private function setup_variables() {
+
+		// Component Name
+		$this->name          = __( 'Forum', 'bbpress' );
+		$this->nav_item_name = __( 'Forum', 'bbpress' );
+
+		// Component slugs (hardcoded to match bbPress 1.x functionality)
+		$this->slug          = 'forum';
+		$this->topic_slug    = 'topic';
+		$this->reply_slug    = 'reply';
+
+		// Forum component is visible
+		$this->visibility = 'public';
+
+		// Set positions towards end
+		$this->create_step_position = 15;
+		$this->nav_item_position    = 10;
+
+		// Allow create step and show in nav
+		$this->enable_create_step   = true;
+		$this->enable_nav_item      = true;
+		$this->enable_edit_item     = true;
+
+		// Template file to load, and action to hook display on to
+		$this->template_file        = 'groups/single/plugins';
+		$this->display_hook         = 'bp_template_content';
+	}
+
+	/**
+	 * Setup the group forums class actions
+	 *
+	 * @since bbPress (r4552)
+	 */
+	private function setup_actions() {
+
+		// Possibly redirect
+		add_action( 'bbp_template_redirect',         array( $this, 'redirect_canonical'              ) );
+
+		// Remove group forum cap map when view is done
+		add_action( 'bbp_after_group_forum_display', array( $this, 'remove_group_forum_meta_cap_map' ) );
+
+		// bbPress needs to listen to BuddyPress group deletion.
+		add_action( 'groups_before_delete_group',    array( $this, 'disconnect_forum_from_group'     ) );
+
+		// Adds a bbPress metabox to the new BuddyPress Group Admin UI
+		add_action( 'bp_groups_admin_meta_boxes',    array( $this, 'group_admin_ui_edit_screen'      ) );
+
+		// Saves the bbPress options if they come from the BuddyPress Group Admin UI
+		add_action( 'bp_group_admin_edit_after',     array( $this, 'edit_screen_save'                ) );
+
+		// Adds a hidden input value to the "Group Settings" page
+		add_action( 'bp_before_group_settings_admin', array( $this, 'group_settings_hidden_field'    ) );
+	}
+
+	/**
+	 * Setup the group forums class filters
+	 *
+	 * @since bbPress (r4552)
+	 */
+	private function setup_filters() {
+
+		// Group forum pagination
+		add_filter( 'bbp_topic_pagination',      array( $this, 'topic_pagination'   ) );
+		add_filter( 'bbp_replies_pagination',    array( $this, 'replies_pagination' ) );
+
+		// Tweak the redirect field
+		add_filter( 'bbp_new_topic_redirect_to', array( $this, 'new_topic_redirect_to'        ), 10, 3 );
+		add_filter( 'bbp_new_reply_redirect_to', array( $this, 'new_reply_redirect_to'        ), 10, 3 );
+
+		// Map forum/topic/replys permalinks to their groups
+		add_filter( 'bbp_get_forum_permalink',   array( $this, 'map_forum_permalink_to_group' ), 10, 2 );
+		add_filter( 'bbp_get_topic_permalink',   array( $this, 'map_topic_permalink_to_group' ), 10, 2 );
+		add_filter( 'bbp_get_reply_permalink',   array( $this, 'map_reply_permalink_to_group' ), 10, 2 );
+
+		// Map reply edit links to their groups
+		add_filter( 'bbp_get_reply_edit_url',    array( $this, 'map_reply_edit_url_to_group'  ), 10, 2 );
+
+		// Map assorted template function permalinks
+		add_filter( 'post_link',                 array( $this, 'post_link'                    ), 10, 2 );
+		add_filter( 'page_link',                 array( $this, 'page_link'                    ), 10, 2 );
+		add_filter( 'post_type_link',            array( $this, 'post_type_link'               ), 10, 2 );
+
+		// Map group forum activity items to groups
+		add_filter( 'bbp_before_record_activity_parse_args', array( $this, 'map_activity_to_group' ) );
+
+		/** Caps **************************************************************/
+
+		// Only add these filters if inside a group forum
+		if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'forum' ) ) {
+
+			// Allow group member to view private/hidden forums
+			add_filter( 'bbp_map_meta_caps', array( $this, 'map_group_forum_meta_caps' ), 10, 4 );
+
+			// Group member permissions to view the topic and reply forms
+			add_filter( 'bbp_current_user_can_access_create_topic_form', array( $this, 'form_permissions' ) );
+			add_filter( 'bbp_current_user_can_access_create_reply_form', array( $this, 'form_permissions' ) );
+		}
+	}
+
+	/**
+	 * The primary display function for group forums
+	 */
+	public function display() {
+
+		// Prevent Topic Parent from appearing
+		add_action( 'bbp_theme_before_topic_form_forum', array( $this, 'ob_start'     ) );
+		add_action( 'bbp_theme_after_topic_form_forum',  array( $this, 'ob_end_clean' ) );
+		add_action( 'bbp_theme_after_topic_form_forum',  array( $this, 'topic_parent' ) );
+
+		// Prevent Forum Parent from appearing
+		add_action( 'bbp_theme_before_forum_form_parent', array( $this, 'ob_start'     ) );
+		add_action( 'bbp_theme_after_forum_form_parent',  array( $this, 'ob_end_clean' ) );
+		add_action( 'bbp_theme_after_forum_form_parent',  array( $this, 'forum_parent' ) );
+
+		// Hide breadcrumb
+		add_filter( 'bbp_no_breadcrumb', '__return_true' );
+
+		$this->display_forums( 0 );
+	}
+
+	/**
+	 * Maybe unset the group forum nav item if group does not have a forum
+	 *
+	 * @since bbPress (r4552)
+	 *
+	 * @return If not viewing a single group
+	 */
+	public function maybe_unset_forum_menu() {
+
+		// Bail if not viewing a single group
+		if ( ! bp_is_group() )
+			return;
+
+		// Are forums enabled for this group?
+		$checked = bp_get_new_group_enable_forum() || groups_get_groupmeta( bp_get_new_group_id(), 'forum_id' );
+
+		// Tweak the nav item variable based on if group has forum or not
+		$this->enable_nav_item = (bool) $checked;
+	}
+
+	/**
+	 * Allow group members to have advanced priviledges in group forum topics.
+	 *
+	 * @since bbPress (r4434)
+	 *
+	 * @param array $caps
+	 * @param string $cap
+	 * @param int $user_id
+	 * @param array $args
+	 * @return array
+	 */
+	public function map_group_forum_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+
+		switch ( $cap ) {
+
+			// If user is a group mmember, allow them to create content.
+			case 'read_forum'          :
+			case 'publish_replies'     :
+			case 'publish_topics'      :
+			case 'read_hidden_forums'  :
+			case 'read_private_forums' :
+				if ( bbp_group_is_member() || bbp_group_is_mod() || bbp_group_is_admin() ) {
+					$caps = array( 'participate' );
+				}
+				break;
+
+			// If user is a group mod ar admin, map to participate cap.
+			case 'moderate'     :
+			case 'edit_topic'   :
+			case 'edit_reply'   :
+			case 'view_trash'   :
+			case 'edit_others_replies' :
+			case 'edit_others_topics'  :
+				if ( bbp_group_is_mod() || bbp_group_is_admin() ) {
+					$caps = array( 'participate' );
+				}
+				break;
+
+			// If user is a group admin, allow them to delete topics and replies.
+			case 'delete_topic' :
+			case 'delete_reply' :
+				if ( bbp_group_is_admin() ) {
+					$caps = array( 'participate' );
+				}
+				break;
+		}
+
+		return apply_filters( 'bbp_map_group_forum_topic_meta_caps', $caps, $cap, $user_id, $args );
+	}
+
+	/**
+	 * Remove the topic meta cap map, so it doesn't interfere with sidebars.
+	 *
+	 * @since bbPress (r4434)
+	 */
+	public function remove_group_forum_meta_cap_map() {
+		remove_filter( 'bbp_map_meta_caps', array( $this, 'map_group_forum_meta_caps' ), 99, 4 );
+	}
+
+	/** Edit ******************************************************************/
+
+	/**
+	 * Show forums and new forum form when editing a group
+	 *
+	 * @since bbPress (r3563)
+	 * @param object $group (the group to edit if in Group Admin UI)
+	 * @uses is_admin() To check if we're in the Group Admin UI
+	 * @uses bbp_get_template_part()
+	 */
+	public function edit_screen( $group = false ) {
+		$forum_id  = 0;
+		$group_id  = empty( $group->id ) ? bp_get_new_group_id() : $group->id ;
+		$forum_ids = bbp_get_group_forum_ids( $group_id );
+
+		// Get the first forum ID
+		if ( !empty( $forum_ids ) ) {
+			$forum_id = (int) is_array( $forum_ids ) ? $forum_ids[0] : $forum_ids;
+		}
+
+		// Should box be checked already?
+		$checked = is_admin() ? bp_group_is_forum_enabled( $group ) : bp_get_new_group_enable_forum() || bp_group_is_forum_enabled( bp_get_group_id() ); ?>
+
+		<h4><?php esc_html_e( 'Group Forum Settings', 'bbpress' ); ?></h4>
+
+		<fieldset>
+			<legend class="screen-reader-text"><?php esc_html_e( 'Group Forum Settings', 'bbpress' ); ?></legend>
+			<p><?php esc_html_e( 'Create a discussion forum to allow members of this group to communicate in a structured, bulletin-board style fashion.', 'bbpress' ); ?></p>
+
+			<div class="field-group">
+				<div class="checkbox">
+					<label><input type="checkbox" name="bbp-edit-group-forum" id="bbp-edit-group-forum" value="1"<?php checked( $checked ); ?> /> <?php esc_html_e( 'Yes. I want this group to have a forum.', 'bbpress' ); ?></label>
+				</div>
+
+				<p class="description"><?php esc_html_e( 'Saying no will not delete existing forum content.', 'bbpress' ); ?></p>
+			</div>
+
+			<?php if ( bbp_is_user_keymaster() ) : ?>
+				<div class="field-group">
+					<label for="bbp_group_forum_id"><?php esc_html_e( 'Group Forum:', 'bbpress' ); ?></label>
+					<?php
+						bbp_dropdown( array(
+							'select_id' => 'bbp_group_forum_id',
+							'show_none' => __( '(No Forum)', 'bbpress' ),
+							'selected'  => $forum_id
+						) );
+					?>
+					<p class="description"><?php esc_html_e( 'Network administrators can reconfigure which forum belongs to this group.', 'bbpress' ); ?></p>
+				</div>
+			<?php endif; ?>
+
+			<?php if ( !is_admin() ) : ?>
+				<input type="submit" value="<?php esc_attr_e( 'Save Settings', 'bbpress' ); ?>" />
+			<?php endif; ?>
+
+		</fieldset>
+
+		<?php
+
+		// Verify intent
+		if ( is_admin() ) {
+			wp_nonce_field( 'groups_edit_save_' . $this->slug, 'forum_group_admin_ui' );
+		} else {
+			wp_nonce_field( 'groups_edit_save_' . $this->slug );
+		}
+	}
+
+	/**
+	 * Save the Group Forum data on edit
+	 *
+	 * @since bbPress (r3465)
+	 * @param int $group_id (to handle Group Admin UI hook bp_group_admin_edit_after )
+	 * @uses bbp_new_forum_handler() To check for forum creation
+	 * @uses bbp_edit_forum_handler() To check for forum edit
+	 */
+	public function edit_screen_save( $group_id = 0 ) {
+
+		// Bail if not a POST action
+		if ( ! bbp_is_post_request() )
+			return;
+
+		// Admin Nonce check
+		if ( is_admin() ) {
+			check_admin_referer( 'groups_edit_save_' . $this->slug, 'forum_group_admin_ui' );
+
+		// Theme-side Nonce check
+		} elseif ( ! bbp_verify_nonce_request( 'groups_edit_save_' . $this->slug ) ) {
+			bbp_add_error( 'bbp_edit_group_forum_screen_save', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+			return;
+ 		}
+
+		$edit_forum = !empty( $_POST['bbp-edit-group-forum'] ) ? true : false;
+		$forum_id   = 0;
+		$group_id   = !empty( $group_id ) ? $group_id : bp_get_current_group_id();
+
+		// Keymasters have the ability to reconfigure forums
+		if ( bbp_is_user_keymaster() ) {
+			$forum_ids = ! empty( $_POST['bbp_group_forum_id'] ) ? (array) (int) $_POST['bbp_group_forum_id'] : array();
+
+		// Use the existing forum IDs
+		} else {
+			$forum_ids = array_values( bbp_get_group_forum_ids( $group_id ) );
+		}
+
+		// Normalize group forum relationships now
+		if ( !empty( $forum_ids ) ) {
+
+			// Loop through forums, and make sure they exist
+			foreach ( $forum_ids as $forum_id ) {
+
+				// Look for forum
+				$forum = bbp_get_forum( $forum_id );
+
+				// No forum exists, so break the relationship
+				if ( empty( $forum ) ) {
+					$this->remove_forum( array( 'forum_id' => $forum_id ) );
+					unset( $forum_ids[$forum_id] );
+				}
+			}
+
+			// No support for multiple forums yet
+			$forum_id = (int) ( is_array( $forum_ids ) ? $forum_ids[0] : $forum_ids );
+		}
+
+		// Update the group ID and forum ID relationships
+		bbp_update_group_forum_ids( $group_id, (array) $forum_ids );
+		bbp_update_forum_group_ids( $forum_id, (array) $group_id  );
+
+		// Update the group forum setting
+		$group = $this->toggle_group_forum( $group_id, $edit_forum );
+
+		// Create a new forum
+		if ( empty( $forum_id ) && ( true === $edit_forum ) ) {
+
+			// Set the default forum status
+			switch ( $group->status ) {
+				case 'hidden'  :
+					$status = bbp_get_hidden_status_id();
+					break;
+				case 'private' :
+					$status = bbp_get_private_status_id();
+					break;
+				case 'public'  :
+				default        :
+					$status = bbp_get_public_status_id();
+					break;
+			}
+
+			// Create the initial forum
+			$forum_id = bbp_insert_forum( array(
+				'post_parent'  => bbp_get_group_forums_root_id(),
+				'post_title'   => $group->name,
+				'post_content' => $group->description,
+				'post_status'  => $status
+			) );
+
+			// Setup forum args with forum ID
+			$new_forum_args = array( 'forum_id' => $forum_id );
+
+			// If in admin, also include the group ID
+			if ( is_admin() && !empty( $group_id ) ) {
+				$new_forum_args['group_id'] = $group_id;
+			}
+
+			// Run the BP-specific functions for new groups
+			$this->new_forum( $new_forum_args );
+		}
+
+		// Redirect after save when not in admin
+		if ( !is_admin() ) {
+			bp_core_redirect( trailingslashit( bp_get_group_permalink( buddypress()->groups->current_group ) . '/admin/' . $this->slug ) );
+		}
+	}
+
+	/**
+	 * Adds a metabox to BuddyPress Group Admin UI
+	 *
+	 * @since bbPress (r4814)
+	 *
+	 * @uses add_meta_box
+	 * @uses BBP_Forums_Group_Extension::group_admin_ui_display_metabox() To display the edit screen
+	 */
+	public function group_admin_ui_edit_screen() {
+		add_meta_box(
+			'bbpress_group_admin_ui_meta_box',
+			_x( 'Discussion Forum', 'group admin edit screen', 'bbpress' ),
+			array( $this, 'group_admin_ui_display_metabox' ),
+			get_current_screen()->id,
+			'side',
+			'core'
+		);
+	}
+
+	/**
+	 * Displays the bbPress metabox in BuddyPress Group Admin UI
+	 *
+	 * @since bbPress (r4814)
+	 *
+	 * @param object $item (group object)
+	 * @uses add_meta_box
+	 * @uses BBP_Forums_Group_Extension::edit_screen() To get the html
+	 */
+	public function group_admin_ui_display_metabox( $item ) {
+		$this->edit_screen( $item );
+	}
+
+	/** Create ****************************************************************/
+
+	/**
+	 * Show forums and new forum form when creating a group
+	 *
+	 * @since bbPress (r3465)
+	 */
+	public function create_screen( $group_id = 0 ) {
+
+		// Bail if not looking at this screen
+		if ( !bp_is_group_creation_step( $this->slug ) )
+			return false;
+
+		// Check for possibly empty group_id
+		if ( empty( $group_id ) ) {
+			$group_id = bp_get_new_group_id();
+		}
+
+		$checked = bp_get_new_group_enable_forum() || groups_get_groupmeta( $group_id, 'forum_id' ); ?>
+
+		<h4><?php esc_html_e( 'Group Forum', 'bbpress' ); ?></h4>
+
+		<p><?php esc_html_e( 'Create a discussion forum to allow members of this group to communicate in a structured, bulletin-board style fashion.', 'bbpress' ); ?></p>
+
+		<div class="checkbox">
+			<label><input type="checkbox" name="bbp-create-group-forum" id="bbp-create-group-forum" value="1"<?php checked( $checked ); ?> /> <?php esc_html_e( 'Yes. I want this group to have a forum.', 'bbpress' ); ?></label>
+		</div>
+
+		<?php
+	}
+
+	/**
+	 * Save the Group Forum data on create
+	 *
+	 * @since bbPress (r3465)
+	 */
+	public function create_screen_save( $group_id = 0 ) {
+
+		// Nonce check
+		if ( ! bbp_verify_nonce_request( 'groups_create_save_' . $this->slug ) ) {
+			bbp_add_error( 'bbp_create_group_forum_screen_save', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+			return;
+		}
+
+		// Check for possibly empty group_id
+		if ( empty( $group_id ) ) {
+			$group_id = bp_get_new_group_id();
+		}
+
+		$create_forum = !empty( $_POST['bbp-create-group-forum'] ) ? true : false;
+		$forum_id     = 0;
+		$forum_ids    = bbp_get_group_forum_ids( $group_id );
+
+		if ( !empty( $forum_ids ) )
+			$forum_id = (int) is_array( $forum_ids ) ? $forum_ids[0] : $forum_ids;
+
+		// Create a forum, or not
+		switch ( $create_forum ) {
+			case true  :
+
+				// Bail if initial content was already created
+				if ( !empty( $forum_id ) )
+					return;
+
+				// Set the default forum status
+				switch ( bp_get_new_group_status() ) {
+					case 'hidden'  :
+						$status = bbp_get_hidden_status_id();
+						break;
+					case 'private' :
+						$status = bbp_get_private_status_id();
+						break;
+					case 'public'  :
+					default        :
+						$status = bbp_get_public_status_id();
+						break;
+				}
+
+				// Create the initial forum
+				$forum_id = bbp_insert_forum( array(
+					'post_parent'  => bbp_get_group_forums_root_id(),
+					'post_title'   => bp_get_new_group_name(),
+					'post_content' => bp_get_new_group_description(),
+					'post_status'  => $status
+				) );
+
+				// Run the BP-specific functions for new groups
+				$this->new_forum( array( 'forum_id' => $forum_id ) );
+
+				// Update forum active
+				groups_update_groupmeta( bp_get_new_group_id(), '_bbp_forum_enabled_' . $forum_id, true );
+
+				// Toggle forum on
+				$this->toggle_group_forum( bp_get_new_group_id(), true );
+
+				break;
+			case false :
+
+				// Forum was created but is now being undone
+				if ( !empty( $forum_id ) ) {
+
+					// Delete the forum
+					wp_delete_post( $forum_id, true );
+
+					// Delete meta values
+					groups_delete_groupmeta( bp_get_new_group_id(), 'forum_id' );
+					groups_delete_groupmeta( bp_get_new_group_id(), '_bbp_forum_enabled_' . $forum_id );
+
+					// Toggle forum off
+					$this->toggle_group_forum( bp_get_new_group_id(), false );
+				}
+
+				break;
+		}
+	}
+
+	/**
+	 * Used to start an output buffer
+	 */
+	public function ob_start() {
+		ob_start();
+	}
+
+	/**
+	 * Used to end an output buffer
+	 */
+	public function ob_end_clean() {
+		ob_end_clean();
+	}
+
+	/**
+	 * Creating a group forum or category (including root for group)
+	 *
+	 * @since bbPress (r3653)
+	 * @param type $forum_args
+	 * @uses bbp_get_forum_id()
+	 * @uses bp_get_current_group_id()
+	 * @uses bbp_add_forum_id_to_group()
+	 * @uses bbp_add_group_id_to_forum()
+	 * @return if no forum_id is available
+	 */
+	public function new_forum( $forum_args = array() ) {
+
+		// Bail if no forum_id was passed
+		if ( empty( $forum_args['forum_id'] ) )
+			return;
+
+		// Validate forum_id
+		$forum_id = bbp_get_forum_id( $forum_args['forum_id'] );
+		$group_id = !empty( $forum_args['group_id'] ) ? $forum_args['group_id'] : bp_get_current_group_id();
+
+		bbp_add_forum_id_to_group( $group_id, $forum_id );
+		bbp_add_group_id_to_forum( $forum_id, $group_id );
+	}
+
+	/**
+	 * Removing a group forum or category (including root for group)
+	 *
+	 * @since bbPress (r3653)
+	 * @param type $forum_args
+	 * @uses bbp_get_forum_id()
+	 * @uses bp_get_current_group_id()
+	 * @uses bbp_add_forum_id_to_group()
+	 * @uses bbp_add_group_id_to_forum()
+	 * @return if no forum_id is available
+	 */
+	public function remove_forum( $forum_args = array() ) {
+
+		// Bail if no forum_id was passed
+		if ( empty( $forum_args['forum_id'] ) )
+			return;
+
+		// Validate forum_id
+		$forum_id = bbp_get_forum_id( $forum_args['forum_id'] );
+		$group_id = !empty( $forum_args['group_id'] ) ? $forum_args['group_id'] : bp_get_current_group_id();
+
+		bbp_remove_forum_id_from_group( $group_id, $forum_id );
+		bbp_remove_group_id_from_forum( $forum_id, $group_id );
+	}
+
+	/**
+	 * Listening to BuddyPress Group deletion to remove the forum
+	 *
+	 * @param int $group_id The group ID
+	 * @uses bbp_get_group_forum_ids()
+	 * @uses BBP_Forums_Group_Extension::remove_forum()
+	 */
+	public function disconnect_forum_from_group( $group_id = 0 ) {
+
+		// Bail if no group ID available
+		if ( empty( $group_id ) ) {
+			return;
+		}
+
+		// Get the forums for the current group
+		$forum_ids = bbp_get_group_forum_ids( $group_id );
+
+		// Use the first forum ID
+		if ( empty( $forum_ids ) )
+			return;
+
+		// Get the first forum ID
+		$forum_id = (int) is_array( $forum_ids ) ? $forum_ids[0] : $forum_ids;
+		$this->remove_forum( array(
+			'forum_id' => $forum_id,
+			'group_id' => $group_id
+		) );
+	}
+
+	/**
+	 * Toggle the enable_forum group setting on or off
+	 *
+	 * @since bbPress (r4612)
+	 *
+	 * @param int $group_id The group to toggle
+	 * @param bool $enabled True for on, false for off
+	 * @uses groups_get_group() To get the group to toggle
+	 * @return False if group is not found, otherwise return the group
+	 */
+	public function toggle_group_forum( $group_id = 0, $enabled = false ) {
+
+		// Get the group
+		$group = groups_get_group( array( 'group_id' => $group_id ) );
+
+		// Bail if group cannot be found
+		if ( empty( $group ) )
+			return false;
+
+		// Set forum enabled status
+		$group->enable_forum = (int) $enabled;
+
+		// Save the group
+		$group->save();
+
+		// Maybe disconnect forum from group
+		if ( empty( $enabled ) ) {
+			$this->disconnect_forum_from_group( $group_id );
+		}
+
+		// Update bbPress' internal private and forum ID variables
+		bbp_repair_forum_visibility();
+
+		// Return the group
+		return $group;
+	}
+
+	/** Display Methods *******************************************************/
+
+	/**
+	 * Output the forums for a group in the edit screens
+	 *
+	 * As of right now, bbPress only supports 1-to-1 group forum relationships.
+	 * In the future, many-to-many should be allowed.
+	 *
+	 * @since bbPress (r3653)
+	 * @uses bp_get_current_group_id()
+	 * @uses bbp_get_group_forum_ids()
+	 * @uses bbp_has_forums()
+	 * @uses bbp_get_template_part()
+	 */
+	public function display_forums( $offset = 0 ) {
+		global $wp_query;
+
+		// Allow actions immediately before group forum output
+		do_action( 'bbp_before_group_forum_display' );
+
+		// Load up bbPress once
+		$bbp = bbpress();
+
+		/** Query Resets ******************************************************/
+
+		// Forum data
+		$forum_action = bp_action_variable( $offset );
+		$forum_ids    = bbp_get_group_forum_ids( bp_get_current_group_id() );
+		$forum_id     = array_shift( $forum_ids );
+
+		// Always load up the group forum
+		bbp_has_forums( array(
+			'p'           => $forum_id,
+			'post_parent' => null
+		) );
+
+		// Set the global forum ID
+		$bbp->current_forum_id = $forum_id;
+
+		// Assume forum query
+		bbp_set_query_name( 'bbp_single_forum' ); ?>
+
+		<div id="bbpress-forums">
+
+			<?php switch ( $forum_action ) :
+
+				/** Single Forum **********************************************/
+
+				case false  :
+				case 'page' :
+
+					// Strip the super stickies from topic query
+					add_filter( 'bbp_get_super_stickies', array( $this, 'no_super_stickies'  ), 10, 1 );
+
+					// Unset the super sticky option on topic form
+					add_filter( 'bbp_get_topic_types',    array( $this, 'unset_super_sticky' ), 10, 1 );
+
+					// Query forums and show them if they exist
+					if ( bbp_forums() ) :
+
+						// Setup the forum
+						bbp_the_forum(); ?>
+
+						<h3><?php bbp_forum_title(); ?></h3>
+
+						<?php bbp_get_template_part( 'content', 'single-forum' );
+
+					// No forums found
+					else : ?>
+
+						<div id="message" class="info">
+							<p><?php esc_html_e( 'This group does not currently have a forum.', 'bbpress' ); ?></p>
+						</div>
+
+					<?php endif;
+
+					break;
+
+				/** Single Topic **********************************************/
+
+				case $this->topic_slug :
+
+					// hide the 'to front' admin links
+					add_filter( 'bbp_get_topic_stick_link', array( $this, 'hide_super_sticky_admin_link' ), 10, 2 );
+
+					// Get the topic
+					bbp_has_topics( array(
+						'name'           => bp_action_variable( $offset + 1 ),
+						'posts_per_page' => 1,
+						'show_stickies'  => false
+					) );
+
+					// If no topic, 404
+					if ( ! bbp_topics() ) {
+						bp_do_404( bbp_get_forum_permalink( $forum_id ) ); ?>
+						<h3><?php bbp_forum_title(); ?></h3>
+						<?php bbp_get_template_part( 'feedback', 'no-topics' );
+						return;
+					}
+
+					// Setup the topic
+					bbp_the_topic(); ?>
+
+					<h3><?php bbp_topic_title(); ?></h3>
+
+					<?php
+
+					// Topic edit
+					if ( bp_action_variable( $offset + 2 ) === bbp_get_edit_rewrite_id() ) :
+
+						// Unset the super sticky link on edit topic template
+						add_filter( 'bbp_get_topic_types', array( $this, 'unset_super_sticky' ), 10, 1 );
+
+						// Set the edit switches
+						$wp_query->bbp_is_edit       = true;
+						$wp_query->bbp_is_topic_edit = true;
+
+						// Setup the global forum ID
+						$bbp->current_topic_id       = get_the_ID();
+
+						// Merge
+						if ( !empty( $_GET['action'] ) && 'merge' === $_GET['action'] ) :
+							bbp_set_query_name( 'bbp_topic_merge' );
+							bbp_get_template_part( 'form', 'topic-merge' );
+
+						// Split
+						elseif ( !empty( $_GET['action'] ) && 'split' === $_GET['action'] ) :
+							bbp_set_query_name( 'bbp_topic_split' );
+							bbp_get_template_part( 'form', 'topic-split' );
+
+						// Edit
+						else :
+							bbp_set_query_name( 'bbp_topic_form' );
+							bbp_get_template_part( 'form', 'topic' );
+
+						endif;
+
+					// Single Topic
+					else:
+						bbp_set_query_name( 'bbp_single_topic' );
+						bbp_get_template_part( 'content', 'single-topic' );
+					endif;
+					break;
+
+				/** Single Reply **********************************************/
+
+				case $this->reply_slug :
+
+					// Get the reply
+					bbp_has_replies( array(
+						'name'           => bp_action_variable( $offset + 1 ),
+						'posts_per_page' => 1
+					) );
+
+					// If no topic, 404
+					if ( ! bbp_replies() ) {
+						bp_do_404( bbp_get_forum_permalink( $forum_id ) ); ?>
+						<h3><?php bbp_forum_title(); ?></h3>
+						<?php bbp_get_template_part( 'feedback', 'no-replies' );
+						return;
+					}
+
+					// Setup the reply
+					bbp_the_reply(); ?>
+
+					<h3><?php bbp_reply_title(); ?></h3>
+
+					<?php if ( bp_action_variable( $offset + 2 ) === bbp_get_edit_rewrite_id() ) :
+
+						// Set the edit switches
+						$wp_query->bbp_is_edit       = true;
+						$wp_query->bbp_is_reply_edit = true;
+
+						// Setup the global reply ID
+						$bbp->current_reply_id       = get_the_ID();
+
+						// Move
+						if ( !empty( $_GET['action'] ) && ( 'move' === $_GET['action'] ) ) :
+							bbp_set_query_name( 'bbp_reply_move' );
+							bbp_get_template_part( 'form', 'reply-move' );
+
+						// Edit
+						else :
+							bbp_set_query_name( 'bbp_reply_form' );
+							bbp_get_template_part( 'form', 'reply' );
+						endif;
+					endif;
+					break;
+			endswitch;
+
+			// Reset the query
+			wp_reset_query(); ?>
+
+		</div>
+
+		<?php
+
+		// Allow actions immediately after group forum output
+		do_action( 'bbp_after_group_forum_display' );
+	}
+
+	/** Super sticky filters ***************************************************/
+
+	/**
+	 * Strip super stickies from the topic query
+	 *
+	 * @since bbPress (r4810)
+	 * @access private
+	 * @param array $super the super sticky post ID's
+	 * @return array (empty)
+	 */
+	public function no_super_stickies( $super = array() ) {
+		$super = array();
+		return $super;
+	}
+
+	/**
+	 * Unset the type super sticky from topic type
+	 *
+	 * @since bbPress (r4810)
+	 * @access private
+	 * @param array $args
+	 * @return array $args without the to-front link
+	 */
+	public function unset_super_sticky( $args = array() ) {
+		if ( isset( $args['super'] ) ) {
+			unset( $args['super'] );
+		}
+		return $args;
+	}
+
+	/**
+	 * Ugly preg_replace to hide the to front admin link
+	 *
+	 * @since bbPress (r4810)
+	 * @access private
+	 * @param string $retval
+	 * @param array $args
+	 * @return string $retval without the to-front link
+	 */
+	public function hide_super_sticky_admin_link( $retval = '', $args = array() ) {
+		if ( strpos( $retval, '(' ) ) {
+			$retval = preg_replace( '/(\(.+?)+(\))/i', '', $retval );
+		}
+
+		return $retval;
+	}
+
+	/** Redirect Helpers ******************************************************/
+
+	/**
+	 * Redirect to the group forum screen
+	 *
+	 * @since bbPress (r3653)
+	 * @param str $redirect_url
+	 * @param str $redirect_to
+	 */
+	public function new_topic_redirect_to( $redirect_url = '', $redirect_to = '', $topic_id = 0 ) {
+		if ( bp_is_group() ) {
+			$topic        = bbp_get_topic( $topic_id );
+			$topic_hash   = '#post-' . $topic_id;
+			$redirect_url = trailingslashit( bp_get_group_permalink( groups_get_current_group() ) ) . trailingslashit( $this->slug ) . trailingslashit( $this->topic_slug ) . trailingslashit( $topic->post_name ) . $topic_hash;
+		}
+
+		return $redirect_url;
+	}
+
+	/**
+	 * Redirect to the group forum screen
+	 *
+	 * @since bbPress (r3653)
+	 */
+	public function new_reply_redirect_to( $redirect_url = '', $redirect_to = '', $reply_id = 0 ) {
+		global $wp_rewrite;
+
+		if ( bp_is_group() ) {
+			$topic_id       = bbp_get_reply_topic_id( $reply_id );
+			$topic          = bbp_get_topic( $topic_id );
+			$reply_position = bbp_get_reply_position( $reply_id, $topic_id );
+			$reply_page     = ceil( (int) $reply_position / (int) bbp_get_replies_per_page() );
+			$reply_hash     = '#post-' . $reply_id;
+			$topic_url      = trailingslashit( bp_get_group_permalink( groups_get_current_group() ) ) . trailingslashit( $this->slug ) . trailingslashit( $this->topic_slug ) . trailingslashit( $topic->post_name );
+
+			// Don't include pagination if on first page
+			if ( 1 >= $reply_page ) {
+				$redirect_url = trailingslashit( $topic_url ) . $reply_hash;
+
+			// Include pagination
+			} else {
+				$redirect_url = trailingslashit( $topic_url ) . trailingslashit( $wp_rewrite->pagination_base ) . trailingslashit( $reply_page ) . $reply_hash;
+			}
+
+			// Add topic view query arg back to end if it is set
+			if ( bbp_get_view_all() ) {
+				$redirect_url = bbp_add_view_all( $redirect_url );
+			}
+		}
+
+		return $redirect_url;
+	}
+
+	/**
+	 * Redirect to the group admin forum edit screen
+	 *
+	 * @since bbPress (r3653)
+	 * @uses groups_get_current_group()
+	 * @uses bp_is_group_admin_screen()
+	 * @uses trailingslashit()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_groups_root_slug()
+	 */
+	public function edit_redirect_to( $redirect_url = '' ) {
+
+		// Get the current group, if there is one
+		$group = groups_get_current_group();
+
+		// If this is a group of any kind, empty out the redirect URL
+		if ( bp_is_group_admin_screen( $this->slug ) )
+			$redirect_url = trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . $group->slug . '/admin/' . $this->slug );
+
+		return $redirect_url;
+	}
+
+	/** Form Helpers **********************************************************/
+
+	public function forum_parent() {
+	?>
+
+		<input type="hidden" name="bbp_forum_parent_id" id="bbp_forum_parent_id" value="<?php bbp_group_forums_root_id(); ?>" />
+
+	<?php
+	}
+
+	public function topic_parent() {
+
+		$forum_ids = bbp_get_group_forum_ids( bp_get_current_group_id() ); ?>
+
+		<p>
+			<label for="bbp_forum_id"><?php esc_html_e( 'Forum:', 'bbpress' ); ?></label><br />
+			<?php bbp_dropdown( array( 'include' => $forum_ids, 'selected' => bbp_get_form_topic_forum() ) ); ?>
+		</p>
+
+	<?php
+	}
+
+	/**
+	 * Permissions to view the 'New Topic'/'Reply To' form in a BuddyPress group.
+	 *
+	 * @since bbPress (r4608)
+	 *
+	 * @param bool $retval Are we allowed to view the reply form?
+	 * @uses bp_is_group() To determine if we're on a group page
+	 * @uses is_user_logged_in() To determine if a user is logged in.
+	 * @uses bbp_is_user_keymaster() Is the current user a keymaster?
+	 * @uses bbp_group_is_member() Is the current user a member of the group?
+	 * @uses bbp_group_is_user_banned() Is the current user banned from the group?
+	 *
+	 * @return bool
+	 */
+	public function form_permissions( $retval = false ) {
+
+		// Bail if not a group
+		if ( ! bp_is_group() ) {
+			return $retval;
+		}
+
+		// Bail if user is not logged in
+		if ( ! is_user_logged_in() ) {
+			return $retval;
+
+		// Keymasters can always pass go
+		} elseif ( bbp_is_user_keymaster() ) {
+			$retval = true;
+
+		// Non-members cannot see forms
+		} elseif ( ! bbp_group_is_member() ) {
+			$retval = false;
+
+		// Banned users cannot see forms
+		} elseif ( bbp_group_is_banned() ) {
+			$retval = false;
+		}
+
+		return $retval;
+	}
+
+	/**
+	 * Add a hidden input field on the group settings page if the group forum is
+	 * enabled.
+	 *
+	 * Due to the way BuddyPress' group admin settings page saves its settings,
+	 * we need to let BP know that bbPress added a forum.
+	 *
+	 * @since bbPress (r5026)
+	 *
+	 * @link http://bbpress.trac.wordpress.org/ticket/2339/
+	 * @see groups_screen_group_admin_settings()
+	 */
+	public function group_settings_hidden_field() {
+
+		// if a forum is not enabled, we don't need to add this field
+		if ( ! bp_group_is_forum_enabled() )
+			return; ?>
+
+		<input type="hidden" name="group-show-forum" id="group-show-forum" value="1" />
+
+	<?php
+	}
+
+	/** Permalink Mappers *****************************************************/
+
+	/**
+	 * Maybe map a bbPress forum/topic/reply permalink to the corresponding group
+	 *
+	 * @param int $post_id
+	 * @uses get_post()
+	 * @uses bbp_is_reply()
+	 * @uses bbp_get_reply_topic_id()
+	 * @uses bbp_get_reply_forum_id()
+	 * @uses bbp_is_topic()
+	 * @uses bbp_get_topic_forum_id()
+	 * @uses bbp_is_forum()
+	 * @uses get_post_field()
+	 * @uses bbp_get_forum_group_ids()
+	 * @uses groups_get_group()
+	 * @uses bp_get_group_admin_permalink()
+	 * @uses bp_get_group_permalink()
+	 * @return Bail early if not a group forum post
+	 * @return string
+	 */
+	private function maybe_map_permalink_to_group( $post_id = 0, $url = false ) {
+
+		switch ( get_post_type( $post_id ) ) {
+
+			// Reply
+			case bbp_get_reply_post_type() :
+				$topic_id = bbp_get_reply_topic_id( $post_id );
+				$forum_id = bbp_get_reply_forum_id( $post_id );
+				$url_end  = trailingslashit( $this->reply_slug ) . get_post_field( 'post_name', $post_id );
+				break;
+
+			// Topic
+			case bbp_get_topic_post_type() :
+				$topic_id = $post_id;
+				$forum_id = bbp_get_topic_forum_id( $post_id );
+				$url_end  = trailingslashit( $this->topic_slug ) . get_post_field( 'post_name', $post_id );
+				break;
+
+			// Forum
+			case bbp_get_forum_post_type() :
+				$forum_id = $post_id;
+				$url_end  = ''; //get_post_field( 'post_name', $post_id );
+				break;
+
+			// Unknown
+			default :
+				return $url;
+				break;
+		}
+
+		// Get group ID's for this forum
+		$group_ids = bbp_get_forum_group_ids( $forum_id );
+
+		// Bail if the post isn't associated with a group
+		if ( empty( $group_ids ) )
+			return $url;
+
+		// @todo Multiple group forums/forum groups
+		$group_id = $group_ids[0];
+		$group    = groups_get_group( array( 'group_id' => $group_id ) );
+
+		if ( bp_is_group_admin_screen( $this->slug ) ) {
+			$group_permalink = trailingslashit( bp_get_group_admin_permalink( $group ) );
+		} else {
+			$group_permalink = trailingslashit( bp_get_group_permalink( $group ) );
+		}
+
+		return trailingslashit( trailingslashit( $group_permalink . $this->slug ) . $url_end );
+	}
+
+	/**
+	 * Map a forum permalink to its corresponding group
+	 *
+	 * @since bbPress (r3802)
+	 * @param string $url
+	 * @param int $forum_id
+	 * @uses maybe_map_permalink_to_group()
+	 * @return string
+	 */
+	public function map_forum_permalink_to_group( $url, $forum_id ) {
+		return $this->maybe_map_permalink_to_group( $forum_id, $url );
+	}
+
+	/**
+	 * Map a topic permalink to its group forum
+	 *
+	 * @since bbPress (r3802)
+	 * @param string $url
+	 * @param int $topic_id
+	 * @uses maybe_map_permalink_to_group()
+	 * @return string
+	 */
+	public function map_topic_permalink_to_group( $url, $topic_id ) {
+		return $this->maybe_map_permalink_to_group( $topic_id, $url );
+	}
+
+	/**
+	 * Map a reply permalink to its group forum
+	 *
+	 * @since bbPress (r3802)
+	 * @param string $url
+	 * @param int $reply_id
+	 * @uses maybe_map_permalink_to_group()
+	 * @return string
+	 */
+	public function map_reply_permalink_to_group( $url, $reply_id ) {
+		return $this->maybe_map_permalink_to_group( bbp_get_reply_topic_id( $reply_id ), $url );
+	}
+
+	/**
+	 * Map a reply edit link to its group forum
+	 *
+	 * @param string $url
+	 * @param int $reply_id
+	 * @uses maybe_map_permalink_to_group()
+	 * @return string
+	 */
+	public function map_reply_edit_url_to_group( $url, $reply_id ) {
+		$new = $this->maybe_map_permalink_to_group( $reply_id );
+
+		if ( empty( $new ) )
+			return $url;
+
+		return trailingslashit( $new ) . bbpress()->edit_id  . '/';
+	}
+
+	/**
+	 * Map a post link to its group forum
+	 *
+	 * @param string $url
+	 * @param obj $post
+	 * @param boolean $leavename
+	 * @uses maybe_map_permalink_to_group()
+	 * @return string
+	 */
+	public function post_link( $url, $post ) {
+		return $this->maybe_map_permalink_to_group( $post->ID, $url );
+	}
+
+	/**
+	 * Map a page link to its group forum
+	 *
+	 * @param string $url
+	 * @param int $post_id
+	 * @param $sample
+	 * @uses maybe_map_permalink_to_group()
+	 * @return string
+	 */
+	public function page_link( $url, $post_id ) {
+		return $this->maybe_map_permalink_to_group( $post_id, $url );
+	}
+
+	/**
+	 * Map a custom post type link to its group forum
+	 *
+	 * @param string $url
+	 * @param obj $post
+	 * @param $leavename
+	 * @param $sample
+	 * @uses maybe_map_permalink_to_group()
+	 * @return string
+	 */
+	public function post_type_link( $url, $post ) {
+		return $this->maybe_map_permalink_to_group( $post->ID, $url );
+	}
+
+	/**
+	 * Fix pagination of topics on forum view
+	 *
+	 * @param array $args
+	 * @global $wp_rewrite
+	 * @uses bbp_get_forum_id()
+	 * @uses maybe_map_permalink_to_group
+	 * @return array
+ 	 */
+	public function topic_pagination( $args ) {
+		$new = $this->maybe_map_permalink_to_group( bbp_get_forum_id() );
+
+		if ( empty( $new ) )
+			return $args;
+
+		global $wp_rewrite;
+
+		$args['base'] = trailingslashit( $new ) . $wp_rewrite->pagination_base . '/%#%/';
+
+		return $args;
+	}
+
+	/**
+	 * Fix pagination of replies on topic view
+	 *
+	 * @param array $args
+	 * @global $wp_rewrite
+	 * @uses bbp_get_topic_id()
+	 * @uses maybe_map_permalink_to_group
+	 * @return array
+	 */
+	public function replies_pagination( $args ) {
+		$new = $this->maybe_map_permalink_to_group( bbp_get_topic_id() );
+		if ( empty( $new ) )
+			return $args;
+
+		global $wp_rewrite;
+
+		$args['base'] = trailingslashit( $new ) . $wp_rewrite->pagination_base . '/%#%/';
+
+		return $args;
+	}
+
+	/**
+	 * Ensure that forum content associated with a BuddyPress group can only be
+	 * viewed via the group URL.
+	 *
+	 * @since bbPress (r3802)
+	 */
+	public function redirect_canonical() {
+
+		// Viewing a single forum
+		if ( bbp_is_single_forum() ) {
+			$forum_id  = get_the_ID();
+			$group_ids = bbp_get_forum_group_ids( $forum_id );
+
+		// Viewing a single topic
+		} elseif ( bbp_is_single_topic() ) {
+			$topic_id  = get_the_ID();
+			$slug      = get_post_field( 'post_name', $topic_id );
+			$forum_id  = bbp_get_topic_forum_id( $topic_id );
+			$group_ids = bbp_get_forum_group_ids( $forum_id );
+
+		// Not a forum or topic
+		} else {
+			return;
+		}
+
+		// Bail if not a group forum
+		if ( empty( $group_ids ) )
+			return;
+
+		// Use the first group ID
+		$group_id 	 = $group_ids[0];
+		$group    	 = groups_get_group( array( 'group_id' => $group_id ) );
+		$group_link  = trailingslashit( bp_get_group_permalink( $group ) );
+		$redirect_to = trailingslashit( $group_link . $this->slug );
+
+		// Add topic slug to URL
+		if ( bbp_is_single_topic() ) {
+			$redirect_to  = trailingslashit( $redirect_to . $this->topic_slug . '/' . $slug );
+		}
+
+		bp_core_redirect( $redirect_to );
+	}
+
+	/** Activity **************************************************************/
+
+	/**
+	 * Map a forum post to its corresponding group in the group activity stream.
+	 *
+	 * @since bbPress (r4396)
+	 *
+	 * @param array $args Arguments from BBP_BuddyPress_Activity::record_activity()
+	 * @uses groups_get_current_group() To see if we're posting from a BP group
+	 *
+	 * @return array
+	 */
+	public function map_activity_to_group( $args = array() ) {
+
+		// Get current BP group
+		$group = groups_get_current_group();
+
+		// Not posting from a BuddyPress group? stop now!
+		if ( empty( $group ) )
+			return $args;
+
+		// Set the component to 'groups' so the activity item shows up in the group
+		$args['component']         = buddypress()->groups->id;
+
+		// Move the forum post ID to the secondary item ID
+		$args['secondary_item_id'] = $args['item_id'];
+
+		// Set the item ID to the group ID so the activity item shows up in the group
+		$args['item_id']           = $group->id;
+
+		// Update the group's last activity
+		groups_update_last_activity( $group->id );
+
+		return $args;
+	}
+}
+endif;
Index: /tags/2.5.4/includes/extend/buddypress/index.php
===================================================================
--- /tags/2.5.4/includes/extend/buddypress/index.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/buddypress/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/extend/buddypress/loader.php
===================================================================
--- /tags/2.5.4/includes/extend/buddypress/loader.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/buddypress/loader.php	(revision 5382)
@@ -0,0 +1,325 @@
+<?php
+
+/**
+ * bbPress BuddyPress Component Class
+ *
+ * bbPress and BuddyPress are designed to connect together seamlessly and
+ * invisibly, and this is the hunk of code necessary to make that happen.
+ *
+ * The code in this BuddyPress Extension does some pretty complicated stuff,
+ * far outside the realm of the simplicity bbPress is traditionally known for.
+ *
+ * While the rest of bbPress serves as an example of how to write pretty, simple
+ * code, what's in these files is pure madness. It should not be used as an
+ * example of anything other than successfully juggling chainsaws and puppy-dogs.
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Forums_Component' ) ) :
+/**
+ * Loads Forums Component
+ *
+ * @since bbPress (r3552)
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ */
+class BBP_Forums_Component extends BP_Component {
+
+	/**
+	 * Start the forums component creation process
+	 *
+	 * @since bbPress (r3552)
+	 */
+	public function __construct() {
+		parent::start(
+			'forums',
+			__( 'Forums', 'bbpress' ),
+			bbpress()->includes_dir . 'extend/buddypress/'
+		);
+		$this->includes();
+		$this->setup_globals();
+		$this->setup_actions();
+		$this->fully_loaded();
+	}
+
+	/**
+	 * Include BuddyPress classes and functions
+	 */
+	public function includes( $includes = array() ) {
+
+		// Helper BuddyPress functions
+		$includes[] = 'functions.php';
+
+		// Members modifications
+		$includes[] = 'members.php';
+
+		// BuddyPress Notfications Extension functions
+		if ( bp_is_active( 'notifications' ) ) {
+			$includes[] = 'notifications.php';
+		}
+
+		// BuddyPress Activity Extension class
+		if ( bp_is_active( 'activity' ) ) {
+			$includes[] = 'activity.php';
+		}
+
+		// BuddyPress Group Extension class
+		if ( bbp_is_group_forums_active() && bp_is_active( 'groups' ) ) {
+			$includes[] = 'groups.php';
+		}
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Setup globals
+	 *
+	 * The BP_FORUMS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since bbPress (r3552)
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Define the parent forum ID
+		if ( !defined( 'BP_FORUMS_PARENT_FORUM_ID' ) )
+			define( 'BP_FORUMS_PARENT_FORUM_ID', 1 );
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_FORUMS_SLUG' ) )
+			define( 'BP_FORUMS_SLUG', $this->id );
+
+		// All arguments for forums component
+		$args = array(
+			'path'          => BP_PLUGIN_DIR,
+			'slug'          => BP_FORUMS_SLUG,
+			'root_slug'     => isset( $bp->pages->forums->slug ) ? $bp->pages->forums->slug : BP_FORUMS_SLUG,
+			'has_directory' => false,
+			'search_string' => __( 'Search Forums...', 'bbpress' ),
+		);
+
+		parent::setup_globals( $args );
+	}
+
+	/**
+	 * Setup the actions
+	 *
+	 * @since bbPress (r3395)
+	 * @access private
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 * @link http://bbpress.trac.wordpress.org/ticket/2176
+	 */
+	public function setup_actions() {
+
+		// Setup the components
+		add_action( 'bp_init', array( $this, 'setup_components' ), 7 );
+
+		parent::setup_actions();
+	}
+
+	/**
+	 * Instantiate classes for BuddyPress integration
+	 *
+	 * @since bbPress (r3395)
+	 */
+	public function setup_components() {
+
+		// Always load the members component
+		bbpress()->extend->buddypress->members = new BBP_BuddyPress_Members;
+
+		// Create new activity class
+		if ( bp_is_active( 'activity' ) ) {
+			bbpress()->extend->buddypress->activity = new BBP_BuddyPress_Activity;
+		}
+
+		// Register the group extension only if groups are active
+		if ( bbp_is_group_forums_active() && bp_is_active( 'groups' ) ) {
+			bp_register_group_extension( 'BBP_Forums_Group_Extension' );
+		}
+	}
+
+	/**
+	 * Allow the variables, actions, and filters to be modified by third party
+	 * plugins and themes.
+	 *
+	 * @since bbPress (r3902)
+	 */
+	private function fully_loaded() {
+		do_action_ref_array( 'bbp_buddypress_loaded', array( $this ) );
+	}
+
+	/**
+	 * Setup BuddyBar navigation
+	 *
+	 * @since bbPress (r3552)
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		// Stop if there is no user displayed or logged in
+		if ( !is_user_logged_in() && !bp_displayed_user_id() )
+			return;
+
+		// Define local variable(s)
+		$user_domain = '';
+
+		// Add 'Forums' to the main navigation
+		$main_nav = array(
+			'name'                => __( 'Forums', 'bbpress' ),
+			'slug'                => $this->slug,
+			'position'            => 80,
+			'screen_function'     => 'bbp_member_forums_screen_topics',
+			'default_subnav_slug' => bbp_get_topic_archive_slug(),
+			'item_css_id'         => $this->id
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_id() )
+			$user_domain = bp_displayed_user_domain();
+		elseif ( bp_loggedin_user_domain() )
+			$user_domain = bp_loggedin_user_domain();
+		else
+			return;
+
+		// User link
+		$forums_link = trailingslashit( $user_domain . $this->slug );
+
+		// Topics started
+		$sub_nav[] = array(
+			'name'            => __( 'Topics Started', 'bbpress' ),
+			'slug'            => bbp_get_topic_archive_slug(),
+			'parent_url'      => $forums_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bbp_member_forums_screen_topics',
+			'position'        => 20,
+			'item_css_id'     => 'topics'
+		);
+
+		// Replies to topics
+		$sub_nav[] = array(
+			'name'            => __( 'Replies Created', 'bbpress' ),
+			'slug'            => bbp_get_reply_archive_slug(),
+			'parent_url'      => $forums_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bbp_member_forums_screen_replies',
+			'position'        => 40,
+			'item_css_id'     => 'replies'
+		);
+
+		// Favorite topics
+		$sub_nav[] = array(
+			'name'            => __( 'Favorites', 'bbpress' ),
+			'slug'            => bbp_get_user_favorites_slug(),
+			'parent_url'      => $forums_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bbp_member_forums_screen_favorites',
+			'position'        => 60,
+			'item_css_id'     => 'favorites'
+		);
+
+		// Subscribed topics (my profile only)
+		if ( bp_is_my_profile() ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Subscriptions', 'bbpress' ),
+				'slug'            => bbp_get_user_subscriptions_slug(),
+				'parent_url'      => $forums_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'bbp_member_forums_screen_subscriptions',
+				'position'        => 60,
+				'item_css_id'     => 'subscriptions'
+			);
+		}
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up the admin bar
+	 *
+	 * @since bbPress (r3552)
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$user_domain = bp_loggedin_user_domain();
+			$forums_link = trailingslashit( $user_domain . $this->slug );
+
+			// Add the "My Account" sub menus
+			$wp_admin_nav[] = array(
+				'parent' => buddypress()->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => __( 'Forums', 'bbpress' ),
+				'href'   => trailingslashit( $forums_link )
+			);
+
+			// Topics
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-topics',
+				'title'  => __( 'Topics Started', 'bbpress' ),
+				'href'   => trailingslashit( $forums_link . bbp_get_topic_archive_slug() )
+			);
+
+			// Replies
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-replies',
+				'title'  => __( 'Replies Created', 'bbpress' ),
+				'href'   => trailingslashit( $forums_link . bbp_get_reply_archive_slug() )
+			);
+
+			// Favorites
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-favorites',
+				'title'  => __( 'Favorite Topics', 'bbpress' ),
+				'href'   => trailingslashit( $forums_link . bbp_get_user_favorites_slug() )
+			);
+
+			// Subscriptions
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-subscriptions',
+				'title'  => __( 'Subscribed Topics', 'bbpress' ),
+				'href'   => trailingslashit( $forums_link . bbp_get_user_subscriptions_slug() )
+			);
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Sets up the title for pages and <title>
+	 *
+	 * @since bbPress (r3552)
+	 */
+	public function setup_title() {
+		$bp = buddypress();
+
+		// Adjust title based on view
+		if ( bp_is_forums_component() ) {
+			if ( bp_is_my_profile() ) {
+				$bp->bp_options_title = __( 'Forums', 'bbpress' );
+			} elseif ( bp_is_user() ) {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb'
+				) );
+				$bp->bp_options_title = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+endif;
Index: /tags/2.5.4/includes/extend/buddypress/members.php
===================================================================
--- /tags/2.5.4/includes/extend/buddypress/members.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/buddypress/members.php	(revision 5382)
@@ -0,0 +1,176 @@
+<?php
+
+/**
+ * bbPress BuddyPress Members Class
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BBP_Forums_Members' ) ) :
+/**
+ * Member profile modifications
+ *
+ * @since bbPress (r4395)
+ *
+ * @package bbPress
+ * @subpackage BuddyPress
+ */
+class BBP_BuddyPress_Members {
+
+	/**
+	 * Main constructor for modifying bbPress profile links
+	 *
+	 * @since bbPress (r4395)
+	 */
+	public function __construct() {
+		$this->setup_actions();
+		$this->setup_filters();
+	}
+
+	/**
+	 * Setup the actions
+	 *
+	 * @since bbPress (r4395)
+	 *
+	 * @access private
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_actions() {
+
+		// Allow unsubscribe/unfavorite links to work
+		add_action( 'bp_template_redirect', array( $this, 'set_member_forum_query_vars' ) );
+
+		/** Favorites *********************************************************/
+
+		// Move handler to 'bp_actions' - BuddyPress bypasses template_loader
+		remove_action( 'template_redirect', 'bbp_favorites_handler', 1 );
+		add_action(    'bp_actions',        'bbp_favorites_handler', 1 );
+
+		/** Subscriptions *****************************************************/
+
+		// Move handler to 'bp_actions' - BuddyPress bypasses template_loader
+		remove_action( 'template_redirect', 'bbp_subscriptions_handler', 1 );
+		add_action(    'bp_actions',        'bbp_subscriptions_handler', 1 );
+	}
+
+	/**
+	 * Setup the filters
+	 *
+	 * @since bbPress (r4395)
+	 *
+	 * @access private
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_filters() {
+		add_filter( 'bbp_pre_get_user_profile_url',    array( $this, 'user_profile_url'            )        );
+		add_filter( 'bbp_get_favorites_permalink',     array( $this, 'get_favorites_permalink'     ), 10, 2 );
+		add_filter( 'bbp_get_subscriptions_permalink', array( $this, 'get_subscriptions_permalink' ), 10, 2 );
+	}
+
+	/** Filters ***************************************************************/
+
+	/**
+	 * Override bbPress profile URL with BuddyPress profile URL
+	 *
+	 * @since bbPress (r3401)
+	 * @param string $url
+	 * @param int $user_id
+	 * @param string $user_nicename
+	 * @return string
+	 */
+	public function user_profile_url( $user_id ) {
+
+		// Define local variable(s)
+		$profile_url    = '';
+		$component_slug = bbpress()->extend->buddypress->slug;
+
+		// Special handling for forum component
+		if ( bp_is_current_component( $component_slug ) ) {
+
+			// Empty action or 'topics' action
+			if ( !bp_current_action() || bp_is_current_action( bbp_get_topic_archive_slug() ) ) {
+				$profile_url = bp_core_get_user_domain( $user_id ) . $component_slug . '/' . bbp_get_topic_archive_slug();
+
+			// Empty action or 'topics' action
+			} elseif ( bp_is_current_action( bbp_get_reply_archive_slug() ) ) {
+				$profile_url = bp_core_get_user_domain( $user_id ) . $component_slug . '/' . bbp_get_reply_archive_slug();
+
+			// 'favorites' action
+			} elseif ( bbp_is_favorites_active() && bp_is_current_action( bbp_get_user_favorites_slug() ) ) {
+				$profile_url = $this->get_favorites_permalink( '', $user_id );
+
+			// 'subscriptions' action
+			} elseif ( bbp_is_subscriptions_active() && bp_is_current_action( bbp_get_user_subscriptions_slug() ) ) {
+				$profile_url = $this->get_subscriptions_permalink( '', $user_id );
+			}
+
+		// Not in users' forums area
+		} else {
+			$profile_url = bp_core_get_user_domain( $user_id );
+		}
+
+		return trailingslashit( $profile_url );
+	}
+
+	/**
+	 * Override bbPress favorites URL with BuddyPress profile URL
+	 *
+	 * @since bbPress (r3721)
+	 * @param string $url
+	 * @param int $user_id
+	 * @return string
+	 */
+	public function get_favorites_permalink( $url, $user_id ) {
+		$component_slug = bbpress()->extend->buddypress->slug;
+		$url            = trailingslashit( bp_core_get_user_domain( $user_id ) . $component_slug . '/' . bbp_get_user_favorites_slug() );
+		return $url;
+	}
+
+	/**
+	 * Override bbPress subscriptions URL with BuddyPress profile URL
+	 *
+	 * @since bbPress (r3721)
+	 * @param string $url
+	 * @param int $user_id
+	 * @return string
+	 */
+	public function get_subscriptions_permalink( $url, $user_id ) {
+		$component_slug = bbpress()->extend->buddypress->slug;
+		$url            = trailingslashit( bp_core_get_user_domain( $user_id ) . $component_slug . '/' . bbp_get_user_subscriptions_slug() );
+		return $url;
+	}
+
+	/**
+	 * Set favorites and subscriptions query variables if viewing member profile
+	 * pages.
+	 *
+	 * @since bbPress (r4615)
+	 *
+	 * @global WP_Query $wp_query
+	 * @return If not viewing your own profile
+	 */
+	public function set_member_forum_query_vars() {
+
+		// Special handling for forum component
+		if ( ! bp_is_my_profile() )
+			return;
+
+		global $wp_query;
+
+		// 'favorites' action
+		if ( bbp_is_favorites_active() && bp_is_current_action( bbp_get_user_favorites_slug() ) ) {
+			$wp_query->bbp_is_single_user_favs = true;
+
+		// 'subscriptions' action
+		} elseif ( bbp_is_subscriptions_active() && bp_is_current_action( bbp_get_user_subscriptions_slug() ) ) {
+			$wp_query->bbp_is_single_user_subs = true;
+		}
+	}
+}
+endif;
Index: /tags/2.5.4/includes/extend/buddypress/notifications.php
===================================================================
--- /tags/2.5.4/includes/extend/buddypress/notifications.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/buddypress/notifications.php	(revision 5382)
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * Filter registered notifications components, and add 'forums' to the queried
+ * 'component_name' array.
+ *
+ * @since bbPress (r5232)
+ *
+ * @see BP_Notifications_Notification::get()
+ * @param array $component_names
+ * @return array
+ */
+function bbp_filter_notifications_get_registered_components( $component_names = array() ) {
+
+	// Force $component_names to be an array
+	if ( ! is_array( $component_names ) ) {
+		$component_names = array();
+	}
+
+	// Add 'forums' component to registered components array
+	array_push( $component_names, bbp_get_component_name() );
+
+	// Return component's with 'forums' appended
+	return $component_names;
+}
+add_filter( 'bp_notifications_get_registered_components', 'bbp_filter_notifications_get_registered_components', 10 );
+
+/**
+ * Format the BuddyBar/Toolbar notifications
+ *
+ * @since bbPress (r5155)
+ *
+ * @package bbPress
+ *
+ * @param string $action The kind of notification being rendered
+ * @param int $item_id The primary item id
+ * @param int $secondary_item_id The secondary item id
+ * @param int $total_items The total number of messaging-related notifications waiting for the user
+ * @param string $format 'string' for BuddyBar-compatible notifications; 'array' for WP Toolbar
+ */
+function bbp_format_buddypress_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) {
+
+	// New reply notifications
+	if ( 'bbp_new_reply' === $action ) {
+		$topic_id    = bbp_get_reply_topic_id( $item_id );
+		$topic_title = bbp_get_topic_title( $topic_id );
+		$topic_link  = wp_nonce_url( add_query_arg( array( 'action' => 'bbp_mark_read', 'topic_id' => $topic_id ), bbp_get_reply_url( $item_id ) ), 'bbp_mark_topic_' . $topic_id );
+		$title_attr  = __( 'Topic Replies', 'bbpress' );
+
+		if ( (int) $total_items > 1 ) {
+			$text   = sprintf( __( 'You have %d new replies', 'bbpress' ), (int) $total_items );
+			$filter = 'bbp_multiple_new_subscription_notification';
+		} else {
+			if ( !empty( $secondary_item_id ) ) {
+				$text = sprintf( __( 'You have %d new reply to %2$s from %3$s', 'bbpress' ), (int) $total_items, $topic_title, bp_core_get_user_displayname( $secondary_item_id ) );
+			} else {
+				$text = sprintf( __( 'You have %d new reply to %s',             'bbpress' ), (int) $total_items, $topic_title );
+			}
+			$filter = 'bbp_single_new_subscription_notification';
+		}
+
+		// WordPress Toolbar
+		if ( 'string' === $format ) {
+			$return = apply_filters( $filter, '<a href="' . esc_url( $topic_link ) . '" title="' . esc_attr( $title_attr ) . '">' . esc_html( $text ) . '</a>', (int) $total_items, $text, $topic_link );
+
+		// Deprecated BuddyBar
+		} else {
+			$return = apply_filters( $filter, array(
+				'text' => $text,
+				'link' => $topic_link
+			), $topic_link, (int) $total_items, $text, $topic_title );
+		}
+
+		do_action( 'bbp_format_buddypress_notifications', $action, $item_id, $secondary_item_id, $total_items );
+
+		return $return;
+	}
+}
+add_filter( 'bp_notifications_get_notifications_for_user', 'bbp_format_buddypress_notifications', 10, 5 );
+
+/**
+ * Hooked into the new reply function, this notification action is responsible
+ * for notifying topic and hierarchical reply authors of topic replies.
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $reply_id
+ * @param int $topic_id
+ * @param int $forum_id (not used)
+ * @param array $anonymous_data (not used)
+ * @param int $author_id
+ * @param bool $is_edit Used to bail if this gets hooked to an edit action
+ * @param int $reply_to
+ */
+function bbp_buddypress_add_notification( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = false, $author_id = 0, $is_edit = false, $reply_to = 0 ) {
+
+	// Bail if somehow this is hooked to an edit action
+	if ( !empty( $is_edit ) ) {
+		return;
+	}
+
+	// Get autohr information
+	$topic_author_id   = bbp_get_topic_author_id( $topic_id );
+	$secondary_item_id = $author_id;
+
+	// Hierarchical replies
+	if ( !empty( $reply_to ) ) {
+		$reply_to_item_id = bbp_get_topic_author_id( $reply_to );
+	}
+
+	// Get some reply information
+	$args = array(
+		'user_id'          => $topic_author_id,
+		'item_id'          => $topic_id,
+		'component_name'   => bbp_get_component_name(),
+		'component_action' => 'bbp_new_reply',
+		'date_notified'    => get_post( $reply_id )->post_date,
+	);
+
+ 	// Notify the topic author if not the current reply author
+ 	if ( $author_id !== $topic_author_id ) {
+		$args['secondary_item_id'] = $secondary_item_id ;
+
+		bp_notifications_add_notification( $args );
+ 	}
+ 
+ 	// Notify the immediate reply author if not the current reply author
+ 	if ( !empty( $reply_to ) && ( $author_id !== $reply_to_item_id ) ) {
+		$args['secondary_item_id'] = $reply_to_item_id ;
+
+		bp_notifications_add_notification( $args );
+ 	}
+}
+add_action( 'bbp_new_reply', 'bbp_buddypress_add_notification', 10, 7 );
+
+/**
+ * Mark notifications as read when reading a topic
+ *
+ * @since bbPress (r5155)
+ *
+ * @return If not trying to mark a notification as read
+ */
+function bbp_buddypress_mark_notifications( $action = '' ) {
+
+	// Bail if no topic ID is passed
+	if ( empty( $_GET['topic_id'] ) ) {
+		return;
+	}
+
+	// Bail if action is not for this function
+	if ( 'bbp_mark_read' !== $action ) {
+		return;
+	}
+
+	// Get required data
+	$user_id  = bp_loggedin_user_id();
+	$topic_id = intval( $_GET['topic_id'] );
+
+	// Check nonce
+	if ( ! bbp_verify_nonce_request( 'bbp_mark_topic_' . $topic_id ) ) {
+		bbp_add_error( 'bbp_notification_topic_id', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+
+	// Check current user's ability to edit the user
+	} elseif ( !current_user_can( 'edit_user', $user_id ) ) {
+		bbp_add_error( 'bbp_notification_permissions', __( '<strong>ERROR</strong>: You do not have permission to mark notifications for that user.', 'bbpress' ) );
+	}
+
+	// Bail if we have errors
+	if ( ! bbp_has_errors() ) {
+
+		// Attempt to clear notifications for the current user from this topic
+		$success = bp_notifications_mark_notifications_by_item_id( $user_id, $topic_id, bbp_get_component_name(), 'bbp_new_reply' );
+
+		// Do additional subscriptions actions
+		do_action( 'bbp_notifications_handler', $success, $user_id, $topic_id, $action );
+	}
+
+	// Redirect to the topic
+	$redirect = bbp_get_reply_url( $topic_id );
+
+	// Redirect
+	wp_safe_redirect( $redirect );
+
+	// For good measure
+	exit();
+}
+add_action( 'bbp_get_request', 'bbp_buddypress_mark_notifications', 1 );
Index: /tags/2.5.4/includes/extend/index.php
===================================================================
--- /tags/2.5.4/includes/extend/index.php	(revision 5382)
+++ /tags/2.5.4/includes/extend/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/forums/capabilities.php
===================================================================
--- /tags/2.5.4/includes/forums/capabilities.php	(revision 5382)
+++ /tags/2.5.4/includes/forums/capabilities.php	(revision 5382)
@@ -0,0 +1,188 @@
+<?php
+
+/**
+ * bbPress Forum Capabilites
+ *
+ * Used to map forum capabilities to WordPress's existing capabilities.
+ *
+ * @package bbPress
+ * @subpackage Capabilities
+ */
+
+/**
+ * Return forum capabilities
+ *
+ * @since bbPress (r2593)
+ *
+ * @uses apply_filters() Calls 'bbp_get_forum_caps' with the capabilities
+ * @return array Forum capabilities
+ */
+function bbp_get_forum_caps() {
+	return apply_filters( 'bbp_get_forum_caps', array (
+		'edit_posts'          => 'edit_forums',
+		'edit_others_posts'   => 'edit_others_forums',
+		'publish_posts'       => 'publish_forums',
+		'read_private_posts'  => 'read_private_forums',
+		'read_hidden_posts'   => 'read_hidden_forums',
+		'delete_posts'        => 'delete_forums',
+		'delete_others_posts' => 'delete_others_forums'
+	) );
+}
+
+/**
+ * Maps forum capabilities
+ *
+ * @since bbPress (r4242)
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ * @uses get_post() To get the post
+ * @uses get_post_type_object() To get the post type object
+ * @uses apply_filters() Filter capability map results
+ * @return array Actual capabilities for meta capability
+ */
+function bbp_map_forum_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+
+	// What capability is being checked?
+	switch ( $cap ) {
+
+		/** Reading ***********************************************************/
+
+		case 'read_private_forums' :
+		case 'read_hidden_forums'  :
+
+			// Moderators can always read private/hidden forums
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( 'moderate' );
+			}
+
+			break;
+
+		case 'read_forum' :
+
+			// User cannot spectate
+			if ( ! user_can( $user_id, 'spectate' ) ) {
+				$caps = array( 'do_not_allow' );
+
+			// Do some post ID based logic
+			} else {
+
+				// Get the post
+				$_post = get_post( $args[0] );
+				if ( !empty( $_post ) ) {
+
+					// Get caps for post type object
+					$post_type = get_post_type_object( $_post->post_type );
+
+					// Post is public
+					if ( bbp_get_public_status_id() === $_post->post_status ) {
+						$caps = array( 'spectate' );
+
+					// User is author so allow read
+					} elseif ( (int) $user_id === (int) $_post->post_author ) {
+						$caps = array( 'spectate' );
+
+					// Unknown so map to private posts
+					} else {
+						$caps = array( $post_type->cap->read_private_posts );
+					}
+				}
+			}
+
+			break;
+
+		/** Publishing ********************************************************/
+
+		case 'publish_forums'  :
+
+			// Moderators can always edit
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( 'moderate' );
+			}
+
+			break;
+
+		/** Editing ***********************************************************/
+
+		// Used primarily in wp-admin
+		case 'edit_forums'         :
+		case 'edit_others_forums'  :
+
+			// Moderators can always edit
+			if ( user_can( $user_id, 'keep_gate' ) ) {
+				$caps = array( 'keep_gate' );
+
+			// Otherwise, block
+			} else {
+				$caps = array( 'do_not_allow' );
+			}
+
+			break;
+
+		// Used everywhere
+		case 'edit_forum' :
+
+			// Get the post
+			$_post = get_post( $args[0] );
+			if ( !empty( $_post ) ) {
+
+				// Get caps for post type object
+				$post_type = get_post_type_object( $_post->post_type );
+				$caps      = array();
+
+				// Add 'do_not_allow' cap if user is spam or deleted
+				if ( bbp_is_user_inactive( $user_id ) ) {
+					$caps[] = 'do_not_allow';
+
+				// User is author so allow edit if not in admin
+				} elseif ( !is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
+					$caps[] = $post_type->cap->edit_posts;
+
+				// Unknown, so map to edit_others_posts
+				} else {
+					$caps[] = $post_type->cap->edit_others_posts;
+				}
+			}
+
+			break;
+
+		/** Deleting **********************************************************/
+
+		// Allow forum authors to delete forums (for BuddyPress groups, etc)
+		case 'delete_forum' :
+
+			// Get the post
+			$_post = get_post( $args[0] );
+			if ( !empty( $_post ) ) {
+
+				// Get caps for post type object
+				$post_type = get_post_type_object( $_post->post_type );
+				$caps      = array();
+
+				// Add 'do_not_allow' cap if user is spam or deleted
+				if ( bbp_is_user_inactive( $user_id ) ) {
+					$caps[] = 'do_not_allow';
+
+				// User is author so allow to delete
+				} elseif ( (int) $user_id === (int) $_post->post_author ) {
+					$caps[] = $post_type->cap->delete_posts;
+
+				// Unknown so map to delete_others_posts
+				} else {
+					$caps[] = $post_type->cap->delete_others_posts;
+				}
+			}
+
+			break;
+
+		/** Admin *************************************************************/
+
+		case 'bbp_forums_admin' :
+			$caps = array( 'keep_gate' );
+			break;
+	}
+
+	return apply_filters( 'bbp_map_forum_meta_caps', $caps, $cap, $user_id, $args );
+}
Index: /tags/2.5.4/includes/forums/functions.php
===================================================================
--- /tags/2.5.4/includes/forums/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/forums/functions.php	(revision 5382)
@@ -0,0 +1,2352 @@
+<?php
+
+/**
+ * bbPress Forum Functions
+ *
+ * @package bbPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Insert ********************************************************************/
+
+/**
+ * A wrapper for wp_insert_post() that also includes the necessary meta values
+ * for the forum to function properly.
+ *
+ * @since bbPress (r3349)
+ *
+ * @uses bbp_parse_args()
+ * @uses bbp_get_forum_post_type()
+ * @uses wp_insert_post()
+ * @uses update_post_meta()
+ *
+ * @param array $forum_data Forum post data
+ * @param arrap $forum_meta Forum meta data
+ */
+function bbp_insert_forum( $forum_data = array(), $forum_meta = array() ) {
+
+	// Forum
+	$forum_data = bbp_parse_args( $forum_data, array(
+		'post_parent'    => 0, // forum ID
+		'post_status'    => bbp_get_public_status_id(),
+		'post_type'      => bbp_get_forum_post_type(),
+		'post_author'    => bbp_get_current_user_id(),
+		'post_password'  => '',
+		'post_content'   => '',
+		'post_title'     => '',
+		'menu_order'     => 0,
+		'comment_status' => 'closed'
+	), 'insert_forum' );
+
+	// Insert forum
+	$forum_id   = wp_insert_post( $forum_data );
+
+	// Bail if no forum was added
+	if ( empty( $forum_id ) ) {
+		return false;
+	}
+
+	// Forum meta
+	$forum_meta = bbp_parse_args( $forum_meta, array(
+		'reply_count'          => 0,
+		'topic_count'          => 0,
+		'topic_count_hidden'   => 0,
+		'total_reply_count'    => 0,
+		'total_topic_count'    => 0,
+		'last_topic_id'        => 0,
+		'last_reply_id'        => 0,
+		'last_active_id'       => 0,
+		'last_active_time'     => 0,
+		'forum_subforum_count' => 0,
+	), 'insert_forum_meta' );
+
+	// Insert forum meta
+	foreach ( $forum_meta as $meta_key => $meta_value ) {
+		update_post_meta( $forum_id, '_bbp_' . $meta_key, $meta_value );
+	}
+
+	// Return new forum ID
+	return $forum_id;
+}
+
+/** Post Form Handlers ********************************************************/
+
+/**
+ * Handles the front end forum submission
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses bbp_is_anonymous() To check if an anonymous post is being made
+ * @uses current_user_can() To check if the current user can publish forum
+ * @uses bbp_get_current_user_id() To get the current user id
+ * @uses bbp_filter_anonymous_post_data() To filter anonymous data
+ * @uses bbp_set_current_anonymous_user_data() To set the anonymous user cookies
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses esc_attr() For sanitization
+ * @uses bbp_is_forum_category() To check if the forum is a category
+ * @uses bbp_is_forum_closed() To check if the forum is closed
+ * @uses bbp_is_forum_private() To check if the forum is private
+ * @uses bbp_check_for_flood() To check for flooding
+ * @uses bbp_check_for_duplicate() To check for duplicates
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses remove_filter() To remove kses filters if needed
+ * @uses apply_filters() Calls 'bbp_new_forum_pre_title' with the content
+ * @uses apply_filters() Calls 'bbp_new_forum_pre_content' with the content
+ * @uses bbPress::errors::get_error_codes() To get the {@link WP_Error} errors
+ * @uses wp_insert_post() To insert the forum
+ * @uses do_action() Calls 'bbp_new_forum' with the forum id, forum id,
+ *                    anonymous data and reply author
+ * @uses bbp_stick_forum() To stick or super stick the forum
+ * @uses bbp_unstick_forum() To unstick the forum
+ * @uses bbp_get_forum_permalink() To get the forum permalink
+ * @uses wp_safe_redirect() To redirect to the forum link
+ * @uses bbPress::errors::get_error_messages() To get the {@link WP_Error} error
+ *                                              messages
+ */
+function bbp_new_forum_handler( $action = '' ) {
+
+	// Bail if action is not bbp-new-forum
+	if ( 'bbp-new-forum' !== $action )
+		return;
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'bbp-new-forum' ) ) {
+		bbp_add_error( 'bbp_new_forum_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Define local variable(s)
+	$view_all = $anonymous_data = false;
+	$forum_parent_id = $forum_author = 0;
+	$forum_title = $forum_content = '';
+
+	/** Forum Author **********************************************************/
+
+	// User cannot create forums
+	if ( !current_user_can( 'publish_forums' ) ) {
+		bbp_add_error( 'bbp_forum_permissions', __( '<strong>ERROR</strong>: You do not have permission to create new forums.', 'bbpress' ) );
+		return;
+	}
+
+	// Forum author is current user
+	$forum_author = bbp_get_current_user_id();
+
+	// Remove kses filters from title and content for capable users and if the nonce is verified
+	if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_forum'] ) && wp_create_nonce( 'bbp-unfiltered-html-forum_new' ) === $_POST['_bbp_unfiltered_html_forum'] ) {
+		remove_filter( 'bbp_new_forum_pre_title',   'wp_filter_kses'      );
+		remove_filter( 'bbp_new_forum_pre_content', 'bbp_encode_bad',  10 );
+		remove_filter( 'bbp_new_forum_pre_content', 'bbp_filter_kses', 30 );
+	}
+
+	/** Forum Title ***********************************************************/
+
+	if ( !empty( $_POST['bbp_forum_title'] ) )
+		$forum_title = esc_attr( strip_tags( $_POST['bbp_forum_title'] ) );
+
+	// Filter and sanitize
+	$forum_title = apply_filters( 'bbp_new_forum_pre_title', $forum_title );
+
+	// No forum title
+	if ( empty( $forum_title ) )
+		bbp_add_error( 'bbp_forum_title', __( '<strong>ERROR</strong>: Your forum needs a title.', 'bbpress' ) );
+
+	/** Forum Content *********************************************************/
+
+	if ( !empty( $_POST['bbp_forum_content'] ) )
+		$forum_content = $_POST['bbp_forum_content'];
+
+	// Filter and sanitize
+	$forum_content = apply_filters( 'bbp_new_forum_pre_content', $forum_content );
+
+	// No forum content
+	if ( empty( $forum_content ) )
+		bbp_add_error( 'bbp_forum_content', __( '<strong>ERROR</strong>: Your forum description cannot be empty.', 'bbpress' ) );
+
+	/** Forum Parent **********************************************************/
+
+	// Forum parent was passed (the norm)
+	if ( !empty( $_POST['bbp_forum_parent_id'] ) ) {
+		$forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
+	}
+
+	// Filter and sanitize
+	$forum_parent_id = apply_filters( 'bbp_new_forum_pre_parent_id', $forum_parent_id );
+
+	// No forum parent was passed (should never happen)
+	if ( empty( $forum_parent_id ) ) {
+		bbp_add_error( 'bbp_new_forum_missing_parent', __( '<strong>ERROR</strong>: Your forum must have a parent.', 'bbpress' ) );
+
+	// Forum exists
+	} elseif ( !empty( $forum_parent_id ) ) {
+
+		// Forum is a category
+		if ( bbp_is_forum_category( $forum_parent_id ) ) {
+			bbp_add_error( 'bbp_new_forum_forum_category', __( '<strong>ERROR</strong>: This forum is a category. No forums can be created in this forum.', 'bbpress' ) );
+		}
+
+		// Forum is closed and user cannot access
+		if ( bbp_is_forum_closed( $forum_parent_id ) && !current_user_can( 'edit_forum', $forum_parent_id ) ) {
+			bbp_add_error( 'bbp_new_forum_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new forums.', 'bbpress' ) );
+		}
+
+		// Forum is private and user cannot access
+		if ( bbp_is_forum_private( $forum_parent_id ) && !current_user_can( 'read_private_forums' ) ) {
+			bbp_add_error( 'bbp_new_forum_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
+		}
+
+		// Forum is hidden and user cannot access
+		if ( bbp_is_forum_hidden( $forum_parent_id ) && !current_user_can( 'read_hidden_forums' ) ) {
+			bbp_add_error( 'bbp_new_forum_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
+		}
+	}
+
+	/** Forum Flooding ********************************************************/
+
+	if ( !bbp_check_for_flood( $anonymous_data, $forum_author ) )
+		bbp_add_error( 'bbp_forum_flood', __( '<strong>ERROR</strong>: Slow down; you move too fast.', 'bbpress' ) );
+
+	/** Forum Duplicate *******************************************************/
+
+	if ( !bbp_check_for_duplicate( array( 'post_type' => bbp_get_forum_post_type(), 'post_author' => $forum_author, 'post_content' => $forum_content, 'anonymous_data' => $anonymous_data ) ) )
+		bbp_add_error( 'bbp_forum_duplicate', __( '<strong>ERROR</strong>: This forum already exists.', 'bbpress' ) );
+
+	/** Forum Blacklist *******************************************************/
+
+	if ( !bbp_check_for_blacklist( $anonymous_data, $forum_author, $forum_title, $forum_content ) )
+		bbp_add_error( 'bbp_forum_blacklist', __( '<strong>ERROR</strong>: Your forum cannot be created at this time.', 'bbpress' ) );
+
+	/** Forum Moderation ******************************************************/
+
+	$post_status = bbp_get_public_status_id();
+	if ( !bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content ) )
+		$post_status = bbp_get_pending_status_id();
+
+	/** Additional Actions (Before Save) **************************************/
+
+	do_action( 'bbp_new_forum_pre_extras', $forum_parent_id );
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors *************************************************************/
+
+	// Add the content of the form to $forum_data as an array
+	// Just in time manipulation of forum data before being created
+	$forum_data = apply_filters( 'bbp_new_forum_pre_insert', array(
+		'post_author'    => $forum_author,
+		'post_title'     => $forum_title,
+		'post_content'   => $forum_content,
+		'post_parent'    => $forum_parent_id,
+		'post_status'    => $post_status,
+		'post_type'      => bbp_get_forum_post_type(),
+		'comment_status' => 'closed'
+	) );
+
+	// Insert forum
+	$forum_id = wp_insert_post( $forum_data );
+
+	/** No Errors *************************************************************/
+
+	if ( !empty( $forum_id ) && !is_wp_error( $forum_id ) ) {
+
+		/** Trash Check *******************************************************/
+
+		// If the forum is trash, or the forum_status is switched to
+		// trash, trash it properly
+		if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( $forum_data['post_status'] === bbp_get_trash_status_id() ) ) {
+
+			// Trash the reply
+			wp_trash_post( $forum_id );
+
+			// Force view=all
+			$view_all = true;
+		}
+
+		/** Spam Check ********************************************************/
+
+		// If reply or forum are spam, officially spam this reply
+		if ( $forum_data['post_status'] === bbp_get_spam_status_id() ) {
+			add_post_meta( $forum_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );
+
+			// Force view=all
+			$view_all = true;
+		}
+
+		/** Update counts, etc... *********************************************/
+
+		do_action( 'bbp_new_forum', array(
+			'forum_id'           => $forum_id,
+			'post_parent'        => $forum_parent_id,
+			'forum_author'       => $forum_author,
+			'last_topic_id'      => 0,
+			'last_reply_id'      => 0,
+			'last_active_id'     => 0,
+			'last_active_time'   => 0,
+			'last_active_status' => bbp_get_public_status_id()
+		) );
+
+		/** Additional Actions (After Save) ***********************************/
+
+		do_action( 'bbp_new_forum_post_extras', $forum_id );
+
+		/** Redirect **********************************************************/
+
+		// Redirect to
+		$redirect_to  = bbp_get_redirect_to();
+
+		// Get the forum URL
+		$redirect_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
+
+		// Add view all?
+		if ( bbp_get_view_all() || !empty( $view_all ) ) {
+
+			// User can moderate, so redirect to forum with view all set
+			if ( current_user_can( 'moderate' ) ) {
+				$redirect_url = bbp_add_view_all( $redirect_url );
+
+			// User cannot moderate, so redirect to forum
+			} else {
+				$redirect_url = bbp_get_forum_permalink( $forum_id );
+			}
+		}
+
+		// Allow to be filtered
+		$redirect_url = apply_filters( 'bbp_new_forum_redirect_to', $redirect_url, $redirect_to );
+
+		/** Successful Save ***************************************************/
+
+		// Redirect back to new forum
+		wp_safe_redirect( $redirect_url );
+
+		// For good measure
+		exit();
+
+	// Errors
+	} else {
+		$append_error = ( is_wp_error( $forum_id ) && $forum_id->get_error_message() ) ? $forum_id->get_error_message() . ' ' : '';
+		bbp_add_error( 'bbp_forum_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your forum:' . $append_error, 'bbpress' ) );
+	}
+}
+
+/**
+ * Handles the front end edit forum submission
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbPress:errors::add() To log various error messages
+ * @uses bbp_get_forum() To get the forum
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses bbp_is_forum_anonymous() To check if forum is by an anonymous user
+ * @uses current_user_can() To check if the current user can edit the forum
+ * @uses bbp_filter_anonymous_post_data() To filter anonymous data
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses esc_attr() For sanitization
+ * @uses bbp_is_forum_category() To check if the forum is a category
+ * @uses bbp_is_forum_closed() To check if the forum is closed
+ * @uses bbp_is_forum_private() To check if the forum is private
+ * @uses remove_filter() To remove kses filters if needed
+ * @uses apply_filters() Calls 'bbp_edit_forum_pre_title' with the title and
+ *                        forum id
+ * @uses apply_filters() Calls 'bbp_edit_forum_pre_content' with the content
+ *                        and forum id
+ * @uses bbPress::errors::get_error_codes() To get the {@link WP_Error} errors
+ * @uses wp_save_post_revision() To save a forum revision
+ * @uses bbp_update_forum_revision_log() To update the forum revision log
+ * @uses wp_update_post() To update the forum
+ * @uses do_action() Calls 'bbp_edit_forum' with the forum id, forum id,
+ *                    anonymous data and reply author
+ * @uses bbp_move_forum_handler() To handle movement of a forum from one forum
+ *                                 to another
+ * @uses bbp_get_forum_permalink() To get the forum permalink
+ * @uses wp_safe_redirect() To redirect to the forum link
+ * @uses bbPress::errors::get_error_messages() To get the {@link WP_Error} error
+ *                                              messages
+ */
+function bbp_edit_forum_handler( $action = '' ) {
+
+	// Bail if action is not bbp-edit-forum
+	if ( 'bbp-edit-forum' !== $action )
+		return;
+
+	// Define local variable(s)
+	$anonymous_data = array();
+	$forum = $forum_id = $forum_parent_id = 0;
+	$forum_title = $forum_content = $forum_edit_reason = '';
+
+	/** Forum *****************************************************************/
+
+	// Forum id was not passed
+	if ( empty( $_POST['bbp_forum_id'] ) ) {
+		bbp_add_error( 'bbp_edit_forum_id', __( '<strong>ERROR</strong>: Forum ID not found.', 'bbpress' ) );
+		return;
+
+	// Forum id was passed
+	} elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
+		$forum_id = (int) $_POST['bbp_forum_id'];
+		$forum    = bbp_get_forum( $forum_id );
+	}
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'bbp-edit-forum_' . $forum_id ) ) {
+		bbp_add_error( 'bbp_edit_forum_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+
+	// Forum does not exist
+	} elseif ( empty( $forum ) ) {
+		bbp_add_error( 'bbp_edit_forum_not_found', __( '<strong>ERROR</strong>: The forum you want to edit was not found.', 'bbpress' ) );
+		return;
+
+	// User cannot edit this forum
+	} elseif ( !current_user_can( 'edit_forum', $forum_id ) ) {
+		bbp_add_error( 'bbp_edit_forum_permissions', __( '<strong>ERROR</strong>: You do not have permission to edit that forum.', 'bbpress' ) );
+		return;
+	}
+
+	// Remove kses filters from title and content for capable users and if the nonce is verified
+	if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_forum'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-forum_' . $forum_id ) === $_POST['_bbp_unfiltered_html_forum'] ) ) {
+		remove_filter( 'bbp_edit_forum_pre_title',   'wp_filter_kses'      );
+		remove_filter( 'bbp_edit_forum_pre_content', 'bbp_encode_bad',  10 );
+		remove_filter( 'bbp_edit_forum_pre_content', 'bbp_filter_kses', 30 );
+	}
+
+	/** Forum Parent ***********************************************************/
+
+	// Forum parent id was passed
+	if ( !empty( $_POST['bbp_forum_parent_id'] ) ) {
+		$forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
+	}
+
+	// Current forum this forum is in
+	$current_parent_forum_id = bbp_get_forum_parent_id( $forum_id );
+
+	// Forum exists
+	if ( !empty( $forum_parent_id ) && ( $forum_parent_id !== $current_parent_forum_id ) ) {
+
+		// Forum is closed and user cannot access
+		if ( bbp_is_forum_closed( $forum_parent_id ) && !current_user_can( 'edit_forum', $forum_parent_id ) ) {
+			bbp_add_error( 'bbp_edit_forum_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new forums.', 'bbpress' ) );
+		}
+
+		// Forum is private and user cannot access
+		if ( bbp_is_forum_private( $forum_parent_id ) && !current_user_can( 'read_private_forums' ) ) {
+			bbp_add_error( 'bbp_edit_forum_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
+		}
+
+		// Forum is hidden and user cannot access
+		if ( bbp_is_forum_hidden( $forum_parent_id ) && !current_user_can( 'read_hidden_forums' ) ) {
+			bbp_add_error( 'bbp_edit_forum_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
+		}
+	}
+
+	/** Forum Title ***********************************************************/
+
+	if ( !empty( $_POST['bbp_forum_title'] ) )
+		$forum_title = esc_attr( strip_tags( $_POST['bbp_forum_title'] ) );
+
+	// Filter and sanitize
+	$forum_title = apply_filters( 'bbp_edit_forum_pre_title', $forum_title, $forum_id );
+
+	// No forum title
+	if ( empty( $forum_title ) )
+		bbp_add_error( 'bbp_edit_forum_title', __( '<strong>ERROR</strong>: Your forum needs a title.', 'bbpress' ) );
+
+	/** Forum Content *********************************************************/
+
+	if ( !empty( $_POST['bbp_forum_content'] ) )
+		$forum_content = $_POST['bbp_forum_content'];
+
+	// Filter and sanitize
+	$forum_content = apply_filters( 'bbp_edit_forum_pre_content', $forum_content, $forum_id );
+
+	// No forum content
+	if ( empty( $forum_content ) )
+		bbp_add_error( 'bbp_edit_forum_content', __( '<strong>ERROR</strong>: Your forum description cannot be empty.', 'bbpress' ) );
+
+	/** Forum Blacklist *******************************************************/
+
+	if ( !bbp_check_for_blacklist( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) )
+		bbp_add_error( 'bbp_forum_blacklist', __( '<strong>ERROR</strong>: Your forum cannot be edited at this time.', 'bbpress' ) );
+
+	/** Forum Moderation ******************************************************/
+
+	$post_status = bbp_get_public_status_id();
+	if ( !bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) )
+		$post_status = bbp_get_pending_status_id();
+
+	/** Additional Actions (Before Save) **************************************/
+
+	do_action( 'bbp_edit_forum_pre_extras', $forum_id );
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors *************************************************************/
+
+	// Add the content of the form to $forum_data as an array
+	// Just in time manipulation of forum data before being edited
+	$forum_data = apply_filters( 'bbp_edit_forum_pre_insert', array(
+		'ID'           => $forum_id,
+		'post_title'   => $forum_title,
+		'post_content' => $forum_content,
+		'post_status'  => $post_status,
+		'post_parent'  => $forum_parent_id
+	) );
+
+	// Insert forum
+	$forum_id = wp_update_post( $forum_data );
+
+	/** Revisions *************************************************************/
+
+	/**
+	 * @todo omitted for 2.1
+	// Revision Reason
+	if ( !empty( $_POST['bbp_forum_edit_reason'] ) )
+		$forum_edit_reason = esc_attr( strip_tags( $_POST['bbp_forum_edit_reason'] ) );
+
+	// Update revision log
+	if ( !empty( $_POST['bbp_log_forum_edit'] ) && ( "1" === $_POST['bbp_log_forum_edit'] ) && ( $revision_id = wp_save_post_revision( $forum_id ) ) ) {
+		bbp_update_forum_revision_log( array(
+			'forum_id'    => $forum_id,
+			'revision_id' => $revision_id,
+			'author_id'   => bbp_get_current_user_id(),
+			'reason'      => $forum_edit_reason
+		) );
+	}
+	 */
+
+	/** No Errors *************************************************************/
+
+	if ( !empty( $forum_id ) && !is_wp_error( $forum_id ) ) {
+
+		// Update counts, etc...
+		do_action( 'bbp_edit_forum', array(
+			'forum_id'           => $forum_id,
+			'post_parent'        => $forum_parent_id,
+			'forum_author'       => $forum->post_author,
+			'last_topic_id'      => 0,
+			'last_reply_id'      => 0,
+			'last_active_id'     => 0,
+			'last_active_time'   => 0,
+			'last_active_status' => bbp_get_public_status_id()
+		) );
+
+		// If the new forum parent id is not equal to the old forum parent
+		// id, run the bbp_move_forum action and pass the forum's parent id
+		// as the first arg and new forum parent id as the second.
+		// @todo implement
+		//if ( $forum_id !== $forum->post_parent )
+		//	bbp_move_forum_handler( $forum_parent_id, $forum->post_parent, $forum_id );
+
+		/** Additional Actions (After Save) ***********************************/
+
+		do_action( 'bbp_edit_forum_post_extras', $forum_id );
+
+		/** Redirect **********************************************************/
+
+		// Redirect to
+		$redirect_to = bbp_get_redirect_to();
+
+		// View all?
+		$view_all = bbp_get_view_all();
+
+		// Get the forum URL
+		$forum_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
+
+		// Add view all?
+		if ( !empty( $view_all ) )
+			$forum_url = bbp_add_view_all( $forum_url );
+
+		// Allow to be filtered
+		$forum_url = apply_filters( 'bbp_edit_forum_redirect_to', $forum_url, $view_all, $redirect_to );
+
+		/** Successful Edit ***************************************************/
+
+		// Redirect back to new forum
+		wp_safe_redirect( $forum_url );
+
+		// For good measure
+		exit();
+
+	/** Errors ****************************************************************/
+
+	} else {
+		$append_error = ( is_wp_error( $forum_id ) && $forum_id->get_error_message() ) ? $forum_id->get_error_message() . ' ' : '';
+		bbp_add_error( 'bbp_forum_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your forum:' . $append_error . 'Please try again.', 'bbpress' ) );
+	}
+}
+
+/**
+ * Handle the saving of core forum metadata (Status, Visibility, and Type)
+ *
+ * @since bbPress (r3678)
+ * @param int $forum_id
+ * @uses bbp_is_forum_closed() To check if forum is closed
+ * @uses bbp_close_forum() To close forum
+ * @uses bbp_open_forum() To open forum
+ * @uses bbp_is_forum_category() To check if forum is a category
+ * @uses bbp_categorize_forum() To turn forum into a category
+ * @uses bbp_normalize_forum() To turn category into forum
+ * @uses bbp_get_public_status_id() To get the public status ID
+ * @uses bbp_get_private_status_id() To get the private status ID
+ * @uses bbp_get_hidden_status_id() To get the hidden status ID
+ * @uses bbp_get_forum_visibility() To get the forums visibility
+ * @uses bbp_hide_forum() To hide a forum
+ * @uses bbp_privatize_forum() To make a forum private
+ * @uses bbp_publicize_forum() To make a forum public
+ * @return If forum ID is empty
+ */
+function bbp_save_forum_extras( $forum_id = 0 ) {
+
+	// Validate the forum ID
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Bail if forum ID is empty
+	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) )
+		return;
+
+	/** Forum Status ******************************************************/
+
+	if ( !empty( $_POST['bbp_forum_status'] ) && in_array( $_POST['bbp_forum_status'], array( 'open', 'closed' ) ) ) {
+		if ( 'closed' === $_POST['bbp_forum_status'] && !bbp_is_forum_closed( $forum_id, false ) ) {
+			bbp_close_forum( $forum_id );
+		} elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_closed( $forum_id, false ) ) {
+			bbp_open_forum( $forum_id );
+		}
+	}
+
+	/** Forum Type ********************************************************/
+
+	if ( !empty( $_POST['bbp_forum_type'] ) && in_array( $_POST['bbp_forum_type'], array( 'forum', 'category' ) ) ) {
+		if ( 'category' === $_POST['bbp_forum_type'] && !bbp_is_forum_category( $forum_id ) ) {
+			bbp_categorize_forum( $forum_id );
+		} elseif ( 'forum' === $_POST['bbp_forum_type'] && bbp_is_forum_category( $forum_id ) ) {
+			bbp_normalize_forum( $forum_id );
+		}
+	}
+
+	/** Forum Visibility **************************************************/
+
+	if ( !empty( $_POST['bbp_forum_visibility'] ) && in_array( $_POST['bbp_forum_visibility'], array( bbp_get_public_status_id(), bbp_get_private_status_id(), bbp_get_hidden_status_id() ) ) ) {
+
+		// Get forums current visibility
+		$visibility = bbp_get_forum_visibility( $forum_id );
+
+		// What is the new forum visibility setting?
+		switch ( $_POST['bbp_forum_visibility'] ) {
+
+			// Hidden
+			case bbp_get_hidden_status_id()  :
+				bbp_hide_forum( $forum_id, $visibility );
+				break;
+
+			// Private
+			case bbp_get_private_status_id() :
+				bbp_privatize_forum( $forum_id, $visibility );
+				break;
+
+			// Publish (default)
+			case bbp_get_public_status_id()  :
+			default        :
+				bbp_publicize_forum( $forum_id, $visibility );
+				break;
+		}
+	}
+}
+
+/** Forum Actions *************************************************************/
+
+/**
+ * Closes a forum
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id forum id
+ * @uses do_action() Calls 'bbp_close_forum' with the forum id
+ * @uses update_post_meta() To add the previous status to a meta
+ * @uses do_action() Calls 'bbp_opened_forum' with the forum id
+ * @return mixed False or {@link WP_Error} on failure, forum id on success
+ */
+function bbp_close_forum( $forum_id = 0 ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	do_action( 'bbp_close_forum',  $forum_id );
+
+	update_post_meta( $forum_id, '_bbp_status', 'closed' );
+
+	do_action( 'bbp_closed_forum', $forum_id );
+
+	return $forum_id;
+}
+
+/**
+ * Opens a forum
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id forum id
+ * @uses do_action() Calls 'bbp_open_forum' with the forum id
+ * @uses get_post_meta() To get the previous status
+ * @uses update_post_meta() To delete the previous status meta
+ * @uses do_action() Calls 'bbp_opened_forum' with the forum id
+ * @return mixed False or {@link WP_Error} on failure, forum id on success
+ */
+function bbp_open_forum( $forum_id = 0 ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	do_action( 'bbp_open_forum',   $forum_id );
+
+	update_post_meta( $forum_id, '_bbp_status', 'open' );
+
+	do_action( 'bbp_opened_forum', $forum_id );
+
+	return $forum_id;
+}
+
+/**
+ * Make the forum a category
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses update_post_meta() To update the forum category meta
+ * @return bool False on failure, true on success
+ */
+function bbp_categorize_forum( $forum_id = 0 ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	do_action( 'bbp_categorize_forum',  $forum_id );
+
+	update_post_meta( $forum_id, '_bbp_forum_type', 'category' );
+
+	do_action( 'bbp_categorized_forum', $forum_id );
+
+	return $forum_id;
+}
+
+/**
+ * Remove the category status from a forum
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses delete_post_meta() To delete the forum category meta
+ * @return bool False on failure, true on success
+ */
+function bbp_normalize_forum( $forum_id = 0 ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	do_action( 'bbp_normalize_forum',  $forum_id );
+
+	update_post_meta( $forum_id, '_bbp_forum_type', 'forum' );
+
+	do_action( 'bbp_normalized_forum', $forum_id );
+
+	return $forum_id;
+}
+
+/**
+ * Mark the forum as public
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses update_post_meta() To update the forum private meta
+ * @return bool False on failure, true on success
+ */
+function bbp_publicize_forum( $forum_id = 0, $current_visibility = '' ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	do_action( 'bbp_publicize_forum',  $forum_id );
+
+	// Get private forums
+	$private = bbp_get_private_forum_ids();
+
+	// Find this forum in the array
+	if ( in_array( $forum_id, $private ) ) {
+
+		$offset = array_search( $forum_id, $private );
+
+		// Splice around it
+		array_splice( $private, $offset, 1 );
+
+		// Update private forums minus this one
+		update_option( '_bbp_private_forums', array_unique( array_filter( array_values( $private ) ) ) );
+	}
+
+	// Get hidden forums
+	$hidden = bbp_get_hidden_forum_ids();
+
+	// Find this forum in the array
+	if ( in_array( $forum_id, $hidden ) ) {
+
+		$offset = array_search( $forum_id, $hidden );
+
+		// Splice around it
+		array_splice( $hidden, $offset, 1 );
+
+		// Update hidden forums minus this one
+		update_option( '_bbp_hidden_forums', array_unique( array_filter( array_values( $hidden ) ) ) );
+	}
+
+	// Only run queries if visibility is changing
+	if ( bbp_get_public_status_id() !== $current_visibility ) {
+
+		// Update forums visibility setting
+		global $wpdb;
+		$wpdb->update( $wpdb->posts, array( 'post_status' => bbp_get_public_status_id() ), array( 'ID' => $forum_id ) );
+		wp_transition_post_status( bbp_get_public_status_id(), $current_visibility, get_post( $forum_id ) );
+		bbp_clean_post_cache( $forum_id );
+	}
+
+	do_action( 'bbp_publicized_forum', $forum_id );
+
+	return $forum_id;
+}
+
+/**
+ * Mark the forum as private
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses update_post_meta() To update the forum private meta
+ * @return bool False on failure, true on success
+ */
+function bbp_privatize_forum( $forum_id = 0, $current_visibility = '' ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	do_action( 'bbp_privatize_forum',  $forum_id );
+
+	// Only run queries if visibility is changing
+	if ( bbp_get_private_status_id() !== $current_visibility ) {
+
+		// Get hidden forums
+		$hidden = bbp_get_hidden_forum_ids();
+
+		// Find this forum in the array
+		if ( in_array( $forum_id, $hidden ) ) {
+
+			$offset = array_search( $forum_id, $hidden );
+
+			// Splice around it
+			array_splice( $hidden, $offset, 1 );
+
+			// Update hidden forums minus this one
+			update_option( '_bbp_hidden_forums', array_unique( array_filter( array_values( $hidden ) ) ) );
+		}
+
+		// Add to '_bbp_private_forums' site option
+		$private   = bbp_get_private_forum_ids();
+		$private[] = $forum_id;
+		update_option( '_bbp_private_forums', array_unique( array_filter( array_values( $private ) ) ) );
+
+		// Update forums visibility setting
+		global $wpdb;
+		$wpdb->update( $wpdb->posts, array( 'post_status' => bbp_get_private_status_id() ), array( 'ID' => $forum_id ) );
+		wp_transition_post_status( bbp_get_private_status_id(), $current_visibility, get_post( $forum_id ) );
+		bbp_clean_post_cache( $forum_id );
+	}
+
+	do_action( 'bbp_privatized_forum', $forum_id );
+
+	return $forum_id;
+}
+
+/**
+ * Mark the forum as hidden
+ *
+ * @since bbPress (r2996)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses update_post_meta() To update the forum private meta
+ * @return bool False on failure, true on success
+ */
+function bbp_hide_forum( $forum_id = 0, $current_visibility = '' ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	do_action( 'bbp_hide_forum', $forum_id );
+
+	// Only run queries if visibility is changing
+	if ( bbp_get_hidden_status_id() !== $current_visibility ) {
+
+		// Get private forums
+		$private = bbp_get_private_forum_ids();
+
+		// Find this forum in the array
+		if ( in_array( $forum_id, $private ) ) {
+
+			$offset = array_search( $forum_id, $private );
+
+			// Splice around it
+			array_splice( $private, $offset, 1 );
+
+			// Update private forums minus this one
+			update_option( '_bbp_private_forums', array_unique( array_filter( array_values( $private ) ) ) );
+		}
+
+		// Add to '_bbp_hidden_forums' site option
+		$hidden   = bbp_get_hidden_forum_ids();
+		$hidden[] = $forum_id;
+		update_option( '_bbp_hidden_forums', array_unique( array_filter( array_values( $hidden ) ) ) );
+
+		// Update forums visibility setting
+		global $wpdb;
+		$wpdb->update( $wpdb->posts, array( 'post_status' => bbp_get_hidden_status_id() ), array( 'ID' => $forum_id ) );
+		wp_transition_post_status( bbp_get_hidden_status_id(), $current_visibility, get_post( $forum_id ) );
+		bbp_clean_post_cache( $forum_id );
+	}
+
+	do_action( 'bbp_hid_forum',  $forum_id );
+
+	return $forum_id;
+}
+
+/**
+ * Recaches the private and hidden forums
+ *
+ * @since bbPress (r5017)
+ *
+ * @uses delete_option() to delete private and hidden forum pointers
+ * @uses WP_Query() To query post IDs
+ * @uses is_wp_error() To return if error occurred
+ * @uses update_option() To update the private and hidden post ID pointers
+ * @return array An array of the status code and the message
+ */
+function bbp_repair_forum_visibility() {
+
+	// First, delete everything.
+	delete_option( '_bbp_private_forums' );
+	delete_option( '_bbp_hidden_forums'  );
+
+	// Next, get all the private and hidden forums
+	$private_forums = new WP_Query( array(
+		'suppress_filters' => true,
+		'nopaging'         => true,
+		'post_type'        => bbp_get_forum_post_type(),
+		'post_status'      => bbp_get_private_status_id(),
+		'fields'           => 'ids'
+	) );
+	$hidden_forums = new WP_Query( array(
+		'suppress_filters' => true,
+		'nopaging'         => true,
+		'post_type'        => bbp_get_forum_post_type(),
+		'post_status'      => bbp_get_hidden_status_id(),
+		'fields'           => 'ids'
+	) );
+
+	// Reset the $post global
+	wp_reset_postdata();
+
+	// Bail if queries returned errors
+	if ( is_wp_error( $private_forums ) || is_wp_error( $hidden_forums ) )
+		return false;
+
+	// Update the private/hidden options
+	update_option( '_bbp_private_forums', $private_forums->posts ); // Private forums
+	update_option( '_bbp_hidden_forums',  $hidden_forums->posts  ); // Hidden forums
+
+	// Complete results
+	return true;
+}
+
+/** Subscriptions *************************************************************/
+
+/**
+ * Remove a deleted forum from all users' subscriptions
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $forum_id Get the forum ID to remove
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+ * @uses bbp_get_forum_id To get the forum id
+ * @uses bbp_get_forum_subscribers() To get the forum subscribers
+ * @uses bbp_remove_user_subscription() To remove the user subscription
+ */
+function bbp_remove_forum_from_all_subscriptions( $forum_id = 0 ) {
+
+	// Subscriptions are not active
+	if ( ! bbp_is_subscriptions_active() ) {
+		return;
+	}
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Bail if no forum
+	if ( empty( $forum_id ) ) {
+		return;
+	}
+
+	// Get users
+	$users = (array) bbp_get_forum_subscribers( $forum_id );
+
+	// Users exist
+	if ( !empty( $users ) ) {
+
+		// Loop through users
+		foreach ( $users as $user ) {
+
+			// Remove each user
+			bbp_remove_user_subscription( $user, $forum_id );
+		}
+	}
+}
+
+/** Count Bumpers *************************************************************/
+
+/**
+ * Bump the total topic count of a forum
+ *
+ * @since bbPress (r3825)
+ *
+ * @param int $forum_id Optional. Forum id.
+ * @param int $difference Optional. Default 1
+ * @param bool $update_ancestors Optional. Default true
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses update_post_meta() To update the forum's topic count meta
+ * @uses apply_filters() Calls 'bbp_bump_forum_topic_count' with the topic
+ *                        count, forum id, and difference
+ * @return int Forum topic count
+ */
+function bbp_bump_forum_topic_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
+
+	// Get some counts
+	$forum_id          = bbp_get_forum_id( $forum_id );
+	$topic_count       = bbp_get_forum_topic_count( $forum_id, false, true );
+	$total_topic_count = bbp_get_forum_topic_count( $forum_id, true,  true );
+
+	// Update this forum id
+	update_post_meta( $forum_id, '_bbp_topic_count',       (int) $topic_count       + (int) $difference );
+	update_post_meta( $forum_id, '_bbp_total_topic_count', (int) $total_topic_count + (int) $difference );
+
+	// Check for ancestors
+	if ( true === $update_ancestors ) {
+
+		// Get post ancestors
+		$forum     = get_post( $forum_id );
+		$ancestors = get_post_ancestors( $forum );
+
+		// If has ancestors, loop through them...
+		if ( !empty( $ancestors ) ) {
+			foreach ( (array) $ancestors as $parent_forum_id ) {
+
+				// Get forum counts
+				$parent_topic_count       = bbp_get_forum_topic_count( $parent_forum_id, false, true );
+				$parent_total_topic_count = bbp_get_forum_topic_count( $parent_forum_id, true,  true );
+
+				// Update counts
+				update_post_meta( $parent_forum_id, '_bbp_topic_count',       (int) $parent_topic_count       + (int) $difference );
+				update_post_meta( $parent_forum_id, '_bbp_total_topic_count', (int) $parent_total_topic_count + (int) $difference );
+			}
+		}
+	}
+
+	return (int) apply_filters( 'bbp_bump_forum_topic_count', (int) $total_topic_count + (int) $difference, $forum_id, (int) $difference, (bool) $update_ancestors );
+}
+
+/**
+ * Bump the total hidden topic count of a forum
+ *
+ * @since bbPress (r3825)
+ *
+ * @param int $forum_id Optional. Forum id.
+ * @param int $difference Optional. Default 1
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses update_post_meta() To update the forum's topic count meta
+ * @uses apply_filters() Calls 'bbp_bump_forum_topic_count_hidden' with the
+ *                        topic count, forum id, and difference
+ * @return int Forum hidden topic count
+ */
+function bbp_bump_forum_topic_count_hidden( $forum_id = 0, $difference = 1 ) {
+
+	// Get some counts
+	$forum_id    = bbp_get_forum_id( $forum_id );
+	$topic_count = bbp_get_forum_topic_count_hidden( $forum_id, true );
+	$new_count   = (int) $topic_count + (int) $difference;
+
+	// Update this forum id
+	update_post_meta( $forum_id, '_bbp_topic_count_hidden', (int) $new_count );
+
+	return (int) apply_filters( 'bbp_bump_forum_topic_count_hidden', (int) $new_count, $forum_id, (int) $difference );
+}
+
+/**
+ * Bump the total topic count of a forum
+ *
+ * @since bbPress (r3825)
+ *
+ * @param int $forum_id Optional. Forum id.
+ * @param int $difference Optional. Default 1
+ * @param bool $update_ancestors Optional. Default true
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses update_post_meta() To update the forum's topic count meta
+ * @uses apply_filters() Calls 'bbp_bump_forum_reply_count' with the topic
+ *                        count, forum id, and difference
+ * @return int Forum topic count
+ */
+function bbp_bump_forum_reply_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
+
+	// Get some counts
+	$forum_id          = bbp_get_forum_id( $forum_id );
+	$topic_count       = bbp_get_forum_reply_count( $forum_id, false, true );
+	$total_reply_count = bbp_get_forum_reply_count( $forum_id, true,  true );
+
+	// Update this forum id
+	update_post_meta( $forum_id, '_bbp_reply_count',       (int) $topic_count       + (int) $difference );
+	update_post_meta( $forum_id, '_bbp_total_reply_count', (int) $total_reply_count + (int) $difference );
+
+	// Check for ancestors
+	if ( true === $update_ancestors ) {
+
+		// Get post ancestors
+		$forum     = get_post( $forum_id );
+		$ancestors = get_post_ancestors( $forum );
+
+		// If has ancestors, loop through them...
+		if ( !empty( $ancestors ) ) {
+			foreach ( (array) $ancestors as $parent_forum_id ) {
+
+				// Get forum counts
+				$parent_topic_count       = bbp_get_forum_reply_count( $parent_forum_id, false, true );
+				$parent_total_reply_count = bbp_get_forum_reply_count( $parent_forum_id, true,  true );
+
+				// Update counts
+				update_post_meta( $parent_forum_id, '_bbp_reply_count',       (int) $parent_topic_count       + (int) $difference );
+				update_post_meta( $parent_forum_id, '_bbp_total_reply_count', (int) $parent_total_reply_count + (int) $difference );
+			}
+		}
+	}
+
+	return (int) apply_filters( 'bbp_bump_forum_reply_count', (int) $total_reply_count + (int) $difference, $forum_id, (int) $difference, (bool) $update_ancestors );
+}
+
+/** Forum Updaters ************************************************************/
+
+/**
+ * Update the forum last topic id
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_forum_query_subforum_ids() To get the subforum ids
+ * @uses bbp_update_forum_last_topic_id() To update the last topic id of child
+ *                                         forums
+ * @uses get_posts() To get the most recent topic in the forum
+ * @uses update_post_meta() To update the forum's last active id meta
+ * @uses apply_filters() Calls 'bbp_update_forum_last_topic_id' with the last
+ *                        reply id and forum id
+ * @return bool True on success, false on failure
+ */
+function bbp_update_forum_last_topic_id( $forum_id = 0, $topic_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Define local variable(s)
+	$children_last_topic = 0;
+
+	// Do some calculation if not manually set
+	if ( empty( $topic_id ) ) {
+
+		// Loop through children and add together forum reply counts
+		$children = bbp_forum_query_subforum_ids( $forum_id );
+		if ( !empty( $children ) ) {
+			foreach ( (array) $children as $child ) {
+				$children_last_topic = bbp_update_forum_last_topic_id( $child ); // Recursive
+			}
+		}
+
+		// Setup recent topic query vars
+		$post_vars = array(
+			'post_parent' => $forum_id,
+			'post_type'   => bbp_get_topic_post_type(),
+			'meta_key'    => '_bbp_last_active_time',
+			'orderby'     => 'meta_value',
+			'numberposts' => 1
+		);
+
+		// Get the most recent topic in this forum_id
+		$recent_topic = get_posts( $post_vars );
+		if ( !empty( $recent_topic ) ) {
+			$topic_id = $recent_topic[0]->ID;
+		}
+	}
+
+	// Cast as integer in case of empty or string
+	$topic_id            = (int) $topic_id;
+	$children_last_topic = (int) $children_last_topic;
+
+	// If child forums have higher id, use that instead
+	if ( !empty( $children ) && ( $children_last_topic > $topic_id ) )
+		$topic_id = $children_last_topic;
+
+	// Update the last public topic ID
+	if ( bbp_is_topic_published( $topic_id ) )
+		update_post_meta( $forum_id, '_bbp_last_topic_id', $topic_id );
+
+	return (int) apply_filters( 'bbp_update_forum_last_topic_id', $topic_id, $forum_id );
+}
+
+/**
+ * Update the forum last reply id
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_forum_query_subforum_ids() To get the subforum ids
+ * @uses bbp_update_forum_last_reply_id() To update the last reply id of child
+ *                                         forums
+ * @uses bbp_forum_query_topic_ids() To get the topic ids in the forum
+ * @uses bbp_forum_query_last_reply_id() To get the forum's last reply id
+ * @uses bbp_is_reply_published() To make sure the reply is published
+ * @uses update_post_meta() To update the forum's last active id meta
+ * @uses apply_filters() Calls 'bbp_update_forum_last_reply_id' with the last
+ *                        reply id and forum id
+ * @return bool True on success, false on failure
+ */
+function bbp_update_forum_last_reply_id( $forum_id = 0, $reply_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Define local variable(s)
+	$children_last_reply = 0;
+
+	// Do some calculation if not manually set
+	if ( empty( $reply_id ) ) {
+
+		// Loop through children and get the most recent reply id
+		$children = bbp_forum_query_subforum_ids( $forum_id );
+		if ( !empty( $children ) ) {
+			foreach ( (array) $children as $child ) {
+				$children_last_reply = bbp_update_forum_last_reply_id( $child ); // Recursive
+			}
+		}
+
+		// If this forum has topics...
+		$topic_ids = bbp_forum_query_topic_ids( $forum_id );
+		if ( !empty( $topic_ids ) ) {
+
+			// ...get the most recent reply from those topics...
+			$reply_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
+
+			// ...and compare it to the most recent topic id...
+			$reply_id = ( $reply_id > max( $topic_ids ) ) ? $reply_id : max( $topic_ids );
+		}
+	}
+
+	// Cast as integer in case of empty or string
+	$reply_id            = (int) $reply_id;
+	$children_last_reply = (int) $children_last_reply;
+
+	// If child forums have higher ID, check for newer reply id
+	if ( !empty( $children ) && ( $children_last_reply > $reply_id ) )
+		$reply_id = $children_last_reply;
+
+	// Update the last public reply ID
+	if ( bbp_is_reply_published( $reply_id ) )
+		update_post_meta( $forum_id, '_bbp_last_reply_id', $reply_id );
+
+	return (int) apply_filters( 'bbp_update_forum_last_reply_id', $reply_id, $forum_id );
+}
+
+/**
+ * Update the forum last active post id
+ *
+ * @since bbPress (r2860)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param int $active_id Optional. Active post id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_forum_query_subforum_ids() To get the subforum ids
+ * @uses bbp_update_forum_last_active_id() To update the last active id of
+ *                                          child forums
+ * @uses bbp_forum_query_topic_ids() To get the topic ids in the forum
+ * @uses bbp_forum_query_last_reply_id() To get the forum's last reply id
+ * @uses get_post_status() To make sure the reply is published
+ * @uses update_post_meta() To update the forum's last active id meta
+ * @uses apply_filters() Calls 'bbp_update_forum_last_active_id' with the last
+ *                        active post id and forum id
+ * @return bool True on success, false on failure
+ */
+function bbp_update_forum_last_active_id( $forum_id = 0, $active_id = 0 ) {
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Define local variable(s)
+	$children_last_active = 0;
+
+	// Do some calculation if not manually set
+	if ( empty( $active_id ) ) {
+
+		// Loop through children and add together forum reply counts
+		$children = bbp_forum_query_subforum_ids( $forum_id );
+		if ( !empty( $children ) ) {
+			foreach ( (array) $children as $child ) {
+				$children_last_active = bbp_update_forum_last_active_id( $child, $active_id );
+			}
+		}
+
+		// Don't count replies if the forum is a category
+		$topic_ids = bbp_forum_query_topic_ids( $forum_id );
+		if ( !empty( $topic_ids ) ) {
+			$active_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
+			$active_id = $active_id > max( $topic_ids ) ? $active_id : max( $topic_ids );
+
+		// Forum has no topics
+		} else {
+			$active_id = 0;
+		}
+	}
+
+	// Cast as integer in case of empty or string
+	$active_id            = (int) $active_id;
+	$children_last_active = (int) $children_last_active;
+
+	// If child forums have higher id, use that instead
+	if ( !empty( $children ) && ( $children_last_active > $active_id ) )
+		$active_id = $children_last_active;
+
+	// Update only if published
+	if ( bbp_get_public_status_id() === get_post_status( $active_id ) )
+		update_post_meta( $forum_id, '_bbp_last_active_id', (int) $active_id );
+
+	return (int) apply_filters( 'bbp_update_forum_last_active_id', (int) $active_id, $forum_id );
+}
+
+/**
+ * Update the forums last active date/time (aka freshness)
+ *
+ * @since bbPress (r2680)
+ *
+ * @param int $forum_id Optional. Topic id
+ * @param string $new_time Optional. New time in mysql format
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_forum_last_active_id() To get the forum's last post id
+ * @uses get_post_field() To get the post date of the forum's last post
+ * @uses update_post_meta() To update the forum last active time
+ * @uses apply_filters() Calls 'bbp_update_forum_last_active' with the new time
+ *                        and forum id
+ * @return bool True on success, false on failure
+ */
+function bbp_update_forum_last_active_time( $forum_id = 0, $new_time = '' ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Check time and use current if empty
+	if ( empty( $new_time ) )
+		$new_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $forum_id ) );
+
+	// Update only if there is a time
+	if ( !empty( $new_time ) )
+		update_post_meta( $forum_id, '_bbp_last_active_time', $new_time );
+
+	return (int) apply_filters( 'bbp_update_forum_last_active', $new_time, $forum_id );
+}
+
+/**
+ * Update the forum sub-forum count
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @return bool True on success, false on failure
+ */
+function bbp_update_forum_subforum_count( $forum_id = 0, $subforums = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $subforums ) )
+		$subforums = count( bbp_forum_query_subforum_ids( $forum_id ) );
+
+	update_post_meta( $forum_id, '_bbp_forum_subforum_count', (int) $subforums );
+
+	return (int) apply_filters( 'bbp_update_forum_subforum_count', (int) $subforums, $forum_id );
+}
+
+/**
+ * Adjust the total topic count of a forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
+ *                       is a topic or a forum. If it's a topic, its parent,
+ *                       i.e. the forum is automatically retrieved.
+ * @param bool $total_count Optional. To return the total count or normal
+ *                           count?
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_forum_query_subforum_ids() To get the subforum ids
+ * @uses bbp_update_forum_topic_count() To update the forum topic count
+ * @uses bbp_forum_query_topic_ids() To get the forum topic ids
+ * @uses update_post_meta() To update the forum's topic count meta
+ * @uses apply_filters() Calls 'bbp_update_forum_topic_count' with the topic
+ *                        count and forum id
+ * @return int Forum topic count
+ */
+function bbp_update_forum_topic_count( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+	$children_topic_count = 0;
+
+	// Loop through subforums and add together forum topic counts
+	$children = bbp_forum_query_subforum_ids( $forum_id );
+	if ( !empty( $children ) ) {
+		foreach ( (array) $children as $child ) {
+			$children_topic_count += bbp_update_forum_topic_count( $child ); // Recursive
+		}
+	}
+
+	// Get total topics for this forum
+	$topics = (int) count( bbp_forum_query_topic_ids( $forum_id ) );
+
+	// Calculate total topics in this forum
+	$total_topics = $topics + $children_topic_count;
+
+	// Update the count
+	update_post_meta( $forum_id, '_bbp_topic_count',       (int) $topics       );
+	update_post_meta( $forum_id, '_bbp_total_topic_count', (int) $total_topics );
+
+	return (int) apply_filters( 'bbp_update_forum_topic_count', (int) $total_topics, $forum_id );
+}
+
+/**
+ * Adjust the total hidden topic count of a forum (hidden includes trashed and spammed topics)
+ *
+ * @since bbPress (r2888)
+ *
+ * @param int $forum_id Optional. Topic id to update
+ * @param int $topic_count Optional. Set the topic count manually
+ * @uses bbp_is_topic() To check if the supplied id is a topic
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses wpdb::prepare() To prepare our sql query
+ * @uses wpdb::get_col() To execute our query and get the column back
+ * @uses update_post_meta() To update the forum hidden topic count meta
+ * @uses apply_filters() Calls 'bbp_update_forum_topic_count_hidden' with the
+ *                        hidden topic count and forum id
+ * @return int Topic hidden topic count
+ */
+function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = 0 ) {
+	global $wpdb;
+
+	// If topic_id was passed as $forum_id, then get its forum
+	if ( bbp_is_topic( $forum_id ) ) {
+		$topic_id = bbp_get_topic_id( $forum_id );
+		$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+	// $forum_id is not a topic_id, so validate and proceed
+	} else {
+		$forum_id = bbp_get_forum_id( $forum_id );
+	}
+
+	// Can't update what isn't there
+	if ( !empty( $forum_id ) ) {
+
+		// Get topics of forum
+		if ( empty( $topic_count ) ) {
+			$post_status = "'" . implode( "','", array( bbp_get_trash_status_id(), bbp_get_spam_status_id() ) ) . "'";
+			$topic_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s';", $forum_id, bbp_get_topic_post_type() ) );
+		}
+
+		// Update the count
+		update_post_meta( $forum_id, '_bbp_topic_count_hidden', (int) $topic_count );
+	}
+
+	return (int) apply_filters( 'bbp_update_forum_topic_count_hidden', (int) $topic_count, $forum_id );
+}
+
+/**
+ * Adjust the total reply count of a forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
+ *                       is a topic or a forum. If it's a topic, its parent,
+ *                       i.e. the forum is automatically retrieved.
+ * @param bool $total_count Optional. To return the total count or normal
+ *                           count?
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_forum_query_subforum_ids() To get the subforum ids
+ * @uses bbp_update_forum_reply_count() To update the forum reply count
+ * @uses bbp_forum_query_topic_ids() To get the forum topic ids
+ * @uses wpdb::prepare() To prepare the sql statement
+ * @uses wpdb::get_var() To execute the query and get the var back
+ * @uses update_post_meta() To update the forum's reply count meta
+ * @uses apply_filters() Calls 'bbp_update_forum_topic_count' with the reply
+ *                        count and forum id
+ * @return int Forum reply count
+ */
+function bbp_update_forum_reply_count( $forum_id = 0 ) {
+	global $wpdb;
+
+	$forum_id = bbp_get_forum_id( $forum_id );
+	$children_reply_count = 0;
+
+	// Loop through children and add together forum reply counts
+	$children = bbp_forum_query_subforum_ids( $forum_id );
+	if ( !empty( $children ) ) {
+		foreach ( (array) $children as $child ) {
+			$children_reply_count += bbp_update_forum_reply_count( $child );
+		}
+	}
+
+	// Don't count replies if the forum is a category
+	$topic_ids = bbp_forum_query_topic_ids( $forum_id );
+	if ( !empty( $topic_ids ) ) {
+		$topic_ids   = implode( ',', wp_parse_id_list( $topic_ids ) );
+		$reply_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_parent IN ( {$topic_ids} ) AND post_status = '%s' AND post_type = '%s';", bbp_get_public_status_id(), bbp_get_reply_post_type() ) );
+	} else {
+		$reply_count = 0;
+	}
+
+	// Calculate total replies in this forum
+	$total_replies = (int) $reply_count + $children_reply_count;
+
+	// Update the count
+	update_post_meta( $forum_id, '_bbp_reply_count',       (int) $reply_count   );
+	update_post_meta( $forum_id, '_bbp_total_reply_count', (int) $total_replies );
+
+	return (int) apply_filters( 'bbp_update_forum_reply_count', (int) $total_replies, $forum_id );
+}
+
+/**
+ * Updates the counts of a forum.
+ *
+ * This calls a few internal functions that all run manual queries against the
+ * database to get their results. As such, this function can be costly to run
+ * but is necessary to keep everything accurate.
+ *
+ * @since bbPress (r2908)
+ *
+ * @param mixed $args Supports these arguments:
+ *  - forum_id: Forum id
+ *  - last_topic_id: Last topic id
+ *  - last_reply_id: Last reply id
+ *  - last_active_id: Last active post id
+ *  - last_active_time: last active time
+ * @uses bbp_update_forum_last_topic_id() To update the forum last topic id
+ * @uses bbp_update_forum_last_reply_id() To update the forum last reply id
+ * @uses bbp_update_forum_last_active_id() To update the last active post id
+ * @uses get_post_field() To get the post date of the last active id
+ * @uses bbp_update_forum_last_active_time()  To update the last active time
+ * @uses bbp_update_forum_subforum_count() To update the subforum count
+ * @uses bbp_update_forum_topic_count() To update the forum topic count
+ * @uses bbp_update_forum_reply_count() To update the forum reply count
+ * @uses bbp_update_forum_topic_count_hidden() To update the hidden topic count
+ */
+function bbp_update_forum( $args = '' ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'forum_id'           => 0,
+		'post_parent'        => 0,
+		'last_topic_id'      => 0,
+		'last_reply_id'      => 0,
+		'last_active_id'     => 0,
+		'last_active_time'   => 0,
+		'last_active_status' => bbp_get_public_status_id()
+	), 'update_forum' );
+
+	// Last topic and reply ID's
+	bbp_update_forum_last_topic_id( $r['forum_id'], $r['last_topic_id'] );
+	bbp_update_forum_last_reply_id( $r['forum_id'], $r['last_reply_id'] );
+
+	// Active dance
+	$r['last_active_id'] = bbp_update_forum_last_active_id( $r['forum_id'], $r['last_active_id'] );
+
+	// If no active time was passed, get it from the last_active_id
+	if ( empty( $r['last_active_time'] ) ) {
+		$r['last_active_time'] = get_post_field( 'post_date', $r['last_active_id'] );
+	}
+
+	if ( bbp_get_public_status_id() === $r['last_active_status'] ) {
+		bbp_update_forum_last_active_time( $r['forum_id'], $r['last_active_time'] );
+	}
+
+	// Counts
+	bbp_update_forum_subforum_count    ( $r['forum_id'] );
+	bbp_update_forum_reply_count       ( $r['forum_id'] );
+	bbp_update_forum_topic_count       ( $r['forum_id'] );
+	bbp_update_forum_topic_count_hidden( $r['forum_id'] );
+
+	// Update the parent forum if one was passed
+	if ( !empty( $r['post_parent'] ) && is_numeric( $r['post_parent'] ) ) {
+		bbp_update_forum( array(
+			'forum_id'    => $r['post_parent'],
+			'post_parent' => get_post_field( 'post_parent', $r['post_parent'] )
+		) );
+	}
+}
+
+/** Helpers *******************************************************************/
+
+/**
+ * Return an associative array of available topic statuses
+ *
+ * @since bbPress (r5059)
+ *
+ * @return array
+ */
+function bbp_get_forum_statuses() {
+	return apply_filters( 'bbp_get_forum_statuses', array(
+		'open'   => _x( 'Open',    'Open the forum',  'bbpress' ),
+		'closed' => _x( 'Closed',  'Close the forum', 'bbpress' )
+	) );
+}
+
+/**
+ * Return an associative array of forum types
+ *
+ * @since bbPress (r5059)
+ *
+ * @return array
+ */
+function bbp_get_forum_types() {
+	return apply_filters( 'bbp_get_forum_types', array(
+		'forum'    => _x( 'Forum',    'Forum accepts new topics', 'bbpress' ),
+		'category' => _x( 'Category', 'Forum is a category',      'bbpress' )
+	) );
+}
+
+/**
+ * Return an associative array of forum visibility
+ *
+ * @since bbPress (r5059)
+ *
+ * @return array
+ */
+function bbp_get_forum_visibilities() {
+	return apply_filters( 'bbp_get_forum_visibilities', array(
+		bbp_get_public_status_id()  => _x( 'Public',  'Make forum public',  'bbpress' ),
+		bbp_get_private_status_id() => _x( 'Private', 'Make forum private', 'bbpress' ),
+		bbp_get_hidden_status_id()  => _x( 'Hidden',  'Make forum hidden',  'bbpress' )
+	) );
+}
+
+/** Queries *******************************************************************/
+
+/**
+ * Returns the hidden forum ids
+ *
+ * Only hidden forum ids are returned. Public and private ids are not.
+ *
+ * @since bbPress (r3007)
+ *
+ * @uses get_option() Returns the unserialized array of hidden forum ids
+ * @uses apply_filters() Calls 'bbp_forum_query_topic_ids' with the topic ids
+ *                        and forum id
+ */
+function bbp_get_hidden_forum_ids() {
+   	$forum_ids = get_option( '_bbp_hidden_forums', array() );
+
+	return apply_filters( 'bbp_get_hidden_forum_ids', (array) $forum_ids );
+}
+
+/**
+ * Returns the private forum ids
+ *
+ * Only private forum ids are returned. Public and hidden ids are not.
+ *
+ * @since bbPress (r3007)
+ *
+ * @uses get_option() Returns the unserialized array of private forum ids
+ * @uses apply_filters() Calls 'bbp_forum_query_topic_ids' with the topic ids
+ *                        and forum id
+ */
+function bbp_get_private_forum_ids() {
+   	$forum_ids = get_option( '_bbp_private_forums', array() );
+
+	return apply_filters( 'bbp_get_private_forum_ids', (array) $forum_ids );
+}
+
+/**
+ * Returns a meta_query that either includes or excludes hidden forum IDs
+ * from a query.
+ *
+ * @since bbPress (r3291)
+ *
+ * @param string Optional. The type of value to return. (string|array|meta_query)
+ *
+ * @uses bbp_is_user_keymaster()
+ * @uses bbp_get_hidden_forum_ids()
+ * @uses bbp_get_private_forum_ids()
+ * @uses apply_filters()
+ */
+function bbp_exclude_forum_ids( $type = 'string' ) {
+
+	// Setup arrays
+	$private = $hidden = $meta_query = $forum_ids = array();
+
+	// Default return value
+	switch ( $type ) {
+		case 'string' :
+			$retval = '';
+			break;
+
+		case 'array'  :
+			$retval = array();
+			break;
+
+		case 'meta_query' :
+			$retval = array( array() ) ;
+			break;
+	}
+
+	// Exclude for everyone but keymasters
+	if ( ! bbp_is_user_keymaster() ) {
+
+		// Private forums
+		if ( !current_user_can( 'read_private_forums' ) )
+			$private = bbp_get_private_forum_ids();
+
+		// Hidden forums
+		if ( !current_user_can( 'read_hidden_forums' ) )
+			$hidden  = bbp_get_hidden_forum_ids();
+
+		// Merge private and hidden forums together
+		$forum_ids = (array) array_filter( wp_parse_id_list( array_merge( $private, $hidden ) ) );
+
+		// There are forums that need to be excluded
+		if ( !empty( $forum_ids ) ) {
+
+			switch ( $type ) {
+
+				// Separate forum ID's into a comma separated string
+				case 'string' :
+					$retval = implode( ',', $forum_ids );
+					break;
+
+				// Use forum_ids array
+				case 'array'  :
+					$retval = $forum_ids;
+					break;
+
+				// Build a meta_query
+				case 'meta_query' :
+					$retval = array(
+						'key'     => '_bbp_forum_id',
+						'value'   => implode( ',', $forum_ids ),
+						'type'    => 'numeric',
+						'compare' => ( 1 < count( $forum_ids ) ) ? 'NOT IN' : '!='
+					);
+					break;
+			}
+		}
+	}
+
+	// Filter and return the results
+	return apply_filters( 'bbp_exclude_forum_ids', $retval, $forum_ids, $type );
+}
+
+/**
+ * Adjusts forum, topic, and reply queries to exclude items that might be
+ * contained inside hidden or private forums that the user does not have the
+ * capability to view.
+ *
+ * Doing it with an action allows us to trap all WP_Query's rather than needing
+ * to hardcode this logic into each query. It also protects forum content for
+ * plugins that might be doing their own queries.
+ *
+ * @since bbPress (r3291)
+ *
+ * @param WP_Query $posts_query
+ *
+ * @uses apply_filters()
+ * @uses bbp_exclude_forum_ids()
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_reply_post_type()
+ * @return WP_Query
+ */
+function bbp_pre_get_posts_normalize_forum_visibility( $posts_query = null ) {
+
+	// Bail if all forums are explicitly allowed
+	if ( true === apply_filters( 'bbp_include_all_forums', false, $posts_query ) ) {
+		return;
+	}
+
+	// Bail if $posts_query is not an object or of incorrect class
+	if ( !is_object( $posts_query ) || !is_a( $posts_query, 'WP_Query' ) ) {
+		return;
+	}
+
+	// Get query post types array .
+	$post_types = (array) $posts_query->get( 'post_type' );
+
+	// Forums
+	if ( bbp_get_forum_post_type() === implode( '', $post_types ) ) {
+
+		// Prevent accidental wp-admin post_row override
+		if ( is_admin() && isset( $_REQUEST['post_status'] ) ) {
+			return;
+		}
+
+		/** Default ***********************************************************/
+
+		// Get any existing post status
+		$post_stati = $posts_query->get( 'post_status' );
+
+		// Default to public status
+		if ( empty( $post_stati ) ) {
+			$post_stati[] = bbp_get_public_status_id();
+
+		// Split the status string
+		} elseif ( is_string( $post_stati ) ) {
+			$post_stati = explode( ',', $post_stati );
+		}
+
+		/** Private ***********************************************************/
+
+		// Remove bbp_get_private_status_id() if user is not capable
+		if ( ! current_user_can( 'read_private_forums' ) ) {
+			$key = array_search( bbp_get_private_status_id(), $post_stati );
+			if ( !empty( $key ) ) {
+				unset( $post_stati[$key] );
+			}
+
+		// ...or add it if they are
+		} else {
+			$post_stati[] = bbp_get_private_status_id();
+		}
+
+		/** Hidden ************************************************************/
+
+		// Remove bbp_get_hidden_status_id() if user is not capable
+		if ( ! current_user_can( 'read_hidden_forums' ) ) {
+			$key = array_search( bbp_get_hidden_status_id(), $post_stati );
+			if ( !empty( $key ) ) {
+				unset( $post_stati[$key] );
+			}
+
+		// ...or add it if they are
+		} else {
+			$post_stati[] = bbp_get_hidden_status_id();
+		}
+
+		// Add the statuses
+		$posts_query->set( 'post_status', array_unique( array_filter( $post_stati ) ) );
+	}
+
+	// Topics Or Replies
+	if ( array_intersect( array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ), $post_types ) ) {
+
+		// Get forums to exclude
+		$forum_ids = bbp_exclude_forum_ids( 'meta_query' );
+
+		// Bail if no forums to exclude
+		if ( ! array_filter( $forum_ids ) ) {
+			return;
+		}
+
+		// Get any existing meta queries
+		$meta_query   = $posts_query->get( 'meta_query' );
+
+		// Add our meta query to existing
+		$meta_query[] = $forum_ids;
+
+		// Set the meta_query var
+		$posts_query->set( 'meta_query', $meta_query );
+	}
+}
+
+/**
+ * Returns the forum's topic ids
+ *
+ * Only topics with published and closed statuses are returned
+ *
+ * @since bbPress (r2908)
+ *
+ * @param int $forum_id Forum id
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_public_child_ids() To get the topic ids
+ * @uses apply_filters() Calls 'bbp_forum_query_topic_ids' with the topic ids
+ *                        and forum id
+ */
+function bbp_forum_query_topic_ids( $forum_id ) {
+   	$topic_ids = bbp_get_public_child_ids( $forum_id, bbp_get_topic_post_type() );
+
+	return apply_filters( 'bbp_forum_query_topic_ids', $topic_ids, $forum_id );
+}
+
+/**
+ * Returns the forum's subforum ids
+ *
+ * Only forums with published status are returned
+ *
+ * @since bbPress (r2908)
+ *
+ * @param int $forum_id Forum id
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_public_child_ids() To get the forum ids
+ * @uses apply_filters() Calls 'bbp_forum_query_subforum_ids' with the subforum
+ *                        ids and forum id
+ */
+function bbp_forum_query_subforum_ids( $forum_id ) {
+	$subforum_ids = bbp_get_all_child_ids( $forum_id, bbp_get_forum_post_type() );
+	//usort( $subforum_ids, '_bbp_forum_query_usort_subforum_ids' );
+
+	return apply_filters( 'bbp_get_forum_subforum_ids', $subforum_ids, $forum_id );
+}
+
+/**
+ * Callback to sort forum ID's based on last active time
+ *
+ * @since bbPress (r3789)
+ * @param int $a First forum ID to compare
+ * @param int $b Second forum ID to compare
+ * @return Position change based on sort
+ */
+function _bbp_forum_query_usort_subforum_ids( $a = 0, $b = 0 ) {
+	$ta = get_post_meta( $a, '_bbp_last_active_time', true );
+	$tb = get_post_meta( $b, '_bbp_last_active_time', true );
+	return ( $ta < $tb ) ? -1 : 1;
+}
+
+/**
+ * Returns the forum's last reply id
+ *
+ * @since bbPress (r2908)
+ *
+ * @param int $forum_id Forum id
+ * @param int $topic_ids Optional. Topic ids
+ * @uses wp_cache_get() To check for cache and retrieve it
+ * @uses bbp_forum_query_topic_ids() To get the forum's topic ids
+ * @uses wpdb::prepare() To prepare the query
+ * @uses wpdb::get_var() To execute the query and get the var back
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wp_cache_set() To set the cache for future use
+ * @uses apply_filters() Calls 'bbp_forum_query_last_reply_id' with the reply id
+ *                        and forum id
+ */
+function bbp_forum_query_last_reply_id( $forum_id, $topic_ids = 0 ) {
+	global $wpdb;
+
+	$cache_id = 'bbp_get_forum_' . $forum_id . '_reply_id';
+	$reply_id = (int) wp_cache_get( $cache_id, 'bbpress_posts' );
+
+	if ( false === $reply_id ) {
+
+		if ( empty( $topic_ids ) ) {
+			$topic_ids = bbp_forum_query_topic_ids( $forum_id );
+		}
+
+		if ( !empty( $topic_ids ) ) {
+			$topic_ids = implode( ',', wp_parse_id_list( $topic_ids ) );
+			$reply_id  = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent IN ( {$topic_ids} ) AND post_status = '%s' AND post_type = '%s' ORDER BY ID DESC LIMIT 1;", bbp_get_public_status_id(), bbp_get_reply_post_type() ) );
+			wp_cache_set( $cache_id, $reply_id, 'bbpress_posts' ); // May be (int) 0
+		} else {
+			wp_cache_set( $cache_id, '0', 'bbpress_posts' );
+		}
+	}
+
+	return (int) apply_filters( 'bbp_get_forum_last_reply_id', (int) $reply_id, $forum_id );
+}
+
+/** Listeners *****************************************************************/
+
+/**
+ * Check if it's a hidden forum or a topic or reply of a hidden forum and if
+ * the user can't view it, then sets a 404
+ *
+ * @since bbPress (r2996)
+ *
+ * @uses current_user_can() To check if the current user can read private forums
+ * @uses is_singular() To check if it's a singular page
+ * @uses bbp_is_user_keymaster() To check if user is a keymaster
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_reply_post_type() TO get the reply post type
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_get_reply_forum_id() To get the reply forum id
+ * @uses bbp_is_forum_hidden() To check if the forum is hidden or not
+ * @uses bbp_set_404() To set a 404 status
+ */
+function bbp_forum_enforce_hidden() {
+
+	// Bail if not viewing a single item or if user has caps
+	if ( !is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_hidden_forums' ) )
+		return;
+
+	global $wp_query;
+
+	// Define local variable
+	$forum_id = 0;
+
+	// Check post type
+	switch ( $wp_query->get( 'post_type' ) ) {
+
+		// Forum
+		case bbp_get_forum_post_type() :
+			$forum_id = bbp_get_forum_id( $wp_query->post->ID );
+			break;
+
+		// Topic
+		case bbp_get_topic_post_type() :
+			$forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
+			break;
+
+		// Reply
+		case bbp_get_reply_post_type() :
+			$forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
+			break;
+
+	}
+
+	// If forum is explicitly hidden and user not capable, set 404
+	if ( !empty( $forum_id ) && bbp_is_forum_hidden( $forum_id ) && !current_user_can( 'read_hidden_forums' ) )
+		bbp_set_404();
+}
+
+/**
+ * Check if it's a private forum or a topic or reply of a private forum and if
+ * the user can't view it, then sets a 404
+ *
+ * @since bbPress (r2996)
+ *
+ * @uses current_user_can() To check if the current user can read private forums
+ * @uses is_singular() To check if it's a singular page
+ * @uses bbp_is_user_keymaster() To check if user is a keymaster
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_reply_post_type() TO get the reply post type
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_get_reply_forum_id() To get the reply forum id
+ * @uses bbp_is_forum_private() To check if the forum is private or not
+ * @uses bbp_set_404() To set a 404 status
+ */
+function bbp_forum_enforce_private() {
+
+	// Bail if not viewing a single item or if user has caps
+	if ( !is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_private_forums' ) )
+		return;
+
+	global $wp_query;
+
+	// Define local variable
+	$forum_id = 0;
+
+	// Check post type
+	switch ( $wp_query->get( 'post_type' ) ) {
+
+		// Forum
+		case bbp_get_forum_post_type() :
+			$forum_id = bbp_get_forum_id( $wp_query->post->ID );
+			break;
+
+		// Topic
+		case bbp_get_topic_post_type() :
+			$forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
+			break;
+
+		// Reply
+		case bbp_get_reply_post_type() :
+			$forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
+			break;
+
+	}
+
+	// If forum is explicitly hidden and user not capable, set 404
+	if ( !empty( $forum_id ) && bbp_is_forum_private( $forum_id ) && !current_user_can( 'read_private_forums' ) )
+		bbp_set_404();
+}
+
+/** Permissions ***************************************************************/
+
+/**
+ * Redirect if unathorized user is attempting to edit a forum
+ *
+ * @since bbPress (r3607)
+ *
+ * @uses bbp_is_forum_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_forum_id()
+ * @uses wp_safe_redirect()
+ * @uses bbp_get_forum_permalink()
+ */
+function bbp_check_forum_edit() {
+
+	// Bail if not editing a topic
+	if ( !bbp_is_forum_edit() )
+		return;
+
+	// User cannot edit topic, so redirect back to reply
+	if ( !current_user_can( 'edit_forum', bbp_get_forum_id() ) ) {
+		wp_safe_redirect( bbp_get_forum_permalink() );
+		exit();
+	}
+}
+
+/**
+ * Delete all topics (and their replies) for a specific forum ID
+ *
+ * @since bbPress (r3668)
+ *
+ * @param int $forum_id
+ * @uses bbp_get_forum_id() To validate the forum ID
+ * @uses bbp_is_forum() To make sure it's a forum
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_topics() To make sure there are topics to loop through
+ * @uses wp_trash_post() To trash the post
+ * @uses update_post_meta() To update the forum meta of trashed topics
+ * @return If forum is not valid
+ */
+function bbp_delete_forum_topics( $forum_id = 0 ) {
+
+	// Validate forum ID
+	$forum_id = bbp_get_forum_id( $forum_id );
+	if ( empty( $forum_id ) )
+		return;
+
+	// Forum is being permanently deleted, so its content has go too
+	// Note that we get all post statuses here
+	$topics = new WP_Query( array(
+		'suppress_filters' => true,
+		'post_type'        => bbp_get_topic_post_type(),
+		'post_parent'      => $forum_id,
+		'post_status'      => array_keys( get_post_stati() ),
+		'posts_per_page'   => -1,
+		'nopaging'         => true,
+		'fields'           => 'id=>parent'
+	) );
+
+	// Loop through and delete child topics. Topic replies will get deleted by
+	// the bbp_delete_topic() action.
+	if ( !empty( $topics->posts ) ) {
+		foreach ( $topics->posts as $topic ) {
+			wp_delete_post( $topic->ID, true );
+		}
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	// Cleanup
+	unset( $topics );
+}
+
+/**
+ * Trash all topics inside a forum
+ *
+ * @since bbPress (r3668)
+ *
+ * @param int $forum_id
+ * @uses bbp_get_forum_id() To validate the forum ID
+ * @uses bbp_is_forum() To make sure it's a forum
+ * @uses bbp_get_public_status_id() To return public post status
+ * @uses bbp_get_closed_status_id() To return closed post status
+ * @uses bbp_get_pending_status_id() To return pending post status
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wp_trash_post() To trash the post
+ * @uses update_post_meta() To update the forum meta of trashed topics
+ * @return If forum is not valid
+ */
+function bbp_trash_forum_topics( $forum_id = 0 ) {
+
+	// Validate forum ID
+	$forum_id = bbp_get_forum_id( $forum_id );
+	if ( empty( $forum_id ) )
+		return;
+
+	// Allowed post statuses to pre-trash
+	$post_stati = implode( ',', array(
+		bbp_get_public_status_id(),
+		bbp_get_closed_status_id(),
+		bbp_get_pending_status_id()
+	) );
+
+	// Forum is being trashed, so its topics and replies are trashed too
+	$topics = new WP_Query( array(
+		'suppress_filters' => true,
+		'post_type'        => bbp_get_topic_post_type(),
+		'post_parent'      => $forum_id,
+		'post_status'      => $post_stati,
+		'posts_per_page'   => -1,
+		'nopaging'         => true,
+		'fields'           => 'id=>parent'
+	) );
+
+	// Loop through and trash child topics. Topic replies will get trashed by
+	// the bbp_trash_topic() action.
+	if ( !empty( $topics->posts ) ) {
+
+		// Prevent debug notices
+		$pre_trashed_topics = array();
+
+		// Loop through topics, trash them, and add them to array
+		foreach ( $topics->posts as $topic ) {
+			wp_trash_post( $topic->ID, true );
+			$pre_trashed_topics[] = $topic->ID;
+		}
+
+		// Set a post_meta entry of the topics that were trashed by this action.
+		// This is so we can possibly untrash them, without untrashing topics
+		// that were purposefully trashed before.
+		update_post_meta( $forum_id, '_bbp_pre_trashed_topics', $pre_trashed_topics );
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	// Cleanup
+	unset( $topics );
+}
+
+/**
+ * Trash all topics inside a forum
+ *
+ * @since bbPress (r3668)
+ *
+ * @param int $forum_id
+ * @uses bbp_get_forum_id() To validate the forum ID
+ * @uses bbp_is_forum() To make sure it's a forum
+ * @uses get_post_meta() To update the forum meta of trashed topics
+ * @uses wp_untrash_post() To trash the post
+ * @return If forum is not valid
+ */
+function bbp_untrash_forum_topics( $forum_id = 0 ) {
+
+	// Validate forum ID
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $forum_id ) )
+		return;
+
+	// Get the topics that were not previously trashed
+	$pre_trashed_topics = get_post_meta( $forum_id, '_bbp_pre_trashed_topics', true );
+
+	// There are topics to untrash
+	if ( !empty( $pre_trashed_topics ) ) {
+
+		// Maybe reverse the trashed topics array
+		if ( is_array( $pre_trashed_topics ) )
+			$pre_trashed_topics = array_reverse( $pre_trashed_topics );
+
+		// Loop through topics
+		foreach ( (array) $pre_trashed_topics as $topic ) {
+			wp_untrash_post( $topic );
+		}
+	}
+}
+
+/** Before Delete/Trash/Untrash ***********************************************/
+
+/**
+ * Called before deleting a forum.
+ *
+ * This function is supplemental to the actual forum deletion which is
+ * handled by WordPress core API functions. It is used to clean up after
+ * a forum that is being deleted.
+ *
+ * @since bbPress (r3668)
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_is_forum() To check if the passed id is a forum
+ * @uses do_action() Calls 'bbp_delete_forum' with the forum id
+ */
+function bbp_delete_forum( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
+		return false;
+
+	do_action( 'bbp_delete_forum', $forum_id );
+}
+
+/**
+ * Called before trashing a forum
+ *
+ * This function is supplemental to the actual forum being trashed which is
+ * handled by WordPress core API functions. It is used to clean up after
+ * a forum that is being trashed.
+ *
+ * @since bbPress (r3668)
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_is_forum() To check if the passed id is a forum
+ * @uses do_action() Calls 'bbp_trash_forum' with the forum id
+ */
+function bbp_trash_forum( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
+		return false;
+
+	do_action( 'bbp_trash_forum', $forum_id );
+}
+
+/**
+ * Called before untrashing a forum
+ *
+ * @since bbPress (r3668)
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_is_forum() To check if the passed id is a forum
+ * @uses do_action() Calls 'bbp_untrash_forum' with the forum id
+ */
+function bbp_untrash_forum( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
+		return false;
+
+	do_action( 'bbp_untrash_forum', $forum_id );
+}
+
+/** After Delete/Trash/Untrash ************************************************/
+
+/**
+ * Called after deleting a forum
+ *
+ * @since bbPress (r3668)
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_is_forum() To check if the passed id is a forum
+ * @uses do_action() Calls 'bbp_deleted_forum' with the forum id
+ */
+function bbp_deleted_forum( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
+		return false;
+
+	do_action( 'bbp_deleted_forum', $forum_id );
+}
+
+/**
+ * Called after trashing a forum
+ *
+ * @since bbPress (r3668)
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_is_forum() To check if the passed id is a forum
+ * @uses do_action() Calls 'bbp_trashed_forum' with the forum id
+ */
+function bbp_trashed_forum( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
+		return false;
+
+	do_action( 'bbp_trashed_forum', $forum_id );
+}
+
+/**
+ * Called after untrashing a forum
+ *
+ * @since bbPress (r3668)
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_is_forum() To check if the passed id is a forum
+ * @uses do_action() Calls 'bbp_untrashed_forum' with the forum id
+ */
+function bbp_untrashed_forum( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
+		return false;
+
+	do_action( 'bbp_untrashed_forum', $forum_id );
+}
Index: /tags/2.5.4/includes/forums/index.php
===================================================================
--- /tags/2.5.4/includes/forums/index.php	(revision 5382)
+++ /tags/2.5.4/includes/forums/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/forums/template.php
===================================================================
--- /tags/2.5.4/includes/forums/template.php	(revision 5382)
+++ /tags/2.5.4/includes/forums/template.php	(revision 5382)
@@ -0,0 +1,2670 @@
+<?php
+
+/**
+ * bbPress Forum Template Tags
+ *
+ * @package bbPress
+ * @subpackage TemplateTags
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Post Type *****************************************************************/
+
+/**
+ * Output the unique id of the custom post type for forums
+ *
+ * @since bbPress (r2857)
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ */
+function bbp_forum_post_type() {
+	echo bbp_get_forum_post_type();
+}
+	/**
+	 * Return the unique id of the custom post type for forums
+	 *
+	 * @since bbPress (r2857)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_forum_post_type' with the forum
+	 *                        post type id
+	 * @return string The unique forum post type id
+	 */
+	function bbp_get_forum_post_type() {
+		return apply_filters( 'bbp_get_forum_post_type', bbpress()->forum_post_type );
+	}
+
+
+/**
+ * Return array of labels used by the forum post type
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_forum_post_type_labels() {
+	return apply_filters( 'bbp_get_forum_post_type_labels', array(
+		'name'               => __( 'Forums',                   'bbpress' ),
+		'menu_name'          => __( 'Forums',                   'bbpress' ),
+		'singular_name'      => __( 'Forum',                    'bbpress' ),
+		'all_items'          => __( 'All Forums',               'bbpress' ),
+		'add_new'            => __( 'New Forum',                'bbpress' ),
+		'add_new_item'       => __( 'Create New Forum',         'bbpress' ),
+		'edit'               => __( 'Edit',                     'bbpress' ),
+		'edit_item'          => __( 'Edit Forum',               'bbpress' ),
+		'new_item'           => __( 'New Forum',                'bbpress' ),
+		'view'               => __( 'View Forum',               'bbpress' ),
+		'view_item'          => __( 'View Forum',               'bbpress' ),
+		'search_items'       => __( 'Search Forums',            'bbpress' ),
+		'not_found'          => __( 'No forums found',          'bbpress' ),
+		'not_found_in_trash' => __( 'No forums found in Trash', 'bbpress' ),
+		'parent_item_colon'  => __( 'Parent Forum:',            'bbpress' )
+	) );
+}
+
+/**
+ * Return array of forum post type rewrite settings
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_forum_post_type_rewrite() {
+	return apply_filters( 'bbp_get_forum_post_type_rewrite', array(
+		'slug'       => bbp_get_forum_slug(),
+		'with_front' => false
+	) );
+}
+
+/**
+ * Return array of features the forum post type supports
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_forum_post_type_supports() {
+	return apply_filters( 'bbp_get_forum_post_type_supports', array(
+		'title',
+		'editor',
+		'revisions'
+	) );
+}
+
+/** Forum Loop ****************************************************************/
+
+/**
+ * The main forum loop.
+ *
+ * WordPress makes this easy for us.
+ *
+ * @since bbPress (r2464)
+ *
+ * @param mixed $args All the arguments supported by {@link WP_Query}
+ * @uses WP_Query To make query and get the forums
+ * @uses bbp_get_forum_post_type() To get the forum post type id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses get_option() To get the forums per page option
+ * @uses current_user_can() To check if the current user is capable of editing
+ *                           others' forums
+ * @uses apply_filters() Calls 'bbp_has_forums' with
+ *                        bbPres::forum_query::have_posts()
+ *                        and bbPres::forum_query
+ * @return object Multidimensional array of forum information
+ */
+function bbp_has_forums( $args = '' ) {
+
+	// Forum archive only shows root
+	if ( bbp_is_forum_archive() ) {
+		$default_post_parent = 0;
+
+	// User subscriptions shows any
+	} elseif ( bbp_is_subscriptions() ) {
+		$default_post_parent = 'any';
+
+	// Could be anything, so look for possible parent ID
+	} else {
+		$default_post_parent = bbp_get_forum_id();
+	}
+
+	// Parse arguments with default forum query for most circumstances
+	$bbp_f = bbp_parse_args( $args, array(
+		'post_type'           => bbp_get_forum_post_type(),
+		'post_parent'         => $default_post_parent,
+		'post_status'         => bbp_get_public_status_id(),
+		'posts_per_page'      => get_option( '_bbp_forums_per_page', 50 ),
+		'ignore_sticky_posts' => true,
+		'orderby'             => 'menu_order title',
+		'order'               => 'ASC'
+	), 'has_forums' );
+
+	// Run the query
+	$bbp              = bbpress();
+	$bbp->forum_query = new WP_Query( $bbp_f );
+
+	return apply_filters( 'bbp_has_forums', $bbp->forum_query->have_posts(), $bbp->forum_query );
+}
+
+/**
+ * Whether there are more forums available in the loop
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses bbPress:forum_query::have_posts() To check if there are more forums
+ *                                          available
+ * @return object Forum information
+ */
+function bbp_forums() {
+
+	// Put into variable to check against next
+	$have_posts = bbpress()->forum_query->have_posts();
+
+	// Reset the post data when finished
+	if ( empty( $have_posts ) )
+		wp_reset_postdata();
+
+	return $have_posts;
+}
+
+/**
+ * Loads up the current forum in the loop
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses bbPress:forum_query::the_post() To get the current forum
+ * @return object Forum information
+ */
+function bbp_the_forum() {
+	return bbpress()->forum_query->the_post();
+}
+
+/** Forum *********************************************************************/
+
+/**
+ * Output forum id
+ *
+ * @since bbPress (r2464)
+ *
+ * @param $forum_id Optional. Used to check emptiness
+ * @uses bbp_get_forum_id() To get the forum id
+ */
+function bbp_forum_id( $forum_id = 0 ) {
+	echo bbp_get_forum_id( $forum_id );
+}
+	/**
+	 * Return the forum id
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param $forum_id Optional. Used to check emptiness
+	 * @uses bbPress::forum_query::in_the_loop To check if we're in the loop
+	 * @uses bbPress::forum_query::post::ID To get the forum id
+	 * @uses WP_Query::post::ID To get the forum id
+	 * @uses bbp_is_forum() To check if the search result is a forum
+	 * @uses bbp_is_single_forum() To check if it's a forum page
+	 * @uses bbp_is_single_topic() To check if it's a topic page
+	 * @uses bbp_get_topic_forum_id() To get the topic forum id
+	 * @uses get_post_field() To get the post's post type
+	 * @uses apply_filters() Calls 'bbp_get_forum_id' with the forum id and
+	 *                        supplied forum id
+	 * @return int The forum id
+	 */
+	function bbp_get_forum_id( $forum_id = 0 ) {
+		global $wp_query;
+
+		$bbp = bbpress();
+
+		// Easy empty checking
+		if ( !empty( $forum_id ) && is_numeric( $forum_id ) ) {
+			$bbp_forum_id = $forum_id;
+
+		// Currently inside a forum loop
+		} elseif ( !empty( $bbp->forum_query->in_the_loop ) && isset( $bbp->forum_query->post->ID ) ) {
+			$bbp_forum_id = $bbp->forum_query->post->ID;
+
+		// Currently inside a search loop
+		} elseif ( !empty( $bbp->search_query->in_the_loop ) && isset( $bbp->search_query->post->ID ) && bbp_is_forum( $bbp->search_query->post->ID ) ) {
+			$bbp_forum_id = $bbp->search_query->post->ID;
+
+		// Currently viewing a forum
+		} elseif ( ( bbp_is_single_forum() || bbp_is_forum_edit() ) && !empty( $bbp->current_forum_id ) ) {
+			$bbp_forum_id = $bbp->current_forum_id;
+
+		// Currently viewing a forum
+		} elseif ( ( bbp_is_single_forum() || bbp_is_forum_edit() ) && isset( $wp_query->post->ID ) ) {
+			$bbp_forum_id = $wp_query->post->ID;
+
+		// Currently viewing a topic
+		} elseif ( bbp_is_single_topic() ) {
+			$bbp_forum_id = bbp_get_topic_forum_id();
+
+		// Fallback
+		} else {
+			$bbp_forum_id = 0;
+		}
+
+		return (int) apply_filters( 'bbp_get_forum_id', (int) $bbp_forum_id, $forum_id );
+	}
+
+/**
+ * Gets a forum
+ *
+ * @since bbPress (r2787)
+ *
+ * @param int|object $forum forum id or forum object
+ * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. Default = OBJECT
+ * @param string $filter Optional Sanitation filter. See {@link sanitize_post()}
+ * @uses get_post() To get the forum
+ * @uses apply_filters() Calls 'bbp_get_forum' with the forum, output type and
+ *                        sanitation filter
+ * @return mixed Null if error or forum (in specified form) if success
+ */
+function bbp_get_forum( $forum, $output = OBJECT, $filter = 'raw' ) {
+
+	// Use forum ID
+	if ( empty( $forum ) || is_numeric( $forum ) )
+		$forum = bbp_get_forum_id( $forum );
+
+	// Attempt to load the forum
+	$forum = get_post( $forum, OBJECT, $filter );
+	if ( empty( $forum ) )
+		return $forum;
+
+	// Bail if post_type is not a forum
+	if ( $forum->post_type !== bbp_get_forum_post_type() )
+		return null;
+
+	// Tweak the data type to return
+	if ( $output === OBJECT ) {
+		return $forum;
+
+	} elseif ( $output === ARRAY_A ) {
+		$_forum = get_object_vars( $forum );
+		return $_forum;
+
+	} elseif ( $output === ARRAY_N ) {
+		$_forum = array_values( get_object_vars( $forum ) );
+		return $_forum;
+
+	}
+
+	return apply_filters( 'bbp_get_forum', $forum, $output, $filter );
+}
+
+/**
+ * Output the link to the forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_permalink() To get the permalink
+ */
+function bbp_forum_permalink( $forum_id = 0 ) {
+	echo esc_url( bbp_get_forum_permalink( $forum_id ) );
+}
+	/**
+	 * Return the link to the forum
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @param $string $redirect_to Optional. Pass a redirect value for use with
+	 *                              shortcodes and other fun things.
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_permalink() Get the permalink of the forum
+	 * @uses apply_filters() Calls 'bbp_get_forum_permalink' with the forum
+	 *                        link
+	 * @return string Permanent link to forum
+	 */
+	function bbp_get_forum_permalink( $forum_id = 0, $redirect_to = '' ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		// Use the redirect address
+		if ( !empty( $redirect_to ) ) {
+			$forum_permalink = esc_url_raw( $redirect_to );
+
+		// Use the topic permalink
+		} else {
+			$forum_permalink = get_permalink( $forum_id );
+		}
+
+		return apply_filters( 'bbp_get_forum_permalink', $forum_permalink, $forum_id );
+	}
+
+/**
+ * Output the title of the forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_title() To get the forum title
+ */
+function bbp_forum_title( $forum_id = 0 ) {
+	echo bbp_get_forum_title( $forum_id );
+}
+	/**
+	 * Return the title of the forum
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_the_title() To get the forum title
+	 * @uses apply_filters() Calls 'bbp_get_forum_title' with the title
+	 * @return string Title of forum
+	 */
+	function bbp_get_forum_title( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$title    = get_the_title( $forum_id );
+
+		return apply_filters( 'bbp_get_forum_title', $title, $forum_id );
+	}
+
+/**
+ * Output the forum archive title
+ *
+ * @since bbPress (r3249)
+ *
+ * @param string $title Default text to use as title
+ */
+function bbp_forum_archive_title( $title = '' ) {
+	echo bbp_get_forum_archive_title( $title );
+}
+	/**
+	 * Return the forum archive title
+	 *
+	 * @since bbPress (r3249)
+	 *
+	 * @param string $title Default text to use as title
+	 *
+	 * @uses bbp_get_page_by_path() Check if page exists at root path
+	 * @uses get_the_title() Use the page title at the root path
+	 * @uses get_post_type_object() Load the post type object
+	 * @uses bbp_get_forum_post_type() Get the forum post type ID
+	 * @uses get_post_type_labels() Get labels for forum post type
+	 * @uses apply_filters() Allow output to be manipulated
+	 *
+	 * @return string The forum archive title
+	 */
+	function bbp_get_forum_archive_title( $title = '' ) {
+
+		// If no title was passed
+		if ( empty( $title ) ) {
+
+			// Set root text to page title
+			$page = bbp_get_page_by_path( bbp_get_root_slug() );
+			if ( !empty( $page ) ) {
+				$title = get_the_title( $page->ID );
+
+			// Default to forum post type name label
+			} else {
+				$fto    = get_post_type_object( bbp_get_forum_post_type() );
+				$title  = $fto->labels->name;
+			}
+		}
+
+		return apply_filters( 'bbp_get_forum_archive_title', $title );
+	}
+
+/**
+ * Output the content of the forum
+ *
+ * @since bbPress (r2780)
+ *
+ * @param int $forum_id Optional. Topic id
+ * @uses bbp_get_forum_content() To get the forum content
+ */
+function bbp_forum_content( $forum_id = 0 ) {
+	echo bbp_get_forum_content( $forum_id );
+}
+	/**
+	 * Return the content of the forum
+	 *
+	 * @since bbPress (r2780)
+	 *
+	 * @param int $forum_id Optional. Topic id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses post_password_required() To check if the forum requires pass
+	 * @uses get_the_password_form() To get the password form
+	 * @uses get_post_field() To get the content post field
+	 * @uses apply_filters() Calls 'bbp_get_forum_content' with the content
+	 *                        and forum id
+	 * @return string Content of the forum
+	 */
+	function bbp_get_forum_content( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		// Check if password is required
+		if ( post_password_required( $forum_id ) )
+			return get_the_password_form();
+
+		$content = get_post_field( 'post_content', $forum_id );
+
+		return apply_filters( 'bbp_get_forum_content', $content, $forum_id );
+	}
+
+/**
+ * Allow forum rows to have adminstrative actions
+ *
+ * @since bbPress (r3653)
+ * @uses do_action()
+ * @todo Links and filter
+ */
+function bbp_forum_row_actions() {
+	do_action( 'bbp_forum_row_actions' );
+}
+
+/**
+ * Output the forums last active ID
+ *
+ * @since bbPress (r2860)
+ *
+ * @uses bbp_get_forum_last_active_id() To get the forum's last active id
+ * @param int $forum_id Optional. Forum id
+ */
+function bbp_forum_last_active_id( $forum_id = 0 ) {
+	echo bbp_get_forum_last_active_id( $forum_id );
+}
+	/**
+	 * Return the forums last active ID
+	 *
+	 * @since bbPress (r2860)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the forum's last active id
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_active_id' with
+	 *                        the last active id and forum id
+	 * @return int Forum's last active id
+	 */
+	function bbp_get_forum_last_active_id( $forum_id = 0 ) {
+		$forum_id  = bbp_get_forum_id( $forum_id );
+		$active_id = get_post_meta( $forum_id, '_bbp_last_active_id', true );
+
+		return (int) apply_filters( 'bbp_get_forum_last_active_id', (int) $active_id, $forum_id );
+	}
+
+/**
+ * Output the forums last update date/time (aka freshness)
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses bbp_get_forum_last_active_time() To get the forum freshness
+ * @param int $forum_id Optional. Forum id
+ */
+function bbp_forum_last_active_time( $forum_id = 0 ) {
+	echo bbp_get_forum_last_active_time( $forum_id );
+}
+	/**
+	 * Return the forums last update date/time (aka freshness)
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To retrieve forum last active meta
+	 * @uses bbp_get_forum_last_reply_id() To get forum's last reply id
+	 * @uses get_post_field() To get the post date of the reply
+	 * @uses bbp_get_forum_last_topic_id() To get forum's last topic id
+	 * @uses bbp_get_topic_last_active_time() To get time when the topic was
+	 *                                    last active
+	 * @uses bbp_convert_date() To convert the date
+	 * @uses bbp_get_time_since() To get time in since format
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_active' with last
+	 *                        active time and forum id
+	 * @return string Forum last update date/time (freshness)
+	 */
+	function bbp_get_forum_last_active_time( $forum_id = 0 ) {
+
+		// Verify forum and get last active meta
+		$forum_id    = bbp_get_forum_id( $forum_id );
+		$last_active = get_post_meta( $forum_id, '_bbp_last_active_time', true );
+
+		if ( empty( $last_active ) ) {
+			$reply_id = bbp_get_forum_last_reply_id( $forum_id );
+			if ( !empty( $reply_id ) ) {
+				$last_active = get_post_field( 'post_date', $reply_id );
+			} else {
+				$topic_id = bbp_get_forum_last_topic_id( $forum_id );
+				if ( !empty( $topic_id ) ) {
+					$last_active = bbp_get_topic_last_active_time( $topic_id );
+				}
+			}
+		}
+
+		$active_time = !empty( $last_active ) ? bbp_get_time_since( bbp_convert_date( $last_active ) ) : '';
+
+		return apply_filters( 'bbp_get_forum_last_active', $active_time, $forum_id );
+	}
+
+/**
+ * Output link to the most recent activity inside a forum.
+ *
+ * Outputs a complete link with attributes and content.
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_freshness_link() To get the forum freshness link
+ */
+function bbp_forum_freshness_link( $forum_id = 0) {
+	echo bbp_get_forum_freshness_link( $forum_id );
+}
+	/**
+	 * Returns link to the most recent activity inside a forum.
+	 *
+	 * Returns a complete link with attributes and content.
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_active_id() To get the forum last active id
+	 * @uses bbp_get_forum_last_reply_id() To get the forum last reply id
+	 * @uses bbp_get_forum_last_topic_id() To get the forum last topic id
+	 * @uses bbp_get_forum_last_reply_url() To get the forum last reply url
+	 * @uses bbp_get_forum_last_reply_title() To get the forum last reply
+	 *                                         title
+	 * @uses bbp_get_forum_last_topic_permalink() To get the forum last
+	 *                                             topic permalink
+	 * @uses bbp_get_forum_last_topic_title() To get the forum last topic
+	 *                                         title
+	 * @uses bbp_get_forum_last_active_time() To get the time when the forum
+	 *                                         was last active
+	 * @uses apply_filters() Calls 'bbp_get_forum_freshness_link' with the
+	 *                        link and forum id
+	 */
+	function bbp_get_forum_freshness_link( $forum_id = 0 ) {
+		$forum_id  = bbp_get_forum_id( $forum_id );
+		$active_id = bbp_get_forum_last_active_id( $forum_id );
+		$link_url  = $title = '';
+
+		if ( empty( $active_id ) )
+			$active_id = bbp_get_forum_last_reply_id( $forum_id );
+
+		if ( empty( $active_id ) )
+			$active_id = bbp_get_forum_last_topic_id( $forum_id );
+
+		if ( bbp_is_topic( $active_id ) ) {
+			$link_url = bbp_get_forum_last_topic_permalink( $forum_id );
+			$title    = bbp_get_forum_last_topic_title( $forum_id );
+		} elseif ( bbp_is_reply( $active_id ) ) {
+			$link_url = bbp_get_forum_last_reply_url( $forum_id );
+			$title    = bbp_get_forum_last_reply_title( $forum_id );
+		}
+
+		$time_since = bbp_get_forum_last_active_time( $forum_id );
+
+		if ( !empty( $time_since ) && !empty( $link_url ) )
+			$anchor = '<a href="' . esc_url( $link_url ) . '" title="' . esc_attr( $title ) . '">' . esc_html( $time_since ) . '</a>';
+		else
+			$anchor = esc_html__( 'No Topics', 'bbpress' );
+
+		return apply_filters( 'bbp_get_forum_freshness_link', $anchor, $forum_id, $time_since, $link_url, $title, $active_id );
+	}
+
+/**
+ * Output parent ID of a forum, if exists
+ *
+ * @since bbPress (r3675)
+ *
+ * @param int $forum_id Forum ID
+ * @uses bbp_get_forum_parent_id() To get the forum's parent ID
+ */
+function bbp_forum_parent_id( $forum_id = 0 ) {
+	echo bbp_get_forum_parent_id( $forum_id );
+}
+	/**
+	 * Return ID of forum parent, if exists
+	 *
+	 * @since bbPress (r3675)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_field() To get the forum parent
+	 * @uses apply_filters() Calls 'bbp_get_forum_parent' with the parent & forum id
+	 * @return int Forum parent
+	 */
+	function bbp_get_forum_parent_id( $forum_id = 0 ) {
+		$forum_id  = bbp_get_forum_id( $forum_id );
+		$parent_id = get_post_field( 'post_parent', $forum_id );
+
+		return (int) apply_filters( 'bbp_get_forum_parent_id', (int) $parent_id, $forum_id );
+	}
+
+/**
+ * Return array of parent forums
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_forum() To get the forum
+ * @uses apply_filters() Calls 'bbp_get_forum_ancestors' with the ancestors
+ *                        and forum id
+ * @return array Forum ancestors
+ */
+function bbp_get_forum_ancestors( $forum_id = 0 ) {
+	$forum_id  = bbp_get_forum_id( $forum_id );
+	$ancestors = array();
+	$forum     = bbp_get_forum( $forum_id );
+
+	if ( !empty( $forum ) ) {
+		while ( 0 !== (int) $forum->post_parent ) {
+			$ancestors[] = $forum->post_parent;
+			$forum       = bbp_get_forum( $forum->post_parent );
+		}
+	}
+
+	return apply_filters( 'bbp_get_forum_ancestors', $ancestors, $forum_id );
+}
+
+/**
+ * Return subforums of given forum
+ *
+ * @since bbPress (r2747)
+ *
+ * @param mixed $args All the arguments supported by {@link WP_Query}
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses current_user_can() To check if the current user is capable of
+ *                           reading private forums
+ * @uses get_posts() To get the subforums
+ * @uses apply_filters() Calls 'bbp_forum_get_subforums' with the subforums
+ *                        and the args
+ * @return mixed false if none, array of subs if yes
+ */
+function bbp_forum_get_subforums( $args = '' ) {
+
+	// Use passed integer as post_parent
+	if ( is_numeric( $args ) )
+		$args = array( 'post_parent' => $args );
+
+	// Setup possible post__not_in array
+	$post_stati[] = bbp_get_public_status_id();
+
+	// Super admin get whitelisted post statuses
+	if ( bbp_is_user_keymaster() ) {
+		$post_stati = array( bbp_get_public_status_id(), bbp_get_private_status_id(), bbp_get_hidden_status_id() );
+
+	// Not a keymaster, so check caps
+	} else {
+
+		// Check if user can read private forums
+		if ( current_user_can( 'read_private_forums' ) ) {
+			$post_stati[] = bbp_get_private_status_id();
+		}
+
+		// Check if user can read hidden forums
+		if ( current_user_can( 'read_hidden_forums' ) ) {
+			$post_stati[] = bbp_get_hidden_status_id();
+		}
+	}
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'post_parent'         => 0,
+		'post_type'           => bbp_get_forum_post_type(),
+		'post_status'         => implode( ',', $post_stati ),
+		'posts_per_page'      => get_option( '_bbp_forums_per_page', 50 ),
+		'orderby'             => 'menu_order title',
+		'order'               => 'ASC',
+		'ignore_sticky_posts' => true,
+		'no_found_rows'       => true
+	), 'forum_get_subforums' );
+	$r['post_parent'] = bbp_get_forum_id( $r['post_parent'] );
+
+	// Create a new query for the subforums
+	$get_posts = new WP_Query();
+
+	// No forum passed
+	$sub_forums = !empty( $r['post_parent'] ) ? $get_posts->query( $r ) : array();
+
+	return (array) apply_filters( 'bbp_forum_get_subforums', $sub_forums, $r );
+}
+
+/**
+ * Output a list of forums (can be used to list subforums)
+ *
+ * @param mixed $args The function supports these args:
+ *  - before: To put before the output. Defaults to '<ul class="bbp-forums">'
+ *  - after: To put after the output. Defaults to '</ul>'
+ *  - link_before: To put before every link. Defaults to '<li class="bbp-forum">'
+ *  - link_after: To put after every link. Defaults to '</li>'
+ *  - separator: Separator. Defaults to ', '
+ *  - forum_id: Forum id. Defaults to ''
+ *  - show_topic_count - To show forum topic count or not. Defaults to true
+ *  - show_reply_count - To show forum reply count or not. Defaults to true
+ * @uses bbp_forum_get_subforums() To check if the forum has subforums or not
+ * @uses bbp_get_forum_permalink() To get forum permalink
+ * @uses bbp_get_forum_title() To get forum title
+ * @uses bbp_is_forum_category() To check if a forum is a category
+ * @uses bbp_get_forum_topic_count() To get forum topic count
+ * @uses bbp_get_forum_reply_count() To get forum reply count
+ */
+function bbp_list_forums( $args = '' ) {
+
+	// Define used variables
+	$output = $sub_forums = $topic_count = $reply_count = $counts = '';
+	$i = 0;
+	$count = array();
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'before'            => '<ul class="bbp-forums-list">',
+		'after'             => '</ul>',
+		'link_before'       => '<li class="bbp-forum">',
+		'link_after'        => '</li>',
+		'count_before'      => ' (',
+		'count_after'       => ')',
+		'count_sep'         => ', ',
+		'separator'         => ', ',
+		'forum_id'          => '',
+		'show_topic_count'  => true,
+		'show_reply_count'  => true,
+	), 'list_forums' );
+
+	// Loop through forums and create a list
+	$sub_forums = bbp_forum_get_subforums( $r['forum_id'] );
+	if ( !empty( $sub_forums ) ) {
+
+		// Total count (for separator)
+		$total_subs = count( $sub_forums );
+		foreach ( $sub_forums as $sub_forum ) {
+			$i++; // Separator count
+
+			// Get forum details
+			$count     = array();
+			$show_sep  = $total_subs > $i ? $r['separator'] : '';
+			$permalink = bbp_get_forum_permalink( $sub_forum->ID );
+			$title     = bbp_get_forum_title( $sub_forum->ID );
+
+			// Show topic count
+			if ( !empty( $r['show_topic_count'] ) && !bbp_is_forum_category( $sub_forum->ID ) ) {
+				$count['topic'] = bbp_get_forum_topic_count( $sub_forum->ID );
+			}
+
+			// Show reply count
+			if ( !empty( $r['show_reply_count'] ) && !bbp_is_forum_category( $sub_forum->ID ) ) {
+				$count['reply'] = bbp_get_forum_reply_count( $sub_forum->ID );
+			}
+
+			// Counts to show
+			if ( !empty( $count ) ) {
+				$counts = $r['count_before'] . implode( $r['count_sep'], $count ) . $r['count_after'];
+			}
+
+			// Build this sub forums link
+			$output .= $r['link_before'] . '<a href="' . esc_url( $permalink ) . '" class="bbp-forum-link">' . $title . $counts . '</a>' . $show_sep . $r['link_after'];
+		}
+
+		// Output the list
+		echo apply_filters( 'bbp_list_forums', $r['before'] . $output . $r['after'], $r );
+	}
+}
+
+/** Forum Subscriptions *******************************************************/
+
+/**
+ * Output the forum subscription link
+ *
+ * @since bbPress (r5156)
+ *
+ * @uses bbp_get_forum_subscription_link()
+ */
+function bbp_forum_subscription_link( $args = array() ) {
+	echo bbp_get_forum_subscription_link( $args );
+}
+
+	/**
+	 * Get the forum subscription link
+	 *
+	 * A custom wrapper for bbp_get_user_subscribe_link()
+	 *
+	 * @since bbPress (r5156)
+	 *
+	 * @uses bbp_parse_args()
+	 * @uses bbp_get_user_subscribe_link()
+	 * @uses apply_filters() Calls 'bbp_get_forum_subscribe_link'
+	 */
+	function bbp_get_forum_subscription_link( $args = array() ) {
+
+		// No link
+		$retval = false;
+
+		// Parse the arguments
+		$r = bbp_parse_args( $args, array(
+			'forum_id'    => 0,
+			'user_id'     => 0,
+			'before'      => '',
+			'after'       => '',
+			'subscribe'   => __( 'Subscribe',   'bbpress' ),
+			'unsubscribe' => __( 'Unsubscribe', 'bbpress' )
+		), 'get_forum_subscribe_link' );
+
+		// No link for categories until we support subscription hierarchy
+		// @see http://bbpress.trac.wordpress.org/ticket/2475
+		if ( ! bbp_is_forum_category() ) {
+			$retval = bbp_get_user_subscribe_link( $r );
+		}
+
+		return apply_filters( 'bbp_get_forum_subscribe_link', $retval, $r );
+	}
+
+/** Forum Last Topic **********************************************************/
+
+/**
+ * Output the forum's last topic id
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses bbp_get_forum_last_topic_id() To get the forum's last topic id
+ * @param int $forum_id Optional. Forum id
+ */
+function bbp_forum_last_topic_id( $forum_id = 0 ) {
+	echo bbp_get_forum_last_topic_id( $forum_id );
+}
+	/**
+	 * Return the forum's last topic id
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the forum's last topic id
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_topic_id' with the
+	 *                        forum and topic id
+	 * @return int Forum's last topic id
+	 */
+	function bbp_get_forum_last_topic_id( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$topic_id = get_post_meta( $forum_id, '_bbp_last_topic_id', true );
+
+		return (int) apply_filters( 'bbp_get_forum_last_topic_id', (int) $topic_id, $forum_id );
+	}
+
+/**
+ * Output the title of the last topic inside a forum
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_topic_title() To get the forum's last topic's title
+ */
+function bbp_forum_last_topic_title( $forum_id = 0 ) {
+	echo bbp_get_forum_last_topic_title( $forum_id );
+}
+	/**
+	 * Return the title of the last topic inside a forum
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_topic_id() To get the forum's last topic id
+	 * @uses bbp_get_topic_title() To get the topic's title
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_topic_title' with the
+	 *                        topic title and forum id
+	 * @return string Forum's last topic's title
+	 */
+	function bbp_get_forum_last_topic_title( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$topic_id = bbp_get_forum_last_topic_id( $forum_id );
+		$title    = !empty( $topic_id ) ? bbp_get_topic_title( $topic_id ) : '';
+
+		return apply_filters( 'bbp_get_forum_last_topic_title', $title, $forum_id );
+	}
+
+/**
+ * Output the link to the last topic in a forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_topic_permalink() To get the forum's last topic's
+ *                                             permanent link
+ */
+function bbp_forum_last_topic_permalink( $forum_id = 0 ) {
+	echo esc_url( bbp_get_forum_last_topic_permalink( $forum_id ) );
+}
+	/**
+	 * Return the link to the last topic in a forum
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_topic_id() To get the forum's last topic id
+	 * @uses bbp_get_topic_permalink() To get the topic's permalink
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_topic_permalink' with
+	 *                        the topic link and forum id
+	 * @return string Permanent link to topic
+	 */
+	function bbp_get_forum_last_topic_permalink( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		return apply_filters( 'bbp_get_forum_last_topic_permalink', bbp_get_topic_permalink( bbp_get_forum_last_topic_id( $forum_id ) ), $forum_id );
+	}
+
+/**
+ * Return the author ID of the last topic of a forum
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_forum_last_topic_id() To get the forum's last topic id
+ * @uses bbp_get_topic_author_id() To get the topic's author id
+ * @uses apply_filters() Calls 'bbp_get_forum_last_topic_author' with the author
+ *                        id and forum id
+ * @return int Forum's last topic's author id
+ */
+function bbp_get_forum_last_topic_author_id( $forum_id = 0 ) {
+	$forum_id  = bbp_get_forum_id( $forum_id );
+	$author_id = bbp_get_topic_author_id( bbp_get_forum_last_topic_id( $forum_id ) );
+	return (int) apply_filters( 'bbp_get_forum_last_topic_author_id', (int) $author_id, $forum_id );
+}
+
+/**
+ * Output link to author of last topic of forum
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_topic_author_link() To get the forum's last topic's
+ *                                               author link
+ */
+function bbp_forum_last_topic_author_link( $forum_id = 0 ) {
+	echo bbp_get_forum_last_topic_author_link( $forum_id );
+}
+	/**
+	 * Return link to author of last topic of forum
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_topic_author_id() To get the forum's last
+	 *                                             topic's author id
+	 * @uses bbp_get_user_profile_link() To get the author's profile link
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_topic_author_link'
+	 *                        with the author link and forum id
+	 * @return string Forum's last topic's author link
+	 */
+	function bbp_get_forum_last_topic_author_link( $forum_id = 0 ) {
+		$forum_id    = bbp_get_forum_id( $forum_id );
+		$author_id   = bbp_get_forum_last_topic_author_id( $forum_id );
+		$author_link = bbp_get_user_profile_link( $author_id );
+		return apply_filters( 'bbp_get_forum_last_topic_author_link', $author_link, $forum_id );
+	}
+
+/** Forum Last Reply **********************************************************/
+
+/**
+ * Output the forums last reply id
+ *
+ * @since bbPress (r2464)
+ *
+ * @uses bbp_get_forum_last_reply_id() To get the forum's last reply id
+ * @param int $forum_id Optional. Forum id
+ */
+function bbp_forum_last_reply_id( $forum_id = 0 ) {
+	echo bbp_get_forum_last_reply_id( $forum_id );
+}
+	/**
+	 * Return the forums last reply id
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the forum's last reply id
+	 * @uses bbp_get_forum_last_topic_id() To get the forum's last topic id
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_reply_id' with
+	 *                        the last reply id and forum id
+	 * @return int Forum's last reply id
+	 */
+	function bbp_get_forum_last_reply_id( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$reply_id = get_post_meta( $forum_id, '_bbp_last_reply_id', true );
+
+		if ( empty( $reply_id ) )
+			$reply_id = bbp_get_forum_last_topic_id( $forum_id );
+
+		return (int) apply_filters( 'bbp_get_forum_last_reply_id', (int) $reply_id, $forum_id );
+	}
+
+/**
+ * Output the title of the last reply inside a forum
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_reply_title() To get the forum's last reply's title
+ */
+function bbp_forum_last_reply_title( $forum_id = 0 ) {
+	echo bbp_get_forum_last_reply_title( $forum_id );
+}
+	/**
+	 * Return the title of the last reply inside a forum
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_reply_id() To get the forum's last reply id
+	 * @uses bbp_get_reply_title() To get the reply title
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_reply_title' with the
+	 *                        reply title and forum id
+	 * @return string
+	 */
+	function bbp_get_forum_last_reply_title( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		return apply_filters( 'bbp_get_forum_last_reply_title', bbp_get_reply_title( bbp_get_forum_last_reply_id( $forum_id ) ), $forum_id );
+	}
+
+/**
+ * Output the link to the last reply in a forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_reply_permalink() To get the forum last reply link
+ */
+function bbp_forum_last_reply_permalink( $forum_id = 0 ) {
+	echo esc_url( bbp_get_forum_last_reply_permalink( $forum_id ) );
+}
+	/**
+	 * Return the link to the last reply in a forum
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_reply_id() To get the forum's last reply id
+	 * @uses bbp_get_reply_permalink() To get the reply permalink
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_reply_permalink' with
+	 *                        the reply link and forum id
+	 * @return string Permanent link to the forum's last reply
+	 */
+	function bbp_get_forum_last_reply_permalink( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		return apply_filters( 'bbp_get_forum_last_reply_permalink', bbp_get_reply_permalink( bbp_get_forum_last_reply_id( $forum_id ) ), $forum_id );
+	}
+
+/**
+ * Output the url to the last reply in a forum
+ *
+ * @since bbPress (r2683)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_reply_url() To get the forum last reply url
+ */
+function bbp_forum_last_reply_url( $forum_id = 0 ) {
+	echo esc_url( bbp_get_forum_last_reply_url( $forum_id ) );
+}
+	/**
+	 * Return the url to the last reply in a forum
+	 *
+	 * @since bbPress (r2683)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_reply_id() To get the forum's last reply id
+	 * @uses bbp_get_reply_url() To get the reply url
+	 * @uses bbp_get_forum_last_topic_permalink() To get the forum's last
+	 *                                             topic's permalink
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_reply_url' with the
+	 *                        reply url and forum id
+	 * @return string Paginated URL to latest reply
+	 */
+	function bbp_get_forum_last_reply_url( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		// If forum has replies, get the last reply and use its url
+		$reply_id = bbp_get_forum_last_reply_id( $forum_id );
+		if ( !empty( $reply_id ) ) {
+			$reply_url = bbp_get_reply_url( $reply_id );
+
+		// No replies, so look for topics and use last permalink
+		} else {
+			$reply_url = bbp_get_forum_last_topic_permalink( $forum_id );
+
+			// No topics either, so set $reply_url as empty string
+			if ( empty( $reply_url ) ) {
+				$reply_url = '';
+			}
+		}
+
+		// Filter and return
+		return apply_filters( 'bbp_get_forum_last_reply_url', $reply_url, $forum_id );
+	}
+
+/**
+ * Output author ID of last reply of forum
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_reply_author_id() To get the forum's last reply
+ *                                             author id
+ */
+function bbp_forum_last_reply_author_id( $forum_id = 0 ) {
+	echo bbp_get_forum_last_reply_author_id( $forum_id );
+}
+	/**
+	 * Return author ID of last reply of forum
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_reply_author_id() To get the forum's last
+	 *                                             reply's author id
+	 * @uses bbp_get_reply_author_id() To get the reply's author id
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_reply_author_id' with
+	 *                        the author id and forum id
+	 * @return int Forum's last reply author id
+	 */
+	function bbp_get_forum_last_reply_author_id( $forum_id = 0 ) {
+		$forum_id  = bbp_get_forum_id( $forum_id );
+		$author_id = bbp_get_reply_author_id( bbp_get_forum_last_reply_id( $forum_id ) );
+		return apply_filters( 'bbp_get_forum_last_reply_author_id', $author_id, $forum_id );
+	}
+
+/**
+ * Output link to author of last reply of forum
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_last_reply_author_link() To get the forum's last reply's
+ *                                               author link
+ */
+function bbp_forum_last_reply_author_link( $forum_id = 0 ) {
+	echo bbp_get_forum_last_reply_author_link( $forum_id );
+}
+	/**
+	 * Return link to author of last reply of forum
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_last_reply_author_id() To get the forum's last
+	 *                                             reply's author id
+	 * @uses bbp_get_user_profile_link() To get the reply's author's profile
+	 *                                    link
+	 * @uses apply_filters() Calls 'bbp_get_forum_last_reply_author_link'
+	 *                        with the author link and forum id
+	 * @return string Link to author of last reply of forum
+	 */
+	function bbp_get_forum_last_reply_author_link( $forum_id = 0 ) {
+		$forum_id    = bbp_get_forum_id( $forum_id );
+		$author_id   = bbp_get_forum_last_reply_author_id( $forum_id );
+		$author_link = bbp_get_user_profile_link( $author_id );
+		return apply_filters( 'bbp_get_forum_last_reply_author_link', $author_link, $forum_id );
+	}
+
+/** Forum Counts **************************************************************/
+
+/**
+ * Output the topics link of the forum
+ *
+ * @since bbPress (r2883)
+ *
+ * @param int $forum_id Optional. Topic id
+ * @uses bbp_get_forum_topics_link() To get the forum topics link
+ */
+function bbp_forum_topics_link( $forum_id = 0 ) {
+	echo bbp_get_forum_topics_link( $forum_id );
+}
+
+	/**
+	 * Return the topics link of the forum
+	 *
+	 * @since bbPress (r2883)
+	 *
+	 * @param int $forum_id Optional. Topic id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum() To get the forum
+	 * @uses bbp_get_forum_topic_count() To get the forum topic count
+	 * @uses bbp_get_forum_permalink() To get the forum permalink
+	 * @uses remove_query_arg() To remove args from the url
+	 * @uses bbp_get_forum_topic_count_hidden() To get the forum hidden
+	 *                                           topic count
+	 * @uses current_user_can() To check if the current user can edit others
+	 *                           topics
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses apply_filters() Calls 'bbp_get_forum_topics_link' with the
+	 *                        topics link and forum id
+	 */
+	function bbp_get_forum_topics_link( $forum_id = 0 ) {
+		$forum    = bbp_get_forum( $forum_id );
+		$forum_id = $forum->ID;
+		$topics   = sprintf( _n( '%s topic', '%s topics', bbp_get_forum_topic_count( $forum_id, true, false ), 'bbpress' ), bbp_get_forum_topic_count( $forum_id ) );
+		$retval   = '';
+
+		// First link never has view=all
+		if ( bbp_get_view_all( 'edit_others_topics' ) )
+			$retval .= "<a href='" . esc_url( bbp_remove_view_all( bbp_get_forum_permalink( $forum_id ) ) ) . "'>" . esc_html( $topics ) . "</a>";
+		else
+			$retval .= esc_html( $topics );
+
+		// Get deleted topics
+		$deleted = bbp_get_forum_topic_count_hidden( $forum_id );
+
+		// This forum has hidden topics
+		if ( !empty( $deleted ) && current_user_can( 'edit_others_topics' ) ) {
+
+			// Extra text
+			$extra = sprintf( __( ' (+ %d hidden)', 'bbpress' ), $deleted );
+
+			// No link
+			if ( bbp_get_view_all() ) {
+				$retval .= " $extra";
+
+			// Link
+			} else {
+				$retval .= " <a href='" . esc_url( bbp_add_view_all( bbp_get_forum_permalink( $forum_id ), true ) ) . "'>" . esc_html( $extra ) . "</a>";
+			}
+		}
+
+		return apply_filters( 'bbp_get_forum_topics_link', $retval, $forum_id );
+	}
+
+/**
+ * Output total sub-forum count of a forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id to check
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_forum_subforum_count() To get the forum's subforum count
+ */
+function bbp_forum_subforum_count( $forum_id = 0, $integer = false ) {
+	echo bbp_get_forum_subforum_count( $forum_id, $integer );
+}
+	/**
+	 * Return total subforum count of a forum
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the subforum count
+	 * @uses apply_filters() Calls 'bbp_get_forum_subforum_count' with the
+	 *                        subforum count and forum id
+	 * @return int Forum's subforum count
+	 */
+	function bbp_get_forum_subforum_count( $forum_id = 0, $integer = false ) {
+		$forum_id    = bbp_get_forum_id( $forum_id );
+		$forum_count = (int) get_post_meta( $forum_id, '_bbp_forum_subforum_count', true );
+		$filter      = ( true === $integer ) ? 'bbp_get_forum_subforum_count_int' : 'bbp_get_forum_subforum_count';
+
+		return apply_filters( $filter, $forum_count, $forum_id );
+	}
+
+/**
+ * Output total topic count of a forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param bool $total_count Optional. To get the total count or normal count?
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_forum_topic_count() To get the forum topic count
+ */
+function bbp_forum_topic_count( $forum_id = 0, $total_count = true, $integer = false ) {
+	echo bbp_get_forum_topic_count( $forum_id, $total_count, $integer );
+}
+	/**
+	 * Return total topic count of a forum
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @param bool $total_count Optional. To get the total count or normal
+	 *                           count? Defaults to total.
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the forum topic count
+	 * @uses apply_filters() Calls 'bbp_get_forum_topic_count' with the
+	 *                        topic count and forum id
+	 * @return int Forum topic count
+	 */
+	function bbp_get_forum_topic_count( $forum_id = 0, $total_count = true, $integer = false ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$meta_key = empty( $total_count ) ? '_bbp_topic_count' : '_bbp_total_topic_count';
+		$topics   = (int) get_post_meta( $forum_id, $meta_key, true );
+		$filter   = ( true === $integer ) ? 'bbp_get_forum_topic_count_int' : 'bbp_get_forum_topic_count';
+
+		return apply_filters( $filter, $topics, $forum_id );
+	}
+
+/**
+ * Output total reply count of a forum
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param bool $total_count Optional. To get the total count or normal count?
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_forum_reply_count() To get the forum reply count
+ */
+function bbp_forum_reply_count( $forum_id = 0, $total_count = true, $integer = false ) {
+	echo bbp_get_forum_reply_count( $forum_id, $total_count, $integer );
+}
+	/**
+	 * Return total post count of a forum
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @param bool $total_count Optional. To get the total count or normal
+	 *                           count?
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the forum reply count
+	 * @uses apply_filters() Calls 'bbp_get_forum_reply_count' with the
+	 *                        reply count and forum id
+	 * @return int Forum reply count
+	 */
+	function bbp_get_forum_reply_count( $forum_id = 0, $total_count = true, $integer = false ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$meta_key = empty( $total_count ) ? '_bbp_reply_count' : '_bbp_total_reply_count';
+		$replies  = (int) get_post_meta( $forum_id, $meta_key, true );
+		$filter   = ( true === $integer ) ? 'bbp_get_forum_reply_count_int' : 'bbp_get_forum_reply_count';
+
+		return apply_filters( $filter, $replies, $forum_id );
+	}
+
+/**
+ * Output total post count of a forum
+ *
+ * @since bbPress (r2954)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param bool $total_count Optional. To get the total count or normal count?
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_forum_post_count() To get the forum post count
+ */
+function bbp_forum_post_count( $forum_id = 0, $total_count = true, $integer = false ) {
+	echo bbp_get_forum_post_count( $forum_id, $total_count, $integer );
+}
+	/**
+	 * Return total post count of a forum
+	 *
+	 * @since bbPress (r2954)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @param bool $total_count Optional. To get the total count or normal
+	 *                           count?
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the forum post count
+	 * @uses apply_filters() Calls 'bbp_get_forum_post_count' with the
+	 *                        post count and forum id
+	 * @return int Forum post count
+	 */
+	function bbp_get_forum_post_count( $forum_id = 0, $total_count = true, $integer = false ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$topics   = bbp_get_forum_topic_count( $forum_id, $total_count, true );
+		$meta_key = empty( $total_count ) ? '_bbp_reply_count' : '_bbp_total_reply_count';
+		$replies  = (int) get_post_meta( $forum_id, $meta_key, true );
+		$retval   = $replies + $topics;
+		$filter   = ( true === $integer ) ? 'bbp_get_forum_post_count_int' : 'bbp_get_forum_post_count';
+
+		return apply_filters( $filter, $retval, $forum_id );
+	}
+
+/**
+ * Output total hidden topic count of a forum (hidden includes trashed and
+ * spammed topics)
+ *
+ * @since bbPress (r2883)
+ *
+ * @param int $forum_id Optional. Topic id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_forum_topic_count_hidden() To get the forum hidden topic count
+ */
+function bbp_forum_topic_count_hidden( $forum_id = 0, $integer = false ) {
+	echo bbp_get_forum_topic_count_hidden( $forum_id, $integer );
+}
+	/**
+	 * Return total hidden topic count of a forum (hidden includes trashed
+	 * and spammed topics)
+	 *
+	 * @since bbPress (r2883)
+	 *
+	 * @param int $forum_id Optional. Topic id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_meta() To get the hidden topic count
+	 * @uses apply_filters() Calls 'bbp_get_forum_topic_count_hidden' with
+	 *                        the hidden topic count and forum id
+	 * @return int Topic hidden topic count
+	 */
+	function bbp_get_forum_topic_count_hidden( $forum_id = 0, $integer = false ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$topics   = (int) get_post_meta( $forum_id, '_bbp_topic_count_hidden', true );
+		$filter   = ( true === $integer ) ? 'bbp_get_forum_topic_count_hidden_int' : 'bbp_get_forum_topic_count_hidden';
+
+		return apply_filters( $filter, $topics, $forum_id );
+	}
+
+/**
+ * Output the status of the forum
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_status() To get the forum status
+ */
+function bbp_forum_status( $forum_id = 0 ) {
+	echo bbp_get_forum_status( $forum_id );
+}
+	/**
+	 * Return the status of the forum
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_status() To get the forum's status
+	 * @uses apply_filters() Calls 'bbp_get_forum_status' with the status
+	 *                        and forum id
+	 * @return string Status of forum
+	 */
+	function bbp_get_forum_status( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$status   = get_post_meta( $forum_id, '_bbp_status', true );
+		if ( empty( $status ) )
+			$status = 'open';
+
+		return apply_filters( 'bbp_get_forum_status', $status, $forum_id );
+	}
+
+/**
+ * Output the visibility of the forum
+ *
+ * @since bbPress (r2997)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_visibility() To get the forum visibility
+ */
+function bbp_forum_visibility( $forum_id = 0 ) {
+	echo bbp_get_forum_visibility( $forum_id );
+}
+	/**
+	 * Return the visibility of the forum
+	 *
+	 * @since bbPress (r2997)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_visibility() To get the forum's visibility
+	 * @uses apply_filters() Calls 'bbp_get_forum_visibility' with the visibility
+	 *                        and forum id
+	 * @return string Status of forum
+	 */
+	function bbp_get_forum_visibility( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		return apply_filters( 'bbp_get_forum_visibility', get_post_status( $forum_id ), $forum_id );
+	}
+
+/**
+ * Output the type of the forum
+ *
+ * @since bbPress (r3563)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_type() To get the forum type
+ */
+function bbp_forum_type( $forum_id = 0 ) {
+	echo bbp_get_forum_type( $forum_id );
+}
+	/**
+	 * Return the type of forum (category/forum/etc...)
+	 *
+	 * @since bbPress (r3563)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses get_post_meta() To get the forum category meta
+	 * @return bool Whether the forum is a category or not
+	 */
+	function bbp_get_forum_type( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$retval   = get_post_meta( $forum_id, '_bbp_forum_type', true );
+		if ( empty( $retval ) )
+			$retval = 'forum';
+
+		return apply_filters( 'bbp_get_forum_type', $retval, $forum_id );
+	}
+
+/**
+ * Is the forum a category?
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_type() To get the forum type
+ * @return bool Whether the forum is a category or not
+ */
+function bbp_is_forum_category( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+	$type     = bbp_get_forum_type( $forum_id );
+	$retval   = ( !empty( $type ) && 'category' === $type );
+
+	return (bool) apply_filters( 'bbp_is_forum_category', (bool) $retval, $forum_id );
+}
+
+/**
+ * Is the forum open?
+ *
+ * @since bbPress (r2746)
+ * @param int $forum_id Optional. Forum id
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_is_forum_closed() To check if the forum is closed or not
+ * @return bool Whether the forum is open or not
+ */
+function bbp_is_forum_open( $forum_id = 0 ) {
+	return !bbp_is_forum_closed( $forum_id );
+}
+
+	/**
+	 * Is the forum closed?
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @param bool $check_ancestors Check if the ancestors are closed (only
+	 *                               if they're a category)
+	 * @uses bbp_get_forum_status() To get the forum status
+	 * @uses bbp_get_forum_ancestors() To get the forum ancestors
+	 * @uses bbp_is_forum_category() To check if the forum is a category
+	 * @uses bbp_is_forum_closed() To check if the forum is closed
+	 * @return bool True if closed, false if not
+	 */
+	function bbp_is_forum_closed( $forum_id = 0, $check_ancestors = true ) {
+
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$retval    = ( bbp_get_closed_status_id() === bbp_get_forum_status( $forum_id ) );
+
+		if ( !empty( $check_ancestors ) ) {
+			$ancestors = bbp_get_forum_ancestors( $forum_id );
+
+			foreach ( (array) $ancestors as $ancestor ) {
+				if ( bbp_is_forum_category( $ancestor, false ) && bbp_is_forum_closed( $ancestor, false ) ) {
+					$retval = true;
+				}
+			}
+		}
+
+		return (bool) apply_filters( 'bbp_is_forum_closed', (bool) $retval, $forum_id, $check_ancestors );
+	}
+
+/**
+ * Is the forum public?
+ *
+ * @since bbPress (r2997)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param bool $check_ancestors Check if the ancestors are public (only if
+ *                               they're a category)
+ * @uses get_post_meta() To get the forum public meta
+ * @uses bbp_get_forum_ancestors() To get the forum ancestors
+ * @uses bbp_is_forum_category() To check if the forum is a category
+ * @uses bbp_is_forum_closed() To check if the forum is closed
+ * @return bool True if closed, false if not
+ */
+function bbp_is_forum_public( $forum_id = 0, $check_ancestors = true ) {
+
+	$forum_id   = bbp_get_forum_id( $forum_id );
+	$visibility = bbp_get_forum_visibility( $forum_id );
+
+	// If post status is public, return true
+	$retval = ( bbp_get_public_status_id() === $visibility );
+
+	// Check ancestors and inherit their privacy setting for display
+	if ( !empty( $check_ancestors ) ) {
+		$ancestors = bbp_get_forum_ancestors( $forum_id );
+
+		foreach ( (array) $ancestors as $ancestor ) {
+			if ( bbp_is_forum( $ancestor ) && bbp_is_forum_public( $ancestor, false ) ) {
+				$retval = true;
+			}
+		}
+	}
+
+	return (bool) apply_filters( 'bbp_is_forum_public', (bool) $retval, $forum_id, $check_ancestors );
+}
+
+/**
+ * Is the forum private?
+ *
+ * @since bbPress (r2746)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param bool $check_ancestors Check if the ancestors are private (only if
+ *                               they're a category)
+ * @uses get_post_meta() To get the forum private meta
+ * @uses bbp_get_forum_ancestors() To get the forum ancestors
+ * @uses bbp_is_forum_category() To check if the forum is a category
+ * @uses bbp_is_forum_closed() To check if the forum is closed
+ * @return bool True if closed, false if not
+ */
+function bbp_is_forum_private( $forum_id = 0, $check_ancestors = true ) {
+
+	$forum_id   = bbp_get_forum_id( $forum_id );
+	$visibility = bbp_get_forum_visibility( $forum_id );
+
+	// If post status is private, return true
+	$retval = ( bbp_get_private_status_id() === $visibility );
+
+	// Check ancestors and inherit their privacy setting for display
+	if ( !empty( $check_ancestors ) ) {
+		$ancestors = bbp_get_forum_ancestors( $forum_id );
+
+		foreach ( (array) $ancestors as $ancestor ) {
+			if ( bbp_is_forum( $ancestor ) && bbp_is_forum_private( $ancestor, false ) ) {
+				$retval = true;
+			}
+		}
+	}
+
+	return (bool) apply_filters( 'bbp_is_forum_private', (bool) $retval, $forum_id, $check_ancestors );
+}
+
+/**
+ * Is the forum hidden?
+ *
+ * @since bbPress (r2997)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @param bool $check_ancestors Check if the ancestors are private (only if
+ *                               they're a category)
+ * @uses get_post_meta() To get the forum private meta
+ * @uses bbp_get_forum_ancestors() To get the forum ancestors
+ * @uses bbp_is_forum_category() To check if the forum is a category
+ * @uses bbp_is_forum_closed() To check if the forum is closed
+ * @return bool True if closed, false if not
+ */
+function bbp_is_forum_hidden( $forum_id = 0, $check_ancestors = true ) {
+
+	$forum_id   = bbp_get_forum_id( $forum_id );
+	$visibility = bbp_get_forum_visibility( $forum_id );
+
+	// If post status is private, return true
+	$retval = ( bbp_get_hidden_status_id() === $visibility );
+
+	// Check ancestors and inherit their privacy setting for display
+	if ( !empty( $check_ancestors ) ) {
+		$ancestors = bbp_get_forum_ancestors( $forum_id );
+
+		foreach ( (array) $ancestors as $ancestor ) {
+			if ( bbp_is_forum( $ancestor ) && bbp_is_forum_hidden( $ancestor, false ) ) {
+				$retval = true;
+			}
+		}
+	}
+
+	return (bool) apply_filters( 'bbp_is_forum_hidden', (bool) $retval, $forum_id, $check_ancestors );
+}
+
+/**
+ * Output the author of the forum
+ *
+ * @since bbPress (r3675)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_author() To get the forum author
+ */
+function bbp_forum_author_display_name( $forum_id = 0 ) {
+	echo bbp_get_forum_author_display_name( $forum_id );
+}
+	/**
+	 * Return the author of the forum
+	 *
+	 * @since bbPress (r3675)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_author_id() To get the forum author id
+	 * @uses get_the_author_meta() To get the display name of the author
+	 * @uses apply_filters() Calls 'bbp_get_forum_author' with the author
+	 *                        and forum id
+	 * @return string Author of forum
+	 */
+	function bbp_get_forum_author_display_name( $forum_id = 0 ) {
+		$forum_id = bbp_get_forum_id( $forum_id );
+		$author   = get_the_author_meta( 'display_name', bbp_get_forum_author_id( $forum_id ) );
+
+		return apply_filters( 'bbp_get_forum_author_display_name', $author, $forum_id );
+	}
+
+/**
+ * Output the author ID of the forum
+ *
+ * @since bbPress (r3675)
+ *
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_forum_author_id() To get the forum author id
+ */
+function bbp_forum_author_id( $forum_id = 0 ) {
+	echo bbp_get_forum_author_id( $forum_id );
+}
+	/**
+	 * Return the author ID of the forum
+	 *
+	 * @since bbPress (r3675)
+	 *
+	 * @param int $forum_id Optional. Forum id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses get_post_field() To get the forum author id
+	 * @uses apply_filters() Calls 'bbp_get_forum_author_id' with the author
+	 *                        id and forum id
+	 * @return string Author of forum
+	 */
+	function bbp_get_forum_author_id( $forum_id = 0 ) {
+		$forum_id  = bbp_get_forum_id( $forum_id );
+		$author_id = get_post_field( 'post_author', $forum_id );
+
+		return (int) apply_filters( 'bbp_get_forum_author_id', (int) $author_id, $forum_id );
+	}
+
+/**
+ * Replace forum meta details for users that cannot view them.
+ *
+ * @since bbPress (r3162)
+ *
+ * @param string $retval
+ * @param int $forum_id
+ *
+ * @uses bbp_is_forum_private()
+ * @uses current_user_can()
+ *
+ * @return string
+ */
+function bbp_suppress_private_forum_meta( $retval, $forum_id ) {
+	if ( bbp_is_forum_private( $forum_id, false ) && !current_user_can( 'read_private_forums' ) )
+		$retval = '-';
+
+	return apply_filters( 'bbp_suppress_private_forum_meta', $retval );
+}
+
+/**
+ * Replace forum author details for users that cannot view them.
+ *
+ * @since bbPress (r3162)
+ *
+ * @param string $retval
+ * @param int $forum_id
+ *
+ * @uses bbp_is_forum_private()
+ * @uses get_post_field()
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_is_forum_private()
+ * @uses bbp_get_topic_forum_id()
+ * @uses bbp_get_reply_post_type()
+ * @uses bbp_get_reply_forum_id()
+ *
+ * @return string
+ */
+function bbp_suppress_private_author_link( $author_link, $args ) {
+
+	// Assume the author link is the return value
+	$retval = $author_link;
+
+	// Show the normal author link
+	if ( !empty( $args['post_id'] ) && !current_user_can( 'read_private_forums' ) ) {
+
+		// What post type are we looking at?
+		$post_type = get_post_field( 'post_type', $args['post_id'] );
+
+		switch ( $post_type ) {
+
+			// Topic
+			case bbp_get_topic_post_type() :
+				if ( bbp_is_forum_private( bbp_get_topic_forum_id( $args['post_id'] ) ) )
+					$retval = '';
+
+				break;
+
+			// Reply
+			case bbp_get_reply_post_type() :
+				if ( bbp_is_forum_private( bbp_get_reply_forum_id( $args['post_id'] ) ) )
+					$retval = '';
+
+				break;
+
+			// Post
+			default :
+				if ( bbp_is_forum_private( $args['post_id'] ) )
+					$retval = '';
+
+				break;
+		}
+	}
+
+	return apply_filters( 'bbp_suppress_private_author_link', $retval );
+}
+
+/**
+ * Output the row class of a forum
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $forum_id Optional. Forum ID.
+ * @param array Extra classes you can pass when calling this function
+ * @uses bbp_get_forum_class() To get the row class of the forum
+ */
+function bbp_forum_class( $forum_id = 0, $classes = array() ) {
+	echo bbp_get_forum_class( $forum_id, $classes );
+}
+	/**
+	 * Return the row class of a forum
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $forum_id Optional. Forum ID
+	 * @param array Extra classes you can pass when calling this function
+	 * @uses bbp_get_forum_id() To validate the forum id
+	 * @uses bbp_is_forum_category() To see if forum is a category
+	 * @uses bbp_get_forum_status() To get the forum status
+	 * @uses bbp_get_forum_visibility() To get the forum visibility
+	 * @uses bbp_get_forum_parent_id() To get the forum parent id
+	 * @uses get_post_class() To get all the classes including ours
+	 * @uses apply_filters() Calls 'bbp_get_forum_class' with the classes
+	 * @return string Row class of the forum
+	 */
+	function bbp_get_forum_class( $forum_id = 0, $classes = array() ) {
+		$bbp       = bbpress();
+		$forum_id  = bbp_get_forum_id( $forum_id );
+		$count     = isset( $bbp->forum_query->current_post ) ? $bbp->forum_query->current_post : 1;
+		$classes   = (array) $classes;
+
+		// Get some classes
+		$classes[] = 'loop-item-' . $count;
+		$classes[] = ( (int) $count % 2 )                      ? 'even'              : 'odd';
+		$classes[] = bbp_is_forum_category( $forum_id )        ? 'status-category'   : '';
+		$classes[] = bbp_get_forum_subforum_count( $forum_id ) ? 'bbp-has-subforums' : '';
+		$classes[] = bbp_get_forum_parent_id( $forum_id )      ? 'bbp-parent-forum-' . bbp_get_forum_parent_id( $forum_id ) : '';
+		$classes[] = 'bbp-forum-status-'     . bbp_get_forum_status( $forum_id );
+		$classes[] = 'bbp-forum-visibility-' . bbp_get_forum_visibility( $forum_id );
+
+		// Ditch the empties
+		$classes   = array_filter( $classes );
+		$classes   = get_post_class( $classes, $forum_id );
+
+		// Filter the results
+		$classes   = apply_filters( 'bbp_get_forum_class', $classes, $forum_id );
+		$retval    = 'class="' . implode( ' ', $classes ) . '"';
+
+		return $retval;
+	}
+
+/** Single Forum **************************************************************/
+
+/**
+ * Output a fancy description of the current forum, including total topics,
+ * total replies, and last activity.
+ *
+ * @since bbPress (r2860)
+ *
+ * @param array $args Arguments passed to alter output
+ * @uses bbp_get_single_forum_description() Return the eventual output
+ */
+function bbp_single_forum_description( $args = '' ) {
+	echo bbp_get_single_forum_description( $args );
+}
+	/**
+	 * Return a fancy description of the current forum, including total
+	 * topics, total replies, and last activity.
+	 *
+	 * @since bbPress (r2860)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - forum_id: Forum id
+	 *  - before: Before the text
+	 *  - after: After the text
+	 *  - size: Size of the avatar
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_forum_topic_count() To get the forum topic count
+	 * @uses bbp_get_forum_reply_count() To get the forum reply count
+	 * @uses bbp_get_forum_freshness_link() To get the forum freshness link
+	 * @uses bbp_get_forum_last_active_id() To get the forum last active id
+	 * @uses bbp_get_author_link() To get the author link
+	 * @uses add_filter() To add the 'view all' filter back
+	 * @uses apply_filters() Calls 'bbp_get_single_forum_description' with
+	 *                        the description and args
+	 * @return string Filtered forum description
+	 */
+	function bbp_get_single_forum_description( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'forum_id'  => 0,
+			'before'    => '<div class="bbp-template-notice info"><p class="bbp-forum-description">',
+			'after'     => '</p></div>',
+			'size'      => 14,
+			'feed'      => true
+		), 'get_single_forum_description' );
+
+		// Validate forum_id
+		$forum_id = bbp_get_forum_id( $r['forum_id'] );
+
+		// Unhook the 'view all' query var adder
+		remove_filter( 'bbp_get_forum_permalink', 'bbp_add_view_all' );
+
+		// Get some forum data
+		$tc_int      = bbp_get_forum_topic_count( $forum_id, false );
+		$rc_int      = bbp_get_forum_reply_count( $forum_id, false );
+		$topic_count = bbp_get_forum_topic_count( $forum_id );
+		$reply_count = bbp_get_forum_reply_count( $forum_id );
+		$last_active = bbp_get_forum_last_active_id( $forum_id );
+
+		// Has replies
+		if ( !empty( $reply_count ) ) {
+			$reply_text = sprintf( _n( '%s reply', '%s replies', $rc_int, 'bbpress' ), $reply_count );
+		}
+
+		// Forum has active data
+		if ( !empty( $last_active ) ) {
+			$topic_text      = bbp_get_forum_topics_link( $forum_id );
+			$time_since      = bbp_get_forum_freshness_link( $forum_id );
+			$last_updated_by = bbp_get_author_link( array( 'post_id' => $last_active, 'size' => $r['size'] ) );
+
+		// Forum has no last active data
+		} else {
+			$topic_text      = sprintf( _n( '%s topic', '%s topics', $tc_int, 'bbpress' ), $topic_count );
+		}
+
+		// Forum has active data
+		if ( !empty( $last_active ) ) {
+
+			if ( !empty( $reply_count ) ) {
+
+				if ( bbp_is_forum_category( $forum_id ) ) {
+					$retstr = sprintf( esc_html__( 'This category contains %1$s and %2$s, and was last updated by %3$s %4$s.', 'bbpress' ), $topic_text, $reply_text, $last_updated_by, $time_since );
+				} else {
+					$retstr = sprintf( esc_html__( 'This forum contains %1$s and %2$s, and was last updated by %3$s %4$s.',    'bbpress' ), $topic_text, $reply_text, $last_updated_by, $time_since );
+				}
+
+			} else {
+
+				if ( bbp_is_forum_category( $forum_id ) ) {
+					$retstr = sprintf( esc_html__( 'This category contains %1$s, and was last updated by %2$s %3$s.', 'bbpress' ), $topic_text, $last_updated_by, $time_since );
+				} else {
+					$retstr = sprintf( esc_html__( 'This forum contains %1$s, and was last updated by %2$s %3$s.',    'bbpress' ), $topic_text, $last_updated_by, $time_since );
+				}
+			}
+
+		// Forum has no last active data
+		} else {
+
+			if ( !empty( $reply_count ) ) {
+
+				if ( bbp_is_forum_category( $forum_id ) ) {
+					$retstr = sprintf( esc_html__( 'This category contains %1$s and %2$s.', 'bbpress' ), $topic_text, $reply_text );
+				} else {
+					$retstr = sprintf( esc_html__( 'This forum contains %1$s and %2$s.',    'bbpress' ), $topic_text, $reply_text );
+				}
+
+			} else {
+
+				if ( !empty( $topic_count ) ) {
+
+					if ( bbp_is_forum_category( $forum_id ) ) {
+						$retstr = sprintf( esc_html__( 'This category contains %1$s.', 'bbpress' ), $topic_text );
+					} else {
+						$retstr = sprintf( esc_html__( 'This forum contains %1$s.',    'bbpress' ), $topic_text );
+					}
+
+				} else {
+					$retstr = esc_html__( 'This forum is empty.', 'bbpress' );
+				}
+			}
+		}
+
+		// Add feeds
+		//$feed_links = ( !empty( $r['feed'] ) ) ? bbp_get_forum_topics_feed_link ( $forum_id ) . bbp_get_forum_replies_feed_link( $forum_id ) : '';
+
+		// Add the 'view all' filter back
+		add_filter( 'bbp_get_forum_permalink', 'bbp_add_view_all' );
+
+		// Combine the elements together
+		$retstr = $r['before'] . $retstr . $r['after'];
+
+		// Return filtered result
+		return apply_filters( 'bbp_get_single_forum_description', $retstr, $r );
+	}
+
+/** Forms *********************************************************************/
+
+/**
+ * Output the value of forum title field
+ *
+ * @since bbPress (r3551)
+ *
+ * @uses bbp_get_form_forum_title() To get the value of forum title field
+ */
+function bbp_form_forum_title() {
+	echo bbp_get_form_forum_title();
+}
+	/**
+	 * Return the value of forum title field
+	 *
+	 * @since bbPress (r3551)
+	 *
+	 * @uses bbp_is_forum_edit() To check if it's forum edit page
+	 * @uses apply_filters() Calls 'bbp_get_form_forum_title' with the title
+	 * @return string Value of forum title field
+	 */
+	function bbp_get_form_forum_title() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_forum_title'] ) ) {
+			$forum_title = $_POST['bbp_forum_title'];
+
+		// Get edit data
+		} elseif ( bbp_is_forum_edit() ) {
+			$forum_title = bbp_get_global_post_field( 'post_title', 'raw' );
+
+		// No data
+		} else {
+			$forum_title = '';
+		}
+
+		return apply_filters( 'bbp_get_form_forum_title', esc_attr( $forum_title ) );
+	}
+
+/**
+ * Output the value of forum content field
+ *
+ * @since bbPress (r3551)
+ *
+ * @uses bbp_get_form_forum_content() To get value of forum content field
+ */
+function bbp_form_forum_content() {
+	echo bbp_get_form_forum_content();
+}
+	/**
+	 * Return the value of forum content field
+	 *
+	 * @since bbPress (r3551)
+	 *
+	 * @uses bbp_is_forum_edit() To check if it's the forum edit page
+	 * @uses apply_filters() Calls 'bbp_get_form_forum_content' with the content
+	 * @return string Value of forum content field
+	 */
+	function bbp_get_form_forum_content() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_forum_content'] ) ) {
+			$forum_content = stripslashes( $_POST['bbp_forum_content'] );
+
+		// Get edit data
+		} elseif ( bbp_is_forum_edit() ) {
+			$forum_content = bbp_get_global_post_field( 'post_content', 'raw' );
+
+		// No data
+		} else {
+			$forum_content = '';
+		}
+
+		return apply_filters( 'bbp_get_form_forum_content', $forum_content );
+	}
+
+/**
+ * Output value of forum parent
+ *
+ * @since bbPress (r3551)
+ *
+ * @uses bbp_get_form_forum_parent() To get the topic's forum id
+ */
+function bbp_form_forum_parent() {
+	echo bbp_get_form_forum_parent();
+}
+	/**
+	 * Return value of forum parent
+	 *
+	 * @since bbPress (r3551)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_get_forum_parent_id() To get the topic forum id
+	 * @uses apply_filters() Calls 'bbp_get_form_forum_parent' with the forum
+	 * @return string Value of topic content field
+	 */
+	function bbp_get_form_forum_parent() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_forum_id'] ) ) {
+			$forum_parent = $_POST['bbp_forum_id'];
+
+		// Get edit data
+		} elseif ( bbp_is_forum_edit() ) {
+			$forum_parent = bbp_get_forum_parent_id();
+
+		// No data
+		} else {
+			$forum_parent = 0;
+		}
+
+		return apply_filters( 'bbp_get_form_forum_parent', esc_attr( $forum_parent ) );
+	}
+
+/**
+ * Output value of forum type
+ *
+ * @since bbPress (r3563)
+ *
+ * @uses bbp_get_form_forum_type() To get the topic's forum id
+ */
+function bbp_form_forum_type() {
+	echo bbp_get_form_forum_type();
+}
+	/**
+	 * Return value of forum type
+	 *
+	 * @since bbPress (r3563)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_get_forum_type_id() To get the topic forum id
+	 * @uses apply_filters() Calls 'bbp_get_form_forum_type' with the forum
+	 * @return string Value of topic content field
+	 */
+	function bbp_get_form_forum_type() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_forum_type'] ) ) {
+			$forum_type = $_POST['bbp_forum_type'];
+
+		// Get edit data
+		} elseif ( bbp_is_forum_edit() ) {
+			$forum_type = bbp_get_forum_type();
+
+		// No data
+		} else {
+			$forum_type = 'forum';
+		}
+
+		return apply_filters( 'bbp_get_form_forum_type', esc_attr( $forum_type ) );
+	}
+
+/**
+ * Output value of forum visibility
+ *
+ * @since bbPress (r3563)
+ *
+ * @uses bbp_get_form_forum_visibility() To get the topic's forum id
+ */
+function bbp_form_forum_visibility() {
+	echo bbp_get_form_forum_visibility();
+}
+	/**
+	 * Return value of forum visibility
+	 *
+	 * @since bbPress (r3563)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_get_forum_visibility_id() To get the topic forum id
+	 * @uses apply_filters() Calls 'bbp_get_form_forum_visibility' with the forum
+	 * @return string Value of topic content field
+	 */
+	function bbp_get_form_forum_visibility() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_forum_visibility'] ) ) {
+			$forum_visibility = $_POST['bbp_forum_visibility'];
+
+		// Get edit data
+		} elseif ( bbp_is_forum_edit() ) {
+			$forum_visibility = bbp_get_forum_visibility();
+
+		// No data
+		} else {
+			$forum_visibility = bbpress()->public_status_id;
+		}
+
+		return apply_filters( 'bbp_get_form_forum_visibility', esc_attr( $forum_visibility ) );
+	}
+	
+/**
+ * Output checked value of forum subscription
+ *
+ * @since bbPress (r5156)
+ *
+ * @uses bbp_get_form_forum_subscribed() To get the subscribed checkbox value
+ */
+function bbp_form_forum_subscribed() {
+	echo bbp_get_form_forum_subscribed();
+}
+	/**
+	 * Return checked value of forum subscription
+	 *
+	 * @since bbPress (r5156)
+	 *
+	 * @uses bbp_is_forum_edit() To check if it's the forum edit page
+	 * @uses bbp_get_global_post_field() To get current post author
+	 * @uses bbp_get_current_user_id() To get the current user id
+	 * @uses bbp_is_user_subscribed_to_forum() To check if the user is
+	 *                                          subscribed to the forum
+	 * @uses apply_filters() Calls 'bbp_get_form_forum_subscribed' with the
+	 *                option
+	 * @return string Checked value of forum subscription
+	 */
+	function bbp_get_form_forum_subscribed() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_forum_subscription'] ) ) {
+			$forum_subscribed = (bool) $_POST['bbp_forum_subscription'];
+
+		// Get edit data
+		} elseif ( bbp_is_forum_edit() || bbp_is_reply_edit() ) {
+
+			// Get current posts author
+			$post_author = bbp_get_global_post_field( 'post_author', 'raw' );
+
+			// Post author is not the current user
+			if ( bbp_get_current_user_id() !== $post_author ) {
+				$forum_subscribed = bbp_is_user_subscribed_to_forum( $post_author );
+
+			// Post author is the current user
+			} else {
+				$forum_subscribed = bbp_is_user_subscribed_to_forum( bbp_get_current_user_id() );
+			}
+
+		// Get current status
+		} elseif ( bbp_is_single_forum() ) {
+			$forum_subscribed = bbp_is_user_subscribed_to_forum( bbp_get_current_user_id() );
+
+		// No data
+		} else {
+			$forum_subscribed = false;
+		}
+
+		// Get checked output
+		$checked = checked( $forum_subscribed, true, false );
+
+		return apply_filters( 'bbp_get_form_forum_subscribed', $checked, $forum_subscribed );
+	}
+
+/** Form Dropdowns ************************************************************/
+
+/**
+ * Output value forum type dropdown
+ *
+ * @since bbPress (r3563)
+ *
+ * @param int $forum_id The forum id to use
+ * @uses bbp_get_form_forum_type() To get the topic's forum id
+ */
+function bbp_form_forum_type_dropdown( $args = '' ) {
+	echo bbp_get_form_forum_type_dropdown( $args );
+}
+	/**
+	 * Return the forum type dropdown
+	 *
+	 * @since bbPress (r3563)
+	 *
+	 * @param int $forum_id The forum id to use
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_get_forum_type() To get the forum type
+	 * @uses apply_filters()
+	 * @return string HTML select list for selecting forum type
+	 */
+	function bbp_get_form_forum_type_dropdown( $args = '' ) {
+
+		// Backpat for handling passing of a forum ID as integer
+		if ( is_int( $args ) ) {
+			$forum_id = (int) $args;
+			$args     = array();
+		} else {
+			$forum_id = 0;
+		}
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'select_id'    => 'bbp_forum_type',
+			'tab'          => bbp_get_tab_index(),
+			'forum_id'     => $forum_id,
+			'selected'     => false
+		), 'forum_type_select' );
+
+		// No specific selected value passed
+		if ( empty( $r['selected'] ) ) {
+
+			// Post value is passed
+			if ( bbp_is_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
+				$r['selected'] = $_POST[ $r['select_id'] ];
+
+			// No Post value was passed
+			} else {
+
+				// Edit topic
+				if ( bbp_is_forum_edit() ) {
+					$r['forum_id'] = bbp_get_forum_id( $r['forum_id'] );
+					$r['selected'] = bbp_get_forum_type( $r['forum_id'] );
+
+				// New topic
+				} else {
+					$r['selected'] = bbp_get_public_status_id();
+				}
+			}
+		}
+
+		// Used variables
+		$tab = ! empty( $r['tab'] ) ? ' tabindex="' . (int) $r['tab'] . '"' : '';
+
+		// Start an output buffer, we'll finish it after the select loop
+		ob_start(); ?>
+
+		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ) ?>_select"<?php echo $tab; ?>>
+
+			<?php foreach ( bbp_get_forum_types() as $key => $label ) : ?>
+
+				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>
+
+			<?php endforeach; ?>
+
+		</select>
+
+		<?php
+
+		// Return the results
+		return apply_filters( 'bbp_get_form_forum_type_dropdown', ob_get_clean(), $r );
+	}
+
+/**
+ * Output value forum status dropdown
+ *
+ * @since bbPress (r3563)
+ *
+ * @param int $forum_id The forum id to use
+ * @uses bbp_get_form_forum_status() To get the topic's forum id
+ */
+function bbp_form_forum_status_dropdown( $args = '' ) {
+	echo bbp_get_form_forum_status_dropdown( $args );
+}
+	/**
+	 * Return the forum status dropdown
+	 *
+	 * @since bbPress (r3563)
+	 *
+	 * @param int $forum_id The forum id to use
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_get_forum_status() To get the forum status
+	 * @uses apply_filters()
+	 * @return string HTML select list for selecting forum status
+	 */
+	function bbp_get_form_forum_status_dropdown( $args = '' ) {
+
+		// Backpat for handling passing of a forum ID
+		if ( is_int( $args ) ) {
+			$forum_id = (int) $args;
+			$args     = array();
+		} else {
+			$forum_id = 0;
+		}
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'select_id'    => 'bbp_forum_status',
+			'tab'          => bbp_get_tab_index(),
+			'forum_id'     => $forum_id,
+			'selected'     => false
+		), 'forum_status_select' );
+
+		// No specific selected value passed
+		if ( empty( $r['selected'] ) ) {
+
+			// Post value is passed
+			if ( bbp_is_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
+				$r['selected'] = $_POST[ $r['select_id'] ];
+
+			// No Post value was passed
+			} else {
+
+				// Edit topic
+				if ( bbp_is_forum_edit() ) {
+					$r['forum_id'] = bbp_get_forum_id( $r['forum_id'] );
+					$r['selected'] = bbp_get_forum_status( $r['forum_id'] );
+
+				// New topic
+				} else {
+					$r['selected'] = bbp_get_public_status_id();
+				}
+			}
+		}
+
+		// Used variables
+		$tab = ! empty( $r['tab'] ) ? ' tabindex="' . (int) $r['tab'] . '"' : '';
+
+		// Start an output buffer, we'll finish it after the select loop
+		ob_start(); ?>
+
+		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ) ?>_select"<?php echo $tab; ?>>
+
+			<?php foreach ( bbp_get_forum_statuses() as $key => $label ) : ?>
+
+				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>
+
+			<?php endforeach; ?>
+
+		</select>
+
+		<?php
+
+		// Return the results
+		return apply_filters( 'bbp_get_form_forum_status_dropdown', ob_get_clean(), $r );
+	}
+
+/**
+ * Output value forum visibility dropdown
+ *
+ * @since bbPress (r3563)
+ *
+ * @param int $forum_id The forum id to use
+ * @uses bbp_get_form_forum_visibility() To get the topic's forum id
+ */
+function bbp_form_forum_visibility_dropdown( $args = '' ) {
+	echo bbp_get_form_forum_visibility_dropdown( $args );
+}
+	/**
+	 * Return the forum visibility dropdown
+	 *
+	 * @since bbPress (r3563)
+	 *
+	 * @param int $forum_id The forum id to use
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_get_forum_visibility() To get the forum visibility
+	 * @uses apply_filters()
+	 * @return string HTML select list for selecting forum visibility
+	 */
+	function bbp_get_form_forum_visibility_dropdown( $args = '' ) {
+
+		// Backpat for handling passing of a forum ID
+		if ( is_int( $args ) ) {
+			$forum_id = (int) $args;
+			$args     = array();
+		} else {
+			$forum_id = 0;
+		}
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'select_id'    => 'bbp_forum_visibility',
+			'tab'          => bbp_get_tab_index(),
+			'forum_id'     => $forum_id,
+			'selected'     => false
+		), 'forum_type_select' );
+
+		// No specific selected value passed
+		if ( empty( $r['selected'] ) ) {
+
+			// Post value is passed
+			if ( bbp_is_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
+				$r['selected'] = $_POST[ $r['select_id'] ];
+
+			// No Post value was passed
+			} else {
+
+				// Edit topic
+				if ( bbp_is_forum_edit() ) {
+					$r['forum_id'] = bbp_get_forum_id( $r['forum_id'] );
+					$r['selected'] = bbp_get_forum_visibility( $r['forum_id'] );
+
+				// New topic
+				} else {
+					$r['selected'] = bbp_get_public_status_id();
+				}
+			}
+		}
+
+		// Used variables
+		$tab = ! empty( $r['tab'] ) ? ' tabindex="' . (int) $r['tab'] . '"' : '';
+
+		// Start an output buffer, we'll finish it after the select loop
+		ob_start(); ?>
+
+		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ) ?>_select"<?php echo $tab; ?>>
+
+			<?php foreach ( bbp_get_forum_visibilities() as $key => $label ) : ?>
+
+				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>
+
+			<?php endforeach; ?>
+
+		</select>
+
+		<?php
+
+		// Return the results
+		return apply_filters( 'bbp_get_form_forum_type_dropdown', ob_get_clean(), $r );
+	}
+
+/** Feeds *********************************************************************/
+
+/**
+ * Output the link for the forum feed
+ *
+ * @since bbPress (r3172)
+ *
+ * @param type $forum_id Optional. Forum ID.
+ *
+ * @uses bbp_get_forum_topics_feed_link()
+ */
+function bbp_forum_topics_feed_link( $forum_id = 0 ) {
+	echo bbp_get_forum_topics_feed_link( $forum_id );
+}
+	/**
+	 * Retrieve the link for the forum feed
+	 *
+	 * @since bbPress (r3172)
+	 *
+	 * @param int $forum_id Optional. Forum ID.
+	 *
+	 * @uses bbp_get_forum_id()
+	 * @uses get_option()
+	 * @uses trailingslashit()
+	 * @uses bbp_get_forum_permalink()
+	 * @uses user_trailingslashit()
+	 * @uses bbp_get_forum_post_type()
+	 * @uses get_post_field()
+	 * @uses apply_filters()
+	 *
+	 * @return string
+	 */
+	function bbp_get_forum_topics_feed_link( $forum_id = 0 ) {
+
+		// Validate forum id
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		// Forum is valid
+		if ( !empty( $forum_id ) ) {
+
+			// Define local variable(s)
+			$link = '';
+
+			// Pretty permalinks
+			if ( get_option( 'permalink_structure' ) ) {
+
+				// Forum link
+				$url = trailingslashit( bbp_get_forum_permalink( $forum_id ) ) . 'feed';
+				$url = user_trailingslashit( $url, 'single_feed' );
+
+			// Unpretty permalinks
+			} else {
+				$url = home_url( add_query_arg( array(
+					'feed'                    => 'rss2',
+					bbp_get_forum_post_type() => get_post_field( 'post_name', $forum_id )
+				) ) );
+			}
+
+			$link = '<a href="' . esc_url( $url ) . '" class="bbp-forum-rss-link topics"><span>' . esc_attr__( 'Topics', 'bbpress' ) . '</span></a>';
+		}
+
+		return apply_filters( 'bbp_get_forum_topics_feed_link', $link, $url, $forum_id );
+	}
+
+/**
+ * Output the link for the forum replies feed
+ *
+ * @since bbPress (r3172)
+ *
+ * @param type $forum_id Optional. Forum ID.
+ *
+ * @uses bbp_get_forum_replies_feed_link()
+ */
+function bbp_forum_replies_feed_link( $forum_id = 0 ) {
+	echo bbp_get_forum_replies_feed_link( $forum_id );
+}
+	/**
+	 * Retrieve the link for the forum replies feed
+	 *
+	 * @since bbPress (r3172)
+	 *
+	 * @param int $forum_id Optional. Forum ID.
+	 *
+	 * @uses bbp_get_forum_id()
+	 * @uses get_option()
+	 * @uses trailingslashit()
+	 * @uses bbp_get_forum_permalink()
+	 * @uses user_trailingslashit()
+	 * @uses bbp_get_forum_post_type()
+	 * @uses get_post_field()
+	 * @uses apply_filters()
+	 *
+	 * @return string
+	 */
+	function bbp_get_forum_replies_feed_link( $forum_id = 0 ) {
+
+		// Validate forum id
+		$forum_id = bbp_get_forum_id( $forum_id );
+
+		// Forum is valid
+		if ( !empty( $forum_id ) ) {
+
+			// Define local variable(s)
+			$link = '';
+
+			// Pretty permalinks
+			if ( get_option( 'permalink_structure' ) ) {
+
+				// Forum link
+				$url = trailingslashit( bbp_get_forum_permalink( $forum_id ) ) . 'feed';
+				$url = user_trailingslashit( $url, 'single_feed' );
+				$url = add_query_arg( array( 'type' => 'reply' ), $url );
+
+			// Unpretty permalinks
+			} else {
+				$url = home_url( add_query_arg( array(
+					'type'                    => 'reply',
+					'feed'                    => 'rss2',
+					bbp_get_forum_post_type() => get_post_field( 'post_name', $forum_id )
+				) ) );
+			}
+
+			$link = '<a href="' . esc_url( $url ) . '" class="bbp-forum-rss-link replies"><span>' . esc_html__( 'Replies', 'bbpress' ) . '</span></a>';
+		}
+
+		return apply_filters( 'bbp_get_forum_replies_feed_link', $link, $url, $forum_id );
+	}
Index: /tags/2.5.4/includes/index.php
===================================================================
--- /tags/2.5.4/includes/index.php	(revision 5382)
+++ /tags/2.5.4/includes/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/replies/capabilities.php
===================================================================
--- /tags/2.5.4/includes/replies/capabilities.php	(revision 5382)
+++ /tags/2.5.4/includes/replies/capabilities.php	(revision 5382)
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * bbPress Reply Capabilites
+ *
+ * Used to map reply capabilities to WordPress's existing capabilities.
+ *
+ * @package bbPress
+ * @subpackage Capabilities
+ */
+
+/**
+ * Return reply capabilities
+ *
+ * @since bbPress (r2593)
+ *
+ * @uses apply_filters() Calls 'bbp_get_reply_caps' with the capabilities
+ * @return array Reply capabilities
+ */
+function bbp_get_reply_caps() {
+	return apply_filters( 'bbp_get_reply_caps', array (
+		'edit_posts'          => 'edit_replies',
+		'edit_others_posts'   => 'edit_others_replies',
+		'publish_posts'       => 'publish_replies',
+		'read_private_posts'  => 'read_private_replies',
+		'delete_posts'        => 'delete_replies',
+		'delete_others_posts' => 'delete_others_replies'
+	) );
+}
+
+/**
+ * Maps topic capabilities
+ *
+ * @since bbPress (r4242)
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ * @uses get_post() To get the post
+ * @uses get_post_type_object() To get the post type object
+ * @uses apply_filters() Filter mapped results
+ * @return array Actual capabilities for meta capability
+ */
+function bbp_map_reply_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+
+	// What capability is being checked?
+	switch ( $cap ) {
+
+		/** Reading ***********************************************************/
+
+		case 'read_reply' :
+
+			// User cannot spectate
+			if ( ! user_can( $user_id, 'spectate' ) ) {
+				$caps = array( 'do_not_allow' );
+
+			// Do some post ID based logic
+			} else {
+
+				// Get the post
+				$_post = get_post( $args[0] );
+				if ( !empty( $_post ) ) {
+
+					// Get caps for post type object
+					$post_type = get_post_type_object( $_post->post_type );
+
+					// Post is public
+					if ( bbp_get_public_status_id() === $_post->post_status ) {
+						$caps = array( 'spectate' );
+
+					// User is author so allow read
+					} elseif ( (int) $user_id === (int) $_post->post_author ) {
+						$caps = array( 'spectate' );
+
+					// Unknown so map to private posts
+					} else {
+						$caps = array( $post_type->cap->read_private_posts );
+					}
+				}
+			}
+
+			break;
+
+		/** Publishing ********************************************************/
+
+		case 'publish_replies' :
+
+			// Moderators can always publish
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( 'moderate' );
+			}
+
+			break;
+
+		/** Editing ***********************************************************/
+
+		// Used primarily in wp-admin
+		case 'edit_replies'        :
+		case 'edit_others_replies' :
+
+			// Moderators can always edit
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( 'moderate' );
+
+			// Otherwise, block
+			} else {
+				$caps = array( 'do_not_allow' );
+			}
+
+			break;
+
+		// Used everywhere
+		case 'edit_reply' :
+
+			// Get the post
+			$_post = get_post( $args[0] );
+			if ( !empty( $_post ) ) {
+
+				// Get caps for post type object
+				$post_type = get_post_type_object( $_post->post_type );
+				$caps      = array();
+
+				// Add 'do_not_allow' cap if user is spam or deleted
+				if ( bbp_is_user_inactive( $user_id ) ) {
+					$caps[] = 'do_not_allow';
+
+				// User is author so allow edit if not in admin
+				} elseif ( !is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
+					$caps[] = $post_type->cap->edit_posts;
+
+				// Unknown, so map to edit_others_posts
+				} else {
+					$caps[] = $post_type->cap->edit_others_posts;
+				}
+			}
+
+			break;
+
+		/** Deleting **********************************************************/
+
+		case 'delete_reply' :
+
+			// Get the post
+			$_post = get_post( $args[0] );
+			if ( !empty( $_post ) ) {
+
+				// Get caps for post type object
+				$post_type = get_post_type_object( $_post->post_type );
+				$caps      = array();
+
+				// Add 'do_not_allow' cap if user is spam or deleted
+				if ( bbp_is_user_inactive( $user_id ) ) {
+					$caps[] = 'do_not_allow';
+
+				// Moderators can always edit forum content
+				} elseif ( user_can( $user_id, 'moderate' ) ) {
+					$caps[] = 'moderate';
+
+				// Unknown so map to delete_others_posts
+				} else {
+					$caps[] = $post_type->cap->delete_others_posts;
+				}
+			}
+
+			break;
+
+		// Moderation override
+		case 'delete_replies'        :
+		case 'delete_others_replies' :
+
+			// Moderators can always delete
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( 'moderate' );
+			}
+
+			break;
+
+		/** Admin *************************************************************/
+
+		case 'bbp_replies_admin' :
+			$caps = array( 'moderate' );
+			break;
+	}
+
+	return apply_filters( 'bbp_map_reply_meta_caps', $caps, $cap, $user_id, $args );
+}
Index: /tags/2.5.4/includes/replies/functions.php
===================================================================
--- /tags/2.5.4/includes/replies/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/replies/functions.php	(revision 5382)
@@ -0,0 +1,2250 @@
+<?php
+
+/**
+ * bbPress Reply Functions
+ *
+ * @package bbPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Insert ********************************************************************/
+
+/**
+ * A wrapper for wp_insert_post() that also includes the necessary meta values
+ * for the reply to function properly.
+ *
+ * @since bbPress (r3349)
+ *
+ * @uses bbp_parse_args()
+ * @uses bbp_get_reply_post_type()
+ * @uses wp_insert_post()
+ * @uses update_post_meta()
+ *
+ * @param array $reply_data Forum post data
+ * @param arrap $reply_meta Forum meta data
+ */
+function bbp_insert_reply( $reply_data = array(), $reply_meta = array() ) {
+
+	// Forum
+	$reply_data = bbp_parse_args( $reply_data, array(
+		'post_parent'    => 0, // topic ID
+		'post_status'    => bbp_get_public_status_id(),
+		'post_type'      => bbp_get_reply_post_type(),
+		'post_author'    => bbp_get_current_user_id(),
+		'post_password'  => '',
+		'post_content'   => '',
+		'post_title'     => '',
+		'menu_order'     => 0,
+		'comment_status' => 'closed'
+	), 'insert_reply' );
+
+	// Insert reply
+	$reply_id   = wp_insert_post( $reply_data );
+
+	// Bail if no reply was added
+	if ( empty( $reply_id ) ) {
+		return false;
+	}
+
+	// Forum meta
+	$reply_meta = bbp_parse_args( $reply_meta, array(
+		'author_ip' => bbp_current_author_ip(),
+		'forum_id'  => 0,
+		'topic_id'  => 0,
+	), 'insert_reply_meta' );
+
+	// Insert reply meta
+	foreach ( $reply_meta as $meta_key => $meta_value ) {
+		update_post_meta( $reply_id, '_bbp_' . $meta_key, $meta_value );
+	}
+
+	// Update the topic
+	$topic_id = bbp_get_reply_topic_id( $reply_id );
+	if ( !empty( $topic_id ) ) {
+		bbp_update_topic( $topic_id );
+	}
+
+	// Return new reply ID
+	return $reply_id;
+}
+
+/** Post Form Handlers ********************************************************/
+
+/**
+ * Handles the front end reply submission
+ *
+ * @since bbPress (r2574)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses bbp_is_anonymous() To check if an anonymous post is being made
+ * @uses current_user_can() To check if the current user can publish replies
+ * @uses bbp_get_current_user_id() To get the current user id
+ * @uses bbp_filter_anonymous_post_data() To filter anonymous data
+ * @uses bbp_set_current_anonymous_user_data() To set the anonymous user
+ *                                                cookies
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses remove_filter() To remove kses filters if needed
+ * @uses esc_attr() For sanitization
+ * @uses bbp_check_for_flood() To check for flooding
+ * @uses bbp_check_for_duplicate() To check for duplicates
+ * @uses apply_filters() Calls 'bbp_new_reply_pre_title' with the title
+ * @uses apply_filters() Calls 'bbp_new_reply_pre_content' with the content
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wp_set_post_terms() To set the topic tags
+ * @uses wp_insert_post() To insert the reply
+ * @uses do_action() Calls 'bbp_new_reply' with the reply id, topic id, forum
+ *                    id, anonymous data, reply author, edit (false), and
+ *                    the reply to id
+ * @uses bbp_get_reply_url() To get the paginated url to the reply
+ * @uses wp_safe_redirect() To redirect to the reply url
+ * @uses bbPress::errors::get_error_message() To get the {@link WP_Error} error
+ *                                              message
+ */
+function bbp_new_reply_handler( $action = '' ) {
+
+	// Bail if action is not bbp-new-reply
+	if ( 'bbp-new-reply' !== $action )
+		return;
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'bbp-new-reply' ) ) {
+		bbp_add_error( 'bbp_new_reply_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Define local variable(s)
+	$topic_id = $forum_id = $reply_author = $anonymous_data = $reply_to = 0;
+	$reply_title = $reply_content = $terms = '';
+
+	/** Reply Author **********************************************************/
+
+	// User is anonymous
+	if ( bbp_is_anonymous() ) {
+
+		// Filter anonymous data
+		$anonymous_data = bbp_filter_anonymous_post_data();
+
+		// Anonymous data checks out, so set cookies, etc...
+		if ( !empty( $anonymous_data ) && is_array( $anonymous_data ) ) {
+			bbp_set_current_anonymous_user_data( $anonymous_data );
+		}
+
+	// User is logged in
+	} else {
+
+		// User cannot create replies
+		if ( !current_user_can( 'publish_replies' ) ) {
+			bbp_add_error( 'bbp_reply_permissions', __( '<strong>ERROR</strong>: You do not have permission to reply.', 'bbpress' ) );
+		}
+
+		// Reply author is current user
+		$reply_author = bbp_get_current_user_id();
+
+	}
+
+	/** Topic ID **************************************************************/
+
+	// Topic id was not passed
+	if ( empty( $_POST['bbp_topic_id'] ) ) {
+		bbp_add_error( 'bbp_reply_topic_id', __( '<strong>ERROR</strong>: Topic ID is missing.', 'bbpress' ) );
+
+	// Topic id is not a number
+	} elseif ( ! is_numeric( $_POST['bbp_topic_id'] ) ) {
+		bbp_add_error( 'bbp_reply_topic_id', __( '<strong>ERROR</strong>: Topic ID must be a number.', 'bbpress' ) );
+
+	// Topic id might be valid
+	} else {
+
+		// Get the topic id
+		$posted_topic_id = intval( $_POST['bbp_topic_id'] );
+
+		// Topic id is a negative number
+		if ( 0 > $posted_topic_id ) {
+			bbp_add_error( 'bbp_reply_topic_id', __( '<strong>ERROR</strong>: Topic ID cannot be a negative number.', 'bbpress' ) );
+
+		// Topic does not exist
+		} elseif ( ! bbp_get_topic( $posted_topic_id ) ) {
+			bbp_add_error( 'bbp_reply_topic_id', __( '<strong>ERROR</strong>: Topic does not exist.', 'bbpress' ) );
+
+		// Use the POST'ed topic id
+		} else {
+			$topic_id = $posted_topic_id;
+		}
+	}
+
+	/** Forum ID **************************************************************/
+
+	// Try to use the forum id of the topic
+	if ( !isset( $_POST['bbp_forum_id'] ) && !empty( $topic_id ) ) {
+		$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+	// Error check the POST'ed forum id
+	} elseif ( isset( $_POST['bbp_forum_id'] ) ) {
+
+		// Empty Forum id was passed
+		if ( empty( $_POST['bbp_forum_id'] ) ) {
+			bbp_add_error( 'bbp_reply_forum_id', __( '<strong>ERROR</strong>: Forum ID is missing.', 'bbpress' ) );
+
+		// Forum id is not a number
+		} elseif ( ! is_numeric( $_POST['bbp_forum_id'] ) ) {
+			bbp_add_error( 'bbp_reply_forum_id', __( '<strong>ERROR</strong>: Forum ID must be a number.', 'bbpress' ) );
+
+		// Forum id might be valid
+		} else {
+
+			// Get the forum id
+			$posted_forum_id = intval( $_POST['bbp_forum_id'] );
+
+			// Forum id is empty
+			if ( 0 === $posted_forum_id ) {
+				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID is missing.', 'bbpress' ) );
+
+			// Forum id is a negative number
+			} elseif ( 0 > $posted_forum_id ) {
+				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID cannot be a negative number.', 'bbpress' ) );
+
+			// Forum does not exist
+			} elseif ( ! bbp_get_forum( $posted_forum_id ) ) {
+				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum does not exist.', 'bbpress' ) );
+
+			// Use the POST'ed forum id
+			} else {
+				$forum_id = $posted_forum_id;
+			}
+		}
+	}
+
+	// Forum exists
+	if ( !empty( $forum_id ) ) {
+
+		// Forum is a category
+		if ( bbp_is_forum_category( $forum_id ) ) {
+			bbp_add_error( 'bbp_new_reply_forum_category', __( '<strong>ERROR</strong>: This forum is a category. No replies can be created in this forum.', 'bbpress' ) );
+
+		// Forum is not a category
+		} else {
+
+			// Forum is closed and user cannot access
+			if ( bbp_is_forum_closed( $forum_id ) && !current_user_can( 'edit_forum', $forum_id ) ) {
+				bbp_add_error( 'bbp_new_reply_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new replies.', 'bbpress' ) );
+			}
+
+			// Forum is private and user cannot access
+			if ( bbp_is_forum_private( $forum_id ) ) {
+				if ( !current_user_can( 'read_private_forums' ) ) {
+					bbp_add_error( 'bbp_new_reply_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new replies in it.', 'bbpress' ) );
+				}
+
+			// Forum is hidden and user cannot access
+			} elseif ( bbp_is_forum_hidden( $forum_id ) ) {
+				if ( !current_user_can( 'read_hidden_forums' ) ) {
+					bbp_add_error( 'bbp_new_reply_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new replies in it.', 'bbpress' ) );
+				}
+			}
+		}
+	}
+
+	/** Unfiltered HTML *******************************************************/
+
+	// Remove kses filters from title and content for capable users and if the nonce is verified
+	if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_reply'] ) && wp_create_nonce( 'bbp-unfiltered-html-reply_' . $topic_id ) === $_POST['_bbp_unfiltered_html_reply'] ) {
+		remove_filter( 'bbp_new_reply_pre_title',   'wp_filter_kses'      );
+		remove_filter( 'bbp_new_reply_pre_content', 'bbp_encode_bad',  10 );
+		remove_filter( 'bbp_new_reply_pre_content', 'bbp_filter_kses', 30 );
+	}
+
+	/** Reply Title ***********************************************************/
+
+	if ( !empty( $_POST['bbp_reply_title'] ) )
+		$reply_title = esc_attr( strip_tags( $_POST['bbp_reply_title'] ) );
+
+	// Filter and sanitize
+	$reply_title = apply_filters( 'bbp_new_reply_pre_title', $reply_title );
+
+	/** Reply Content *********************************************************/
+
+	if ( !empty( $_POST['bbp_reply_content'] ) )
+		$reply_content = $_POST['bbp_reply_content'];
+
+	// Filter and sanitize
+	$reply_content = apply_filters( 'bbp_new_reply_pre_content', $reply_content );
+
+	// No reply content
+	if ( empty( $reply_content ) )
+		bbp_add_error( 'bbp_reply_content', __( '<strong>ERROR</strong>: Your reply cannot be empty.', 'bbpress' ) );
+
+	/** Reply Flooding ********************************************************/
+
+	if ( !bbp_check_for_flood( $anonymous_data, $reply_author ) )
+		bbp_add_error( 'bbp_reply_flood', __( '<strong>ERROR</strong>: Slow down; you move too fast.', 'bbpress' ) );
+
+	/** Reply Duplicate *******************************************************/
+
+	if ( !bbp_check_for_duplicate( array( 'post_type' => bbp_get_reply_post_type(), 'post_author' => $reply_author, 'post_content' => $reply_content, 'post_parent' => $topic_id, 'anonymous_data' => $anonymous_data ) ) )
+		bbp_add_error( 'bbp_reply_duplicate', __( '<strong>ERROR</strong>: Duplicate reply detected; it looks as though you&#8217;ve already said that!', 'bbpress' ) );
+
+	/** Reply Blacklist *******************************************************/
+
+	if ( !bbp_check_for_blacklist( $anonymous_data, $reply_author, $reply_title, $reply_content ) )
+		bbp_add_error( 'bbp_reply_blacklist', __( '<strong>ERROR</strong>: Your reply cannot be created at this time.', 'bbpress' ) );
+
+	/** Reply Status **********************************************************/
+
+	// Maybe put into moderation
+	if ( !bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content ) ) {
+		$reply_status = bbp_get_pending_status_id();
+
+	// Default
+	} else {
+		$reply_status = bbp_get_public_status_id();
+	}
+
+	/** Reply To **************************************************************/
+
+	// Handle Reply To of the reply; $_REQUEST for non-JS submissions
+	if ( isset( $_REQUEST['bbp_reply_to'] ) ) {
+		$reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'] );
+	}
+
+	/** Topic Closed **********************************************************/
+
+	// If topic is closed, moderators can still reply
+	if ( bbp_is_topic_closed( $topic_id ) && ! current_user_can( 'moderate' ) ) {
+		bbp_add_error( 'bbp_reply_topic_closed', __( '<strong>ERROR</strong>: Topic is closed.', 'bbpress' ) );
+	}
+
+	/** Topic Tags ************************************************************/
+
+	// Either replace terms
+	if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags' ) && ! empty( $_POST['bbp_topic_tags'] ) ) {
+		$terms = esc_attr( strip_tags( $_POST['bbp_topic_tags'] ) );
+
+	// ...or remove them.
+	} elseif ( isset( $_POST['bbp_topic_tags'] ) ) {
+		$terms = '';
+
+	// Existing terms
+	} else {
+		$terms = bbp_get_topic_tag_names( $topic_id );
+	}
+
+	/** Additional Actions (Before Save) **************************************/
+
+	do_action( 'bbp_new_reply_pre_extras', $topic_id, $forum_id );
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors *************************************************************/
+
+	// Add the content of the form to $reply_data as an array
+	// Just in time manipulation of reply data before being created
+	$reply_data = apply_filters( 'bbp_new_reply_pre_insert', array(
+		'post_author'    => $reply_author,
+		'post_title'     => $reply_title,
+		'post_content'   => $reply_content,
+		'post_status'    => $reply_status,
+		'post_parent'    => $topic_id,
+		'post_type'      => bbp_get_reply_post_type(),
+		'comment_status' => 'closed',
+		'menu_order'     => bbp_get_topic_reply_count( $topic_id, false ) + 1
+	) );
+
+	// Insert reply
+	$reply_id = wp_insert_post( $reply_data );
+
+	/** No Errors *************************************************************/
+
+	// Check for missing reply_id or error
+	if ( !empty( $reply_id ) && !is_wp_error( $reply_id ) ) {
+
+		/** Topic Tags ********************************************************/
+
+		// Just in time manipulation of reply terms before being edited
+		$terms = apply_filters( 'bbp_new_reply_pre_set_terms', $terms, $topic_id, $reply_id );
+
+		// Insert terms
+		$terms = wp_set_post_terms( $topic_id, $terms, bbp_get_topic_tag_tax_id(), false );
+
+		// Term error
+		if ( is_wp_error( $terms ) ) {
+			bbp_add_error( 'bbp_reply_tags', __( '<strong>ERROR</strong>: There was a problem adding the tags to the topic.', 'bbpress' ) );
+		}
+
+		/** Trash Check *******************************************************/
+
+		// If this reply starts as trash, add it to pre_trashed_replies
+		// for the topic, so it is properly restored.
+		if ( bbp_is_topic_trash( $topic_id ) || ( $reply_data['post_status'] === bbp_get_trash_status_id() ) ) {
+
+			// Trash the reply
+			wp_trash_post( $reply_id );
+
+			// Only add to pre-trashed array if topic is trashed
+			if ( bbp_is_topic_trash( $topic_id ) ) {
+
+				// Get pre_trashed_replies for topic
+				$pre_trashed_replies = get_post_meta( $topic_id, '_bbp_pre_trashed_replies', true );
+
+				// Add this reply to the end of the existing replies
+				$pre_trashed_replies[] = $reply_id;
+
+				// Update the pre_trashed_reply post meta
+				update_post_meta( $topic_id, '_bbp_pre_trashed_replies', $pre_trashed_replies );
+			}
+
+		/** Spam Check ********************************************************/
+
+		// If reply or topic are spam, officially spam this reply
+		} elseif ( bbp_is_topic_spam( $topic_id ) || ( $reply_data['post_status'] === bbp_get_spam_status_id() ) ) {
+			add_post_meta( $reply_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );
+
+			// Only add to pre-spammed array if topic is spam
+			if ( bbp_is_topic_spam( $topic_id ) ) {
+
+				// Get pre_spammed_replies for topic
+				$pre_spammed_replies = get_post_meta( $topic_id, '_bbp_pre_spammed_replies', true );
+
+				// Add this reply to the end of the existing replies
+				$pre_spammed_replies[] = $reply_id;
+
+				// Update the pre_spammed_replies post meta
+				update_post_meta( $topic_id, '_bbp_pre_spammed_replies', $pre_spammed_replies );
+			}
+		}
+
+		/** Update counts, etc... *********************************************/
+
+		do_action( 'bbp_new_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author, false, $reply_to );
+
+		/** Additional Actions (After Save) ***********************************/
+
+		do_action( 'bbp_new_reply_post_extras', $reply_id );
+
+		/** Redirect **********************************************************/
+
+		// Redirect to
+		$redirect_to = bbp_get_redirect_to();
+
+		// Get the reply URL
+		$reply_url = bbp_get_reply_url( $reply_id, $redirect_to );
+
+		// Allow to be filtered
+		$reply_url = apply_filters( 'bbp_new_reply_redirect_to', $reply_url, $redirect_to, $reply_id );
+
+		/** Successful Save ***************************************************/
+
+		// Redirect back to new reply
+		wp_safe_redirect( $reply_url );
+
+		// For good measure
+		exit();
+
+	/** Errors ****************************************************************/
+
+	} else {
+		$append_error = ( is_wp_error( $reply_id ) && $reply_id->get_error_message() ) ? $reply_id->get_error_message() . ' ' : '';
+		bbp_add_error( 'bbp_reply_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your reply:' . $append_error . 'Please try again.', 'bbpress' ) );
+	}
+}
+
+/**
+ * Handles the front end edit reply submission
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_get_reply() To get the reply
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses bbp_is_reply_anonymous() To check if the reply was by an anonymous user
+ * @uses current_user_can() To check if the current user can edit that reply
+ * @uses bbp_filter_anonymous_post_data() To filter anonymous data
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses remove_filter() To remove kses filters if needed
+ * @uses esc_attr() For sanitization
+ * @uses apply_filters() Calls 'bbp_edit_reply_pre_title' with the title and
+ *                       reply id
+ * @uses apply_filters() Calls 'bbp_edit_reply_pre_content' with the content
+ *                        reply id
+ * @uses wp_set_post_terms() To set the topic tags
+ * @uses bbp_has_errors() To get the {@link WP_Error} errors
+ * @uses wp_save_post_revision() To save a reply revision
+ * @uses bbp_update_reply_revision_log() To update the reply revision log
+ * @uses wp_update_post() To update the reply
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_get_reply_to() To get the reply to id
+ * @uses do_action() Calls 'bbp_edit_reply' with the reply id, topic id, forum
+ *                    id, anonymous data, reply author, bool true (for edit),
+ *                    and the reply to id
+ * @uses bbp_get_reply_url() To get the paginated url to the reply
+ * @uses wp_safe_redirect() To redirect to the reply url
+ * @uses bbPress::errors::get_error_message() To get the {@link WP_Error} error
+ *                                             message
+ */
+function bbp_edit_reply_handler( $action = '' ) {
+
+	// Bail if action is not bbp-edit-reply
+	if ( 'bbp-edit-reply' !== $action )
+		return;
+
+	// Define local variable(s)
+	$revisions_removed = false;
+	$reply = $reply_id = $reply_author = $topic_id = $forum_id = $anonymous_data = 0;
+	$reply_title = $reply_content = $reply_edit_reason = $terms = '';
+
+	/** Reply *****************************************************************/
+
+	// Reply id was not passed
+	if ( empty( $_POST['bbp_reply_id'] ) ) {
+		bbp_add_error( 'bbp_edit_reply_id', __( '<strong>ERROR</strong>: Reply ID not found.', 'bbpress' ) );
+		return;
+
+	// Reply id was passed
+	} elseif ( is_numeric( $_POST['bbp_reply_id'] ) ) {
+		$reply_id = (int) $_POST['bbp_reply_id'];
+		$reply    = bbp_get_reply( $reply_id );
+	}
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'bbp-edit-reply_' . $reply_id ) ) {
+		bbp_add_error( 'bbp_edit_reply_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Reply does not exist
+	if ( empty( $reply ) ) {
+		bbp_add_error( 'bbp_edit_reply_not_found', __( '<strong>ERROR</strong>: The reply you want to edit was not found.', 'bbpress' ) );
+		return;
+
+	// Reply exists
+	} else {
+
+		// Check users ability to create new reply
+		if ( ! bbp_is_reply_anonymous( $reply_id ) ) {
+
+			// User cannot edit this reply
+			if ( !current_user_can( 'edit_reply', $reply_id ) ) {
+				bbp_add_error( 'bbp_edit_reply_permissions', __( '<strong>ERROR</strong>: You do not have permission to edit that reply.', 'bbpress' ) );
+				return;
+			}
+
+			// Set reply author
+			$reply_author = bbp_get_reply_author_id( $reply_id );
+
+		// It is an anonymous post
+		} else {
+
+			// Filter anonymous data
+			$anonymous_data = bbp_filter_anonymous_post_data();
+		}
+	}
+
+	// Remove kses filters from title and content for capable users and if the nonce is verified
+	if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_reply'] ) && wp_create_nonce( 'bbp-unfiltered-html-reply_' . $reply_id ) === $_POST['_bbp_unfiltered_html_reply'] ) {
+		remove_filter( 'bbp_edit_reply_pre_title',   'wp_filter_kses'      );
+		remove_filter( 'bbp_edit_reply_pre_content', 'bbp_encode_bad',  10 );
+		remove_filter( 'bbp_edit_reply_pre_content', 'bbp_filter_kses', 30 );
+	}
+
+	/** Reply Topic ***********************************************************/
+
+	$topic_id = bbp_get_reply_topic_id( $reply_id );
+
+	/** Topic Forum ***********************************************************/
+
+	$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+	// Forum exists
+	if ( !empty( $forum_id ) && ( $forum_id !== bbp_get_reply_forum_id( $reply_id ) ) ) {
+
+		// Forum is a category
+		if ( bbp_is_forum_category( $forum_id ) ) {
+			bbp_add_error( 'bbp_edit_reply_forum_category', __( '<strong>ERROR</strong>: This forum is a category. No replies can be created in this forum.', 'bbpress' ) );
+
+		// Forum is not a category
+		} else {
+
+			// Forum is closed and user cannot access
+			if ( bbp_is_forum_closed( $forum_id ) && !current_user_can( 'edit_forum', $forum_id ) ) {
+				bbp_add_error( 'bbp_edit_reply_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new replies.', 'bbpress' ) );
+			}
+
+			// Forum is private and user cannot access
+			if ( bbp_is_forum_private( $forum_id ) ) {
+				if ( !current_user_can( 'read_private_forums' ) ) {
+					bbp_add_error( 'bbp_edit_reply_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new replies in it.', 'bbpress' ) );
+				}
+
+			// Forum is hidden and user cannot access
+			} elseif ( bbp_is_forum_hidden( $forum_id ) ) {
+				if ( !current_user_can( 'read_hidden_forums' ) ) {
+					bbp_add_error( 'bbp_edit_reply_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new replies in it.', 'bbpress' ) );
+				}
+			}
+		}
+	}
+
+	/** Reply Title ***********************************************************/
+
+	if ( !empty( $_POST['bbp_reply_title'] ) )
+		$reply_title = esc_attr( strip_tags( $_POST['bbp_reply_title'] ) );
+
+	// Filter and sanitize
+	$reply_title = apply_filters( 'bbp_edit_reply_pre_title', $reply_title, $reply_id );
+
+	/** Reply Content *********************************************************/
+
+	if ( !empty( $_POST['bbp_reply_content'] ) )
+		$reply_content = $_POST['bbp_reply_content'];
+
+	// Filter and sanitize
+	$reply_content = apply_filters( 'bbp_edit_reply_pre_content', $reply_content, $reply_id );
+
+	// No reply content
+	if ( empty( $reply_content ) )
+		bbp_add_error( 'bbp_edit_reply_content', __( '<strong>ERROR</strong>: Your reply cannot be empty.', 'bbpress' ) );
+
+	/** Reply Blacklist *******************************************************/
+
+	if ( !bbp_check_for_blacklist( $anonymous_data, $reply_author, $reply_title, $reply_content ) )
+		bbp_add_error( 'bbp_reply_blacklist', __( '<strong>ERROR</strong>: Your reply cannot be edited at this time.', 'bbpress' ) );
+
+	/** Reply Status **********************************************************/
+
+	// Maybe put into moderation
+	if ( !bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content ) ) {
+
+		// Set post status to pending if public
+		if ( bbp_get_public_status_id() === $reply->post_status ) {
+			$reply_status = bbp_get_pending_status_id();
+		}
+
+	// Use existing post_status
+	} else {
+		$reply_status = $reply->post_status;
+	}
+
+	/** Reply To **************************************************************/
+
+	// Handle Reply To of the reply; $_REQUEST for non-JS submissions
+	if ( isset( $_REQUEST['bbp_reply_to'] ) ) {
+		$reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'] );
+	}
+
+	/** Topic Tags ************************************************************/
+
+	// Either replace terms
+	if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags' ) && ! empty( $_POST['bbp_topic_tags'] ) ) {
+		$terms = esc_attr( strip_tags( $_POST['bbp_topic_tags'] ) );
+
+	// ...or remove them.
+	} elseif ( isset( $_POST['bbp_topic_tags'] ) ) {
+		$terms = '';
+
+	// Existing terms
+	} else {
+		$terms = bbp_get_topic_tag_names( $topic_id );
+	}
+
+	/** Additional Actions (Before Save) **************************************/
+
+	do_action( 'bbp_edit_reply_pre_extras', $reply_id );
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors *************************************************************/
+
+	// Add the content of the form to $reply_data as an array
+	// Just in time manipulation of reply data before being edited
+	$reply_data = apply_filters( 'bbp_edit_reply_pre_insert', array(
+		'ID'           => $reply_id,
+		'post_title'   => $reply_title,
+		'post_content' => $reply_content,
+		'post_status'  => $reply_status,
+		'post_parent'  => $topic_id,
+		'post_author'  => $reply_author,
+		'post_type'    => bbp_get_reply_post_type()
+	) );
+
+	// Toggle revisions to avoid duplicates
+	if ( post_type_supports( bbp_get_reply_post_type(), 'revisions' ) ) {
+		$revisions_removed = true;
+		remove_post_type_support( bbp_get_reply_post_type(), 'revisions' );
+	}
+
+	// Insert topic
+	$reply_id = wp_update_post( $reply_data );
+
+	// Toggle revisions back on
+	if ( true === $revisions_removed ) {
+		$revisions_removed = false;
+		add_post_type_support( bbp_get_reply_post_type(), 'revisions' );
+	}
+
+	/** Topic Tags ************************************************************/
+
+	// Just in time manipulation of reply terms before being edited
+	$terms = apply_filters( 'bbp_edit_reply_pre_set_terms', $terms, $topic_id, $reply_id );
+
+	// Insert terms
+	$terms = wp_set_post_terms( $topic_id, $terms, bbp_get_topic_tag_tax_id(), false );
+
+	// Term error
+	if ( is_wp_error( $terms ) ) {
+		bbp_add_error( 'bbp_reply_tags', __( '<strong>ERROR</strong>: There was a problem adding the tags to the topic.', 'bbpress' ) );
+	}
+
+	/** Revisions *************************************************************/
+
+	// Revision Reason
+	if ( !empty( $_POST['bbp_reply_edit_reason'] ) )
+		$reply_edit_reason = esc_attr( strip_tags( $_POST['bbp_reply_edit_reason'] ) );
+
+	// Update revision log
+	if ( !empty( $_POST['bbp_log_reply_edit'] ) && ( "1" === $_POST['bbp_log_reply_edit'] ) ) {
+		$revision_id = wp_save_post_revision( $reply_id );
+		if ( !empty( $revision_id ) ) {
+			bbp_update_reply_revision_log( array(
+				'reply_id'    => $reply_id,
+				'revision_id' => $revision_id,
+				'author_id'   => bbp_get_current_user_id(),
+				'reason'      => $reply_edit_reason
+			) );
+		}
+	}
+
+	/** No Errors *************************************************************/
+
+	if ( !empty( $reply_id ) && !is_wp_error( $reply_id ) ) {
+
+		// Update counts, etc...
+		do_action( 'bbp_edit_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author , true, $reply_to );
+
+		/** Additional Actions (After Save) ***********************************/
+
+		do_action( 'bbp_edit_reply_post_extras', $reply_id );
+
+		/** Redirect **********************************************************/
+
+		// Redirect to
+		$redirect_to = bbp_get_redirect_to();
+
+		// Get the reply URL
+		$reply_url = bbp_get_reply_url( $reply_id, $redirect_to );
+
+		// Allow to be filtered
+		$reply_url = apply_filters( 'bbp_edit_reply_redirect_to', $reply_url, $redirect_to );
+
+		/** Successful Edit ***************************************************/
+
+		// Redirect back to new reply
+		wp_safe_redirect( $reply_url );
+
+		// For good measure
+		exit();
+
+	/** Errors ****************************************************************/
+
+	} else {
+		$append_error = ( is_wp_error( $reply_id ) && $reply_id->get_error_message() ) ? $reply_id->get_error_message() . ' ' : '';
+		bbp_add_error( 'bbp_reply_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your reply:' . $append_error . 'Please try again.', 'bbpress' ) );
+	}
+}
+
+/**
+ * Handle all the extra meta stuff from posting a new reply or editing a reply
+ *
+ * @param int $reply_id Optional. Reply id
+ * @param int $topic_id Optional. Topic id
+ * @param int $forum_id Optional. Forum id
+ * @param bool|array $anonymous_data Optional logged-out user data.
+ * @param int $author_id Author id
+ * @param bool $is_edit Optional. Is the post being edited? Defaults to false.
+ * @param int $reply_to Optional. Reply to id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_current_user_id() To get the current user id
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses update_post_meta() To update the reply metas
+ * @uses set_transient() To update the flood check transient for the ip
+ * @uses bbp_update_user_last_posted() To update the users last posted time
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions feature is
+ *                                      activated or not
+ * @uses bbp_is_user_subscribed() To check if the user is subscribed
+ * @uses bbp_remove_user_subscription() To remove the user's subscription
+ * @uses bbp_add_user_subscription() To add the user's subscription
+ * @uses bbp_update_reply_forum_id() To update the reply forum id
+ * @uses bbp_update_reply_topic_id() To update the reply topic id
+ * @uses bbp_update_reply_to() To update the reply to id
+ * @uses bbp_update_reply_walker() To update the reply's ancestors' counts
+ */
+function bbp_update_reply( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = false, $author_id = 0, $is_edit = false, $reply_to = 0 ) {
+
+	// Validate the ID's passed from 'bbp_new_reply' action
+	$reply_id = bbp_get_reply_id( $reply_id );
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$forum_id = bbp_get_forum_id( $forum_id );
+	$reply_to = bbp_validate_reply_to( $reply_to );
+
+	// Bail if there is no reply
+	if ( empty( $reply_id ) )
+		return;
+
+	// Check author_id
+	if ( empty( $author_id ) )
+		$author_id = bbp_get_current_user_id();
+
+	// Check topic_id
+	if ( empty( $topic_id ) )
+		$topic_id = bbp_get_reply_topic_id( $reply_id );
+
+	// Check forum_id
+	if ( !empty( $topic_id ) && empty( $forum_id ) )
+		$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+	// If anonymous post, store name, email, website and ip in post_meta.
+	// It expects anonymous_data to be sanitized.
+	// Check bbp_filter_anonymous_post_data() for sanitization.
+	if ( !empty( $anonymous_data ) && is_array( $anonymous_data ) ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $anonymous_data, array(
+			'bbp_anonymous_name'    => '',
+			'bbp_anonymous_email'   => '',
+			'bbp_anonymous_website' => '',
+		), 'update_reply' );
+
+		// Update all anonymous metas
+		foreach ( $r as $anon_key => $anon_value ) {
+			update_post_meta( $reply_id, '_' . $anon_key, (string) $anon_value, false );
+		}
+
+		// Set transient for throttle check (only on new, not edit)
+		if ( empty( $is_edit ) ) {
+			set_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted', time() );
+		}
+
+	} else {
+		if ( empty( $is_edit ) && !current_user_can( 'throttle' ) ) {
+			bbp_update_user_last_posted( $author_id );
+		}
+	}
+
+	// Handle Subscription Checkbox
+	if ( bbp_is_subscriptions_active() && !empty( $author_id ) && !empty( $topic_id ) ) {
+		$subscribed = bbp_is_user_subscribed( $author_id, $topic_id );
+		$subscheck  = ( !empty( $_POST['bbp_topic_subscription'] ) && ( 'bbp_subscribe' === $_POST['bbp_topic_subscription'] ) ) ? true : false;
+
+		// Subscribed and unsubscribing
+		if ( true === $subscribed && false === $subscheck ) {
+			bbp_remove_user_subscription( $author_id, $topic_id );
+
+		// Subscribing
+		} elseif ( false === $subscribed && true === $subscheck ) {
+			bbp_add_user_subscription( $author_id, $topic_id );
+		}
+	}
+
+	// Reply meta relating to reply position in tree
+	bbp_update_reply_forum_id( $reply_id, $forum_id );
+	bbp_update_reply_topic_id( $reply_id, $topic_id );
+	bbp_update_reply_to      ( $reply_id, $reply_to );
+
+	// Update associated topic values if this is a new reply
+	if ( empty( $is_edit ) ) {
+
+		// Update poster IP if not editing
+		update_post_meta( $reply_id, '_bbp_author_ip', bbp_current_author_ip(), false );
+
+		// Last active time
+		$last_active_time = current_time( 'mysql' );
+
+		// Walk up ancestors and do the dirty work
+		bbp_update_reply_walker( $reply_id, $last_active_time, $forum_id, $topic_id, false );
+	}
+}
+
+/**
+ * Walk up the ancestor tree from the current reply, and update all the counts
+ *
+ * @since bbPress (r2884)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @param string $last_active_time Optional. Last active time
+ * @param int $forum_id Optional. Forum id
+ * @param int $topic_id Optional. Topic id
+ * @param bool $refresh If set to true, unsets all the previous parameters.
+ *                       Defaults to true
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_reply_forum_id() To get the reply forum id
+ * @uses get_post_ancestors() To get the ancestors of the reply
+ * @uses bbp_is_reply() To check if the ancestor is a reply
+ * @uses bbp_is_topic() To check if the ancestor is a topic
+ * @uses bbp_update_topic_last_reply_id() To update the topic last reply id
+ * @uses bbp_update_topic_last_active_id() To update the topic last active id
+ * @uses bbp_get_topic_last_active_id() To get the topic last active id
+ * @uses get_post_field() To get the post date of the last active id
+ * @uses bbp_update_topic_last_active_time() To update the last active topic meta
+ * @uses bbp_update_topic_voice_count() To update the topic voice count
+ * @uses bbp_update_topic_reply_count() To update the topic reply count
+ * @uses bbp_update_topic_reply_count_hidden() To update the topic hidden reply
+ *                                              count
+ * @uses bbp_is_forum() To check if the ancestor is a forum
+ * @uses bbp_update_forum_last_topic_id() To update the last topic id forum meta
+ * @uses bbp_update_forum_last_reply_id() To update the last reply id forum meta
+ * @uses bbp_update_forum_last_active_id() To update the forum last active id
+ * @uses bbp_get_forum_last_active_id() To get the forum last active id
+ * @uses bbp_update_forum_last_active_time() To update the forum last active time
+ * @uses bbp_update_forum_reply_count() To update the forum reply count
+ */
+function bbp_update_reply_walker( $reply_id, $last_active_time = '', $forum_id = 0, $topic_id = 0, $refresh = true ) {
+
+	// Verify the reply ID
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	// Reply was passed
+	if ( !empty( $reply_id ) ) {
+
+		// Get the topic ID if none was passed
+		if ( empty( $topic_id ) ) {
+			$topic_id = bbp_get_reply_topic_id( $reply_id );
+		}
+
+		// Get the forum ID if none was passed
+		if ( empty( $forum_id ) ) {
+			$forum_id = bbp_get_reply_forum_id( $reply_id );
+		}
+	}
+
+	// Set the active_id based on topic_id/reply_id
+	$active_id = empty( $reply_id ) ? $topic_id : $reply_id;
+
+	// Setup ancestors array to walk up
+	$ancestors = array_values( array_unique( array_merge( array( $topic_id, $forum_id ), (array) get_post_ancestors( $topic_id ) ) ) );
+
+	// If we want a full refresh, unset any of the possibly passed variables
+	if ( true === $refresh )
+		$forum_id = $topic_id = $reply_id = $active_id = $last_active_time = 0;
+
+	// Walk up ancestors
+	if ( !empty( $ancestors ) ) {
+		foreach ( $ancestors as $ancestor ) {
+
+			// Reply meta relating to most recent reply
+			if ( bbp_is_reply( $ancestor ) ) {
+				// @todo - hierarchical replies
+
+			// Topic meta relating to most recent reply
+			} elseif ( bbp_is_topic( $ancestor ) ) {
+
+				// Last reply and active ID's
+				bbp_update_topic_last_reply_id ( $ancestor, $reply_id  );
+				bbp_update_topic_last_active_id( $ancestor, $active_id );
+
+				// Get the last active time if none was passed
+				$topic_last_active_time = $last_active_time;
+				if ( empty( $last_active_time ) ) {
+					$topic_last_active_time = get_post_field( 'post_date', bbp_get_topic_last_active_id( $ancestor ) );
+				}
+
+				// Only update if reply is published
+				if ( bbp_is_reply_published( $reply_id ) ) {
+					bbp_update_topic_last_active_time( $ancestor, $topic_last_active_time );
+				}
+
+				// Counts
+				bbp_update_topic_voice_count       ( $ancestor );
+				bbp_update_topic_reply_count       ( $ancestor );
+				bbp_update_topic_reply_count_hidden( $ancestor );
+
+			// Forum meta relating to most recent topic
+			} elseif ( bbp_is_forum( $ancestor ) ) {
+
+				// Last topic and reply ID's
+				bbp_update_forum_last_topic_id( $ancestor, $topic_id );
+				bbp_update_forum_last_reply_id( $ancestor, $reply_id );
+
+				// Last Active
+				bbp_update_forum_last_active_id( $ancestor, $active_id );
+
+				// Get the last active time if none was passed
+				$forum_last_active_time = $last_active_time;
+				if ( empty( $last_active_time ) ) {
+					$forum_last_active_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $ancestor ) );
+				}
+
+				// Only update if reply is published
+				if ( bbp_is_reply_published( $reply_id ) ) {
+					bbp_update_forum_last_active_time( $ancestor, $forum_last_active_time );
+				}
+
+				// Counts
+				bbp_update_forum_reply_count( $ancestor );
+			}
+		}
+	}
+}
+
+/** Reply Updaters ************************************************************/
+
+/**
+ * Update the reply with its forum id it is in
+ *
+ * @since bbPress (r2855)
+ *
+ * @param int $reply_id Optional. Reply id to update
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses get_post_ancestors() To get the reply's forum
+ * @uses get_post_field() To get the post type of the post
+ * @uses update_post_meta() To update the reply forum id meta
+ * @uses apply_filters() Calls 'bbp_update_reply_forum_id' with the forum id
+ *                        and reply id
+ * @return bool Reply's forum id
+ */
+function bbp_update_reply_forum_id( $reply_id = 0, $forum_id = 0 ) {
+
+	// Validation
+	$reply_id = bbp_get_reply_id( $reply_id );
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// If no forum_id was passed, walk up ancestors and look for forum type
+	if ( empty( $forum_id ) ) {
+
+		// Get ancestors
+		$ancestors = (array) get_post_ancestors( $reply_id );
+
+		// Loop through ancestors
+		if ( !empty( $ancestors ) ) {
+			foreach ( $ancestors as $ancestor ) {
+
+				// Get first parent that is a forum
+				if ( get_post_field( 'post_type', $ancestor ) === bbp_get_forum_post_type() ) {
+					$forum_id = $ancestor;
+
+					// Found a forum, so exit the loop and continue
+					continue;
+				}
+			}
+		}
+	}
+
+	// Update the forum ID
+	bbp_update_forum_id( $reply_id, $forum_id );
+
+	return apply_filters( 'bbp_update_reply_forum_id', (int) $forum_id, $reply_id );
+}
+
+/**
+ * Update the reply with its topic id it is in
+ *
+ * @since bbPress (r2855)
+ *
+ * @param int $reply_id Optional. Reply id to update
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses get_post_ancestors() To get the reply's topic
+ * @uses get_post_field() To get the post type of the post
+ * @uses update_post_meta() To update the reply topic id meta
+ * @uses apply_filters() Calls 'bbp_update_reply_topic_id' with the topic id
+ *                        and reply id
+ * @return bool Reply's topic id
+ */
+function bbp_update_reply_topic_id( $reply_id = 0, $topic_id = 0 ) {
+
+	// Validation
+	$reply_id = bbp_get_reply_id( $reply_id );
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	// If no topic_id was passed, walk up ancestors and look for topic type
+	if ( empty( $topic_id ) ) {
+
+		// Get ancestors
+		$ancestors = (array) get_post_ancestors( $reply_id );
+
+		// Loop through ancestors
+		if ( !empty( $ancestors ) ) {
+			foreach ( $ancestors as $ancestor ) {
+
+				// Get first parent that is a forum
+				if ( get_post_field( 'post_type', $ancestor ) === bbp_get_topic_post_type() ) {
+					$topic_id = $ancestor;
+
+					// Found a forum, so exit the loop and continue
+					continue;
+				}
+			}
+		}
+	}
+
+	// Update the topic ID
+	bbp_update_topic_id( $reply_id, $topic_id );
+
+	return apply_filters( 'bbp_update_reply_topic_id', (int) $topic_id, $reply_id );
+}
+
+/*
+ * Update the reply's meta data with its reply to id
+ *
+ * @since bbPress (r4944)
+ *
+ * @param int $reply_id Reply id to update
+ * @param int $reply_to Optional. Reply to id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses update_post_meta() To update the reply to meta
+ * @uses apply_filters() Calls 'bbp_update_reply_to' with the reply id and
+ *                        and reply to id
+ * @return bool Reply's parent reply id
+ */
+function bbp_update_reply_to( $reply_id = 0, $reply_to = 0 ) {
+
+	// Validation
+	$reply_id = bbp_get_reply_id( $reply_id );
+	$reply_to = bbp_validate_reply_to( $reply_to );
+
+	// Update or delete the `reply_to` postmeta
+	if ( ! empty( $reply_id ) ) {
+
+		// Update the reply to
+		if ( !empty( $reply_to ) ) {
+			update_post_meta( $reply_id, '_bbp_reply_to', $reply_to );
+
+		// Delete the reply to
+		} else {
+			delete_post_meta( $reply_id, '_bbp_reply_to' );
+		}
+	}
+
+	return (int) apply_filters( 'bbp_update_reply_to', (int) $reply_to, $reply_id );
+}
+
+/**
+ * Update the revision log of the reply
+ *
+ * @since bbPress (r2782)
+ *
+ * @param mixed $args Supports these args:
+ *  - reply_id: reply id
+ *  - author_id: Author id
+ *  - reason: Reason for editing
+ *  - revision_id: Revision id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_format_revision_reason() To format the reason
+ * @uses bbp_get_reply_raw_revision_log() To get the raw reply revision log
+ * @uses update_post_meta() To update the reply revision log meta
+ * @return mixed False on failure, true on success
+ */
+function bbp_update_reply_revision_log( $args = '' ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'reason'      => '',
+		'reply_id'    => 0,
+		'author_id'   => 0,
+		'revision_id' => 0
+	), 'update_reply_revision_log' );
+
+	// Populate the variables
+	$r['reason']      = bbp_format_revision_reason( $r['reason'] );
+	$r['reply_id']    = bbp_get_reply_id( $r['reply_id'] );
+	$r['author_id']   = bbp_get_user_id ( $r['author_id'], false, true );
+	$r['revision_id'] = (int) $r['revision_id'];
+
+	// Get the logs and append the new one to those
+	$revision_log                      = bbp_get_reply_raw_revision_log( $r['reply_id'] );
+	$revision_log[ $r['revision_id'] ] = array( 'author' => $r['author_id'], 'reason' => $r['reason'] );
+
+	// Finally, update
+	update_post_meta( $r['reply_id'], '_bbp_revision_log', $revision_log );
+
+	return apply_filters( 'bbp_update_reply_revision_log', $revision_log, $r['reply_id'] );
+}
+
+/**
+ * Move reply handler
+ *
+ * Handles the front end move reply submission
+ *
+ * @since bbPress (r4521)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_get_reply() To get the reply
+ * @uses bbp_get_topic() To get the topics
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit the reply and topics
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses do_action() Calls 'bbp_pre_move_reply' with the from reply id, source
+ *                    and destination topic ids
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wpdb::prepare() To prepare our sql query
+ * @uses wpdb::get_results() To execute the sql query and get results
+ * @uses wp_update_post() To update the replies
+ * @uses bbp_update_reply_topic_id() To update the reply topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_update_reply_forum_id() To update the reply forum id
+ * @uses do_action() Calls 'bbp_split_topic_reply' with the reply id and
+ *                    destination topic id
+ * @uses bbp_update_topic_last_reply_id() To update the topic last reply id
+ * @uses bbp_update_topic_last_active_time() To update the topic last active meta
+ * @uses do_action() Calls 'bbp_post_split_topic' with the destination and
+ *                    source topic ids and source topic's forum id
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ * @uses wp_safe_redirect() To redirect to the topic link
+ */
+function bbp_move_reply_handler( $action = '' ) {
+
+	// Bail if action is not 'bbp-move-reply'
+	if ( 'bbp-move-reply' !== $action )
+		return;
+
+	// Prevent debug notices
+	$move_reply_id = $destination_topic_id = 0;
+	$destination_topic_title = '';
+	$destination_topic = $move_reply = $source_topic = '';
+
+	/** Move Reply ***********************************************************/
+
+	if ( empty( $_POST['bbp_reply_id'] ) ) {
+		bbp_add_error( 'bbp_move_reply_reply_id', __( '<strong>ERROR</strong>: Reply ID to move not found!', 'bbpress' ) );
+	} else {
+		$move_reply_id = (int) $_POST['bbp_reply_id'];
+	}
+
+	$move_reply = bbp_get_reply( $move_reply_id );
+
+	// Reply exists
+	if ( empty( $move_reply ) )
+		bbp_add_error( 'bbp_mover_reply_r_not_found', __( '<strong>ERROR</strong>: The reply you want to move was not found.', 'bbpress' ) );
+
+	/** Topic to Move From ***************************************************/
+
+	// Get the reply's current topic
+	$source_topic = bbp_get_topic( $move_reply->post_parent );
+
+	// No topic
+	if ( empty( $source_topic ) ) {
+		bbp_add_error( 'bbp_move_reply_source_not_found', __( '<strong>ERROR</strong>: The topic you want to move from was not found.', 'bbpress' ) );
+	}
+
+	// Nonce check failed
+	if ( ! bbp_verify_nonce_request( 'bbp-move-reply_' . $move_reply->ID ) ) {
+		bbp_add_error( 'bbp_move_reply_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Use cannot edit topic
+	if ( !current_user_can( 'edit_topic', $source_topic->ID ) ) {
+		bbp_add_error( 'bbp_move_reply_source_permission', __( '<strong>ERROR</strong>: You do not have the permissions to edit the source topic.', 'bbpress' ) );
+	}
+
+	// How to move
+	if ( !empty( $_POST['bbp_reply_move_option'] ) ) {
+		$move_option = (string) trim( $_POST['bbp_reply_move_option'] );
+	}
+
+	// Invalid move option
+	if ( empty( $move_option ) || !in_array( $move_option, array( 'existing', 'topic' ) ) ) {
+		bbp_add_error( 'bbp_move_reply_option', __( '<strong>ERROR</strong>: You need to choose a valid move option.', 'bbpress' ) );
+
+	// Valid move option
+	} else {
+
+		// What kind of move
+		switch ( $move_option ) {
+
+			// Into an existing topic
+			case 'existing' :
+
+				// Get destination topic id
+				if ( empty( $_POST['bbp_destination_topic'] ) ) {
+					bbp_add_error( 'bbp_move_reply_destination_id', __( '<strong>ERROR</strong>: Destination topic ID not found!', 'bbpress' ) );
+				} else {
+					$destination_topic_id = (int) $_POST['bbp_destination_topic'];
+				}
+
+				// Get the destination topic
+				$destination_topic = bbp_get_topic( $destination_topic_id );
+
+				// No destination topic
+				if ( empty( $destination_topic ) ) {
+					bbp_add_error( 'bbp_move_reply_destination_not_found', __( '<strong>ERROR</strong>: The topic you want to move to was not found!', 'bbpress' ) );
+				}
+
+				// User cannot edit the destination topic
+				if ( !current_user_can( 'edit_topic', $destination_topic->ID ) ) {
+					bbp_add_error( 'bbp_move_reply_destination_permission', __( '<strong>ERROR</strong>: You do not have the permissions to edit the destination topic!', 'bbpress' ) );
+				}
+
+				// Bump the reply position
+				$reply_position = bbp_get_topic_reply_count( $destination_topic->ID ) + 1;
+
+				// Update the reply
+				wp_update_post( array(
+					'ID'          => $move_reply->ID,
+					'post_title'  => sprintf( __( 'Reply To: %s', 'bbpress' ), $destination_topic->post_title ),
+					'post_name'   => false, // will be automatically generated
+					'post_parent' => $destination_topic->ID,
+					'menu_order'  => $reply_position,
+					'guid'        => ''
+				) );
+
+				// Adjust reply meta values
+				bbp_update_reply_topic_id( $move_reply->ID, $destination_topic->ID );
+				bbp_update_reply_forum_id( $move_reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );
+
+				break;
+
+			// Move reply to a new topic
+			case 'topic' :
+			default :
+
+				// User needs to be able to publish topics
+				if ( current_user_can( 'publish_topics' ) ) {
+
+					// Use the new title that was passed
+					if ( !empty( $_POST['bbp_reply_move_destination_title'] ) ) {
+						$destination_topic_title = esc_attr( strip_tags( $_POST['bbp_reply_move_destination_title'] ) );
+
+					// Use the source topic title
+					} else {
+						$destination_topic_title = $source_topic->post_title;
+					}
+
+					// Update the topic
+					$destination_topic_id = wp_update_post( array(
+						'ID'          => $move_reply->ID,
+						'post_title'  => $destination_topic_title,
+						'post_name'   => false,
+						'post_type'   => bbp_get_topic_post_type(),
+						'post_parent' => $source_topic->post_parent,
+						'guid'        => ''
+					) );
+					$destination_topic = bbp_get_topic( $destination_topic_id );
+
+					// Make sure the new topic knows its a topic
+					bbp_update_topic_topic_id( $move_reply->ID );
+
+					// Shouldn't happen
+					if ( false === $destination_topic_id || is_wp_error( $destination_topic_id ) || empty( $destination_topic ) ) {
+						bbp_add_error( 'bbp_move_reply_destination_reply', __( '<strong>ERROR</strong>: There was a problem converting the reply into the topic. Please try again.', 'bbpress' ) );
+					}
+
+				// User cannot publish posts
+				} else {
+					bbp_add_error( 'bbp_move_reply_destination_permission', __( '<strong>ERROR</strong>: You do not have the permissions to create new topics. The reply could not be converted into a topic.', 'bbpress' ) );
+				}
+
+				break;
+		}
+	}
+
+	// Bail if there are errors
+	if ( bbp_has_errors() ) {
+		return;
+	}
+
+	/** No Errors - Clean Up **************************************************/
+
+	// Update counts, etc...
+	do_action( 'bbp_pre_move_reply', $move_reply->ID, $source_topic->ID, $destination_topic->ID );
+
+	/** Date Check ************************************************************/
+
+	// Check if the destination topic is older than the move reply
+	if ( strtotime( $move_reply->post_date ) < strtotime( $destination_topic->post_date ) ) {
+
+		// Set destination topic post_date to 1 second before from reply
+		$destination_post_date = date( 'Y-m-d H:i:s', strtotime( $move_reply->post_date ) - 1 );
+
+		// Update destination topic
+		wp_update_post( array(
+			'ID'            => $destination_topic_id,
+			'post_date'     => $destination_post_date,
+			'post_date_gmt' => get_gmt_from_date( $destination_post_date )
+		) );
+	}
+
+	// Set the last reply ID and freshness to the move_reply
+	$last_reply_id = $move_reply->ID;
+	$freshness     = $move_reply->post_date;
+
+	// Get the reply to
+	$parent = bbp_get_reply_to( $move_reply->ID );
+
+	// Fix orphaned children
+	$children = get_posts( array(
+		'post_type'  => bbp_get_reply_post_type(),
+		'meta_key'   => '_bbp_reply_to',
+		'meta_value' => $move_reply->ID,
+	) );
+	foreach ( $children as $child )
+		bbp_update_reply_to( $child->ID, $parent );
+
+	// Remove reply_to from moved reply
+	delete_post_meta( $move_reply->ID, '_bbp_reply_to' ); 
+
+	// It is a new topic and we need to set some default metas to make
+	// the topic display in bbp_has_topics() list
+	if ( 'topic' === $move_option ) {
+		bbp_update_topic_last_reply_id   ( $destination_topic->ID, $last_reply_id );
+		bbp_update_topic_last_active_id  ( $destination_topic->ID, $last_reply_id );
+		bbp_update_topic_last_active_time( $destination_topic->ID, $freshness     );
+
+	// Otherwise update the existing destination topic
+	} else {
+		bbp_update_topic_last_reply_id   ( $destination_topic->ID );
+		bbp_update_topic_last_active_id  ( $destination_topic->ID );
+		bbp_update_topic_last_active_time( $destination_topic->ID );
+	}
+
+	// Update source topic ID last active
+	bbp_update_topic_last_reply_id   ( $source_topic->ID );
+	bbp_update_topic_last_active_id  ( $source_topic->ID );
+	bbp_update_topic_last_active_time( $source_topic->ID );
+
+	/** Successful Move ******************************************************/
+
+	// Update counts, etc...
+	do_action( 'bbp_post_move_reply', $move_reply->ID, $source_topic->ID, $destination_topic->ID );
+
+	// Redirect back to the topic
+	wp_safe_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
+
+	// For good measure
+	exit();
+}
+
+/**
+ * Fix counts on reply move
+ *
+ * When a reply is moved, update the counts of source and destination topic
+ * and their forums.
+ *
+ * @since bbPress (r4521)
+ *
+ * @param int $move_reply_id Move reply id
+ * @param int $source_topic_id Source topic id
+ * @param int $destination_topic_id Destination topic id
+ * @uses bbp_update_forum_topic_count() To update the forum topic counts
+ * @uses bbp_update_forum_reply_count() To update the forum reply counts
+ * @uses bbp_update_topic_reply_count() To update the topic reply counts
+ * @uses bbp_update_topic_voice_count() To update the topic voice counts
+ * @uses bbp_update_topic_reply_count_hidden() To update the topic hidden reply
+ *                                              count
+ * @uses do_action() Calls 'bbp_move_reply_count' with the move reply id,
+ *                    source topic id & destination topic id
+ */
+function bbp_move_reply_count( $move_reply_id, $source_topic_id, $destination_topic_id ) {
+
+	// Forum topic counts
+	bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) );
+
+	// Forum reply counts
+	bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) );
+
+	// Topic reply counts
+	bbp_update_topic_reply_count( $source_topic_id      );
+	bbp_update_topic_reply_count( $destination_topic_id );
+
+	// Topic hidden reply counts
+	bbp_update_topic_reply_count_hidden( $source_topic_id      );
+	bbp_update_topic_reply_count_hidden( $destination_topic_id );
+
+	// Topic voice counts
+	bbp_update_topic_voice_count( $source_topic_id      );
+	bbp_update_topic_voice_count( $destination_topic_id );
+
+	do_action( 'bbp_move_reply_count', $move_reply_id, $source_topic_id, $destination_topic_id );
+}
+
+/** Reply Actions *************************************************************/
+
+/**
+ * Handles the front end spamming/unspamming and trashing/untrashing/deleting of
+ * replies
+ *
+ * @since bbPress (r2740)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_get_reply() To get the reply
+ * @uses current_user_can() To check if the user is capable of editing or
+ *                           deleting the reply
+ * @uses check_ajax_referer() To verify the nonce and check the referer
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_is_reply_spam() To check if the reply is marked as spam
+ * @uses bbp_spam_reply() To make the reply as spam
+ * @uses bbp_unspam_reply() To unmark the reply as spam
+ * @uses wp_trash_post() To trash the reply
+ * @uses wp_untrash_post() To untrash the reply
+ * @uses wp_delete_post() To delete the reply
+ * @uses do_action() Calls 'bbp_toggle_reply_handler' with success, post data
+ *                    and action
+ * @uses bbp_get_reply_url() To get the reply url
+ * @uses add_query_arg() To add custom args to the reply url
+ * @uses wp_safe_redirect() To redirect to the reply
+ * @uses bbPress::errors:add() To log the error messages
+ */
+function bbp_toggle_reply_handler( $action = '' ) {
+
+	// Bail if required GET actions aren't passed
+	if ( empty( $_GET['reply_id'] ) )
+		return;
+
+	// Setup possible get actions
+	$possible_actions = array(
+		'bbp_toggle_reply_spam',
+		'bbp_toggle_reply_trash'
+	);
+
+	// Bail if actions aren't meant for this function
+	if ( !in_array( $action, $possible_actions ) )
+		return;
+
+	$failure   = '';                         // Empty failure string
+	$view_all  = false;                      // Assume not viewing all
+	$reply_id  = (int) $_GET['reply_id'];    // What's the reply id?
+	$success   = false;                      // Flag
+	$post_data = array( 'ID' => $reply_id ); // Prelim array
+
+	// Make sure reply exists
+	$reply = bbp_get_reply( $reply_id );
+	if ( empty( $reply ) )
+		return;
+
+	// What is the user doing here?
+	if ( !current_user_can( 'edit_reply', $reply->ID ) || ( 'bbp_toggle_reply_trash' === $action && !current_user_can( 'delete_reply', $reply->ID ) ) ) {
+		bbp_add_error( 'bbp_toggle_reply_permission', __( '<strong>ERROR:</strong> You do not have the permission to do that!', 'bbpress' ) );
+		return;
+	}
+
+	// What action are we trying to perform?
+	switch ( $action ) {
+
+		// Toggle spam
+		case 'bbp_toggle_reply_spam' :
+			check_ajax_referer( 'spam-reply_' . $reply_id );
+
+			$is_spam  = bbp_is_reply_spam( $reply_id );
+			$success  = $is_spam ? bbp_unspam_reply( $reply_id ) : bbp_spam_reply( $reply_id );
+			$failure  = $is_spam ? __( '<strong>ERROR</strong>: There was a problem unmarking the reply as spam!', 'bbpress' ) : __( '<strong>ERROR</strong>: There was a problem marking the reply as spam!', 'bbpress' );
+			$view_all = !$is_spam;
+
+			break;
+
+		// Toggle trash
+		case 'bbp_toggle_reply_trash' :
+
+			$sub_action = in_array( $_GET['sub_action'], array( 'trash', 'untrash', 'delete' ) ) ? $_GET['sub_action'] : false;
+
+			if ( empty( $sub_action ) )
+				break;
+
+			switch ( $sub_action ) {
+				case 'trash':
+					check_ajax_referer( 'trash-' . bbp_get_reply_post_type() . '_' . $reply_id );
+
+					$view_all = true;
+					$success  = wp_trash_post( $reply_id );
+					$failure  = __( '<strong>ERROR</strong>: There was a problem trashing the reply!', 'bbpress' );
+
+					break;
+
+				case 'untrash':
+					check_ajax_referer( 'untrash-' . bbp_get_reply_post_type() . '_' . $reply_id );
+
+					$success = wp_untrash_post( $reply_id );
+					$failure = __( '<strong>ERROR</strong>: There was a problem untrashing the reply!', 'bbpress' );
+
+					break;
+
+				case 'delete':
+					check_ajax_referer( 'delete-' . bbp_get_reply_post_type() . '_' . $reply_id );
+
+					$success = wp_delete_post( $reply_id );
+					$failure = __( '<strong>ERROR</strong>: There was a problem deleting the reply!', 'bbpress' );
+
+					break;
+			}
+
+			break;
+	}
+
+	// Do additional reply toggle actions
+	do_action( 'bbp_toggle_reply_handler', $success, $post_data, $action );
+
+	// No errors
+	if ( ( false !== $success ) && !is_wp_error( $success ) ) {
+
+		/** Redirect **********************************************************/
+
+		// Redirect to
+		$redirect_to = bbp_get_redirect_to();
+
+		// Get the reply URL
+		$reply_url = bbp_get_reply_url( $reply_id, $redirect_to );
+
+		// Add view all if needed
+		if ( !empty( $view_all ) )
+			$reply_url = bbp_add_view_all( $reply_url, true );
+
+		// Redirect back to reply
+		wp_safe_redirect( $reply_url );
+
+		// For good measure
+		exit();
+
+	// Handle errors
+	} else {
+		bbp_add_error( 'bbp_toggle_reply', $failure );
+	}
+}
+
+/** Reply Actions *************************************************************/
+
+/**
+ * Marks a reply as spam
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $reply_id Reply id
+ * @uses bbp_get_reply() To get the reply
+ * @uses do_action() Calls 'bbp_spam_reply' with the reply ID
+ * @uses add_post_meta() To add the previous status to a meta
+ * @uses wp_update_post() To insert the updated post
+ * @uses do_action() Calls 'bbp_spammed_reply' with the reply ID
+ * @return mixed False or {@link WP_Error} on failure, reply id on success
+ */
+function bbp_spam_reply( $reply_id = 0 ) {
+
+	// Get reply
+	$reply = bbp_get_reply( $reply_id );
+	if ( empty( $reply ) )
+		return $reply;
+
+	// Bail if already spam
+	if ( bbp_get_spam_status_id() === $reply->post_status )
+		return false;
+
+	// Execute pre spam code
+	do_action( 'bbp_spam_reply', $reply_id );
+
+	// Add the original post status as post meta for future restoration
+	add_post_meta( $reply_id, '_bbp_spam_meta_status', $reply->post_status );
+
+	// Set post status to spam
+	$reply->post_status = bbp_get_spam_status_id();
+
+	// No revisions
+	remove_action( 'pre_post_update', 'wp_save_post_revision' );
+
+	// Update the reply
+	$reply_id = wp_update_post( $reply );
+
+	// Execute post spam code
+	do_action( 'bbp_spammed_reply', $reply_id );
+
+	// Return reply_id
+	return $reply_id;
+}
+
+/**
+ * Unspams a reply
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $reply_id Reply id
+ * @uses bbp_get_reply() To get the reply
+ * @uses do_action() Calls 'bbp_unspam_reply' with the reply ID
+ * @uses get_post_meta() To get the previous status meta
+ * @uses delete_post_meta() To delete the previous status meta
+ * @uses wp_update_post() To insert the updated post
+ * @uses do_action() Calls 'bbp_unspammed_reply' with the reply ID
+ * @return mixed False or {@link WP_Error} on failure, reply id on success
+ */
+function bbp_unspam_reply( $reply_id = 0 ) {
+
+	// Get reply
+	$reply = bbp_get_reply( $reply_id );
+	if ( empty( $reply ) )
+		return $reply;
+
+	// Bail if already not spam
+	if ( bbp_get_spam_status_id() !== $reply->post_status )
+		return false;
+
+	// Execute pre unspam code
+	do_action( 'bbp_unspam_reply', $reply_id );
+
+	// Get pre spam status
+	$reply->post_status = get_post_meta( $reply_id, '_bbp_spam_meta_status', true );
+
+	// If no previous status, default to publish
+	if ( empty( $reply->post_status ) ) {
+		$reply->post_status = bbp_get_public_status_id();
+	}
+
+	// Delete pre spam meta
+	delete_post_meta( $reply_id, '_bbp_spam_meta_status' );
+
+	// No revisions
+	remove_action( 'pre_post_update', 'wp_save_post_revision' );
+
+	// Update the reply
+	$reply_id = wp_update_post( $reply );
+
+	// Execute post unspam code
+	do_action( 'bbp_unspammed_reply', $reply_id );
+
+	// Return reply_id
+	return $reply_id;
+}
+
+/** Before Delete/Trash/Untrash ***********************************************/
+
+/**
+ * Called before deleting a reply
+ *
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_is_reply() To check if the passed id is a reply
+ * @uses do_action() Calls 'bbp_delete_reply' with the reply id
+ */
+function bbp_delete_reply( $reply_id = 0 ) {
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	if ( empty( $reply_id ) || !bbp_is_reply( $reply_id ) )
+		return false;
+
+	do_action( 'bbp_delete_reply', $reply_id );
+}
+
+/**
+ * Called before trashing a reply
+ *
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_is_reply() To check if the passed id is a reply
+ * @uses do_action() Calls 'bbp_trash_reply' with the reply id
+ */
+function bbp_trash_reply( $reply_id = 0 ) {
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	if ( empty( $reply_id ) || !bbp_is_reply( $reply_id ) )
+		return false;
+
+	do_action( 'bbp_trash_reply', $reply_id );
+}
+
+/**
+ * Called before untrashing (restoring) a reply
+ *
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_is_reply() To check if the passed id is a reply
+ * @uses do_action() Calls 'bbp_unstrash_reply' with the reply id
+ */
+function bbp_untrash_reply( $reply_id = 0 ) {
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	if ( empty( $reply_id ) || !bbp_is_reply( $reply_id ) )
+		return false;
+
+	do_action( 'bbp_untrash_reply', $reply_id );
+}
+
+/** After Delete/Trash/Untrash ************************************************/
+
+/**
+ * Called after deleting a reply
+ *
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_is_reply() To check if the passed id is a reply
+ * @uses do_action() Calls 'bbp_deleted_reply' with the reply id
+ */
+function bbp_deleted_reply( $reply_id = 0 ) {
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	if ( empty( $reply_id ) || !bbp_is_reply( $reply_id ) )
+		return false;
+
+	do_action( 'bbp_deleted_reply', $reply_id );
+}
+
+/**
+ * Called after trashing a reply
+ *
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_is_reply() To check if the passed id is a reply
+ * @uses do_action() Calls 'bbp_trashed_reply' with the reply id
+ */
+function bbp_trashed_reply( $reply_id = 0 ) {
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	if ( empty( $reply_id ) || !bbp_is_reply( $reply_id ) )
+		return false;
+
+	do_action( 'bbp_trashed_reply', $reply_id );
+}
+
+/**
+ * Called after untrashing (restoring) a reply
+ *
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_is_reply() To check if the passed id is a reply
+ * @uses do_action() Calls 'bbp_untrashed_reply' with the reply id
+ */
+function bbp_untrashed_reply( $reply_id = 0 ) {
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	if ( empty( $reply_id ) || !bbp_is_reply( $reply_id ) )
+		return false;
+
+	do_action( 'bbp_untrashed_reply', $reply_id );
+}
+
+/** Settings ******************************************************************/
+
+/**
+ * Return the replies per page setting
+ *
+ * @since bbPress (r3540)
+ *
+ * @param int $default Default replies per page (15)
+ * @uses get_option() To get the setting
+ * @uses apply_filters() To allow the return value to be manipulated
+ * @return int
+ */
+function bbp_get_replies_per_page( $default = 15 ) {
+
+	// Get database option and cast as integer
+	$retval = get_option( '_bbp_replies_per_page', $default );
+
+	// If return val is empty, set it to default
+	if ( empty( $retval ) )
+		$retval = $default;
+
+	// Filter and return
+	return (int) apply_filters( 'bbp_get_replies_per_page', $retval, $default );
+}
+
+/**
+ * Return the replies per RSS page setting
+ *
+ * @since bbPress (r3540)
+ *
+ * @param int $default Default replies per page (25)
+ * @uses get_option() To get the setting
+ * @uses apply_filters() To allow the return value to be manipulated
+ * @return int
+ */
+function bbp_get_replies_per_rss_page( $default = 25 ) {
+
+	// Get database option and cast as integer
+	$retval = get_option( '_bbp_replies_per_rss_page', $default );
+
+	// If return val is empty, set it to default
+	if ( empty( $retval ) )
+		$retval = $default;
+
+	// Filter and return
+	return (int) apply_filters( 'bbp_get_replies_per_rss_page', $retval, $default );
+}
+
+/** Autoembed *****************************************************************/
+
+/**
+ * Check if autoembeds are enabled and hook them in if so
+ *
+ * @since bbPress (r3752)
+ * @global WP_Embed $wp_embed
+ */
+function bbp_reply_content_autoembed() {
+	global $wp_embed;
+
+	if ( bbp_use_autoembed() && is_a( $wp_embed, 'WP_Embed' ) ) {
+		add_filter( 'bbp_get_reply_content', array( $wp_embed, 'autoembed' ), 2 );
+	}
+}
+
+/** Filters *******************************************************************/
+
+/**
+ * Used by bbp_has_replies() to add the lead topic post to the posts loop
+ *
+ * This function filters the 'post_where' of the WP_Query, and changes the query
+ * to include both the topic AND its children in the same loop.
+ *
+ * @since bbPress (r4058)
+ *
+ * @param string $where
+ * @return string
+ */
+function _bbp_has_replies_where( $where = '', $query = false ) {
+
+	/** Bail ******************************************************************/
+
+	// Bail if the sky is falling
+	if ( empty( $where ) || empty( $query ) ) {
+		return $where;
+	}
+
+	// Bail if no post_parent to replace
+	if ( ! is_numeric( $query->get( 'post_parent' ) ) ) {
+		return $where;
+	}
+
+	// Bail if not a topic and reply query
+	if ( array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ) !== $query->get( 'post_type' ) ) {
+		return $where;
+	}
+
+	// Bail if including or excluding specific post ID's
+	if ( $query->get( 'post__not_in' ) || $query->get( 'post__in' ) ) {
+		return $where;
+	}
+
+	/** Proceed ***************************************************************/
+
+	global $wpdb;
+
+	// Table name for posts
+	$table_name = $wpdb->prefix . 'posts';
+
+	// Get the topic ID from the post_parent, set in bbp_has_replies()
+	$topic_id   = bbp_get_topic_id( $query->get( 'post_parent' ) );
+
+	// The texts to search for
+	$search     = array(
+		"FROM {$table_name} " ,
+		"WHERE 1=1  AND {$table_name}.post_parent = {$topic_id}"
+	);
+
+	// The texts to replace them with
+	$replace     = array(
+		$search[0] . "FORCE INDEX (PRIMARY, post_parent) " ,
+		"WHERE 1=1 AND ({$table_name}.ID = {$topic_id} OR {$table_name}.post_parent = {$topic_id})"
+	);
+
+	// Try to replace the search text with the replacement
+	$new_where = str_replace( $search, $replace, $where );
+	if ( ! empty( $new_where ) ) {
+		$where = $new_where;
+	}
+
+	return $where;
+}
+
+/** Feeds *********************************************************************/
+
+/**
+ * Output an RSS2 feed of replies, based on the query passed.
+ *
+ * @since bbPress (r3171)
+ *
+ * @uses bbp_version()
+ * @uses bbp_is_single_topic()
+ * @uses bbp_user_can_view_forum()
+ * @uses bbp_get_topic_forum_id()
+ * @uses bbp_show_load_topic()
+ * @uses bbp_topic_permalink()
+ * @uses bbp_topic_title()
+ * @uses bbp_get_topic_reply_count()
+ * @uses bbp_topic_content()
+ * @uses bbp_has_replies()
+ * @uses bbp_replies()
+ * @uses bbp_the_reply()
+ * @uses bbp_reply_url()
+ * @uses bbp_reply_title()
+ * @uses bbp_reply_content()
+ * @uses get_wp_title_rss()
+ * @uses get_option()
+ * @uses bloginfo_rss
+ * @uses self_link()
+ * @uses the_author()
+ * @uses get_post_time()
+ * @uses rss_enclosure()
+ * @uses do_action()
+ * @uses apply_filters()
+ *
+ * @param array $replies_query
+ */
+function bbp_display_replies_feed_rss2( $replies_query = array() ) {
+
+	// User cannot access forum this topic is in
+	if ( bbp_is_single_topic() && !bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) )
+		return;
+
+	// Adjust the title based on context
+	if ( bbp_is_single_topic() && bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) )
+		$title = apply_filters( 'wp_title_rss', get_wp_title_rss( ' &#187; ' ) );
+	elseif ( !bbp_show_lead_topic() )
+		$title = ' &#187; ' .  __( 'All Posts',   'bbpress' );
+	else
+		$title = ' &#187; ' .  __( 'All Replies', 'bbpress' );
+
+	// Display the feed
+	header( 'Content-Type: ' . feed_content_type( 'rss-http' ) . '; charset=' . get_option( 'blog_charset' ), true );
+	header( 'Status: 200 OK' );
+	echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>'; ?>
+
+	<rss version="2.0"
+		xmlns:content="http://purl.org/rss/1.0/modules/content/"
+		xmlns:wfw="http://wellformedweb.org/CommentAPI/"
+		xmlns:dc="http://purl.org/dc/elements/1.1/"
+		xmlns:atom="http://www.w3.org/2005/Atom"
+
+		<?php do_action( 'bbp_feed' ); ?>
+	>
+
+	<channel>
+		<title><?php bloginfo_rss('name'); echo $title; ?></title>
+		<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
+		<link><?php self_link(); ?></link>
+		<description><?php //?></description>
+		<pubDate><?php echo mysql2date( 'D, d M Y H:i:s O', current_time( 'mysql' ), false ); ?></pubDate>
+		<generator>http://bbpress.org/?v=<?php bbp_version(); ?></generator>
+		<language><?php bloginfo_rss( 'language' ); ?></language>
+
+		<?php do_action( 'bbp_feed_head' ); ?>
+
+		<?php if ( bbp_is_single_topic() ) : ?>
+			<?php if ( bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) ) : ?>
+				<?php if ( bbp_show_lead_topic() ) : ?>
+
+					<item>
+						<guid><?php bbp_topic_permalink(); ?></guid>
+						<title><![CDATA[<?php bbp_topic_title(); ?>]]></title>
+						<link><?php bbp_topic_permalink(); ?></link>
+						<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
+						<dc:creator><?php the_author(); ?></dc:creator>
+
+						<description>
+							<![CDATA[
+							<p><?php printf( __( 'Replies: %s', 'bbpress' ), bbp_get_topic_reply_count() ); ?></p>
+							<?php bbp_topic_content(); ?>
+							]]>
+						</description>
+
+						<?php rss_enclosure(); ?>
+
+						<?php do_action( 'bbp_feed_item' ); ?>
+
+					</item>
+
+				<?php endif; ?>
+			<?php endif; ?>
+		<?php endif; ?>
+
+		<?php if ( bbp_has_replies( $replies_query ) ) : ?>
+			<?php while ( bbp_replies() ) : bbp_the_reply(); ?>
+
+				<item>
+					<guid><?php bbp_reply_url(); ?></guid>
+					<title><![CDATA[<?php bbp_reply_title(); ?>]]></title>
+					<link><?php bbp_reply_url(); ?></link>
+					<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
+					<dc:creator><?php the_author() ?></dc:creator>
+
+					<description>
+						<![CDATA[
+						<?php bbp_reply_content(); ?>
+						]]>
+					</description>
+
+					<?php rss_enclosure(); ?>
+
+					<?php do_action( 'bbp_feed_item' ); ?>
+
+				</item>
+
+			<?php endwhile; ?>
+		<?php endif; ?>
+
+		<?php do_action( 'bbp_feed_footer' ); ?>
+
+	</channel>
+	</rss>
+
+<?php
+
+	// We're done here
+	exit();
+}
+
+/** Permissions ***************************************************************/
+
+/**
+ * Redirect if unathorized user is attempting to edit a reply
+ *
+ * @since bbPress (r3605)
+ *
+ * @uses bbp_is_reply_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_topic_id()
+ * @uses wp_safe_redirect()
+ * @uses bbp_get_topic_permalink()
+ */
+function bbp_check_reply_edit() {
+
+	// Bail if not editing a topic
+	if ( !bbp_is_reply_edit() )
+		return;
+
+	// User cannot edit topic, so redirect back to reply
+	if ( !current_user_can( 'edit_reply', bbp_get_reply_id() ) ) {
+		wp_safe_redirect( bbp_get_reply_url() );
+		exit();
+	}
+}
+
+/** Reply Position ************************************************************/
+
+/**
+ * Update the position of the reply.
+ *
+ * The reply position is stored in the menu_order column of the posts table.
+ * This is done to prevent using a meta_query to retrieve posts in the proper
+ * freshness order. By updating the menu_order accordingly, we're able to
+ * leverage core WordPress query ordering much more effectively.
+ *
+ * @since bbPress (r3933)
+ *
+ * @global type $wpdb
+ * @param type $reply_id
+ * @param type $reply_position
+ * @return mixed
+ */
+function bbp_update_reply_position( $reply_id = 0, $reply_position = 0 ) {
+
+	// Bail if reply_id is empty
+	$reply_id = bbp_get_reply_id( $reply_id );
+	if ( empty( $reply_id ) )
+		return false;
+
+	// If no position was passed, get it from the db and update the menu_order
+	if ( empty( $reply_position ) ) {
+		$reply_position = bbp_get_reply_position_raw( $reply_id, bbp_get_reply_topic_id( $reply_id ) );
+	}
+
+	// Update the replies' 'menp_order' with the reply position
+	wp_update_post( array(
+		'ID'         => $reply_id,
+		'menu_order' => $reply_position
+	) );
+
+	return (int) $reply_position;
+}
+
+/**
+ * Get the position of a reply by querying the DB directly for the replies
+ * of a given topic.
+ *
+ * @since bbPress (r3933)
+ *
+ * @param int $reply_id
+ * @param int $topic_id
+ */
+function bbp_get_reply_position_raw( $reply_id = 0, $topic_id = 0 ) {
+
+	// Get required data
+	$reply_id       = bbp_get_reply_id( $reply_id );
+	$topic_id       = !empty( $topic_id ) ? bbp_get_topic_id( $topic_id ) : bbp_get_reply_topic_id( $reply_id );
+	$reply_position = 0;
+
+	// If reply is actually the first post in a topic, return 0
+	if ( $reply_id !== $topic_id ) {
+
+		// Make sure the topic has replies before running another query
+		$reply_count = bbp_get_topic_reply_count( $topic_id, false );
+		if ( !empty( $reply_count ) ) {
+
+			// Get reply id's
+			$topic_replies = bbp_get_all_child_ids( $topic_id, bbp_get_reply_post_type() );
+			if ( !empty( $topic_replies ) ) {
+
+				// Reverse replies array and search for current reply position
+				$topic_replies  = array_reverse( $topic_replies );
+				$reply_position = array_search( (string) $reply_id, $topic_replies );
+
+				// Bump the position to compensate for the lead topic post
+				$reply_position++;
+			}
+		}
+	}
+
+	return (int) $reply_position;
+}
+
+/** Hierarchical Replies ******************************************************/
+
+/**
+ * List replies
+ *
+ * @since bbPress (r4944)
+ */
+function bbp_list_replies( $args = array() ) {
+
+	// Reset the reply depth
+	bbpress()->reply_query->reply_depth = 0;
+
+	// In reply loop
+	bbpress()->reply_query->in_the_loop = true;
+
+	$r = bbp_parse_args( $args, array(
+		'walker'       => null,
+		'max_depth'    => bbp_thread_replies_depth(),
+		'style'        => 'ul',
+		'callback'     => null,
+		'end_callback' => null,
+		'page'         => 1,
+		'per_page'     => -1
+	), 'list_replies' );
+
+	// Get replies to loop through in $_replies
+	$walker = new BBP_Walker_Reply;
+	$walker->paged_walk( bbpress()->reply_query->posts, $r['max_depth'], $r['page'], $r['per_page'], $r );
+
+	bbpress()->max_num_pages            = $walker->max_pages;
+	bbpress()->reply_query->in_the_loop = false;
+}
+
+/**
+ * Validate a `reply_to` field for hierarchical replies
+ * 
+ * Checks for 2 scenarios:
+ * -- The reply to ID is actually a reply
+ * -- The reply to ID does not match the current reply
+ *
+ * @since bbPress (r5377)
+ *
+ * @param int $reply_to
+ * @param int $reply_id
+ *
+ * @return int $reply_to
+ */
+function bbp_validate_reply_to( $reply_to = 0, $reply_id = 0 ) {
+
+	// The parent reply must actually be a reply
+	if ( ! bbp_is_reply( $reply_to ) ) {
+		$reply_to = 0;
+	}
+
+	// The parent reply cannot be itself
+	if ( $reply_id === $reply_to ) {
+		$reply_to = 0;
+	}
+
+	return (int) $reply_to;
+}
Index: /tags/2.5.4/includes/replies/index.php
===================================================================
--- /tags/2.5.4/includes/replies/index.php	(revision 5382)
+++ /tags/2.5.4/includes/replies/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/replies/template.php
===================================================================
--- /tags/2.5.4/includes/replies/template.php	(revision 5382)
+++ /tags/2.5.4/includes/replies/template.php	(revision 5382)
@@ -0,0 +1,2543 @@
+<?php
+
+/**
+ * bbPress Reply Template Tags
+ *
+ * @package bbPress
+ * @subpackage TemplateTags
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Post Type *****************************************************************/
+
+/**
+ * Return the unique id of the custom post type for replies
+ *
+ * @since bbPress (r2857)
+ *
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ */
+function bbp_reply_post_type() {
+	echo bbp_get_reply_post_type();
+}
+	/**
+	 * Return the unique id of the custom post type for replies
+	 *
+	 * @since bbPress (r2857)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_forum_post_type' with the forum
+	 *                        post type id
+	 * @return string The unique reply post type id
+	 */
+	function bbp_get_reply_post_type() {
+		return apply_filters( 'bbp_get_reply_post_type', bbpress()->reply_post_type );
+	}
+
+/**
+ * Return array of labels used by the reply post type
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_reply_post_type_labels() {
+	return apply_filters( 'bbp_get_reply_post_type_labels', array(
+		'name'               => __( 'Replies',                   'bbpress' ),
+		'menu_name'          => __( 'Replies',                   'bbpress' ),
+		'singular_name'      => __( 'Reply',                     'bbpress' ),
+		'all_items'          => __( 'All Replies',               'bbpress' ),
+		'add_new'            => __( 'New Reply',                 'bbpress' ),
+		'add_new_item'       => __( 'Create New Reply',          'bbpress' ),
+		'edit'               => __( 'Edit',                      'bbpress' ),
+		'edit_item'          => __( 'Edit Reply',                'bbpress' ),
+		'new_item'           => __( 'New Reply',                 'bbpress' ),
+		'view'               => __( 'View Reply',                'bbpress' ),
+		'view_item'          => __( 'View Reply',                'bbpress' ),
+		'search_items'       => __( 'Search Replies',            'bbpress' ),
+		'not_found'          => __( 'No replies found',          'bbpress' ),
+		'not_found_in_trash' => __( 'No replies found in Trash', 'bbpress' ),
+		'parent_item_colon'  => __( 'Topic:',                    'bbpress' )
+	) );
+}
+
+/**
+ * Return array of reply post type rewrite settings
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_reply_post_type_rewrite() {
+	return apply_filters( 'bbp_get_reply_post_type_rewrite', array(
+		'slug'       => bbp_get_reply_slug(),
+		'with_front' => false
+	) );
+}
+
+/**
+ * Return array of features the reply post type supports
+ *
+ * @since bbPress (rx5129)
+ *
+ * @return array
+ */
+function bbp_get_reply_post_type_supports() {
+	return apply_filters( 'bbp_get_reply_post_type_supports', array(
+		'title',
+		'editor',
+		'revisions'
+	) );
+}
+
+/** Reply Loop Functions ******************************************************/
+
+/**
+ * The main reply loop. WordPress makes this easy for us
+ *
+ * @since bbPress (r2553)
+ *
+ * @param mixed $args All the arguments supported by {@link WP_Query}
+ * @uses bbp_show_lead_topic() Are we showing the topic as a lead?
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses get_option() To get the replies per page option
+ * @uses bbp_get_paged() To get the current page value
+ * @uses current_user_can() To check if the current user is capable of editing
+ *                           others' replies
+ * @uses WP_Query To make query and get the replies
+ * @uses WP_Rewrite::using_permalinks() To check if the blog is using permalinks
+ * @uses get_permalink() To get the permalink
+ * @uses add_query_arg() To add custom args to the url
+ * @uses apply_filters() Calls 'bbp_replies_pagination' with the pagination args
+ * @uses paginate_links() To paginate the links
+ * @uses apply_filters() Calls 'bbp_has_replies' with
+ *                        bbPres::reply_query::have_posts()
+ *                        and bbPres::reply_query
+ * @return object Multidimensional array of reply information
+ */
+function bbp_has_replies( $args = '' ) {
+	global $wp_rewrite;
+
+	/** Defaults **************************************************************/
+
+	// Other defaults
+	$default_reply_search   = !empty( $_REQUEST['rs'] ) ? $_REQUEST['rs']    : false;
+	$default_post_parent    = ( bbp_is_single_topic() ) ? bbp_get_topic_id() : 'any';
+	$default_post_type      = ( bbp_is_single_topic() && bbp_show_lead_topic() ) ? bbp_get_reply_post_type() : array( bbp_get_topic_post_type(), bbp_get_reply_post_type() );
+	$default_thread_replies = (bool) ( bbp_is_single_topic() && bbp_thread_replies() );
+
+	// Default query args
+	$default = array(
+		'post_type'           => $default_post_type,         // Only replies
+		'post_parent'         => $default_post_parent,       // Of this topic
+		'posts_per_page'      => bbp_get_replies_per_page(), // This many
+		'paged'               => bbp_get_paged(),            // On this page
+		'orderby'             => 'date',                     // Sorted by date
+		'order'               => 'ASC',                      // Oldest to newest
+		'hierarchical'        => $default_thread_replies,    // Hierarchical replies
+		'ignore_sticky_posts' => true,                       // Stickies not supported
+		's'                   => $default_reply_search,      // Maybe search
+	);
+
+	// What are the default allowed statuses (based on user caps)
+	if ( bbp_get_view_all() ) {
+
+		// Default view=all statuses
+		$post_statuses = array(
+			bbp_get_public_status_id(),
+			bbp_get_closed_status_id(),
+			bbp_get_spam_status_id(),
+			bbp_get_trash_status_id()
+		);
+
+		// Add support for private status
+		if ( current_user_can( 'read_private_replies' ) ) {
+			$post_statuses[] = bbp_get_private_status_id();
+		}
+
+		// Join post statuses together
+		$default['post_status'] = implode( ',', $post_statuses );
+
+	// Lean on the 'perm' query var value of 'readable' to provide statuses
+	} else {
+		$default['perm'] = 'readable';
+	}
+
+	/** Setup *****************************************************************/
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, $default, 'has_replies' );
+
+	// Set posts_per_page value if replies are threaded
+	$replies_per_page = $r['posts_per_page'];
+	if ( true === $r['hierarchical'] ) {
+		$r['posts_per_page'] = -1;
+	}
+
+	// Get bbPress
+	$bbp = bbpress();
+
+	// Call the query
+	$bbp->reply_query = new WP_Query( $r );
+
+	// Add pagination values to query object
+	$bbp->reply_query->posts_per_page = $replies_per_page;
+	$bbp->reply_query->paged          = $r['paged'];
+
+	// Never home, regardless of what parse_query says
+	$bbp->reply_query->is_home        = false;
+
+	// Reset is_single if single topic
+	if ( bbp_is_single_topic() ) {
+		$bbp->reply_query->is_single = true;
+	}
+
+	// Only add reply to if query returned results
+	if ( (int) $bbp->reply_query->found_posts ) {
+
+		// Get reply to for each reply
+		foreach ( $bbp->reply_query->posts as &$post ) {
+
+			// Check for reply post type
+			if ( bbp_get_reply_post_type() === $post->post_type ) {
+				$reply_to = bbp_get_reply_to( $post->ID );
+
+				// Make sure it's a reply to a reply
+				if ( empty( $reply_to ) || ( bbp_get_reply_topic_id( $post->ID ) === $reply_to ) ) {
+					$reply_to = 0;
+				}
+
+				// Add reply_to to the post object so we can walk it later
+				$post->reply_to = $reply_to;
+			}
+		}
+	}
+
+	// Only add pagination if query returned results
+	if ( (int) $bbp->reply_query->found_posts && (int) $bbp->reply_query->posts_per_page ) {
+
+		// If pretty permalinks are enabled, make our pagination pretty
+		if ( $wp_rewrite->using_permalinks() ) {
+
+			// User's replies
+			if ( bbp_is_single_user_replies() ) {
+				$base = bbp_get_user_replies_created_url( bbp_get_displayed_user_id() );
+
+			// Root profile page
+			} elseif ( bbp_is_single_user() ) {
+				$base = bbp_get_user_profile_url( bbp_get_displayed_user_id() );
+
+			// Page or single post
+			} elseif ( is_page() || is_single() ) {
+				$base = get_permalink();
+
+			// Single topic
+			} else {
+				$base = get_permalink( bbp_get_topic_id() );
+			}
+
+			$base = trailingslashit( $base ) . user_trailingslashit( $wp_rewrite->pagination_base . '/%#%/' );
+
+		// Unpretty permalinks
+		} else {
+			$base = add_query_arg( 'paged', '%#%' );
+		}
+
+		// Figure out total pages
+		if ( true === $r['hierarchical'] ) {
+			$walker      = new BBP_Walker_Reply;
+			$total_pages = ceil( (int) $walker->get_number_of_root_elements( $bbp->reply_query->posts ) / (int) $replies_per_page );
+		} else {
+			$total_pages = ceil( (int) $bbp->reply_query->found_posts / (int) $replies_per_page );
+
+			// Add pagination to query object
+			$bbp->reply_query->pagination_links = paginate_links( apply_filters( 'bbp_replies_pagination', array(
+				'base'      => $base,
+				'format'    => '',
+				'total'     => $total_pages,
+				'current'   => (int) $bbp->reply_query->paged,
+				'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
+				'next_text' => is_rtl() ? '&larr;' : '&rarr;',
+				'mid_size'  => 1,
+				'add_args'  => ( bbp_get_view_all() ) ? array( 'view' => 'all' ) : false
+			) ) );
+
+			// Remove first page from pagination
+			if ( $wp_rewrite->using_permalinks() ) {
+				$bbp->reply_query->pagination_links = str_replace( $wp_rewrite->pagination_base . '/1/', '', $bbp->reply_query->pagination_links );
+			} else {
+				$bbp->reply_query->pagination_links = str_replace( '&#038;paged=1', '', $bbp->reply_query->pagination_links );
+			}
+		}
+	}
+
+	// Return object
+	return apply_filters( 'bbp_has_replies', $bbp->reply_query->have_posts(), $bbp->reply_query );
+}
+
+/**
+ * Whether there are more replies available in the loop
+ *
+ * @since bbPress (r2553)
+ *
+ * @uses WP_Query bbPress::reply_query::have_posts() To check if there are more
+ *                                                    replies available
+ * @return object Replies information
+ */
+function bbp_replies() {
+
+	// Put into variable to check against next
+	$have_posts = bbpress()->reply_query->have_posts();
+
+	// Reset the post data when finished
+	if ( empty( $have_posts ) )
+		wp_reset_postdata();
+
+	return $have_posts;
+}
+
+/**
+ * Loads up the current reply in the loop
+ *
+ * @since bbPress (r2553)
+ *
+ * @uses WP_Query bbPress::reply_query::the_post() To get the current reply
+ * @return object Reply information
+ */
+function bbp_the_reply() {
+	return bbpress()->reply_query->the_post();
+}
+
+/**
+ * Output reply id
+ *
+ * @since bbPress (r2553)
+ *
+ * @param $reply_id Optional. Used to check emptiness
+ * @uses bbp_get_reply_id() To get the reply id
+ */
+function bbp_reply_id( $reply_id = 0 ) {
+	echo bbp_get_reply_id( $reply_id );
+}
+	/**
+	 * Return the id of the reply in a replies loop
+	 *
+	 * @since bbPress (r2553)
+	 *
+	 * @param $reply_id Optional. Used to check emptiness
+	 * @uses bbPress::reply_query::post::ID To get the reply id
+	 * @uses bbp_is_reply() To check if the search result is a reply
+	 * @uses bbp_is_single_reply() To check if it's a reply page
+	 * @uses bbp_is_reply_edit() To check if it's a reply edit page
+	 * @uses get_post_field() To get the post's post type
+	 * @uses WP_Query::post::ID To get the reply id
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses apply_filters() Calls 'bbp_get_reply_id' with the reply id and
+	 *                        supplied reply id
+	 * @return int The reply id
+	 */
+	function bbp_get_reply_id( $reply_id = 0 ) {
+		global $wp_query;
+
+		$bbp = bbpress();
+
+		// Easy empty checking
+		if ( !empty( $reply_id ) && is_numeric( $reply_id ) ) {
+			$bbp_reply_id = $reply_id;
+
+		// Currently inside a replies loop
+		} elseif ( !empty( $bbp->reply_query->in_the_loop ) && isset( $bbp->reply_query->post->ID ) ) {
+			$bbp_reply_id = $bbp->reply_query->post->ID;
+
+		// Currently inside a search loop
+		} elseif ( !empty( $bbp->search_query->in_the_loop ) && isset( $bbp->search_query->post->ID ) && bbp_is_reply( $bbp->search_query->post->ID ) ) {
+			$bbp_reply_id = $bbp->search_query->post->ID;
+
+		// Currently viewing a forum
+		} elseif ( ( bbp_is_single_reply() || bbp_is_reply_edit() ) && !empty( $bbp->current_reply_id ) ) {
+			$bbp_reply_id = $bbp->current_reply_id;
+
+		// Currently viewing a reply
+		} elseif ( ( bbp_is_single_reply() || bbp_is_reply_edit() ) && isset( $wp_query->post->ID ) ) {
+			$bbp_reply_id = $wp_query->post->ID;
+
+		// Fallback
+		} else {
+			$bbp_reply_id = 0;
+		}
+
+		return (int) apply_filters( 'bbp_get_reply_id', $bbp_reply_id, $reply_id );
+	}
+
+/**
+ * Gets a reply
+ *
+ * @since bbPress (r2787)
+ *
+ * @param int|object $reply reply id or reply object
+ * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. Default = OBJECT
+ * @param string $filter Optional Sanitation filter. See {@link sanitize_post()}
+ * @uses get_post() To get the reply
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses apply_filters() Calls 'bbp_get_reply' with the reply, output type and
+ *                        sanitation filter
+ * @return mixed Null if error or reply (in specified form) if success
+ */
+function bbp_get_reply( $reply, $output = OBJECT, $filter = 'raw' ) {
+	if ( empty( $reply ) || is_numeric( $reply ) )
+		$reply = bbp_get_reply_id( $reply );
+
+	$reply = get_post( $reply, OBJECT, $filter );
+	if ( empty( $reply ) )
+		return $reply;
+
+	if ( $reply->post_type !== bbp_get_reply_post_type() )
+		return null;
+
+	if ( $output === OBJECT ) {
+		return $reply;
+
+	} elseif ( $output === ARRAY_A ) {
+		$_reply = get_object_vars( $reply );
+		return $_reply;
+
+	} elseif ( $output === ARRAY_N ) {
+		$_reply = array_values( get_object_vars( $reply ) );
+		return $_reply;
+
+	}
+
+	return apply_filters( 'bbp_get_reply', $reply, $output, $filter );
+}
+
+/**
+ * Output the link to the reply in the reply loop
+ *
+ * @since bbPress (r2553)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_permalink() To get the reply permalink
+ */
+function bbp_reply_permalink( $reply_id = 0 ) {
+	echo esc_url( bbp_get_reply_permalink( $reply_id ) );
+}
+	/**
+	 * Return the link to the reply
+	 *
+	 * @since bbPress (r2553)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_permalink() To get the permalink of the reply
+	 * @uses apply_filters() Calls 'bbp_get_reply_permalink' with the link
+	 *                        and reply id
+	 * @return string Permanent link to reply
+	 */
+	function bbp_get_reply_permalink( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		return apply_filters( 'bbp_get_reply_permalink', get_permalink( $reply_id ), $reply_id );
+	}
+/**
+ * Output the paginated url to the reply in the reply loop
+ *
+ * @since bbPress (r2679)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_url() To get the reply url
+ */
+function bbp_reply_url( $reply_id = 0 ) {
+	echo esc_url( bbp_get_reply_url( $reply_id ) );
+}
+	/**
+	 * Return the paginated url to the reply in the reply loop
+	 *
+	 * @since bbPress (r2679)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @param $string $redirect_to Optional. Pass a redirect value for use with
+	 *                              shortcodes and other fun things.
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply_topic_id() To get the reply topic id
+	 * @uses bbp_get_topic_permalink() To get the topic permalink
+	 * @uses bbp_get_reply_position() To get the reply position
+	 * @uses get_option() To get the replies per page option
+	 * @uses WP_Rewrite::using_permalinks() To check if the blog uses
+	 *                                       permalinks
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses apply_filters() Calls 'bbp_get_reply_url' with the reply url,
+	 *                        reply id and bool count hidden
+	 * @return string Link to reply relative to paginated topic
+	 */
+	function bbp_get_reply_url( $reply_id = 0, $redirect_to = '' ) {
+
+		// Set needed variables
+		$reply_id   = bbp_get_reply_id      ( $reply_id );
+		$topic_id   = bbp_get_reply_topic_id( $reply_id );
+
+		// Hierarchical reply page
+		if ( bbp_thread_replies() ) {
+			$reply_page = 1;
+
+		// Standard reply page
+		} else {
+			$reply_page = ceil( (int) bbp_get_reply_position( $reply_id, $topic_id ) / (int) bbp_get_replies_per_page() );
+		}
+
+		$reply_hash = '#post-' . $reply_id;
+		$topic_link = bbp_get_topic_permalink( $topic_id, $redirect_to );
+		$topic_url  = remove_query_arg( 'view', $topic_link );
+
+		// Don't include pagination if on first page
+		if ( 1 >= $reply_page ) {
+			$url = trailingslashit( $topic_url ) . $reply_hash;
+
+		// Include pagination
+		} else {
+			global $wp_rewrite;
+
+			// Pretty permalinks
+			if ( $wp_rewrite->using_permalinks() ) {
+				$url = trailingslashit( $topic_url ) . trailingslashit( $wp_rewrite->pagination_base ) . trailingslashit( $reply_page ) . $reply_hash;
+
+			// Yucky links
+			} else {
+				$url = add_query_arg( 'paged', $reply_page, $topic_url ) . $reply_hash;
+			}
+		}
+
+		// Add topic view query arg back to end if it is set
+		if ( bbp_get_view_all() )
+			$url = bbp_add_view_all( $url );
+
+		return apply_filters( 'bbp_get_reply_url', $url, $reply_id, $redirect_to );
+	}
+
+/**
+ * Output the title of the reply
+ *
+ * @since bbPress (r2553)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_title() To get the reply title
+ */
+function bbp_reply_title( $reply_id = 0 ) {
+	echo bbp_get_reply_title( $reply_id );
+}
+
+	/**
+	 * Return the title of the reply
+	 *
+	 * @since bbPress (r2553)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_the_title() To get the reply title
+	 * @uses apply_filters() Calls 'bbp_get_reply_title' with the title and
+	 *                        reply id
+	 * @return string Title of reply
+	 */
+	function bbp_get_reply_title( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		return apply_filters( 'bbp_get_reply_title', get_the_title( $reply_id ), $reply_id );
+	}
+
+	/**
+	 * Get empty reply title fallback.
+	 *
+	 * @since bbPress (r5177)
+	 *
+	 * @param string $reply_title Required. Reply Title
+	 * @param int $reply_id Required. Reply ID
+	 * @uses bbp_get_reply_topic_title() To get the reply topic title
+	 * @uses apply_filters() Calls 'bbp_get_reply_title_fallback' with the title and reply ID
+	 * @return string Title of reply
+	 */
+	function bbp_get_reply_title_fallback( $post_title = '', $post_id = 0 ) {
+
+		// Bail if title not empty, or post is not a reply
+		if ( ! empty( $post_title ) || ! bbp_is_reply( $post_id ) ) {
+			return $post_title;
+		}
+
+		// Get reply topic title.
+		$topic_title = bbp_get_reply_topic_title( $post_id );
+
+		// Get empty reply title fallback.
+		$reply_title = sprintf( __( 'Reply To: %s', 'bbpress' ), $topic_title );
+
+		return apply_filters( 'bbp_get_reply_title_fallback', $reply_title, $post_id, $topic_title );
+	}
+
+/**
+ * Output the content of the reply
+ *
+ * @since bbPress (r2553)
+ *
+ * @param int $reply_id Optional. reply id
+ * @uses bbp_get_reply_content() To get the reply content
+ */
+function bbp_reply_content( $reply_id = 0 ) {
+	echo bbp_get_reply_content( $reply_id );
+}
+	/**
+	 * Return the content of the reply
+	 *
+	 * @since bbPress (r2780)
+	 *
+	 * @param int $reply_id Optional. reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses post_password_required() To check if the reply requires pass
+	 * @uses get_the_password_form() To get the password form
+	 * @uses get_post_field() To get the content post field
+	 * @uses apply_filters() Calls 'bbp_get_reply_content' with the content
+	 *                        and reply id
+	 * @return string Content of the reply
+	 */
+	function bbp_get_reply_content( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// Check if password is required
+		if ( post_password_required( $reply_id ) )
+			return get_the_password_form();
+
+		$content = get_post_field( 'post_content', $reply_id );
+
+		return apply_filters( 'bbp_get_reply_content', $content, $reply_id );
+	}
+
+/**
+ * Output the excerpt of the reply
+ *
+ * @since bbPress (r2751)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @param int $length Optional. Length of the excerpt. Defaults to 100 letters
+ * @uses bbp_get_reply_excerpt() To get the reply excerpt
+ */
+function bbp_reply_excerpt( $reply_id = 0, $length = 100 ) {
+	echo bbp_get_reply_excerpt( $reply_id, $length );
+}
+	/**
+	 * Return the excerpt of the reply
+	 *
+	 * @since bbPress (r2751)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @param int $length Optional. Length of the excerpt. Defaults to 100
+	 *                     letters
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_post_field() To get the excerpt
+	 * @uses bbp_get_reply_content() To get the reply content
+	 * @uses apply_filters() Calls 'bbp_get_reply_excerpt' with the excerpt,
+	 *                        reply id and length
+	 * @return string Reply Excerpt
+	 */
+	function bbp_get_reply_excerpt( $reply_id = 0, $length = 100 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+		$length   = (int) $length;
+		$excerpt  = get_post_field( 'post_excerpt', $reply_id );
+
+		if ( empty( $excerpt ) ) {
+			$excerpt = bbp_get_reply_content( $reply_id );
+		}
+
+		$excerpt = trim ( strip_tags( $excerpt ) );
+
+		// Multibyte support
+		if ( function_exists( 'mb_strlen' ) ) {
+			$excerpt_length = mb_strlen( $excerpt );
+		} else {
+			$excerpt_length = strlen( $excerpt );
+		}
+
+		if ( !empty( $length ) && ( $excerpt_length > $length ) ) {
+			$excerpt  = substr( $excerpt, 0, $length - 1 );
+			$excerpt .= '&hellip;';
+		}
+
+		return apply_filters( 'bbp_get_reply_excerpt', $excerpt, $reply_id, $length );
+	}
+
+/**
+ * Output the post date and time of a reply
+ *
+ * @since bbPress (r4155)
+ *
+ * @param int $reply_id Optional. Reply id.
+ * @param bool $humanize Optional. Humanize output using time_since
+ * @param bool $gmt Optional. Use GMT
+ * @uses bbp_get_reply_post_date() to get the output
+ */
+function bbp_reply_post_date( $reply_id = 0, $humanize = false, $gmt = false ) {
+	echo bbp_get_reply_post_date( $reply_id, $humanize, $gmt );
+}
+	/**
+	 * Return the post date and time of a reply
+	 *
+	 * @since bbPress (r4155)
+	 *
+	 * @param int $reply_id Optional. Reply id.
+	 * @param bool $humanize Optional. Humanize output using time_since
+	 * @param bool $gmt Optional. Use GMT
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_post_time() to get the reply post time
+	 * @uses bbp_get_time_since() to maybe humanize the reply post time
+	 * @return string
+	 */
+	function bbp_get_reply_post_date( $reply_id = 0, $humanize = false, $gmt = false ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// 4 days, 4 hours ago
+		if ( !empty( $humanize ) ) {
+			$gmt_s  = !empty( $gmt ) ? 'G' : 'U';
+			$date   = get_post_time( $gmt_s, $gmt, $reply_id );
+			$time   = false; // For filter below
+			$result = bbp_get_time_since( $date );
+
+		// August 4, 2012 at 2:37 pm
+		} else {
+			$date   = get_post_time( get_option( 'date_format' ), $gmt, $reply_id, true );
+			$time   = get_post_time( get_option( 'time_format' ), $gmt, $reply_id, true );
+			$result = sprintf( _x( '%1$s at %2$s', 'date at time', 'bbpress' ), $date, $time );
+		}
+
+		return apply_filters( 'bbp_get_reply_post_date', $result, $reply_id, $humanize, $gmt, $date, $time );
+	}
+
+/**
+ * Append revisions to the reply content
+ *
+ * @since bbPress (r2782)
+ *
+ * @param string $content Optional. Content to which we need to append the revisions to
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_revision_log() To get the reply revision log
+ * @uses apply_filters() Calls 'bbp_reply_append_revisions' with the processed
+ *                        content, original content and reply id
+ * @return string Content with the revisions appended
+ */
+function bbp_reply_content_append_revisions( $content = '', $reply_id = 0 ) {
+
+	// Bail if in admin or feed
+	if ( is_admin() || is_feed() )
+		return $content;
+
+	// Validate the ID
+	$reply_id = bbp_get_reply_id( $reply_id );
+
+	return apply_filters( 'bbp_reply_append_revisions', $content . bbp_get_reply_revision_log( $reply_id ), $content, $reply_id );
+}
+
+/**
+ * Output the revision log of the reply
+ *
+ * @since bbPress (r2782)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_revision_log() To get the reply revision log
+ */
+function bbp_reply_revision_log( $reply_id = 0 ) {
+	echo bbp_get_reply_revision_log( $reply_id );
+}
+	/**
+	 * Return the formatted revision log of the reply
+	 *
+	 * @since bbPress (r2782)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply_revisions() To get the reply revisions
+	 * @uses bbp_get_reply_raw_revision_log() To get the raw revision log
+	 * @uses bbp_get_reply_author_display_name() To get the reply author
+	 * @uses bbp_get_reply_author_link() To get the reply author link
+	 * @uses bbp_convert_date() To convert the date
+	 * @uses bbp_get_time_since() To get the time in since format
+	 * @uses apply_filters() Calls 'bbp_get_reply_revision_log' with the
+	 *                        log and reply id
+	 * @return string Revision log of the reply
+	 */
+	function bbp_get_reply_revision_log( $reply_id = 0 ) {
+
+		// Create necessary variables
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// Show the topic reply log if this is a topic in a reply loop
+		if ( bbp_is_topic( $reply_id ) ) {
+			return bbp_get_topic_revision_log( $reply_id );
+		}
+
+		// Get the reply revision log (out of post meta
+		$revision_log = bbp_get_reply_raw_revision_log( $reply_id );
+
+		// Check reply and revision log exist
+		if ( empty( $reply_id ) || empty( $revision_log ) || !is_array( $revision_log ) )
+			return false;
+
+		// Get the actual revisions
+		$revisions = bbp_get_reply_revisions( $reply_id );
+		if ( empty( $revisions ) )
+			return false;
+
+		$r = "\n\n" . '<ul id="bbp-reply-revision-log-' . esc_attr( $reply_id ) . '" class="bbp-reply-revision-log">' . "\n\n";
+
+		// Loop through revisions
+		foreach ( (array) $revisions as $revision ) {
+
+			if ( empty( $revision_log[$revision->ID] ) ) {
+				$author_id = $revision->post_author;
+				$reason    = '';
+			} else {
+				$author_id = $revision_log[$revision->ID]['author'];
+				$reason    = $revision_log[$revision->ID]['reason'];
+			}
+
+			$author = bbp_get_author_link( array( 'size' => 14, 'link_text' => bbp_get_reply_author_display_name( $revision->ID ), 'post_id' => $revision->ID ) );
+			$since  = bbp_get_time_since( bbp_convert_date( $revision->post_modified ) );
+
+			$r .= "\t" . '<li id="bbp-reply-revision-log-' . esc_attr( $reply_id ) . '-item-' . esc_attr( $revision->ID ) . '" class="bbp-reply-revision-log-item">' . "\n";
+			if ( !empty( $reason ) ) {
+				$r .= "\t\t" . sprintf( esc_html__( 'This reply was modified %1$s by %2$s. Reason: %3$s', 'bbpress' ), esc_html( $since ), $author, esc_html( $reason ) ) . "\n";
+			} else {
+				$r .= "\t\t" . sprintf( esc_html__( 'This reply was modified %1$s by %2$s.', 'bbpress' ), esc_html( $since ), $author ) . "\n";
+			}
+			$r .= "\t" . '</li>' . "\n";
+
+		}
+
+		$r .= "\n" . '</ul>' . "\n\n";
+
+		return apply_filters( 'bbp_get_reply_revision_log', $r, $reply_id );
+	}
+		/**
+		 * Return the raw revision log of the reply
+		 *
+		 * @since bbPress (r2782)
+		 *
+		 * @param int $reply_id Optional. Reply id
+		 * @uses bbp_get_reply_id() To get the reply id
+		 * @uses get_post_meta() To get the revision log meta
+		 * @uses apply_filters() Calls 'bbp_get_reply_raw_revision_log'
+		 *                        with the log and reply id
+		 * @return string Raw revision log of the reply
+		 */
+		function bbp_get_reply_raw_revision_log( $reply_id = 0 ) {
+			$reply_id     = bbp_get_reply_id( $reply_id );
+			$revision_log = get_post_meta( $reply_id, '_bbp_revision_log', true );
+			$revision_log = empty( $revision_log ) ? array() : $revision_log;
+
+			return apply_filters( 'bbp_get_reply_raw_revision_log', $revision_log, $reply_id );
+		}
+
+/**
+ * Return the revisions of the reply
+ *
+ * @since bbPress (r2782)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses wp_get_post_revisions() To get the reply revisions
+ * @uses apply_filters() Calls 'bbp_get_reply_revisions'
+ *                        with the revisions and reply id
+ * @return string reply revisions
+ */
+function bbp_get_reply_revisions( $reply_id = 0 ) {
+	$reply_id  = bbp_get_reply_id( $reply_id );
+	$revisions = wp_get_post_revisions( $reply_id, array( 'order' => 'ASC' ) );
+
+	return apply_filters( 'bbp_get_reply_revisions', $revisions, $reply_id );
+}
+
+/**
+ * Return the revision count of the reply
+ *
+ * @since bbPress (r2782)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_reply_revisions() To get the reply revisions
+ * @uses apply_filters() Calls 'bbp_get_reply_revision_count'
+ *                        with the revision count and reply id
+ * @return string reply revision count
+ */
+function bbp_get_reply_revision_count( $reply_id = 0, $integer = false ) {
+	$count  = (int) count( bbp_get_reply_revisions( $reply_id ) );
+	$filter = ( true === $integer ) ? 'bbp_get_reply_revision_count_int' : 'bbp_get_reply_revision_count';
+
+	return apply_filters( $filter, $count, $reply_id );
+}
+
+/**
+ * Output the status of the reply
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_status() To get the reply status
+ */
+function bbp_reply_status( $reply_id = 0 ) {
+	echo bbp_get_reply_status( $reply_id );
+}
+	/**
+	 * Return the status of the reply
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_post_status() To get the reply status
+	 * @uses apply_filters() Calls 'bbp_get_reply_status' with the reply id
+	 * @return string Status of reply
+	 */
+	function bbp_get_reply_status( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+		return apply_filters( 'bbp_get_reply_status', get_post_status( $reply_id ), $reply_id );
+	}
+
+/**
+ * Is the reply not spam or deleted?
+ *
+ * @since bbPress (r3496)
+ *
+ * @param int $reply_id Optional. Topic id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_reply_status() To get the reply status
+ * @return bool True if published, false if not.
+ */
+function bbp_is_reply_published( $reply_id = 0 ) {
+	$reply_status = bbp_get_reply_status( bbp_get_reply_id( $reply_id ) ) === bbp_get_public_status_id();
+	return (bool) apply_filters( 'bbp_is_reply_published', (bool) $reply_status, $reply_id );
+}
+
+/**
+ * Is the reply marked as spam?
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_reply_status() To get the reply status
+ * @return bool True if spam, false if not.
+ */
+function bbp_is_reply_spam( $reply_id = 0 ) {
+	$reply_status = bbp_get_reply_status( bbp_get_reply_id( $reply_id ) ) === bbp_get_spam_status_id();
+	return (bool) apply_filters( 'bbp_is_reply_spam', (bool) $reply_status, $reply_id );
+}
+
+/**
+ * Is the reply trashed?
+ *
+ * @since bbPress (r2884)
+ *
+ * @param int $reply_id Optional. Topic id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_reply_status() To get the reply status
+ * @return bool True if spam, false if not.
+ */
+function bbp_is_reply_trash( $reply_id = 0 ) {
+	$reply_status = bbp_get_reply_status( bbp_get_reply_id( $reply_id ) ) === bbp_get_trash_status_id();
+	return (bool) apply_filters( 'bbp_is_reply_trash', (bool) $reply_status, $reply_id );
+}
+
+/**
+ * Is the reply by an anonymous user?
+ *
+ * @since bbPress (r2753)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_reply_author_id() To get the reply author id
+ * @uses get_post_meta() To get the anonymous name and email metas
+ * @return bool True if the post is by an anonymous user, false if not.
+ */
+function bbp_is_reply_anonymous( $reply_id = 0 ) {
+	$reply_id = bbp_get_reply_id( $reply_id );
+	$retval   = false;
+
+	if ( !bbp_get_reply_author_id( $reply_id ) )
+		$retval = true;
+
+	elseif ( get_post_meta( $reply_id, '_bbp_anonymous_name', true ) )
+		$retval = true;
+
+	elseif ( get_post_meta( $reply_id, '_bbp_anonymous_email', true ) )
+		$retval = true;
+
+	return (bool) apply_filters( 'bbp_is_reply_anonymous', $retval, $reply_id );
+}
+
+/**
+ * Deprecated. Use bbp_reply_author_display_name() instead.
+ *
+ * Output the author of the reply
+ *
+ * @since bbPress (r2667)
+ * @deprecated bbPress (r5119)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_author() To get the reply author
+ */
+function bbp_reply_author( $reply_id = 0 ) {
+	echo bbp_get_reply_author( $reply_id );
+}
+	/**
+	 * Deprecated. Use bbp_get_reply_author_display_name() instead.
+	 *
+	 * Return the author of the reply
+	 *
+	 * @since bbPress (r2667)
+	 * @deprecated bbPress (r5119)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_is_reply_anonymous() To check if the reply is by an
+	 *                                 anonymous user
+	 * @uses get_the_author_meta() To get the reply author display name
+	 * @uses get_post_meta() To get the anonymous poster name
+	 * @uses apply_filters() Calls 'bbp_get_reply_author' with the reply
+	 *                        author and reply id
+	 * @return string Author of reply
+	 */
+	function bbp_get_reply_author( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		if ( !bbp_is_reply_anonymous( $reply_id ) ) {
+			$author = get_the_author_meta( 'display_name', bbp_get_reply_author_id( $reply_id ) );
+		} else {
+			$author = get_post_meta( $reply_id, '_bbp_anonymous_name', true );
+		}
+
+		return apply_filters( 'bbp_get_reply_author', $author, $reply_id );
+	}
+
+/**
+ * Output the author ID of the reply
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_author_id() To get the reply author id
+ */
+function bbp_reply_author_id( $reply_id = 0 ) {
+	echo bbp_get_reply_author_id( $reply_id );
+}
+	/**
+	 * Return the author ID of the reply
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_post_field() To get the reply author id
+	 * @uses apply_filters() Calls 'bbp_get_reply_author_id' with the author
+	 *                        id and reply id
+	 * @return string Author id of reply
+	 */
+	function bbp_get_reply_author_id( $reply_id = 0 ) {
+		$reply_id  = bbp_get_reply_id( $reply_id );
+		$author_id = get_post_field( 'post_author', $reply_id );
+
+		return (int) apply_filters( 'bbp_get_reply_author_id', $author_id, $reply_id );
+	}
+
+/**
+ * Output the author display_name of the reply
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_author_display_name()
+ */
+function bbp_reply_author_display_name( $reply_id = 0 ) {
+	echo bbp_get_reply_author_display_name( $reply_id );
+}
+	/**
+	 * Return the author display_name of the reply
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_is_reply_anonymous() To check if the reply is by an
+	 *                                 anonymous user
+	 * @uses bbp_get_reply_author_id() To get the reply author id
+	 * @uses get_the_author_meta() To get the reply author's display name
+	 * @uses get_post_meta() To get the anonymous poster's name
+	 * @uses apply_filters() Calls 'bbp_get_reply_author_display_name' with
+	 *                        the author display name and reply id
+	 * @return string Reply's author's display name
+	 */
+	function bbp_get_reply_author_display_name( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// User is not a guest
+		if ( !bbp_is_reply_anonymous( $reply_id ) ) {
+
+			// Get the author ID
+			$author_id = bbp_get_reply_author_id( $reply_id );
+
+			// Try to get a display name
+			$author_name = get_the_author_meta( 'display_name', $author_id );
+
+			// Fall back to user login
+			if ( empty( $author_name ) ) {
+				$author_name = get_the_author_meta( 'user_login', $author_id );
+			}
+
+		// User does not have an account
+		} else {
+			$author_name = get_post_meta( $reply_id, '_bbp_anonymous_name', true );
+		}
+
+		// If nothing could be found anywhere, use Anonymous
+		if ( empty( $author_name ) )
+			$author_name = __( 'Anonymous', 'bbpress' );
+
+		// Encode possible UTF8 display names
+		if ( seems_utf8( $author_name ) === false )
+			$author_name = utf8_encode( $author_name );
+
+		return apply_filters( 'bbp_get_reply_author_display_name', $author_name, $reply_id );
+	}
+
+/**
+ * Output the author avatar of the reply
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @param int $size Optional. Size of the avatar. Defaults to 40
+ * @uses bbp_get_reply_author_avatar() To get the reply author id
+ */
+function bbp_reply_author_avatar( $reply_id = 0, $size = 40 ) {
+	echo bbp_get_reply_author_avatar( $reply_id, $size );
+}
+	/**
+	 * Return the author avatar of the reply
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @param int $size Optional. Size of the avatar. Defaults to 40
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_is_reply_anonymous() To check if the reply is by an
+	 *                                 anonymous user
+	 * @uses bbp_get_reply_author_id() To get the reply author id
+	 * @uses get_post_meta() To get the anonymous poster's email id
+	 * @uses get_avatar() To get the avatar
+	 * @uses apply_filters() Calls 'bbp_get_reply_author_avatar' with the
+	 *                        author avatar, reply id and size
+	 * @return string Avatar of author of the reply
+	 */
+	function bbp_get_reply_author_avatar( $reply_id = 0, $size = 40 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+		if ( !empty( $reply_id ) ) {
+			// Check for anonymous user
+			if ( !bbp_is_reply_anonymous( $reply_id ) ) {
+				$author_avatar = get_avatar( bbp_get_reply_author_id( $reply_id ), $size );
+			} else {
+				$author_avatar = get_avatar( get_post_meta( $reply_id, '_bbp_anonymous_email', true ), $size );
+			}
+		} else {
+			$author_avatar = '';
+		}
+
+		return apply_filters( 'bbp_get_reply_author_avatar', $author_avatar, $reply_id, $size );
+	}
+
+/**
+ * Output the author link of the reply
+ *
+ * @since bbPress (r2717)
+ *
+ * @param mixed $args Optional. If it is an integer, it is used as reply id.
+ * @uses bbp_get_reply_author_link() To get the reply author link
+ */
+function bbp_reply_author_link( $args = '' ) {
+	echo bbp_get_reply_author_link( $args );
+}
+	/**
+	 * Return the author link of the reply
+	 *
+	 * @since bbPress (r2717)
+	 *
+	 * @param mixed $args Optional. If an integer, it is used as reply id.
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_is_reply_anonymous() To check if the reply is by an
+	 *                                 anonymous user
+	 * @uses bbp_get_reply_author_url() To get the reply author url
+	 * @uses bbp_get_reply_author_avatar() To get the reply author avatar
+	 * @uses bbp_get_reply_author_display_name() To get the reply author display
+	 *                                      name
+	 * @uses bbp_get_user_display_role() To get the reply author display role
+	 * @uses bbp_get_reply_author_id() To get the reply author id
+	 * @uses apply_filters() Calls 'bbp_get_reply_author_link' with the
+	 *                        author link and args
+	 * @return string Author link of reply
+	 */
+	function bbp_get_reply_author_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'post_id'    => 0,
+			'link_title' => '',
+			'type'       => 'both',
+			'size'       => 80,
+			'sep'        => '&nbsp;',
+			'show_role'  => false
+		), 'get_reply_author_link' );
+
+		// Used as reply_id
+		if ( is_numeric( $args ) ) {
+			$reply_id = bbp_get_reply_id( $args );
+		} else {
+			$reply_id = bbp_get_reply_id( $r['post_id'] );
+		}
+
+		// Reply ID is good
+		if ( !empty( $reply_id ) ) {
+
+			// Get some useful reply information
+			$author_url = bbp_get_reply_author_url( $reply_id );
+			$anonymous  = bbp_is_reply_anonymous( $reply_id );
+
+			// Tweak link title if empty
+			if ( empty( $r['link_title'] ) ) {
+				$link_title = sprintf( empty( $anonymous ) ? __( 'View %s\'s profile', 'bbpress' ) : __( 'Visit %s\'s website', 'bbpress' ), bbp_get_reply_author_display_name( $reply_id ) );
+
+			// Use what was passed if not
+			} else {
+				$link_title = $r['link_title'];
+			}
+
+			// Setup title and author_links array
+			$link_title   = !empty( $link_title ) ? ' title="' . esc_attr( $link_title ) . '"' : '';
+			$author_links = array();
+
+			// Get avatar
+			if ( 'avatar' === $r['type'] || 'both' === $r['type'] ) {
+				$author_links['avatar'] = bbp_get_reply_author_avatar( $reply_id, $r['size'] );
+			}
+
+			// Get display name
+			if ( 'name' === $r['type']   || 'both' === $r['type'] ) {
+				$author_links['name'] = bbp_get_reply_author_display_name( $reply_id );
+			}
+
+			// Link class
+			$link_class = ' class="bbp-author-' . esc_attr( $r['type'] ) . '"';
+
+			// Add links if not anonymous and existing user
+			if ( empty( $anonymous ) && bbp_user_has_profile( bbp_get_reply_author_id( $reply_id ) ) ) {
+
+				// Assemble the links
+				foreach ( $author_links as $link => $link_text ) {
+					$link_class = ' class="bbp-author-' . $link . '"';
+					$author_link[] = sprintf( '<a href="%1$s"%2$s%3$s>%4$s</a>', esc_url( $author_url ), $link_title, $link_class, $link_text );
+				}
+
+				if ( true === $r['show_role'] ) {
+					$author_link[] = bbp_get_reply_author_role( array( 'reply_id' => $reply_id ) );
+				}
+
+				$author_link = implode( $r['sep'], $author_link );
+
+			// No links if anonymous
+			} else {
+				$author_link = implode( $r['sep'], $author_links );
+			}
+
+		// No replies so link is empty
+		} else {
+			$author_link = '';
+		}
+
+		return apply_filters( 'bbp_get_reply_author_link', $author_link, $r );
+	}
+
+/**
+ * Output the author url of the reply
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_author_url() To get the reply author url
+ */
+function bbp_reply_author_url( $reply_id = 0 ) {
+	echo esc_url( bbp_get_reply_author_url( $reply_id ) );
+}
+	/**
+	 * Return the author url of the reply
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_is_reply_anonymous() To check if the reply is by an anonymous
+	 *                                 user
+	 * @uses bbp_user_has_profile() To check if the user has a profile
+	 * @uses bbp_get_reply_author_id() To get the reply author id
+	 * @uses bbp_get_user_profile_url() To get the user profile url
+	 * @uses get_post_meta() To get the anonymous poster's website url
+	 * @uses apply_filters() Calls bbp_get_reply_author_url with the author
+	 *                        url & reply id
+	 * @return string Author URL of the reply
+	 */
+	function bbp_get_reply_author_url( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// Check for anonymous user or non-existant user
+		if ( !bbp_is_reply_anonymous( $reply_id ) && bbp_user_has_profile( bbp_get_reply_author_id( $reply_id ) ) ) {
+			$author_url = bbp_get_user_profile_url( bbp_get_reply_author_id( $reply_id ) );
+		} else {
+			$author_url = get_post_meta( $reply_id, '_bbp_anonymous_website', true );
+			if ( empty( $author_url ) ) {
+				$author_url = '';
+			}
+		}
+
+		return apply_filters( 'bbp_get_reply_author_url', $author_url, $reply_id );
+	}
+
+/**
+ * Output the reply author email address
+ *
+ * @since bbPress (r3445)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_author_email() To get the reply author email
+ */
+function bbp_reply_author_email( $reply_id = 0 ) {
+	echo bbp_get_reply_author_email( $reply_id );
+}
+	/**
+	 * Return the reply author email address
+	 *
+	 * @since bbPress (r3445)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_is_reply_anonymous() To check if the reply is by an anonymous
+	 *                                 user
+	 * @uses bbp_get_reply_author_id() To get the reply author id
+	 * @uses get_userdata() To get the user data
+	 * @uses get_post_meta() To get the anonymous poster's website email
+	 * @uses apply_filters() Calls bbp_get_reply_author_email with the author
+	 *                        email & reply id
+	 * @return string Reply author email address
+	 */
+	function bbp_get_reply_author_email( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// Not anonymous
+		if ( !bbp_is_reply_anonymous( $reply_id ) ) {
+
+			// Use reply author email address
+			$user_id      = bbp_get_reply_author_id( $reply_id );
+			$user         = get_userdata( $user_id );
+			$author_email = !empty( $user->user_email ) ? $user->user_email : '';
+
+		// Anonymous
+		} else {
+
+			// Get email from post meta
+			$author_email = get_post_meta( $reply_id, '_bbp_anonymous_email', true );
+
+			// Sanity check for missing email address
+			if ( empty( $author_email ) ) {
+				$author_email = '';
+			}
+		}
+
+		return apply_filters( 'bbp_get_reply_author_email', $author_email, $reply_id );
+	}
+
+/**
+ * Output the reply author role
+ *
+ * @since bbPress (r3860)
+ *
+ * @param array $args Optional.
+ * @uses bbp_get_reply_author_role() To get the reply author role
+ */
+function bbp_reply_author_role( $args = array() ) {
+	echo bbp_get_reply_author_role( $args );
+}
+	/**
+	 * Return the reply author role
+	 *
+	 * @since bbPress (r3860)
+	 *
+	 * @param array $args Optional.
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_user_display_role() To get the user display role
+	 * @uses bbp_get_reply_author_id() To get the reply author id
+	 * @uses apply_filters() Calls bbp_get_reply_author_role with the author
+	 *                        role & args
+	 * @return string Reply author role
+	 */
+	function bbp_get_reply_author_role( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'reply_id' => 0,
+			'class'    => 'bbp-author-role',
+			'before'   => '',
+			'after'    => ''
+		), 'get_reply_author_role' );
+
+		$reply_id    = bbp_get_reply_id( $r['reply_id'] );
+		$role        = bbp_get_user_display_role( bbp_get_reply_author_id( $reply_id ) );
+		$author_role = sprintf( '%1$s<div class="%2$s">%3$s</div>%4$s', $r['before'], esc_attr( $r['class'] ), esc_html( $role ), $r['after'] );
+
+		return apply_filters( 'bbp_get_reply_author_role', $author_role, $r );
+	}
+
+/**
+ * Output the topic title a reply belongs to
+ *
+ * @since bbPress (r2553)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_topic_title() To get the reply topic title
+ */
+function bbp_reply_topic_title( $reply_id = 0 ) {
+	echo bbp_get_reply_topic_title( $reply_id );
+}
+	/**
+	 * Return the topic title a reply belongs to
+	 *
+	 * @since bbPress (r2553)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply_topic_id() To get the reply topic id
+	 * @uses bbp_get_topic_title() To get the reply topic title
+	 * @uses apply_filters() Calls 'bbp_get_reply_topic_title' with the
+	 *                        topic title and reply id
+	 * @return string Reply's topic's title
+	 */
+	function bbp_get_reply_topic_title( $reply_id = 0 ) {
+		$reply_id = bbp_get_reply_id( $reply_id );
+		$topic_id = bbp_get_reply_topic_id( $reply_id );
+
+		return apply_filters( 'bbp_get_reply_topic_title', bbp_get_topic_title( $topic_id ), $reply_id );
+	}
+
+/**
+ * Output the topic id a reply belongs to
+ *
+ * @since bbPress (r2553)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ */
+function bbp_reply_topic_id( $reply_id = 0 ) {
+	echo bbp_get_reply_topic_id( $reply_id );
+}
+	/**
+	 * Return the topic id a reply belongs to
+	 *
+	 * @since bbPress (r2553)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_post_meta() To get the reply topic id from meta
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses apply_filters() Calls 'bbp_get_reply_topic_id' with the topic
+	 *                        id and reply id
+	 * @return int Reply's topic id
+	 */
+	function bbp_get_reply_topic_id( $reply_id = 0 ) {
+
+		// Assume there is no topic id
+		$topic_id = 0;
+
+		// Check that reply_id is valid
+		if ( $reply_id = bbp_get_reply_id( $reply_id ) )
+
+			// Get topic_id from reply
+			if ( $topic_id = get_post_meta( $reply_id, '_bbp_topic_id', true ) )
+
+				// Validate the topic_id
+				$topic_id = bbp_get_topic_id( $topic_id );
+
+		return (int) apply_filters( 'bbp_get_reply_topic_id', $topic_id, $reply_id );
+	}
+
+/**
+ * Output the forum id a reply belongs to
+ *
+ * @since bbPress (r2679)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_forum_id() To get the reply forum id
+ */
+function bbp_reply_forum_id( $reply_id = 0 ) {
+	echo bbp_get_reply_forum_id( $reply_id );
+}
+	/**
+	 * Return the forum id a reply belongs to
+	 *
+	 * @since bbPress (r2679)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_post_meta() To get the reply forum id
+	 * @uses apply_filters() Calls 'bbp_get_reply_forum_id' with the forum
+	 *                        id and reply id
+	 * @return int Reply's forum id
+	 */
+	function bbp_get_reply_forum_id( $reply_id = 0 ) {
+
+		// Assume there is no forum
+		$forum_id = 0;
+
+		// Check that reply_id is valid
+		if ( $reply_id = bbp_get_reply_id( $reply_id ) )
+
+			// Get forum_id from reply
+			if ( $forum_id = get_post_meta( $reply_id, '_bbp_forum_id', true ) )
+
+				// Validate the forum_id
+				$forum_id = bbp_get_forum_id( $forum_id );
+
+		return (int) apply_filters( 'bbp_get_reply_forum_id', $forum_id, $reply_id );
+	}
+
+/**
+ * Output the reply's ancestor reply id
+ *
+ * @since bbPress (r4944)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_ancestor_id() To get the reply's ancestor id
+ */
+function bbp_reply_ancestor_id( $reply_id = 0 ) {
+	echo bbp_get_reply_ancestor_id( $reply_id );
+}
+	/**
+	 * Return the reply's ancestor reply id
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @param in $reply_id Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 */
+	function bbp_get_reply_ancestor_id( $reply_id = 0 ) {
+
+		// Validation
+		$reply_id = bbp_get_reply_id( $reply_id );
+		if ( empty( $reply_id ) )
+			return false;
+
+		// Find highest reply ancestor
+		$ancestor_id = $reply_id;
+		while ( $parent_id = bbp_get_reply_to( $ancestor_id ) ) {
+			if ( empty( $parent_id ) || ( $parent_id === $ancestor_id ) || ( bbp_get_reply_topic_id( $reply_id ) === $parent_id ) || ( $parent_id === $reply_id ) ) {
+				break;
+			}
+			$ancestor_id = $parent_id;
+		}
+
+		return (int) $ancestor_id;
+	}
+
+/**
+ * Output the reply to id of a reply
+ *
+ * @since bbPress (r4944)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_to() To get the reply to id
+ */
+function bbp_reply_to( $reply_id = 0 ) {
+	echo bbp_get_reply_to( $reply_id );
+}
+	/**
+	 * Return the reply to id of a reply
+	 *
+ 	 * @since bbPress (r4944)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses get_post_meta() To get the reply to id
+	 * @uses apply_filters() Calls 'bbp_get_reply_to' with the reply to id and
+	 *                        reply id
+	 * @return int Reply's reply to id
+	 */
+	function bbp_get_reply_to( $reply_id = 0 ) {
+
+		// Assume there is no reply_to set
+		$reply_to = 0;
+
+		// Check that reply_id is valid
+		$reply_id = bbp_get_reply_id( $reply_id );
+
+		// Get reply_to value
+		if ( !empty( $reply_id ) ) {
+			$reply_to = (int) get_post_meta( $reply_id, '_bbp_reply_to', true );
+		}
+
+		return (int) apply_filters( 'bbp_get_reply_to', $reply_to, $reply_id );
+	}
+
+/**
+ * Output the link for the reply to
+ *
+ * @since bbPress (r4944)
+ *
+ * @param array $args
+ * @uses bbp_get_reply_to_link() To get the reply to link
+ */
+function bbp_reply_to_link( $args = array() ) {
+	echo bbp_get_reply_to_link( $args );
+}
+
+	/**
+	 * Return the link for a reply to a reply
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @param array $args Arguments
+	 * @uses bbp_current_user_can_access_create_reply_form() To check permissions
+	 * @uses bbp_get_reply_id() To validate the reply id
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses apply_filters() Calls 'bbp_get_reply_to_link' with the formatted link,
+	 *                        the arguments array, and the reply
+	 * @return string Link for a reply to a reply
+	 */
+	function bbp_get_reply_to_link( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'reply_text'   => __( 'Reply', 'bbpress' ),
+			'depth'        => 0,
+			'add_below'    => 'post',
+			'respond_id'   => 'new-reply-' . bbp_get_topic_id(),
+		), 'get_reply_to_link' );
+
+		// Get the reply to use it's ID and post_parent
+		$reply = bbp_get_reply( bbp_get_reply_id( (int) $r['id'] ) );
+
+		// Bail if no reply or user cannot reply
+		if ( empty( $reply ) || ! bbp_current_user_can_access_create_reply_form() )
+			return;
+
+		// Build the URI and return value
+		$uri = remove_query_arg( array( 'bbp_reply_to' ) );
+		$uri = add_query_arg( array( 'bbp_reply_to' => $reply->ID ) );
+		$uri = wp_nonce_url( $uri, 'respond_id_' . $reply->ID );
+		$uri = $uri . '#new-post';
+
+		// Only add onclick if replies are threaded
+		if ( bbp_thread_replies() ) {
+
+			// Array of classes to pass to moveForm
+			$move_form = array(
+				$r['add_below'] . '-' . $reply->ID,
+				$reply->ID,
+				$r['respond_id'],
+				$reply->post_parent
+			);
+
+			// Build the onclick
+			$onclick  = ' onclick="return addReply.moveForm(\'' . implode( "','", $move_form ) . '\');"';
+
+		// No onclick if replies are not threaded
+		} else {
+			$onclick  = '';
+		}
+
+		// Add $uri to the array, to be passed through the filter
+		$r['uri'] = $uri;
+		$retval   = $r['link_before'] . '<a href="' . esc_url( $r['uri'] ) . '" class="bbp-reply-to-link"' . $onclick . '>' . esc_html( $r['reply_text'] ) . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_reply_to_link', $retval, $r, $args );
+	}
+
+/**
+ * Output the reply to a reply cancellation link
+ *
+ * @since bbPress (r4944)
+ *
+ * @uses bbp_get_cancel_reply_to_link() To get the reply cancellation link
+ */
+function bbp_cancel_reply_to_link( $text = '' ) {
+	echo bbp_get_cancel_reply_to_link( $text );
+}
+	/**
+	 * Return the cancellation link for a reply to a reply
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @param string $text The cancel text
+	 * @uses apply_filters() Calls 'bbp_get_cancel_reply_to_link' with the cancellation
+	 *                        link and the cancel text
+	 * @return string The cancellation link
+	 */
+	function bbp_get_cancel_reply_to_link( $text = '' ) {
+
+		// Bail if not hierarchical or editing a reply
+		if ( ! bbp_thread_replies() || bbp_is_reply_edit() ) {
+			return;
+		}
+
+		// Set default text
+		if ( empty( $text ) ) {
+			$text = __( 'Cancel', 'bbpress' );
+		}
+
+		$reply_to = isset( $_GET['bbp_reply_to'] ) ? (int) $_GET['bbp_reply_to'] : 0;
+
+		// Set visibility
+		$style  = !empty( $reply_to ) ? '' : ' style="display:none;"';
+		$link   = remove_query_arg( array( 'bbp_reply_to', '_wpnonce' ) ) . '#post-' . $reply_to;
+		$retval = '<a rel="nofollow" id="bbp-cancel-reply-to-link" href="' . esc_url( $link ) . '"' . $style . '>' . esc_html( $text ) . '</a>';
+
+		return apply_filters( 'bbp_get_cancel_reply_to_link', $retval, $link, $text );
+	}
+
+/**
+ * Output the numeric position of a reply within a topic
+ *
+ * @since bbPress (r2984)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_reply_position() To get the reply position
+ */
+function bbp_reply_position( $reply_id = 0, $topic_id = 0 ) {
+	echo bbp_get_reply_position( $reply_id, $topic_id );
+}
+	/**
+	 * Return the numeric position of a reply within a topic
+	 *
+	 * @since bbPress (r2984)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply_topic_id() Get the topic id of the reply id
+	 * @uses bbp_get_topic_reply_count() To get the topic reply count
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses bbp_get_reply_position_raw() To get calculate the reply position
+	 * @uses bbp_update_reply_position() To update the reply position
+	 * @uses bbp_show_lead_topic() Bump the count if lead topic is included
+	 * @uses apply_filters() Calls 'bbp_get_reply_position' with the reply
+	 *                        position, reply id and topic id
+	 * @return int Reply position
+	 */
+	function bbp_get_reply_position( $reply_id = 0, $topic_id = 0 ) {
+
+		// Get required data
+		$reply_id       = bbp_get_reply_id( $reply_id );
+		$reply_position = get_post_field( 'menu_order', $reply_id );
+
+		// Reply doesn't have a position so get the raw value
+		if ( empty( $reply_position ) ) {
+			$topic_id = !empty( $topic_id ) ? bbp_get_topic_id( $topic_id ) : bbp_get_reply_topic_id( $reply_id );
+
+			// Post is not the topic
+			if ( $reply_id !== $topic_id ) {
+				$reply_position = bbp_get_reply_position_raw( $reply_id, $topic_id );
+
+				// Update the reply position in the posts table so we'll never have
+				// to hit the DB again.
+				if ( !empty( $reply_position ) ) {
+					bbp_update_reply_position( $reply_id, $reply_position );
+				}
+
+			// Topic's position is always 0
+			} else {
+				$reply_position = 0;
+			}
+		}
+
+		// Bump the position by one if the lead topic is in the replies loop
+		if ( ! bbp_show_lead_topic() )
+			$reply_position++;
+
+		return (int) apply_filters( 'bbp_get_reply_position', $reply_position, $reply_id, $topic_id );
+	}
+
+/** Reply Admin Links *********************************************************/
+
+/**
+ * Output admin links for reply
+ *
+ * @since bbPress (r2667)
+ *
+ * @param array $args See {@link bbp_get_reply_admin_links()}
+ * @uses bbp_get_reply_admin_links() To get the reply admin links
+ */
+function bbp_reply_admin_links( $args = array() ) {
+	echo bbp_get_reply_admin_links( $args );
+}
+	/**
+	 * Return admin links for reply
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param array $args This function supports these arguments:
+	 *  - id: Optional. Reply id
+	 *  - before: HTML before the links. Defaults to
+	 *             '<span class="bbp-admin-links">'
+	 *  - after: HTML after the links. Defaults to '</span>'
+	 *  - sep: Separator. Defaults to ' | '
+	 *  - links: Array of the links to display. By default, edit, trash,
+	 *            spam, reply move, and topic split links are displayed
+	 * @uses bbp_is_topic() To check if it's the topic page
+	 * @uses bbp_is_reply() To check if it's the reply page
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply_edit_link() To get the reply edit link
+	 * @uses bbp_get_reply_trash_link() To get the reply trash link
+	 * @uses bbp_get_reply_spam_link() To get the reply spam link
+	 * @uses bbp_get_reply_move_link() To get the reply move link
+	 * @uses bbp_get_topic_split_link() To get the topic split link
+	 * @uses current_user_can() To check if the current user can edit or
+	 *                           delete the reply
+	 * @uses apply_filters() Calls 'bbp_get_reply_admin_links' with the
+	 *                        reply admin links and args
+	 * @return string Reply admin links
+	 */
+	function bbp_get_reply_admin_links( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'     => 0,
+			'before' => '<span class="bbp-admin-links">',
+			'after'  => '</span>',
+			'sep'    => ' | ',
+			'links'  => array()
+		), 'get_reply_admin_links' );
+
+		$r['id'] = bbp_get_reply_id( (int) $r['id'] );
+
+		// If post is a topic, return the topic admin links instead
+		if ( bbp_is_topic( $r['id'] ) ) {
+			return bbp_get_topic_admin_links( $args );
+		}
+
+		// If post is not a reply, return
+		if ( !bbp_is_reply( $r['id'] ) ) {
+			return;
+		}
+
+		// If topic is trashed, do not show admin links
+		if ( bbp_is_topic_trash( bbp_get_reply_topic_id( $r['id'] ) ) ) {
+			return;
+		}
+
+		// If no links were passed, default to the standard
+		if ( empty( $r['links'] ) ) {
+			$r['links'] = apply_filters( 'bbp_reply_admin_links', array(
+				'edit'  => bbp_get_reply_edit_link ( $r ),
+				'move'  => bbp_get_reply_move_link ( $r ),
+				'split' => bbp_get_topic_split_link( $r ),
+				'trash' => bbp_get_reply_trash_link( $r ),
+				'spam'  => bbp_get_reply_spam_link ( $r ),
+				'reply' => bbp_get_reply_to_link   ( $r )
+			), $r['id'] );
+		}
+
+		// See if links need to be unset
+		$reply_status = bbp_get_reply_status( $r['id'] );
+		if ( in_array( $reply_status, array( bbp_get_spam_status_id(), bbp_get_trash_status_id() ) ) ) {
+
+			// Spam link shouldn't be visible on trashed topics
+			if ( bbp_get_trash_status_id() === $reply_status ) {
+				unset( $r['links']['spam'] );
+
+			// Trash link shouldn't be visible on spam topics
+			} elseif ( bbp_get_spam_status_id() === $reply_status ) {
+				unset( $r['links']['trash'] );
+			}
+		}
+
+		// Process the admin links
+		$links  = implode( $r['sep'], array_filter( $r['links'] ) );
+		$retval = $r['before'] . $links . $r['after'];
+
+		return apply_filters( 'bbp_get_reply_admin_links', $retval, $r, $args );
+	}
+
+/**
+ * Output the edit link of the reply
+ *
+ * @since bbPress (r2740)
+ *
+ * @param mixed $args See {@link bbp_get_reply_edit_link()}
+ * @uses bbp_get_reply_edit_link() To get the reply edit link
+ */
+function bbp_reply_edit_link( $args = '' ) {
+	echo bbp_get_reply_edit_link( $args );
+}
+
+	/**
+	 * Return the edit link of the reply
+	 *
+	 * @since bbPress (r2740)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - id: Reply id
+	 *  - link_before: HTML before the link
+	 *  - link_after: HTML after the link
+	 *  - edit_text: Edit text. Defaults to 'Edit'
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses current_user_can() To check if the current user can edit the
+	 *                           reply
+	 * @uses bbp_get_reply_edit_url() To get the reply edit url
+	 * @uses apply_filters() Calls 'bbp_get_reply_edit_link' with the reply
+	 *                        edit link and args
+	 * @return string Reply edit link
+	 */
+	function bbp_get_reply_edit_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'edit_text'    => esc_html__( 'Edit', 'bbpress' )
+		), 'get_reply_edit_link' );
+
+		$reply = bbp_get_reply( bbp_get_reply_id( (int) $r['id'] ) );
+
+		// Bypass check if user has caps
+		if ( !current_user_can( 'edit_others_replies' ) ) {
+
+			// User cannot edit or it is past the lock time
+			if ( empty( $reply ) || !current_user_can( 'edit_reply', $reply->ID ) || bbp_past_edit_lock( $reply->post_date_gmt ) ) {
+				return;
+			}
+		}
+
+		// Get uri
+		$uri = bbp_get_reply_edit_url( $r['id'] );
+
+		// Bail if no uri
+		if ( empty( $uri ) )
+			return;
+
+		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-reply-edit-link">' . $r['edit_text'] . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_reply_edit_link', $retval, $r );
+	}
+
+/**
+ * Output URL to the reply edit page
+ *
+ * @since bbPress (r2753)
+ *
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_get_reply_edit_url() To get the reply edit url
+ */
+function bbp_reply_edit_url( $reply_id = 0 ) {
+	echo esc_url( bbp_get_reply_edit_url( $reply_id ) );
+}
+	/**
+	 * Return URL to the reply edit page
+	 *
+	 * @since bbPress (r2753)
+	 *
+	 * @param int $reply_id Optional. Reply id
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses bbp_get_reply_post_type() To get the reply post type
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses apply_filters() Calls 'bbp_get_reply_edit_url' with the edit
+	 *                        url and reply id
+	 * @return string Reply edit url
+	 */
+	function bbp_get_reply_edit_url( $reply_id = 0 ) {
+		global $wp_rewrite;
+
+		$bbp   = bbpress();
+		$reply = bbp_get_reply( bbp_get_reply_id( $reply_id ) );
+		if ( empty( $reply ) )
+			return;
+
+		$reply_link = bbp_remove_view_all( bbp_get_reply_permalink( $reply_id ) );
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url = trailingslashit( $reply_link ) . $bbp->edit_id;
+			$url = trailingslashit( $url );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array( bbp_get_reply_post_type() => $reply->post_name, $bbp->edit_id => '1' ), $reply_link );
+		}
+
+		// Maybe add view all
+		$url = bbp_add_view_all( $url );
+
+		return apply_filters( 'bbp_get_reply_edit_url', $url, $reply_id );
+	}
+
+/**
+ * Output the trash link of the reply
+ *
+ * @since bbPress (r2740)
+ *
+ * @param mixed $args See {@link bbp_get_reply_trash_link()}
+ * @uses bbp_get_reply_trash_link() To get the reply trash link
+ */
+function bbp_reply_trash_link( $args = '' ) {
+	echo bbp_get_reply_trash_link( $args );
+}
+
+	/**
+	 * Return the trash link of the reply
+	 *
+	 * @since bbPress (r2740)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - id: Reply id
+	 *  - link_before: HTML before the link
+	 *  - link_after: HTML after the link
+	 *  - sep: Separator
+	 *  - trash_text: Trash text
+	 *  - restore_text: Restore text
+	 *  - delete_text: Delete text
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses current_user_can() To check if the current user can delete the
+	 *                           reply
+	 * @uses bbp_is_reply_trash() To check if the reply is trashed
+	 * @uses bbp_get_reply_status() To get the reply status
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses bbp_get_reply_edit_url() To get the reply edit url
+	 * @uses apply_filters() Calls 'bbp_get_reply_trash_link' with the reply
+	 *                        trash link and args
+	 * @return string Reply trash link
+	 */
+	function bbp_get_reply_trash_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'sep'          => ' | ',
+			'trash_text'   => esc_html__( 'Trash',   'bbpress' ),
+			'restore_text' => esc_html__( 'Restore', 'bbpress' ),
+			'delete_text'  => esc_html__( 'Delete',  'bbpress' )
+		), 'get_reply_trash_link' );
+
+		$actions = array();
+		$reply   = bbp_get_reply( bbp_get_reply_id( (int) $r['id'] ) );
+
+		if ( empty( $reply ) || !current_user_can( 'delete_reply', $reply->ID ) ) {
+			return;
+		}
+
+		if ( bbp_is_reply_trash( $reply->ID ) ) {
+			$actions['untrash'] = '<a title="' . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_reply_trash', 'sub_action' => 'untrash', 'reply_id' => $reply->ID ) ), 'untrash-' . $reply->post_type . '_' . $reply->ID ) ) . '" class="bbp-reply-restore-link">' . $r['restore_text'] . '</a>';
+		} elseif ( EMPTY_TRASH_DAYS ) {
+			$actions['trash']   = '<a title="' . esc_attr__( 'Move this item to the Trash',      'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_reply_trash', 'sub_action' => 'trash',   'reply_id' => $reply->ID ) ), 'trash-'   . $reply->post_type . '_' . $reply->ID ) ) . '" class="bbp-reply-trash-link">'   . $r['trash_text']   . '</a>';
+		}
+
+		if ( bbp_is_reply_trash( $reply->ID ) || !EMPTY_TRASH_DAYS ) {
+			$actions['delete']  = '<a title="' . esc_attr__( 'Delete this item permanently',     'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_reply_trash', 'sub_action' => 'delete',  'reply_id' => $reply->ID ) ), 'delete-'  . $reply->post_type . '_' . $reply->ID ) ) . '" onclick="return confirm(\'' . esc_js( __( 'Are you sure you want to delete that permanently?', 'bbpress' ) ) . '\' );" class="bbp-reply-delete-link">' . $r['delete_text'] . '</a>';
+		}
+
+		// Process the admin links
+		$retval = $r['link_before'] . implode( $r['sep'], $actions ) . $r['link_after'];
+
+		return apply_filters( 'bbp_get_reply_trash_link', $retval, $r );
+	}
+
+/**
+ * Output the spam link of the reply
+ *
+ * @since bbPress (r2740)
+ *
+ * @param mixed $args See {@link bbp_get_reply_spam_link()}
+ * @uses bbp_get_reply_spam_link() To get the reply spam link
+ */
+function bbp_reply_spam_link( $args = '' ) {
+	echo bbp_get_reply_spam_link( $args );
+}
+
+	/**
+	 * Return the spam link of the reply
+	 *
+	 * @since bbPress (r2740)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - id: Reply id
+	 *  - link_before: HTML before the link
+	 *  - link_after: HTML after the link
+	 *  - spam_text: Spam text
+	 *  - unspam_text: Unspam text
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses current_user_can() To check if the current user can edit the
+	 *                           reply
+	 * @uses bbp_is_reply_spam() To check if the reply is marked as spam
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses bbp_get_reply_edit_url() To get the reply edit url
+	 * @uses apply_filters() Calls 'bbp_get_reply_spam_link' with the reply
+	 *                        spam link and args
+	 * @return string Reply spam link
+	 */
+	function bbp_get_reply_spam_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'spam_text'    => esc_html__( 'Spam',   'bbpress' ),
+			'unspam_text'  => esc_html__( 'Unspam', 'bbpress' )
+		), 'get_reply_spam_link' );
+
+		$reply = bbp_get_reply( bbp_get_reply_id( (int) $r['id'] ) );
+
+		if ( empty( $reply ) || !current_user_can( 'moderate', $reply->ID ) )
+			return;
+
+		$display  = bbp_is_reply_spam( $reply->ID ) ? $r['unspam_text'] : $r['spam_text'];
+		$uri      = add_query_arg( array( 'action' => 'bbp_toggle_reply_spam', 'reply_id' => $reply->ID ) );
+		$uri      = wp_nonce_url( $uri, 'spam-reply_' . $reply->ID );
+		$retval   = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-reply-spam-link">' . $display . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_reply_spam_link', $retval, $r );
+	}
+
+/**
+ * Move reply link
+ *
+ * Output the move link of the reply
+ *
+ * @since bbPress (r4521)
+ *
+ * @param mixed $args See {@link bbp_get_reply_move_link()}
+ * @uses bbp_get_reply_move_link() To get the reply move link
+ */
+function bbp_reply_move_link( $args = '' ) {
+	echo bbp_get_reply_move_link( $args );
+}
+
+	/**
+	 * Get move reply link
+	 *
+	 * Return the move link of the reply
+	 *
+	 * @since bbPress (r4521)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - id: Reply id
+	 *  - link_before: HTML before the link
+	 *  - link_after: HTML after the link
+	 *  - move_text: Move text
+	 *  - move_title: Move title attribute
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses current_user_can() To check if the current user can edit the
+	 *                           topic
+	 * @uses bbp_get_reply_topic_id() To get the reply topic id
+	 * @uses bbp_get_reply_edit_url() To get the reply edit url
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses apply_filters() Calls 'bbp_get_reply_move_link' with the reply
+	 *                        move link and args
+	 * @return string Reply move link
+	 */
+	function bbp_get_reply_move_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'          => 0,
+			'link_before' => '',
+			'link_after'  => '',
+			'split_text'  => esc_html__( 'Move',            'bbpress' ),
+			'split_title' => esc_attr__( 'Move this reply', 'bbpress' )
+		), 'get_reply_move_link' );
+
+		$reply_id = bbp_get_reply_id( $r['id'] );
+		$topic_id = bbp_get_reply_topic_id( $reply_id );
+
+		if ( empty( $reply_id ) || !current_user_can( 'moderate', $topic_id ) )
+			return;
+
+		$uri = add_query_arg( array(
+			'action'   => 'move',
+			'reply_id' => $reply_id
+		), bbp_get_reply_edit_url( $reply_id ) );
+
+		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" title="' . $r['split_title'] . '" class="bbp-reply-move-link">' . $r['split_text'] . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_reply_move_link', $retval, $r );
+	}
+
+/**
+ * Split topic link
+ *
+ * Output the split link of the topic (but is bundled with each reply)
+ *
+ * @since bbPress (r2756)
+ *
+ * @param mixed $args See {@link bbp_get_topic_split_link()}
+ * @uses bbp_get_topic_split_link() To get the topic split link
+ */
+function bbp_topic_split_link( $args = '' ) {
+	echo bbp_get_topic_split_link( $args );
+}
+
+	/**
+	 * Get split topic link
+	 *
+	 * Return the split link of the topic (but is bundled with each reply)
+	 *
+	 * @since bbPress (r2756)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - id: Reply id
+	 *  - link_before: HTML before the link
+	 *  - link_after: HTML after the link
+	 *  - split_text: Split text
+	 *  - split_title: Split title attribute
+	 * @uses bbp_get_reply_id() To get the reply id
+	 * @uses bbp_get_reply() To get the reply
+	 * @uses current_user_can() To check if the current user can edit the
+	 *                           topic
+	 * @uses bbp_get_reply_topic_id() To get the reply topic id
+	 * @uses bbp_get_topic_edit_url() To get the topic edit url
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_split_link' with the topic
+	 *                        split link and args
+	 * @return string Topic split link
+	 */
+	function bbp_get_topic_split_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'          => 0,
+			'link_before' => '',
+			'link_after'  => '',
+			'split_text'  => esc_html__( 'Split',                           'bbpress' ),
+			'split_title' => esc_attr__( 'Split the topic from this reply', 'bbpress' )
+		), 'get_topic_split_link' );
+
+		$reply_id = bbp_get_reply_id( $r['id'] );
+		$topic_id = bbp_get_reply_topic_id( $reply_id );
+
+		if ( empty( $reply_id ) || !current_user_can( 'moderate', $topic_id ) )
+			return;
+
+		$uri =  add_query_arg( array(
+			'action'   => 'split',
+			'reply_id' => $reply_id
+		), bbp_get_topic_edit_url( $topic_id ) );
+
+		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" title="' . $r['split_title'] . '" class="bbp-topic-split-link">' . $r['split_text'] . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_split_link', $retval, $r );
+	}
+
+/**
+ * Output the row class of a reply
+ *
+ * @since bbPress (r2678)
+ *
+ * @param int $reply_id Optional. Reply ID
+ * @param array Extra classes you can pass when calling this function
+ * @uses bbp_get_reply_class() To get the reply class
+ */
+function bbp_reply_class( $reply_id = 0, $classes = array() ) {
+	echo bbp_get_reply_class( $reply_id, $classes );
+}
+	/**
+	 * Return the row class of a reply
+	 *
+	 * @since bbPress (r2678)
+	 *
+	 * @param int $reply_id Optional. Reply ID
+	 * @param array Extra classes you can pass when calling this function
+	 * @uses bbp_get_reply_id() To validate the reply id
+	 * @uses bbp_get_reply_forum_id() To get the reply's forum id
+	 * @uses bbp_get_reply_topic_id() To get the reply's topic id
+	 * @uses get_post_class() To get all the classes including ours
+	 * @uses apply_filters() Calls 'bbp_get_reply_class' with the classes
+	 * @return string Row class of the reply
+	 */
+	function bbp_get_reply_class( $reply_id = 0, $classes = array() ) {
+		$bbp       = bbpress();
+		$reply_id  = bbp_get_reply_id( $reply_id );
+		$count     = isset( $bbp->reply_query->current_post ) ? $bbp->reply_query->current_post : 1;
+		$classes   = (array) $classes;
+		$classes[] = ( (int) $count % 2 ) ? 'even' : 'odd';
+		$classes[] = 'bbp-parent-forum-'   . bbp_get_reply_forum_id( $reply_id );
+		$classes[] = 'bbp-parent-topic-'   . bbp_get_reply_topic_id( $reply_id );
+		$classes[] = 'bbp-reply-position-' . bbp_get_reply_position( $reply_id );
+		$classes[] = 'user-id-' . bbp_get_reply_author_id( $reply_id );
+		$classes[] = ( bbp_get_reply_author_id( $reply_id ) === bbp_get_topic_author_id( bbp_get_reply_topic_id( $reply_id ) ) ? 'topic-author' : '' );
+		$classes   = array_filter( $classes );
+		$classes   = get_post_class( $classes, $reply_id );
+		$classes   = apply_filters( 'bbp_get_reply_class', $classes, $reply_id );
+		$retval    = 'class="' . implode( ' ', $classes ) . '"';
+
+		return $retval;
+	}
+
+/**
+ * Output the topic pagination count
+ *
+ * @since bbPress (r2519)
+ *
+ * @uses bbp_get_topic_pagination_count() To get the topic pagination count
+ */
+function bbp_topic_pagination_count() {
+	echo bbp_get_topic_pagination_count();
+}
+	/**
+	 * Return the topic pagination count
+	 *
+	 * @since bbPress (r2519)
+	 *
+	 * @uses bbp_number_format() To format the number value
+	 * @uses bbp_show_lead_topic() Are we showing the topic as a lead?
+	 * @uses apply_filters() Calls 'bbp_get_topic_pagination_count' with the
+	 *                        pagination count
+	 * @return string Topic pagination count
+	 */
+	function bbp_get_topic_pagination_count() {
+		$bbp = bbpress();
+
+		// Define local variable(s)
+		$retstr = '';
+
+		// Set pagination values
+		$start_num = intval( ( $bbp->reply_query->paged - 1 ) * $bbp->reply_query->posts_per_page ) + 1;
+		$from_num  = bbp_number_format( $start_num );
+		$to_num    = bbp_number_format( ( $start_num + ( $bbp->reply_query->posts_per_page - 1 ) > $bbp->reply_query->found_posts ) ? $bbp->reply_query->found_posts : $start_num + ( $bbp->reply_query->posts_per_page - 1 ) );
+		$total_int = (int) $bbp->reply_query->found_posts;
+		$total     = bbp_number_format( $total_int );
+
+		// We are threading replies
+		if ( bbp_thread_replies() && bbp_is_single_topic() ) {
+			return;
+			$walker  = new BBP_Walker_Reply;
+			$threads = (int) $walker->get_number_of_root_elements( $bbp->reply_query->posts );
+
+			// Adjust for topic
+			$threads--;
+			$retstr  = sprintf( _n( 'Viewing %1$s reply thread', 'Viewing %1$s reply threads', $threads, 'bbbpress' ), bbp_number_format( $threads ) );
+
+		// We are not including the lead topic
+		} elseif ( bbp_show_lead_topic() ) {
+
+			// Several replies in a topic with a single page
+			if ( empty( $to_num ) ) {
+				$retstr = sprintf( _n( 'Viewing %1$s reply', 'Viewing %1$s replies', $total_int, 'bbpress' ), $total );
+
+			// Several replies in a topic with several pages
+			} else {
+				$retstr = sprintf( _n( 'Viewing %2$s replies (of %4$s total)', 'Viewing %1$s replies - %2$s through %3$s (of %4$s total)', $bbp->reply_query->post_count, 'bbpress' ), $bbp->reply_query->post_count, $from_num, $to_num, $total );
+			}
+
+		// We are including the lead topic
+		} else {
+
+			// Several posts in a topic with a single page
+			if ( empty( $to_num ) ) {
+				$retstr = sprintf( _n( 'Viewing %1$s post', 'Viewing %1$s posts', $total_int, 'bbpress' ), $total );
+
+			// Several posts in a topic with several pages
+			} else {
+				$retstr = sprintf( _n( 'Viewing %2$s post (of %4$s total)', 'Viewing %1$s posts - %2$s through %3$s (of %4$s total)', $bbp->reply_query->post_count, 'bbpress' ), $bbp->reply_query->post_count, $from_num, $to_num, $total );
+			}
+		}
+
+		// Filter and return
+		return apply_filters( 'bbp_get_topic_pagination_count', esc_html( $retstr ) );
+	}
+
+/**
+ * Output topic pagination links
+ *
+ * @since bbPress (r2519)
+ *
+ * @uses bbp_get_topic_pagination_links() To get the topic pagination links
+ */
+function bbp_topic_pagination_links() {
+	echo bbp_get_topic_pagination_links();
+}
+	/**
+	 * Return topic pagination links
+	 *
+	 * @since bbPress (r2519)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_topic_pagination_links' with the
+	 *                        pagination links
+	 * @return string Topic pagination links
+	 */
+	function bbp_get_topic_pagination_links() {
+		$bbp = bbpress();
+
+		if ( !isset( $bbp->reply_query->pagination_links ) || empty( $bbp->reply_query->pagination_links ) )
+			return false;
+
+		return apply_filters( 'bbp_get_topic_pagination_links', $bbp->reply_query->pagination_links );
+	}
+
+/** Forms *********************************************************************/
+
+/**
+ * Output the value of reply content field
+ *
+ * @since bbPress (r31301)
+ *
+ * @uses bbp_get_form_reply_content() To get value of reply content field
+ */
+function bbp_form_reply_content() {
+	echo bbp_get_form_reply_content();
+}
+	/**
+	 * Return the value of reply content field
+	 *
+	 * @since bbPress (r31301)
+	 *
+	 * @uses bbp_is_reply_edit() To check if it's the reply edit page
+	 * @uses apply_filters() Calls 'bbp_get_form_reply_content' with the content
+	 * @return string Value of reply content field
+	 */
+	function bbp_get_form_reply_content() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_reply_content'] ) ) {
+			$reply_content = stripslashes( $_POST['bbp_reply_content'] );
+
+		// Get edit data
+		} elseif ( bbp_is_reply_edit() ) {
+			$reply_content = bbp_get_global_post_field( 'post_content', 'raw' );
+
+		// No data
+		} else {
+			$reply_content = '';
+		}
+
+		return apply_filters( 'bbp_get_form_reply_content', $reply_content );
+	}
+
+/**
+ * Output the value of the reply to field
+ *
+ * @since bbPress (r4944)
+ *
+ * @uses bbp_get_form_reply_to() To get value of the reply to field
+ */
+function bbp_form_reply_to() {
+	echo bbp_get_form_reply_to();
+}
+
+	/**
+	 * Return the value of reply to field
+	 *
+	 * @since bbPress (r4944)
+	 *
+	 * @uses bbp_get_reply_id() To validate the reply to
+	 * @uses apply_filters() Calls 'bbp_get_form_reply_to' with the reply to
+	 * @return string Value of reply to field
+	 */
+	function bbp_get_form_reply_to() {
+
+		// Set initial value
+		$reply_to = 0;
+
+		// Get $_REQUEST data
+		if ( isset( $_REQUEST['bbp_reply_to'] ) ) {
+			$reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'] );
+		}
+
+		// If empty, get from meta
+		if ( empty( $reply_to ) ) {
+			$reply_to = bbp_get_reply_to();
+		}
+
+		return (int) apply_filters( 'bbp_get_form_reply_to', $reply_to );
+	}
+
+/**
+ * Output checked value of reply log edit field
+ *
+ * @since bbPress (r31301)
+ *
+ * @uses bbp_get_form_reply_log_edit() To get the reply log edit value
+ */
+function bbp_form_reply_log_edit() {
+	echo bbp_get_form_reply_log_edit();
+}
+	/**
+	 * Return checked value of reply log edit field
+	 *
+	 * @since bbPress (r31301)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_form_reply_log_edit' with the
+	 *                        log edit value
+	 * @return string Reply log edit checked value
+	 */
+	function bbp_get_form_reply_log_edit() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_log_reply_edit'] ) ) {
+			$reply_revision = $_POST['bbp_log_reply_edit'];
+
+		// No data
+		} else {
+			$reply_revision = 1;
+		}
+
+		return apply_filters( 'bbp_get_form_reply_log_edit', checked( $reply_revision, true, false ) );
+	}
+
+/**
+ * Output the value of the reply edit reason
+ *
+ * @since bbPress (r31301)
+ *
+ * @uses bbp_get_form_reply_edit_reason() To get the reply edit reason value
+ */
+function bbp_form_reply_edit_reason() {
+	echo bbp_get_form_reply_edit_reason();
+}
+	/**
+	 * Return the value of the reply edit reason
+	 *
+	 * @since bbPress (r31301)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_form_reply_edit_reason' with the
+	 *                        reply edit reason value
+	 * @return string Reply edit reason value
+	 */
+	function bbp_get_form_reply_edit_reason() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_reply_edit_reason'] ) ) {
+			$reply_edit_reason = $_POST['bbp_reply_edit_reason'];
+
+		// No data
+		} else {
+			$reply_edit_reason = '';
+		}
+
+		return apply_filters( 'bbp_get_form_reply_edit_reason', esc_attr( $reply_edit_reason ) );
+	}
Index: /tags/2.5.4/includes/search/functions.php
===================================================================
--- /tags/2.5.4/includes/search/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/search/functions.php	(revision 5382)
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * bbPress Search Functions
+ *
+ * @package bbPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Query *********************************************************************/
+
+/**
+ * Run the search query
+ *
+ * @since bbPress (r4579) 
+ *
+ * @param mixed $new_args New arguments
+ * @uses bbp_get_search_query_args() To get the search query args
+ * @uses bbp_parse_args() To parse the args
+ * @uses bbp_has_search_results() To make the search query
+ * @return bool False if no results, otherwise if search results are there
+ */
+function bbp_search_query( $new_args = array() ) {
+
+	// Existing arguments 
+	$query_args = bbp_get_search_query_args();
+
+	// Merge arguments
+	if ( !empty( $new_args ) ) {
+		$new_args   = bbp_parse_args( $new_args, array(), 'search_query' );
+		$query_args = array_merge( $query_args, $new_args );
+	}
+
+	return bbp_has_search_results( $query_args );
+}
+
+/**
+ * Return the search's query args
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses bbp_get_search_terms() To get the search terms
+ * @return array Query arguments
+ */
+function bbp_get_search_query_args() {
+
+	// Get search terms
+	$search_terms = bbp_get_search_terms();
+	$retval       = !empty( $search_terms ) ? array( 's' => $search_terms ) : array();
+
+	return apply_filters( 'bbp_get_search_query_args', $retval );
+}
+
+/**
+ * Redirect to search results page if needed
+ *
+ * @since bbPress (r4928)
+ * @return If a redirect is not needed
+ */
+function bbp_search_results_redirect() {
+	global $wp_rewrite;
+	
+	// Bail if not a search request action
+	if ( empty( $_GET['action'] ) || ( 'bbp-search-request' !== $_GET['action'] ) ) {
+		return;
+	}
+
+	// Bail if not using pretty permalinks
+	if ( ! $wp_rewrite->using_permalinks() ) {
+		return;
+	}
+
+	// Get the redirect URL
+	$redirect_to = bbp_get_search_results_url();
+	if ( empty( $redirect_to ) ) {
+		return;
+	}
+
+	// Redirect and bail
+	wp_safe_redirect( $redirect_to );
+	exit();
+}
Index: /tags/2.5.4/includes/search/index.php
===================================================================
--- /tags/2.5.4/includes/search/index.php	(revision 5382)
+++ /tags/2.5.4/includes/search/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/search/template.php
===================================================================
--- /tags/2.5.4/includes/search/template.php	(revision 5382)
+++ /tags/2.5.4/includes/search/template.php	(revision 5382)
@@ -0,0 +1,440 @@
+<?php
+
+/**
+ * bbPress Search Template Tags
+ *
+ * @package bbPress
+ * @subpackage TemplateTags
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Search Loop Functions *****************************************************/
+
+/**
+ * The main search loop. WordPress does the heavy lifting.
+ *
+ * @since bbPress (r4579)
+ *
+ * @param mixed $args All the arguments supported by {@link WP_Query}
+ * @uses bbp_get_view_all() Are we showing all results?
+ * @uses bbp_get_public_status_id() To get the public status id
+ * @uses bbp_get_closed_status_id() To get the closed status id
+ * @uses bbp_get_spam_status_id() To get the spam status id
+ * @uses bbp_get_trash_status_id() To get the trash status id
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_replies_per_page() To get the replies per page option
+ * @uses bbp_get_paged() To get the current page value
+ * @uses bbp_get_search_terms() To get the search terms
+ * @uses WP_Query To make query and get the search results
+ * @uses WP_Rewrite::using_permalinks() To check if the blog is using permalinks
+ * @uses bbp_get_search_url() To get the forum search url
+ * @uses paginate_links() To paginate search results
+ * @uses apply_filters() Calls 'bbp_has_search_results' with
+ *                        bbPress::search_query::have_posts()
+ *                        and bbPress::reply_query
+ * @return object Multidimensional array of search information
+ */
+function bbp_has_search_results( $args = '' ) {
+	global $wp_rewrite;
+
+	/** Defaults **************************************************************/
+
+	$default_post_type = array( bbp_get_forum_post_type(), bbp_get_topic_post_type(), bbp_get_reply_post_type() );
+
+	// Default query args
+	$default = array(
+		'post_type'           => $default_post_type,         // Forums, topics, and replies
+		'posts_per_page'      => bbp_get_replies_per_page(), // This many
+		'paged'               => bbp_get_paged(),            // On this page
+		'orderby'             => 'date',                     // Sorted by date
+		'order'               => 'DESC',                     // Most recent first
+		'ignore_sticky_posts' => true,                       // Stickies not supported
+		's'                   => bbp_get_search_terms(),     // This is a search
+	);
+
+	// What are the default allowed statuses (based on user caps)
+	if ( bbp_get_view_all() ) {
+
+		// Default view=all statuses
+		$post_statuses = array(
+			bbp_get_public_status_id(),
+			bbp_get_closed_status_id(),
+			bbp_get_spam_status_id(),
+			bbp_get_trash_status_id()
+		);
+
+		// Add support for private status
+		if ( current_user_can( 'read_private_topics' ) ) {
+			$post_statuses[] = bbp_get_private_status_id();
+		}
+
+		// Join post statuses together
+		$default['post_status'] = implode( ',', $post_statuses );
+
+	// Lean on the 'perm' query var value of 'readable' to provide statuses
+	} else {
+		$default['perm'] = 'readable';
+	}
+
+	/** Setup *****************************************************************/
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, $default, 'has_search_results' );
+
+	// Get bbPress
+	$bbp = bbpress();
+
+	// Call the query
+	if ( ! empty( $r['s'] ) ) {
+		$bbp->search_query = new WP_Query( $r );
+	}
+
+	// Add pagination values to query object
+	$bbp->search_query->posts_per_page = $r['posts_per_page'];
+	$bbp->search_query->paged          = $r['paged'];
+
+	// Never home, regardless of what parse_query says
+	$bbp->search_query->is_home        = false;
+
+	// Only add pagination is query returned results
+	if ( ! empty( $bbp->search_query->found_posts ) && ! empty( $bbp->search_query->posts_per_page ) ) {
+
+		// Array of arguments to add after pagination links
+		$add_args = array();
+
+		// If pretty permalinks are enabled, make our pagination pretty
+		if ( $wp_rewrite->using_permalinks() ) {
+
+			// Shortcode territory
+			if ( is_page() || is_single() ) {
+				$base = trailingslashit( get_permalink() );
+
+			// Default search location
+			} else {
+				$base = trailingslashit( bbp_get_search_results_url() );
+			}
+
+			// Add pagination base
+			$base = $base . user_trailingslashit( $wp_rewrite->pagination_base . '/%#%/' );
+
+		// Unpretty permalinks
+		} else {
+			$base = add_query_arg( 'paged', '%#%' );
+		}
+
+		// Add args
+		if ( bbp_get_view_all() ) {
+			$add_args['view'] = 'all';
+		}
+
+		// Add pagination to query object
+		$bbp->search_query->pagination_links = paginate_links(
+			apply_filters( 'bbp_search_results_pagination', array(
+				'base'      => $base,
+				'format'    => '',
+				'total'     => ceil( (int) $bbp->search_query->found_posts / (int) $r['posts_per_page'] ),
+				'current'   => (int) $bbp->search_query->paged,
+				'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
+				'next_text' => is_rtl() ? '&larr;' : '&rarr;',
+				'mid_size'  => 1,
+				'add_args'  => $add_args, 
+			) )
+		);
+
+		// Remove first page from pagination
+		if ( $wp_rewrite->using_permalinks() ) {
+			$bbp->search_query->pagination_links = str_replace( $wp_rewrite->pagination_base . '/1/', '', $bbp->search_query->pagination_links );
+		} else {
+			$bbp->search_query->pagination_links = str_replace( '&#038;paged=1', '', $bbp->search_query->pagination_links );
+		}
+	}
+
+	// Return object
+	return apply_filters( 'bbp_has_search_results', $bbp->search_query->have_posts(), $bbp->search_query );
+}
+
+/**
+ * Whether there are more search results available in the loop
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses WP_Query bbPress::search_query::have_posts() To check if there are more
+ *                                                     search results available
+ * @return object Search information
+ */
+function bbp_search_results() {
+
+	// Put into variable to check against next
+	$have_posts = bbpress()->search_query->have_posts();
+
+	// Reset the post data when finished
+	if ( empty( $have_posts ) )
+		wp_reset_postdata();
+
+	return $have_posts;
+}
+
+/**
+ * Loads up the current search result in the loop
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses WP_Query bbPress::search_query::the_post() To get the current search result
+ * @return object Search information
+ */
+function bbp_the_search_result() {
+	$search_result = bbpress()->search_query->the_post();
+
+	// Reset each current (forum|topic|reply) id
+	bbpress()->current_forum_id = bbp_get_forum_id();
+	bbpress()->current_topic_id = bbp_get_topic_id();
+	bbpress()->current_reply_id = bbp_get_reply_id();
+
+	return $search_result;
+}
+
+/**
+ * Output the search page title
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses bbp_get_search_title()
+ */
+function bbp_search_title() {
+	echo bbp_get_search_title();
+}
+
+	/**
+	 * Get the search page title
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @uses bbp_get_search_terms()
+	 */
+	function bbp_get_search_title() {
+
+		// Get search terms
+		$search_terms = bbp_get_search_terms();
+
+		// No search terms specified
+		if ( empty( $search_terms ) ) {
+			$title = esc_html__( 'Search', 'bbpress' );
+
+		// Include search terms in title
+		} else {
+			$title = sprintf( esc_html__( "Search Results for '%s'", 'bbpress' ), esc_attr( $search_terms ) );
+		}
+
+		return apply_filters( 'bbp_get_search_title', $title, $search_terms );
+	}
+
+/**
+ * Output the search url
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses bbp_get_search_url() To get the search url
+ */
+function bbp_search_url() {
+	echo esc_url( bbp_get_search_url() );
+}
+	/**
+	 * Return the search url
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @uses user_trailingslashit() To fix slashes
+	 * @uses trailingslashit() To fix slashes
+	 * @uses bbp_get_forums_url() To get the root forums url
+	 * @uses bbp_get_search_slug() To get the search slug
+	 * @uses add_query_arg() To help make unpretty permalinks
+	 * @return string Search url
+	 */
+	function bbp_get_search_url() {
+		global $wp_rewrite;
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url = $wp_rewrite->root . bbp_get_search_slug();
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array( bbp_get_search_rewrite_id() => '' ), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_search_url', $url );
+	}
+
+/**
+ * Output the search results url
+ *
+ * @since bbPress (r4928)
+ *
+ * @uses bbp_get_search_url() To get the search url
+ */
+function bbp_search_results_url() {
+	echo esc_url( bbp_get_search_results_url() );
+}
+	/**
+	 * Return the search url
+	 *
+	 * @since bbPress (r4928)
+	 *
+	 * @uses user_trailingslashit() To fix slashes
+	 * @uses trailingslashit() To fix slashes
+	 * @uses bbp_get_forums_url() To get the root forums url
+	 * @uses bbp_get_search_slug() To get the search slug
+	 * @uses add_query_arg() To help make unpretty permalinks
+	 * @return string Search url
+	 */
+	function bbp_get_search_results_url() {
+		global $wp_rewrite;
+
+		// Get the search terms
+		$search_terms = bbp_get_search_terms();
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+
+			// Root search URL
+			$url = $wp_rewrite->root . bbp_get_search_slug();
+
+			// Append search terms
+			if ( !empty( $search_terms ) ) {
+				$url = trailingslashit( $url ) . user_trailingslashit( urlencode( $search_terms ) );
+			}
+
+			// Run through home_url()
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array( bbp_get_search_rewrite_id() => urlencode( $search_terms ) ), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_search_results_url', $url );
+	}
+
+/**
+ * Output the search terms
+ *
+ * @since bbPress (r4579)
+ *
+ * @param string $search_terms Optional. Search terms
+ * @uses bbp_get_search_terms() To get the search terms
+ */
+function bbp_search_terms( $search_terms = '' ) {
+	echo bbp_get_search_terms( $search_terms );
+}
+
+	/**
+	 * Get the search terms
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * If search terms are supplied, those are used. Otherwise check the
+	 * search rewrite id query var.
+	 *
+	 * @param string $passed_terms Optional. Search terms
+	 * @uses sanitize_title() To sanitize the search terms
+	 * @uses get_query_var() To get the search terms from query variable
+	 * @return bool|string Search terms on success, false on failure
+	 */
+	function bbp_get_search_terms( $passed_terms = '' ) {
+
+		// Sanitize terms if they were passed in
+		if ( !empty( $passed_terms ) ) {
+			$search_terms = sanitize_title( $passed_terms );
+
+		// Use query variable if not
+		} else {
+			$search_terms = get_query_var( bbp_get_search_rewrite_id() );
+		}
+
+		// Trim whitespace and decode, or set explicitly to false if empty
+		$search_terms = !empty( $search_terms ) ? urldecode( trim( $search_terms ) ) : false;
+
+		return apply_filters( 'bbp_get_search_terms', $search_terms, $passed_terms );
+	}
+
+/**
+ * Output the search result pagination count
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses bbp_get_search_pagination_count() To get the search result pagination count
+ */
+function bbp_search_pagination_count() {
+	echo bbp_get_search_pagination_count();
+}
+
+	/**
+	 * Return the search results pagination count
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @uses bbp_number_format() To format the number value
+	 * @uses apply_filters() Calls 'bbp_get_search_pagination_count' with the
+	 *                        pagination count
+	 * @return string Search pagination count
+	 */
+	function bbp_get_search_pagination_count() {
+		$bbp = bbpress();
+
+		// Define local variable(s)
+		$retstr = '';
+
+		// Set pagination values
+		$start_num = intval( ( $bbp->search_query->paged - 1 ) * $bbp->search_query->posts_per_page ) + 1;
+		$from_num  = bbp_number_format( $start_num );
+		$to_num    = bbp_number_format( ( $start_num + ( $bbp->search_query->posts_per_page - 1 ) > $bbp->search_query->found_posts ) ? $bbp->search_query->found_posts : $start_num + ( $bbp->search_query->posts_per_page - 1 ) );
+		$total_int = (int) $bbp->search_query->found_posts;
+		$total     = bbp_number_format( $total_int );
+
+		// Single page of results
+		if ( empty( $to_num ) ) {
+			$retstr = sprintf( _n( 'Viewing %1$s result', 'Viewing %1$s results', $total_int, 'bbpress' ), $total );
+
+		// Several pages of results
+		} else {
+			$retstr = sprintf( _n( 'Viewing %2$s results (of %4$s total)', 'Viewing %1$s results - %2$s through %3$s (of %4$s total)', $bbp->search_query->post_count, 'bbpress' ), $bbp->search_query->post_count, $from_num, $to_num, $total );
+
+		}
+
+		// Filter and return
+		return apply_filters( 'bbp_get_search_pagination_count', esc_html( $retstr ) );
+	}
+
+/**
+ * Output search pagination links
+ *
+ * @since bbPress (r4579)
+ *
+ * @uses bbp_get_search_pagination_links() To get the search pagination links
+ */
+function bbp_search_pagination_links() {
+	echo bbp_get_search_pagination_links();
+}
+
+	/**
+	 * Return search pagination links
+	 *
+	 * @since bbPress (r4579)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_search_pagination_links' with the
+	 *                        pagination links
+	 * @return string Search pagination links
+	 */
+	function bbp_get_search_pagination_links() {
+		$bbp = bbpress();
+
+		if ( !isset( $bbp->search_query->pagination_links ) || empty( $bbp->search_query->pagination_links ) )
+			return false;
+
+		return apply_filters( 'bbp_get_search_pagination_links', $bbp->search_query->pagination_links );
+	}
Index: /tags/2.5.4/includes/topics/capabilities.php
===================================================================
--- /tags/2.5.4/includes/topics/capabilities.php	(revision 5382)
+++ /tags/2.5.4/includes/topics/capabilities.php	(revision 5382)
@@ -0,0 +1,236 @@
+<?php
+
+/**
+ * bbPress Topic Capabilites
+ *
+ * Used to map topic capabilities to WordPress's existing capabilities.
+ *
+ * @package bbPress
+ * @subpackage Capabilities
+ */
+
+/**
+ * Return topic capabilities
+ *
+ * @since bbPress (r2593)
+ *
+ * @uses apply_filters() Calls 'bbp_get_topic_caps' with the capabilities
+ * @return array Topic capabilities
+ */
+function bbp_get_topic_caps() {
+	return apply_filters( 'bbp_get_topic_caps', array (
+		'edit_posts'          => 'edit_topics',
+		'edit_others_posts'   => 'edit_others_topics',
+		'publish_posts'       => 'publish_topics',
+		'read_private_posts'  => 'read_private_topics',
+		'read_hidden_posts'   => 'read_hidden_topics',
+		'delete_posts'        => 'delete_topics',
+		'delete_others_posts' => 'delete_others_topics'
+	) );
+}
+
+/**
+ * Return topic tag capabilities
+ *
+ * @since bbPress (r2593)
+ *
+ * @uses apply_filters() Calls 'bbp_get_topic_tag_caps' with the capabilities
+ * @return array Topic tag capabilities
+ */
+function bbp_get_topic_tag_caps() {
+	return apply_filters( 'bbp_get_topic_tag_caps', array (
+		'manage_terms' => 'manage_topic_tags',
+		'edit_terms'   => 'edit_topic_tags',
+		'delete_terms' => 'delete_topic_tags',
+		'assign_terms' => 'assign_topic_tags'
+	) );
+}
+
+/**
+ * Maps topic capabilities
+ *
+ * @since bbPress (r4242)
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ * @uses get_post() To get the post
+ * @uses get_post_type_object() To get the post type object
+ * @uses apply_filters() Filter capability map results
+ * @return array Actual capabilities for meta capability
+ */
+function bbp_map_topic_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+
+	// What capability is being checked?
+	switch ( $cap ) {
+
+		/** Reading ***********************************************************/
+
+		case 'read_topic' :
+
+			// User cannot spectate
+			if ( ! user_can( $user_id, 'spectate' ) ) {
+				$caps = array( 'do_not_allow' );
+
+			// Do some post ID based logic
+			} else {
+
+				// Get the post
+				$_post = get_post( $args[0] );
+				if ( !empty( $_post ) ) {
+
+					// Get caps for post type object
+					$post_type = get_post_type_object( $_post->post_type );
+
+					// Post is public
+					if ( bbp_get_public_status_id() === $_post->post_status ) {
+						$caps = array( 'spectate' );
+
+					// User is author so allow read
+					} elseif ( (int) $user_id === (int) $_post->post_author ) {
+						$caps = array( 'spectate' );
+
+					// Unknown so map to private posts
+					} else {
+						$caps = array( $post_type->cap->read_private_posts );
+					}
+				}
+			}
+
+			break;
+
+		/** Publishing ********************************************************/
+
+		case 'publish_topics'  :
+
+			// Moderators can always publish
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( 'moderate' );
+			}
+
+			break;
+
+		/** Editing ***********************************************************/
+
+		// Used primarily in wp-admin
+		case 'edit_topics'        :
+		case 'edit_others_topics' :
+
+			// Moderators can always edit
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( $cap );
+
+			// Otherwise, block
+			} else {
+				$caps = array( 'do_not_allow' );
+			}
+
+			break;
+
+		// Used everywhere
+		case 'edit_topic' :
+
+			// Get the post
+			$_post = get_post( $args[0] );
+			if ( !empty( $_post ) ) {
+
+				// Get caps for post type object
+				$post_type = get_post_type_object( $_post->post_type );
+				$caps      = array();
+
+				// Add 'do_not_allow' cap if user is spam or deleted
+				if ( bbp_is_user_inactive( $user_id ) ) {
+					$caps[] = 'do_not_allow';
+
+				// User is author so allow edit if not in admin
+				} elseif ( !is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
+					$caps[] = $post_type->cap->edit_posts;
+
+				// Unknown, so map to edit_others_posts
+				} else {
+					$caps[] = $post_type->cap->edit_others_posts;
+				}
+			}
+
+			break;
+
+		/** Deleting **********************************************************/
+
+		case 'delete_topic' :
+
+			// Get the post
+			$_post = get_post( $args[0] );
+			if ( !empty( $_post ) ) {
+
+				// Get caps for post type object
+				$post_type = get_post_type_object( $_post->post_type );
+				$caps      = array();
+
+				// Add 'do_not_allow' cap if user is spam or deleted
+				if ( bbp_is_user_inactive( $user_id ) ) {
+					$caps[] = 'do_not_allow';
+
+				// Moderators can always edit forum content
+				} elseif ( user_can( $user_id, 'moderate' ) ) {
+					$caps[] = 'moderate';
+
+				// Unknown so map to delete_others_posts
+				} else {
+					$caps[] = $post_type->cap->delete_others_posts;
+				}
+			}
+
+			break;
+
+		// Moderation override
+		case 'delete_topics'         :
+		case 'delete_others_topics'  :
+
+			// Moderators can always delete
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( $cap );
+			}
+
+			break;
+
+		/** Admin *************************************************************/
+
+		case 'bbp_topics_admin' :
+			$caps = array( 'moderate' );
+			break;
+	}
+
+	return apply_filters( 'bbp_map_topic_meta_caps', $caps, $cap, $user_id, $args );
+}
+
+/**
+ * Maps topic tag capabilities
+ *
+ * @since bbPress (r4242)
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ * @uses apply_filters() Filter capability map results
+ * @return array Actual capabilities for meta capability
+ */
+function bbp_map_topic_tag_meta_caps( $caps, $cap, $user_id, $args ) {
+
+	// What capability is being checked?
+	switch ( $cap ) {
+		case 'manage_topic_tags'    :
+		case 'edit_topic_tags'      :
+		case 'delete_topic_tags'    :
+		case 'assign_topic_tags'    :
+		case 'bbp_topic_tags_admin' :
+
+			// Moderators can always edit
+			if ( user_can( $user_id, 'moderate' ) ) {
+				$caps = array( 'moderate' );
+			}
+	}
+
+	return apply_filters( 'bbp_map_topic_tag_meta_caps', $caps, $cap, $user_id, $args );
+}
Index: /tags/2.5.4/includes/topics/functions.php
===================================================================
--- /tags/2.5.4/includes/topics/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/topics/functions.php	(revision 5382)
@@ -0,0 +1,3538 @@
+<?php
+
+/**
+ * bbPress Topic Functions
+ *
+ * @package bbPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Insert ********************************************************************/
+
+/**
+ * A wrapper for wp_insert_post() that also includes the necessary meta values
+ * for the topic to function properly.
+ *
+ * @since bbPress (r3349)
+ *
+ * @uses bbp_parse_args()
+ * @uses bbp_get_topic_post_type()
+ * @uses wp_insert_post()
+ * @uses update_post_meta()
+ *
+ * @param array $topic_data Forum post data
+ * @param arrap $topic_meta Forum meta data
+ */
+function bbp_insert_topic( $topic_data = array(), $topic_meta = array() ) {
+
+	// Parse arguments against default values
+	$topic_data = bbp_parse_args( $topic_data, array(
+		'post_parent'    => 0, // forum ID
+		'post_status'    => bbp_get_public_status_id(),
+		'post_type'      => bbp_get_topic_post_type(),
+		'post_author'    => bbp_get_current_user_id(),
+		'post_password'  => '',
+		'post_content'   => '',
+		'post_title'     => '',
+		'comment_status' => 'closed',
+		'menu_order'     => 0,
+	), 'insert_topic' );
+
+	// Insert topic
+	$topic_id   = wp_insert_post( $topic_data );
+
+	// Bail if no topic was added
+	if ( empty( $topic_id ) )
+		return false;
+
+	// Parse arguments against default values
+	$topic_meta = bbp_parse_args( $topic_meta, array(
+		'author_ip'          => bbp_current_author_ip(),
+		'forum_id'           => 0,
+		'topic_id'           => $topic_id,
+		'voice_count'        => 1,
+		'reply_count'        => 0,
+		'reply_count_hidden' => 0,
+		'last_reply_id'      => 0,
+		'last_active_id'     => $topic_id,
+		'last_active_time'   => get_post_field( 'post_date', $topic_id, 'db' ),
+	), 'insert_topic_meta' );
+
+	// Insert topic meta
+	foreach ( $topic_meta as $meta_key => $meta_value ) {
+		update_post_meta( $topic_id, '_bbp_' . $meta_key, $meta_value );
+	}
+
+	// Update the forum
+	$forum_id = bbp_get_topic_forum_id( $topic_id );
+	if ( !empty( $forum_id ) ) {
+		bbp_update_forum( array( 'forum_id' => $forum_id ) );
+	}
+
+	// Return new topic ID
+	return $topic_id;
+}
+
+/** Post Form Handlers ********************************************************/
+
+/**
+ * Handles the front end topic submission
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the referer
+ * @uses bbp_is_anonymous() To check if an anonymous post is being made
+ * @uses current_user_can() To check if the current user can publish topic
+ * @uses bbp_get_current_user_id() To get the current user id
+ * @uses bbp_filter_anonymous_post_data() To filter anonymous data
+ * @uses bbp_set_current_anonymous_user_data() To set the anonymous user cookies
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses esc_attr() For sanitization
+ * @uses bbp_is_forum_category() To check if the forum is a category
+ * @uses bbp_is_forum_closed() To check if the forum is closed
+ * @uses bbp_is_forum_private() To check if the forum is private
+ * @uses bbp_check_for_flood() To check for flooding
+ * @uses bbp_check_for_duplicate() To check for duplicates
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses remove_filter() To remove kses filters if needed
+ * @uses apply_filters() Calls 'bbp_new_topic_pre_title' with the content
+ * @uses apply_filters() Calls 'bbp_new_topic_pre_content' with the content
+ * @uses bbPress::errors::get_error_codes() To get the {@link WP_Error} errors
+ * @uses wp_insert_post() To insert the topic
+ * @uses do_action() Calls 'bbp_new_topic' with the topic id, forum id,
+ *                    anonymous data and reply author
+ * @uses bbp_stick_topic() To stick or super stick the topic
+ * @uses bbp_unstick_topic() To unstick the topic
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ * @uses wp_safe_redirect() To redirect to the topic link
+ * @uses bbPress::errors::get_error_messages() To get the {@link WP_Error} error
+ *                                              messages
+ */
+function bbp_new_topic_handler( $action = '' ) {
+
+	// Bail if action is not bbp-new-topic
+	if ( 'bbp-new-topic' !== $action )
+		return;
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'bbp-new-topic' ) ) {
+		bbp_add_error( 'bbp_new_topic_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Define local variable(s)
+	$view_all = false;
+	$forum_id = $topic_author = $anonymous_data = 0;
+	$topic_title = $topic_content = '';
+	$terms = array( bbp_get_topic_tag_tax_id() => array() );
+
+	/** Topic Author **********************************************************/
+
+	// User is anonymous
+	if ( bbp_is_anonymous() ) {
+
+		// Filter anonymous data
+		$anonymous_data = bbp_filter_anonymous_post_data();
+
+		// Anonymous data checks out, so set cookies, etc...
+		if ( !empty( $anonymous_data ) && is_array( $anonymous_data ) ) {
+			bbp_set_current_anonymous_user_data( $anonymous_data );
+		}
+
+	// User is logged in
+	} else {
+
+		// User cannot create topics
+		if ( !current_user_can( 'publish_topics' ) ) {
+			bbp_add_error( 'bbp_topic_permissions', __( '<strong>ERROR</strong>: You do not have permission to create new topics.', 'bbpress' ) );
+			return;
+		}
+
+		// Topic author is current user
+		$topic_author = bbp_get_current_user_id();
+	}
+
+	// Remove kses filters from title and content for capable users and if the nonce is verified
+	if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_topic'] ) && wp_create_nonce( 'bbp-unfiltered-html-topic_new' ) === $_POST['_bbp_unfiltered_html_topic'] ) {
+		remove_filter( 'bbp_new_topic_pre_title',   'wp_filter_kses'      );
+		remove_filter( 'bbp_new_topic_pre_content', 'bbp_encode_bad',  10 );
+		remove_filter( 'bbp_new_topic_pre_content', 'bbp_filter_kses', 30 );
+	}
+
+	/** Topic Title ***********************************************************/
+
+	if ( !empty( $_POST['bbp_topic_title'] ) )
+		$topic_title = esc_attr( strip_tags( $_POST['bbp_topic_title'] ) );
+
+	// Filter and sanitize
+	$topic_title = apply_filters( 'bbp_new_topic_pre_title', $topic_title );
+
+	// No topic title
+	if ( empty( $topic_title ) )
+		bbp_add_error( 'bbp_topic_title', __( '<strong>ERROR</strong>: Your topic needs a title.', 'bbpress' ) );
+
+	/** Topic Content *********************************************************/
+
+	if ( !empty( $_POST['bbp_topic_content'] ) )
+		$topic_content = $_POST['bbp_topic_content'];
+
+	// Filter and sanitize
+	$topic_content = apply_filters( 'bbp_new_topic_pre_content', $topic_content );
+
+	// No topic content
+	if ( empty( $topic_content ) )
+		bbp_add_error( 'bbp_topic_content', __( '<strong>ERROR</strong>: Your topic cannot be empty.', 'bbpress' ) );
+
+	/** Topic Forum ***********************************************************/
+
+	// Error check the POST'ed topic id
+	if ( isset( $_POST['bbp_forum_id'] ) ) {
+
+		// Empty Forum id was passed
+		if ( empty( $_POST['bbp_forum_id'] ) ) {
+			bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID is missing.', 'bbpress' ) );
+
+		// Forum id is not a number
+		} elseif ( ! is_numeric( $_POST['bbp_forum_id'] ) ) {
+			bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID must be a number.', 'bbpress' ) );
+
+		// Forum id might be valid
+		} else {
+
+			// Get the forum id
+			$posted_forum_id = intval( $_POST['bbp_forum_id'] );
+
+			// Forum id is empty
+			if ( 0 === $posted_forum_id ) {
+				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID is missing.', 'bbpress' ) );
+
+			// Forum id is a negative number
+			} elseif ( 0 > $posted_forum_id ) {
+				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID cannot be a negative number.', 'bbpress' ) );
+
+			// Forum does not exist
+			} elseif ( ! bbp_get_forum( $posted_forum_id ) ) {
+				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum does not exist.', 'bbpress' ) );
+
+			// Use the POST'ed forum id
+			} else {
+				$forum_id = $posted_forum_id;
+			}
+		}
+	}
+
+	// Forum exists
+	if ( !empty( $forum_id ) ) {
+
+		// Forum is a category
+		if ( bbp_is_forum_category( $forum_id ) ) {
+			bbp_add_error( 'bbp_new_topic_forum_category', __( '<strong>ERROR</strong>: This forum is a category. No topics can be created in this forum.', 'bbpress' ) );
+
+		// Forum is not a category
+		} else {
+
+			// Forum is closed and user cannot access
+			if ( bbp_is_forum_closed( $forum_id ) && !current_user_can( 'edit_forum', $forum_id ) ) {
+				bbp_add_error( 'bbp_new_topic_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new topics.', 'bbpress' ) );
+			}
+
+			// Forum is private and user cannot access
+			if ( bbp_is_forum_private( $forum_id ) ) {
+				if ( !current_user_can( 'read_private_forums' ) ) {
+					bbp_add_error( 'bbp_new_topic_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
+				}
+
+			// Forum is hidden and user cannot access
+			} elseif ( bbp_is_forum_hidden( $forum_id ) ) {
+				if ( !current_user_can( 'read_hidden_forums' ) ) {
+					bbp_add_error( 'bbp_new_topic_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
+				}
+			}
+		}
+	}
+
+	/** Topic Flooding ********************************************************/
+
+	if ( !bbp_check_for_flood( $anonymous_data, $topic_author ) )
+		bbp_add_error( 'bbp_topic_flood', __( '<strong>ERROR</strong>: Slow down; you move too fast.', 'bbpress' ) );
+
+	/** Topic Duplicate *******************************************************/
+
+	if ( !bbp_check_for_duplicate( array( 'post_type' => bbp_get_topic_post_type(), 'post_author' => $topic_author, 'post_content' => $topic_content, 'anonymous_data' => $anonymous_data ) ) )
+		bbp_add_error( 'bbp_topic_duplicate', __( '<strong>ERROR</strong>: Duplicate topic detected; it looks as though you&#8217;ve already said that!', 'bbpress' ) );
+
+	/** Topic Blacklist *******************************************************/
+
+	if ( !bbp_check_for_blacklist( $anonymous_data, $topic_author, $topic_title, $topic_content ) )
+		bbp_add_error( 'bbp_topic_blacklist', __( '<strong>ERROR</strong>: Your topic cannot be created at this time.', 'bbpress' ) );
+
+	/** Topic Status **********************************************************/
+
+	// Maybe put into moderation
+	if ( !bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content ) ) {
+		$topic_status = bbp_get_pending_status_id();
+
+	// Check a whitelist of possible topic status ID's
+	} elseif ( !empty( $_POST['bbp_topic_status'] ) && in_array( $_POST['bbp_topic_status'], array_keys( bbp_get_topic_statuses() ) ) ) {
+		$topic_status = $_POST['bbp_topic_status'];
+
+	// Default to published if nothing else
+	} else {
+		$topic_status = bbp_get_public_status_id();
+	}
+
+	/** Topic Tags ************************************************************/
+
+	if ( bbp_allow_topic_tags() && !empty( $_POST['bbp_topic_tags'] ) ) {
+
+		// Escape tag input
+		$terms = esc_attr( strip_tags( $_POST['bbp_topic_tags'] ) );
+
+		// Explode by comma
+		if ( strstr( $terms, ',' ) ) {
+			$terms = explode( ',', $terms );
+		}
+
+		// Add topic tag ID as main key
+		$terms = array( bbp_get_topic_tag_tax_id() => $terms );
+	}
+
+	/** Additional Actions (Before Save) **************************************/
+
+	do_action( 'bbp_new_topic_pre_extras', $forum_id );
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors *************************************************************/
+
+	// Add the content of the form to $topic_data as an array.
+	// Just in time manipulation of topic data before being created
+	$topic_data = apply_filters( 'bbp_new_topic_pre_insert', array(
+		'post_author'    => $topic_author,
+		'post_title'     => $topic_title,
+		'post_content'   => $topic_content,
+		'post_status'    => $topic_status,
+		'post_parent'    => $forum_id,
+		'post_type'      => bbp_get_topic_post_type(),
+		'tax_input'      => $terms,
+		'comment_status' => 'closed'
+	) );
+
+	// Insert topic
+	$topic_id = wp_insert_post( $topic_data );
+
+	/** No Errors *************************************************************/
+
+	if ( !empty( $topic_id ) && !is_wp_error( $topic_id ) ) {
+
+		/** Trash Check *******************************************************/
+
+		// If the forum is trash, or the topic_status is switched to
+		// trash, trash it properly
+		if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( $topic_data['post_status'] === bbp_get_trash_status_id() ) ) {
+
+			// Trash the reply
+			wp_trash_post( $topic_id );
+
+			// Force view=all
+			$view_all = true;
+		}
+
+		/** Spam Check ********************************************************/
+
+		// If reply or topic are spam, officially spam this reply
+		if ( $topic_data['post_status'] === bbp_get_spam_status_id() ) {
+			add_post_meta( $topic_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );
+
+			// Force view=all
+			$view_all = true;
+		}
+
+		/** Update counts, etc... *********************************************/
+
+		do_action( 'bbp_new_topic', $topic_id, $forum_id, $anonymous_data, $topic_author );
+
+		/** Stickies **********************************************************/
+
+		// Sticky check after 'bbp_new_topic' action so forum ID meta is set
+		if ( !empty( $_POST['bbp_stick_topic'] ) && in_array( $_POST['bbp_stick_topic'], array( 'stick', 'super', 'unstick' ) ) ) {
+
+			// What's the caps?
+			if ( current_user_can( 'moderate' ) ) {
+
+				// What's the haps?
+				switch ( $_POST['bbp_stick_topic'] ) {
+
+					// Sticky in this forum
+					case 'stick'   :
+						bbp_stick_topic( $topic_id );
+						break;
+
+					// Super sticky in all forums
+					case 'super'   :
+						bbp_stick_topic( $topic_id, true );
+						break;
+
+					// We can avoid this as it is a new topic
+					case 'unstick' :
+					default        :
+						break;
+				}
+			}
+		}
+
+		/** Additional Actions (After Save) ***********************************/
+
+		do_action( 'bbp_new_topic_post_extras', $topic_id );
+
+		/** Redirect **********************************************************/
+
+		// Redirect to
+		$redirect_to = bbp_get_redirect_to();
+
+		// Get the topic URL
+		$redirect_url = bbp_get_topic_permalink( $topic_id, $redirect_to );
+
+		// Add view all?
+		if ( bbp_get_view_all() || !empty( $view_all ) ) {
+
+			// User can moderate, so redirect to topic with view all set
+			if ( current_user_can( 'moderate' ) ) {
+				$redirect_url = bbp_add_view_all( $redirect_url );
+
+			// User cannot moderate, so redirect to forum
+			} else {
+				$redirect_url = bbp_get_forum_permalink( $forum_id );
+			}
+		}
+
+		// Allow to be filtered
+		$redirect_url = apply_filters( 'bbp_new_topic_redirect_to', $redirect_url, $redirect_to, $topic_id );
+
+		/** Successful Save ***************************************************/
+
+		// Redirect back to new topic
+		wp_safe_redirect( $redirect_url );
+
+		// For good measure
+		exit();
+
+	// Errors
+	} else {
+		$append_error = ( is_wp_error( $topic_id ) && $topic_id->get_error_message() ) ? $topic_id->get_error_message() . ' ' : '';
+		bbp_add_error( 'bbp_topic_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your topic:' . $append_error, 'bbpress' ) );
+	}
+}
+
+/**
+ * Handles the front end edit topic submission
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_get_topic() To get the topic
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses bbp_is_topic_anonymous() To check if topic is by an anonymous user
+ * @uses current_user_can() To check if the current user can edit the topic
+ * @uses bbp_filter_anonymous_post_data() To filter anonymous data
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses esc_attr() For sanitization
+ * @uses bbp_is_forum_category() To check if the forum is a category
+ * @uses bbp_is_forum_closed() To check if the forum is closed
+ * @uses bbp_is_forum_private() To check if the forum is private
+ * @uses remove_filter() To remove kses filters if needed
+ * @uses apply_filters() Calls 'bbp_edit_topic_pre_title' with the title and
+ *                        topic id
+ * @uses apply_filters() Calls 'bbp_edit_topic_pre_content' with the content
+ *                        and topic id
+ * @uses bbPress::errors::get_error_codes() To get the {@link WP_Error} errors
+ * @uses wp_save_post_revision() To save a topic revision
+ * @uses bbp_update_topic_revision_log() To update the topic revision log
+ * @uses bbp_stick_topic() To stick or super stick the topic
+ * @uses bbp_unstick_topic() To unstick the topic
+ * @uses wp_update_post() To update the topic
+ * @uses do_action() Calls 'bbp_edit_topic' with the topic id, forum id,
+ *                    anonymous data and reply author
+ * @uses bbp_move_topic_handler() To handle movement of a topic from one forum
+ *                                 to another
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ * @uses wp_safe_redirect() To redirect to the topic link
+ * @uses bbPress::errors::get_error_messages() To get the {@link WP_Error} error
+ *                                              messages
+ */
+function bbp_edit_topic_handler( $action = '' ) {
+
+	// Bail if action is not bbp-edit-topic
+	if ( 'bbp-edit-topic' !== $action )
+		return;
+
+	// Define local variable(s)
+	$revisions_removed = false;
+	$topic = $topic_id = $topic_author = $forum_id = $anonymous_data = 0;
+	$topic_title = $topic_content = $topic_edit_reason = '';
+
+	/** Topic *****************************************************************/
+
+	// Topic id was not passed
+	if ( empty( $_POST['bbp_topic_id'] ) ) {
+		bbp_add_error( 'bbp_edit_topic_id', __( '<strong>ERROR</strong>: Topic ID not found.', 'bbpress' ) );
+		return;
+
+	// Topic id was passed
+	} elseif ( is_numeric( $_POST['bbp_topic_id'] ) ) {
+		$topic_id = (int) $_POST['bbp_topic_id'];
+		$topic    = bbp_get_topic( $topic_id );
+	}
+
+	// Topic does not exist
+	if ( empty( $topic ) ) {
+		bbp_add_error( 'bbp_edit_topic_not_found', __( '<strong>ERROR</strong>: The topic you want to edit was not found.', 'bbpress' ) );
+		return;
+
+	// Topic exists
+	} else {
+
+		// Check users ability to create new topic
+		if ( ! bbp_is_topic_anonymous( $topic_id ) ) {
+
+			// User cannot edit this topic
+			if ( !current_user_can( 'edit_topic', $topic_id ) ) {
+				bbp_add_error( 'bbp_edit_topic_permissions', __( '<strong>ERROR</strong>: You do not have permission to edit that topic.', 'bbpress' ) );
+			}
+
+			// Set topic author
+			$topic_author = bbp_get_topic_author_id( $topic_id );
+
+		// It is an anonymous post
+		} else {
+
+			// Filter anonymous data
+			$anonymous_data = bbp_filter_anonymous_post_data( array(), true );
+		}
+	}
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'bbp-edit-topic_' . $topic_id ) ) {
+		bbp_add_error( 'bbp_edit_topic_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Remove kses filters from title and content for capable users and if the nonce is verified
+	if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_topic'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-topic_' . $topic_id ) === $_POST['_bbp_unfiltered_html_topic'] ) ) {
+		remove_filter( 'bbp_edit_topic_pre_title',   'wp_filter_kses'      );
+		remove_filter( 'bbp_edit_topic_pre_content', 'bbp_encode_bad',  10 );
+		remove_filter( 'bbp_edit_topic_pre_content', 'bbp_filter_kses', 30 );
+	}
+
+	/** Topic Forum ***********************************************************/
+
+	// Forum id was not passed
+	if ( empty( $_POST['bbp_forum_id'] ) ) {
+		bbp_add_error( 'bbp_topic_forum_id', __( '<strong>ERROR</strong>: Forum ID is missing.', 'bbpress' ) );
+
+	// Forum id was passed
+	} elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
+		$forum_id = (int) $_POST['bbp_forum_id'];
+	}
+
+	// Current forum this topic is in
+	$current_forum_id = bbp_get_topic_forum_id( $topic_id );
+
+	// Forum exists
+	if ( !empty( $forum_id ) && ( $forum_id !== $current_forum_id ) ) {
+
+		// Forum is a category
+		if ( bbp_is_forum_category( $forum_id ) ) {
+			bbp_add_error( 'bbp_edit_topic_forum_category', __( '<strong>ERROR</strong>: This forum is a category. No topics can be created in it.', 'bbpress' ) );
+
+		// Forum is not a category
+		} else {
+
+			// Forum is closed and user cannot access
+			if ( bbp_is_forum_closed( $forum_id ) && !current_user_can( 'edit_forum', $forum_id ) ) {
+				bbp_add_error( 'bbp_edit_topic_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new topics.', 'bbpress' ) );
+			}
+
+			// Forum is private and user cannot access
+			if ( bbp_is_forum_private( $forum_id ) ) {
+				if ( !current_user_can( 'read_private_forums' ) ) {
+					bbp_add_error( 'bbp_edit_topic_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
+				}
+
+			// Forum is hidden and user cannot access
+			} elseif ( bbp_is_forum_hidden( $forum_id ) ) {
+				if ( !current_user_can( 'read_hidden_forums' ) ) {
+					bbp_add_error( 'bbp_edit_topic_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
+				}
+			}
+		}
+	}
+
+	/** Topic Title ***********************************************************/
+
+	if ( !empty( $_POST['bbp_topic_title'] ) )
+		$topic_title = esc_attr( strip_tags( $_POST['bbp_topic_title'] ) );
+
+	// Filter and sanitize
+	$topic_title = apply_filters( 'bbp_edit_topic_pre_title', $topic_title, $topic_id );
+
+	// No topic title
+	if ( empty( $topic_title ) )
+		bbp_add_error( 'bbp_edit_topic_title', __( '<strong>ERROR</strong>: Your topic needs a title.', 'bbpress' ) );
+
+	/** Topic Content *********************************************************/
+
+	if ( !empty( $_POST['bbp_topic_content'] ) )
+		$topic_content = $_POST['bbp_topic_content'];
+
+	// Filter and sanitize
+	$topic_content = apply_filters( 'bbp_edit_topic_pre_content', $topic_content, $topic_id );
+
+	// No topic content
+	if ( empty( $topic_content ) )
+		bbp_add_error( 'bbp_edit_topic_content', __( '<strong>ERROR</strong>: Your topic cannot be empty.', 'bbpress' ) );
+
+	/** Topic Blacklist *******************************************************/
+
+	if ( !bbp_check_for_blacklist( $anonymous_data, $topic_author, $topic_title, $topic_content ) )
+		bbp_add_error( 'bbp_topic_blacklist', __( '<strong>ERROR</strong>: Your topic cannot be edited at this time.', 'bbpress' ) );
+
+	/** Topic Status **********************************************************/
+
+	// Maybe put into moderation
+	if ( !bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content ) ) {
+
+		// Set post status to pending if public or closed
+		if ( in_array( $topic->post_status, array( bbp_get_public_status_id(), bbp_get_closed_status_id() ) ) ) {
+			$topic_status = bbp_get_pending_status_id();
+		}
+
+	// Check a whitelist of possible topic status ID's
+	} elseif ( !empty( $_POST['bbp_topic_status'] ) && in_array( $_POST['bbp_topic_status'], array_keys( bbp_get_topic_statuses() ) ) ) {
+		$topic_status = $_POST['bbp_topic_status'];
+
+	// Use existing post_status
+	} else {
+		$topic_status = $topic->post_status;
+	}
+
+	/** Topic Tags ************************************************************/
+
+	// Either replace terms
+	if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags' ) && ! empty( $_POST['bbp_topic_tags'] ) ) {
+
+		// Escape tag input
+		$terms = esc_attr( strip_tags( $_POST['bbp_topic_tags'] ) );
+
+		// Explode by comma
+		if ( strstr( $terms, ',' ) )
+			$terms = explode( ',', $terms );
+
+		// Add topic tag ID as main key
+		$terms = array( bbp_get_topic_tag_tax_id() => $terms );
+
+	// ...or remove them.
+	} elseif ( isset( $_POST['bbp_topic_tags'] ) ) {
+		$terms = array( bbp_get_topic_tag_tax_id() => array() );
+
+	// Existing terms
+	} else {
+		$terms = array( bbp_get_topic_tag_tax_id() => explode( ',', bbp_get_topic_tag_names( $topic_id, ',' ) ) );
+	}
+
+	/** Additional Actions (Before Save) **************************************/
+
+	do_action( 'bbp_edit_topic_pre_extras', $topic_id );
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors *************************************************************/
+
+	// Add the content of the form to $topic_data as an array
+	// Just in time manipulation of topic data before being edited
+	$topic_data = apply_filters( 'bbp_edit_topic_pre_insert', array(
+		'ID'           => $topic_id,
+		'post_title'   => $topic_title,
+		'post_content' => $topic_content,
+		'post_status'  => $topic_status,
+		'post_parent'  => $forum_id,
+		'post_author'  => $topic_author,
+		'post_type'    => bbp_get_topic_post_type(),
+		'tax_input'    => $terms,
+	) );
+
+	// Toggle revisions to avoid duplicates
+	if ( post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
+		$revisions_removed = true;
+		remove_post_type_support( bbp_get_topic_post_type(), 'revisions' );
+	}
+
+	// Insert topic
+	$topic_id = wp_update_post( $topic_data );
+
+	// Toggle revisions back on
+	if ( true === $revisions_removed ) {
+		$revisions_removed = false;
+		add_post_type_support( bbp_get_topic_post_type(), 'revisions' );
+	}
+
+	/** No Errors *************************************************************/
+
+	if ( !empty( $topic_id ) && !is_wp_error( $topic_id ) ) {
+
+		// Update counts, etc...
+		do_action( 'bbp_edit_topic', $topic_id, $forum_id, $anonymous_data, $topic_author , true /* Is edit */ );
+
+		/** Revisions *********************************************************/
+
+		// Revision Reason
+		if ( !empty( $_POST['bbp_topic_edit_reason'] ) ) {
+			$topic_edit_reason = esc_attr( strip_tags( $_POST['bbp_topic_edit_reason'] ) );
+		}
+
+		// Update revision log
+		if ( !empty( $_POST['bbp_log_topic_edit'] ) && ( "1" === $_POST['bbp_log_topic_edit'] ) )  {
+			$revision_id = wp_save_post_revision( $topic_id );
+			if ( ! empty( $revision_id ) ) {
+				bbp_update_topic_revision_log( array(
+					'topic_id'    => $topic_id,
+					'revision_id' => $revision_id,
+					'author_id'   => bbp_get_current_user_id(),
+					'reason'      => $topic_edit_reason
+				) );
+			}
+		}
+
+		/** Move Topic ********************************************************/
+
+		// If the new forum id is not equal to the old forum id, run the
+		// bbp_move_topic action and pass the topic's forum id as the
+		// first arg and topic id as the second to update counts.
+		if ( $forum_id !== $topic->post_parent ) {
+			bbp_move_topic_handler( $topic_id, $topic->post_parent, $forum_id );
+		}
+
+		/** Stickies **********************************************************/
+
+		if ( !empty( $_POST['bbp_stick_topic'] ) && in_array( $_POST['bbp_stick_topic'], array_keys( bbp_get_topic_types() ) ) ) {
+
+			// What's the caps?
+			if ( current_user_can( 'moderate' ) ) {
+
+				// What's the haps?
+				switch ( $_POST['bbp_stick_topic'] ) {
+
+					// Sticky in forum
+					case 'stick'   :
+						bbp_stick_topic( $topic_id );
+						break;
+
+					// Sticky in all forums
+					case 'super'   :
+						bbp_stick_topic( $topic_id, true );
+						break;
+
+					// Normal
+					case 'unstick' :
+					default        :
+						bbp_unstick_topic( $topic_id );
+						break;
+				}
+			}
+		}
+
+		/** Additional Actions (After Save) ***********************************/
+
+		do_action( 'bbp_edit_topic_post_extras', $topic_id );
+
+		/** Redirect **********************************************************/
+
+		// Redirect to
+		$redirect_to = bbp_get_redirect_to();
+
+		// View all?
+		$view_all = bbp_get_view_all();
+
+		// Get the topic URL
+		$topic_url = bbp_get_topic_permalink( $topic_id, $redirect_to );
+
+		// Add view all?
+		if ( !empty( $view_all ) )
+			$topic_url = bbp_add_view_all( $topic_url );
+
+		// Allow to be filtered
+		$topic_url = apply_filters( 'bbp_edit_topic_redirect_to', $topic_url, $view_all, $redirect_to );
+
+		/** Successful Edit ***************************************************/
+
+		// Redirect back to new topic
+		wp_safe_redirect( $topic_url );
+
+		// For good measure
+		exit();
+
+	/** Errors ****************************************************************/
+
+	} else {
+		$append_error = ( is_wp_error( $topic_id ) && $topic_id->get_error_message() ) ? $topic_id->get_error_message() . ' ' : '';
+		bbp_add_error( 'bbp_topic_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your topic:' . $append_error . 'Please try again.', 'bbpress' ) );
+	}
+}
+
+/**
+ * Handle all the extra meta stuff from posting a new topic
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param int $forum_id Optional. Forum id
+ * @param bool|array $anonymous_data Optional logged-out user data.
+ * @param int $author_id Author id
+ * @param bool $is_edit Optional. Is the post being edited? Defaults to false.
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_current_user_id() To get the current user id
+ * @yses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses update_post_meta() To update the topic metas
+ * @uses set_transient() To update the flood check transient for the ip
+ * @uses bbp_update_user_last_posted() To update the users last posted time
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions feature is
+ *                                      activated or not
+ * @uses bbp_is_user_subscribed() To check if the user is subscribed
+ * @uses bbp_remove_user_subscription() To remove the user's subscription
+ * @uses bbp_add_user_subscription() To add the user's subscription
+ * @uses bbp_update_topic_forum_id() To update the topic's forum id
+ * @uses bbp_update_topic_topic_id() To update the topic's topic id
+ * @uses bbp_update_topic_last_reply_id() To update the last reply id topic meta
+ * @uses bbp_update_topic_last_active_id() To update the topic last active id
+ * @uses bbp_update_topic_last_active_time() To update the last active topic meta
+ * @uses bbp_update_topic_reply_count() To update the topic reply count
+ * @uses bbp_update_topic_reply_count_hidden() To udpate the topic hidden reply count
+ * @uses bbp_update_topic_voice_count() To update the topic voice count
+ * @uses bbp_update_topic_walker() To udpate the topic's ancestors
+ */
+function bbp_update_topic( $topic_id = 0, $forum_id = 0, $anonymous_data = false, $author_id = 0, $is_edit = false ) {
+
+	// Validate the ID's passed from 'bbp_new_topic' action
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$forum_id = bbp_get_forum_id( $forum_id );
+
+	// Bail if there is no topic
+	if ( empty( $topic_id ) )
+		return;
+
+	// Check author_id
+	if ( empty( $author_id ) )
+		$author_id = bbp_get_current_user_id();
+
+	// Check forum_id
+	if ( empty( $forum_id ) )
+		$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+	// If anonymous post, store name, email, website and ip in post_meta.
+	// It expects anonymous_data to be sanitized.
+	// Check bbp_filter_anonymous_post_data() for sanitization.
+	if ( !empty( $anonymous_data ) && is_array( $anonymous_data ) ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $anonymous_data, array(
+			'bbp_anonymous_name'    => '',
+			'bbp_anonymous_email'   => '',
+			'bbp_anonymous_website' => '',
+		), 'update_topic' );
+
+		// Update all anonymous metas
+		foreach ( $r as $anon_key => $anon_value ) {
+			update_post_meta( $topic_id, '_' . $anon_key, (string) $anon_value, false );
+		}
+
+		// Set transient for throttle check (only on new, not edit)
+		if ( empty( $is_edit ) ) {
+			set_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted', time() );
+		}
+
+	} else {
+		if ( empty( $is_edit ) && !current_user_can( 'throttle' ) ) {
+			bbp_update_user_last_posted( $author_id );
+		}
+	}
+
+	// Handle Subscription Checkbox
+	if ( bbp_is_subscriptions_active() && !empty( $author_id ) ) {
+		$subscribed = bbp_is_user_subscribed( $author_id, $topic_id );
+		$subscheck  = ( !empty( $_POST['bbp_topic_subscription'] ) && ( 'bbp_subscribe' === $_POST['bbp_topic_subscription'] ) ) ? true : false;
+
+		// Subscribed and unsubscribing
+		if ( true === $subscribed && false === $subscheck ) {
+			bbp_remove_user_subscription( $author_id, $topic_id );
+
+		// Subscribing
+		} elseif ( false === $subscribed && true === $subscheck ) {
+			bbp_add_user_subscription( $author_id, $topic_id );
+		}
+	}
+
+	// Forum topic meta
+	bbp_update_topic_forum_id( $topic_id, $forum_id );
+	bbp_update_topic_topic_id( $topic_id, $topic_id );
+
+	// Update associated topic values if this is a new topic
+	if ( empty( $is_edit ) ) {
+
+		// Update poster IP if not editing
+		update_post_meta( $topic_id, '_bbp_author_ip', bbp_current_author_ip(), false );
+
+		// Last active time
+		$last_active = current_time( 'mysql' );
+
+		// Reply topic meta
+		bbp_update_topic_last_reply_id      ( $topic_id, 0            );
+		bbp_update_topic_last_active_id     ( $topic_id, $topic_id    );
+		bbp_update_topic_last_active_time   ( $topic_id, $last_active );
+		bbp_update_topic_reply_count        ( $topic_id, 0            );
+		bbp_update_topic_reply_count_hidden ( $topic_id, 0            );
+		bbp_update_topic_voice_count        ( $topic_id               );
+
+		// Walk up ancestors and do the dirty work
+		bbp_update_topic_walker( $topic_id, $last_active, $forum_id, 0, false );
+	}
+}
+
+/**
+ * Walks up the post_parent tree from the current topic_id, and updates the
+ * counts of forums above it. This calls a few internal functions that all run
+ * manual queries against the database to get their results. As such, this
+ * function can be costly to run but is necessary to keep everything accurate.
+ *
+ * @since bbPress (r2800)
+ * @param int $topic_id Topic id
+ * @param string $last_active_time Optional. Last active time
+ * @param int $forum_id Optional. Forum id
+ * @param int $reply_id Optional. Reply id
+ * @param bool $refresh Reset all the previous parameters? Defaults to true.
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses get_post_ancestors() To get the topic's ancestors
+ * @uses bbp_is_forum() To check if the ancestor is a forum
+ * @uses bbp_update_forum() To update the forum
+ */
+function bbp_update_topic_walker( $topic_id, $last_active_time = '', $forum_id = 0, $reply_id = 0, $refresh = true ) {
+
+	// Validate topic_id
+	$topic_id  = bbp_get_topic_id( $topic_id );
+
+	// Define local variable(s)
+	$active_id = 0;
+
+	// Topic was passed
+	if ( !empty( $topic_id ) ) {
+
+		// Get the forum ID if none was passed
+		if ( empty( $forum_id )  ) {
+			$forum_id = bbp_get_topic_forum_id( $topic_id );
+		}
+
+		// Set the active_id based on topic_id/reply_id
+		$active_id = empty( $reply_id ) ? $topic_id : $reply_id;
+	}
+
+	// Get topic ancestors
+	$ancestors = array_values( array_unique( array_merge( array( $forum_id ), (array) get_post_ancestors( $topic_id ) ) ) );
+
+	// Topic status
+	$topic_status = get_post_status( $topic_id );
+
+	// If we want a full refresh, unset any of the possibly passed variables
+	if ( true === $refresh ) {
+		$forum_id = $topic_id = $reply_id = $active_id = $last_active_time = 0;
+		$topic_status = bbp_get_public_status_id();
+	}
+
+	// Loop through ancestors
+	if ( !empty( $ancestors ) ) {
+		foreach ( $ancestors as $ancestor ) {
+
+			// If ancestor is a forum, update counts
+			if ( bbp_is_forum( $ancestor ) ) {
+
+				// Update the forum
+				bbp_update_forum( array(
+					'forum_id'           => $ancestor,
+					'last_topic_id'      => $topic_id,
+					'last_reply_id'      => $reply_id,
+					'last_active_id'     => $active_id,
+					'last_active_time'   => 0,
+					'last_active_status' => $topic_status
+				) );
+			}
+		}
+	}
+}
+
+/**
+ * Handle the moving of a topic from one forum to another. This includes walking
+ * up the old and new branches and updating the counts.
+ *
+ * @param int $topic_id Topic id
+ * @param int $old_forum_id Old forum id
+ * @param int $new_forum_id New forum id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_stickies() To get the old forums sticky topics
+ * @uses delete_post_meta() To delete the forum sticky meta
+ * @uses update_post_meta() To update the old forum sticky meta
+ * @uses bbp_stick_topic() To stick the topic in the new forum
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_all_child_ids() To get the public child ids
+ * @uses bbp_update_reply_forum_id() To update the reply forum id
+ * @uses bbp_update_topic_forum_id() To update the topic forum id
+ * @uses get_post_ancestors() To get the topic's ancestors
+ * @uses bbp_is_forum() To check if the ancestor is a forum
+ * @uses bbp_update_forum() To update the forum
+ */
+function bbp_move_topic_handler( $topic_id, $old_forum_id, $new_forum_id ) {
+
+	// Validate parameters
+	$topic_id     = bbp_get_topic_id( $topic_id     );
+	$old_forum_id = bbp_get_forum_id( $old_forum_id );
+	$new_forum_id = bbp_get_forum_id( $new_forum_id );
+
+	// Update topic forum's ID
+	bbp_update_topic_forum_id( $topic_id, $new_forum_id );
+
+	/** Stickies **************************************************************/
+
+	// Get forum stickies
+	$old_stickies = bbp_get_stickies( $old_forum_id );
+
+	// Only proceed if stickies are found
+	if ( !empty( $old_stickies ) ) {
+
+		// Define local variables
+		$updated_stickies = array();
+
+		// Loop through stickies of forum and add misses to the updated array
+		foreach ( (array) $old_stickies as $sticky_topic_id ) {
+			if ( $topic_id !== $sticky_topic_id ) {
+				$updated_stickies[] = $sticky_topic_id;
+			}
+		}
+
+		// If stickies are different, update or delete them
+		if ( $updated_stickies !== $old_stickies ) {
+
+			// No more stickies so delete the meta
+			if ( empty( $updated_stickies ) ) {
+				delete_post_meta( $old_forum_id, '_bbp_sticky_topics' );
+
+			// Still stickies so update the meta
+			} else {
+				update_post_meta( $old_forum_id, '_bbp_sticky_topics', $updated_stickies );
+			}
+
+			// Topic was sticky, so restick in new forum
+			bbp_stick_topic( $topic_id );
+		}
+	}
+
+	/** Topic Replies *********************************************************/
+
+	// Get the topics replies
+	$replies = bbp_get_all_child_ids( $topic_id, bbp_get_reply_post_type() );
+
+	// Update the forum_id of all replies in the topic
+	foreach ( $replies as $reply_id ) {
+		bbp_update_reply_forum_id( $reply_id, $new_forum_id );
+	}
+
+	/** Old forum_id **********************************************************/
+
+	// Get topic ancestors
+	$old_forum_ancestors = array_values( array_unique( array_merge( array( $old_forum_id ), (array) get_post_ancestors( $old_forum_id ) ) ) );
+
+	// Loop through ancestors and update them
+	if ( !empty( $old_forum_ancestors ) ) {
+		foreach ( $old_forum_ancestors as $ancestor ) {
+			if ( bbp_is_forum( $ancestor ) ) {
+				bbp_update_forum( array(
+					'forum_id' => $ancestor,
+				) );
+			}
+		}
+	}
+
+	/** New forum_id **********************************************************/
+
+	// Make sure we're not walking twice
+	if ( !in_array( $new_forum_id, $old_forum_ancestors ) ) {
+
+		// Get topic ancestors
+		$new_forum_ancestors = array_values( array_unique( array_merge( array( $new_forum_id ), (array) get_post_ancestors( $new_forum_id ) ) ) );
+
+		// Make sure we're not walking twice
+		$new_forum_ancestors = array_diff( $new_forum_ancestors, $old_forum_ancestors );
+
+		// Loop through ancestors and update them
+		if ( !empty( $new_forum_ancestors ) ) {
+			foreach ( $new_forum_ancestors as $ancestor ) {
+				if ( bbp_is_forum( $ancestor ) ) {
+					bbp_update_forum( array(
+						'forum_id' => $ancestor,
+					) );
+				}
+			}
+		}
+	}
+}
+
+/**
+ * Merge topic handler
+ *
+ * Handles the front end merge topic submission
+ *
+ * @since bbPress (r2756)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_get_topic() To get the topics
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit the topics
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses do_action() Calls 'bbp_merge_topic' with the destination and source
+ *                    topic ids
+ * @uses bbp_get_topic_subscribers() To get the source topic subscribers
+ * @uses bbp_add_user_subscription() To add the user subscription
+ * @uses bbp_remove_user_subscription() To remove the user subscription
+ * @uses bbp_get_topic_favoriters() To get the source topic favoriters
+ * @uses bbp_add_user_favorite() To add the user favorite
+ * @uses bbp_remove_user_favorite() To remove the user favorite
+ * @uses wp_get_post_terms() To get the source topic tags
+ * @uses wp_set_post_terms() To set the topic tags
+ * @uses wp_delete_object_term_relationships() To delete the topic tags
+ * @uses bbp_open_topic() To open the topic
+ * @uses bbp_unstick_topic() To unstick the topic
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses get_posts() To get the replies
+ * @uses wp_update_post() To update the topic
+ * @uses bbp_update_reply_topic_id() To update the reply topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_update_reply_forum_id() To update the reply forum id
+ * @uses do_action() Calls 'bbp_merged_topic_reply' with the reply id and
+ *                    destination topic id
+ * @uses do_action() Calls 'bbp_merged_topic' with the destination and source
+ *                    topic ids and source topic's forum id
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ * @uses wp_safe_redirect() To redirect to the topic link
+ */
+function bbp_merge_topic_handler( $action = '' ) {
+
+	// Bail if action is not bbp-merge-topic
+	if ( 'bbp-merge-topic' !== $action )
+		return;
+
+	// Define local variable(s)
+	$source_topic_id = $destination_topic_id = 0;
+	$source_topic = $destination_topic = 0;
+	$subscribers = $favoriters = $replies = array();
+
+	/** Source Topic **********************************************************/
+
+	// Topic id
+	if ( empty( $_POST['bbp_topic_id'] ) ) {
+		bbp_add_error( 'bbp_merge_topic_source_id', __( '<strong>ERROR</strong>: Topic ID not found.', 'bbpress' ) );
+	} else {
+		$source_topic_id = (int) $_POST['bbp_topic_id'];
+	}
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'bbp-merge-topic_' . $source_topic_id ) ) {
+		bbp_add_error( 'bbp_merge_topic_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+
+	// Source topic not found
+	} elseif ( !$source_topic = bbp_get_topic( $source_topic_id ) ) {
+		bbp_add_error( 'bbp_merge_topic_source_not_found', __( '<strong>ERROR</strong>: The topic you want to merge was not found.', 'bbpress' ) );
+		return;
+	}
+
+	// Cannot edit source topic
+	if ( !current_user_can( 'edit_topic', $source_topic->ID ) ) {
+		bbp_add_error( 'bbp_merge_topic_source_permission', __( '<strong>ERROR</strong>: You do not have the permissions to edit the source topic.', 'bbpress' ) );
+		return;
+	}
+
+	/** Destination Topic *****************************************************/
+
+	// Topic id
+	if ( empty( $_POST['bbp_destination_topic'] ) )
+		bbp_add_error( 'bbp_merge_topic_destination_id', __( '<strong>ERROR</strong>: Destination topic ID not found.', 'bbpress' ) );
+	else
+		$destination_topic_id = (int) $_POST['bbp_destination_topic'];
+
+	// Destination topic not found
+	if ( !$destination_topic = bbp_get_topic( $destination_topic_id ) )
+		bbp_add_error( 'bbp_merge_topic_destination_not_found', __( '<strong>ERROR</strong>: The topic you want to merge to was not found.', 'bbpress' ) );
+
+	// Cannot edit destination topic
+	if ( !current_user_can( 'edit_topic', $destination_topic->ID ) )
+		bbp_add_error( 'bbp_merge_topic_destination_permission', __( '<strong>ERROR</strong>: You do not have the permissions to edit the destination topic.', 'bbpress' ) );
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors *************************************************************/
+
+	// Update counts, etc...
+	do_action( 'bbp_merge_topic', $destination_topic->ID, $source_topic->ID );
+
+	/** Date Check ************************************************************/
+
+	// Check if the destination topic is older than the source topic
+	if ( strtotime( $source_topic->post_date ) < strtotime( $destination_topic->post_date ) ) {
+
+		// Set destination topic post_date to 1 second before source topic
+		$destination_post_date = date( 'Y-m-d H:i:s', strtotime( $source_topic->post_date ) - 1 );
+
+		// Update destination topic
+		wp_update_post( array(
+			'ID'            => $destination_topic_id,
+			'post_date'     => $destination_post_date,
+			'post_date_gmt' => get_gmt_from_date( $destination_post_date )
+		) );
+	}
+
+	/** Subscriptions *********************************************************/
+
+	// Get subscribers from source topic
+	$subscribers = bbp_get_topic_subscribers( $source_topic->ID );
+
+	// Remove the topic from everybody's subscriptions
+	if ( !empty( $subscribers ) ) {
+
+		// Loop through each user
+		foreach ( (array) $subscribers as $subscriber ) {
+
+			// Shift the subscriber if told to
+			if ( !empty( $_POST['bbp_topic_subscribers'] ) && ( "1" === $_POST['bbp_topic_subscribers'] ) && bbp_is_subscriptions_active() )
+				bbp_add_user_subscription( $subscriber, $destination_topic->ID );
+
+			// Remove old subscription
+			bbp_remove_user_subscription( $subscriber, $source_topic->ID );
+		}
+	}
+
+	/** Favorites *************************************************************/
+
+	// Get favoriters from source topic
+	$favoriters = bbp_get_topic_favoriters( $source_topic->ID );
+
+	// Remove the topic from everybody's favorites
+	if ( !empty( $favoriters ) ) {
+
+		// Loop through each user
+		foreach ( (array) $favoriters as $favoriter ) {
+
+			// Shift the favoriter if told to
+			if ( !empty( $_POST['bbp_topic_favoriters'] ) && "1" === $_POST['bbp_topic_favoriters'] )
+				bbp_add_user_favorite( $favoriter, $destination_topic->ID );
+
+			// Remove old favorite
+			bbp_remove_user_favorite( $favoriter, $source_topic->ID );
+		}
+	}
+
+	/** Tags ******************************************************************/
+
+	// Get the source topic tags
+	$source_topic_tags = wp_get_post_terms( $source_topic->ID, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );
+
+	// Tags to possibly merge
+	if ( !empty( $source_topic_tags ) && !is_wp_error( $source_topic_tags ) ) {
+
+		// Shift the tags if told to
+		if ( !empty( $_POST['bbp_topic_tags'] ) && ( "1" === $_POST['bbp_topic_tags'] ) )
+			wp_set_post_terms( $destination_topic->ID, $source_topic_tags, bbp_get_topic_tag_tax_id(), true );
+
+		// Delete the tags from the source topic
+		wp_delete_object_term_relationships( $source_topic->ID, bbp_get_topic_tag_tax_id() );
+	}
+
+	/** Source Topic **********************************************************/
+
+	// Status
+	bbp_open_topic( $source_topic->ID );
+
+	// Sticky
+	bbp_unstick_topic( $source_topic->ID );
+
+	// Get the replies of the source topic
+	$replies = (array) get_posts( array(
+		'post_parent'    => $source_topic->ID,
+		'post_type'      => bbp_get_reply_post_type(),
+		'posts_per_page' => -1,
+		'order'          => 'ASC'
+	) );
+
+	// Prepend the source topic to its replies array for processing
+	array_unshift( $replies, $source_topic );
+
+	if ( !empty( $replies ) ) {
+
+		/** Merge Replies *****************************************************/
+
+		// Change the post_parent of each reply to the destination topic id
+		foreach ( $replies as $reply ) {
+
+			// Update the reply
+			wp_update_post( array(
+				'ID'          => $reply->ID,
+				'post_title'  => sprintf( __( 'Reply To: %s', 'bbpress' ), $destination_topic->post_title ),
+				'post_name'   => false,
+				'post_type'   => bbp_get_reply_post_type(),
+				'post_parent' => $destination_topic->ID,
+				'guid'        => ''
+			) );
+
+			// Adjust reply meta values
+			bbp_update_reply_topic_id( $reply->ID, $destination_topic->ID                           );
+			bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );
+
+			// Adjust reply to values
+			$reply_to = bbp_get_reply_to( $reply->ID );
+			if ( empty( $reply_to ) ) {
+				bbp_update_reply_to( $reply->ID, $source_topic->ID );
+			}
+
+			// Do additional actions per merged reply
+			do_action( 'bbp_merged_topic_reply', $reply->ID, $destination_topic->ID );
+		}
+	}
+
+	/** Successful Merge ******************************************************/
+
+	// Update topic's last meta data
+	bbp_update_topic_last_reply_id   ( $destination_topic->ID );
+	bbp_update_topic_last_active_id  ( $destination_topic->ID );
+	bbp_update_topic_last_active_time( $destination_topic->ID );
+
+	// Send the post parent of the source topic as it has been shifted
+	// (possibly to a new forum) so we need to update the counts of the
+	// old forum as well as the new one
+	do_action( 'bbp_merged_topic', $destination_topic->ID, $source_topic->ID, $source_topic->post_parent );
+
+	// Redirect back to new topic
+	wp_safe_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
+
+	// For good measure
+	exit();
+}
+
+/**
+ * Fix counts on topic merge
+ *
+ * When a topic is merged, update the counts of source and destination topic
+ * and their forums.
+ *
+ * @since bbPress (r2756)
+ *
+ * @param int $destination_topic_id Destination topic id
+ * @param int $source_topic_id Source topic id
+ * @param int $source_topic_forum Source topic's forum id
+ * @uses bbp_update_forum_topic_count() To update the forum topic counts
+ * @uses bbp_update_forum_reply_count() To update the forum reply counts
+ * @uses bbp_update_topic_reply_count() To update the topic reply counts
+ * @uses bbp_update_topic_voice_count() To update the topic voice counts
+ * @uses bbp_update_topic_reply_count_hidden() To update the topic hidden reply
+ *                                              count
+ * @uses do_action() Calls 'bbp_merge_topic_count' with the destination topic
+ *                    id, source topic id & source topic forum id
+ */
+function bbp_merge_topic_count( $destination_topic_id, $source_topic_id, $source_topic_forum_id ) {
+
+	/** Source Topic **********************************************************/
+
+	// Forum Topic Counts
+	bbp_update_forum_topic_count( $source_topic_forum_id );
+
+	// Forum Reply Counts
+	bbp_update_forum_reply_count( $source_topic_forum_id );
+
+	/** Destination Topic *****************************************************/
+
+	// Topic Reply Counts
+	bbp_update_topic_reply_count( $destination_topic_id );
+
+	// Topic Hidden Reply Counts
+	bbp_update_topic_reply_count_hidden( $destination_topic_id );
+
+	// Topic Voice Counts
+	bbp_update_topic_voice_count( $destination_topic_id );
+
+	do_action( 'bbp_merge_topic_count', $destination_topic_id, $source_topic_id, $source_topic_forum_id );
+}
+
+/**
+ * Split topic handler
+ *
+ * Handles the front end split topic submission
+ *
+ * @since bbPress (r2756)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_add_error() To add an error message
+ * @uses bbp_get_reply() To get the reply
+ * @uses bbp_get_topic() To get the topics
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit the topics
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses do_action() Calls 'bbp_pre_split_topic' with the from reply id, source
+ *                    and destination topic ids
+ * @uses bbp_get_topic_subscribers() To get the source topic subscribers
+ * @uses bbp_add_user_subscription() To add the user subscription
+ * @uses bbp_get_topic_favoriters() To get the source topic favoriters
+ * @uses bbp_add_user_favorite() To add the user favorite
+ * @uses wp_get_post_terms() To get the source topic tags
+ * @uses wp_set_post_terms() To set the topic tags
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wpdb::prepare() To prepare our sql query
+ * @uses wpdb::get_results() To execute the sql query and get results
+ * @uses wp_update_post() To update the replies
+ * @uses bbp_update_reply_topic_id() To update the reply topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_update_reply_forum_id() To update the reply forum id
+ * @uses do_action() Calls 'bbp_split_topic_reply' with the reply id and
+ *                    destination topic id
+ * @uses bbp_update_topic_last_reply_id() To update the topic last reply id
+ * @uses bbp_update_topic_last_active_time() To update the topic last active meta
+ * @uses do_action() Calls 'bbp_post_split_topic' with the destination and
+ *                    source topic ids and source topic's forum id
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ * @uses wp_safe_redirect() To redirect to the topic link
+ */
+function bbp_split_topic_handler( $action = '' ) {
+
+	// Bail if action is not 'bbp-split-topic'
+	if ( 'bbp-split-topic' !== $action )
+		return;
+
+	global $wpdb;
+
+	// Prevent debug notices
+	$from_reply_id = $destination_topic_id = 0;
+	$destination_topic_title = '';
+	$destination_topic = $from_reply = $source_topic = '';
+	$split_option = false;
+
+	/** Split Reply ***********************************************************/
+
+	if ( empty( $_POST['bbp_reply_id'] ) )
+		bbp_add_error( 'bbp_split_topic_reply_id', __( '<strong>ERROR</strong>: Reply ID to split the topic from not found!', 'bbpress' ) );
+	else
+		$from_reply_id = (int) $_POST['bbp_reply_id'];
+
+	$from_reply = bbp_get_reply( $from_reply_id );
+
+	// Reply exists
+	if ( empty( $from_reply ) )
+		bbp_add_error( 'bbp_split_topic_r_not_found', __( '<strong>ERROR</strong>: The reply you want to split from was not found.', 'bbpress' ) );
+
+	/** Topic to Split ********************************************************/
+
+	// Get the topic being split
+	$source_topic = bbp_get_topic( $from_reply->post_parent );
+
+	// No topic
+	if ( empty( $source_topic ) )
+		bbp_add_error( 'bbp_split_topic_source_not_found', __( '<strong>ERROR</strong>: The topic you want to split was not found.', 'bbpress' ) );
+
+	// Nonce check failed
+	if ( ! bbp_verify_nonce_request( 'bbp-split-topic_' . $source_topic->ID ) ) {
+		bbp_add_error( 'bbp_split_topic_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Use cannot edit topic
+	if ( !current_user_can( 'edit_topic', $source_topic->ID ) )
+		bbp_add_error( 'bbp_split_topic_source_permission', __( '<strong>ERROR</strong>: You do not have the permissions to edit the source topic.', 'bbpress' ) );
+
+	// How to Split
+	if ( !empty( $_POST['bbp_topic_split_option'] ) )
+		$split_option = (string) trim( $_POST['bbp_topic_split_option'] );
+
+	// Invalid split option
+	if ( empty( $split_option ) || !in_array( $split_option, array( 'existing', 'reply' ) ) ) {
+		bbp_add_error( 'bbp_split_topic_option', __( '<strong>ERROR</strong>: You need to choose a valid split option.', 'bbpress' ) );
+
+	// Valid Split Option
+	} else {
+
+		// What kind of split
+		switch ( $split_option ) {
+
+			// Into an existing topic
+			case 'existing' :
+
+				// Get destination topic id
+				if ( empty( $_POST['bbp_destination_topic'] ) )
+					bbp_add_error( 'bbp_split_topic_destination_id', __( '<strong>ERROR</strong>: Destination topic ID not found!', 'bbpress' ) );
+				else
+					$destination_topic_id = (int) $_POST['bbp_destination_topic'];
+
+				// Get the destination topic
+				$destination_topic = bbp_get_topic( $destination_topic_id );
+
+				// No destination topic
+				if ( empty( $destination_topic ) )
+					bbp_add_error( 'bbp_split_topic_destination_not_found', __( '<strong>ERROR</strong>: The topic you want to split to was not found!', 'bbpress' ) );
+
+				// User cannot edit the destination topic
+				if ( !current_user_can( 'edit_topic', $destination_topic->ID ) )
+					bbp_add_error( 'bbp_split_topic_destination_permission', __( '<strong>ERROR</strong>: You do not have the permissions to edit the destination topic!', 'bbpress' ) );
+
+				break;
+
+			// Split at reply into a new topic
+			case 'reply' :
+			default :
+
+				// User needs to be able to publish topics
+				if ( current_user_can( 'publish_topics' ) ) {
+
+					// Use the new title that was passed
+					if ( !empty( $_POST['bbp_topic_split_destination_title'] ) ) {
+						$destination_topic_title = esc_attr( strip_tags( $_POST['bbp_topic_split_destination_title'] ) );
+
+					// Use the source topic title
+					} else {
+						$destination_topic_title = $source_topic->post_title;
+					}
+
+					// Update the topic
+					$destination_topic_id = wp_update_post( array(
+						'ID'          => $from_reply->ID,
+						'post_title'  => $destination_topic_title,
+						'post_name'   => false,
+						'post_type'   => bbp_get_topic_post_type(),
+						'post_parent' => $source_topic->post_parent,
+						'menu_order'  => 0,
+						'guid'        => ''
+					) );
+					$destination_topic = bbp_get_topic( $destination_topic_id );
+
+					// Make sure the new topic knows its a topic
+					bbp_update_topic_topic_id( $from_reply->ID );
+
+					// Shouldn't happen
+					if ( false === $destination_topic_id || is_wp_error( $destination_topic_id ) || empty( $destination_topic ) ) {
+						bbp_add_error( 'bbp_split_topic_destination_reply', __( '<strong>ERROR</strong>: There was a problem converting the reply into the topic. Please try again.', 'bbpress' ) );
+					}
+
+				// User cannot publish posts
+				} else {
+					bbp_add_error( 'bbp_split_topic_destination_permission', __( '<strong>ERROR</strong>: You do not have the permissions to create new topics. The reply could not be converted into a topic.', 'bbpress' ) );
+				}
+
+				break;
+		}
+	}
+
+	// Bail if there are errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No Errors - Do the Spit ***********************************************/
+
+	// Update counts, etc...
+	do_action( 'bbp_pre_split_topic', $from_reply->ID, $source_topic->ID, $destination_topic->ID );
+
+	/** Date Check ************************************************************/
+
+	// Check if the destination topic is older than the from reply
+	if ( strtotime( $from_reply->post_date ) < strtotime( $destination_topic->post_date ) ) {
+
+		// Set destination topic post_date to 1 second before from reply
+		$destination_post_date = date( 'Y-m-d H:i:s', strtotime( $from_reply->post_date ) - 1 );
+
+		// Update destination topic
+		wp_update_post( array(
+			'ID'            => $destination_topic_id,
+			'post_date'     => $destination_post_date,
+			'post_date_gmt' => get_gmt_from_date( $destination_post_date )
+		) );
+	}
+
+	/** Subscriptions *********************************************************/
+
+	// Copy the subscribers
+	if ( !empty( $_POST['bbp_topic_subscribers'] ) && "1" === $_POST['bbp_topic_subscribers'] && bbp_is_subscriptions_active() ) {
+
+		// Get the subscribers
+		$subscribers = bbp_get_topic_subscribers( $source_topic->ID );
+
+		if ( !empty( $subscribers ) ) {
+
+			// Add subscribers to new topic
+			foreach ( (array) $subscribers as $subscriber ) {
+				bbp_add_user_subscription( $subscriber, $destination_topic->ID );
+			}
+		}
+	}
+
+	/** Favorites *************************************************************/
+
+	// Copy the favoriters if told to
+	if ( !empty( $_POST['bbp_topic_favoriters'] ) && ( "1" === $_POST['bbp_topic_favoriters'] ) ) {
+
+		// Get the favoriters
+		$favoriters = bbp_get_topic_favoriters( $source_topic->ID );
+
+		if ( !empty( $favoriters ) ) {
+
+			// Add the favoriters to new topic
+			foreach ( (array) $favoriters as $favoriter ) {
+				bbp_add_user_favorite( $favoriter, $destination_topic->ID );
+			}
+		}
+	}
+
+	/** Tags ******************************************************************/
+
+	// Copy the tags if told to
+	if ( !empty( $_POST['bbp_topic_tags'] ) && ( "1" === $_POST['bbp_topic_tags'] ) ) {
+
+		// Get the source topic tags
+		$source_topic_tags = wp_get_post_terms( $source_topic->ID, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );
+
+		if ( !empty( $source_topic_tags ) ) {
+			wp_set_post_terms( $destination_topic->ID, $source_topic_tags, bbp_get_topic_tag_tax_id(), true );
+		}
+	}
+
+	/** Split Replies *********************************************************/
+
+	// get_posts() is not used because it doesn't allow us to use '>='
+	// comparision without a filter.
+	$replies = (array) $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->posts} WHERE {$wpdb->posts}.post_date >= %s AND {$wpdb->posts}.post_parent = %d AND {$wpdb->posts}.post_type = %s ORDER BY {$wpdb->posts}.post_date ASC", $from_reply->post_date, $source_topic->ID, bbp_get_reply_post_type() ) );
+
+	// Make sure there are replies to loop through
+	if ( !empty( $replies ) && !is_wp_error( $replies ) ) {
+
+		// Calculate starting point for reply positions
+		switch ( $split_option ) {
+
+			// Get topic reply count for existing topic
+			case 'existing' :
+				$reply_position = bbp_get_topic_reply_count( $destination_topic->ID );
+				break;
+
+			// Account for new lead topic
+			case 'reply'    :
+				$reply_position = 1;
+				break;
+		}
+
+		// Save reply ids
+		$reply_ids = array();
+
+		// Change the post_parent of each reply to the destination topic id
+		foreach ( $replies as $reply ) {
+
+			// Bump the reply position each iteration through the loop
+			$reply_position++;
+
+			// Update the reply
+			wp_update_post( array(
+				'ID'          => $reply->ID,
+				'post_title'  => sprintf( __( 'Reply To: %s', 'bbpress' ), $destination_topic->post_title ),
+				'post_name'   => false, // will be automatically generated
+				'post_parent' => $destination_topic->ID,
+				'menu_order'  => $reply_position,
+				'guid'        => ''
+			) );
+
+			// Gather reply ids
+			$reply_ids[] = $reply->ID;
+
+			// Adjust reply meta values
+			bbp_update_reply_topic_id( $reply->ID, $destination_topic->ID                           );
+			bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );
+
+			// Adjust reply to values
+			$reply_to = bbp_get_reply_to( $reply->ID );
+
+			// Not a reply to a reply that moved over
+			if ( !in_array( $reply_to, $reply_ids ) ) {
+				bbp_update_reply_to( $reply->ID, 0 );
+			}
+
+			// New topic from reply can't be a reply to
+			if ( ( $from_reply->ID === $destination_topic->ID ) && ( $from_reply->ID === $reply_to ) ) {
+				bbp_update_reply_to( $reply->ID, 0 );
+			}
+
+			// Do additional actions per split reply
+			do_action( 'bbp_split_topic_reply', $reply->ID, $destination_topic->ID );
+		}
+
+		// Remove reply to from new topic
+		if ( $from_reply->ID === $destination_topic->ID ) {
+			delete_post_meta( $from_reply->ID, '_bbp_reply_to' );
+		}
+
+		// Set the last reply ID and freshness
+		$last_reply_id = $reply->ID;
+		$freshness     = $reply->post_date;
+
+	// Set the last reply ID and freshness to the from_reply
+	} else {
+		$last_reply_id = $from_reply->ID;
+		$freshness     = $from_reply->post_date;
+	}
+
+	// It is a new topic and we need to set some default metas to make
+	// the topic display in bbp_has_topics() list
+	if ( 'reply' === $split_option ) {
+		bbp_update_topic_last_reply_id   ( $destination_topic->ID, $last_reply_id );
+		bbp_update_topic_last_active_id  ( $destination_topic->ID, $last_reply_id );
+		bbp_update_topic_last_active_time( $destination_topic->ID, $freshness     );
+	}
+
+	// Update source topic ID last active
+	bbp_update_topic_last_reply_id   ( $source_topic->ID );
+	bbp_update_topic_last_active_id  ( $source_topic->ID );
+	bbp_update_topic_last_active_time( $source_topic->ID );
+
+	/** Successful Split ******************************************************/
+
+	// Update counts, etc...
+	do_action( 'bbp_post_split_topic', $from_reply->ID, $source_topic->ID, $destination_topic->ID );
+
+	// Redirect back to the topic
+	wp_safe_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
+
+	// For good measure
+	exit();
+}
+
+/**
+ * Fix counts on topic split
+ *
+ * When a topic is split, update the counts of source and destination topic
+ * and their forums.
+ *
+ * @since bbPress (r2756)
+ *
+ * @param int $from_reply_id From reply id
+ * @param int $source_topic_id Source topic id
+ * @param int $destination_topic_id Destination topic id
+ * @uses bbp_update_forum_topic_count() To update the forum topic counts
+ * @uses bbp_update_forum_reply_count() To update the forum reply counts
+ * @uses bbp_update_topic_reply_count() To update the topic reply counts
+ * @uses bbp_update_topic_voice_count() To update the topic voice counts
+ * @uses bbp_update_topic_reply_count_hidden() To update the topic hidden reply
+ *                                              count
+ * @uses do_action() Calls 'bbp_split_topic_count' with the from reply id,
+ *                    source topic id & destination topic id
+ */
+function bbp_split_topic_count( $from_reply_id, $source_topic_id, $destination_topic_id ) {
+
+	// Forum Topic Counts
+	bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) );
+
+	// Forum Reply Counts
+	bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) );
+
+	// Topic Reply Counts
+	bbp_update_topic_reply_count( $source_topic_id      );
+	bbp_update_topic_reply_count( $destination_topic_id );
+
+	// Topic Hidden Reply Counts
+	bbp_update_topic_reply_count_hidden( $source_topic_id      );
+	bbp_update_topic_reply_count_hidden( $destination_topic_id );
+
+	// Topic Voice Counts
+	bbp_update_topic_voice_count( $source_topic_id      );
+	bbp_update_topic_voice_count( $destination_topic_id );
+
+	do_action( 'bbp_split_topic_count', $from_reply_id, $source_topic_id, $destination_topic_id );
+}
+
+/**
+ * Handles the front end tag management (renaming, merging, destroying)
+ *
+ * @since bbPress (r2768)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit/delete tags
+ * @uses bbp_add_error() To add an error message
+ * @uses wp_update_term() To update the topic tag
+ * @uses get_term_link() To get the topic tag url
+ * @uses term_exists() To check if the topic tag already exists
+ * @uses wp_insert_term() To insert a topic tag
+ * @uses wp_delete_term() To delete the topic tag
+ * @uses home_url() To get the blog's home page url
+ * @uses do_action() Calls actions based on the actions with associated args
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ * @uses wp_safe_redirect() To redirect to the url
+ */
+function bbp_edit_topic_tag_handler( $action = '' ) {
+
+	// Bail if required POST actions aren't passed
+	if ( empty( $_POST['tag-id'] ) )
+		return;
+
+	// Setup possible get actions
+	$possible_actions = array(
+		'bbp-update-topic-tag',
+		'bbp-merge-topic-tag',
+		'bbp-delete-topic-tag'
+	);
+
+	// Bail if actions aren't meant for this function
+	if ( !in_array( $action, $possible_actions ) )
+		return;
+
+	// Setup vars
+	$tag_id = (int) $_POST['tag-id'];
+	$tag    = get_term( $tag_id, bbp_get_topic_tag_tax_id() );
+
+	// Tag does not exist
+	if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
+		bbp_add_error( 'bbp_manage_topic_invalid_tag', sprintf( __( '<strong>ERROR</strong>: The following problem(s) have been found while getting the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
+		return;
+	}
+
+	// What action are we trying to perform?
+	switch ( $action ) {
+
+		// Update tag
+		case 'bbp-update-topic-tag' :
+
+			// Nonce check
+			if ( ! bbp_verify_nonce_request( 'update-tag_' . $tag_id ) ) {
+				bbp_add_error( 'bbp_manage_topic_tag_update_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+				return;
+			}
+
+			// Can user edit topic tags?
+			if ( !current_user_can( 'edit_topic_tags' ) ) {
+				bbp_add_error( 'bbp_manage_topic_tag_update_permissions', __( '<strong>ERROR</strong>: You do not have the permissions to edit the topic tags.', 'bbpress' ) );
+				return;
+			}
+
+			// No tag name was provided
+			if ( empty( $_POST['tag-name'] ) || !$name = $_POST['tag-name'] ) {
+				bbp_add_error( 'bbp_manage_topic_tag_update_name', __( '<strong>ERROR</strong>: You need to enter a tag name.', 'bbpress' ) );
+				return;
+			}
+
+			// Attempt to update the tag
+			$slug = !empty( $_POST['tag-slug'] ) ? $_POST['tag-slug'] : '';
+			$tag  = wp_update_term( $tag_id, bbp_get_topic_tag_tax_id(), array( 'name' => $name, 'slug' => $slug ) );
+
+			// Cannot update tag
+			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
+				bbp_add_error( 'bbp_manage_topic_tag_update_error', sprintf( __( '<strong>ERROR</strong>: The following problem(s) have been found while updating the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
+				return;
+			}
+
+			// Redirect
+			$redirect = get_term_link( $tag_id, bbp_get_topic_tag_tax_id() );
+
+			// Update counts, etc...
+			do_action( 'bbp_update_topic_tag', $tag_id, $tag, $name, $slug );
+
+			break;
+
+		// Merge two tags
+		case 'bbp-merge-topic-tag'  :
+
+			// Nonce check
+			if ( ! bbp_verify_nonce_request( 'merge-tag_' . $tag_id ) ) {
+				bbp_add_error( 'bbp_manage_topic_tag_merge_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+				return;
+			}
+
+			// Can user edit topic tags?
+			if ( !current_user_can( 'edit_topic_tags' ) ) {
+				bbp_add_error( 'bbp_manage_topic_tag_merge_permissions', __( '<strong>ERROR</strong>: You do not have the permissions to edit the topic tags.', 'bbpress' ) );
+				return;
+			}
+
+			// No tag name was provided
+			if ( empty( $_POST['tag-existing-name'] ) || !$name = $_POST['tag-existing-name'] ) {
+				bbp_add_error( 'bbp_manage_topic_tag_merge_name', __( '<strong>ERROR</strong>: You need to enter a tag name.', 'bbpress' ) );
+				return;
+			}
+
+			// If term does not exist, create it
+			if ( !$tag = term_exists( $name, bbp_get_topic_tag_tax_id() ) )
+				$tag = wp_insert_term( $name, bbp_get_topic_tag_tax_id() );
+
+			// Problem inserting the new term
+			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
+				bbp_add_error( 'bbp_manage_topic_tag_merge_error', sprintf( __( '<strong>ERROR</strong>: The following problem(s) have been found while merging the tags: %s', 'bbpress' ), $tag->get_error_message() ) );
+				return;
+			}
+
+			// Merging in to...
+			$to_tag = $tag['term_id'];
+
+			// Attempting to merge a tag into itself
+			if ( $tag_id === $to_tag ) {
+				bbp_add_error( 'bbp_manage_topic_tag_merge_same', __( '<strong>ERROR</strong>: The tags which are being merged can not be the same.', 'bbpress' ) );
+				return;
+			}
+
+			// Delete the old term
+			$tag = wp_delete_term( $tag_id, bbp_get_topic_tag_tax_id(), array( 'default' => $to_tag, 'force_default' => true ) );
+
+			// Error merging the terms
+			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
+				bbp_add_error( 'bbp_manage_topic_tag_merge_error', sprintf( __( '<strong>ERROR</strong>: The following problem(s) have been found while merging the tags: %s', 'bbpress' ), $tag->get_error_message() ) );
+				return;
+			}
+
+			// Redirect
+			$redirect = get_term_link( (int) $to_tag, bbp_get_topic_tag_tax_id() );
+
+			// Update counts, etc...
+			do_action( 'bbp_merge_topic_tag', $tag_id, $to_tag, $tag );
+
+			break;
+
+		// Delete tag
+		case 'bbp-delete-topic-tag' :
+
+			// Nonce check
+			if ( ! bbp_verify_nonce_request( 'delete-tag_' . $tag_id ) ) {
+				bbp_add_error( 'bbp_manage_topic_tag_delete_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+				return;
+			}
+
+			// Can user delete topic tags?
+			if ( !current_user_can( 'delete_topic_tags' ) ) {
+				bbp_add_error( 'bbp_manage_topic_tag_delete_permissions', __( '<strong>ERROR</strong>: You do not have the permissions to delete the topic tags.', 'bbpress' ) );
+				return;
+			}
+
+			// Attempt to delete term
+			$tag = wp_delete_term( $tag_id, bbp_get_topic_tag_tax_id() );
+
+			// Error deleting term
+			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
+				bbp_add_error( 'bbp_manage_topic_tag_delete_error', sprintf( __( '<strong>ERROR</strong>: The following problem(s) have been found while deleting the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
+				return;
+			}
+
+			// We don't have any other place to go other than home! Or we may die because of the 404 disease
+			$redirect = home_url();
+
+			// Update counts, etc...
+			do_action( 'bbp_delete_topic_tag', $tag_id, $tag );
+
+			break;
+	}
+
+	/** Successful Moderation *************************************************/
+
+	// Redirect back
+	$redirect = ( !empty( $redirect ) && !is_wp_error( $redirect ) ) ? $redirect : home_url();
+	wp_safe_redirect( $redirect );
+
+	// For good measure
+	exit();
+}
+
+/** Helpers *******************************************************************/
+
+/**
+ * Return an associative array of available topic statuses
+ *
+ * @since bbPress (r5059)
+ *
+ * @return array
+ */
+function bbp_get_topic_statuses() {
+	return apply_filters( 'bbp_get_topic_statuses', array(
+		bbp_get_public_status_id()  => _x( 'Open',    'Open the topic',        'bbpress' ),
+		bbp_get_closed_status_id()  => _x( 'Closed',  'Close the topic',       'bbpress' ),
+		bbp_get_spam_status_id()    => _x( 'Spam',    'Spam the topic',        'bbpress' ),
+		bbp_get_trash_status_id()   => _x( 'Trash',   'Trash the topic',       'bbpress' ),
+		bbp_get_pending_status_id() => _x( 'Pending', 'Mark topic as pending', 'bbpress' ),
+	) );
+}
+
+/**
+ * Return an associative array of topic sticky types
+ *
+ * @since bbPress (r5059)
+ *
+ * @return array
+ */
+function bbp_get_topic_types() {
+	return apply_filters( 'bbp_get_topic_types', array(
+		'unstick' => _x( 'Normal',       'Unstick a topic',         'bbpress' ),
+		'stick'   => _x( 'Sticky',       'Make topic sticky',       'bbpress' ),
+		'super'   => _x( 'Super Sticky', 'Make topic super sticky', 'bbpress' )
+	) );
+}
+
+/** Stickies ******************************************************************/
+
+/**
+ * Return sticky topics of a forum
+ *
+ * @since bbPress (r2592)
+ *
+ * @param int $forum_id Optional. If not passed, super stickies are returned.
+ * @uses bbp_get_super_stickies() To get the super stickies
+ * @uses get_post_meta() To get the forum stickies
+ * @uses apply_filters() Calls 'bbp_get_stickies' with the stickies and forum id
+ * @return array IDs of sticky topics of a forum or super stickies
+ */
+function bbp_get_stickies( $forum_id = 0 ) {
+	$stickies = empty( $forum_id ) ? bbp_get_super_stickies() : get_post_meta( $forum_id, '_bbp_sticky_topics', true );
+	$stickies = ( empty( $stickies ) || !is_array( $stickies ) ) ? array() : $stickies;
+
+	return apply_filters( 'bbp_get_stickies', $stickies, (int) $forum_id );
+}
+
+/**
+ * Return topics stuck to front page of the forums
+ *
+ * @since bbPress (r2592)
+ *
+ * @uses get_option() To get super sticky topics
+ * @uses apply_filters() Calls 'bbp_get_super_stickies' with the stickies
+ * @return array IDs of super sticky topics
+ */
+function bbp_get_super_stickies() {
+	$stickies = get_option( '_bbp_super_sticky_topics', array() );
+	$stickies = ( empty( $stickies ) || !is_array( $stickies ) ) ? array() : $stickies;
+
+	return apply_filters( 'bbp_get_super_stickies', $stickies );
+}
+
+/** Topics Actions ************************************************************/
+
+/**
+ * Handles the front end opening/closing, spamming/unspamming,
+ * sticking/unsticking and trashing/untrashing/deleting of topics
+ *
+ * @since bbPress (r2727)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_get_topic() To get the topic
+ * @uses current_user_can() To check if the user is capable of editing or
+ *                           deleting the topic
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses check_ajax_referer() To verify the nonce and check the referer
+ * @uses bbp_is_topic_open() To check if the topic is open
+ * @uses bbp_close_topic() To close the topic
+ * @uses bbp_open_topic() To open the topic
+ * @uses bbp_is_topic_sticky() To check if the topic is a sticky
+ * @uses bbp_unstick_topic() To unstick the topic
+ * @uses bbp_stick_topic() To stick the topic
+ * @uses bbp_is_topic_spam() To check if the topic is marked as spam
+ * @uses bbp_spam_topic() To make the topic as spam
+ * @uses bbp_unspam_topic() To unmark the topic as spam
+ * @uses wp_trash_post() To trash the topic
+ * @uses wp_untrash_post() To untrash the topic
+ * @uses wp_delete_post() To delete the topic
+ * @uses do_action() Calls 'bbp_toggle_topic_handler' with success, post data
+ *                    and action
+ * @uses bbp_get_forum_permalink() To get the forum link
+ * @uses bbp_get_topic_permalink() To get the topic link
+ * @uses add_query_arg() To add args to the url
+ * @uses wp_safe_redirect() To redirect to the topic
+ * @uses bbPress::errors:add() To log the error messages
+ */
+function bbp_toggle_topic_handler( $action = '' ) {
+
+	// Bail if required GET actions aren't passed
+	if ( empty( $_GET['topic_id'] ) )
+		return;
+
+	// Setup possible get actions
+	$possible_actions = array(
+		'bbp_toggle_topic_close',
+		'bbp_toggle_topic_stick',
+		'bbp_toggle_topic_spam',
+		'bbp_toggle_topic_trash'
+	);
+
+	// Bail if actions aren't meant for this function
+	if ( !in_array( $action, $possible_actions ) )
+		return;
+
+	$failure   = '';                         // Empty failure string
+	$view_all  = false;                      // Assume not viewing all
+	$topic_id  = (int) $_GET['topic_id'];    // What's the topic id?
+	$success   = false;                      // Flag
+	$post_data = array( 'ID' => $topic_id ); // Prelim array
+	$redirect  = '';                         // Empty redirect URL
+
+	// Make sure topic exists
+	$topic = bbp_get_topic( $topic_id );
+	if ( empty( $topic ) )
+		return;
+
+	// What is the user doing here?
+	if ( !current_user_can( 'edit_topic', $topic->ID ) || ( 'bbp_toggle_topic_trash' === $action && !current_user_can( 'delete_topic', $topic->ID ) ) ) {
+		bbp_add_error( 'bbp_toggle_topic_permission', __( '<strong>ERROR:</strong> You do not have the permission to do that.', 'bbpress' ) );
+		return;
+	}
+
+	// What action are we trying to perform?
+	switch ( $action ) {
+
+		// Toggle open/close
+		case 'bbp_toggle_topic_close' :
+			check_ajax_referer( 'close-topic_' . $topic_id );
+
+			$is_open = bbp_is_topic_open( $topic_id );
+			$success = true === $is_open ? bbp_close_topic( $topic_id ) : bbp_open_topic( $topic_id );
+			$failure = true === $is_open ? __( '<strong>ERROR</strong>: There was a problem closing the topic.', 'bbpress' ) : __( '<strong>ERROR</strong>: There was a problem opening the topic.', 'bbpress' );
+
+			break;
+
+		// Toggle sticky/super-sticky/unstick
+		case 'bbp_toggle_topic_stick' :
+			check_ajax_referer( 'stick-topic_' . $topic_id );
+
+			$is_sticky = bbp_is_topic_sticky( $topic_id );
+			$is_super  = false === $is_sticky && !empty( $_GET['super'] ) && ( "1" === $_GET['super'] ) ? true : false;
+			$success   = true  === $is_sticky ? bbp_unstick_topic( $topic_id ) : bbp_stick_topic( $topic_id, $is_super );
+			$failure   = true  === $is_sticky ? __( '<strong>ERROR</strong>: There was a problem unsticking the topic.', 'bbpress' ) : __( '<strong>ERROR</strong>: There was a problem sticking the topic.', 'bbpress' );
+
+			break;
+
+		// Toggle spam
+		case 'bbp_toggle_topic_spam' :
+			check_ajax_referer( 'spam-topic_' . $topic_id );
+
+			$is_spam  = bbp_is_topic_spam( $topic_id );
+			$success  = true === $is_spam ? bbp_unspam_topic( $topic_id ) : bbp_spam_topic( $topic_id );
+			$failure  = true === $is_spam ? __( '<strong>ERROR</strong>: There was a problem unmarking the topic as spam.', 'bbpress' ) : __( '<strong>ERROR</strong>: There was a problem marking the topic as spam.', 'bbpress' );
+			$view_all = !$is_spam;
+
+			break;
+
+		// Toggle trash
+		case 'bbp_toggle_topic_trash' :
+
+			$sub_action = !empty( $_GET['sub_action'] ) && in_array( $_GET['sub_action'], array( 'trash', 'untrash', 'delete' ) ) ? $_GET['sub_action'] : false;
+
+			if ( empty( $sub_action ) )
+				break;
+
+			switch ( $sub_action ) {
+				case 'trash':
+					check_ajax_referer( 'trash-' . bbp_get_topic_post_type() . '_' . $topic_id );
+
+					$view_all = true;
+					$success  = wp_trash_post( $topic_id );
+					$failure  = __( '<strong>ERROR</strong>: There was a problem trashing the topic.', 'bbpress' );
+
+					break;
+
+				case 'untrash':
+					check_ajax_referer( 'untrash-' . bbp_get_topic_post_type() . '_' . $topic_id );
+
+					$success = wp_untrash_post( $topic_id );
+					$failure = __( '<strong>ERROR</strong>: There was a problem untrashing the topic.', 'bbpress' );
+
+					break;
+
+				case 'delete':
+					check_ajax_referer( 'delete-' . bbp_get_topic_post_type() . '_' . $topic_id );
+
+					$success = wp_delete_post( $topic_id );
+					$failure = __( '<strong>ERROR</strong>: There was a problem deleting the topic.', 'bbpress' );
+
+					break;
+			}
+
+			break;
+	}
+
+	// Do additional topic toggle actions
+	do_action( 'bbp_toggle_topic_handler', $success, $post_data, $action );
+
+	// No errors
+	if ( false !== $success && !is_wp_error( $success ) ) {
+
+		// Redirect back to the topic's forum
+		if ( isset( $sub_action ) && ( 'delete' === $sub_action ) ) {
+			$redirect = bbp_get_forum_permalink( $success->post_parent );
+
+		// Redirect back to the topic
+		} else {
+
+			// Get the redirect detination
+			$permalink = bbp_get_topic_permalink( $topic_id );
+			$redirect  = bbp_add_view_all( $permalink, $view_all );
+		}
+
+		wp_safe_redirect( $redirect );
+
+		// For good measure
+		exit();
+
+	// Handle errors
+	} else {
+		bbp_add_error( 'bbp_toggle_topic', $failure );
+	}
+}
+
+/** Favorites & Subscriptions *************************************************/
+
+/**
+ * Remove a deleted topic from all users' favorites
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $topic_id Get the topic id to remove
+ * @uses bbp_get_topic_id To get the topic id
+ * @uses bbp_get_topic_favoriters() To get the topic's favoriters
+ * @uses bbp_remove_user_favorite() To remove the topic from user's favorites
+ */
+function bbp_remove_topic_from_all_favorites( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	// Bail if no topic
+	if ( empty( $topic_id ) )
+		return;
+
+	// Get users
+	$users = (array) bbp_get_topic_favoriters( $topic_id );
+
+	// Users exist
+	if ( !empty( $users ) ) {
+
+		// Loop through users
+		foreach ( $users as $user ) {
+
+			// Remove each user
+			bbp_remove_user_favorite( $user, $topic_id );
+		}
+	}
+}
+
+/**
+ * Remove a deleted topic from all users' subscriptions
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $topic_id Get the topic id to remove
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+ * @uses bbp_get_topic_id To get the topic id
+ * @uses bbp_get_topic_subscribers() To get the topic subscribers
+ * @uses bbp_remove_user_subscription() To remove the user subscription
+ */
+function bbp_remove_topic_from_all_subscriptions( $topic_id = 0 ) {
+
+	// Subscriptions are not active
+	if ( !bbp_is_subscriptions_active() )
+		return;
+
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	// Bail if no topic
+	if ( empty( $topic_id ) )
+		return;
+
+	// Get users
+	$users = (array) bbp_get_topic_subscribers( $topic_id );
+
+	// Users exist
+	if ( !empty( $users ) ) {
+
+		// Loop through users
+		foreach ( $users as $user ) {
+
+			// Remove each user
+			bbp_remove_user_subscription( $user, $topic_id );
+		}
+	}
+}
+
+/** Count Bumpers *************************************************************/
+
+/**
+ * Bump the total reply count of a topic
+ *
+ * @since bbPress (r3825)
+ *
+ * @param int $topic_id Optional. Forum id.
+ * @param int $difference Optional. Default 1
+ * @param bool $update_ancestors Optional. Default true
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses update_post_meta() To update the topic's reply count meta
+ * @uses apply_filters() Calls 'bbp_bump_topic_reply_count' with the reply
+ *                        count, topic id, and difference
+ * @return int Forum reply count
+ */
+function bbp_bump_topic_reply_count( $topic_id = 0, $difference = 1 ) {
+
+	// Get counts
+	$topic_id    = bbp_get_topic_id( $topic_id );
+	$reply_count = bbp_get_topic_reply_count( $topic_id, true );
+	$new_count   = (int) $reply_count + (int) $difference;
+
+	// Update this topic id's reply count
+	update_post_meta( $topic_id, '_bbp_reply_count', (int) $new_count );
+
+	return (int) apply_filters( 'bbp_bump_topic_reply_count', (int) $new_count, $topic_id, (int) $difference );
+}
+
+/**
+ * Bump the total hidden reply count of a topic
+ *
+ * @since bbPress (r3825)
+ *
+ * @param int $topic_id Optional. Forum id.
+ * @param int $difference Optional. Default 1
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses update_post_meta() To update the topic's reply count meta
+ * @uses apply_filters() Calls 'bbp_bump_topic_reply_count_hidden' with the
+ *                        reply count, topic id, and difference
+ * @return int Forum hidden reply count
+ */
+function bbp_bump_topic_reply_count_hidden( $topic_id = 0, $difference = 1 ) {
+
+	// Get counts
+	$topic_id    = bbp_get_topic_id( $topic_id );
+	$reply_count = bbp_get_topic_reply_count_hidden( $topic_id, true );
+	$new_count   = (int) $reply_count + (int) $difference;
+
+	// Update this topic id's hidder reply count
+	update_post_meta( $topic_id, '_bbp_reply_count_hidden', (int) $new_count );
+
+	return (int) apply_filters( 'bbp_bump_topic_reply_count_hidden', (int) $new_count, $topic_id, (int) $difference );
+}
+
+/** Topic Updaters ************************************************************/
+
+/**
+ * Update the topic's forum id
+ *
+ * @since bbPress (r2855)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @param int $forum_id Optional. Forum id
+ * @uses bbp_is_reply() TO check if the passed topic id is a reply
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses get_post_field() To get the post parent of the topic id
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses update_post_meta() To update the topic forum id meta
+ * @uses apply_filters() Calls 'bbp_update_topic_forum_id' with the forum id
+ *                        and topic id
+ * @return int Forum id
+ */
+function bbp_update_topic_forum_id( $topic_id = 0, $forum_id = 0 ) {
+
+	// If it's a reply, then get the parent (topic id)
+	if ( bbp_is_reply( $topic_id ) ) {
+		$topic_id = bbp_get_reply_topic_id( $topic_id );
+	} else {
+		$topic_id = bbp_get_topic_id( $topic_id );
+	}
+
+	if ( empty( $forum_id ) ) {
+		$forum_id = get_post_field( 'post_parent', $topic_id );
+	}
+
+	update_post_meta( $topic_id, '_bbp_forum_id', (int) $forum_id );
+
+	return apply_filters( 'bbp_update_topic_forum_id', (int) $forum_id, $topic_id );
+}
+
+/**
+ * Update the topic's topic id
+ *
+ * @since bbPress (r2954)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses update_post_meta() To update the topic's topic id meta
+ * @uses apply_filters() Calls 'bbp_update_topic_topic_id' with the topic id
+ * @return int Topic id
+ */
+function bbp_update_topic_topic_id( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	update_post_meta( $topic_id, '_bbp_topic_id', (int) $topic_id );
+
+	return apply_filters( 'bbp_update_topic_topic_id', (int) $topic_id );
+}
+
+/**
+ * Adjust the total reply count of a topic
+ *
+ * @since bbPress (r2467)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @param int $reply_count Optional. Set the reply count manually.
+ * @uses bbp_is_reply() To check if the passed topic id is a reply
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_public_child_count() To get the reply count
+ * @uses update_post_meta() To update the topic reply count meta
+ * @uses apply_filters() Calls 'bbp_update_topic_reply_count' with the reply
+ *                        count and topic id
+ * @return int Topic reply count
+ */
+function bbp_update_topic_reply_count( $topic_id = 0, $reply_count = 0 ) {
+
+	// If it's a reply, then get the parent (topic id)
+	if ( bbp_is_reply( $topic_id ) ) {
+		$topic_id = bbp_get_reply_topic_id( $topic_id );
+	} else {
+		$topic_id = bbp_get_topic_id( $topic_id );
+	}
+
+	// Get replies of topic if not passed
+	if ( empty( $reply_count ) ) {
+		$reply_count = bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() );
+	}
+
+	update_post_meta( $topic_id, '_bbp_reply_count', (int) $reply_count );
+
+	return apply_filters( 'bbp_update_topic_reply_count', (int) $reply_count, $topic_id );
+}
+
+/**
+ * Adjust the total hidden reply count of a topic (hidden includes trashed and spammed replies)
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @param int $reply_count Optional. Set the reply count manually
+ * @uses bbp_is_reply() To check if the passed topic id is a reply
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses wpdb::prepare() To prepare our sql query
+ * @uses wpdb::get_var() To execute our query and get the var back
+ * @uses update_post_meta() To update the topic hidden reply count meta
+ * @uses apply_filters() Calls 'bbp_update_topic_reply_count_hidden' with the
+ *                        hidden reply count and topic id
+ * @return int Topic hidden reply count
+ */
+function bbp_update_topic_reply_count_hidden( $topic_id = 0, $reply_count = 0 ) {
+	global $wpdb;
+
+	// If it's a reply, then get the parent (topic id)
+	if ( bbp_is_reply( $topic_id ) ) {
+		$topic_id = bbp_get_reply_topic_id( $topic_id );
+	} else {
+		$topic_id = bbp_get_topic_id( $topic_id );
+	}
+
+	// Get replies of topic
+	if ( empty( $reply_count ) ) {
+		$post_status = "'" . implode( "','", array( bbp_get_trash_status_id(), bbp_get_spam_status_id() ) ) . "'";
+		$reply_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s';", $topic_id, bbp_get_reply_post_type() ) );
+	}
+
+	update_post_meta( $topic_id, '_bbp_reply_count_hidden', (int) $reply_count );
+
+	return apply_filters( 'bbp_update_topic_reply_count_hidden', (int) $reply_count, $topic_id );
+}
+
+/**
+ * Update the topic with the last active post ID
+ *
+ * @since bbPress (r2888)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @param int $active_id Optional. active id
+ * @uses bbp_is_reply() To check if the passed topic id is a reply
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_public_child_last_id() To get the last public reply id
+ * @uses bbp_get_active_id() To get the active id
+ * @uses update_post_meta() To update the topic last active id meta
+ * @uses apply_filters() Calls 'bbp_update_topic_last_active_id' with the active
+ *                        id and topic id
+ * @return int Active id
+ */
+function bbp_update_topic_last_active_id( $topic_id = 0, $active_id = 0 ) {
+
+	// If it's a reply, then get the parent (topic id)
+	if ( bbp_is_reply( $topic_id ) ) {
+		$topic_id = bbp_get_reply_topic_id( $topic_id );
+	} else {
+		$topic_id = bbp_get_topic_id( $topic_id );
+	}
+
+	if ( empty( $active_id ) ) {
+		$active_id = bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() );
+	}
+
+	// Adjust last_id's based on last_reply post_type
+	if ( empty( $active_id ) || !bbp_is_reply( $active_id ) ) {
+		$active_id = $topic_id;
+	}
+
+	// Update only if published
+	if ( bbp_get_public_status_id() === get_post_status( $active_id ) ) {
+		update_post_meta( $topic_id, '_bbp_last_active_id', (int) $active_id );
+	}
+
+	return apply_filters( 'bbp_update_topic_last_active_id', (int) $active_id, $topic_id );
+}
+
+/**
+ * Update the topics last active date/time (aka freshness)
+ *
+ * @since bbPress (r2680)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param string $new_time Optional. New time in mysql format
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses current_time() To get the current time
+ * @uses update_post_meta() To update the topic last active meta
+ * @return bool True on success, false on failure
+ */
+function bbp_update_topic_last_active_time( $topic_id = 0, $new_time = '' ) {
+
+	// If it's a reply, then get the parent (topic id)
+	if ( bbp_is_reply( $topic_id ) ) {
+		$topic_id = bbp_get_reply_topic_id( $topic_id );
+	} else {
+		$topic_id = bbp_get_topic_id( $topic_id );
+	}
+
+	// Check time and use current if empty
+	if ( empty( $new_time ) ) {
+		$new_time = get_post_field( 'post_date', bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() ) );
+	}
+
+	// Update only if published
+	if ( !empty( $new_time ) ) {
+		update_post_meta( $topic_id, '_bbp_last_active_time', $new_time );
+	}
+
+	return apply_filters( 'bbp_update_topic_last_active_time', $new_time, $topic_id );
+}
+
+/**
+ * Update the topic with the most recent reply ID
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @param int $reply_id Optional. Reply id
+ * @uses bbp_is_reply() To check if the passed topic id is a reply
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_public_child_last_id() To get the last public reply id
+ * @uses update_post_meta() To update the topic last reply id meta
+ * @uses apply_filters() Calls 'bbp_update_topic_last_reply_id' with the reply
+ *                        id and topic id
+ * @return int Reply id
+ */
+function bbp_update_topic_last_reply_id( $topic_id = 0, $reply_id = 0 ) {
+
+	// If it's a reply, then get the parent (topic id)
+	if ( empty( $reply_id ) && bbp_is_reply( $topic_id ) ) {
+		$reply_id = bbp_get_reply_id( $topic_id );
+		$topic_id = bbp_get_reply_topic_id( $reply_id );
+	} else {
+		$reply_id = bbp_get_reply_id( $reply_id );
+		$topic_id = bbp_get_topic_id( $topic_id );
+	}
+
+	if ( empty( $reply_id ) ) {
+		$reply_id = bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() );
+	}
+
+	// Adjust last_id's based on last_reply post_type
+	if ( empty( $reply_id ) || !bbp_is_reply( $reply_id ) ) {
+		$reply_id = 0;
+	}
+
+	// Update if reply is published
+	if ( bbp_is_reply_published( $reply_id ) ) {
+		update_post_meta( $topic_id, '_bbp_last_reply_id', (int) $reply_id );
+	}
+
+	return apply_filters( 'bbp_update_topic_last_reply_id', (int) $reply_id, $topic_id );
+}
+
+/**
+ * Adjust the total voice count of a topic
+ *
+ * @since bbPress (r2567)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @uses bbp_is_reply() To check if the passed topic id is a reply
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wpdb::prepare() To prepare our sql query
+ * @uses wpdb::get_col() To execute our query and get the column back
+ * @uses update_post_meta() To update the topic voice count meta
+ * @uses apply_filters() Calls 'bbp_update_topic_voice_count' with the voice
+ *                        count and topic id
+ * @return int Voice count
+ */
+function bbp_update_topic_voice_count( $topic_id = 0 ) {
+	global $wpdb;
+
+	// If it's a reply, then get the parent (topic id)
+	if ( bbp_is_reply( $topic_id ) ) {
+		$topic_id = bbp_get_reply_topic_id( $topic_id );
+	} elseif ( bbp_is_topic( $topic_id ) ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+	} else {
+		return;
+	}
+
+	// Query the DB to get voices in this topic
+	$voices = $wpdb->get_col( $wpdb->prepare( "SELECT COUNT( DISTINCT post_author ) FROM {$wpdb->posts} WHERE ( post_parent = %d AND post_status = '%s' AND post_type = '%s' ) OR ( ID = %d AND post_type = '%s' );", $topic_id, bbp_get_public_status_id(), bbp_get_reply_post_type(), $topic_id, bbp_get_topic_post_type() ) );
+
+	// If there's an error, make sure we have at least have 1 voice
+	$voices = ( empty( $voices ) || is_wp_error( $voices ) ) ? 1 : $voices[0];
+
+	// Update the voice count for this topic id
+	update_post_meta( $topic_id, '_bbp_voice_count', (int) $voices );
+
+	return apply_filters( 'bbp_update_topic_voice_count', (int) $voices, $topic_id );
+}
+
+/**
+ * Adjust the total anonymous reply count of a topic
+ *
+ * @since bbPress (r2567)
+ *
+ * @param int $topic_id Optional. Topic id to update
+ * @uses bbp_is_reply() To check if the passed topic id is a reply
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_reply_topic_id() To get the reply topic id
+ * @uses bbp_get_reply_post_type() To get the reply post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses wpdb::prepare() To prepare our sql query
+ * @uses wpdb::get_col() To execute our query and get the column back
+ * @uses update_post_meta() To update the topic anonymous reply count meta
+ * @uses apply_filters() Calls 'bbp_update_topic_anonymous_reply_count' with the
+ *                        anonymous reply count and topic id
+ * @return int Anonymous reply count
+ */
+function bbp_update_topic_anonymous_reply_count( $topic_id = 0 ) {
+	global $wpdb;
+
+	// If it's a reply, then get the parent (topic id)
+	if ( bbp_is_reply( $topic_id ) ) {
+		$topic_id = bbp_get_reply_topic_id( $topic_id );
+	} elseif ( bbp_is_topic( $topic_id ) ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+	} else {
+		return;
+	}
+
+	$anonymous_replies = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( ID ) FROM {$wpdb->posts} WHERE ( post_parent = %d AND post_status = '%s' AND post_type = '%s' AND post_author = 0 ) OR ( ID = %d AND post_type = '%s' AND post_author = 0 );", $topic_id, bbp_get_public_status_id(), bbp_get_reply_post_type(), $topic_id, bbp_get_topic_post_type() ) );
+
+	update_post_meta( $topic_id, '_bbp_anonymous_reply_count', (int) $anonymous_replies );
+
+	return apply_filters( 'bbp_update_topic_anonymous_reply_count', (int) $anonymous_replies, $topic_id );
+}
+
+/**
+ * Update the revision log of the topic
+ *
+ * @since bbPress (r2782)
+ *
+ * @param mixed $args Supports these args:
+ *  - topic_id: Topic id
+ *  - author_id: Author id
+ *  - reason: Reason for editing
+ *  - revision_id: Revision id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_format_revision_reason() To format the reason
+ * @uses bbp_get_topic_raw_revision_log() To get the raw topic revision log
+ * @uses update_post_meta() To update the topic revision log meta
+ * @return mixed False on failure, true on success
+ */
+function bbp_update_topic_revision_log( $args = '' ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'reason'      => '',
+		'topic_id'    => 0,
+		'author_id'   => 0,
+		'revision_id' => 0
+	), 'update_topic_revision_log' );
+
+	// Populate the variables
+	$r['reason']      = bbp_format_revision_reason( $r['reason'] );
+	$r['topic_id']    = bbp_get_topic_id( $r['topic_id'] );
+	$r['author_id']   = bbp_get_user_id ( $r['author_id'], false, true );
+	$r['revision_id'] = (int) $r['revision_id'];
+
+	// Get the logs and append the new one to those
+	$revision_log                      = bbp_get_topic_raw_revision_log( $r['topic_id'] );
+	$revision_log[ $r['revision_id'] ] = array( 'author' => $r['author_id'], 'reason' => $r['reason'] );
+
+	// Finally, update
+	return update_post_meta( $r['topic_id'], '_bbp_revision_log', $revision_log );
+}
+
+/** Topic Actions *************************************************************/
+
+/**
+ * Closes a topic
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $topic_id Topic id
+ * @uses bbp_get_topic() To get the topic
+ * @uses do_action() Calls 'bbp_close_topic' with the topic id
+ * @uses add_post_meta() To add the previous status to a meta
+ * @uses wp_update_post() To update the topic with the new status
+ * @uses do_action() Calls 'bbp_opened_topic' with the topic id
+ * @return mixed False or {@link WP_Error} on failure, topic id on success
+ */
+function bbp_close_topic( $topic_id = 0 ) {
+
+	// Get topic
+	$topic = bbp_get_topic( $topic_id );
+	if ( empty( $topic ) )
+		return $topic;
+
+	// Bail if already closed
+	if ( bbp_get_closed_status_id() === $topic->post_status )
+		return false;
+
+	// Execute pre close code
+	do_action( 'bbp_close_topic', $topic_id );
+
+	// Add pre close status
+	add_post_meta( $topic_id, '_bbp_status', $topic->post_status );
+
+	// Set closed status
+	$topic->post_status = bbp_get_closed_status_id();
+
+	// No revisions
+	remove_action( 'pre_post_update', 'wp_save_post_revision' );
+
+	// Update topic
+	$topic_id = wp_update_post( $topic );
+
+	// Execute post close code
+	do_action( 'bbp_closed_topic', $topic_id );
+
+	// Return topic_id
+	return $topic_id;
+}
+
+/**
+ * Opens a topic
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $topic_id Topic id
+ * @uses bbp_get_topic() To get the topic
+ * @uses do_action() Calls 'bbp_open_topic' with the topic id
+ * @uses get_post_meta() To get the previous status
+ * @uses delete_post_meta() To delete the previous status meta
+ * @uses wp_update_post() To update the topic with the new status
+ * @uses do_action() Calls 'bbp_opened_topic' with the topic id
+ * @return mixed False or {@link WP_Error} on failure, topic id on success
+ */
+function bbp_open_topic( $topic_id = 0 ) {
+
+	// Get topic
+	$topic = bbp_get_topic( $topic_id );
+	if ( empty( $topic ) )
+		return $topic;
+
+	// Bail if already open
+	if ( bbp_get_closed_status_id() !== $topic->post_status )
+		return false;
+
+	// Execute pre open code
+	do_action( 'bbp_open_topic', $topic_id );
+
+	// Get previous status
+	$topic_status       = get_post_meta( $topic_id, '_bbp_status', true );
+
+	// Set previous status
+	$topic->post_status = $topic_status;
+
+	// Remove old status meta
+	delete_post_meta( $topic_id, '_bbp_status' );
+
+	// No revisions
+	remove_action( 'pre_post_update', 'wp_save_post_revision' );
+
+	// Update topic
+	$topic_id = wp_update_post( $topic );
+
+	// Execute post open code
+	do_action( 'bbp_opened_topic', $topic_id );
+
+	// Return topic_id
+	return $topic_id;
+}
+
+/**
+ * Marks a topic as spam
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $topic_id Topic id
+ * @uses bbp_get_topic() To get the topic
+ * @uses do_action() Calls 'bbp_spam_topic' with the topic id
+ * @uses add_post_meta() To add the previous status to a meta
+ * @uses wp_update_post() To update the topic with the new status
+ * @uses do_action() Calls 'bbp_spammed_topic' with the topic id
+ * @return mixed False or {@link WP_Error} on failure, topic id on success
+ */
+function bbp_spam_topic( $topic_id = 0 ) {
+
+	// Get the topic
+	$topic = bbp_get_topic( $topic_id );
+	if ( empty( $topic ) )
+		return $topic;
+
+	// Bail if topic is spam
+	if ( bbp_get_spam_status_id() === $topic->post_status )
+		return false;
+
+	// Execute pre spam code
+	do_action( 'bbp_spam_topic', $topic_id );
+
+	/** Trash Replies *********************************************************/
+
+	// Topic is being spammed, so its replies are trashed
+	$replies = new WP_Query( array(
+		'suppress_filters' => true,
+		'post_type'        => bbp_get_reply_post_type(),
+		'post_status'      => bbp_get_public_status_id(),
+		'post_parent'      => $topic_id,
+		'posts_per_page'   => -1,
+		'nopaging'         => true,
+		'fields'           => 'id=>parent'
+	) );
+
+	if ( !empty( $replies->posts ) ) {
+
+		// Prevent debug notices
+		$pre_spammed_replies = array();
+
+		// Loop through replies, trash them, and add them to array
+		foreach ( $replies->posts as $reply ) {
+			wp_trash_post( $reply->ID );
+			$pre_spammed_replies[] = $reply->ID;
+		}
+
+		// Set a post_meta entry of the replies that were trashed by this action.
+		// This is so we can possibly untrash them, without untrashing replies
+		// that were purposefully trashed before.
+		update_post_meta( $topic_id, '_bbp_pre_spammed_replies', $pre_spammed_replies );
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	// Cleanup
+	unset( $replies );
+
+	/** Topic Tags ************************************************************/
+
+	// Add the original post status as post meta for future restoration
+	add_post_meta( $topic_id, '_bbp_spam_meta_status', $topic->post_status );
+
+	// Get topic tags
+	$terms = get_the_terms( $topic_id, bbp_get_topic_tag_tax_id() );
+
+	// Define local variable(s)
+	$term_names = array();
+
+	// Topic has tags
+	if ( !empty( $terms ) ) {
+
+		// Loop through and collect term names
+		foreach ( $terms as $term ) {
+			$term_names[] = $term->name;
+		}
+
+		// Topic terms have slugs
+		if ( !empty( $term_names ) ) {
+
+			// Add the original post status as post meta for future restoration
+			add_post_meta( $topic_id, '_bbp_spam_topic_tags', $term_names );
+
+			// Empty the topic of its tags
+			$topic->tax_input = array( bbp_get_topic_tag_tax_id() => '' );
+		}
+	}
+
+	// Set post status to spam
+	$topic->post_status = bbp_get_spam_status_id();
+
+	// No revisions
+	remove_action( 'pre_post_update', 'wp_save_post_revision' );
+
+	// Update the topic
+	$topic_id = wp_update_post( $topic );
+
+	// Execute post spam code
+	do_action( 'bbp_spammed_topic', $topic_id );
+
+	// Return topic_id
+	return $topic_id;
+}
+
+/**
+ * Unspams a topic
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $topic_id Topic id
+ * @uses bbp_get_topic() To get the topic
+ * @uses do_action() Calls 'bbp_unspam_topic' with the topic id
+ * @uses get_post_meta() To get the previous status
+ * @uses delete_post_meta() To delete the previous status meta
+ * @uses wp_update_post() To update the topic with the new status
+ * @uses do_action() Calls 'bbp_unspammed_topic' with the topic id
+ * @return mixed False or {@link WP_Error} on failure, topic id on success
+ */
+function bbp_unspam_topic( $topic_id = 0 ) {
+
+	// Get the topic
+	$topic = bbp_get_topic( $topic_id );
+	if ( empty( $topic ) )
+		return $topic;
+
+	// Bail if already not spam
+	if ( bbp_get_spam_status_id() !== $topic->post_status )
+		return false;
+
+	// Execute pre unspam code
+	do_action( 'bbp_unspam_topic', $topic_id );
+
+	/** Untrash Replies *******************************************************/
+
+	// Get the replies that were not previously trashed
+	$pre_spammed_replies = get_post_meta( $topic_id, '_bbp_pre_spammed_replies', true );
+
+	// There are replies to untrash
+	if ( !empty( $pre_spammed_replies ) ) {
+
+		// Maybe reverse the trashed replies array
+		if ( is_array( $pre_spammed_replies ) )
+			$pre_spammed_replies = array_reverse( $pre_spammed_replies );
+
+		// Loop through replies
+		foreach ( (array) $pre_spammed_replies as $reply ) {
+			wp_untrash_post( $reply );
+		}
+	}
+
+	/** Topic Tags ************************************************************/
+
+	// Get pre-spam topic tags
+	$terms = get_post_meta( $topic_id, '_bbp_spam_topic_tags', true );
+
+	// Topic had tags before it was spammed
+	if ( !empty( $terms ) ) {
+
+		// Set the tax_input of the topic
+		$topic->tax_input = array( bbp_get_topic_tag_tax_id() => $terms );
+
+		// Delete pre-spam topic tag meta
+		delete_post_meta( $topic_id, '_bbp_spam_topic_tags' );
+	}
+
+	/** Topic Status **********************************************************/
+
+	// Get pre spam status
+	$topic_status = get_post_meta( $topic_id, '_bbp_spam_meta_status', true );
+
+	// If no previous status, default to publish
+	if ( empty( $topic_status ) ) {
+		$topic_status = bbp_get_public_status_id();
+	}
+
+	// Set post status to pre spam
+	$topic->post_status = $topic_status;
+
+	// Delete pre spam meta
+	delete_post_meta( $topic_id, '_bbp_spam_meta_status' );
+
+	// No revisions
+	remove_action( 'pre_post_update', 'wp_save_post_revision' );
+
+	// Update the topic
+	$topic_id = wp_update_post( $topic );
+
+	// Execute post unspam code
+	do_action( 'bbp_unspammed_topic', $topic_id );
+
+	// Return topic_id
+	return $topic_id;
+}
+
+/**
+ * Sticks a topic to a forum or front
+ *
+ * @since bbPress (r2754)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param int $super Should we make the topic a super sticky?
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_unstick_topic() To unstick the topic
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_get_stickies() To get the stickies
+ * @uses do_action() 'bbp_stick_topic' with topic id and bool super
+ * @uses update_option() To update the super stickies option
+ * @uses update_post_meta() To update the forum stickies meta
+ * @uses do_action() Calls 'bbp_sticked_topic' with the topic id, bool super
+ *                    and success
+ * @return bool True on success, false on failure
+ */
+function bbp_stick_topic( $topic_id = 0, $super = false ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	// Bail if a topic is not a topic (prevents revisions as stickies)
+	if ( ! bbp_is_topic( $topic_id ) )
+		return false;
+
+	// We may have a super sticky to which we want to convert into a normal
+	// sticky and vice versa; unstick the topic first to avoid any possible error.
+	bbp_unstick_topic( $topic_id );
+
+	$forum_id = empty( $super ) ? bbp_get_topic_forum_id( $topic_id ) : 0;
+	$stickies = bbp_get_stickies( $forum_id );
+
+	do_action( 'bbp_stick_topic', $topic_id, $super );
+
+	if ( !is_array( $stickies ) ) {
+		$stickies   = array( $topic_id );
+	} else {
+		$stickies[] = $topic_id;
+	}
+
+	// Pull out duplicates and empties
+	$stickies = array_unique( array_filter( $stickies ) );
+
+	// Unset incorrectly stuck revisions
+	foreach ( (array) $stickies as $key => $id ) {
+		if ( ! bbp_is_topic( $id ) ) {
+			unset( $stickies[$key] );
+		}
+	}
+
+	// Reset keys
+	$stickies = array_values( $stickies );
+	$success  = !empty( $super ) ? update_option( '_bbp_super_sticky_topics', $stickies ) : update_post_meta( $forum_id, '_bbp_sticky_topics', $stickies );
+
+	do_action( 'bbp_sticked_topic', $topic_id, $super, $success );
+
+	return (bool) $success;
+}
+
+/**
+ * Unsticks a topic both from front and it's forum
+ *
+ * @since bbPress (r2754)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_is_topic_super_sticky() To check if the topic is a super sticky
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_get_stickies() To get the forum stickies
+ * @uses do_action() Calls 'bbp_unstick_topic' with the topic id
+ * @uses delete_option() To delete the super stickies option
+ * @uses update_option() To update the super stickies option
+ * @uses delete_post_meta() To delete the forum stickies meta
+ * @uses update_post_meta() To update the forum stickies meta
+ * @uses do_action() Calls 'bbp_unsticked_topic' with the topic id and success
+ * @return bool Always true.
+ */
+function bbp_unstick_topic( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$super    = bbp_is_topic_super_sticky( $topic_id );
+	$forum_id = empty( $super ) ? bbp_get_topic_forum_id( $topic_id ) : 0;
+	$stickies = bbp_get_stickies( $forum_id );
+	$offset   = array_search( $topic_id, $stickies );
+
+	do_action( 'bbp_unstick_topic', $topic_id );
+
+	if ( empty( $stickies ) ) {
+		$success = true;
+	} elseif ( !in_array( $topic_id, $stickies ) ) {
+		$success = true;
+	} elseif ( false === $offset ) {
+		$success = true;
+	} else {
+		array_splice( $stickies, $offset, 1 );
+		if ( empty( $stickies ) ) {
+			$success = !empty( $super ) ? delete_option( '_bbp_super_sticky_topics'            ) : delete_post_meta( $forum_id, '_bbp_sticky_topics'            );
+		} else {
+			$success = !empty( $super ) ? update_option( '_bbp_super_sticky_topics', $stickies ) : update_post_meta( $forum_id, '_bbp_sticky_topics', $stickies );
+		}
+	}
+
+	do_action( 'bbp_unsticked_topic', $topic_id, $success );
+
+	return (bool) $success;
+}
+
+/** Before Delete/Trash/Untrash ***********************************************/
+
+/**
+ * Called before deleting a topic.
+ *
+ * This function is supplemental to the actual topic deletion which is
+ * handled by WordPress core API functions. It is used to clean up after
+ * a topic that is being deleted.
+ *
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_is_topic() To check if the passed id is a topic
+ * @uses do_action() Calls 'bbp_delete_topic' with the topic id
+ * @uses bbp_has_replies() To check if the topic has replies
+ * @uses bbp_replies() To loop through the replies
+ * @uses bbp_the_reply() To set a reply as the current reply in the loop
+ * @uses bbp_get_reply_id() To get the reply id
+ * @uses wp_delete_post() To delete the reply
+ */
+function bbp_delete_topic( $topic_id = 0 ) {
+
+	// Validate topic ID
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	if ( empty( $topic_id ) || !bbp_is_topic( $topic_id ) )
+		return false;
+
+	do_action( 'bbp_delete_topic', $topic_id );
+
+	// Topic is being permanently deleted, so its replies gotta go too
+	// Note that we get all post statuses here
+	$replies = new WP_Query( array(
+		'suppress_filters' => true,
+		'post_type'        => bbp_get_reply_post_type(),
+		'post_status'      => array_keys( get_post_stati() ),
+		'post_parent'      => $topic_id,
+		'posts_per_page'   => -1,
+		'nopaging'         => true,
+		'fields'           => 'id=>parent'
+	) );
+
+	// Loop through and delete child replies
+	if ( ! empty( $replies->posts ) ) {
+		foreach ( $replies->posts as $reply ) {
+			wp_delete_post( $reply->ID, true );
+		}
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	// Cleanup
+	unset( $replies );
+}
+
+/**
+ * Called before trashing a topic
+ *
+ * This function is supplemental to the actual topic being trashed which is
+ * handled by WordPress core API functions. It is used to clean up after
+ * a topic that is being trashed.
+ *
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_is_topic() To check if the passed id is a topic
+ * @uses do_action() Calls 'bbp_trash_topic' with the topic id
+ * @uses wp_trash_post() To trash the reply
+ * @uses update_post_meta() To save a list of just trashed replies for future use
+ */
+function bbp_trash_topic( $topic_id = 0 ) {
+
+	// Validate topic ID
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	if ( empty( $topic_id ) || !bbp_is_topic( $topic_id ) )
+		return false;
+
+	do_action( 'bbp_trash_topic', $topic_id );
+
+	// Topic is being trashed, so its replies are trashed too
+	$replies = new WP_Query( array(
+		'suppress_filters' => true,
+		'post_type'        => bbp_get_reply_post_type(),
+		'post_status'      => bbp_get_public_status_id(),
+		'post_parent'      => $topic_id,
+		'posts_per_page'   => -1,
+		'nopaging'         => true,
+		'fields'           => 'id=>parent'
+	) );
+
+	if ( !empty( $replies->posts ) ) {
+
+		// Prevent debug notices
+		$pre_trashed_replies = array();
+
+		// Loop through replies, trash them, and add them to array
+		foreach ( $replies->posts as $reply ) {
+			wp_trash_post( $reply->ID );
+			$pre_trashed_replies[] = $reply->ID;
+		}
+
+		// Set a post_meta entry of the replies that were trashed by this action.
+		// This is so we can possibly untrash them, without untrashing replies
+		// that were purposefully trashed before.
+		update_post_meta( $topic_id, '_bbp_pre_trashed_replies', $pre_trashed_replies );
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	// Cleanup
+	unset( $replies );
+}
+
+/**
+ * Called before untrashing a topic
+ *
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_is_topic() To check if the passed id is a topic
+ * @uses do_action() Calls 'bbp_untrash_topic' with the topic id
+ * @uses get_post_meta() To get the list of replies which were trashed with the
+ *                        topic
+ * @uses wp_untrash_post() To untrash the reply
+ */
+function bbp_untrash_topic( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	if ( empty( $topic_id ) || !bbp_is_topic( $topic_id ) )
+		return false;
+
+	do_action( 'bbp_untrash_topic', $topic_id );
+
+	// Get the replies that were not previously trashed
+	$pre_trashed_replies = get_post_meta( $topic_id, '_bbp_pre_trashed_replies', true );
+
+	// There are replies to untrash
+	if ( !empty( $pre_trashed_replies ) ) {
+
+		// Maybe reverse the trashed replies array
+		if ( is_array( $pre_trashed_replies ) )
+			$pre_trashed_replies = array_reverse( $pre_trashed_replies );
+
+		// Loop through replies
+		foreach ( (array) $pre_trashed_replies as $reply ) {
+			wp_untrash_post( $reply );
+		}
+	}
+}
+
+/** After Delete/Trash/Untrash ************************************************/
+
+/**
+ * Called after deleting a topic
+ *
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_is_topic() To check if the passed id is a topic
+ * @uses do_action() Calls 'bbp_deleted_topic' with the topic id
+ */
+function bbp_deleted_topic( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	if ( empty( $topic_id ) || !bbp_is_topic( $topic_id ) )
+		return false;
+
+	do_action( 'bbp_deleted_topic', $topic_id );
+}
+
+/**
+ * Called after trashing a topic
+ *
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_is_topic() To check if the passed id is a topic
+ * @uses do_action() Calls 'bbp_trashed_topic' with the topic id
+ */
+function bbp_trashed_topic( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	if ( empty( $topic_id ) || !bbp_is_topic( $topic_id ) )
+		return false;
+
+	do_action( 'bbp_trashed_topic', $topic_id );
+}
+
+/**
+ * Called after untrashing a topic
+ *
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_is_topic() To check if the passed id is a topic
+ * @uses do_action() Calls 'bbp_untrashed_topic' with the topic id
+ */
+function bbp_untrashed_topic( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	if ( empty( $topic_id ) || !bbp_is_topic( $topic_id ) )
+		return false;
+
+	do_action( 'bbp_untrashed_topic', $topic_id );
+}
+
+/** Settings ******************************************************************/
+
+/**
+ * Return the topics per page setting
+ *
+ * @since bbPress (r3540)
+ *
+ * @param int $default Default replies per page (15)
+ * @uses get_option() To get the setting
+ * @uses apply_filters() To allow the return value to be manipulated
+ * @return int
+ */
+function bbp_get_topics_per_page( $default = 15 ) {
+
+	// Get database option and cast as integer
+	$retval = get_option( '_bbp_topics_per_page', $default );
+
+	// If return val is empty, set it to default
+	if ( empty( $retval ) )
+		$retval = $default;
+
+	// Filter and return
+	return (int) apply_filters( 'bbp_get_topics_per_page', $retval, $default );
+}
+
+/**
+ * Return the topics per RSS page setting
+ *
+ * @since bbPress (r3540)
+ *
+ * @param int $default Default replies per page (25)
+ * @uses get_option() To get the setting
+ * @uses apply_filters() To allow the return value to be manipulated
+ * @return int
+ */
+function bbp_get_topics_per_rss_page( $default = 25 ) {
+
+	// Get database option and cast as integer
+	$retval = get_option( '_bbp_topics_per_rss_page', $default );
+
+	// If return val is empty, set it to default
+	if ( empty( $retval ) )
+		$retval = $default;
+
+	// Filter and return
+	return (int) apply_filters( 'bbp_get_topics_per_rss_page', $retval, $default );
+}
+
+/** Topic Tags ****************************************************************/
+
+/**
+ * Get topic tags for a specific topic ID
+ *
+ * @since bbPress (r4165)
+ *
+ * @param int $topic_id
+ * @param string $sep
+ * @return string
+ */
+function bbp_get_topic_tag_names( $topic_id = 0, $sep = ', ' ) {
+	$topic_id   = bbp_get_topic_id( $topic_id );
+	$topic_tags = array_filter( (array) get_the_terms( $topic_id, bbp_get_topic_tag_tax_id() ) );
+	$terms      = array();
+	foreach ( $topic_tags as $term ) {
+		$terms[] = $term->name;
+	}
+	$terms = !empty( $terms ) ? implode( $sep, $terms ) : '';
+
+	return apply_filters( 'bbp_get_topic_tags', $terms, $topic_id );
+}
+
+/** Autoembed *****************************************************************/
+
+/**
+ * Check if autoembeds are enabled and hook them in if so
+ *
+ * @since bbPress (r3752)
+ * @global WP_Embed $wp_embed
+ */
+function bbp_topic_content_autoembed() {
+	global $wp_embed;
+
+	if ( bbp_use_autoembed() && is_a( $wp_embed, 'WP_Embed' ) ) {
+		add_filter( 'bbp_get_topic_content', array( $wp_embed, 'autoembed' ), 2 );
+	}
+}
+
+/** Feeds *********************************************************************/
+
+/**
+ * Output an RSS2 feed of topics, based on the query passed.
+ *
+ * @since bbPress (r3171)
+ *
+ * @uses bbp_version()
+ * @uses bbp_is_single_topic()
+ * @uses bbp_user_can_view_forum()
+ * @uses bbp_get_topic_forum_id()
+ * @uses bbp_show_load_topic()
+ * @uses bbp_topic_permalink()
+ * @uses bbp_topic_title()
+ * @uses bbp_get_topic_reply_count()
+ * @uses bbp_topic_content()
+ * @uses bbp_has_topics()
+ * @uses bbp_topics()
+ * @uses bbp_the_topic()
+ * @uses get_wp_title_rss()
+ * @uses get_option()
+ * @uses bloginfo_rss
+ * @uses self_link()
+ * @uses the_author()
+ * @uses get_post_time()
+ * @uses rss_enclosure()
+ * @uses do_action()
+ * @uses apply_filters()
+ *
+ * @param array $topics_query
+ */
+function bbp_display_topics_feed_rss2( $topics_query = array() ) {
+
+	// User cannot access this forum
+	if ( bbp_is_single_forum() && !bbp_user_can_view_forum( array( 'forum_id' => bbp_get_forum_id() ) ) )
+		return;
+
+	// Display the feed
+	header( 'Content-Type: ' . feed_content_type( 'rss-http' ) . '; charset=' . get_option( 'blog_charset' ), true );
+	header( 'Status: 200 OK' );
+	echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>'; ?>
+
+	<rss version="2.0"
+		xmlns:content="http://purl.org/rss/1.0/modules/content/"
+		xmlns:wfw="http://wellformedweb.org/CommentAPI/"
+		xmlns:dc="http://purl.org/dc/elements/1.1/"
+		xmlns:atom="http://www.w3.org/2005/Atom"
+
+		<?php do_action( 'bbp_feed' ); ?>
+	>
+
+	<channel>
+
+		<title><?php bloginfo_rss( 'name' ); ?> &#187; <?php _e( 'All Topics', 'bbpress' ); ?></title>
+		<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
+		<link><?php self_link(); ?></link>
+		<description><?php //?></description>
+		<pubDate><?php echo mysql2date( 'D, d M Y H:i:s O', current_time( 'mysql' ), false ); ?></pubDate>
+		<generator>http://bbpress.org/?v=<?php bbp_version(); ?></generator>
+		<language><?php bloginfo_rss( 'language' ); ?></language>
+
+		<?php do_action( 'bbp_feed_head' ); ?>
+
+		<?php if ( bbp_has_topics( $topics_query ) ) : ?>
+
+			<?php while ( bbp_topics() ) : bbp_the_topic(); ?>
+
+				<item>
+					<guid><?php bbp_topic_permalink(); ?></guid>
+					<title><![CDATA[<?php bbp_topic_title(); ?>]]></title>
+					<link><?php bbp_topic_permalink(); ?></link>
+					<pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_post_meta( bbp_get_topic_id(), '_bbp_last_active_time', true ) ); ?></pubDate>
+					<dc:creator><?php the_author() ?></dc:creator>
+
+					<?php if ( !post_password_required() ) : ?>
+
+					<description>
+						<![CDATA[
+						<p><?php printf( esc_html__( 'Replies: %s', 'bbpress' ), bbp_get_topic_reply_count() ); ?></p>
+						<?php bbp_topic_content(); ?>
+						]]>
+					</description>
+
+					<?php rss_enclosure(); ?>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bbp_feed_item' ); ?>
+
+				</item>
+
+				<?php endwhile; ?>
+			<?php endif; ?>
+
+		<?php do_action( 'bbp_feed_footer' ); ?>
+
+	</channel>
+	</rss>
+
+<?php
+	exit();
+}
+
+/** Permissions ***************************************************************/
+
+/**
+ * Redirect if unathorized user is attempting to edit a topic
+ *
+ * @since bbPress (r3605)
+ *
+ * @uses bbp_is_topic_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_topic_id()
+ * @uses wp_safe_redirect()
+ * @uses bbp_get_topic_permalink()
+ */
+function bbp_check_topic_edit() {
+
+	// Bail if not editing a topic
+	if ( !bbp_is_topic_edit() )
+		return;
+
+	// User cannot edit topic, so redirect back to topic
+	if ( !current_user_can( 'edit_topic', bbp_get_topic_id() ) ) {
+		wp_safe_redirect( bbp_get_topic_permalink() );
+		exit();
+	}
+}
+
+/**
+ * Redirect if unathorized user is attempting to edit a topic tag
+ *
+ * @since bbPress (r3605)
+ *
+ * @uses bbp_is_topic_tag_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_topic_tag_id()
+ * @uses wp_safe_redirect()
+ * @uses bbp_get_topic_tag_link()
+ */
+function bbp_check_topic_tag_edit() {
+
+	// Bail if not editing a topic tag
+	if ( !bbp_is_topic_tag_edit() )
+		return;
+
+	// Bail if current user cannot edit topic tags
+	if ( !current_user_can( 'edit_topic_tags', bbp_get_topic_tag_id() ) ) {
+		wp_safe_redirect( bbp_get_topic_tag_link() );
+		exit();
+	}
+}
Index: /tags/2.5.4/includes/topics/index.php
===================================================================
--- /tags/2.5.4/includes/topics/index.php	(revision 5382)
+++ /tags/2.5.4/includes/topics/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/topics/template.php
===================================================================
--- /tags/2.5.4/includes/topics/template.php	(revision 5382)
+++ /tags/2.5.4/includes/topics/template.php	(revision 5382)
@@ -0,0 +1,4010 @@
+<?php
+
+/**
+ * bbPress Topic Template Tags
+ *
+ * @package bbPress
+ * @subpackage TemplateTags
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Post Type *****************************************************************/
+
+/**
+ * Output the unique id of the custom post type for topics
+ *
+ * @since bbPress (r2857)
+ *
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ */
+function bbp_topic_post_type() {
+	echo bbp_get_topic_post_type();
+}
+	/**
+	 * Return the unique id of the custom post type for topics
+	 *
+	 * @since bbPress (r2857)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_topic_post_type' with the topic
+	 *                        post type id
+	 * @return string The unique topic post type id
+	 */
+	function bbp_get_topic_post_type() {
+		return apply_filters( 'bbp_get_topic_post_type', bbpress()->topic_post_type );
+	}
+
+/**
+ * Return array of labels used by the topic post type
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_topic_post_type_labels() {
+	return apply_filters( 'bbp_get_topic_post_type_labels', array(
+		'name'               => __( 'Topics',                   'bbpress' ),
+		'menu_name'          => __( 'Topics',                   'bbpress' ),
+		'singular_name'      => __( 'Topic',                    'bbpress' ),
+		'all_items'          => __( 'All Topics',               'bbpress' ),
+		'add_new'            => __( 'New Topic',                'bbpress' ),
+		'add_new_item'       => __( 'Create New Topic',         'bbpress' ),
+		'edit'               => __( 'Edit',                     'bbpress' ),
+		'edit_item'          => __( 'Edit Topic',               'bbpress' ),
+		'new_item'           => __( 'New Topic',                'bbpress' ),
+		'view'               => __( 'View Topic',               'bbpress' ),
+		'view_item'          => __( 'View Topic',               'bbpress' ),
+		'search_items'       => __( 'Search Topics',            'bbpress' ),
+		'not_found'          => __( 'No topics found',          'bbpress' ),
+		'not_found_in_trash' => __( 'No topics found in Trash', 'bbpress' ),
+		'parent_item_colon'  => __( 'Forum:',                   'bbpress' )
+	) );
+}
+
+/**
+ * Return array of topic post type rewrite settings
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_topic_post_type_rewrite() {
+	return apply_filters( 'bbp_get_topic_post_type_rewrite', array(
+		'slug'       => bbp_get_topic_slug(),
+		'with_front' => false
+	) );
+}
+
+/**
+ * Return array of features the topic post type supports
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_topic_post_type_supports() {
+	return apply_filters( 'bbp_get_topic_post_type_supports', array(
+		'title',
+		'editor',
+		'revisions'
+	) );
+}
+
+/**
+ * The plugin version of bbPress comes with two topic display options:
+ * - Traditional: Topics are included in the reply loop (default)
+ * - New Style: Topics appear as "lead" posts, ahead of replies
+ *
+ * @since bbPress (r2954)
+ * @param $show_lead Optional. Default false
+ * @return bool Yes if the topic appears as a lead, otherwise false
+ */
+function bbp_show_lead_topic( $show_lead = false ) {
+
+	// Never separate the lead topic in feeds
+	if ( is_feed() )
+		return false;
+
+	return (bool) apply_filters( 'bbp_show_lead_topic', (bool) $show_lead );
+}
+
+/** Topic Loop ****************************************************************/
+
+/**
+ * The main topic loop. WordPress makes this easy for us
+ *
+ * @since bbPress (r2485)
+ *
+ * @param mixed $args All the arguments supported by {@link WP_Query}
+ * @uses current_user_can() To check if the current user can edit other's topics
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses WP_Query To make query and get the topics
+ * @uses is_page() To check if it's a page
+ * @uses bbp_is_single_forum() To check if it's a forum
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses bbp_get_paged() To get the current page value
+ * @uses bbp_get_super_stickies() To get the super stickies
+ * @uses bbp_get_stickies() To get the forum stickies
+ * @uses wpdb::get_results() To execute our query and get the results
+ * @uses WP_Rewrite::using_permalinks() To check if the blog is using permalinks
+ * @uses get_permalink() To get the permalink
+ * @uses add_query_arg() To add custom args to the url
+ * @uses apply_filters() Calls 'bbp_topics_pagination' with the pagination args
+ * @uses paginate_links() To paginate the links
+ * @uses apply_filters() Calls 'bbp_has_topics' with
+ *                        bbPres::topic_query::have_posts()
+ *                        and bbPres::topic_query
+ * @return object Multidimensional array of topic information
+ */
+function bbp_has_topics( $args = '' ) {
+	global $wp_rewrite;
+
+	/** Defaults **************************************************************/
+
+	// Other defaults
+	$default_topic_search  = !empty( $_REQUEST['ts'] ) ? $_REQUEST['ts'] : false;
+	$default_show_stickies = (bool) ( bbp_is_single_forum() || bbp_is_topic_archive() ) && ( false === $default_topic_search );
+	$default_post_parent   = bbp_is_single_forum() ? bbp_get_forum_id() : 'any';
+
+	// Default argument array
+	$default = array(
+		'post_type'      => bbp_get_topic_post_type(), // Narrow query down to bbPress topics
+		'post_parent'    => $default_post_parent,      // Forum ID
+		'meta_key'       => '_bbp_last_active_time',   // Make sure topic has some last activity time
+		'orderby'        => 'meta_value',              // 'meta_value', 'author', 'date', 'title', 'modified', 'parent', rand',
+		'order'          => 'DESC',                    // 'ASC', 'DESC'
+		'posts_per_page' => bbp_get_topics_per_page(), // Topics per page
+		'paged'          => bbp_get_paged(),           // Page Number
+		's'              => $default_topic_search,     // Topic Search
+		'show_stickies'  => $default_show_stickies,    // Ignore sticky topics?
+		'max_num_pages'  => false,                     // Maximum number of pages to show
+	);
+
+	// What are the default allowed statuses (based on user caps)
+	if ( bbp_get_view_all() ) {
+
+		// Default view=all statuses
+		$post_statuses = array(
+			bbp_get_public_status_id(),
+			bbp_get_closed_status_id(),
+			bbp_get_spam_status_id(),
+			bbp_get_trash_status_id()
+		);
+
+		// Add support for private status
+		if ( current_user_can( 'read_private_topics' ) ) {
+			$post_statuses[] = bbp_get_private_status_id();
+		}
+
+		// Join post statuses together
+		$default['post_status'] = implode( ',', $post_statuses );
+
+	// Lean on the 'perm' query var value of 'readable' to provide statuses
+	} else {
+		$default['perm'] = 'readable';
+	}
+
+	// Maybe query for topic tags
+	if ( bbp_is_topic_tag() ) {
+		$default['term']     = bbp_get_topic_tag_slug();
+		$default['taxonomy'] = bbp_get_topic_tag_tax_id();
+	}
+
+	/** Setup *****************************************************************/
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, $default, 'has_topics' );
+
+	// Get bbPress
+	$bbp = bbpress();
+
+	// Call the query
+	$bbp->topic_query = new WP_Query( $r );
+
+	// Set post_parent back to 0 if originally set to 'any'
+	if ( 'any' === $r['post_parent'] )
+		$r['post_parent'] = 0;
+
+	// Limited the number of pages shown
+	if ( !empty( $r['max_num_pages'] ) )
+		$bbp->topic_query->max_num_pages = $r['max_num_pages'];
+
+	/** Stickies **************************************************************/
+
+	// Put sticky posts at the top of the posts array
+	if ( !empty( $r['show_stickies'] ) && $r['paged'] <= 1 ) {
+
+		// Get super stickies and stickies in this forum
+		$stickies = bbp_get_super_stickies();
+
+		// Get stickies for current forum
+		if ( !empty( $r['post_parent'] ) ) {
+			$stickies = array_merge( $stickies, bbp_get_stickies( $r['post_parent'] ) );
+		}
+
+		// Remove any duplicate stickies
+		$stickies = array_unique( $stickies );
+
+		// We have stickies
+		if ( is_array( $stickies ) && !empty( $stickies ) ) {
+
+			// Start the offset at -1 so first sticky is at correct 0 offset
+			$sticky_offset = -1;
+
+			// Loop over topics and relocate stickies to the front.
+			foreach ( $stickies as $sticky_index => $sticky_ID ) {
+
+				// Get the post offset from the posts array
+				$post_offsets = wp_filter_object_list( $bbp->topic_query->posts, array( 'ID' => $sticky_ID ), 'OR', 'ID' );
+
+				// Continue if no post offsets
+				if ( empty( $post_offsets ) ) {
+					continue;
+				}
+
+				// Loop over posts in current query and splice them into position
+				foreach ( array_keys( $post_offsets ) as $post_offset ) {
+					$sticky_offset++;
+
+					$sticky = $bbp->topic_query->posts[$post_offset];
+
+					// Remove sticky from current position
+					array_splice( $bbp->topic_query->posts, $post_offset, 1 );
+
+					// Move to front, after other stickies
+					array_splice( $bbp->topic_query->posts, $sticky_offset, 0, array( $sticky ) );
+
+					// Cleanup
+					unset( $stickies[$sticky_index] );
+					unset( $sticky );
+				}
+
+				// Cleanup
+				unset( $post_offsets );
+			}
+
+			// Cleanup
+			unset( $sticky_offset );
+
+			// If any posts have been excluded specifically, Ignore those that are sticky.
+			if ( !empty( $stickies ) && !empty( $r['post__not_in'] ) ) {
+				$stickies = array_diff( $stickies, $r['post__not_in'] );
+			}
+
+			// Fetch sticky posts that weren't in the query results
+			if ( !empty( $stickies ) ) {
+
+				// Query to use in get_posts to get sticky posts
+				$sticky_query = array(
+					'post_type'   => bbp_get_topic_post_type(),
+					'post_parent' => 'any',
+					'meta_key'    => '_bbp_last_active_time',
+					'orderby'     => 'meta_value',
+					'order'       => 'DESC',
+					'include'     => $stickies
+				);
+
+				// Cleanup
+				unset( $stickies );
+
+				// Conditionally exclude private/hidden forum ID's
+				$exclude_forum_ids = bbp_exclude_forum_ids( 'array' );
+				if ( ! empty( $exclude_forum_ids ) ) {
+					$sticky_query['post_parent__not_in'] = $exclude_forum_ids;
+				}
+
+				// What are the default allowed statuses (based on user caps)
+				if ( bbp_get_view_all() ) {
+					$sticky_query['post_status'] = $r['post_status'];
+
+				// Lean on the 'perm' query var value of 'readable' to provide statuses
+				} else {
+					$sticky_query['post_status'] = $r['perm'];
+				}
+
+				// Get all stickies
+				$sticky_posts = get_posts( $sticky_query );
+				if ( !empty( $sticky_posts ) ) {
+
+					// Get a count of the visible stickies
+					$sticky_count = count( $sticky_posts );
+
+					// Merge the stickies topics with the query topics .
+					$bbp->topic_query->posts       = array_merge( $sticky_posts, $bbp->topic_query->posts );
+
+					// Adjust loop and counts for new sticky positions
+					$bbp->topic_query->found_posts = (int) $bbp->topic_query->found_posts + (int) $sticky_count;
+					$bbp->topic_query->post_count  = (int) $bbp->topic_query->post_count  + (int) $sticky_count;
+
+					// Cleanup
+					unset( $sticky_posts );
+				}
+			}
+		}
+	}
+
+	// If no limit to posts per page, set it to the current post_count
+	if ( -1 === $r['posts_per_page'] )
+		$r['posts_per_page'] = $bbp->topic_query->post_count;
+
+	// Add pagination values to query object
+	$bbp->topic_query->posts_per_page = $r['posts_per_page'];
+	$bbp->topic_query->paged          = $r['paged'];
+
+	// Only add pagination if query returned results
+	if ( ( (int) $bbp->topic_query->post_count || (int) $bbp->topic_query->found_posts ) && (int) $bbp->topic_query->posts_per_page ) {
+
+		// Limit the number of topics shown based on maximum allowed pages
+		if ( ( !empty( $r['max_num_pages'] ) ) && $bbp->topic_query->found_posts > $bbp->topic_query->max_num_pages * $bbp->topic_query->post_count )
+			$bbp->topic_query->found_posts = $bbp->topic_query->max_num_pages * $bbp->topic_query->post_count;
+
+		// If pretty permalinks are enabled, make our pagination pretty
+		if ( $wp_rewrite->using_permalinks() ) {
+
+			// User's topics
+			if ( bbp_is_single_user_topics() ) {
+				$base = bbp_get_user_topics_created_url( bbp_get_displayed_user_id() );
+
+			// User's favorites
+			} elseif ( bbp_is_favorites() ) {
+				$base = bbp_get_favorites_permalink( bbp_get_displayed_user_id() );
+
+			// User's subscriptions
+			} elseif ( bbp_is_subscriptions() ) {
+				$base = bbp_get_subscriptions_permalink( bbp_get_displayed_user_id() );
+
+			// Root profile page
+			} elseif ( bbp_is_single_user() ) {
+				$base = bbp_get_user_profile_url( bbp_get_displayed_user_id() );
+
+			// View
+			} elseif ( bbp_is_single_view() ) {
+				$base = bbp_get_view_url();
+
+			// Topic tag
+			} elseif ( bbp_is_topic_tag() ) {
+				$base = bbp_get_topic_tag_link();
+
+			// Page or single post
+			} elseif ( is_page() || is_single() ) {
+				$base = get_permalink();
+
+			// Forum archive
+			} elseif ( bbp_is_forum_archive() ) {
+				$base = bbp_get_forums_url();
+
+			// Topic archive
+			} elseif ( bbp_is_topic_archive() ) {
+				$base = bbp_get_topics_url();
+
+			// Default
+			} else {
+				$base = get_permalink( (int) $r['post_parent'] );
+			}
+
+			// Use pagination base
+			$base = trailingslashit( $base ) . user_trailingslashit( $wp_rewrite->pagination_base . '/%#%/' );
+
+		// Unpretty pagination
+		} else {
+			$base = add_query_arg( 'paged', '%#%' );
+		}
+
+		// Pagination settings with filter
+		$bbp_topic_pagination = apply_filters( 'bbp_topic_pagination', array (
+			'base'      => $base,
+			'format'    => '',
+			'total'     => $r['posts_per_page'] === $bbp->topic_query->found_posts ? 1 : ceil( (int) $bbp->topic_query->found_posts / (int) $r['posts_per_page'] ),
+			'current'   => (int) $bbp->topic_query->paged,
+			'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
+			'next_text' => is_rtl() ? '&larr;' : '&rarr;',
+			'mid_size'  => 1
+		) );
+
+		// Add pagination to query object
+		$bbp->topic_query->pagination_links = paginate_links( $bbp_topic_pagination );
+
+		// Remove first page from pagination
+		$bbp->topic_query->pagination_links = str_replace( $wp_rewrite->pagination_base . "/1/'", "'", $bbp->topic_query->pagination_links );
+	}
+
+	// Return object
+	return apply_filters( 'bbp_has_topics', $bbp->topic_query->have_posts(), $bbp->topic_query );
+}
+
+/**
+ * Whether there are more topics available in the loop
+ *
+ * @since bbPress (r2485)
+ *
+ * @uses WP_Query bbPress::topic_query::have_posts()
+ * @return object Topic information
+ */
+function bbp_topics() {
+
+	// Put into variable to check against next
+	$have_posts = bbpress()->topic_query->have_posts();
+
+	// Reset the post data when finished
+	if ( empty( $have_posts ) )
+		wp_reset_postdata();
+
+	return $have_posts;
+}
+
+/**
+ * Loads up the current topic in the loop
+ *
+ * @since bbPress (r2485)
+ *
+ * @uses WP_Query bbPress::topic_query::the_post()
+ * @return object Topic information
+ */
+function bbp_the_topic() {
+	return bbpress()->topic_query->the_post();
+}
+
+/**
+ * Output the topic id
+ *
+ * @since bbPress (r2485)
+ *
+ * @uses bbp_get_topic_id() To get the topic id
+ */
+function bbp_topic_id( $topic_id = 0) {
+	echo bbp_get_topic_id( $topic_id );
+}
+	/**
+	 * Return the topic id
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param $topic_id Optional. Used to check emptiness
+	 * @uses bbPress::topic_query::post::ID To get the topic id
+	 * @uses bbp_is_topic() To check if the search result is a topic
+	 * @uses bbp_is_single_topic() To check if it's a topic page
+	 * @uses bbp_is_topic_edit() To check if it's a topic edit page
+	 * @uses bbp_is_single_reply() To check if it it's a reply page
+	 * @uses bbp_is_reply_edit() To check if it's a reply edit page
+	 * @uses bbp_get_reply_topic_edit() To get the reply topic id
+	 * @uses get_post_field() To get the post's post type
+	 * @uses WP_Query::post::ID To get the topic id
+	 * @uses bbp_get_topic_post_type() To get the topic post type
+	 * @uses apply_filters() Calls 'bbp_get_topic_id' with the topic id and
+	 *                        supplied topic id
+	 * @return int The topic id
+	 */
+	function bbp_get_topic_id( $topic_id = 0 ) {
+		global $wp_query;
+
+		$bbp = bbpress();
+
+		// Easy empty checking
+		if ( !empty( $topic_id ) && is_numeric( $topic_id ) ) {
+			$bbp_topic_id = $topic_id;
+
+		// Currently inside a topic loop
+		} elseif ( !empty( $bbp->topic_query->in_the_loop ) && isset( $bbp->topic_query->post->ID ) ) {
+			$bbp_topic_id = $bbp->topic_query->post->ID;
+
+		// Currently inside a search loop
+		} elseif ( !empty( $bbp->search_query->in_the_loop ) && isset( $bbp->search_query->post->ID ) && bbp_is_topic( $bbp->search_query->post->ID ) ) {
+			$bbp_topic_id = $bbp->search_query->post->ID;
+
+		// Currently viewing/editing a topic, likely alone
+		} elseif ( ( bbp_is_single_topic() || bbp_is_topic_edit() ) && !empty( $bbp->current_topic_id ) ) {
+			$bbp_topic_id = $bbp->current_topic_id;
+
+		// Currently viewing/editing a topic, likely in a loop
+		} elseif ( ( bbp_is_single_topic() || bbp_is_topic_edit() ) && isset( $wp_query->post->ID ) ) {
+			$bbp_topic_id = $wp_query->post->ID;
+
+		// Currently viewing/editing a reply
+		} elseif ( bbp_is_single_reply() || bbp_is_reply_edit() ) {
+			$bbp_topic_id = bbp_get_reply_topic_id();
+
+		// Fallback
+		} else {
+			$bbp_topic_id = 0;
+		}
+
+		return (int) apply_filters( 'bbp_get_topic_id', (int) $bbp_topic_id, $topic_id );
+	}
+
+/**
+ * Gets a topic
+ *
+ * @since bbPress (r2787)
+ *
+ * @param int|object $topic Topic id or topic object
+ * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. Default = OBJECT
+ * @param string $filter Optional Sanitation filter. See {@link sanitize_post()}
+ * @uses get_post() To get the topic
+ * @uses apply_filters() Calls 'bbp_get_topic' with the topic, output type and
+ *                        sanitation filter
+ * @return mixed Null if error or topic (in specified form) if success
+ */
+function bbp_get_topic( $topic, $output = OBJECT, $filter = 'raw' ) {
+
+	// Use topic ID
+	if ( empty( $topic ) || is_numeric( $topic ) )
+		$topic = bbp_get_topic_id( $topic );
+
+	// Attempt to load the topic
+	$topic = get_post( $topic, OBJECT, $filter );
+	if ( empty( $topic ) )
+		return $topic;
+
+	// Bail if post_type is not a topic
+	if ( $topic->post_type !== bbp_get_topic_post_type() )
+		return null;
+
+	// Tweak the data type to return
+	if ( $output === OBJECT ) {
+		return $topic;
+
+	} elseif ( $output === ARRAY_A ) {
+		$_topic = get_object_vars( $topic );
+		return $_topic;
+
+	} elseif ( $output === ARRAY_N ) {
+		$_topic = array_values( get_object_vars( $topic ) );
+		return $_topic;
+
+	}
+
+	return apply_filters( 'bbp_get_topic', $topic, $output, $filter );
+}
+
+/**
+ * Output the link to the topic in the topic loop
+ *
+ * @since bbPress (r2485)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param $string $redirect_to Optional. Pass a redirect value for use with
+ *                              shortcodes and other fun things.
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ */
+function bbp_topic_permalink( $topic_id = 0, $redirect_to = '' ) {
+	echo esc_url( bbp_get_topic_permalink( $topic_id, $redirect_to ) );
+}
+	/**
+	 * Return the link to the topic
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @param $string $redirect_to Optional. Pass a redirect value for use with
+	 *                              shortcodes and other fun things.
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_permalink() To get the topic permalink
+	 * @uses esc_url_raw() To clean the redirect_to url
+	 * @uses apply_filters() Calls 'bbp_get_topic_permalink' with the link
+	 *                        and topic id
+	 * @return string Permanent link to topic
+	 */
+	function bbp_get_topic_permalink( $topic_id = 0, $redirect_to = '' ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Use the redirect address
+		if ( !empty( $redirect_to ) ) {
+			$topic_permalink = esc_url_raw( $redirect_to );
+
+		// Use the topic permalink
+		} else {
+			$topic_permalink = get_permalink( $topic_id );
+		}
+
+		return apply_filters( 'bbp_get_topic_permalink', $topic_permalink, $topic_id );
+	}
+
+/**
+ * Output the title of the topic
+ *
+ * @since bbPress (r2485)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_title() To get the topic title
+ */
+function bbp_topic_title( $topic_id = 0 ) {
+	echo bbp_get_topic_title( $topic_id );
+}
+	/**
+	 * Return the title of the topic
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_the_title() To get the title
+	 * @uses apply_filters() Calls 'bbp_get_topic_title' with the title and
+	 *                        topic id
+	 * @return string Title of topic
+	 */
+	function bbp_get_topic_title( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$title    = get_the_title( $topic_id );
+
+		return apply_filters( 'bbp_get_topic_title', $title, $topic_id );
+	}
+
+/**
+ * Output the topic archive title
+ *
+ * @since bbPress (r3249)
+ *
+ * @param string $title Default text to use as title
+ */
+function bbp_topic_archive_title( $title = '' ) {
+	echo bbp_get_topic_archive_title( $title );
+}
+	/**
+	 * Return the topic archive title
+	 *
+	 * @since bbPress (r3249)
+	 *
+	 * @param string $title Default text to use as title
+	 *
+	 * @uses bbp_get_page_by_path() Check if page exists at root path
+	 * @uses get_the_title() Use the page title at the root path
+	 * @uses get_post_type_object() Load the post type object
+	 * @uses bbp_get_topic_post_type() Get the topic post type ID
+	 * @uses get_post_type_labels() Get labels for topic post type
+	 * @uses apply_filters() Allow output to be manipulated
+	 *
+	 * @return string The topic archive title
+	 */
+	function bbp_get_topic_archive_title( $title = '' ) {
+
+		// If no title was passed
+		if ( empty( $title ) ) {
+
+			// Set root text to page title
+			$page = bbp_get_page_by_path( bbp_get_topic_archive_slug() );
+			if ( !empty( $page ) ) {
+				$title = get_the_title( $page->ID );
+
+			// Default to topic post type name label
+			} else {
+				$tto    = get_post_type_object( bbp_get_topic_post_type() );
+				$title  = $tto->labels->name;
+			}
+		}
+
+		return apply_filters( 'bbp_get_topic_archive_title', $title );
+	}
+
+/**
+ * Output the content of the topic
+ *
+ * @since bbPress (r2780)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_content() To get the topic content
+ */
+function bbp_topic_content( $topic_id = 0 ) {
+	echo bbp_get_topic_content( $topic_id );
+}
+	/**
+	 * Return the content of the topic
+	 *
+	 * @since bbPress (r2780)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses post_password_required() To check if the topic requires pass
+	 * @uses get_the_password_form() To get the password form
+	 * @uses get_post_field() To get the content post field
+	 * @uses apply_filters() Calls 'bbp_get_topic_content' with the content
+	 *                        and topic id
+	 * @return string Content of the topic
+	 */
+	function bbp_get_topic_content( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Check if password is required
+		if ( post_password_required( $topic_id ) )
+			return get_the_password_form();
+
+		$content = get_post_field( 'post_content', $topic_id );
+
+		return apply_filters( 'bbp_get_topic_content', $content, $topic_id );
+	}
+
+/**
+ * Output the excerpt of the topic
+ *
+ * @since bbPress (r2780)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param int $length Optional. Length of the excerpt. Defaults to 100 letters
+ * @uses bbp_get_topic_excerpt() To get the topic excerpt
+ */
+function bbp_topic_excerpt( $topic_id = 0, $length = 100 ) {
+	echo bbp_get_topic_excerpt( $topic_id, $length );
+}
+	/**
+	 * Return the excerpt of the topic
+	 *
+	 * @since bbPress (r2780)
+	 *
+	 * @param int $topic_id Optional. topic id
+	 * @param int $length Optional. Length of the excerpt. Defaults to 100
+	 *                     letters
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_field() To get the excerpt
+	 * @uses bbp_get_topic_content() To get the topic content
+	 * @uses apply_filters() Calls 'bbp_get_topic_excerpt' with the excerpt,
+	 *                        topic id and length
+	 * @return string topic Excerpt
+	 */
+	function bbp_get_topic_excerpt( $topic_id = 0, $length = 100 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$length   = (int) $length;
+		$excerpt  = get_post_field( 'post_excerpt', $topic_id );
+
+		if ( empty( $excerpt ) ) {
+			$excerpt = bbp_get_topic_content( $topic_id );
+		}
+
+		$excerpt = trim( strip_tags( $excerpt ) );
+
+		// Multibyte support
+		if ( function_exists( 'mb_strlen' ) ) {
+			$excerpt_length = mb_strlen( $excerpt );
+		} else {
+			$excerpt_length = strlen( $excerpt );
+		}
+
+		if ( !empty( $length ) && ( $excerpt_length > $length ) ) {
+			$excerpt  = substr( $excerpt, 0, $length - 1 );
+			$excerpt .= '&hellip;';
+		}
+
+		return apply_filters( 'bbp_get_topic_excerpt', $excerpt, $topic_id, $length );
+	}
+
+/**
+ * Output the post date and time of a topic
+ *
+ * @since bbPress (r4155)
+ *
+ * @param int $topic_id Optional. Topic id.
+ * @param bool $humanize Optional. Humanize output using time_since
+ * @param bool $gmt Optional. Use GMT
+ * @uses bbp_get_topic_post_date() to get the output
+ */
+function bbp_topic_post_date( $topic_id = 0, $humanize = false, $gmt = false ) {
+	echo bbp_get_topic_post_date( $topic_id, $humanize, $gmt );
+}
+	/**
+	 * Return the post date and time of a topic
+	 *
+	 * @since bbPress (r4155)
+	 *
+	 * @param int $topic_id Optional. Topic id.
+	 * @param bool $humanize Optional. Humanize output using time_since
+	 * @param bool $gmt Optional. Use GMT
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_time() to get the topic post time
+	 * @uses bbp_get_time_since() to maybe humanize the topic post time
+	 * @return string
+	 */
+	function bbp_get_topic_post_date( $topic_id = 0, $humanize = false, $gmt = false ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// 4 days, 4 hours ago
+		if ( !empty( $humanize ) ) {
+			$gmt_s  = !empty( $gmt ) ? 'U' : 'G';
+			$date   = get_post_time( $gmt_s, $gmt, $topic_id );
+			$time   = false; // For filter below
+			$result = bbp_get_time_since( $date );
+
+		// August 4, 2012 at 2:37 pm
+		} else {
+			$date   = get_post_time( get_option( 'date_format' ), $gmt, $topic_id, true );
+			$time   = get_post_time( get_option( 'time_format' ), $gmt, $topic_id, true );
+			$result = sprintf( _x( '%1$s at %2$s', 'date at time', 'bbpress' ), $date, $time );
+		}
+
+		return apply_filters( 'bbp_get_topic_post_date', $result, $topic_id, $humanize, $gmt, $date, $time );
+	}
+
+/**
+ * Output pagination links of a topic within the topic loop
+ *
+ * @since bbPress (r2966)
+ *
+ * @param mixed $args See {@link bbp_get_topic_pagination()}
+ * @uses bbp_get_topic_pagination() To get the topic pagination links
+ */
+function bbp_topic_pagination( $args = '' ) {
+	echo bbp_get_topic_pagination( $args );
+}
+	/**
+	 * Returns pagination links of a topic within the topic loop
+	 *
+	 * @since bbPress (r2966)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - topic_id: Topic id
+	 *  - before: Before the links
+	 *  - after: After the links
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses WP_Rewrite::using_permalinks() To check if the blog is using
+	 *                                       permalinks
+	 * @uses user_trailingslashit() To add a trailing slash
+	 * @uses trailingslashit() To add a trailing slash
+	 * @uses get_permalink() To get the permalink of the topic
+	 * @uses add_query_arg() To add query args
+	 * @uses bbp_get_topic_reply_count() To get topic reply count
+	 * @uses bbp_show_topic_lead() Are we showing the topic as a lead?
+	 * @uses get_option() To get replies per page option
+	 * @uses paginate_links() To paginate the links
+	 * @uses apply_filters() Calls 'bbp_get_topic_pagination' with the links
+	 *                        and arguments
+	 * @return string Pagination links
+	 */
+	function bbp_get_topic_pagination( $args = '' ) {
+		global $wp_rewrite;
+
+		// Bail if threading replies
+		if ( bbp_thread_replies() ) {
+			return;
+		}
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'topic_id' => bbp_get_topic_id(),
+			'before'   => '<span class="bbp-topic-pagination">',
+			'after'    => '</span>',
+		), 'get_topic_pagination' );
+
+		// If pretty permalinks are enabled, make our pagination pretty
+		if ( $wp_rewrite->using_permalinks() ) {
+			$base = trailingslashit( get_permalink( $r['topic_id'] ) ) . user_trailingslashit( $wp_rewrite->pagination_base . '/%#%/' );
+		} else {
+			$base = add_query_arg( 'paged', '%#%', get_permalink( $r['topic_id'] ) );
+		}
+
+		// Get total and add 1 if topic is included in the reply loop
+		$total = bbp_get_topic_reply_count( $r['topic_id'], true );
+
+		// Bump if topic is in loop
+		if ( !bbp_show_lead_topic() )
+			$total++;
+
+		// Pagination settings
+		$pagination = array(
+			'base'      => $base,
+			'format'    => '',
+			'total'     => ceil( (int) $total / (int) bbp_get_replies_per_page() ),
+			'current'   => 0,
+			'prev_next' => false,
+			'mid_size'  => 2,
+			'end_size'  => 3,
+			'add_args'  => ( bbp_get_view_all() ) ? array( 'view' => 'all' ) : false
+		);
+
+		// Add pagination to query object
+		$pagination_links = paginate_links( $pagination );
+		if ( !empty( $pagination_links ) ) {
+
+			// Remove first page from pagination
+			if ( $wp_rewrite->using_permalinks() ) {
+				$pagination_links = str_replace( $wp_rewrite->pagination_base . '/1/', '', $pagination_links );
+			} else {
+				$pagination_links = str_replace( '&#038;paged=1', '', $pagination_links );
+			}
+
+			// Add before and after to pagination links
+			$pagination_links = $r['before'] . $pagination_links . $r['after'];
+		}
+
+		return apply_filters( 'bbp_get_topic_pagination', $pagination_links, $args );
+	}
+
+/**
+ * Append revisions to the topic content
+ *
+ * @since bbPress (r2782)
+ *
+ * @param string $content Optional. Content to which we need to append the revisions to
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_revision_log() To get the topic revision log
+ * @uses apply_filters() Calls 'bbp_topic_append_revisions' with the processed
+ *                        content, original content and topic id
+ * @return string Content with the revisions appended
+ */
+function bbp_topic_content_append_revisions( $content = '', $topic_id = 0 ) {
+
+	// Bail if in admin or feed
+	if ( is_admin() || is_feed() )
+		return;
+
+	// Validate the ID
+	$topic_id = bbp_get_topic_id( $topic_id );
+
+	return apply_filters( 'bbp_topic_append_revisions', $content . bbp_get_topic_revision_log( $topic_id ), $content, $topic_id );
+}
+
+/**
+ * Output the revision log of the topic
+ *
+ * @since bbPress (r2782)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_revision_log() To get the topic revision log
+ */
+function bbp_topic_revision_log( $topic_id = 0 ) {
+	echo bbp_get_topic_revision_log( $topic_id );
+}
+	/**
+	 * Return the formatted revision log of the topic
+	 *
+	 * @since bbPress (r2782)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic_revisions() To get the topic revisions
+	 * @uses bbp_get_topic_raw_revision_log() To get the raw revision log
+	 * @uses bbp_get_topic_author_display_name() To get the topic author
+	 * @uses bbp_get_author_link() To get the topic author link
+	 * @uses bbp_convert_date() To convert the date
+	 * @uses bbp_get_time_since() To get the time in since format
+	 * @uses apply_filters() Calls 'bbp_get_topic_revision_log' with the
+	 *                        log and topic id
+	 * @return string Revision log of the topic
+	 */
+	function bbp_get_topic_revision_log( $topic_id = 0 ) {
+		// Create necessary variables
+		$topic_id     = bbp_get_topic_id( $topic_id );
+		$revision_log = bbp_get_topic_raw_revision_log( $topic_id );
+
+		if ( empty( $topic_id ) || empty( $revision_log ) || !is_array( $revision_log ) )
+			return false;
+
+		$revisions = bbp_get_topic_revisions( $topic_id );
+		if ( empty( $revisions ) )
+			return false;
+
+		$r = "\n\n" . '<ul id="bbp-topic-revision-log-' . esc_attr( $topic_id ) . '" class="bbp-topic-revision-log">' . "\n\n";
+
+		// Loop through revisions
+		foreach ( (array) $revisions as $revision ) {
+
+			if ( empty( $revision_log[$revision->ID] ) ) {
+				$author_id = $revision->post_author;
+				$reason    = '';
+			} else {
+				$author_id = $revision_log[$revision->ID]['author'];
+				$reason    = $revision_log[$revision->ID]['reason'];
+			}
+
+			$author = bbp_get_author_link( array( 'size' => 14, 'link_text' => bbp_get_topic_author_display_name( $revision->ID ), 'post_id' => $revision->ID ) );
+			$since  = bbp_get_time_since( bbp_convert_date( $revision->post_modified ) );
+
+			$r .= "\t" . '<li id="bbp-topic-revision-log-' . esc_attr( $topic_id ) . '-item-' . esc_attr( $revision->ID ) . '" class="bbp-topic-revision-log-item">' . "\n";
+			if ( !empty( $reason ) ) {
+				$r .= "\t\t" . sprintf( __( 'This topic was modified %1$s by %2$s. Reason: %3$s', 'bbpress' ), esc_html( $since ), $author, esc_html( $reason ) ) . "\n";
+			} else {
+				$r .= "\t\t" . sprintf( __( 'This topic was modified %1$s by %2$s.', 'bbpress' ), esc_html( $since ), $author ) . "\n";
+			}
+			$r .= "\t" . '</li>' . "\n";
+
+		}
+
+		$r .= "\n" . '</ul>' . "\n\n";
+
+		return apply_filters( 'bbp_get_topic_revision_log', $r, $topic_id );
+	}
+		/**
+		 * Return the raw revision log of the topic
+		 *
+		 * @since bbPress (r2782)
+		 *
+		 * @param int $topic_id Optional. Topic id
+		 * @uses bbp_get_topic_id() To get the topic id
+		 * @uses get_post_meta() To get the revision log meta
+		 * @uses apply_filters() Calls 'bbp_get_topic_raw_revision_log'
+		 *                        with the log and topic id
+		 * @return string Raw revision log of the topic
+		 */
+		function bbp_get_topic_raw_revision_log( $topic_id = 0 ) {
+			$topic_id = bbp_get_topic_id( $topic_id );
+
+			$revision_log = get_post_meta( $topic_id, '_bbp_revision_log', true );
+			$revision_log = empty( $revision_log ) ? array() : $revision_log;
+
+			return apply_filters( 'bbp_get_topic_raw_revision_log', $revision_log, $topic_id );
+		}
+
+/**
+ * Return the revisions of the topic
+ *
+ * @since bbPress (r2782)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses wp_get_post_revisions() To get the topic revisions
+ * @uses apply_filters() Calls 'bbp_get_topic_revisions'
+ *                        with the revisions and topic id
+ * @return string Topic revisions
+ */
+function bbp_get_topic_revisions( $topic_id = 0 ) {
+	$topic_id  = bbp_get_topic_id( $topic_id );
+	$revisions = wp_get_post_revisions( $topic_id, array( 'order' => 'ASC' ) );
+
+	return apply_filters( 'bbp_get_topic_revisions', $revisions, $topic_id );
+}
+
+/**
+ * Return the revision count of the topic
+ *
+ * @since bbPress (r2782)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_revisions() To get the topic revisions
+ * @uses apply_filters() Calls 'bbp_get_topic_revision_count'
+ *                        with the revision count and topic id
+ * @return string Topic revision count
+ */
+function bbp_get_topic_revision_count( $topic_id = 0, $integer = false ) {
+	$count  = (int) count( bbp_get_topic_revisions( $topic_id ) );
+	$filter = ( true === $integer ) ? 'bbp_get_topic_revision_count_int' : 'bbp_get_topic_revision_count';
+
+	return apply_filters( $filter, $count, $topic_id );
+}
+
+/**
+ * Output the status of the topic
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_status() To get the topic status
+ */
+function bbp_topic_status( $topic_id = 0 ) {
+	echo bbp_get_topic_status( $topic_id );
+}
+	/**
+	 * Return the status of the topic
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_status() To get the topic status
+	 * @uses apply_filters() Calls 'bbp_get_topic_status' with the status
+	 *                        and topic id
+	 * @return string Status of topic
+	 */
+	function bbp_get_topic_status( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		return apply_filters( 'bbp_get_topic_status', get_post_status( $topic_id ), $topic_id );
+	}
+
+/**
+ * Is the topic open to new replies?
+ *
+ * @since bbPress (r2727)
+ *
+ * @uses bbp_get_topic_status()
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_is_topic_closed() To check if the topic is closed
+ * @return bool True if open, false if closed.
+ */
+function bbp_is_topic_open( $topic_id = 0 ) {
+	return !bbp_is_topic_closed( $topic_id );
+}
+
+	/**
+	 * Is the topic closed to new replies?
+	 *
+	 * @since bbPress (r2746)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_status() To get the topic status
+	 * @uses apply_filters() Calls 'bbp_is_topic_closed' with the topic id
+	 *
+	 * @return bool True if closed, false if not.
+	 */
+	function bbp_is_topic_closed( $topic_id = 0 ) {
+		$closed = bbp_get_topic_status( $topic_id ) === bbp_get_closed_status_id();
+		return (bool) apply_filters( 'bbp_is_topic_closed', (bool) $closed, $topic_id );
+	}
+
+/**
+ * Is the topic a sticky or super sticky?
+ *
+ * @since bbPress (r2754)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param int $check_super Optional. If set to true and if the topic is not a
+ *                           normal sticky, it is checked if it is a super
+ *                           sticky or not. Defaults to true.
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_topic_forum_id() To get the topic forum id
+ * @uses bbp_get_stickies() To get the stickies
+ * @uses bbp_is_topic_super_sticky() To check if the topic is a super sticky
+ * @return bool True if sticky or super sticky, false if not.
+ */
+function bbp_is_topic_sticky( $topic_id = 0, $check_super = true ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$forum_id = bbp_get_topic_forum_id( $topic_id );
+	$stickies = bbp_get_stickies( $forum_id );
+
+	if ( in_array( $topic_id, $stickies ) || ( !empty( $check_super ) && bbp_is_topic_super_sticky( $topic_id ) ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the topic a super sticky?
+ *
+ * @since bbPress (r2754)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_super_stickies() To get the super stickies
+ * @return bool True if super sticky, false if not.
+ */
+function bbp_is_topic_super_sticky( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$stickies = bbp_get_super_stickies( $topic_id );
+
+	return in_array( $topic_id, $stickies );
+}
+
+/**
+ * Is the topic not spam or deleted?
+ *
+ * @since bbPress (r3496)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_topic_status() To get the topic status
+ * @uses apply_filters() Calls 'bbp_is_topic_published' with the topic id
+ * @return bool True if published, false if not.
+ */
+function bbp_is_topic_published( $topic_id = 0 ) {
+	$topic_status = bbp_get_topic_status( bbp_get_topic_id( $topic_id ) ) === bbp_get_public_status_id();
+	return (bool) apply_filters( 'bbp_is_topic_published', (bool) $topic_status, $topic_id );
+}
+
+/**
+ * Is the topic marked as spam?
+ *
+ * @since bbPress (r2727)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_topic_status() To get the topic status
+ * @uses apply_filters() Calls 'bbp_is_topic_spam' with the topic id
+ * @return bool True if spam, false if not.
+ */
+function bbp_is_topic_spam( $topic_id = 0 ) {
+	$topic_status = bbp_get_topic_status( bbp_get_topic_id( $topic_id ) ) === bbp_get_spam_status_id();
+	return (bool) apply_filters( 'bbp_is_topic_spam', (bool) $topic_status, $topic_id );
+}
+
+/**
+ * Is the topic trashed?
+ *
+ * @since bbPress (r2888)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_topic_status() To get the topic status
+ * @uses apply_filters() Calls 'bbp_is_topic_trash' with the topic id
+ * @return bool True if trashed, false if not.
+ */
+function bbp_is_topic_trash( $topic_id = 0 ) {
+	$topic_status = bbp_get_topic_status( bbp_get_topic_id( $topic_id ) ) === bbp_get_trash_status_id();
+	return (bool) apply_filters( 'bbp_is_topic_trash', (bool) $topic_status, $topic_id );
+}
+
+/**
+ * Is the posted by an anonymous user?
+ *
+ * @since bbPress (r2753)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses bbp_get_topic_author_id() To get the topic author id
+ * @uses get_post_meta() To get the anonymous user name and email meta
+ * @uses apply_filters() Calls 'bbp_is_topic_anonymous' with the topic id
+ * @return bool True if the post is by an anonymous user, false if not.
+ */
+function bbp_is_topic_anonymous( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+	$retval   = false;
+
+	if ( !bbp_get_topic_author_id( $topic_id ) )
+		$retval = true;
+
+	elseif ( get_post_meta( $topic_id, '_bbp_anonymous_name',  true ) )
+		$retval = true;
+
+	elseif ( get_post_meta( $topic_id, '_bbp_anonymous_email', true ) )
+		$retval = true;
+
+	// The topic is by an anonymous user
+	return (bool) apply_filters( 'bbp_is_topic_anonymous', $retval, $topic_id );
+}
+
+/**
+ * Deprecated. Use bbp_topic_author_display_name() instead.
+ *
+ * Output the author of the topic.
+ *
+ * @since bbPress (r2590)
+ * @deprecated bbPress (r5119)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_author() To get the topic author
+ */
+function bbp_topic_author( $topic_id = 0 ) {
+	echo bbp_get_topic_author( $topic_id );
+}
+	/**
+	 * Deprecated. Use bbp_get_topic_author_display_name() instead.
+	 *
+	 * Return the author of the topic
+	 *
+	 * @since bbPress (r2590)
+	 * @deprecated bbPress (r5119)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_is_topic_anonymous() To check if the topic is by an
+	 *                                 anonymous user
+	 * @uses bbp_get_topic_author_id() To get the topic author id
+	 * @uses get_the_author_meta() To get the display name of the author
+	 * @uses get_post_meta() To get the name of the anonymous poster
+	 * @uses apply_filters() Calls 'bbp_get_topic_author' with the author
+	 *                        and topic id
+	 * @return string Author of topic
+	 */
+	function bbp_get_topic_author( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		if ( !bbp_is_topic_anonymous( $topic_id ) ) {
+			$author = get_the_author_meta( 'display_name', bbp_get_topic_author_id( $topic_id ) );
+		} else {
+			$author = get_post_meta( $topic_id, '_bbp_anonymous_name', true );
+		}
+
+		return apply_filters( 'bbp_get_topic_author', $author, $topic_id );
+	}
+
+/**
+ * Output the author ID of the topic
+ *
+ * @since bbPress (r2590)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_author_id() To get the topic author id
+ */
+function bbp_topic_author_id( $topic_id = 0 ) {
+	echo bbp_get_topic_author_id( $topic_id );
+}
+	/**
+	 * Return the author ID of the topic
+	 *
+	 * @since bbPress (r2590)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_field() To get the topic author id
+	 * @uses apply_filters() Calls 'bbp_get_topic_author_id' with the author
+	 *                        id and topic id
+	 * @return string Author of topic
+	 */
+	function bbp_get_topic_author_id( $topic_id = 0 ) {
+		$topic_id  = bbp_get_topic_id( $topic_id );
+		$author_id = get_post_field( 'post_author', $topic_id );
+
+		return (int) apply_filters( 'bbp_get_topic_author_id', (int) $author_id, $topic_id );
+	}
+
+/**
+ * Output the author display_name of the topic
+ *
+ * @since bbPress (r2590)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_author_display_name() To get the topic author's display
+ *                                            name
+ */
+function bbp_topic_author_display_name( $topic_id = 0 ) {
+	echo bbp_get_topic_author_display_name( $topic_id );
+}
+	/**
+	 * Return the author display_name of the topic
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_is_topic_anonymous() To check if the topic is by an
+	 *                                 anonymous user
+	 * @uses bbp_get_topic_author_id() To get the topic author id
+	 * @uses get_the_author_meta() To get the author meta
+	 * @uses get_post_meta() To get the anonymous user name
+	 * @uses apply_filters() Calls 'bbp_get_topic_author_id' with the
+	 *                        display name and topic id
+	 * @return string Topic's author's display name
+	 */
+	function bbp_get_topic_author_display_name( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Check for anonymous user
+		if ( !bbp_is_topic_anonymous( $topic_id ) ) {
+
+			// Get the author ID
+			$author_id = bbp_get_topic_author_id( $topic_id );
+
+			// Try to get a display name
+			$author_name = get_the_author_meta( 'display_name', $author_id );
+
+			// Fall back to user login
+			if ( empty( $author_name ) ) {
+				$author_name = get_the_author_meta( 'user_login', $author_id );
+			}
+
+		// User does not have an account
+		} else {
+			$author_name = get_post_meta( $topic_id, '_bbp_anonymous_name', true );
+		}
+
+		// If nothing could be found anywhere, use Anonymous
+		if ( empty( $author_name ) )
+			$author_name = __( 'Anonymous', 'bbpress' );
+
+		// Encode possible UTF8 display names
+		if ( seems_utf8( $author_name ) === false )
+			$author_name = utf8_encode( $author_name );
+
+		return apply_filters( 'bbp_get_topic_author_display_name', $author_name, $topic_id );
+	}
+
+/**
+ * Output the author avatar of the topic
+ *
+ * @since bbPress (r2590)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param int $size Optional. Avatar size. Defaults to 40
+ * @uses bbp_get_topic_author_avatar() To get the topic author avatar
+ */
+function bbp_topic_author_avatar( $topic_id = 0, $size = 40 ) {
+	echo bbp_get_topic_author_avatar( $topic_id, $size );
+}
+	/**
+	 * Return the author avatar of the topic
+	 *
+	 * @since bbPress (r2590)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @param int $size Optional. Avatar size. Defaults to 40
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_is_topic_anonymous() To check if the topic is by an
+	 *                                 anonymous user
+	 * @uses bbp_get_topic_author_id() To get the topic author id
+	 * @uses get_post_meta() To get the anonymous user's email
+	 * @uses get_avatar() To get the avatar
+	 * @uses apply_filters() Calls 'bbp_get_topic_author_avatar' with the
+	 *                        avatar, topic id and size
+	 * @return string Avatar of the author of the topic
+	 */
+	function bbp_get_topic_author_avatar( $topic_id = 0, $size = 40 ) {
+		$author_avatar = '';
+
+		$topic_id = bbp_get_topic_id( $topic_id );
+		if ( !empty( $topic_id ) ) {
+			if ( !bbp_is_topic_anonymous( $topic_id ) ) {
+				$author_avatar = get_avatar( bbp_get_topic_author_id( $topic_id ), $size );
+			} else {
+				$author_avatar = get_avatar( get_post_meta( $topic_id, '_bbp_anonymous_email', true ), $size );
+			}
+		}
+
+		return apply_filters( 'bbp_get_topic_author_avatar', $author_avatar, $topic_id, $size );
+	}
+
+/**
+ * Output the author link of the topic
+ *
+ * @since bbPress (r2717)
+ *
+ * @param mixed|int $args If it is an integer, it is used as topic_id. Optional.
+ * @uses bbp_get_topic_author_link() To get the topic author link
+ */
+function bbp_topic_author_link( $args = '' ) {
+	echo bbp_get_topic_author_link( $args );
+}
+	/**
+	 * Return the author link of the topic
+	 *
+	 * @since bbPress (r2717)
+	 *
+	 * @param mixed|int $args If it is an integer, it is used as topic id.
+	 *                         Optional.
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic_author_display_name() To get the topic author
+	 * @uses bbp_is_topic_anonymous() To check if the topic is by an
+	 *                                 anonymous user
+	 * @uses bbp_get_topic_author_url() To get the topic author url
+	 * @uses bbp_get_topic_author_avatar() To get the topic author avatar
+	 * @uses bbp_get_topic_author_display_name() To get the topic author display
+	 *                                      name
+	 * @uses bbp_get_user_display_role() To get the topic author display role
+	 * @uses bbp_get_topic_author_id() To get the topic author id
+	 * @uses apply_filters() Calls 'bbp_get_topic_author_link' with the link
+	 *                        and args
+	 * @return string Author link of topic
+	 */
+	function bbp_get_topic_author_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'post_id'    => 0,
+			'link_title' => '',
+			'type'       => 'both',
+			'size'       => 80,
+			'sep'        => '&nbsp;',
+			'show_role'  => false
+		), 'get_topic_author_link' );
+
+		// Used as topic_id
+		if ( is_numeric( $args ) ) {
+			$topic_id = bbp_get_topic_id( $args );
+		} else {
+			$topic_id = bbp_get_topic_id( $r['post_id'] );
+		}
+
+		// Topic ID is good
+		if ( !empty( $topic_id ) ) {
+
+			// Get some useful topic information
+			$author_url = bbp_get_topic_author_url( $topic_id );
+			$anonymous  = bbp_is_topic_anonymous( $topic_id );
+
+			// Tweak link title if empty
+			if ( empty( $r['link_title'] ) ) {
+				$link_title = sprintf( empty( $anonymous ) ? __( 'View %s\'s profile', 'bbpress' ) : __( 'Visit %s\'s website', 'bbpress' ), bbp_get_topic_author_display_name( $topic_id ) );
+
+			// Use what was passed if not
+			} else {
+				$link_title = $r['link_title'];
+			}
+
+			// Setup title and author_links array
+			$link_title   = !empty( $link_title ) ? ' title="' . esc_attr( $link_title ) . '"' : '';
+			$author_links = array();
+
+			// Get avatar
+			if ( 'avatar' === $r['type'] || 'both' === $r['type'] ) {
+				$author_links['avatar'] = bbp_get_topic_author_avatar( $topic_id, $r['size'] );
+			}
+
+			// Get display name
+			if ( 'name' === $r['type'] || 'both' === $r['type'] ) {
+				$author_links['name'] = bbp_get_topic_author_display_name( $topic_id );
+			}
+
+			// Link class
+			$link_class = ' class="bbp-author-' . esc_attr( $r['type'] ) . '"';
+
+			// Add links if not anonymous
+			if ( empty( $anonymous ) && bbp_user_has_profile( bbp_get_topic_author_id( $topic_id ) ) ) {
+
+				// Assemble the links
+				foreach ( $author_links as $link => $link_text ) {
+					$link_class = ' class="bbp-author-' . esc_attr( $link ) . '"';
+					$author_link[] = sprintf( '<a href="%1$s"%2$s%3$s>%4$s</a>', esc_url( $author_url ), $link_title, $link_class, $link_text );
+				}
+
+				if ( true === $r['show_role'] ) {
+					$author_link[] = bbp_get_topic_author_role( array( 'topic_id' => $topic_id ) );
+				}
+
+				$author_link = implode( $r['sep'], $author_link );
+
+			// No links if anonymous
+			} else {
+				$author_link = implode( $r['sep'], $author_links );
+			}
+
+		} else {
+			$author_link = '';
+		}
+
+		return apply_filters( 'bbp_get_topic_author_link', $author_link, $args );
+	}
+
+/**
+ * Output the author url of the topic
+ *
+ * @since bbPress (r2590)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_author_url() To get the topic author url
+ */
+function bbp_topic_author_url( $topic_id = 0 ) {
+	echo esc_url( bbp_get_topic_author_url( $topic_id ) );
+}
+
+	/**
+	 * Return the author url of the topic
+	 *
+	 * @since bbPress (r2590)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_is_topic_anonymous() To check if the topic is by an anonymous
+	 *                                 user or not
+	 * @uses bbp_user_has_profile() To check if the user has a profile
+	 * @uses bbp_get_topic_author_id() To get topic author id
+	 * @uses bbp_get_user_profile_url() To get profile url
+	 * @uses get_post_meta() To get anonmous user's website
+	 * @uses apply_filters() Calls 'bbp_get_topic_author_url' with the link &
+	 *                        topic id
+	 * @return string Author URL of topic
+	 */
+	function bbp_get_topic_author_url( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Check for anonymous user or non-existant user
+		if ( !bbp_is_topic_anonymous( $topic_id ) && bbp_user_has_profile( bbp_get_topic_author_id( $topic_id ) ) ) {
+			$author_url = bbp_get_user_profile_url( bbp_get_topic_author_id( $topic_id ) );
+		} else {
+			$author_url = get_post_meta( $topic_id, '_bbp_anonymous_website', true );
+
+			// Set empty author_url as empty string
+			if ( empty( $author_url ) ) {
+				$author_url = '';
+			}
+		}
+
+		return apply_filters( 'bbp_get_topic_author_url', $author_url, $topic_id );
+	}
+
+/**
+ * Output the topic author email address
+ *
+ * @since bbPress (r3445)
+ *
+ * @param int $topic_id Optional. Reply id
+ * @uses bbp_get_topic_author_email() To get the topic author email
+ */
+function bbp_topic_author_email( $topic_id = 0 ) {
+	echo bbp_get_topic_author_email( $topic_id );
+}
+	/**
+	 * Return the topic author email address
+	 *
+	 * @since bbPress (r3445)
+	 *
+	 * @param int $topic_id Optional. Reply id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_is_topic_anonymous() To check if the topic is by an anonymous
+	 *                                 user
+	 * @uses bbp_get_topic_author_id() To get the topic author id
+	 * @uses get_userdata() To get the user data
+	 * @uses get_post_meta() To get the anonymous poster's email
+	 * @uses apply_filters() Calls bbp_get_topic_author_email with the author
+	 *                        email & topic id
+	 * @return string Topic author email address
+	 */
+	function bbp_get_topic_author_email( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Not anonymous user
+		if ( !bbp_is_topic_anonymous( $topic_id ) ) {
+
+			// Use topic author email address
+			$user_id      = bbp_get_topic_author_id( $topic_id );
+			$user         = get_userdata( $user_id );
+			$author_email = !empty( $user->user_email ) ? $user->user_email : '';
+
+		// Anonymous
+		} else {
+
+			// Get email from post meta
+			$author_email = get_post_meta( $topic_id, '_bbp_anonymous_email', true );
+
+			// Sanity check for missing email address
+			if ( empty( $author_email ) ) {
+				$author_email = '';
+			}
+		}
+
+		return apply_filters( 'bbp_get_topic_author_email', $author_email, $topic_id );
+	}
+
+/**
+ * Output the topic author role
+ *
+ * @since bbPress (r3860)
+ *
+ * @param array $args Optional.
+ * @uses bbp_get_topic_author_role() To get the topic author role
+ */
+function bbp_topic_author_role( $args = array() ) {
+	echo bbp_get_topic_author_role( $args );
+}
+	/**
+	 * Return the topic author role
+	 *
+	 * @since bbPress (r3860)
+	 *
+	 * @param array $args Optional.
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_user_display_role() To get the user display role
+	 * @uses bbp_get_topic_author_id() To get the topic author id
+	 * @uses apply_filters() Calls bbp_get_topic_author_role with the author
+	 *                        role & args
+	 * @return string topic author role
+	 */
+	function bbp_get_topic_author_role( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'topic_id' => 0,
+			'class'    => 'bbp-author-role',
+			'before'   => '',
+			'after'    => ''
+		), 'get_topic_author_role' );
+
+		$topic_id    = bbp_get_topic_id( $r['topic_id'] );
+		$role        = bbp_get_user_display_role( bbp_get_topic_author_id( $topic_id ) );
+		$author_role = sprintf( '%1$s<div class="%2$s">%3$s</div>%4$s', $r['before'], $r['class'], $role, $r['after'] );
+
+		return apply_filters( 'bbp_get_topic_author_role', $author_role, $r );
+	}
+
+
+/**
+ * Output the title of the forum a topic belongs to
+ *
+ * @since bbPress (r2485)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_forum_title() To get the topic's forum title
+ */
+function bbp_topic_forum_title( $topic_id = 0 ) {
+	echo bbp_get_topic_forum_title( $topic_id );
+}
+	/**
+	 * Return the title of the forum a topic belongs to
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get topic id
+	 * @uses bbp_get_topic_forum_id() To get topic's forum id
+	 * @uses apply_filters() Calls 'bbp_get_topic_forum' with the forum
+	 *                        title and topic id
+	 * @return string Topic forum title
+	 */
+	function bbp_get_topic_forum_title( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$forum_id = bbp_get_topic_forum_id( $topic_id );
+
+		return apply_filters( 'bbp_get_topic_forum', bbp_get_forum_title( $forum_id ), $topic_id, $forum_id );
+	}
+
+/**
+ * Output the forum id a topic belongs to
+ *
+ * @since bbPress (r2491)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_forum_id()
+ */
+function bbp_topic_forum_id( $topic_id = 0 ) {
+	echo bbp_get_topic_forum_id( $topic_id );
+}
+	/**
+	 * Return the forum id a topic belongs to
+	 *
+	 * @since bbPress (r2491)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get topic id
+	 * @uses get_post_meta() To retrieve get topic's forum id meta
+	 * @uses apply_filters() Calls 'bbp_get_topic_forum_id' with the forum
+	 *                        id and topic id
+	 * @return int Topic forum id
+	 */
+	function bbp_get_topic_forum_id( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$forum_id = get_post_meta( $topic_id, '_bbp_forum_id', true );
+
+		return (int) apply_filters( 'bbp_get_topic_forum_id', (int) $forum_id, $topic_id );
+	}
+
+/**
+ * Output the topics last active ID
+ *
+ * @since bbPress (r2860)
+ *
+ * @param int $topic_id Optional. Forum id
+ * @uses bbp_get_topic_last_active_id() To get the topic's last active id
+ */
+function bbp_topic_last_active_id( $topic_id = 0 ) {
+	echo bbp_get_topic_last_active_id( $topic_id );
+}
+	/**
+	 * Return the topics last active ID
+	 *
+	 * @since bbPress (r2860)
+	 *
+	 * @param int $topic_id Optional. Forum id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_meta() To get the topic's last active id
+	 * @uses apply_filters() Calls 'bbp_get_topic_last_active_id' with
+	 *                        the last active id and topic id
+	 * @return int Forum's last active id
+	 */
+	function bbp_get_topic_last_active_id( $topic_id = 0 ) {
+		$topic_id  = bbp_get_topic_id( $topic_id );
+		$active_id = get_post_meta( $topic_id, '_bbp_last_active_id', true );
+
+		return (int) apply_filters( 'bbp_get_topic_last_active_id', (int) $active_id, $topic_id );
+	}
+
+/**
+ * Output the topics last update date/time (aka freshness)
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_last_active_time() To get topic freshness
+ */
+function bbp_topic_last_active_time( $topic_id = 0 ) {
+	echo bbp_get_topic_last_active_time( $topic_id );
+}
+	/**
+	 * Return the topics last update date/time (aka freshness)
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get topic id
+	 * @uses get_post_meta() To get the topic lst active meta
+	 * @uses bbp_get_topic_last_reply_id() To get topic last reply id
+	 * @uses get_post_field() To get the post date of topic/reply
+	 * @uses bbp_convert_date() To convert date
+	 * @uses bbp_get_time_since() To get time in since format
+	 * @uses apply_filters() Calls 'bbp_get_topic_last_active' with topic
+	 *                        freshness and topic id
+	 * @return string Topic freshness
+	 */
+	function bbp_get_topic_last_active_time( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Try to get the most accurate freshness time possible
+		$last_active = get_post_meta( $topic_id, '_bbp_last_active_time', true );
+		if ( empty( $last_active ) ) {
+			$reply_id = bbp_get_topic_last_reply_id( $topic_id );
+			if ( !empty( $reply_id ) ) {
+				$last_active = get_post_field( 'post_date', $reply_id );
+			} else {
+				$last_active = get_post_field( 'post_date', $topic_id );
+			}
+		}
+
+		$last_active = !empty( $last_active ) ? bbp_get_time_since( bbp_convert_date( $last_active ) ) : '';
+
+		// Return the time since
+		return apply_filters( 'bbp_get_topic_last_active', $last_active, $topic_id );
+	}
+
+/** Topic Subscriptions *******************************************************/
+
+/**
+ * Output the topic subscription link
+ *
+ * @since bbPress (r5156)
+ *
+ * @uses bbp_get_topic_subscription_link()
+ */
+function bbp_topic_subscription_link( $args = array() ) {
+	echo bbp_get_topic_subscription_link( $args );
+}
+
+	/**
+	 * Get the forum subscription link
+	 *
+	 * A custom wrapper for bbp_get_user_subscribe_link()
+	 *
+	 * @since bbPress (r5156)
+	 *
+	 * @uses bbp_parse_args()
+	 * @uses bbp_get_user_subscribe_link()
+	 * @uses apply_filters() Calls 'bbp_get_topic_subscribe_link'
+	 */
+	function bbp_get_topic_subscription_link( $args = array() ) {
+
+		// No link
+		$retval = false;
+
+		// Parse the arguments
+		$r = bbp_parse_args( $args, array(
+			'user_id'     => 0,
+			'topic_id'    => 0,
+			'before'      => '&nbsp;|&nbsp;',
+			'after'       => '',
+			'subscribe'   => __( 'Subscribe',   'bbpress' ),
+			'unsubscribe' => __( 'Unsubscribe', 'bbpress' )
+		), 'get_forum_subscribe_link' );
+
+		// Get the link
+		$retval = bbp_get_user_subscribe_link( $r );
+
+		return apply_filters( 'bbp_get_topic_subscribe_link', $retval, $r );
+	}
+
+/** Topic Favorites ***********************************************************/
+
+/**
+ * Output the topic favorite link
+ *
+ * @since bbPress (r5156)
+ *
+ * @uses bbp_get_topic_favorite_link()
+ */
+function bbp_topic_favorite_link( $args = array() ) {
+	echo bbp_get_topic_favorite_link( $args );
+}
+
+	/**
+	 * Get the forum favorite link
+	 *
+	 * A custom wrapper for bbp_get_user_favorite_link()
+	 *
+	 * @since bbPress (r5156)
+	 *
+	 * @uses bbp_parse_args()
+	 * @uses bbp_get_user_favorites_link()
+	 * @uses apply_filters() Calls 'bbp_get_topic_favorite_link'
+	 */
+	function bbp_get_topic_favorite_link( $args = array() ) {
+
+		// No link
+		$retval = false;
+
+		// Parse the arguments
+		$r = bbp_parse_args( $args, array(
+			'user_id'   => 0,
+			'topic_id'  => 0,
+			'before'    => '',
+			'after'     => '',
+			'favorite'  => __( 'Favorite',   'bbpress' ),
+			'favorited' => __( 'Unfavorite', 'bbpress' )
+		), 'get_forum_favorite_link' );
+
+		// Get the link
+		$retval = bbp_get_user_favorites_link( $r );
+
+		return apply_filters( 'bbp_get_topic_favorite_link', $retval, $r );
+	}
+
+/** Topic Last Reply **********************************************************/
+
+/**
+ * Output the id of the topics last reply
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_last_reply_id() To get the topic last reply id
+ */
+function bbp_topic_last_reply_id( $topic_id = 0 ) {
+	echo bbp_get_topic_last_reply_id( $topic_id );
+}
+	/**
+	 * Return the topics last update date/time (aka freshness)
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_meta() To get the last reply id meta
+	 * @uses apply_filters() Calls 'bbp_get_topic_last_reply_id' with the
+	 *                        last reply id and topic id
+	 * @return int Topic last reply id
+	 */
+	function bbp_get_topic_last_reply_id( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$reply_id = get_post_meta( $topic_id, '_bbp_last_reply_id', true );
+
+		if ( empty( $reply_id ) )
+			$reply_id = $topic_id;
+
+		return (int) apply_filters( 'bbp_get_topic_last_reply_id', (int) $reply_id, $topic_id );
+	}
+
+/**
+ * Output the title of the last reply inside a topic
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_last_reply_title() To get the topic last reply title
+ */
+function bbp_topic_last_reply_title( $topic_id = 0 ) {
+	echo bbp_get_topic_last_reply_title( $topic_id );
+}
+	/**
+	 * Return the title of the last reply inside a topic
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic_last_reply_id() To get the topic last reply id
+	 * @uses bbp_get_reply_title() To get the reply title
+	 * @uses apply_filters() Calls 'bbp_get_topic_last_topic_title' with
+	 *                        the reply title and topic id
+	 * @return string Topic last reply title
+	 */
+	function bbp_get_topic_last_reply_title( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		return apply_filters( 'bbp_get_topic_last_topic_title', bbp_get_reply_title( bbp_get_topic_last_reply_id( $topic_id ) ), $topic_id );
+	}
+
+/**
+ * Output the link to the last reply in a topic
+ *
+ * @since bbPress (r2464)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_last_reply_permalink() To get the topic's last reply link
+ */
+function bbp_topic_last_reply_permalink( $topic_id = 0 ) {
+	echo esc_url( bbp_get_topic_last_reply_permalink( $topic_id ) );
+}
+	/**
+	 * Return the link to the last reply in a topic
+	 *
+	 * @since bbPress (r2464)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic_last_reply_id() To get the topic last reply id
+	 * @uses bbp_get_reply_permalink() To get the reply permalink
+	 * @uses apply_filters() Calls 'bbp_get_topic_last_topic_permalink' with
+	 *                        the reply permalink and topic id
+	 * @return string Permanent link to the reply
+	 */
+	function bbp_get_topic_last_reply_permalink( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		return apply_filters( 'bbp_get_topic_last_reply_permalink', bbp_get_reply_permalink( bbp_get_topic_last_reply_id( $topic_id ) ) );
+	}
+
+/**
+ * Output the link to the last reply in a topic
+ *
+ * @since bbPress (r2683)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_last_reply_url() To get the topic last reply url
+ */
+function bbp_topic_last_reply_url( $topic_id = 0 ) {
+	echo esc_url( bbp_get_topic_last_reply_url( $topic_id ) );
+}
+	/**
+	 * Return the link to the last reply in a topic
+	 *
+	 * @since bbPress (r2683)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic_last_reply_id() To get the topic last reply id
+	 * @uses bbp_get_reply_url() To get the reply url
+	 * @uses bbp_get_reply_permalink() To get the reply permalink
+	 * @uses apply_filters() Calls 'bbp_get_topic_last_topic_url' with
+	 *                        the reply url and topic id
+	 * @return string Topic last reply url
+	 */
+	function bbp_get_topic_last_reply_url( $topic_id = 0 ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$reply_id = bbp_get_topic_last_reply_id( $topic_id );
+
+		if ( !empty( $reply_id ) && ( $reply_id !== $topic_id ) ) {
+			$reply_url = bbp_get_reply_url( $reply_id );
+		} else {
+			$reply_url = bbp_get_topic_permalink( $topic_id );
+		}
+
+		return apply_filters( 'bbp_get_topic_last_reply_url', $reply_url );
+	}
+
+/**
+ * Output link to the most recent activity inside a topic, complete with link
+ * attributes and content.
+ *
+ * @since bbPress (r2625)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_freshness_link() To get the topic freshness link
+ */
+function bbp_topic_freshness_link( $topic_id = 0 ) {
+	echo bbp_get_topic_freshness_link( $topic_id );
+}
+	/**
+	 * Returns link to the most recent activity inside a topic, complete
+	 * with link attributes and content.
+	 *
+	 * @since bbPress (r2625)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic_last_reply_url() To get the topic last reply url
+	 * @uses bbp_get_topic_last_reply_title() To get the reply title
+	 * @uses bbp_get_topic_last_active_time() To get the topic freshness
+	 * @uses apply_filters() Calls 'bbp_get_topic_freshness_link' with the
+	 *                        link and topic id
+	 * @return string Topic freshness link
+	 */
+	function bbp_get_topic_freshness_link( $topic_id = 0 ) {
+		$topic_id   = bbp_get_topic_id( $topic_id );
+		$link_url   = bbp_get_topic_last_reply_url( $topic_id );
+		$title      = bbp_get_topic_last_reply_title( $topic_id );
+		$time_since = bbp_get_topic_last_active_time( $topic_id );
+
+		if ( !empty( $time_since ) )
+			$anchor = '<a href="' . esc_url( $link_url ) . '" title="' . esc_attr( $title ) . '">' . esc_html( $time_since ) . '</a>';
+		else
+			$anchor = __( 'No Replies', 'bbpress' );
+
+		return apply_filters( 'bbp_get_topic_freshness_link', $anchor, $topic_id, $time_since, $link_url, $title );
+	}
+
+/**
+ * Output the replies link of the topic
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_replies_link() To get the topic replies link
+ */
+function bbp_topic_replies_link( $topic_id = 0 ) {
+	echo bbp_get_topic_replies_link( $topic_id );
+}
+
+	/**
+	 * Return the replies link of the topic
+	 *
+	 * @since bbPress (r2740)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses bbp_get_topic_reply_count() To get the topic reply count
+	 * @uses bbp_get_topic_permalink() To get the topic permalink
+	 * @uses remove_query_arg() To remove args from the url
+	 * @uses bbp_get_topic_reply_count_hidden() To get the topic hidden
+	 *                                           reply count
+	 * @uses current_user_can() To check if the current user can edit others
+	 *                           replies
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_replies_link' with the
+	 *                        replies link and topic id
+	 */
+	function bbp_get_topic_replies_link( $topic_id = 0 ) {
+
+		$topic    = bbp_get_topic( bbp_get_topic_id( (int) $topic_id ) );
+		$topic_id = $topic->ID;
+		$replies  = sprintf( _n( '%s reply', '%s replies', bbp_get_topic_reply_count( $topic_id, true ), 'bbpress' ), bbp_get_topic_reply_count( $topic_id ) );
+		$retval   = '';
+
+		// First link never has view=all
+		if ( bbp_get_view_all( 'edit_others_replies' ) )
+			$retval .= "<a href='" . esc_url( bbp_remove_view_all( bbp_get_topic_permalink( $topic_id ) ) ) . "'>$replies</a>";
+		else
+			$retval .= $replies;
+
+		// Any deleted replies?
+		$deleted = bbp_get_topic_reply_count_hidden( $topic_id );
+
+		// This forum has hidden topics
+		if ( !empty( $deleted ) && current_user_can( 'edit_others_replies' ) ) {
+
+			// Extra text
+			$extra = sprintf( __( ' (+ %d hidden)', 'bbpress' ), $deleted );
+
+			// No link
+			if ( bbp_get_view_all() ) {
+				$retval .= " $extra";
+
+			// Link
+			} else {
+				$retval .= " <a href='" . esc_url( bbp_add_view_all( bbp_get_topic_permalink( $topic_id ), true ) ) . "'>$extra</a>";
+			}
+		}
+
+		return apply_filters( 'bbp_get_topic_replies_link', $retval, $topic_id );
+	}
+
+/**
+ * Output total reply count of a topic
+ *
+ * @since bbPress (r2485)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_topic_reply_count() To get the topic reply count
+ */
+function bbp_topic_reply_count( $topic_id = 0, $integer = false ) {
+	echo bbp_get_topic_reply_count( $topic_id, $integer );
+}
+	/**
+	 * Return total reply count of a topic
+	 *
+	 * @since bbPress (r2485)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_meta() To get the topic reply count meta
+	 * @uses apply_filters() Calls 'bbp_get_topic_reply_count' with the
+	 *                        reply count and topic id
+	 * @return int Reply count
+	 */
+	function bbp_get_topic_reply_count( $topic_id = 0, $integer = false ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$replies  = (int) get_post_meta( $topic_id, '_bbp_reply_count', true );
+		$filter   = ( true === $integer ) ? 'bbp_get_topic_reply_count_int' : 'bbp_get_topic_reply_count';
+
+		return apply_filters( $filter, $replies, $topic_id );
+	}
+
+/**
+ * Output total post count of a topic
+ *
+ * @since bbPress (r2954)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_topic_post_count() To get the topic post count
+ */
+function bbp_topic_post_count( $topic_id = 0, $integer = false ) {
+	echo bbp_get_topic_post_count( $topic_id, $integer );
+}
+	/**
+	 * Return total post count of a topic
+	 *
+	 * @since bbPress (r2954)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_meta() To get the topic post count meta
+	 * @uses apply_filters() Calls 'bbp_get_topic_post_count' with the
+	 *                        post count and topic id
+	 * @return int Post count
+	 */
+	function bbp_get_topic_post_count( $topic_id = 0, $integer = false ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$replies  = (int) get_post_meta( $topic_id, '_bbp_reply_count', true ) + 1;
+		$filter   = ( true === $integer ) ? 'bbp_get_topic_post_count_int' : 'bbp_get_topic_post_count';
+
+		return apply_filters( $filter, $replies, $topic_id );
+	}
+
+/**
+ * Output total hidden reply count of a topic (hidden includes trashed and
+ * spammed replies)
+ *
+ * @since bbPress (r2740)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_topic_reply_count_hidden() To get the topic hidden reply count
+ */
+function bbp_topic_reply_count_hidden( $topic_id = 0, $integer = false ) {
+	echo bbp_get_topic_reply_count_hidden( $topic_id, $integer );
+}
+	/**
+	 * Return total hidden reply count of a topic (hidden includes trashed
+	 * and spammed replies)
+	 *
+	 * @since bbPress (r2740)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_meta() To get the hidden reply count
+	 * @uses apply_filters() Calls 'bbp_get_topic_reply_count_hidden' with
+	 *                        the hidden reply count and topic id
+	 * @return int Topic hidden reply count
+	 */
+	function bbp_get_topic_reply_count_hidden( $topic_id = 0, $integer = false ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$replies  = (int) get_post_meta( $topic_id, '_bbp_reply_count_hidden', true );
+		$filter   = ( true === $integer ) ? 'bbp_get_topic_reply_count_hidden_int' : 'bbp_get_topic_reply_count_hidden';
+
+		return apply_filters( $filter, $replies, $topic_id );
+	}
+
+/**
+ * Output total voice count of a topic
+ *
+ * @since bbPress (r2567)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_voice_count() To get the topic voice count
+ */
+function bbp_topic_voice_count( $topic_id = 0, $integer = false ) {
+	echo bbp_get_topic_voice_count( $topic_id, $integer );
+}
+	/**
+	 * Return total voice count of a topic
+	 *
+	 * @since bbPress (r2567)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_post_meta() To get the voice count meta
+	 * @uses apply_filters() Calls 'bbp_get_topic_voice_count' with the
+	 *                        voice count and topic id
+	 * @return int Voice count of the topic
+	 */
+	function bbp_get_topic_voice_count( $topic_id = 0, $integer = false ) {
+		$topic_id = bbp_get_topic_id( $topic_id );
+		$voices   = (int) get_post_meta( $topic_id, '_bbp_voice_count', true );
+		$filter   = ( true === $integer ) ? 'bbp_get_topic_voice_count_int' : 'bbp_get_topic_voice_count';
+
+		return apply_filters( $filter, $voices, $topic_id );
+	}
+
+/**
+ * Output a the tags of a topic
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param mixed $args See {@link bbp_get_topic_tag_list()}
+ * @uses bbp_get_topic_tag_list() To get the topic tag list
+ */
+function bbp_topic_tag_list( $topic_id = 0, $args = '' ) {
+	echo bbp_get_topic_tag_list( $topic_id, $args );
+}
+	/**
+	 * Return the tags of a topic
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @param array $args This function supports these arguments:
+	 *  - before: Before the tag list
+	 *  - sep: Tag separator
+	 *  - after: After the tag list
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses get_the_term_list() To get the tags list
+	 * @return string Tag list of the topic
+	 */
+	function bbp_get_topic_tag_list( $topic_id = 0, $args = '' ) {
+
+		// Bail if topic-tags are off
+		if ( ! bbp_allow_topic_tags() )
+			return;
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'before' => '<div class="bbp-topic-tags"><p>' . esc_html__( 'Tagged:', 'bbpress' ) . '&nbsp;',
+			'sep'    => ', ',
+			'after'  => '</p></div>'
+		), 'get_topic_tag_list' );
+
+		$topic_id = bbp_get_topic_id( $topic_id );
+
+		// Topic is spammed, so display pre-spam terms
+		if ( bbp_is_topic_spam( $topic_id ) ) {
+
+			// Get pre-spam terms
+			$terms = get_post_meta( $topic_id, '_bbp_spam_topic_tags', true );
+
+			// If terms exist, explode them and compile the return value
+			if ( !empty( $terms ) ) {
+				$terms  = implode( $r['sep'], $terms );
+				$retval = $r['before'] . $terms . $r['after'];
+
+			// No terms so return emty string
+			} else {
+				$retval = '';
+			}
+
+		// Topic is not spam so display a clickable term list
+		} else {
+			$retval = get_the_term_list( $topic_id, bbp_get_topic_tag_tax_id(), $r['before'], $r['sep'], $r['after'] );
+		}
+
+		return $retval;
+	}
+
+/**
+ * Output the row class of a topic
+ *
+ * @since bbPress (r2667)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @param array Extra classes you can pass when calling this function
+ * @uses bbp_get_topic_class() To get the topic class
+ */
+function bbp_topic_class( $topic_id = 0, $classes = array() ) {
+	echo bbp_get_topic_class( $topic_id, $classes );
+}
+	/**
+	 * Return the row class of a topic
+	 *
+	 * @since bbPress (r2667)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @param array Extra classes you can pass when calling this function
+	 * @uses bbp_is_topic_sticky() To check if the topic is a sticky
+	 * @uses bbp_is_topic_super_sticky() To check if the topic is a super sticky
+	 * @uses bbp_get_topic_forum_id() To get the topic forum id
+	 * @uses get_post_class() To get the topic classes
+	 * @uses apply_filters() Calls 'bbp_get_topic_class' with the classes
+	 *                        and topic id
+	 * @return string Row class of a topic
+	 */
+	function bbp_get_topic_class( $topic_id = 0, $classes = array() ) {
+		$bbp       = bbpress();
+		$topic_id  = bbp_get_topic_id( $topic_id );
+		$count     = isset( $bbp->topic_query->current_post ) ? $bbp->topic_query->current_post : 1;
+		$classes   = (array) $classes;
+		$classes[] = ( (int) $count % 2 )                    ? 'even'         : 'odd';
+		$classes[] = bbp_is_topic_sticky( $topic_id, false ) ? 'sticky'       : '';
+		$classes[] = bbp_is_topic_super_sticky( $topic_id  ) ? 'super-sticky' : '';
+		$classes[] = 'bbp-parent-forum-' . bbp_get_topic_forum_id( $topic_id );
+		$classes[] = 'user-id-' . bbp_get_topic_author_id( $topic_id );
+		$classes   = array_filter( $classes );
+		$classes   = get_post_class( $classes, $topic_id );
+		$classes   = apply_filters( 'bbp_get_topic_class', $classes, $topic_id );
+		$retval    = 'class="' . implode( ' ', $classes ) . '"';
+
+		return $retval;
+	}
+
+/** Topic Admin Links *********************************************************/
+
+/**
+ * Output admin links for topic
+ *
+ * @param array $args See {@link bbp_get_topic_admin_links()}
+ * @uses bbp_get_topic_admin_links() To get the topic admin links
+ */
+function bbp_topic_admin_links( $args = array() ) {
+	echo bbp_get_topic_admin_links( $args );
+}
+	/**
+	 * Return admin links for topic.
+	 *
+	 * Move topic functionality is handled by the edit topic page.
+	 *
+	 * @param array $args This function supports these arguments:
+	 *  - id: Optional. Topic id
+	 *  - before: Before the links
+	 *  - after: After the links
+	 *  - sep: Links separator
+	 *  - links: Topic admin links array
+	 * @uses current_user_can() To check if the current user can edit/delete
+	 *                           the topic
+	 * @uses bbp_get_topic_edit_link() To get the topic edit link
+	 * @uses bbp_get_topic_trash_link() To get the topic trash link
+	 * @uses bbp_get_topic_close_link() To get the topic close link
+	 * @uses bbp_get_topic_spam_link() To get the topic spam link
+	 * @uses bbp_get_topic_stick_link() To get the topic stick link
+	 * @uses bbp_get_topic_merge_link() To get the topic merge link
+	 * @uses bbp_get_topic_status() To get the topic status
+	 * @uses apply_filters() Calls 'bbp_get_topic_admin_links' with the
+	 *                        topic admin links and args
+	 * @return string Topic admin links
+	 */
+	function bbp_get_topic_admin_links( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array (
+			'id'     => bbp_get_topic_id(),
+			'before' => '<span class="bbp-admin-links">',
+			'after'  => '</span>',
+			'sep'    => ' | ',
+			'links'  => array()
+		), 'get_topic_admin_links' );
+
+		if ( empty( $r['links'] ) ) {
+			$r['links'] = apply_filters( 'bbp_topic_admin_links', array(
+				'edit'  => bbp_get_topic_edit_link ( $r ),
+				'close' => bbp_get_topic_close_link( $r ),
+				'stick' => bbp_get_topic_stick_link( $r ),
+				'merge' => bbp_get_topic_merge_link( $r ),
+				'trash' => bbp_get_topic_trash_link( $r ),
+				'spam'  => bbp_get_topic_spam_link ( $r ),
+				'reply' => bbp_get_topic_reply_link( $r )
+			), $r['id'] );
+		}
+
+		// See if links need to be unset
+		$topic_status = bbp_get_topic_status( $r['id'] );
+		if ( in_array( $topic_status, array( bbp_get_spam_status_id(), bbp_get_trash_status_id() ) ) ) {
+
+			// Close link shouldn't be visible on trashed/spammed topics
+			unset( $r['links']['close'] );
+
+			// Spam link shouldn't be visible on trashed topics
+			if ( bbp_get_trash_status_id() === $topic_status ) {
+				unset( $r['links']['spam'] );
+
+			// Trash link shouldn't be visible on spam topics
+			} elseif ( bbp_get_spam_status_id() === $topic_status ) {
+				unset( $r['links']['trash'] );
+			}
+		}
+
+		// Process the admin links
+		$links  = implode( $r['sep'], array_filter( $r['links'] ) );
+		$retval = $r['before'] . $links . $r['after'];
+
+		return apply_filters( 'bbp_get_topic_admin_links', $retval, $r, $args );
+	}
+
+/**
+ * Output the edit link of the topic
+ *
+ * @since bbPress (r2727)
+ *
+ * @param mixed $args See {@link bbp_get_topic_edit_link()}
+ * @uses bbp_get_topic_edit_link() To get the topic edit link
+ */
+function bbp_topic_edit_link( $args = '' ) {
+	echo bbp_get_topic_edit_link( $args );
+}
+
+	/**
+	 * Return the edit link of the topic
+	 *
+	 * @since bbPress (r2727)
+	 *
+	 * @param mixed $args This function supports these args:
+	 *  - id: Optional. Topic id
+	 *  - link_before: Before the link
+	 *  - link_after: After the link
+	 *  - edit_text: Edit text
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses current_user_can() To check if the current user can edit the
+	 *                           topic
+	 * @uses bbp_get_topic_edit_url() To get the topic edit url
+	 * @uses apply_filters() Calls 'bbp_get_topic_edit_link' with the link
+	 *                        and args
+	 * @return string Topic edit link
+	 */
+	function bbp_get_topic_edit_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'edit_text'    => esc_html__( 'Edit', 'bbpress' )
+		), 'get_topic_edit_link' );
+
+		$topic = bbp_get_topic( bbp_get_topic_id( (int) $r['id'] ) );
+
+		// Bypass check if user has caps
+		if ( !current_user_can( 'edit_others_topics' ) ) {
+
+			// User cannot edit or it is past the lock time
+			if ( empty( $topic ) || !current_user_can( 'edit_topic', $topic->ID ) || bbp_past_edit_lock( $topic->post_date_gmt ) ) {
+				return;
+			}
+		}
+
+		// Get uri
+		$uri = bbp_get_topic_edit_url( $r['id'] );
+
+		// Bail if no uri
+		if ( empty( $uri ) )
+			return;
+
+		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-edit-link">' . $r['edit_text'] . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_edit_link', $retval, $r );
+	}
+
+/**
+ * Output URL to the topic edit page
+ *
+ * @since bbPress (r2753)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_topic_edit_url() To get the topic edit url
+ */
+function bbp_topic_edit_url( $topic_id = 0 ) {
+	echo esc_url( bbp_get_topic_edit_url( $topic_id ) );
+}
+	/**
+	 * Return URL to the topic edit page
+	 *
+	 * @since bbPress (r2753)
+	 *
+	 * @param int $topic_id Optional. Topic id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_edit_url' with the edit
+	 *                        url and topic id
+	 * @return string Topic edit url
+	 */
+	function bbp_get_topic_edit_url( $topic_id = 0 ) {
+		global $wp_rewrite;
+
+		$bbp = bbpress();
+
+		$topic = bbp_get_topic( bbp_get_topic_id( $topic_id ) );
+		if ( empty( $topic ) )
+			return;
+
+		// Remove view=all link from edit
+		$topic_link = bbp_remove_view_all( bbp_get_topic_permalink( $topic_id ) );
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url = trailingslashit( $topic_link ) . $bbp->edit_id;
+			$url = trailingslashit( $url );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array( bbp_get_topic_post_type() => $topic->post_name, $bbp->edit_id => '1' ), $topic_link );
+		}
+
+		// Maybe add view=all
+		$url = bbp_add_view_all( $url );
+
+		return apply_filters( 'bbp_get_topic_edit_url', $url, $topic_id );
+	}
+
+/**
+ * Output the trash link of the topic
+ *
+ * @since bbPress (r2727)
+ *
+ * @param mixed $args See {@link bbp_get_topic_trash_link()}
+ * @uses bbp_get_topic_trash_link() To get the topic trash link
+ */
+function bbp_topic_trash_link( $args = '' ) {
+	echo bbp_get_topic_trash_link( $args );
+}
+
+	/**
+	 * Return the trash link of the topic
+	 *
+	 * @since bbPress (r2727)
+	 *
+	 * @param mixed $args This function supports these args:
+	 *  - id: Optional. Topic id
+	 *  - link_before: Before the link
+	 *  - link_after: After the link
+	 *  - sep: Links separator
+	 *  - trash_text: Trash text
+	 *  - restore_text: Restore text
+	 *  - delete_text: Delete text
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses current_user_can() To check if the current user can delete the
+	 *                           topic
+	 * @uses bbp_is_topic_trash() To check if the topic is trashed
+	 * @uses bbp_get_topic_status() To get the topic status
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_trash_link' with the link
+	 *                        and args
+	 * @return string Topic trash link
+	 */
+	function bbp_get_topic_trash_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'sep'          => ' | ',
+			'trash_text'   => esc_html__( 'Trash',   'bbpress' ),
+			'restore_text' => esc_html__( 'Restore', 'bbpress' ),
+			'delete_text'  => esc_html__( 'Delete',  'bbpress' )
+		), 'get_topic_trash_link' );
+
+		$actions = array();
+		$topic   = bbp_get_topic( bbp_get_topic_id( (int) $r['id'] ) );
+
+		if ( empty( $topic ) || !current_user_can( 'delete_topic', $topic->ID ) ) {
+			return;
+		}
+
+		if ( bbp_is_topic_trash( $topic->ID ) ) {
+			$actions['untrash'] = '<a title="' . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_topic_trash', 'sub_action' => 'untrash', 'topic_id' => $topic->ID ) ), 'untrash-' . $topic->post_type . '_' . $topic->ID ) ) . '" class="bbp-topic-restore-link">' . $r['restore_text'] . '</a>';
+		} elseif ( EMPTY_TRASH_DAYS ) {
+			$actions['trash']   = '<a title="' . esc_attr__( 'Move this item to the Trash',      'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_topic_trash', 'sub_action' => 'trash',   'topic_id' => $topic->ID ) ), 'trash-'   . $topic->post_type . '_' . $topic->ID ) ) . '" class="bbp-topic-trash-link">'   . $r['trash_text']   . '</a>';
+		}
+
+		if ( bbp_is_topic_trash( $topic->ID ) || !EMPTY_TRASH_DAYS ) {
+			$actions['delete']  = '<a title="' . esc_attr__( 'Delete this item permanently',     'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_topic_trash', 'sub_action' => 'delete',  'topic_id' => $topic->ID ) ), 'delete-'  . $topic->post_type . '_' . $topic->ID ) ) . '" onclick="return confirm(\'' . esc_js( __( 'Are you sure you want to delete that permanently?', 'bbpress' ) ) . '\' );" class="bbp-topic-delete-link">' . $r['delete_text'] . '</a>';
+		}
+
+		// Process the admin links
+		$retval = $r['link_before'] . implode( $r['sep'], $actions ) . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_trash_link', $retval, $r );
+	}
+
+/**
+ * Output the close link of the topic
+ *
+ * @since bbPress (r2727)
+ *
+ * @param mixed $args See {@link bbp_get_topic_close_link()}
+ * @uses bbp_get_topic_close_link() To get the topic close link
+ */
+function bbp_topic_close_link( $args = '' ) {
+	echo bbp_get_topic_close_link( $args );
+}
+
+	/**
+	 * Return the close link of the topic
+	 *
+	 * @since bbPress (r2727)
+	 *
+	 * @param mixed $args This function supports these args:
+	 *  - id: Optional. Topic id
+	 *  - link_before: Before the link
+	 *  - link_after: After the link
+	 *  - close_text: Close text
+	 *  - open_text: Open text
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses current_user_can() To check if the current user can edit the topic
+	 * @uses bbp_is_topic_open() To check if the topic is open
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_close_link' with the link
+	 *                        and args
+	 * @return string Topic close link
+	 */
+	function bbp_get_topic_close_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'          => 0,
+			'link_before' => '',
+			'link_after'  => '',
+			'sep'         => ' | ',
+			'close_text'  => _x( 'Close', 'Topic Status', 'bbpress' ),
+			'open_text'   => _x( 'Open',  'Topic Status', 'bbpress' )
+		), 'get_topic_close_link' );
+
+		$topic = bbp_get_topic( bbp_get_topic_id( (int) $r['id'] ) );
+
+		if ( empty( $topic ) || !current_user_can( 'moderate', $topic->ID ) )
+			return;
+
+		$display = bbp_is_topic_open( $topic->ID ) ? $r['close_text'] : $r['open_text'];
+		$uri     = add_query_arg( array( 'action' => 'bbp_toggle_topic_close', 'topic_id' => $topic->ID ) );
+		$uri     = wp_nonce_url( $uri, 'close-topic_' . $topic->ID );
+		$retval  = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-close-link">' . $display . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_close_link', $retval, $r );
+	}
+
+/**
+ * Output the stick link of the topic
+ *
+ * @since bbPress (r2754)
+ *
+ * @param mixed $args See {@link bbp_get_topic_stick_link()}
+ * @uses bbp_get_topic_stick_link() To get the topic stick link
+ */
+function bbp_topic_stick_link( $args = '' ) {
+	echo bbp_get_topic_stick_link( $args );
+}
+
+	/**
+	 * Return the stick link of the topic
+	 *
+	 * @since bbPress (r2754)
+	 *
+	 * @param mixed $args This function supports these args:
+	 *  - id: Optional. Topic id
+	 *  - link_before: Before the link
+	 *  - link_after: After the link
+	 *  - stick_text: Stick text
+	 *  - unstick_text: Unstick text
+	 *  - super_text: Stick to front text
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses current_user_can() To check if the current user can edit the
+	 *                           topic
+	 * @uses bbp_is_topic_sticky() To check if the topic is a sticky
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_stick_link' with the link
+	 *                        and args
+	 * @return string Topic stick link
+	 */
+	function bbp_get_topic_stick_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'stick_text'   => esc_html__( 'Stick',      'bbpress' ),
+			'unstick_text' => esc_html__( 'Unstick',    'bbpress' ),
+			'super_text'   => esc_html__( '(to front)', 'bbpress' ),
+		), 'get_topic_stick_link' );
+
+		$topic = bbp_get_topic( bbp_get_topic_id( (int) $r['id'] ) );
+
+		if ( empty( $topic ) || !current_user_can( 'moderate', $topic->ID ) )
+			return;
+
+		$is_sticky = bbp_is_topic_sticky( $topic->ID );
+
+		$stick_uri = add_query_arg( array( 'action' => 'bbp_toggle_topic_stick', 'topic_id' => $topic->ID ) );
+		$stick_uri = wp_nonce_url( $stick_uri, 'stick-topic_' . $topic->ID );
+
+		$stick_display = ( true === $is_sticky ) ? $r['unstick_text'] : $r['stick_text'];
+		$stick_display = '<a href="' . esc_url( $stick_uri ) . '" class="bbp-topic-sticky-link">' . $stick_display . '</a>';
+
+		if ( empty( $is_sticky ) ) {
+			$super_uri = add_query_arg( array( 'action' => 'bbp_toggle_topic_stick', 'topic_id' => $topic->ID, 'super' => 1 ) );
+			$super_uri = wp_nonce_url( $super_uri, 'stick-topic_' . $topic->ID );
+
+			$super_display = ' <a href="' . esc_url( $super_uri ) . '" class="bbp-topic-super-sticky-link">' . $r['super_text'] . '</a>';
+		} else {
+			$super_display = '';
+		}
+
+		// Combine the HTML into 1 string
+		$retval = $r['link_before'] . $stick_display . $super_display . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_stick_link', $retval, $r );
+	}
+
+/**
+ * Output the merge link of the topic
+ *
+ * @since bbPress (r2756)
+ *
+ * @param mixed $args
+ * @uses bbp_get_topic_merge_link() To get the topic merge link
+ */
+function bbp_topic_merge_link( $args = '' ) {
+	echo bbp_get_topic_merge_link( $args );
+}
+
+	/**
+	 * Return the merge link of the topic
+	 *
+	 * @since bbPress (r2756)
+	 *
+	 * @param mixed $args This function supports these args:
+	 *  - id: Optional. Topic id
+	 *  - link_before: Before the link
+	 *  - link_after: After the link
+	 *  - merge_text: Merge text
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses bbp_get_topic_edit_url() To get the topic edit url
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses esc_url() To escape the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_merge_link' with the link
+	 *                        and args
+	 * @return string Topic merge link
+	 */
+	function bbp_get_topic_merge_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'merge_text'   => esc_html__( 'Merge', 'bbpress' ),
+		), 'get_topic_merge_link' );
+
+		$topic = bbp_get_topic( bbp_get_topic_id( (int) $r['id'] ) );
+
+		if ( empty( $topic ) || !current_user_can( 'moderate', $topic->ID ) )
+			return;
+
+		$uri    = add_query_arg( array( 'action' => 'merge' ), bbp_get_topic_edit_url( $topic->ID ) );
+		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-merge-link">' . $r['merge_text'] . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_merge_link', $retval, $args );
+	}
+
+/**
+ * Output the spam link of the topic
+ *
+ * @since bbPress (r2727)
+ *
+ * @param mixed $args See {@link bbp_get_topic_spam_link()}
+ * @uses bbp_get_topic_spam_link() Topic spam link
+ */
+function bbp_topic_spam_link( $args = '' ) {
+	echo bbp_get_topic_spam_link( $args );
+}
+
+	/**
+	 * Return the spam link of the topic
+	 *
+	 * @since bbPress (r2727)
+	 *
+	 * @param mixed $args This function supports these args:
+	 *  - id: Optional. Topic id
+	 *  - link_before: Before the link
+	 *  - link_after: After the link
+	 *  - spam_text: Spam text
+	 *  - unspam_text: Unspam text
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses current_user_can() To check if the current user can edit the topic
+	 * @uses bbp_is_topic_spam() To check if the topic is marked as spam
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses wp_nonce_url() To nonce the url
+	 * @uses esc_url() To escape the url
+	 * @uses apply_filters() Calls 'bbp_get_topic_spam_link' with the link
+	 *                        and args
+	 * @return string Topic spam link
+	 */
+	function bbp_get_topic_spam_link( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'sep'          => ' | ',
+			'spam_text'    => esc_html__( 'Spam',   'bbpress' ),
+			'unspam_text'  => esc_html__( 'Unspam', 'bbpress' )
+		), 'get_topic_spam_link' );
+
+		$topic = bbp_get_topic( bbp_get_topic_id( (int) $r['id'] ) );
+
+		if ( empty( $topic ) || !current_user_can( 'moderate', $topic->ID ) )
+			return;
+
+		$display = bbp_is_topic_spam( $topic->ID ) ? $r['unspam_text'] : $r['spam_text'];
+		$uri     = add_query_arg( array( 'action' => 'bbp_toggle_topic_spam', 'topic_id' => $topic->ID ) );
+		$uri     = wp_nonce_url( $uri, 'spam-topic_' . $topic->ID );
+		$retval  = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-spam-link">' . $display . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_spam_link', $retval, $r );
+	}
+
+/**
+ * Output the link to go directly to the reply form
+ *
+ * @since bbPress (r4966)
+ *
+ * @param array $args
+ * @uses bbp_get_reply_to_link() To get the reply to link
+ */
+function bbp_topic_reply_link( $args = array() ) {
+	echo bbp_get_topic_reply_link( $args );
+}
+
+	/**
+	 * Return the link to go directly to the reply form
+	 *
+	 * @since bbPress (r4966)
+	 *
+	 * @param array $args Arguments
+	 * @uses bbp_current_user_can_access_create_reply_form() To check permissions
+	 * @uses bbp_get_topic_id() To validate the topic id
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses apply_filters() Calls 'bbp_get_topic_reply_link' with the formatted link,
+	 *                        the arguments array, and the topic
+	 * @return string Link for a reply to a topic
+	 */
+	function bbp_get_topic_reply_link( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'id'           => 0,
+			'link_before'  => '',
+			'link_after'   => '',
+			'reply_text'   => esc_html__( 'Reply', 'bbpress' ),
+		), 'get_topic_reply_link' );
+
+		// Get the reply to use it's ID and post_parent
+		$topic = bbp_get_topic( bbp_get_topic_id( (int) $r['id'] ) );
+
+		// Bail if no reply or user cannot reply
+		if ( empty( $topic ) || ! bbp_current_user_can_access_create_reply_form() )
+			return;
+
+		$uri = '#new-post';
+
+		// Add $uri to the array, to be passed through the filter
+		$r['uri'] = $uri;
+		$retval   = $r['link_before'] . '<a href="' . esc_url( $r['uri'] ) . '" class="bbp-topic-reply-link">' . $r['reply_text'] . '</a>' . $r['link_after'];
+
+		return apply_filters( 'bbp_get_topic_reply_link', $retval, $r, $args );
+	}
+
+/** Topic Pagination **********************************************************/
+
+/**
+ * Output the pagination count
+ *
+ * @since bbPress (r2519)
+ *
+ * @uses bbp_get_forum_pagination_count() To get the forum pagination count
+ */
+function bbp_forum_pagination_count() {
+	echo bbp_get_forum_pagination_count();
+}
+	/**
+	 * Return the pagination count
+	 *
+	 * @since bbPress (r2519)
+	 *
+	 * @uses bbp_number_format() To format the number value
+	 * @uses apply_filters() Calls 'bbp_get_forum_pagination_count' with the
+	 *                        pagination count
+	 * @return string Forum Pagintion count
+	 */
+	function bbp_get_forum_pagination_count() {
+		$bbp = bbpress();
+
+		if ( empty( $bbp->topic_query ) )
+			return false;
+
+		// Set pagination values
+		$start_num = intval( ( $bbp->topic_query->paged - 1 ) * $bbp->topic_query->posts_per_page ) + 1;
+		$from_num  = bbp_number_format( $start_num );
+		$to_num    = bbp_number_format( ( $start_num + ( $bbp->topic_query->posts_per_page - 1 ) > $bbp->topic_query->found_posts ) ? $bbp->topic_query->found_posts : $start_num + ( $bbp->topic_query->posts_per_page - 1 ) );
+		$total_int = (int) !empty( $bbp->topic_query->found_posts ) ? $bbp->topic_query->found_posts : $bbp->topic_query->post_count;
+		$total     = bbp_number_format( $total_int );
+
+		// Several topics in a forum with a single page
+		if ( empty( $to_num ) ) {
+			$retstr = sprintf( _n( 'Viewing %1$s topic', 'Viewing %1$s topics', $total_int, 'bbpress' ), $total );
+
+		// Several topics in a forum with several pages
+		} else {
+			$retstr = sprintf( _n( 'Viewing topic %2$s (of %4$s total)', 'Viewing %1$s topics - %2$s through %3$s (of %4$s total)', $total_int, 'bbpress' ), $bbp->topic_query->post_count, $from_num, $to_num, $total );
+		}
+
+		// Filter and return
+		return apply_filters( 'bbp_get_forum_pagination_count', esc_html( $retstr ) );
+	}
+
+/**
+ * Output pagination links
+ *
+ * @since bbPress (r2519)
+ *
+ * @uses bbp_get_forum_pagination_links() To get the pagination links
+ */
+function bbp_forum_pagination_links() {
+	echo bbp_get_forum_pagination_links();
+}
+	/**
+	 * Return pagination links
+	 *
+	 * @since bbPress (r2519)
+	 *
+	 * @uses bbPress::topic_query::pagination_links To get the links
+	 * @return string Pagination links
+	 */
+	function bbp_get_forum_pagination_links() {
+		$bbp = bbpress();
+
+		if ( empty( $bbp->topic_query ) )
+			return false;
+
+		return apply_filters( 'bbp_get_forum_pagination_links', $bbp->topic_query->pagination_links );
+	}
+
+/**
+ * Displays topic notices
+ *
+ * @since bbPress (r2744)
+ *
+ * @uses bbp_is_single_topic() To check if it's a topic page
+ * @uses bbp_get_topic_status() To get the topic status
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses apply_filters() Calls 'bbp_topic_notices' with the notice text, topic
+ *                        status and topic id
+ * @uses bbp_add_error() To add an error message
+ */
+function bbp_topic_notices() {
+
+	// Bail if not viewing a topic
+	if ( !bbp_is_single_topic() )
+		return;
+
+	// Get the topic_status
+	$topic_status = bbp_get_topic_status();
+
+	// Get the topic status
+	switch ( $topic_status ) {
+
+		// Spam notice
+		case bbp_get_spam_status_id() :
+			$notice_text = __( 'This topic is marked as spam.', 'bbpress' );
+			break;
+
+		// Trashed notice
+		case bbp_get_trash_status_id() :
+			$notice_text = __( 'This topic is in the trash.',   'bbpress' );
+			break;
+
+		// Standard status
+		default :
+			$notice_text = '';
+			break;
+	}
+
+	// Filter notice text and bail if empty
+	$notice_text = apply_filters( 'bbp_topic_notices', $notice_text, $topic_status, bbp_get_topic_id() );
+	if ( empty( $notice_text ) )
+		return;
+
+	bbp_add_error( 'topic_notice', $notice_text, 'message' );
+}
+
+/**
+ * Displays topic type select box (normal/sticky/super sticky)
+ *
+ * @since bbPress (r5059)
+ * @deprecated since bbPress (r5059)
+ *
+ * @param $args This function supports these arguments:
+ *  - select_id: Select id. Defaults to bbp_stick_topic
+ *  - tab: Tabindex
+ *  - topic_id: Topic id
+ *  - selected: Override the selected option
+ */
+function bbp_topic_type_select( $args = '' ) {
+	echo bbp_get_form_topic_type_dropdown( $args );
+}
+
+/**
+ * Displays topic type select box (normal/sticky/super sticky)
+ *
+ * @since bbPress (r5059)
+ *
+ * @param $args This function supports these arguments:
+ *  - select_id: Select id. Defaults to bbp_stick_topic
+ *  - tab: Tabindex
+ *  - topic_id: Topic id
+ *  - selected: Override the selected option
+ */
+function bbp_form_topic_type_dropdown( $args = '' ) {
+	echo bbp_get_form_topic_type_dropdown( $args );
+}
+	/**
+	 * Returns topic type select box (normal/sticky/super sticky)
+	 *
+	 * @since bbPress (r5059)
+	 *
+	 * @param $args This function supports these arguments:
+	 *  - select_id: Select id. Defaults to bbp_stick_topic
+	 *  - tab: Tabindex
+	 *  - topic_id: Topic id
+	 *  - selected: Override the selected option
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_is_single_topic() To check if we're viewing a single topic
+	 * @uses bbp_is_topic_edit() To check if it is the topic edit page
+	 * @uses bbp_is_topic_super_sticky() To check if the topic is a super sticky
+	 * @uses bbp_is_topic_sticky() To check if the topic is a sticky
+	 */
+	function bbp_get_form_topic_type_dropdown( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'select_id'    => 'bbp_stick_topic',
+			'tab'          => bbp_get_tab_index(),
+			'topic_id'     => 0,
+			'selected'     => false
+		), 'topic_type_select' );
+
+		// No specific selected value passed
+		if ( empty( $r['selected'] ) ) {
+
+			// Post value is passed
+			if ( bbp_is_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
+				$r['selected'] = $_POST[ $r['select_id'] ];
+
+			// No Post value passed
+			} else {
+
+				// Edit topic
+				if ( bbp_is_single_topic() || bbp_is_topic_edit() ) {
+
+					// Get current topic id
+					$topic_id = bbp_get_topic_id( $r['topic_id'] );
+
+					// Topic is super sticky
+					if ( bbp_is_topic_super_sticky( $topic_id ) ) {
+						$r['selected'] = 'super';
+
+					// Topic is sticky or normal
+					} else {
+						$r['selected'] = bbp_is_topic_sticky( $topic_id, false ) ? 'stick' : 'unstick';
+					}
+				}
+			}
+		}
+
+		// Used variables
+		$tab = !empty( $r['tab'] ) ? ' tabindex="' . (int) $r['tab'] . '"' : '';
+
+		// Start an output buffer, we'll finish it after the select loop
+		ob_start(); ?>
+
+		<select name="<?php echo esc_attr( $r['select_id'] ); ?>" id="<?php echo esc_attr( $r['select_id'] ); ?>_select"<?php echo $tab; ?>>
+
+			<?php foreach ( bbp_get_topic_types() as $key => $label ) : ?>
+
+				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>
+
+			<?php endforeach; ?>
+
+		</select>
+
+		<?php
+
+		// Return the results
+		return apply_filters( 'bbp_get_form_topic_type_dropdown', ob_get_clean(), $r );
+	}
+
+/**
+ * Output value topic status dropdown
+ *
+ * @since bbPress (r5059)
+ *
+ * @param int $topic_id The topic id to use
+ */
+function bbp_form_topic_status_dropdown( $args = '' ) {
+	echo bbp_get_form_topic_status_dropdown( $args );
+}
+	/**
+	 * Returns topic status downdown
+	 *
+	 * This dropdown is only intended to be seen by users with the 'moderate'
+	 * capability. Because of this, no additional capablitiy checks are performed
+	 * within this function to check available topic statuses.
+	 *
+	 * @since bbPress (r5059)
+	 *
+	 * @param $args This function supports these arguments:
+	 *  - select_id: Select id. Defaults to bbp_open_close_topic
+	 *  - tab: Tabindex
+	 *  - topic_id: Topic id
+	 *  - selected: Override the selected option
+	 */
+	function bbp_get_form_topic_status_dropdown( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'select_id' => 'bbp_topic_status',
+			'tab'       => bbp_get_tab_index(),
+			'topic_id'  => 0,
+			'selected'  => false
+		), 'topic_open_close_select' );
+
+		// No specific selected value passed
+		if ( empty( $r['selected'] ) ) {
+
+			// Post value is passed
+			if ( bbp_is_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
+				$r['selected'] = $_POST[ $r['select_id'] ];
+
+			// No Post value was passed
+			} else {
+
+				// Edit topic
+				if ( bbp_is_topic_edit() ) {
+					$r['topic_id'] = bbp_get_topic_id( $r['topic_id'] );
+					$r['selected'] = bbp_get_topic_status( $r['topic_id'] );
+
+				// New topic
+				} else {
+					$r['selected'] = bbp_get_public_status_id();
+				}
+			}
+		}
+
+		// Used variables
+		$tab = ! empty( $r['tab'] ) ? ' tabindex="' . (int) $r['tab'] . '"' : '';
+
+		// Start an output buffer, we'll finish it after the select loop
+		ob_start(); ?>
+
+		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ); ?>_select"<?php echo $tab; ?>>
+
+			<?php foreach ( bbp_get_topic_statuses( $r['topic_id'] ) as $key => $label ) : ?>
+
+				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>
+
+			<?php endforeach; ?>
+
+		</select>
+
+		<?php
+
+		// Return the results
+		return apply_filters( 'bbp_get_form_topic_status_dropdown', ob_get_clean(), $r );
+	}
+
+/** Single Topic **************************************************************/
+
+/**
+ * Output a fancy description of the current topic, including total topics,
+ * total replies, and last activity.
+ *
+ * @since bbPress (r2860)
+ *
+ * @param array $args See {@link bbp_get_single_topic_description()}
+ * @uses bbp_get_single_topic_description() Return the eventual output
+ */
+function bbp_single_topic_description( $args = '' ) {
+	echo bbp_get_single_topic_description( $args );
+}
+	/**
+	 * Return a fancy description of the current topic, including total topics,
+	 * total replies, and last activity.
+	 *
+	 * @since bbPress (r2860)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - topic_id: Topic id
+	 *  - before: Before the text
+	 *  - after: After the text
+	 *  - size: Size of the avatar
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_topic_voice_count() To get the topic voice count
+	 * @uses bbp_get_topic_reply_count() To get the topic reply count
+	 * @uses bbp_get_topic_freshness_link() To get the topic freshness link
+	 * @uses bbp_get_topic_last_active_id() To get the topic last active id
+	 * @uses bbp_get_reply_author_link() To get the reply author link
+	 * @uses apply_filters() Calls 'bbp_get_single_topic_description' with
+	 *                        the description and args
+	 * @return string Filtered topic description
+	 */
+	function bbp_get_single_topic_description( $args = '' ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'topic_id'  => 0,
+			'before'    => '<div class="bbp-template-notice info"><p class="bbp-topic-description">',
+			'after'     => '</p></div>',
+			'size'      => 14
+		), 'get_single_topic_description' );
+
+		// Validate topic_id
+		$topic_id = bbp_get_topic_id( $r['topic_id'] );
+
+		// Unhook the 'view all' query var adder
+		remove_filter( 'bbp_get_topic_permalink', 'bbp_add_view_all' );
+
+		// Build the topic description
+		$vc_int      = bbp_get_topic_voice_count   ( $topic_id, true  );
+		$voice_count = bbp_get_topic_voice_count   ( $topic_id, false );
+		$reply_count = bbp_get_topic_replies_link  ( $topic_id        );
+		$time_since  = bbp_get_topic_freshness_link( $topic_id        );
+
+		// Singular/Plural
+		$voice_count = sprintf( _n( '%s voice', '%s voices', $vc_int, 'bbpress' ), $voice_count );
+
+		// Topic has replies
+		$last_reply = bbp_get_topic_last_reply_id( $topic_id );
+		if ( !empty( $last_reply ) ) {
+			$last_updated_by = bbp_get_author_link( array( 'post_id' => $last_reply, 'size' => $r['size'] ) );
+			$retstr          = sprintf( esc_html__( 'This topic contains %1$s, has %2$s, and was last updated by %3$s %4$s.', 'bbpress' ), $reply_count, $voice_count, $last_updated_by, $time_since );
+
+		// Topic has no replies
+		} elseif ( ! empty( $voice_count ) && ! empty( $reply_count ) ) {
+			$retstr = sprintf( esc_html__( 'This topic contains %1$s and has %2$s.', 'bbpress' ), $voice_count, $reply_count );
+
+		// Topic has no replies and no voices
+		} elseif ( empty( $voice_count ) && empty( $reply_count ) ) {
+			$retstr = sprintf( esc_html__( 'This topic has no replies.', 'bbpress' ), $voice_count, $reply_count );
+		}
+
+		// Add the 'view all' filter back
+		add_filter( 'bbp_get_topic_permalink', 'bbp_add_view_all' );
+
+		// Combine the elements together
+		$retstr = $r['before'] . $retstr . $r['after'];
+
+		// Return filtered result
+		return apply_filters( 'bbp_get_single_topic_description', $retstr, $r );
+	}
+
+/** Topic Tags ****************************************************************/
+
+/**
+ * Output the unique id of the topic tag taxonomy
+ *
+ * @since bbPress (r3348)
+ *
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ */
+function bbp_topic_tag_tax_id() {
+	echo bbp_get_topic_tag_tax_id();
+}
+	/**
+	 * Return the unique id of the topic tag taxonomy
+	 *
+	 * @since bbPress (r3348)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_topic_tag_tax_id' with the topic tax id
+	 * @return string The unique topic tag taxonomy
+	 */
+	function bbp_get_topic_tag_tax_id() {
+		return apply_filters( 'bbp_get_topic_tag_tax_id', bbpress()->topic_tag_tax_id );
+	}
+
+/**
+ * Return array of labels used by the topic-tag taxonomy
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_topic_tag_tax_labels() {
+	return apply_filters( 'bbp_get_topic_tag_tax_labels', array(
+		'name'          => __( 'Topic Tags',     'bbpress' ),
+		'singular_name' => __( 'Topic Tag',      'bbpress' ),
+		'search_items'  => __( 'Search Tags',    'bbpress' ),
+		'popular_items' => __( 'Popular Tags',   'bbpress' ),
+		'all_items'     => __( 'All Tags',       'bbpress' ),
+		'edit_item'     => __( 'Edit Tag',       'bbpress' ),
+		'update_item'   => __( 'Update Tag',     'bbpress' ),
+		'add_new_item'  => __( 'Add New Tag',    'bbpress' ),
+		'new_item_name' => __( 'New Tag Name',   'bbpress' ),
+		'view_item'     => __( 'View Topic Tag', 'bbpress' )
+	) );
+}
+
+/**
+ * Return an array of topic-tag taxonomy rewrite settings
+ *
+ * @since bbPress (r5129)
+ *
+ * @return array
+ */
+function bbp_get_topic_tag_tax_rewrite() {
+	return apply_filters( 'bbp_get_topic_tag_tax_rewrite', array(
+		'slug'       => bbp_get_topic_tag_tax_slug(),
+		'with_front' => false
+	) );
+}
+
+/**
+ * Output the id of the current tag
+ *
+ * @since bbPress (r3109)
+ *
+ * @uses bbp_get_topic_tag_id()
+ */
+function bbp_topic_tag_id( $tag = '' ) {
+	echo bbp_get_topic_tag_id( $tag );
+}
+	/**
+	 * Return the id of the current tag
+	 *
+	 * @since bbPress (r3109)
+	 *
+	 * @uses get_term_by()
+	 * @uses get_queried_object()
+	 * @uses get_query_var()
+	 * @uses apply_filters()
+	 *
+	 * @return string Term Name
+	 */
+	function bbp_get_topic_tag_id( $tag = '' ) {
+
+		// Get the term
+		if ( ! empty( $tag ) ) {
+			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
+		} else {
+			$tag  = get_query_var( 'term' );
+			$term = get_queried_object();
+		}
+
+		// Add before and after if description exists
+		if ( !empty( $term->term_id ) ) {
+			$retval = $term->term_id;
+
+		// No id
+		} else {
+			$retval = '';
+		}
+
+		return (int) apply_filters( 'bbp_get_topic_tag_id', (int) $retval, $tag );
+	}
+
+/**
+ * Output the name of the current tag
+ *
+ * @since bbPress (r3109)
+ *
+ * @uses bbp_get_topic_tag_name()
+ */
+function bbp_topic_tag_name( $tag = '' ) {
+	echo bbp_get_topic_tag_name( $tag );
+}
+	/**
+	 * Return the name of the current tag
+	 *
+	 * @since bbPress (r3109)
+	 *
+	 * @uses get_term_by()
+	 * @uses get_queried_object()
+	 * @uses get_query_var()
+	 * @uses apply_filters()
+	 *
+	 * @return string Term Name
+	 */
+	function bbp_get_topic_tag_name( $tag = '' ) {
+
+		// Get the term
+		if ( ! empty( $tag ) ) {
+			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
+		} else {
+			$tag  = get_query_var( 'term' );
+			$term = get_queried_object();
+		}
+
+		// Add before and after if description exists
+		if ( !empty( $term->name ) ) {
+			$retval = $term->name;
+
+		// No name
+		} else {
+			$retval = '';
+		}
+
+		return apply_filters( 'bbp_get_topic_tag_name', $retval );
+	}
+
+/**
+ * Output the slug of the current tag
+ *
+ * @since bbPress (r3109)
+ *
+ * @uses bbp_get_topic_tag_slug()
+ */
+function bbp_topic_tag_slug( $tag = '' ) {
+	echo bbp_get_topic_tag_slug( $tag );
+}
+	/**
+	 * Return the slug of the current tag
+	 *
+	 * @since bbPress (r3109)
+	 *
+	 * @uses get_term_by()
+	 * @uses get_queried_object()
+	 * @uses get_query_var()
+	 * @uses apply_filters()
+	 *
+	 * @return string Term Name
+	 */
+	function bbp_get_topic_tag_slug( $tag = '' ) {
+
+		// Get the term
+		if ( ! empty( $tag ) ) {
+			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
+		} else {
+			$tag  = get_query_var( 'term' );
+			$term = get_queried_object();
+		}
+
+		// Add before and after if description exists
+		if ( !empty( $term->slug ) ) {
+			$retval = $term->slug;
+
+		// No slug
+		} else {
+			$retval = '';
+		}
+
+		return apply_filters( 'bbp_get_topic_tag_slug', $retval );
+	}
+
+/**
+ * Output the link of the current tag
+ *
+ * @since bbPress (r3348)
+ *
+ * @uses bbp_get_topic_tag_link()
+ */
+function bbp_topic_tag_link( $tag = '' ) {
+	echo esc_url( bbp_get_topic_tag_link( $tag ) );
+}
+	/**
+	 * Return the link of the current tag
+	 *
+	 * @since bbPress (r3348)
+	 *
+	 * @uses get_term_by()
+	 * @uses get_queried_object()
+	 * @uses get_query_var()
+	 * @uses apply_filters()
+	 *
+	 * @return string Term Name
+	 */
+	function bbp_get_topic_tag_link( $tag = '' ) {
+
+		// Get the term
+		if ( ! empty( $tag ) ) {
+			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
+		} else {
+			$tag  = get_query_var( 'term' );
+			$term = get_queried_object();
+		}
+
+		// Add before and after if description exists
+		if ( !empty( $term->term_id ) ) {
+			$retval = get_term_link( $term, bbp_get_topic_tag_tax_id() );
+
+		// No link
+		} else {
+			$retval = '';
+		}
+
+		return apply_filters( 'bbp_get_topic_tag_link', $retval, $tag );
+	}
+
+/**
+ * Output the link of the current tag
+ *
+ * @since bbPress (r3348)
+ *
+ * @uses bbp_get_topic_tag_edit_link()
+ */
+function bbp_topic_tag_edit_link( $tag = '' ) {
+	echo esc_url( bbp_get_topic_tag_edit_link( $tag ) );
+}
+	/**
+	 * Return the link of the current tag
+	 *
+	 * @since bbPress (r3348)
+	 *
+	 * @uses get_term_by()
+	 * @uses get_queried_object()
+	 * @uses get_query_var()
+	 * @uses apply_filters()
+	 *
+	 * @return string Term Name
+	 */
+	function bbp_get_topic_tag_edit_link( $tag = '' ) {
+		global $wp_rewrite;
+
+		// Get the term
+		if ( ! empty( $tag ) ) {
+			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
+		} else {
+			$tag  = get_query_var( 'term' );
+			$term = get_queried_object();
+		}
+
+		// Add before and after if description exists
+		if ( !empty( $term->term_id ) ) {
+
+			$bbp = bbpress();
+
+			// Pretty
+			if ( $wp_rewrite->using_permalinks() ) {
+				$retval = user_trailingslashit( trailingslashit( bbp_get_topic_tag_link() ) . $bbp->edit_id );
+
+			// Ugly
+			} else {
+				$retval = add_query_arg( array( $bbp->edit_id => '1' ), bbp_get_topic_tag_link() );
+			}
+
+		// No link
+		} else {
+			$retval = '';
+		}
+
+		return apply_filters( 'bbp_get_topic_tag_edit_link', $retval, $tag );
+	}
+
+/**
+ * Output the description of the current tag
+ *
+ * @since bbPress (r3109)
+ *
+ * @uses bbp_get_topic_tag_description()
+ */
+function bbp_topic_tag_description( $args = array() ) {
+	echo bbp_get_topic_tag_description( $args );
+}
+	/**
+	 * Return the description of the current tag
+	 *
+	 * @since bbPress (r3109)
+	 *
+	 * @uses get_term_by()
+	 * @uses get_queried_object()
+	 * @uses get_query_var()
+	 * @uses apply_filters()
+	 * @param array $args before|after|tag
+	 *
+	 * @return string Term Name
+	 */
+	function bbp_get_topic_tag_description( $args = array() ) {
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'before' => '<div class="bbp-topic-tag-description"><p>',
+			'after'  => '</p></div>',
+			'tag'    => ''
+		), 'get_topic_tag_description' );
+
+		// Get the term
+		if ( ! empty( $r['tag'] ) ) {
+			$term = get_term_by( 'slug', $r['tag'], bbp_get_topic_tag_tax_id() );
+		} else {
+			$tag      = get_query_var( 'term' );
+			$r['tag'] = $tag;
+			$term     = get_queried_object();
+		}
+
+		// Add before and after if description exists
+		if ( !empty( $term->description ) ) {
+			$retval = $r['before'] . $term->description . $r['after'];
+
+		// No description, no HTML
+		} else {
+			$retval = '';
+		}
+
+		return apply_filters( 'bbp_get_topic_tag_description', $retval, $r );
+	}
+
+/** Forms *********************************************************************/
+
+/**
+ * Output the value of topic title field
+ *
+ * @since bbPress (r2976)
+ *
+ * @uses bbp_get_form_topic_title() To get the value of topic title field
+ */
+function bbp_form_topic_title() {
+	echo bbp_get_form_topic_title();
+}
+	/**
+	 * Return the value of topic title field
+	 *
+	 * @since bbPress (r2976)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's topic edit page
+	 * @uses apply_filters() Calls 'bbp_get_form_topic_title' with the title
+	 * @return string Value of topic title field
+	 */
+	function bbp_get_form_topic_title() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_topic_title'] ) ) {
+			$topic_title = $_POST['bbp_topic_title'];
+
+		// Get edit data
+		} elseif ( bbp_is_topic_edit() ) {
+			$topic_title = bbp_get_global_post_field( 'post_title', 'raw' );
+
+		// No data
+		} else {
+			$topic_title = '';
+		}
+
+		return apply_filters( 'bbp_get_form_topic_title', esc_attr( $topic_title ) );
+	}
+
+/**
+ * Output the value of topic content field
+ *
+ * @since bbPress (r2976)
+ *
+ * @uses bbp_get_form_topic_content() To get value of topic content field
+ */
+function bbp_form_topic_content() {
+	echo bbp_get_form_topic_content();
+}
+	/**
+	 * Return the value of topic content field
+	 *
+	 * @since bbPress (r2976)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses apply_filters() Calls 'bbp_get_form_topic_content' with the content
+	 * @return string Value of topic content field
+	 */
+	function bbp_get_form_topic_content() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_topic_content'] ) ) {
+			$topic_content = stripslashes( $_POST['bbp_topic_content'] );
+
+		// Get edit data
+		} elseif ( bbp_is_topic_edit() ) {
+			$topic_content = bbp_get_global_post_field( 'post_content', 'raw' );
+
+		// No data
+		} else {
+			$topic_content = '';
+		}
+
+		return apply_filters( 'bbp_get_form_topic_content', $topic_content );
+	}
+
+/**
+ * Allow topic rows to have adminstrative actions
+ *
+ * @since bbPress (r3653)
+ * @uses do_action()
+ * @todo Links and filter
+ */
+function bbp_topic_row_actions() {
+	do_action( 'bbp_topic_row_actions' );
+}
+
+/**
+ * Output value of topic tags field
+ *
+ * @since bbPress (r2976)
+ * @uses bbp_get_form_topic_tags() To get the value of topic tags field
+ */
+function bbp_form_topic_tags() {
+	echo bbp_get_form_topic_tags();
+}
+	/**
+	 * Return value of topic tags field
+	 *
+	 * @since bbPress (r2976)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses apply_filters() Calls 'bbp_get_form_topic_tags' with the tags
+	 * @return string Value of topic tags field
+	 */
+	function bbp_get_form_topic_tags() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_topic_tags'] ) ) {
+			$topic_tags = $_POST['bbp_topic_tags'];
+
+		// Get edit data
+		} elseif ( bbp_is_single_topic() || bbp_is_single_reply() || bbp_is_topic_edit() || bbp_is_reply_edit() ) {
+
+			// Determine the topic id based on the post type
+			switch ( get_post_type() ) {
+
+				// Post is a topic
+				case bbp_get_topic_post_type() :
+					$topic_id = get_the_ID();
+					break;
+
+				// Post is a reply
+				case bbp_get_reply_post_type() :
+					$topic_id = bbp_get_reply_topic_id( get_the_ID() );
+					break;
+			}
+
+			// Topic exists
+			if ( !empty( $topic_id ) ) {
+
+				// Topic is spammed so display pre-spam terms
+				if ( bbp_is_topic_spam( $topic_id ) ) {
+
+					// Get pre-spam terms
+					$new_terms = get_post_meta( $topic_id, '_bbp_spam_topic_tags', true );
+
+					// If terms exist, explode them and compile the return value
+					if ( empty( $new_terms ) ) {
+						$new_terms = '';
+					}
+
+				// Topic is not spam so get real terms
+				} else {
+					$terms = array_filter( (array) get_the_terms( $topic_id, bbp_get_topic_tag_tax_id() ) );
+
+					// Loop through them
+					foreach ( $terms as $term ) {
+						$new_terms[] = $term->name;
+					}
+				}
+
+			// Define local variable(s)
+			} else {
+				$new_terms = '';
+			}
+
+			// Set the return value
+			$topic_tags = ( !empty( $new_terms ) ) ? implode( ', ', $new_terms ) : '';
+
+		// No data
+		} else {
+			$topic_tags = '';
+		}
+
+		return apply_filters( 'bbp_get_form_topic_tags', esc_attr( $topic_tags ) );
+	}
+
+/**
+ * Output value of topic forum
+ *
+ * @since bbPress (r2976)
+ *
+ * @uses bbp_get_form_topic_forum() To get the topic's forum id
+ */
+function bbp_form_topic_forum() {
+	echo bbp_get_form_topic_forum();
+}
+	/**
+	 * Return value of topic forum
+	 *
+	 * @since bbPress (r2976)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_get_topic_forum_id() To get the topic forum id
+	 * @uses apply_filters() Calls 'bbp_get_form_topic_forum' with the forum
+	 * @return string Value of topic content field
+	 */
+	function bbp_get_form_topic_forum() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_forum_id'] ) ) {
+			$topic_forum = (int) $_POST['bbp_forum_id'];
+
+		// Get edit data
+		} elseif ( bbp_is_topic_edit() ) {
+			$topic_forum = bbp_get_topic_forum_id();
+
+		// No data
+		} else {
+			$topic_forum = 0;
+		}
+
+		return apply_filters( 'bbp_get_form_topic_forum', $topic_forum );
+	}
+
+/**
+ * Output checked value of topic subscription
+ *
+ * @since bbPress (r2976)
+ *
+ * @uses bbp_get_form_topic_subscribed() To get the subscribed checkbox value
+ */
+function bbp_form_topic_subscribed() {
+	echo bbp_get_form_topic_subscribed();
+}
+	/**
+	 * Return checked value of topic subscription
+	 *
+	 * @since bbPress (r2976)
+	 *
+	 * @uses bbp_is_topic_edit() To check if it's the topic edit page
+	 * @uses bbp_is_user_subscribed_to_topic() To check if the user is
+	 *                                          subscribed to the topic
+	 * @uses apply_filters() Calls 'bbp_get_form_topic_subscribed' with the
+	 *                        option
+	 * @return string Checked value of topic subscription
+	 */
+	function bbp_get_form_topic_subscribed() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_topic_subscription'] ) ) {
+			$topic_subscribed = (bool) $_POST['bbp_topic_subscription'];
+
+		// Get edit data
+		} elseif ( bbp_is_topic_edit() || bbp_is_reply_edit() ) {
+
+			// Get current posts author
+			$post_author = bbp_get_global_post_field( 'post_author', 'raw' );
+
+			// Post author is not the current user
+			if ( bbp_get_current_user_id() !== $post_author ) {
+				$topic_subscribed = bbp_is_user_subscribed_to_topic( $post_author );
+
+			// Post author is the current user
+			} else {
+				$topic_subscribed = bbp_is_user_subscribed_to_topic( bbp_get_current_user_id() );
+			}
+
+		// Get current status
+		} elseif ( bbp_is_single_topic() ) {
+			$topic_subscribed = bbp_is_user_subscribed_to_topic( bbp_get_current_user_id() );
+
+		// No data
+		} else {
+			$topic_subscribed = false;
+		}
+
+		// Get checked output
+		$checked = checked( $topic_subscribed, true, false );
+
+		return apply_filters( 'bbp_get_form_topic_subscribed', $checked, $topic_subscribed );
+	}
+
+/**
+ * Output checked value of topic log edit field
+ *
+ * @since bbPress (r2976)
+ *
+ * @uses bbp_get_form_topic_log_edit() To get the topic log edit value
+ */
+function bbp_form_topic_log_edit() {
+	echo bbp_get_form_topic_log_edit();
+}
+	/**
+	 * Return checked value of topic log edit field
+	 *
+	 * @since bbPress (r2976)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_form_topic_log_edit' with the
+	 *                        log edit value
+	 * @return string Topic log edit checked value
+	 */
+	function bbp_get_form_topic_log_edit() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_log_topic_edit'] ) ) {
+			$topic_revision = (int) $_POST['bbp_log_topic_edit'];
+
+		// No data
+		} else {
+			$topic_revision = 1;
+		}
+
+		// Get checked output
+		$checked = checked( $topic_revision, true, false );
+
+		return apply_filters( 'bbp_get_form_topic_log_edit', $checked, $topic_revision );
+	}
+
+/**
+ * Output the value of the topic edit reason
+ *
+ * @since bbPress (r2976)
+ *
+ * @uses bbp_get_form_topic_edit_reason() To get the topic edit reason value
+ */
+function bbp_form_topic_edit_reason() {
+	echo bbp_get_form_topic_edit_reason();
+}
+	/**
+	 * Return the value of the topic edit reason
+	 *
+	 * @since bbPress (r2976)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_form_topic_edit_reason' with the
+	 *                        topic edit reason value
+	 * @return string Topic edit reason value
+	 */
+	function bbp_get_form_topic_edit_reason() {
+
+		// Get _POST data
+		if ( bbp_is_post_request() && isset( $_POST['bbp_topic_edit_reason'] ) ) {
+			$topic_edit_reason = $_POST['bbp_topic_edit_reason'];
+
+		// No data
+		} else {
+			$topic_edit_reason = '';
+		}
+
+		return apply_filters( 'bbp_get_form_topic_edit_reason', esc_attr( $topic_edit_reason ) );
+	}
Index: /tags/2.5.4/includes/users/capabilities.php
===================================================================
--- /tags/2.5.4/includes/users/capabilities.php	(revision 5382)
+++ /tags/2.5.4/includes/users/capabilities.php	(revision 5382)
@@ -0,0 +1,695 @@
+<?php
+
+/**
+ * bbPress User Capabilites
+ *
+ * Used to map user capabilities to WordPress's existing capabilities.
+ *
+ * @package bbPress
+ * @subpackage Capabilities
+ */
+
+/**
+ * Maps primary capabilities
+ *
+ * @since bbPress (r4242)
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ * @uses apply_filters() Filter mapped results
+ * @return array Actual capabilities for meta capability
+ */
+function bbp_map_primary_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+
+	// What capability is being checked?
+	switch ( $cap ) {
+		case 'spectate'    :
+		case 'participate' :
+		case 'moderate'    :
+
+			// Do not allow inactive users
+			if ( bbp_is_user_inactive( $user_id ) ) {
+				$caps = array( 'do_not_allow' );
+
+			// Moderators are always participants
+			} else {
+				$caps = array( $cap );
+			}
+
+			break;
+	}
+
+	return apply_filters( 'bbp_map_primary_meta_caps', $caps, $cap, $user_id, $args );
+}
+
+/**
+ * Return a user's main role
+ *
+ * @since bbPress (r3860)
+ *
+ * @param int $user_id
+ * @uses bbp_get_user_id() To get the user id
+ * @uses get_userdata() To get the user data
+ * @uses apply_filters() Calls 'bbp_set_user_role' with the role and user id
+ * @return string
+ */
+function bbp_set_user_role( $user_id = 0, $new_role = '' ) {
+
+	// Validate user id
+	$user_id = bbp_get_user_id( $user_id, false, false );
+	$user    = get_userdata( $user_id );
+
+	// User exists
+	if ( !empty( $user ) ) {
+
+		// Get users forum role
+		$role = bbp_get_user_role( $user_id );
+
+		// User already has this role so no new role is set
+		if ( $new_role === $role ) {
+			$new_role = false;
+
+		// Users role is different than the new role
+		} else {
+
+			// Remove the old role
+			if ( ! empty( $role ) ) {
+				$user->remove_role( $role );
+			}
+
+			// Add the new role
+			if ( !empty( $new_role ) ) {
+
+				// Make sure bbPress roles are added
+				bbp_add_forums_roles();
+
+				$user->add_role( $new_role );
+			}
+		}
+
+	// User does don exist so return false
+	} else {
+		$new_role = false;
+	}
+
+	return apply_filters( 'bbp_set_user_role', $new_role, $user_id, $user );
+}
+
+/**
+ * Return a user's forums role
+ *
+ * @since bbPress (r3860)
+ *
+ * @param int $user_id
+ * @uses bbp_get_user_id() To get the user id
+ * @uses get_userdata() To get the user data
+ * @uses apply_filters() Calls 'bbp_get_user_role' with the role and user id
+ * @return string
+ */
+function bbp_get_user_role( $user_id = 0 ) {
+
+	// Validate user id
+	$user_id = bbp_get_user_id( $user_id );
+	$user    = get_userdata( $user_id );
+	$role    = false;
+
+	// User has roles so look for a bbPress one
+	if ( ! empty( $user->roles ) ) {
+
+		// Look for a bbPress role
+		$roles = array_intersect(
+			array_values( $user->roles ),
+			array_keys( bbp_get_dynamic_roles() )
+		);
+
+		// If there's a role in the array, use the first one. This isn't very
+		// smart, but since roles aren't exactly hierarchical, and bbPress
+		// does not yet have a UI for multiple user roles, it's fine for now.
+		if ( !empty( $roles ) ) {
+			$role = array_shift( $roles );
+		}
+	}
+
+	return apply_filters( 'bbp_get_user_role', $role, $user_id, $user );
+}
+
+/**
+ * Return a user's blog role
+ *
+ * @since bbPress (r4446)
+ *
+ * @param int $user_id
+ * @uses bbp_get_user_id() To get the user id
+ * @uses get_userdata() To get the user data
+ * @uses apply_filters() Calls 'bbp_get_user_blog_role' with the role and user id
+ * @return string
+ */
+function bbp_get_user_blog_role( $user_id = 0 ) {
+
+	// Add bbPress roles (returns $wp_roles global)
+	bbp_add_forums_roles();
+
+	// Validate user id
+	$user_id = bbp_get_user_id( $user_id );
+	$user    = get_userdata( $user_id );
+	$role    = false;
+
+	// User has roles so lets
+	if ( ! empty( $user->roles ) ) {
+
+		// Look for a non bbPress role
+		$roles     = array_intersect(
+			array_values( $user->roles ),
+			array_keys( bbp_get_blog_roles() )
+		);
+
+		// If there's a role in the array, use the first one. This isn't very
+		// smart, but since roles aren't exactly hierarchical, and WordPress
+		// does not yet have a UI for multiple user roles, it's fine for now.
+		if ( !empty( $roles ) ) {
+			$role = array_shift( $roles );
+		}
+	}
+
+	return apply_filters( 'bbp_get_user_blog_role', $role, $user_id, $user );
+}
+
+/**
+ * Helper function hooked to 'bbp_profile_update' action to save or
+ * update user roles and capabilities.
+ *
+ * @since bbPress (r4235)
+ *
+ * @param int $user_id
+ * @uses bbp_reset_user_caps() to reset caps
+ * @usse bbp_save_user_caps() to save caps
+ */
+function bbp_profile_update_role( $user_id = 0 ) {
+
+	// Bail if no user ID was passed
+	if ( empty( $user_id ) )
+		return;
+
+	// Bail if no role
+	if ( ! isset( $_POST['bbp-forums-role'] ) )
+		return;
+
+	// Fromus role we want the user to have
+	$new_role    = sanitize_text_field( $_POST['bbp-forums-role'] );
+	$forums_role = bbp_get_user_role( $user_id );
+
+	// Bail if no role change
+	if ( $new_role === $forums_role )
+		return;
+
+	// Bail if trying to set their own role
+	if ( bbp_is_user_home_edit() )
+		return;
+	
+	// Bail if current user cannot promote the passing user
+	if ( ! current_user_can( 'promote_user', $user_id ) )
+		return;
+
+	// Set the new forums role
+	bbp_set_user_role( $user_id, $new_role );
+}
+
+/**
+ * Add the default role to the current user if needed
+ *
+ * This function will bail if the forum is not global in a multisite
+ * installation of WordPress, or if the user is marked as spam or deleted.
+ *
+ * @since bbPress (r3380)
+ *
+ * @uses is_user_logged_in() To bail if user is not logged in
+ * @uses bbp_get_user_role() To bail if user already has a role
+ * @uses bbp_is_user_inactive() To bail if user is inactive
+ * @uses bbp_allow_global_access() To know whether to save role to database
+ * @uses bbp_get_user_role_map() To get the WP to BBP role map array
+ * @uses bbp_get_default_role() To get the site's default forums role
+ * @uses get_option()
+ *
+ * @return If not multisite, not global, or user is deleted/spammed
+ */
+function bbp_set_current_user_default_role() {
+
+	/** Sanity ****************************************************************/
+
+	// Bail if deactivating bbPress
+	if ( bbp_is_deactivation() )
+		return;
+
+	// Catch all, to prevent premature user initialization
+	if ( ! did_action( 'set_current_user' ) )
+		return;
+
+	// Bail if not logged in or already a member of this site
+	if ( ! is_user_logged_in() )
+		return;
+
+	// Get the current user ID
+	$user_id = bbp_get_current_user_id();
+
+	// Bail if user already has a forums role
+	if ( bbp_get_user_role( $user_id ) )
+		return;
+
+	// Bail if user is marked as spam or is deleted
+	if ( bbp_is_user_inactive( $user_id ) )
+		return;
+
+	/** Ready *****************************************************************/
+
+	// Load up bbPress once
+	$bbp         = bbpress();
+
+	// Get whether or not to add a role to the user account
+	$add_to_site = bbp_allow_global_access();
+
+	// Get the current user's WordPress role. Set to empty string if none found.
+	$user_role   = bbp_get_user_blog_role( $user_id );
+
+	// Get the role map
+	$role_map    = bbp_get_user_role_map();
+
+	/** Forum Role ************************************************************/
+
+	// Use a mapped role
+	if ( isset( $role_map[$user_role] ) ) {
+		$new_role = $role_map[$user_role];
+
+	// Use the default role
+	} else {
+		$new_role = bbp_get_default_role();
+	}
+
+	/** Add or Map ************************************************************/
+
+	// Add the user to the site
+	if ( true === $add_to_site ) {
+
+		// Make sure bbPress roles are added
+		bbp_add_forums_roles();
+
+		$bbp->current_user->add_role( $new_role );
+
+	// Don't add the user, but still give them the correct caps dynamically
+	} else {		
+		$bbp->current_user->caps[$new_role] = true;
+		$bbp->current_user->get_role_caps();
+	}
+}
+
+/**
+ * Return a map of WordPress roles to bbPress roles. Used to automatically grant
+ * appropriate bbPress roles to WordPress users that wouldn't already have a
+ * role in the forums. Also guarantees WordPress admins get the Keymaster role.
+ *
+ * @since bbPress (r4334)
+ *
+ * @return array Filtered array of WordPress roles to bbPress roles
+ */
+function bbp_get_user_role_map() {
+
+	// Get the default role once here
+	$default_role = bbp_get_default_role();
+
+	// Return filtered results, forcing admins to keymasters.
+	return (array) apply_filters( 'bbp_get_user_role_map', array (
+		'administrator' => bbp_get_keymaster_role(),
+		'editor'        => $default_role,
+		'author'        => $default_role,
+		'contributor'   => $default_role,
+		'subscriber'    => $default_role
+	) );
+}
+
+/** User Status ***************************************************************/
+
+/**
+ * Checks if the user has been marked as a spammer.
+ *
+ * @since bbPress (r3355)
+ *
+ * @param int $user_id int The ID for the user.
+ * @return bool True if spammer, False if not.
+ */
+function bbp_is_user_spammer( $user_id = 0 ) {
+
+	// Default to current user
+	if ( empty( $user_id ) && is_user_logged_in() )
+		$user_id = bbp_get_current_user_id();
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	// Assume user is not spam
+	$is_spammer = false;
+
+	// Get user data
+	$user = get_userdata( $user_id );
+
+	// No user found
+	if ( empty( $user ) ) {
+		$is_spammer = false;
+
+	// Check if spam
+	} elseif ( !empty( $user->spam ) ) {
+		$is_spammer = true;
+	}
+
+	return (bool) apply_filters( 'bbp_core_is_user_spammer', $is_spammer );
+}
+
+/**
+ * Mark a users topics and replies as spam when the user is marked as spam
+ *
+ * @since bbPress (r3405)
+ *
+ * @global WPDB $wpdb
+ * @param int $user_id Optional. User ID to spam. Defaults to displayed user.
+
+ * @uses bbp_is_single_user()
+ * @uses bbp_is_user_home()
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_is_user_keymaster()
+ * @uses get_blogs_of_user()
+ * @uses get_current_blog_id()
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_reply_post_type()
+ * @uses switch_to_blog()
+ * @uses get_post_type()
+ * @uses bbp_spam_topic()
+ * @uses bbp_spam_reply()
+ * @uses restore_current_blog()
+ *
+ * @return If no user ID passed
+ */
+function bbp_make_spam_user( $user_id = 0 ) {
+
+	// Use displayed user if it's not yourself
+	if ( empty( $user_id ) && bbp_is_single_user() && !bbp_is_user_home() )
+		$user_id = bbp_get_displayed_user_id();
+
+	// Bail if no user ID
+	if ( empty( $user_id ) )
+		return false;
+
+	// Bail if user ID is keymaster
+	if ( bbp_is_user_keymaster( $user_id ) )
+		return false;
+
+	// Arm the torpedos
+	global $wpdb;
+
+	// Get the blog IDs of the user to mark as spam
+	$blogs = get_blogs_of_user( $user_id, true );
+
+	// If user has no blogs, they are a guest on this site
+	if ( empty( $blogs ) )
+		$blogs[$wpdb->blogid] = array();
+
+	// Make array of post types to mark as spam
+	$post_types  = array( bbp_get_topic_post_type(), bbp_get_reply_post_type() );
+	$post_types  = "'" . implode( "', '", $post_types ) . "'";
+
+	// Loop through blogs and remove their posts
+	foreach ( (array) array_keys( $blogs ) as $blog_id ) {
+
+		// Switch to the blog ID
+		switch_to_blog( $blog_id );
+
+		// Get topics and replies
+		$posts = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_author = %d AND post_status = '%s' AND post_type IN ( {$post_types} )", $user_id, bbp_get_public_status_id() ) );
+
+		// Loop through posts and spam them
+		if ( !empty( $posts ) ) {
+			foreach ( $posts as $post_id ) {
+
+				// The routines for topics ang replies are different, so use the
+				// correct one based on the post type
+				switch ( get_post_type( $post_id ) ) {
+
+					case bbp_get_topic_post_type() :
+						bbp_spam_topic( $post_id );
+						break;
+
+					case bbp_get_reply_post_type() :
+						bbp_spam_reply( $post_id );
+						break;
+				}
+			}
+		}
+
+		// Switch back to current blog
+		restore_current_blog();
+	}
+
+	// Success
+	return true;
+}
+
+/**
+ * Mark a users topics and replies as spam when the user is marked as spam
+ *
+ * @since bbPress (r3405)
+ *
+ * @global WPDB $wpdb
+ * @param int $user_id Optional. User ID to unspam. Defaults to displayed user.
+ *
+ * @uses bbp_is_single_user()
+ * @uses bbp_is_user_home()
+ * @uses bbp_get_displayed_user_id()
+ * @uses bbp_is_user_keymaster()
+ * @uses get_blogs_of_user()
+ * @uses bbp_get_topic_post_type()
+ * @uses bbp_get_reply_post_type()
+ * @uses switch_to_blog()
+ * @uses get_post_type()
+ * @uses bbp_unspam_topic()
+ * @uses bbp_unspam_reply()
+ * @uses restore_current_blog()
+ *
+ * @return If no user ID passed
+ */
+function bbp_make_ham_user( $user_id = 0 ) {
+
+	// Use displayed user if it's not yourself
+	if ( empty( $user_id ) && bbp_is_single_user() && !bbp_is_user_home() )
+		$user_id = bbp_get_displayed_user_id();
+
+	// Bail if no user ID
+	if ( empty( $user_id ) )
+		return false;
+
+	// Bail if user ID is keymaster
+	if ( bbp_is_user_keymaster( $user_id ) )
+		return false;
+
+	// Arm the torpedos
+	global $wpdb;
+
+	// Get the blog IDs of the user to mark as spam
+	$blogs = get_blogs_of_user( $user_id, true );
+
+	// If user has no blogs, they are a guest on this site
+	if ( empty( $blogs ) )
+		$blogs[$wpdb->blogid] = array();
+
+	// Make array of post types to mark as spam
+	$post_types = array( bbp_get_topic_post_type(), bbp_get_reply_post_type() );
+	$post_types = "'" . implode( "', '", $post_types ) . "'";
+
+	// Loop through blogs and remove their posts
+	foreach ( (array) array_keys( $blogs ) as $blog_id ) {
+
+		// Switch to the blog ID
+		switch_to_blog( $blog_id );
+
+		// Get topics and replies
+		$posts = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_author = %d AND post_status = '%s' AND post_type IN ( {$post_types} )", $user_id, bbp_get_spam_status_id() ) );
+
+		// Loop through posts and spam them
+		if ( !empty( $posts ) ) {
+			foreach ( $posts as $post_id ) {
+
+				// The routines for topics ang replies are different, so use the
+				// correct one based on the post type
+				switch ( get_post_type( $post_id ) ) {
+
+					case bbp_get_topic_post_type() :
+						bbp_unspam_topic( $post_id );
+						break;
+
+					case bbp_get_reply_post_type() :
+						bbp_unspam_reply( $post_id );
+						break;
+				}
+			}
+		}
+
+		// Switch back to current blog
+		restore_current_blog();
+	}
+
+	// Success
+	return true;
+}
+
+/**
+ * Checks if the user has been marked as deleted.
+ *
+ * @since bbPress (r3355)
+ *
+ * @param int $user_id int The ID for the user.
+ * @return bool True if deleted, False if not.
+ */
+function bbp_is_user_deleted( $user_id = 0 ) {
+
+	// Default to current user
+	if ( empty( $user_id ) && is_user_logged_in() )
+		$user_id = bbp_get_current_user_id();
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	// Assume user is not deleted
+	$is_deleted = false;
+
+	// Get user data
+	$user = get_userdata( $user_id );
+
+	// No user found
+	if ( empty( $user ) ) {
+		$is_deleted = true;
+
+	// Check if deleted
+	} elseif ( !empty( $user->deleted ) ) {
+		$is_deleted = true;
+	}
+
+	return (bool) apply_filters( 'bbp_core_is_user_deleted', $is_deleted );
+}
+
+/**
+ * Checks if user is active
+ *
+ * @since bbPress (r3502)
+ *
+ * @uses is_user_logged_in() To check if user is logged in
+ * @uses bbp_get_displayed_user_id() To get current user ID
+ * @uses bbp_is_user_spammer() To check if user is spammer
+ * @uses bbp_is_user_deleted() To check if user is deleted
+ *
+ * @param int $user_id The user ID to check
+ * @return bool True if public, false if not
+ */
+function bbp_is_user_active( $user_id = 0 ) {
+
+	// Default to current user
+	if ( empty( $user_id ) && is_user_logged_in() )
+		$user_id = bbp_get_current_user_id();
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	// Check spam
+	if ( bbp_is_user_spammer( $user_id ) )
+		return false;
+
+	// Check deleted
+	if ( bbp_is_user_deleted( $user_id ) )
+		return false;
+
+	// Assume true if not spam or deleted
+	return true;
+}
+
+/**
+ * Checks if user is not active.
+ *
+ * @since bbPress (r3502)
+ *
+ * @uses is_user_logged_in() To check if user is logged in
+ * @uses bbp_get_displayed_user_id() To get current user ID
+ * @uses bbp_is_user_active() To check if user is active
+ *
+ * @param int $user_id The user ID to check. Defaults to current user ID
+ * @return bool True if inactive, false if active
+ */
+function bbp_is_user_inactive( $user_id = 0 ) {
+
+	// Default to current user
+	if ( empty( $user_id ) && is_user_logged_in() )
+		$user_id = bbp_get_current_user_id();
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	// Return the inverse of active
+	return !bbp_is_user_active( $user_id );
+}
+
+/**
+ * Checks if user is a keymaster
+ *
+ * @since bbPress (r4783)
+ *
+ * @param int $user_id 
+ * @return bool True if keymaster, false if not
+ */
+function bbp_is_user_keymaster( $user_id = 0 ) {
+
+	// Default to current user ID if none is passed
+	$_user_id = (int) ! empty( $user_id ) ? $user_id : bbp_get_current_user_id();
+
+	// Filter and return
+	return (bool) apply_filters( 'bbp_is_user_keymaster', user_can( $_user_id, 'keep_gate' ), $_user_id, $user_id );
+}
+
+/**
+ * Does a user have a profile for the current site
+ *
+ * @since bbPress (r4362)
+ *
+ * @param int $user_id User ID to check
+ * @param int $blog_id Blog ID to check
+ *
+ * @uses bbp_get_user_id() To verify the user ID
+ * @uses get_userdata() To get the user's data
+ * @uses bbp_is_user_keymaster() To determine if user can see inactive users
+ * @uses bbp_is_user_inactive() To check if user is spammer or deleted
+ * @uses apply_filters() To allow override of this functions result
+ *
+ * @return boolean Whether or not the user has a profile on this blog_id
+ */
+function bbp_user_has_profile( $user_id = 0 ) {
+
+	// Assume every user has a profile
+	$retval  = true;
+
+	// Validate user ID, default to displayed or current user
+	$user_id = bbp_get_user_id( $user_id, true, true );
+
+	// Try to get this user's data
+	$user    = get_userdata( $user_id );
+
+	// No user found, return false
+	if ( empty( $user ) ) {
+		$retval = false;
+
+	// User is inactive, and current user is not a keymaster
+	} elseif ( ! bbp_is_user_keymaster() && bbp_is_user_inactive( $user->ID ) ) {
+		$retval = false;
+	}
+
+	// Filter and return
+	return (bool) apply_filters( 'bbp_show_user_profile', $retval, $user_id );
+}
Index: /tags/2.5.4/includes/users/functions.php
===================================================================
--- /tags/2.5.4/includes/users/functions.php	(revision 5382)
+++ /tags/2.5.4/includes/users/functions.php	(revision 5382)
@@ -0,0 +1,1714 @@
+<?php
+
+/**
+ * bbPress User Functions
+ *
+ * @package bbPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Redirect back to $url when attempting to use the login page
+ *
+ * @since bbPress (r2815)
+ *
+ * @param string $url The url
+ * @param string $raw_url Raw url
+ * @param object $user User object
+ * @uses is_wp_error() To check if the user param is a {@link WP_Error}
+ * @uses admin_url() To get the admin url
+ * @uses home_url() To get the home url
+ * @uses esc_url() To escape the url
+ * @uses wp_safe_redirect() To redirect
+ */
+function bbp_redirect_login( $url = '', $raw_url = '', $user = '' ) {
+
+	// Raw redirect_to was passed, so use it
+	if ( !empty( $raw_url ) )
+		$url = $raw_url;
+
+	// $url was manually set in wp-login.php to redirect to admin
+	elseif ( admin_url() === $url )
+		$url = home_url();
+
+	// $url is empty
+	elseif ( empty( $url ) )
+		$url = home_url();
+
+	return apply_filters( 'bbp_redirect_login', $url, $raw_url, $user );
+}
+
+/**
+ * Is an anonymous topic/reply being made?
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses is_user_logged_in() Is the user logged in?
+ * @uses bbp_allow_anonymous() Is anonymous posting allowed?
+ * @uses apply_filters() Calls 'bbp_is_anonymous' with the return value
+ * @return bool True if anonymous is allowed and user is not logged in, false if
+ *               anonymous is not allowed or user is logged in
+ */
+function bbp_is_anonymous() {
+	if ( !is_user_logged_in() && bbp_allow_anonymous() )
+		$is_anonymous = true;
+	else
+		$is_anonymous = false;
+
+	return apply_filters( 'bbp_is_anonymous', $is_anonymous );
+}
+
+/**
+ * Echoes the values for current poster (uses WP comment cookies)
+ *
+ * @since bbPress (r2734)
+ *
+ * @param string $key Which value to echo?
+ * @uses bbp_get_current_anonymous_user_data() To get the current anonymous user
+ *                                              data
+ */
+function bbp_current_anonymous_user_data( $key = '' ) {
+	echo bbp_get_current_anonymous_user_data( $key );
+}
+
+	/**
+	 * Get the cookies for current poster (uses WP comment cookies).
+	 *
+	 * @since bbPress (r2734)
+	 *
+	 * @param string $key Optional. Which value to get? If not given, then
+	 *                     an array is returned.
+	 * @uses sanitize_comment_cookies() To sanitize the current poster data
+	 * @uses wp_get_current_commenter() To get the current poster data	 *
+	 * @return string|array Cookie(s) for current poster
+	 */
+	function bbp_get_current_anonymous_user_data( $key = '' ) {
+		$cookie_names = array(
+			'name'  => 'comment_author',
+			'email' => 'comment_author_email',
+			'url'   => 'comment_author_url',
+
+			// Here just for the sake of them, use the above ones
+			'comment_author'       => 'comment_author',
+			'comment_author_email' => 'comment_author_email',
+			'comment_author_url'   => 'comment_author_url',
+		);
+
+		sanitize_comment_cookies();
+
+		$bbp_current_poster = wp_get_current_commenter();
+
+		if ( !empty( $key ) && in_array( $key, array_keys( $cookie_names ) ) )
+			return $bbp_current_poster[$cookie_names[$key]];
+
+		return $bbp_current_poster;
+	}
+
+/**
+ * Set the cookies for current poster (uses WP comment cookies)
+ *
+ * @since bbPress (r2734)
+ *
+ * @param array $anonymous_data With keys 'bbp_anonymous_name',
+ *                               'bbp_anonymous_email', 'bbp_anonymous_website'.
+ *                               Should be sanitized (see
+ *                               {@link bbp_filter_anonymous_post_data()} for
+ *                               sanitization)
+ * @uses apply_filters() Calls 'comment_cookie_lifetime' for cookie lifetime.
+ *                        Defaults to 30000000.
+ */
+function bbp_set_current_anonymous_user_data( $anonymous_data = array() ) {
+	if ( empty( $anonymous_data ) || !is_array( $anonymous_data ) )
+		return;
+
+	$comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
+
+	setcookie( 'comment_author_'       . COOKIEHASH, $anonymous_data['bbp_anonymous_name'],    time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
+	setcookie( 'comment_author_email_' . COOKIEHASH, $anonymous_data['bbp_anonymous_email'],   time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
+	setcookie( 'comment_author_url_'   . COOKIEHASH, $anonymous_data['bbp_anonymous_website'], time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
+}
+
+/**
+ * Get the poster IP address
+ *
+ * @since bbPress (r3120)
+ *
+ * @return string
+ */
+function bbp_current_author_ip() {
+	$retval = preg_replace( '/[^0-9a-fA-F:., ]/', '', $_SERVER['REMOTE_ADDR'] );
+
+	return apply_filters( 'bbp_current_author_ip', $retval );
+}
+
+/**
+ * Get the poster user agent
+ *
+ * @since bbPress (r3446)
+ *
+ * @return string
+ */
+function bbp_current_author_ua() {
+	$retval = !empty( $_SERVER['HTTP_USER_AGENT'] ) ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : '';
+
+	return apply_filters( 'bbp_current_author_ua', $retval );
+}
+
+/** Post Counts ***************************************************************/
+
+/**
+ * Return the raw database count of topics by a user
+ *
+ * @since bbPress (r3633)
+ * @global WPDB $wpdb
+ * @uses bbp_get_user_id()
+ * @uses get_posts_by_author_sql()
+ * @uses bbp_get_topic_post_type()
+ * @uses apply_filters()
+ * @return int Raw DB count of topics
+ */
+function bbp_get_user_topic_count_raw( $user_id = 0 ) {
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	global $wpdb;
+
+	$where = get_posts_by_author_sql( bbp_get_topic_post_type(), true, $user_id );
+	$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} {$where}" );
+
+	return (int) apply_filters( 'bbp_get_user_topic_count_raw', $count, $user_id );
+}
+
+/**
+ * Return the raw database count of replies by a user
+ *
+ * @since bbPress (r3633)
+ * @global WPDB $wpdb
+ * @uses bbp_get_user_id()
+ * @uses get_posts_by_author_sql()
+ * @uses bbp_get_reply_post_type()
+ * @uses apply_filters()
+ * @return int Raw DB count of replies
+ */
+function bbp_get_user_reply_count_raw( $user_id = 0 ) {
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	global $wpdb;
+
+	$where = get_posts_by_author_sql( bbp_get_reply_post_type(), true, $user_id );
+	$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} {$where}" );
+
+	return (int) apply_filters( 'bbp_get_user_reply_count_raw', $count, $user_id );
+}
+
+/** Favorites *****************************************************************/
+
+/**
+ * Get the users who have made the topic favorite
+ *
+ * @since bbPress (r2658)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses wpdb::get_col() To execute our query and get the column back
+ * @uses apply_filters() Calls 'bbp_get_topic_favoriters' with the users and
+ *                        topic id
+ * @return array|bool Results if the topic has any favoriters, otherwise false
+ */
+function bbp_get_topic_favoriters( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+	if ( empty( $topic_id ) )
+		return;
+
+	global $wpdb;
+
+	$key   = $wpdb->prefix . '_bbp_favorites';
+	$users = wp_cache_get( 'bbp_get_topic_favoriters_' . $topic_id, 'bbpress_users' );
+	if ( false === $users ) {
+		$users = $wpdb->get_col( "SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$key}' and FIND_IN_SET('{$topic_id}', meta_value) > 0" );
+		wp_cache_set( 'bbp_get_topic_favoriters_' . $topic_id, $users, 'bbpress_users' );
+	}
+
+	return apply_filters( 'bbp_get_topic_favoriters', $users );
+}
+
+/**
+ * Get a user's favorite topics
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_favorites_topic_ids() To get the user's favorites
+ * @uses bbp_has_topics() To get the topics
+ * @uses apply_filters() Calls 'bbp_get_user_favorites' with the topic query and
+ *                        user id
+ * @return array|bool Results if user has favorites, otherwise false
+ */
+function bbp_get_user_favorites( $user_id = 0 ) {
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	// If user has favorites, load them
+	$favorites = bbp_get_user_favorites_topic_ids( $user_id );
+	if ( !empty( $favorites ) ) {
+		$query = bbp_has_topics( array( 'post__in' => $favorites ) );
+	} else {
+		$query = false;
+	}
+
+	return apply_filters( 'bbp_get_user_favorites', $query, $user_id, $favorites );
+}
+
+/**
+ * Get a user's favorite topics' ids
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_id() To get the user id
+ * @uses get_user_option() To get the user favorites
+ * @uses apply_filters() Calls 'bbp_get_user_favorites_topic_ids' with
+ *                        the favorites and user id
+ * @return array|bool Results if user has favorites, otherwise false
+ */
+function bbp_get_user_favorites_topic_ids( $user_id = 0 ) {
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	$favorites = get_user_option( '_bbp_favorites', $user_id );
+	$favorites = array_filter( wp_parse_id_list( $favorites ) );
+
+	return (array) apply_filters( 'bbp_get_user_favorites_topic_ids', $favorites, $user_id );
+}
+
+/**
+ * Check if a topic is in user's favorites or not
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_user_id() To get the user id
+ * @uses bbp_get_user_favorites_topic_ids() To get the user favorites
+ * @uses bbp_get_topic() To get the topic
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses apply_filters() Calls 'bbp_is_user_favorite' with the bool, user id,
+ *                        topic id and favorites
+ * @return bool True if the topic is in user's favorites, otherwise false
+ */
+function bbp_is_user_favorite( $user_id = 0, $topic_id = 0 ) {
+
+	$user_id = bbp_get_user_id( $user_id, true, true );
+	if ( empty( $user_id ) )
+		return false;
+
+	$retval    = false;
+	$favorites = bbp_get_user_favorites_topic_ids( $user_id );
+
+	if ( !empty( $favorites ) ) {
+
+		// Checking a specific topic id
+		if ( !empty( $topic_id ) ) {
+			$topic    = bbp_get_topic( $topic_id );
+			$topic_id = !empty( $topic ) ? $topic->ID : 0;
+
+		// Using the global topic id
+		} elseif ( bbp_get_topic_id() ) {
+			$topic_id = bbp_get_topic_id();
+
+		// Use the current post id
+		} elseif ( !bbp_get_topic_id() ) {
+			$topic_id = get_the_ID();
+		}
+
+		// Is topic_id in the user's favorites
+		if ( !empty( $topic_id ) ) {
+			$retval = in_array( $topic_id, $favorites );
+		}
+	}
+
+	return (bool) apply_filters( 'bbp_is_user_favorite', (bool) $retval, $user_id, $topic_id, $favorites );
+}
+
+/**
+ * Add a topic to user's favorites
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_user_favorites_topic_ids() To get the user favorites
+ * @uses update_user_option() To update the user favorites
+ * @uses do_action() Calls 'bbp_add_user_favorite' with the user id and topic id
+ * @return bool Always true
+ */
+function bbp_add_user_favorite( $user_id = 0, $topic_id = 0 ) {
+	if ( empty( $user_id ) || empty( $topic_id ) )
+		return false;
+
+	$topic = bbp_get_topic( $topic_id );
+	if ( empty( $topic ) )
+		return false;
+
+	$favorites = bbp_get_user_favorites_topic_ids( $user_id );
+	if ( !in_array( $topic_id, $favorites ) ) {
+		$favorites[] = $topic_id;
+		$favorites   = implode( ',', wp_parse_id_list( array_filter( $favorites ) ) );
+		update_user_option( $user_id, '_bbp_favorites', $favorites );
+	}
+
+	do_action( 'bbp_add_user_favorite', $user_id, $topic_id );
+
+	return true;
+}
+
+/**
+ * Remove a topic from user's favorites
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_user_favorites_topic_ids() To get the user favorites
+ * @uses update_user_option() To update the user favorites
+ * @uses delete_user_option() To delete the user favorites meta
+ * @uses do_action() Calls 'bbp_remove_user_favorite' with the user & topic id
+ * @return bool True if the topic was removed from user's favorites, otherwise
+ *               false
+ */
+function bbp_remove_user_favorite( $user_id, $topic_id ) {
+	if ( empty( $user_id ) || empty( $topic_id ) )
+		return false;
+
+	$favorites = (array) bbp_get_user_favorites_topic_ids( $user_id );
+	if ( empty( $favorites ) )
+		return false;
+
+	$pos = array_search( $topic_id, $favorites );
+	if ( is_numeric( $pos ) ) {
+		array_splice( $favorites, $pos, 1 );
+		$favorites = array_filter( $favorites );
+
+		if ( !empty( $favorites ) ) {
+			$favorites = implode( ',', wp_parse_id_list( $favorites ) );
+			update_user_option( $user_id, '_bbp_favorites', $favorites );
+		} else {
+			delete_user_option( $user_id, '_bbp_favorites' );
+		}
+	}
+
+	do_action( 'bbp_remove_user_favorite', $user_id, $topic_id );
+
+	return true;
+}
+
+/**
+ * Handles the front end adding and removing of favorite topics
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_get_user_id() To get the user id
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit the user
+ * @uses bbPress:errors:add() To log the error messages
+ * @uses bbp_is_user_favorite() To check if the topic is in user's favorites
+ * @uses bbp_remove_user_favorite() To remove the user favorite
+ * @uses bbp_add_user_favorite() To add the user favorite
+ * @uses do_action() Calls 'bbp_favorites_handler' with success, user id, topic
+ *                    id and action
+ * @uses bbp_is_favorites() To check if it's the favorites page
+ * @uses bbp_get_favorites_link() To get the favorites page link
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ * @uses wp_safe_redirect() To redirect to the url
+ */
+function bbp_favorites_handler( $action = '' ) {
+
+	if ( !bbp_is_favorites_active() )
+		return false;
+
+	// Bail if no topic ID is passed
+	if ( empty( $_GET['topic_id'] ) )
+		return;
+
+	// Setup possible get actions
+	$possible_actions = array(
+		'bbp_favorite_add',
+		'bbp_favorite_remove',
+	);
+
+	// Bail if actions aren't meant for this function
+	if ( !in_array( $action, $possible_actions ) )
+		return;
+
+	// What action is taking place?
+	$topic_id    = intval( $_GET['topic_id'] );
+	$user_id     = bbp_get_user_id( 0, true, true );
+
+	// Check for empty topic
+	if ( empty( $topic_id ) ) {
+		bbp_add_error( 'bbp_favorite_topic_id', __( '<strong>ERROR</strong>: No topic was found! Which topic are you marking/unmarking as favorite?', 'bbpress' ) );
+
+	// Check nonce
+	} elseif ( ! bbp_verify_nonce_request( 'toggle-favorite_' . $topic_id ) ) {
+		bbp_add_error( 'bbp_favorite_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+
+	// Check current user's ability to edit the user
+	} elseif ( !current_user_can( 'edit_user', $user_id ) ) {
+		bbp_add_error( 'bbp_favorite_permissions', __( '<strong>ERROR</strong>: You don\'t have the permission to edit favorites of that user!', 'bbpress' ) );
+	}
+
+	// Bail if errors
+	if ( bbp_has_errors() )
+		return;
+
+	/** No errors *************************************************************/
+
+	$is_favorite = bbp_is_user_favorite( $user_id, $topic_id );
+	$success     = false;
+
+	if ( true === $is_favorite && 'bbp_favorite_remove' === $action )
+		$success = bbp_remove_user_favorite( $user_id, $topic_id );
+	elseif ( false === $is_favorite && 'bbp_favorite_add' === $action )
+		$success = bbp_add_user_favorite( $user_id, $topic_id );
+
+	// Do additional favorites actions
+	do_action( 'bbp_favorites_handler', $success, $user_id, $topic_id, $action );
+
+	// Success!
+	if ( true === $success ) {
+
+		// Redirect back from whence we came
+		if ( bbp_is_favorites() ) {
+			$redirect = bbp_get_favorites_permalink( $user_id );
+		} elseif ( bbp_is_single_user() ) {
+			$redirect = bbp_get_user_profile_url();
+		} elseif ( is_singular( bbp_get_topic_post_type() ) ) {
+			$redirect = bbp_get_topic_permalink( $topic_id );
+		} elseif ( is_single() || is_page() ) {
+			$redirect = get_permalink();
+		} else {
+			$redirect = get_permalink( $topic_id );
+		}
+
+		wp_safe_redirect( $redirect );
+
+		// For good measure
+		exit();
+
+	// Fail! Handle errors
+	} elseif ( true === $is_favorite && 'bbp_favorite_remove' === $action ) {
+		bbp_add_error( 'bbp_favorite_remove', __( '<strong>ERROR</strong>: There was a problem removing that topic from favorites!', 'bbpress' ) );
+	} elseif ( false === $is_favorite && 'bbp_favorite_add' === $action ) {
+		bbp_add_error( 'bbp_favorite_add',    __( '<strong>ERROR</strong>: There was a problem favoriting that topic!', 'bbpress' ) );
+	}
+}
+
+/** Subscriptions *************************************************************/
+
+/**
+ * Get the users who have subscribed to the forum
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $forum_id Optional. forum id
+ * @uses wpdb::get_col() To execute our query and get the column back
+ * @uses apply_filters() Calls 'bbp_get_forum_subscribers' with the subscribers
+ * @return array|bool Results if the forum has any subscribers, otherwise false
+ */
+function bbp_get_forum_subscribers( $forum_id = 0 ) {
+	$forum_id = bbp_get_forum_id( $forum_id );
+	if ( empty( $forum_id ) )
+		return;
+
+	global $wpdb;
+
+	$key   = $wpdb->prefix . '_bbp_forum_subscriptions';
+	$users = wp_cache_get( 'bbp_get_forum_subscribers_' . $forum_id, 'bbpress_users' );
+	if ( false === $users ) {
+		$users = $wpdb->get_col( "SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$key}' and FIND_IN_SET('{$forum_id}', meta_value) > 0" );
+		wp_cache_set( 'bbp_get_forum_subscribers_' . $forum_id, $users, 'bbpress_users' );
+	}
+
+	return apply_filters( 'bbp_get_forum_subscribers', $users );
+}
+
+/**
+ * Get the users who have subscribed to the topic
+ *
+ * @since bbPress (r2668)
+ *
+ * @param int $topic_id Optional. Topic id
+ * @uses wpdb::get_col() To execute our query and get the column back
+ * @uses apply_filters() Calls 'bbp_get_topic_subscribers' with the subscribers
+ * @return array|bool Results if the topic has any subscribers, otherwise false
+ */
+function bbp_get_topic_subscribers( $topic_id = 0 ) {
+	$topic_id = bbp_get_topic_id( $topic_id );
+	if ( empty( $topic_id ) )
+		return;
+
+	global $wpdb;
+
+	$key   = $wpdb->prefix . '_bbp_subscriptions';
+	$users = wp_cache_get( 'bbp_get_topic_subscribers_' . $topic_id, 'bbpress_users' );
+	if ( false === $users ) {
+		$users = $wpdb->get_col( "SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$key}' and FIND_IN_SET('{$topic_id}', meta_value) > 0" );
+		wp_cache_set( 'bbp_get_topic_subscribers_' . $topic_id, $users, 'bbpress_users' );
+	}
+
+	return apply_filters( 'bbp_get_topic_subscribers', $users );
+}
+
+/**
+ * Get a user's subscribed topics
+ *
+ * @since bbPress (r2668)
+ *
+ * @deprecated since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_topic_subscriptions() To get the user's subscriptions
+ * @return array|bool Results if user has subscriptions, otherwise false
+ */
+function bbp_get_user_subscriptions( $user_id = 0 ) {
+	_deprecated_function( __FUNCTION__, 2.5, 'bbp_get_user_topic_subscriptions()' );
+	$query = bbp_get_user_topic_subscriptions( $user_id );
+	return apply_filters( 'bbp_get_user_subscriptions', $query, $user_id );
+}
+
+/**
+ * Get a user's subscribed topics
+ *
+ * @since bbPress (r2668)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_subscribed_topic_ids() To get the user's subscriptions
+ * @uses bbp_has_topics() To get the topics
+ * @uses apply_filters() Calls 'bbp_get_user_subscriptions' with the topic query
+ *                        and user id
+ * @return array|bool Results if user has subscriptions, otherwise false
+ */
+function bbp_get_user_topic_subscriptions( $user_id = 0 ) {
+
+	// Default to the displayed user
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) ) {
+		return false;
+	}
+
+	// If user has subscriptions, load them
+	$subscriptions = bbp_get_user_subscribed_topic_ids( $user_id );
+	if ( !empty( $subscriptions ) ) {
+		$query = bbp_has_topics( array( 'post__in' => $subscriptions ) );
+	} else {
+		$query = false;
+	}
+
+	return apply_filters( 'bbp_get_user_topic_subscriptions', $query, $user_id );
+}
+
+/**
+ * Get a user's subscribed forums
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_subscribed_forum_ids() To get the user's subscriptions
+ * @uses bbp_has_forums() To get the forums
+ * @uses apply_filters() Calls 'bbp_get_user_forum_subscriptions' with the forum
+ *                        query and user id
+ * @return array|bool Results if user has subscriptions, otherwise false
+ */
+function bbp_get_user_forum_subscriptions( $user_id = 0 ) {
+
+	// Default to the displayed user
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) ) {
+		return false;
+	}
+
+	// If user has subscriptions, load them
+	$subscriptions = bbp_get_user_subscribed_forum_ids( $user_id );
+	if ( !empty( $subscriptions ) ) {
+		$query = bbp_has_forums( array( 'post__in' => $subscriptions ) );
+	} else {
+		$query = false;
+	}
+
+	return apply_filters( 'bbp_get_user_forum_subscriptions', $query, $user_id );
+}
+
+/**
+ * Get a user's subscribed forum ids
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_id() To get the user id
+ * @uses get_user_option() To get the user's subscriptions
+ * @uses apply_filters() Calls 'bbp_get_user_subscribed_forum_ids' with
+ *                        the subscriptions and user id
+ * @return array|bool Results if user has subscriptions, otherwise false
+ */
+function bbp_get_user_subscribed_forum_ids( $user_id = 0 ) {
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	$subscriptions = get_user_option( '_bbp_forum_subscriptions', $user_id );
+	$subscriptions = array_filter( wp_parse_id_list( $subscriptions ) );
+
+	return (array) apply_filters( 'bbp_get_user_subscribed_forum_ids', $subscriptions, $user_id );
+}
+
+/**
+ * Get a user's subscribed topics' ids
+ *
+ * @since bbPress (r2668)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_id() To get the user id
+ * @uses get_user_option() To get the user's subscriptions
+ * @uses apply_filters() Calls 'bbp_get_user_subscribed_topic_ids' with
+ *                        the subscriptions and user id
+ * @return array|bool Results if user has subscriptions, otherwise false
+ */
+function bbp_get_user_subscribed_topic_ids( $user_id = 0 ) {
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	$subscriptions = get_user_option( '_bbp_subscriptions', $user_id );
+	$subscriptions = array_filter( wp_parse_id_list( $subscriptions ) );
+
+	return (array) apply_filters( 'bbp_get_user_subscribed_topic_ids', $subscriptions, $user_id );
+}
+
+/**
+ * Check if a topic or forum is in user's subscription list or not
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $forum_id Optional. Topic id
+ * @uses get_post() To get the post object
+ * @uses bbp_get_user_subscribed_forum_ids() To get the user's forum subscriptions
+ * @uses bbp_get_user_subscribed_topic_ids() To get the user's topic subscriptions
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses apply_filters() Calls 'bbp_is_user_subscribed' with the bool, user id,
+ *                        forum/topic id and subsriptions
+ * @return bool True if the forum or topic is in user's subscriptions, otherwise false
+ */
+function bbp_is_user_subscribed( $user_id = 0, $object_id = 0 ) {
+
+	// Assume user is not subscribed
+	$retval = false;
+
+	// Setup ID's array
+	$subscribed_ids = array();
+
+	// User and object ID's are passed
+	if ( ! empty( $user_id ) && ! empty( $object_id ) ) {
+
+		// Get the post type
+		$post_type = get_post_type( $object_id );
+
+		// Post exists, so check the types
+		if ( ! empty( $post_type ) ) {
+
+			switch( $post_type ) {
+
+				// Forum
+				case bbp_get_forum_post_type() :
+					$subscribed_ids = bbp_get_user_subscribed_forum_ids( $user_id );
+					$retval         = bbp_is_user_subscribed_to_forum( $user_id, $object_id, $subscribed_ids );
+					break;
+
+				// Topic (default)
+				case bbp_get_topic_post_type() :
+				default :
+					$subscribed_ids = bbp_get_user_subscribed_topic_ids( $user_id );
+					$retval         = bbp_is_user_subscribed_to_topic( $user_id, $object_id, $subscribed_ids );
+					break;
+			}
+		}
+	}
+
+	return (bool) apply_filters( 'bbp_is_user_subscribed', $retval, $user_id, $object_id, $subscribed_ids );
+}
+
+/**
+ * Check if a forum is in user's subscription list or not
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $forum_id Optional. Topic id
+ * @param array $subscribed_ids Optional. Array of forum ID's to check
+ * @uses bbp_get_user_id() To get the user id
+ * @uses bbp_get_user_subscribed_forum_ids() To get the user's subscriptions
+ * @uses bbp_get_forum() To get the forum
+ * @uses bbp_get_forum_id() To get the forum id
+ * @uses apply_filters() Calls 'bbp_is_user_subscribed' with the bool, user id,
+ *                        forum id and subsriptions
+ * @return bool True if the forum is in user's subscriptions, otherwise false
+ */
+function bbp_is_user_subscribed_to_forum( $user_id = 0, $forum_id = 0, $subscribed_ids = array() ) {
+
+	// Assume user is not subscribed
+	$retval = false;
+
+	// Validate user
+	$user_id = bbp_get_user_id( $user_id, true, true );
+	if ( ! empty( $user_id ) ) {
+
+		// Get subscription ID's if none passed
+		if ( empty( $subscribed_ids ) ) {
+			$subscribed_ids = bbp_get_user_subscribed_forum_ids( $user_id );
+		}
+
+		// User has forum subscriptions
+		if ( ! empty( $subscribed_ids ) ) {
+
+			// Checking a specific forum id
+			if ( ! empty( $forum_id ) ) {
+				$forum    = bbp_get_forum( $forum_id );
+				$forum_id = ! empty( $forum ) ? $forum->ID : 0;
+
+			// Using the global forum id
+			} elseif ( bbp_get_forum_id() ) {
+				$forum_id = bbp_get_forum_id();
+
+			// Use the current post id
+			} elseif ( ! bbp_get_forum_id() ) {
+				$forum_id = get_the_ID();
+			}
+
+			// Is forum_id in the user's favorites
+			if ( ! empty( $forum_id ) ) {
+				$retval = in_array( $forum_id, $subscribed_ids );
+			}
+		}
+	}
+
+	return (bool) apply_filters( 'bbp_is_user_subscribed_to_forum', (bool) $retval, $user_id, $forum_id, $subscribed_ids );
+}
+
+/**
+ * Check if a topic is in user's subscription list or not
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @param array $subscribed_ids Optional. Array of topic ID's to check
+ * @uses bbp_get_user_id() To get the user id
+ * @uses bbp_get_user_subscribed_topic_ids() To get the user's subscriptions
+ * @uses bbp_get_topic() To get the topic
+ * @uses bbp_get_topic_id() To get the topic id
+ * @uses apply_filters() Calls 'bbp_is_user_subscribed' with the bool, user id,
+ *                        topic id and subsriptions
+ * @return bool True if the topic is in user's subscriptions, otherwise false
+ */
+function bbp_is_user_subscribed_to_topic( $user_id = 0, $topic_id = 0, $subscribed_ids = array() ) {
+
+	// Assume user is not subscribed
+	$retval = false;
+
+	// Validate user
+	$user_id = bbp_get_user_id( $user_id, true, true );
+	if ( !empty( $user_id ) ) {
+
+		// Get subscription ID's if none passed
+		if ( empty( $subscribed_ids ) ) {
+			$subscribed_ids = bbp_get_user_subscribed_topic_ids( $user_id );
+		}
+
+		// User has topic subscriptions
+		if ( ! empty( $subscribed_ids ) ) {
+
+			// Checking a specific topic id
+			if ( ! empty( $topic_id ) ) {
+				$topic    = bbp_get_topic( $topic_id );
+				$topic_id = ! empty( $topic ) ? $topic->ID : 0;
+
+			// Using the global topic id
+			} elseif ( bbp_get_topic_id() ) {
+				$topic_id = bbp_get_topic_id();
+
+			// Use the current post id
+			} elseif ( !bbp_get_topic_id() ) {
+				$topic_id = get_the_ID();
+			}
+
+			// Is topic_id in the user's favorites
+			if ( ! empty( $topic_id ) ) {
+				$retval = in_array( $topic_id, $subscribed_ids );
+			}
+		}
+	}
+
+	return (bool) apply_filters( 'bbp_is_user_subscribed_to_topic', (bool) $retval, $user_id, $topic_id, $subscribed_ids );
+}
+
+/**
+ * Add a topic to user's subscriptions
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @uses get_post() To get the post object
+ * @uses bbp_get_user_subscribed_forum_ids() To get the user's forum subscriptions
+ * @uses bbp_get_user_subscribed_topic_ids() To get the user's topic subscriptions
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses update_user_option() To update the user's subscriptions
+ * @uses do_action() Calls 'bbp_add_user_subscription' with the user & topic id
+ * @return bool Always true
+ */
+function bbp_add_user_subscription( $user_id = 0, $object_id = 0 ) {
+	if ( empty( $user_id ) || empty( $object_id ) ) {
+		return false;
+	}
+
+	// Get the post type
+	$post_type = get_post_type( $object_id );
+	if ( empty( $post_type ) ) {
+		return false;
+	}
+
+	switch( $post_type ) {
+
+		// Forum
+		case bbp_get_forum_post_type() :
+			bbp_add_user_forum_subscription( $user_id, $object_id );
+			break;
+
+		// Topic
+		case bbp_get_topic_post_type() :
+		default :
+			bbp_add_user_topic_subscription( $user_id, $object_id );
+			break;
+	}
+
+	do_action( 'bbp_add_user_subscription', $user_id, $object_id, $post_type );
+
+	return true;
+}
+
+/**
+ * Add a forum to user's subscriptions
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $forum_id Optional. forum id
+ * @uses bbp_get_user_subscribed_forum_ids() To get the user's subscriptions
+ * @uses bbp_get_forum() To get the forum
+ * @uses update_user_option() To update the user's subscriptions
+ * @uses do_action() Calls 'bbp_add_user_subscription' with the user & forum id
+ * @return bool Always true
+ */
+function bbp_add_user_forum_subscription( $user_id = 0, $forum_id = 0 ) {
+	if ( empty( $user_id ) || empty( $forum_id ) ) {
+		return false;
+	}
+
+	$forum = bbp_get_forum( $forum_id );
+	if ( empty( $forum ) ) {
+		return false;
+	}
+
+	$subscriptions = (array) bbp_get_user_subscribed_forum_ids( $user_id );
+	if ( !in_array( $forum_id, $subscriptions ) ) {
+		$subscriptions[] = $forum_id;
+		$subscriptions   = implode( ',', wp_parse_id_list( array_filter( $subscriptions ) ) );
+		update_user_option( $user_id, '_bbp_forum_subscriptions', $subscriptions );
+
+		wp_cache_delete( 'bbp_get_forum_subscribers_' . $forum_id, 'bbpress_users' );
+	}
+
+	do_action( 'bbp_add_user_forum_subscription', $user_id, $forum_id );
+
+	return true;
+}
+
+/**
+ * Add a topic to user's subscriptions
+ *
+ * @since bbPress (r2668)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_user_subscribed_topic_ids() To get the user's subscriptions
+ * @uses bbp_get_topic() To get the topic
+ * @uses update_user_option() To update the user's subscriptions
+ * @uses do_action() Calls 'bbp_add_user_subscription' with the user & topic id
+ * @return bool Always true
+ */
+function bbp_add_user_topic_subscription( $user_id = 0, $topic_id = 0 ) {
+	if ( empty( $user_id ) || empty( $topic_id ) ) {
+		return false;
+	}
+
+	$topic = bbp_get_topic( $topic_id );
+	if ( empty( $topic ) ) {
+		return false;
+	}
+
+	$subscriptions = (array) bbp_get_user_subscribed_topic_ids( $user_id );
+	if ( !in_array( $topic_id, $subscriptions ) ) {
+		$subscriptions[] = $topic_id;
+		$subscriptions   = implode( ',', wp_parse_id_list( array_filter( $subscriptions ) ) );
+		update_user_option( $user_id, '_bbp_subscriptions', $subscriptions );
+
+		wp_cache_delete( 'bbp_get_topic_subscribers_' . $topic_id, 'bbpress_users' );
+	}
+
+	do_action( 'bbp_add_user_topic_subscription', $user_id, $topic_id );
+
+	return true;
+}
+
+/**
+ * Remove a topic from user's subscriptions
+ *
+ * @since bbPress (r2668)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @uses get_post() To get the post object
+ * @uses bbp_get_forum_post_type() To get the forum post type
+ * @uses bbp_get_topic_post_type() To get the topic post type
+ * @uses bbp_remove_user_forum_subscription() To remove the user's subscription
+ * @uses bbp_remove_user_topic_subscription() To remove the user's subscription
+ * @uses do_action() Calls 'bbp_remove_user_subscription' with the user id and
+ *                    topic id
+ * @return bool True if the topic was removed from user's subscriptions,
+ *               otherwise false
+ */
+function bbp_remove_user_subscription( $user_id = 0, $object_id = 0 ) {
+	if ( empty( $user_id ) || empty( $object_id ) ) {
+		return false;
+	}
+
+	$post_type = get_post_type( $object_id );
+	if ( empty( $post_type ) ) {
+		return false;
+	}
+
+	switch( $post_type ) {
+
+		// Forum
+		case bbp_get_forum_post_type() :
+			bbp_remove_user_forum_subscription( $user_id, $object_id );
+			break;
+
+		// Topic
+		case bbp_get_topic_post_type() :
+		default :
+			bbp_remove_user_topic_subscription( $user_id, $object_id );
+			break;
+	}
+
+	do_action( 'bbp_remove_user_subscription', $user_id, $object_id, $post_type );
+
+	return true;
+}
+
+/**
+ * Remove a forum from user's subscriptions
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $forum_id Optional. forum id
+ * @uses bbp_get_user_subscribed_forum_ids() To get the user's subscriptions
+ * @uses update_user_option() To update the user's subscriptions
+ * @uses delete_user_option() To delete the user's subscriptions meta
+ * @uses do_action() Calls 'bbp_remove_user_subscription' with the user id and
+ *                    forum id
+ * @return bool True if the forum was removed from user's subscriptions,
+ *               otherwise false
+ */
+function bbp_remove_user_forum_subscription( $user_id, $forum_id ) {
+	if ( empty( $user_id ) || empty( $forum_id ) ) {
+		return false;
+	}
+
+	$subscriptions = (array) bbp_get_user_subscribed_forum_ids( $user_id );
+	if ( empty( $subscriptions ) ) {
+		return false;
+	}
+
+	$pos = array_search( $forum_id, $subscriptions );
+	if ( false === $pos ) {
+		return false;
+	}
+
+	array_splice( $subscriptions, $pos, 1 );
+	$subscriptions = array_filter( $subscriptions );
+
+	if ( !empty( $subscriptions ) ) {
+		$subscriptions = implode( ',', wp_parse_id_list( $subscriptions ) );
+		update_user_option( $user_id, '_bbp_forum_subscriptions', $subscriptions );
+	} else {
+		delete_user_option( $user_id, '_bbp_forum_subscriptions' );
+	}
+
+	wp_cache_delete( 'bbp_get_forum_subscribers_' . $forum_id, 'bbpress_users' );
+
+	do_action( 'bbp_remove_user_forum_subscription', $user_id, $forum_id );
+
+	return true;
+}
+
+/**
+ * Remove a topic from user's subscriptions
+ *
+ * @since bbPress (r5156)
+ *
+ * @param int $user_id Optional. User id
+ * @param int $topic_id Optional. Topic id
+ * @uses bbp_get_user_subscribed_topic_ids() To get the user's subscriptions
+ * @uses update_user_option() To update the user's subscriptions
+ * @uses delete_user_option() To delete the user's subscriptions meta
+ * @uses do_action() Calls 'bbp_remove_user_topic_subscription' with the user id and
+ *                    topic id
+ * @return bool True if the topic was removed from user's subscriptions,
+ *               otherwise false
+ */
+function bbp_remove_user_topic_subscription( $user_id, $topic_id ) {
+	if ( empty( $user_id ) || empty( $topic_id ) ) {
+		return false;
+	}
+
+	$subscriptions = (array) bbp_get_user_subscribed_topic_ids( $user_id );
+	if ( empty( $subscriptions ) ) {
+		return false;
+	}
+
+	$pos = array_search( $topic_id, $subscriptions );
+	if ( false === $pos ) {
+		return false;
+	}
+
+	array_splice( $subscriptions, $pos, 1 );
+	$subscriptions = array_filter( $subscriptions );
+
+	if ( !empty( $subscriptions ) ) {
+		$subscriptions = implode( ',', wp_parse_id_list( $subscriptions ) );
+		update_user_option( $user_id, '_bbp_subscriptions', $subscriptions );
+	} else {
+		delete_user_option( $user_id, '_bbp_subscriptions' );
+	}
+
+	wp_cache_delete( 'bbp_get_topic_subscribers_' . $topic_id, 'bbpress_users' );
+
+	do_action( 'bbp_remove_user_topic_subscription', $user_id, $topic_id );
+
+	return true;
+}
+
+/**
+ * Handles the front end subscribing and unsubscribing forums
+ *
+ * @since bbPress (r5156)
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+ * @uses bbp_get_user_id() To get the user id
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit the user
+ * @uses bbPress:errors:add() To log the error messages
+ * @uses bbp_is_user_subscribed() To check if the forum is in user's
+ *                                 subscriptions
+ * @uses bbp_remove_user_subscription() To remove the user subscription
+ * @uses bbp_add_user_subscription() To add the user subscription
+ * @uses do_action() Calls 'bbp_subscriptions_handler' with success, user id,
+ *                    forum id and action
+ * @uses bbp_is_subscription() To check if it's the subscription page
+ * @uses bbp_get_forum_permalink() To get the forum permalink
+ * @uses wp_safe_redirect() To redirect to the url
+ */
+function bbp_forum_subscriptions_handler( $action = '' ) {
+
+	if ( ! bbp_is_subscriptions_active() ) {
+		return false;
+	}
+
+	// Bail if no forum ID is passed
+	if ( empty( $_GET['forum_id'] ) ) {
+		return;
+	}
+
+	// Setup possible get actions
+	$possible_actions = array(
+		'bbp_subscribe',
+		'bbp_unsubscribe',
+	);
+
+	// Bail if actions aren't meant for this function
+	if ( ! in_array( $action, $possible_actions ) ) {
+		return;
+	}
+
+	// Get required data
+	$user_id  = bbp_get_user_id( 0, true, true );
+	$forum_id = intval( $_GET['forum_id'] );
+
+	// Check for empty forum
+	if ( empty( $forum_id ) ) {
+		bbp_add_error( 'bbp_subscription_forum_id', __( '<strong>ERROR</strong>: No forum was found! Which forum are you subscribing/unsubscribing to?', 'bbpress' ) );
+
+	// Check nonce
+	} elseif ( ! bbp_verify_nonce_request( 'toggle-subscription_' . $forum_id ) ) {
+		bbp_add_error( 'bbp_subscription_forum_id', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+
+	// Check current user's ability to edit the user
+	} elseif ( !current_user_can( 'edit_user', $user_id ) ) {
+		bbp_add_error( 'bbp_subscription_permissions', __( '<strong>ERROR</strong>: You don\'t have the permission to edit favorites of that user!', 'bbpress' ) );
+	}
+
+	// Bail if we have errors
+	if ( bbp_has_errors() ) {
+		return;
+	}
+
+	/** No errors *************************************************************/
+
+	$is_subscription = bbp_is_user_subscribed( $user_id, $forum_id );
+	$success         = false;
+
+	if ( true === $is_subscription && 'bbp_unsubscribe' === $action ) {
+		$success = bbp_remove_user_subscription( $user_id, $forum_id );
+	} elseif ( false === $is_subscription && 'bbp_subscribe' === $action ) {
+		$success = bbp_add_user_subscription( $user_id, $forum_id );
+	}
+
+	// Do additional subscriptions actions
+	do_action( 'bbp_subscriptions_handler', $success, $user_id, $forum_id, $action );
+
+	// Success!
+	if ( true === $success ) {
+
+		// Redirect back from whence we came
+		if ( bbp_is_subscriptions() ) {
+			$redirect = bbp_get_subscriptions_permalink( $user_id );
+		} elseif ( bbp_is_single_user() ) {
+			$redirect = bbp_get_user_profile_url();
+		} elseif ( is_singular( bbp_get_forum_post_type() ) ) {
+			$redirect = bbp_get_forum_permalink( $forum_id );
+		} elseif ( is_single() || is_page() ) {
+			$redirect = get_permalink();
+		} else {
+			$redirect = get_permalink( $forum_id );
+		}
+
+		wp_safe_redirect( $redirect );
+
+		// For good measure
+		exit();
+
+	// Fail! Handle errors
+	} elseif ( true === $is_subscription && 'bbp_unsubscribe' === $action ) {
+		bbp_add_error( 'bbp_unsubscribe', __( '<strong>ERROR</strong>: There was a problem unsubscribing from that forum!', 'bbpress' ) );
+	} elseif ( false === $is_subscription && 'bbp_subscribe' === $action ) {
+		bbp_add_error( 'bbp_subscribe',    __( '<strong>ERROR</strong>: There was a problem subscribing to that forum!', 'bbpress' ) );
+	}
+}
+
+/**
+ * Handles the front end subscribing and unsubscribing topics
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+ * @uses bbp_get_user_id() To get the user id
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit the user
+ * @uses bbPress:errors:add() To log the error messages
+ * @uses bbp_is_user_subscribed() To check if the topic is in user's
+ *                                 subscriptions
+ * @uses bbp_remove_user_subscription() To remove the user subscription
+ * @uses bbp_add_user_subscription() To add the user subscription
+ * @uses do_action() Calls 'bbp_subscriptions_handler' with success, user id,
+ *                    topic id and action
+ * @uses bbp_is_subscription() To check if it's the subscription page
+ * @uses bbp_get_topic_permalink() To get the topic permalink
+ * @uses wp_safe_redirect() To redirect to the url
+ */
+function bbp_subscriptions_handler( $action = '' ) {
+
+	if ( !bbp_is_subscriptions_active() ) {
+		return false;
+	}
+
+	// Bail if no topic ID is passed
+	if ( empty( $_GET['topic_id'] ) ) {
+		return;
+	}
+
+	// Setup possible get actions
+	$possible_actions = array(
+		'bbp_subscribe',
+		'bbp_unsubscribe',
+	);
+
+	// Bail if actions aren't meant for this function
+	if ( !in_array( $action, $possible_actions ) ) {
+		return;
+	}
+
+	// Get required data
+	$user_id  = bbp_get_user_id( 0, true, true );
+	$topic_id = intval( $_GET['topic_id'] );
+
+	// Check for empty topic
+	if ( empty( $topic_id ) ) {
+		bbp_add_error( 'bbp_subscription_topic_id', __( '<strong>ERROR</strong>: No topic was found! Which topic are you subscribing/unsubscribing to?', 'bbpress' ) );
+
+	// Check nonce
+	} elseif ( ! bbp_verify_nonce_request( 'toggle-subscription_' . $topic_id ) ) {
+		bbp_add_error( 'bbp_subscription_topic_id', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+
+	// Check current user's ability to edit the user
+	} elseif ( !current_user_can( 'edit_user', $user_id ) ) {
+		bbp_add_error( 'bbp_subscription_permissions', __( '<strong>ERROR</strong>: You don\'t have the permission to edit favorites of that user!', 'bbpress' ) );
+	}
+
+	// Bail if we have errors
+	if ( bbp_has_errors() ) {
+		return;
+	}
+
+	/** No errors *************************************************************/
+
+	$is_subscription = bbp_is_user_subscribed( $user_id, $topic_id );
+	$success         = false;
+
+	if ( true === $is_subscription && 'bbp_unsubscribe' === $action ) {
+		$success = bbp_remove_user_subscription( $user_id, $topic_id );
+	} elseif ( false === $is_subscription && 'bbp_subscribe' === $action ) {
+		$success = bbp_add_user_subscription( $user_id, $topic_id );
+	}
+
+	// Do additional subscriptions actions
+	do_action( 'bbp_subscriptions_handler', $success, $user_id, $topic_id, $action );
+
+	// Success!
+	if ( true === $success ) {
+
+		// Redirect back from whence we came
+		if ( bbp_is_subscriptions() ) {
+			$redirect = bbp_get_subscriptions_permalink( $user_id );
+		} elseif ( bbp_is_single_user() ) {
+			$redirect = bbp_get_user_profile_url();
+		} elseif ( is_singular( bbp_get_topic_post_type() ) ) {
+			$redirect = bbp_get_topic_permalink( $topic_id );
+		} elseif ( is_single() || is_page() ) {
+			$redirect = get_permalink();
+		} else {
+			$redirect = get_permalink( $topic_id );
+		}
+
+		wp_safe_redirect( $redirect );
+
+		// For good measure
+		exit();
+
+	// Fail! Handle errors
+	} elseif ( true === $is_subscription && 'bbp_unsubscribe' === $action ) {
+		bbp_add_error( 'bbp_unsubscribe', __( '<strong>ERROR</strong>: There was a problem unsubscribing from that topic!', 'bbpress' ) );
+	} elseif ( false === $is_subscription && 'bbp_subscribe' === $action ) {
+		bbp_add_error( 'bbp_subscribe',    __( '<strong>ERROR</strong>: There was a problem subscribing to that topic!', 'bbpress' ) );
+	}
+}
+
+/** Edit **********************************************************************/
+
+/**
+ * Handles the front end user editing
+ *
+ * @param string $action The requested action to compare this function to
+ * @uses is_multisite() To check if it's a multisite
+ * @uses bbp_is_user_home() To check if the user is at home (the display page
+ *                           is the one of the logged in user)
+ * @uses get_option() To get the displayed user's new email id option
+ * @uses wpdb::prepare() To sanitize our sql query
+ * @uses wpdb::get_var() To execute our query and get back the variable
+ * @uses wpdb::query() To execute our query
+ * @uses wp_update_user() To update the user
+ * @uses delete_option() To delete the displayed user's email id option
+ * @uses bbp_get_user_profile_edit_url() To get the edit profile url
+ * @uses wp_safe_redirect() To redirect to the url
+ * @uses bbp_verify_nonce_request() To verify the nonce and check the request
+ * @uses current_user_can() To check if the current user can edit the user
+ * @uses do_action() Calls 'personal_options_update' or
+ *                   'edit_user_options_update' (based on if it's the user home)
+ *                   with the displayed user id
+ * @uses edit_user() To edit the user based on the post data
+ * @uses get_userdata() To get the user data
+ * @uses is_email() To check if the string is an email id or not
+ * @uses wpdb::get_blog_prefix() To get the blog prefix
+ * @uses is_network_admin() To check if the user is the network admin
+ * @uses revoke_super_admin() To revoke super admin priviledges
+ * @uses grant_super_admin() To grant super admin priviledges
+ * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
+ */
+function bbp_edit_user_handler( $action = '' ) {
+
+	// Bail if action is not 'bbp-update-user'
+	if ( 'bbp-update-user' !== $action )
+		return;
+
+	// Get the displayed user ID
+	$user_id = bbp_get_displayed_user_id();
+
+	// Execute confirmed email change. See send_confirmation_on_profile_email().
+	if ( is_multisite() && bbp_is_user_home_edit() && isset( $_GET['newuseremail'] ) ) {
+
+		$new_email = get_option( $user_id . '_new_email' );
+
+		if ( $new_email['hash'] === $_GET['newuseremail'] ) {
+			$user             = new WP_User();
+			$user->ID         = $user_id;
+			$user->user_email = esc_html( trim( $new_email['newemail'] ) );
+
+			global $wpdb;
+
+			if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->signups} WHERE user_login = %s", bbp_get_displayed_user_field( 'user_login', 'raw' ) ) ) ) {
+				$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->signups} SET user_email = %s WHERE user_login = %s", $user->user_email, bbp_get_displayed_user_field( 'user_login', 'raw' ) ) );
+			}
+
+			wp_update_user( get_object_vars( $user ) );
+			delete_option( $user_id . '_new_email' );
+
+			wp_safe_redirect( add_query_arg( array( 'updated' => 'true' ), bbp_get_user_profile_edit_url( $user_id ) ) );
+			exit();
+		}
+
+	// Delete new email address from user options
+	} elseif ( is_multisite() && bbp_is_user_home_edit() && !empty( $_GET['dismiss'] ) && ( $user_id . '_new_email' === $_GET['dismiss'] ) ) {
+		delete_option( $user_id . '_new_email' );
+		wp_safe_redirect( add_query_arg( array( 'updated' => 'true' ), bbp_get_user_profile_edit_url( $user_id ) ) );
+		exit();
+	}
+
+	// Nonce check
+	if ( ! bbp_verify_nonce_request( 'update-user_' . $user_id ) ) {
+		bbp_add_error( 'bbp_update_user_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Cap check
+	if ( ! current_user_can( 'edit_user', $user_id ) ) {
+		bbp_add_error( 'bbp_update_user_capability', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
+		return;
+	}
+
+	// Do action based on who's profile you're editing
+	$edit_action = bbp_is_user_home_edit() ? 'personal_options_update' : 'edit_user_profile_update';
+	do_action( $edit_action, $user_id );
+
+	// Prevent edit_user() from wiping out the user's Toolbar on front setting
+	if ( !isset( $_POST['admin_bar_front'] ) && _get_admin_bar_pref( 'front', $user_id ) ) {
+		$_POST['admin_bar_front'] = 1;
+	}
+
+	// Handle user edit
+	$edit_user = edit_user( $user_id );
+
+	// Error(s) editng the user, so copy them into the global
+	if ( is_wp_error( $edit_user ) ) {
+		bbpress()->errors = $edit_user;
+
+	// Successful edit to redirect
+	} elseif ( is_integer( $edit_user ) ) {
+
+		// Maybe update super admin ability
+		if ( is_multisite() && ! bbp_is_user_home_edit() ) {
+			empty( $_POST['super_admin'] ) ? revoke_super_admin( $edit_user ) : grant_super_admin( $edit_user );
+		}
+
+		$redirect = add_query_arg( array( 'updated' => 'true' ), bbp_get_user_profile_edit_url( $edit_user ) );
+
+		wp_safe_redirect( $redirect );
+		exit;
+	}
+}
+
+/**
+ * Conditionally hook the core WordPress output actions to the end of the
+ * default user's edit profile template.
+ *
+ * This allows clever plugin authors to conditionally unhook the WordPress core
+ * output actions if they don't want any unexpected junk to appear there, and
+ * also avoids needing to pollute the templates with additional logic and actions.
+ *
+ * @since bbPress (r4273)
+ *
+ * @uses bbp_is_user_home_edit() To switch the action fired
+ * @uses get_userdata() To get the current user's data
+ * @uses bbp_get_displayed_user_id() To get the currently displayed user ID
+ */
+function bbp_user_edit_after() {
+	$action = bbp_is_user_home_edit() ? 'show_user_profile' : 'edit_user_profile';
+
+	do_action( $action, get_userdata( bbp_get_displayed_user_id() ) );
+}
+
+/** User Queries **************************************************************/
+
+/**
+ * Get the topics that a user created
+ *
+ * @since bbPress (r2660)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_id() To get the topic id
+ * @uses bbp_has_topics() To get the topics created by the user
+ * @return array|bool Results if the user has created topics, otherwise false
+ */
+function bbp_get_user_topics_started( $user_id = 0 ) {
+
+	// Validate user
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	// Try to get the topics
+	$query = bbp_has_topics( array(
+		'author' => $user_id
+	) );
+
+	return apply_filters( 'bbp_get_user_topics_started', $query, $user_id );
+}
+
+/**
+ * Get the replies that a user created
+ *
+ * @since bbPress (r4225)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_id() To get the topic id
+ * @uses bbp_has_replies() To get the topics created by the user
+ * @return array|bool Results if the user has created topics, otherwise false
+ */
+function bbp_get_user_replies_created( $user_id = 0 ) {
+
+	// Validate user
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	// Try to get the topics
+	$query = bbp_has_replies( array(
+		'post_type' => bbp_get_reply_post_type(),
+		'order'     => 'DESC',
+		'author'    => $user_id
+	) );
+
+	return apply_filters( 'bbp_get_user_replies_created', $query, $user_id );
+}
+
+/**
+ * Get the total number of users on the forums
+ *
+ * @since bbPress (r2769)
+ * @uses count_users() To execute our query and get the var back
+ * @uses apply_filters() Calls 'bbp_get_total_users' with number of users
+ * @return int Total number of users
+ */
+function bbp_get_total_users() {
+	$user_count = count_users();
+	return apply_filters( 'bbp_get_total_users', (int) $user_count['total_users'] );
+}
+
+/** Premissions ***************************************************************/
+
+/**
+ * Redirect if unathorized user is attempting to edit another user
+ *
+ * This is hooked to 'bbp_template_redirect' and controls the conditions under
+ * which a user can edit another user (or themselves.) If these conditions are
+ * met. We assume a user cannot perform this task, and look for ways they can
+ * earn the ability to access this template.
+ *
+ * @since bbPress (r3605)
+ *
+ * @uses bbp_is_topic_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_topic_id()
+ * @uses wp_safe_redirect()
+ * @uses bbp_get_topic_permalink()
+ */
+function bbp_check_user_edit() {
+
+	// Bail if not editing a topic
+	if ( ! bbp_is_single_user_edit() )
+		return;
+
+	// Default to false
+	$redirect = true;
+
+	// Allow user to edit their own profile
+	if ( bbp_is_user_home_edit() ) {
+		$redirect = false;
+
+	// Allow if current user can edit the displayed user
+	} elseif ( current_user_can( 'edit_user', bbp_get_displayed_user_id() ) ) {
+		$redirect = false;
+
+	// Allow if user can manage network users, or edit-any is enabled
+	} elseif ( current_user_can( 'manage_network_users' ) || apply_filters( 'enable_edit_any_user_configuration', false ) ) {
+		$redirect = false;
+	}
+
+	// Maybe redirect back to profile page
+	if ( true === $redirect ) {
+		wp_safe_redirect( bbp_get_user_profile_url( bbp_get_displayed_user_id() ) );
+		exit();
+	}
+}
+
+/**
+ * Check if a user is blocked, or cannot spectate the forums.
+ *
+ * @since bbPress (r2996)
+ *
+ * @uses is_user_logged_in() To check if user is logged in
+ * @uses bbp_is_user_keymaster() To check if user is a keymaster
+ * @uses current_user_can() To check if the current user can spectate
+ * @uses is_bbpress() To check if in a bbPress section of the site
+ * @uses bbp_set_404() To set a 404 status
+ */
+function bbp_forum_enforce_blocked() {
+
+	// Bail if not logged in or keymaster
+	if ( ! is_user_logged_in() || bbp_is_user_keymaster() ) {
+		return;
+	}
+
+	// Set 404 if in bbPress and user cannot spectate
+	if ( is_bbpress() && ! current_user_can( 'spectate' ) ) {
+		bbp_set_404();
+	}
+}
+
+/** Sanitization **************************************************************/
+
+/**
+ * Sanitize displayed user data, when viewing and editing any user.
+ *
+ * This somewhat monolithic function handles the escaping and sanitization of
+ * user data for a bbPress profile. There are two reasons this all happers here:
+ *
+ * 1. bbPress took a similar approach to WordPress, and funnels all user profile
+ *    data through a central helper. This eventually calls sanitize_user_field()
+ *    which applies a few context based filters, which some third party plugins
+ *    might be relying on bbPress to play nicely with.
+ *
+ * 2. Early versions of bbPress 2.x templates did not escape this data meaning
+ *    a backwards compatible approach like this one was necessary to protect
+ *    existing installations that may have custom template parts.
+ *
+ * @since bbPress (r5368)
+ *
+ * @param string $value
+ * @param string $field
+ * @param string $context
+ * @return string
+ */
+function bbp_sanitize_displayed_user_field( $value = '', $field = '', $context = 'display' ) {
+
+	// Bail if not editing or displaying (maybe we'll do more here later)
+	if ( ! in_array( $context, array( 'edit', 'display' ) ) ) {
+		return $value;
+	}
+
+	// By default, no filter set (consider making this an array later)
+	$filter = false;
+
+	// Big switch statement to decide which user field we're sanitizing and how
+	switch ( $field ) {
+
+		// Description is a paragraph
+		case 'description' :
+			$filter = ( 'edit' === $context ) ? '' : 'wp_kses_data';
+			break;
+
+		// Email addresses are sanitized with a specific function
+		case 'user_email'  :
+			$filter = 'sanitize_email';
+			break;
+
+		// Name & login fields
+		case 'user_login'   :
+		case 'display_name' :
+		case 'first_name'   :
+		case 'last_name'    :
+		case 'nick_name'    :
+			$filter = ( 'edit' === $context ) ? 'esc_attr' : 'esc_html';
+			break;
+
+		// wp-includes/default-filters.php escapes this for us via esc_url()
+		case 'user_url' :
+			break;
+	}
+
+	// Run any applicable filters on the value
+	if ( ! empty( $filter ) ) {
+		$value = call_user_func( $filter, $value );
+	}
+
+	return $value;
+}
+
+/** Converter *****************************************************************/
+
+/**
+ * Convert passwords from previous platfrom encryption to WordPress encryption.
+ *
+ * @since bbPress (r3813)
+ * @global WPDB $wpdb
+ */
+function bbp_user_maybe_convert_pass() {
+
+	// Bail if no username
+	$username = !empty( $_POST['log'] ) ? $_POST['log'] : '';
+	if ( empty( $username ) )
+		return;
+
+	global $wpdb;
+
+	// Bail if no user password to convert
+	$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->users} INNER JOIN {$wpdb->usermeta} ON user_id = ID WHERE meta_key = '_bbp_class' AND user_login = '%s' LIMIT 1", $username ) );
+	if ( empty( $row ) || is_wp_error( $row ) )
+		return;
+
+	// Setup admin (to include converter)
+	require_once( bbpress()->includes_dir . 'admin/admin.php' );
+
+	// Create the admin object
+	bbp_admin();
+
+	// Convert password
+	require_once( bbpress()->admin->admin_dir . 'converter.php' );
+	require_once( bbpress()->admin->admin_dir . 'converters/' . $row->meta_value . '.php' );
+
+	// Create the converter
+	$converter = bbp_new_converter( $row->meta_value );
+
+	// Try to call the conversion method
+	if ( is_a( $converter, 'BBP_Converter_Base' ) && method_exists( $converter, 'callback_pass' ) ) {
+		$converter->callback_pass( $username, $_POST['pwd'] );
+	}
+}
Index: /tags/2.5.4/includes/users/index.php
===================================================================
--- /tags/2.5.4/includes/users/index.php	(revision 5382)
+++ /tags/2.5.4/includes/users/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/includes/users/options.php
===================================================================
--- /tags/2.5.4/includes/users/options.php	(revision 5382)
+++ /tags/2.5.4/includes/users/options.php	(revision 5382)
@@ -0,0 +1,290 @@
+<?php
+
+/**
+ * bbPress User Options
+ *
+ * @package bbPress
+ * @subpackage UserOptions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Get the default user options and their values
+ *
+ * @since bbPress (r3910)
+ * @return array Filtered user option names and values
+ */
+function bbp_get_default_user_options() {
+
+	// Default options
+	return apply_filters( 'bbp_get_default_user_options', array(
+		'_bbp_last_posted'   => '0', // For checking flooding
+		'_bbp_topic_count'   => '0', // Total topics per site
+		'_bbp_reply_count'   => '0', // Total replies per site
+		'_bbp_favorites'     => '',  // Favorite topics per site
+		'_bbp_subscriptions' => ''   // Subscribed topics per site
+	) );
+}
+
+/**
+ * Add default user options
+ *
+ * This is destructive, so existing bbPress user options will be overridden.
+ *
+ * @since bbPress (r3910)
+ * @uses bbp_get_default_user_options() To get default options
+ * @uses update_user_option() Adds default options
+ * @uses do_action() Calls 'bbp_add_user_options'
+ */
+function bbp_add_user_options( $user_id = 0 ) {
+
+	// Validate user id
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return;
+
+	// Add default options
+	foreach ( bbp_get_default_user_options() as $key => $value )
+		update_user_option( $user_id, $key, $value );
+
+	// Allow previously activated plugins to append their own user options.
+	do_action( 'bbp_add_user_options', $user_id );
+}
+
+/**
+ * Delete default user options
+ *
+ * Hooked to bbp_uninstall, it is only called once when bbPress is uninstalled.
+ * This is destructive, so existing bbPress user options will be destroyed.
+ *
+ * @since bbPress (r3910)
+ * @uses bbp_get_default_user_options() To get default options
+ * @uses delete_user_option() Removes default options
+ * @uses do_action() Calls 'bbp_delete_options'
+ */
+function bbp_delete_user_options( $user_id = 0 ) {
+
+	// Validate user id
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return;
+
+	// Add default options
+	foreach ( array_keys( bbp_get_default_user_options() ) as $key )
+		delete_user_option( $user_id, $key );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bbp_delete_user_options', $user_id );
+}
+
+/**
+ * Add filters to each bbPress option and allow them to be overloaded from
+ * inside the $bbp->options array.
+ *
+ * @since bbPress (r3910)
+ * @uses bbp_get_default_user_options() To get default options
+ * @uses add_filter() To add filters to 'pre_option_{$key}'
+ * @uses do_action() Calls 'bbp_add_option_filters'
+ */
+function bbp_setup_user_option_filters() {
+
+	// Add filters to each bbPress option
+	foreach ( array_keys( bbp_get_default_user_options() ) as $key )
+		add_filter( 'get_user_option_' . $key, 'bbp_filter_get_user_option', 10, 3 );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bbp_setup_user_option_filters' );
+}
+
+/**
+ * Filter default options and allow them to be overloaded from inside the
+ * $bbp->user_options array.
+ *
+ * @since bbPress (r3910)
+ * @param bool $value Optional. Default value false
+ * @return mixed false if not overloaded, mixed if set
+ */
+function bbp_filter_get_user_option( $value = false, $option = '', $user = 0 ) {
+	$bbp = bbpress();
+
+	// Check the options global for preset value
+	if ( isset( $user->ID ) && isset( $bbp->user_options[$user->ID] ) && !empty( $bbp->user_options[$user->ID][$option] ) )
+		$value = $bbp->user_options[$user->ID][$option];
+
+	// Always return a value, even if false
+	return $value;
+}
+
+/** Post Counts ***************************************************************/
+
+/**
+ * Output a users topic count
+ *
+ * @since bbPress (r3632)
+ *
+ * @param int $user_id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_user_topic_count()
+ * @return string
+ */
+function bbp_user_topic_count( $user_id = 0, $integer = false ) {
+	echo bbp_get_user_topic_count( $user_id, $integer );
+}
+	/**
+	 * Return a users reply count
+	 *
+	 * @since bbPress (r3632)
+	 *
+	 * @param int $user_id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_user_id()
+	 * @uses get_user_option()
+	 * @uses apply_filters()
+	 * @return string
+	 */
+	function bbp_get_user_topic_count( $user_id = 0, $integer = false ) {
+
+		// Validate user id
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		$count  = (int) get_user_option( '_bbp_topic_count', $user_id );
+		$filter = ( false === $integer ) ? 'bbp_get_user_topic_count_int' : 'bbp_get_user_topic_count';
+
+		return apply_filters( $filter, $count, $user_id );
+	}
+
+/**
+ * Output a users reply count
+ *
+ * @since bbPress (r3632)
+ *
+ * @param int $user_id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_user_reply_count()
+ * @return string
+ */
+function bbp_user_reply_count( $user_id = 0, $integer = false ) {
+	echo bbp_get_user_reply_count( $user_id, $integer );
+}
+	/**
+	 * Return a users reply count
+	 *
+	 * @since bbPress (r3632)
+	 *
+	 * @param int $user_id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_user_id()
+	 * @uses get_user_option()
+	 * @uses apply_filters()
+	 * @return string
+	 */
+	function bbp_get_user_reply_count( $user_id = 0, $integer = false ) {
+
+		// Validate user id
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		$count  = (int) get_user_option( '_bbp_reply_count', $user_id );
+		$filter = ( true === $integer ) ? 'bbp_get_user_topic_count_int' : 'bbp_get_user_topic_count';
+
+		return apply_filters( $filter, $count, $user_id );
+	}
+
+/**
+ * Output a users total post count
+ *
+ * @since bbPress (r3632)
+ *
+ * @param int $user_id
+ * @param boolean $integer Optional. Whether or not to format the result
+ * @uses bbp_get_user_post_count()
+ * @return string
+ */
+function bbp_user_post_count( $user_id = 0, $integer = false ) {
+	echo bbp_get_user_post_count( $user_id, $integer );
+}
+	/**
+	 * Return a users total post count
+	 *
+	 * @since bbPress (r3632)
+	 *
+	 * @param int $user_id
+	 * @param boolean $integer Optional. Whether or not to format the result
+	 * @uses bbp_get_user_id()
+	 * @uses get_user_option()
+	 * @uses apply_filters()
+	 * @return string
+	 */
+	function bbp_get_user_post_count( $user_id = 0, $integer = false ) {
+
+		// Validate user id
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		$topics  = bbp_get_user_topic_count( $user_id, true );
+		$replies = bbp_get_user_reply_count( $user_id, true );
+		$count   = (int) $topics + $replies;
+		$filter  = ( true === $integer ) ? 'bbp_get_user_post_count_int' : 'bbp_get_user_post_count';
+
+		return apply_filters( $filter, $count, $user_id );
+	}
+
+/** Last Posted ***************************************************************/
+
+/**
+ * Update a users last posted time, for use with post throttling
+ *
+ * @since bbPress (r3910)
+ * @param int $user_id User ID to update
+ * @param int $time Time in time() format
+ * @return bool False if no user or failure, true if successful
+ */
+function bbp_update_user_last_posted( $user_id = 0, $time = 0 ) {
+
+	// Validate user id
+	$user_id = bbp_get_user_id( $user_id );
+	if ( empty( $user_id ) )
+		return false;
+
+	// Set time to now if nothing is passed
+	if ( empty( $time ) )
+		$time = time();
+
+	return update_user_option( $user_id, '_bbp_last_posted', $time );
+}
+
+/**
+ * Output the raw value of the last posted time.
+ *
+ * @since bbPress (r3910)
+ * @param int $user_id User ID to retrieve value for
+ * @uses bbp_get_user_last_posted() To output the last posted time
+ */
+function bbp_user_last_posted( $user_id = 0 ) {
+	echo bbp_get_user_last_posted( $user_id );
+}
+
+	/**
+	 * Return the raw value of teh last posted time.
+	 *
+	 * @since bbPress (r3910)
+	 * @param int $user_id User ID to retrieve value for
+	 * @return mixed False if no user, time() format if exists
+	 */
+	function bbp_get_user_last_posted( $user_id = 0 ) {
+
+		// Validate user id
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		$time = get_user_option( '_bbp_last_posted', $user_id );
+
+		return apply_filters( 'bbp_get_user_last_posted', $time, $user_id );
+	}
Index: /tags/2.5.4/includes/users/template.php
===================================================================
--- /tags/2.5.4/includes/users/template.php	(revision 5382)
+++ /tags/2.5.4/includes/users/template.php	(revision 5382)
@@ -0,0 +1,2044 @@
+<?php
+
+/**
+ * bbPress User Template Tags
+ *
+ * @package bbPress
+ * @subpackage TemplateTags
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Users *********************************************************************/
+
+/**
+ * Output a validated user id
+ *
+ * @since bbPress (r2729)
+ *
+ * @param int $user_id Optional. User id
+ * @param bool $displayed_user_fallback Fallback on displayed user?
+ * @param bool $current_user_fallback Fallback on current user?
+ * @uses bbp_get_user_id() To get the user id
+ */
+function bbp_user_id( $user_id = 0, $displayed_user_fallback = true, $current_user_fallback = false ) {
+	echo bbp_get_user_id( $user_id, $displayed_user_fallback, $current_user_fallback );
+}
+	/**
+	 * Return a validated user id
+	 *
+	 * @since bbPress (r2729)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @param bool $displayed_user_fallback Fallback on displayed user?
+	 * @param bool $current_user_fallback Fallback on current user?
+	 * @uses get_query_var() To get the 'bbp_user_id' query var
+	 * @uses apply_filters() Calls 'bbp_get_user_id' with the user id
+	 * @return int Validated user id
+	 */
+	function bbp_get_user_id( $user_id = 0, $displayed_user_fallback = true, $current_user_fallback = false ) {
+		$bbp = bbpress();
+
+		// Easy empty checking
+		if ( !empty( $user_id ) && is_numeric( $user_id ) ) {
+			$bbp_user_id = $user_id;
+
+		// Currently viewing or editing a user
+		} elseif ( ( true === $displayed_user_fallback ) && !empty( $bbp->displayed_user->ID ) ) {
+			$bbp_user_id = $bbp->displayed_user->ID;
+
+		// Maybe fallback on the current_user ID
+		} elseif ( ( true === $current_user_fallback ) && !empty( $bbp->current_user->ID ) ) {
+			$bbp_user_id = $bbp->current_user->ID;
+
+		// Failsafe
+		} else {
+			$bbp_user_id = 0;
+		}
+
+		return (int) apply_filters( 'bbp_get_user_id', (int) $bbp_user_id, $displayed_user_fallback, $current_user_fallback );
+	}
+
+/**
+ * Output ID of current user
+ *
+ * @since bbPress (r2574)
+ *
+ * @uses bbp_get_current_user_id() To get the current user id
+ */
+function bbp_current_user_id() {
+	echo bbp_get_current_user_id();
+}
+	/**
+	 * Return ID of current user
+	 *
+	 * @since bbPress (r2574)
+	 *
+	 * @uses bbp_get_user_id() To get the current user id
+	 * @uses apply_filters() Calls 'bbp_get_current_user_id' with the id
+	 * @return int Current user id
+	 */
+	function bbp_get_current_user_id() {
+		return apply_filters( 'bbp_get_current_user_id', bbp_get_user_id( 0, false, true ) );
+	}
+
+/**
+ * Output ID of displayed user
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses bbp_get_displayed_user_id() To get the displayed user id
+ */
+function bbp_displayed_user_id() {
+	echo bbp_get_displayed_user_id();
+}
+	/**
+	 * Return ID of displayed user
+	 *
+	 * @since bbPress (r2688)
+	 *
+	 * @uses bbp_get_user_id() To get the displayed user id
+	 * @uses apply_filters() Calls 'bbp_get_displayed_user_id' with the id
+	 * @return int Displayed user id
+	 */
+	function bbp_get_displayed_user_id() {
+		return apply_filters( 'bbp_get_displayed_user_id', bbp_get_user_id( 0, true, false ) );
+	}
+
+/**
+ * Output a sanitized user field value
+ *
+ * This function relies on the $filter parameter to decide how to sanitize
+ * the field value that it finds. Since it uses the WP_User object's magic
+ * __get() method, it can also be used to get user_meta values.
+ *
+ * @since bbPress (r2688)
+ *
+ * @param string $field Field to get
+ * @param string $filter How to filter the field value (null|raw|db|display|edit)
+ * @uses bbp_get_displayed_user_field() To get the field
+ */
+function bbp_displayed_user_field( $field = '', $filter = 'display' ) {
+	echo bbp_get_displayed_user_field( $field, $filter );
+}
+	/**
+	 * Return a sanitized user field value
+	 *
+	 * This function relies on the $filter parameter to decide how to sanitize
+	 * the field value that it finds. Since it uses the WP_User object's magic
+	 * __get() method, it can also be used to get user_meta values.
+	 *
+	 * @since bbPress (r2688)
+	 *
+	 * @param string $field Field to get
+	 * @param string $filter How to filter the field value (null|raw|db|display|edit)
+	 * @see WP_User::__get() for more on how the value is retrieved
+	 * @see sanitize_user_field() for more on how the value is sanitized
+	 * @uses apply_filters() Calls 'bbp_get_displayed_user_field' with the value
+	 * @return string|bool Value of the field if it exists, else false
+	 */
+	function bbp_get_displayed_user_field( $field = '', $filter = 'display' ) {
+
+		// Get the displayed user
+		$user         = bbpress()->displayed_user;
+
+		// Juggle the user filter property because we don't want to muck up how
+		// other code might interact with this object.
+		$old_filter   = $user->filter;
+		$user->filter = $filter;
+
+		// Get the field value from the WP_User object. We don't need to perform
+		// an isset() because the WP_User::__get() does it for us.
+		$value        = $user->$field;
+
+		// Put back the user filter property that was previously juggled above.
+		$user->filter = $old_filter;
+
+		// Return empty
+		return apply_filters( 'bbp_get_displayed_user_field', $value, $field, $filter );
+	}
+
+/**
+ * Output name of current user
+ *
+ * @since bbPress (r2574)
+ *
+ * @uses bbp_get_current_user_name() To get the current user name
+ */
+function bbp_current_user_name() {
+	echo bbp_get_current_user_name();
+}
+	/**
+	 * Return name of current user
+	 *
+	 * @since bbPress (r2574)
+	 *
+	 * @uses apply_filters() Calls 'bbp_get_current_user_name' with the
+	 *                        current user name
+	 * @return string
+	 */
+	function bbp_get_current_user_name() {
+		global $user_identity;
+
+		$current_user_name = is_user_logged_in() ? $user_identity : __( 'Anonymous', 'bbpress' );
+
+		return apply_filters( 'bbp_get_current_user_name', $current_user_name );
+	}
+
+/**
+ * Output avatar of current user
+ *
+ * @since bbPress (r2574)
+ *
+ * @param int $size Size of the avatar. Defaults to 40
+ * @uses bbp_get_current_user_avatar() To get the current user avatar
+ */
+function bbp_current_user_avatar( $size = 40 ) {
+	echo bbp_get_current_user_avatar( $size );
+}
+
+	/**
+	 * Return avatar of current user
+	 *
+	 * @since bbPress (r2574)
+	 *
+	 * @param int $size Size of the avatar. Defaults to 40
+	 * @uses bbp_get_current_user_id() To get the current user id
+	 * @uses bbp_get_current_anonymous_user_data() To get the current
+	 *                                              anonymous user's email
+	 * @uses get_avatar() To get the avatar
+	 * @uses apply_filters() Calls 'bbp_get_current_user_avatar' with the
+	 *                        avatar and size
+	 * @return string Current user avatar
+	 */
+	function bbp_get_current_user_avatar( $size = 40 ) {
+
+		$user = bbp_get_current_user_id();
+		if ( empty( $user ) )
+			$user = bbp_get_current_anonymous_user_data( 'email' );
+
+		$avatar = get_avatar( $user, $size );
+
+		return apply_filters( 'bbp_get_current_user_avatar', $avatar, $size );
+	}
+
+/**
+ * Output link to the profile page of a user
+ *
+ * @since bbPress (r2688)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_profile_link() To get user profile link
+ */
+function bbp_user_profile_link( $user_id = 0 ) {
+	echo bbp_get_user_profile_link( $user_id );
+}
+	/**
+	 * Return link to the profile page of a user
+	 *
+	 * @since bbPress (r2688)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @uses bbp_get_user_id() To get user id
+	 * @uses get_userdata() To get user data
+	 * @uses bbp_get_user_profile_url() To get user profile url
+	 * @uses apply_filters() Calls 'bbp_get_user_profile_link' with the user
+	 *                        profile link and user id
+	 * @return string User profile link
+	 */
+	function bbp_get_user_profile_link( $user_id = 0 ) {
+
+		// Validate user id
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		$user      = get_userdata( $user_id );
+		$user_link = '<a href="' . esc_url( bbp_get_user_profile_url( $user_id ) ) . '">' . esc_html( $user->display_name ) . '</a>';
+
+		return apply_filters( 'bbp_get_user_profile_link', $user_link, $user_id );
+	}
+
+/**
+ * Output a users nicename to the screen
+ *
+ * @since bbPress (r4671)
+ *
+ * @param int $user_id User ID whose nicename to get
+ * @param array $args before|after|user_id|force
+ */
+function bbp_user_nicename( $user_id = 0, $args = array() ) {
+	echo bbp_get_user_nicename( $user_id, $args );
+}
+	/**
+	 * Return a users nicename to the screen
+	 *
+	 * @since bbPress (r4671)
+	 *
+	 * @param int $user_id User ID whose nicename to get
+	 * @param array $args before|after|user_id|force
+	 * @return string User nicename, maybe wrapped in before/after strings
+	 */
+	function bbp_get_user_nicename( $user_id = 0, $args = array() ) {
+
+		// Bail if no user ID passed
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		// Parse default arguments
+		$r = bbp_parse_args( $args, array(
+			'user_id' => $user_id,
+			'before'  => '',
+			'after'   => '',
+			'force'   => ''
+		), 'get_user_nicename' );
+
+		// Get the user data and nicename
+		if ( empty( $r['force'] ) ) {
+			$user     = get_userdata( $user_id );
+			$nicename = $user->user_nicename;
+
+		// Force the nicename to something else
+		} else {
+			$nicename = (string) $r['force'];
+		}
+
+		// Maybe wrap the nicename
+		$retval = !empty( $nicename ) ? ( $r['before'] . $nicename . $r['after'] ) : '';
+
+		// Filter and return
+		return (string) apply_filters( 'bbp_get_user_nicename', $retval, $user_id, $r );
+	}
+
+/**
+ * Output URL to the profile page of a user
+ *
+ * @since bbPress (r2688)
+ *
+ * @param int $user_id Optional. User id
+ * @param string $user_nicename Optional. User nicename
+ * @uses bbp_get_user_profile_url() To get user profile url
+ */
+function bbp_user_profile_url( $user_id = 0, $user_nicename = '' ) {
+	echo esc_url( bbp_get_user_profile_url( $user_id, $user_nicename ) );
+}
+	/**
+	 * Return URL to the profile page of a user
+	 *
+	 * @since bbPress (r2688)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @param string $user_nicename Optional. User nicename
+	 * @uses bbp_get_user_id() To get user id
+	 * @uses WP_Rewrite::using_permalinks() To check if the blog is using
+	 *                                       permalinks
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses home_url() To get blog home url
+	 * @uses apply_filters() Calls 'bbp_get_user_profile_url' with the user
+	 *                        profile url, user id and user nicename
+	 * @return string User profile url
+	 */
+	function bbp_get_user_profile_url( $user_id = 0, $user_nicename = '' ) {
+		global $wp_rewrite;
+
+		// Use displayed user ID if there is one, and one isn't requested
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		// Allow early overriding of the profile URL to cut down on processing
+		$early_profile_url = apply_filters( 'bbp_pre_get_user_profile_url', (int) $user_id );
+		if ( is_string( $early_profile_url ) )
+			return $early_profile_url;
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url = $wp_rewrite->root . bbp_get_user_slug() . '/%' . bbp_get_user_rewrite_id() . '%';
+
+			// Get username if not passed
+			if ( empty( $user_nicename ) ) {
+				$user_nicename = bbp_get_user_nicename( $user_id );
+			}
+
+			$url = str_replace( '%' . bbp_get_user_rewrite_id() . '%', $user_nicename, $url );
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array( bbp_get_user_rewrite_id() => $user_id ), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_user_profile_url', $url, $user_id, $user_nicename );
+	}
+
+/**
+ * Output link to the profile edit page of a user
+ *
+ * @since bbPress (r2688)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_user_profile_edit_link() To get user profile edit link
+ */
+function bbp_user_profile_edit_link( $user_id = 0 ) {
+	echo bbp_get_user_profile_edit_link( $user_id );
+}
+	/**
+	 * Return link to the profile edit page of a user
+	 *
+	 * @since bbPress (r2688)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @uses bbp_get_user_id() To get user id
+	 * @uses get_userdata() To get user data
+	 * @uses bbp_get_user_profile_edit_url() To get user profile edit url
+	 * @uses apply_filters() Calls 'bbp_get_user_profile_link' with the edit
+	 *                        link and user id
+	 * @return string User profile edit link
+	 */
+	function bbp_get_user_profile_edit_link( $user_id = 0 ) {
+
+		// Validate user id
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		$user      = get_userdata( $user_id );
+		$edit_link = '<a href="' . esc_url( bbp_get_user_profile_url( $user_id ) ) . '">' . esc_html( $user->display_name ) . '</a>';
+		return apply_filters( 'bbp_get_user_profile_edit_link', $edit_link, $user_id );
+	}
+
+/**
+ * Output URL to the profile edit page of a user
+ *
+ * @since bbPress (r2688)
+ *
+ * @param int $user_id Optional. User id
+ * @param string $user_nicename Optional. User nicename
+ * @uses bbp_get_user_profile_edit_url() To get user profile edit url
+ */
+function bbp_user_profile_edit_url( $user_id = 0, $user_nicename = '' ) {
+	echo esc_url( bbp_get_user_profile_edit_url( $user_id, $user_nicename ) );
+}
+	/**
+	 * Return URL to the profile edit page of a user
+	 *
+	 * @since bbPress (r2688)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @param string $user_nicename Optional. User nicename
+	 * @uses bbp_get_user_id() To get user id
+	 * @uses WP_Rewrite::using_permalinks() To check if the blog is using
+	 *                                       permalinks
+	 * @uses add_query_arg() To add custom args to the url
+	 * @uses home_url() To get blog home url
+	 * @uses apply_filters() Calls 'bbp_get_user_edit_profile_url' with the
+	 *                        edit profile url, user id and user nicename
+	 * @return string
+	 */
+	function bbp_get_user_profile_edit_url( $user_id = 0, $user_nicename = '' ) {
+		global $wp_rewrite;
+
+		$bbp     = bbpress();
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url = $wp_rewrite->root . bbp_get_user_slug() . '/%' . $bbp->user_id . '%/' . $bbp->edit_id;
+
+			// Get username if not passed
+			if ( empty( $user_nicename ) ) {
+				$user = get_userdata( $user_id );
+				if ( !empty( $user->user_nicename ) ) {
+					$user_nicename = $user->user_nicename;
+				}
+			}
+
+			$url = str_replace( '%' . $bbp->user_id . '%', $user_nicename, $url );
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array( $bbp->user_id => $user_id, $bbp->edit_id => '1' ), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_user_edit_profile_url', $url, $user_id, $user_nicename );
+
+	}
+
+/**
+ * Output a user's main role for display
+ *
+ * @since bbPress (r3860)
+ *
+ * @param int $user_id
+ * @uses bbp_get_user_display_role To get the user display role
+ */
+function bbp_user_display_role( $user_id = 0 ) {
+	echo bbp_get_user_display_role( $user_id );
+}
+	/**
+	 * Return a user's main role for display
+	 *
+	 * @since bbPress (r3860)
+	 *
+	 * @param int $user_id
+	 * @uses bbp_get_user_id() to verify the user ID
+	 * @uses bbp_is_user_inactive() to check if user is inactive
+	 * @uses user_can() to check if user has special capabilities
+	 * @uses apply_filters() Calls 'bbp_get_user_display_role' with the
+	 *                        display role, user id, and user role
+	 * @return string
+	 */
+	function bbp_get_user_display_role( $user_id = 0 ) {
+
+		// Validate user id
+		$user_id = bbp_get_user_id( $user_id );
+
+		// User is not registered
+		if ( empty( $user_id ) ) {
+			$role = __( 'Guest', 'bbpress' );
+
+		// User is not active
+		} elseif ( bbp_is_user_inactive( $user_id ) ) {
+			$role = __( 'Inactive', 'bbpress' );
+
+		// User have a role
+		} else {
+			$role_id = bbp_get_user_role( $user_id );
+			$role    = bbp_get_dynamic_role_name( $role_id );
+		}
+
+		// No role found so default to generic "Member"
+		if ( empty( $role ) ) {
+			$role = __( 'Member', 'bbpress' );
+		}
+
+		return apply_filters( 'bbp_get_user_display_role', $role, $user_id );
+	}
+
+/**
+ * Output the link to the admin section
+ *
+ * @since bbPress (r2827)
+ *
+ * @param mixed $args Optional. See {@link bbp_get_admin_link()}
+ * @uses bbp_get_admin_link() To get the admin link
+ */
+function bbp_admin_link( $args = '' ) {
+	echo bbp_get_admin_link( $args );
+}
+	/**
+	 * Return the link to the admin section
+	 *
+	 * @since bbPress (r2827)
+	 *
+	 * @param mixed $args Optional. This function supports these arguments:
+	 *  - text: The text
+	 *  - before: Before the lnk
+	 *  - after: After the link
+	 * @uses current_user_can() To check if the current user can moderate
+	 * @uses admin_url() To get the admin url
+	 * @uses apply_filters() Calls 'bbp_get_admin_link' with the link & args
+	 * @return The link
+	 */
+	function bbp_get_admin_link( $args = '' ) {
+		if ( !current_user_can( 'moderate' ) )
+			return;
+
+		if ( !empty( $args ) && is_string( $args ) && ( false === strpos( $args, '=' ) ) )
+			$args = array( 'text' => $args );
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'text'   => __( 'Admin', 'bbpress' ),
+			'before' => '',
+			'after'  => ''
+		), 'get_admin_link' );
+
+		$retval = $r['before'] . '<a href="' . esc_url( admin_url() ) . '">' . $r['text'] . '</a>' . $r['after'];
+
+		return apply_filters( 'bbp_get_admin_link', $retval, $r );
+	}
+
+/** User IP *******************************************************************/
+
+/**
+ * Output the author IP address of a post
+ *
+ * @since bbPress (r3120)
+ *
+ * @param mixed $args Optional. If it is an integer, it is used as post id.
+ * @uses bbp_get_author_ip() To get the post author link
+ */
+function bbp_author_ip( $args = '' ) {
+	echo bbp_get_author_ip( $args );
+}
+	/**
+	 * Return the author IP address of a post
+	 *
+	 * @since bbPress (r3120)
+	 *
+	 * @param mixed $args Optional. If an integer, it is used as reply id.
+	 * @uses get_post_meta() To check if it's a topic page
+	 * @return string Author link of reply
+	 */
+	function bbp_get_author_ip( $args = '' ) {
+
+		// Used as post id
+		$post_id = is_numeric( $args ) ? (int) $args : 0;
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'post_id' => $post_id,
+			'before'  => '<span class="bbp-author-ip">(',
+			'after'   => ')</span>'
+		), 'get_author_ip' );
+
+		// Get the author IP meta value
+		$author_ip = get_post_meta( $r['post_id'], '_bbp_author_ip', true );
+		if ( !empty( $author_ip ) ) {
+			$author_ip = $r['before'] . $author_ip . $r['after'];
+
+		// No IP address
+		} else {
+			$author_ip = '';
+		}
+
+		return apply_filters( 'bbp_get_author_ip', $author_ip, $r );
+	}
+
+/** Anonymous Fields **********************************************************/
+
+/**
+ * Output the author disylay-name of a topic or reply.
+ *
+ * Convenience function to ensure proper template functions are called
+ * and correct filters are executed. Used primarily to display topic
+ * and reply author information in the anonymous form template-part.
+ *
+ * @since bbPress (r5119)
+ *
+ * @param int $post_id
+ * @uses bbp_get_author_display_name() to get the author name
+ */
+function bbp_author_display_name( $post_id = 0 ) {
+	echo bbp_get_author_display_name( $post_id );
+}
+
+	/**
+	 * Return the author name of a topic or reply.
+	 *
+	 * Convenience function to ensure proper template functions are called
+	 * and correct filters are executed. Used primarily to display topic
+	 * and reply author information in the anonymous form template-part.
+	 *
+	 * @since bbPress (r5119)
+	 *
+	 * @param int $post_id
+	 *
+	 * @uses bbp_is_topic_edit()
+	 * @uses bbp_get_topic_author_display_name()
+	 * @uses bbp_is_reply_edit()
+	 * @uses bbp_get_reply_author_display_name()
+	 * @uses bbp_current_anonymous_user_data()
+	 *
+	 * @return string The name of the author
+	 */
+	function bbp_get_author_display_name( $post_id = 0 ) {
+
+		// Define local variable(s)
+		$retval = '';
+
+		// Topic edit
+		if ( bbp_is_topic_edit() ) {
+			$retval = bbp_get_topic_author_display_name( $post_id );
+
+		// Reply edit
+		} elseif ( bbp_is_reply_edit() ) {
+			$retval = bbp_get_reply_author_display_name( $post_id );
+
+		// Not an edit, so rely on current user cookie data
+		} else {
+			$retval = bbp_current_anonymous_user_data( 'name' );
+		}
+
+		return apply_filters( 'bbp_get_author_display_name', $retval, $post_id );
+	}
+
+/**
+ * Output the author email of a topic or reply.
+ *
+ * Convenience function to ensure proper template functions are called
+ * and correct filters are executed. Used primarily to display topic
+ * and reply author information in the anonymous user form template-part.
+ *
+ * @since bbPress (r5119)
+ *
+ * @param int $post_id
+ * @uses bbp_get_author_email() to get the author email
+ */
+function bbp_author_email( $post_id = 0 ) {
+	echo bbp_get_author_email( $post_id );
+}
+
+	/**
+	 * Return the author email of a topic or reply.
+	 *
+	 * Convenience function to ensure proper template functions are called
+	 * and correct filters are executed. Used primarily to display topic
+	 * and reply author information in the anonymous user form template-part.
+	 *
+	 * @since bbPress (r5119)
+	 *
+	 * @param int $post_id
+	 *
+	 * @uses bbp_is_topic_edit()
+	 * @uses bbp_get_topic_author_email()
+	 * @uses bbp_is_reply_edit()
+	 * @uses bbp_get_reply_author_email()
+	 * @uses bbp_current_anonymous_user_data()
+	 *
+	 * @return string The email of the author
+	 */
+	function bbp_get_author_email( $post_id = 0 ) {
+
+		// Define local variable(s)
+		$retval = '';
+
+		// Topic edit
+		if ( bbp_is_topic_edit() ) {
+			$retval = bbp_get_topic_author_email( $post_id );
+
+		// Reply edit
+		} elseif ( bbp_is_reply_edit() ) {
+			$retval = bbp_get_reply_author_email( $post_id );
+
+		// Not an edit, so rely on current user cookie data
+		} else {
+			$retval = bbp_current_anonymous_user_data( 'email' );
+		}
+
+		return apply_filters( 'bbp_get_author_email', $retval, $post_id );
+	}
+
+/**
+ * Output the author url of a topic or reply.
+ *
+ * Convenience function to ensure proper template functions are called
+ * and correct filters are executed. Used primarily to display topic
+ * and reply author information in the anonymous user form template-part.
+ *
+ * @since bbPress (r5119)
+ *
+ * @param int $post_id
+ * @uses bbp_get_author_url() to get the author url
+ */
+function bbp_author_url( $post_id = 0 ) {
+	echo bbp_get_author_url( $post_id );
+}
+
+	/**
+	 * Return the author url of a topic or reply.
+	 *
+	 * Convenience function to ensure proper template functions are called
+	 * and correct filters are executed. Used primarily to display topic
+	 * and reply author information in the anonymous user form template-part.
+	 *
+	 * @since bbPress (r5119)
+	 *
+	 * @param int $post_id
+	 *
+	 * @uses bbp_is_topic_edit()
+	 * @uses bbp_get_topic_author_url()
+	 * @uses bbp_is_reply_edit()
+	 * @uses bbp_get_reply_author_url()
+	 * @uses bbp_current_anonymous_user_data()
+	 *
+	 * @return string The url of the author
+	 */
+	function bbp_get_author_url( $post_id = 0 ) {
+
+		// Define local variable(s)
+		$retval = '';
+
+		// Topic edit
+		if ( bbp_is_topic_edit() ) {
+			$retval = bbp_get_topic_author_url( $post_id );
+
+		// Reply edit
+		} elseif ( bbp_is_reply_edit() ) {
+			$retval = bbp_get_reply_author_url( $post_id );
+
+		// Not an edit, so rely on current user cookie data
+		} else {
+			$retval = bbp_current_anonymous_user_data( 'url' );
+		}
+
+		return apply_filters( 'bbp_get_author_url', $retval, $post_id );
+	}
+
+/** Favorites *****************************************************************/
+
+/**
+ * Output the link to the user's favorites page (profile page)
+ *
+ * @since bbPress (r2652)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_favorites_permalink() To get the favorites permalink
+ */
+function bbp_favorites_permalink( $user_id = 0 ) {
+	echo esc_url( bbp_get_favorites_permalink( $user_id ) );
+}
+	/**
+	 * Return the link to the user's favorites page (profile page)
+	 *
+	 * @since bbPress (r2652)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @uses bbp_get_user_profile_url() To get the user profile url
+	 * @uses apply_filters() Calls 'bbp_get_favorites_permalink' with the
+	 *                        user profile url and user id
+	 * @return string Permanent link to user profile page
+	 */
+	function bbp_get_favorites_permalink( $user_id = 0 ) {
+		global $wp_rewrite;
+
+		// Use displayed user ID if there is one, and one isn't requested
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		// Allow early overriding of the profile URL to cut down on processing
+		$early_profile_url = apply_filters( 'bbp_pre_get_favorites_permalink', (int) $user_id );
+		if ( is_string( $early_profile_url ) )
+			return $early_profile_url;
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url = $wp_rewrite->root . bbp_get_user_slug() . '/%' . bbp_get_user_rewrite_id() . '%/%' . bbp_get_user_favorites_rewrite_id() . '%';
+			$user = get_userdata( $user_id );
+			if ( ! empty( $user->user_nicename ) ) {
+				$user_nicename = $user->user_nicename;
+			} else {
+				$user_nicename = $user->user_login;
+			}
+			$url = str_replace( '%' . bbp_get_user_rewrite_id() . '%', $user_nicename, $url );
+			$url = str_replace( '%' . bbp_get_user_favorites_rewrite_id() . '%', bbp_get_user_favorites_slug(), $url );
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array(
+				bbp_get_user_rewrite_id()           => $user_id,
+				bbp_get_user_favorites_rewrite_id() => bbp_get_user_favorites_slug(),
+			), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_favorites_permalink', $url, $user_id );
+	}
+
+/**
+ * Output the link to make a topic favorite/remove a topic from favorites
+ *
+ * @since bbPress (r2652)
+ *
+ * @param mixed $args See {@link bbp_get_user_favorites_link()}
+ * @param int $user_id Optional. User id
+ * @param bool $wrap Optional. If you want to wrap the link in <span id="favorite-toggle">.
+ * @uses bbp_get_user_favorites_link() To get the user favorites link
+ */
+function bbp_user_favorites_link( $args = array(), $user_id = 0, $wrap = true ) {
+	echo bbp_get_user_favorites_link( $args, $user_id, $wrap );
+}
+	/**
+	 * User favorites link
+	 *
+	 * Return the link to make a topic favorite/remove a topic from
+	 * favorites
+	 *
+	 * @since bbPress (r2652)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - subscribe: Favorite text
+	 *  - unsubscribe: Unfavorite text
+	 *  - user_id: User id
+	 *  - topic_id: Topic id
+	 *  - before: Before the link
+	 *  - after: After the link
+	 * @param int $user_id Optional. User id
+	 * @param int $topic_id Optional. Topic id
+	 * @param bool $wrap Optional. If you want to wrap the link in <span id="favorite-toggle">. See ajax_favorite()
+	 * @uses bbp_get_user_id() To get the user id
+	 * @uses current_user_can() If the current user can edit the user
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_is_user_favorite() To check if the topic is user's favorite
+	 * @uses bbp_get_favorites_permalink() To get the favorites permalink
+	 * @uses bbp_get_topic_permalink() To get the topic permalink
+	 * @uses bbp_is_favorites() Is it the favorites page?
+	 * @uses apply_filters() Calls 'bbp_get_user_favorites_link' with the
+	 *                        html, add args, remove args, user & topic id
+	 * @return string User favorites link
+	 */
+	function bbp_get_user_favorites_link( $args = '', $user_id = 0, $wrap = true ) {
+		if ( ! bbp_is_favorites_active() ) {
+			return false;
+		}
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'favorite'  => __( 'Favorite',  'bbpress' ),
+			'favorited' => __( 'Favorited', 'bbpress' ),
+			'user_id'   => 0,
+			'topic_id'  => 0,
+			'before'    => '',
+			'after'     => ''
+		), 'get_user_favorites_link' );
+
+		// Validate user and topic ID's
+		$user_id  = bbp_get_user_id( $r['user_id'], true, true );
+		$topic_id = bbp_get_topic_id( $r['topic_id'] );
+		if ( empty( $user_id ) || empty( $topic_id ) ) {
+			return false;
+		}
+
+		// No link if you can't edit yourself
+		if ( ! current_user_can( 'edit_user', (int) $user_id ) ) {
+			return false;
+		}
+
+		// Decide which link to show
+		$is_fav = bbp_is_user_favorite( $user_id, $topic_id );
+		if ( ! empty( $is_fav ) ) {
+			$text       = $r['favorited'];
+			$query_args = array( 'action' => 'bbp_favorite_remove', 'topic_id' => $topic_id );
+		} else {
+			$text       = $r['favorite'];
+			$query_args = array( 'action' => 'bbp_favorite_add',    'topic_id' => $topic_id );
+		}
+
+		// Create the link based where the user is and if the topic is
+		// already the user's favorite
+		if ( bbp_is_favorites() ) {
+			$permalink = bbp_get_favorites_permalink( $user_id );
+		} elseif ( bbp_is_single_topic() || bbp_is_single_reply() ) {
+			$permalink = bbp_get_topic_permalink( $topic_id );
+		} else {
+			$permalink = get_permalink();
+		}
+
+		$url  = esc_url( wp_nonce_url( add_query_arg( $query_args, $permalink ), 'toggle-favorite_' . $topic_id ) );
+		$sub  = $is_fav ? ' class="is-favorite"' : '';
+		$html = sprintf( '%s<span id="favorite-%d"  %s><a href="%s" class="favorite-toggle" data-topic="%d">%s</a></span>%s', $r['before'], $topic_id, $sub, $url, $topic_id, $text, $r['after'] );
+
+		// Initial output is wrapped in a span, ajax output is hooked to this
+		if ( ! empty( $wrap ) ) {
+			$html = '<span id="favorite-toggle">' . $html . '</span>';
+		}
+
+		// Return the link
+		return apply_filters( 'bbp_get_user_favorites_link', $html, $r, $user_id, $topic_id );
+	}
+
+/** Subscriptions *************************************************************/
+
+/**
+ * Output the link to the user's subscriptions page (profile page)
+ *
+ * @since bbPress (r2688)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_subscriptions_permalink() To get the subscriptions link
+ */
+function bbp_subscriptions_permalink( $user_id = 0 ) {
+	echo esc_url( bbp_get_subscriptions_permalink( $user_id ) );
+}
+	/**
+	 * Return the link to the user's subscriptions page (profile page)
+	 *
+	 * @since bbPress (r2688)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @uses bbp_get_user_profile_url() To get the user profile url
+	 * @uses apply_filters() Calls 'bbp_get_subscriptions_permalink' with
+	 *                        the user profile url and user id
+	 * @return string Permanent link to user subscriptions page
+	 */
+	function bbp_get_subscriptions_permalink( $user_id = 0 ) {
+		global $wp_rewrite;
+
+		// Use displayed user ID if there is one, and one isn't requested
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		// Allow early overriding of the profile URL to cut down on processing
+		$early_profile_url = apply_filters( 'bbp_pre_get_subscriptions_permalink', (int) $user_id );
+		if ( is_string( $early_profile_url ) )
+			return $early_profile_url;
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url  = $wp_rewrite->root . bbp_get_user_slug() . '/%' . bbp_get_user_rewrite_id() . '%/%' . bbp_get_user_subscriptions_rewrite_id() . '%';
+			$user = get_userdata( $user_id );
+			if ( ! empty( $user->user_nicename ) ) {
+				$user_nicename = $user->user_nicename;
+			} else {
+				$user_nicename = $user->user_login;
+			}
+			$url = str_replace( '%' . bbp_get_user_rewrite_id()               . '%', $user_nicename,                    $url );
+			$url = str_replace( '%' . bbp_get_user_subscriptions_rewrite_id() . '%', bbp_get_user_subscriptions_slug(), $url );
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array(
+				bbp_get_user_rewrite_id()           => $user_id,
+				bbp_get_user_subscriptions_rewrite_id() => bbp_get_user_subscriptions_slug(),
+			), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_subscriptions_permalink', $url, $user_id );
+	}
+
+/**
+ * Output the link to subscribe/unsubscribe from a topic
+ *
+ * @since bbPress (r2668)
+ *
+ * @param mixed $args See {@link bbp_get_user_subscribe_link()}
+ * @param int $user_id Optional. User id
+ * @param bool $wrap Optional. If you want to wrap the link in <span id="subscription-toggle">.
+ * @uses bbp_get_user_subscribe_link() To get the subscribe link
+ */
+function bbp_user_subscribe_link( $args = '', $user_id = 0, $wrap = true ) {
+	echo bbp_get_user_subscribe_link( $args, $user_id, $wrap );
+}
+	/**
+	 * Return the link to subscribe/unsubscribe from a forum or topic
+	 *
+	 * @since bbPress (r2668)
+	 *
+	 * @param mixed $args This function supports these arguments:
+	 *  - subscribe: Subscribe text
+	 *  - unsubscribe: Unsubscribe text
+	 *  - user_id: User id
+	 *  - topic_id: Topic id
+	 *  - forum_id: Forum id
+	 *  - before: Before the link
+	 *  - after: After the link
+	 * @param int $user_id Optional. User id
+	 * @param bool $wrap Optional. If you want to wrap the link in <span id="subscription-toggle">.
+	 * @uses bbp_is_subscriptions_active() to check if subscriptions are active
+	 * @uses bbp_get_user_id() To get the user id
+	 * @uses bbp_get_user_id() To get the user id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses current_user_can() To check if the current user can edit user
+	 * @uses bbp_is_user_subscribed_to_forum() To check if the user is subscribed to the forum
+	 * @uses bbp_is_user_subscribed_to_topic() To check if the user is subscribed to the topic
+	 * @uses bbp_is_subscriptions() To check if it's the subscriptions page
+	 * @uses bbp_get_subscriptions_permalink() To get subscriptions link
+	 * @uses bbp_get_topic_permalink() To get topic link
+	 * @uses apply_filters() Calls 'bbp_get_user_subscribe_link' with the
+	 *                        link, args, user id & topic id
+	 * @return string Permanent link to topic
+	 */
+	function bbp_get_user_subscribe_link( $args = '', $user_id = 0, $wrap = true ) {
+		if ( ! bbp_is_subscriptions_active() ) {
+			return;
+		}
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'subscribe'   => __( 'Subscribe',   'bbpress' ),
+			'unsubscribe' => __( 'Unsubscribe', 'bbpress' ),
+			'user_id'     => 0,
+			'topic_id'    => 0,
+			'forum_id'    => 0,
+			'before'      => '&nbsp;|&nbsp;',
+			'after'       => ''
+		), 'get_user_subscribe_link' );
+
+		// Validate user and object ID's
+		$user_id  = bbp_get_user_id( $r['user_id'], true, true );
+		$topic_id = bbp_get_topic_id( $r['topic_id'] );
+		$forum_id = bbp_get_forum_id( $r['forum_id'] );
+		if ( empty( $user_id ) || ( empty( $topic_id ) && empty( $forum_id ) ) ) {
+			return false;
+		}
+
+		// No link if you can't edit yourself
+		if ( ! current_user_can( 'edit_user', (int) $user_id ) ) {
+			return false;
+		}
+
+		// Check if viewing a single forum
+		if ( empty( $topic_id ) && ! empty( $forum_id ) ) {
+
+			// Decide which link to show
+			$is_subscribed = bbp_is_user_subscribed_to_forum( $user_id, $forum_id );
+			if ( ! empty( $is_subscribed ) ) {
+				$text       = $r['unsubscribe'];
+				$query_args = array( 'action' => 'bbp_unsubscribe', 'forum_id' => $forum_id );
+			} else {
+				$text       = $r['subscribe'];
+				$query_args = array( 'action' => 'bbp_subscribe',   'forum_id' => $forum_id );
+			}
+
+			// Create the link based where the user is and if the user is
+			// subscribed already
+			if ( bbp_is_subscriptions() ) {
+				$permalink = bbp_get_subscriptions_permalink( $user_id );
+			} elseif ( bbp_is_single_forum() || bbp_is_single_reply() ) {
+				$permalink = bbp_get_forum_permalink( $forum_id );
+			} else {
+				$permalink = get_permalink();
+			}
+
+			$url  = esc_url( wp_nonce_url( add_query_arg( $query_args, $permalink ), 'toggle-subscription_' . $forum_id ) );
+			$sub  = $is_subscribed ? ' class="is-subscribed"' : '';
+			$html = sprintf( '%s<span id="subscribe-%d"  %s><a href="%s" class="subscription-toggle" data-forum="%d">%s</a></span>%s', $r['before'], $forum_id, $sub, $url, $forum_id, $text, $r['after'] );
+
+			// Initial output is wrapped in a span, ajax output is hooked to this
+			if ( !empty( $wrap ) ) {
+				$html = '<span id="subscription-toggle">' . $html . '</span>';
+			}
+
+		} else {
+
+			// Decide which link to show
+			$is_subscribed = bbp_is_user_subscribed_to_topic( $user_id, $topic_id );
+			if ( ! empty( $is_subscribed ) ) {
+				$text       = $r['unsubscribe'];
+				$query_args = array( 'action' => 'bbp_unsubscribe', 'topic_id' => $topic_id );
+			} else {
+				$text       = $r['subscribe'];
+				$query_args = array( 'action' => 'bbp_subscribe',   'topic_id' => $topic_id );
+			}
+
+			// Create the link based where the user is and if the user is
+			// subscribed already
+			if ( bbp_is_subscriptions() ) {
+				$permalink = bbp_get_subscriptions_permalink( $user_id );
+			} elseif ( bbp_is_single_topic() || bbp_is_single_reply() ) {
+				$permalink = bbp_get_topic_permalink( $topic_id );
+			} else {
+				$permalink = get_permalink();
+			}
+
+			$url  = esc_url( wp_nonce_url( add_query_arg( $query_args, $permalink ), 'toggle-subscription_' . $topic_id ) );
+			$sub  = $is_subscribed ? ' class="is-subscribed"' : '';
+			$html = sprintf( '%s<span id="subscribe-%d"  %s><a href="%s" class="subscription-toggle" data-topic="%d">%s</a></span>%s', $r['before'], $topic_id, $sub, $url, $topic_id, $text, $r['after'] );
+
+			// Initial output is wrapped in a span, ajax output is hooked to this
+			if ( !empty( $wrap ) ) {
+				$html = '<span id="subscription-toggle">' . $html . '</span>';
+			}
+		}
+
+		// Return the link
+		return apply_filters( 'bbp_get_user_subscribe_link', $html, $r, $user_id, $topic_id );
+	}
+
+
+/** Edit User *****************************************************************/
+
+/**
+ * Edit profile success message
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses bbp_is_single_user() To check if it's the profile page
+ * @uses bbp_is_single_user_edit() To check if it's the profile edit page
+ */
+function bbp_notice_edit_user_success() {
+	if ( isset( $_GET['updated'] ) && ( bbp_is_single_user() || bbp_is_single_user_edit() ) ) : ?>
+
+	<div class="bbp-template-notice updated">
+		<p><?php esc_html_e( 'User updated.', 'bbpress' ); ?></p>
+	</div>
+
+	<?php endif;
+}
+
+/**
+ * Super admin privileges notice
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses is_multisite() To check if the blog is multisite
+ * @uses bbp_is_single_user() To check if it's the profile page
+ * @uses bbp_is_single_user_edit() To check if it's the profile edit page
+ * @uses current_user_can() To check if the current user can manage network
+ *                           options
+ * @uses bbp_get_displayed_user_id() To get the displayed user id
+ * @uses is_super_admin() To check if the user is super admin
+ * @uses bbp_is_user_home() To check if it's the user home
+ * @uses bbp_is_user_home_edit() To check if it's the user home edit
+ */
+function bbp_notice_edit_user_is_super_admin() {
+	if ( is_multisite() && ( bbp_is_single_user() || bbp_is_single_user_edit() ) && current_user_can( 'manage_network_options' ) && is_super_admin( bbp_get_displayed_user_id() ) ) : ?>
+
+	<div class="bbp-template-notice important">
+		<p><?php bbp_is_user_home() || bbp_is_user_home_edit() ? esc_html_e( 'You have super admin privileges.', 'bbpress' ) : esc_html_e( 'This user has super admin privileges.', 'bbpress' ); ?></p>
+	</div>
+
+<?php endif;
+}
+
+/**
+ * Drop down for selecting the user's display name
+ *
+ * @since bbPress (r2688)
+ */
+function bbp_edit_user_display_name() {
+	$bbp            = bbpress();
+	$public_display = array();
+	$public_display['display_username'] = $bbp->displayed_user->user_login;
+
+	if ( !empty( $bbp->displayed_user->nickname ) )
+		$public_display['display_nickname']  = $bbp->displayed_user->nickname;
+
+	if ( !empty( $bbp->displayed_user->first_name ) )
+		$public_display['display_firstname'] = $bbp->displayed_user->first_name;
+
+	if ( !empty( $bbp->displayed_user->last_name ) )
+		$public_display['display_lastname']  = $bbp->displayed_user->last_name;
+
+	if ( !empty( $bbp->displayed_user->first_name ) && !empty( $bbp->displayed_user->last_name ) ) {
+		$public_display['display_firstlast'] = $bbp->displayed_user->first_name . ' ' . $bbp->displayed_user->last_name;
+		$public_display['display_lastfirst'] = $bbp->displayed_user->last_name  . ' ' . $bbp->displayed_user->first_name;
+	}
+
+	if ( !in_array( $bbp->displayed_user->display_name, $public_display ) ) // Only add this if it isn't duplicated elsewhere
+		$public_display = array( 'display_displayname' => $bbp->displayed_user->display_name ) + $public_display;
+
+	$public_display = array_map( 'trim', $public_display );
+	$public_display = array_unique( $public_display ); ?>
+
+	<select name="display_name" id="display_name">
+
+	<?php foreach ( $public_display as $id => $item ) : ?>
+
+		<option id="<?php echo $id; ?>" value="<?php echo esc_attr( $item ); ?>"<?php selected( $bbp->displayed_user->display_name, $item ); ?>><?php echo $item; ?></option>
+
+	<?php endforeach; ?>
+
+	</select>
+
+<?php
+}
+
+/**
+ * Output blog role selector (for user edit)
+ *
+ * @since bbPress (r2688)
+ */
+function bbp_edit_user_blog_role() {
+
+	// Return if no user is being edited
+	if ( ! bbp_is_single_user_edit() )
+		return;
+
+	// Get users current blog role
+	$user_role  = bbp_get_user_blog_role( bbp_get_displayed_user_id() );
+
+	// Get the blog roles
+	$blog_roles = bbp_get_blog_roles(); ?>
+
+	<select name="role" id="role">
+		<option value=""><?php esc_html_e( '&mdash; No role for this site &mdash;', 'bbpress' ); ?></option>
+
+		<?php foreach ( $blog_roles as $role => $details ) : ?>
+
+			<option <?php selected( $user_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo translate_user_role( $details['name'] ); ?></option>
+
+		<?php endforeach; ?>
+
+	</select>
+
+	<?php
+}
+
+/**
+ * Output forum role selector (for user edit)
+ *
+ * @since bbPress (r4284)
+ */
+function bbp_edit_user_forums_role() {
+
+	// Return if no user is being edited
+	if ( ! bbp_is_single_user_edit() )
+		return;
+
+	// Get the user's current forum role
+	$user_role     = bbp_get_user_role( bbp_get_displayed_user_id() );
+
+	// Get the folum roles
+	$dynamic_roles = bbp_get_dynamic_roles();
+
+	// Only keymasters can set other keymasters
+	if ( ! bbp_is_user_keymaster() )
+		unset( $dynamic_roles[ bbp_get_keymaster_role() ] ); ?>
+
+	<select name="bbp-forums-role" id="bbp-forums-role">
+		<option value=""><?php esc_html_e( '&mdash; No role for these forums &mdash;', 'bbpress' ); ?></option>
+
+		<?php foreach ( $dynamic_roles as $role => $details ) : ?>
+
+			<option <?php selected( $user_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo translate_user_role( $details['name'] ); ?></option>
+
+		<?php endforeach; ?>
+
+	</select>
+
+	<?php
+}
+
+/**
+ * Return user contact methods Selectbox
+ *
+ * @since bbPress (r2688)
+ *
+ * @uses _wp_get_user_contactmethods() To get the contact methods
+ * @uses apply_filters() Calls 'bbp_edit_user_contact_methods' with the methods
+ * @return string User contact methods
+ */
+function bbp_edit_user_contact_methods() {
+
+	// Get the core WordPress contact methods
+	$contact_methods = _wp_get_user_contactmethods( bbpress()->displayed_user );
+
+	return apply_filters( 'bbp_edit_user_contact_methods', $contact_methods );
+}
+
+/** Topics Created ************************************************************/
+
+/**
+ * Output the link to the user's topics
+ *
+ * @since bbPress (r4225)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_favorites_permalink() To get the favorites permalink
+ */
+function bbp_user_topics_created_url( $user_id = 0 ) {
+	echo esc_url( bbp_get_user_topics_created_url( $user_id ) );
+}
+	/**
+	 * Return the link to the user's topics
+	 *
+	 * @since bbPress (r4225)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @uses bbp_get_user_profile_url() To get the user profile url
+	 * @uses apply_filters() Calls 'bbp_get_favorites_permalink' with the
+	 *                        user profile url and user id
+	 * @return string Permanent link to user profile page
+	 */
+	function bbp_get_user_topics_created_url( $user_id = 0 ) {
+		global $wp_rewrite;
+
+		// Use displayed user ID if there is one, and one isn't requested
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		// Allow early overriding of the profile URL to cut down on processing
+		$early_url = apply_filters( 'bbp_pre_get_user_topics_created_url', (int) $user_id );
+		if ( is_string( $early_url ) )
+			return $early_url;
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url  = $wp_rewrite->root . bbp_get_user_slug() . '/%' . bbp_get_user_rewrite_id() . '%/' . bbp_get_topic_archive_slug();
+			$user = get_userdata( $user_id );
+			if ( ! empty( $user->user_nicename ) ) {
+				$user_nicename = $user->user_nicename;
+			} else {
+				$user_nicename = $user->user_login;
+			}
+			$url = str_replace( '%' . bbp_get_user_rewrite_id() . '%', $user_nicename, $url );
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array(
+				bbp_get_user_rewrite_id()        => $user_id,
+				bbp_get_user_topics_rewrite_id() => '1',
+			), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_user_topics_created_url', $url, $user_id );
+	}
+
+/** Topics Created ************************************************************/
+
+/**
+ * Output the link to the user's replies
+ *
+ * @since bbPress (r4225)
+ *
+ * @param int $user_id Optional. User id
+ * @uses bbp_get_favorites_permalink() To get the favorites permalink
+ */
+function bbp_user_replies_created_url( $user_id = 0 ) {
+	echo esc_url( bbp_get_user_replies_created_url( $user_id ) );
+}
+	/**
+	 * Return the link to the user's replies
+	 *
+	 * @since bbPress (r4225)
+	 *
+	 * @param int $user_id Optional. User id
+	 * @uses bbp_get_user_profile_url() To get the user profile url
+	 * @uses apply_filters() Calls 'bbp_get_favorites_permalink' with the
+	 *                        user profile url and user id
+	 * @return string Permanent link to user profile page
+	 */
+	function bbp_get_user_replies_created_url( $user_id = 0 ) {
+		global $wp_rewrite;
+
+		// Use displayed user ID if there is one, and one isn't requested
+		$user_id = bbp_get_user_id( $user_id );
+		if ( empty( $user_id ) )
+			return false;
+
+		// Allow early overriding of the profile URL to cut down on processing
+		$early_url = apply_filters( 'bbp_pre_get_user_replies_created_url', (int) $user_id );
+		if ( is_string( $early_url ) )
+			return $early_url;
+
+		// Pretty permalinks
+		if ( $wp_rewrite->using_permalinks() ) {
+			$url  = $wp_rewrite->root . bbp_get_user_slug() . '/%' . bbp_get_user_rewrite_id() . '%/' . bbp_get_reply_archive_slug();
+			$user = get_userdata( $user_id );
+			if ( ! empty( $user->user_nicename ) ) {
+				$user_nicename = $user->user_nicename;
+			} else {
+				$user_nicename = $user->user_login;
+			}
+			$url = str_replace( '%' . bbp_get_user_rewrite_id() . '%', $user_nicename, $url );
+			$url = home_url( user_trailingslashit( $url ) );
+
+		// Unpretty permalinks
+		} else {
+			$url = add_query_arg( array(
+				bbp_get_user_rewrite_id()         => $user_id,
+				bbp_get_user_replies_rewrite_id() => '1',
+			), home_url( '/' ) );
+		}
+
+		return apply_filters( 'bbp_get_user_replies_created_url', $url, $user_id );
+	}
+
+/** Login *********************************************************************/
+
+/**
+ * Handle the login and registration template notices
+ *
+ * @since bbPress (r2970)
+ *
+ * @uses WP_Error bbPress::errors::add() To add an error or message
+ */
+function bbp_login_notices() {
+
+	// loggedout was passed
+	if ( !empty( $_GET['loggedout'] ) && ( true === $_GET['loggedout'] ) ) {
+		bbp_add_error( 'loggedout', __( 'You are now logged out.', 'bbpress' ), 'message' );
+
+	// registration is disabled
+	} elseif ( !empty( $_GET['registration'] ) && ( 'disabled' === $_GET['registration'] ) ) {
+		bbp_add_error( 'registerdisabled', __( 'New user registration is currently not allowed.', 'bbpress' ) );
+
+	// Prompt user to check their email
+	} elseif ( !empty( $_GET['checkemail'] ) && in_array( $_GET['checkemail'], array( 'confirm', 'newpass', 'registered' ) ) ) {
+
+		switch ( $_GET['checkemail'] ) {
+
+			// Email needs confirmation
+			case 'confirm' :
+				bbp_add_error( 'confirm',    __( 'Check your e-mail for the confirmation link.',     'bbpress' ), 'message' );
+				break;
+
+			// User requested a new password
+			case 'newpass' :
+				bbp_add_error( 'newpass',    __( 'Check your e-mail for your new password.',         'bbpress' ), 'message' );
+				break;
+
+			// User is newly registered
+			case 'registered' :
+				bbp_add_error( 'registered', __( 'Registration complete. Please check your e-mail.', 'bbpress' ), 'message' );
+				break;
+		}
+	}
+}
+
+/**
+ * Redirect a user back to their profile if they are already logged in.
+ *
+ * This should be used before {@link get_header()} is called in template files
+ * where the user should never have access to the contents of that file.
+ *
+ * @since bbPress (r2815)
+ *
+ * @param string $url The URL to redirect to
+ * @uses is_user_logged_in() Check if user is logged in
+ * @uses wp_safe_redirect() To safely redirect
+ * @uses bbp_get_user_profile_url() To get the profile url of the user
+ * @uses bbp_get_current_user_id() To get the current user id
+ */
+function bbp_logged_in_redirect( $url = '' ) {
+
+	// Bail if user is not logged in
+	if ( !is_user_logged_in() )
+		return;
+
+	// Setup the profile page to redirect to
+	$redirect_to = !empty( $url ) ? $url : bbp_get_user_profile_url( bbp_get_current_user_id() );
+
+	// Do a safe redirect and exit
+	wp_safe_redirect( $redirect_to );
+	exit;
+}
+
+/**
+ * Output the required hidden fields when logging in
+ *
+ * @since bbPress (r2815)
+ *
+ * @uses apply_filters() To allow custom redirection
+ * @uses bbp_redirect_to_field() To output the hidden request url field
+ * @uses wp_nonce_field() To generate hidden nonce fields
+ */
+function bbp_user_login_fields() {
+?>
+
+		<input type="hidden" name="user-cookie" value="1" />
+
+		<?php
+
+		// Allow custom login redirection
+		$redirect_to = apply_filters( 'bbp_user_login_redirect_to', '' );
+		bbp_redirect_to_field( $redirect_to );
+
+		// Prevent intention hi-jacking of log-in form
+		wp_nonce_field( 'bbp-user-login' );
+}
+
+/** Register ******************************************************************/
+
+/**
+ * Output the required hidden fields when registering
+ *
+ * @since bbPress (r2815)
+ *
+ * @uses add_query_arg() To add query args
+ * @uses bbp_login_url() To get the login url
+ * @uses apply_filters() To allow custom redirection
+ * @uses bbp_redirect_to_field() To output the redirect to field
+ * @uses wp_nonce_field() To generate hidden nonce fields
+ */
+function bbp_user_register_fields() {
+?>
+
+		<input type="hidden" name="action"      value="register" />
+		<input type="hidden" name="user-cookie" value="1" />
+
+		<?php
+
+		// Allow custom registration redirection
+		$redirect_to = apply_filters( 'bbp_user_register_redirect_to', '' );
+		bbp_redirect_to_field( add_query_arg( array( 'checkemail' => 'registered' ), $redirect_to ) );
+
+		// Prevent intention hi-jacking of sign-up form
+		wp_nonce_field( 'bbp-user-register' );
+}
+
+/** Lost Password *************************************************************/
+
+/**
+ * Output the required hidden fields when user lost password
+ *
+ * @since bbPress (r2815)
+ *
+ * @uses apply_filters() To allow custom redirection
+ * @uses bbp_redirect_to_field() Set referer
+ * @uses wp_nonce_field() To generate hidden nonce fields
+ */
+function bbp_user_lost_pass_fields() {
+?>
+
+		<input type="hidden" name="user-cookie" value="1" />
+
+		<?php
+
+		// Allow custom lost pass redirection
+		$redirect_to = apply_filters( 'bbp_user_lost_pass_redirect_to', get_permalink() );
+		bbp_redirect_to_field( add_query_arg( array( 'checkemail' => 'confirm' ), $redirect_to ) );
+
+		// Prevent intention hi-jacking of lost pass form
+		wp_nonce_field( 'bbp-user-lost-pass' );
+}
+
+/** Author Avatar *************************************************************/
+
+/**
+ * Output the author link of a post
+ *
+ * @since bbPress (r2875)
+ *
+ * @param mixed $args Optional. If it is an integer, it is used as post id.
+ * @uses bbp_get_author_link() To get the post author link
+ */
+function bbp_author_link( $args = '' ) {
+	echo bbp_get_author_link( $args );
+}
+	/**
+	 * Return the author link of the post
+	 *
+	 * @since bbPress (r2875)
+	 *
+	 * @param mixed $args Optional. If an integer, it is used as reply id.
+	 * @uses bbp_is_topic() To check if it's a topic page
+	 * @uses bbp_get_topic_author_link() To get the topic author link
+	 * @uses bbp_is_reply() To check if it's a reply page
+	 * @uses bbp_get_reply_author_link() To get the reply author link
+	 * @uses get_post_field() To get the post author
+	 * @uses bbp_is_reply_anonymous() To check if the reply is by an
+	 *                                 anonymous user
+	 * @uses get_the_author_meta() To get the author name
+	 * @uses bbp_get_user_profile_url() To get the author profile url
+	 * @uses get_avatar() To get the author avatar
+	 * @uses apply_filters() Calls 'bbp_get_reply_author_link' with the
+	 *                        author link and args
+	 * @return string Author link of reply
+	 */
+	function bbp_get_author_link( $args = '' ) {
+
+		$post_id = is_numeric( $args ) ? (int) $args : 0;
+
+		// Parse arguments against default values
+		$r = bbp_parse_args( $args, array(
+			'post_id'    => $post_id,
+			'link_title' => '',
+			'type'       => 'both',
+			'size'       => 80
+		), 'get_author_link' );
+
+		// Confirmed topic
+		if ( bbp_is_topic( $r['post_id'] ) ) {
+			return bbp_get_topic_author_link( $r );
+
+		// Confirmed reply
+		} elseif ( bbp_is_reply( $r['post_id'] ) ) {
+			return bbp_get_reply_author_link( $r );
+		}
+
+		// Get the post author and proceed
+		$user_id = get_post_field( 'post_author', $r['post_id'] );
+
+		// Neither a reply nor a topic, so could be a revision
+		if ( !empty( $r['post_id'] ) ) {
+
+			// Generate title with the display name of the author
+			if ( empty( $r['link_title'] ) ) {
+				$r['link_title'] = sprintf( !bbp_is_reply_anonymous( $r['post_id'] ) ? __( 'View %s\'s profile', 'bbpress' ) : __( 'Visit %s\'s website', 'bbpress' ), get_the_author_meta( 'display_name', $user_id ) );
+			}
+
+			// Assemble some link bits
+			$link_title = !empty( $r['link_title'] ) ? ' title="' . $r['link_title'] . '"' : '';
+			$anonymous  = bbp_is_reply_anonymous( $r['post_id'] );
+
+			// Get avatar
+			if ( 'avatar' === $r['type'] || 'both' === $r['type'] ) {
+				$author_links[] = get_avatar( $user_id, $r['size'] );
+			}
+
+			// Get display name
+			if ( 'name' === $r['type'] || 'both' === $r['type'] ) {
+				$author_links[] = get_the_author_meta( 'display_name', $user_id );
+			}
+
+			// Add links if not anonymous
+			if ( empty( $anonymous ) && bbp_user_has_profile( $user_id ) ) {
+				$author_url = bbp_get_user_profile_url( $user_id );
+				foreach ( $author_links as $link_text ) {
+					$author_link[] = sprintf( '<a href="%1$s"%2$s>%3$s</a>', $author_url, $link_title, $link_text );
+				}
+				$author_link = implode( '&nbsp;', $author_link );
+
+			// No links if anonymous
+			} else {
+				$author_link = implode( '&nbsp;', $author_links );
+			}
+
+		// No post so link is empty
+		} else {
+			$author_link = '';
+		}
+
+		return apply_filters( 'bbp_get_author_link', $author_link, $r );
+	}
+
+/** Capabilities **************************************************************/
+
+/**
+ * Check if the user can access a specific forum
+ *
+ * @since bbPress (r3127)
+ *
+ * @uses bbp_get_current_user_id()
+ * @uses bbp_get_forum_id()
+ * @uses bbp_allow_anonymous()
+ * @uses bbp_parse_args()
+ * @uses bbp_get_user_id()
+ * @uses current_user_can()
+ * @uses bbp_is_user_keymaster()
+ * @uses bbp_is_forum_public()
+ * @uses bbp_is_forum_private()
+ * @uses bbp_is_forum_hidden()
+ * @uses current_user_can()
+ * @uses apply_filters()
+ *
+ * @return bool
+ */
+function bbp_user_can_view_forum( $args = '' ) {
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'user_id'         => bbp_get_current_user_id(),
+		'forum_id'        => bbp_get_forum_id(),
+		'check_ancestors' => false
+	), 'user_can_view_forum' );
+
+	// Validate parsed values
+	$user_id  = bbp_get_user_id( $r['user_id'], false, false );
+	$forum_id = bbp_get_forum_id( $r['forum_id'] );
+	$retval   = false;
+
+	// User is a keymaster
+	if ( !empty( $user_id ) && bbp_is_user_keymaster( $user_id ) ) {
+		$retval = true;
+
+	// Forum is public, and user can read forums or is not logged in
+	} elseif ( bbp_is_forum_public( $forum_id, $r['check_ancestors'] ) ) {
+		$retval = true;
+
+	// Forum is private, and user can see it
+	} elseif ( bbp_is_forum_private( $forum_id, $r['check_ancestors'] ) && user_can( $user_id, 'read_private_forums' ) ) {
+		$retval = true;
+
+	// Forum is hidden, and user can see it
+	} elseif ( bbp_is_forum_hidden ( $forum_id, $r['check_ancestors'] ) && user_can( $user_id, 'read_hidden_forums'  ) ) {
+		$retval = true;
+	}
+
+	return apply_filters( 'bbp_user_can_view_forum', $retval, $forum_id, $user_id );
+}
+
+/**
+ * Check if the current user can publish topics
+ *
+ * @since bbPress (r3127)
+ *
+ * @uses bbp_is_user_keymaster()
+ * @uses is_user_logged_in()
+ * @uses bbp_allow_anonymous()
+ * @uses bbp_is_user_active()
+ * @uses current_user_can()
+ * @uses apply_filters()
+ *
+ * @return bool
+ */
+function bbp_current_user_can_publish_topics() {
+
+	// Users need to earn access
+	$retval = false;
+
+	// Always allow keymasters
+	if ( bbp_is_user_keymaster() ) {
+		$retval = true;
+
+	// Do not allow anonymous if not enabled
+	} elseif ( !is_user_logged_in() && bbp_allow_anonymous() ) {
+		$retval = true;
+
+	// User is logged in
+	} elseif ( current_user_can( 'publish_topics' ) ) {
+		$retval = true;
+	}
+
+	// Allow access to be filtered
+	return (bool) apply_filters( 'bbp_current_user_can_publish_topics', $retval );
+}
+
+/**
+ * Check if the current user can publish forums
+ *
+ * @since bbPress (r3549)
+ *
+ * @uses bbp_is_user_keymaster()
+ * @uses bbp_is_user_active()
+ * @uses current_user_can()
+ * @uses apply_filters()
+ *
+ * @return bool
+ */
+function bbp_current_user_can_publish_forums() {
+
+	// Users need to earn access
+	$retval = false;
+
+	// Always allow keymasters
+	if ( bbp_is_user_keymaster() ) {
+		$retval = true;
+
+	// User is logged in
+	} elseif ( current_user_can( 'publish_forums' ) ) {
+		$retval = true;
+	}
+
+	// Allow access to be filtered
+	return (bool) apply_filters( 'bbp_current_user_can_publish_forums', $retval );
+}
+
+/**
+ * Check if the current user can publish replies
+ *
+ * @since bbPress (r3127)
+ *
+ * @uses bbp_is_user_keymaster()
+ * @uses is_user_logged_in()
+ * @uses bbp_allow_anonymous()
+ * @uses bbp_is_user_active()
+ * @uses current_user_can()
+ * @uses apply_filters()
+ *
+ * @return bool
+ */
+function bbp_current_user_can_publish_replies() {
+
+	// Users need to earn access
+	$retval = false;
+
+	// Always allow keymasters
+	if ( bbp_is_user_keymaster() ) {
+		$retval = true;
+
+	// Do not allow anonymous if not enabled
+	} elseif ( !is_user_logged_in() && bbp_allow_anonymous() ) {
+		$retval = true;
+
+	// User is logged in
+	} elseif ( current_user_can( 'publish_replies' ) ) {
+		$retval = true;
+	}
+
+	// Allow access to be filtered
+	return (bool) apply_filters( 'bbp_current_user_can_publish_replies', $retval );
+}
+
+/** Forms *********************************************************************/
+
+/**
+ * The following functions should be turned into mapped meta capabilities in a
+ * future version. They exist only to remove complex logistical capability
+ * checks from within template parts.
+ */
+
+/**
+ * Get the forums the current user has the ability to see and post to
+ *
+ * @since bbPress (r3127)
+ *
+ * @uses bbp_get_forum_post_type()
+ * @uses get_posts()
+ *
+ * @param type $args
+ * @return type
+ */
+function bbp_get_forums_for_current_user( $args = array() ) {
+
+	// Setup arrays
+	$private = $hidden = $post__not_in = array();
+
+	// Private forums
+	if ( !current_user_can( 'read_private_forums' ) )
+		$private = bbp_get_private_forum_ids();
+
+	// Hidden forums
+	if ( !current_user_can( 'read_hidden_forums' ) )
+		$hidden  = bbp_get_hidden_forum_ids();
+
+	// Merge private and hidden forums together and remove any empties
+	$forum_ids = (array) array_filter( wp_parse_id_list( array_merge( $private, $hidden ) ) );
+
+	// There are forums that need to be ex
+	if ( !empty( $forum_ids ) )
+		$post__not_in = implode( ',', $forum_ids );
+
+	// Parse arguments against default values
+	$r = bbp_parse_args( $args, array(
+		'post_type'   => bbp_get_forum_post_type(),
+		'post_status' => bbp_get_public_status_id(),
+		'numberposts' => -1,
+		'exclude'     => $post__not_in
+	), 'get_forums_for_current_user' );
+
+	// Get the forums
+	$forums = get_posts( $r );
+
+	// No availabe forums
+	if ( empty( $forums ) )
+		$forums = false;
+
+	return apply_filters( 'bbp_get_forums_for_current_user', $forums );
+}
+
+/**
+ * Performs a series of checks to ensure the current user can create forums.
+ *
+ * @since bbPress (r3549)
+ *
+ * @uses bbp_is_user_keymaster()
+ * @uses bbp_is_forum_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_forum_id()
+ *
+ * @return bool
+ */
+function bbp_current_user_can_access_create_forum_form() {
+
+	// Users need to earn access
+	$retval = false;
+
+	// Always allow keymasters
+	if ( bbp_is_user_keymaster() ) {
+		$retval = true;
+
+	// Looking at a single forum & forum is open
+	} elseif ( ( is_page() || is_single() ) && bbp_is_forum_open() ) {
+		$retval = bbp_current_user_can_publish_forums();
+
+	// User can edit this topic
+	} elseif ( bbp_is_forum_edit() ) {
+		$retval = current_user_can( 'edit_forum', bbp_get_forum_id() );
+	}
+
+	// Allow access to be filtered
+	return (bool) apply_filters( 'bbp_current_user_can_access_create_forum_form', (bool) $retval );
+}
+
+/**
+ * Performs a series of checks to ensure the current user can create topics.
+ *
+ * @since bbPress (r3127)
+ *
+ * @uses bbp_is_user_keymaster()
+ * @uses bbp_is_topic_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_topic_id()
+ * @uses bbp_allow_anonymous()
+ * @uses is_user_logged_in()
+ *
+ * @return bool
+ */
+function bbp_current_user_can_access_create_topic_form() {
+
+	// Users need to earn access
+	$retval = false;
+
+	// Always allow keymasters
+	if ( bbp_is_user_keymaster() ) {
+		$retval = true;
+
+	// Looking at a single forum & forum is open
+	} elseif ( ( bbp_is_single_forum() || is_page() || is_single() ) && bbp_is_forum_open() ) {
+		$retval = bbp_current_user_can_publish_topics();
+
+	// User can edit this topic
+	} elseif ( bbp_is_topic_edit() ) {
+		$retval = current_user_can( 'edit_topic', bbp_get_topic_id() );
+	}
+
+	// Allow access to be filtered
+	return (bool) apply_filters( 'bbp_current_user_can_access_create_topic_form', (bool) $retval );
+}
+
+/**
+ * Performs a series of checks to ensure the current user can create replies.
+ *
+ * @since bbPress (r3127)
+ *
+ * @uses bbp_is_user_keymaster()
+ * @uses bbp_is_topic_edit()
+ * @uses current_user_can()
+ * @uses bbp_get_topic_id()
+ * @uses bbp_allow_anonymous()
+ * @uses is_user_logged_in()
+ *
+ * @return bool
+ */
+function bbp_current_user_can_access_create_reply_form() {
+
+	// Users need to earn access
+	$retval = false;
+
+	// Always allow keymasters
+	if ( bbp_is_user_keymaster() ) {
+		$retval = true;
+
+	// Looking at a single topic, topic is open, and forum is open
+	} elseif ( ( bbp_is_single_topic() || is_page() || is_single() ) && bbp_is_topic_open() && bbp_is_forum_open() ) {
+		$retval = bbp_current_user_can_publish_replies();
+
+	// User can edit this topic
+	} elseif ( bbp_is_reply_edit() ) {
+		$retval = current_user_can( 'edit_reply', bbp_get_reply_id() );
+	}
+
+	// Allow access to be filtered
+	return (bool) apply_filters( 'bbp_current_user_can_access_create_reply_form', (bool) $retval );
+}
+
+/**
+ * Performs a series of checks to ensure the current user should see the
+ * anonymous user form fields.
+ *
+ * @since bbPress (r5119)
+ *
+ * @uses bbp_is_anonymous()
+ * @uses bbp_is_topic_edit()
+ * @uses bbp_is_topic_anonymous()
+ * @uses bbp_is_reply_edit()
+ * @uses bbp_is_reply_anonymous()
+ *
+ * @return bool
+ */
+function bbp_current_user_can_access_anonymous_user_form() {
+
+	// Users need to earn access
+	$retval = false;
+
+	// User is not logged in, and anonymous posting is allowed
+	if ( bbp_is_anonymous() ) {
+		$retval = true;
+
+	// User is editing a topic, and topic is authored by anonymous user
+	} elseif ( bbp_is_topic_edit() && bbp_is_topic_anonymous() ) {
+		$retval = true;
+
+	// User is editing a reply, and reply is authored by anonymous user
+	} elseif ( bbp_is_reply_edit() && bbp_is_reply_anonymous() ) {
+		$retval = true;
+	}
+
+	// Allow access to be filtered
+	return (bool) apply_filters( 'bbp_current_user_can_access_anonymous_user_form', (bool) $retval );
+}
Index: /tags/2.5.4/index.php
===================================================================
--- /tags/2.5.4/index.php	(revision 5382)
+++ /tags/2.5.4/index.php	(revision 5382)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * Do not modify the files in this folder.
+ */
Index: /tags/2.5.4/languages/bbpress.pot
===================================================================
--- /tags/2.5.4/languages/bbpress.pot	(revision 5382)
+++ /tags/2.5.4/languages/bbpress.pot	(revision 5382)
@@ -0,0 +1,4943 @@
+# Copyright (C) 2014 bbPress
+# This file is distributed under the same license as the bbPress package.
+msgid ""
+msgstr ""
+"Project-Id-Version: bbPress 2.5.4\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/bbpress\n"
+"POT-Creation-Date: 2014-01-11 18:30:39+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
+"Last-Translator: JOHN JAMES JACOBY <jjj@bbpress.org>\n"
+"Language-Team: ENGLISH <jjj@bbpress.org>\n"
+
+#: bbpress.php:133 bbpress.php:140
+msgid "Cheatin&#8217; huh?"
+msgstr ""
+
+#: bbpress.php:404 templates/default/bbpress-functions.php:51
+msgid "bbPress Default"
+msgstr ""
+
+#: bbpress.php:484
+msgid "bbPress Forums"
+msgstr ""
+
+#: bbpress.php:509
+msgid "bbPress Topics"
+msgstr ""
+
+#: bbpress.php:534
+msgid "bbPress Replies"
+msgstr ""
+
+#: bbpress.php:569
+msgctxt "post"
+msgid "Closed"
+msgstr ""
+
+#: bbpress.php:570
+msgctxt "post"
+msgid "Closed <span class=\"count\">(%s)</span>"
+msgid_plural "Closed <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bbpress.php:580
+msgctxt "post"
+msgid "Spam"
+msgstr ""
+
+#: bbpress.php:581
+msgctxt "post"
+msgid "Spam <span class=\"count\">(%s)</span>"
+msgid_plural "Spam <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bbpress.php:593
+msgctxt "post"
+msgid "Orphan"
+msgstr ""
+
+#: bbpress.php:594
+msgctxt "post"
+msgid "Orphan <span class=\"count\">(%s)</span>"
+msgid_plural "Orphans <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bbpress.php:606
+msgctxt "post"
+msgid "Hidden"
+msgstr ""
+
+#: bbpress.php:607
+msgctxt "post"
+msgid "Hidden <span class=\"count\">(%s)</span>"
+msgid_plural "Hidden <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bbpress.php:677
+msgid "Most popular topics"
+msgstr ""
+
+#: bbpress.php:689
+msgid "Topics with no replies"
+msgstr ""
+
+#: includes/admin/admin.php:200 includes/admin/functions.php:243
+#: includes/admin/tools.php:34
+msgid "Repair Forums"
+msgstr ""
+
+#: includes/admin/admin.php:201
+msgid "Forum Repair"
+msgstr ""
+
+#: includes/admin/admin.php:210 includes/admin/functions.php:247
+#: includes/admin/settings.php:1509
+msgid "Import Forums"
+msgstr ""
+
+#: includes/admin/admin.php:211
+msgid "Forum Import"
+msgstr ""
+
+#: includes/admin/admin.php:220 includes/admin/functions.php:251
+#: includes/admin/tools.php:1132
+msgid "Reset Forums"
+msgstr ""
+
+#: includes/admin/admin.php:221
+msgid "Forum Reset"
+msgstr ""
+
+#: includes/admin/admin.php:235 includes/admin/admin.php:236
+#: includes/admin/admin.php:246 includes/admin/admin.php:247
+#: includes/admin/users.php:82 includes/common/widgets.php:662
+#: includes/extend/buddypress/loader.php:42
+#: includes/extend/buddypress/loader.php:175
+#: includes/extend/buddypress/loader.php:261
+#: includes/extend/buddypress/loader.php:312 includes/forums/template.php:47
+#: includes/forums/template.php:48
+#: templates/default/bbpress/content-statistics.php:22
+msgid "Forums"
+msgstr ""
+
+#: includes/admin/admin.php:259 includes/admin/admin.php:260
+#: includes/admin/admin.php:268 includes/admin/admin.php:269
+msgid "Welcome to bbPress"
+msgstr ""
+
+#: includes/admin/admin.php:282 includes/admin/admin.php:283
+#: includes/admin/admin.php:304 includes/admin/admin.php:305
+#: includes/admin/admin.php:986 includes/admin/admin.php:1073
+msgid "Update Forums"
+msgstr ""
+
+#: includes/admin/admin.php:512
+msgid "Settings"
+msgstr ""
+
+#: includes/admin/admin.php:517
+msgid "About"
+msgstr ""
+
+#: includes/admin/admin.php:532
+msgid "Right Now in Forums"
+msgstr ""
+
+#: includes/admin/admin.php:549
+msgid "About bbPress"
+msgstr ""
+
+#: includes/admin/admin.php:634
+msgctxt "admin color scheme"
+msgid "Mint"
+msgstr ""
+
+#: includes/admin/admin.php:643
+msgctxt "admin color scheme"
+msgid "Evergreen"
+msgstr ""
+
+#: includes/admin/admin.php:710 includes/admin/admin.php:734
+msgid "%s - %s"
+msgstr ""
+
+#: includes/admin/admin.php:752 includes/admin/admin.php:829
+msgid "Welcome to bbPress %s"
+msgstr ""
+
+#: includes/admin/admin.php:753
+msgid ""
+"Thank you for updating! bbPress %s is bundled up and ready to weather the "
+"storm of users in your community!"
+msgstr ""
+
+#: includes/admin/admin.php:754 includes/admin/admin.php:831
+msgid "Version %s"
+msgstr ""
+
+#: includes/admin/admin.php:758 includes/admin/admin.php:835
+msgid "What&#8217;s New"
+msgstr ""
+
+#: includes/admin/admin.php:760 includes/admin/admin.php:837
+msgid "Credits"
+msgstr ""
+
+#: includes/admin/admin.php:765
+msgid "Forum Subscriptions"
+msgstr ""
+
+#: includes/admin/admin.php:769
+msgid "Subscribe to Forums"
+msgstr ""
+
+#: includes/admin/admin.php:770
+msgid "Now your users can subscribe to new topics in specific forums."
+msgstr ""
+
+#: includes/admin/admin.php:774
+msgid "Manage Subscriptions"
+msgstr ""
+
+#: includes/admin/admin.php:775
+msgid ""
+"Your users can manage all of their subscriptions in one convenient location."
+msgstr ""
+
+#: includes/admin/admin.php:781
+msgid "Converters"
+msgstr ""
+
+#: includes/admin/admin.php:785
+msgid ""
+"We&#8217;re all abuzz about the hive of new importers, AEF, Drupal, FluxBB, "
+"Kunena Forums for Joomla, MyBB, Phorum, PHPFox, PHPWind, PunBB, SMF, Xenforo "
+"and XMB. Existing importers are now sweeter than honey with improved "
+"importing stickies, topic tags, forum categories and the sting is now gone "
+"if you need to remove imported users."
+msgstr ""
+
+#: includes/admin/admin.php:791
+msgid "Theme Compatibility"
+msgstr ""
+
+#: includes/admin/admin.php:792
+msgid "Better handling of styles and scripts in the template stack."
+msgstr ""
+
+#: includes/admin/admin.php:796
+msgid "Polyglot support"
+msgstr ""
+
+#: includes/admin/admin.php:797
+msgid "bbPress fully supports automatic translation updates."
+msgstr ""
+
+#: includes/admin/admin.php:801
+msgid "User capabilities"
+msgstr ""
+
+#: includes/admin/admin.php:802
+msgid ""
+"Roles and capabilities have been swept through, cleaned up, and simplified."
+msgstr ""
+
+#: includes/admin/admin.php:808 includes/admin/admin.php:912
+msgid "Go to Forum Settings"
+msgstr ""
+
+#: includes/admin/admin.php:830
+msgid ""
+"Thank you for updating! bbPress %s is waxed, polished, and ready for you to "
+"take it for a lap or two around the block!"
+msgstr ""
+
+#: includes/admin/admin.php:841
+msgid "bbPress is created by a worldwide swarm of busy, busy bees."
+msgstr ""
+
+#: includes/admin/admin.php:843
+msgid "Project Leaders"
+msgstr ""
+
+#: includes/admin/admin.php:848
+msgid "Founding Developer"
+msgstr ""
+
+#: includes/admin/admin.php:853
+msgid "Lead Developer"
+msgstr ""
+
+#: includes/admin/admin.php:858 includes/admin/admin.php:877
+msgid "Feature Developer"
+msgstr ""
+
+#: includes/admin/admin.php:863
+msgid "Converter Specialist"
+msgstr ""
+
+#: includes/admin/admin.php:867
+msgid "Contributing Developers"
+msgstr ""
+
+#: includes/admin/admin.php:872
+msgid "Bug Testing"
+msgstr ""
+
+#: includes/admin/admin.php:881
+msgid "Core Contributors to bbPress 2.5"
+msgstr ""
+
+#: includes/admin/admin.php:938 includes/admin/admin.php:960
+msgid "Update Forum"
+msgstr ""
+
+#: includes/admin/admin.php:949 includes/admin/admin.php:1003
+msgid "All done!"
+msgstr ""
+
+#: includes/admin/admin.php:950 includes/admin/admin.php:1004
+msgid "Go Back"
+msgstr ""
+
+#: includes/admin/admin.php:959
+msgid ""
+"You can update your forum through this page. Hit the link below to update."
+msgstr ""
+
+#: includes/admin/admin.php:1029
+msgid ""
+"Warning! Problem updating %1$s. Your server may not be able to connect to "
+"sites running on it. Error message: <em>%2$s</em>"
+msgstr ""
+
+#: includes/admin/admin.php:1053
+msgid ""
+"If your browser doesn&#8217;t start loading the next page automatically, "
+"click this link:"
+msgstr ""
+
+#: includes/admin/admin.php:1054
+msgid "Next Forums"
+msgstr ""
+
+#: includes/admin/admin.php:1072
+msgid ""
+"You can update all the forums on your network through this page. It works by "
+"calling the update script of each site automatically. Hit the link below to "
+"update."
+msgstr ""
+
+#: includes/admin/converter.php:84
+msgid "Database Settings"
+msgstr ""
+
+#: includes/admin/converter.php:87
+msgid "Select Platform"
+msgstr ""
+
+#: includes/admin/converter.php:91
+msgid "Database Server"
+msgstr ""
+
+#: includes/admin/converter.php:95
+msgid "Database Port"
+msgstr ""
+
+#: includes/admin/converter.php:99
+msgid "Database Name"
+msgstr ""
+
+#: includes/admin/converter.php:103
+msgid "Database User"
+msgstr ""
+
+#: includes/admin/converter.php:107
+msgid "Database Password"
+msgstr ""
+
+#: includes/admin/converter.php:111
+msgid "Table Prefix"
+msgstr ""
+
+#: includes/admin/converter.php:115
+msgid "Options"
+msgstr ""
+
+#: includes/admin/converter.php:118
+msgid "Rows Limit"
+msgstr ""
+
+#: includes/admin/converter.php:122
+msgid "Delay Time"
+msgstr ""
+
+#: includes/admin/converter.php:126
+msgid "Convert Users"
+msgstr ""
+
+#: includes/admin/converter.php:130
+msgid "Start Over"
+msgstr ""
+
+#: includes/admin/converter.php:134
+msgid "Purge Previous Import"
+msgstr ""
+
+#: includes/admin/converter.php:223
+msgid "Starting Conversion"
+msgstr ""
+
+#: includes/admin/converter.php:248 includes/admin/converter.php:520
+msgid "Conversion Complete"
+msgstr ""
+
+#: includes/admin/converter.php:342
+msgid "No data to clean"
+msgstr ""
+
+#: includes/admin/converter.php:346
+msgid "Deleting previously converted data (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:362
+msgid "No users to convert"
+msgstr ""
+
+#: includes/admin/converter.php:366
+msgid "Converting users (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:382
+msgid "No passwords to clear"
+msgstr ""
+
+#: includes/admin/converter.php:386
+msgid "Delete users WordPress default passwords (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:401
+msgid "No forums to convert"
+msgstr ""
+
+#: includes/admin/converter.php:405
+msgid "Converting forums (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:416
+msgid "No forum parents to convert"
+msgstr ""
+
+#: includes/admin/converter.php:420
+msgid "Calculating forum hierarchy (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:431
+msgid "No topics to convert"
+msgstr ""
+
+#: includes/admin/converter.php:435
+msgid "Converting topics (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:446
+msgid "No stickies to stick"
+msgstr ""
+
+#: includes/admin/converter.php:450
+msgid "Calculating topic stickies (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:461
+msgid "No super stickies to stick"
+msgstr ""
+
+#: includes/admin/converter.php:465
+msgid "Calculating topic super stickies (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:476
+msgid "No tags to convert"
+msgstr ""
+
+#: includes/admin/converter.php:480
+msgid "Converting topic tags (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:491
+msgid "No replies to convert"
+msgstr ""
+
+#: includes/admin/converter.php:495
+msgid "Converting replies (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converter.php:506
+msgid "No reply_to parents to convert"
+msgstr ""
+
+#: includes/admin/converter.php:510
+msgid "Calculating reply_to parents (%1$s - %2$s)"
+msgstr ""
+
+#: includes/admin/converters/AEF.php:688
+#: includes/admin/converters/FluxBB.php:643
+#: includes/admin/converters/Invision.php:525
+#: includes/admin/converters/Kunena1.php:543
+#: includes/admin/converters/Kunena2.php:585
+#: includes/admin/converters/Kunena3.php:812
+#: includes/admin/converters/PHPFox3.php:649
+#: includes/admin/converters/PunBB.php:677
+#: includes/admin/converters/SMF.php:656
+#: includes/admin/converters/SimplePress5.php:537
+#: includes/admin/converters/Vanilla.php:535
+#: includes/admin/converters/XMB.php:705
+#: includes/admin/converters/XenForo.php:722
+#: includes/admin/converters/bbPress1.php:636
+#: includes/admin/converters/phpBB.php:816
+#: includes/admin/converters/vBulletin.php:652
+#: includes/admin/converters/vBulletin3.php:652
+msgid "Re: "
+msgstr ""
+
+#: includes/admin/forums.php:121 includes/admin/replies.php:132
+#: includes/admin/settings.php:1549 includes/admin/topics.php:132
+msgid "Overview"
+msgstr ""
+
+#: includes/admin/forums.php:123
+msgid ""
+"This screen displays the individual forums on your site. You can customize "
+"the display of this screen to suit your workflow."
+msgstr ""
+
+#: includes/admin/forums.php:129 includes/admin/replies.php:140
+#: includes/admin/topics.php:140
+msgid "Screen Content"
+msgstr ""
+
+#: includes/admin/forums.php:131 includes/admin/replies.php:142
+#: includes/admin/topics.php:142
+msgid ""
+"You can customize the display of this screen&#8217;s contents in a number of "
+"ways:"
+msgstr ""
+
+#: includes/admin/forums.php:133
+msgid ""
+"You can hide/display columns based on your needs and decide how many forums "
+"to list per screen using the Screen Options tab."
+msgstr ""
+
+#: includes/admin/forums.php:134
+msgid ""
+"You can filter the list of forums by forum status using the text links in "
+"the upper left to show All, Published, or Trashed forums. The default view "
+"is to show all forums."
+msgstr ""
+
+#: includes/admin/forums.php:135
+msgid ""
+"You can refine the list to show only forums from a specific month by using "
+"the dropdown menus above the forums list. Click the Filter button after "
+"making your selection. You also can refine the list by clicking on the forum "
+"creator in the forums list."
+msgstr ""
+
+#: includes/admin/forums.php:142 includes/admin/replies.php:154
+#: includes/admin/topics.php:153
+msgid "Available Actions"
+msgstr ""
+
+#: includes/admin/forums.php:144
+msgid ""
+"Hovering over a row in the forums list will display action links that allow "
+"you to manage your forum. You can perform the following actions:"
+msgstr ""
+
+#: includes/admin/forums.php:146
+msgid ""
+"<strong>Edit</strong> takes you to the editing screen for that forum. You "
+"can also reach that screen by clicking on the forum title."
+msgstr ""
+
+#: includes/admin/forums.php:147
+msgid ""
+"<strong>Trash</strong> removes your forum from this list and places it in "
+"the trash, from which you can permanently delete it."
+msgstr ""
+
+#: includes/admin/forums.php:148
+msgid ""
+"<strong>View</strong> will show you what your draft forum will look like if "
+"you publish it. View will take you to your live site to view the forum. "
+"Which link is available depends on your forum&#8217;s status."
+msgstr ""
+
+#: includes/admin/forums.php:155 includes/admin/replies.php:169
+#: includes/admin/topics.php:170
+msgid "Bulk Actions"
+msgstr ""
+
+#: includes/admin/forums.php:157
+msgid ""
+"You can also edit or move multiple forums to the trash at once. Select the "
+"forums you want to act on using the checkboxes, then select the action you "
+"want to take from the Bulk Actions menu and click Apply."
+msgstr ""
+
+#: includes/admin/forums.php:158
+msgid ""
+"When using Bulk Edit, you can change the metadata (categories, author, etc.) "
+"for all selected forums at once. To remove a forum from the grouping, just "
+"click the x next to its name in the Bulk Edit area that appears."
+msgstr ""
+
+#: includes/admin/forums.php:163 includes/admin/forums.php:222
+#: includes/admin/replies.php:177 includes/admin/replies.php:234
+#: includes/admin/settings.php:1595 includes/admin/topics.php:178
+#: includes/admin/topics.php:234
+msgid "For more information:"
+msgstr ""
+
+#: includes/admin/forums.php:164 includes/admin/forums.php:223
+#: includes/admin/replies.php:178 includes/admin/replies.php:235
+#: includes/admin/settings.php:1596 includes/admin/topics.php:179
+#: includes/admin/topics.php:235
+msgid ""
+"<a href=\"http://codex.bbpress.org\" target=\"_blank\">bbPress "
+"Documentation</a>"
+msgstr ""
+
+#: includes/admin/forums.php:165 includes/admin/forums.php:224
+#: includes/admin/replies.php:179 includes/admin/replies.php:236
+#: includes/admin/settings.php:1597 includes/admin/topics.php:180
+#: includes/admin/topics.php:236
+msgid ""
+"<a href=\"http://bbpress.org/forums/\" target=\"_blank\">bbPress Support "
+"Forums</a>"
+msgstr ""
+
+#: includes/admin/forums.php:179
+msgid ""
+"The title field and the big forum editing Area are fixed in place, but you "
+"can reposition all the other boxes using drag and drop, and can minimize or "
+"expand them by clicking the title bar of each box. Use the Screen Options "
+"tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, "
+"Discussion, Slug, Author) or to choose a 1- or 2-column layout for this "
+"screen."
+msgstr ""
+
+#: includes/admin/forums.php:183 includes/admin/replies.php:197
+#: includes/admin/topics.php:198
+msgid "Customizing This Display"
+msgstr ""
+
+#: includes/admin/forums.php:189
+msgid "Title and Forum Editor"
+msgstr ""
+
+#: includes/admin/forums.php:191
+msgid ""
+"<strong>Title</strong> - Enter a title for your forum. After you enter a "
+"title, you&#8217;ll see the permalink below, which you can edit."
+msgstr ""
+
+#: includes/admin/forums.php:192
+msgid ""
+"<strong>Forum Editor</strong> - Enter the text for your forum. There are two "
+"modes of editing: Visual and HTML. Choose the mode by clicking on the "
+"appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon "
+"in the row to get a second row of controls. The HTML mode allows you to "
+"enter raw HTML along with your forum text. You can insert media files by "
+"clicking the icons above the forum editor and following the directions. You "
+"can go to the distraction-free writing screen via the Fullscreen icon in "
+"Visual mode (second to last in the top row) or the Fullscreen button in HTML "
+"mode (last in the row). Once there, you can make buttons visible by hovering "
+"over the top area. Exit Fullscreen back to the regular forum editor."
+msgstr ""
+
+#: includes/admin/forums.php:195
+msgid ""
+"<strong>Publish</strong> - You can set the terms of publishing your forum in "
+"the Publish box. For Status, Visibility, and Publish (immediately), click on "
+"the Edit link to reveal more options. Visibility includes options for "
+"password-protecting a forum or making it stay at the top of your blog "
+"indefinitely (sticky). Publish (immediately) allows you to set a future or "
+"past date and time, so you can schedule a forum to be published in the "
+"future or backdate a forum."
+msgstr ""
+
+#: includes/admin/forums.php:198
+msgid ""
+"<strong>Featured Image</strong> - This allows you to associate an image with "
+"your forum without inserting it. This is usually useful only if your theme "
+"makes use of the featured image as a forum thumbnail on the home page, a "
+"custom header, etc."
+msgstr ""
+
+#: includes/admin/forums.php:203 includes/admin/forums.php:243
+msgid "Forum Attributes"
+msgstr ""
+
+#: includes/admin/forums.php:205
+msgid "Select the attributes that your forum should have:"
+msgstr ""
+
+#: includes/admin/forums.php:207
+msgid ""
+"<strong>Type</strong> indicates if the forum is a category or forum. "
+"Categories generally contain other forums."
+msgstr ""
+
+#: includes/admin/forums.php:208
+msgid ""
+"<strong>Status</strong> allows you to close a forum to new topics and forums."
+msgstr ""
+
+#: includes/admin/forums.php:209
+msgid ""
+"<strong>Visibility</strong> lets you pick the scope of each forum and what "
+"users are allowed to access it."
+msgstr ""
+
+#: includes/admin/forums.php:210
+msgid ""
+"<strong>Parent</strong> dropdown determines the parent forum. Select the "
+"forum or category from the dropdown, or leave the default (No Parent) to "
+"create the forum at the root of your forums."
+msgstr ""
+
+#: includes/admin/forums.php:211
+msgid "<strong>Order</strong> allows you to order your forums numerically."
+msgstr ""
+
+#: includes/admin/forums.php:217 includes/admin/replies.php:229
+#: includes/admin/topics.php:229
+msgid "Publish Box"
+msgstr ""
+
+#: includes/admin/forums.php:409 includes/admin/metaboxes.php:50
+#: includes/admin/metaboxes.php:380 includes/admin/metaboxes.php:434
+#: includes/admin/replies.php:570 includes/admin/settings.php:293
+#: includes/admin/topics.php:633 includes/extend/buddypress/groups.php:52
+#: includes/extend/buddypress/groups.php:53 includes/forums/template.php:49
+#: templates/default/bbpress/loop-forums.php:19
+msgid "Forum"
+msgstr ""
+
+#: includes/admin/forums.php:410 includes/admin/settings.php:222
+#: includes/admin/settings.php:243 includes/admin/topics.php:632
+#: includes/extend/buddypress/activity.php:354
+#: includes/forums/template.php:2602 includes/topics/template.php:47
+#: includes/topics/template.php:48
+#: templates/default/bbpress/content-statistics.php:27
+#: templates/default/bbpress/loop-forums.php:20
+msgid "Topics"
+msgstr ""
+
+#: includes/admin/forums.php:411 includes/admin/settings.php:230
+#: includes/admin/settings.php:251 includes/admin/topics.php:634
+#: includes/core/theme-compat.php:646
+#: includes/extend/buddypress/activity.php:355
+#: includes/forums/template.php:2666 includes/replies/template.php:47
+#: includes/replies/template.php:48
+#: templates/default/bbpress/content-statistics.php:32
+#: templates/default/bbpress/loop-forums.php:21
+#: templates/default/bbpress/loop-replies.php:32
+#: templates/default/bbpress/loop-replies.php:70
+#: templates/default/bbpress/loop-topics.php:21
+msgid "Replies"
+msgstr ""
+
+#: includes/admin/forums.php:412
+#: templates/default/bbpress/content-single-topic-lead.php:18
+#: templates/default/bbpress/content-single-topic-lead.php:90
+msgid "Creator"
+msgstr ""
+
+#: includes/admin/forums.php:413 includes/admin/replies.php:573
+#: includes/admin/topics.php:637
+msgid "Created"
+msgstr ""
+
+#: includes/admin/forums.php:414 includes/admin/topics.php:638
+#: templates/default/bbpress/loop-forums.php:22
+#: templates/default/bbpress/loop-topics.php:22
+msgid "Freshness"
+msgstr ""
+
+#: includes/admin/forums.php:463 includes/forums/template.php:601
+msgid "No Topics"
+msgstr ""
+
+#: includes/admin/forums.php:529
+msgid "Forum updated. <a href=\"%s\">View forum</a>"
+msgstr ""
+
+#: includes/admin/forums.php:532 includes/admin/replies.php:853
+#: includes/admin/topics.php:923
+msgid "Custom field updated."
+msgstr ""
+
+#: includes/admin/forums.php:535 includes/admin/replies.php:856
+#: includes/admin/topics.php:926
+msgid "Custom field deleted."
+msgstr ""
+
+#: includes/admin/forums.php:538
+msgid "Forum updated."
+msgstr ""
+
+#. translators: %s: date and time of the revision
+#: includes/admin/forums.php:543
+msgid "Forum restored to revision from %s"
+msgstr ""
+
+#: includes/admin/forums.php:547
+msgid "Forum created. <a href=\"%s\">View forum</a>"
+msgstr ""
+
+#: includes/admin/forums.php:550
+msgid "Forum saved."
+msgstr ""
+
+#: includes/admin/forums.php:553
+msgid "Forum submitted. <a target=\"_blank\" href=\"%s\">Preview forum</a>"
+msgstr ""
+
+#: includes/admin/forums.php:556
+msgid ""
+"Forum scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s"
+"\">Preview forum</a>"
+msgstr ""
+
+#. translators: Publish box date format, see http:php.net/date
+#: includes/admin/forums.php:558 includes/admin/replies.php:879
+#: includes/admin/topics.php:949
+msgid "M j, Y @ G:i"
+msgstr ""
+
+#: includes/admin/forums.php:563
+msgid "Forum draft updated. <a target=\"_blank\" href=\"%s\">Preview forum</a>"
+msgstr ""
+
+#: includes/admin/metaboxes.php:42
+msgid "Discussion"
+msgstr ""
+
+#: includes/admin/metaboxes.php:67 includes/admin/metaboxes.php:458
+#: includes/admin/replies.php:571 includes/admin/settings.php:301
+#: includes/topics/template.php:49
+#: templates/default/bbpress/content-single-topic-lead.php:22
+#: templates/default/bbpress/content-single-topic-lead.php:94
+#: templates/default/bbpress/loop-topics.php:19
+msgid "Topic"
+msgid_plural "Topics"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/metaboxes.php:84 includes/admin/settings.php:325
+#: includes/replies/template.php:49 includes/replies/template.php:1619
+#: includes/topics/template.php:2923
+msgid "Reply"
+msgid_plural "Replies"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/metaboxes.php:103 includes/admin/settings.php:309
+#: includes/topics/template.php:3369
+msgid "Topic Tag"
+msgid_plural "Topic Tags"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/metaboxes.php:127
+msgid "Users &amp; Moderation"
+msgstr ""
+
+#: includes/admin/metaboxes.php:135
+msgid "User"
+msgid_plural "Users"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/metaboxes.php:154
+msgid "Hidden Topic"
+msgid_plural "Hidden Topics"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/metaboxes.php:176
+msgid "Hidden Reply"
+msgid_plural "Hidden Replies"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/metaboxes.php:198
+msgid "Empty Topic Tag"
+msgid_plural "Empty Topic Tags"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/admin/metaboxes.php:222
+msgid "You are using <span class=\"b\">bbPress %s</span>."
+msgstr ""
+
+#: includes/admin/metaboxes.php:261 includes/admin/metaboxes.php:262
+#: includes/admin/metaboxes.php:355
+msgid "Type:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:273 includes/admin/metaboxes.php:274
+#: includes/admin/metaboxes.php:367
+#: templates/default/bbpress/form-forum.php:100
+msgid "Status:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:285 includes/admin/metaboxes.php:286
+#: templates/default/bbpress/form-forum.php:109
+msgid "Visibility:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:299
+msgid "Parent:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:300
+msgid "Forum Parent"
+msgstr ""
+
+#: includes/admin/metaboxes.php:314 includes/admin/metaboxes.php:394
+#: includes/admin/metaboxes.php:448
+msgid "&mdash; No parent &mdash;"
+msgstr ""
+
+#: includes/admin/metaboxes.php:321
+msgid "Order:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:322
+msgid "Forum Order"
+msgstr ""
+
+#: includes/admin/metaboxes.php:356
+msgid "Topic Type"
+msgstr ""
+
+#: includes/admin/metaboxes.php:368
+msgid "Select whether to open or close the topic."
+msgstr ""
+
+#: includes/admin/metaboxes.php:379 includes/admin/metaboxes.php:433
+#: includes/extend/buddypress/groups.php:1038 includes/topics/template.php:61
+#: templates/default/bbpress/form-topic.php:114
+msgid "Forum:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:457 includes/replies/template.php:61
+msgid "Topic:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:463
+msgid "Reply To:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:464
+msgid "Reply To"
+msgstr ""
+
+#: includes/admin/metaboxes.php:496
+#: templates/default/bbpress/form-topic-tag.php:35
+msgid "Name:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:497
+#: templates/default/bbpress/form-user-edit.php:14
+#: templates/default/bbpress/form-user-edit.php:19
+msgid "Name"
+msgstr ""
+
+#: includes/admin/metaboxes.php:502
+msgid "Email:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:503
+#: templates/default/bbpress/form-user-edit.php:103
+#: templates/default/bbpress/form-user-register.php:28
+msgid "Email"
+msgstr ""
+
+#: includes/admin/metaboxes.php:508
+#: templates/default/bbpress/form-anonymous.php:32
+msgid "Website:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:509
+#: templates/default/bbpress/form-user-edit.php:57
+msgid "Website"
+msgstr ""
+
+#: includes/admin/metaboxes.php:516
+msgid "ID:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:517
+msgid "ID"
+msgstr ""
+
+#: includes/admin/metaboxes.php:524
+msgid "IP:"
+msgstr ""
+
+#: includes/admin/metaboxes.php:525
+msgid "IP Address"
+msgstr ""
+
+#: includes/admin/replies.php:134
+msgid ""
+"This screen provides access to all of your replies. You can customize the "
+"display of this screen to suit your workflow."
+msgstr ""
+
+#: includes/admin/replies.php:144
+msgid ""
+"You can hide/display columns based on your needs and decide how many replies "
+"to list per screen using the Screen Options tab."
+msgstr ""
+
+#: includes/admin/replies.php:145
+msgid ""
+"You can filter the list of replies by reply status using the text links in "
+"the upper left to show All, Published, Draft, or Trashed replies. The "
+"default view is to show all replies."
+msgstr ""
+
+#: includes/admin/replies.php:146
+msgid ""
+"You can view replies in a simple title list or with an excerpt. Choose the "
+"view you prefer by clicking on the icons at the top of the list on the right."
+msgstr ""
+
+#: includes/admin/replies.php:147
+msgid ""
+"You can refine the list to show only replies in a specific category or from "
+"a specific month by using the dropdown menus above the replies list. Click "
+"the Filter button after making your selection. You also can refine the list "
+"by clicking on the reply author, category or tag in the replies list."
+msgstr ""
+
+#: includes/admin/replies.php:156
+msgid ""
+"Hovering over a row in the replies list will display action links that allow "
+"you to manage your reply. You can perform the following actions:"
+msgstr ""
+
+#: includes/admin/replies.php:158
+msgid ""
+"<strong>Edit</strong> takes you to the editing screen for that reply. You "
+"can also reach that screen by clicking on the reply title."
+msgstr ""
+
+#: includes/admin/replies.php:160
+msgid ""
+"<strong>Trash</strong> removes your reply from this list and places it in "
+"the trash, from which you can permanently delete it."
+msgstr ""
+
+#: includes/admin/replies.php:161
+msgid ""
+"<strong>Spam</strong> removes your reply from this list and places it in the "
+"spam queue, from which you can permanently delete it."
+msgstr ""
+
+#: includes/admin/replies.php:162
+msgid ""
+"<strong>Preview</strong> will show you what your draft reply will look like "
+"if you publish it. View will take you to your live site to view the reply. "
+"Which link is available depends on your reply&#8217;s status."
+msgstr ""
+
+#: includes/admin/replies.php:171
+msgid ""
+"You can also edit or move multiple replies to the trash at once. Select the "
+"replies you want to act on using the checkboxes, then select the action you "
+"want to take from the Bulk Actions menu and click Apply."
+msgstr ""
+
+#: includes/admin/replies.php:172
+msgid ""
+"When using Bulk Edit, you can change the metadata (categories, author, etc.) "
+"for all selected replies at once. To remove a reply from the grouping, just "
+"click the x next to its name in the Bulk Edit area that appears."
+msgstr ""
+
+#: includes/admin/replies.php:193
+msgid ""
+"The title field and the big reply editing Area are fixed in place, but you "
+"can reposition all the other boxes using drag and drop, and can minimize or "
+"expand them by clicking the title bar of each box. Use the Screen Options "
+"tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, "
+"Discussion, Slug, Author) or to choose a 1- or 2-column layout for this "
+"screen."
+msgstr ""
+
+#: includes/admin/replies.php:203
+msgid "Title and Reply Editor"
+msgstr ""
+
+#: includes/admin/replies.php:205
+msgid ""
+"<strong>Title</strong> - Enter a title for your reply. After you enter a "
+"title, you&#8217;ll see the permalink below, which you can edit."
+msgstr ""
+
+#: includes/admin/replies.php:206
+msgid ""
+"<strong>Reply Editor</strong> - Enter the text for your reply. There are two "
+"modes of editing: Visual and HTML. Choose the mode by clicking on the "
+"appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon "
+"in the row to get a second row of controls. The HTML mode allows you to "
+"enter raw HTML along with your reply text. You can insert media files by "
+"clicking the icons above the reply editor and following the directions. You "
+"can go to the distraction-free writing screen via the Fullscreen icon in "
+"Visual mode (second to last in the top row) or the Fullscreen button in HTML "
+"mode (last in the row). Once there, you can make buttons visible by hovering "
+"over the top area. Exit Fullscreen back to the regular reply editor."
+msgstr ""
+
+#: includes/admin/replies.php:209
+msgid ""
+"<strong>Publish</strong> - You can set the terms of publishing your reply in "
+"the Publish box. For Status, Visibility, and Publish (immediately), click on "
+"the Edit link to reveal more options. Visibility includes options for "
+"password-protecting a reply or making it stay at the top of your blog "
+"indefinitely (sticky). Publish (immediately) allows you to set a future or "
+"past date and time, so you can schedule a reply to be published in the "
+"future or backdate a reply."
+msgstr ""
+
+#: includes/admin/replies.php:212
+msgid ""
+"<strong>Featured Image</strong> - This allows you to associate an image with "
+"your reply without inserting it. This is usually useful only if your theme "
+"makes use of the featured image as a reply thumbnail on the home page, a "
+"custom header, etc."
+msgstr ""
+
+#: includes/admin/replies.php:217 includes/admin/replies.php:255
+msgid "Reply Attributes"
+msgstr ""
+
+#: includes/admin/replies.php:219
+msgid "Select the attributes that your reply should have:"
+msgstr ""
+
+#: includes/admin/replies.php:221
+msgid ""
+"<strong>Forum</strong> dropdown determines the parent forum that the reply "
+"belongs to. Select the forum, or leave the default (Use Forum of Topic) to "
+"post the reply in forum of the topic."
+msgstr ""
+
+#: includes/admin/replies.php:222
+msgid ""
+"<strong>Topic</strong> determines the parent topic that the reply belongs to."
+msgstr ""
+
+#: includes/admin/replies.php:223
+msgid "<strong>Reply To</strong> determines the threading of the reply."
+msgstr ""
+
+#: includes/admin/replies.php:347 includes/admin/topics.php:363
+#: templates/default/bbpress/form-anonymous.php:17
+msgid "Author Information"
+msgstr ""
+
+#: includes/admin/replies.php:461
+msgid "The reply was not found!"
+msgstr ""
+
+#: includes/admin/replies.php:464 includes/admin/topics.php:488
+msgid "You do not have the permission to do that!"
+msgstr ""
+
+#: includes/admin/replies.php:532
+msgid "There was a problem marking the reply \"%1$s\" as spam."
+msgstr ""
+
+#: includes/admin/replies.php:532
+msgid "Reply \"%1$s\" successfully marked as spam."
+msgstr ""
+
+#: includes/admin/replies.php:536
+msgid "There was a problem unmarking the reply \"%1$s\" as spam."
+msgstr ""
+
+#: includes/admin/replies.php:536
+msgid "Reply \"%1$s\" successfully unmarked as spam."
+msgstr ""
+
+#: includes/admin/replies.php:569
+msgid "Title"
+msgstr ""
+
+#: includes/admin/replies.php:572 includes/admin/topics.php:636
+#: templates/default/bbpress/loop-replies.php:18
+#: templates/default/bbpress/loop-replies.php:60
+#: templates/default/bbpress/loop-search.php:18
+#: templates/default/bbpress/loop-search.php:40
+msgid "Author"
+msgstr ""
+
+#: includes/admin/replies.php:626 includes/admin/replies.php:634
+msgid "No Topic"
+msgstr ""
+
+#: includes/admin/replies.php:652 includes/admin/replies.php:667
+#: includes/admin/topics.php:688
+msgid "No Forum"
+msgstr ""
+
+#: includes/admin/replies.php:658
+msgid "(Mismatch)"
+msgstr ""
+
+#: includes/admin/replies.php:726 includes/admin/topics.php:777
+msgid "View &#8220;%s&#8221;"
+msgstr ""
+
+#: includes/admin/replies.php:726 includes/admin/topics.php:777
+msgid "View"
+msgstr ""
+
+#: includes/admin/replies.php:737
+msgid "Mark the reply as not spam"
+msgstr ""
+
+#: includes/admin/replies.php:737 includes/admin/topics.php:808
+msgid "Not spam"
+msgstr ""
+
+#: includes/admin/replies.php:739
+msgid "Mark this reply as spam"
+msgstr ""
+
+#: includes/admin/replies.php:739 includes/admin/topics.php:810
+#: includes/replies/template.php:2103 includes/topics/template.php:2874
+msgid "Spam"
+msgstr ""
+
+#: includes/admin/replies.php:748 includes/admin/topics.php:818
+#: includes/replies/template.php:2045 includes/topics/template.php:2630
+msgid "Restore this item from the Trash"
+msgstr ""
+
+#: includes/admin/replies.php:748 includes/admin/topics.php:818
+#: includes/replies/template.php:2033 includes/topics/template.php:2618
+msgid "Restore"
+msgstr ""
+
+#: includes/admin/replies.php:750 includes/admin/topics.php:820
+#: includes/replies/template.php:2047 includes/topics/template.php:2632
+msgid "Move this item to the Trash"
+msgstr ""
+
+#: includes/admin/replies.php:750 includes/admin/topics.php:820
+#: includes/replies/template.php:2032 includes/topics/template.php:2617
+msgid "Trash"
+msgstr ""
+
+#: includes/admin/replies.php:754 includes/admin/topics.php:824
+#: includes/replies/template.php:2051 includes/topics/template.php:2636
+msgid "Delete this item permanently"
+msgstr ""
+
+#: includes/admin/replies.php:754 includes/admin/topics.php:824
+msgid "Delete Permanently"
+msgstr ""
+
+#: includes/admin/replies.php:780 includes/admin/topics.php:850
+msgid "Empty Spam"
+msgstr ""
+
+#: includes/admin/replies.php:790 includes/admin/topics.php:860
+msgid "In all forums"
+msgstr ""
+
+#: includes/admin/replies.php:850
+msgid "Reply updated. <a href=\"%s\">View topic</a>"
+msgstr ""
+
+#: includes/admin/replies.php:859
+msgid "Reply updated."
+msgstr ""
+
+#. translators: %s: date and time of the revision
+#: includes/admin/replies.php:864
+msgid "Reply restored to revision from %s"
+msgstr ""
+
+#: includes/admin/replies.php:868
+msgid "Reply created. <a href=\"%s\">View topic</a>"
+msgstr ""
+
+#: includes/admin/replies.php:871
+msgid "Reply saved."
+msgstr ""
+
+#: includes/admin/replies.php:874
+msgid "Reply submitted. <a target=\"_blank\" href=\"%s\">Preview topic</a>"
+msgstr ""
+
+#: includes/admin/replies.php:877
+msgid ""
+"Reply scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s"
+"\">Preview topic</a>"
+msgstr ""
+
+#: includes/admin/replies.php:884
+msgid "Reply draft updated. <a target=\"_blank\" href=\"%s\">Preview topic</a>"
+msgstr ""
+
+#: includes/admin/settings.php:24
+msgid "Forum User Settings"
+msgstr ""
+
+#: includes/admin/settings.php:29
+msgid "Forum Features"
+msgstr ""
+
+#: includes/admin/settings.php:34
+msgid "Forum Theme Packages"
+msgstr ""
+
+#: includes/admin/settings.php:39
+msgid "Topics and Replies Per Page"
+msgstr ""
+
+#: includes/admin/settings.php:44
+msgid "Topics and Replies Per RSS Page"
+msgstr ""
+
+#: includes/admin/settings.php:49
+msgid "Forum Root Slug"
+msgstr ""
+
+#: includes/admin/settings.php:54
+msgid "Single Forum Slugs"
+msgstr ""
+
+#: includes/admin/settings.php:59
+msgid "Forum User Slugs"
+msgstr ""
+
+#: includes/admin/settings.php:64
+msgid "BuddyPress Integration"
+msgstr ""
+
+#: includes/admin/settings.php:69
+msgid "Akismet Integration"
+msgstr ""
+
+#: includes/admin/settings.php:91
+msgid "Disallow editing after"
+msgstr ""
+
+#: includes/admin/settings.php:99
+msgid "Throttle posting every"
+msgstr ""
+
+#: includes/admin/settings.php:107
+msgid "Anonymous posting"
+msgstr ""
+
+#: includes/admin/settings.php:115
+msgid "Auto role"
+msgstr ""
+
+#: includes/admin/settings.php:134 includes/admin/settings.php:1690
+msgid "Revisions"
+msgstr ""
+
+#: includes/admin/settings.php:142 includes/extend/buddypress/loader.php:218
+#: templates/default/bbpress/user-details.php:48
+msgid "Favorites"
+msgstr ""
+
+#: includes/admin/settings.php:150 includes/extend/buddypress/loader.php:230
+#: templates/default/bbpress/user-details.php:58
+msgid "Subscriptions"
+msgstr ""
+
+#: includes/admin/settings.php:158
+msgid "Topic tags"
+msgstr ""
+
+#: includes/admin/settings.php:166 includes/admin/settings.php:333
+#: includes/common/template.php:2314 includes/search/template.php:225
+#: templates/default/bbpress/form-search.php:17
+msgid "Search"
+msgstr ""
+
+#: includes/admin/settings.php:174
+msgid "Post Formatting"
+msgstr ""
+
+#: includes/admin/settings.php:182
+msgid "Auto-embed links"
+msgstr ""
+
+#: includes/admin/settings.php:190
+msgid "Reply Threading"
+msgstr ""
+
+#: includes/admin/settings.php:209
+msgid "Current Package"
+msgstr ""
+
+#: includes/admin/settings.php:264
+msgid "Forum Root"
+msgstr ""
+
+#: includes/admin/settings.php:272
+msgid "Forum Prefix"
+msgstr ""
+
+#: includes/admin/settings.php:280
+msgid "Forum root should show"
+msgstr ""
+
+#: includes/admin/settings.php:317
+msgid "Topic View"
+msgstr ""
+
+#: includes/admin/settings.php:346
+msgid "User Base"
+msgstr ""
+
+#: includes/admin/settings.php:354 includes/extend/buddypress/loader.php:196
+#: includes/extend/buddypress/loader.php:269
+#: templates/default/bbpress/user-details.php:35
+msgid "Topics Started"
+msgstr ""
+
+#: includes/admin/settings.php:362 includes/extend/buddypress/loader.php:207
+#: includes/extend/buddypress/loader.php:277
+#: templates/default/bbpress/user-details.php:41
+msgid "Replies Created"
+msgstr ""
+
+#: includes/admin/settings.php:370 includes/extend/buddypress/loader.php:285
+msgid "Favorite Topics"
+msgstr ""
+
+#: includes/admin/settings.php:378
+msgid "Topic Subscriptions"
+msgstr ""
+
+#: includes/admin/settings.php:391
+msgid "Enable Group Forums"
+msgstr ""
+
+#: includes/admin/settings.php:399
+msgid "Group Forums Parent"
+msgstr ""
+
+#: includes/admin/settings.php:412
+msgid "Use Akismet"
+msgstr ""
+
+#: includes/admin/settings.php:450
+msgid "Setting time limits and other user posting capabilities"
+msgstr ""
+
+#: includes/admin/settings.php:467 includes/common/functions.php:123
+msgid "minutes"
+msgstr ""
+
+#: includes/admin/settings.php:483 includes/common/functions.php:124
+msgid "seconds"
+msgstr ""
+
+#: includes/admin/settings.php:499
+msgid "Allow guest users without accounts to create topics and replies"
+msgstr ""
+
+#: includes/admin/settings.php:533
+msgid "Automatically give registered visitors the %s forum role"
+msgstr ""
+
+#: includes/admin/settings.php:549
+msgid "Forum features that can be toggled on and off"
+msgstr ""
+
+#: includes/admin/settings.php:565
+msgid "Allow users to mark topics as favorites"
+msgstr ""
+
+#: includes/admin/settings.php:581
+msgid "Allow users to subscribe to forums and topics"
+msgstr ""
+
+#: includes/admin/settings.php:597
+msgid "Allow topics to have tags"
+msgstr ""
+
+#: includes/admin/settings.php:613
+msgid "Allow forum wide search"
+msgstr ""
+
+#: includes/admin/settings.php:652
+msgid "Enable threaded (nested) replies %s levels deep"
+msgstr ""
+
+#: includes/admin/settings.php:669
+msgid "Allow topic and reply revision logging"
+msgstr ""
+
+#: includes/admin/settings.php:685
+msgid "Add toolbar & buttons to textareas to help with HTML formatting"
+msgstr ""
+
+#: includes/admin/settings.php:698
+msgid "How your forum content is displayed within your existing theme."
+msgstr ""
+
+#: includes/admin/settings.php:722
+msgid "%1$s - %2$s"
+msgstr ""
+
+#: includes/admin/settings.php:728
+msgid "will serve all bbPress templates"
+msgstr ""
+
+#: includes/admin/settings.php:732
+msgid "No template packages available."
+msgstr ""
+
+#: includes/admin/settings.php:748
+msgid ""
+"Embed media (YouTube, Twitter, Flickr, etc...) directly into topics and "
+"replies"
+msgstr ""
+
+#: includes/admin/settings.php:763
+msgid "How many topics and replies to show per page"
+msgstr ""
+
+#: includes/admin/settings.php:779 includes/admin/settings.php:795
+#: includes/admin/settings.php:826 includes/admin/settings.php:842
+msgid "per page"
+msgstr ""
+
+#: includes/admin/settings.php:810
+msgid "How many topics and replies to show per RSS page"
+msgstr ""
+
+#: includes/admin/settings.php:860
+msgid ""
+"Customize your Forums root. Partner with a WordPress Page and use Shortcodes "
+"for more flexibility."
+msgstr ""
+
+#: includes/admin/settings.php:893
+msgid "Prefix all forum content with the Forum Root slug (Recommended)"
+msgstr ""
+
+#: includes/admin/settings.php:913
+msgid "Forum Index"
+msgstr ""
+
+#: includes/admin/settings.php:916
+msgid "Topics by Freshness"
+msgstr ""
+
+#: includes/admin/settings.php:943
+msgid "Customize your user profile slugs."
+msgstr ""
+
+#: includes/admin/settings.php:1043
+msgid ""
+"Custom slugs for single forums, topics, replies, tags, views, and search."
+msgstr ""
+
+#: includes/admin/settings.php:1161
+msgid "Forum settings for BuddyPress"
+msgstr ""
+
+#: includes/admin/settings.php:1177
+msgid "Allow BuddyPress Groups to have their own forums"
+msgstr ""
+
+#: includes/admin/settings.php:1194
+msgid "&mdash; Forum root &mdash;"
+msgstr ""
+
+#: includes/admin/settings.php:1202
+msgid "is the parent for all group forums"
+msgstr ""
+
+#: includes/admin/settings.php:1203
+msgid ""
+"Using the Forum Root is not recommended. Changing this does not move "
+"existing forums."
+msgstr ""
+
+#: includes/admin/settings.php:1218
+msgid "Forum settings for Akismet"
+msgstr ""
+
+#: includes/admin/settings.php:1235
+msgid "Allow Akismet to actively prevent forum spam."
+msgstr ""
+
+#: includes/admin/settings.php:1258
+msgid "Forums Settings"
+msgstr ""
+
+#: includes/admin/settings.php:1267
+#: templates/default/bbpress/form-user-edit.php:173
+msgid "Save Changes"
+msgstr ""
+
+#: includes/admin/settings.php:1286
+msgid ""
+"Information about your previous forums database so that they can be "
+"converted. <strong>Backup your database before proceeding.</strong>"
+msgstr ""
+
+#: includes/admin/settings.php:1316
+msgid "is the previous forum software"
+msgstr ""
+
+#: includes/admin/settings.php:1330
+msgid "IP or hostname"
+msgstr ""
+
+#: includes/admin/settings.php:1344
+msgid "Use default 3306 if unsure"
+msgstr ""
+
+#: includes/admin/settings.php:1358
+msgid "User for your database connection"
+msgstr ""
+
+#: includes/admin/settings.php:1372
+msgid "Password to access the database"
+msgstr ""
+
+#: includes/admin/settings.php:1386
+msgid "Name of the database with your old forum data"
+msgstr ""
+
+#: includes/admin/settings.php:1399
+msgid "Some optional parameters to help tune the conversion process."
+msgstr ""
+
+#: includes/admin/settings.php:1413
+msgid ""
+"(If converting from BuddyPress Forums, use \"wp_bb_\" or your custom prefix)"
+msgstr ""
+
+#: includes/admin/settings.php:1427
+msgid "rows to process at a time"
+msgstr ""
+
+#: includes/admin/settings.php:1428
+msgid "Keep this low if you experience out-of-memory issues."
+msgstr ""
+
+#: includes/admin/settings.php:1442
+msgid "second(s) delay between each group of rows"
+msgstr ""
+
+#: includes/admin/settings.php:1443
+msgid "Keep this high to prevent too-many-connection issues."
+msgstr ""
+
+#: includes/admin/settings.php:1457
+msgid "Start a fresh conversion from the beginning"
+msgstr ""
+
+#: includes/admin/settings.php:1458
+msgid "You should clean old conversion information before starting over."
+msgstr ""
+
+#: includes/admin/settings.php:1472
+msgid "Purge all information from a previously attempted import"
+msgstr ""
+
+#: includes/admin/settings.php:1473
+msgid ""
+"Use this if an import failed and you want to remove that incomplete data."
+msgstr ""
+
+#: includes/admin/settings.php:1487
+msgid "Attempt to import user accounts from previous forums"
+msgstr ""
+
+#: includes/admin/settings.php:1488
+msgid ""
+"Non-bbPress passwords cannot be automatically converted. They will be "
+"converted as each user logs in."
+msgstr ""
+
+#: includes/admin/settings.php:1518
+msgid "Start"
+msgstr ""
+
+#: includes/admin/settings.php:1519
+msgid "Stop"
+msgstr ""
+
+#: includes/admin/settings.php:1550
+msgid "This screen provides access to all of the Forums settings."
+msgstr ""
+
+#: includes/admin/settings.php:1551
+msgid ""
+"Please see the additional help tabs for more information on each indiviual "
+"section."
+msgstr ""
+
+#: includes/admin/settings.php:1557
+msgid "Main Settings"
+msgstr ""
+
+#: includes/admin/settings.php:1558
+msgid "In the Main Settings you have a number of options:"
+msgstr ""
+
+#: includes/admin/settings.php:1561
+msgid ""
+"You can choose to lock a post after a certain number of minutes. \"Locking "
+"post editing\" will prevent the author from editing some amount of time "
+"after saving a post."
+msgstr ""
+
+#: includes/admin/settings.php:1562
+msgid ""
+"\"Throttle time\" is the amount of time required between posts from a single "
+"author. The higher the throttle time, the longer a user will need to wait "
+"between posting to the forum."
+msgstr ""
+
+#: includes/admin/settings.php:1563
+msgid ""
+"Favorites are a way for users to save and later return to topics they favor. "
+"This is enabled by default."
+msgstr ""
+
+#: includes/admin/settings.php:1564
+msgid ""
+"Subscriptions allow users to subscribe for notifications to topics that "
+"interest them. This is enabled by default."
+msgstr ""
+
+#: includes/admin/settings.php:1565
+msgid ""
+"Topic-Tags allow users to filter topics between forums. This is enabled by "
+"default."
+msgstr ""
+
+#: includes/admin/settings.php:1566
+msgid ""
+"\"Anonymous Posting\" allows guest users who do not have accounts on your "
+"site to both create topics as well as replies."
+msgstr ""
+
+#: includes/admin/settings.php:1567
+msgid ""
+"The Fancy Editor brings the luxury of the Visual editor and HTML editor from "
+"the traditional WordPress dashboard into your theme."
+msgstr ""
+
+#: includes/admin/settings.php:1568
+msgid ""
+"Auto-embed will embed the media content from a URL directly into the "
+"replies. For example: links to Flickr and YouTube."
+msgstr ""
+
+#: includes/admin/settings.php:1571
+msgid ""
+"You must click the Save Changes button at the bottom of the screen for new "
+"settings to take effect."
+msgstr ""
+
+#: includes/admin/settings.php:1577
+msgid "Per Page"
+msgstr ""
+
+#: includes/admin/settings.php:1578
+msgid ""
+"Per Page settings allow you to control the number of topics and replies "
+"appear on each page."
+msgstr ""
+
+#: includes/admin/settings.php:1579
+msgid ""
+"This is comparable to the WordPress \"Reading Settings\" page, where you can "
+"set the number of posts that should show on blog pages and in feeds."
+msgstr ""
+
+#: includes/admin/settings.php:1580
+msgid ""
+"These are broken up into two separate groups: one for what appears in your "
+"theme, another for RSS feeds."
+msgstr ""
+
+#: includes/admin/settings.php:1586
+msgid "Slugs"
+msgstr ""
+
+#: includes/admin/settings.php:1587
+msgid ""
+"The Slugs section allows you to control the permalink structure for your "
+"forums."
+msgstr ""
+
+#: includes/admin/settings.php:1588
+msgid ""
+"\"Archive Slugs\" are used as the \"root\" for your forums and topics. If "
+"you combine these values with existing page slugs, bbPress will attempt to "
+"output the most correct title and content."
+msgstr ""
+
+#: includes/admin/settings.php:1589
+msgid ""
+"\"Single Slugs\" are used as a prefix when viewing an individual forum, "
+"topic, reply, user, or view."
+msgstr ""
+
+#: includes/admin/settings.php:1590
+msgid ""
+"In the event of a slug collision with WordPress or BuddyPress, a warning "
+"will appear next to the problem slug(s)."
+msgstr ""
+
+#: includes/admin/settings.php:1688
+#: templates/default/bbpress/loop-forums.php:21
+#: templates/default/bbpress/loop-replies.php:24
+#: templates/default/bbpress/loop-replies.php:66
+#: templates/default/bbpress/loop-topics.php:21
+msgid "Posts"
+msgstr ""
+
+#: includes/admin/settings.php:1689
+msgid "Pages"
+msgstr ""
+
+#: includes/admin/settings.php:1691
+msgid "Attachments"
+msgstr ""
+
+#: includes/admin/settings.php:1692
+msgid "Menus"
+msgstr ""
+
+#: includes/admin/settings.php:1695
+msgid "Tag base"
+msgstr ""
+
+#: includes/admin/settings.php:1698
+msgid "Category base"
+msgstr ""
+
+#: includes/admin/settings.php:1703
+msgid "Forums base"
+msgstr ""
+
+#: includes/admin/settings.php:1706
+msgid "Topics base"
+msgstr ""
+
+#: includes/admin/settings.php:1709
+msgid "Forum slug"
+msgstr ""
+
+#: includes/admin/settings.php:1712
+msgid "Topic slug"
+msgstr ""
+
+#: includes/admin/settings.php:1715
+msgid "Reply slug"
+msgstr ""
+
+#: includes/admin/settings.php:1718
+msgid "User base"
+msgstr ""
+
+#: includes/admin/settings.php:1721
+msgid "View base"
+msgstr ""
+
+#: includes/admin/settings.php:1724
+msgid "Topic tag slug"
+msgstr ""
+
+#: includes/admin/settings.php:1736
+msgid "%s page"
+msgstr ""
+
+#: includes/admin/settings.php:1755
+msgid "Possible %1$s conflict: %2$s"
+msgstr ""
+
+#: includes/admin/tools.php:36
+msgid ""
+"bbPress keeps track of relationships between forums, topics, replies, and "
+"topic tags, and users. Occasionally these relationships become out of sync, "
+"most often after an import or migration. Use the tools below to manually "
+"recalculate these relationships."
+msgstr ""
+
+#: includes/admin/tools.php:37
+msgid ""
+"Some of these tools create substantial database overhead. Avoid running more "
+"than 1 repair job at a time."
+msgstr ""
+
+#: includes/admin/tools.php:43
+msgid "Relationships to Repair:"
+msgstr ""
+
+#: includes/admin/tools.php:46
+msgid "Repair"
+msgstr ""
+
+#: includes/admin/tools.php:61
+msgid "Repair Items"
+msgstr ""
+
+#: includes/admin/tools.php:161
+msgid "Recalculate the parent topic for each post"
+msgstr ""
+
+#: includes/admin/tools.php:162
+msgid "Recalculate the parent forum for each post"
+msgstr ""
+
+#: includes/admin/tools.php:163
+msgid "Recalculate private and hidden forums"
+msgstr ""
+
+#: includes/admin/tools.php:164
+msgid "Recalculate last activity in each topic and forum"
+msgstr ""
+
+#: includes/admin/tools.php:165
+msgid "Recalculate the sticky relationship of each topic"
+msgstr ""
+
+#: includes/admin/tools.php:166
+msgid "Repair BuddyPress Group Forum relationships"
+msgstr ""
+
+#: includes/admin/tools.php:167
+msgid "Count topics in each forum"
+msgstr ""
+
+#: includes/admin/tools.php:168
+msgid "Count replies in each forum"
+msgstr ""
+
+#: includes/admin/tools.php:169
+msgid "Count replies in each topic"
+msgstr ""
+
+#: includes/admin/tools.php:170
+msgid "Count voices in each topic"
+msgstr ""
+
+#: includes/admin/tools.php:171
+msgid "Count spammed & trashed replies in each topic"
+msgstr ""
+
+#: includes/admin/tools.php:172
+msgid "Count topics for each user"
+msgstr ""
+
+#: includes/admin/tools.php:173
+msgid "Count replies for each user"
+msgstr ""
+
+#: includes/admin/tools.php:174
+msgid "Remove trashed topics from user favorites"
+msgstr ""
+
+#: includes/admin/tools.php:175
+msgid "Remove trashed topics from user subscriptions"
+msgstr ""
+
+#: includes/admin/tools.php:176
+msgid "Remove trashed forums from user subscriptions"
+msgstr ""
+
+#: includes/admin/tools.php:177
+msgid "Remap existing users to default forum roles"
+msgstr ""
+
+#: includes/admin/tools.php:197
+msgid "Counting the number of replies in each topic&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:198 includes/admin/tools.php:241
+#: includes/admin/tools.php:283 includes/admin/tools.php:328
+#: includes/admin/tools.php:445 includes/admin/tools.php:479
+#: includes/admin/tools.php:511 includes/admin/tools.php:556
+#: includes/admin/tools.php:601 includes/admin/tools.php:663
+#: includes/admin/tools.php:724 includes/admin/tools.php:792
+#: includes/admin/tools.php:840 includes/admin/tools.php:946
+#: includes/admin/tools.php:1006 includes/admin/tools.php:1027
+#: includes/admin/tools.php:1081
+msgid "Failed!"
+msgstr ""
+
+#: includes/admin/tools.php:224 includes/admin/tools.php:267
+#: includes/admin/tools.php:293 includes/admin/tools.php:460
+#: includes/admin/tools.php:494 includes/admin/tools.php:539
+#: includes/admin/tools.php:584 includes/admin/tools.php:646
+#: includes/admin/tools.php:707 includes/admin/tools.php:768
+#: includes/admin/tools.php:930 includes/admin/tools.php:987
+#: includes/admin/tools.php:1010 includes/admin/tools.php:1065
+#: includes/admin/tools.php:1110
+msgid "Complete!"
+msgstr ""
+
+#: includes/admin/tools.php:240
+msgid "Counting the number of voices in each topic&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:282
+msgid ""
+"Counting the number of spammed and trashed replies in each topic&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:307
+msgid "Repairing BuddyPress group-forum relationships&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:408
+msgid "Group Forums"
+msgstr ""
+
+#: includes/admin/tools.php:409
+msgid "group-forums"
+msgstr ""
+
+#: includes/admin/tools.php:425
+msgid ""
+"Complete! %s groups updated; %s forums updated; %s forum statuses synced."
+msgstr ""
+
+#: includes/admin/tools.php:444
+msgid "Counting the number of topics in each forum&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:478
+msgid "Counting the number of replies in each forum&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:510
+msgid "Counting the number of topics each user has created&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:555
+msgid "Counting the number of topics to which each user has replied&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:600
+msgid "Removing trashed topics from user favorites&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:630 includes/admin/tools.php:691
+#: includes/admin/tools.php:752
+msgid "Nothing to remove!"
+msgstr ""
+
+#: includes/admin/tools.php:662
+msgid "Removing trashed topics from user subscriptions&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:723
+msgid "Removing trashed forums from user subscriptions&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:785
+msgid "Remapping forum role for each user on this site&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:823
+msgid "Complete! %s users updated."
+msgstr ""
+
+#: includes/admin/tools.php:839
+msgid "Recomputing latest post in every topic and forum&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:945
+msgid "Repairing the sticky topic to the parent forum relationships&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1002
+msgid "Recalculating forum visibility &hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1026
+msgid "Recalculating the forum for each post &hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1080
+msgid "Recalculating the topic for each post &hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1133
+msgid ""
+"Revert your forums back to a brand new installation. This process cannot be "
+"undone."
+msgstr ""
+
+#: includes/admin/tools.php:1134
+msgid "Backup your database before proceeding."
+msgstr ""
+
+#: includes/admin/tools.php:1140
+msgid "The following data will be removed:"
+msgstr ""
+
+#: includes/admin/tools.php:1142 includes/forums/template.php:50
+msgid "All Forums"
+msgstr ""
+
+#: includes/admin/tools.php:1143 includes/topics/functions.php:3440
+#: includes/topics/template.php:50
+msgid "All Topics"
+msgstr ""
+
+#: includes/admin/tools.php:1144 includes/replies/functions.php:1994
+#: includes/replies/template.php:50
+msgid "All Replies"
+msgstr ""
+
+#: includes/admin/tools.php:1145
+msgid "All Topic Tags"
+msgstr ""
+
+#: includes/admin/tools.php:1146
+msgid "Related Meta Data"
+msgstr ""
+
+#: includes/admin/tools.php:1147
+msgid "Forum Settings"
+msgstr ""
+
+#: includes/admin/tools.php:1148
+msgid "Forum Activity"
+msgstr ""
+
+#: includes/admin/tools.php:1149
+msgid "Forum User Roles"
+msgstr ""
+
+#: includes/admin/tools.php:1150
+msgid "Importer Helper Data"
+msgstr ""
+
+#: includes/admin/tools.php:1154
+msgid "Delete imported users?"
+msgstr ""
+
+#: includes/admin/tools.php:1157 includes/admin/tools.php:1167
+msgid "Say it ain't so!"
+msgstr ""
+
+#: includes/admin/tools.php:1158
+msgid ""
+"This option will delete all previously imported users, and cannot be undone."
+msgstr ""
+
+#: includes/admin/tools.php:1159
+msgid ""
+"Note: Resetting without this checked will delete the meta-data necessary to "
+"delete these users."
+msgstr ""
+
+#: includes/admin/tools.php:1164
+msgid "Are you sure you want to do this?"
+msgstr ""
+
+#: includes/admin/tools.php:1168
+msgid "This process cannot be undone."
+msgstr ""
+
+#: includes/admin/tools.php:1169
+msgid "Human sacrifice, dogs and cats living together... mass hysteria!"
+msgstr ""
+
+#: includes/admin/tools.php:1177
+msgid "Reset bbPress"
+msgstr ""
+
+#: includes/admin/tools.php:1210
+msgid "Failed"
+msgstr ""
+
+#: includes/admin/tools.php:1211
+msgid "Success!"
+msgstr ""
+
+#: includes/admin/tools.php:1218
+msgid "Deleting Posts&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1231
+msgid "Deleting Post Meta&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1240
+msgid "Deleting Topic Tags&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1255
+msgid "Deleting User&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1260 includes/admin/tools.php:1268
+msgid "Deleting User Meta&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1276
+msgid "Deleting Conversion Table&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1288
+msgid "Deleting Settings&hellip; %s"
+msgstr ""
+
+#: includes/admin/tools.php:1294
+msgid "Deleting Roles and Capabilities&hellip; %s"
+msgstr ""
+
+#: includes/admin/topics.php:134
+msgid ""
+"This screen displays the individual topics on your site. You can customize "
+"the display of this screen to suit your workflow."
+msgstr ""
+
+#: includes/admin/topics.php:144
+msgid ""
+"You can hide/display columns based on your needs and decide how many topics "
+"to list per screen using the Screen Options tab."
+msgstr ""
+
+#: includes/admin/topics.php:145
+msgid ""
+"You can filter the list of topics by topic status using the text links in "
+"the upper left to show All, Published, or Trashed topics. The default view "
+"is to show all topics."
+msgstr ""
+
+#: includes/admin/topics.php:146
+msgid ""
+"You can refine the list to show only topics from a specific month by using "
+"the dropdown menus above the topics list. Click the Filter button after "
+"making your selection. You also can refine the list by clicking on the topic "
+"creator in the topics list."
+msgstr ""
+
+#: includes/admin/topics.php:155
+msgid ""
+"Hovering over a row in the topics list will display action links that allow "
+"you to manage your topic. You can perform the following actions:"
+msgstr ""
+
+#: includes/admin/topics.php:157
+msgid ""
+"<strong>Edit</strong> takes you to the editing screen for that topic. You "
+"can also reach that screen by clicking on the topic title."
+msgstr ""
+
+#: includes/admin/topics.php:158
+msgid ""
+"<strong>Trash</strong> removes your topic from this list and places it in "
+"the trash, from which you can permanently delete it."
+msgstr ""
+
+#: includes/admin/topics.php:159
+msgid ""
+"<strong>Spam</strong> removes your topic from this list and places it in the "
+"spam queue, from which you can permanently delete it."
+msgstr ""
+
+#: includes/admin/topics.php:160
+msgid ""
+"<strong>Preview</strong> will show you what your draft topic will look like "
+"if you publish it. View will take you to your live site to view the topic. "
+"Which link is available depends on your topic&#8217;s status."
+msgstr ""
+
+#: includes/admin/topics.php:161
+msgid ""
+"<strong>Close</strong> will mark the selected topic as &#8217;closed&#8217; "
+"and disable the option to post new replies to the topic."
+msgstr ""
+
+#: includes/admin/topics.php:162
+msgid ""
+"<strong>Stick</strong> will keep the selected topic &#8217;pinned&#8217; to "
+"the top the parent forum topic list."
+msgstr ""
+
+#: includes/admin/topics.php:163
+msgid ""
+"<strong>Stick <em>(to front)</em></strong> will keep the selected topic "
+"&#8217;pinned&#8217; to the top of ALL forums and be visable in any forums "
+"topics list."
+msgstr ""
+
+#: includes/admin/topics.php:172
+msgid ""
+"You can also edit or move multiple topics to the trash at once. Select the "
+"topics you want to act on using the checkboxes, then select the action you "
+"want to take from the Bulk Actions menu and click Apply."
+msgstr ""
+
+#: includes/admin/topics.php:173
+msgid ""
+"When using Bulk Edit, you can change the metadata (categories, author, etc.) "
+"for all selected topics at once. To remove a topic from the grouping, just "
+"click the x next to its name in the Bulk Edit area that appears."
+msgstr ""
+
+#: includes/admin/topics.php:194
+msgid ""
+"The title field and the big topic editing Area are fixed in place, but you "
+"can reposition all the other boxes using drag and drop, and can minimize or "
+"expand them by clicking the title bar of each box. Use the Screen Options "
+"tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, "
+"Discussion, Slug, Author) or to choose a 1- or 2-column layout for this "
+"screen."
+msgstr ""
+
+#: includes/admin/topics.php:204
+msgid "Title and Topic Editor"
+msgstr ""
+
+#: includes/admin/topics.php:206
+msgid ""
+"<strong>Title</strong> - Enter a title for your topic. After you enter a "
+"title, you&#8217;ll see the permalink below, which you can edit."
+msgstr ""
+
+#: includes/admin/topics.php:207
+msgid ""
+"<strong>Topic Editor</strong> - Enter the text for your topic. There are two "
+"modes of editing: Visual and HTML. Choose the mode by clicking on the "
+"appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon "
+"in the row to get a second row of controls. The HTML mode allows you to "
+"enter raw HTML along with your topic text. You can insert media files by "
+"clicking the icons above the topic editor and following the directions. You "
+"can go to the distraction-free writing screen via the Fullscreen icon in "
+"Visual mode (second to last in the top row) or the Fullscreen button in HTML "
+"mode (last in the row). Once there, you can make buttons visible by hovering "
+"over the top area. Exit Fullscreen back to the regular topic editor."
+msgstr ""
+
+#: includes/admin/topics.php:210
+msgid ""
+"<strong>Publish</strong> - You can set the terms of publishing your topic in "
+"the Publish box. For Status, Visibility, and Publish (immediately), click on "
+"the Edit link to reveal more options. Visibility includes options for "
+"password-protecting a topic or making it stay at the top of your blog "
+"indefinitely (sticky). Publish (immediately) allows you to set a future or "
+"past date and time, so you can schedule a topic to be published in the "
+"future or backdate a topic."
+msgstr ""
+
+#: includes/admin/topics.php:213
+msgid ""
+"<strong>Featured Image</strong> - This allows you to associate an image with "
+"your topic without inserting it. This is usually useful only if your theme "
+"makes use of the featured image as a topic thumbnail on the home page, a "
+"custom header, etc."
+msgstr ""
+
+#: includes/admin/topics.php:218 includes/admin/topics.php:255
+msgid "Topic Attributes"
+msgstr ""
+
+#: includes/admin/topics.php:220
+msgid "Select the attributes that your topic should have:"
+msgstr ""
+
+#: includes/admin/topics.php:222
+msgid ""
+"<strong>Forum</strong> dropdown determines the parent forum that the topic "
+"belongs to. Select the forum or category from the dropdown, or leave the "
+"default (No Forum) to post the topic without an assigned forum."
+msgstr ""
+
+#: includes/admin/topics.php:223
+msgid ""
+"<strong>Topic Type</strong> dropdown indicates the sticky status of the "
+"topic. Selecting the super sticky option would stick the topic to the front "
+"of your forums, i.e. the topic index, sticky option would stick the topic to "
+"its respective forum. Selecting normal would not stick the topic anywhere."
+msgstr ""
+
+#: includes/admin/topics.php:485
+msgid "The topic was not found!"
+msgstr ""
+
+#: includes/admin/topics.php:575
+msgid "There was a problem opening the topic \"%1$s\"."
+msgstr ""
+
+#: includes/admin/topics.php:575
+msgid "Topic \"%1$s\" successfully opened."
+msgstr ""
+
+#: includes/admin/topics.php:579
+msgid "There was a problem closing the topic \"%1$s\"."
+msgstr ""
+
+#: includes/admin/topics.php:579
+msgid "Topic \"%1$s\" successfully closed."
+msgstr ""
+
+#: includes/admin/topics.php:583
+msgid "There was a problem sticking the topic \"%1$s\" to front."
+msgstr ""
+
+#: includes/admin/topics.php:583
+msgid "Topic \"%1$s\" successfully sticked to front."
+msgstr ""
+
+#: includes/admin/topics.php:587
+msgid "There was a problem sticking the topic \"%1$s\"."
+msgstr ""
+
+#: includes/admin/topics.php:587
+msgid "Topic \"%1$s\" successfully sticked."
+msgstr ""
+
+#: includes/admin/topics.php:591
+msgid "There was a problem unsticking the topic \"%1$s\"."
+msgstr ""
+
+#: includes/admin/topics.php:591
+msgid "Topic \"%1$s\" successfully unsticked."
+msgstr ""
+
+#: includes/admin/topics.php:595
+msgid "There was a problem marking the topic \"%1$s\" as spam."
+msgstr ""
+
+#: includes/admin/topics.php:595
+msgid "Topic \"%1$s\" successfully marked as spam."
+msgstr ""
+
+#: includes/admin/topics.php:599
+msgid "There was a problem unmarking the topic \"%1$s\" as spam."
+msgstr ""
+
+#: includes/admin/topics.php:599
+msgid "Topic \"%1$s\" successfully unmarked as spam."
+msgstr ""
+
+#: includes/admin/topics.php:635 templates/default/bbpress/loop-topics.php:20
+msgid "Voices"
+msgstr ""
+
+#: includes/admin/topics.php:695 includes/extend/buddypress/groups.php:291
+#: templates/default/bbpress/form-topic.php:117
+msgid "(No Forum)"
+msgstr ""
+
+#: includes/admin/topics.php:730 includes/topics/template.php:2064
+msgid "No Replies"
+msgstr ""
+
+#: includes/admin/topics.php:787
+msgid "Close this topic"
+msgstr ""
+
+#: includes/admin/topics.php:787
+msgctxt "Close a Topic"
+msgid "Close"
+msgstr ""
+
+#: includes/admin/topics.php:789
+msgid "Open this topic"
+msgstr ""
+
+#: includes/admin/topics.php:789
+msgctxt "Open a Topic"
+msgid "Open"
+msgstr ""
+
+#: includes/admin/topics.php:798
+msgid "Unstick this topic"
+msgstr ""
+
+#: includes/admin/topics.php:798 includes/topics/template.php:2748
+msgid "Unstick"
+msgstr ""
+
+#: includes/admin/topics.php:801
+msgid "Stick this topic to its forum"
+msgstr ""
+
+#: includes/admin/topics.php:801 includes/topics/template.php:2747
+msgid "Stick"
+msgstr ""
+
+#: includes/admin/topics.php:801
+msgid "Stick this topic to front"
+msgstr ""
+
+#: includes/admin/topics.php:801 includes/topics/template.php:2749
+msgid "(to front)"
+msgstr ""
+
+#: includes/admin/topics.php:808
+msgid "Mark the topic as not spam"
+msgstr ""
+
+#: includes/admin/topics.php:810
+msgid "Mark this topic as spam"
+msgstr ""
+
+#: includes/admin/topics.php:920
+msgid "Topic updated. <a href=\"%s\">View topic</a>"
+msgstr ""
+
+#: includes/admin/topics.php:929
+msgid "Topic updated."
+msgstr ""
+
+#. translators: %s: date and time of the revision
+#: includes/admin/topics.php:934
+msgid "Topic restored to revision from %s"
+msgstr ""
+
+#: includes/admin/topics.php:938
+msgid "Topic created. <a href=\"%s\">View topic</a>"
+msgstr ""
+
+#: includes/admin/topics.php:941
+msgid "Topic saved."
+msgstr ""
+
+#: includes/admin/topics.php:944
+msgid "Topic submitted. <a target=\"_blank\" href=\"%s\">Preview topic</a>"
+msgstr ""
+
+#: includes/admin/topics.php:947
+msgid ""
+"Topic scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" href=\"%2$s"
+"\">Preview topic</a>"
+msgstr ""
+
+#: includes/admin/topics.php:954
+msgid "Topic draft updated. <a target=\"_blank\" href=\"%s\">Preview topic</a>"
+msgstr ""
+
+#: includes/admin/users.php:87 includes/admin/users.php:213
+#: templates/default/bbpress/form-user-roles.php:20
+msgid "Forum Role"
+msgstr ""
+
+#: includes/admin/users.php:96 includes/admin/users.php:100
+#: includes/users/template.php:1290
+msgid "&mdash; No role for these forums &mdash;"
+msgstr ""
+
+#: includes/admin/users.php:138 includes/admin/users.php:140
+msgid "Change forum role to&hellip;"
+msgstr ""
+
+#: includes/admin/users.php:144
+msgid "Change"
+msgstr ""
+
+#: includes/admin/users.php:212
+msgid "Site Role"
+msgstr ""
+
+#: includes/common/functions.php:112
+msgid "sometime"
+msgstr ""
+
+#: includes/common/functions.php:113
+msgid "right now"
+msgstr ""
+
+#: includes/common/functions.php:114
+msgid "%s ago"
+msgstr ""
+
+#: includes/common/functions.php:118
+msgid "year"
+msgstr ""
+
+#: includes/common/functions.php:118
+msgid "years"
+msgstr ""
+
+#: includes/common/functions.php:119
+msgid "month"
+msgstr ""
+
+#: includes/common/functions.php:119
+msgid "months"
+msgstr ""
+
+#: includes/common/functions.php:120
+msgid "week"
+msgstr ""
+
+#: includes/common/functions.php:120
+msgid "weeks"
+msgstr ""
+
+#: includes/common/functions.php:121
+msgid "day"
+msgstr ""
+
+#: includes/common/functions.php:121
+msgid "days"
+msgstr ""
+
+#: includes/common/functions.php:122
+msgid "hour"
+msgstr ""
+
+#: includes/common/functions.php:122
+msgid "hours"
+msgstr ""
+
+#: includes/common/functions.php:123
+msgid "minute"
+msgstr ""
+
+#: includes/common/functions.php:124
+msgid "second"
+msgstr ""
+
+#: includes/common/functions.php:179
+msgctxt "Separator in time since"
+msgid ","
+msgstr ""
+
+#: includes/common/functions.php:512 includes/common/functions.php:544
+msgid "Private: %s"
+msgstr ""
+
+#: includes/common/functions.php:513 includes/common/functions.php:545
+msgid "Spammed: %s"
+msgstr ""
+
+#: includes/common/functions.php:514 includes/common/functions.php:546
+msgid "Trashed: %s"
+msgstr ""
+
+#: includes/common/functions.php:624
+msgid "<strong>ERROR</strong>: Invalid author name submitted!"
+msgstr ""
+
+#: includes/common/functions.php:628
+msgid "<strong>ERROR</strong>: Invalid email address submitted!"
+msgstr ""
+
+#: includes/common/functions.php:1074
+msgid ""
+"%1$s wrote:\n"
+"\n"
+"%2$s\n"
+"\n"
+"Post Link: %3$s\n"
+"\n"
+"-----------\n"
+"\n"
+"You are receiving this email because you subscribed to a forum topic.\n"
+"\n"
+"Login and visit the topic to unsubscribe from these emails."
+msgstr ""
+
+#: includes/common/functions.php:1193
+msgid ""
+"%1$s wrote:\n"
+"\n"
+"%2$s\n"
+"\n"
+"Topic Link: %3$s\n"
+"\n"
+"-----------\n"
+"\n"
+"You are receiving this email because you subscribed to a forum.\n"
+"\n"
+"Login and visit the topic to unsubscribe from these emails."
+msgstr ""
+
+#: includes/common/functions.php:1905
+msgid ""
+"Conditional query tags do not work before the query is run. Before then, "
+"they always return false."
+msgstr ""
+
+#: includes/common/template.php:1441
+msgid "No topics available"
+msgstr ""
+
+#: includes/common/template.php:1446
+msgid "No forums available"
+msgstr ""
+
+#: includes/common/template.php:1451
+msgid "None available"
+msgstr ""
+
+#: includes/common/template.php:2122
+msgid "Home"
+msgstr ""
+
+#: includes/common/template.php:2192
+msgid "(Edit)"
+msgstr ""
+
+#: includes/common/template.php:2196 includes/common/template.php:2310
+#: includes/common/template.php:2575 includes/core/theme-compat.php:739
+#: templates/default/extras/taxonomy-topic-tag-edit.php:17
+#: templates/default/extras/taxonomy-topic-tag.php:17
+msgid "Topic Tag: %s"
+msgstr ""
+
+#: includes/common/template.php:2200 includes/forums/template.php:53
+#: includes/replies/template.php:53 includes/replies/template.php:1908
+#: includes/topics/template.php:53 includes/topics/template.php:2493
+#: templates/default/bbpress/user-details.php:65
+msgid "Edit"
+msgstr ""
+
+#: includes/common/template.php:2217
+msgid "&lsaquo;"
+msgstr ""
+
+#: includes/common/template.php:2217
+msgid "&rsaquo;"
+msgstr ""
+
+#: includes/common/template.php:2485
+msgid "Log Out"
+msgstr ""
+
+#: includes/common/template.php:2539
+msgid "Forum Edit: %s"
+msgstr ""
+
+#: includes/common/template.php:2544
+msgid "Topic Edit: %s"
+msgstr ""
+
+#: includes/common/template.php:2549
+msgid "Reply Edit: %s"
+msgstr ""
+
+#: includes/common/template.php:2554
+msgid "Topic Tag Edit: %s"
+msgstr ""
+
+#: includes/common/template.php:2561
+msgid "Forum: %s"
+msgstr ""
+
+#: includes/common/template.php:2566
+msgid "Topic: %s"
+msgstr ""
+
+#: includes/common/template.php:2584
+msgctxt "User viewing his/her own profile"
+msgid "Your"
+msgstr ""
+
+#: includes/common/template.php:2588
+msgctxt "User viewing another users profile"
+msgid "%s's"
+msgstr ""
+
+#: includes/common/template.php:2593
+msgid "%s Topics"
+msgstr ""
+
+#: includes/common/template.php:2597
+msgid "%s Replies"
+msgstr ""
+
+#: includes/common/template.php:2601
+msgid "%s Favorites"
+msgstr ""
+
+#: includes/common/template.php:2605
+msgid "%s Subscriptions"
+msgstr ""
+
+#: includes/common/template.php:2609
+msgid "%s Profile"
+msgstr ""
+
+#: includes/common/template.php:2617
+msgid "Edit Your Profile"
+msgstr ""
+
+#: includes/common/template.php:2622
+#: templates/default/bbpress/user-details.php:65
+msgid "Edit %s's Profile"
+msgstr ""
+
+#: includes/common/template.php:2630
+msgid "View: %s"
+msgstr ""
+
+#: includes/common/widgets.php:39
+msgid ""
+"A simple login form with optional links to sign-up and lost password pages."
+msgstr ""
+
+#: includes/common/widgets.php:42
+msgid "(bbPress) Login Widget"
+msgstr ""
+
+#: includes/common/widgets.php:89 includes/common/widgets.php:110
+#: templates/default/bbpress/form-user-login.php:14
+#: templates/default/bbpress/form-user-login.php:35
+msgid "Log In"
+msgstr ""
+
+#: includes/common/widgets.php:92
+#: templates/default/bbpress/form-user-edit.php:98
+#: templates/default/bbpress/form-user-login.php:17
+#: templates/default/bbpress/form-user-register.php:23
+msgid "Username"
+msgstr ""
+
+#: includes/common/widgets.php:97
+#: templates/default/bbpress/form-user-login.php:22
+msgid "Password"
+msgstr ""
+
+#: includes/common/widgets.php:103
+msgid "Remember Me"
+msgstr ""
+
+#: includes/common/widgets.php:122
+#: templates/default/bbpress/form-user-register.php:36
+msgid "Register"
+msgstr ""
+
+#: includes/common/widgets.php:128
+#: templates/default/bbpress/form-user-lost-pass.php:14
+msgid "Lost Password"
+msgstr ""
+
+#: includes/common/widgets.php:185 includes/common/widgets.php:337
+#: includes/common/widgets.php:465 includes/common/widgets.php:634
+#: includes/common/widgets.php:876 includes/common/widgets.php:1030
+#: includes/common/widgets.php:1234
+msgid "Title:"
+msgstr ""
+
+#: includes/common/widgets.php:190
+msgid "Register URI:"
+msgstr ""
+
+#: includes/common/widgets.php:195
+msgid "Lost Password URI:"
+msgstr ""
+
+#: includes/common/widgets.php:243
+msgid "A list of registered optional topic views."
+msgstr ""
+
+#: includes/common/widgets.php:246
+msgid "(bbPress) Topic Views List"
+msgstr ""
+
+#: includes/common/widgets.php:384
+msgid "The bbPress forum search form."
+msgstr ""
+
+#: includes/common/widgets.php:387
+msgid "(bbPress) Forum Search Form"
+msgstr ""
+
+#: includes/common/widgets.php:483 includes/forums/template.php:58
+msgid "Search Forums"
+msgstr ""
+
+#: includes/common/widgets.php:512
+msgid "A list of forums with an option to set the parent."
+msgstr ""
+
+#: includes/common/widgets.php:515
+msgid "(bbPress) Forums List"
+msgstr ""
+
+#: includes/common/widgets.php:640 includes/common/widgets.php:880
+msgid "Parent Forum ID:"
+msgstr ""
+
+#: includes/common/widgets.php:646 includes/common/widgets.php:886
+msgid "\"0\" to show only root - \"any\" to show all"
+msgstr ""
+
+#: includes/common/widgets.php:692
+msgid "A list of recent topics, sorted by popularity or freshness."
+msgstr ""
+
+#: includes/common/widgets.php:695
+msgid "(bbPress) Recent Topics"
+msgstr ""
+
+#: includes/common/widgets.php:815
+msgctxt "widgets"
+msgid "by %1$s"
+msgstr ""
+
+#: includes/common/widgets.php:877
+msgid "Maximum topics to show:"
+msgstr ""
+
+#: includes/common/widgets.php:889 includes/common/widgets.php:1236
+msgid "Show post date:"
+msgstr ""
+
+#: includes/common/widgets.php:890
+msgid "Show topic author:"
+msgstr ""
+
+#: includes/common/widgets.php:893
+msgid "Order By:"
+msgstr ""
+
+#: includes/common/widgets.php:895
+msgid "Newest Topics"
+msgstr ""
+
+#: includes/common/widgets.php:896
+#: templates/default/extras/page-forum-statistics.php:34
+msgid "Popular Topics"
+msgstr ""
+
+#: includes/common/widgets.php:897
+msgid "Topics With Recent Replies"
+msgstr ""
+
+#: includes/common/widgets.php:914
+msgid "Recent Topics"
+msgstr ""
+
+#: includes/common/widgets.php:948
+msgid "Some statistics from your forum."
+msgstr ""
+
+#: includes/common/widgets.php:951
+msgid "(bbPress) Statistics"
+msgstr ""
+
+#: includes/common/widgets.php:1048
+msgid "Forum Statistics"
+msgstr ""
+
+#: includes/common/widgets.php:1078
+msgid "A list of the most recent replies."
+msgstr ""
+
+#: includes/common/widgets.php:1081
+msgid "(bbPress) Recent Replies"
+msgstr ""
+
+#. translators: 1: reply author, 2: reply link, 3: reply timestamp
+#: includes/common/widgets.php:1166
+msgctxt "widgets"
+msgid "%1$s on %2$s %3$s"
+msgstr ""
+
+#. translators: 1: reply link, 2: reply timestamp
+#: includes/common/widgets.php:1172
+msgctxt "widgets"
+msgid "%1$s %2$s"
+msgstr ""
+
+#. translators: 1: reply author, 2: reply link
+#: includes/common/widgets.php:1178
+msgctxt "widgets"
+msgid "%1$s on %2$s"
+msgstr ""
+
+#. translators: 1: reply link
+#: includes/common/widgets.php:1184
+msgctxt "widgets"
+msgid "%1$s"
+msgstr ""
+
+#: includes/common/widgets.php:1235
+msgid "Maximum replies to show:"
+msgstr ""
+
+#: includes/common/widgets.php:1237
+msgid "Show reply author:"
+msgstr ""
+
+#: includes/common/widgets.php:1252
+msgid "Recent Replies"
+msgstr ""
+
+#: includes/core/capabilities.php:380
+msgid "Keymaster"
+msgstr ""
+
+#: includes/core/capabilities.php:386
+msgid "Moderator"
+msgstr ""
+
+#: includes/core/capabilities.php:392
+msgid "Participant"
+msgstr ""
+
+#: includes/core/capabilities.php:398
+msgid "Spectator"
+msgstr ""
+
+#: includes/core/capabilities.php:404
+msgid "Blocked"
+msgstr ""
+
+#: includes/core/capabilities.php:523
+msgid "Editable forum roles no longer exist."
+msgstr ""
+
+#: includes/core/sub-actions.php:147
+msgid "The current user is being initialized without using $wp->init()."
+msgstr ""
+
+#: includes/core/update.php:186
+msgid "General"
+msgstr ""
+
+#: includes/core/update.php:187
+msgid "General chit-chat"
+msgstr ""
+
+#: includes/core/update.php:188
+msgid "Hello World!"
+msgstr ""
+
+#: includes/core/update.php:189
+msgid "I am the first topic in your new forums."
+msgstr ""
+
+#: includes/core/update.php:190
+msgid "Re: Hello World!"
+msgstr ""
+
+#: includes/core/update.php:191
+msgid "Oh, and this is what a reply looks like."
+msgstr ""
+
+#: includes/extend/akismet.php:309
+msgid "%1$s reported this %2$s as spam"
+msgstr ""
+
+#: includes/extend/akismet.php:316
+msgid "%1$s reported this %2$s as not spam"
+msgstr ""
+
+#: includes/extend/akismet.php:405
+msgid "No response"
+msgstr ""
+
+#: includes/extend/akismet.php:463
+msgid "Akismet caught this post as spam"
+msgstr ""
+
+#: includes/extend/akismet.php:467 includes/extend/akismet.php:482
+msgid "Post status was changed to %s"
+msgstr ""
+
+#: includes/extend/akismet.php:475
+msgid "Akismet cleared this post as not spam"
+msgstr ""
+
+#: includes/extend/akismet.php:489
+msgid ""
+"Akismet was unable to check this post (response: %s), will automatically "
+"retry again later."
+msgstr ""
+
+#: includes/extend/akismet.php:735 includes/extend/akismet.php:745
+msgid "Akismet History"
+msgstr ""
+
+#: includes/extend/akismet.php:793
+msgid "No recorded history. Akismet has not checked this post."
+msgstr ""
+
+#: includes/extend/buddypress/activity.php:195
+msgid "New forum topic"
+msgstr ""
+
+#: includes/extend/buddypress/activity.php:196
+msgid "New forum reply"
+msgstr ""
+
+#: includes/extend/buddypress/activity.php:420
+msgid "%1$s started the topic %2$s in the forum %3$s"
+msgstr ""
+
+#: includes/extend/buddypress/activity.php:565
+msgid "%1$s replied to the topic %2$s in the forum %3$s"
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:271
+#: includes/extend/buddypress/groups.php:274
+msgid "Group Forum Settings"
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:275
+#: includes/extend/buddypress/groups.php:476
+msgid ""
+"Create a discussion forum to allow members of this group to communicate in a "
+"structured, bulletin-board style fashion."
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:279
+#: includes/extend/buddypress/groups.php:479
+msgid "Yes. I want this group to have a forum."
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:282
+msgid "Saying no will not delete existing forum content."
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:287
+msgid "Group Forum:"
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:295
+msgid ""
+"Network administrators can reconfigure which forum belongs to this group."
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:300
+msgid "Save Settings"
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:335
+#: includes/extend/buddypress/groups.php:494
+#: includes/extend/buddypress/notifications.php:161
+#: includes/forums/functions.php:118 includes/forums/functions.php:395
+#: includes/replies/functions.php:116 includes/replies/functions.php:518
+#: includes/replies/functions.php:1245 includes/topics/functions.php:122
+#: includes/topics/functions.php:520 includes/topics/functions.php:1153
+#: includes/topics/functions.php:1456 includes/topics/functions.php:1820
+#: includes/topics/functions.php:1859 includes/topics/functions.php:1916
+#: includes/users/functions.php:459 includes/users/functions.php:1174
+#: includes/users/functions.php:1280 includes/users/functions.php:1407
+#: includes/users/functions.php:1413
+msgid "<strong>ERROR</strong>: Are you sure you wanted to do that?"
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:433
+msgctxt "group admin edit screen"
+msgid "Discussion Forum"
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:474
+msgid "Group Forum"
+msgstr ""
+
+#: includes/extend/buddypress/groups.php:771
+msgid "This group does not currently have a forum."
+msgstr ""
+
+#: includes/extend/buddypress/loader.php:105
+msgid "Search Forums..."
+msgstr ""
+
+#: includes/extend/buddypress/loader.php:293
+#: templates/default/bbpress/user-subscriptions.php:34
+msgid "Subscribed Topics"
+msgstr ""
+
+#: includes/extend/buddypress/notifications.php:48
+msgid "Topic Replies"
+msgstr ""
+
+#: includes/extend/buddypress/notifications.php:51
+msgid "You have %d new replies"
+msgstr ""
+
+#: includes/extend/buddypress/notifications.php:55
+msgid "You have %d new reply to %2$s from %3$s"
+msgstr ""
+
+#: includes/extend/buddypress/notifications.php:57
+msgid "You have %d new reply to %s"
+msgstr ""
+
+#: includes/extend/buddypress/notifications.php:165
+msgid ""
+"<strong>ERROR</strong>: You do not have permission to mark notifications for "
+"that user."
+msgstr ""
+
+#: includes/forums/functions.php:131
+msgid ""
+"<strong>ERROR</strong>: You do not have permission to create new forums."
+msgstr ""
+
+#: includes/forums/functions.php:155 includes/forums/functions.php:455
+msgid "<strong>ERROR</strong>: Your forum needs a title."
+msgstr ""
+
+#: includes/forums/functions.php:167 includes/forums/functions.php:467
+msgid "<strong>ERROR</strong>: Your forum description cannot be empty."
+msgstr ""
+
+#: includes/forums/functions.php:181
+msgid "<strong>ERROR</strong>: Your forum must have a parent."
+msgstr ""
+
+#: includes/forums/functions.php:188
+msgid ""
+"<strong>ERROR</strong>: This forum is a category. No forums can be created "
+"in this forum."
+msgstr ""
+
+#: includes/forums/functions.php:193 includes/forums/functions.php:431
+msgid "<strong>ERROR</strong>: This forum has been closed to new forums."
+msgstr ""
+
+#: includes/forums/functions.php:198 includes/forums/functions.php:436
+msgid ""
+"<strong>ERROR</strong>: This forum is private and you do not have the "
+"capability to read or create new forums in it."
+msgstr ""
+
+#: includes/forums/functions.php:203 includes/forums/functions.php:441
+msgid ""
+"<strong>ERROR</strong>: This forum is hidden and you do not have the "
+"capability to read or create new forums in it."
+msgstr ""
+
+#: includes/forums/functions.php:210 includes/replies/functions.php:293
+#: includes/topics/functions.php:260
+msgid "<strong>ERROR</strong>: Slow down; you move too fast."
+msgstr ""
+
+#: includes/forums/functions.php:215
+msgid "<strong>ERROR</strong>: This forum already exists."
+msgstr ""
+
+#: includes/forums/functions.php:220
+msgid "<strong>ERROR</strong>: Your forum cannot be created at this time."
+msgstr ""
+
+#: includes/forums/functions.php:384
+msgid "<strong>ERROR</strong>: Forum ID not found."
+msgstr ""
+
+#: includes/forums/functions.php:400
+msgid "<strong>ERROR</strong>: The forum you want to edit was not found."
+msgstr ""
+
+#: includes/forums/functions.php:405
+msgid "<strong>ERROR</strong>: You do not have permission to edit that forum."
+msgstr ""
+
+#: includes/forums/functions.php:472
+msgid "<strong>ERROR</strong>: Your forum cannot be edited at this time."
+msgstr ""
+
+#: includes/forums/functions.php:1602
+msgctxt "Open the forum"
+msgid "Open"
+msgstr ""
+
+#: includes/forums/functions.php:1603
+msgctxt "Close the forum"
+msgid "Closed"
+msgstr ""
+
+#: includes/forums/functions.php:1616
+msgctxt "Forum accepts new topics"
+msgid "Forum"
+msgstr ""
+
+#: includes/forums/functions.php:1617
+msgctxt "Forum is a category"
+msgid "Category"
+msgstr ""
+
+#: includes/forums/functions.php:1630
+msgctxt "Make forum public"
+msgid "Public"
+msgstr ""
+
+#: includes/forums/functions.php:1631
+msgctxt "Make forum private"
+msgid "Private"
+msgstr ""
+
+#: includes/forums/functions.php:1632
+msgctxt "Make forum hidden"
+msgid "Hidden"
+msgstr ""
+
+#: includes/forums/template.php:51 includes/forums/template.php:55
+msgid "New Forum"
+msgstr ""
+
+#: includes/forums/template.php:52 templates/default/bbpress/form-forum.php:37
+msgid "Create New Forum"
+msgstr ""
+
+#: includes/forums/template.php:54
+msgid "Edit Forum"
+msgstr ""
+
+#: includes/forums/template.php:56 includes/forums/template.php:57
+msgid "View Forum"
+msgstr ""
+
+#: includes/forums/template.php:59
+msgid "No forums found"
+msgstr ""
+
+#: includes/forums/template.php:60
+msgid "No forums found in Trash"
+msgstr ""
+
+#: includes/forums/template.php:61
+#: templates/default/bbpress/form-forum.php:118
+msgid "Parent Forum:"
+msgstr ""
+
+#: includes/forums/template.php:840 includes/topics/template.php:1846
+#: includes/users/template.php:1058
+msgid "Subscribe"
+msgstr ""
+
+#: includes/forums/template.php:841 includes/topics/template.php:1847
+#: includes/users/template.php:1059
+msgid "Unsubscribe"
+msgstr ""
+
+#: includes/forums/template.php:1239 includes/forums/template.php:1977
+msgid "%s topic"
+msgid_plural "%s topics"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/forums/template.php:1255 includes/topics/template.php:2120
+msgid " (+ %d hidden)"
+msgstr ""
+
+#: includes/forums/template.php:1966 includes/topics/template.php:2104
+msgid "%s reply"
+msgid_plural "%s replies"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/forums/template.php:1986
+msgid ""
+"This category contains %1$s and %2$s, and was last updated by %3$s %4$s."
+msgstr ""
+
+#: includes/forums/template.php:1988
+msgid "This forum contains %1$s and %2$s, and was last updated by %3$s %4$s."
+msgstr ""
+
+#: includes/forums/template.php:1994
+msgid "This category contains %1$s, and was last updated by %2$s %3$s."
+msgstr ""
+
+#: includes/forums/template.php:1996
+msgid "This forum contains %1$s, and was last updated by %2$s %3$s."
+msgstr ""
+
+#: includes/forums/template.php:2006
+msgid "This category contains %1$s and %2$s."
+msgstr ""
+
+#: includes/forums/template.php:2008
+msgid "This forum contains %1$s and %2$s."
+msgstr ""
+
+#: includes/forums/template.php:2016
+msgid "This category contains %1$s."
+msgstr ""
+
+#: includes/forums/template.php:2018
+msgid "This forum contains %1$s."
+msgstr ""
+
+#: includes/forums/template.php:2022
+msgid "This forum is empty."
+msgstr ""
+
+#: includes/replies/functions.php:142
+msgid "<strong>ERROR</strong>: You do not have permission to reply."
+msgstr ""
+
+#: includes/replies/functions.php:154
+msgid "<strong>ERROR</strong>: Topic ID is missing."
+msgstr ""
+
+#: includes/replies/functions.php:158
+msgid "<strong>ERROR</strong>: Topic ID must be a number."
+msgstr ""
+
+#: includes/replies/functions.php:168
+msgid "<strong>ERROR</strong>: Topic ID cannot be a negative number."
+msgstr ""
+
+#: includes/replies/functions.php:172
+msgid "<strong>ERROR</strong>: Topic does not exist."
+msgstr ""
+
+#: includes/replies/functions.php:191 includes/replies/functions.php:205
+#: includes/topics/functions.php:196 includes/topics/functions.php:210
+#: includes/topics/functions.php:535
+msgid "<strong>ERROR</strong>: Forum ID is missing."
+msgstr ""
+
+#: includes/replies/functions.php:195 includes/topics/functions.php:200
+msgid "<strong>ERROR</strong>: Forum ID must be a number."
+msgstr ""
+
+#: includes/replies/functions.php:209 includes/topics/functions.php:214
+msgid "<strong>ERROR</strong>: Forum ID cannot be a negative number."
+msgstr ""
+
+#: includes/replies/functions.php:213 includes/topics/functions.php:218
+msgid "<strong>ERROR</strong>: Forum does not exist."
+msgstr ""
+
+#: includes/replies/functions.php:227 includes/replies/functions.php:574
+msgid ""
+"<strong>ERROR</strong>: This forum is a category. No replies can be created "
+"in this forum."
+msgstr ""
+
+#: includes/replies/functions.php:234 includes/replies/functions.php:581
+msgid "<strong>ERROR</strong>: This forum has been closed to new replies."
+msgstr ""
+
+#: includes/replies/functions.php:240 includes/replies/functions.php:587
+msgid ""
+"<strong>ERROR</strong>: This forum is private and you do not have the "
+"capability to read or create new replies in it."
+msgstr ""
+
+#: includes/replies/functions.php:246 includes/replies/functions.php:593
+msgid ""
+"<strong>ERROR</strong>: This forum is hidden and you do not have the "
+"capability to read or create new replies in it."
+msgstr ""
+
+#: includes/replies/functions.php:288 includes/replies/functions.php:617
+msgid "<strong>ERROR</strong>: Your reply cannot be empty."
+msgstr ""
+
+#: includes/replies/functions.php:298
+msgid ""
+"<strong>ERROR</strong>: Duplicate reply detected; it looks as though "
+"you&#8217;ve already said that!"
+msgstr ""
+
+#: includes/replies/functions.php:303
+msgid "<strong>ERROR</strong>: Your reply cannot be created at this time."
+msgstr ""
+
+#: includes/replies/functions.php:320
+msgid "<strong>ERROR</strong>: Topic is closed."
+msgstr ""
+
+#: includes/replies/functions.php:379 includes/replies/functions.php:701
+msgid ""
+"<strong>ERROR</strong>: There was a problem adding the tags to the topic."
+msgstr ""
+
+#: includes/replies/functions.php:507
+msgid "<strong>ERROR</strong>: Reply ID not found."
+msgstr ""
+
+#: includes/replies/functions.php:524
+msgid "<strong>ERROR</strong>: The reply you want to edit was not found."
+msgstr ""
+
+#: includes/replies/functions.php:535
+msgid "<strong>ERROR</strong>: You do not have permission to edit that reply."
+msgstr ""
+
+#: includes/replies/functions.php:622
+msgid "<strong>ERROR</strong>: Your reply cannot be edited at this time."
+msgstr ""
+
+#: includes/replies/functions.php:1222
+msgid "<strong>ERROR</strong>: Reply ID to move not found!"
+msgstr ""
+
+#: includes/replies/functions.php:1231
+msgid "<strong>ERROR</strong>: The reply you want to move was not found."
+msgstr ""
+
+#: includes/replies/functions.php:1240
+msgid "<strong>ERROR</strong>: The topic you want to move from was not found."
+msgstr ""
+
+#: includes/replies/functions.php:1251 includes/topics/functions.php:1164
+#: includes/topics/functions.php:1462
+msgid ""
+"<strong>ERROR</strong>: You do not have the permissions to edit the source "
+"topic."
+msgstr ""
+
+#: includes/replies/functions.php:1261
+msgid "<strong>ERROR</strong>: You need to choose a valid move option."
+msgstr ""
+
+#: includes/replies/functions.php:1274 includes/topics/functions.php:1483
+msgid "<strong>ERROR</strong>: Destination topic ID not found!"
+msgstr ""
+
+#: includes/replies/functions.php:1284
+msgid "<strong>ERROR</strong>: The topic you want to move to was not found!"
+msgstr ""
+
+#: includes/replies/functions.php:1289 includes/topics/functions.php:1496
+msgid ""
+"<strong>ERROR</strong>: You do not have the permissions to edit the "
+"destination topic!"
+msgstr ""
+
+#: includes/replies/functions.php:1298 includes/replies/template.php:571
+#: includes/topics/functions.php:1294 includes/topics/functions.php:1652
+#: templates/default/bbpress/form-reply.php:29
+msgid "Reply To: %s"
+msgstr ""
+
+#: includes/replies/functions.php:1343 includes/topics/functions.php:1533
+msgid ""
+"<strong>ERROR</strong>: There was a problem converting the reply into the "
+"topic. Please try again."
+msgstr ""
+
+#: includes/replies/functions.php:1348 includes/topics/functions.php:1538
+msgid ""
+"<strong>ERROR</strong>: You do not have the permissions to create new "
+"topics. The reply could not be converted into a topic."
+msgstr ""
+
+#: includes/replies/functions.php:1530
+msgid "<strong>ERROR:</strong> You do not have the permission to do that!"
+msgstr ""
+
+#: includes/replies/functions.php:1543
+msgid ""
+"<strong>ERROR</strong>: There was a problem unmarking the reply as spam!"
+msgstr ""
+
+#: includes/replies/functions.php:1543
+msgid "<strong>ERROR</strong>: There was a problem marking the reply as spam!"
+msgstr ""
+
+#: includes/replies/functions.php:1562
+msgid "<strong>ERROR</strong>: There was a problem trashing the reply!"
+msgstr ""
+
+#: includes/replies/functions.php:1570
+msgid "<strong>ERROR</strong>: There was a problem untrashing the reply!"
+msgstr ""
+
+#: includes/replies/functions.php:1578
+msgid "<strong>ERROR</strong>: There was a problem deleting the reply!"
+msgstr ""
+
+#: includes/replies/functions.php:1992
+msgid "All Posts"
+msgstr ""
+
+#: includes/replies/functions.php:2034 includes/topics/functions.php:3465
+msgid "Replies: %s"
+msgstr ""
+
+#: includes/replies/template.php:51 includes/replies/template.php:55
+msgid "New Reply"
+msgstr ""
+
+#: includes/replies/template.php:52
+msgid "Create New Reply"
+msgstr ""
+
+#: includes/replies/template.php:54
+msgid "Edit Reply"
+msgstr ""
+
+#: includes/replies/template.php:56 includes/replies/template.php:57
+msgid "View Reply"
+msgstr ""
+
+#: includes/replies/template.php:58
+msgid "Search Replies"
+msgstr ""
+
+#: includes/replies/template.php:59
+msgid "No replies found"
+msgstr ""
+
+#: includes/replies/template.php:60
+msgid "No replies found in Trash"
+msgstr ""
+
+#: includes/replies/template.php:706 includes/topics/template.php:809
+msgctxt "date at time"
+msgid "%1$s at %2$s"
+msgstr ""
+
+#: includes/replies/template.php:804
+msgid "This reply was modified %1$s by %2$s. Reason: %3$s"
+msgstr ""
+
+#: includes/replies/template.php:806
+msgid "This reply was modified %1$s by %2$s."
+msgstr ""
+
+#: includes/replies/template.php:1098 includes/topics/template.php:1368
+#: includes/users/template.php:184
+msgid "Anonymous"
+msgstr ""
+
+#: includes/replies/template.php:1210 includes/topics/template.php:1481
+#: includes/users/template.php:1651
+msgid "View %s's profile"
+msgstr ""
+
+#: includes/replies/template.php:1210 includes/topics/template.php:1481
+#: includes/users/template.php:1651
+msgid "Visit %s's website"
+msgstr ""
+
+#: includes/replies/template.php:1693
+msgid "Cancel"
+msgstr ""
+
+#: includes/replies/template.php:2034 includes/topics/template.php:2619
+#: templates/default/bbpress/form-topic-tag.php:88
+#: templates/default/bbpress/form-topic-tag.php:101
+msgid "Delete"
+msgstr ""
+
+#: includes/replies/template.php:2051 includes/topics/template.php:2636
+msgid "Are you sure you want to delete that permanently?"
+msgstr ""
+
+#: includes/replies/template.php:2104 includes/topics/template.php:2875
+msgid "Unspam"
+msgstr ""
+
+#: includes/replies/template.php:2167
+msgid "Move"
+msgstr ""
+
+#: includes/replies/template.php:2168
+msgid "Move this reply"
+msgstr ""
+
+#: includes/replies/template.php:2234
+msgid "Split"
+msgstr ""
+
+#: includes/replies/template.php:2235
+msgid "Split the topic from this reply"
+msgstr ""
+
+#: includes/replies/template.php:2341
+msgid "Viewing %1$s reply thread"
+msgid_plural "Viewing %1$s reply threads"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/replies/template.php:2348
+msgid "Viewing %1$s reply"
+msgid_plural "Viewing %1$s replies"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/replies/template.php:2352
+msgid "Viewing %2$s replies (of %4$s total)"
+msgid_plural "Viewing %1$s replies - %2$s through %3$s (of %4$s total)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/replies/template.php:2360
+msgid "Viewing %1$s post"
+msgid_plural "Viewing %1$s posts"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/replies/template.php:2364
+msgid "Viewing %2$s post (of %4$s total)"
+msgid_plural "Viewing %1$s posts - %2$s through %3$s (of %4$s total)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/search/template.php:229
+msgid "Search Results for '%s'"
+msgstr ""
+
+#: includes/search/template.php:401
+msgid "Viewing %1$s result"
+msgid_plural "Viewing %1$s results"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/search/template.php:405
+msgid "Viewing %2$s results (of %4$s total)"
+msgid_plural "Viewing %1$s results - %2$s through %3$s (of %4$s total)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/topics/functions.php:150
+msgid ""
+"<strong>ERROR</strong>: You do not have permission to create new topics."
+msgstr ""
+
+#: includes/topics/functions.php:175 includes/topics/functions.php:585
+msgid "<strong>ERROR</strong>: Your topic needs a title."
+msgstr ""
+
+#: includes/topics/functions.php:187 includes/topics/functions.php:597
+msgid "<strong>ERROR</strong>: Your topic cannot be empty."
+msgstr ""
+
+#: includes/topics/functions.php:232
+msgid ""
+"<strong>ERROR</strong>: This forum is a category. No topics can be created "
+"in this forum."
+msgstr ""
+
+#: includes/topics/functions.php:239 includes/topics/functions.php:557
+msgid "<strong>ERROR</strong>: This forum has been closed to new topics."
+msgstr ""
+
+#: includes/topics/functions.php:245 includes/topics/functions.php:563
+msgid ""
+"<strong>ERROR</strong>: This forum is private and you do not have the "
+"capability to read or create new topics in it."
+msgstr ""
+
+#: includes/topics/functions.php:251 includes/topics/functions.php:569
+msgid ""
+"<strong>ERROR</strong>: This forum is hidden and you do not have the "
+"capability to read or create new topics in it."
+msgstr ""
+
+#: includes/topics/functions.php:265
+msgid ""
+"<strong>ERROR</strong>: Duplicate topic detected; it looks as though "
+"you&#8217;ve already said that!"
+msgstr ""
+
+#: includes/topics/functions.php:270
+msgid "<strong>ERROR</strong>: Your topic cannot be created at this time."
+msgstr ""
+
+#: includes/topics/functions.php:482 includes/topics/functions.php:1146
+msgid "<strong>ERROR</strong>: Topic ID not found."
+msgstr ""
+
+#: includes/topics/functions.php:493
+msgid "<strong>ERROR</strong>: The topic you want to edit was not found."
+msgstr ""
+
+#: includes/topics/functions.php:504
+msgid "<strong>ERROR</strong>: You do not have permission to edit that topic."
+msgstr ""
+
+#: includes/topics/functions.php:550
+msgid ""
+"<strong>ERROR</strong>: This forum is a category. No topics can be created "
+"in it."
+msgstr ""
+
+#: includes/topics/functions.php:602
+msgid "<strong>ERROR</strong>: Your topic cannot be edited at this time."
+msgstr ""
+
+#: includes/topics/functions.php:1158
+msgid "<strong>ERROR</strong>: The topic you want to merge was not found."
+msgstr ""
+
+#: includes/topics/functions.php:1172
+msgid "<strong>ERROR</strong>: Destination topic ID not found."
+msgstr ""
+
+#: includes/topics/functions.php:1178
+msgid "<strong>ERROR</strong>: The topic you want to merge to was not found."
+msgstr ""
+
+#: includes/topics/functions.php:1182
+msgid ""
+"<strong>ERROR</strong>: You do not have the permissions to edit the "
+"destination topic."
+msgstr ""
+
+#: includes/topics/functions.php:1435
+msgid "<strong>ERROR</strong>: Reply ID to split the topic from not found!"
+msgstr ""
+
+#: includes/topics/functions.php:1443
+msgid "<strong>ERROR</strong>: The reply you want to split from was not found."
+msgstr ""
+
+#: includes/topics/functions.php:1452
+msgid "<strong>ERROR</strong>: The topic you want to split was not found."
+msgstr ""
+
+#: includes/topics/functions.php:1470
+msgid "<strong>ERROR</strong>: You need to choose a valid split option."
+msgstr ""
+
+#: includes/topics/functions.php:1492
+msgid "<strong>ERROR</strong>: The topic you want to split to was not found!"
+msgstr ""
+
+#: includes/topics/functions.php:1808
+msgid ""
+"<strong>ERROR</strong>: The following problem(s) have been found while "
+"getting the tag: %s"
+msgstr ""
+
+#: includes/topics/functions.php:1826 includes/topics/functions.php:1865
+msgid ""
+"<strong>ERROR</strong>: You do not have the permissions to edit the topic "
+"tags."
+msgstr ""
+
+#: includes/topics/functions.php:1832 includes/topics/functions.php:1871
+msgid "<strong>ERROR</strong>: You need to enter a tag name."
+msgstr ""
+
+#: includes/topics/functions.php:1842
+msgid ""
+"<strong>ERROR</strong>: The following problem(s) have been found while "
+"updating the tag: %s"
+msgstr ""
+
+#: includes/topics/functions.php:1881 includes/topics/functions.php:1899
+msgid ""
+"<strong>ERROR</strong>: The following problem(s) have been found while "
+"merging the tags: %s"
+msgstr ""
+
+#: includes/topics/functions.php:1890
+msgid ""
+"<strong>ERROR</strong>: The tags which are being merged can not be the same."
+msgstr ""
+
+#: includes/topics/functions.php:1922
+msgid ""
+"<strong>ERROR</strong>: You do not have the permissions to delete the topic "
+"tags."
+msgstr ""
+
+#: includes/topics/functions.php:1931
+msgid ""
+"<strong>ERROR</strong>: The following problem(s) have been found while "
+"deleting the tag: %s"
+msgstr ""
+
+#: includes/topics/functions.php:1965
+msgctxt "Open the topic"
+msgid "Open"
+msgstr ""
+
+#: includes/topics/functions.php:1966
+msgctxt "Close the topic"
+msgid "Closed"
+msgstr ""
+
+#: includes/topics/functions.php:1967
+msgctxt "Spam the topic"
+msgid "Spam"
+msgstr ""
+
+#: includes/topics/functions.php:1968
+msgctxt "Trash the topic"
+msgid "Trash"
+msgstr ""
+
+#: includes/topics/functions.php:1969
+msgctxt "Mark topic as pending"
+msgid "Pending"
+msgstr ""
+
+#: includes/topics/functions.php:1982
+msgctxt "Unstick a topic"
+msgid "Normal"
+msgstr ""
+
+#: includes/topics/functions.php:1983
+msgctxt "Make topic sticky"
+msgid "Sticky"
+msgstr ""
+
+#: includes/topics/functions.php:1984
+msgctxt "Make topic super sticky"
+msgid "Super Sticky"
+msgstr ""
+
+#: includes/topics/functions.php:2090
+msgid "<strong>ERROR:</strong> You do not have the permission to do that."
+msgstr ""
+
+#: includes/topics/functions.php:2103
+msgid "<strong>ERROR</strong>: There was a problem closing the topic."
+msgstr ""
+
+#: includes/topics/functions.php:2103
+msgid "<strong>ERROR</strong>: There was a problem opening the topic."
+msgstr ""
+
+#: includes/topics/functions.php:2114
+msgid "<strong>ERROR</strong>: There was a problem unsticking the topic."
+msgstr ""
+
+#: includes/topics/functions.php:2114
+msgid "<strong>ERROR</strong>: There was a problem sticking the topic."
+msgstr ""
+
+#: includes/topics/functions.php:2124
+msgid ""
+"<strong>ERROR</strong>: There was a problem unmarking the topic as spam."
+msgstr ""
+
+#: includes/topics/functions.php:2124
+msgid "<strong>ERROR</strong>: There was a problem marking the topic as spam."
+msgstr ""
+
+#: includes/topics/functions.php:2143
+msgid "<strong>ERROR</strong>: There was a problem trashing the topic."
+msgstr ""
+
+#: includes/topics/functions.php:2151
+msgid "<strong>ERROR</strong>: There was a problem untrashing the topic."
+msgstr ""
+
+#: includes/topics/functions.php:2159
+msgid "<strong>ERROR</strong>: There was a problem deleting the topic."
+msgstr ""
+
+#: includes/topics/template.php:51 includes/topics/template.php:55
+msgid "New Topic"
+msgstr ""
+
+#: includes/topics/template.php:52 templates/default/bbpress/form-topic.php:43
+msgid "Create New Topic"
+msgstr ""
+
+#: includes/topics/template.php:54
+msgid "Edit Topic"
+msgstr ""
+
+#: includes/topics/template.php:56 includes/topics/template.php:57
+msgid "View Topic"
+msgstr ""
+
+#: includes/topics/template.php:58
+msgid "Search Topics"
+msgstr ""
+
+#: includes/topics/template.php:59
+msgid "No topics found"
+msgstr ""
+
+#: includes/topics/template.php:60
+msgid "No topics found in Trash"
+msgstr ""
+
+#: includes/topics/template.php:991
+msgid "This topic was modified %1$s by %2$s. Reason: %3$s"
+msgstr ""
+
+#: includes/topics/template.php:993
+msgid "This topic was modified %1$s by %2$s."
+msgstr ""
+
+#: includes/topics/template.php:1891 includes/users/template.php:894
+msgid "Favorite"
+msgstr ""
+
+#: includes/topics/template.php:1892
+msgid "Unfavorite"
+msgstr ""
+
+#: includes/topics/template.php:2297
+msgid "Tagged:"
+msgstr ""
+
+#: includes/topics/template.php:2687
+msgctxt "Topic Status"
+msgid "Close"
+msgstr ""
+
+#: includes/topics/template.php:2688
+msgctxt "Topic Status"
+msgid "Open"
+msgstr ""
+
+#: includes/topics/template.php:2818
+#: templates/default/bbpress/form-topic-tag.php:59
+#: templates/default/bbpress/form-topic-tag.php:73
+msgid "Merge"
+msgstr ""
+
+#: includes/topics/template.php:2979
+msgid "Viewing %1$s topic"
+msgid_plural "Viewing %1$s topics"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/topics/template.php:2983
+msgid "Viewing topic %2$s (of %4$s total)"
+msgid_plural "Viewing %1$s topics - %2$s through %3$s (of %4$s total)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/topics/template.php:3043
+msgid "This topic is marked as spam."
+msgstr ""
+
+#: includes/topics/template.php:3048
+msgid "This topic is in the trash."
+msgstr ""
+
+#: includes/topics/template.php:3308
+msgid "%s voice"
+msgid_plural "%s voices"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/topics/template.php:3314
+msgid "This topic contains %1$s, has %2$s, and was last updated by %3$s %4$s."
+msgstr ""
+
+#: includes/topics/template.php:3318
+msgid "This topic contains %1$s and has %2$s."
+msgstr ""
+
+#: includes/topics/template.php:3322
+msgid "This topic has no replies."
+msgstr ""
+
+#: includes/topics/template.php:3368
+#: templates/default/bbpress/content-statistics.php:37
+msgid "Topic Tags"
+msgstr ""
+
+#: includes/topics/template.php:3370
+msgid "Search Tags"
+msgstr ""
+
+#: includes/topics/template.php:3371
+msgid "Popular Tags"
+msgstr ""
+
+#: includes/topics/template.php:3372
+msgid "All Tags"
+msgstr ""
+
+#: includes/topics/template.php:3373
+msgid "Edit Tag"
+msgstr ""
+
+#: includes/topics/template.php:3374
+msgid "Update Tag"
+msgstr ""
+
+#: includes/topics/template.php:3375
+msgid "Add New Tag"
+msgstr ""
+
+#: includes/topics/template.php:3376
+msgid "New Tag Name"
+msgstr ""
+
+#: includes/topics/template.php:3377
+msgid "View Topic Tag"
+msgstr ""
+
+#: includes/users/functions.php:455
+msgid ""
+"<strong>ERROR</strong>: No topic was found! Which topic are you marking/"
+"unmarking as favorite?"
+msgstr ""
+
+#: includes/users/functions.php:463 includes/users/functions.php:1178
+#: includes/users/functions.php:1284
+msgid ""
+"<strong>ERROR</strong>: You don't have the permission to edit favorites of "
+"that user!"
+msgstr ""
+
+#: includes/users/functions.php:506
+msgid ""
+"<strong>ERROR</strong>: There was a problem removing that topic from "
+"favorites!"
+msgstr ""
+
+#: includes/users/functions.php:508
+msgid "<strong>ERROR</strong>: There was a problem favoriting that topic!"
+msgstr ""
+
+#: includes/users/functions.php:1170
+msgid ""
+"<strong>ERROR</strong>: No forum was found! Which forum are you subscribing/"
+"unsubscribing to?"
+msgstr ""
+
+#: includes/users/functions.php:1223
+msgid ""
+"<strong>ERROR</strong>: There was a problem unsubscribing from that forum!"
+msgstr ""
+
+#: includes/users/functions.php:1225
+msgid "<strong>ERROR</strong>: There was a problem subscribing to that forum!"
+msgstr ""
+
+#: includes/users/functions.php:1276
+msgid ""
+"<strong>ERROR</strong>: No topic was found! Which topic are you subscribing/"
+"unsubscribing to?"
+msgstr ""
+
+#: includes/users/functions.php:1329
+msgid ""
+"<strong>ERROR</strong>: There was a problem unsubscribing from that topic!"
+msgstr ""
+
+#: includes/users/functions.php:1331
+msgid "<strong>ERROR</strong>: There was a problem subscribing to that topic!"
+msgstr ""
+
+#: includes/users/template.php:503
+msgid "Guest"
+msgstr ""
+
+#: includes/users/template.php:507
+msgid "Inactive"
+msgstr ""
+
+#: includes/users/template.php:517
+msgid "Member"
+msgstr ""
+
+#: includes/users/template.php:557
+msgid "Admin"
+msgstr ""
+
+#: includes/users/template.php:895
+msgid "Favorited"
+msgstr ""
+
+#: includes/users/template.php:1163
+msgid "User updated."
+msgstr ""
+
+#: includes/users/template.php:1188
+msgid "You have super admin privileges."
+msgstr ""
+
+#: includes/users/template.php:1188
+msgid "This user has super admin privileges."
+msgstr ""
+
+#: includes/users/template.php:1255
+msgid "&mdash; No role for this site &mdash;"
+msgstr ""
+
+#: includes/users/template.php:1453
+msgid "You are now logged out."
+msgstr ""
+
+#: includes/users/template.php:1457
+msgid "New user registration is currently not allowed."
+msgstr ""
+
+#: includes/users/template.php:1466
+msgid "Check your e-mail for the confirmation link."
+msgstr ""
+
+#: includes/users/template.php:1471
+msgid "Check your e-mail for your new password."
+msgstr ""
+
+#: includes/users/template.php:1476
+msgid "Registration complete. Please check your e-mail."
+msgstr ""
+
+#: templates/default/bbpress/content-statistics.php:17
+msgid "Registered Users"
+msgstr ""
+
+#: templates/default/bbpress/content-statistics.php:44
+msgid "Empty Topic Tags"
+msgstr ""
+
+#: templates/default/bbpress/content-statistics.php:53
+msgid "Hidden Topics"
+msgstr ""
+
+#: templates/default/bbpress/content-statistics.php:64
+msgid "Hidden Replies"
+msgstr ""
+
+#: templates/default/bbpress/feedback-logged-in.php:13
+msgid "You are already logged in."
+msgstr ""
+
+#: templates/default/bbpress/feedback-no-access.php:13
+msgid "Private"
+msgstr ""
+
+#: templates/default/bbpress/feedback-no-access.php:16
+msgid "You do not have permission to view this forum."
+msgstr ""
+
+#: templates/default/bbpress/feedback-no-forums.php:13
+msgid "Oh bother! No forums were found here!"
+msgstr ""
+
+#: templates/default/bbpress/feedback-no-replies.php:13
+msgid "Oh bother! No replies were found here!"
+msgstr ""
+
+#: templates/default/bbpress/feedback-no-search.php:13
+msgid "Oh bother! No search results were found here!"
+msgstr ""
+
+#: templates/default/bbpress/feedback-no-topics.php:13
+msgid "Oh bother! No topics were found here!"
+msgstr ""
+
+#: templates/default/bbpress/form-anonymous.php:17
+msgid "Your information:"
+msgstr ""
+
+#: templates/default/bbpress/form-anonymous.php:22
+msgid "Name (required):"
+msgstr ""
+
+#: templates/default/bbpress/form-anonymous.php:27
+msgid "Mail (will not be published) (required):"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:35
+#: templates/default/bbpress/form-topic.php:41
+msgid "Now Editing &ldquo;%s&rdquo;"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:37
+msgid "Create New Forum in &ldquo;%s&rdquo;"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:47
+msgid ""
+"This forum is closed to new content, however your account still allows you "
+"to do so."
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:55
+#: templates/default/bbpress/form-reply.php:44
+#: templates/default/bbpress/form-topic.php:61
+msgid "Your account has the ability to post unrestricted HTML content."
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:67
+msgid "Forum Name (Maximum Length: %d):"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:82
+#: templates/default/bbpress/form-reply.php:64
+#: templates/default/bbpress/form-topic.php:90
+msgid ""
+"You may use these <abbr title=\"HyperText Markup Language\">HTML</abbr> tags "
+"and attributes:"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:91
+msgid "Forum Type:"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:123
+msgid "(No Parent)"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:138
+#: templates/default/bbpress/form-reply-move.php:72
+#: templates/default/bbpress/form-reply.php:135
+#: templates/default/bbpress/form-topic-merge.php:93
+#: templates/default/bbpress/form-topic-split.php:97
+#: templates/default/bbpress/form-topic.php:203
+msgid "Submit"
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:161
+msgid "The forum &#8216;%s&#8217; is closed to new content."
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:169
+msgid "You cannot create new forums."
+msgstr ""
+
+#: templates/default/bbpress/form-forum.php:169
+msgid "You must be logged in to create new forums."
+msgstr ""
+
+#: templates/default/bbpress/form-protected.php:14
+msgid "Protected"
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:24
+msgid "Move reply \"%s\""
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:29
+msgid ""
+"You can either make this reply a new topic with a new title, or merge it "
+"into an existing topic."
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:33
+msgid ""
+"If you choose an existing topic, replies will be ordered by the time and "
+"date they were created."
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:37
+msgid "Move Method"
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:41
+#: templates/default/bbpress/form-topic-split.php:41
+msgid "New topic in <strong>%s</strong> titled:"
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:42
+msgid "Moved: %s"
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:49
+#: templates/default/bbpress/form-topic-split.php:49
+msgid "Use an existing topic in this forum:"
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:68
+#: templates/default/bbpress/form-topic-merge.php:89
+#: templates/default/bbpress/form-topic-split.php:93
+msgid "<strong>WARNING:</strong> This process cannot be undone."
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:85
+msgid "You do not have the permissions to edit this reply!"
+msgstr ""
+
+#: templates/default/bbpress/form-reply-move.php:85
+msgid "You cannot edit this reply."
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:36
+msgid ""
+"This topic is marked as closed to new replies, however your posting "
+"capabilities still allow you to do so."
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:75
+msgid "Tags:"
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:93
+#: templates/default/bbpress/form-topic.php:164
+msgid "Notify the author of follow-up replies via email"
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:97
+#: templates/default/bbpress/form-topic.php:168
+msgid "Notify me of follow-up replies via email"
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:114
+#: templates/default/bbpress/form-topic.php:184
+msgid "Keep a log of this edit:"
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:118
+#: templates/default/bbpress/form-topic.php:188
+msgid "Optional reason for editing:"
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:158
+msgid "The topic &#8216;%s&#8217; is closed to new replies."
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:166
+#: templates/default/bbpress/form-topic.php:226
+msgid "The forum &#8216;%s&#8217; is closed to new topics and replies."
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:174
+msgid "You cannot reply to this topic."
+msgstr ""
+
+#: templates/default/bbpress/form-reply.php:174
+msgid "You must be logged in to reply to this topic."
+msgstr ""
+
+#: templates/default/bbpress/form-search.php:14
+msgid "Search for:"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:24
+msgid "Merge topic \"%s\""
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:29
+msgid ""
+"Select the topic to merge this one into. The destination topic will remain "
+"the lead topic, and this one will change into a reply."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:30
+msgid ""
+"To keep this topic as the lead, go to the other topic and use the merge tool "
+"from there instead."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:34
+msgid ""
+"All replies within both topics will be merged chronologically. The order of "
+"the merged replies is based on the time and date they were posted. If the "
+"destination topic was created after this one, it's post date will be updated "
+"to second earlier than this one."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:38
+msgid "Destination"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:42
+msgid "Merge with this topic:"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:56
+msgid "There are no other topics in this forum to merge with."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:64
+#: templates/default/bbpress/form-topic-split.php:68
+msgid "Topic Extras"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:71
+msgid "Merge topic subscribers"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:76
+msgid "Merge topic favoriters"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:81
+msgid "Merge topic tags"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:106
+#: templates/default/bbpress/form-topic-split.php:110
+msgid "You do not have the permissions to edit this topic!"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-merge.php:106
+#: templates/default/bbpress/form-topic-split.php:110
+msgid "You cannot edit this topic."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:24
+msgid "Split topic \"%s\""
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:29
+msgid ""
+"When you split a topic, you are slicing it in half starting with the reply "
+"you just selected. Choose to use that reply as a new topic with a new title, "
+"or merge those replies into an existing topic."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:33
+msgid ""
+"If you use the existing topic option, replies within both topics will be "
+"merged chronologically. The order of the merged replies is based on the time "
+"and date they were posted."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:37
+msgid "Split Method"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:42
+msgid "Split: %s"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:75
+msgid "Copy subscribers to the new topic"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:80
+msgid "Copy favoriters to the new topic"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-split.php:85
+msgid "Copy topic tags to the new topic"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:18
+msgid "Manage Tag: \"%s\""
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:22
+msgid "Rename"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:25
+msgid "Leave the slug empty to have one automatically generated."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:29
+msgid ""
+"Changing the slug affects its permalink. Any links to the old slug will stop "
+"working."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:40
+msgid "Slug:"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:45
+msgid "Update"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:62
+msgid "Merging tags together cannot be undone."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:68
+msgid "Existing tag:"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:73
+msgid ""
+"Are you sure you want to merge the \"%s\" tag into the tag you specified?"
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:91
+msgid "This does not delete your topics. Only the tag itself is deleted."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:94
+msgid "Deleting a tag cannot be undone."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:95
+msgid "Any links to this tag will no longer function."
+msgstr ""
+
+#: templates/default/bbpress/form-topic-tag.php:101
+msgid ""
+"Are you sure you want to delete the \"%s\" tag? This is permanent and cannot "
+"be undone."
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:43
+msgid "Create New Topic in &ldquo;%s&rdquo;"
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:53
+msgid ""
+"This forum is marked as closed to new topics, however your posting "
+"capabilities still allow you to do so."
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:75
+msgid "Topic Title (Maximum Length: %d):"
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:101
+msgid "Topic Tags:"
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:133
+msgid "Topic Type:"
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:145
+msgid "Topic Status:"
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:234
+msgid "You cannot create new topics."
+msgstr ""
+
+#: templates/default/bbpress/form-topic.php:234
+msgid "You must be logged in to create new topics."
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:24
+msgid "First Name"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:29
+msgid "Last Name"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:34
+msgid "Nickname"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:39
+msgid "Display Name"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:49
+#: templates/default/bbpress/form-user-edit.php:52
+msgid "Contact Info"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:74
+#: templates/default/bbpress/form-user-edit.php:77
+msgid "About Yourself"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:74
+#: templates/default/bbpress/form-user-edit.php:77
+msgid "About the user"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:82
+msgid "Biographical Info"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:90
+#: templates/default/bbpress/form-user-edit.php:93
+msgid "Account"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:115
+msgid ""
+"There is a pending email address change to <code>%1$s</code>. <a href=\"%2$s"
+"\">Cancel</a>"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:124
+msgid "New Password"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:127
+msgid ""
+"If you would like to change the password type a new one. Otherwise leave "
+"this blank."
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:130
+msgid "Type your new password again."
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:133
+msgid ""
+"Your password should be at least ten characters long. Use upper and lower "
+"case letters, numbers, and symbols to make it even stronger."
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:143
+#: templates/default/bbpress/form-user-edit.php:146
+msgid "User Role"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:153
+msgid "Network Role"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:156
+msgid "Grant this user super admin privileges for the Network."
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:178
+msgid "Update Profile"
+msgstr ""
+
+#: templates/default/bbpress/form-user-edit.php:178
+msgid "Update User"
+msgstr ""
+
+#: templates/default/bbpress/form-user-login.php:28
+msgid "Keep me signed in"
+msgstr ""
+
+#: templates/default/bbpress/form-user-lost-pass.php:18
+msgid "Username or Email"
+msgstr ""
+
+#: templates/default/bbpress/form-user-lost-pass.php:27
+msgid "Reset My Password"
+msgstr ""
+
+#: templates/default/bbpress/form-user-register.php:14
+msgid "Create an Account"
+msgstr ""
+
+#: templates/default/bbpress/form-user-register.php:17
+msgid "Your username must be unique, and cannot be changed later."
+msgstr ""
+
+#: templates/default/bbpress/form-user-register.php:18
+msgid ""
+"We use your email address to email you a secure password and verify your "
+"account."
+msgstr ""
+
+#: templates/default/bbpress/form-user-roles.php:13
+msgid "Blog Role"
+msgstr ""
+
+#: templates/default/bbpress/loop-search-forum.php:16
+msgid "Last updated %s"
+msgstr ""
+
+#: templates/default/bbpress/loop-search-forum.php:26
+msgid "Forum: "
+msgstr ""
+
+#: templates/default/bbpress/loop-search-reply.php:24
+msgid "In reply to: "
+msgstr ""
+
+#: templates/default/bbpress/loop-search-topic.php:26
+msgid "Topic: "
+msgstr ""
+
+#: templates/default/bbpress/loop-search-topic.php:33
+msgid "in group forum "
+msgstr ""
+
+#: templates/default/bbpress/loop-search-topic.php:37
+msgid "in forum "
+msgstr ""
+
+#: templates/default/bbpress/loop-search.php:22
+#: templates/default/bbpress/loop-search.php:44
+msgid "Search Results"
+msgstr ""
+
+#: templates/default/bbpress/loop-single-reply.php:21
+msgid "in reply to: "
+msgstr ""
+
+#: templates/default/bbpress/loop-single-topic.php:60
+msgid "Started by: %1$s"
+msgstr ""
+
+#: templates/default/bbpress/loop-single-topic.php:68
+msgid "in: <a href=\"%1$s\">%2$s</a>"
+msgstr ""
+
+#: templates/default/bbpress/user-details.php:29
+msgid "%s's Profile"
+msgstr ""
+
+#: templates/default/bbpress/user-details.php:29
+#: templates/default/bbpress/user-profile.php:15
+msgid "Profile"
+msgstr ""
+
+#: templates/default/bbpress/user-details.php:35
+msgid "%s's Topics Started"
+msgstr ""
+
+#: templates/default/bbpress/user-details.php:41
+msgid "%s's Replies Created"
+msgstr ""
+
+#: templates/default/bbpress/user-details.php:48
+msgid "%s's Favorites"
+msgstr ""
+
+#: templates/default/bbpress/user-details.php:58
+msgid "%s's Subscriptions"
+msgstr ""
+
+#: templates/default/bbpress/user-favorites.php:15
+msgid "Favorite Forum Topics"
+msgstr ""
+
+#: templates/default/bbpress/user-favorites.php:28
+msgid "You currently have no favorite topics."
+msgstr ""
+
+#: templates/default/bbpress/user-favorites.php:28
+msgid "This user has no favorite topics."
+msgstr ""
+
+#: templates/default/bbpress/user-profile.php:24
+msgid "Forum Role: %s"
+msgstr ""
+
+#: templates/default/bbpress/user-profile.php:25
+msgid "Topics Started: %s"
+msgstr ""
+
+#: templates/default/bbpress/user-profile.php:26
+msgid "Replies Created: %s"
+msgstr ""
+
+#: templates/default/bbpress/user-replies-created.php:15
+msgid "Forum Replies Created"
+msgstr ""
+
+#: templates/default/bbpress/user-replies-created.php:28
+msgid "You have not replied to any topics."
+msgstr ""
+
+#: templates/default/bbpress/user-replies-created.php:28
+msgid "This user has not replied to any topics."
+msgstr ""
+
+#: templates/default/bbpress/user-subscriptions.php:19
+msgid "Subscribed Forums"
+msgstr ""
+
+#: templates/default/bbpress/user-subscriptions.php:28
+msgid "You are not currently subscribed to any forums."
+msgstr ""
+
+#: templates/default/bbpress/user-subscriptions.php:28
+msgid "This user is not currently subscribed to any forums."
+msgstr ""
+
+#: templates/default/bbpress/user-subscriptions.php:47
+msgid "You are not currently subscribed to any topics."
+msgstr ""
+
+#: templates/default/bbpress/user-subscriptions.php:47
+msgid "This user is not currently subscribed to any topics."
+msgstr ""
+
+#: templates/default/bbpress/user-topics-created.php:15
+msgid "Forum Topics Started"
+msgstr ""
+
+#: templates/default/bbpress/user-topics-created.php:28
+msgid "You have not created any topics."
+msgstr ""
+
+#: templates/default/bbpress/user-topics-created.php:28
+msgid "This user has not created any topics."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:248
+#: templates/default/bbpress-functions.php:257
+msgid "Something went wrong. Refresh your browser and try again."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:285
+#: templates/default/bbpress-functions.php:421
+msgid "Subscriptions are no longer active."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:290
+msgid "Please login to subscribe to this forum."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:299
+#: templates/default/bbpress-functions.php:367
+#: templates/default/bbpress-functions.php:435
+msgid "You do not have permission to do this."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:307
+msgid "The forum could not be found."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:312
+#: templates/default/bbpress-functions.php:380
+#: templates/default/bbpress-functions.php:448
+msgid "Are you sure you meant to do that?"
+msgstr ""
+
+#: templates/default/bbpress-functions.php:320
+#: templates/default/bbpress-functions.php:388
+#: templates/default/bbpress-functions.php:456
+msgid "The request was unsuccessful. Please try again."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:353
+msgid "Favorites are no longer active."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:358
+msgid "Please login to make this topic a favorite."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:375
+#: templates/default/bbpress-functions.php:443
+msgid "The topic could not be found."
+msgstr ""
+
+#: templates/default/bbpress-functions.php:426
+msgid "Please login to subscribe to this topic."
+msgstr ""
+
+#: templates/default/extras/page-forum-statistics.php:22
+msgid "<p>Here are the statistics and popular topics of our forums.</p>"
+msgstr ""
+
+#: templates/default/extras/page-topic-tags.php:22
+msgid ""
+"<p>This is a collection of tags that are currently popular on our forums.</p>"
+msgstr ""
+
+#. Plugin Name of the plugin/theme
+msgid "bbPress"
+msgstr ""
+
+#. #-#-#-#-#  plugin.pot (bbPress 2.5.4)  #-#-#-#-#
+#. Plugin URI of the plugin/theme
+#. #-#-#-#-#  plugin.pot (bbPress 2.5.4)  #-#-#-#-#
+#. Author URI of the plugin/theme
+msgid "http://bbpress.org"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid "bbPress is forum software with a twist from the creators of WordPress."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "The bbPress Community"
+msgstr ""
Index: /tags/2.5.4/languages/index.php
===================================================================
--- /tags/2.5.4/languages/index.php	(revision 5382)
+++ /tags/2.5.4/languages/index.php	(revision 5382)
@@ -0,0 +1,7 @@
+<?php
+
+/**
+ * Do not put custom translations here. They will be deleted on bbPress updates.
+ *
+ * Keep custom bbPress translations in /wp-content/languages/bbpress/
+ */
Index: /tags/2.5.4/license.txt
===================================================================
--- /tags/2.5.4/license.txt	(revision 5382)
+++ /tags/2.5.4/license.txt	(revision 5382)
@@ -0,0 +1,281 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+              51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
Index: /tags/2.5.4/readme.txt
===================================================================
--- /tags/2.5.4/readme.txt	(revision 5382)
+++ /tags/2.5.4/readme.txt	(revision 5382)
@@ -0,0 +1,261 @@
+=== bbPress ===
+Contributors: matt, johnjamesjacoby, jmdodd, netweb
+Tags: forums, discussion, support, theme, akismet, multisite
+Requires at least: 3.6
+Tested up to: 3.9
+Stable tag: 2.5.4
+License: GPLv2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+
+bbPress is forum software, made the WordPress way
+
+== Description ==
+
+Have you ever been frustrated with forum or bulletin board software that was slow, bloated and always got your server hacked? bbPress is focused on ease of integration, ease of use, web standards, and speed.
+
+We're keeping things as small and light as possible while still allowing for great add-on features through WordPress's extensive plugin system. What does all that mean? bbPress is lean, mean, and ready to take on any job you throw at it.
+
+== Installation ==
+
+= From your WordPress dashboard =
+
+1. Visit 'Plugins > Add New'
+2. Search for 'bbPress'
+3. Activate bbPress from your Plugins page. (You'll be greeted with a Welcome page.)
+4. Visit 'Forums > Add New' and create some forums. (You can always delete these later.)
+5a. If you have pretty permalinks enabled, visit yourdomain.com/forums.
+5b. If you do not have pretty permalinks enabled, visit yourdomain.com?post_type=forum
+
+= From WordPress.org =
+
+1. Download bbPress.
+2. Upload the 'bbpress' directory to your '/wp-content/plugins/' directory, using your favorite method (ftp, sftp, scp, etc...)
+3. Activate bbPress from your Plugins page. (You'll be greeted with a Welcome page.)
+4. Visit 'Forums > Add New' and create some forums. (You can always delete these later.)
+5a. If you have pretty permalinks enabled, visit yourdomain.com/forums.
+5b. If you do not have pretty permalinks enabled, visit yourdomain.com?post_type=forum
+
+= Extra =
+
+1. Visit 'Settings > Forums' and adjust your configuration.
+2. Adjust the CSS of your theme as needed, to make everything pretty.
+
+== Changelog ==
+
+= 2.5.4 =
+* Fix reply editing causing polluted hierarchy
+* Add tool for repairing reply positions within topics
+* Improved custom slug and displayed user field sanitization
+* Improved SSL support when relying on theme compatibility
+
+= 2.5.3 =
+* WordPress 3.8 support (dashicons, new color schemes)
+* Fix dropdown selects in settings pages
+* Fix accidental topic subscription removal on reply form
+* Fix poor grammar in profile title element
+* Fix admin area SSL support
+
+= 2.5.2 =
+* Fix BuddyPress (1.9.1) Notification integration
+
+= 2.5.1 =
+* Updated subscriptions setting description
+* Fix forum subscriptions not appearing on profiles for some users
+* Allow links to have targets
+* Improve Windows compatibility
+
+= 2.5 =
+* Added forum subscriptions
+* Added importers for AEF, Drupal, FluxBB, Kunena Forums (Joomla), MyBB, Phorum, PHPFox, PHPWind, PunBB, SMF, Xenforo and XMB
+* Added BuddyPress Notifications integration
+* Added ability to enqueue scripts and styles in the template stack
+* Fix various existing importer scripts
+* Fix forum visibility meta saving
+* Fix Akismet anonymous user meta checking
+* Fix inconsistent bbp_dropdown() results
+* Fix topic and reply ping-status inconsistencies
+
+= 2.4.1 =
+* Fix forum status saving
+* Fix widget settings saving
+* Fix custom wp_title compatibility
+* Fix search results custom permalink compatibility
+* Fix custom user topics & replies pages
+* Fix hierarchical reply handling in converter
+
+= 2.4 =
+* Added hierarchical reply support
+* Added ability to disable forum search
+* Reorganized settings page
+* Improved rewrite rules
+* Improved responsive CSS
+* Improved code posting
+* Improved user capability integration
+* Improved cache getting and setting
+* Audit strict type comparisons
+* Audit GlotPress string escaping
+* Audit title attribute usage
+* Audit WordPress core function usage
+* General code clean-up
+
+= 2.3.2 =
+* Improved posting of preformatted code
+* Improved theme compatibility CSS
+* Improved BuddyPress Activity Streams integration
+
+= 2.3.1 =
+* Improved posting of preformatted code
+* Fix deleting of post cache group
+* Fix moderators not having view_trash capability
+
+= 2.3 =
+* Added forum search functionality
+* Improved BuddyPress Group Forums integration
+* Improved allowed tags in topics and replies
+* Added template stack support to theme compatability
+* Added more forum migration options
+
+= 2.2.4 =
+* Prepare converter queries
+* Improve validation and sanitization of form values
+
+= 2.2.3 =
+* Improve compatibility with some themes
+* Fix integration with BuddyPress Group Forums
+* Fix BuddyPress Activity Stream integration
+
+= 2.2.2 =
+* RTL and i18n fixes
+* Improved user profile theme compatibility
+* Fixed incorrect link in credits page
+* Fixed admin area JS issues related to topic suggest
+* Fixed template part reference in extras user edit template
+
+= 2.2.1 =
+* Fix role mapping for non-WordPress roles
+* Fix issue with private forums being blocked
+* Allow moderators to see hidden forums
+
+= 2.2 =
+* Improved user roles and capabilities
+* Improved theme compatibility
+* Improved BuddyPress Group Forums integration
+* Improved forums convertion tool
+* Improved forums tools and settings
+* Improved multisite support
+* Added What's New and Credits pages
+* WordPress 3.5 and BuddyPress 1.7 ready
+
+= 2.1.2 =
+* Fixed admin-side help verbiage
+* Fixed reply height CSS
+* Fixed password converter
+* Fixed child post trash and delete functions
+
+= 2.1.1 =
+* Fixed Invision, phpBB, and vBulletin importers
+* Fixed private/hidden forum bugs
+* Fixed topic split meta values
+* Fixed theme compatibility logic error
+* Fixed role mask issues for shared user installs
+* Fixed missing function cruft
+* Fixed missing filter on displayed user fields
+
+= 2.1 =
+* WordPress 3.4 compatibility
+* Deprecate $bbp global, use bbpress() singleton
+* Private forums now visible to registered users
+* Updated forum converter
+* Topic and reply edits now ran through Akismet
+* Fixed Akismet edit bug
+* Fixed Widgets nooping globals
+* Fixed translation load order
+* Fixed user-edit bugs
+* Fixed settings screen regressions
+* Improved post cache invalidation
+* Improved admin-side nonce checks
+* Improved admin settings API
+* Improved bbPress 1.1 converter
+* Improved BuddyPress integration
+* Improved Theme-Compatibility
+* Improved template coverage
+* Improved query performance
+* Improved breadcrumb behavior
+* Improved multisite integration
+* Improved code clarity
+* Improved RTL styling
+* Added 2x menu icons for HiDPI displays
+* Added fancy editor support
+* Added fallback theme picker
+* Added tools for importing, resetting, and removing
+
+= 2.0 =
+* Released on September 21, 2011
+
+= 2.0-rc-5 =
+* Fixed Genesis incompatibilities
+* Fixed BuddyPress activity stream issues
+* Fixed Subscription email sending issues
+* Fixed Theme Compat display issues for some themes
+* Improved Theme Compat class
+* More future proofing internal API's
+
+= 2.0-rc-4 =
+* BuddyPress @mention integration
+* Improved Akismet user agent handling
+* Added blacklist_keys support
+* Fixed spam/deleted user handling
+* Updated green admin color scheme for WordPress 3.2
+* Added actions to topic/reply forms
+* Improved support for future ajaxification
+
+= 2.0-rc-3 =
+* Fixed activation/deactivation
+* Added Forum Participant role for multisite use
+
+= 2.0-rc-2 =
+* BuddyPress activity action integration
+* Multisite integration
+* Fixed a bushel of bugs
+* Fixed tag pagination again
+* Fixed ajax priority loading
+
+= 2.0-rc-1 =
+* Fixed tag pagination
+* Broke tag pagination
+* Squashed a bunch of bugs
+
+= 2.0-beta-3b =
+* Fix regression in forum index theme compatibility template
+* Audit usage of get strings for moderator level and above users
+
+= 2.0-beta-3 =
+* Akismet integration
+* Fixes replies within wp-admin
+* Fixes reply notification links
+* Fixes inconsistent breadcrumb behavior
+* Fixes theme compatibility issues
+* Fixes archive and page conflicts
+* Improvements to unpretty permalink support
+* Improvements to importer
+* Improvements to multisite support
+* Normalize theme, shortcodes, and template parts
+* Add humans.txt
+* Add empty index.php files to prevent snooping
+* Add max length to topic titles (default 80 chars)
+
+= 2.0-beta-2 =
+* GlotPress integration
+* Fixes Forum archive bug
+* Fixes and improvements to importer
+* Adds home link support to breadcrumb
+* Improvements to Theme Compatibility
+* Numerous template and CSS improvements
+* RTL support
+* Improved multisite support
+* Add filters for future anti-spam support
+* Add missing breadcrumbs to various template files
+* Topic/reply trash fixes
+
+= 2.0-beta-1 =
+* In development
Index: /tags/2.5.4/templates/default/bbpress-functions.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress-functions.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress-functions.php	(revision 5382)
@@ -0,0 +1,470 @@
+<?php
+
+/**
+ * Functions of bbPress's Default theme
+ *
+ * @package bbPress
+ * @subpackage BBP_Theme_Compat
+ * @since bbPress (r3732)
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Theme Setup ***************************************************************/
+
+if ( !class_exists( 'BBP_Default' ) ) :
+
+/**
+ * Loads bbPress Default Theme functionality
+ *
+ * This is not a real theme by WordPress standards, and is instead used as the
+ * fallback for any WordPress theme that does not have bbPress templates in it.
+ *
+ * To make your custom theme bbPress compatible and customize the templates, you
+ * can copy these files into your theme without needing to merge anything
+ * together; bbPress should safely handle the rest.
+ *
+ * See @link BBP_Theme_Compat() for more.
+ *
+ * @since bbPress (r3732)
+ *
+ * @package bbPress
+ * @subpackage BBP_Theme_Compat
+ */
+class BBP_Default extends BBP_Theme_Compat {
+
+	/** Functions *************************************************************/
+
+	/**
+	 * The main bbPress (Default) Loader
+	 *
+	 * @since bbPress (r3732)
+	 *
+	 * @uses BBP_Default::setup_globals()
+	 * @uses BBP_Default::setup_actions()
+	 */
+	public function __construct( $properties = array() ) {
+
+		parent::__construct( bbp_parse_args( $properties, array(
+			'id'      => 'default',
+			'name'    => __( 'bbPress Default', 'bbpress' ),
+			'version' => bbp_get_version(),
+			'dir'     => trailingslashit( bbpress()->themes_dir . 'default' ),
+			'url'     => trailingslashit( bbpress()->themes_url . 'default' ),
+		), 'default_theme' ) );
+
+		$this->setup_actions();
+	}
+
+	/**
+	 * Setup the theme hooks
+	 *
+	 * @since bbPress (r3732)
+	 * @access private
+	 *
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_actions() {
+
+		/** Scripts ***********************************************************/
+
+		add_action( 'bbp_enqueue_scripts',         array( $this, 'enqueue_styles'          ) ); // Enqueue theme CSS
+		add_action( 'bbp_enqueue_scripts',         array( $this, 'enqueue_scripts'         ) ); // Enqueue theme JS
+		add_filter( 'bbp_enqueue_scripts',         array( $this, 'localize_topic_script'   ) ); // Enqueue theme script localization
+		add_action( 'bbp_ajax_favorite',           array( $this, 'ajax_favorite'           ) ); // Handles the topic ajax favorite/unfavorite
+		add_action( 'bbp_ajax_subscription',       array( $this, 'ajax_subscription'       ) ); // Handles the topic ajax subscribe/unsubscribe
+		add_action( 'bbp_ajax_forum_subscription', array( $this, 'ajax_forum_subscription' ) ); // Handles the forum ajax subscribe/unsubscribe
+
+		/** Template Wrappers *************************************************/
+
+		add_action( 'bbp_before_main_content',  array( $this, 'before_main_content'   ) ); // Top wrapper HTML
+		add_action( 'bbp_after_main_content',   array( $this, 'after_main_content'    ) ); // Bottom wrapper HTML
+
+		/** Override **********************************************************/
+
+		do_action_ref_array( 'bbp_theme_compat_actions', array( &$this ) );
+	}
+
+	/**
+	 * Inserts HTML at the top of the main content area to be compatible with
+	 * the Twenty Twelve theme.
+	 *
+	 * @since bbPress (r3732)
+	 */
+	public function before_main_content() {
+	?>
+
+		<div id="bbp-container">
+			<div id="bbp-content" role="main">
+
+	<?php
+	}
+
+	/**
+	 * Inserts HTML at the bottom of the main content area to be compatible with
+	 * the Twenty Twelve theme.
+	 *
+	 * @since bbPress (r3732)
+	 */
+	public function after_main_content() {
+	?>
+
+			</div><!-- #bbp-content -->
+		</div><!-- #bbp-container -->
+
+	<?php
+	}
+
+	/**
+	 * Load the theme CSS
+	 *
+	 * @since bbPress (r3732)
+	 *
+	 * @uses wp_enqueue_style() To enqueue the styles
+	 */
+	public function enqueue_styles() {
+
+		// Setup styles array
+		$styles = array();
+
+		// LTR
+		$styles['bbp-default'] = array(
+			'file'         => 'css/bbpress.css',
+			'dependencies' => array()
+		);
+
+		// RTL helpers
+		if ( is_rtl() ) {
+			$styles['bbp-default-rtl'] = array(
+				'file'         => 'css/bbpress-rtl.css',
+				'dependencies' => array( 'bbp-default' )
+			);
+		}
+
+		// Filter the scripts
+		$styles = apply_filters( 'bbp_default_styles', $styles );
+
+		// Enqueue the styles
+		foreach ( $styles as $handle => $attributes ) {
+			bbp_enqueue_style( $handle, $attributes['file'], $attributes['dependencies'], $this->version, 'screen' );
+		}
+	}
+
+	/**
+	 * Enqueue the required Javascript files
+	 *
+	 * @since bbPress (r3732)
+	 *
+	 * @uses bbp_is_single_forum() To check if it's the forum page
+	 * @uses bbp_is_single_topic() To check if it's the topic page
+	 * @uses bbp_thread_replies() To check if threaded replies are enabled
+	 * @uses bbp_is_single_user_edit() To check if it's the profile edit page
+	 * @uses wp_enqueue_script() To enqueue the scripts
+	 */
+	public function enqueue_scripts() {
+
+		// Setup scripts array
+		$scripts = array();
+
+		// Always pull in jQuery for TinyMCE shortcode usage
+		if ( bbp_use_wp_editor() ) {
+			$scripts['bbpress-editor'] = array(
+				'file'         => 'js/editor.js',
+				'dependencies' => array( 'jquery' )
+			);
+		}
+
+		// Forum-specific scripts
+		if ( bbp_is_single_forum() ) {
+			$scripts['bbpress-forum'] = array(
+				'file'         => 'js/forum.js',
+				'dependencies' => array( 'jquery' )
+			);
+		}
+
+		// Topic-specific scripts
+		if ( bbp_is_single_topic() ) {
+
+			// Topic favorite/unsubscribe
+			$scripts['bbpress-topic'] = array(
+				'file'         => 'js/topic.js',
+				'dependencies' => array( 'jquery' )
+			);
+
+			// Hierarchical replies
+			if ( bbp_thread_replies() ) {
+				$scripts['bbpress-reply'] = array(
+					'file'         => 'js/reply.js',
+					'dependencies' => array( 'jquery' )
+				);
+			}
+		}
+
+		// User Profile edit
+		if ( bbp_is_single_user_edit() ) {
+			$scripts['bbpress-user'] = array(
+				'file'         => 'js/user.js',
+				'dependencies' => array( 'user-query' )
+			);
+		}
+
+		// Filter the scripts
+		$scripts = apply_filters( 'bbp_default_scripts', $scripts );
+
+		// Enqueue the scripts
+		foreach ( $scripts as $handle => $attributes ) {
+			bbp_enqueue_script( $handle, $attributes['file'], $attributes['dependencies'], $this->version, 'screen' );
+		}
+	}
+
+	/**
+	 * Load localizations for topic script
+	 *
+	 * These localizations require information that may not be loaded even by init.
+	 *
+	 * @since bbPress (r3732)
+	 *
+	 * @uses bbp_is_single_forum() To check if it's the forum page
+	 * @uses bbp_is_single_topic() To check if it's the topic page
+	 * @uses is_user_logged_in() To check if user is logged in
+	 * @uses bbp_get_current_user_id() To get the current user id
+	 * @uses bbp_get_forum_id() To get the forum id
+	 * @uses bbp_get_topic_id() To get the topic id
+	 * @uses bbp_get_favorites_permalink() To get the favorites permalink
+	 * @uses bbp_is_user_favorite() To check if the topic is in user's favorites
+	 * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+	 * @uses bbp_is_user_subscribed() To check if the user is subscribed to topic
+	 * @uses bbp_get_topic_permalink() To get the topic permalink
+	 * @uses wp_localize_script() To localize the script
+	 */
+	public function localize_topic_script() {
+
+		// Single forum
+		if ( bbp_is_single_forum() ) {
+			wp_localize_script( 'bbpress-forum', 'bbpForumJS', array(
+				'bbp_ajaxurl'        => bbp_get_ajax_url(),
+				'generic_ajax_error' => __( 'Something went wrong. Refresh your browser and try again.', 'bbpress' ),
+				'is_user_logged_in'  => is_user_logged_in(),
+				'subs_nonce'         => wp_create_nonce( 'toggle-subscription_' . get_the_ID() )
+			) );
+
+		// Single topic
+		} elseif ( bbp_is_single_topic() ) {
+			wp_localize_script( 'bbpress-topic', 'bbpTopicJS', array(
+				'bbp_ajaxurl'        => bbp_get_ajax_url(),
+				'generic_ajax_error' => __( 'Something went wrong. Refresh your browser and try again.', 'bbpress' ),
+				'is_user_logged_in'  => is_user_logged_in(),
+				'fav_nonce'          => wp_create_nonce( 'toggle-favorite_' .     get_the_ID() ),
+				'subs_nonce'         => wp_create_nonce( 'toggle-subscription_' . get_the_ID() )
+			) );
+		}
+	}
+
+	/**
+	 * AJAX handler to Subscribe/Unsubscribe a user from a forum
+	 *
+	 * @since bbPress (r5155)
+	 *
+	 * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+	 * @uses bbp_is_user_logged_in() To check if user is logged in
+	 * @uses bbp_get_current_user_id() To get the current user id
+	 * @uses current_user_can() To check if the current user can edit the user
+	 * @uses bbp_get_forum() To get the forum
+	 * @uses wp_verify_nonce() To verify the nonce
+	 * @uses bbp_is_user_subscribed() To check if the forum is in user's subscriptions
+	 * @uses bbp_remove_user_subscriptions() To remove the forum from user's subscriptions
+	 * @uses bbp_add_user_subscriptions() To add the forum from user's subscriptions
+	 * @uses bbp_ajax_response() To return JSON
+	 */
+	public function ajax_forum_subscription() {
+
+		// Bail if subscriptions are not active
+		if ( ! bbp_is_subscriptions_active() ) {
+			bbp_ajax_response( false, __( 'Subscriptions are no longer active.', 'bbpress' ), 300 );
+		}
+
+		// Bail if user is not logged in
+		if ( ! is_user_logged_in() ) {
+			bbp_ajax_response( false, __( 'Please login to subscribe to this forum.', 'bbpress' ), 301 );
+		}
+
+		// Get user and forum data
+		$user_id = bbp_get_current_user_id();
+		$id      = intval( $_POST['id'] );
+
+		// Bail if user cannot add favorites for this user
+		if ( ! current_user_can( 'edit_user', $user_id ) ) {
+			bbp_ajax_response( false, __( 'You do not have permission to do this.', 'bbpress' ), 302 );
+		}
+
+		// Get the forum
+		$forum = bbp_get_forum( $id );
+
+		// Bail if forum cannot be found
+		if ( empty( $forum ) ) {
+			bbp_ajax_response( false, __( 'The forum could not be found.', 'bbpress' ), 303 );
+		}
+
+		// Bail if user did not take this action
+		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'toggle-subscription_' . $forum->ID ) ) {
+			bbp_ajax_response( false, __( 'Are you sure you meant to do that?', 'bbpress' ), 304 );
+		}
+
+		// Take action
+		$status = bbp_is_user_subscribed( $user_id, $forum->ID ) ? bbp_remove_user_subscription( $user_id, $forum->ID ) : bbp_add_user_subscription( $user_id, $forum->ID );
+
+		// Bail if action failed
+		if ( empty( $status ) ) {
+			bbp_ajax_response( false, __( 'The request was unsuccessful. Please try again.', 'bbpress' ), 305 );
+		}
+
+		// Put subscription attributes in convenient array
+		$attrs = array(
+			'forum_id' => $forum->ID,
+			'user_id'  => $user_id
+		);
+
+		// Action succeeded
+		bbp_ajax_response( true, bbp_get_forum_subscription_link( $attrs, $user_id, false ), 200 );
+	}
+
+	/**
+	 * AJAX handler to add or remove a topic from a user's favorites
+	 *
+	 * @since bbPress (r3732)
+	 *
+	 * @uses bbp_is_favorites_active() To check if favorites are active
+	 * @uses bbp_is_user_logged_in() To check if user is logged in
+	 * @uses bbp_get_current_user_id() To get the current user id
+	 * @uses current_user_can() To check if the current user can edit the user
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses wp_verify_nonce() To verify the nonce & check the referer
+	 * @uses bbp_is_user_favorite() To check if the topic is user's favorite
+	 * @uses bbp_remove_user_favorite() To remove the topic from user's favorites
+	 * @uses bbp_add_user_favorite() To add the topic from user's favorites
+	 * @uses bbp_ajax_response() To return JSON
+	 */
+	public function ajax_favorite() {
+
+		// Bail if favorites are not active
+		if ( ! bbp_is_favorites_active() ) {
+			bbp_ajax_response( false, __( 'Favorites are no longer active.', 'bbpress' ), 300 );
+		}
+
+		// Bail if user is not logged in
+		if ( ! is_user_logged_in() ) {
+			bbp_ajax_response( false, __( 'Please login to make this topic a favorite.', 'bbpress' ), 301 );
+		}
+
+		// Get user and topic data
+		$user_id = bbp_get_current_user_id();
+		$id      = !empty( $_POST['id'] ) ? intval( $_POST['id'] ) : 0;
+
+		// Bail if user cannot add favorites for this user
+		if ( ! current_user_can( 'edit_user', $user_id ) ) {
+			bbp_ajax_response( false, __( 'You do not have permission to do this.', 'bbpress' ), 302 );
+		}
+
+		// Get the topic
+		$topic = bbp_get_topic( $id );
+
+		// Bail if topic cannot be found
+		if ( empty( $topic ) ) {
+			bbp_ajax_response( false, __( 'The topic could not be found.', 'bbpress' ), 303 );
+		}
+
+		// Bail if user did not take this action
+		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'toggle-favorite_' . $topic->ID ) ) {
+			bbp_ajax_response( false, __( 'Are you sure you meant to do that?', 'bbpress' ), 304 );
+		}
+
+		// Take action
+		$status = bbp_is_user_favorite( $user_id, $topic->ID ) ? bbp_remove_user_favorite( $user_id, $topic->ID ) : bbp_add_user_favorite( $user_id, $topic->ID );
+
+		// Bail if action failed
+		if ( empty( $status ) ) {
+			bbp_ajax_response( false, __( 'The request was unsuccessful. Please try again.', 'bbpress' ), 305 );
+		}
+
+		// Put subscription attributes in convenient array
+		$attrs = array(
+			'topic_id' => $topic->ID,
+			'user_id'  => $user_id
+		);
+
+		// Action succeeded
+		bbp_ajax_response( true, bbp_get_user_favorites_link( $attrs, $user_id, false ), 200 );
+	}
+
+	/**
+	 * AJAX handler to Subscribe/Unsubscribe a user from a topic
+	 *
+	 * @since bbPress (r3732)
+	 *
+	 * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
+	 * @uses bbp_is_user_logged_in() To check if user is logged in
+	 * @uses bbp_get_current_user_id() To get the current user id
+	 * @uses current_user_can() To check if the current user can edit the user
+	 * @uses bbp_get_topic() To get the topic
+	 * @uses wp_verify_nonce() To verify the nonce
+	 * @uses bbp_is_user_subscribed() To check if the topic is in user's subscriptions
+	 * @uses bbp_remove_user_subscriptions() To remove the topic from user's subscriptions
+	 * @uses bbp_add_user_subscriptions() To add the topic from user's subscriptions
+	 * @uses bbp_ajax_response() To return JSON
+	 */
+	public function ajax_subscription() {
+
+		// Bail if subscriptions are not active
+		if ( ! bbp_is_subscriptions_active() ) {
+			bbp_ajax_response( false, __( 'Subscriptions are no longer active.', 'bbpress' ), 300 );
+		}
+
+		// Bail if user is not logged in
+		if ( ! is_user_logged_in() ) {
+			bbp_ajax_response( false, __( 'Please login to subscribe to this topic.', 'bbpress' ), 301 );
+		}
+
+		// Get user and topic data
+		$user_id = bbp_get_current_user_id();
+		$id      = intval( $_POST['id'] );
+
+		// Bail if user cannot add favorites for this user
+		if ( ! current_user_can( 'edit_user', $user_id ) ) {
+			bbp_ajax_response( false, __( 'You do not have permission to do this.', 'bbpress' ), 302 );
+		}
+
+		// Get the topic
+		$topic = bbp_get_topic( $id );
+
+		// Bail if topic cannot be found
+		if ( empty( $topic ) ) {
+			bbp_ajax_response( false, __( 'The topic could not be found.', 'bbpress' ), 303 );
+		}
+
+		// Bail if user did not take this action
+		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'toggle-subscription_' . $topic->ID ) ) {
+			bbp_ajax_response( false, __( 'Are you sure you meant to do that?', 'bbpress' ), 304 );
+		}
+
+		// Take action
+		$status = bbp_is_user_subscribed( $user_id, $topic->ID ) ? bbp_remove_user_subscription( $user_id, $topic->ID ) : bbp_add_user_subscription( $user_id, $topic->ID );
+
+		// Bail if action failed
+		if ( empty( $status ) ) {
+			bbp_ajax_response( false, __( 'The request was unsuccessful. Please try again.', 'bbpress' ), 305 );
+		}
+
+		// Put subscription attributes in convenient array
+		$attrs = array(
+			'topic_id' => $topic->ID,
+			'user_id'  => $user_id
+		);
+
+		// Action succeeded
+		bbp_ajax_response( true, bbp_get_user_subscribe_link( $attrs, $user_id, false ), 200 );
+	}
+}
+new BBP_Default();
+endif;
Index: /tags/2.5.4/templates/default/bbpress/content-archive-forum.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-archive-forum.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-archive-forum.php	(revision 5382)
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Archive Forum Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php if ( bbp_allow_search() ) : ?>
+
+		<div class="bbp-search-form">
+
+			<?php bbp_get_template_part( 'form', 'search' ); ?>
+
+		</div>
+
+	<?php endif; ?>
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php bbp_forum_subscription_link(); ?>
+
+	<?php do_action( 'bbp_template_before_forums_index' ); ?>
+
+	<?php if ( bbp_has_forums() ) : ?>
+
+		<?php bbp_get_template_part( 'loop',     'forums'    ); ?>
+
+	<?php else : ?>
+
+		<?php bbp_get_template_part( 'feedback', 'no-forums' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_template_after_forums_index' ); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/content-archive-topic.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-archive-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-archive-topic.php	(revision 5382)
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Archive Topic Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php if ( bbp_allow_search() ) : ?>
+
+		<div class="bbp-search-form">
+
+			<?php bbp_get_template_part( 'form', 'search' ); ?>
+
+		</div>
+
+	<?php endif; ?>
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php if ( bbp_is_topic_tag() ) bbp_topic_tag_description(); ?>
+
+	<?php do_action( 'bbp_template_before_topics_index' ); ?>
+
+	<?php if ( bbp_has_topics() ) : ?>
+
+		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+		<?php bbp_get_template_part( 'loop',       'topics'    ); ?>
+
+		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+	<?php else : ?>
+
+		<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_template_after_topics_index' ); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/content-search.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-search.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-search.php	(revision 5382)
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * Search Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php bbp_set_query_name( bbp_get_search_rewrite_id() ); ?>
+
+	<?php do_action( 'bbp_template_before_search' ); ?>
+
+	<?php if ( bbp_has_search_results() ) : ?>
+
+		 <?php bbp_get_template_part( 'pagination', 'search' ); ?>
+
+		 <?php bbp_get_template_part( 'loop',       'search' ); ?>
+
+		 <?php bbp_get_template_part( 'pagination', 'search' ); ?>
+
+	<?php elseif ( bbp_get_search_terms() ) : ?>
+
+		 <?php bbp_get_template_part( 'feedback',   'no-search' ); ?>
+
+	<?php else : ?>
+
+		<?php bbp_get_template_part( 'form', 'search' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_template_after_search_results' ); ?>
+
+</div>
+
Index: /tags/2.5.4/templates/default/bbpress/content-single-forum.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-single-forum.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-single-forum.php	(revision 5382)
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Single Forum Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php bbp_forum_subscription_link(); ?>
+
+	<?php do_action( 'bbp_template_before_single_forum' ); ?>
+
+	<?php if ( post_password_required() ) : ?>
+
+		<?php bbp_get_template_part( 'form', 'protected' ); ?>
+
+	<?php else : ?>
+
+		<?php bbp_single_forum_description(); ?>
+
+		<?php if ( bbp_has_forums() ) : ?>
+
+			<?php bbp_get_template_part( 'loop', 'forums' ); ?>
+
+		<?php endif; ?>
+
+		<?php if ( !bbp_is_forum_category() && bbp_has_topics() ) : ?>
+
+			<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+			<?php bbp_get_template_part( 'loop',       'topics'    ); ?>
+
+			<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+			<?php bbp_get_template_part( 'form',       'topic'     ); ?>
+
+		<?php elseif ( !bbp_is_forum_category() ) : ?>
+
+			<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>
+
+			<?php bbp_get_template_part( 'form',       'topic'     ); ?>
+
+		<?php endif; ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_template_after_single_forum' ); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/content-single-reply.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-single-reply.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-single-reply.php	(revision 5382)
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * Single Reply Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php do_action( 'bbp_template_before_single_reply' ); ?>
+
+	<?php if ( post_password_required() ) : ?>
+
+		<?php bbp_get_template_part( 'form', 'protected' ); ?>
+
+	<?php else : ?>
+
+		<?php bbp_get_template_part( 'loop', 'single-reply' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_template_after_single_reply' ); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/content-single-topic-lead.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-single-topic-lead.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-single-topic-lead.php	(revision 5382)
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * Single Topic Lead Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php do_action( 'bbp_template_before_lead_topic' ); ?>
+
+<ul id="bbp-topic-<?php bbp_topic_id(); ?>-lead" class="bbp-lead-topic">
+
+	<li class="bbp-header">
+
+		<div class="bbp-topic-author"><?php  _e( 'Creator',  'bbpress' ); ?></div><!-- .bbp-topic-author -->
+
+		<div class="bbp-topic-content">
+
+			<?php _e( 'Topic', 'bbpress' ); ?>
+
+			<?php bbp_topic_subscription_link(); ?>
+
+			<?php bbp_topic_favorite_link(); ?>
+
+		</div><!-- .bbp-topic-content -->
+
+	</li><!-- .bbp-header -->
+
+	<li class="bbp-body">
+
+		<div class="bbp-topic-header">
+
+			<div class="bbp-meta">
+
+				<span class="bbp-topic-post-date"><?php bbp_topic_post_date(); ?></span>
+
+				<a href="<?php bbp_topic_permalink(); ?>" class="bbp-topic-permalink">#<?php bbp_topic_id(); ?></a>
+
+				<?php do_action( 'bbp_theme_before_topic_admin_links' ); ?>
+
+				<?php bbp_topic_admin_links(); ?>
+
+				<?php do_action( 'bbp_theme_after_topic_admin_links' ); ?>
+
+			</div><!-- .bbp-meta -->
+
+		</div><!-- .bbp-topic-header -->
+
+		<div id="post-<?php bbp_topic_id(); ?>" <?php bbp_topic_class(); ?>>
+
+			<div class="bbp-topic-author">
+
+				<?php do_action( 'bbp_theme_before_topic_author_details' ); ?>
+
+				<?php bbp_topic_author_link( array( 'sep' => '<br />', 'show_role' => true ) ); ?>
+
+				<?php if ( bbp_is_user_keymaster() ) : ?>
+
+					<?php do_action( 'bbp_theme_before_topic_author_admin_details' ); ?>
+
+					<div class="bbp-topic-ip"><?php bbp_author_ip( bbp_get_topic_id() ); ?></div>
+
+					<?php do_action( 'bbp_theme_after_topic_author_admin_details' ); ?>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bbp_theme_after_topic_author_details' ); ?>
+
+			</div><!-- .bbp-topic-author -->
+
+			<div class="bbp-topic-content">
+
+				<?php do_action( 'bbp_theme_before_topic_content' ); ?>
+
+				<?php bbp_topic_content(); ?>
+
+				<?php do_action( 'bbp_theme_after_topic_content' ); ?>
+
+			</div><!-- .bbp-topic-content -->
+
+		</div><!-- #post-<?php bbp_topic_id(); ?> -->
+
+	</li><!-- .bbp-body -->
+
+	<li class="bbp-footer">
+
+		<div class="bbp-topic-author"><?php  _e( 'Creator',  'bbpress' ); ?></div>
+
+		<div class="bbp-topic-content">
+
+			<?php _e( 'Topic', 'bbpress' ); ?>
+
+		</div><!-- .bbp-topic-content -->
+
+	</li>
+
+</ul><!-- #bbp-topic-<?php bbp_topic_id(); ?>-lead -->
+
+<?php do_action( 'bbp_template_after_lead_topic' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/content-single-topic.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-single-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-single-topic.php	(revision 5382)
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Single Topic Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php do_action( 'bbp_template_before_single_topic' ); ?>
+
+	<?php if ( post_password_required() ) : ?>
+
+		<?php bbp_get_template_part( 'form', 'protected' ); ?>
+
+	<?php else : ?>
+
+		<?php bbp_topic_tag_list(); ?>
+
+		<?php bbp_single_topic_description(); ?>
+
+		<?php if ( bbp_show_lead_topic() ) : ?>
+
+			<?php bbp_get_template_part( 'content', 'single-topic-lead' ); ?>
+
+		<?php endif; ?>
+
+		<?php if ( bbp_has_replies() ) : ?>
+
+			<?php bbp_get_template_part( 'pagination', 'replies' ); ?>
+
+			<?php bbp_get_template_part( 'loop',       'replies' ); ?>
+
+			<?php bbp_get_template_part( 'pagination', 'replies' ); ?>
+
+		<?php endif; ?>
+
+		<?php bbp_get_template_part( 'form', 'reply' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_template_after_single_topic' ); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/content-single-user.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-single-user.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-single-user.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Single User Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<div id="bbp-user-wrapper">
+		<?php bbp_get_template_part( 'user', 'details' ); ?>
+
+		<div id="bbp-user-body">
+			<?php if ( bbp_is_favorites()                 ) bbp_get_template_part( 'user', 'favorites'       ); ?>
+			<?php if ( bbp_is_subscriptions()             ) bbp_get_template_part( 'user', 'subscriptions'   ); ?>
+			<?php if ( bbp_is_single_user_topics()        ) bbp_get_template_part( 'user', 'topics-created'  ); ?>
+			<?php if ( bbp_is_single_user_replies()       ) bbp_get_template_part( 'user', 'replies-created' ); ?>
+			<?php if ( bbp_is_single_user_edit()          ) bbp_get_template_part( 'form', 'user-edit'       ); ?>
+			<?php if ( bbp_is_single_user_profile()       ) bbp_get_template_part( 'user', 'profile'         ); ?>
+		</div>
+	</div>
+</div>
Index: /tags/2.5.4/templates/default/bbpress/content-single-view.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-single-view.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-single-view.php	(revision 5382)
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * Single View Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php bbp_set_query_name( bbp_get_view_rewrite_id() ); ?>
+
+	<?php if ( bbp_view_query() ) : ?>
+
+		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+		<?php bbp_get_template_part( 'loop',       'topics'    ); ?>
+
+		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+	<?php else : ?>
+
+		<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>
+
+	<?php endif; ?>
+
+	<?php bbp_reset_query_name(); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/content-statistics.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-statistics.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-statistics.php	(revision 5382)
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Statistics Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+// Get the statistics
+$stats = bbp_get_statistics(); ?>
+
+<dl role="main">
+
+	<?php do_action( 'bbp_before_statistics' ); ?>
+
+	<dt><?php _e( 'Registered Users', 'bbpress' ); ?></dt>
+	<dd>
+		<strong><?php echo esc_html( $stats['user_count'] ); ?></strong>
+	</dd>
+
+	<dt><?php _e( 'Forums', 'bbpress' ); ?></dt>
+	<dd>
+		<strong><?php echo esc_html( $stats['forum_count'] ); ?></strong>
+	</dd>
+
+	<dt><?php _e( 'Topics', 'bbpress' ); ?></dt>
+	<dd>
+		<strong><?php echo esc_html( $stats['topic_count'] ); ?></strong>
+	</dd>
+
+	<dt><?php _e( 'Replies', 'bbpress' ); ?></dt>
+	<dd>
+		<strong><?php echo esc_html( $stats['reply_count'] ); ?></strong>
+	</dd>
+
+	<dt><?php _e( 'Topic Tags', 'bbpress' ); ?></dt>
+	<dd>
+		<strong><?php echo esc_html( $stats['topic_tag_count'] ); ?></strong>
+	</dd>
+
+	<?php if ( !empty( $stats['empty_topic_tag_count'] ) ) : ?>
+
+		<dt><?php _e( 'Empty Topic Tags', 'bbpress' ); ?></dt>
+		<dd>
+			<strong><?php echo esc_html( $stats['empty_topic_tag_count'] ); ?></strong>
+		</dd>
+
+	<?php endif; ?>
+
+	<?php if ( !empty( $stats['topic_count_hidden'] ) ) : ?>
+
+		<dt><?php _e( 'Hidden Topics', 'bbpress' ); ?></dt>
+		<dd>
+			<strong>
+				<abbr title="<?php echo esc_attr( $stats['hidden_topic_title'] ); ?>"><?php echo esc_html( $stats['topic_count_hidden'] ); ?></abbr>
+			</strong>
+		</dd>
+
+	<?php endif; ?>
+
+	<?php if ( !empty( $stats['reply_count_hidden'] ) ) : ?>
+
+		<dt><?php _e( 'Hidden Replies', 'bbpress' ); ?></dt>
+		<dd>
+			<strong>
+				<abbr title="<?php echo esc_attr( $stats['hidden_reply_title'] ); ?>"><?php echo esc_html( $stats['reply_count_hidden'] ); ?></abbr>
+			</strong>
+		</dd>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_after_statistics' ); ?>
+
+</dl>
+
+<?php unset( $stats );
Index: /tags/2.5.4/templates/default/bbpress/content-topic-tag-edit.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/content-topic-tag-edit.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/content-topic-tag-edit.php	(revision 5382)
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * Topic Tag Edit Content Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php bbp_topic_tag_description(); ?>
+
+	<?php do_action( 'bbp_template_before_topic_tag_edit' ); ?>
+
+	<?php bbp_get_template_part( 'form', 'topic-tag' ); ?>
+
+	<?php do_action( 'bbp_template_after_topic_tag_edit' ); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/feedback-logged-in.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/feedback-logged-in.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/feedback-logged-in.php	(revision 5382)
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * Logged In Feedback Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-template-notice info">
+	<p><?php _e( 'You are already logged in.', 'bbpress' ); ?></p>
+</div>
Index: /tags/2.5.4/templates/default/bbpress/feedback-no-access.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/feedback-no-access.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/feedback-no-access.php	(revision 5382)
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * No Access Feedback Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="forum-private" class="bbp-forum-content">
+	<h1 class="entry-title"><?php _e( 'Private', 'bbpress' ); ?></h1>
+	<div class="entry-content">
+		<div class="bbp-template-notice info">
+			<p><?php _e( 'You do not have permission to view this forum.', 'bbpress' ); ?></p>
+		</div>
+	</div>
+</div><!-- #forum-private -->
Index: /tags/2.5.4/templates/default/bbpress/feedback-no-forums.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/feedback-no-forums.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/feedback-no-forums.php	(revision 5382)
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * No Forums Feedback Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-template-notice">
+	<p><?php _e( 'Oh bother! No forums were found here!', 'bbpress' ); ?></p>
+</div>
Index: /tags/2.5.4/templates/default/bbpress/feedback-no-replies.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/feedback-no-replies.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/feedback-no-replies.php	(revision 5382)
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * No Replies Feedback Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-template-notice">
+	<p><?php _e( 'Oh bother! No replies were found here!', 'bbpress' ); ?></p>
+</div>
Index: /tags/2.5.4/templates/default/bbpress/feedback-no-search.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/feedback-no-search.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/feedback-no-search.php	(revision 5382)
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * No Search Results Feedback Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-template-notice">
+	<p><?php _e( 'Oh bother! No search results were found here!', 'bbpress' ); ?></p>
+</div>
Index: /tags/2.5.4/templates/default/bbpress/feedback-no-topics.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/feedback-no-topics.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/feedback-no-topics.php	(revision 5382)
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * No Topics Feedback Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-template-notice">
+	<p><?php _e( 'Oh bother! No topics were found here!', 'bbpress' ); ?></p>
+</div>
Index: /tags/2.5.4/templates/default/bbpress/form-anonymous.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-anonymous.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-anonymous.php	(revision 5382)
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Anonymous User
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php if ( bbp_current_user_can_access_anonymous_user_form() ) : ?>
+
+	<?php do_action( 'bbp_theme_before_anonymous_form' ); ?>
+
+	<fieldset class="bbp-form">
+		<legend><?php ( bbp_is_topic_edit() || bbp_is_reply_edit() ) ? _e( 'Author Information', 'bbpress' ) : _e( 'Your information:', 'bbpress' ); ?></legend>
+
+		<?php do_action( 'bbp_theme_anonymous_form_extras_top' ); ?>
+
+		<p>
+			<label for="bbp_anonymous_author"><?php _e( 'Name (required):', 'bbpress' ); ?></label><br />
+			<input type="text" id="bbp_anonymous_author"  value="<?php bbp_author_display_name(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_anonymous_name" />
+		</p>
+
+		<p>
+			<label for="bbp_anonymous_email"><?php _e( 'Mail (will not be published) (required):', 'bbpress' ); ?></label><br />
+			<input type="text" id="bbp_anonymous_email"   value="<?php bbp_author_email(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_anonymous_email" />
+		</p>
+
+		<p>
+			<label for="bbp_anonymous_website"><?php _e( 'Website:', 'bbpress' ); ?></label><br />
+			<input type="text" id="bbp_anonymous_website" value="<?php bbp_author_url(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_anonymous_website" />
+		</p>
+
+		<?php do_action( 'bbp_theme_anonymous_form_extras_bottom' ); ?>
+
+	</fieldset>
+
+	<?php do_action( 'bbp_theme_after_anonymous_form' ); ?>
+
+<?php endif; ?>
Index: /tags/2.5.4/templates/default/bbpress/form-forum.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-forum.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-forum.php	(revision 5382)
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * New/Edit Forum
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php if ( bbp_is_forum_edit() ) : ?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php bbp_single_forum_description( array( 'forum_id' => bbp_get_forum_id() ) ); ?>
+
+<?php endif; ?>
+
+<?php if ( bbp_current_user_can_access_create_forum_form() ) : ?>
+
+	<div id="new-forum-<?php bbp_forum_id(); ?>" class="bbp-forum-form">
+
+		<form id="new-post" name="new-post" method="post" action="<?php the_permalink(); ?>">
+
+			<?php do_action( 'bbp_theme_before_forum_form' ); ?>
+
+			<fieldset class="bbp-form">
+				<legend>
+
+					<?php
+						if ( bbp_is_forum_edit() )
+							printf( __( 'Now Editing &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_forum_title() );
+						else
+							bbp_is_single_forum() ? printf( __( 'Create New Forum in &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_forum_title() ) : _e( 'Create New Forum', 'bbpress' );
+					?>
+
+				</legend>
+
+				<?php do_action( 'bbp_theme_before_forum_form_notices' ); ?>
+
+				<?php if ( !bbp_is_forum_edit() && bbp_is_forum_closed() ) : ?>
+
+					<div class="bbp-template-notice">
+						<p><?php _e( 'This forum is closed to new content, however your account still allows you to do so.', 'bbpress' ); ?></p>
+					</div>
+
+				<?php endif; ?>
+
+				<?php if ( current_user_can( 'unfiltered_html' ) ) : ?>
+
+					<div class="bbp-template-notice">
+						<p><?php _e( 'Your account has the ability to post unrestricted HTML content.', 'bbpress' ); ?></p>
+					</div>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bbp_template_notices' ); ?>
+
+				<div>
+
+					<?php do_action( 'bbp_theme_before_forum_form_title' ); ?>
+
+					<p>
+						<label for="bbp_forum_title"><?php printf( __( 'Forum Name (Maximum Length: %d):', 'bbpress' ), bbp_get_title_max_length() ); ?></label><br />
+						<input type="text" id="bbp_forum_title" value="<?php bbp_form_forum_title(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_forum_title" maxlength="<?php bbp_title_max_length(); ?>" />
+					</p>
+
+					<?php do_action( 'bbp_theme_after_forum_form_title' ); ?>
+
+					<?php do_action( 'bbp_theme_before_forum_form_content' ); ?>
+
+					<?php bbp_the_content( array( 'context' => 'forum' ) ); ?>
+
+					<?php do_action( 'bbp_theme_after_forum_form_content' ); ?>
+
+					<?php if ( ! ( bbp_use_wp_editor() || current_user_can( 'unfiltered_html' ) ) ) : ?>
+
+						<p class="form-allowed-tags">
+							<label><?php _e( 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes:','bbpress' ); ?></label><br />
+							<code><?php bbp_allowed_tags(); ?></code>
+						</p>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bbp_theme_before_forum_form_type' ); ?>
+
+					<p>
+						<label for="bbp_forum_type"><?php _e( 'Forum Type:', 'bbpress' ); ?></label><br />
+						<?php bbp_form_forum_type_dropdown(); ?>
+					</p>
+
+					<?php do_action( 'bbp_theme_after_forum_form_type' ); ?>
+
+					<?php do_action( 'bbp_theme_before_forum_form_status' ); ?>
+
+					<p>
+						<label for="bbp_forum_status"><?php _e( 'Status:', 'bbpress' ); ?></label><br />
+						<?php bbp_form_forum_status_dropdown(); ?>
+					</p>
+
+					<?php do_action( 'bbp_theme_after_forum_form_status' ); ?>
+
+					<?php do_action( 'bbp_theme_before_forum_form_status' ); ?>
+
+					<p>
+						<label for="bbp_forum_visibility"><?php _e( 'Visibility:', 'bbpress' ); ?></label><br />
+						<?php bbp_form_forum_visibility_dropdown(); ?>
+					</p>
+
+					<?php do_action( 'bbp_theme_after_forum_visibility_status' ); ?>
+
+					<?php do_action( 'bbp_theme_before_forum_form_parent' ); ?>
+
+					<p>
+						<label for="bbp_forum_parent_id"><?php _e( 'Parent Forum:', 'bbpress' ); ?></label><br />
+
+						<?php
+							bbp_dropdown( array(
+								'select_id' => 'bbp_forum_parent_id',
+								'show_none' => __( '(No Parent)', 'bbpress' ),
+								'selected'  => bbp_get_form_forum_parent(),
+								'exclude'   => bbp_get_forum_id()
+							) );
+						?>
+					</p>
+
+					<?php do_action( 'bbp_theme_after_forum_form_parent' ); ?>
+
+					<?php do_action( 'bbp_theme_before_forum_form_submit_wrapper' ); ?>
+
+					<div class="bbp-submit-wrapper">
+
+						<?php do_action( 'bbp_theme_before_forum_form_submit_button' ); ?>
+
+						<button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_forum_submit" name="bbp_forum_submit" class="button submit"><?php _e( 'Submit', 'bbpress' ); ?></button>
+
+						<?php do_action( 'bbp_theme_after_forum_form_submit_button' ); ?>
+
+					</div>
+
+					<?php do_action( 'bbp_theme_after_forum_form_submit_wrapper' ); ?>
+
+				</div>
+
+				<?php bbp_forum_form_fields(); ?>
+
+			</fieldset>
+
+			<?php do_action( 'bbp_theme_after_forum_form' ); ?>
+
+		</form>
+	</div>
+
+<?php elseif ( bbp_is_forum_closed() ) : ?>
+
+	<div id="no-forum-<?php bbp_forum_id(); ?>" class="bbp-no-forum">
+		<div class="bbp-template-notice">
+			<p><?php printf( __( 'The forum &#8216;%s&#8217; is closed to new content.', 'bbpress' ), bbp_get_forum_title() ); ?></p>
+		</div>
+	</div>
+
+<?php else : ?>
+
+	<div id="no-forum-<?php bbp_forum_id(); ?>" class="bbp-no-forum">
+		<div class="bbp-template-notice">
+			<p><?php is_user_logged_in() ? _e( 'You cannot create new forums.', 'bbpress' ) : _e( 'You must be logged in to create new forums.', 'bbpress' ); ?></p>
+		</div>
+	</div>
+
+<?php endif; ?>
+
+<?php if ( bbp_is_forum_edit() ) : ?>
+
+</div>
+
+<?php endif; ?>
Index: /tags/2.5.4/templates/default/bbpress/form-protected.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-protected.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-protected.php	(revision 5382)
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * Password Protected
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+	<fieldset class="bbp-form" id="bbp-protected">
+		<Legend><?php _e( 'Protected', 'bbpress' ); ?></legend>
+
+		<?php echo get_the_password_form(); ?>
+
+	</fieldset>
+</div>
Index: /tags/2.5.4/templates/default/bbpress/form-reply-move.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-reply-move.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-reply-move.php	(revision 5382)
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Move Reply
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php if ( is_user_logged_in() && current_user_can( 'edit_topic', bbp_get_topic_id() ) ) : ?>
+
+		<div id="move-reply-<?php bbp_topic_id(); ?>" class="bbp-reply-move">
+
+			<form id="move_reply" name="move_reply" method="post" action="<?php the_permalink(); ?>">
+
+				<fieldset class="bbp-form">
+
+					<legend><?php printf( __( 'Move reply "%s"', 'bbpress' ), bbp_get_reply_title() ); ?></legend>
+
+					<div>
+
+						<div class="bbp-template-notice info">
+							<p><?php _e( 'You can either make this reply a new topic with a new title, or merge it into an existing topic.', 'bbpress' ); ?></p>
+						</div>
+
+						<div class="bbp-template-notice">
+							<p><?php _e( 'If you choose an existing topic, replies will be ordered by the time and date they were created.', 'bbpress' ); ?></p>
+						</div>
+
+						<fieldset class="bbp-form">
+							<legend><?php _e( 'Move Method', 'bbpress' ); ?></legend>
+
+							<div>
+								<input name="bbp_reply_move_option" id="bbp_reply_move_option_reply" type="radio" checked="checked" value="topic" tabindex="<?php bbp_tab_index(); ?>" />
+								<label for="bbp_reply_move_option_reply"><?php printf( __( 'New topic in <strong>%s</strong> titled:', 'bbpress' ), bbp_get_forum_title( bbp_get_reply_forum_id( bbp_get_reply_id() ) ) ); ?></label>
+								<input type="text" id="bbp_reply_move_destination_title" value="<?php printf( __( 'Moved: %s', 'bbpress' ), bbp_get_reply_title() ); ?>" tabindex="<?php bbp_tab_index(); ?>" size="35" name="bbp_reply_move_destination_title" />
+							</div>
+
+							<?php if ( bbp_has_topics( array( 'show_stickies' => false, 'post_parent' => bbp_get_reply_forum_id( bbp_get_reply_id() ), 'post__not_in' => array( bbp_get_reply_topic_id( bbp_get_reply_id() ) ) ) ) ) : ?>
+
+								<div>
+									<input name="bbp_reply_move_option" id="bbp_reply_move_option_existing" type="radio" value="existing" tabindex="<?php bbp_tab_index(); ?>" />
+									<label for="bbp_reply_move_option_existing"><?php _e( 'Use an existing topic in this forum:', 'bbpress' ); ?></label>
+
+									<?php
+										bbp_dropdown( array(
+											'post_type'   => bbp_get_topic_post_type(),
+											'post_parent' => bbp_get_reply_forum_id( bbp_get_reply_id() ),
+											'selected'    => -1,
+											'exclude'     => bbp_get_reply_topic_id( bbp_get_reply_id() ),
+											'select_id'   => 'bbp_destination_topic'
+										) );
+									?>
+
+								</div>
+
+							<?php endif; ?>
+
+						</fieldset>
+
+						<div class="bbp-template-notice error">
+							<p><?php _e( '<strong>WARNING:</strong> This process cannot be undone.', 'bbpress' ); ?></p>
+						</div>
+
+						<div class="bbp-submit-wrapper">
+							<button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_move_reply_submit" name="bbp_move_reply_submit" class="button submit"><?php _e( 'Submit', 'bbpress' ); ?></button>
+						</div>
+					</div>
+
+					<?php bbp_move_reply_form_fields(); ?>
+
+				</fieldset>
+			</form>
+		</div>
+
+	<?php else : ?>
+
+		<div id="no-reply-<?php bbp_reply_id(); ?>" class="bbp-no-reply">
+			<div class="entry-content"><?php is_user_logged_in() ? _e( 'You do not have the permissions to edit this reply!', 'bbpress' ) : _e( 'You cannot edit this reply.', 'bbpress' ); ?></div>
+		</div>
+
+	<?php endif; ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/form-reply.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-reply.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-reply.php	(revision 5382)
@@ -0,0 +1,184 @@
+<?php
+
+/**
+ * New/Edit Reply
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php if ( bbp_is_reply_edit() ) : ?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+<?php endif; ?>
+
+<?php if ( bbp_current_user_can_access_create_reply_form() ) : ?>
+
+	<div id="new-reply-<?php bbp_topic_id(); ?>" class="bbp-reply-form">
+
+		<form id="new-post" name="new-post" method="post" action="<?php the_permalink(); ?>">
+
+			<?php do_action( 'bbp_theme_before_reply_form' ); ?>
+
+			<fieldset class="bbp-form">
+				<legend><?php printf( __( 'Reply To: %s', 'bbpress' ), bbp_get_topic_title() ); ?></legend>
+
+				<?php do_action( 'bbp_theme_before_reply_form_notices' ); ?>
+
+				<?php if ( !bbp_is_topic_open() && !bbp_is_reply_edit() ) : ?>
+
+					<div class="bbp-template-notice">
+						<p><?php _e( 'This topic is marked as closed to new replies, however your posting capabilities still allow you to do so.', 'bbpress' ); ?></p>
+					</div>
+
+				<?php endif; ?>
+
+				<?php if ( current_user_can( 'unfiltered_html' ) ) : ?>
+
+					<div class="bbp-template-notice">
+						<p><?php _e( 'Your account has the ability to post unrestricted HTML content.', 'bbpress' ); ?></p>
+					</div>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bbp_template_notices' ); ?>
+
+				<div>
+
+					<?php bbp_get_template_part( 'form', 'anonymous' ); ?>
+
+					<?php do_action( 'bbp_theme_before_reply_form_content' ); ?>
+
+					<?php bbp_the_content( array( 'context' => 'reply' ) ); ?>
+
+					<?php do_action( 'bbp_theme_after_reply_form_content' ); ?>
+
+					<?php if ( ! ( bbp_use_wp_editor() || current_user_can( 'unfiltered_html' ) ) ) : ?>
+
+						<p class="form-allowed-tags">
+							<label><?php _e( 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes:','bbpress' ); ?></label><br />
+							<code><?php bbp_allowed_tags(); ?></code>
+						</p>
+
+					<?php endif; ?>
+					
+					<?php if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags' ) ) : ?>
+
+						<?php do_action( 'bbp_theme_before_reply_form_tags' ); ?>
+
+						<p>
+							<label for="bbp_topic_tags"><?php _e( 'Tags:', 'bbpress' ); ?></label><br />
+							<input type="text" value="<?php bbp_form_topic_tags(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_topic_tags" id="bbp_topic_tags" <?php disabled( bbp_is_topic_spam() ); ?> />
+						</p>
+
+						<?php do_action( 'bbp_theme_after_reply_form_tags' ); ?>
+
+					<?php endif; ?>
+
+					<?php if ( bbp_is_subscriptions_active() && !bbp_is_anonymous() && ( !bbp_is_reply_edit() || ( bbp_is_reply_edit() && !bbp_is_reply_anonymous() ) ) ) : ?>
+
+						<?php do_action( 'bbp_theme_before_reply_form_subscription' ); ?>
+
+						<p>
+
+							<input name="bbp_topic_subscription" id="bbp_topic_subscription" type="checkbox" value="bbp_subscribe"<?php bbp_form_topic_subscribed(); ?> tabindex="<?php bbp_tab_index(); ?>" />
+
+							<?php if ( bbp_is_reply_edit() && ( bbp_get_reply_author_id() !== bbp_get_current_user_id() ) ) : ?>
+
+								<label for="bbp_topic_subscription"><?php _e( 'Notify the author of follow-up replies via email', 'bbpress' ); ?></label>
+
+							<?php else : ?>
+
+								<label for="bbp_topic_subscription"><?php _e( 'Notify me of follow-up replies via email', 'bbpress' ); ?></label>
+
+							<?php endif; ?>
+
+						</p>
+
+						<?php do_action( 'bbp_theme_after_reply_form_subscription' ); ?>
+
+					<?php endif; ?>
+
+					<?php if ( bbp_allow_revisions() && bbp_is_reply_edit() ) : ?>
+
+						<?php do_action( 'bbp_theme_before_reply_form_revisions' ); ?>
+
+						<fieldset class="bbp-form">
+							<legend>
+								<input name="bbp_log_reply_edit" id="bbp_log_reply_edit" type="checkbox" value="1" <?php bbp_form_reply_log_edit(); ?> tabindex="<?php bbp_tab_index(); ?>" />
+								<label for="bbp_log_reply_edit"><?php _e( 'Keep a log of this edit:', 'bbpress' ); ?></label><br />
+							</legend>
+
+							<div>
+								<label for="bbp_reply_edit_reason"><?php printf( __( 'Optional reason for editing:', 'bbpress' ), bbp_get_current_user_name() ); ?></label><br />
+								<input type="text" value="<?php bbp_form_reply_edit_reason(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_reply_edit_reason" id="bbp_reply_edit_reason" />
+							</div>
+						</fieldset>
+
+						<?php do_action( 'bbp_theme_after_reply_form_revisions' ); ?>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bbp_theme_before_reply_form_submit_wrapper' ); ?>
+
+					<div class="bbp-submit-wrapper">
+
+						<?php do_action( 'bbp_theme_before_reply_form_submit_button' ); ?>
+
+						<?php bbp_cancel_reply_to_link(); ?>
+
+						<button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_reply_submit" name="bbp_reply_submit" class="button submit"><?php _e( 'Submit', 'bbpress' ); ?></button>
+
+						<?php do_action( 'bbp_theme_after_reply_form_submit_button' ); ?>
+
+					</div>
+
+					<?php do_action( 'bbp_theme_after_reply_form_submit_wrapper' ); ?>
+
+				</div>
+
+				<?php bbp_reply_form_fields(); ?>
+
+			</fieldset>
+
+			<?php do_action( 'bbp_theme_after_reply_form' ); ?>
+
+		</form>
+	</div>
+
+<?php elseif ( bbp_is_topic_closed() ) : ?>
+
+	<div id="no-reply-<?php bbp_topic_id(); ?>" class="bbp-no-reply">
+		<div class="bbp-template-notice">
+			<p><?php printf( __( 'The topic &#8216;%s&#8217; is closed to new replies.', 'bbpress' ), bbp_get_topic_title() ); ?></p>
+		</div>
+	</div>
+
+<?php elseif ( bbp_is_forum_closed( bbp_get_topic_forum_id() ) ) : ?>
+
+	<div id="no-reply-<?php bbp_topic_id(); ?>" class="bbp-no-reply">
+		<div class="bbp-template-notice">
+			<p><?php printf( __( 'The forum &#8216;%s&#8217; is closed to new topics and replies.', 'bbpress' ), bbp_get_forum_title( bbp_get_topic_forum_id() ) ); ?></p>
+		</div>
+	</div>
+
+<?php else : ?>
+
+	<div id="no-reply-<?php bbp_topic_id(); ?>" class="bbp-no-reply">
+		<div class="bbp-template-notice">
+			<p><?php is_user_logged_in() ? _e( 'You cannot reply to this topic.', 'bbpress' ) : _e( 'You must be logged in to reply to this topic.', 'bbpress' ); ?></p>
+		</div>
+	</div>
+
+<?php endif; ?>
+
+<?php if ( bbp_is_reply_edit() ) : ?>
+
+</div>
+
+<?php endif; ?>
Index: /tags/2.5.4/templates/default/bbpress/form-search.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-search.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-search.php	(revision 5382)
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * Search 
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<form role="search" method="get" id="bbp-search-form" action="<?php bbp_search_url(); ?>">
+	<div>
+		<label class="screen-reader-text hidden" for="bbp_search"><?php _e( 'Search for:', 'bbpress' ); ?></label>
+		<input type="hidden" name="action" value="bbp-search-request" />
+		<input tabindex="<?php bbp_tab_index(); ?>" type="text" value="<?php echo esc_attr( bbp_get_search_terms() ); ?>" name="bbp_search" id="bbp_search" />
+		<input tabindex="<?php bbp_tab_index(); ?>" class="button" type="submit" id="bbp_search_submit" value="<?php esc_attr_e( 'Search', 'bbpress' ); ?>" />
+	</div>
+</form>
Index: /tags/2.5.4/templates/default/bbpress/form-topic-merge.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-topic-merge.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-topic-merge.php	(revision 5382)
@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * Merge Topic
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php if ( is_user_logged_in() && current_user_can( 'edit_topic', bbp_get_topic_id() ) ) : ?>
+
+		<div id="merge-topic-<?php bbp_topic_id(); ?>" class="bbp-topic-merge">
+
+			<form id="merge_topic" name="merge_topic" method="post" action="<?php the_permalink(); ?>">
+
+				<fieldset class="bbp-form">
+
+					<legend><?php printf( __( 'Merge topic "%s"', 'bbpress' ), bbp_get_topic_title() ); ?></legend>
+
+					<div>
+
+						<div class="bbp-template-notice info">
+							<p><?php _e( 'Select the topic to merge this one into. The destination topic will remain the lead topic, and this one will change into a reply.', 'bbpress' ); ?></p>
+							<p><?php _e( 'To keep this topic as the lead, go to the other topic and use the merge tool from there instead.', 'bbpress' ); ?></p>
+						</div>
+
+						<div class="bbp-template-notice">
+							<p><?php _e( 'All replies within both topics will be merged chronologically. The order of the merged replies is based on the time and date they were posted. If the destination topic was created after this one, it\'s post date will be updated to second earlier than this one.', 'bbpress' ); ?></p>
+						</div>
+
+						<fieldset class="bbp-form">
+							<legend><?php _e( 'Destination', 'bbpress' ); ?></legend>
+							<div>
+								<?php if ( bbp_has_topics( array( 'show_stickies' => false, 'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ), 'post__not_in' => array( bbp_get_topic_id() ) ) ) ) : ?>
+
+									<label for="bbp_destination_topic"><?php _e( 'Merge with this topic:', 'bbpress' ); ?></label>
+
+									<?php
+										bbp_dropdown( array(
+											'post_type'   => bbp_get_topic_post_type(),
+											'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ),
+											'selected'    => -1,
+											'exclude'     => bbp_get_topic_id(),
+											'select_id'   => 'bbp_destination_topic'
+										) );
+									?>
+
+								<?php else : ?>
+
+									<label><?php _e( 'There are no other topics in this forum to merge with.', 'bbpress' ); ?></label>
+
+								<?php endif; ?>
+
+							</div>
+						</fieldset>
+
+						<fieldset class="bbp-form">
+							<legend><?php _e( 'Topic Extras', 'bbpress' ); ?></legend>
+
+							<div>
+
+								<?php if ( bbp_is_subscriptions_active() ) : ?>
+
+									<input name="bbp_topic_subscribers" id="bbp_topic_subscribers" type="checkbox" value="1" checked="checked" tabindex="<?php bbp_tab_index(); ?>" />
+									<label for="bbp_topic_subscribers"><?php _e( 'Merge topic subscribers', 'bbpress' ); ?></label><br />
+
+								<?php endif; ?>
+
+								<input name="bbp_topic_favoriters" id="bbp_topic_favoriters" type="checkbox" value="1" checked="checked" tabindex="<?php bbp_tab_index(); ?>" />
+								<label for="bbp_topic_favoriters"><?php _e( 'Merge topic favoriters', 'bbpress' ); ?></label><br />
+
+								<?php if ( bbp_allow_topic_tags() ) : ?>
+
+									<input name="bbp_topic_tags" id="bbp_topic_tags" type="checkbox" value="1" checked="checked" tabindex="<?php bbp_tab_index(); ?>" />
+									<label for="bbp_topic_tags"><?php _e( 'Merge topic tags', 'bbpress' ); ?></label><br />
+
+								<?php endif; ?>
+
+							</div>
+						</fieldset>
+
+						<div class="bbp-template-notice error">
+							<p><?php _e( '<strong>WARNING:</strong> This process cannot be undone.', 'bbpress' ); ?></p>
+						</div>
+
+						<div class="bbp-submit-wrapper">
+							<button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_merge_topic_submit" name="bbp_merge_topic_submit" class="button submit"><?php _e( 'Submit', 'bbpress' ); ?></button>
+						</div>
+					</div>
+
+					<?php bbp_merge_topic_form_fields(); ?>
+
+				</fieldset>
+			</form>
+		</div>
+
+	<?php else : ?>
+
+		<div id="no-topic-<?php bbp_topic_id(); ?>" class="bbp-no-topic">
+			<div class="entry-content"><?php is_user_logged_in() ? _e( 'You do not have the permissions to edit this topic!', 'bbpress' ) : _e( 'You cannot edit this topic.', 'bbpress' ); ?></div>
+		</div>
+
+	<?php endif; ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/form-topic-split.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-topic-split.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-topic-split.php	(revision 5382)
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Split Topic
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+	<?php if ( is_user_logged_in() && current_user_can( 'edit_topic', bbp_get_topic_id() ) ) : ?>
+
+		<div id="split-topic-<?php bbp_topic_id(); ?>" class="bbp-topic-split">
+
+			<form id="split_topic" name="split_topic" method="post" action="<?php the_permalink(); ?>">
+
+				<fieldset class="bbp-form">
+
+					<legend><?php printf( __( 'Split topic "%s"', 'bbpress' ), bbp_get_topic_title() ); ?></legend>
+
+					<div>
+
+						<div class="bbp-template-notice info">
+							<p><?php _e( 'When you split a topic, you are slicing it in half starting with the reply you just selected. Choose to use that reply as a new topic with a new title, or merge those replies into an existing topic.', 'bbpress' ); ?></p>
+						</div>
+
+						<div class="bbp-template-notice">
+							<p><?php _e( 'If you use the existing topic option, replies within both topics will be merged chronologically. The order of the merged replies is based on the time and date they were posted.', 'bbpress' ); ?></p>
+						</div>
+
+						<fieldset class="bbp-form">
+							<legend><?php _e( 'Split Method', 'bbpress' ); ?></legend>
+
+							<div>
+								<input name="bbp_topic_split_option" id="bbp_topic_split_option_reply" type="radio" checked="checked" value="reply" tabindex="<?php bbp_tab_index(); ?>" />
+								<label for="bbp_topic_split_option_reply"><?php printf( __( 'New topic in <strong>%s</strong> titled:', 'bbpress' ), bbp_get_forum_title( bbp_get_topic_forum_id( bbp_get_topic_id() ) ) ); ?></label>
+								<input type="text" id="bbp_topic_split_destination_title" value="<?php printf( __( 'Split: %s', 'bbpress' ), bbp_get_topic_title() ); ?>" tabindex="<?php bbp_tab_index(); ?>" size="35" name="bbp_topic_split_destination_title" />
+							</div>
+
+							<?php if ( bbp_has_topics( array( 'show_stickies' => false, 'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ), 'post__not_in' => array( bbp_get_topic_id() ) ) ) ) : ?>
+
+								<div>
+									<input name="bbp_topic_split_option" id="bbp_topic_split_option_existing" type="radio" value="existing" tabindex="<?php bbp_tab_index(); ?>" />
+									<label for="bbp_topic_split_option_existing"><?php _e( 'Use an existing topic in this forum:', 'bbpress' ); ?></label>
+
+									<?php
+										bbp_dropdown( array(
+											'post_type'   => bbp_get_topic_post_type(),
+											'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ),
+											'selected'    => -1,
+											'exclude'     => bbp_get_topic_id(),
+											'select_id'   => 'bbp_destination_topic'
+										) );
+									?>
+
+								</div>
+
+							<?php endif; ?>
+
+						</fieldset>
+
+						<fieldset class="bbp-form">
+							<legend><?php _e( 'Topic Extras', 'bbpress' ); ?></legend>
+
+							<div>
+
+								<?php if ( bbp_is_subscriptions_active() ) : ?>
+
+									<input name="bbp_topic_subscribers" id="bbp_topic_subscribers" type="checkbox" value="1" checked="checked" tabindex="<?php bbp_tab_index(); ?>" />
+									<label for="bbp_topic_subscribers"><?php _e( 'Copy subscribers to the new topic', 'bbpress' ); ?></label><br />
+
+								<?php endif; ?>
+
+								<input name="bbp_topic_favoriters" id="bbp_topic_favoriters" type="checkbox" value="1" checked="checked" tabindex="<?php bbp_tab_index(); ?>" />
+								<label for="bbp_topic_favoriters"><?php _e( 'Copy favoriters to the new topic', 'bbpress' ); ?></label><br />
+
+								<?php if ( bbp_allow_topic_tags() ) : ?>
+
+									<input name="bbp_topic_tags" id="bbp_topic_tags" type="checkbox" value="1" checked="checked" tabindex="<?php bbp_tab_index(); ?>" />
+									<label for="bbp_topic_tags"><?php _e( 'Copy topic tags to the new topic', 'bbpress' ); ?></label><br />
+
+								<?php endif; ?>
+
+							</div>
+						</fieldset>
+
+						<div class="bbp-template-notice error">
+							<p><?php _e( '<strong>WARNING:</strong> This process cannot be undone.', 'bbpress' ); ?></p>
+						</div>
+
+						<div class="bbp-submit-wrapper">
+							<button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_merge_topic_submit" name="bbp_merge_topic_submit" class="button submit"><?php _e( 'Submit', 'bbpress' ); ?></button>
+						</div>
+					</div>
+
+					<?php bbp_split_topic_form_fields(); ?>
+
+				</fieldset>
+			</form>
+		</div>
+
+	<?php else : ?>
+
+		<div id="no-topic-<?php bbp_topic_id(); ?>" class="bbp-no-topic">
+			<div class="entry-content"><?php is_user_logged_in() ? _e( 'You do not have the permissions to edit this topic!', 'bbpress' ) : _e( 'You cannot edit this topic.', 'bbpress' ); ?></div>
+		</div>
+
+	<?php endif; ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/form-topic-tag.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-topic-tag.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-topic-tag.php	(revision 5382)
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Edit Topic Tag
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php if ( current_user_can( 'edit_topic_tags' ) ) : ?>
+
+	<div id="edit-topic-tag-<?php bbp_topic_tag_id(); ?>" class="bbp-topic-tag-form">
+
+		<fieldset class="bbp-form" id="bbp-edit-topic-tag">
+
+			<legend><?php printf( __( 'Manage Tag: "%s"', 'bbpress' ), bbp_get_topic_tag_name() ); ?></legend>
+
+			<fieldset class="bbp-form" id="tag-rename">
+
+				<legend><?php _e( 'Rename', 'bbpress' ); ?></legend>
+
+				<div class="bbp-template-notice info">
+					<p><?php _e( 'Leave the slug empty to have one automatically generated.', 'bbpress' ); ?></p>
+				</div>
+
+				<div class="bbp-template-notice">
+					<p><?php _e( 'Changing the slug affects its permalink. Any links to the old slug will stop working.', 'bbpress' ); ?></p>
+				</div>
+
+				<form id="rename_tag" name="rename_tag" method="post" action="<?php the_permalink(); ?>">
+
+					<div>
+						<label for="tag-name"><?php _e( 'Name:', 'bbpress' ); ?></label>
+						<input type="text" id="tag-name" name="tag-name" size="20" maxlength="40" tabindex="<?php bbp_tab_index(); ?>" value="<?php echo esc_attr( bbp_get_topic_tag_name() ); ?>" />
+					</div>
+
+					<div>
+						<label for="tag-slug"><?php _e( 'Slug:', 'bbpress' ); ?></label>
+						<input type="text" id="tag-slug" name="tag-slug" size="20" maxlength="40" tabindex="<?php bbp_tab_index(); ?>" value="<?php echo esc_attr( apply_filters( 'editable_slug', bbp_get_topic_tag_slug() ) ); ?>" />
+					</div>
+
+					<div class="bbp-submit-wrapper">
+						<button type="submit" tabindex="<?php bbp_tab_index(); ?>" class="button submit"><?php esc_attr_e( 'Update', 'bbpress' ); ?></button>
+
+						<input type="hidden" name="tag-id" value="<?php bbp_topic_tag_id(); ?>" />
+						<input type="hidden" name="action" value="bbp-update-topic-tag" />
+
+						<?php wp_nonce_field( 'update-tag_' . bbp_get_topic_tag_id() ); ?>
+
+					</div>
+				</form>
+
+			</fieldset>
+
+			<fieldset class="bbp-form" id="tag-merge">
+
+				<legend><?php _e( 'Merge', 'bbpress' ); ?></legend>
+
+				<div class="bbp-template-notice">
+					<p><?php _e( 'Merging tags together cannot be undone.', 'bbpress' ); ?></p>
+				</div>
+
+				<form id="merge_tag" name="merge_tag" method="post" action="<?php the_permalink(); ?>">
+
+					<div>
+						<label for="tag-existing-name"><?php _e( 'Existing tag:', 'bbpress' ); ?></label>
+						<input type="text" id="tag-existing-name" name="tag-existing-name" size="22" tabindex="<?php bbp_tab_index(); ?>" maxlength="40" />
+					</div>
+
+					<div class="bbp-submit-wrapper">
+						<button type="submit" tabindex="<?php bbp_tab_index(); ?>" class="button submit" onclick="return confirm('<?php echo esc_js( sprintf( __( 'Are you sure you want to merge the "%s" tag into the tag you specified?', 'bbpress' ), bbp_get_topic_tag_name() ) ); ?>');"><?php esc_attr_e( 'Merge', 'bbpress' ); ?></button>
+
+						<input type="hidden" name="tag-id" value="<?php bbp_topic_tag_id(); ?>" />
+						<input type="hidden" name="action" value="bbp-merge-topic-tag" />
+
+						<?php wp_nonce_field( 'merge-tag_' . bbp_get_topic_tag_id() ); ?>
+					</div>
+				</form>
+
+			</fieldset>
+
+			<?php if ( current_user_can( 'delete_topic_tags' ) ) : ?>
+
+				<fieldset class="bbp-form" id="delete-tag">
+
+					<legend><?php _e( 'Delete', 'bbpress' ); ?></legend>
+
+					<div class="bbp-template-notice info">
+						<p><?php _e( 'This does not delete your topics. Only the tag itself is deleted.', 'bbpress' ); ?></p>
+					</div>
+					<div class="bbp-template-notice">
+						<p><?php _e( 'Deleting a tag cannot be undone.', 'bbpress' ); ?></p>
+						<p><?php _e( 'Any links to this tag will no longer function.', 'bbpress' ); ?></p>
+					</div>
+
+					<form id="delete_tag" name="delete_tag" method="post" action="<?php the_permalink(); ?>">
+
+						<div class="bbp-submit-wrapper">
+							<button type="submit" tabindex="<?php bbp_tab_index(); ?>" class="button submit" onclick="return confirm('<?php echo esc_js( sprintf( __( 'Are you sure you want to delete the "%s" tag? This is permanent and cannot be undone.', 'bbpress' ), bbp_get_topic_tag_name() ) ); ?>');"><?php esc_attr_e( 'Delete', 'bbpress' ); ?></button>
+
+							<input type="hidden" name="tag-id" value="<?php bbp_topic_tag_id(); ?>" />
+							<input type="hidden" name="action" value="bbp-delete-topic-tag" />
+
+							<?php wp_nonce_field( 'delete-tag_' . bbp_get_topic_tag_id() ); ?>
+						</div>
+					</form>
+
+				</fieldset>
+
+			<?php endif; ?>
+
+		</fieldset>
+	</div>
+
+<?php endif; ?>
Index: /tags/2.5.4/templates/default/bbpress/form-topic.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-topic.php	(revision 5382)
@@ -0,0 +1,244 @@
+<?php
+
+/**
+ * New/Edit Topic
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php if ( !bbp_is_single_forum() ) : ?>
+
+<div id="bbpress-forums">
+
+	<?php bbp_breadcrumb(); ?>
+
+<?php endif; ?>
+
+<?php if ( bbp_is_topic_edit() ) : ?>
+
+	<?php bbp_topic_tag_list( bbp_get_topic_id() ); ?>
+
+	<?php bbp_single_topic_description( array( 'topic_id' => bbp_get_topic_id() ) ); ?>
+
+<?php endif; ?>
+
+<?php if ( bbp_current_user_can_access_create_topic_form() ) : ?>
+
+	<div id="new-topic-<?php bbp_topic_id(); ?>" class="bbp-topic-form">
+
+		<form id="new-post" name="new-post" method="post" action="<?php the_permalink(); ?>">
+
+			<?php do_action( 'bbp_theme_before_topic_form' ); ?>
+
+			<fieldset class="bbp-form">
+				<legend>
+
+					<?php
+						if ( bbp_is_topic_edit() )
+							printf( __( 'Now Editing &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_topic_title() );
+						else
+							bbp_is_single_forum() ? printf( __( 'Create New Topic in &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_forum_title() ) : _e( 'Create New Topic', 'bbpress' );
+					?>
+
+				</legend>
+
+				<?php do_action( 'bbp_theme_before_topic_form_notices' ); ?>
+
+				<?php if ( !bbp_is_topic_edit() && bbp_is_forum_closed() ) : ?>
+
+					<div class="bbp-template-notice">
+						<p><?php _e( 'This forum is marked as closed to new topics, however your posting capabilities still allow you to do so.', 'bbpress' ); ?></p>
+					</div>
+
+				<?php endif; ?>
+
+				<?php if ( current_user_can( 'unfiltered_html' ) ) : ?>
+
+					<div class="bbp-template-notice">
+						<p><?php _e( 'Your account has the ability to post unrestricted HTML content.', 'bbpress' ); ?></p>
+					</div>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bbp_template_notices' ); ?>
+
+				<div>
+
+					<?php bbp_get_template_part( 'form', 'anonymous' ); ?>
+
+					<?php do_action( 'bbp_theme_before_topic_form_title' ); ?>
+
+					<p>
+						<label for="bbp_topic_title"><?php printf( __( 'Topic Title (Maximum Length: %d):', 'bbpress' ), bbp_get_title_max_length() ); ?></label><br />
+						<input type="text" id="bbp_topic_title" value="<?php bbp_form_topic_title(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_topic_title" maxlength="<?php bbp_title_max_length(); ?>" />
+					</p>
+
+					<?php do_action( 'bbp_theme_after_topic_form_title' ); ?>
+
+					<?php do_action( 'bbp_theme_before_topic_form_content' ); ?>
+
+					<?php bbp_the_content( array( 'context' => 'topic' ) ); ?>
+
+					<?php do_action( 'bbp_theme_after_topic_form_content' ); ?>
+
+					<?php if ( ! ( bbp_use_wp_editor() || current_user_can( 'unfiltered_html' ) ) ) : ?>
+
+						<p class="form-allowed-tags">
+							<label><?php _e( 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes:','bbpress' ); ?></label><br />
+							<code><?php bbp_allowed_tags(); ?></code>
+						</p>
+
+					<?php endif; ?>
+
+					<?php if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags' ) ) : ?>
+
+						<?php do_action( 'bbp_theme_before_topic_form_tags' ); ?>
+
+						<p>
+							<label for="bbp_topic_tags"><?php _e( 'Topic Tags:', 'bbpress' ); ?></label><br />
+							<input type="text" value="<?php bbp_form_topic_tags(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_topic_tags" id="bbp_topic_tags" <?php disabled( bbp_is_topic_spam() ); ?> />
+						</p>
+
+						<?php do_action( 'bbp_theme_after_topic_form_tags' ); ?>
+
+					<?php endif; ?>
+
+					<?php if ( !bbp_is_single_forum() ) : ?>
+
+						<?php do_action( 'bbp_theme_before_topic_form_forum' ); ?>
+
+						<p>
+							<label for="bbp_forum_id"><?php _e( 'Forum:', 'bbpress' ); ?></label><br />
+							<?php
+								bbp_dropdown( array(
+									'show_none' => __( '(No Forum)', 'bbpress' ),
+									'selected'  => bbp_get_form_topic_forum()
+								) );
+							?>
+						</p>
+
+						<?php do_action( 'bbp_theme_after_topic_form_forum' ); ?>
+
+					<?php endif; ?>
+
+					<?php if ( current_user_can( 'moderate' ) ) : ?>
+
+						<?php do_action( 'bbp_theme_before_topic_form_type' ); ?>
+
+						<p>
+
+							<label for="bbp_stick_topic"><?php _e( 'Topic Type:', 'bbpress' ); ?></label><br />
+
+							<?php bbp_form_topic_type_dropdown(); ?>
+
+						</p>
+
+						<?php do_action( 'bbp_theme_after_topic_form_type' ); ?>
+
+						<?php do_action( 'bbp_theme_before_topic_form_status' ); ?>
+
+						<p>
+
+							<label for="bbp_topic_status"><?php _e( 'Topic Status:', 'bbpress' ); ?></label><br />
+
+							<?php bbp_form_topic_status_dropdown(); ?>
+
+						</p>
+
+						<?php do_action( 'bbp_theme_after_topic_form_status' ); ?>
+
+					<?php endif; ?>
+
+					<?php if ( bbp_is_subscriptions_active() && !bbp_is_anonymous() && ( !bbp_is_topic_edit() || ( bbp_is_topic_edit() && !bbp_is_topic_anonymous() ) ) ) : ?>
+
+						<?php do_action( 'bbp_theme_before_topic_form_subscriptions' ); ?>
+
+						<p>
+							<input name="bbp_topic_subscription" id="bbp_topic_subscription" type="checkbox" value="bbp_subscribe" <?php bbp_form_topic_subscribed(); ?> tabindex="<?php bbp_tab_index(); ?>" />
+
+							<?php if ( bbp_is_topic_edit() && ( bbp_get_topic_author_id() !== bbp_get_current_user_id() ) ) : ?>
+
+								<label for="bbp_topic_subscription"><?php _e( 'Notify the author of follow-up replies via email', 'bbpress' ); ?></label>
+
+							<?php else : ?>
+
+								<label for="bbp_topic_subscription"><?php _e( 'Notify me of follow-up replies via email', 'bbpress' ); ?></label>
+
+							<?php endif; ?>
+						</p>
+
+						<?php do_action( 'bbp_theme_after_topic_form_subscriptions' ); ?>
+
+					<?php endif; ?>
+
+					<?php if ( bbp_allow_revisions() && bbp_is_topic_edit() ) : ?>
+
+						<?php do_action( 'bbp_theme_before_topic_form_revisions' ); ?>
+
+						<fieldset class="bbp-form">
+							<legend>
+								<input name="bbp_log_topic_edit" id="bbp_log_topic_edit" type="checkbox" value="1" <?php bbp_form_topic_log_edit(); ?> tabindex="<?php bbp_tab_index(); ?>" />
+								<label for="bbp_log_topic_edit"><?php _e( 'Keep a log of this edit:', 'bbpress' ); ?></label><br />
+							</legend>
+
+							<div>
+								<label for="bbp_topic_edit_reason"><?php printf( __( 'Optional reason for editing:', 'bbpress' ), bbp_get_current_user_name() ); ?></label><br />
+								<input type="text" value="<?php bbp_form_topic_edit_reason(); ?>" tabindex="<?php bbp_tab_index(); ?>" size="40" name="bbp_topic_edit_reason" id="bbp_topic_edit_reason" />
+							</div>
+						</fieldset>
+
+						<?php do_action( 'bbp_theme_after_topic_form_revisions' ); ?>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bbp_theme_before_topic_form_submit_wrapper' ); ?>
+
+					<div class="bbp-submit-wrapper">
+
+						<?php do_action( 'bbp_theme_before_topic_form_submit_button' ); ?>
+
+						<button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_topic_submit" name="bbp_topic_submit" class="button submit"><?php _e( 'Submit', 'bbpress' ); ?></button>
+
+						<?php do_action( 'bbp_theme_after_topic_form_submit_button' ); ?>
+
+					</div>
+
+					<?php do_action( 'bbp_theme_after_topic_form_submit_wrapper' ); ?>
+
+				</div>
+
+				<?php bbp_topic_form_fields(); ?>
+
+			</fieldset>
+
+			<?php do_action( 'bbp_theme_after_topic_form' ); ?>
+
+		</form>
+	</div>
+
+<?php elseif ( bbp_is_forum_closed() ) : ?>
+
+	<div id="no-topic-<?php bbp_topic_id(); ?>" class="bbp-no-topic">
+		<div class="bbp-template-notice">
+			<p><?php printf( __( 'The forum &#8216;%s&#8217; is closed to new topics and replies.', 'bbpress' ), bbp_get_forum_title() ); ?></p>
+		</div>
+	</div>
+
+<?php else : ?>
+
+	<div id="no-topic-<?php bbp_topic_id(); ?>" class="bbp-no-topic">
+		<div class="bbp-template-notice">
+			<p><?php is_user_logged_in() ? _e( 'You cannot create new topics.', 'bbpress' ) : _e( 'You must be logged in to create new topics.', 'bbpress' ); ?></p>
+		</div>
+	</div>
+
+<?php endif; ?>
+
+<?php if ( !bbp_is_single_forum() ) : ?>
+
+</div>
+
+<?php endif; ?>
Index: /tags/2.5.4/templates/default/bbpress/form-user-edit.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-user-edit.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-user-edit.php	(revision 5382)
@@ -0,0 +1,182 @@
+<?php
+
+/**
+ * bbPress User Profile Edit Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<form id="bbp-your-profile" action="<?php bbp_user_profile_edit_url( bbp_get_displayed_user_id() ); ?>" method="post" enctype="multipart/form-data">
+
+	<h2 class="entry-title"><?php _e( 'Name', 'bbpress' ) ?></h2>
+
+	<?php do_action( 'bbp_user_edit_before' ); ?>
+
+	<fieldset class="bbp-form">
+		<legend><?php _e( 'Name', 'bbpress' ) ?></legend>
+
+		<?php do_action( 'bbp_user_edit_before_name' ); ?>
+
+		<div>
+			<label for="first_name"><?php _e( 'First Name', 'bbpress' ) ?></label>
+			<input type="text" name="first_name" id="first_name" value="<?php bbp_displayed_user_field( 'first_name', 'edit' ); ?>" class="regular-text" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<div>
+			<label for="last_name"><?php _e( 'Last Name', 'bbpress' ) ?></label>
+			<input type="text" name="last_name" id="last_name" value="<?php bbp_displayed_user_field( 'last_name', 'edit' ); ?>" class="regular-text" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<div>
+			<label for="nickname"><?php _e( 'Nickname', 'bbpress' ); ?></label>
+			<input type="text" name="nickname" id="nickname" value="<?php bbp_displayed_user_field( 'nickname', 'edit' ); ?>" class="regular-text" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<div>
+			<label for="display_name"><?php _e( 'Display Name', 'bbpress' ) ?></label>
+
+			<?php bbp_edit_user_display_name(); ?>
+
+		</div>
+
+		<?php do_action( 'bbp_user_edit_after_name' ); ?>
+
+	</fieldset>
+
+	<h2 class="entry-title"><?php _e( 'Contact Info', 'bbpress' ) ?></h2>
+
+	<fieldset class="bbp-form">
+		<legend><?php _e( 'Contact Info', 'bbpress' ) ?></legend>
+
+		<?php do_action( 'bbp_user_edit_before_contact' ); ?>
+
+		<div>
+			<label for="url"><?php _e( 'Website', 'bbpress' ) ?></label>
+			<input type="text" name="url" id="url" value="<?php bbp_displayed_user_field( 'user_url', 'edit' ); ?>" class="regular-text code" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<?php foreach ( bbp_edit_user_contact_methods() as $name => $desc ) : ?>
+
+			<div>
+				<label for="<?php echo esc_attr( $name ); ?>"><?php echo apply_filters( 'user_' . $name . '_label', $desc ); ?></label>
+				<input type="text" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $name ); ?>" value="<?php bbp_displayed_user_field( $name, 'edit' ); ?>" class="regular-text" tabindex="<?php bbp_tab_index(); ?>" />
+			</div>
+
+		<?php endforeach; ?>
+
+		<?php do_action( 'bbp_user_edit_after_contact' ); ?>
+
+	</fieldset>
+
+	<h2 class="entry-title"><?php bbp_is_user_home_edit() ? _e( 'About Yourself', 'bbpress' ) : _e( 'About the user', 'bbpress' ); ?></h2>
+
+	<fieldset class="bbp-form">
+		<legend><?php bbp_is_user_home_edit() ? _e( 'About Yourself', 'bbpress' ) : _e( 'About the user', 'bbpress' ); ?></legend>
+
+		<?php do_action( 'bbp_user_edit_before_about' ); ?>
+
+		<div>
+			<label for="description"><?php _e( 'Biographical Info', 'bbpress' ); ?></label>
+			<textarea name="description" id="description" rows="5" cols="30" tabindex="<?php bbp_tab_index(); ?>"><?php bbp_displayed_user_field( 'description', 'edit' ); ?></textarea>
+		</div>
+
+		<?php do_action( 'bbp_user_edit_after_about' ); ?>
+
+	</fieldset>
+
+	<h2 class="entry-title"><?php _e( 'Account', 'bbpress' ) ?></h2>
+
+	<fieldset class="bbp-form">
+		<legend><?php _e( 'Account', 'bbpress' ) ?></legend>
+
+		<?php do_action( 'bbp_user_edit_before_account' ); ?>
+
+		<div>
+			<label for="user_login"><?php _e( 'Username', 'bbpress' ); ?></label>
+			<input type="text" name="user_login" id="user_login" value="<?php bbp_displayed_user_field( 'user_login', 'edit' ); ?>" disabled="disabled" class="regular-text" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<div>
+			<label for="email"><?php _e( 'Email', 'bbpress' ); ?></label>
+
+			<input type="text" name="email" id="email" value="<?php bbp_displayed_user_field( 'user_email', 'edit' ); ?>" class="regular-text" tabindex="<?php bbp_tab_index(); ?>" />
+
+			<?php
+
+			// Handle address change requests
+			$new_email = get_option( bbp_get_displayed_user_id() . '_new_email' );
+			if ( !empty( $new_email ) && $new_email !== bbp_get_displayed_user_field( 'user_email', 'edit' ) ) : ?>
+
+				<span class="updated inline">
+
+					<?php printf( __( 'There is a pending email address change to <code>%1$s</code>. <a href="%2$s">Cancel</a>', 'bbpress' ), $new_email['newemail'], esc_url( self_admin_url( 'user.php?dismiss=' . bbp_get_current_user_id()  . '_new_email' ) ) ); ?>
+
+				</span>
+
+			<?php endif; ?>
+
+		</div>
+
+		<div id="password">
+			<label for="pass1"><?php _e( 'New Password', 'bbpress' ); ?></label>
+			<fieldset class="bbp-form password">
+				<input type="password" name="pass1" id="pass1" size="16" value="" autocomplete="off" tabindex="<?php bbp_tab_index(); ?>" />
+				<span class="description"><?php _e( 'If you would like to change the password type a new one. Otherwise leave this blank.', 'bbpress' ); ?></span>
+
+				<input type="password" name="pass2" id="pass2" size="16" value="" autocomplete="off" tabindex="<?php bbp_tab_index(); ?>" />
+				<span class="description"><?php _e( 'Type your new password again.', 'bbpress' ); ?></span><br />
+
+				<div id="pass-strength-result"></div>
+				<span class="description indicator-hint"><?php _e( 'Your password should be at least ten characters long. Use upper and lower case letters, numbers, and symbols to make it even stronger.', 'bbpress' ); ?></span>
+			</fieldset>
+		</div>
+
+		<?php do_action( 'bbp_user_edit_after_account' ); ?>
+
+	</fieldset>
+
+	<?php if ( current_user_can( 'edit_users' ) && ! bbp_is_user_home_edit() ) : ?>
+
+		<h2 class="entry-title"><?php _e( 'User Role', 'bbpress' ) ?></h2>
+
+		<fieldset class="bbp-form">
+			<legend><?php _e( 'User Role', 'bbpress' ); ?></legend>
+
+			<?php do_action( 'bbp_user_edit_before_role' ); ?>
+
+			<?php if ( is_multisite() && is_super_admin() && current_user_can( 'manage_network_options' ) ) : ?>
+
+				<div>
+					<label for="super_admin"><?php _e( 'Network Role', 'bbpress' ); ?></label>
+					<label>
+						<input class="checkbox" type="checkbox" id="super_admin" name="super_admin"<?php checked( is_super_admin( bbp_get_displayed_user_id() ) ); ?> tabindex="<?php bbp_tab_index(); ?>" />
+						<?php _e( 'Grant this user super admin privileges for the Network.', 'bbpress' ); ?>
+					</label>
+				</div>
+
+			<?php endif; ?>
+
+			<?php bbp_get_template_part( 'form', 'user-roles' ); ?>
+
+			<?php do_action( 'bbp_user_edit_after_role' ); ?>
+
+		</fieldset>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_user_edit_after' ); ?>
+
+	<fieldset class="submit">
+		<legend><?php _e( 'Save Changes', 'bbpress' ); ?></legend>
+		<div>
+
+			<?php bbp_edit_user_form_fields(); ?>
+
+			<button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_user_edit_submit" name="bbp_user_edit_submit" class="button submit user-submit"><?php bbp_is_user_home_edit() ? _e( 'Update Profile', 'bbpress' ) : _e( 'Update User', 'bbpress' ); ?></button>
+		</div>
+	</fieldset>
+
+</form>
Index: /tags/2.5.4/templates/default/bbpress/form-user-login.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-user-login.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-user-login.php	(revision 5382)
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * User Login Form
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<form method="post" action="<?php bbp_wp_login_action( array( 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
+	<fieldset class="bbp-form">
+		<legend><?php _e( 'Log In', 'bbpress' ); ?></legend>
+
+		<div class="bbp-username">
+			<label for="user_login"><?php _e( 'Username', 'bbpress' ); ?>: </label>
+			<input type="text" name="log" value="<?php bbp_sanitize_val( 'user_login', 'text' ); ?>" size="20" id="user_login" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<div class="bbp-password">
+			<label for="user_pass"><?php _e( 'Password', 'bbpress' ); ?>: </label>
+			<input type="password" name="pwd" value="<?php bbp_sanitize_val( 'user_pass', 'password' ); ?>" size="20" id="user_pass" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<div class="bbp-remember-me">
+			<input type="checkbox" name="rememberme" value="forever" <?php checked( bbp_get_sanitize_val( 'rememberme', 'checkbox' ) ); ?> id="rememberme" tabindex="<?php bbp_tab_index(); ?>" />
+			<label for="rememberme"><?php _e( 'Keep me signed in', 'bbpress' ); ?></label>
+		</div>
+
+		<?php do_action( 'login_form' ); ?>
+
+		<div class="bbp-submit-wrapper">
+
+			<button type="submit" tabindex="<?php bbp_tab_index(); ?>" name="user-submit" class="button submit user-submit"><?php _e( 'Log In', 'bbpress' ); ?></button>
+
+			<?php bbp_user_login_fields(); ?>
+
+		</div>
+	</fieldset>
+</form>
Index: /tags/2.5.4/templates/default/bbpress/form-user-lost-pass.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-user-lost-pass.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-user-lost-pass.php	(revision 5382)
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * User Lost Password Form
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<form method="post" action="<?php bbp_wp_login_action( array( 'action' => 'lostpassword', 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
+	<fieldset class="bbp-form">
+		<legend><?php _e( 'Lost Password', 'bbpress' ); ?></legend>
+
+		<div class="bbp-username">
+			<p>
+				<label for="user_login" class="hide"><?php _e( 'Username or Email', 'bbpress' ); ?>: </label>
+				<input type="text" name="user_login" value="" size="20" id="user_login" tabindex="<?php bbp_tab_index(); ?>" />
+			</p>
+		</div>
+
+		<?php do_action( 'login_form', 'resetpass' ); ?>
+
+		<div class="bbp-submit-wrapper">
+
+			<button type="submit" tabindex="<?php bbp_tab_index(); ?>" name="user-submit" class="button submit user-submit"><?php _e( 'Reset My Password', 'bbpress' ); ?></button>
+
+			<?php bbp_user_lost_pass_fields(); ?>
+
+		</div>
+	</fieldset>
+</form>
Index: /tags/2.5.4/templates/default/bbpress/form-user-register.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-user-register.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-user-register.php	(revision 5382)
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * User Registration Form
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<form method="post" action="<?php bbp_wp_login_action( array( 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
+	<fieldset class="bbp-form">
+		<legend><?php _e( 'Create an Account', 'bbpress' ); ?></legend>
+
+		<div class="bbp-template-notice">
+			<p><?php _e( 'Your username must be unique, and cannot be changed later.', 'bbpress' ) ?></p>
+			<p><?php _e( 'We use your email address to email you a secure password and verify your account.', 'bbpress' ) ?></p>
+
+		</div>
+
+		<div class="bbp-username">
+			<label for="user_login"><?php _e( 'Username', 'bbpress' ); ?>: </label>
+			<input type="text" name="user_login" value="<?php bbp_sanitize_val( 'user_login' ); ?>" size="20" id="user_login" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<div class="bbp-email">
+			<label for="user_email"><?php _e( 'Email', 'bbpress' ); ?>: </label>
+			<input type="text" name="user_email" value="<?php bbp_sanitize_val( 'user_email' ); ?>" size="20" id="user_email" tabindex="<?php bbp_tab_index(); ?>" />
+		</div>
+
+		<?php do_action( 'register_form' ); ?>
+
+		<div class="bbp-submit-wrapper">
+
+			<button type="submit" tabindex="<?php bbp_tab_index(); ?>" name="user-submit" class="button submit user-submit"><?php _e( 'Register', 'bbpress' ); ?></button>
+
+			<?php bbp_user_register_fields(); ?>
+
+		</div>
+	</fieldset>
+</form>
Index: /tags/2.5.4/templates/default/bbpress/form-user-roles.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/form-user-roles.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/form-user-roles.php	(revision 5382)
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * User Roles Profile Edit Part
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div>
+	<label for="role"><?php _e( 'Blog Role', 'bbpress' ) ?></label>
+
+	<?php bbp_edit_user_blog_role(); ?>
+
+</div>
+
+<div>
+	<label for="forum-role"><?php _e( 'Forum Role', 'bbpress' ) ?></label>
+
+	<?php bbp_edit_user_forums_role(); ?>
+
+</div>
Index: /tags/2.5.4/templates/default/bbpress/loop-forums.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-forums.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-forums.php	(revision 5382)
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * Forums Loop
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php do_action( 'bbp_template_before_forums_loop' ); ?>
+
+<ul id="forums-list-<?php bbp_forum_id(); ?>" class="bbp-forums">
+
+	<li class="bbp-header">
+
+		<ul class="forum-titles">
+			<li class="bbp-forum-info"><?php _e( 'Forum', 'bbpress' ); ?></li>
+			<li class="bbp-forum-topic-count"><?php _e( 'Topics', 'bbpress' ); ?></li>
+			<li class="bbp-forum-reply-count"><?php bbp_show_lead_topic() ? _e( 'Replies', 'bbpress' ) : _e( 'Posts', 'bbpress' ); ?></li>
+			<li class="bbp-forum-freshness"><?php _e( 'Freshness', 'bbpress' ); ?></li>
+		</ul>
+
+	</li><!-- .bbp-header -->
+
+	<li class="bbp-body">
+
+		<?php while ( bbp_forums() ) : bbp_the_forum(); ?>
+
+			<?php bbp_get_template_part( 'loop', 'single-forum' ); ?>
+
+		<?php endwhile; ?>
+
+	</li><!-- .bbp-body -->
+
+	<li class="bbp-footer">
+
+		<div class="tr">
+			<p class="td colspan4">&nbsp;</p>
+		</div><!-- .tr -->
+
+	</li><!-- .bbp-footer -->
+
+</ul><!-- .forums-directory -->
+
+<?php do_action( 'bbp_template_after_forums_loop' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/loop-replies.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-replies.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-replies.php	(revision 5382)
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * Replies Loop
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php do_action( 'bbp_template_before_replies_loop' ); ?>
+
+<ul id="topic-<?php bbp_topic_id(); ?>-replies" class="forums bbp-replies">
+
+	<li class="bbp-header">
+
+		<div class="bbp-reply-author"><?php  _e( 'Author',  'bbpress' ); ?></div><!-- .bbp-reply-author -->
+
+		<div class="bbp-reply-content">
+
+			<?php if ( !bbp_show_lead_topic() ) : ?>
+
+				<?php _e( 'Posts', 'bbpress' ); ?>
+
+				<?php bbp_topic_subscription_link(); ?>
+
+				<?php bbp_user_favorites_link(); ?>
+
+			<?php else : ?>
+
+				<?php _e( 'Replies', 'bbpress' ); ?>
+
+			<?php endif; ?>
+
+		</div><!-- .bbp-reply-content -->
+
+	</li><!-- .bbp-header -->
+
+	<li class="bbp-body">
+
+		<?php if ( bbp_thread_replies() ) : ?>
+
+			<?php bbp_list_replies(); ?>
+
+		<?php else : ?>
+
+			<?php while ( bbp_replies() ) : bbp_the_reply(); ?>
+
+				<?php bbp_get_template_part( 'loop', 'single-reply' ); ?>
+
+			<?php endwhile; ?>
+
+		<?php endif; ?>
+
+	</li><!-- .bbp-body -->
+
+	<li class="bbp-footer">
+
+		<div class="bbp-reply-author"><?php  _e( 'Author',  'bbpress' ); ?></div>
+
+		<div class="bbp-reply-content">
+
+			<?php if ( !bbp_show_lead_topic() ) : ?>
+
+				<?php _e( 'Posts', 'bbpress' ); ?>
+
+			<?php else : ?>
+
+				<?php _e( 'Replies', 'bbpress' ); ?>
+
+			<?php endif; ?>
+
+		</div><!-- .bbp-reply-content -->
+
+	</li><!-- .bbp-footer -->
+
+</ul><!-- #topic-<?php bbp_topic_id(); ?>-replies -->
+
+<?php do_action( 'bbp_template_after_replies_loop' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/loop-search-forum.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-search-forum.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-search-forum.php	(revision 5382)
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Search Loop - Single Forum
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-forum-header">
+
+	<div class="bbp-meta">
+
+		<span class="bbp-forum-post-date"><?php printf( __( 'Last updated %s', 'bbpress' ), bbp_get_forum_last_active_time() ); ?></span>
+
+		<a href="<?php bbp_forum_permalink(); ?>" class="bbp-forum-permalink">#<?php bbp_forum_id(); ?></a>
+
+	</div><!-- .bbp-meta -->
+
+	<div class="bbp-forum-title">
+
+		<?php do_action( 'bbp_theme_before_forum_title' ); ?>
+
+		<h3><?php _e( 'Forum: ', 'bbpress' ); ?><a href="<?php bbp_forum_permalink(); ?>"><?php bbp_forum_title(); ?></a></h3>
+
+		<?php do_action( 'bbp_theme_after_forum_title' ); ?>
+
+	</div><!-- .bbp-forum-title -->
+
+</div><!-- .bbp-forum-header -->
+
+<div id="post-<?php bbp_forum_id(); ?>" <?php bbp_forum_class(); ?>>
+
+	<div class="bbp-forum-content">
+
+		<?php do_action( 'bbp_theme_before_forum_content' ); ?>
+
+		<?php bbp_forum_content(); ?>
+
+		<?php do_action( 'bbp_theme_after_forum_content' ); ?>
+
+	</div><!-- .bbp-forum-content -->
+
+</div><!-- #post-<?php bbp_forum_id(); ?> -->
Index: /tags/2.5.4/templates/default/bbpress/loop-search-reply.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-search-reply.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-search-reply.php	(revision 5382)
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * Search Loop - Single Reply
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-reply-header">
+
+	<div class="bbp-meta">
+
+		<span class="bbp-reply-post-date"><?php bbp_reply_post_date(); ?></span>
+
+		<a href="<?php bbp_reply_url(); ?>" class="bbp-reply-permalink">#<?php bbp_reply_id(); ?></a>
+
+	</div><!-- .bbp-meta -->
+
+	<div class="bbp-reply-title">
+
+		<h3><?php _e( 'In reply to: ', 'bbpress' ); ?>
+		<a class="bbp-topic-permalink" href="<?php bbp_topic_permalink( bbp_get_reply_topic_id() ); ?>"><?php bbp_topic_title( bbp_get_reply_topic_id() ); ?></a></h3>
+
+	</div><!-- .bbp-reply-title -->
+
+</div><!-- .bbp-reply-header -->
+
+<div id="post-<?php bbp_reply_id(); ?>" <?php bbp_reply_class(); ?>>
+
+	<div class="bbp-reply-author">
+
+		<?php do_action( 'bbp_theme_before_reply_author_details' ); ?>
+
+		<?php bbp_reply_author_link( array( 'sep' => '<br />', 'show_role' => true ) ); ?>
+
+		<?php if ( bbp_is_user_keymaster() ) : ?>
+
+			<?php do_action( 'bbp_theme_before_reply_author_admin_details' ); ?>
+
+			<div class="bbp-reply-ip"><?php bbp_author_ip( bbp_get_reply_id() ); ?></div>
+
+			<?php do_action( 'bbp_theme_after_reply_author_admin_details' ); ?>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bbp_theme_after_reply_author_details' ); ?>
+
+	</div><!-- .bbp-reply-author -->
+
+	<div class="bbp-reply-content">
+
+		<?php do_action( 'bbp_theme_before_reply_content' ); ?>
+
+		<?php bbp_reply_content(); ?>
+
+		<?php do_action( 'bbp_theme_after_reply_content' ); ?>
+
+	</div><!-- .bbp-reply-content -->
+
+</div><!-- #post-<?php bbp_reply_id(); ?> -->
+
Index: /tags/2.5.4/templates/default/bbpress/loop-search-topic.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-search-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-search-topic.php	(revision 5382)
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Search Loop - Single Topic
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div class="bbp-topic-header">
+
+	<div class="bbp-meta">
+
+		<span class="bbp-topic-post-date"><?php bbp_topic_post_date( bbp_get_topic_id() ); ?></span>
+
+		<a href="<?php bbp_topic_permalink(); ?>" class="bbp-topic-permalink">#<?php bbp_topic_id(); ?></a>
+
+	</div><!-- .bbp-meta -->
+
+	<div class="bbp-topic-title">
+
+		<?php do_action( 'bbp_theme_before_topic_title' ); ?>
+
+		<h3><?php _e( 'Topic: ', 'bbpress' ); ?>
+		<a href="<?php bbp_topic_permalink(); ?>"><?php bbp_topic_title(); ?></a></h3>
+
+		<div class="bbp-topic-title-meta">
+
+			<?php if ( function_exists( 'bbp_is_forum_group_forum' ) && bbp_is_forum_group_forum( bbp_get_topic_forum_id() ) ) : ?>
+
+				<?php _e( 'in group forum ', 'bbpress' ); ?>
+
+			<?php else : ?>
+
+				<?php _e( 'in forum ', 'bbpress' ); ?>
+
+			<?php endif; ?>
+
+			<a href="<?php bbp_forum_permalink( bbp_get_topic_forum_id() ); ?>"><?php bbp_forum_title( bbp_get_topic_forum_id() ); ?></a>
+
+		</div><!-- .bbp-topic-title-meta -->
+
+		<?php do_action( 'bbp_theme_after_topic_title' ); ?>
+
+	</div><!-- .bbp-topic-title -->
+
+</div><!-- .bbp-topic-header -->
+
+<div id="post-<?php bbp_topic_id(); ?>" <?php bbp_topic_class(); ?>>
+
+	<div class="bbp-topic-author">
+
+		<?php do_action( 'bbp_theme_before_topic_author_details' ); ?>
+
+		<?php bbp_topic_author_link( array( 'sep' => '<br />', 'show_role' => true ) ); ?>
+
+		<?php if ( bbp_is_user_keymaster() ) : ?>
+
+			<?php do_action( 'bbp_theme_before_topic_author_admin_details' ); ?>
+
+			<div class="bbp-reply-ip"><?php bbp_author_ip( bbp_get_topic_id() ); ?></div>
+
+			<?php do_action( 'bbp_theme_after_topic_author_admin_details' ); ?>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bbp_theme_after_topic_author_details' ); ?>
+
+	</div><!-- .bbp-topic-author -->
+
+	<div class="bbp-topic-content">
+
+		<?php do_action( 'bbp_theme_before_topic_content' ); ?>
+
+		<?php bbp_topic_content(); ?>
+
+		<?php do_action( 'bbp_theme_after_topic_content' ); ?>
+
+	</div><!-- .bbp-topic-content -->
+
+</div><!-- #post-<?php bbp_topic_id(); ?> -->
Index: /tags/2.5.4/templates/default/bbpress/loop-search.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-search.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-search.php	(revision 5382)
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * Search Loop
+ *
+ * @package bbPress
+ * @subpackage Theme
+*/
+
+?>
+
+<?php do_action( 'bbp_template_before_search_results_loop' ); ?>
+
+<ul id="bbp-search-results" class="forums bbp-search-results">
+
+	<li class="bbp-header">
+
+		<div class="bbp-search-author"><?php  _e( 'Author',  'bbpress' ); ?></div><!-- .bbp-reply-author -->
+
+		<div class="bbp-search-content">
+
+			<?php _e( 'Search Results', 'bbpress' ); ?>
+
+		</div><!-- .bbp-search-content -->
+
+	</li><!-- .bbp-header -->
+
+	<li class="bbp-body">
+
+		<?php while ( bbp_search_results() ) : bbp_the_search_result(); ?>
+
+			<?php bbp_get_template_part( 'loop', 'search-' . get_post_type() ); ?>
+
+		<?php endwhile; ?>
+
+	</li><!-- .bbp-body -->
+
+	<li class="bbp-footer">
+
+		<div class="bbp-search-author"><?php  _e( 'Author',  'bbpress' ); ?></div>
+
+		<div class="bbp-search-content">
+
+			<?php _e( 'Search Results', 'bbpress' ); ?>
+
+		</div><!-- .bbp-search-content -->
+
+	</li><!-- .bbp-footer -->
+
+</ul><!-- #bbp-search-results -->
+
+<?php do_action( 'bbp_template_after_search_results_loop' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/loop-single-forum.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-single-forum.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-single-forum.php	(revision 5382)
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Forums Loop - Single Forum
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<ul id="bbp-forum-<?php bbp_forum_id(); ?>" <?php bbp_forum_class(); ?>>
+
+	<li class="bbp-forum-info">
+
+		<?php if ( bbp_is_user_home() && bbp_is_subscriptions() ) : ?>
+
+			<span class="bbp-row-actions">
+
+				<?php do_action( 'bbp_theme_before_forum_subscription_action' ); ?>
+
+				<?php bbp_forum_subscription_link( array( 'before' => '', 'subscribe' => '+', 'unsubscribe' => '&times;' ) ); ?>
+
+				<?php do_action( 'bbp_theme_after_forum_subscription_action' ); ?>
+
+			</span>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bbp_theme_before_forum_title' ); ?>
+
+		<a class="bbp-forum-title" href="<?php bbp_forum_permalink(); ?>"><?php bbp_forum_title(); ?></a>
+
+		<?php do_action( 'bbp_theme_after_forum_title' ); ?>
+
+		<?php do_action( 'bbp_theme_before_forum_description' ); ?>
+
+		<div class="bbp-forum-content"><?php bbp_forum_content(); ?></div>
+
+		<?php do_action( 'bbp_theme_after_forum_description' ); ?>
+
+		<?php do_action( 'bbp_theme_before_forum_sub_forums' ); ?>
+
+		<?php bbp_list_forums(); ?>
+
+		<?php do_action( 'bbp_theme_after_forum_sub_forums' ); ?>
+
+		<?php bbp_forum_row_actions(); ?>
+
+	</li>
+
+	<li class="bbp-forum-topic-count"><?php bbp_forum_topic_count(); ?></li>
+
+	<li class="bbp-forum-reply-count"><?php bbp_show_lead_topic() ? bbp_forum_reply_count() : bbp_forum_post_count(); ?></li>
+
+	<li class="bbp-forum-freshness">
+
+		<?php do_action( 'bbp_theme_before_forum_freshness_link' ); ?>
+
+		<?php bbp_forum_freshness_link(); ?>
+
+		<?php do_action( 'bbp_theme_after_forum_freshness_link' ); ?>
+
+		<p class="bbp-topic-meta">
+
+			<?php do_action( 'bbp_theme_before_topic_author' ); ?>
+
+			<span class="bbp-topic-freshness-author"><?php bbp_author_link( array( 'post_id' => bbp_get_forum_last_active_id(), 'size' => 14 ) ); ?></span>
+
+			<?php do_action( 'bbp_theme_after_topic_author' ); ?>
+
+		</p>
+	</li>
+
+</ul><!-- #bbp-forum-<?php bbp_forum_id(); ?> -->
Index: /tags/2.5.4/templates/default/bbpress/loop-single-reply.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-single-reply.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-single-reply.php	(revision 5382)
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * Replies Loop - Single Reply
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<div id="post-<?php bbp_reply_id(); ?>" class="bbp-reply-header">
+
+	<div class="bbp-meta">
+
+		<span class="bbp-reply-post-date"><?php bbp_reply_post_date(); ?></span>
+
+		<?php if ( bbp_is_single_user_replies() ) : ?>
+
+			<span class="bbp-header">
+				<?php _e( 'in reply to: ', 'bbpress' ); ?>
+				<a class="bbp-topic-permalink" href="<?php bbp_topic_permalink( bbp_get_reply_topic_id() ); ?>"><?php bbp_topic_title( bbp_get_reply_topic_id() ); ?></a>
+			</span>
+
+		<?php endif; ?>
+
+		<a href="<?php bbp_reply_url(); ?>" class="bbp-reply-permalink">#<?php bbp_reply_id(); ?></a>
+
+		<?php do_action( 'bbp_theme_before_reply_admin_links' ); ?>
+
+		<?php bbp_reply_admin_links(); ?>
+
+		<?php do_action( 'bbp_theme_after_reply_admin_links' ); ?>
+
+	</div><!-- .bbp-meta -->
+
+</div><!-- #post-<?php bbp_reply_id(); ?> -->
+
+<div <?php bbp_reply_class(); ?>>
+
+	<div class="bbp-reply-author">
+
+		<?php do_action( 'bbp_theme_before_reply_author_details' ); ?>
+
+		<?php bbp_reply_author_link( array( 'sep' => '<br />', 'show_role' => true ) ); ?>
+
+		<?php if ( bbp_is_user_keymaster() ) : ?>
+
+			<?php do_action( 'bbp_theme_before_reply_author_admin_details' ); ?>
+
+			<div class="bbp-reply-ip"><?php bbp_author_ip( bbp_get_reply_id() ); ?></div>
+
+			<?php do_action( 'bbp_theme_after_reply_author_admin_details' ); ?>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bbp_theme_after_reply_author_details' ); ?>
+
+	</div><!-- .bbp-reply-author -->
+
+	<div class="bbp-reply-content">
+
+		<?php do_action( 'bbp_theme_before_reply_content' ); ?>
+
+		<?php bbp_reply_content(); ?>
+
+		<?php do_action( 'bbp_theme_after_reply_content' ); ?>
+
+	</div><!-- .bbp-reply-content -->
+
+</div><!-- .reply -->
Index: /tags/2.5.4/templates/default/bbpress/loop-single-topic.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-single-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-single-topic.php	(revision 5382)
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * Topics Loop - Single
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<ul id="bbp-topic-<?php bbp_topic_id(); ?>" <?php bbp_topic_class(); ?>>
+
+	<li class="bbp-topic-title">
+
+		<?php if ( bbp_is_user_home() ) : ?>
+
+			<?php if ( bbp_is_favorites() ) : ?>
+
+				<span class="bbp-row-actions">
+
+					<?php do_action( 'bbp_theme_before_topic_favorites_action' ); ?>
+
+					<?php bbp_topic_favorite_link( array( 'before' => '', 'favorite' => '+', 'favorited' => '&times;' ) ); ?>
+
+					<?php do_action( 'bbp_theme_after_topic_favorites_action' ); ?>
+
+				</span>
+
+			<?php elseif ( bbp_is_subscriptions() ) : ?>
+
+				<span class="bbp-row-actions">
+
+					<?php do_action( 'bbp_theme_before_topic_subscription_action' ); ?>
+
+					<?php bbp_topic_subscription_link( array( 'before' => '', 'subscribe' => '+', 'unsubscribe' => '&times;' ) ); ?>
+
+					<?php do_action( 'bbp_theme_after_topic_subscription_action' ); ?>
+
+				</span>
+
+			<?php endif; ?>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bbp_theme_before_topic_title' ); ?>
+
+		<a class="bbp-topic-permalink" href="<?php bbp_topic_permalink(); ?>"><?php bbp_topic_title(); ?></a>
+
+		<?php do_action( 'bbp_theme_after_topic_title' ); ?>
+
+		<?php bbp_topic_pagination(); ?>
+
+		<?php do_action( 'bbp_theme_before_topic_meta' ); ?>
+
+		<p class="bbp-topic-meta">
+
+			<?php do_action( 'bbp_theme_before_topic_started_by' ); ?>
+
+			<span class="bbp-topic-started-by"><?php printf( __( 'Started by: %1$s', 'bbpress' ), bbp_get_topic_author_link( array( 'size' => '14' ) ) ); ?></span>
+
+			<?php do_action( 'bbp_theme_after_topic_started_by' ); ?>
+
+			<?php if ( !bbp_is_single_forum() || ( bbp_get_topic_forum_id() !== bbp_get_forum_id() ) ) : ?>
+
+				<?php do_action( 'bbp_theme_before_topic_started_in' ); ?>
+
+				<span class="bbp-topic-started-in"><?php printf( __( 'in: <a href="%1$s">%2$s</a>', 'bbpress' ), bbp_get_forum_permalink( bbp_get_topic_forum_id() ), bbp_get_forum_title( bbp_get_topic_forum_id() ) ); ?></span>
+
+				<?php do_action( 'bbp_theme_after_topic_started_in' ); ?>
+
+			<?php endif; ?>
+
+		</p>
+
+		<?php do_action( 'bbp_theme_after_topic_meta' ); ?>
+
+		<?php bbp_topic_row_actions(); ?>
+
+	</li>
+
+	<li class="bbp-topic-voice-count"><?php bbp_topic_voice_count(); ?></li>
+
+	<li class="bbp-topic-reply-count"><?php bbp_show_lead_topic() ? bbp_topic_reply_count() : bbp_topic_post_count(); ?></li>
+
+	<li class="bbp-topic-freshness">
+
+		<?php do_action( 'bbp_theme_before_topic_freshness_link' ); ?>
+
+		<?php bbp_topic_freshness_link(); ?>
+
+		<?php do_action( 'bbp_theme_after_topic_freshness_link' ); ?>
+
+		<p class="bbp-topic-meta">
+
+			<?php do_action( 'bbp_theme_before_topic_freshness_author' ); ?>
+
+			<span class="bbp-topic-freshness-author"><?php bbp_author_link( array( 'post_id' => bbp_get_topic_last_active_id(), 'size' => 14 ) ); ?></span>
+
+			<?php do_action( 'bbp_theme_after_topic_freshness_author' ); ?>
+
+		</p>
+	</li>
+
+</ul><!-- #bbp-topic-<?php bbp_topic_id(); ?> -->
Index: /tags/2.5.4/templates/default/bbpress/loop-topics.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/loop-topics.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/loop-topics.php	(revision 5382)
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Topics Loop
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php do_action( 'bbp_template_before_topics_loop' ); ?>
+
+<ul id="bbp-forum-<?php bbp_forum_id(); ?>" class="bbp-topics">
+
+	<li class="bbp-header">
+
+		<ul class="forum-titles">
+			<li class="bbp-topic-title"><?php _e( 'Topic', 'bbpress' ); ?></li>
+			<li class="bbp-topic-voice-count"><?php _e( 'Voices', 'bbpress' ); ?></li>
+			<li class="bbp-topic-reply-count"><?php bbp_show_lead_topic() ? _e( 'Replies', 'bbpress' ) : _e( 'Posts', 'bbpress' ); ?></li>
+			<li class="bbp-topic-freshness"><?php _e( 'Freshness', 'bbpress' ); ?></li>
+		</ul>
+
+	</li>
+
+	<li class="bbp-body">
+
+		<?php while ( bbp_topics() ) : bbp_the_topic(); ?>
+
+			<?php bbp_get_template_part( 'loop', 'single-topic' ); ?>
+
+		<?php endwhile; ?>
+
+	</li>
+
+	<li class="bbp-footer">
+
+		<div class="tr">
+			<p>
+				<span class="td colspan<?php echo ( bbp_is_user_home() && ( bbp_is_favorites() || bbp_is_subscriptions() ) ) ? '5' : '4'; ?>">&nbsp;</span>
+			</p>
+		</div><!-- .tr -->
+
+	</li>
+
+</ul><!-- #bbp-forum-<?php bbp_forum_id(); ?> -->
+
+<?php do_action( 'bbp_template_after_topics_loop' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/pagination-replies.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/pagination-replies.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/pagination-replies.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Pagination for pages of replies (when viewing a topic)
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php do_action( 'bbp_template_before_pagination_loop' ); ?>
+
+<div class="bbp-pagination">
+	<div class="bbp-pagination-count">
+
+		<?php bbp_topic_pagination_count(); ?>
+
+	</div>
+
+	<div class="bbp-pagination-links">
+
+		<?php bbp_topic_pagination_links(); ?>
+
+	</div>
+</div>
+
+<?php do_action( 'bbp_template_after_pagination_loop' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/pagination-search.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/pagination-search.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/pagination-search.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Pagination for pages of search results 
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php do_action( 'bbp_template_before_pagination_loop' ); ?>
+
+<div class="bbp-pagination">
+	<div class="bbp-pagination-count">
+
+		<?php bbp_search_pagination_count(); ?>
+
+	</div>
+
+	<div class="bbp-pagination-links">
+
+		<?php bbp_search_pagination_links(); ?>
+
+	</div>
+</div>
+
+<?php do_action( 'bbp_template_after_pagination_loop' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/pagination-topics.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/pagination-topics.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/pagination-topics.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Pagination for pages of topics (when viewing a forum)
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+<?php do_action( 'bbp_template_before_pagination_loop' ); ?>
+
+<div class="bbp-pagination">
+	<div class="bbp-pagination-count">
+
+		<?php bbp_forum_pagination_count(); ?>
+
+	</div>
+
+	<div class="bbp-pagination-links">
+
+		<?php bbp_forum_pagination_links(); ?>
+
+	</div>
+</div>
+
+<?php do_action( 'bbp_template_after_pagination_loop' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/user-details.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/user-details.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/user-details.php	(revision 5382)
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * User Details
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+	<?php do_action( 'bbp_template_before_user_details' ); ?>
+
+	<div id="bbp-single-user-details">
+		<div id="bbp-user-avatar">
+
+			<span class='vcard'>
+				<a class="url fn n" href="<?php bbp_user_profile_url(); ?>" title="<?php bbp_displayed_user_field( 'display_name' ); ?>" rel="me">
+					<?php echo get_avatar( bbp_get_displayed_user_field( 'user_email', 'raw' ), apply_filters( 'bbp_single_user_details_avatar_size', 150 ) ); ?>
+				</a>
+			</span>
+
+		</div><!-- #author-avatar -->
+
+		<div id="bbp-user-navigation">
+			<ul>
+				<li class="<?php if ( bbp_is_single_user_profile() ) :?>current<?php endif; ?>">
+					<span class="vcard bbp-user-profile-link">
+						<a class="url fn n" href="<?php bbp_user_profile_url(); ?>" title="<?php printf( esc_attr__( "%s's Profile", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>" rel="me"><?php _e( 'Profile', 'bbpress' ); ?></a>
+					</span>
+				</li>
+
+				<li class="<?php if ( bbp_is_single_user_topics() ) :?>current<?php endif; ?>">
+					<span class='bbp-user-topics-created-link'>
+						<a href="<?php bbp_user_topics_created_url(); ?>" title="<?php printf( esc_attr__( "%s's Topics Started", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php _e( 'Topics Started', 'bbpress' ); ?></a>
+					</span>
+				</li>
+
+				<li class="<?php if ( bbp_is_single_user_replies() ) :?>current<?php endif; ?>">
+					<span class='bbp-user-replies-created-link'>
+						<a href="<?php bbp_user_replies_created_url(); ?>" title="<?php printf( esc_attr__( "%s's Replies Created", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php _e( 'Replies Created', 'bbpress' ); ?></a>
+					</span>
+				</li>
+
+				<?php if ( bbp_is_favorites_active() ) : ?>
+					<li class="<?php if ( bbp_is_favorites() ) :?>current<?php endif; ?>">
+						<span class="bbp-user-favorites-link">
+							<a href="<?php bbp_favorites_permalink(); ?>" title="<?php printf( esc_attr__( "%s's Favorites", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php _e( 'Favorites', 'bbpress' ); ?></a>
+						</span>
+					</li>
+				<?php endif; ?>
+
+				<?php if ( bbp_is_user_home() || current_user_can( 'edit_users' ) ) : ?>
+
+					<?php if ( bbp_is_subscriptions_active() ) : ?>
+						<li class="<?php if ( bbp_is_subscriptions() ) :?>current<?php endif; ?>">
+							<span class="bbp-user-subscriptions-link">
+								<a href="<?php bbp_subscriptions_permalink(); ?>" title="<?php printf( esc_attr__( "%s's Subscriptions", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php _e( 'Subscriptions', 'bbpress' ); ?></a>
+							</span>
+						</li>
+					<?php endif; ?>
+
+					<li class="<?php if ( bbp_is_single_user_edit() ) :?>current<?php endif; ?>">
+						<span class="bbp-user-edit-link">
+							<a href="<?php bbp_user_profile_edit_url(); ?>" title="<?php printf( esc_attr__( "Edit %s's Profile", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php _e( 'Edit', 'bbpress' ); ?></a>
+						</span>
+					</li>
+
+				<?php endif; ?>
+
+			</ul>
+		</div><!-- #bbp-user-navigation -->
+	</div><!-- #bbp-single-user-details -->
+
+	<?php do_action( 'bbp_template_after_user_details' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/user-favorites.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/user-favorites.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/user-favorites.php	(revision 5382)
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * User Favorites
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+	<?php do_action( 'bbp_template_before_user_favorites' ); ?>
+
+	<div id="bbp-user-favorites" class="bbp-user-favorites">
+		<h2 class="entry-title"><?php _e( 'Favorite Forum Topics', 'bbpress' ); ?></h2>
+		<div class="bbp-user-section">
+
+			<?php if ( bbp_get_user_favorites() ) : ?>
+
+				<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+				<?php bbp_get_template_part( 'loop',       'topics' ); ?>
+
+				<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+			<?php else : ?>
+
+				<p><?php bbp_is_user_home() ? _e( 'You currently have no favorite topics.', 'bbpress' ) : _e( 'This user has no favorite topics.', 'bbpress' ); ?></p>
+
+			<?php endif; ?>
+
+		</div>
+	</div><!-- #bbp-user-favorites -->
+
+	<?php do_action( 'bbp_template_after_user_favorites' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/user-profile.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/user-profile.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/user-profile.php	(revision 5382)
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * User Profile
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+	<?php do_action( 'bbp_template_before_user_profile' ); ?>
+
+	<div id="bbp-user-profile" class="bbp-user-profile">
+		<h2 class="entry-title"><?php _e( 'Profile', 'bbpress' ); ?></h2>
+		<div class="bbp-user-section">
+
+			<?php if ( bbp_get_displayed_user_field( 'description' ) ) : ?>
+
+				<p class="bbp-user-description"><?php bbp_displayed_user_field( 'description' ); ?></p>
+
+			<?php endif; ?>
+
+			<p class="bbp-user-forum-role"><?php  printf( __( 'Forum Role: %s',      'bbpress' ), bbp_get_user_display_role()    ); ?></p>
+			<p class="bbp-user-topic-count"><?php printf( __( 'Topics Started: %s',  'bbpress' ), bbp_get_user_topic_count_raw() ); ?></p>
+			<p class="bbp-user-reply-count"><?php printf( __( 'Replies Created: %s', 'bbpress' ), bbp_get_user_reply_count_raw() ); ?></p>
+		</div>
+	</div><!-- #bbp-author-topics-started -->
+
+	<?php do_action( 'bbp_template_after_user_profile' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/user-replies-created.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/user-replies-created.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/user-replies-created.php	(revision 5382)
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * User Replies Created
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+	<?php do_action( 'bbp_template_before_user_replies' ); ?>
+
+	<div id="bbp-user-replies-created" class="bbp-user-replies-created">
+		<h2 class="entry-title"><?php _e( 'Forum Replies Created', 'bbpress' ); ?></h2>
+		<div class="bbp-user-section">
+
+			<?php if ( bbp_get_user_replies_created() ) : ?>
+
+				<?php bbp_get_template_part( 'pagination', 'replies' ); ?>
+
+				<?php bbp_get_template_part( 'loop',       'replies' ); ?>
+
+				<?php bbp_get_template_part( 'pagination', 'replies' ); ?>
+
+			<?php else : ?>
+
+				<p><?php bbp_is_user_home() ? _e( 'You have not replied to any topics.', 'bbpress' ) : _e( 'This user has not replied to any topics.', 'bbpress' ); ?></p>
+
+			<?php endif; ?>
+
+		</div>
+	</div><!-- #bbp-user-replies-created -->
+
+	<?php do_action( 'bbp_template_after_user_replies' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/user-subscriptions.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/user-subscriptions.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/user-subscriptions.php	(revision 5382)
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * User Subscriptions
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+	<?php do_action( 'bbp_template_before_user_subscriptions' ); ?>
+
+	<?php if ( bbp_is_subscriptions_active() ) : ?>
+
+		<?php if ( bbp_is_user_home() || current_user_can( 'edit_users' ) ) : ?>
+
+			<div id="bbp-user-subscriptions" class="bbp-user-subscriptions">
+				<h2 class="entry-title"><?php _e( 'Subscribed Forums', 'bbpress' ); ?></h2>
+				<div class="bbp-user-section">
+
+					<?php if ( bbp_get_user_forum_subscriptions() ) : ?>
+
+						<?php bbp_get_template_part( 'loop', 'forums' ); ?>
+
+					<?php else : ?>
+
+						<p><?php bbp_is_user_home() ? _e( 'You are not currently subscribed to any forums.', 'bbpress' ) : _e( 'This user is not currently subscribed to any forums.', 'bbpress' ); ?></p>
+
+					<?php endif; ?>
+
+				</div>
+
+				<h2 class="entry-title"><?php _e( 'Subscribed Topics', 'bbpress' ); ?></h2>
+				<div class="bbp-user-section">
+
+					<?php if ( bbp_get_user_topic_subscriptions() ) : ?>
+
+						<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+						<?php bbp_get_template_part( 'loop',       'topics' ); ?>
+
+						<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+					<?php else : ?>
+
+						<p><?php bbp_is_user_home() ? _e( 'You are not currently subscribed to any topics.', 'bbpress' ) : _e( 'This user is not currently subscribed to any topics.', 'bbpress' ); ?></p>
+
+					<?php endif; ?>
+
+				</div>
+			</div><!-- #bbp-user-subscriptions -->
+
+		<?php endif; ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_template_after_user_subscriptions' ); ?>
Index: /tags/2.5.4/templates/default/bbpress/user-topics-created.php
===================================================================
--- /tags/2.5.4/templates/default/bbpress/user-topics-created.php	(revision 5382)
+++ /tags/2.5.4/templates/default/bbpress/user-topics-created.php	(revision 5382)
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * User Topics Created
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+?>
+
+	<?php do_action( 'bbp_template_before_user_topics_created' ); ?>
+
+	<div id="bbp-user-topics-started" class="bbp-user-topics-started">
+		<h2 class="entry-title"><?php _e( 'Forum Topics Started', 'bbpress' ); ?></h2>
+		<div class="bbp-user-section">
+
+			<?php if ( bbp_get_user_topics_started() ) : ?>
+
+				<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+				<?php bbp_get_template_part( 'loop',       'topics' ); ?>
+
+				<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+			<?php else : ?>
+
+				<p><?php bbp_is_user_home() ? _e( 'You have not created any topics.', 'bbpress' ) : _e( 'This user has not created any topics.', 'bbpress' ); ?></p>
+
+			<?php endif; ?>
+
+		</div>
+	</div><!-- #bbp-user-topics-started -->
+
+	<?php do_action( 'bbp_template_after_user_topics_created' ); ?>
Index: /tags/2.5.4/templates/default/css/bbpress-rtl.css
===================================================================
--- /tags/2.5.4/templates/default/css/bbpress-rtl.css	(revision 5382)
+++ /tags/2.5.4/templates/default/css/bbpress-rtl.css	(revision 5382)
@@ -0,0 +1,344 @@
+/**
+ * bbPress RTL (Right-To-Left) CSS
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+/* =bbPress Style
+-------------------------------------------------------------- */
+
+#bbpress-forums .bbp-forums-list {
+    border-right: 1px solid #ddd;
+    padding-right: 15px;
+    margin: 0 5px 0 0;
+    padding-left: 0;
+    border-left: 0;
+}
+#bbpress-forums ul.bbp-threaded-replies {
+    margin-right: 50px;
+    margin-left: 0;
+}
+li.bbp-forum-info,
+li.bbp-topic-title {
+    float: right;
+    text-align: right;
+}
+li.bbp-forum-topic-count,
+li.bbp-topic-voice-count,
+li.bbp-forum-reply-count,
+li.bbp-topic-reply-count {
+    float: right;
+}
+li.bbp-forum-freshness,
+li.bbp-topic-freshness {
+    float: right;
+}
+#bbpress-forums div.bbp-topic-author a.bbp-author-name,
+#bbpress-forums div.bbp-reply-author a.bbp-author-name {
+    clear: right;
+}
+li.bbp-header div.bbp-topic-content span#subscription-toggle,
+li.bbp-header div.bbp-topic-content span#favorite-toggle,
+li.bbp-header div.bbp-reply-content span#subscription-toggle,
+li.bbp-header div.bbp-reply-content span#favorite-toggle {
+    float: left;
+}
+#bbpress-forums div.bbp-forum-author,
+#bbpress-forums div.bbp-topic-author,
+#bbpress-forums div.bbp-reply-author {
+    float: right;
+}
+#bbpress-forums li.bbp-header .bbp-search-author,
+#bbpress-forums li.bbp-footer .bbp-search-author,
+#bbpress-forums li.bbp-header .bbp-forum-author,
+#bbpress-forums li.bbp-footer .bbp-forum-author,
+#bbpress-forums li.bbp-header .bbp-topic-author,
+#bbpress-forums li.bbp-footer .bbp-topic-author,
+#bbpress-forums li.bbp-header .bbp-reply-author,
+#bbpress-forums li.bbp-footer .bbp-reply-author {
+    float: right;
+}
+#bbpress-forums li.bbp-header .bbp-search-content,
+#bbpress-forums li.bbp-footer .bbp-search-content,
+#bbpress-forums li.bbp-header .bbp-forum-content,
+#bbpress-forums li.bbp-footer .bbp-forum-content,
+#bbpress-forums li.bbp-header .bbp-topic-content,
+#bbpress-forums li.bbp-footer .bbp-topic-content,
+#bbpress-forums li.bbp-header .bbp-reply-content,
+#bbpress-forums li.bbp-footer .bbp-reply-content {
+    margin-right: 140px;
+    text-align: right;
+    margin-left: 0;
+}
+
+/* =Topic and reply content
+-------------------------------------------------------------- */
+
+#bbpress-forums div.bbp-forum-content,
+#bbpress-forums div.bbp-topic-content,
+#bbpress-forums div.bbp-reply-content {
+    padding: 12px 0 12px 12px;
+    margin-right: 130px;
+    text-align: right;
+    margin-left: 0;
+}
+
+/* =Reply to
+-------------------------------------------------------------- */
+
+#bbpress-forums div.bbp-reply-to {
+    padding: 12px 0px 12px 12px;
+    margin-right: 130px;
+    text-align: left;
+    margin-left: 0;
+}
+#bbpress-forums div#bbp-cancel-reply-to {
+    text-align: left;
+}
+
+/* =Breadcrumb and Tags
+-------------------------------------------------------------- */
+
+div.bbp-breadcrumb {
+    float: right;
+}
+
+/* =Search
+-------------------------------------------------------------- */
+
+#bbpress-forums #bbp-search-form {
+    clear: right;
+}
+#bbpress-forums div.bbp-search-form {
+    float: left;
+}
+
+/* =Admin Links
+-------------------------------------------------------------- */
+
+span.bbp-admin-links {
+    float: left;
+}
+fieldset span.bbp-admin-links {
+    float: right;
+}
+.bbp-forum-header a.bbp-forum-permalink,
+.bbp-topic-header a.bbp-topic-permalink,
+.bbp-reply-header a.bbp-reply-permalink {
+    margin-right: 10px;
+    margin-left: 0;
+    float: left;
+}
+
+/* =Pagination
+-------------------------------------------------------------- */
+
+.bbp-pagination-count {
+    float: right;
+}
+.bbp-pagination-links {
+    float: left;
+}
+.bbp-pagination-links a,
+.bbp-pagination-links span.current {
+    margin-right: 5px;
+    margin-left: 0;
+    float: right;
+}
+.bbp-pagination-links span.dots {
+    margin-right: 5px;
+    margin-left: 0;
+    float: right;
+}
+.bbp-pagination {
+    float: right;
+}
+.bbp-topic-pagination {
+    margin-right: 5px;
+    margin-left: 0;
+}
+
+/* =Forms
+-------------------------------------------------------------- */
+
+#bbpress-forums fieldset.bbp-form {
+    clear: right;
+}
+#bbpress-forums fieldset.bbp-forum-form-attributes {
+    margin-right: 25px;
+    margin-left: 25px;
+    float: left;
+}
+.bbp-topic-form,
+.bbp-reply-form,
+.bbp-topic-tag-form {
+    clear: right;
+}
+body.topic-edit .bbp-topic-form div.avatar img,
+body.reply-edit .bbp-reply-form div.avatar img,
+body.single-forum .bbp-topic-form div.avatar img,
+body.single-reply .bbp-reply-form div.avatar img {
+    margin-left: 0;
+}
+#bbpress-forums div.bbp-topic-tags {
+    float: left;
+}
+div.bbp-submit-wrapper {
+    float: left;
+}
+
+
+/* =TinyMCE in themes
+-------------------------------------------------------------- */
+
+#bbpress-forums div.bbp-the-content-wrapper input {
+    margin: 0 0 0 2px;
+}
+
+/* =Edit User
+-------------------------------------------------------------- */
+
+#bbpress-forums #bbp-your-profile fieldset div {
+    float: right;
+    clear: right;
+}
+#bbpress-forums #bbp-your-profile fieldset label[for] {
+    padding: 5px 5px 5px 20px;
+    text-align: left;
+    float: right;
+}
+#bbpress-forums #bbp-your-profile fieldset dl label[for] {
+    text-align: right;
+}
+#bbpress-forums #bbp-your-profile fieldset span.description {
+    float: right;
+    clear: right;
+}
+#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description {
+    margin-right: 0;
+}
+#bbpress-forums #bbp-your-profile fieldset.submit button {
+    float: left;
+}
+
+/* =Widgets
+-------------------------------------------------------------- */
+
+.bbp-login-form .bbp-submit-wrapper {
+    text-align: left;
+}
+.bbp-login-form .bbp-login-links a {
+    float: right;
+    clear: right;
+}
+.bbp-logged-in img.avatar {
+    margin: 0 0 0 15px;
+    float: right;
+}
+
+/* =Avatars
+-------------------------------------------------------------- */
+
+fieldset div.avatar {
+    float: left;
+}
+
+/* =BuddyPress Activity Streams
+-------------------------------------------------------------- */
+
+.activity-list li.bbp_topic_create .activity-content .activity-inner,
+.activity-list li.bbp_reply_create .activity-content .activity-inner {
+    border-right: 2px solid #eaeaea;
+    padding-right: 10px;
+    margin-right: 5px;
+    padding-right:0;
+    border-right:0;
+    margin-right:0;
+}
+
+
+/* =User Pages
+-------------------------------------------------------------- */
+
+#bbpress-forums #bbp-user-wrapper {
+    float: right;
+}
+#bbpress-forums #bbp-single-user-details {
+    float: right;
+}
+#bbpress-forums #bbp-single-user-details #bbp-user-description {
+    margin-right: 180px;
+    margin-left: 0;
+}
+#bbpress-forums #bbp-user-body {
+    margin-right: 180px;
+    margin-left: 0;
+}
+
+/*--------------------------------------------------------------
+ Media Queries
+--------------------------------------------------------------*/
+
+/* =Standard Mobile Landscape
+-------------------------------------------------------------- */
+@media only screen and (max-width: 480px) {
+    #bbpress-forums div.bbp-topic-tags {
+        clear: left;
+        float: left;
+    }
+    span.bbp-reply-post-date {
+        float: left;
+    }
+    span.bbp-admin-links {
+        clear: left;
+        float: left;
+    }
+    #bbpress-forums .bbp-body div.bbp-reply-author {
+        padding-left: 80px;
+        padding-right: 0;
+        text-align: left;
+    }
+    #bbpress-forums div.bbp-reply-author a.bbp-author-name {
+        margin-left: 0;
+    }
+    #bbpress-forums div.bbp-reply-author img.avatar {
+        left: auto;
+        left: 0;
+    }
+    div.bbp-submit-wrapper {
+        float: left;
+    }
+    #bbpress-forums #bbp-user-body {
+        margin-left: 0;
+    }
+}
+
+/* =Standard Mobile Portrait
+-------------------------------------------------------------- */
+@media only screen and (max-width: 320px) {
+    #bbpress-forums li.bbp-header div.bbp-reply-author {
+        text-align: left;
+    }
+    #bbpress-forums li.bbp-header div.bbp-reply-content {
+        margin-left: 25%;
+        margin-right: 0;
+    }
+}
+
+/* =Extra Small Mobile
+-------------------------------------------------------------- */
+@media only screen and (max-width: 240px) {
+    #bbpress-forums li.bbp-body li.bbp-topic-freshness,
+    #bbpress-forums li.bbp-header div.bbp-reply-content {
+        margin-left: 0;
+        text-align: left;
+    }
+    #bbpress-forums li.bbp-footer div.bbp-reply-content {
+        margin-left: 0;
+    }
+    #bbpress-forums li.bbp-body div.bbp-reply-author {
+        padding-left: 60px;
+        padding-right: 0;
+    }
+}
Index: /tags/2.5.4/templates/default/css/bbpress-rtl.min.css
===================================================================
--- /tags/2.5.4/templates/default/css/bbpress-rtl.min.css	(revision 5382)
+++ /tags/2.5.4/templates/default/css/bbpress-rtl.min.css	(revision 5382)
@@ -0,0 +1,1 @@
+#bbpress-forums hr{margin:0 0 24px 0}#bbpress-forums{background:transparent;clear:both;margin-bottom:20px;overflow:hidden;font-size:12px}#bbpress-forums div.even,#bbpress-forums ul.even{background-color:#fff}#bbpress-forums div.odd,#bbpress-forums ul.odd{background-color:#fbfbfb}body.reply-edit .reply{float:none}#bbpress-forums .type-reply{height:auto;width:100%}#bbpress-forums div.bbp-forum-header,#bbpress-forums div.bbp-topic-header,#bbpress-forums div.bbp-reply-header{background-color:#f4f4f4}#bbpress-forums .status-trash.even,#bbpress-forums .status-spam.even{background-color:#fee}#bbpress-forums .status-trash.odd,#bbpress-forums .status-spam.odd{background-color:#fdd}#bbpress-forums .status-closed,#bbpress-forums .status-closed a{color:#ccc}#bbpress-forums ul{background:0;list-style:none;margin:0;padding:0}#bbpress-forums ul.bbp-threaded-replies{margin-right:50px}#bbpress-forums li{background:0;margin:0;list-style:none}#bbpress-forums ul.bbp-lead-topic,#bbpress-forums ul.bbp-topics,#bbpress-forums ul.bbp-forums,#bbpress-forums ul.bbp-replies,#bbpress-forums ul.bbp-search-results{font-size:12px;overflow:hidden;border:1px solid #eee;margin-bottom:20px;clear:both}#bbpress-forums li.bbp-header,#bbpress-forums li.bbp-body,#bbpress-forums li.bbp-footer{clear:both}#bbpress-forums li.bbp-header,#bbpress-forums li.bbp-footer{background:#f3f3f3;border-top:1px solid #eee;font-weight:bold;padding:8px;text-align:center}#bbpress-forums li.bbp-header{background:#eaeaea}#bbpress-forums li.bbp-header ul{overflow:hidden}#bbpress-forums .bbp-forums-list{margin:0 5px 0 0;padding-right:15px;border-right:1px solid #ddd}#bbpress-forums .bbp-forums-list li{display:inline;font-size:11px}#bbpress-forums li.bbp-footer p{margin:0;line-height:1em}li.bbp-forum-info,li.bbp-topic-title{float:right;text-align:right;width:55%}li.bbp-forum-topic-count,li.bbp-topic-voice-count,li.bbp-forum-reply-count,li.bbp-topic-reply-count{float:right;text-align:center;width:10%}li.bbp-forum-freshness,li.bbp-topic-freshness{text-align:center;float:right;width:22%}#bbpress-forums li.bbp-body ul.forum,#bbpress-forums li.bbp-body ul.topic{border-top:1px solid #eee;overflow:hidden;padding:8px}li.bbp-header div.bbp-topic-content span#subscription-toggle,li.bbp-header div.bbp-topic-content span#favorite-toggle,li.bbp-header div.bbp-reply-content span#subscription-toggle,li.bbp-header div.bbp-reply-content span#favorite-toggle{float:left}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-topic-title h3,#bbpress-forums div.bbp-reply-title h3{background:0;border:0;font-size:16px;line-height:1em;margin:8px 0;padding:0;text-transform:none}#bbpress-forums div.bbp-forum-author,#bbpress-forums div.bbp-topic-author,#bbpress-forums div.bbp-reply-author{float:right;text-align:center;width:115px}#bbpress-forums div.bbp-forum-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar,#bbpress-forums div.bbp-reply-author img.avatar{border:0;max-width:80px;padding:0;margin:12px auto 0 auto;float:none}#bbpress-forums div.bbp-forum-author a.bbp-author-name,#bbpress-forums div.bbp-topic-author a.bbp-author-name,#bbpress-forums div.bbp-reply-author a.bbp-author-name{margin:0 12px;word-break:break-word;display:inline-block}#bbpress-forums div.bbp-topic-author a.bbp-author-name,#bbpress-forums div.bbp-reply-author a.bbp-author-name{clear:right;display:block}#bbpress-forums div.bbp-forum-author .bbp-author-role,#bbpress-forums div.bbp-topic-author .bbp-author-role,#bbpress-forums div.bbp-reply-author .bbp-author-role{font-size:11px;font-style:italic}#bbpress-forums li.bbp-header .bbp-search-author,#bbpress-forums li.bbp-footer .bbp-search-author,#bbpress-forums li.bbp-header .bbp-forum-author,#bbpress-forums li.bbp-footer .bbp-forum-author,#bbpress-forums li.bbp-header .bbp-topic-author,#bbpress-forums li.bbp-footer .bbp-topic-author,#bbpress-forums li.bbp-header .bbp-reply-author,#bbpress-forums li.bbp-footer .bbp-reply-author{float:right;margin:0;padding:0;width:120px}#bbpress-forums li.bbp-header .bbp-search-content,#bbpress-forums li.bbp-footer .bbp-search-content,#bbpress-forums li.bbp-header .bbp-forum-content,#bbpress-forums li.bbp-footer .bbp-forum-content,#bbpress-forums li.bbp-header .bbp-topic-content,#bbpress-forums li.bbp-footer .bbp-topic-content,#bbpress-forums li.bbp-header .bbp-reply-content,#bbpress-forums li.bbp-footer .bbp-reply-content{margin-right:140px;padding:0;text-align:right}div.bbp-forum-header,div.bbp-topic-header,div.bbp-reply-header,li.bbp-body div.hentry{margin-bottom:0;overflow:hidden;padding:8px}div.bbp-forum-header,div.bbp-topic-header,div.bbp-reply-header{border-top:1px solid #ddd;clear:both}span.bbp-author-ip{font-family:'Helvetica Neue',Arial,Helvetica,'Nimbus Sans L',sans-serif;font-size:11px;font-weight:bold;color:#aaa}#bbpress-forums div.bbp-forum-content,#bbpress-forums div.bbp-topic-content,#bbpress-forums div.bbp-reply-content{margin-right:130px;padding:12px 0 12px 12px;text-align:right}#bbpress-forums div.bbp-forum-content:after,#bbpress-forums div.bbp-topic-content:after,#bbpress-forums div.bbp-reply-content:after{clear:both;content:".";display:block;float:none;height:0;font-size:0;visibility:hidden}#bbpress-forums div.bbp-topic-content a,#bbpress-forums div.bbp-reply-content a{background:0;border:0;display:inline;font-weight:normal;margin:0;padding:0}#bbpress-forums div.bbp-topic-content h1,#bbpress-forums div.bbp-reply-content h1,#bbpress-forums div.bbp-topic-content h2,#bbpress-forums div.bbp-reply-content h2,#bbpress-forums div.bbp-topic-content h3,#bbpress-forums div.bbp-reply-content h3,#bbpress-forums div.bbp-topic-content h4,#bbpress-forums div.bbp-reply-content h4,#bbpress-forums div.bbp-topic-content h5,#bbpress-forums div.bbp-reply-content h5,#bbpress-forums div.bbp-topic-content h6,#bbpress-forums div.bbp-reply-content h6{clear:none;line-height:1em;margin:24px 0;padding:0}#bbpress-forums div.bbp-topic-content img,#bbpress-forums div.bbp-reply-content img{max-width:100%}#bbpress-forums div.bbp-topic-content ul,#bbpress-forums div.bbp-reply-content ul,#bbpress-forums div.bbp-topic-content ol,#bbpress-forums div.bbp-reply-content ol{margin:0 15px 15px;padding:0}#bbpress-forums div.bbp-topic-content ul li,#bbpress-forums div.bbp-reply-content ul li{list-style-type:disc}#bbpress-forums div.bbp-topic-content ol li,#bbpress-forums div.bbp-reply-content ol li{list-style-type:decimal}#bbpress-forums div.bbp-topic-content ol li li,#bbpress-forums div.bbp-reply-content ol li li{list-style-type:lower-alpha}#bbpress-forums div.bbp-topic-content ol li li li,#bbpress-forums div.bbp-reply-content ol li li li{list-style-type:upper-roman}#bbpress-forums div.bbp-topic-content code,#bbpress-forums div.bbp-reply-content code,#bbpress-forums div.bbp-topic-content pre,#bbpress-forums div.bbp-reply-content pre{font-family:Inconsolata,Consolas,Monaco,Lucida Console,monospace;display:inline-block;background-color:#f9f9f9;border:1px solid #ddd;padding:0 5px;max-width:95%;vertical-align:middle;margin-top:-3px}#bbpress-forums div.bbp-topic-content pre,#bbpress-forums div.bbp-reply-content pre{display:block;line-height:18px;margin:0 0 24px;padding:5px 10px;white-space:pre;overflow:auto}#bbpress-forums div.bbp-topic-content pre code,#bbpress-forums div.bbp-reply-content pre code{display:block;border:0;padding:0;margin:0;background-color:transparent;overflow-wrap:normal;overflow:scroll;max-width:100%}#bbpress-forums div.bbp-reply-to{margin-right:130px;padding:12px 0 12px 12px;text-align:left}#bbpress-forums div#bbp-cancel-reply-to{text-align:left}div.bbp-breadcrumb{float:right}div.bbp-breadcrumb,div.bbp-topic-tags{font-size:12px}#bbpress-forums div.bbp-breadcrumb p,#bbpress-forums div.bbp-topic-tags p{margin-bottom:10px}#bbpress-forums div.bbp-topic-tags{float:left}#bbp-topic-hot-tags{clear:both}#bbpress-forums #bbp-search-form{clear:right}#bbpress-forums #bbp-search-form .hidden{height:0;width:0;overflow:hidden;position:absolute;background:0;left:-999em}#bbpress-forums #bbp-search-form #bbp_search{display:inline-block;width:auto}#bbpress-forums div.bbp-search-form{float:left}span.bbp-admin-links{float:left;color:#ddd}span.bbp-admin-links a{color:#bbb;font-weight:normal;font-size:10px;text-transform:uppercase;text-decoration:none}fieldset span.bbp-admin-links{float:right}tr td span.bbp-admin-links a:hover{color:#ff4b33}td.bbp-topic-admin-links,td.bbp-topic-counts{width:50%}.bbp-forum-header a.bbp-forum-permalink,.bbp-topic-header a.bbp-topic-permalink,.bbp-reply-header a.bbp-reply-permalink{float:left;margin-right:10px;color:#ccc}.bbp-topic-action #favorite-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:bold;font-size:13px}.bbp-topic-action #favorite-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-topic-action #favorite-toggle span.is-favorite a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-topic-action #favorite-toggle span.is-favorite a:hover{color:#c88;border-color:#c88;background-color:#fdd}.bbp-topic-action #subscription-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:bold;font-size:13px}.bbp-topic-action #subscription-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-topic-action #subscription-toggle span.is-subscribed a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-topic-action #subscription-toggle span.is-subscribed a:hover{color:#c88;border-color:#c88;background-color:#fdd}#bbpress-forums .bbp-forum-info .bbp-forum-content,#bbpress-forums p.bbp-topic-meta{font-size:11px;margin:5px 0 5px;padding:0;word-wrap:break-word}#bbpress-forums p.bbp-topic-meta span{white-space:nowrap}.bbp-pagination-count{float:right;border:1px solid transparent}.bbp-pagination-links{float:left;list-style:none;display:inline}.bbp-pagination-links a,.bbp-pagination-links span.current{display:block;float:right;padding:0 5px;margin-right:5px;border:1px solid #efefef;text-decoration:none}.bbp-pagination-links a:hover,.bbp-pagination-links span.current{background:#eee;opacity:.8;border:1px solid #ddd}.bbp-pagination-links span.dots{display:block;float:right;padding:1px 4px;margin-right:5px}.bbp-pagination{float:right;width:100%;margin-bottom:15px}.bbp-topic-pagination{display:inline-block;margin-right:5px;margin-bottom:2px}.bbp-topic-pagination a{font-size:10px;line-height:10px;padding:1px 3px;border:1px solid #ddd;text-decoration:none}#bbpress-forums fieldset.bbp-form{clear:right}#bbpress-forums fieldset.bbp-form{border:1px solid #eee;padding:10px 20px;margin-bottom:10px}#bbpress-forums fieldset.bbp-form legend{padding:5px}#bbpress-forums fieldset.bbp-form label{margin:0;display:inline-block}#bbp-edit-topic-tag.bbp-form fieldset.bbp-form label,#bbp-login fieldset label,#bbp-register fieldset label,#bbp-lost-pass fieldset label{width:100px}#bbpress-forums fieldset.bbp-form p,#bbpress-forums fieldset.bbp-form textarea,#bbpress-forums fieldset.bbp-form select,#bbpress-forums fieldset.bbp-form input{margin:0 0 8px}textarea#bbp_reply_content,textarea#bbp_topic_content,textarea#bbp_forum_content{width:97%;box-sizing:border-box}textarea#bbp_forum_content{height:210px}#bbpress-forums fieldset.bbp-forum-form-attributes{width:200px;float:left;clear:none;margin-right:25px}#bbpress-forums fieldset select#bbp_forum_id{max-width:200px}.bbp-topic-form,.bbp-reply-form,.bbp-topic-tag-form{clear:right}body.topic-edit .bbp-topic-form div.avatar img,body.reply-edit .bbp-reply-form div.avatar img,body.single-forum .bbp-topic-form div.avatar img,body.single-reply .bbp-reply-form div.avatar img{margin-left:0;padding:10px;border:1px solid #ddd;line-height:0;background-color:#efefef}body.page .bbp-reply-form code,body.page .bbp-topic-form code,body.single-topic .bbp-reply-form code,body.single-forum .bbp-topic-form code,body.topic-edit .bbp-topic-form code,body.reply-edit .bbp-reply-form code{font-size:10px;background-color:#f0fff8;border:1px solid #ceefe1;display:block;padding:8px;margin-top:5px;width:369px}#merge_tag,#delete_tag{display:inline}div.bbp-submit-wrapper{margin-top:15px;float:left;clear:both}p.form-allowed-tags{max-width:100%}#bbpress-forums div.bbp-the-content-wrapper{margin-bottom:10px}#bbpress-forums div.bbp-the-content-wrapper textarea.bbp-the-content{width:100%;margin:0;font-size:12px}#bbpress-forums div.bbp-the-content-wrapper table,#bbpress-forums div.bbp-the-content-wrapper tbody,#bbpress-forums div.bbp-the-content-wrapper tr,#bbpress-forums div.bbp-the-content-wrapper td{border:0;padding:0;margin:0;width:auto;line-height:1em}#bbpress-forums div.bbp-the-content-wrapper input{font-size:12px;padding:5px;margin:0 0 0 2px;line-height:1em}#bbpress-forums div.bbp-the-content-wrapper div.quicktags-toolbar{padding:5px;min-height:26px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:4px 4px 8px}#bbpress-forums div.wp-editor-container{margin:0;padding:0;line-height:0}#bbpress-forums div.bbp-the-content-wrapper td.mceStatusbar{line-height:16px}#bbpress-forums #bbp-your-profile fieldset{padding:20px 20px 0 20px}#bbpress-forums #bbp-your-profile fieldset div{margin-bottom:20px;float:right;width:100%;clear:right}#bbpress-forums #bbp-your-profile fieldset select{margin-bottom:0}#bbpress-forums #bbp-your-profile fieldset input,#bbpress-forums #bbp-your-profile fieldset textarea{margin-bottom:0;width:60%;background:#f9f9f9;border:1px solid #ddd;box-shadow:none;padding:5px 8px;border-radius:0}#bbpress-forums #bbp-your-profile fieldset input:focus,#bbpress-forums #bbp-your-profile fieldset textarea:focus{border:1px solid #ccc;box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);outline-color:rgba(240,255,240,0.1)}#bbpress-forums #bbp-your-profile fieldset.bbp-form input.checkbox{width:auto}#bbpress-forums #bbp-your-profile fieldset legend{display:none}#bbpress-forums #bbp-your-profile fieldset label[for]{float:right;width:20%;padding:5px 5px 5px 20px;text-align:left;cursor:pointer}#bbpress-forums #bbp-your-profile fieldset dl label[for]{text-align:right;width:60%}#bbpress-forums #bbp-your-profile fieldset span.description{margin:5px 0 0 20%;font-size:12px;font-style:italic;float:right;clear:right;width:60%;padding:5px 8px;border:#cee1ef 1px solid;background-color:#f0f8ff}#bbpress-forums #bbp-your-profile fieldset fieldset{margin:0;border:0;padding:0;clear:none;float:none}#bbpress-forums #bbp-your-profile fieldset fieldset.password{width:60%;display:inline}#bbpress-forums #bbp-your-profile fieldset fieldset.password input,#bbpress-forums #bbp-your-profile fieldset fieldset.password span{width:100%}#bbpress-forums #bbp-your-profile fieldset fieldset.capabilities dl{margin:0}#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description{margin-right:0;margin-bottom:20px}#bbpress-forums #bbp-your-profile fieldset.submit button{float:left}div.bbp-template-notice,div.indicator-hint{border-width:1px;border-style:solid;padding:0 .6em;margin:5px 0 15px;border-radius:3px;background-color:#ffffe0;border-color:#e6db55;color:#000;clear:both}div.bbp-template-notice a{color:#555;text-decoration:none}div.bbp-template-notice a:hover{color:#000}div.bbp-template-notice.info{border:#cee1ef 1px solid;background-color:#f0f8ff}div.bbp-template-notice.important{border:#e6db55 1px solid;background-color:#fffbcc}div.bbp-template-notice.error,div.bbp-template-notice.warning{background-color:#ffebe8;border-color:#c00}div.bbp-template-notice.error a,div.bbp-template-notice.warning a{color:#c00}div.bbp-template-notice p{margin:.5em 0 6px 0 !important;padding:2px;font-size:12px;line-height:140%}.bbp-topics-front ul.super-sticky,.bbp-topics ul.super-sticky,.bbp-topics ul.sticky,.bbp-forum-content ul.sticky{background-color:#ffffe0 !important;font-size:1.1em}#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log,#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log{border-top:1px dotted #ddd;width:100%;margin:0;padding:8px 0 0 0;font-size:11px;color:#aaa}#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log li,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log li,#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log li{list-style-type:none}.bbp-login-form fieldset legend{display:none}.bbp-login-form .bbp-username input,.bbp-login-form .bbp-email input,.bbp-login-form .bbp-password input{padding:5px}.bbp-login-form label{width:140px;display:inline-block}#sidebar .bbp-login-form label{width:70px}.bbp-login-form .bbp-username,.bbp-login-form .bbp-email,.bbp-login-form .bbp-password,.bbp-login-form .bbp-remember-me,.bbp-login-form .bbp-submit-wrapper{margin-top:10px}.bbp-login-form .bbp-submit-wrapper{text-align:left}.bbp-login-form .bbp-login-links a{float:right;clear:right}.bbp-logged-in img.avatar{float:right;margin:0 0 0 15px}.bbp-logged-in h4{font-weight:bold;font-size:1.3em;clear:none;margin-bottom:10px}#bbpress-forums p.bbp-topic-meta img.avatar,#bbpress-forums ul.bbp-reply-revision-log img.avatar,#bbpress-forums ul.bbp-topic-revision-log img.avatar,#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums .widget_display_topics img.avatar,#bbpress-forums .widget_display_replies img.avatar{float:none;margin-bottom:-7px;border:3px double #ddd}fieldset div.avatar{float:left}.activity-list li.bbp_topic_create .activity-content .activity-inner,.activity-list li.bbp_reply_create .activity-content .activity-inner{border-right:2px solid #eaeaea;margin-right:5px;padding-right:10px}#bbpress-forums h1{clear:none;font-size:1.8em;line-height:1em;padding-bottom:10px}#bbpress-forums #bbp-user-wrapper{float:right;width:100%}#bbpress-forums .bbp-user-section{overflow:auto}#bbpress-forums #bbp-user-wrapper h2.entry-title{font-size:1.4em;margin:0;padding-bottom:10px;padding-top:0;clear:none}#bbpress-forums #bbp-user-wrapper ul.bbp-lead-topic,#bbpress-forums #bbp-user-wrapper ul.bbp-topics,#bbpress-forums #bbp-user-wrapper ul.bbp-forums,#bbpress-forums #bbp-user-wrapper ul.bbp-replies,#bbpress-forums #bbp-user-wrapper fieldset.bbp-form{clear:none}#bbpress-forums #bbp-single-user-details{margin:0;width:150px;float:right;overflow:hidden}#bbpress-forums #bbp-single-user-details #bbp-user-avatar{margin:0;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-avatar img.avatar{border:0;height:150px;padding:0;margin:0 0 20px 0;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-description{float:none;margin-right:180px}#bbpress-forums #bbp-single-user-details #bbp-user-navigation{float:none;margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li{margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation a{padding:5px 8px;display:block;border:1px solid transparent;text-decoration:none}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li.current a{background:#eee;opacity:.8}#bbpress-forums #bbp-user-body{margin-right:180px}body.my-account #bbpress-forums{border-top:0;padding-top:0;margin-bottom:0}#bbpress-forums dl.bbp-user-capabilities{display:inline-block;vertical-align:top}#bbpress-forums dl.bbp-user-capabilities dt{margin:0 0 10px;text-transform:capitalize}#bbpress-forums dl.bbp-user-capabilities dd{margin:0;padding:0}#bbpress-forums div.row-actions{font-size:11px;visibility:hidden}#bbpress-forums li:hover>div.row-actions{visibility:visible}@media screen and (max-device-width:480px),screen and (-webkit-min-device-pixel-ratio:2){-webkit-text-size-adjust:none}@media only screen and (max-width:480px){#bbpress-forums div.bbp-topic-tags{clear:right;float:right}div.bbp-search-form input,div.bbp-search-form button{font-size:11px;padding:2px}li.bbp-forum-info,li.bbp-topic-title{width:45%}li.bbp-forum-topic-count,li.bbp-forum-reply-count,li.bbp-topic-voice-count,li.bbp-topic-reply-count{width:15%}span.bbp-reply-post-date{float:right}span.bbp-admin-links{clear:right;float:right}#bbpress-forums .bbp-forums-list li{display:block;font-size:11px}#bbpress-forums div.bbp-reply-author{margin:-15px 10px 10px;min-height:100px;padding-right:80px;position:relative;text-align:right;width:100%}#bbpress-forums div.bbp-reply-author a.bbp-author-name{clear:none;display:inline-block;margin-right:0;word-wrap:break-word}#bbpress-forums div.bbp-reply-author img.avatar{position:absolute;top:15px;right:0;width:60px;height:auto}#bbpress-forums div.bbp-reply-author .bbp-author-role{font-size:12px;font-style:normal}#bbpress-forums .bbp-body div.bbp-reply-content{clear:both;margin:10px;padding:0}#bbpress-forums div.bbp-reply-content p{margin-bottom:1em}div.bbp-submit-wrapper{float:right}#bbpress-forums fieldset.bbp-form{padding:0 10px 10px}#bbpress-forums #bbp-user-body{clear:both;margin-right:0;word-wrap:break-word}}@media only screen and (max-width:320px){#bbpress-forums div.bbp-search-form{margin-bottom:10px}#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-body li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title,#bbpress-forums li.bbp-body li.bbp-topic-title{width:100%}#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title{text-align:center;text-transform:uppercase}#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count{width:20%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness{width:58%}#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-freshness{margin-top:7px}#bbpress-forums li.bbp-header,#bbpress-forums li.bbp-footer{font-size:10px}#bbpress-forums li.bbp-header div.bbp-reply-author{text-align:right;width:25%}#bbpress-forums li.bbp-header div.bbp-reply-content{margin-right:25%}#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums p.bbp-topic-meta img.avatar{width:14px;height:auto}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:1px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar td{width:20px;height:20px}#bbpress-forums div.wp-editor-container{width:100%;overflow:auto}#bbpress-forums input#bbp_topic_title,#bbpress-forums input#bbp_topic_tags{width:95%}}@media only screen and (max-width:240px){#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-footer div.bbp-reply-author,#bbpress-forums li.bbp-footer div.bbp-reply-content{width:45%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header div.bbp-reply-author,#bbpress-forums li.bbp-header div.bbp-reply-content{clear:both;width:100%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{text-align:center}#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header div.bbp-reply-content{margin-right:0;text-align:right}#bbpress-forums li.bbp-body li.bbp-topic-freshness p.bbp-topic-meta{display:inline-block}#bbpress-forums li.bbp-header{overflow:hidden}#bbpress-forums li.bbp-footer div.bbp-reply-content{display:inline-block;margin-right:0}#bbpress-forums li.bbp-body div.bbp-reply-author{min-height:60px;padding-right:60px}#bbpress-forums div.bbp-reply-author img.avatar{width:40px;height:auto}}
Index: /tags/2.5.4/templates/default/css/bbpress.css
===================================================================
--- /tags/2.5.4/templates/default/css/bbpress.css	(revision 5382)
+++ /tags/2.5.4/templates/default/css/bbpress.css	(revision 5382)
@@ -0,0 +1,1342 @@
+/**
+ * bbPress specific CSS
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+/* =bbPress Style
+-------------------------------------------------------------- */
+
+#bbpress-forums hr {
+	margin: 0 0 24px 0;
+}
+
+#bbpress-forums {
+	background: transparent;
+	clear: both;
+	margin-bottom: 20px;
+	overflow: hidden;
+	font-size: 12px;
+}
+
+#bbpress-forums div.even,
+#bbpress-forums ul.even {
+	background-color: #fff;
+}
+
+#bbpress-forums div.odd,
+#bbpress-forums ul.odd {
+	background-color: #fbfbfb;
+}
+
+body.reply-edit .reply {
+	float: none;
+}
+
+#bbpress-forums div.reply {
+	height: auto;
+	width: 100%;
+}
+
+#bbpress-forums div.bbp-forum-header,
+#bbpress-forums div.bbp-topic-header,
+#bbpress-forums div.bbp-reply-header {
+	background-color: #f4f4f4;
+}
+
+#bbpress-forums .status-trash.even,
+#bbpress-forums .status-spam.even {
+	background-color: #fee;
+}
+#bbpress-forums .status-trash.odd,
+#bbpress-forums .status-spam.odd {
+	background-color: #fdd;
+}
+
+#bbpress-forums .status-closed,
+#bbpress-forums .status-closed a {
+	color: #ccc;
+}
+
+#bbpress-forums ul {
+	background:  none;
+	list-style: none;
+	margin: 0;
+	padding: 0;
+}
+
+#bbpress-forums ul.bbp-threaded-replies {
+	margin-left: 50px;
+}
+
+#bbpress-forums li {
+	background: none;
+	margin: 0;
+	list-style: none;
+}
+
+#bbpress-forums ul.bbp-lead-topic,
+#bbpress-forums ul.bbp-topics,
+#bbpress-forums ul.bbp-forums,
+#bbpress-forums ul.bbp-replies,
+#bbpress-forums ul.bbp-search-results {
+	font-size: 12px;
+	overflow: hidden;
+	border: 1px solid #eee;
+	margin-bottom: 20px;
+	clear: both;
+}
+
+#bbpress-forums li.bbp-header,
+#bbpress-forums li.bbp-body,
+#bbpress-forums li.bbp-footer {
+	clear: both;
+}
+
+#bbpress-forums li.bbp-header,
+#bbpress-forums li.bbp-footer {
+	background: #f3f3f3;
+	border-top: 1px solid #eee;
+	font-weight: bold;
+	padding: 8px;
+	text-align: center;
+}
+
+#bbpress-forums li.bbp-header {
+	background: #eaeaea;
+}
+
+#bbpress-forums li.bbp-header ul {
+	overflow: hidden;
+}
+
+#bbpress-forums .bbp-forums-list {
+	margin: 0 0 0 5px;
+	padding-left: 15px;
+	border-left: 1px solid #ddd;
+}
+
+#bbpress-forums .bbp-forums-list li {
+	display: inline;
+	font-size: 11px;
+}
+
+#bbpress-forums li.bbp-footer p {
+	margin: 0;
+	line-height: 1em;
+}
+
+li.bbp-forum-info,
+li.bbp-topic-title {
+	float: left;
+	text-align: left;
+	width: 55%;
+}
+li.bbp-forum-topic-count,
+li.bbp-topic-voice-count,
+li.bbp-forum-reply-count,
+li.bbp-topic-reply-count {
+	float: left;
+	text-align: center;
+	width: 10%;
+}
+
+li.bbp-forum-freshness,
+li.bbp-topic-freshness {
+	text-align: center;
+	float: left;
+	width: 22%;
+}
+
+#bbpress-forums li.bbp-body ul.forum,
+#bbpress-forums li.bbp-body ul.topic {
+	border-top: 1px solid #eee;
+	overflow: hidden;
+	padding: 8px;
+}
+
+li.bbp-header div.bbp-topic-content span#subscription-toggle,
+li.bbp-header div.bbp-topic-content span#favorite-toggle,
+li.bbp-header div.bbp-reply-content span#subscription-toggle,
+li.bbp-header div.bbp-reply-content span#favorite-toggle {
+	float: right;
+}
+
+#bbpress-forums div.bbp-forum-title h3,
+#bbpress-forums div.bbp-topic-title h3,
+#bbpress-forums div.bbp-reply-title h3 {
+	background: none;
+	border: none;
+	font-size: 16px;
+ 	line-height: 1em;
+ 	margin: 8px 0;
+	padding: 0;
+	text-transform: none;
+}
+
+#bbpress-forums div.bbp-forum-author,
+#bbpress-forums div.bbp-topic-author,
+#bbpress-forums div.bbp-reply-author {
+	float: left;
+	text-align: center;
+	width: 115px;
+}
+
+#bbpress-forums div.bbp-forum-author img.avatar,
+#bbpress-forums div.bbp-topic-author img.avatar,
+#bbpress-forums div.bbp-reply-author img.avatar {
+	border: none;
+	max-width: 80px;
+	padding: 0;
+	margin: 12px auto 0 auto;
+	float: none;
+}
+
+#bbpress-forums div.bbp-forum-author a.bbp-author-name,
+#bbpress-forums div.bbp-topic-author a.bbp-author-name,
+#bbpress-forums div.bbp-reply-author a.bbp-author-name {
+	margin: 0 12px;
+	word-break: break-word;
+	display: inline-block;
+}
+
+#bbpress-forums div.bbp-topic-author a.bbp-author-name,
+#bbpress-forums div.bbp-reply-author a.bbp-author-name {
+	clear: left;
+	display: block;
+}
+
+#bbpress-forums div.bbp-forum-author .bbp-author-role,
+#bbpress-forums div.bbp-topic-author .bbp-author-role,
+#bbpress-forums div.bbp-reply-author .bbp-author-role {
+	font-size: 11px;
+	font-style: italic;
+}
+
+#bbpress-forums li.bbp-header .bbp-search-author,
+#bbpress-forums li.bbp-footer .bbp-search-author,
+#bbpress-forums li.bbp-header .bbp-forum-author,
+#bbpress-forums li.bbp-footer .bbp-forum-author,
+#bbpress-forums li.bbp-header .bbp-topic-author,
+#bbpress-forums li.bbp-footer .bbp-topic-author,
+#bbpress-forums li.bbp-header .bbp-reply-author,
+#bbpress-forums li.bbp-footer .bbp-reply-author {
+	float: left;
+	margin: 0;
+	padding: 0;
+	width: 120px;
+}
+
+#bbpress-forums li.bbp-header .bbp-search-content,
+#bbpress-forums li.bbp-footer .bbp-search-content,
+#bbpress-forums li.bbp-header .bbp-forum-content,
+#bbpress-forums li.bbp-footer .bbp-forum-content,
+#bbpress-forums li.bbp-header .bbp-topic-content,
+#bbpress-forums li.bbp-footer .bbp-topic-content,
+#bbpress-forums li.bbp-header .bbp-reply-content,
+#bbpress-forums li.bbp-footer .bbp-reply-content {
+	margin-left: 140px;
+	padding: 0;
+	text-align: left;
+}
+
+div.bbp-forum-header,
+div.bbp-topic-header,
+div.bbp-reply-header,
+li.bbp-body div.hentry {
+	margin-bottom: 0;
+	overflow: hidden;
+	padding: 8px;
+}
+
+div.bbp-forum-header,
+div.bbp-topic-header,
+div.bbp-reply-header {
+	border-top: 1px solid #ddd;
+	clear: both;
+}
+
+span.bbp-author-ip {
+	font-family: 'Helvetica Neue', Arial, Helvetica, 'Nimbus Sans L', sans-serif;
+	font-size: 11px;
+	font-weight: bold;
+	color: #aaa;
+}
+
+/* =Topic and reply content
+-------------------------------------------------------------- */
+
+#bbpress-forums div.bbp-forum-content,
+#bbpress-forums div.bbp-topic-content,
+#bbpress-forums div.bbp-reply-content {
+	margin-left: 130px;
+	padding: 12px 12px 12px 0;
+	text-align: left;
+}
+
+/* Clearing hack */
+#bbpress-forums div.bbp-forum-content:after,
+#bbpress-forums div.bbp-topic-content:after,
+#bbpress-forums div.bbp-reply-content:after {
+	clear: both;
+	content: ".";
+	display: block;
+	float: none;
+	height: 0;
+	font-size: 0;
+	visibility: hidden;
+}
+
+#bbpress-forums div.bbp-topic-content a,
+#bbpress-forums div.bbp-reply-content a {
+	background: none;
+	border: none;
+	display: inline;
+	font-weight: normal;
+	margin: 0;
+	padding: 0;
+}
+
+#bbpress-forums div.bbp-topic-content h1,
+#bbpress-forums div.bbp-reply-content h1,
+#bbpress-forums div.bbp-topic-content h2,
+#bbpress-forums div.bbp-reply-content h2,
+#bbpress-forums div.bbp-topic-content h3,
+#bbpress-forums div.bbp-reply-content h3,
+#bbpress-forums div.bbp-topic-content h4,
+#bbpress-forums div.bbp-reply-content h4,
+#bbpress-forums div.bbp-topic-content h5,
+#bbpress-forums div.bbp-reply-content h5,
+#bbpress-forums div.bbp-topic-content h6,
+#bbpress-forums div.bbp-reply-content h6 {
+	clear: none;
+	line-height: 1em;
+	margin: 24px 0;
+	padding: 0;
+}
+
+#bbpress-forums div.bbp-topic-content img,
+#bbpress-forums div.bbp-reply-content img {
+	max-width: 100%;
+}
+
+#bbpress-forums div.bbp-topic-content ul,
+#bbpress-forums div.bbp-reply-content ul,
+#bbpress-forums div.bbp-topic-content ol,
+#bbpress-forums div.bbp-reply-content ol {
+	margin: 0 15px 15px;
+	padding: 0;
+}
+
+#bbpress-forums div.bbp-topic-content ul li,
+#bbpress-forums div.bbp-reply-content ul li {
+	list-style-type: disc;
+}
+
+#bbpress-forums div.bbp-topic-content ol li,
+#bbpress-forums div.bbp-reply-content ol li {
+	list-style-type: decimal;
+}
+
+#bbpress-forums div.bbp-topic-content ol li li,
+#bbpress-forums div.bbp-reply-content ol li li {
+	list-style-type: lower-alpha;
+}
+
+#bbpress-forums div.bbp-topic-content ol li li li,
+#bbpress-forums div.bbp-reply-content ol li li li {
+	list-style-type: upper-roman;
+}
+
+#bbpress-forums div.bbp-topic-content code,
+#bbpress-forums div.bbp-reply-content code,
+#bbpress-forums div.bbp-topic-content pre,
+#bbpress-forums div.bbp-reply-content pre {
+	font-family: Inconsolata, Consolas, Monaco, Lucida Console, monospace;
+	display: inline-block;
+	background-color: #f9f9f9;
+	border: 1px solid #ddd;
+	padding: 0 5px;
+	max-width: 95%;
+	vertical-align: middle;
+	margin-top: -3px;
+}
+
+#bbpress-forums div.bbp-topic-content pre,
+#bbpress-forums div.bbp-reply-content pre {
+	display: block;
+	line-height: 18px;
+	margin: 0 0 24px;
+	padding: 5px 10px;
+	white-space: pre;
+	overflow: auto;
+}
+
+#bbpress-forums div.bbp-topic-content pre code,
+#bbpress-forums div.bbp-reply-content pre code {
+	display: block;
+	border: none;
+	padding: 0;
+	margin: 0;
+	background-color: transparent;
+	overflow-wrap: normal;
+	overflow: auto;
+	max-width: 100%;
+}
+
+/* =Reply to
+-------------------------------------------------------------- */
+
+#bbpress-forums div.bbp-reply-to {
+	margin-left: 130px;
+	padding: 12px 12px 12px 0;
+	text-align: right;
+}
+
+#bbpress-forums div#bbp-cancel-reply-to {
+	text-align: right;
+}
+
+/* =Breadcrumb and Tags
+-------------------------------------------------------------- */
+
+div.bbp-breadcrumb {
+	float: left;
+}
+
+div.bbp-breadcrumb,
+div.bbp-topic-tags {
+	font-size: 12px;
+}
+
+#bbpress-forums div.bbp-breadcrumb p,
+#bbpress-forums div.bbp-topic-tags p {
+	margin-bottom: 10px
+}
+
+#bbpress-forums div.bbp-topic-tags {
+	float: right;
+}
+
+#bbp-topic-hot-tags {
+	clear: both;
+}
+
+/* =Search
+-------------------------------------------------------------- */
+
+#bbpress-forums #bbp-search-form {
+	clear: left;
+}
+
+	#bbpress-forums #bbp-search-form .hidden {
+		height: 0;
+		width: 0;
+		overflow: hidden;
+		position: absolute;
+		background: none;
+		left: -999em;
+	}
+
+	#bbpress-forums #bbp-search-form #bbp_search {
+		display: inline-block;
+		width: auto;
+	}
+
+#bbpress-forums div.bbp-search-form {
+	float: right;
+}
+
+/* =Admin Links
+-------------------------------------------------------------- */
+
+span.bbp-admin-links {
+	float: right;
+	color: #ddd;
+}
+span.bbp-admin-links a {
+	color: #bbb;
+	font-weight: normal;
+	font-size: 10px;
+	text-transform: uppercase;
+	text-decoration: none;
+}
+fieldset span.bbp-admin-links {
+	float: left;
+}
+tr td span.bbp-admin-links a:hover {
+	color: #ff4b33;
+}
+td.bbp-topic-admin-links,
+td.bbp-topic-counts {
+	width: 50%;
+}
+
+.bbp-forum-header a.bbp-forum-permalink,
+.bbp-topic-header a.bbp-topic-permalink,
+.bbp-reply-header a.bbp-reply-permalink {
+	float: right;
+	margin-left: 10px;
+	color: #ccc;
+}
+
+/* =Toggles
+-------------------------------------------------------------- */
+
+.bbp-row-actions #favorite-toggle a {
+	text-decoration: none;
+	padding: 0 3px 1px;
+	color: #7c7;
+	border: 1px solid #aca;
+	background-color: #dfd;
+	font-weight: bold;
+	font-size: 13px;
+	}
+	.bbp-row-actions #favorite-toggle a:hover {
+		color: #5a5;
+		border-color: #7c7;
+		background-color: #beb;
+	}
+	.bbp-row-actions #favorite-toggle span.is-favorite a {
+		color: #faa;
+		border: 1px solid #faa;
+		background-color: #fee;
+		}
+		.bbp-row-actions #favorite-toggle span.is-favorite a:hover {
+			color: #c88;
+			border-color: #c88;
+			background-color: #fdd;
+		}
+
+.bbp-row-actions #subscription-toggle a {
+	text-decoration: none;
+	padding: 0 3px 1px;
+	color: #7c7;
+	border: 1px solid #aca;
+	background-color: #dfd;
+	font-weight: bold;
+	font-size: 13px;
+	}
+	.bbp-row-actions #subscription-toggle a:hover {
+		color: #5a5;
+		border-color: #7c7;
+		background-color: #beb;
+	}
+	.bbp-row-actions #subscription-toggle span.is-subscribed a {
+		color: #faa;
+		border: 1px solid #faa;
+		background-color: #fee;
+		}
+		.bbp-row-actions #subscription-toggle span.is-subscribed a:hover {
+			color: #c88;
+			border-color: #c88;
+			background-color: #fdd;
+		}
+
+#bbpress-forums .bbp-forum-info .bbp-forum-content,
+#bbpress-forums p.bbp-topic-meta {
+	font-size: 11px;
+	margin: 5px 0 5px;
+	padding: 0;
+	word-wrap: break-word;
+}
+
+#bbpress-forums p.bbp-topic-meta span {
+	white-space: nowrap;
+}
+
+/* =Pagination
+-------------------------------------------------------------- */
+
+.bbp-pagination-count {
+	float: left;
+	border: 1px solid transparent;
+}
+
+.bbp-pagination-links {
+	float: right;
+	list-style: none;
+	display: inline;
+	}
+	.bbp-pagination-links a,
+	.bbp-pagination-links span.current {
+		display: block;
+		float: left;
+		padding: 0px 5px;
+		margin-left: 5px;
+		border: 1px solid #efefef;
+		text-decoration: none;
+		}
+		.bbp-pagination-links a:hover,
+		.bbp-pagination-links span.current {
+			background: #eee;
+			opacity: 0.8;
+			border: 1px solid #ddd;
+		}
+
+	.bbp-pagination-links span.dots {
+		display: block;
+		float: left;
+		padding: 1px 4px;
+		margin-left: 5px;
+	}
+
+.bbp-pagination {
+	float: left;
+	width: 100%;
+	margin-bottom: 15px;
+}
+
+.bbp-topic-pagination {
+	display: inline-block;
+	margin-left: 5px;
+	margin-bottom: 2px;
+	}
+	.bbp-topic-pagination a {
+		font-size: 10px;
+		line-height: 10px;
+		padding: 1px 3px;
+		border: 1px solid #ddd;
+		text-decoration: none;
+	}
+
+
+/* =Forms
+-------------------------------------------------------------- */
+
+#bbpress-forums fieldset.bbp-form {
+	clear: left;
+}
+
+#bbpress-forums fieldset.bbp-form {
+	border: 1px solid #eee;
+	padding: 10px 20px;
+	margin-bottom: 10px;
+}
+
+#bbpress-forums fieldset.bbp-form legend {
+	padding: 5px;
+}
+
+#bbpress-forums fieldset.bbp-form label {
+	margin: 0;
+	display: inline-block;
+}
+
+#bbp-edit-topic-tag.bbp-form fieldset.bbp-form label,
+#bbp-login fieldset label,
+#bbp-register fieldset label,
+#bbp-lost-pass fieldset label {
+	width: 100px;
+}
+
+#bbpress-forums fieldset.bbp-form p,
+#bbpress-forums fieldset.bbp-form textarea,
+#bbpress-forums fieldset.bbp-form select,
+#bbpress-forums fieldset.bbp-form input {
+	margin: 0 0 8px;
+}
+
+textarea#bbp_reply_content,
+textarea#bbp_topic_content,
+textarea#bbp_forum_content {
+	width: 97%;
+	box-sizing: border-box;
+}
+
+textarea#bbp_forum_content {
+	height: 210px;
+}
+
+#bbpress-forums fieldset.bbp-forum-form-attributes {
+	width: 200px;
+	float: right;
+	clear: none;
+	margin-left: 25px;
+}
+
+/**
+ * Fix for too-long forum names, usually from conversion
+ */
+#bbpress-forums fieldset select#bbp_forum_id {
+	max-width: 200px;
+}
+
+.bbp-topic-form,
+.bbp-reply-form,
+.bbp-topic-tag-form {
+	clear: left;
+}
+body.topic-edit .bbp-topic-form div.avatar img,
+body.reply-edit .bbp-reply-form div.avatar img,
+body.single-forum .bbp-topic-form div.avatar img,
+body.single-reply .bbp-reply-form div.avatar img {
+	margin-right: 0;
+	padding: 10px;
+	border: 1px solid #ddd;
+	line-height: 0;
+	background-color: #efefef;
+}
+
+body.page .bbp-reply-form code,
+body.page .bbp-topic-form code,
+body.single-topic .bbp-reply-form code,
+body.single-forum .bbp-topic-form code,
+body.topic-edit .bbp-topic-form code,
+body.reply-edit .bbp-reply-form code {
+	font-size: 10px;
+	background-color: #f0fff8;
+	border: 1px solid #CEEFE1;
+	display: block;
+	padding: 8px;
+	margin-top: 5px;
+	width: 369px;
+}
+
+#merge_tag,
+#delete_tag {
+	display: inline;
+}
+
+div.bbp-submit-wrapper {
+	margin-top: 15px;
+	float: right;
+	clear: both;
+}
+
+p.form-allowed-tags {
+	max-width: 100%;
+}
+
+/* =TinyMCE in themes
+-------------------------------------------------------------- */
+#bbpress-forums div.bbp-the-content-wrapper {
+	margin-bottom: 10px;
+}
+
+#bbpress-forums div.bbp-the-content-wrapper textarea.bbp-the-content {
+	width: 100%;
+	margin: 0;
+	font-size: 12px;
+}
+
+#bbpress-forums div.bbp-the-content-wrapper table,
+#bbpress-forums div.bbp-the-content-wrapper tbody,
+#bbpress-forums div.bbp-the-content-wrapper tr,
+#bbpress-forums div.bbp-the-content-wrapper td {
+	border: none;
+	padding: 0;
+	margin: 0;
+	width: auto;
+	line-height: 1em;
+}
+
+#bbpress-forums div.bbp-the-content-wrapper input {
+	font-size: 12px;
+	padding: 5px;
+	margin: 0 2px 0 0;
+	line-height: 1em;
+}
+
+#bbpress-forums div.bbp-the-content-wrapper div.quicktags-toolbar {
+	padding: 5px;
+	min-height: 26px;
+}
+#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar {
+	padding: 4px 4px 8px;
+}
+
+#bbpress-forums div.wp-editor-container {
+	margin: 0;
+	padding: 0;
+	line-height: 0;
+}
+
+#bbpress-forums div.bbp-the-content-wrapper td.mceStatusbar {
+	line-height: 16px;
+}
+
+/* =Edit User
+-------------------------------------------------------------- */
+
+#bbpress-forums #bbp-your-profile fieldset {
+	padding: 20px 20px 0 20px;
+}
+	#bbpress-forums #bbp-your-profile fieldset div {
+		margin-bottom: 20px;
+		float: left;
+		width: 100%;
+		clear: left;
+	}
+	#bbpress-forums #bbp-your-profile fieldset select {
+		margin-bottom: 0;
+	}
+	#bbpress-forums #bbp-your-profile fieldset input,
+	#bbpress-forums #bbp-your-profile fieldset textarea {
+		margin-bottom: 0;
+		width: 60%;
+		background: #f9f9f9;
+		border: 1px solid #ddd;
+		box-shadow: none;
+		padding: 5px 8px;
+		border-radius: 0;
+	}
+	#bbpress-forums #bbp-your-profile fieldset input:focus,
+	#bbpress-forums #bbp-your-profile fieldset textarea:focus {
+		border: 1px solid #ccc;
+		box-shadow: inset 1px 1px 1px rgba(0,0,0,0.1);
+		outline-color: rgba(240,255,240,0.1);
+	}
+	#bbpress-forums #bbp-your-profile fieldset.bbp-form input.checkbox {
+		width: auto;
+	}
+	#bbpress-forums #bbp-your-profile fieldset legend {
+		display: none;
+	}
+	#bbpress-forums #bbp-your-profile fieldset label[for] {
+		float: left;
+		width: 20%;
+		padding: 5px 20px 5px 0;
+		text-align: right;
+		cursor: pointer;
+	}
+	#bbpress-forums #bbp-your-profile fieldset dl label[for] {
+		text-align: left;
+		width: 60%;
+	}
+	#bbpress-forums #bbp-your-profile fieldset span.description {
+		margin: 5px 0 0 20%;
+		font-size: 12px;
+		font-style: italic;
+		float: left;
+		clear: left;
+		width: 60%;
+		padding: 5px 8px;
+		border: #cee1ef 1px solid;
+		background-color: #f0f8ff;
+	}
+
+	#bbpress-forums #bbp-your-profile fieldset fieldset {
+		margin: 0;
+		border: none;
+		padding: 0;
+		clear: none;
+		float: none;
+	}
+	#bbpress-forums #bbp-your-profile fieldset fieldset.password {
+		width: 60%;
+		display: inline;
+	}
+	#bbpress-forums #bbp-your-profile fieldset fieldset.password input,
+	#bbpress-forums #bbp-your-profile fieldset fieldset.password span {
+		width: 100%;
+	}
+	#bbpress-forums #bbp-your-profile fieldset fieldset.capabilities dl {
+		margin: 0;
+	}
+	#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description {
+		margin-left: 0;
+		margin-bottom: 20px;
+	}
+
+	#bbpress-forums #bbp-your-profile fieldset.submit button {
+		float: right;
+	}
+
+/* =Notices
+-------------------------------------------------------------- */
+
+div.bbp-template-notice,
+div.indicator-hint {
+	border-width: 1px;
+	border-style: solid;
+	padding: 0 0.6em;
+	margin: 5px 0 15px;
+	border-radius: 3px;
+	background-color: #ffffe0;
+	border-color: #e6db55;
+	color: #000;
+	clear: both;
+}
+div.bbp-template-notice a {
+	color: #555;
+	text-decoration: none;
+}
+	div.bbp-template-notice a:hover {
+		color: #000;
+	}
+	div.bbp-template-notice.info {
+		border: #cee1ef 1px solid;
+		background-color: #f0f8ff;
+	}
+	div.bbp-template-notice.important {
+		border: #e6db55 1px solid;
+		background-color: #fffbcc;
+	}
+	div.bbp-template-notice.error,
+	div.bbp-template-notice.warning {
+		background-color: #ffebe8;
+		border-color: #c00;
+	}
+	div.bbp-template-notice.error a,
+	div.bbp-template-notice.warning a {
+		color: #c00;
+	}
+	div.bbp-template-notice p {
+		margin: 0.5em 0 6px 0 !important;
+		padding: 2px;
+		font-size: 12px;
+		line-height: 140%;
+	}
+
+/* =Stickies
+-------------------------------------------------------------- */
+
+.bbp-topics-front ul.super-sticky,
+.bbp-topics ul.super-sticky,
+.bbp-topics ul.sticky,
+.bbp-forum-content ul.sticky {
+	background-color: #ffffe0 !important;
+	font-size: 1.1em;
+}
+
+/* =Revisions
+-------------------------------------------------------------- */
+
+#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log,
+#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log,
+#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log {
+	border-top: 1px dotted #ddd;
+	width: 100%;
+	margin: 0;
+	padding: 8px 0 0 0;
+	font-size: 11px;
+	color: #aaa;
+}
+
+#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log li,
+#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log li,
+#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log li {
+	list-style-type: none;
+}
+
+/* =Widgets
+-------------------------------------------------------------- */
+
+.bbp-login-form fieldset legend {
+	display: none;
+}
+
+.bbp-login-form .bbp-username input,
+.bbp-login-form .bbp-email input,
+.bbp-login-form .bbp-password input {
+	padding: 5px;
+}
+
+.bbp-login-form label {
+	width: 140px;
+	display: inline-block;
+}
+
+#sidebar .bbp-login-form label {
+	width: 70px;
+}
+
+.bbp-login-form .bbp-username,
+.bbp-login-form .bbp-email,
+.bbp-login-form .bbp-password,
+.bbp-login-form .bbp-remember-me,
+.bbp-login-form .bbp-submit-wrapper {
+	margin-top: 10px;
+}
+
+.bbp-login-form .bbp-remember-me {
+
+}
+
+.bbp-login-form .bbp-submit-wrapper {
+	text-align: right;
+}
+
+.bbp-login-form .bbp-login-links {
+}
+
+.bbp-login-form .bbp-login-links a {
+	float: left;
+	clear: left;
+}
+
+.bbp-logged-in img.avatar {
+	float: left;
+	margin: 0 15px 0 0;
+}
+
+.bbp-logged-in h4 {
+	font-weight: bold;
+	font-size: 1.3em;
+	clear: none;
+	margin-bottom: 10px;
+}
+
+/* =Avatars
+-------------------------------------------------------------- */
+
+#bbpress-forums p.bbp-topic-meta img.avatar,
+#bbpress-forums ul.bbp-reply-revision-log img.avatar,
+#bbpress-forums ul.bbp-topic-revision-log img.avatar,
+#bbpress-forums div.bbp-template-notice img.avatar,
+#bbpress-forums .widget_display_topics img.avatar,
+#bbpress-forums .widget_display_replies img.avatar {
+	float: none;
+	margin-bottom: -7px;
+	border: 3px double #ddd;
+}
+
+fieldset div.avatar {
+	float: right;
+}
+
+/* =BuddyPress Activity Streams
+-------------------------------------------------------------- */
+
+.activity-list li.bbp_topic_create .activity-content .activity-inner,
+.activity-list li.bbp_reply_create .activity-content .activity-inner {
+	border-left: 2px solid #eaeaea;
+	margin-left: 5px;
+	padding-left: 10px;
+}
+
+/* =User Pages
+-------------------------------------------------------------- */
+
+#bbpress-forums h1 {
+	clear: none;
+	font-size: 1.8em;
+	line-height: 1em;
+	padding-bottom: 10px;
+}
+
+#bbpress-forums #bbp-user-wrapper {
+	float: left;
+	width: 100%;
+}
+
+#bbpress-forums .bbp-user-section {
+	overflow: auto;
+}
+
+#bbpress-forums #bbp-user-wrapper h2.entry-title {
+	font-size: 1.4em;
+	margin: 0;
+	padding-bottom: 10px;
+	padding-top: 0;
+	clear: none;
+}
+
+#bbpress-forums #bbp-user-wrapper ul.bbp-lead-topic,
+#bbpress-forums #bbp-user-wrapper ul.bbp-topics,
+#bbpress-forums #bbp-user-wrapper ul.bbp-forums,
+#bbpress-forums #bbp-user-wrapper ul.bbp-replies,
+#bbpress-forums #bbp-user-wrapper fieldset.bbp-form {
+	clear: none;
+}
+
+#bbpress-forums #bbp-single-user-details {
+	margin: 0;
+	width: 150px;
+	float: left;
+	overflow: hidden;
+}
+
+#bbpress-forums #bbp-single-user-details #bbp-user-avatar {
+	margin: 0;
+	width: 150px;
+}
+
+#bbpress-forums #bbp-single-user-details #bbp-user-avatar img.avatar {
+	border: none;
+	height: 150px;
+	padding: 0;
+	margin: 0 0 20px 0;
+	width: 150px;
+}
+
+#bbpress-forums #bbp-single-user-details #bbp-user-description {
+	float: none;
+	margin-left: 180px;
+}
+
+#bbpress-forums #bbp-single-user-details #bbp-user-navigation {
+	float: none;
+	margin: 0;
+}
+
+#bbpress-forums #bbp-single-user-details #bbp-user-navigation li {
+	margin: 0;
+}
+
+#bbpress-forums #bbp-single-user-details #bbp-user-navigation a {
+	padding: 5px 8px;
+	display: block;
+	border: 1px solid transparent;
+	text-decoration: none;
+}
+
+#bbpress-forums #bbp-single-user-details #bbp-user-navigation li.current a {
+	background: #eee;
+	opacity: 0.8;
+}
+
+#bbpress-forums #bbp-user-body {
+	margin-left: 180px;
+}
+
+body.my-account #bbpress-forums {
+	border-top: none;
+	padding-top: 0;
+	margin-bottom: 0;
+}
+
+/* =User Capabilities
+-------------------------------------------------------------- */
+
+#bbpress-forums dl.bbp-user-capabilities {
+	display: inline-block;
+	vertical-align: top;
+}
+
+#bbpress-forums dl.bbp-user-capabilities dt {
+	margin: 0 0 10px;
+	text-transform: capitalize;
+}
+
+#bbpress-forums dl.bbp-user-capabilities dd {
+	margin: 0;
+	padding: 0;
+}
+
+/* =BuddyPress Group Forums
+-------------------------------------------------------------- */
+
+#bbpress-forums div.row-actions {
+	font-size: 11px;
+	visibility: hidden;
+}
+
+#bbpress-forums li:hover > div.row-actions {
+	visibility: visible;
+}
+
+/*--------------------------------------------------------------
+ Media Queries
+--------------------------------------------------------------*/
+
+/* =Standard Mobile Landscape
+-------------------------------------------------------------- */
+@media screen and (max-device-width: 480px), screen and (-webkit-min-device-pixel-ratio: 2) {
+	-webkit-text-size-adjust: none;
+}
+@media only screen and (max-width: 480px) {
+	#bbpress-forums div.bbp-topic-tags {
+		clear: left;
+		float: left;
+	}
+	div.bbp-search-form input,
+	div.bbp-search-form button {
+		font-size: 11px;
+		padding: 2px;
+	}
+	li.bbp-forum-info,
+	li.bbp-topic-title {
+		width: 45%;
+	}
+	li.bbp-forum-topic-count,
+	li.bbp-forum-reply-count,
+	li.bbp-topic-voice-count,
+	li.bbp-topic-reply-count {
+		width: 15%;
+	}
+	span.bbp-reply-post-date {
+		float: left;
+	}
+	span.bbp-admin-links {
+		clear: left;
+		float: left;
+	}
+	#bbpress-forums .bbp-forums-list li {
+		display: block;
+		font-size: 11px;
+	}
+	#bbpress-forums .bbp-body div.bbp-reply-author {
+		margin: -15px 10px 10px;
+		min-height: 100px;
+		padding-left: 80px;
+		position: relative;
+		text-align: left;
+		width: 100%;
+	}
+	#bbpress-forums div.bbp-reply-author a.bbp-author-name {
+		clear: none;
+		display: inline-block;
+		margin-left: 0;
+		word-wrap: break-word;
+	}
+	#bbpress-forums div.bbp-reply-author img.avatar {
+		position: absolute;
+		top: 15px;
+		left: 0;
+		width: 60px;
+		height: auto;
+	}
+	#bbpress-forums div.bbp-reply-author .bbp-author-role {
+		font-size: 12px;
+		font-style: normal;
+	}
+	#bbpress-forums .bbp-body div.bbp-reply-content {
+		clear: both;
+		margin: 10px;
+		padding: 0;
+	}
+	#bbpress-forums div.bbp-reply-content p {
+		margin-bottom: 1em;
+	}
+	div.bbp-submit-wrapper {
+		float: left;
+	}
+	#bbpress-forums fieldset.bbp-form {
+		padding: 0 10px 10px;
+	}
+	#bbpress-forums #bbp-user-body {
+		clear: both;
+		margin-left: 0;
+		word-wrap: break-word;
+	}
+}
+
+/* =Standard Mobile Portrait
+-------------------------------------------------------------- */
+@media only screen and (max-width: 320px) {
+	#bbpress-forums div.bbp-search-form {
+		margin-bottom: 10px;
+	}
+	#bbpress-forums li.bbp-header li.bbp-forum-info,
+	#bbpress-forums li.bbp-body li.bbp-forum-info,
+	#bbpress-forums li.bbp-header li.bbp-topic-title,
+	#bbpress-forums li.bbp-body li.bbp-topic-title {
+		width: 100%;
+	}
+	#bbpress-forums li.bbp-header li.bbp-forum-info,
+	#bbpress-forums li.bbp-header li.bbp-topic-title {
+		text-align: center;
+		text-transform: uppercase;
+	}
+	#bbpress-forums li.bbp-header li.bbp-forum-topic-count,
+	#bbpress-forums li.bbp-header li.bbp-forum-reply-count,
+	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
+	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
+	#bbpress-forums li.bbp-header li.bbp-topic-voice-count,
+	#bbpress-forums li.bbp-header li.bbp-topic-reply-count,
+	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
+	#bbpress-forums li.bbp-body li.bbp-topic-reply-count {
+		width: 20%;
+	}
+	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
+	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
+	#bbpress-forums li.bbp-header li.bbp-topic-freshness,
+	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
+		width: 58%;
+	}
+	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
+	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
+	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
+	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
+	#bbpress-forums li.bbp-body li.bbp-topic-reply-count,
+	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
+		margin-top: 7px;
+	}
+	#bbpress-forums li.bbp-header,
+	#bbpress-forums li.bbp-footer {
+		font-size: 10px;
+	}
+	#bbpress-forums li.bbp-header div.bbp-reply-author {
+		text-align: left;
+		width: 25%;
+	}
+	#bbpress-forums li.bbp-header div.bbp-reply-content {
+		margin-left: 25%;
+	}
+	#bbpress-forums div.bbp-template-notice img.avatar,
+	#bbpress-forums p.bbp-topic-meta img.avatar {
+		width: 14px;
+		height: auto;
+	}
+	#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar {
+		padding: 1px;
+	}
+	#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar td {
+		width: 20px;
+		height: 20px;
+	}
+	#bbpress-forums div.wp-editor-container {
+		width: 100%;
+		overflow: auto;
+	}
+	#bbpress-forums input#bbp_topic_title,
+	#bbpress-forums input#bbp_topic_tags {
+		width: 95%;
+	}
+}
+
+/* =Extra Small Mobile
+-------------------------------------------------------------- */
+@media only screen and (max-width: 240px) {
+	#bbpress-forums li.bbp-header li.bbp-forum-topic-count,
+	#bbpress-forums li.bbp-header li.bbp-forum-reply-count,
+	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
+	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
+	#bbpress-forums li.bbp-header li.bbp-topic-voice-count,
+	#bbpress-forums li.bbp-header li.bbp-topic-reply-count,
+	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
+	#bbpress-forums li.bbp-body li.bbp-topic-reply-count,
+	#bbpress-forums li.bbp-footer div.bbp-reply-author,
+	#bbpress-forums li.bbp-footer div.bbp-reply-content {
+		width: 45%;
+	}
+	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
+	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
+	#bbpress-forums li.bbp-header li.bbp-topic-freshness,
+	#bbpress-forums li.bbp-body li.bbp-topic-freshness,
+	#bbpress-forums li.bbp-header div.bbp-reply-author,
+	#bbpress-forums li.bbp-header div.bbp-reply-content {
+		clear: both;
+		width: 100%;
+	}
+	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
+	#bbpress-forums li.bbp-header li.bbp-topic-freshness {
+		text-align: center;
+	}
+	#bbpress-forums li.bbp-body li.bbp-topic-freshness,
+	#bbpress-forums li.bbp-header div.bbp-reply-content {
+		margin-left: 0;
+		text-align: left;
+	}
+	#bbpress-forums li.bbp-body li.bbp-topic-freshness p.bbp-topic-meta {
+		display: inline-block;
+	}
+	#bbpress-forums li.bbp-header {
+		overflow: hidden;
+	}
+	#bbpress-forums li.bbp-footer div.bbp-reply-content {
+		display: inline-block;
+		margin-left: 0;
+	}
+	#bbpress-forums li.bbp-body div.bbp-reply-author {
+		min-height: 60px;
+		padding-left: 60px;
+	}
+	#bbpress-forums div.bbp-reply-author img.avatar {
+		width: 40px;
+		height: auto;
+	}
+}
Index: /tags/2.5.4/templates/default/css/bbpress.min.css
===================================================================
--- /tags/2.5.4/templates/default/css/bbpress.min.css	(revision 5382)
+++ /tags/2.5.4/templates/default/css/bbpress.min.css	(revision 5382)
@@ -0,0 +1,1 @@
+#bbpress-forums hr{margin:0 0 24px 0}#bbpress-forums{background:transparent;clear:both;margin-bottom:20px;overflow:hidden;font-size:12px}#bbpress-forums div.even,#bbpress-forums ul.even{background-color:#fff}#bbpress-forums div.odd,#bbpress-forums ul.odd{background-color:#fbfbfb}body.reply-edit .reply{float:none}#bbpress-forums div.reply{height:auto;width:100%}#bbpress-forums div.bbp-forum-header,#bbpress-forums div.bbp-topic-header,#bbpress-forums div.bbp-reply-header{background-color:#f4f4f4}#bbpress-forums .status-trash.even,#bbpress-forums .status-spam.even{background-color:#fee}#bbpress-forums .status-trash.odd,#bbpress-forums .status-spam.odd{background-color:#fdd}#bbpress-forums .status-closed,#bbpress-forums .status-closed a{color:#ccc}#bbpress-forums ul{background:0;list-style:none;margin:0;padding:0}#bbpress-forums ul.bbp-threaded-replies{margin-left:50px}#bbpress-forums li{background:0;margin:0;list-style:none}#bbpress-forums ul.bbp-lead-topic,#bbpress-forums ul.bbp-topics,#bbpress-forums ul.bbp-forums,#bbpress-forums ul.bbp-replies,#bbpress-forums ul.bbp-search-results{font-size:12px;overflow:hidden;border:1px solid #eee;margin-bottom:20px;clear:both}#bbpress-forums li.bbp-header,#bbpress-forums li.bbp-body,#bbpress-forums li.bbp-footer{clear:both}#bbpress-forums li.bbp-header,#bbpress-forums li.bbp-footer{background:#f3f3f3;border-top:1px solid #eee;font-weight:bold;padding:8px;text-align:center}#bbpress-forums li.bbp-header{background:#eaeaea}#bbpress-forums li.bbp-header ul{overflow:hidden}#bbpress-forums .bbp-forums-list{margin:0 0 0 5px;padding-left:15px;border-left:1px solid #ddd}#bbpress-forums .bbp-forums-list li{display:inline;font-size:11px}#bbpress-forums li.bbp-footer p{margin:0;line-height:1em}li.bbp-forum-info,li.bbp-topic-title{float:left;text-align:left;width:55%}li.bbp-forum-topic-count,li.bbp-topic-voice-count,li.bbp-forum-reply-count,li.bbp-topic-reply-count{float:left;text-align:center;width:10%}li.bbp-forum-freshness,li.bbp-topic-freshness{text-align:center;float:left;width:22%}#bbpress-forums li.bbp-body ul.forum,#bbpress-forums li.bbp-body ul.topic{border-top:1px solid #eee;overflow:hidden;padding:8px}li.bbp-header div.bbp-topic-content span#subscription-toggle,li.bbp-header div.bbp-topic-content span#favorite-toggle,li.bbp-header div.bbp-reply-content span#subscription-toggle,li.bbp-header div.bbp-reply-content span#favorite-toggle{float:right}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-topic-title h3,#bbpress-forums div.bbp-reply-title h3{background:0;border:0;font-size:16px;line-height:1em;margin:8px 0;padding:0;text-transform:none}#bbpress-forums div.bbp-forum-author,#bbpress-forums div.bbp-topic-author,#bbpress-forums div.bbp-reply-author{float:left;text-align:center;width:115px}#bbpress-forums div.bbp-forum-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar,#bbpress-forums div.bbp-reply-author img.avatar{border:0;max-width:80px;padding:0;margin:12px auto 0 auto;float:none}#bbpress-forums div.bbp-forum-author a.bbp-author-name,#bbpress-forums div.bbp-topic-author a.bbp-author-name,#bbpress-forums div.bbp-reply-author a.bbp-author-name{margin:0 12px;word-break:break-word;display:inline-block}#bbpress-forums div.bbp-topic-author a.bbp-author-name,#bbpress-forums div.bbp-reply-author a.bbp-author-name{clear:left;display:block}#bbpress-forums div.bbp-forum-author .bbp-author-role,#bbpress-forums div.bbp-topic-author .bbp-author-role,#bbpress-forums div.bbp-reply-author .bbp-author-role{font-size:11px;font-style:italic}#bbpress-forums li.bbp-header .bbp-search-author,#bbpress-forums li.bbp-footer .bbp-search-author,#bbpress-forums li.bbp-header .bbp-forum-author,#bbpress-forums li.bbp-footer .bbp-forum-author,#bbpress-forums li.bbp-header .bbp-topic-author,#bbpress-forums li.bbp-footer .bbp-topic-author,#bbpress-forums li.bbp-header .bbp-reply-author,#bbpress-forums li.bbp-footer .bbp-reply-author{float:left;margin:0;padding:0;width:120px}#bbpress-forums li.bbp-header .bbp-search-content,#bbpress-forums li.bbp-footer .bbp-search-content,#bbpress-forums li.bbp-header .bbp-forum-content,#bbpress-forums li.bbp-footer .bbp-forum-content,#bbpress-forums li.bbp-header .bbp-topic-content,#bbpress-forums li.bbp-footer .bbp-topic-content,#bbpress-forums li.bbp-header .bbp-reply-content,#bbpress-forums li.bbp-footer .bbp-reply-content{margin-left:140px;padding:0;text-align:left}div.bbp-forum-header,div.bbp-topic-header,div.bbp-reply-header,li.bbp-body div.hentry{margin-bottom:0;overflow:hidden;padding:8px}div.bbp-forum-header,div.bbp-topic-header,div.bbp-reply-header{border-top:1px solid #ddd;clear:both}span.bbp-author-ip{font-family:'Helvetica Neue',Arial,Helvetica,'Nimbus Sans L',sans-serif;font-size:11px;font-weight:bold;color:#aaa}#bbpress-forums div.bbp-forum-content,#bbpress-forums div.bbp-topic-content,#bbpress-forums div.bbp-reply-content{margin-left:130px;padding:12px 12px 12px 0;text-align:left}#bbpress-forums div.bbp-forum-content:after,#bbpress-forums div.bbp-topic-content:after,#bbpress-forums div.bbp-reply-content:after{clear:both;content:".";display:block;float:none;height:0;font-size:0;visibility:hidden}#bbpress-forums div.bbp-topic-content a,#bbpress-forums div.bbp-reply-content a{background:0;border:0;display:inline;font-weight:normal;margin:0;padding:0}#bbpress-forums div.bbp-topic-content h1,#bbpress-forums div.bbp-reply-content h1,#bbpress-forums div.bbp-topic-content h2,#bbpress-forums div.bbp-reply-content h2,#bbpress-forums div.bbp-topic-content h3,#bbpress-forums div.bbp-reply-content h3,#bbpress-forums div.bbp-topic-content h4,#bbpress-forums div.bbp-reply-content h4,#bbpress-forums div.bbp-topic-content h5,#bbpress-forums div.bbp-reply-content h5,#bbpress-forums div.bbp-topic-content h6,#bbpress-forums div.bbp-reply-content h6{clear:none;line-height:1em;margin:24px 0;padding:0}#bbpress-forums div.bbp-topic-content img,#bbpress-forums div.bbp-reply-content img{max-width:100%}#bbpress-forums div.bbp-topic-content ul,#bbpress-forums div.bbp-reply-content ul,#bbpress-forums div.bbp-topic-content ol,#bbpress-forums div.bbp-reply-content ol{margin:0 15px 15px;padding:0}#bbpress-forums div.bbp-topic-content ul li,#bbpress-forums div.bbp-reply-content ul li{list-style-type:disc}#bbpress-forums div.bbp-topic-content ol li,#bbpress-forums div.bbp-reply-content ol li{list-style-type:decimal}#bbpress-forums div.bbp-topic-content ol li li,#bbpress-forums div.bbp-reply-content ol li li{list-style-type:lower-alpha}#bbpress-forums div.bbp-topic-content ol li li li,#bbpress-forums div.bbp-reply-content ol li li li{list-style-type:upper-roman}#bbpress-forums div.bbp-topic-content code,#bbpress-forums div.bbp-reply-content code,#bbpress-forums div.bbp-topic-content pre,#bbpress-forums div.bbp-reply-content pre{font-family:Inconsolata,Consolas,Monaco,Lucida Console,monospace;display:inline-block;background-color:#f9f9f9;border:1px solid #ddd;padding:0 5px;max-width:95%;vertical-align:middle;margin-top:-3px}#bbpress-forums div.bbp-topic-content pre,#bbpress-forums div.bbp-reply-content pre{display:block;line-height:18px;margin:0 0 24px;padding:5px 10px;white-space:pre;overflow:auto}#bbpress-forums div.bbp-topic-content pre code,#bbpress-forums div.bbp-reply-content pre code{display:block;border:0;padding:0;margin:0;background-color:transparent;overflow-wrap:normal;overflow:auto;max-width:100%}#bbpress-forums div.bbp-reply-to{margin-left:130px;padding:12px 12px 12px 0;text-align:right}#bbpress-forums div#bbp-cancel-reply-to{text-align:right}div.bbp-breadcrumb{float:left}div.bbp-breadcrumb,div.bbp-topic-tags{font-size:12px}#bbpress-forums div.bbp-breadcrumb p,#bbpress-forums div.bbp-topic-tags p{margin-bottom:10px}#bbpress-forums div.bbp-topic-tags{float:right}#bbp-topic-hot-tags{clear:both}#bbpress-forums #bbp-search-form{clear:left}#bbpress-forums #bbp-search-form .hidden{height:0;width:0;overflow:hidden;position:absolute;background:0;left:-999em}#bbpress-forums #bbp-search-form #bbp_search{display:inline-block;width:auto}#bbpress-forums div.bbp-search-form{float:right}span.bbp-admin-links{float:right;color:#ddd}span.bbp-admin-links a{color:#bbb;font-weight:normal;font-size:10px;text-transform:uppercase;text-decoration:none}fieldset span.bbp-admin-links{float:left}tr td span.bbp-admin-links a:hover{color:#ff4b33}td.bbp-topic-admin-links,td.bbp-topic-counts{width:50%}.bbp-forum-header a.bbp-forum-permalink,.bbp-topic-header a.bbp-topic-permalink,.bbp-reply-header a.bbp-reply-permalink{float:right;margin-left:10px;color:#ccc}.bbp-topic-action #favorite-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:bold;font-size:13px}.bbp-topic-action #favorite-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-topic-action #favorite-toggle span.is-favorite a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-topic-action #favorite-toggle span.is-favorite a:hover{color:#c88;border-color:#c88;background-color:#fdd}.bbp-topic-action #subscription-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:bold;font-size:13px}.bbp-topic-action #subscription-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-topic-action #subscription-toggle span.is-subscribed a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-topic-action #subscription-toggle span.is-subscribed a:hover{color:#c88;border-color:#c88;background-color:#fdd}#bbpress-forums .bbp-forum-info .bbp-forum-content,#bbpress-forums p.bbp-topic-meta{font-size:11px;margin:5px 0 5px;padding:0;word-wrap:break-word}#bbpress-forums p.bbp-topic-meta span{white-space:nowrap}.bbp-pagination-count{float:left;border:1px solid transparent}.bbp-pagination-links{float:right;list-style:none;display:inline}.bbp-pagination-links a,.bbp-pagination-links span.current{display:block;float:left;padding:0 5px;margin-left:5px;border:1px solid #efefef;text-decoration:none}.bbp-pagination-links a:hover,.bbp-pagination-links span.current{background:#eee;opacity:.8;border:1px solid #ddd}.bbp-pagination-links span.dots{display:block;float:left;padding:1px 4px;margin-left:5px}.bbp-pagination{float:left;width:100%;margin-bottom:15px}.bbp-topic-pagination{display:inline-block;margin-left:5px;margin-bottom:2px}.bbp-topic-pagination a{font-size:10px;line-height:10px;padding:1px 3px;border:1px solid #ddd;text-decoration:none}#bbpress-forums fieldset.bbp-form{clear:left}#bbpress-forums fieldset.bbp-form{border:1px solid #eee;padding:10px 20px;margin-bottom:10px}#bbpress-forums fieldset.bbp-form legend{padding:5px}#bbpress-forums fieldset.bbp-form label{margin:0;display:inline-block}#bbp-edit-topic-tag.bbp-form fieldset.bbp-form label,#bbp-login fieldset label,#bbp-register fieldset label,#bbp-lost-pass fieldset label{width:100px}#bbpress-forums fieldset.bbp-form p,#bbpress-forums fieldset.bbp-form textarea,#bbpress-forums fieldset.bbp-form select,#bbpress-forums fieldset.bbp-form input{margin:0 0 8px}textarea#bbp_reply_content,textarea#bbp_topic_content,textarea#bbp_forum_content{width:97%;box-sizing:border-box}textarea#bbp_forum_content{height:210px}#bbpress-forums fieldset.bbp-forum-form-attributes{width:200px;float:right;clear:none;margin-left:25px}#bbpress-forums fieldset select#bbp_forum_id{max-width:200px}.bbp-topic-form,.bbp-reply-form,.bbp-topic-tag-form{clear:left}body.topic-edit .bbp-topic-form div.avatar img,body.reply-edit .bbp-reply-form div.avatar img,body.single-forum .bbp-topic-form div.avatar img,body.single-reply .bbp-reply-form div.avatar img{margin-right:0;padding:10px;border:1px solid #ddd;line-height:0;background-color:#efefef}body.page .bbp-reply-form code,body.page .bbp-topic-form code,body.single-topic .bbp-reply-form code,body.single-forum .bbp-topic-form code,body.topic-edit .bbp-topic-form code,body.reply-edit .bbp-reply-form code{font-size:10px;background-color:#f0fff8;border:1px solid #ceefe1;display:block;padding:8px;margin-top:5px;width:369px}#merge_tag,#delete_tag{display:inline}div.bbp-submit-wrapper{margin-top:15px;float:right;clear:both}p.form-allowed-tags{max-width:100%}#bbpress-forums div.bbp-the-content-wrapper{margin-bottom:10px}#bbpress-forums div.bbp-the-content-wrapper textarea.bbp-the-content{width:100%;margin:0;font-size:12px}#bbpress-forums div.bbp-the-content-wrapper table,#bbpress-forums div.bbp-the-content-wrapper tbody,#bbpress-forums div.bbp-the-content-wrapper tr,#bbpress-forums div.bbp-the-content-wrapper td{border:0;padding:0;margin:0;width:auto;line-height:1em}#bbpress-forums div.bbp-the-content-wrapper input{font-size:12px;padding:5px;margin:0 2px 0 0;line-height:1em}#bbpress-forums div.bbp-the-content-wrapper div.quicktags-toolbar{padding:5px;min-height:26px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:4px 4px 8px}#bbpress-forums div.wp-editor-container{margin:0;padding:0;line-height:0}#bbpress-forums div.bbp-the-content-wrapper td.mceStatusbar{line-height:16px}#bbpress-forums #bbp-your-profile fieldset{padding:20px 20px 0 20px}#bbpress-forums #bbp-your-profile fieldset div{margin-bottom:20px;float:left;width:100%;clear:left}#bbpress-forums #bbp-your-profile fieldset select{margin-bottom:0}#bbpress-forums #bbp-your-profile fieldset input,#bbpress-forums #bbp-your-profile fieldset textarea{margin-bottom:0;width:60%;background:#f9f9f9;border:1px solid #ddd;box-shadow:none;padding:5px 8px;border-radius:0}#bbpress-forums #bbp-your-profile fieldset input:focus,#bbpress-forums #bbp-your-profile fieldset textarea:focus{border:1px solid #ccc;box-shadow:inset 1px 1px 1px rgba(0,0,0,0.1);outline-color:rgba(240,255,240,0.1)}#bbpress-forums #bbp-your-profile fieldset.bbp-form input.checkbox{width:auto}#bbpress-forums #bbp-your-profile fieldset legend{display:none}#bbpress-forums #bbp-your-profile fieldset label[for]{float:left;width:20%;padding:5px 20px 5px 0;text-align:right;cursor:pointer}#bbpress-forums #bbp-your-profile fieldset dl label[for]{text-align:left;width:60%}#bbpress-forums #bbp-your-profile fieldset span.description{margin:5px 0 0 20%;font-size:12px;font-style:italic;float:left;clear:left;width:60%;padding:5px 8px;border:#cee1ef 1px solid;background-color:#f0f8ff}#bbpress-forums #bbp-your-profile fieldset fieldset{margin:0;border:0;padding:0;clear:none;float:none}#bbpress-forums #bbp-your-profile fieldset fieldset.password{width:60%;display:inline}#bbpress-forums #bbp-your-profile fieldset fieldset.password input,#bbpress-forums #bbp-your-profile fieldset fieldset.password span{width:100%}#bbpress-forums #bbp-your-profile fieldset fieldset.capabilities dl{margin:0}#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description{margin-left:0;margin-bottom:20px}#bbpress-forums #bbp-your-profile fieldset.submit button{float:right}div.bbp-template-notice,div.indicator-hint{border-width:1px;border-style:solid;padding:0 .6em;margin:5px 0 15px;border-radius:3px;background-color:#ffffe0;border-color:#e6db55;color:#000;clear:both}div.bbp-template-notice a{color:#555;text-decoration:none}div.bbp-template-notice a:hover{color:#000}div.bbp-template-notice.info{border:#cee1ef 1px solid;background-color:#f0f8ff}div.bbp-template-notice.important{border:#e6db55 1px solid;background-color:#fffbcc}div.bbp-template-notice.error,div.bbp-template-notice.warning{background-color:#ffebe8;border-color:#c00}div.bbp-template-notice.error a,div.bbp-template-notice.warning a{color:#c00}div.bbp-template-notice p{margin:.5em 0 6px 0 !important;padding:2px;font-size:12px;line-height:140%}.bbp-topics-front ul.super-sticky,.bbp-topics ul.super-sticky,.bbp-topics ul.sticky,.bbp-forum-content ul.sticky{background-color:#ffffe0 !important;font-size:1.1em}#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log,#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log{border-top:1px dotted #ddd;width:100%;margin:0;padding:8px 0 0 0;font-size:11px;color:#aaa}#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log li,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log li,#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log li{list-style-type:none}.bbp-login-form fieldset legend{display:none}.bbp-login-form .bbp-username input,.bbp-login-form .bbp-email input,.bbp-login-form .bbp-password input{padding:5px}.bbp-login-form label{width:140px;display:inline-block}#sidebar .bbp-login-form label{width:70px}.bbp-login-form .bbp-username,.bbp-login-form .bbp-email,.bbp-login-form .bbp-password,.bbp-login-form .bbp-remember-me,.bbp-login-form .bbp-submit-wrapper{margin-top:10px}.bbp-login-form .bbp-submit-wrapper{text-align:right}.bbp-login-form .bbp-login-links a{float:left;clear:left}.bbp-logged-in img.avatar{float:left;margin:0 15px 0 0}.bbp-logged-in h4{font-weight:bold;font-size:1.3em;clear:none;margin-bottom:10px}#bbpress-forums p.bbp-topic-meta img.avatar,#bbpress-forums ul.bbp-reply-revision-log img.avatar,#bbpress-forums ul.bbp-topic-revision-log img.avatar,#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums .widget_display_topics img.avatar,#bbpress-forums .widget_display_replies img.avatar{float:none;margin-bottom:-7px;border:3px double #ddd}fieldset div.avatar{float:right}.activity-list li.bbp_topic_create .activity-content .activity-inner,.activity-list li.bbp_reply_create .activity-content .activity-inner{border-left:2px solid #eaeaea;margin-left:5px;padding-left:10px}#bbpress-forums h1{clear:none;font-size:1.8em;line-height:1em;padding-bottom:10px}#bbpress-forums #bbp-user-wrapper{float:left;width:100%}#bbpress-forums .bbp-user-section{overflow:auto}#bbpress-forums #bbp-user-wrapper h2.entry-title{font-size:1.4em;margin:0;padding-bottom:10px;padding-top:0;clear:none}#bbpress-forums #bbp-user-wrapper ul.bbp-lead-topic,#bbpress-forums #bbp-user-wrapper ul.bbp-topics,#bbpress-forums #bbp-user-wrapper ul.bbp-forums,#bbpress-forums #bbp-user-wrapper ul.bbp-replies,#bbpress-forums #bbp-user-wrapper fieldset.bbp-form{clear:none}#bbpress-forums #bbp-single-user-details{margin:0;width:150px;float:left;overflow:hidden}#bbpress-forums #bbp-single-user-details #bbp-user-avatar{margin:0;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-avatar img.avatar{border:0;height:150px;padding:0;margin:0 0 20px 0;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-description{float:none;margin-left:180px}#bbpress-forums #bbp-single-user-details #bbp-user-navigation{float:none;margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li{margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation a{padding:5px 8px;display:block;border:1px solid transparent;text-decoration:none}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li.current a{background:#eee;opacity:.8}#bbpress-forums #bbp-user-body{margin-left:180px}body.my-account #bbpress-forums{border-top:0;padding-top:0;margin-bottom:0}#bbpress-forums dl.bbp-user-capabilities{display:inline-block;vertical-align:top}#bbpress-forums dl.bbp-user-capabilities dt{margin:0 0 10px;text-transform:capitalize}#bbpress-forums dl.bbp-user-capabilities dd{margin:0;padding:0}#bbpress-forums div.row-actions{font-size:11px;visibility:hidden}#bbpress-forums li:hover>div.row-actions{visibility:visible}@media screen and (max-device-width:480px),screen and (-webkit-min-device-pixel-ratio:2){-webkit-text-size-adjust:none}@media only screen and (max-width:480px){#bbpress-forums div.bbp-topic-tags{clear:left;float:left}div.bbp-search-form input,div.bbp-search-form button{font-size:11px;padding:2px}li.bbp-forum-info,li.bbp-topic-title{width:45%}li.bbp-forum-topic-count,li.bbp-forum-reply-count,li.bbp-topic-voice-count,li.bbp-topic-reply-count{width:15%}span.bbp-reply-post-date{float:left}span.bbp-admin-links{clear:left;float:left}#bbpress-forums .bbp-forums-list li{display:block;font-size:11px}#bbpress-forums .bbp-body div.bbp-reply-author{margin:-15px 10px 10px;min-height:100px;padding-left:80px;position:relative;text-align:left;width:100%}#bbpress-forums div.bbp-reply-author a.bbp-author-name{clear:none;display:inline-block;margin-left:0;word-wrap:break-word}#bbpress-forums div.bbp-reply-author img.avatar{position:absolute;top:15px;left:0;width:60px;height:auto}#bbpress-forums div.bbp-reply-author .bbp-author-role{font-size:12px;font-style:normal}#bbpress-forums .bbp-body div.bbp-reply-content{clear:both;margin:10px;padding:0}#bbpress-forums div.bbp-reply-content p{margin-bottom:1em}div.bbp-submit-wrapper{float:left}#bbpress-forums fieldset.bbp-form{padding:0 10px 10px}#bbpress-forums #bbp-user-body{clear:both;margin-left:0;word-wrap:break-word}}@media only screen and (max-width:320px){#bbpress-forums div.bbp-search-form{margin-bottom:10px}#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-body li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title,#bbpress-forums li.bbp-body li.bbp-topic-title{width:100%}#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title{text-align:center;text-transform:uppercase}#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count{width:20%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness{width:58%}#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-freshness{margin-top:7px}#bbpress-forums li.bbp-header,#bbpress-forums li.bbp-footer{font-size:10px}#bbpress-forums li.bbp-header div.bbp-reply-author{text-align:left;width:25%}#bbpress-forums li.bbp-header div.bbp-reply-content{margin-left:25%}#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums p.bbp-topic-meta img.avatar{width:14px;height:auto}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:1px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar td{width:20px;height:20px}#bbpress-forums div.wp-editor-container{width:100%;overflow:auto}#bbpress-forums input#bbp_topic_title,#bbpress-forums input#bbp_topic_tags{width:95%}}@media only screen and (max-width:240px){#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-footer div.bbp-reply-author,#bbpress-forums li.bbp-footer div.bbp-reply-content{width:45%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header div.bbp-reply-author,#bbpress-forums li.bbp-header div.bbp-reply-content{clear:both;width:100%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{text-align:center}#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header div.bbp-reply-content{margin-left:0;text-align:left}#bbpress-forums li.bbp-body li.bbp-topic-freshness p.bbp-topic-meta{display:inline-block}#bbpress-forums li.bbp-header{overflow:hidden}#bbpress-forums li.bbp-footer div.bbp-reply-content{display:inline-block;margin-left:0}#bbpress-forums li.bbp-body div.bbp-reply-author{min-height:60px;padding-left:60px}#bbpress-forums div.bbp-reply-author img.avatar{width:40px;height:auto}}
Index: /tags/2.5.4/templates/default/extras/archive-forum.php
===================================================================
--- /tags/2.5.4/templates/default/extras/archive-forum.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/archive-forum.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * bbPress - Forum Archive
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<div id="forum-front" class="bbp-forum-front">
+		<h1 class="entry-title"><?php bbp_forum_archive_title(); ?></h1>
+		<div class="entry-content">
+
+			<?php bbp_get_template_part( 'content', 'archive-forum' ); ?>
+
+		</div>
+	</div><!-- #forum-front -->
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/archive-topic.php
===================================================================
--- /tags/2.5.4/templates/default/extras/archive-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/archive-topic.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * bbPress - Topic Archive
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<div id="topic-front" class="bbp-topics-front">
+		<h1 class="entry-title"><?php bbp_topic_archive_title(); ?></h1>
+		<div class="entry-content">
+
+			<?php bbp_get_template_part( 'content', 'archive-topic' ); ?>
+
+		</div>
+	</div><!-- #topics-front -->
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-create-topic.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-create-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-create-topic.php	(revision 5382)
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * Template Name: bbPress - Create Topic
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-new-topic" class="bbp-new-topic">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php the_content(); ?>
+
+				<?php bbp_get_template_part( 'form', 'topic' ); ?>
+
+			</div>
+		</div><!-- #bbp-new-topic -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-forum-statistics.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-forum-statistics.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-forum-statistics.php	(revision 5382)
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * Template Name: bbPress - Statistics
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-statistics" class="bbp-statistics">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php get_the_content() ? the_content() : _e( '<p>Here are the statistics and popular topics of our forums.</p>', 'bbpress' ); ?>
+
+				<div id="bbpress-forums">
+
+					<?php bbp_get_template_part( 'content', 'statistics' ); ?>
+
+					<?php do_action( 'bbp_before_popular_topics' ); ?>
+
+					<?php bbp_set_query_name( 'bbp_popular_topics' ); ?>
+
+					<?php if ( bbp_view_query( 'popular' ) ) : ?>
+
+						<h2 class="entry-title"><?php _e( 'Popular Topics', 'bbpress' ); ?></h2>
+
+						<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+						<?php bbp_get_template_part( 'loop',       'topics' ); ?>
+
+						<?php bbp_get_template_part( 'pagination', 'topics' ); ?>
+
+					<?php endif; ?>
+
+					<?php bbp_reset_query_name(); ?>
+
+					<?php do_action( 'bbp_after_popular_topics' ); ?>
+
+				</div>
+			</div>
+		</div><!-- #bbp-statistics -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+
+<?php get_footer();
Index: /tags/2.5.4/templates/default/extras/page-front-forums.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-front-forums.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-front-forums.php	(revision 5382)
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * Template Name: bbPress - Forums (Index)
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="forum-front" class="bbp-forum-front">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php the_content(); ?>
+
+				<?php bbp_get_template_part( 'content', 'archive-forum' ); ?>
+
+			</div>
+		</div><!-- #forum-front -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-front-topics.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-front-topics.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-front-topics.php	(revision 5382)
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * Template Name: bbPress - Topics (Newest)
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="topics-front" class="bbp-topics-front">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php the_content(); ?>
+
+				<?php bbp_get_template_part( 'content', 'archive-topic' ); ?>
+
+			</div>
+		</div><!-- #topics-front -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-topic-tags.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-topic-tags.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-topic-tags.php	(revision 5382)
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Template Name: bbPress - Topic Tags
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-topic-tags" class="bbp-topic-tags">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php get_the_content() ? the_content() : _e( '<p>This is a collection of tags that are currently popular on our forums.</p>', 'bbpress' ); ?>
+
+				<div id="bbpress-forums">
+
+					<?php bbp_breadcrumb(); ?>
+
+					<div id="bbp-topic-hot-tags">
+
+						<?php wp_tag_cloud( array( 'smallest' => 9, 'largest' => 38, 'number' => 80, 'taxonomy' => bbp_get_topic_tag_tax_id() ) ); ?>
+
+					</div>
+				</div>
+			</div>
+		</div><!-- #bbp-topic-tags -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-topics-no-replies.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-topics-no-replies.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-topics-no-replies.php	(revision 5382)
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * Template Name: bbPress - Topics (No Replies)
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="topics-front" class="bbp-topics-front">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php the_content(); ?>
+
+				<div id="bbpress-forums">
+
+					<?php bbp_breadcrumb(); ?>
+
+					<?php bbp_set_query_name( 'bbp_no_replies' ); ?>
+
+					<?php if ( bbp_has_topics( array( 'meta_key' => '_bbp_reply_count', 'meta_value' => '1', 'meta_compare' => '<', 'orderby' => 'date', 'show_stickies' => false ) ) ) : ?>
+
+						<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+						<?php bbp_get_template_part( 'loop',       'topics'    ); ?>
+
+						<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>
+
+					<?php else : ?>
+
+						<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>
+
+					<?php endif; ?>
+
+					<?php bbp_reset_query_name(); ?>
+
+				</div>
+			</div>
+		</div><!-- #topics-front -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-user-login.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-user-login.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-user-login.php	(revision 5382)
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Template Name: bbPress - User Login
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+// No logged in users
+bbp_logged_in_redirect();
+
+// Begin Template
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-login" class="bbp-login">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php the_content(); ?>
+
+				<div id="bbpress-forums">
+
+					<?php bbp_breadcrumb(); ?>
+
+					<?php bbp_get_template_part( 'form', 'user-login' ); ?>
+
+				</div>
+			</div>
+		</div><!-- #bbp-login -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-user-lost-pass.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-user-lost-pass.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-user-lost-pass.php	(revision 5382)
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Template Name: bbPress - User Lost Password
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+// No logged in users
+bbp_logged_in_redirect();
+
+// Begin Template
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-lost-pass" class="bbp-lost-pass">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php the_content(); ?>
+
+				<div id="bbpress-forums">
+
+					<?php bbp_breadcrumb(); ?>
+
+					<?php bbp_get_template_part( 'form', 'user-lost-pass' ); ?>
+
+				</div>
+			</div>
+		</div><!-- #bbp-lost-pass -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/page-user-register.php
===================================================================
--- /tags/2.5.4/templates/default/extras/page-user-register.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/page-user-register.php	(revision 5382)
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Template Name: bbPress - User Register
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+// No logged in users
+bbp_logged_in_redirect();
+
+// Begin Template
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-register" class="bbp-register">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php the_content(); ?>
+
+				<div id="bbpress-forums">
+
+					<?php bbp_breadcrumb(); ?>
+
+					<?php bbp_get_template_part( 'form', 'user-register' ); ?>
+
+				</div>
+			</div>
+		</div><!-- #bbp-register -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-forum-edit.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-forum-edit.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-forum-edit.php	(revision 5382)
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * Edit handler for forums
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-edit-page" class="bbp-edit-page">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php bbp_get_template_part( 'form', 'forum' ); ?>
+
+			</div>
+		</div><!-- #bbp-edit-page -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-forum.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-forum.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-forum.php	(revision 5382)
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * Single Forum
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<?php if ( bbp_user_can_view_forum() ) : ?>
+
+			<div id="forum-<?php bbp_forum_id(); ?>" class="bbp-forum-content">
+				<h1 class="entry-title"><?php bbp_forum_title(); ?></h1>
+				<div class="entry-content">
+
+					<?php bbp_get_template_part( 'content', 'single-forum' ); ?>
+
+				</div>
+			</div><!-- #forum-<?php bbp_forum_id(); ?> -->
+
+		<?php else : // Forum exists, user no access ?>
+
+			<?php bbp_get_template_part( 'feedback', 'no-access' ); ?>
+
+		<?php endif; ?>
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-reply-edit.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-reply-edit.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-reply-edit.php	(revision 5382)
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * Edit handler for replies
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-edit-page" class="bbp-edit-page">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php bbp_get_template_part( 'form', 'reply' ); ?>
+
+			</div>
+		</div><!-- #bbp-edit-page -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-reply-move.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-reply-move.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-reply-move.php	(revision 5382)
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Move reply page
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-edit-page" class="bbp-edit-page">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php bbp_get_template_part( 'form', 'reply-move' ); ?>
+
+			</div>
+		</div><!-- #bbp-edit-page -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer();
Index: /tags/2.5.4/templates/default/extras/single-reply.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-reply.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-reply.php	(revision 5382)
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * Single Reply
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php if ( bbp_user_can_view_forum( array( 'forum_id' => bbp_get_reply_forum_id() ) ) ) : ?>
+
+		<?php while ( have_posts() ) : the_post(); ?>
+
+			<div id="bbp-reply-wrapper-<?php bbp_reply_id(); ?>" class="bbp-reply-wrapper">
+				<h1 class="entry-title"><?php bbp_reply_title(); ?></h1>
+				<div class="entry-content">
+
+					<?php bbp_get_template_part( 'content', 'single-reply' ); ?>
+
+				</div><!-- .entry-content -->
+			</div><!-- #bbp-reply-wrapper-<?php bbp_reply_id(); ?> -->
+
+		<?php endwhile; ?>
+
+	<?php elseif ( bbp_is_forum_private( bbp_get_reply_forum_id(), false ) ) : ?>
+
+		<?php bbp_get_template_part( 'feedback', 'no-access' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-topic-edit.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-topic-edit.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-topic-edit.php	(revision 5382)
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * Edit handler for topics
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-edit-page" class="bbp-edit-page">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php bbp_get_template_part( 'form', 'topic' ); ?>
+
+			</div>
+		</div><!-- #bbp-edit-page -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-topic-merge.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-topic-merge.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-topic-merge.php	(revision 5382)
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Merge topic page
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-edit-page" class="bbp-edit-page">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php bbp_get_template_part( 'form', 'topic-merge' ); ?>
+
+			</div>
+		</div><!-- #bbp-edit-page -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-topic-split.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-topic-split.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-topic-split.php	(revision 5382)
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Split topic page
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php while ( have_posts() ) : the_post(); ?>
+
+		<div id="bbp-edit-page" class="bbp-edit-page">
+			<h1 class="entry-title"><?php the_title(); ?></h1>
+			<div class="entry-content">
+
+				<?php bbp_get_template_part( 'form', 'topic-split' ); ?>
+
+			</div>
+		</div><!-- #bbp-edit-page -->
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-topic.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-topic.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-topic.php	(revision 5382)
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * Single Topic
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<?php if ( bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) ) : ?>
+
+		<?php while ( have_posts() ) : the_post(); ?>
+
+			<div id="bbp-topic-wrapper-<?php bbp_topic_id(); ?>" class="bbp-topic-wrapper">
+				<h1 class="entry-title"><?php bbp_topic_title(); ?></h1>
+				<div class="entry-content">
+
+					<?php bbp_get_template_part( 'content', 'single-topic' ); ?>
+
+				</div>
+			</div><!-- #bbp-topic-wrapper-<?php bbp_topic_id(); ?> -->
+
+		<?php endwhile; ?>
+
+	<?php elseif ( bbp_is_forum_private( bbp_get_topic_forum_id(), false ) ) : ?>
+
+		<?php bbp_get_template_part( 'feedback', 'no-access' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-user-edit.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-user-edit.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-user-edit.php	(revision 5382)
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * bbPress User Profile Edit
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<div id="bbp-user-<?php bbp_current_user_id(); ?>" class="bbp-single-user">
+		<div class="entry-content">
+
+			<?php bbp_get_template_part( 'content', 'single-user' ); ?>
+
+		</div><!-- .entry-content -->
+	</div><!-- #bbp-user-<?php bbp_current_user_id(); ?> -->
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-user.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-user.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-user.php	(revision 5382)
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * Single User
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<div id="bbp-user-<?php bbp_current_user_id(); ?>" class="bbp-single-user">
+		<div class="entry-content">
+
+			<?php bbp_get_template_part( 'content', 'single-user' ); ?>
+
+		</div><!-- .entry-content -->
+	</div><!-- #bbp-user-<?php bbp_current_user_id(); ?> -->
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/single-view.php
===================================================================
--- /tags/2.5.4/templates/default/extras/single-view.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/single-view.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Single View
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<div id="bbp-view-<?php bbp_view_id(); ?>" class="bbp-view">
+		<h1 class="entry-title"><?php bbp_view_title(); ?></h1>
+		<div class="entry-content">
+
+			<?php bbp_get_template_part( 'content', 'single-view' ); ?>
+
+		</div>
+	</div><!-- #bbp-view-<?php bbp_view_id(); ?> -->
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/taxonomy-topic-tag-edit.php
===================================================================
--- /tags/2.5.4/templates/default/extras/taxonomy-topic-tag-edit.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/taxonomy-topic-tag-edit.php	(revision 5382)
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Topic Tag Edit
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<div id="topic-tag" class="bbp-topic-tag">
+		<h1 class="entry-title"><?php printf( __( 'Topic Tag: %s', 'bbpress' ), '<span>' . bbp_get_topic_tag_name() . '</span>' ); ?></h1>
+
+		<div class="entry-content">
+
+			<?php bbp_get_template_part( 'content', 'topic-tag-edit' ); ?>
+
+		</div>
+	</div><!-- #topic-tag -->
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/extras/taxonomy-topic-tag.php
===================================================================
--- /tags/2.5.4/templates/default/extras/taxonomy-topic-tag.php	(revision 5382)
+++ /tags/2.5.4/templates/default/extras/taxonomy-topic-tag.php	(revision 5382)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Topic Tag
+ *
+ * @package bbPress
+ * @subpackage Theme
+ */
+
+get_header(); ?>
+
+	<?php do_action( 'bbp_before_main_content' ); ?>
+
+	<?php do_action( 'bbp_template_notices' ); ?>
+
+	<div id="topic-tag" class="bbp-topic-tag">
+		<h1 class="entry-title"><?php printf( __( 'Topic Tag: %s', 'bbpress' ), '<span>' . bbp_get_topic_tag_name() . '</span>' ); ?></h1>
+		<div class="entry-content">
+
+			<?php bbp_get_template_part( 'content', 'archive-topic' ); ?>
+
+		</div>
+	</div><!-- #topic-tag -->
+
+	<?php do_action( 'bbp_after_main_content' ); ?>
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
Index: /tags/2.5.4/templates/default/js/editor.js
===================================================================
--- /tags/2.5.4/templates/default/js/editor.js	(revision 5382)
+++ /tags/2.5.4/templates/default/js/editor.js	(revision 5382)
@@ -0,0 +1,50 @@
+jQuery(document).ready( function() {
+
+	/* Use backticks instead of <code> for the Code button in the editor */
+	if ( typeof( edButtons ) !== 'undefined' ) {
+		edButtons[110] = new QTags.TagButton( 'code', 'code', '`', '`', 'c' );
+		QTags._buttonsInit();
+	}
+
+	/* Tab from topic title */
+	jQuery( '#bbp_topic_title' ).bind( 'keydown.editor-focus', function(e) {
+		if ( e.which !== 9 )
+			return;
+
+		if ( !e.ctrlKey && !e.altKey && !e.shiftKey ) {
+			if ( typeof( tinymce ) !== 'undefined' ) {
+				if ( ! tinymce.activeEditor.isHidden() ) {
+					var editor = tinymce.activeEditor.editorContainer;
+					jQuery( '#' + editor + ' td.mceToolbar > a' ).focus();
+				} else {
+					jQuery( 'textarea.bbp-the-content' ).focus();
+				}
+			} else {
+				jQuery( 'textarea.bbp-the-content' ).focus();
+			}
+
+			e.preventDefault();
+		}
+	});
+
+	/* Shift + tab from topic tags */
+	jQuery( '#bbp_topic_tags' ).bind( 'keydown.editor-focus', function(e) {
+		if ( e.which !== 9 )
+			return;
+
+		if ( e.shiftKey && !e.ctrlKey && !e.altKey ) {
+			if ( typeof( tinymce ) !== 'undefined' ) {
+				if ( ! tinymce.activeEditor.isHidden() ) {
+					var editor = tinymce.activeEditor.editorContainer;
+					jQuery( '#' + editor + ' td.mceToolbar > a' ).focus();
+				} else {
+					jQuery( 'textarea.bbp-the-content' ).focus();
+				}
+			} else {
+				jQuery( 'textarea.bbp-the-content' ).focus();
+			}
+
+			e.preventDefault();
+		}
+	});
+});
Index: /tags/2.5.4/templates/default/js/reply.js
===================================================================
--- /tags/2.5.4/templates/default/js/reply.js	(revision 5382)
+++ /tags/2.5.4/templates/default/js/reply.js	(revision 5382)
@@ -0,0 +1,47 @@
+addReply = {
+	moveForm : function(replyId, parentId, respondId, postId) {
+		var t = this, div, reply = t.I(replyId), respond = t.I(respondId), cancel = t.I('bbp-cancel-reply-to-link'), parent = t.I('bbp_reply_to'), post = t.I('bbp_topic_id');
+
+		if ( ! reply || ! respond || ! cancel || ! parent )
+			return;
+
+		t.respondId = respondId;
+		postId = postId || false;
+
+		if ( ! t.I('bbp-temp-form-div') ) {
+			div = document.createElement('div');
+			div.id = 'bbp-temp-form-div';
+			div.style.display = 'none';
+			respond.parentNode.insertBefore(div, respond);
+		}
+
+		reply.parentNode.insertBefore(respond);
+		if ( post && postId )
+			post.value = postId;
+		parent.value = parentId;
+		cancel.style.display = '';
+
+		cancel.onclick = function() {
+			var t = addReply, temp = t.I('bbp-temp-form-div'), respond = t.I(t.respondId);
+
+			if ( ! temp || ! respond )
+				return;
+
+			t.I('bbp_reply_to').value = '0';
+			temp.parentNode.insertBefore(respond, temp);
+			temp.parentNode.removeChild(temp);
+			this.style.display = 'none';
+			this.onclick = null;
+			return false;
+		}
+
+		try { t.I('bbp_reply_content').focus(); }
+		catch(e) {}
+
+		return false;
+	},
+
+	I : function(e) {
+		return document.getElementById(e);
+	}
+}
Index: /tags/2.5.4/templates/default/js/topic.js
===================================================================
--- /tags/2.5.4/templates/default/js/topic.js	(revision 5382)
+++ /tags/2.5.4/templates/default/js/topic.js	(revision 5382)
@@ -0,0 +1,31 @@
+jQuery( document ).ready( function ( $ ) {
+
+	function bbp_ajax_call( action, topic_id, nonce, update_selector ) {
+		var $data = {
+			action : action,
+			id     : topic_id,
+			nonce  : nonce
+		};
+
+		$.post( bbpTopicJS.bbp_ajaxurl, $data, function ( response ) {
+			if ( response.success ) {
+				$( update_selector ).html( response.content );
+			} else {
+				if ( !response.content ) {
+					response.content = bbpTopicJS.generic_ajax_error;
+				}
+				alert( response.content );
+			}
+		} );
+	}
+
+	$( '#favorite-toggle' ).on( 'click', 'span a.favorite-toggle', function( e ) {
+		e.preventDefault();
+		bbp_ajax_call( 'favorite', $( this ).attr( 'data-topic' ), bbpTopicJS.fav_nonce, '#favorite-toggle' );
+	} );
+
+	$( '#subscription-toggle' ).on( 'click', 'span a.subscription-toggle', function( e ) {
+		e.preventDefault();
+		bbp_ajax_call( 'subscription', $( this ).attr( 'data-topic' ), bbpTopicJS.subs_nonce, '#subscription-toggle' );
+	} );
+} );
Index: /tags/2.5.4/templates/default/js/user.js
===================================================================
--- /tags/2.5.4/templates/default/js/user.js	(revision 5382)
+++ /tags/2.5.4/templates/default/js/user.js	(revision 5382)
@@ -0,0 +1,3 @@
+if ( window.location.hash === '#password' ) {
+	document.getElementById('pass1').focus();
+}
Index: /tags/2.5.4/templates/index.php
===================================================================
--- /tags/2.5.4/templates/index.php	(revision 5382)
+++ /tags/2.5.4/templates/index.php	(revision 5382)
@@ -0,0 +1,7 @@
+<?php
+
+/**
+ * Do not put custom themes here. They will be deleted on bbPress updates.
+ *
+ * Keep custom bbPress themes in /wp-content/themes/
+ */
