دمج Discourse مع MemberMouse

أقوم بصيانة Discourse و MemberMouse على موقعين. آمل أن يكون هذا الدليل مفيدًا للناس. قد تختلف مواصفاتك الدقيقة عن النتائج التي كنت أرغب فيها. يفترض هذا الدليل أنك على دراية بـ hooks و filters في MemberMouse، و واجهة PHP الخاصة بـ MemberMouse. كما يفترض أيضًا أنك قادر على إضافة كود مخصص إلى WordPress بسهولة عبر ملف functions.php أو إضافة مخصصة من صنعك.

إليك ما أضفناه في هذا الدليل لتحقيق ما يلي:

  • تفعيل/تعطيل المستخدم في Discourse بناءً على حالة عضويته في MemberMouse
  • تعيين مجموعات في Discourse تمثل مستويات العضوية في MemberMouse
  • مزامنة تغييرات اسم المستخدم/البريد الإلكتروني بشكل فوري
  • بالإضافة إلى تعديلات صغيرة أخرى مفيدة

الخطوة 1: تثبيت Discourse و WordPress وإضافة wp-discourse لـ WordPress

قم بتثبيت WordPress و Discourse وإضافة wp-discourse لـ WordPress وتشغيلها وتكوينها بشكل صحيح بحيث يعمل WordPress كمزود SSO. هناك العديد من المواضيع حول هذا الأمر هنا.

الخطوة 2: تحديد المربع للسماح لإضافة wp-discourse بإنشاء مستخدم جديد في Discourse عند إنشاء مستخدم في WordPress

وجدت أنه لكي تقوم إضافة wp-discourse فعليًا بإنشاء مستخدم في Discourse عند إنشاء مستخدم في WordPress، كنت بحاجة إلى إجراء تغيير في الكود داخل الإضافة. والسبب في ذلك هو أن الإضافة تعتمد على إجراء “wp_login”، ولكنها تتصرف بشكل مختلف في MemberMouse مقارنة بسلوك WordPress العادي. لذا، يجب عليك إضافة هذا السطر إلى الملف /lib/discourse-sso.php داخل الدالة العامة __construct( $wordpress_email_verifier ):

add_action( 'my_mm_account_added', array( $this, 'create_discourse_user' ), 10, 2 );

وفي ملف functions.php أو في إضافة خاصة بك، أضف الكود التالي:

function add_user_to_discourse($data) {
	do_action( 'my_mm_account_added', $data["username"], get_user_by('ID',$data["member_id"]) );	
}
add_action('mm_member_add', 'add_user_to_discourse');

الخطوة 3: إذا رغبت، اجعل المستخدمين الجدد غير مضطرين للنقر على رابط تفعيل البريد الإلكتروني الخاص بـ Discourse

بشكل افتراضي، سيرسل Discourse بريدًا إلكترونيًا للتفعيل إلى المستخدم الجديد، لكنني اخترت إيقاف ذلك لأن المستخدم قد تجاوز بالفعل عددًا مرضيًا من العقبات في WordPress للانضمام. إذا كان موقع WordPress الخاص بك يتميز بحاجز منخفض للانضمام، فقد لا ترغب في تخطي بريد التفعيل. في حالتنا، يجب عليك الدفع للانضمام. أضف الكود التالي إلى ملف functions.php أو إلى إضافة خاصة تنشئها:

add_filter( 'wpdc_auto_create_user_require_activation', 'my_wpdc_auto_create_user_require_activation' );
function my_wpdc_auto_create_user_require_activation( $require_activation ) {
    return false;
}

الخطوة 4: كلما حدث تغيير في حساب مستخدم MemberMouse:
قم بربط مستويات عضوية MemberMouse بمجموعات Discourse
قم بمزامنة عنوان البريد الإلكتروني واسم المستخدم
قم بتفعيل/تعطيل المستخدم في Discourse حسب الاقتضاء

يمكنك إضافة هذا الكود إلى ملف functions.php أو إلى إضافة خاصة بك.

