Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Display bbPress Posts without a Plugin

[ Display bbPress Posts without a Plugin ] I recently redesigned my .htaccess site, htaccessbook.com. Before the redesign, I was using bbPress for the forum functionality. It worked okay for a few years, but along the way there were all sorts of really nasty bugs and important things breaking. It seemed like, no matter what, each updated version of the bbPress plugin caused serious problems, like replies not working, permalinks changing, and all sorts of other issues. Eventually, I got tired of spending hours after each bbPress update to try and fix things. It was time to find a better way.

No plugins required

After researching possible replacements for bbPress, I felt unimpressed and uninspired. There just weren’t any good fits that met all of my requirements, which honestly were fairly modest. So I gave up on existing “solutions” and decided to roll my own. After some investigation and planning, it turned out that all I needed was a way to display all of the forum topics and replies. Didn’t need any other functionality, just a way to display existing forum content.

Currently the forum is closed to new replies, which is why I needed only to display content. At some point in the future I will reopen the forum and use USP Pro to enable logged in users to submit new topics and replies. But for now, I’m simply displaying the existing forum content publicly on the front-end.

And so that’s what this tutorial is all about: displaying your bbPress content without using a plugin. This may be useful if you are ditching bbPress or in the process of finding another forum solution (which unfortunately is easier said than done).

Before diving in, please understand that this technique is not really meant to be a full-fledged solution. It’s simply a way to access your forum content from the database and display it on the front-end of your WordPress-powered site. With that in mind, here are the steps (and code) required to make it happen.

Step 0: Back up your database and files

Before making any changes, take a moment to ensure that you have a good working backup of your site files and database. This is entirely a precautionary measure and just good practice in general. So if anything unexpected or weird happens, you can restore your site’s functionality as quickly as possible.

Step 1: Add support for Topics and Replies

First, we need to add support for a couple of Custom Post Types (CPTs). When bbPress was installed, it provided the support required for its various CPTs. Now bbPress is removed, but all of that CPT data remains in the database. For this tutorial, we want to display Topics and Replies, so we need to add CPT support accordingly. To do so, add the following template code to your current theme’s functions.php file:

// add support for topic cpt
function shapeSpace_topic_cpt() {
	$labels = array(
		'name'               => __('Topics', 'shapeSpace'),
		'singular_name'      => __('Topic', 'shapeSpace'),
		'menu_name'          => __('Topics', 'shapeSpace'),
		'name_admin_bar'     => __('Topics', 'shapeSpace'),
		'add_new'            => __('Add New', 'shapeSpace'),
		'add_new_item'       => __('Add New Topic', 'shapeSpace'),
		'new_item'           => __('New Topic', 'shapeSpace'),
		'edit_item'          => __('Edit Topic', 'shapeSpace'),
		'view_item'          => __('View Topic', 'shapeSpace'),
		'all_items'          => __('All Topics', 'shapeSpace'),
		'search_items'       => __('Search Topics', 'shapeSpace'),
		'parent_item_colon'  => __('Parent Topics:', 'shapeSpace'),
		'not_found'          => __('No topics found.', 'shapeSpace'),
		'not_found_in_trash' => __('No topics found in Trash.', 'shapeSpace'),
	);
	$args = array(
		'labels'              => $labels,
		'taxonomies'          => array(),
		'public'              => true,
		'publicly_queryable'  => true,
		'show_ui'             => true,
		'show_in_menu'        => true,
		'query_var'           => true,
		'rewrite'             => array('slug' => 'topic'),
		'capability_type'     => 'post',
		'has_archive'         => true,
		'hierarchical'        => false,
		'menu_position'       => null,
		'supports'            => array('title', 'editor', 'author', 'excerpt', 'custom-fields'),
		'exclude_from_search' => false, 
	);
	register_post_type('topic', $args);
}
add_action('init', 'shapeSpace_topic_cpt');



// add support for reply cpt
function shapeSpace_reply_cpt() {
	$labels = array(
		'name'               => __('Replies', 'shapeSpace'),
		'singular_name'      => __('Reply', 'shapeSpace'),
		'menu_name'          => __('Replies', 'shapeSpace'),
		'name_admin_bar'     => __('Replies', 'shapeSpace'),
		'add_new'            => __('Add New', 'shapeSpace'),
		'add_new_item'       => __('Add New Reply', 'shapeSpace'),
		'new_item'           => __('New Reply', 'shapeSpace'),
		'edit_item'          => __('Edit Reply', 'shapeSpace'),
		'view_item'          => __('View Reply', 'shapeSpace'),
		'all_items'          => __('All Replies', 'shapeSpace'),
		'search_items'       => __('Search Replies', 'shapeSpace'),
		'parent_item_colon'  => __('Parent Replies:', 'shapeSpace'),
		'not_found'          => __('No replies found.', 'shapeSpace'),
		'not_found_in_trash' => __('No replies found in Trash.', 'shapeSpace'),
	);
	$args = array(
		'labels'              => $labels,
		'taxonomies'          => array(),
		'public'              => true,
		'publicly_queryable'  => true,
		'show_ui'             => true,
		'show_in_menu'        => true,
		'query_var'           => true,
		'rewrite'             => array('slug' => 'reply'),
		'capability_type'     => 'post',
		'has_archive'         => false,
		'hierarchical'        => false,
		'menu_position'       => null,
		'supports'            => array('title', 'editor', 'author', 'excerpt', 'custom-fields'),
		'exclude_from_search' => true, 
	);
	register_post_type('reply', $args);
}
add_action('init', 'shapeSpace_reply_cpt');

