WP Discourse plugin tips and tricks

This topic has a number of tips and tricks for users of the WP Discourse WordPress plugin.

Adjust the comments_number sync period for WordPress archive pages

To get the correct number of Discourse comments for a post, the plugin needs to periodically make an HTTP request to Discourse to get the current comments number. On single pages this period is set to be no more often than every 10 minutes. For archive pages the period is set to no more than once every 24 hours. The reason for this is to avoid making multiple request to Discourse every time an archive page is accessed.

If you still find that the plugin is making too many request to Discourse when displaying your site’s archive pages, you can adjust the archive_page_sync_period by hooking into the 'discourse_archive_page_sync_period' filter. You do that by adding something like this to your theme’s functions.php file:

add_filter( 'discourse_archive_page_sync_period', 'my_namespace_archive_page_sync_period' );
function my_namespace_archive_page_sync_period( $sync_period ) {
    // This will change to sync_period for archived posts to once a week.
    return WEEK_IN_SECONDS;
}

If you find that the plugin is not making enough requests to Discourse to retrieve the current comment numbers for archive pages, you can add something like this to your theme’s functions.php file. This will set the archive_page_sync_period to 10 minutes.
Note: on a busy site this could place a heavy load on your server.

add_filter( 'discourse_archive_page_sync_period', 'my_namespace_archive_page_sync_period' );
function my_namespace_archive_page_sync_period( $sync_period ) {
    // This will change to sync_period for archived posts to once a week.
    return 10 * MINUTE_IN_SECONDS;
}

Deal with comment number issues when displaying both Discourse and WordPress comments for a post.

The wp-discourse plugin uses the WordPress get_comments_number filter hook so that the number of Discourse comments that have been created for a post can be displayed throughout your theme. This creates a conflict when both Discourse and WordPress comments are being displayed for a post. The plugin is able to resolve that conflict in most places. One place where it can’t be resolved is in the comment title that WordPress themes often display at the head of the comment section. This is the section that begins with something like “2 thoughts on…”

The easiest way to do this is to add a rule to your theme’s css file.

.discourse-comments-area ~ .comments-area .comments-title  {
	display: none;
}

Enable posting by XMLRPC

XML-RPC is a remote procedure call that is often used by blogging software for sending posts to WordPress. Apps that use this procedure include the wordpress.com blogging app.

By default, WP Discourse will not publish posts to Discourse that are created through XML-RPC. The reason for this is that there is no great way to indicate whether a post published through blogging software is meant to be published on Discourse.

If you would like to use blogging software for creating posts that are directly published to Discourse, you need to add some code to your theme’s functions.php file that hooks into the wp_discourse_before_xmlrpc_publish filter. The wp_discourse_before_xmlrpc_publish filter passes two arguments to functions that hook into it. The first argument, $publish_to_discourse is a boolean that is set to false to disable publishing by XML-RPC. The second argument is the post object.

To have all XML-RPC posts automatically published by Discourse you need to write a function that will always return true. Use something like the following code:

Warning: this will cause all posts published through XML-RPC to be published to Discourse, this will include old posts that are edited on blogging software.

add_filter('wp_discourse_before_xmlrpc_publish', 'my_namespace_xmlrpc_publish', 10, 2 );
function my_namespace_xmlrpc_publish( $publish_to_discourse, $post ) {

    return true;
}

Filter XML-RPC posts by post tag

The wordpress.com blogging app allows you to add tags to posts. Tags can be used to control whether or not a post is published to Discourse. To only publish posts that have a ‘discourse’ tag, use something like this:

add_filter('wp_discourse_before_xmlrpc_publish', 'my_namespace_xmlrpc_publish_by_tag', 10, 2 );
function my_namespace_xmlrpc_publish_by_tag( $publish_to_discourse, $post ) {
    if ( has_tag( 'discourse', $post ) ) {

        return true;
    }

    return false;
}

If you would like to use this method, but not have the discourse tag appear in your published posts, you can remove it with some code like this:

