feat: Move customer registration to site-level setting
Moved 'Register as site member' from order-level to site-level setting Frontend Changes: 1. Customer Settings - Added new General section - Auto-register customers as site members toggle - Clear description of functionality - Saved to backend via existing API 2. OrderForm - Removed checkbox - Removed registerAsMember state - Removed checkbox UI - Removed register_as_member from payload - Backend now uses site setting Backend Changes: 1. CustomerSettingsProvider.php - Added auto_register_members setting - Default: false (no) - Stored as woonoow_auto_register_members option - Included in get_settings() - Handled in update_settings() 2. OrdersController.php - Removed register_as_member parameter - Now reads from CustomerSettingsProvider - Site-level setting applies to all orders - Consistent behavior across all order creation Benefits: ✅ Site-level control (not per-order) ✅ Consistent customer experience ✅ Easier to manage (one setting) ✅ No UI clutter in order form ✅ Setting persists across all orders Migration: - Old orders with checkbox: No impact - New orders: Use site setting - Default: Disabled (safe default) Result: Admins can now control customer registration site-wide from Customer Settings instead of per-order checkbox
This commit is contained in:
@@ -181,7 +181,6 @@ export default function OrderForm({
|
|||||||
const [paymentMethod, setPaymentMethod] = React.useState(initial?.payment_method_id || initial?.payment_method || '');
|
const [paymentMethod, setPaymentMethod] = React.useState(initial?.payment_method_id || initial?.payment_method || '');
|
||||||
const [shippingMethod, setShippingMethod] = React.useState(initial?.shipping_method_id || initial?.shipping_method || '');
|
const [shippingMethod, setShippingMethod] = React.useState(initial?.shipping_method_id || initial?.shipping_method || '');
|
||||||
const [note, setNote] = React.useState(initial?.customer_note || '');
|
const [note, setNote] = React.useState(initial?.customer_note || '');
|
||||||
const [registerAsMember, setRegisterAsMember] = React.useState(false);
|
|
||||||
const [selectedCustomerId, setSelectedCustomerId] = React.useState<number | null>(null);
|
const [selectedCustomerId, setSelectedCustomerId] = React.useState<number | null>(null);
|
||||||
const [submitting, setSubmitting] = React.useState(false);
|
const [submitting, setSubmitting] = React.useState(false);
|
||||||
|
|
||||||
@@ -452,7 +451,6 @@ export default function OrderForm({
|
|||||||
payment_method: paymentMethod || undefined,
|
payment_method: paymentMethod || undefined,
|
||||||
shipping_method: shippingMethod || undefined,
|
shipping_method: shippingMethod || undefined,
|
||||||
customer_note: note || undefined,
|
customer_note: note || undefined,
|
||||||
register_as_member: registerAsMember,
|
|
||||||
items: itemsEditable ? items : undefined,
|
items: itemsEditable ? items : undefined,
|
||||||
coupons: showCoupons ? validatedCoupons.map(c => c.code) : undefined,
|
coupons: showCoupons ? validatedCoupons.map(c => c.code) : undefined,
|
||||||
};
|
};
|
||||||
@@ -1047,9 +1045,8 @@ export default function OrderForm({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark customer as selected (hide register checkbox)
|
// Mark customer as selected
|
||||||
setSelectedCustomerId(data.user_id);
|
setSelectedCustomerId(data.user_id);
|
||||||
setRegisterAsMember(false);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Customer autofill error:', e);
|
console.error('Customer autofill error:', e);
|
||||||
@@ -1287,27 +1284,6 @@ export default function OrderForm({
|
|||||||
<Textarea value={note} onChange={e=>setNote(e.target.value)} placeholder={__('Write a note for this order…')} />
|
<Textarea value={note} onChange={e=>setNote(e.target.value)} placeholder={__('Write a note for this order…')} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Register as member checkbox (only for new orders and when no existing customer selected) */}
|
|
||||||
{mode === 'create' && !selectedCustomerId && (
|
|
||||||
<div className="rounded border p-4">
|
|
||||||
<div className="flex items-start gap-2">
|
|
||||||
<Checkbox
|
|
||||||
id="register_member"
|
|
||||||
checked={registerAsMember}
|
|
||||||
onCheckedChange={(v) => setRegisterAsMember(Boolean(v))}
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
|
||||||
<Label htmlFor="register_member" className="cursor-pointer">
|
|
||||||
{__('Register customer as site member')}
|
|
||||||
</Label>
|
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
|
||||||
{__('Customer will receive login credentials via email and can track their orders.')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!hideSubmitButton && (
|
{!hideSubmitButton && (
|
||||||
<Button type="submit" disabled={submitting} className="w-full">
|
<Button type="submit" disabled={submitting} className="w-full">
|
||||||
{submitting ? (mode === 'edit' ? __('Saving…') : __('Creating…')) : (mode === 'edit' ? __('Save changes') : __('Create order'))}
|
{submitting ? (mode === 'edit' ? __('Saving…') : __('Creating…')) : (mode === 'edit' ? __('Save changes') : __('Create order'))}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
|||||||
import { formatMoney, getStoreCurrency } from '@/lib/currency';
|
import { formatMoney, getStoreCurrency } from '@/lib/currency';
|
||||||
|
|
||||||
interface CustomerSettings {
|
interface CustomerSettings {
|
||||||
|
auto_register_members: boolean;
|
||||||
vip_min_spent: number;
|
vip_min_spent: number;
|
||||||
vip_min_orders: number;
|
vip_min_orders: number;
|
||||||
vip_timeframe: 'all' | '30' | '90' | '365';
|
vip_timeframe: 'all' | '30' | '90' | '365';
|
||||||
@@ -20,6 +21,7 @@ interface CustomerSettings {
|
|||||||
|
|
||||||
export default function CustomersSettings() {
|
export default function CustomersSettings() {
|
||||||
const [settings, setSettings] = useState<CustomerSettings>({
|
const [settings, setSettings] = useState<CustomerSettings>({
|
||||||
|
auto_register_members: false,
|
||||||
vip_min_spent: 1000,
|
vip_min_spent: 1000,
|
||||||
vip_min_orders: 10,
|
vip_min_orders: 10,
|
||||||
vip_timeframe: 'all',
|
vip_timeframe: 'all',
|
||||||
@@ -113,6 +115,19 @@ export default function CustomersSettings() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<SettingsCard
|
||||||
|
title={__('General')}
|
||||||
|
description={__('General customer settings')}
|
||||||
|
>
|
||||||
|
<ToggleField
|
||||||
|
id="auto_register_members"
|
||||||
|
label={__('Auto-register customers as site members')}
|
||||||
|
description={__('Automatically create WordPress user accounts for new customers when orders are created. Customers will receive login credentials via email and can track their orders.')}
|
||||||
|
checked={settings.auto_register_members}
|
||||||
|
onCheckedChange={(checked) => setSettings({ ...settings, auto_register_members: checked })}
|
||||||
|
/>
|
||||||
|
</SettingsCard>
|
||||||
|
|
||||||
<SettingsCard
|
<SettingsCard
|
||||||
title={__('VIP Customer Qualification')}
|
title={__('VIP Customer Qualification')}
|
||||||
description={__('Define criteria for identifying VIP customers')}
|
description={__('Define criteria for identifying VIP customers')}
|
||||||
|
|||||||
@@ -780,7 +780,10 @@ class OrdersController {
|
|||||||
$shipping_method = sanitize_text_field( $p['shipping_method'] ?? '' ); // e.g. flat_rate:1
|
$shipping_method = sanitize_text_field( $p['shipping_method'] ?? '' ); // e.g. flat_rate:1
|
||||||
$coupons = array_filter( array_map( 'sanitize_text_field', (array) ( $p['coupons'] ?? [] ) ) );
|
$coupons = array_filter( array_map( 'sanitize_text_field', (array) ( $p['coupons'] ?? [] ) ) );
|
||||||
$note = isset( $p['customer_note'] ) ? wp_kses_post( (string) $p['customer_note'] ) : '';
|
$note = isset( $p['customer_note'] ) ? wp_kses_post( (string) $p['customer_note'] ) : '';
|
||||||
$register_member = (bool) ( $p['register_as_member'] ?? false );
|
|
||||||
|
// Get auto-register setting from customer settings (site-level)
|
||||||
|
$customer_settings = \WooNooW\Compat\CustomerSettingsProvider::get_settings();
|
||||||
|
$register_member = $customer_settings['auto_register_members'] ?? false;
|
||||||
|
|
||||||
// Validation: Collect all missing required fields
|
// Validation: Collect all missing required fields
|
||||||
$validation_errors = [];
|
$validation_errors = [];
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ class CustomerSettingsProvider {
|
|||||||
*/
|
*/
|
||||||
public static function get_settings() {
|
public static function get_settings() {
|
||||||
return [
|
return [
|
||||||
|
// General
|
||||||
|
'auto_register_members' => get_option('woonoow_auto_register_members', 'no') === 'yes',
|
||||||
|
|
||||||
// VIP Customer Qualification
|
// VIP Customer Qualification
|
||||||
'vip_min_spent' => floatval(get_option('woonoow_vip_min_spent', 1000)),
|
'vip_min_spent' => floatval(get_option('woonoow_vip_min_spent', 1000)),
|
||||||
'vip_min_orders' => intval(get_option('woonoow_vip_min_orders', 10)),
|
'vip_min_orders' => intval(get_option('woonoow_vip_min_orders', 10)),
|
||||||
@@ -36,6 +39,11 @@ class CustomerSettingsProvider {
|
|||||||
public static function update_settings($settings) {
|
public static function update_settings($settings) {
|
||||||
$updated = true;
|
$updated = true;
|
||||||
|
|
||||||
|
// General settings
|
||||||
|
if (isset($settings['auto_register_members'])) {
|
||||||
|
$updated = $updated && update_option('woonoow_auto_register_members', $settings['auto_register_members'] ? 'yes' : 'no');
|
||||||
|
}
|
||||||
|
|
||||||
// VIP settings
|
// VIP settings
|
||||||
if (isset($settings['vip_min_spent'])) {
|
if (isset($settings['vip_min_spent'])) {
|
||||||
$updated = $updated && update_option('woonoow_vip_min_spent', floatval($settings['vip_min_spent']));
|
$updated = $updated && update_option('woonoow_vip_min_spent', floatval($settings['vip_min_spent']));
|
||||||
|
|||||||
Reference in New Issue
Block a user