I cannot add user to the discouse forum from a wordpress website when user added in a membership

Hello there i have a problem with discourse forum which is https://community.over40connect.com/ that is connected with my website https://over40connect.com/staging/ using wp discourse plugin and i have created a function to add user to the discourse group when user role change but it is not adding that user into the discourse group here is the code

function add_user_to_discourse_group_on_role_change($user_id, $role) {
    // Check if the role change is relevant for your case
    // For example, you might want to run this only if the new role is 's2member_level1'
    //if ($role === 's2member_level1') {
    // Set the Discourse API endpoint
    $discourse_endpoint = 'https://community.over40connect.com/groups/2/members.json';

    // Set up the data to be sent
    $data = array(
        'usernames' => array('haseebdeveloper'), // The username of the WordPress user to add
    );

    // Make the API request
    $response = wp_remote_post($discourse_endpoint, array(
        'method'      => 'POST',
        'timeout'     => 45,
        'redirection' => 5,
        'httpversion' => '1.0',
        'blocking'    => true,
        'headers'     => array(
            'Content-Type' => 'application/json',
            'Api-Key'      => 'REDACTED', // Add your Discourse API key here
        ),
        'body'        => json_encode($data),
        'cookies'     => array(),
    ));

    // Check for errors and handle the response
    if (!is_wp_error($response)) {
        $response_code = wp_remote_retrieve_response_code($response);

        if ($response_code === 200) {
            $response_body = wp_remote_retrieve_body($response);
            error_log('Discourse API Response: ' . $response_body); // Log the response
            // Handle the response as needed
        } else {
            error_log('Discourse API Error: Unexpected response code - ' . $response_code); // Log the error
            // Handle the error
        }
    } else {
        $error_message = $response->get_error_message();
        error_log('Discourse API Error: ' . $error_message); // Log the error
        // Handle the error
    }
    //}
}
1 Like

Iā€™ve redacted what looked to be an actual API key from your code snippet @Haseeb_Ahmed. You may wish to revoke that one and generate a fresh one. :+1:

4 Likes

From visiting your site, I think your WordPress site is functioning as the DiscourseConnect authentication provider for your Discourse site. If that is correct, you can use the add_user_to_discourse_group helper function to add WordPress users to Discourse groups: wp-discourse/lib/utilities.php at main Ā· discourse/wp-discourse Ā· GitHub. Details about using the function are here:

Note the use statement at the top of the code example:

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;

And how that is then used to call the (static) function:

$result = DiscourseUtilities::add_user_to_discourse_group( $user_id, $group_name );
3 Likes

Hi @simon now i have used only this code

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;

// Hook to execute when a user role changes
add_action('set_user_role', 'add_user_to_discourse_group_on_role_change', 10, 2);

function add_user_to_discourse_group_on_role_change($user_id, $role) {

  
   $group_names = array("volunteers", "moderators");
   $result = DiscourseUtilities::add_user_to_discourse_group( $user_id, $group_names );

    
}

but it still not adding user to the discourse group when i change user role

I think thatā€™s supposed to be a comma-separated string, not an array:

2 Likes

@Firepup650 is correct. The group_names parameter needs to be set to a string. If you are adding users to multiple groups, separate the group names with a comma (with no space after the comma.)

$group_names = "volunteers,moderators";

If itā€™s not working, or even if it is, try logging the value of $result to see whatā€™s being returned.

3 Likes

Hi @Firepup650 thank you for your help now here is my code

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;

// Hook to execute when a user role changes
add_action('set_user_role', 'add_user_to_discourse_group_on_role_change', 10, 2);

function add_user_to_discourse_group_on_role_change($user_id, $role) {

  
   $group_names = array("volunteers", "moderators");
	$group_names_string = implode(",", $group_names);

   $result = DiscourseUtilities::add_user_to_discourse_group( $user_id, $group_names_string );

    
}

it is adding user into volunteers group but not in the moderators can you please tell me what is the issue

1 Like

You canā€™t add users to the ā€œmoderatorsā€, ā€œadminā€, or ā€œstaffā€ groups with this function call. Technically, you canā€™t add users to any ā€œautomaticā€ groups with this approach. You can only add users to custom groups that you have created.

