3 minute read

The core idea of any interactive website is to respond to the user’s actions, which is performed with several steps: collecting inputs, processing then visualizing. Unfortunately, this could not be fully controlled/customized only with WordPress core.

ACF makes it much easier to expand WordPress functionalities, allows us to take full control of not only posts but users (and more…). GForms provides a security & convenient layer to collect user’s info.

By using hooks, you can build fully customized site’s functions like User Management* (login, register, logs,… – totally Front-End), Shopping Cart (easy implemented with cookies), User Thread New Post like Forums, … in a secured & comfortable way, without having to use a bunch of additional plugins for each feature.

Motivation

User Management is always a big disadvantage of using WordPress. This article will give you the solution to some key features such as Register Page, User Post Submit (both front-end), discussing issues about security and other ideas.

Front-End Login Form

If you are looking for a Front-End Login Page, WP provides:

$args = array(
	'redirect' => home_url(), 
	'form_id' => 'loginform-custom',
	'label_username' => __( 'Username' ),
	'label_password' => __( 'Password' ),
	'label_remember' => __( 'Remember Me' ),
	'label_log_in' => __( 'Log in' ),
	'remember' => true
);
wp_login_form( $args );

Or more: https://codex.wordpress.org/Function_Reference/wp_login_form

Now we can totally disable /wp-admin/ for those who are not admins (disable user’s back-end). I picked up this code somewhere, forgive me not mentioning the source (I don’t remember): these lines use ‘admin_init‘ hook.

function wpse66093_no_admin_access()
{
    $redirect = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : home_url( '/' );
    if ( !current_user_can( 'delete_users' ) )
        exit( wp_redirect( $redirect ) );
}
add_action( 'admin_init', 'wpse66093_no_admin_access', 100 );

For authorized /wp-admin/ access (for us), we use the login form to log in, then go /wp-admin/.

Custom Fields & Registration Form

Create Custom Fields

With ACF you can easily create User’s extra fields. Let’s say you created 2 more fields: ‘address‘, ‘phone_number‘ (You should choose “Rule” equal to “All” when creating new Field Group). These values are stored in user’s meta data table.

Create a Register Form

Create the form using GForms, remember required fields like ‘user_login‘ (username), ‘user_pass‘ & our 2 custom fields. Below I used: (Created with GForms)

  1. username
  2. email
  3. password
  4. retype
  5. address
  6. phone_number Respectively.

Reg Form Validation?

Now we face the problem to make sure that the chosen username, email are not used, and if you are careful enough to have created a “Retype Password” input in your reg form then this will be a problem.

We solve this by using GF hook ‘gform_validation‘, this is how we validate username. My Reg Form Id is 2, so the hook name will be ‘gform_validation_2‘:

add_filter( 'gform_validation_2', 'validate_reg');
function validate_reg( $validation_result ) {
	$form = $validation_result['form'];
	$user_name = rgpost( "input_1" );
	if (username_exists($user_name)) {
		$form['fields']['1']['failed_validation'] = true;
		$form['fields']['1']['validation_message'] = 'Username invalid!';
		$validation_result['is_valid'] = false;
	}
	$validation_result['form'] = $form;
	return $validation_result;
}

We use ‘gform_after_submission‘ hook. This is called after a successful submission.

add_action( 'gform_after_submission', 'gform_after_submit', 10, 2 );
function gform_after_submit( $entry, $form ) {
	if ($form['id'] == 2) { // that way, u can implement 'id' == 3, 4, ... below without anothor add_action
		$userdata = array(
			'user_login'  =>  $entry['1'],
			'user_email' => $entry['2'],
			'user_pass'   =>  $entry['3'],
			'last_name' => $entry['5']
		);
		$user_id = wp_insert_user( $userdata ); // DONE
		if( !is_wp_error($user_id) ) {
			// Update meta for custom values
			update_user_meta($user_id, 'address', $entry['6'] );
			update_user_meta($user_id, 'phone_number', $entry['7'] );
		}
	}
}

It’s that easy!

Notice: Now you can (and should) DISABLE New User Registration in WordPress General Options. Our Reg Form will stay fine(due to our wp_insert_user() function)! Then put the reg form a Captcha or Recaptcha Field to prevent spamming.

Password Change Form

Same way with Registration Page. This time we change it directly when validating form. Normally, I created 3 inputs (old one, new one and retype), my Form ID is 4, change ‘gform_validation_4‘ so it fit yours.

add_filter( 'gform_validation_4', 'validate_change_pwd');
function validate_change_pwd( $validation_result ) {
	$form = $validation_result['form'];
	$user_pwd = rgpost( "input_1" );
	$field_value1 = rgpost( "input_2" );
	$field_value2 = rgpost( "input_3" );
	if (!is_user_logged_in()) {
		return $validation_result;
	}
	global $current_user;
	get_currentuserinfo();
	$user = get_user_by( 'login', $current_user->user_login );
	if (!$user || !wp_check_password( $user_pwd, $user->data->user_pass, $user->ID)) {
			$form['fields']['1']['failed_validation'] = true;
			$form['fields']['1']['validation_message'] = 'Password Incorrect!';
			$validation_result['is_valid'] = false;
		}
	}
	if ($field_value1!=$field_value2) {
			$form['fields']['2']['failed_validation'] = true;
			$form['fields']['2']['validation_message'] = 'Password mismatched!';
			$form['fields']['3']['failed_validation'] = true;
			$form['fields']['3']['validation_message'] = 'Password mismatched!';
			$validation_result['is_valid'] = false;
		}
	}
	
	if ($validation_result['is_valid'] == true) {
		wp_set_password($field_value1, $user->ID);
	}
	
	$validation_result['form'] = $form;
    return $validation_result;
}

I believe with these ideas, we could get most of the site’s functions to work as we wish. I’ll be glad if you let me know what you’ve done.