我无法在WordPress网站上将用户添加到Discourse论坛中,尽管用户已加入会员

您好,我在 Discourse 论坛 https://community.over40connect.com/ 上遇到了一个问题,该论坛通过 wp discourse 插件与我的网站 https://over40connect.com/staging/ 连接。我创建了一个函数,在用户角色更改时将用户添加到 Discourse 组,但该用户未被添加到 Discourse 组。这是代码:

function add_user_to_discourse_group_on_role_change($user_id, $role) {
    // 检查角色更改是否与您的情况相关
    // 例如,您可能只想在新角色为 's2member_level1' 时运行此代码
    //if ($role === 's2member_level1') {
    // 设置 Discourse API 端点
    $discourse_endpoint = 'https://community.over40connect.com/groups/2/members.json';

    // 设置要发送的数据
    $data = array(
        'usernames' => array('haseebdeveloper'), // 要添加的 WordPress 用户的用户名
    );

    // 发起 API 请求
    $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', // 在此处添加您的 Discourse API 密钥
        ),
        'body'        => json_encode($data),
        'cookies'     => array(),
    ));

    // 检查错误并处理响应
    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); // 记录响应
            // 根据需要处理响应
        } else {
            error_log('Discourse API Error: Unexpected response code - ' . $response_code); // 记录错误
            // 处理错误
        }
    } else {
        $error_message = $response->get_error_message();
        error_log('Discourse API Error: ' . $error_message); // 记录错误
        // 处理错误
    }
    //}
}
1 个赞

我已经为您隐藏了您代码片段中看起来像是实际 API 密钥的内容,@Haseeb_Ahmed。您可能希望撤销该密钥并生成一个新密钥。:+1:

4 个赞

从访问您的网站来看,我认为您的 WordPress 网站正在作为 DiscourseConnect 身份验证提供程序为您的 Discourse 网站提供服务。如果正确,您可以使用 add_user_to_discourse_group 辅助函数将 WordPress 用户添加到 Discourse 组:https://github.com/discourse/wp-discourse/blob/main/lib/utilities.php#L278-L326。有关使用该函数的详细信息在此处:

请注意代码示例顶部的 use 语句:

use WPDiscourse\\Utilities\\Utilities as DiscourseUtilities;

以及如何使用它来调用(静态)函数:

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

你好 @simon,我现在只使用了这段代码

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 );


}

但当我更改用户角色时,它仍然没有将用户添加到 discourse 组。

我认为这应该是一个逗号分隔的字符串,而不是一个数组:

2 个赞

@Firepup650 说得对。group_names 参数需要设置为一个字符串。如果要将用户添加到多个组,请用逗号分隔组名(逗号后不要加空格)。

$group_names = "volunteers,moderators";

如果不起作用,或者即使起作用了,也请尝试记录 $result 的值,看看返回了什么。

3 个赞

您好 @Firepup650 感谢您的帮助,这是我的代码

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 );

    
}

它将用户添加到 volunteers 组,但没有添加到 moderators 组,您能告诉我问题出在哪里吗?

1 个赞

您无法使用此函数调用将用户添加到“版主”、“管理员”或“员工”组。严格来说,您无法通过此方法将用户添加到任何“自动”组。您只能将用户添加到您创建的自定义组。

编辑:如果您需要将用户添加到版主组,请查看 sync_sso_record 函数:https://github.com/discourse/wp-discourse/blob/main/lib/utilities.php#L70-L81。`add_user_to_discourse_group` 函数只是 sync_sso_record 的一个便捷包装。

moderator(布尔值)是 SSO 参数接受的参数:discourse/lib/discourse_connect_base.rb at 5098338a9649ee8830c8a0781e0eb538e8206eac · discourse/discourse · GitHub add_groups 参数添加您想将用户添加到的任何自定义组。这将允许您通过一次 API 调用将用户添加到“版主”组和“志愿者成员”组。

编辑 2:如果您尝试使用 sync_sso_record 函数方法,您可能需要使用字符串 \"true\" 而不是布尔值 true 作为 moderator 参数。PHP 将 true 解释为 1。我认为 Discourse 接受字符串 \"true\" 来处理这种情况。请注意,您可以使用 get_sso_params 函数来设置 SSO 参数:https://github.com/discourse/wp-discourse/blob/main/lib/utilities.php#L129。在 add_user_to_discourse_group 函数的代码中有一个如何执行此操作的示例。