You can add this code wholesale without any modifications, or you can consult the WP Codex and customize everything according to your needs. Note that some of the parameters defined in these two functions are required in order to properly display the bbPress Topics and Replies.

Step 2:

Once the Custom Post Types are defined, we need a template to display their content. The easiest way to do this is to create a new Page and assign a custom template that contains the following code:

<?php 
	/* Template Name: Forum Posts */ 
	/* 
		This is a temporary Page template for looking up old forum posts
		See also functions.php for creation of related custom post types
	*/
?>
<?php get_header(); ?>

<div class="content" id="content">
	<article class="wrap">
		
		<?php if (current_user_can('manage_options')) : ?>
			
			<?php // Topics
			
			$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
			
			$args = array('post_type' => array('topic'), 'posts_per_page' => 1, 'paged' => $paged, 'order' => 'ASC'); // forum, topic, reply
			
			$temp = $wp_query;
			$wp_query = null;
			
			$wp_query = new WP_Query();
			$wp_query->query($args);
	
			if ($wp_query->have_posts()) : while ($wp_query->have_posts()) : $wp_query->the_post(); ?>
			
			<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
			<div class="meta">Post ID: <?php echo $post->ID; ?> • Forum: <?php echo get_the_title($post->post_parent); ?> • Posted by <?php the_author_posts_link(); ?> on 
			<time datetime="<?php echo the_time('Y-m-j'); ?>" pubdate><?php the_time('l, F jS, Y'); ?></time></div>
			<div class="the-content"><?php the_content(); ?></div>
				
				
				<?php // Replies
				
				$topic = $wp_query->post->ID;
				
				$replies_args = array('post_type' => array('reply'), 'posts_per_page' => -1, 'order' => 'ASC', 'post_parent' => $topic); 
				
				$replies = new WP_Query();
				$replies->query($replies_args);
				if ($replies->have_posts()) : while ($replies->have_posts()) : $replies->the_post(); ?>
					
					<h4><?php the_title(); ?></h4>
					<div class="meta">Post ID: <?php echo $post->ID; ?> • Reply to: <?php echo get_the_title($post->post_parent); ?> • Posted by <?php the_author_posts_link(); ?> on 
					<time datetime="<?php echo the_time('Y-m-j'); ?>" pubdate><?php the_time('l, F jS, Y'); ?></time></div>
					<div class="the-content"><?php the_content(); ?></div>
					
				<?php endwhile; ?>
				<?php endif; ?>
				
				
			<?php endwhile; ?>
			<?php wp_reset_postdata(); ?>
			<?php previous_post_link('<div class="prev">%link</div>', '← %title'); ?>
			<?php next_post_link('<div class="next">%link</div>', '%title →'); ?>
			<?php wp_reset_query(); ?>
			<?php endif; ?>
			
		<?php endif; ?>
		
	</article>
</div>

<?php get_footer(); ?>

This is a complete page template that can be added directly to any custom page (e.g., /mytheme/page-custom.php). Here is a rundown of what it does:

  1. Gets the theme header template
  2. Checks that the current user can manage_options, so only admin-level users can view the forum posts. If desired, you can remove this line and just set the Page visibility to Private or Password Protected. Or if you want to give all users access, you can remove this line (and the last closing endif; statement).
  3. Begins the Loop for forum topics: we set the $paged variable so that paged navigation will work. This will enable the navigation links to work, so you can browse through each forum topic.
  4. Begins the custom loop for the topics. This loop first displays the topic title, date, forum, and other metadata. After displaying the topic content, a second, nested loop is started for the topic replies.
  5. The second loop for replies is similar to the first, parent loop. We grab the topic ID from the parent loop, and then use it to run the replies loop. Inside of the replies loop, we display the reply title, ID, content, and other related information.
  6. After closing each of the two loops, we use wp_reset_postdata() to restore the global $post variable of the main query loop.
  7. Then navigation links are added via previous_post_link() and next_post_link(), enabling navigation through each forum topic.
  8. Lastly and just to be safe, we use wp_reset_query() to restore the $wp_query and global post data to the original main query.

Wrapping thoughts..

Again, this is not meant as any type of permanent solution, but rather just provides an interface for you to access your forum content. It’s meant to give you an idea going forward, to build from and customize as needed to display your topics and replies as needed. You can see my implementation of this basic technique at .htaccess made easy.

About the Author
Jeff Starr = Fullstack Developer. Book Author. Teacher. Human Being.
The Tao of WordPress: Master the art of WordPress.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
BBQ Pro: The fastest firewall to protect your WordPress.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.