add_filter( 'term_links-post_tag', 'my_prefix_remove_discourse_tag' );
function my_prefix_remove_discourse_tag( $tags ) {
    foreach( $tags as $key => $value ) {
        if ( strpos( $value, 'discourse' ) ) {
            unset( $tags[ $key ] );
        }
    }

    return $tags;
}

Filter XML-RPC posts by post date

To only allow posts published after a certain date to be published to Discourse through XML-RPC, add some code like this to your functions.php file. This code will allow all posts published after January 1, 2016 to be published to Discourse.

add_filter('wp_discourse_before_xmlrpc_publish', 'my_namespace_xmlrpc_publish_by_date', 10, 2 );
function my_namespace_xmlrpc_publish_by_date( $publish_to_discourse, $post ) {
	if ( strtotime( $post->post_date ) > strtotime( '2016-01-01') ) {

	    return true;
    }

	return false;
}

Todo: add a filter to the wp-discourse plugin to allow for only publishing new posts (as opposed to edited posts) through XML-RPC.

Deal with WordPress shortcodes

The WP Discourse plugin does not process shortcodes before the content is published to Discourse. If your WordPress posts must include shortcodes in the content that is published to Discourse, those shortcode will be published as [shortcode_name] . Here are three different approaches for dealing with shortcodes that may be in your posts. The first two functions remove the shortcodes, the last function ‘does’ the shortcodes. Note: ‘doing’ the shortcodes will generally result in the output being processed by Discourse as code. This is because of whitespace that gets added to the output.

// Removes anything that looks like a shortcode. This will remove anything in the post that
// occurs inside of brackets `[...]`.
add_filter( 'wp_discourse_excerpt', 'testeleven_remove_shortcodes' );
function testeleven_remove_shortcodes( $excerpt ) {
    $excerpt = preg_replace( '/\[.*\]/', '', $excerpt );

    return $excerpt;
}

// Strips any shortcodes from the post content. If  theme is wrapping content between
// opening and closing shortcodes, that content will be removed as well.
add_filter( 'wp_discourse_excerpt', 'testeleven_strip_shortcodes' );
function testeleven_strip_shortcodes( $excerpt ) {
    $excerpt = strip_shortcodes( $excerpt );

    return $excerpt;
}

// Searches the content for shortcodes and filter shortcodes through their hooks.
add_filter( 'wp_discourse_excerpt', 'testeleven_do_shortcodes' );
function testeleven_do_shortcodes( $excerpt ) {
    $excerpt = do_shortcode( $excerpt );

    return $excerpt;
}

Filter the available categories for a custom post type

Before the Discourse categories are displayed in the ‘Publish to Discourse’ meta-box on the Wordpress admin/post-new page, the filter 'wp_discourse_publish_categories' is applied to them. It is given the Discourse categories array, and the current post as arguments. This can be used in your theme’s functions.php file to limit which categories are available for a given post type.

Here is an example that creates an 'acme_product' post type and then returns the Discourse categories ‘fun’ and ‘scratch’ to be displayed in the Publish to Discourse meta-box for posts of that type.

// Create the post type.
add_action(  'init', 'my_namespace_create_post_type' );
function my_namespace_create_post_type() {
	register_post_type( 'acme_product',
		array(
			'labels' => array(
				'name' => __( 'Products' ),
				'singular_name' => __( 'Product' )
			),
			'public' => true,
			'supports' => array( 'title', 'editor', 'comments', 'custom-fields' ),
			'has_archive' => true,
            'show_in_rest' => true,
		)
	);
}

// Filter the available categories for the 'acme_product' post type.
add_filter( 'wp_discourse_publish_categories', 'my_namespace_filter_categories', 10, 2 );
function my_namespace_filter_categories( $categories, $post ) {
	if ( 'acme_product' === get_post_type( $post ) ) {
		$output = [];
		foreach ( $categories as $category ) {
			if ( 'fun' === $category['name'] || 'scratch' === $category['name'] ) {
				$output[] = $category;
			}
		}
		return $output;
	}

	return $categories;
}

Remove the require_activation flag