3 个赞

您好 @simon,您能否提供一个代码示例,说明如何将用户添加到版主组?

这是基本思路。我假设您需要为该函数添加一些条件,以便在用户的角色更改时,并非所有用户都会被添加到版主组。

function add_user_to_discourse_group_on_role_change( $user_id, $role ) {
	$sso_params = array(
		'external_id' => $user_id,
		'moderator'   => 'true', // 布尔值 'true' 和 'false' 需要设置为字符串!
		'add_groups'  => 'volunteers' // 逗号分隔列表,逗号后没有空格
	);
    DiscourseUtilities::sync_sso_record( $sso_params );
}
1 个赞

您好 @simon,我在这里遇到了一个问题。这是我在用户角色更改时使用的代码:

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
    }
}


    
}

现在,这段代码的目的是根据条件添加或删除用户。但在任何情况下,它都会向论坛管理员发送通知,要求批准、拒绝或删除用户。为什么会这样?例如,在 else 情况中,我只想将用户从特定组中删除,但在该情况下,它再次向管理员发送了“需要审核新用户”的通知。

还有一件事是,当用户在 WordPress 网站上注册时,他们会自动添加到这些组 trust_level_0 和 trust_level_1,原因不明。

请帮忙,我也可以与您分享用户注册钩子。

那是因为它们是核心的 discourse 组,用于管理权限等。

那是因为你开启了需要所有新用户都由管理员批准的设置,正如你的截图提到的:

image

看起来你是在添加新用户,这需要批准,正如我上面提到的。

1 个赞

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 个赞

你好 @simon,我又遇到一个问题了。

我想在用户注册网站时同步用户数据,并将他们添加到 Discourse 中,但自定义字段信息没有同步到 Discourse 的个人资料中。这是我的代码,你可以检查一下:

add_action( 'user_register', 'user_registered_callback', 10, 1 ); // 已调整为只接受一个参数

function user_registered_callback($user_id) {
    // 根据用户 ID 获取用户数据
    $user_data = get_userdata($user_id);

    // 检查用户数据是否存在
    if ($user_data) {
        // 获取用户角色
        $roles = $user_data->roles;

        // 检查用户是否具有 s2Member 角色
        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);

            // 获取自定义字段
            $custom_fields = get_user_option('1709753088_wp_s2member_custom_fields', $user_id);
            // 准备 SSO 参数数组
            $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 {
            // 收集所有级别组
            $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', '');

            // 将所有组合并到一个数组中
            $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)
            );

            // 删除重复项
            $s2member_level_groups = array_unique($s2member_level_groups);

            // 从所有收集的组中删除用户
            foreach ($s2member_level_groups as $group) {
                $result = DiscourseUtilities::remove_user_from_discourse_group($user_id, $group);
                // 你可以根据需要处理 $result
            }
        }
    } else {
        // 处理用户数据不可用的情况
        // 根据你的需求记录消息或以其他方式处理
        error_log("User data not available in user_registered_callback.");
    }
}

现在可以检查一下这段代码:

  $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']
            ];

当我 var_dump($fields_updated); 时,它返回 true,但数据并未添加到 Discourse 的用户个人资料中,这是什么问题?

除非有什么改变,否则你需要使用这里概述的方法:Map custom User Fields - #7 by simon

首先,请确保自定义字段已在 Discourse 中存在。然后,在你的 Discourse 站点的 /admin/customize/user_fields 页面上,在 URL 末尾添加 .json,这样你就可以看到用户字段的 JSON。例如 http://localhost:4200/admin/customize/user_fields.json

使用 JSON 中的 id 值来设置看起来像这样的 SSO 密钥:custom.user_field_<field_id>。例如 custom.user_field_1

我现在无法测试。如果有效,请告诉我。如果尚未完成,应将其记录在自己的主题中。

您好 @simon,我使用了您提到的方法,这是我现在的代码:

add_action( 'user_register', 'user_registered_callback', 10, 1 ); // 调整为只接受一个参数

