Add Groups and Categories (with security) with WP-Discourse or the API?

We run a membership through our Wordpress/Woocommerce system. We’ve been using Discourse on a subdomain with the SSO for a couple years and it’s been working great. I have code in my functions file that adds/removes Group access when the person joins/cancels respectively.

We’ve added a feature in our membership where people can join a small group of 6-8 people for weekly Zoom calls.

To manage this, we have created a Wordpress Post Type called “Cohorts” that has the weekly call information in it and then assigned those Cohorts to a User using custom user fields.

Here’s what I would like to do:

  1. Create a Group for each of the Cohorts
  2. Create a Subcategory for each of the Cohorts that only the Group from #1 has access to.
  3. Put each of the Members in their respective Group which will give them access to their, and on their, subcategory for their Cohort.

I know how to do #3, but is there a way to programmatically add Groups and Subcategories (with the security settings)?

I can’t find this functionality in the WP-Discourse utilities. Also, looking at the API, I can see where to add categories, but not the security functions.

Is what I want to do possible?

Yes, it’s possible. You can make any API request to Discourse from Wordpress using the discourse_request utility method, i.e.

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;
$args =  array(
   "body" => "",
   "type" => "post"
);
$response = DiscourseUtilities::discourse_request( $path, $args );

This will format the request correctly and use the API key and user you’ve provided in the WP Discourse settings. You’ll need a global key for the actions you’re referring to (if you’re also using the same key for normal wp discourse functionality).

Creating a group

The endpoint you want is this: Discourse API Docs. There isn’t a full list of the params in the api docs, but you’ll find them here: discourse/groups_controller.rb at main · discourse/discourse · GitHub

Creating a catetgory

The endpoint you want is this: Discourse API Docs. Likewise the full param list is here: discourse/categories_controller.rb at main · discourse/discourse · GitHub

Note that the “securtiy settings” are handled via the permissions param. You just need to give it an object with group names as the keys and permission level integers as the values, e.g.

{
  "cohort1": 2,
  "staff": 1
}

You’ll find the permission level integer list here: discourse/category_group.rb at main · discourse/discourse · GitHub

2 Likes

@Angus, thank you so much! This was exactly what I needed!

I was able to create my groups, assign users to groups and create the categories with the proper security.

I really appreciate your help.

One other questions though… when I tried to run a PUT to update a Category or Group, I get this error:

Fatal error : Uncaught Error: Call to undefined function wp_remote_put() in […]/public/wp-content/plugins/wp-discourse/lib/plugin-utilities.php:393

Here’s my test code trying to update category ID 61 with a new name:

$path = "/categories/61.json";
$args =  array( 
			"type" => "put",
			"body" => array (
				"name" => "Cohorts 1",
			)
   		);
$response = DiscourseUtilities::discourse_request( $path, $args )

What am I doing wrong?

Any ideas here? Thanks so much!

Sorry Tim, I’ve been away the past few days. It looks like the discourse_request method needs tweaking to support this. I’ll make a PR for that next week and it’ll probably take another week for that to be merged.

If you want it sooner than that you can use the underlying WP methods like so:

$api_credentials = DiscourseUtilities::get_api_credentials();
if ( is_wp_error( $api_credentials ) ) {
    return $api_credentials;
}

$headers = array(
    'Api-Key'      => sanitize_key( $api_credentials['api_key'] ),
    'Api-Username' => sanitize_text_field( $api_credentials['api_username'] ),
    'Accept'       => 'application/json',
);
$body = array( /* specific to the endpoint you're using */ );
$url = /* The absolute url for the endpoint you're using */;

$opts = array(
   'headers' => $headers,
   'body' => json_encode( $body ),
   'method'  => 'PUT'
);

$result =  wp_remote_request( $url, $opts );