Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion inc/apis/schemas/checkout-form-create.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@
'required' => false,
],
'template' => [
'description' => __("Template mode. Can be either 'blank', 'single-step' or 'multi-step'.", 'ultimate-multisite'),
'description' => __("Template mode. Can be either 'blank', 'single-step', 'multi-step' or 'simple'.", 'ultimate-multisite'),
'type' => 'string',
'required' => false,
'enum' => [
'blank',
'single-step',
'multi-step',
'simple',
],
],
'date_created' => [
Expand Down
3 changes: 2 additions & 1 deletion inc/apis/schemas/checkout-form-update.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@
'required' => false,
],
'template' => [
'description' => __("Template mode. Can be either 'blank', 'single-step' or 'multi-step'.", 'ultimate-multisite'),
'description' => __("Template mode. Can be either 'blank', 'single-step', 'multi-step' or 'simple'.", 'ultimate-multisite'),
'type' => 'string',
'required' => false,
'enum' => [
'blank',
'single-step',
'multi-step',
'simple',
],
],
'date_created' => [
Expand Down
60 changes: 56 additions & 4 deletions inc/checkout/class-checkout.php
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,16 @@ protected function maybe_create_customer() {
$username = wu_username_from_email($this->request_or_session('email_address'));
}

/*
* Resolve the password: use the submitted value, or generate one
* when the auto_generate_password flag is present in the session.
*/
$password = $this->request_or_session('password');

if ($this->request_or_session('auto_generate_password')) {
$password = wp_generate_password(16, true, false);
}

/*
* If we get to this point,
* we don't have an existing customer.
Expand All @@ -1065,7 +1075,7 @@ protected function maybe_create_customer() {
$customer_data = [
'username' => $username,
'email' => $this->request_or_session('email_address'),
'password' => $this->request_or_session('password'),
'password' => $password,
'email_verification' => $this->get_customer_email_verification_status(),
'signup_form' => $form_slug,
'meta' => [],
Expand Down Expand Up @@ -2113,6 +2123,33 @@ public function get_checkout_variables() {
return apply_filters('wu_get_checkout_variables', $variables, $this);
}

/**
* Returns true when the current checkout form has a password field
* configured with auto_generate_password enabled.
*
* Used to suppress client-side password validation rules when no
* password input is rendered.
*
* @since 2.0.20
* @return bool
*/
protected function form_has_auto_generate_password(): bool {

if ( ! $this->checkout_form) {
return false;
}

foreach ($this->checkout_form->get_settings() as $step) {
foreach (wu_get_isset($step, 'fields', []) as $field) {
if ('password' === wu_get_isset($field, 'type') && ! empty($field['auto_generate_password'])) {
return true;
}
}
}

return false;
}

/**
* Converts the PHP validation rules into a JS-friendly structure.
*
Expand All @@ -2132,6 +2169,15 @@ public function get_js_validation_rules(): array {

$raw_rules = $this->validation_rules();

/*
* When the checkout form uses auto-generated passwords, strip the
* password-related rules from the JS ruleset so the client-side
* validator does not block submission on a field that is never shown.
*/
if ($this->form_has_auto_generate_password()) {
unset($raw_rules['password'], $raw_rules['password_conf'], $raw_rules['valid_password']);
}

/*
* Rules that require a database lookup or complex server-side logic.
* These are skipped for client-side validation.
Expand Down Expand Up @@ -2260,16 +2306,22 @@ public function validation_rules() {
*
* First, let's set upm the general rules:
*/
/*
* When the password field is set to auto-generate, the customer does
* not submit a password value, so we must not require it.
*/
$auto_generate_password = $this->request_or_session('auto_generate_password');

$rules = [
'email_address' => 'required_without:user_id|email|unique:\WP_User,email',
'email_address_confirmation' => 'same:email_address',
'username' => 'required_without:user_id|alpha_dash|min:4|lowercase|unique:\WP_User,login',
'password' => 'required_without:user_id|min:6',
'password_conf' => 'same:password',
'password' => $auto_generate_password ? '' : 'required_without:user_id|min:6',
'password_conf' => $auto_generate_password ? '' : 'same:password',
'template_id' => 'integer|site_template',
'products' => 'products',
'gateway' => '',
'valid_password' => 'accepted',
'valid_password' => $auto_generate_password ? '' : 'accepted',
'billing_country' => 'country|required_with:billing_country',
'billing_zip_code' => 'required_with:billing_zip_code',
'billing_state' => 'state',
Expand Down
47 changes: 39 additions & 8 deletions inc/checkout/signup-fields/class-signup-field-password.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public function get_icon() {
public function defaults() {

return [
'auto_generate_password' => false,
'password_confirm_field' => false,
'password_confirm_label' => __('Confirm Password', 'ultimate-multisite'),
];
Expand Down Expand Up @@ -166,17 +167,33 @@ public function force_attributes() {
public function get_fields() {

return [
'auto_generate_password' => [
'type' => 'toggle',
'title' => __('Auto-generate', 'ultimate-multisite'),
'desc' => __('Check this option to auto-generate a secure password for the customer. The password will be emailed to them after signup.', 'ultimate-multisite'),
'tooltip' => '',
'value' => 0,
'html_attr' => [
'v-model' => 'auto_generate_password',
],
],
'password_strength_meter' => [
'type' => 'toggle',
'title' => __('Display Password Strength Meter', 'ultimate-multisite'),
'desc' => __('Adds a password strength meter below the password field. Enabling this option also enforces passwords to be strong.', 'ultimate-multisite'),
'value' => 1,
'type' => 'toggle',
'title' => __('Display Password Strength Meter', 'ultimate-multisite'),
'desc' => __('Adds a password strength meter below the password field. Enabling this option also enforces passwords to be strong.', 'ultimate-multisite'),
'value' => 1,
'wrapper_html_attr' => [
'v-show' => '!auto_generate_password',
],
],
'password_confirm_field' => [
'type' => 'toggle',
'title' => __('Display Password Confirm Field', 'ultimate-multisite'),
'desc' => __('Adds a "Confirm your Password" field below the default password field to reduce the chance of making a mistake.', 'ultimate-multisite'),
'value' => 1,
'type' => 'toggle',
'title' => __('Display Password Confirm Field', 'ultimate-multisite'),
'desc' => __('Adds a "Confirm your Password" field below the default password field to reduce the chance of making a mistake.', 'ultimate-multisite'),
'value' => 1,
'wrapper_html_attr' => [
'v-show' => '!auto_generate_password',
],
],
];
}
Expand All @@ -197,6 +214,20 @@ public function to_fields_array($attributes) {
return [];
}

/*
* Auto-generate mode: emit a hidden flag so the checkout handler
* knows to generate a password server-side. No visible fields needed.
*/
if (! empty($attributes['auto_generate_password'])) {
return [
'auto_generate_password' => [
'type' => 'hidden',
'id' => 'auto_generate_password',
'value' => '1',
],
];
}

$checkout_fields = [];

$checkout_fields['password'] = [
Expand Down
126 changes: 125 additions & 1 deletion inc/models/class-checkout-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public function validation_rules() {
'allowed_countries' => 'default:',
'thank_you_page_id' => 'integer',
'conversion_snippets' => 'nullable|default:',
'template' => 'in:blank,single-step,multi-step',
'template' => 'in:blank,single-step,multi-step,simple',
];
}

Expand Down Expand Up @@ -527,6 +527,8 @@ public function use_template($template = 'single-step'): void {
$this->set_settings($fields);
} elseif ('single-step' === $template) {
$fields = $this->get_single_step_template();
} elseif ('simple' === $template) {
$fields = $this->get_simple_template();
}

$this->set_settings($fields);
Expand Down Expand Up @@ -641,6 +643,127 @@ private function get_single_step_template() {
return apply_filters('wu_checkout_form_single_step_template', $steps);
}

/**
* Get the contents of the simple template.
*
* A minimal single-step form where the customer only enters their email
* address. Username, password, site title, and site URL are all
* auto-generated. A product must be pre-selected; template selection is
* shown only when no template has been pre-selected via the URL.
*
* @since 2.0.20
* @return array
*/
private function get_simple_template() {

$plan_ids = wu_get_plans(['fields' => 'ids']);

$steps = [
[
'id' => 'checkout',
'name' => __('Checkout', 'ultimate-multisite'),
'desc' => '',
'fields' => [
[
'step' => 'checkout',
'name' => __('Pre-selected Products', 'ultimate-multisite'),
'type' => 'products',
'id' => 'products',
'products' => implode(',', $plan_ids),
],
[
'step' => 'checkout',
'name' => __('Email', 'ultimate-multisite'),
'type' => 'email',
'id' => 'email_address',
'required' => true,
'placeholder' => '',
'tooltip' => '',
],
[
'step' => 'checkout',
'name' => __('Username', 'ultimate-multisite'),
'type' => 'username',
'id' => 'username',
'required' => true,
'placeholder' => '',
'tooltip' => '',
'auto_generate_username' => true,
],
[
'step' => 'checkout',
'name' => __('Password', 'ultimate-multisite'),
'type' => 'password',
'id' => 'password',
'required' => true,
'placeholder' => '',
'tooltip' => '',
'auto_generate_password' => true,
],
[
'step' => 'checkout',
'name' => __('Site Title', 'ultimate-multisite'),
'type' => 'site_title',
'id' => 'site_title',
'required' => true,
'placeholder' => '',
'tooltip' => '',
'auto_generate_site_title' => true,
],
[
'step' => 'checkout',
'name' => __('Site URL', 'ultimate-multisite'),
'type' => 'site_url',
'id' => 'site_url',
'required' => true,
'placeholder' => '',
'tooltip' => '',
'auto_generate_site_url' => true,
],
[
'step' => 'checkout',
'name' => __('Template Selection', 'ultimate-multisite'),
'type' => 'template_selection',
'id' => 'template_selection',
'template_selection_type' => 'all',
'template_selection_template' => 'clean',
'hide_template_selection_when_pre_selected' => true,
],
[
'step' => 'checkout',
'name' => __('Your Order', 'ultimate-multisite'),
'type' => 'order_summary',
'id' => 'order_summary',
'order_summary_template' => 'clean',
'table_columns' => 'simple',
],
[
'step' => 'checkout',
'name' => __('Payment Method', 'ultimate-multisite'),
'type' => 'payment',
'id' => 'payment',
],
[
'step' => 'checkout',
'name' => __('Billing Address', 'ultimate-multisite'),
'type' => 'billing_address',
'id' => 'billing_address',
'required' => true,
'zip_and_country' => '1',
],
[
'step' => 'checkout',
'name' => __('Checkout', 'ultimate-multisite'),
'type' => 'submit_button',
'id' => 'checkout',
],
],
],
];

return apply_filters('wu_checkout_form_simple_template', $steps);
}

/**
* Get the contents of the multi step template.
*
Expand Down Expand Up @@ -1160,6 +1283,7 @@ public function save() {
$step_types = [
'multi-step',
'single-step',
'simple',
];

if ($this->template && in_array($this->template, $step_types, true)) {
Expand Down