add_action('mm_member_membership_change', 'run_discourse_sync_based_on_mm_acct_change');
add_action('mm_member_status_change', 'run_discourse_sync_based_on_mm_acct_change');
add_action('mm_member_account_update', 'run_discourse_sync_based_on_mm_acct_change');

في الدالة run_discourse_sync_based_on_mm_acct_change، يجب عليك:

(1) استخدام واجهة برمجة تطبيقات (API) الخاصة بـ Discourse للحصول على اسم المستخدم في Discourse لهذا المستخدم (قد يختلف قليلاً عن اسمه في WordPress بسبب قواعد التسمية الخاصة بـ Discourse) ورقم معرف المستخدم في Discourse. (التوثيق)

(2) ربط معرف مستوى العضوية في MemberMouse بمعرف المجموعة المكافئ في Discourse، ثم تعيين المجموعة في Discourse. أولاً، يجب عليك حذف معرف المجموعة القديم. (التوثيق). بعد ذلك، يمكنك تعيين المجموعة الجديدة. (التوثيق)

(3) مزامنة اسم المستخدم والبريد الإلكتروني إذا تم تغييرهما في WordPress. نحن نسمح بتغيير هذين العنصرين فقط في WordPress. حصلت على مساعدة في هذا الجزء هنا.

(4) تفعيل/تعطيل المستخدم في Discourse بناءً على حالته في MemberMouse. التفعيل (التوثيق). يبدو أن التعطيل مفقود من وثائق الـ API. $url = $url_base.‘admin/users/’.$discourse_userid.‘/deactivate.json?’.$api_auth;

الخطوة 5: إعادة التوجيه التلقائي إلى Discourse عند الاقتضاء

(أوصي بشدة بتأجيل هذا الجزء حتى تتعرف جيدًا على كيفية عمل WordPress و Discourse معًا.)

إذا لم يكن المستخدم مسجلًا في Discourse ولم يكن مسجلًا في WordPress. وجاء إلى عنوان URL في Discourse ونقر على زر تسجيل الدخول الأزرق، فسيتم نقله إلى WordPress لتسجيل الدخول، لكن MemberMouse سيقوم بتوجيه المستخدم إلى أي صفحة قمت بتعيينها لإعادة التوجيه إليها في إعدادات MemberMouse. للأسف، لا يتم إعادة توجيه المستخدم مرة أخرى إلى Discourse. لذا، إليك كيف قمت بحل هذه المشكلة. يمكنك إضافة هذا الكود إلى ملف functions.php أو إلى إضافة خاصة بك. (موضوع للمزيد من المعلومات.)

// إذا جاء الشخص من منتدى discourse، قم بإعادته بالضبط إلى المكان الذي كان فيه بعد تسجيل الدخول
function my_mm_login_redirect( $infoObj ) {
	if ( @$_COOKIE['detected_forum_referal'] != '' ) { // يجب عليك العناية بتعيين ملف تعريف الارتباط المؤقت هذا إذا وصل المستخدم حديثًا عبر discourse
		$current_user       = $infoObj->user;
		$user_id            = $current_user->ID;
		// الحمولة والتوقيع.
		$payload = @$_COOKIE['mm_cookie_sso'];
		$sig     = @$_COOKIE['mm_cookie_sig'];
		// تحويل %0B مرة أخرى إلى %0A.
		$payload = rawurldecode( str_replace( '%0B', '%0A', rawurlencode( $payload ) ) );
		// التحقق من صحة التوقيع.
		$sso_secret = 'YOUR-SSO-SECRET';
		$sso        = new \WPDiscourse\SSO\SSO( $sso_secret );
		if ( ! ( $sso->validate( $payload, $sig ) ) ) {
			return '';
		}
		$nonce  = $sso->get_nonce( $payload );
		$params = array(
			'nonce'               => $nonce,
			'username'            => $current_user->user_login,
			'email'               => $current_user->user_email,
			'external_id'         => $user_id,
		);
		$params = apply_filters( 'wpdc_sso_params', $params, $current_user );
		$q = $sso->build_login_string( $params );
		do_action( 'wpdc_sso_provider_before_sso_redirect', $user_id, $current_user );
		// إعادة التوجيه إلى Discourse.
		return('YOUR-FORUM-BASE-URL' . '/session/sso_login?' . $q);
	}
	return('');
}
add_filter( 'mm_login_redirect', 'my_mm_login_redirect', 10, 1 );
17 إعجابًا

