Manage group membership in Discourse with WP Discourse SSO

No, you do not need to enable any of the sso overrides settings.

The add_user_to_discourse_group and remove_user_from_discourse_group functions do not use webhooks. They need to be called from some code that you add to your WordPress site. Tha basic idea is that when your membership plugin adds a member, your code will hook into an action that is provided by the membership plugin and then call:

WPDiscourse\Utilities\Utilities::add_user_to_discourse_group( $wp_user_id, $group_names );

The user’s WordPress user ID should be substituted for $wp_user_id. $group_names should be the name of the Discourse group you want to add the user to. You can add a user to multiple groups by using a comma separated list of group names for $group_names. If you supply multiple group names, make sure there are no spaces between the commas.

The add_user_to_discourse_group and remove_user_from_discourse_group functions are static and namespaced. You need to be sure that you are calling the functions with their namespace.

1 Like

Our user don`t have an primary_group_name, title and some more fields. How we can fix it?

Are these users being added to the group with add_user_to_discourse_group? When added in this way, the users should have the group set as their primary group if you have enabled the ‘Automatically set as primary group’ checkbox on the group’s membership tab on Discourse. If you set the ‘Default title’ field for the group on Discourse, that title should be given to the user when they are added to the group.

1 Like

Yes we do that:

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;

function dcpmp_get_level_for_id( $id ) {
    $levels_to_discourse_groups = array(
        1 => 'forum', 
		2 => 'premium'
    );

    if ( empty( $levels_to_discourse_groups[ $id ] ) ) {

        return new WP_Error( 'pmpdc_group_not_set_error', 'A Discourse group has not been assigned to the level.' );
    }

    return $levels_to_discourse_groups[ $id ];
}

function dcpmp_add_member_to_group( $member_order ) {
    if ( ! empty( $member_order->membership_id ) && ! empty( $member_order->user_id ) ) {
        $user_id = $member_order->user_id;
        $group_name = dcpmp_get_level_for_id( $member_order->membership_id );
        if ( is_wp_error( $group_name ) ) {
            return null;
        }
        $result = DiscourseUtilities::add_user_to_discourse_group( $user_id, $group_name );

        if ( ! empty( $result->success ) ) {
            add_user_meta( $user_id, "dcpmp_group_{$group_name}", 1, true );
        }

        return $result;
    }

    return new WP_Error( 'dcpmp_order_not_set_error', 'There was an error with the PMP order.' );
}

function dcpmp_remove_member_from_group( $level_id, $user_id, $cancel_level ) {
    if ( ! empty( $cancel_level ) ) {
        $group_name = dcpmp_get_level_for_id( $cancel_level );
        if ( is_wp_error( $group_name ) ) {
            return null;
        }

        $result = DiscourseUtilities::remove_user_from_discourse_group( $user_id, $group_name );
        if ( ! empty( $result->success ) ) {
            delete_user_meta( $user_id, "dcpmp_group_{$group_name}" );
        }

        return $result;
    }

    return null;
}

if ( class_exists( '\WPDiscourse\Discourse\Discourse' ) ) {
    add_action( 'pmpro_added_order', 'dcpmp_add_member_to_group' );
    add_action( 'pmpro_after_change_membership_level', 'dcpmp_remove_member_from_group', 10, 3 );
}

we have also enabled the ‘Automatically set as primary group’ checkbox

defatult title is: ★Forum lid★

2 Likes

i can’t figure out what is wrong…

WP:
membership for this user is set to premium
image

we know the connection is working…
but no groups added
image

what am i’m missing ?

If you are developing this on your local computer, you can create a debug.log file in your wp-content folder, and add the following to your wp-config.php file so that you can write to the file:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false );

I add this function in a plugin to write to the debug.log file:

function write_log( ...$log_items ) {
	if ( true === WP_DEBUG ) {
		foreach ( $log_items as $log_item ) {
			if ( is_array( $log_item ) || is_object( $log_item ) ) {
				error_log( print_r( $log_item, true ) );
			} else {
				error_log( $log_item );
			}
		}
	}
}

This will let you add calls to write_log to your code so that you can see what’s going on. For example, in the dcpmp_get_level_for_id function, you can add:

write_log( 'In the dcpmp_get_level_for_id function, called with the id argument set to: ',  $id );

That will let you know if the function is being called, and what argument is being passed to it. Make sure that write_log calls are removed before you add the code to your live site. It is usually possible to work through code in this way, to figure out where it is going wrong.

1 Like

I’ll be honest — I had to abandon use of these methods on my site because I couldn’t get them to work.

Are you calling the group add function from a hook that fires when group membership changes?

we have the sync working. Only NEW memebers are synced or that have changed there membership.

1 Like

Glad the sync is working now! Makes sense that it only applies for new / updated members — the way WordPress works, the code that syncs users to Discourse groups only fires when triggered by certain actions e.g. new member added or membership level changed.

To fill in missing data for existing members added before the syncing was configured, you’d basically want to run a simple script to get all users, loop through and check member level for each, and if applicable call the relevant Discourse group functions.

3 Likes

thanks!
The missing data we will fill by hand because that is not that much.

1 Like

I am working with someone who wants to connect WooCommerce Subscriptions with Discourse, but has Discourse as the SSO master.

It looks like when someone places the order they might not already have a Discourse account, so hooking into the “subscription changed” hooks can’t work.

My current notion is that it might be possible to add a hook to WordPress that gets called at a successful login to WordPress that would then push the group membership over to Discourse. Do you think that could work? Is there some better idea?

Maybe use the API to send a PM to the email address first, creating a staged user account? I’ve found the staged user functionality, probably undocumented and largely unintended, to be super handy - e.g. you can even set a staged user’s notification levels for topics and categories so they can participate by email even before they create their account.

2 Likes

When Discourse is used as the SSO provider, you can check if a WordPress user has a Discourse account by checking if the value returned by this statement is empty:

get_user_meta( $user_id, 'discourse_sso_user_id', true );

You’ll need to do something to handle the case where the user doesn’t yet have a Discourse account. Creating the user via the API and adding them to the appropriate groups is probably the right solution. It will take some work to set that up.

3 Likes

Hey, @simon. It looks like add_user_to_discourse_group works only when WordPress is the SSO Master?

When I call it (configured with Discourse as master) I get

"The add_user_to_discourse_group function can only be used when SSO is enabled."

(It’s taken me hours and hours to figure out how to get useful debugging info out of WordPress. And now this. :crying_cat_face: )

Yes, add_user_to_discourse_group is only for sites that are using WordPress as the SSO Provider. It calls the Discourse sync_sso route.

That’s a fairly good error message you’re getting though. It could be improved to indicate that it only works when WordPress is the SSO Provider.

1 Like

Yeah. The error message is fine (I guess it should mention “sso master”, but I knew right away). It’s just that it wasn’t what I expected, and it’s taken me forever to figure it out. (Not your fault.)

What I’m trying to do now is have a function called at login. I’m trying to get the Discourse username so that I can then do an old-school curl to an API call to add to the group.

		$user_meta= get_user_meta( $user_id, 'discourse_sso_user_id', true );

doesn’t seem to be finding the user. Is that not how it works?

That is the correct way to get the user’s Discourse id if it has been set. $user_id needs to be the WordPress user’s ID. If you’re getting an empty response, the user has not logged in via Discourse yet. Try making the call with a user you know has logged into WordPress from Discourse.

1 Like

Sorry. It turns out that the problem is me not knowing how to get debugging info out of php/wordpress.

I now have the discourse_user_id, so now I can construct a curl to add the user to the desired group. I hope.

Thanks for your help.

For debugging WordPress, see this post: https://meta.discourse.org/t/managing-discourse-group-membership-with-wp-discourse/74724/51.

1 Like