Link custom user field to external website

I am seeing this warning in console on your site:

Plugin API v0.6 is not supported

You need to be on latest Discourse version.

@techAPJ Updated Discourse and all components now. And I no longer see console errors. However, the links are still not visible.

I also noticed the guide haven’t changed from what I did last time (28d ago), were your changes done via the discourse code itself? Thanks again for your help so far.

The issue was happening because this guide is not for linking a username to the main site.
If you are looking for such functionality please refer to this new guide

3 Likes

This is really nifty, I’ve added two fields users can fill, Twitch and Steam. Eventually might even add more.
I’m now trying to have the link displayed as fa icon. This is working, but this way it will display every icon on a new line, so I’ve been trying to combine this, but I’m having issues with it.

<script type="text/discourse-plugin" version="0.6">
    const User = api.container.lookupFactory('model:user');

    api.registerConnectorClass('user-profile-primary', 'steam-link', {
      setupComponent(args, component) {
        component.set('steamLink', args.model.get('steamLink'));
      }
    });

    api.registerConnectorClass('user-card-metadata', 'steam-link', {
      setupComponent(args, component) {
        component.set('steamLink', args.user.get('steamLink'));
      }
    });
    
    api.registerConnectorClass('user-profile-primary', 'twitch-link', {
      setupComponent(args, component) {
        component.set('twitchLink', args.model.get('twitchLink'));
      }
    });

    api.registerConnectorClass('user-card-metadata', 'twitch-link', {
      setupComponent(args, component) {
        component.set('twitchLink', args.user.get('twitchLink'));
      }
    });

This part isn’t that hard, the question is, how do I combine the data, and how do I configure an and/or statement so it also works if a user only added one of the two fields. And, if I add more fields in the future, how I would add them as well.

I figured, if this all happens before I build the HTML, it will be easier to add all icons on the card and profile on one line. :slight_smile:

Anyone with some tips/insights? Right now every field goes through something like this:

<script type='text/x-handlebars' data-template-name='/connectors/user-profile-primary/twitch-link'>
  {{#if twitchLink}}
    <div class="public-user-fields">
      <div class="public-user-field">
        <span class="user-field-value">{{{twitchLink.link}}}</span>
      </div>
    </div>
  {{/if}}
</script>

<script type='text/x-handlebars' data-template-name='/connectors/user-card-metadata/twitch-link'>
  {{#if twitchLink}}
    <h3 class="user-card-public-field">
      <span class="user-field-value">{{{twitchLink.link}}}</span>
    </h3>
  {{/if}}
</script>

How do I tell the {{#if twitchLink}} that it also needs to check for Steam (and maybe Twitter, Facebook, etc. etc.), and display all the icons on one line?

This is the way it is now, so it kind of works, but I would like to have the icons on one line. Because they are generated separately, there are emberxxx classes created, with div’s/span’s with the same name…

What would be the best way to have these icons “generated” on one line?

1 Like

It sounds like you’re doing something like this currently:

<script type='text/x-handlebars'>
  {{#if twitchLink}}
     [...]
  {{/if}}
</script>

<script type='text/x-handlebars'>
  {{#if steamLink}}
    [...]
  {{/if}}
</script>

If instead you do this:

<script type='text/x-handlebars'>
  {{#if twitchLink}}
     [...]
  {{/if}}
  {{#if steamLink}}
    [...]
  {{/if}}
</script>

You can then simply set the style attribute on the outermost div or h3 to display: inline-block;, so, something like this:

{{#if twitchLink}}
  <div class="public-user-fields" style="display: inline-block;">
     [...]

(Or just use elements which are naturally inline).

If you’re looking for more inspiration, this gist should do what you want:

Change the object on line 4 of head.html to change the row of icons, and on line 50 to change the icon & text combo which appears next to the location/site.

11 Likes

Awesome! Gonna check that out later on my desktop. I’ve managed to get the icons on one line through some styling, that screenshot looks a lot better though. Thanks! I’ll post back later! :heart:

1 Like

This looks great, thanks for sharing! But do I understand correctly that that entire code is loaded with every page and that that code will perform multiple api calls every time? (I’m sorry if this is a very dumb question. I don’t know any javascript, just guessing.)

The code piggybacks on the existing code to load the user cards/profiles, so no additional API calls are done, just the usual one to /u/<username>.json. But yes, the entire code is loaded on every ‘real’ page load (i.e. when you hit Discourse from an external site or from typing in a url, or refresh a page), much the same way all the rest of Discourse’s client side code is loaded on every real page load.

3 Likes

Is there an easy way to implement this? I would like to use external_id in my link, but I’m still not clear on how I would go about doing that.

Thanks!

This needs to be done on SSO side, so you will need to look into how your SSO is set-up.

1 Like

I’m just using the WP Discourse plugin.

When I visit the user profile as admin (/admin/users/2/[username]), I do see the External ID under the Single Sign On section at the bottom.

Does that move me any further ahead in the process? Is it just a matter of properly modifying OP’s code?

@simon, is there a good way to do this in the WP Discourse plugin?

Yes, there is. What data do you want to add to the field?

1 Like

Just the External ID to a custom field.

Aside from that, it would be cool if there was an easy way to do it for other fields as well. (ie location or any custom fields on the WP side).

It’s not as easy as I thought. I might not be doing this correctly.

It’s possible to set the value of a UserCustomField through the SSO parameters sent from WordPress by hooking into the wpdc_sso_params filter. If you create a ‘wordpress id’ User Field on Discourse, you can then create new Discourse UserCustomField record by doing something like this:

add_filter( 'wpdc_sso_params', 'my_namespace_custom_fields', 10, 2 );
function my_namespace_custom_fields( $sso_params, $user ) {
    $sso_params['custom.wordpress_id'] = $user->ID;

	return $sso_params;
}

The problem I’m having is that I can’t figure out how to access the value of that record on the front-end of Discourse.

3 Likes

Thanks Simon! Yeah I just poked around as well and couldn’t find the field name anymore. How did you find it through the console?

My solution seems wrong. I’ll look at this some more when I get a chance.

Edit:
I was having some trouble understanding why this works, but after looking through the code a bit more this seems to make sense as a way of setting custom fields through SSO.

Create a user field on Discourse in the way outlined in the OP and then go to your profile as an admin and add a value (any value) to it. You can then go to the Discourse rails console and enter:

UserCustomField.all

A list of all the user_custom_fields on your site will be returned. It will be made up of one or more entries that look something like this:

#<UserCustomField:0x007fa02bb39d18 id: 18, user_id: 1, name: "user_field_8", value: "test value", created_at: Wed, 07 Jun 2017 01:48:10 UTC +00:00, updated_at: Wed, 07 Jun 2017 01:48:10 UTC +00:00>]
Look for the entry that has a value attribute that matches the value you just saved in your custom field. Copy the name of that field into a function on your WordPress site that is something like this:

add_filter( 'wpdc_sso_params', 'my_namespace_set_discourse_custom_field', 10, 2 );
function my_namespace_set_discourse_custom_field( $sso_params, $user ) {
    $sso_params['custom.user_field_7'] = $user->ID;

    return $sso_params;
}

To use the code in the OP, replace the name value (‘User Profile’) in this line:
const externalUserIdField = siteUserFields.filterBy('name', 'User Profile')[0]
with whatever you have called the field you added on Discourse. This is the part of the code that I wasn’t understanding, but it makes more sense after looking at this: https://github.com/discourse/discourse/blob/master/app/controllers/users_controller.rb#L99

Unless there is a better way to do this, I’ll add it to the WP Discourse Plugin Tips and Tricks topic.

3 posts were split to a new topic: How to update user Web Site field via API

This guide is now updated to deprecate api.container.lookupFactory in favor of api.modifyClass.

5 Likes