Buy ExternalDocuments.com

WordPress UsersWP Profile Hacking

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.

PHP
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.