Edit: if you need to add users to the moderators group, have a look at the sync_sso_record function: wp-discourse/lib/utilities.php at main Ā· discourse/wp-discourse Ā· GitHub. The add_user_to_discourse_group function is just a convenience wrapper around sync_sso_record.

moderator (boolean) is an accepted argument for the SSO params: discourse/lib/discourse_connect_base.rb at 5098338a9649ee8830c8a0781e0eb538e8206eac Ā· discourse/discourse Ā· GitHub. You could also add any custom groups that you want to add users to by using the add_groups param. That would allow you to add a user to the ā€œmoderatorsā€ group and the ā€œVolunteer Membersā€ group with a single API call.

Edit 2: If you try the sync_sso_record function approach, you might need to use the string "true" instead of the boolean true for the moderator param. PHP interprets true as 1. I think Discourse accepts the string "true" to deal with that case. Note that you can use the get_sso_params function to set the SSO params: wp-discourse/lib/utilities.php at main Ā· discourse/wp-discourse Ā· GitHub. Thereā€™s an example of how to do that in the add_user_to_discourse_group functionā€™s code.

3 Likes

Hi @simon can you please give me an example with code that how you are saying to add user into moderator group

Hereā€™s the basic idea. Iā€™m assuming youā€™ll need to add some condition to the function so that all users donā€™t get added to the moderators group when their role changes.

function add_user_to_discourse_group_on_role_change( $user_id, $role ) {
	$sso_params = array(
		'external_id' => $user_id,
		'moderator'   => 'true', // the booleans 'true' and 'false' need to be set as strings!
		'add_groups'  => 'volunteers' // comma separated list, with no spaces after commas
	);
    DiscourseUtilities::sync_sso_record( $sso_params );
}
1 Like

Hi @simon listen i am facing a problem here is my code which i am using when user role change

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;

// Hook to execute when a user role changes
add_action('set_user_role', 'add_user_to_discourse_group_on_role_change', 10, 2);

function add_user_to_discourse_group_on_role_change($user_id, $role) {
// 	var_dump($role);
// 	die();
	  if ($role == 's2member_level1') {
            $s2member_level_1_groups = get_option('s2member_level_1_groups', '');
// 		  	$group_names = array("haseeb-group", "moderators");
// 			$s2member_level_1_groups = implode(",", $group_names);
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_1_groups);
// 		  var_dump($result);
// 		  die();
		  	
// 			var_dump($result);
        }
		else if($role == 's2member_level2'){
			   $s2member_level_2_groups = get_option('s2member_level_2_groups', '');
			  $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_2_groups);
		}
		
		else if($role == 's2member_level3'){
			   $s2member_level_3_groups = get_option('s2member_level_3_groups', '');
			  $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_3_groups);
		}
	
		
		else if($role == 's2member_level4'){
			   $s2member_level_4_groups = get_option('s2member_level_4_groups', '');
			  $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_4_groups);
		}
		
		else {
    // Collect all level groups
    $s2member_level_1_groups = get_option('s2member_level_1_groups', '');
    $s2member_level_2_groups = get_option('s2member_level_2_groups', '');
    $s2member_level_3_groups = get_option('s2member_level_3_groups', '');
    $s2member_level_4_groups = get_option('s2member_level_4_groups', '');

    // Combine all groups into one array
    $s2member_level_groups = array_merge(
        explode(',', $s2member_level_1_groups),
        explode(',', $s2member_level_2_groups),
        explode(',', $s2member_level_3_groups),
        explode(',', $s2member_level_4_groups)
    );

    // Remove duplicates
    $s2member_level_groups = array_unique($s2member_level_groups);

    // Remove user from all collected groups
    foreach ($s2member_level_groups as $group) {
        $result = DiscourseUtilities::remove_user_from_discourse_group($user_id, $group);
        // You may handle $result as needed
    }
}


    
}

now the purpose of the code is to add or remove user based on condition but in any case or in any condition it gives notification to the admins of forum that there is need to approve or reject or delete user why it is coming in any case like in the else case i want to just remove user from a specific group but in that case it is again give a notification of review new user to the admin

one more thing is that when user register on the wordpress website it is automatically adding in these groups trust_level_0 and trust_level_1 why i dont know

please help and i can also share user register hook with you

That would be because those are core discourse groups, used for managing permissions and such.