If you’re sure that WordPress is authenticating email addresses, you can tell Discourse that it doesn’t need to. To completely remove the require_activation flag, add something like this to your theme’s functions.php file:

// Replace 'my_prefix' with your site prefix.

add_filter( 'discourse_email_verification', 'my_prefix_discourse_email_verification' );
function my_prefix_discourse_email_verification( $require_activation ) {
    return false;
}

To remove the require_activation flag for specific users, use something like this:

// Replace 'my_prefix' with your site prefix.

add_filter( 'discourse_email_verification', 'my_prefix_discourse_email_verification', 10, 2 );
function my_prefix_discourse_email_verification( $require_activation, $user_id ) {
    $user = get_userdata( $user_id );
    if ( /* some condition tested against $user */ ) {

        return true;
    }

    return false;
}

Display comments without loading the WordPress comments template

The WP Discourse plugin uses the WordPress comments template to load Discourse comments. If your theme is not loading the comments template, you can display comments with the static get_discourse_comments helper function. That function requires you to supply the id of the WordPress post that you want to display comments for. Here’s a simple example of its use:

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;
$discourse_comments = DiscourseUtilities::get_discourse_comments(859);
echo $discourse_comments;

Comments will be displayed in the same way as they are displayed if you select the
Enable Discourse Comments/Display Comments option (found on the plugin’s Comment Settings tab.) When this function is used, the value of that setting is ignored, but all other Comment settings are respected.

Create an SSO Login Link

If you have the SSO Provider option enabled, you can add an SSO login link to your WordPress site by creating a link with the following structure:

<a href="https://discourse.example.com/session/sso?return_path=/">Community</a>

Set the value of return_path to the page on your forum you would like the user to end up on. You can add an SSO login link to a WordPress menu by adding a URL with this structure as a Custom Link in the Menus section of the WordPress dashboard.

Display metadata of a connected Discourse topic

When you have “Publishing” set up so that your Wordpress posts are being posted as Discourse topics, you can display metadata about the Discourse topic by using Template Customisation.

First, you need to decide which template you wish to modify. If, for example, you only wish to show topic metadata, and no replies as comments, then you’ll want to modify the no_replies template.

Once you’ve chosen a template, you can modify it to add Discourse topic metadata. Here’s a snippet that does that, with some comments explaining what the code is doing

// ensure wp-discourse is present using your preferred method,
// e.g. https://wordpress.stackexchange.com/questions/127818/how-to-make-a-plugin-require-another-plugin

// Require the plugin-utilities from the wp-discourse plugin
require_once ABSPATH . 'wp-content/plugins/wp-discourse/lib/plugin-utilities.php';
use WPDiscourse\Shared\PluginUtilities;

// Encapsulate your topic metadata template in a class so you can easily include the plugin utilities
class DiscourseTopicMetadata {
  
  // Include the wp plugin utilities in your class
  use PluginUtilities;
  
  public function __construct() {

    // Add the template filter on the initialization of the class
    add_filter( 'discourse_no_replies_html', array( $this, 'topic_metadata_html' ) );
  }

  function topic_metadata_html( $input ) {
    // Get the discourse permalink from the post metadata
    $discourse_permalink = get_post_meta( get_the_ID(), 'discourse_permalink', true );

    // Use the discourse permanlink to get the topic JSON from Discourse, using the helper method from the plugin utilities which handles authorization for you
    $topic = $this->get_discourse_topic($discourse_permalink);
   
    // Output your markup, including which topic metadata you wish to display
    ob_start();
    ?>
    <div id="discourse-topic-meta">
        <div class="views">
          Views
          <?php echo $topic->views; ?>
        </div>
        <div class="replies">
          Replies
          <?php echo $topic->reply_count; ?>
        </div>
    </div>
    <?php
    
    return ob_get_clean();
  }
}

// Instantiate the class to add the filter
new DiscourseTopicMetadata();

For more details on what topic metadata is available in the response from get_discourse_topic see Discourse API Docs.

14 Likes

2 posts were split to a new topic: What does selecting Update Discourse Topic do?