I am messing with UsersWP as a front-side login and registration system. There are a bunch of plugins, but this one looked OK, so I added it to Riceball.
There aren’t any tools to make the user profile page, and it’s not even templated out, so I decided to try and replace it.
Discussion is below the code.
add_action( 'init', function() {
global $userswp;
remove_action( 'uwp_profile_more_info_tab_content', array( $userswp->profile, 'get_profile_more_info' ), 10, 1 );
add_action( 'uwp_profile_more_info_tab_content', 'custom_get_profile_more_info', 10, 1 );
add_filter( 'uwp_get_max_upload_size', 'custom_modify_get_max_upload_size', 10, 2 );
});
function custom_modify_get_max_upload_size( $a, $b ) {
return 2048 * 1024;
}
function custom_get_profile_more_info( $user_id ) {
global $userswp;
$data = rb_get_profile( $user_id );
$output = rb_apply_template( 'rb_template_more_info', $data );
echo $output;
}
function rb_get_profile( $user_id ) {
global $wpdb;
global $userswp;
$show_type = '[more_info]';
$user = uwp_get_displayed_user();
$table_name = uwp_get_table_prefix() . 'uwp_form_fields';
$form_id = uwp_get_register_form_id( $user->ID );
$fields = $wpdb->get_results( $wpdb->prepare("SELECT * FROM " . $table_name . " WHERE form_type = 'account' AND form_id = %d ORDER BY sort_order ASC", $form_id ));
$result = [];
if ( $fields ) {
$usermeta = isset( $user->ID ) ? uwp_get_usermeta_row( $user->ID ) : array();
$privacy = ! empty( $usermeta ) && ! empty( $usermeta->user_privacy ) ? explode( ',', $usermeta->user_privacy ) : array();
foreach ( $fields as $field ) {
$show_in = explode( ',', $field->show_in );
if ( ! in_array( $show_type, $show_in ) ) {
continue;
}
$display = false;
if ( $field->is_public == '0' ) {
$display = false;
} else if ( $field->is_public == '1' ) {
$display = true;
} else {
if ( ! in_array( $field->htmlvar_name . '_privacy', $privacy ) ) {
$display = true;
}
}
if ( ! $display ) {
continue;
}
// get the raw value
$raw_value = uwp_get_usermeta( $user->ID, $field->htmlvar_name, "" );
// formatted value
$value = $userswp->profile->get_field_value( $field, $user );
$class = isset( $field->css_class ) ? $field->css_class : '';
if ($value) {
$result[] = [
// 'field' => $field,
'field_icon' => $field->field_icon,
'css_class' => $field->css_class,
'field_type' => $field->field_type,
'label' => $field->site_title,
'value' => $value,
'raw_value' => $raw_value
];
}
}
}
return $result;
}
function rb_apply_template( Callable $callable, array $data ) {
// template resolver
return $callable( $data );
}
function rb_template_more_info( $data ) {
// print_r($data);
$personal = array_filter($data, fn($a) => in_array($a['field_type'], ['textarea','file']) );
$mess = array_filter( $data, fn($a) => in_array($a['field_type'], ['url', 'text']) );
$websites = array_filter( $mess, fn($a) => str_starts_with($a['label'], 'Website') );
$socials = array_filter( $mess, fn($a) => !str_starts_with($a['label'], 'Website') );
return
rb_template_personal( $personal )
.rb_template_urls( $websites )
.rb_template_social( $socials )
;
}
function rb_template_personal( $data ) {
$output = [];
foreach($data as $t) {
if ($t['field_type'] != 'file') $output[] = "<h4>" . $t['label'] . "</h4>";
if ($t['field_type'] == 'file') {
$output[] = '<p><img src="'.$t['raw_value'].'"></p>';
} else {
$output[] = '<p>' . $t['value'] . '</p>';
}
}
ob_start(); ?>
<?php echo implode('', $output); ?>
<?php return ob_get_clean();
}
function rb_template_social( $data ) {
$output = [];
foreach( $data as $datum) {
$output[] = '<p>'
. $datum['label']
. ' - <a href="' . $datum['raw_value'] . '" target=_blank>'
. rb_social_media_username($datum['raw_value'])
. '</a></p>';
}
$output = implode('', $output);
ob_start(); ?>
<h3>Social</h3>
<?php echo $output; ?>
<?php return ob_get_clean();
}
function rb_social_media_username($url) {
if (strpos($url, 'bsky.app') !== false) {
// Bluesky
$handle = explode('/', $url);
$handle = end($handle);
return '@' . explode('.', $handle)[0];
} elseif (strpos($url, 'twitter.com') !== false) {
// Twitter
$handle = explode('/', $url);
$handle = end($handle);
return '@' . $handle;
} elseif (strpos($url, 'facebook.com') !== false) {
// Facebook
$handle = explode('/', $url);
$handle = end($handle);
return '@' . $handle;
} elseif (strpos($url, 'tiktok.com') !== false) {
// TikTok
$handle = explode('/', $url);
$handle = end($handle);
return '@' . $handle;
} elseif (strpos($url, 'instagram.com') !== false) {
// Instagram
$handle = explode('/', $url);
$handle = end($handle);
return '@' . $handle;
}
return $url;
}
function rb_template_urls( $data ) {
// gather all the URLs where the label is like "Website #"
$urls = [];
$sites = array_filter($data, fn($a) => preg_match('/^Website (\d+)$/', $a['label'])) ;
foreach($sites as $site) {
$urls[ $site['raw_value'] ] = $site['label'];
}
asort($urls);
// now pluck out the matching labels, ans set the value to the label
foreach($urls as $url=>$label) {
$needle = array_find($data, fn($a) => $a['label'] === $label.' Label') ?? ['value'=>null];
$urls[$url] = $needle['raw_value'];
}
$output = [];
foreach($urls as $url=>$label) {
$output[] = $label ?
"<p><a href='$url' target=_blank>$label</a></p>"
: "<p><a href='$url' target=_blank>$url</a></p>";
}
$output = implode('', $output);
ob_start(); ?>
<h3>Websites</h3>
<?php echo $output; ?>
<?php return ob_get_clean();
}This code’s weird because I hacked on it in WPCode, a coding plugin. I recommend it for working out the nuts and bolts of your code.
Since there isn’t much documentation about writing UsersWP plugins, I had to turn to the sources on GitHub: https://github.com/AyeCode/userswp/
The overall code structure is in class-userswp.php. The application is broken up into classes, and each is instantiated into an object that’s referenced by property in the global $userswp. (They’re kind of like “services”.)
The application services are hooked into WordPress via add_action() and add_filter() calls.
To extend the application, you do the same. You can replace a service endpoint by using remove_action() call. See Line 3 above.
The UsersWP code has data and logic and layout a little bit too mixed-up for comfort, so I did some copy-pasta to break out some of the database access stuff.
The data returned was a little too huge for me, and sometimes too cooked, so I transformed it a little bit.
Then, it was pretty simple to write picture functions, and cobble together a layout. Here’s the work so far: https://riceball.com/profile/admin/
For the most part, it works as expected with UsersWP. You have to create a form with all the relevant fields to fill.
There’s one ugly hack in there to enable the website links. UsersWP doesn’t have a field type for a URL that includes the link text. So I’m using a naming convention to specify websites.
The URL field should be named “Website #”, where # is a 1 digit number.
The link text field should be named “Website # Label”.
The code will match the two fields, and produce a linked website name.