function user_registered_callback($user_id) {
    // 根据用户 ID 获取用户信息
    $user_data = get_userdata($user_id);
// 	$user = get_user_by( 'ID', $user_id );
    // 检查用户信息是否存在
    if ($user_data) {
        // 获取用户角色
        $roles = $user_data->roles;

        // 检查用户是否具有 s2Member 角色
        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();
//             // 获取自定义字段
//             $custom_fields = get_user_option('1709753088_wp_s2member_custom_fields', $user_id);
//             // 准备 SSO 参数数组
//             $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 {
            // 收集所有级别组
            $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', '');

            // 将所有组合并到一个数组中
            $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)
            );

            // 删除重复项
            $s2member_level_groups = array_unique($s2member_level_groups);

            // 从所有收集的组中删除用户
            foreach ($s2member_level_groups as $group) {
                $result = DiscourseUtilities::remove_user_from_discourse_group($user_id, $group);
                // 您可以根据需要处理 $result
            }
        }
    } else {
        // 处理用户信息不可用的情况
        // 根据您的需求记录消息或以其他方式处理
        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);
	
    // 检查 $custom_fields 是否为数组且不为空
    if (is_array($custom_fields) && !empty($custom_fields)) {
        // 将自定义字段分配给 SSO 参数中的相应键
        $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 {
        // 如果 $custom_fields 的格式不符合预期,则记录或显示错误消息
        error_log('Custom fields data is not in the expected format.');
    }

    // 返回修改后的 SSO 参数
    return $sso_params;
}

现在唯一的问题是它没有将 users_reasons 添加到 custom.user_field_5 中,并且会添加其他数据到用户的个人资料中,例如,如果我注释掉这一行 $sso_params['custom.user_field_5'] = $custom_fields['users_reasons'];,它就会将其他字段的数据添加到 Discourse 用户中,如果我不注释掉这一行,则没有任何数据添加到 Discourse 用户资料中。您能告诉我这是什么原因吗?users_reasons 字段在 Discourse 站点和 WordPress 站点上都是多选字段,这可能是原因吗?请告诉我。

是的,问题在于它是一个多选字段。我不确定这是否已得到支持:https://meta.discourse.org/t/add-support-for-multi-select-fields-in-discourseconnect-protocol/219302。

也许现在有办法让它奏效,但我不知道该怎么做。调用的 Discourse 代码在这里:discourse/app/models/discourse_connect.rb at main · discourse/discourse · GitHub

@simon,你能根据你提供的参考资料为我写一个代码示例吗?

我认为这是不可能的。据我所知,自链接帖子发布以来,从 SSO 负载设置自定义字段的代码已略有更改,但并未以允许从 SSO 负载更新多选字段的方式进行更改。

理想情况下,Discourse 会以与处理 add_groups SSO 字段类似的方式处理这种情况:discourse/app/models/discourse_connect.rb at main · discourse/discourse · GitHub SSO 代码需要知道某个自定义字段是否是多选字段。我认为现在的代码没有这些信息。

同样,现在可能有一种方法可以做到这一点,但这超出了我的能力范围。

您好 @simon,我想在 WordPress 和 Discourse 之间同步用户头像。由于我已经在使用 wp discourse 插件进行 SSO,因此我希望当用户在 Discourse 网站上更改头像时,WordPress 网站上的头像也能随之更改。这该如何实现?另外,我希望在 WordPress 网站上使用一个用户头像插件。这是我正在使用的代码:

function my_wpdc_sso_client_updated_user( $updated_user, $query ) {
		$avatar_url = $query['avatar_url'];
		$user_id = $updated_user->ID;
		// 这允许我们使用 download_url() 和 wp_handle_sideload() 函数
	require_once( ABSPATH . 'wp-admin/includes/file.php' );

	// 下载到临时目录
	$temp_file = download_url( $avatar_url );

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

	// 将临时文件移至 uploads 目录
	$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 // 无需检查 'action' 参数
		)
	);

	if( ! empty( $sideload[ 'error' ] ) ) {
		// 如果需要,您可以返回错误消息
		return false;
	}

	// 现在是将上传的图片添加到 WordPress 媒体库
	$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;
	}

	// 更新元数据,重新生成图片尺寸
	require_once( ABSPATH . 'wp-admin/includes/image.php' );

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

	// 返回附件 ID
	update_user_meta($user_id, '1709753088_wp_user_avatar', $attachment_id);
	update_user_meta($user_id, 'wp_user_avatar', $attachment_id);
}

如您所见,我想使用附件 ID 更新用户的元键,但附件 ID 未创建。

期待您的回复。

谢谢。