diff --git a/inc/admin-pages/class-checkout-form-list-admin-page.php b/inc/admin-pages/class-checkout-form-list-admin-page.php index a8d6ff16..f90a7d50 100644 --- a/inc/admin-pages/class-checkout-form-list-admin-page.php +++ b/inc/admin-pages/class-checkout-form-list-admin-page.php @@ -139,6 +139,10 @@ public function render_add_new_checkout_form_modal(): void { 'title' => __('Multi-Step', 'ultimate-multisite'), 'icon' => 'dashicons-before dashicons-excerpt-view', ], + 'simple' => [ + 'title' => __('Simple (Email Only)', 'ultimate-multisite'), + 'icon' => 'dashicons-before dashicons-email-alt', + ], 'blank' => [ 'title' => __('Blank', 'ultimate-multisite'), 'icon' => 'dashicons-before dashicons-admin-page', diff --git a/inc/checkout/class-checkout.php b/inc/checkout/class-checkout.php index 9c38b666..3ab2f702 100644 --- a/inc/checkout/class-checkout.php +++ b/inc/checkout/class-checkout.php @@ -2140,8 +2140,41 @@ public function get_checkout_variables() { */ public function get_js_validation_rules(): array { + /* + * When the checkout form has a password field with auto_generate_password + * enabled, the hidden flag is submitted with the form but is not present + * in the GET request at render time. We detect this from the form settings + * so the JS validator knows to skip password rules without needing the + * flag to be in the request. + */ + $form_auto_generates_password = false; + + if ($this->checkout_form) { + $password_fields = $this->checkout_form->get_all_fields_by_type('password'); + + foreach ($password_fields as $field) { + if (! empty($field['auto_generate_password'])) { + $form_auto_generates_password = true; + break; + } + } + } + $raw_rules = $this->validation_rules(); + /* + * When the form auto-generates the password, clear the password rules + * so the JS validator does not require a password field that is not + * rendered. The server-side validation_rules() already handles this via + * request_or_session(), but at render time the flag is not in the request + * so we must detect it from the form settings instead. + */ + if ($form_auto_generates_password) { + $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. diff --git a/inc/class-wp-ultimo.php b/inc/class-wp-ultimo.php index 67eb9d83..0017b838 100644 --- a/inc/class-wp-ultimo.php +++ b/inc/class-wp-ultimo.php @@ -116,6 +116,21 @@ final class WP_Ultimo { */ public function init(): void { + /* + * Ensure wu_dmtable is registered on $wpdb early in the plugin load. + * Domain_Mapping::startup() only runs during the sunrise/mu-plugins phase + * (it returns early if muplugins_loaded has already fired). Without this, + * any code that accesses $wpdb->wu_dmtable before Domain_Mapping::startup() + * runs triggers a PHP notice about an undefined property, which causes + * "headers already sent" errors that break admin redirects and AJAX. + */ + global $wpdb; + + if (empty($wpdb->wu_dmtable)) { + $wpdb->wu_dmtable = $wpdb->base_prefix . 'wu_domain_mappings'; + $wpdb->ms_global_tables[] = 'wu_domain_mappings'; + } + add_filter('extra_plugin_headers', [$this, 'register_addon_headers']); add_action('admin_init', [$this, 'check_addon_compatibility']); diff --git a/inc/models/class-domain.php b/inc/models/class-domain.php index bcdc5889..d30f2ac8 100644 --- a/inc/models/class-domain.php +++ b/inc/models/class-domain.php @@ -694,6 +694,16 @@ public static function get_by_domain($domains) { $placeholders_in = implode(',', $placeholders); + /* + * Ensure wu_dmtable is set on $wpdb. In normal (non-sunrise) plugin load + * paths Domain_Mapping::startup() may not have run yet, which causes a + * PHP notice about an undefined property. Set it here as a fallback so + * the query can proceed without warnings. + */ + if (empty($wpdb->wu_dmtable)) { + $wpdb->wu_dmtable = $wpdb->base_prefix . 'wu_domain_mappings'; + } + // Prepare the query $query = "SELECT * FROM {$wpdb->wu_dmtable} WHERE domain IN ($placeholders_in) ORDER BY primary_domain DESC, active DESC, secure DESC LIMIT 1";