if i May ask do you need to install the Discourse on its own or … you just need the discourse plugin in your wordpress

You need to install Discourse on it’s own. The plugin just helps WordPress and Discourse talk to each other.

4 إعجابات

thank you m new here and i like this community so im in a process on launching it on my Google cloude…

إعجاب واحد (1)

@lkramer - how does this workflow need to change to use MemberMouse Bundles instead of the MM membership status?

(For us MM memberships are too limited, as a customer can only be in one at a time (free or paid). We have many products, so we use Bundles which allows us infinite flexibility.)

Our use case is as follows:

We sell multiple courses. We control course access using Bundles. “Product 1 Bundle” and “Product 2 Bundle,” etc. Any one customer can have access to one or many (or all) of course courses.

Within Discourse we have a separate course forum (category/group) for each product…

We want customers of “Product 1 Bundle” to only be able to see the Discourse category/group for that course, and so on.

Any idea how your workflow would need to change to allow for our use case?

Thx a ton in advance, Leah!

3 إعجابات

In order to rely on bundles rather than membership levels – anywhere I mentioned membership status/level, you’d just check the person’s bundle status via a MemberMouse php function. So check whether they have bundle X and whether it’s currently ‘active’ and if so, put them in Discourse group X or else remove them from group X. I believe the MemberMouse php function you want is something like this:

if ( mm_member_decision(array("hasBundle"=>"1")) )

Now, regarding only making certain Discourse categories accessible to certain Discourse groups, I’ve never tried it but according to this thread here you can restrict categories to certain groups:

So as long as you can successfully set/unset a person’s Discourse group based on their bundle (which should be do-able), then you can achieve your goal of only having access to certain categories.

4 إعجابات

Another tidbit of potentially helpful info – To learn to use the Discourse API, write some small isolated scripts to get small pieces working as a proof of concept and to know exactly what code works. There are often several ways to interact with an API even within one language. So, e.g, write a little script that just tests the concept of setting and unsetting someone’s Discourse group. This is what I did and then I knew it was safe/reliable to add them into the MemberMouse eco-system where approprirate. :slight_smile:

6 إعجابات

The best way to sync group membership is, of course, the sync_sso and during SSO login (which should go through the same function!! you don’t want to add someone from a group and take them back out when they log in) — because this is way more efficient, only 1 API call to change as many groups as you want.

5 إعجابات

Thx @lkramer! (and @riking)

Thx @riking. So are you saying you can set/unset multiple groups in sync_sso. That’s good to know.

إعجاب واحد (1)

This wasn’t working for me, and I just upgraded, and now there is no create_discourse_user, it seems.

@simon, have you got a suggestion here?

It seems that having to edit the plugin to make membermouse work is something of a bummer. I think that I can imagine code that would solve that if I first could get WordPress to trigger creating the account.

إعجاب واحد (1)

It’s still there: https://github.com/discourse/wp-discourse/blob/master/lib/utilities.php#L306

You need to call it with the namespace WPDiscourse\Utilities\Utilities::create_discourse_user( $user )

There is also a sync_sso_record function that would be better to use if you are able to. It takes an array of sso parameters as an argument. You can get them from the get_sso_params function.

I’m in the process of cleaning up this file. I won’t remove any functions that I’ve posted about on meta. If I break anything, let me know.

Edit: I read the OP more closely. I hadn’t realized it was editing the plugin’s code. That part will be broken by the most recent update. It would be better to call either the create_discourse_user or the sync_sso_record function from WPDiscourse\Utilities, and add the my_mm_account_added hook to your functions.php file or a separate plugin.

4 إعجابات

Thanks, @simon!

Here’s what I’m doing now:

function add_user_to_discourse($data) {
	do_action( 'my_mm_account_added', $data["username"], get_user_by('ID',$data["member_id"]) );
    error_log ("Doing add_user");
}

add_action('mm_member_add', 'add_user_to_discourse');

Also, I have a handful of actions like


add_action('mm_member_membership_change', 'run_discourse_sync_based_on_mm_acct_change');
add_action('mm_member_status_change', 'run_discourse_sync_based_on_mm_acct_change');
add_action('mm_member_account_update', 'run_discourse_sync_based_on_mm_acct_change');

Should all of these call sync_sso_record? And what should go in $user when I call WPDiscourse\Utilities\Utilities::create_discourse_user( $user )? (I’m going to RTFC now, but perhaps your 2 minutes can save me an hour. :slight_smile:)

Edit: OK, should something like this work? I see that it’s getting called, but the user’s not getting created.

function add_user_to_discourse($data) {
    $user['name'] = $data['first_name'] . " " . $data['last_name'];
    $user['user_email'] = $data['email'];
    error_log ("Calling create_discourse_user");
    WPDiscourse\Utilities\Utilities::create_discourse_user( $user );
}

Assuming you are also adding the user to a group, I think you could just call WPDiscourse\Utilities\Utilities::add_user_to_discourse_group( $user_id, 'group,names' ). That gets the sso params for then calls sync_sso_record with the params. The remove_user_from_discourse_group function works in a similar way, except it removes users from a group or groups.

If you just want to create or update a user without dealing with groups, you can do something like this:

$user = get_user_by( 'id', 1 ); // Supply user_id here.
$sso_params = WPDiscourse\Utilities\Utilities::get_sso_params( $user );
WPDiscourse\Utilities\Utilities::sync_sso_record( $sso_params );

If SSO is enabled, I don’t think there would be a reason to prefer the create_discourse_user function over the sync_sso_record function. If you do need to use it, it takes a WordPress user object as the argument: $user = get_user_by( 'id', 1 );

4 إعجابات

Yeah. Sadly, I started with code that was written before add_user_to_discourse_group existed. I was just wondering whether I should change my working API calls to use that instead.

It’s not obvious to me that add_user_to_discourse_group will create the user. Is that happening somewhere that I don’t see?

Yes, it creates a user by sending the SSO parameters to the Discourse /admin/users/sync_sso route. It actually takes a comma separated list of group names as its argument (no spaces between names), so it should be renamed. You can also call it with an empty string as the group_names argument. You have to at least supply an empty string for the group names, or it will throw an error.

4 إعجابات

So, this is a zillion times easier than it used to be!

add_user_to_discourse_group( $user_id, $group_names ) wants the WP userid? and the Discourse group name (no fussing in the json to figure out the group_id?!?!)?

Now I just need to find the $user_id and I’ll be golden.

Edit: $user = get_user_by('ID',$data["member_id"])

Edit: I’m all set! The version of the MemberMouse bundle-to-group function that I was working on yesterday was over 200 lines. The working version today is about 40.

Thanks again, @simon!

إعجابَين (2)

Great! I’ll document the changes to the functions soon. They take the same arguments as before, but behave a little differently. One thing to note is that Discourse will still consider the add_user_to_discourse_group and remove_user_from_discourse_group functions to be API calls - they are just making fewer API calls than the previous version did.

The functions return the status code that is returned from the Discourse request. You want to be getting a 200 response. If you’re adding a lot of users at the same time, you need to look out for 429 status codes and find some way of dealing with them. (When adding one user at a time it shouldn’t be an issue.)

4 إعجابات

Well, I’m pretty sure that last summer when I did this before there was a lot more that I had to do with my own darn API calls. This is pretty great. Hooray that this is now your day job!

إعجاب واحد (1)

Maybe you can write a new and improved MemberMouse guide, Jay, when this is all said and done. :slight_smile: Come to think of it, just a general, “hook Discourse up to your membership plugin” guide would be great for ANY membership plugin. I’m guessing they all have similar “hooks” as MemberMouse.

4 إعجابات