That would be because you have the setting on to require all new users to be approved by staff, as your screenshot mentions:

image

It seems like youā€™re adding new users, which requires approval, as I mentioned above.

1 Like

To add to what @Firepup650 wrote, when your code calls

DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_2_groups);

it is calling a helper function that makes a request to the Discourse sync_sso route: Sync DiscourseConnect user data with the sync_sso route. That request is used to either update an existing user, or to create a new users. If the user with $user_id has never logged into your Discourse site, a new user will be created. They should still be added to the groups without any problem, but it will generate a notification for moderators because your site has enabled the must approve users site setting:

1 Like

Hi @simon i have again facing an issue

i want to sync user data when user register on the website and added on the discourse as well but it is not syncing custom fields information in his profile on discourse here is my code you can check

add_action( 'user_register', 'user_registered_callback', 10, 1 ); // Adjusted to accept only one argument

function user_registered_callback($user_id) {
    // Get user data based on user ID
    $user_data = get_userdata($user_id);

    // Check if user data exists
    if ($user_data) {
        // Get the user roles
        $roles = $user_data->roles;

        // Check if user has s2Member role
        if (in_array('s2member_level1', $roles)) {
            $s2member_level_1_groups = get_option('s2member_level_1_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_1_groups);

            // Get custom fields
            $custom_fields = get_user_option('1709753088_wp_s2member_custom_fields', $user_id);
            // Prepare SSO params array
            $sso_params_array = [];
            $sso_params_array = [
				'external_id' => $user_id,
                'custom.user_interests' => $custom_fields['user_interests'],
                'custom.user_age' => $custom_fields['user_age'],
                'custom.user_gender' => $custom_fields['user_gender'],
                'custom.user_sexual' => $custom_fields['user_sexual'],
                'custom.user_facebook' => $custom_fields['user_facebook'],
                'custom.user_linkedin' => $custom_fields['user_linkedin'],
                'custom.users_reasons' => $custom_fields['users_reasons']
            ];

            $fields_updated = DiscourseUtilities::sync_sso_record($sso_params_array, $user_id);
			var_dump($fields_updated);
			die();
        } elseif (in_array('s2member_level2', $roles)) {
            $s2member_level_2_groups = get_option('s2member_level_2_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_2_groups);
        } elseif (in_array('s2member_level3', $roles)) {
            $s2member_level_3_groups = get_option('s2member_level_3_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_3_groups);
        } elseif (in_array('s2member_level4', $roles)) {
            $s2member_level_4_groups = get_option('s2member_level_4_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_4_groups);
        } else {
            // Collect all level groups
            $s2member_level_1_groups = get_option('s2member_level_1_groups', '');
            $s2member_level_2_groups = get_option('s2member_level_2_groups', '');
            $s2member_level_3_groups = get_option('s2member_level_3_groups', '');
            $s2member_level_4_groups = get_option('s2member_level_4_groups', '');

            // Combine all groups into one array
            $s2member_level_groups = array_merge(
                explode(',', $s2member_level_1_groups),
                explode(',', $s2member_level_2_groups),
                explode(',', $s2member_level_3_groups),
                explode(',', $s2member_level_4_groups)
            );

            // Remove duplicates
            $s2member_level_groups = array_unique($s2member_level_groups);

            // Remove user from all collected groups
            foreach ($s2member_level_groups as $group) {
                $result = DiscourseUtilities::remove_user_from_discourse_group($user_id, $group);
                // You may handle $result as needed
            }
        }
    } else {
        // Handle cases where user data is not available
        // Log a message or handle differently based on your requirements
        error_log("User data not available in user_registered_callback.");
    }
}

now can check this code

  $sso_params_array = [
				'external_id' => $user_id,
                'custom.user_interests' => $custom_fields['user_interests'],
                'custom.user_age' => $custom_fields['user_age'],
                'custom.user_gender' => $custom_fields['user_gender'],
                'custom.user_sexual' => $custom_fields['user_sexual'],
                'custom.user_facebook' => $custom_fields['user_facebook'],
                'custom.user_linkedin' => $custom_fields['user_linkedin'],
                'custom.users_reasons' => $custom_fields['users_reasons']
            ];

when i var_dump($fields_updated); it is giving true but its not adding data into user profile on discourse what is the issue?

Unless something has changed, you need to use the approach that is outlined here: Map custom User Fields - #7 by simon.

First, make sure the custom fields already exist on Discourse. Then, on your Discourse siteā€™s /admin/customize/user_fields page, add .json to the URL so that you can see the userfieldā€™s JSON. For example http://localhost:4200/admin/customize/user_fields.json.

Use the id values from the JSON to set SSO keys that that look like this: custom.user_field_<field_id>. For example custom.user_field_1

I canā€™t test this right now. Let me know if this works. If it hasnā€™t already been done, it should get documented in its own topic.

Hi @simon i have used your approach that you have mentioned and here is my code now

add_action( 'user_register', 'user_registered_callback', 10, 1 ); // Adjusted to accept only one argument

function user_registered_callback($user_id) {
    // Get user data based on user ID
    $user_data = get_userdata($user_id);
// 	$user = get_user_by( 'ID', $user_id );
    // Check if user data exists
    if ($user_data) {
        // Get the user roles
        $roles = $user_data->roles;

        // Check if user has s2Member role
        if (in_array('s2member_level1', $roles)) {
            $s2member_level_1_groups = get_option('s2member_level_1_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_1_groups);
			 $sso_params = array();
//             // Get custom fields
//             $custom_fields = get_user_option('1709753088_wp_s2member_custom_fields', $user_id);
//             // Prepare SSO params array
//             $sso_params_array = [];
//             $sso_params_array = [
// 				'external_id' => $user_id,
//                 'custom.user_field_1' => $custom_fields['user_interests'],
//                 'custom.user_field_2' => $custom_fields['user_age'],
//                 'custom.user_field_3' => $custom_fields['user_gender'],
//                 'custom.user_field_4' => $custom_fields['user_sexual'],
//                 'custom.user_field_5' => $custom_fields['users_reasons']
//             ];

//             $fields_updated = DiscourseUtilities::sync_sso_record($sso_params_array);
			 $sso_params = apply_filters( 'wpdc_sso_params', $sso_params, $user_data );
			var_dump($sso_params);
			die();
        } elseif (in_array('s2member_level2', $roles)) {
            $s2member_level_2_groups = get_option('s2member_level_2_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_2_groups);
        } elseif (in_array('s2member_level3', $roles)) {
            $s2member_level_3_groups = get_option('s2member_level_3_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_3_groups);
        } elseif (in_array('s2member_level4', $roles)) {
            $s2member_level_4_groups = get_option('s2member_level_4_groups', '');
            $result = DiscourseUtilities::add_user_to_discourse_group($user_id, $s2member_level_4_groups);
        } else {
            // Collect all level groups
            $s2member_level_1_groups = get_option('s2member_level_1_groups', '');
            $s2member_level_2_groups = get_option('s2member_level_2_groups', '');
            $s2member_level_3_groups = get_option('s2member_level_3_groups', '');
            $s2member_level_4_groups = get_option('s2member_level_4_groups', '');

            // Combine all groups into one array
            $s2member_level_groups = array_merge(
                explode(',', $s2member_level_1_groups),
                explode(',', $s2member_level_2_groups),
                explode(',', $s2member_level_3_groups),
                explode(',', $s2member_level_4_groups)
            );

            // Remove duplicates
            $s2member_level_groups = array_unique($s2member_level_groups);

            // Remove user from all collected groups
            foreach ($s2member_level_groups as $group) {
                $result = DiscourseUtilities::remove_user_from_discourse_group($user_id, $group);
                // You may handle $result as needed
            }
        }
    } else {
        // Handle cases where user data is not available
        // Log a message or handle differently based on your requirements
        error_log("User data not available in user_registered_callback.");
    }
}




add_filter( 'wpdc_sso_params', 'my_namespace_set_discourse_custom_field', 10, 2 );

function my_namespace_set_discourse_custom_field( $sso_params, $user ) {
    $custom_fields = get_user_option('1709753088_wp_s2member_custom_fields', $user->ID);
	
    // Check if $custom_fields is an array and not empty
    if (is_array($custom_fields) && !empty($custom_fields)) {
        // Assign custom fields to respective keys in the SSO params
        $sso_params['custom.user_field_1'] = $custom_fields['user_interests'];
        $sso_params['custom.user_field_2'] = $custom_fields['user_age'];
        $sso_params['custom.user_field_3'] = $custom_fields['user_gender'];
        $sso_params['custom.user_field_4'] = $custom_fields['user_sexual'];
        $sso_params['custom.user_field_5'] = $custom_fields['users_reasons'];
    } else {
        // Log or display an error message if $custom_fields is not as expected
        error_log('Custom fields data is not in the expected format.');
    }

    // Return modified SSO parameters
    return $sso_params;
}

now only the problem is that it is not adding users_reasons into the custom.user_field_5 and adding other data to the user profile for example if i comment out this line $sso_params[ā€˜custom.user_field_5ā€™] = $custom_fields[ā€˜users_reasonsā€™]; then it is adding others fields data into discourse user and if i not comment this line then no data is adding into the user profile on discourse now i need to say that users_reasons fields on both discourse site and on wordpress site is a multiselect field so it this could the be reason? please tell me

Yes, the problem is that it is a multiselect field. Iā€™m not sure if that is supported yet: Add support for multi-select fields in DiscourseConnect protocol.

Maybe thereā€™s a way to get it to work now, but Iā€™m not seeing how to do it. The Discourse code that gets called is here: discourse/app/models/discourse_connect.rb at main Ā· discourse/discourse Ā· GitHub

Hi @simon can you please write a code example according to my code with your reference you have provided

I donā€™t think itā€™s possible. As far as I can tell, the code for setting custom fields from the SSO payload has been slightly changed since the time that the post I linked to was written, but it hasnā€™t been changed in a way that allows multi-select fields to be updated from the SSO payload.

Ideally, Discourse would handle the case in a similar way to how it handles the add_groups SSO field: discourse/app/models/discourse_connect.rb at main Ā· discourse/discourse Ā· GitHub. For that to work the Discourse SSO code would need to know if a particular custom field was a multi-select field. I donā€™t think the code has that information now.

Again, there might be a way to do it now, but itā€™s beyond me.

Hi @simon i want to sync user avatar between wordpress and discourse as i already using wp discourse plugin for sso now i want when i user change avatar on the discourse website then it should also needs to change on the wordpress website how it can be possible and i want using one user avatar plugin on the wordpress website and here is the code i am using

function my_wpdc_sso_client_updated_user( $updated_user, $query ) {
		$avatar_url = $query['avatar_url'];
		$user_id = $updated_user->ID;
		// it allows us to use download_url() and wp_handle_sideload() functions
	require_once( ABSPATH . 'wp-admin/includes/file.php' );

	// download to temp dir
	$temp_file = download_url( $avatar_url );

	if( is_wp_error( $temp_file ) ) {
		return false;
	}

	// move the temp file into the uploads directory
	$file = array(
		'name'     => basename( $image_url ),
		'type'     => mime_content_type( $temp_file ),
		'tmp_name' => $temp_file,
		'size'     => filesize( $temp_file ),
	);
	$sideload = wp_handle_sideload(
		$file,
		array(
			'test_form'   => false // no needs to check 'action' parameter
		)
	);

	if( ! empty( $sideload[ 'error' ] ) ) {
		// you may return error message if you want
		return false;
	}

	// it is time to add our uploaded image into WordPress media library
	$attachment_id = wp_insert_attachment(
		array(
			'guid'           => $sideload[ 'url' ],
			'post_mime_type' => $sideload[ 'type' ],
			'post_title'     => basename( $sideload[ 'file' ] ),
			'post_content'   => '',
			'post_status'    => 'inherit',
		),
		$sideload[ 'file' ]
	);

	if( is_wp_error( $attachment_id ) || ! $attachment_id ) {
		return false;
	}

	// update medatata, regenerate image sizes
	require_once( ABSPATH . 'wp-admin/includes/image.php' );

	wp_update_attachment_metadata(
		$attachment_id,
		wp_generate_attachment_metadata( $attachment_id, $sideload[ 'file' ] )
	);

	// Return the attachment ID
	update_user_meta($user_id, '1709753088_wp_user_avatar', $attachment_id);
	update_user_meta($user_id, 'wp_user_avatar', $attachment_id);
}

as you can see i want to update meta keys of user using attachment id but attachment id is not going to created

looking to here from you

Thank You