| 1 |
<?php |
| 2 |
/** |
| 3 |
* Delivery & Pickup — Option group definitions. |
| 4 |
* |
| 5 |
* @package Merchant |
| 6 |
*/ |
| 7 |
|
| 8 |
if ( ! defined( 'ABSPATH' ) ) { |
| 9 |
exit; // Exit if accessed directly. |
| 10 |
} |
| 11 |
|
| 12 |
// Choices used by more than one field, built once. |
| 13 |
$weekday_choices = Merchant_Admin_Options::get_weekday_choices(); |
| 14 |
$zone_choices = Merchant_Admin_Options::get_shipping_zone_select2_choices(); |
| 15 |
$category_choices = Merchant_Admin_Options::get_category_select2_choices(); |
| 16 |
$brand_choices = Merchant_Admin_Options::get_brand_select2_choices(); |
| 17 |
|
| 18 |
// Time-only preset; stored value is always H:i. |
| 19 |
$time_picker = array( |
| 20 |
'onlyTimepicker' => true, |
| 21 |
'timeFormat' => 'HH:mm', |
| 22 |
'minDate' => '', |
| 23 |
); |
| 24 |
|
| 25 |
// Subject: short single-value tags only; rest goes in the body. |
| 26 |
$subject_merge_tags = array( |
| 27 |
'{customer_name}' => esc_html__( 'the customer’s first name', 'merchant' ), |
| 28 |
'{order_number}' => esc_html__( 'the order number', 'merchant' ), |
| 29 |
'{fulfilment_type}' => esc_html__( 'your Delivery or Pickup label, whichever the order chose', 'merchant' ), |
| 30 |
'{delivery_date}' => esc_html__( 'the booking date, in the format you set for the checkout', 'merchant' ), |
| 31 |
'{delivery_slot}' => esc_html__( 'the booking slot, as 09:00–11:00', 'merchant' ), |
| 32 |
'{location_name}' => esc_html__( 'the pickup location’s name, empty on a delivery', 'merchant' ), |
| 33 |
); |
| 34 |
|
| 35 |
// Out of subject: long text and links read as spam. |
| 36 |
$body_only_tags = array( |
| 37 |
'{location_address}' => esc_html__( 'the pickup location’s address, empty on a delivery', 'merchant' ), |
| 38 |
'{collection_notes}' => esc_html__( 'the collection notes you set on the pickup location', 'merchant' ), |
| 39 |
'{reschedule_link}' => esc_html__( 'the web address the customer changes the booking at, empty while self-service rescheduling is off', 'merchant' ), |
| 40 |
'{ics_link}' => esc_html__( 'the web address the calendar file downloads from, empty while the calendar download is off', 'merchant' ), |
| 41 |
); |
| 42 |
|
| 43 |
$body_merge_tags = array_merge( |
| 44 |
$subject_merge_tags, |
| 45 |
$body_only_tags, |
| 46 |
array( |
| 47 |
'{booking_details}' => esc_html__( 'a table of every part of the order, in the columns you ticked under Order Emails. Reach for it when orders can arrive in more than one delivery, since the tags above only describe whichever part arrives first', 'merchant' ), |
| 48 |
'{order_details}' => esc_html__( 'the items, quantities and totals, the way WooCommerce prints them in its own order emails', 'merchant' ), |
| 49 |
) |
| 50 |
); |
| 51 |
|
| 52 |
// Subject may show where it moved; details stay in message. |
| 53 |
$subject_moved_tags = array( |
| 54 |
'{previous_delivery}' => esc_html__( 'the date and slot the booking moved from, empty when the order had no booking until now', 'merchant' ), |
| 55 |
'{new_delivery}' => esc_html__( 'the date and slot it moved to', 'merchant' ), |
| 56 |
); |
| 57 |
|
| 58 |
$moved_merge_tags = array_merge( |
| 59 |
$subject_moved_tags, |
| 60 |
array( |
| 61 |
'{moved_booking}' => esc_html__( 'what moved (the items in that part, or the whole order when it arrives in one piece)', 'merchant' ), |
| 62 |
'{moved_part}' => esc_html__( 'the number of the part that moved, empty unless the order arrives in several', 'merchant' ), |
| 63 |
) |
| 64 |
); |
| 65 |
|
| 66 |
/** |
| 67 |
* One "Show more" panel listing the tags a single field reads. |
| 68 |
* |
| 69 |
* @param array<string, string> $tags Tag to description. |
| 70 |
* |
| 71 |
* @return string |
| 72 |
*/ |
| 73 |
$merge_tag_panel = static function ( array $tags ): string { |
| 74 |
$lines = array(); |
| 75 |
|
| 76 |
foreach ( $tags as $tag => $description ) { |
| 77 |
$lines[] = '<strong>' . $tag . ':</strong> ' . $description; |
| 78 |
} |
| 79 |
|
| 80 |
return implode( '<br>', $lines ); |
| 81 |
}; |
| 82 |
|
| 83 |
return array( |
| 84 |
|
| 85 |
array( |
| 86 |
'title' => esc_html__( 'Delivery Schedules', 'merchant' ), |
| 87 |
'module' => Merchant_Delivery_Pickup::MODULE_ID, |
| 88 |
'fields' => array( |
| 89 |
array( |
| 90 |
'id' => 'schedules', |
| 91 |
'type' => 'flexible_content', |
| 92 |
'button_label' => esc_html__( 'Add New Schedule', 'merchant' ), |
| 93 |
'style' => Merchant_Delivery_Pickup::MODULE_ID . '-style default', |
| 94 |
'sorting' => true, |
| 95 |
'duplicate' => true, |
| 96 |
'accordion' => true, |
| 97 |
'layouts' => array( |
| 98 |
'schedule' => array( |
| 99 |
'title' => esc_html__( 'Schedule', 'merchant' ), |
| 100 |
'title-field' => 'schedule_title', |
| 101 |
'status-field' => 'schedule_status', |
| 102 |
'fields' => array( |
| 103 |
array( |
| 104 |
'id' => 'schedule_status', |
| 105 |
'type' => 'select', |
| 106 |
'title' => esc_html__( 'Status', 'merchant' ), |
| 107 |
'options' => array( |
| 108 |
'active' => esc_html__( 'Active', 'merchant' ), |
| 109 |
'inactive' => esc_html__( 'Inactive', 'merchant' ), |
| 110 |
), |
| 111 |
'default' => 'active', |
| 112 |
'ai_meta' => array( |
| 113 |
'usage_hint' => 'Controls whether this schedule is active or inactive. Set to active to enable, inactive to disable.', |
| 114 |
), |
| 115 |
), |
| 116 |
array( |
| 117 |
'id' => 'schedule_title', |
| 118 |
'type' => 'text', |
| 119 |
'title' => esc_html__( 'Schedule name', 'merchant' ), |
| 120 |
'default' => esc_html__( 'Standard delivery', 'merchant' ), |
| 121 |
), |
| 122 |
array( |
| 123 |
'id' => 'fulfilment_type', |
| 124 |
'type' => 'radio', |
| 125 |
'title' => esc_html__( 'Fulfilment type', 'merchant' ), |
| 126 |
'options' => array( |
| 127 |
'delivery' => esc_html__( 'Delivery', 'merchant' ), |
| 128 |
'pickup' => esc_html__( 'Pickup', 'merchant' ), |
| 129 |
), |
| 130 |
'default' => 'delivery', |
| 131 |
'ai_meta' => array( |
| 132 |
'usage_hint' => 'Whether this schedule offers delivery to the customer address or collection from a pickup location.', |
| 133 |
), |
| 134 |
), |
| 135 |
|
| 136 |
array( |
| 137 |
'id' => 'availability_divider', |
| 138 |
'type' => 'divider', |
| 139 |
'title' => esc_html__( 'Availability', 'merchant' ), |
| 140 |
), |
| 141 |
array( |
| 142 |
'id' => 'available_days', |
| 143 |
'type' => 'checkbox_multiple', |
| 144 |
'title' => esc_html__( 'Available days', 'merchant' ), |
| 145 |
'options' => $weekday_choices, |
| 146 |
'default' => array( 'mon', 'tue', 'wed', 'thu', 'fri' ), |
| 147 |
'conditions' => array( |
| 148 |
'relation' => 'AND', |
| 149 |
'terms' => array( |
| 150 |
array( |
| 151 |
'field' => 'slot_mode', |
| 152 |
'operator' => 'in', |
| 153 |
'value' => array( 'time_slots', 'date_only' ), |
| 154 |
), |
| 155 |
), |
| 156 |
), |
| 157 |
), |
| 158 |
array( |
| 159 |
'id' => 'lead_time', |
| 160 |
'type' => 'number', |
| 161 |
'title' => esc_html__( 'Lead time', 'merchant' ), |
| 162 |
'desc' => esc_html__( 'Delay bookings by this much so you have time to prepare. 1 day hides today, 2 days hides today and tomorrow.', 'merchant' ), |
| 163 |
'default' => 1, |
| 164 |
'min' => 0, |
| 165 |
'step' => 1, |
| 166 |
'conditions' => array( |
| 167 |
'relation' => 'AND', |
| 168 |
'terms' => array( |
| 169 |
array( |
| 170 |
'field' => 'slot_mode', |
| 171 |
'operator' => 'in', |
| 172 |
'value' => array( 'time_slots', 'date_only' ), |
| 173 |
), |
| 174 |
), |
| 175 |
), |
| 176 |
), |
| 177 |
array( |
| 178 |
'id' => 'lead_time_unit', |
| 179 |
'type' => 'select', |
| 180 |
'title' => esc_html__( 'Lead time unit', 'merchant' ), |
| 181 |
'options' => array( |
| 182 |
'hours' => esc_html__( 'Hours', 'merchant' ), |
| 183 |
'days' => esc_html__( 'Days', 'merchant' ), |
| 184 |
), |
| 185 |
'default' => 'days', |
| 186 |
'conditions' => array( |
| 187 |
'relation' => 'AND', |
| 188 |
'terms' => array( |
| 189 |
array( |
| 190 |
'field' => 'slot_mode', |
| 191 |
'operator' => 'in', |
| 192 |
'value' => array( 'time_slots', 'date_only' ), |
| 193 |
), |
| 194 |
), |
| 195 |
), |
| 196 |
), |
| 197 |
array( |
| 198 |
'id' => 'max_days_ahead', |
| 199 |
'type' => 'number', |
| 200 |
'title' => esc_html__( 'Bookable window (days)', 'merchant' ), |
| 201 |
'desc' => esc_html__( 'How far into the future customers can book.', 'merchant' ), |
| 202 |
'default' => 14, |
| 203 |
'min' => 1, |
| 204 |
'step' => 1, |
| 205 |
'conditions' => array( |
| 206 |
'relation' => 'AND', |
| 207 |
'terms' => array( |
| 208 |
array( |
| 209 |
'field' => 'slot_mode', |
| 210 |
'operator' => 'in', |
| 211 |
'value' => array( 'time_slots', 'date_only' ), |
| 212 |
), |
| 213 |
), |
| 214 |
), |
| 215 |
), |
| 216 |
array( |
| 217 |
'id' => 'cutoff_time', |
| 218 |
'type' => 'date_time', |
| 219 |
'title' => esc_html__( 'Daily cut-off time', 'merchant' ), |
| 220 |
'desc' => esc_html__( 'Orders placed after this time move to the next available day.', 'merchant' ), |
| 221 |
'placeholder' => '14:00', |
| 222 |
'default' => '14:00', |
| 223 |
'options' => $time_picker, |
| 224 |
'conditions' => array( |
| 225 |
'relation' => 'AND', |
| 226 |
'terms' => array( |
| 227 |
array( |
| 228 |
'field' => 'slot_mode', |
| 229 |
'operator' => 'in', |
| 230 |
'value' => array( 'time_slots', 'date_only' ), |
| 231 |
), |
| 232 |
), |
| 233 |
), |
| 234 |
), |
| 235 |
array( |
| 236 |
'id' => 'allow_same_day', |
| 237 |
'type' => 'switcher', |
| 238 |
'title' => esc_html__( 'Allow same-day', 'merchant' ), |
| 239 |
'default' => 0, |
| 240 |
'conditions' => array( |
| 241 |
'relation' => 'AND', |
| 242 |
'terms' => array( |
| 243 |
array( |
| 244 |
'field' => 'slot_mode', |
| 245 |
'operator' => 'in', |
| 246 |
'value' => array( 'time_slots', 'date_only' ), |
| 247 |
), |
| 248 |
), |
| 249 |
), |
| 250 |
), |
| 251 |
array( |
| 252 |
'id' => 'blackout_dates', |
| 253 |
'type' => 'sortable_repeater', |
| 254 |
'title' => esc_html__( 'Blackout dates', 'merchant' ), |
| 255 |
'desc' => esc_html__( 'Dates you never deliver or open, one per row, in YYYY-MM-DD format.', 'merchant' ), |
| 256 |
'button_label' => esc_html__( 'Add Date', 'merchant' ), |
| 257 |
'default' => array(), |
| 258 |
'conditions' => array( |
| 259 |
'relation' => 'AND', |
| 260 |
'terms' => array( |
| 261 |
array( |
| 262 |
'field' => 'slot_mode', |
| 263 |
'operator' => 'in', |
| 264 |
'value' => array( 'time_slots', 'date_only' ), |
| 265 |
), |
| 266 |
), |
| 267 |
), |
| 268 |
), |
| 269 |
array( |
| 270 |
'id' => 'repeat_blackouts_yearly', |
| 271 |
'type' => 'switcher', |
| 272 |
'title' => esc_html__( 'Repeat blackout dates every year', 'merchant' ), |
| 273 |
'default' => 0, |
| 274 |
'conditions' => array( |
| 275 |
'relation' => 'AND', |
| 276 |
'terms' => array( |
| 277 |
array( |
| 278 |
'field' => 'slot_mode', |
| 279 |
'operator' => 'in', |
| 280 |
'value' => array( 'time_slots', 'date_only' ), |
| 281 |
), |
| 282 |
), |
| 283 |
), |
| 284 |
), |
| 285 |
|
| 286 |
array( |
| 287 |
'id' => 'slots_divider', |
| 288 |
'type' => 'divider', |
| 289 |
'title' => esc_html__( 'Time slots & capacity', 'merchant' ), |
| 290 |
), |
| 291 |
array( |
| 292 |
'id' => 'slot_mode', |
| 293 |
'type' => 'select', |
| 294 |
'title' => esc_html__( 'What customers pick', 'merchant' ), |
| 295 |
'options' => array( |
| 296 |
'time_slots' => esc_html__( 'Date and time slot', 'merchant' ), |
| 297 |
'date_only' => esc_html__( 'Date only', 'merchant' ), |
| 298 |
'fulfilment' => esc_html__( 'Neither (no date to choose)', 'merchant' ), |
| 299 |
), |
| 300 |
'default' => 'time_slots', |
| 301 |
'desc' => esc_html__( 'Pick the last option when you cannot commit to a day yet. Customers choose delivery or collection and you arrange the timing with them. Capacity limits, reminders and rescheduling all need a date, so they do not apply.', 'merchant' ), |
| 302 |
), |
| 303 |
array( |
| 304 |
'id' => 'slot_window_start', |
| 305 |
'type' => 'date_time', |
| 306 |
'title' => esc_html__( 'Slots start at', 'merchant' ), |
| 307 |
'placeholder' => '09:00', |
| 308 |
'default' => '09:00', |
| 309 |
'options' => $time_picker, |
| 310 |
'conditions' => array( |
| 311 |
'relation' => 'AND', |
| 312 |
'terms' => array( |
| 313 |
array( |
| 314 |
'field' => 'slot_mode', |
| 315 |
'operator' => '===', |
| 316 |
'value' => 'time_slots', |
| 317 |
), |
| 318 |
), |
| 319 |
), |
| 320 |
), |
| 321 |
array( |
| 322 |
'id' => 'slot_window_end', |
| 323 |
'type' => 'date_time', |
| 324 |
'title' => esc_html__( 'Slots end at', 'merchant' ), |
| 325 |
'placeholder' => '18:00', |
| 326 |
'default' => '18:00', |
| 327 |
'options' => $time_picker, |
| 328 |
'conditions' => array( |
| 329 |
'relation' => 'AND', |
| 330 |
'terms' => array( |
| 331 |
array( |
| 332 |
'field' => 'slot_mode', |
| 333 |
'operator' => '===', |
| 334 |
'value' => 'time_slots', |
| 335 |
), |
| 336 |
), |
| 337 |
), |
| 338 |
), |
| 339 |
array( |
| 340 |
'id' => 'slot_duration', |
| 341 |
'type' => 'select', |
| 342 |
'title' => esc_html__( 'Slot length', 'merchant' ), |
| 343 |
'options' => Merchant_Delivery_Pickup_Choices::slot_durations(), |
| 344 |
'default' => '120', |
| 345 |
'conditions' => array( |
| 346 |
'relation' => 'AND', |
| 347 |
'terms' => array( |
| 348 |
array( |
| 349 |
'field' => 'slot_mode', |
| 350 |
'operator' => '===', |
| 351 |
'value' => 'time_slots', |
| 352 |
), |
| 353 |
), |
| 354 |
), |
| 355 |
), |
| 356 |
array( |
| 357 |
'id' => 'capacity_per_day', |
| 358 |
'type' => 'number', |
| 359 |
'title' => esc_html__( 'Orders per day', 'merchant' ), |
| 360 |
'desc' => esc_html__( 'Leave at 0 for unlimited.', 'merchant' ), |
| 361 |
'default' => 0, |
| 362 |
'min' => 0, |
| 363 |
'step' => 1, |
| 364 |
'conditions' => array( |
| 365 |
'relation' => 'AND', |
| 366 |
'terms' => array( |
| 367 |
array( |
| 368 |
'field' => 'slot_mode', |
| 369 |
'operator' => 'in', |
| 370 |
'value' => array( 'time_slots', 'date_only' ), |
| 371 |
), |
| 372 |
), |
| 373 |
), |
| 374 |
), |
| 375 |
array( |
| 376 |
'id' => 'capacity_per_slot', |
| 377 |
'type' => 'number', |
| 378 |
'title' => esc_html__( 'Orders per slot', 'merchant' ), |
| 379 |
'desc' => esc_html__( 'Leave at 0 for unlimited.', 'merchant' ), |
| 380 |
'default' => 0, |
| 381 |
'min' => 0, |
| 382 |
'step' => 1, |
| 383 |
'conditions' => array( |
| 384 |
'relation' => 'AND', |
| 385 |
'terms' => array( |
| 386 |
array( |
| 387 |
'field' => 'slot_mode', |
| 388 |
'operator' => '===', |
| 389 |
'value' => 'time_slots', |
| 390 |
), |
| 391 |
), |
| 392 |
), |
| 393 |
), |
| 394 |
array( |
| 395 |
'id' => 'show_remaining', |
| 396 |
'type' => 'switcher', |
| 397 |
'title' => esc_html__( 'Show how many places are left', 'merchant' ), |
| 398 |
'desc' => esc_html__( 'Adds a "2 left" badge to slots that are nearly full.', 'merchant' ), |
| 399 |
'default' => 1, |
| 400 |
'conditions' => array( |
| 401 |
'relation' => 'AND', |
| 402 |
'terms' => array( |
| 403 |
array( |
| 404 |
'field' => 'slot_mode', |
| 405 |
'operator' => 'in', |
| 406 |
'value' => array( 'time_slots', 'date_only' ), |
| 407 |
), |
| 408 |
), |
| 409 |
), |
| 410 |
), |
| 411 |
array( |
| 412 |
'id' => 'remaining_threshold', |
| 413 |
'type' => 'number', |
| 414 |
'title' => esc_html__( 'Show the badge when places left are this many or fewer', 'merchant' ), |
| 415 |
'default' => 3, |
| 416 |
'min' => 1, |
| 417 |
'step' => 1, |
| 418 |
'conditions' => array( |
| 419 |
'relation' => 'AND', |
| 420 |
'terms' => array( |
| 421 |
array( |
| 422 |
'field' => 'show_remaining', |
| 423 |
'operator' => '===', |
| 424 |
'value' => true, |
| 425 |
), |
| 426 |
), |
| 427 |
), |
| 428 |
), |
| 429 |
|
| 430 |
array( |
| 431 |
'id' => 'pricing_divider', |
| 432 |
'type' => 'divider', |
| 433 |
'title' => esc_html__( 'Pricing', 'merchant' ), |
| 434 |
), |
| 435 |
array( |
| 436 |
'id' => 'charge_fee', |
| 437 |
'type' => 'switcher', |
| 438 |
'title' => esc_html__( 'Charge for this schedule', 'merchant' ), |
| 439 |
'default' => 0, |
| 440 |
), |
| 441 |
array( |
| 442 |
'id' => 'fee_type', |
| 443 |
'type' => 'select', |
| 444 |
'title' => esc_html__( 'Charge type', 'merchant' ), |
| 445 |
'options' => array( |
| 446 |
'fixed' => esc_html__( 'Fixed amount', 'merchant' ), |
| 447 |
'percentage' => esc_html__( 'Percentage of the cart subtotal, after discounts', 'merchant' ), |
| 448 |
'per_item' => esc_html__( 'Amount per item', 'merchant' ), |
| 449 |
), |
| 450 |
'default' => 'fixed', |
| 451 |
'conditions' => array( |
| 452 |
'relation' => 'AND', |
| 453 |
'terms' => array( |
| 454 |
array( |
| 455 |
'field' => 'charge_fee', |
| 456 |
'operator' => '===', |
| 457 |
'value' => true, |
| 458 |
), |
| 459 |
), |
| 460 |
), |
| 461 |
), |
| 462 |
array( |
| 463 |
'id' => 'fee_amount', |
| 464 |
'type' => 'number', |
| 465 |
'title' => esc_html__( 'Amount', 'merchant' ), |
| 466 |
'default' => 0, |
| 467 |
'min' => 0, |
| 468 |
'step' => 0.01, |
| 469 |
'conditions' => array( |
| 470 |
'relation' => 'AND', |
| 471 |
'terms' => array( |
| 472 |
array( |
| 473 |
'field' => 'charge_fee', |
| 474 |
'operator' => '===', |
| 475 |
'value' => true, |
| 476 |
), |
| 477 |
), |
| 478 |
), |
| 479 |
), |
| 480 |
array( |
| 481 |
'id' => 'same_day_fee', |
| 482 |
'type' => 'number', |
| 483 |
'title' => esc_html__( 'Same-day surcharge', 'merchant' ), |
| 484 |
'desc' => esc_html__( 'Added on top when the customer picks today.', 'merchant' ), |
| 485 |
'default' => 0, |
| 486 |
'min' => 0, |
| 487 |
'step' => 0.01, |
| 488 |
'conditions' => array( |
| 489 |
'relation' => 'AND', |
| 490 |
'terms' => array( |
| 491 |
array( |
| 492 |
'field' => 'charge_fee', |
| 493 |
'operator' => '===', |
| 494 |
'value' => true, |
| 495 |
), |
| 496 |
array( |
| 497 |
'field' => 'allow_same_day', |
| 498 |
'operator' => '===', |
| 499 |
'value' => true, |
| 500 |
), |
| 501 |
), |
| 502 |
), |
| 503 |
), |
| 504 |
array( |
| 505 |
'id' => 'weekend_fee', |
| 506 |
'type' => 'number', |
| 507 |
'title' => esc_html__( 'Weekend surcharge', 'merchant' ), |
| 508 |
'default' => 0, |
| 509 |
'min' => 0, |
| 510 |
'step' => 0.01, |
| 511 |
'conditions' => array( |
| 512 |
'relation' => 'AND', |
| 513 |
'terms' => array( |
| 514 |
array( |
| 515 |
'field' => 'charge_fee', |
| 516 |
'operator' => '===', |
| 517 |
'value' => true, |
| 518 |
), |
| 519 |
), |
| 520 |
), |
| 521 |
), |
| 522 |
array( |
| 523 |
'id' => 'free_over_cart_total', |
| 524 |
'type' => 'number', |
| 525 |
'title' => esc_html__( 'Free when the cart reaches', 'merchant' ), |
| 526 |
'desc' => esc_html__( 'Checked against the subtotal of the items going the same way, after discounts and excluding tax, so items being collected do not buy free delivery. Leave at 0 to always charge.', 'merchant' ), |
| 527 |
'default' => 0, |
| 528 |
'min' => 0, |
| 529 |
'step' => 0.01, |
| 530 |
'conditions' => array( |
| 531 |
'relation' => 'AND', |
| 532 |
'terms' => array( |
| 533 |
array( |
| 534 |
'field' => 'charge_fee', |
| 535 |
'operator' => '===', |
| 536 |
'value' => true, |
| 537 |
), |
| 538 |
), |
| 539 |
), |
| 540 |
), |
| 541 |
array( |
| 542 |
'id' => 'fee_taxable', |
| 543 |
'type' => 'switcher', |
| 544 |
'title' => esc_html__( 'Charge tax on the fee', 'merchant' ), |
| 545 |
'default' => 1, |
| 546 |
'conditions' => array( |
| 547 |
'relation' => 'AND', |
| 548 |
'terms' => array( |
| 549 |
array( |
| 550 |
'field' => 'charge_fee', |
| 551 |
'operator' => '===', |
| 552 |
'value' => true, |
| 553 |
), |
| 554 |
), |
| 555 |
), |
| 556 |
), |
| 557 |
array( |
| 558 |
'id' => 'fee_tax_class', |
| 559 |
'type' => 'select', |
| 560 |
'title' => esc_html__( 'Tax class', 'merchant' ), |
| 561 |
'options' => Merchant_Delivery_Pickup_Choices::tax_classes(), |
| 562 |
'default' => 'inherit', |
| 563 |
'conditions' => array( |
| 564 |
'relation' => 'AND', |
| 565 |
'terms' => array( |
| 566 |
array( |
| 567 |
'field' => 'charge_fee', |
| 568 |
'operator' => '===', |
| 569 |
'value' => true, |
| 570 |
), |
| 571 |
array( |
| 572 |
'field' => 'fee_taxable', |
| 573 |
'operator' => '===', |
| 574 |
'value' => true, |
| 575 |
), |
| 576 |
), |
| 577 |
), |
| 578 |
), |
| 579 |
|
| 580 |
array( |
| 581 |
'id' => 'eligibility_divider', |
| 582 |
'type' => 'divider', |
| 583 |
'title' => esc_html__( 'Who gets this schedule', 'merchant' ), |
| 584 |
), |
| 585 |
array( |
| 586 |
'id' => 'eligibility_info', |
| 587 |
'type' => 'info', |
| 588 |
'content' => esc_html__( 'Leave everything untouched to offer it to every cart.', 'merchant' ), |
| 589 |
), |
| 590 |
array( |
| 591 |
'id' => 'rules_to_display', |
| 592 |
'type' => 'select', |
| 593 |
'title' => esc_html__( 'Applies to', 'merchant' ), |
| 594 |
'options' => array( |
| 595 |
'all' => esc_html__( 'All Products', 'merchant' ), |
| 596 |
'products' => esc_html__( 'Specific Products', 'merchant' ), |
| 597 |
'categories' => esc_html__( 'Specific Categories', 'merchant' ), |
| 598 |
'tags' => esc_html__( 'Specific Tags', 'merchant' ), |
| 599 |
'brands' => esc_html__( 'Specific Brands', 'merchant' ), |
| 600 |
), |
| 601 |
'default' => 'all', |
| 602 |
'ai_meta' => array( |
| 603 |
'semantic_group' => 'product_targeting', |
| 604 |
'usage_hint' => 'Controls which products this schedule applies to. Set this BEFORE setting product_ids, category_slugs, tag_slugs or brand_slugs — those fields are conditional on this value.', |
| 605 |
), |
| 606 |
), |
| 607 |
array( |
| 608 |
'id' => 'product_ids', |
| 609 |
'type' => 'products_selector', |
| 610 |
'title' => esc_html__( 'Products', 'merchant' ), |
| 611 |
'multiple' => true, |
| 612 |
'desc' => esc_html__( 'Only carts containing these products can use the schedule.', 'merchant' ), |
| 613 |
'conditions' => array( |
| 614 |
'relation' => 'AND', |
| 615 |
'terms' => array( |
| 616 |
array( |
| 617 |
'field' => 'rules_to_display', |
| 618 |
'operator' => '===', |
| 619 |
'value' => 'products', |
| 620 |
), |
| 621 |
), |
| 622 |
), |
| 623 |
'allowed_types' => array( 'simple', 'variable' ), |
| 624 |
'ai_meta' => array( |
| 625 |
'entity' => 'product', |
| 626 |
'value_format' => 'product_id', |
| 627 |
'semantic_group' => 'product_targeting', |
| 628 |
'usage_hint' => 'Use when targeting specific products. Requires rules_to_display=products.', |
| 629 |
), |
| 630 |
), |
| 631 |
array( |
| 632 |
'id' => 'category_slugs', |
| 633 |
'type' => 'select_ajax', |
| 634 |
'title' => esc_html__( 'Categories', 'merchant' ), |
| 635 |
'source' => 'options', |
| 636 |
'multiple' => true, |
| 637 |
'options' => $category_choices, |
| 638 |
'placeholder' => esc_html__( 'Select categories', 'merchant' ), |
| 639 |
'conditions' => array( |
| 640 |
'relation' => 'AND', |
| 641 |
'terms' => array( |
| 642 |
array( |
| 643 |
'field' => 'rules_to_display', |
| 644 |
'operator' => '===', |
| 645 |
'value' => 'categories', |
| 646 |
), |
| 647 |
), |
| 648 |
), |
| 649 |
'ai_meta' => array( |
| 650 |
'entity' => 'category', |
| 651 |
'taxonomy' => 'product_cat', |
| 652 |
'value_format' => 'slug', |
| 653 |
'semantic_group' => 'product_targeting', |
| 654 |
'usage_hint' => 'Use when targeting products by category. Requires rules_to_display=categories.', |
| 655 |
), |
| 656 |
), |
| 657 |
array( |
| 658 |
'id' => 'tag_slugs', |
| 659 |
'type' => 'select_ajax', |
| 660 |
'title' => esc_html__( 'Tags', 'merchant' ), |
| 661 |
'source' => 'options', |
| 662 |
'multiple' => true, |
| 663 |
'options' => Merchant_Admin_Options::get_tag_select2_choices(), |
| 664 |
'placeholder' => esc_html__( 'Select tags', 'merchant' ), |
| 665 |
'conditions' => array( |
| 666 |
'relation' => 'AND', |
| 667 |
'terms' => array( |
| 668 |
array( |
| 669 |
'field' => 'rules_to_display', |
| 670 |
'operator' => '===', |
| 671 |
'value' => 'tags', |
| 672 |
), |
| 673 |
), |
| 674 |
), |
| 675 |
), |
| 676 |
array( |
| 677 |
'id' => 'brand_slugs', |
| 678 |
'type' => 'select_ajax', |
| 679 |
'title' => esc_html__( 'Brands', 'merchant' ), |
| 680 |
'source' => 'options', |
| 681 |
'multiple' => true, |
| 682 |
'options' => $brand_choices, |
| 683 |
'placeholder' => esc_html__( 'Select brands', 'merchant' ), |
| 684 |
'conditions' => array( |
| 685 |
'relation' => 'AND', |
| 686 |
'terms' => array( |
| 687 |
array( |
| 688 |
'field' => 'rules_to_display', |
| 689 |
'operator' => '===', |
| 690 |
'value' => 'brands', |
| 691 |
), |
| 692 |
), |
| 693 |
), |
| 694 |
), |
| 695 |
array( |
| 696 |
'id' => 'enable_exclusions', |
| 697 |
'type' => 'switcher', |
| 698 |
'title' => esc_html__( 'Exclude some products', 'merchant' ), |
| 699 |
'desc' => esc_html__( 'Carts containing an excluded product cannot use this schedule.', 'merchant' ), |
| 700 |
'default' => 0, |
| 701 |
), |
| 702 |
// Excluded axis hides when "Applies to" already targets it. |
| 703 |
array( |
| 704 |
'id' => 'excluded_product_ids', |
| 705 |
'type' => 'products_selector', |
| 706 |
'title' => esc_html__( 'Excluded products', 'merchant' ), |
| 707 |
'multiple' => true, |
| 708 |
'conditions' => array( |
| 709 |
'relation' => 'AND', |
| 710 |
'terms' => array( |
| 711 |
array( |
| 712 |
'field' => 'enable_exclusions', |
| 713 |
'operator' => '===', |
| 714 |
'value' => true, |
| 715 |
), |
| 716 |
array( |
| 717 |
'field' => 'rules_to_display', |
| 718 |
'operator' => '!==', |
| 719 |
'value' => 'products', |
| 720 |
), |
| 721 |
), |
| 722 |
), |
| 723 |
'allowed_types' => array( 'simple', 'variable' ), |
| 724 |
), |
| 725 |
array( |
| 726 |
'id' => 'excluded_category_slugs', |
| 727 |
'type' => 'select_ajax', |
| 728 |
'title' => esc_html__( 'Excluded categories', 'merchant' ), |
| 729 |
'source' => 'options', |
| 730 |
'multiple' => true, |
| 731 |
'options' => $category_choices, |
| 732 |
'placeholder' => esc_html__( 'Select categories', 'merchant' ), |
| 733 |
'conditions' => array( |
| 734 |
'relation' => 'AND', |
| 735 |
'terms' => array( |
| 736 |
array( |
| 737 |
'field' => 'enable_exclusions', |
| 738 |
'operator' => '===', |
| 739 |
'value' => true, |
| 740 |
), |
| 741 |
array( |
| 742 |
'field' => 'rules_to_display', |
| 743 |
'operator' => '!==', |
| 744 |
'value' => 'categories', |
| 745 |
), |
| 746 |
), |
| 747 |
), |
| 748 |
), |
| 749 |
array( |
| 750 |
'id' => 'excluded_brand_slugs', |
| 751 |
'type' => 'select_ajax', |
| 752 |
'title' => esc_html__( 'Excluded brands', 'merchant' ), |
| 753 |
'source' => 'options', |
| 754 |
'multiple' => true, |
| 755 |
'options' => $brand_choices, |
| 756 |
'placeholder' => esc_html__( 'Select brands', 'merchant' ), |
| 757 |
'conditions' => array( |
| 758 |
'relation' => 'AND', |
| 759 |
'terms' => array( |
| 760 |
array( |
| 761 |
'field' => 'enable_exclusions', |
| 762 |
'operator' => '===', |
| 763 |
'value' => true, |
| 764 |
), |
| 765 |
array( |
| 766 |
'field' => 'rules_to_display', |
| 767 |
'operator' => '!==', |
| 768 |
'value' => 'brands', |
| 769 |
), |
| 770 |
), |
| 771 |
), |
| 772 |
), |
| 773 |
array( |
| 774 |
'id' => 'shipping_zone_ids', |
| 775 |
'type' => 'select_ajax', |
| 776 |
'title' => esc_html__( 'Shipping zones', 'merchant' ), |
| 777 |
'source' => 'options', |
| 778 |
'multiple' => true, |
| 779 |
'options' => $zone_choices, |
| 780 |
'placeholder' => esc_html__( 'Any zone', 'merchant' ), |
| 781 |
'desc' => esc_html__( 'Restrict the schedule to customers in these zones.', 'merchant' ), |
| 782 |
), |
| 783 |
array( |
| 784 |
'id' => 'shipping_method_ids', |
| 785 |
'type' => 'select_ajax', |
| 786 |
'title' => esc_html__( 'Shipping methods', 'merchant' ), |
| 787 |
'source' => 'options', |
| 788 |
'multiple' => true, |
| 789 |
'options' => Merchant_Admin_Options::get_shipping_method_select2_choices(), |
| 790 |
'placeholder' => esc_html__( 'Any shipping method', 'merchant' ), |
| 791 |
// A collected order has no shipping rate to restrict. |
| 792 |
'conditions' => array( |
| 793 |
'relation' => 'AND', |
| 794 |
'terms' => array( |
| 795 |
array( |
| 796 |
'field' => 'fulfilment_type', |
| 797 |
'operator' => '===', |
| 798 |
'value' => 'delivery', |
| 799 |
), |
| 800 |
), |
| 801 |
), |
| 802 |
), |
| 803 |
array( |
| 804 |
'id' => 'payment_gateway_ids', |
| 805 |
'type' => 'select_ajax', |
| 806 |
'title' => esc_html__( 'Payment methods', 'merchant' ), |
| 807 |
'source' => 'options', |
| 808 |
'multiple' => true, |
| 809 |
'options' => Merchant_Admin_Options::get_payment_gateway_select2_choices(), |
| 810 |
'placeholder' => esc_html__( 'Any payment method', 'merchant' ), |
| 811 |
'desc' => esc_html__( 'Useful when a courier only accepts prepaid orders.', 'merchant' ), |
| 812 |
), |
| 813 |
array( |
| 814 |
'id' => 'user_role_slugs', |
| 815 |
'type' => 'select_ajax', |
| 816 |
'title' => esc_html__( 'User roles', 'merchant' ), |
| 817 |
'source' => 'options', |
| 818 |
'multiple' => true, |
| 819 |
'options' => Merchant_Admin_Options::get_user_roles_select2_choices(), |
| 820 |
'placeholder' => esc_html__( 'Any customer', 'merchant' ), |
| 821 |
'desc' => esc_html__( 'Keep wholesale route days for wholesale accounts only.', 'merchant' ), |
| 822 |
), |
| 823 |
array( |
| 824 |
'id' => 'min_cart_total', |
| 825 |
'type' => 'number', |
| 826 |
'title' => esc_html__( 'Minimum cart total', 'merchant' ), |
| 827 |
'desc' => esc_html__( 'Checked against the cart subtotal after discounts. Leave at 0 to accept any order value.', 'merchant' ), |
| 828 |
'default' => 0, |
| 829 |
'min' => 0, |
| 830 |
'step' => 0.01, |
| 831 |
), |
| 832 |
), |
| 833 |
), |
| 834 |
), |
| 835 |
), |
| 836 |
), |
| 837 |
), |
| 838 |
|
| 839 |
array( |
| 840 |
'title' => esc_html__( 'Pickup Locations', 'merchant' ), |
| 841 |
'module' => Merchant_Delivery_Pickup::MODULE_ID, |
| 842 |
'fields' => array( |
| 843 |
array( |
| 844 |
'id' => 'suppress_core_pickup', |
| 845 |
'type' => 'switcher', |
| 846 |
'title' => esc_html__( 'Hide WooCommerce Local Pickup', 'merchant' ), |
| 847 |
'desc' => esc_html__( 'These locations replace it, so customers are not offered pickup twice at checkout.', 'merchant' ), |
| 848 |
'default' => 1, |
| 849 |
), |
| 850 |
array( |
| 851 |
'id' => 'pickup_locations', |
| 852 |
'type' => 'flexible_content', |
| 853 |
'button_label' => esc_html__( 'Add New Location', 'merchant' ), |
| 854 |
'style' => Merchant_Delivery_Pickup::MODULE_ID . '-style default', |
| 855 |
'sorting' => true, |
| 856 |
'duplicate' => true, |
| 857 |
'accordion' => true, |
| 858 |
'layouts' => array( |
| 859 |
'location' => array( |
| 860 |
'title' => esc_html__( 'Location', 'merchant' ), |
| 861 |
'title-field' => 'location_name', |
| 862 |
'status-field' => 'location_status', |
| 863 |
'fields' => array( |
| 864 |
array( |
| 865 |
'id' => 'location_status', |
| 866 |
'type' => 'select', |
| 867 |
'title' => esc_html__( 'Status', 'merchant' ), |
| 868 |
'options' => array( |
| 869 |
'active' => esc_html__( 'Active', 'merchant' ), |
| 870 |
'inactive' => esc_html__( 'Inactive', 'merchant' ), |
| 871 |
), |
| 872 |
'default' => 'active', |
| 873 |
), |
| 874 |
array( |
| 875 |
'id' => 'location_name', |
| 876 |
'type' => 'text', |
| 877 |
'title' => esc_html__( 'Location name', 'merchant' ), |
| 878 |
'default' => esc_html__( 'Main store', 'merchant' ), |
| 879 |
), |
| 880 |
array( |
| 881 |
'id' => 'address', |
| 882 |
'type' => 'text', |
| 883 |
'title' => esc_html__( 'Address', 'merchant' ), |
| 884 |
'placeholder' => esc_html__( '12 High Street', 'merchant' ), |
| 885 |
), |
| 886 |
array( |
| 887 |
'id' => 'city', |
| 888 |
'type' => 'text', |
| 889 |
'title' => esc_html__( 'City', 'merchant' ), |
| 890 |
), |
| 891 |
array( |
| 892 |
'id' => 'postcode', |
| 893 |
'type' => 'text', |
| 894 |
'title' => esc_html__( 'Postcode', 'merchant' ), |
| 895 |
), |
| 896 |
array( |
| 897 |
'id' => 'collection_notes', |
| 898 |
'type' => 'textarea', |
| 899 |
'title' => esc_html__( 'Collection notes', 'merchant' ), |
| 900 |
'desc' => esc_html__( 'Shown next to the location at checkout and repeated in the order email.', 'merchant' ), |
| 901 |
), |
| 902 |
array( |
| 903 |
'id' => 'location_hours_divider', |
| 904 |
'type' => 'divider', |
| 905 |
'title' => esc_html__( 'Opening hours & capacity', 'merchant' ), |
| 906 |
), |
| 907 |
array( |
| 908 |
'id' => 'open_days', |
| 909 |
'type' => 'checkbox_multiple', |
| 910 |
'title' => esc_html__( 'Open days', 'merchant' ), |
| 911 |
'options' => $weekday_choices, |
| 912 |
'default' => array( 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ), |
| 913 |
), |
| 914 |
array( |
| 915 |
'id' => 'open_from', |
| 916 |
'type' => 'date_time', |
| 917 |
'title' => esc_html__( 'Open from', 'merchant' ), |
| 918 |
'placeholder' => '09:00', |
| 919 |
'default' => '09:00', |
| 920 |
'options' => $time_picker, |
| 921 |
), |
| 922 |
array( |
| 923 |
'id' => 'open_until', |
| 924 |
'type' => 'date_time', |
| 925 |
'title' => esc_html__( 'Open until', 'merchant' ), |
| 926 |
'placeholder' => '17:30', |
| 927 |
'default' => '17:30', |
| 928 |
'options' => $time_picker, |
| 929 |
), |
| 930 |
array( |
| 931 |
'id' => 'preparation_time', |
| 932 |
'type' => 'number', |
| 933 |
'title' => esc_html__( 'Preparation time (hours)', 'merchant' ), |
| 934 |
'desc' => esc_html__( 'The earliest collection time is pushed out by this much.', 'merchant' ), |
| 935 |
'default' => 2, |
| 936 |
'min' => 0, |
| 937 |
'step' => 1, |
| 938 |
), |
| 939 |
array( |
| 940 |
'id' => 'collections_per_day', |
| 941 |
'type' => 'number', |
| 942 |
'title' => esc_html__( 'Collections per day', 'merchant' ), |
| 943 |
'desc' => esc_html__( 'Leave at 0 for unlimited.', 'merchant' ), |
| 944 |
'default' => 0, |
| 945 |
'min' => 0, |
| 946 |
'step' => 1, |
| 947 |
), |
| 948 |
array( |
| 949 |
'id' => 'location_blackout_dates', |
| 950 |
'type' => 'sortable_repeater', |
| 951 |
'title' => esc_html__( 'Closed dates', 'merchant' ), |
| 952 |
'desc' => esc_html__( 'One date per row, in YYYY-MM-DD format.', 'merchant' ), |
| 953 |
'button_label' => esc_html__( 'Add Date', 'merchant' ), |
| 954 |
'default' => array(), |
| 955 |
), |
| 956 |
array( |
| 957 |
'id' => 'location_pricing_divider', |
| 958 |
'type' => 'divider', |
| 959 |
'title' => esc_html__( 'Pricing & eligibility', 'merchant' ), |
| 960 |
), |
| 961 |
array( |
| 962 |
'id' => 'location_fee', |
| 963 |
'type' => 'number', |
| 964 |
'title' => esc_html__( 'Collection fee', 'merchant' ), |
| 965 |
'desc' => esc_html__( 'Use a negative amount to discount collection instead.', 'merchant' ), |
| 966 |
'default' => 0, |
| 967 |
'step' => 0.01, |
| 968 |
), |
| 969 |
array( |
| 970 |
'id' => 'location_zone_ids', |
| 971 |
'type' => 'select_ajax', |
| 972 |
'title' => esc_html__( 'Offer to these shipping zones', 'merchant' ), |
| 973 |
'source' => 'options', |
| 974 |
'multiple' => true, |
| 975 |
'options' => $zone_choices, |
| 976 |
'placeholder' => esc_html__( 'Any zone', 'merchant' ), |
| 977 |
'desc' => esc_html__( 'WooCommerce shows every pickup location to everyone. This keeps distant customers from picking a shop they cannot reach.', 'merchant' ), |
| 978 |
), |
| 979 |
array( |
| 980 |
'id' => 'location_category_slugs', |
| 981 |
'type' => 'select_ajax', |
| 982 |
'title' => esc_html__( 'Only stocks these categories', 'merchant' ), |
| 983 |
'source' => 'options', |
| 984 |
'multiple' => true, |
| 985 |
'options' => $category_choices, |
| 986 |
'placeholder' => esc_html__( 'Everything', 'merchant' ), |
| 987 |
), |
| 988 |
array( |
| 989 |
'id' => 'staff_user_ids', |
| 990 |
'type' => 'select_ajax', |
| 991 |
'title' => esc_html__( 'Notify these users', 'merchant' ), |
| 992 |
'source' => 'user', |
| 993 |
'multiple' => true, |
| 994 |
'placeholder' => esc_html__( 'Search users', 'merchant' ), |
| 995 |
'desc' => esc_html__( 'Everyone listed here gets a copy of every collection order for this location. Users are notified at the address on their account.', 'merchant' ), |
| 996 |
), |
| 997 |
array( |
| 998 |
'id' => 'staff_emails', |
| 999 |
'type' => 'sortable_repeater', |
| 1000 |
'title' => esc_html__( 'Notify these addresses', 'merchant' ), |
| 1001 |
'desc' => esc_html__( 'For anyone without an account on the store. One address per row, for example shop@example.com.', 'merchant' ), |
| 1002 |
'button_label' => esc_html__( 'Add Email', 'merchant' ), |
| 1003 |
'default' => array(), |
| 1004 |
), |
| 1005 |
), |
| 1006 |
), |
| 1007 |
), |
| 1008 |
), |
| 1009 |
), |
| 1010 |
), |
| 1011 |
|
| 1012 |
array( |
| 1013 |
'title' => esc_html__( 'Checkout Display', 'merchant' ), |
| 1014 |
'module' => Merchant_Delivery_Pickup::MODULE_ID, |
| 1015 |
'fields' => array( |
| 1016 |
array( |
| 1017 |
'id' => 'date_format', |
| 1018 |
'type' => 'select', |
| 1019 |
'title' => esc_html__( 'Date format', 'merchant' ), |
| 1020 |
'options' => array( |
| 1021 |
'site_default' => esc_html__( 'Site default', 'merchant' ), |
| 1022 |
'weekday_day_month' => esc_html__( 'Thu 20 Aug', 'merchant' ), |
| 1023 |
'day_month' => esc_html__( '20 Aug', 'merchant' ), |
| 1024 |
'weekday_day_month_year' => esc_html__( 'Thu 20 Aug 2026', 'merchant' ), |
| 1025 |
'day_month_year' => esc_html__( '20 Aug 2026', 'merchant' ), |
| 1026 |
'weekday_full' => esc_html__( 'Thursday 20 August', 'merchant' ), |
| 1027 |
'day_month_name_year' => esc_html__( '20 August 2026', 'merchant' ), |
| 1028 |
'day_first_numeric' => esc_html__( '20/08/2026', 'merchant' ), |
| 1029 |
'month_first_numeric' => esc_html__( '08/20/2026', 'merchant' ), |
| 1030 |
'iso' => esc_html__( '2026-08-20', 'merchant' ), |
| 1031 |
), |
| 1032 |
'default' => 'weekday_day_month', |
| 1033 |
), |
| 1034 |
array( |
| 1035 |
'id' => 'time_format', |
| 1036 |
'type' => 'select', |
| 1037 |
'title' => esc_html__( 'Time format', 'merchant' ), |
| 1038 |
'options' => array( |
| 1039 |
'site_default' => esc_html__( 'Site default', 'merchant' ), |
| 1040 |
'twenty_four' => esc_html__( '09:00', 'merchant' ), |
| 1041 |
'twenty_four_compact' => esc_html__( '9:00', 'merchant' ), |
| 1042 |
'twenty_four_dot' => esc_html__( '09.00', 'merchant' ), |
| 1043 |
'twelve' => esc_html__( '2:00 pm', 'merchant' ), |
| 1044 |
'twelve_caps' => esc_html__( '2:00 PM', 'merchant' ), |
| 1045 |
'twelve_hour' => esc_html__( '2 pm', 'merchant' ), |
| 1046 |
'twelve_hour_caps' => esc_html__( '2 PM', 'merchant' ), |
| 1047 |
), |
| 1048 |
'default' => 'site_default', |
| 1049 |
), |
| 1050 |
array( |
| 1051 |
'id' => 'show_slot_price', |
| 1052 |
'type' => 'switcher', |
| 1053 |
'title' => esc_html__( 'Show the price on each slot', 'merchant' ), |
| 1054 |
'default' => 1, |
| 1055 |
), |
| 1056 |
array( |
| 1057 |
'id' => 'show_free_delivery_hint', |
| 1058 |
'type' => 'switcher', |
| 1059 |
'title' => esc_html__( 'Show how much more buys free delivery', 'merchant' ), |
| 1060 |
'desc' => esc_html__( 'Counts up to the nearest "Free when the cart reaches" amount among the schedules on offer. Steps aside while the Free Shipping Progress Bar module is active, so customers see one message.', 'merchant' ), |
| 1061 |
'default' => 1, |
| 1062 |
), |
| 1063 |
array( |
| 1064 |
'id' => 'is_required', |
| 1065 |
'type' => 'switcher', |
| 1066 |
'title' => esc_html__( 'Require a choice before checkout', 'merchant' ), |
| 1067 |
'desc' => esc_html__( 'Only enforced when the section actually renders, so a layout without it never blocks checkout.', 'merchant' ), |
| 1068 |
'default' => 1, |
| 1069 |
), |
| 1070 |
array( |
| 1071 |
'id' => 'required_message', |
| 1072 |
'type' => 'text', |
| 1073 |
'title' => esc_html__( 'Message when nothing is chosen', 'merchant' ), |
| 1074 |
'desc' => esc_html__( 'Use {items} for the products still waiting on a choice, and {count} for how many there are.', 'merchant' ), |
| 1075 |
'default' => esc_html__( 'Please choose when you would like your order.', 'merchant' ), |
| 1076 |
'conditions' => array( |
| 1077 |
'relation' => 'AND', |
| 1078 |
'terms' => array( |
| 1079 |
array( |
| 1080 |
'field' => 'is_required', |
| 1081 |
'operator' => '===', |
| 1082 |
'value' => true, |
| 1083 |
), |
| 1084 |
), |
| 1085 |
), |
| 1086 |
), |
| 1087 |
), |
| 1088 |
), |
| 1089 |
|
| 1090 |
array( |
| 1091 |
'title' => esc_html__( 'Order Emails', 'merchant' ), |
| 1092 |
'module' => Merchant_Delivery_Pickup::MODULE_ID, |
| 1093 |
'fields' => array( |
| 1094 |
array( |
| 1095 |
'id' => 'email_to_customer', |
| 1096 |
'type' => 'switcher', |
| 1097 |
'title' => esc_html__( 'Add the block to customer emails', 'merchant' ), |
| 1098 |
'desc' => esc_html__( 'Order confirmation, processing, completed and the customer invoice.', 'merchant' ), |
| 1099 |
'default' => 1, |
| 1100 |
), |
| 1101 |
array( |
| 1102 |
'id' => 'email_to_admin', |
| 1103 |
'type' => 'switcher', |
| 1104 |
'title' => esc_html__( 'Add the block to admin emails', 'merchant' ), |
| 1105 |
'desc' => esc_html__( 'The new order email your team receives.', 'merchant' ), |
| 1106 |
'default' => 1, |
| 1107 |
), |
| 1108 |
array( |
| 1109 |
'id' => 'email_block_heading', |
| 1110 |
'type' => 'text', |
| 1111 |
'title' => esc_html__( 'Block heading', 'merchant' ), |
| 1112 |
'default' => esc_html__( 'Delivery details', 'merchant' ), |
| 1113 |
), |
| 1114 |
array( |
| 1115 |
'id' => 'email_details', |
| 1116 |
'type' => 'checkbox_multiple', |
| 1117 |
'title' => esc_html__( 'Show in the block', 'merchant' ), |
| 1118 |
'options' => array( |
| 1119 |
'fulfilment' => esc_html__( 'Delivery or pickup', 'merchant' ), |
| 1120 |
'date' => esc_html__( 'Chosen date', 'merchant' ), |
| 1121 |
'slot' => esc_html__( 'Chosen time slot', 'merchant' ), |
| 1122 |
'location' => esc_html__( 'Pickup location and address', 'merchant' ), |
| 1123 |
'notes' => esc_html__( 'Collection notes', 'merchant' ), |
| 1124 |
'charge' => esc_html__( 'What the slot cost', 'merchant' ), |
| 1125 |
), |
| 1126 |
'default' => array( 'fulfilment', 'date', 'slot', 'location', 'notes' ), |
| 1127 |
), |
| 1128 |
array( |
| 1129 |
'id' => 'email_position', |
| 1130 |
'type' => 'select', |
| 1131 |
'title' => esc_html__( 'Where in the email', 'merchant' ), |
| 1132 |
'options' => array( |
| 1133 |
'before_order_table' => esc_html__( 'Before the order table', 'merchant' ), |
| 1134 |
'after_order_table' => esc_html__( 'After the order table', 'merchant' ), |
| 1135 |
'after_customer' => esc_html__( 'After the customer details', 'merchant' ), |
| 1136 |
), |
| 1137 |
'default' => 'after_order_table', |
| 1138 |
), |
| 1139 |
), |
| 1140 |
), |
| 1141 |
|
| 1142 |
array( |
| 1143 |
'title' => esc_html__( 'Customer Notifications', 'merchant' ), |
| 1144 |
'module' => Merchant_Delivery_Pickup::MODULE_ID, |
| 1145 |
'fields' => array( |
| 1146 |
array( |
| 1147 |
'type' => 'divider', |
| 1148 |
'title' => esc_html__( 'Reminder before the slot', 'merchant' ), |
| 1149 |
), |
| 1150 |
array( |
| 1151 |
'id' => 'reminder_email', |
| 1152 |
'type' => 'switcher', |
| 1153 |
'title' => esc_html__( 'Send a reminder', 'merchant' ), |
| 1154 |
'desc' => esc_html__( 'Fewer missed deliveries, fewer collections left on the shelf.', 'merchant' ), |
| 1155 |
'default' => 0, |
| 1156 |
), |
| 1157 |
array( |
| 1158 |
'id' => 'reminder_hours_before', |
| 1159 |
'type' => 'number', |
| 1160 |
'title' => esc_html__( 'Hours before the slot', 'merchant' ), |
| 1161 |
'default' => 24, |
| 1162 |
'min' => 1, |
| 1163 |
'step' => 1, |
| 1164 |
'conditions' => array( |
| 1165 |
'relation' => 'AND', |
| 1166 |
'terms' => array( |
| 1167 |
array( |
| 1168 |
'field' => 'reminder_email', |
| 1169 |
'operator' => '===', |
| 1170 |
'value' => true, |
| 1171 |
), |
| 1172 |
), |
| 1173 |
), |
| 1174 |
), |
| 1175 |
array( |
| 1176 |
'id' => 'reminder_email_subject', |
| 1177 |
'type' => 'text', |
| 1178 |
'title' => esc_html__( 'Subject', 'merchant' ), |
| 1179 |
'desc' => esc_html__( 'You can use these codes in the subject. The two that print a table only work in the message.', 'merchant' ), |
| 1180 |
'hidden_desc' => $merge_tag_panel( $subject_merge_tags ), |
| 1181 |
'default' => esc_html__( 'Your order arrives {delivery_date}', 'merchant' ), |
| 1182 |
'conditions' => array( |
| 1183 |
'relation' => 'AND', |
| 1184 |
'terms' => array( |
| 1185 |
array( |
| 1186 |
'field' => 'reminder_email', |
| 1187 |
'operator' => '===', |
| 1188 |
'value' => true, |
| 1189 |
), |
| 1190 |
), |
| 1191 |
), |
| 1192 |
), |
| 1193 |
array( |
| 1194 |
'id' => 'reminder_email_body', |
| 1195 |
'type' => 'textarea_multiline', |
| 1196 |
'title' => esc_html__( 'Message', 'merchant' ), |
| 1197 |
'desc' => esc_html__( 'You can use these codes in the content.', 'merchant' ), |
| 1198 |
'hidden_desc' => $merge_tag_panel( $body_merge_tags ), |
| 1199 |
'default' => __( 'Hello {customer_name}, a quick reminder that order {order_number} is on its way {delivery_date} between {delivery_slot}.', 'merchant' ), |
| 1200 |
'conditions' => array( |
| 1201 |
'relation' => 'AND', |
| 1202 |
'terms' => array( |
| 1203 |
array( |
| 1204 |
'field' => 'reminder_email', |
| 1205 |
'operator' => '===', |
| 1206 |
'value' => true, |
| 1207 |
), |
| 1208 |
), |
| 1209 |
), |
| 1210 |
), |
| 1211 |
|
| 1212 |
array( |
| 1213 |
'type' => 'divider', |
| 1214 |
'title' => esc_html__( 'Ready to collect', 'merchant' ), |
| 1215 |
), |
| 1216 |
array( |
| 1217 |
'id' => 'ready_email', |
| 1218 |
'type' => 'switcher', |
| 1219 |
'title' => esc_html__( 'Tell customers when their order is ready', 'merchant' ), |
| 1220 |
'desc' => esc_html__( 'Sent when you mark a collection order ready.', 'merchant' ), |
| 1221 |
'default' => 1, |
| 1222 |
), |
| 1223 |
array( |
| 1224 |
'id' => 'ready_email_subject', |
| 1225 |
'type' => 'text', |
| 1226 |
'title' => esc_html__( 'Subject', 'merchant' ), |
| 1227 |
'desc' => esc_html__( 'You can use these codes in the subject. The two that print a table only work in the message.', 'merchant' ), |
| 1228 |
'hidden_desc' => $merge_tag_panel( $subject_merge_tags ), |
| 1229 |
'default' => esc_html__( 'Your order is ready at {location_name}', 'merchant' ), |
| 1230 |
'conditions' => array( |
| 1231 |
'relation' => 'AND', |
| 1232 |
'terms' => array( |
| 1233 |
array( |
| 1234 |
'field' => 'ready_email', |
| 1235 |
'operator' => '===', |
| 1236 |
'value' => true, |
| 1237 |
), |
| 1238 |
), |
| 1239 |
), |
| 1240 |
), |
| 1241 |
array( |
| 1242 |
'id' => 'ready_email_body', |
| 1243 |
'type' => 'textarea_multiline', |
| 1244 |
'title' => esc_html__( 'Message', 'merchant' ), |
| 1245 |
'desc' => esc_html__( 'You can use these codes in the content.', 'merchant' ), |
| 1246 |
'hidden_desc' => $merge_tag_panel( $body_merge_tags ), |
| 1247 |
'default' => __( 'Hello {customer_name}, order {order_number} is packed and waiting for you at {location_name}, {location_address}. {collection_notes}', 'merchant' ), |
| 1248 |
'conditions' => array( |
| 1249 |
'relation' => 'AND', |
| 1250 |
'terms' => array( |
| 1251 |
array( |
| 1252 |
'field' => 'ready_email', |
| 1253 |
'operator' => '===', |
| 1254 |
'value' => true, |
| 1255 |
), |
| 1256 |
), |
| 1257 |
), |
| 1258 |
), |
| 1259 |
|
| 1260 |
array( |
| 1261 |
'type' => 'divider', |
| 1262 |
'title' => esc_html__( 'Changed slot', 'merchant' ), |
| 1263 |
), |
| 1264 |
array( |
| 1265 |
'id' => 'reschedule_email', |
| 1266 |
'type' => 'switcher', |
| 1267 |
'title' => esc_html__( 'Confirm a changed date or slot', 'merchant' ), |
| 1268 |
'desc' => esc_html__( 'Sent whether you moved the order or the customer did.', 'merchant' ), |
| 1269 |
'default' => 1, |
| 1270 |
), |
| 1271 |
array( |
| 1272 |
'id' => 'reschedule_email_subject', |
| 1273 |
'type' => 'text', |
| 1274 |
'title' => esc_html__( 'Subject', 'merchant' ), |
| 1275 |
'desc' => esc_html__( 'You can use these codes in the subject. The two that print a table only work in the message.', 'merchant' ), |
| 1276 |
'hidden_desc' => $merge_tag_panel( array_merge( $subject_merge_tags, $subject_moved_tags ) ), |
| 1277 |
'default' => esc_html__( 'A new time for order {order_number}', 'merchant' ), |
| 1278 |
'conditions' => array( |
| 1279 |
'relation' => 'AND', |
| 1280 |
'terms' => array( |
| 1281 |
array( |
| 1282 |
'field' => 'reschedule_email', |
| 1283 |
'operator' => '===', |
| 1284 |
'value' => true, |
| 1285 |
), |
| 1286 |
), |
| 1287 |
), |
| 1288 |
), |
| 1289 |
array( |
| 1290 |
'id' => 'reschedule_email_body', |
| 1291 |
'type' => 'textarea_multiline', |
| 1292 |
'title' => esc_html__( 'Message', 'merchant' ), |
| 1293 |
'desc' => esc_html__( 'You can use these codes in the content.', 'merchant' ), |
| 1294 |
'hidden_desc' => $merge_tag_panel( array_merge( $body_merge_tags, $moved_merge_tags ) ), |
| 1295 |
'default' => __( "Hello {customer_name}, {moved_booking} has been rescheduled to {new_delivery}.\n\n{booking_details}\n\n{order_details}", 'merchant' ), |
| 1296 |
'conditions' => array( |
| 1297 |
'relation' => 'AND', |
| 1298 |
'terms' => array( |
| 1299 |
array( |
| 1300 |
'field' => 'reschedule_email', |
| 1301 |
'operator' => '===', |
| 1302 |
'value' => true, |
| 1303 |
), |
| 1304 |
), |
| 1305 |
), |
| 1306 |
), |
| 1307 |
|
| 1308 |
array( |
| 1309 |
'type' => 'divider', |
| 1310 |
'title' => esc_html__( 'Opting out', 'merchant' ), |
| 1311 |
), |
| 1312 |
array( |
| 1313 |
'id' => 'unsubscribe_link', |
| 1314 |
'type' => 'switcher', |
| 1315 |
'title' => esc_html__( 'Let customers unsubscribe', 'merchant' ), |
| 1316 |
'desc' => esc_html__( 'Adds an unsubscribe link to the reminder, the ready-to-collect and the changed-slot emails, and a matching checkbox on the account details page. It stops all three.', 'merchant' ), |
| 1317 |
'default' => 1, |
| 1318 |
), |
| 1319 |
array( |
| 1320 |
'id' => 'unsubscribe_message', |
| 1321 |
'type' => 'textarea', |
| 1322 |
'title' => esc_html__( 'Confirmation message', 'merchant' ), |
| 1323 |
'desc' => esc_html__( 'Shown after the customer follows the unsubscribe link.', 'merchant' ), |
| 1324 |
'default' => __( 'You will no longer receive delivery and collection emails from us.', 'merchant' ), |
| 1325 |
'conditions' => array( |
| 1326 |
'relation' => 'AND', |
| 1327 |
'terms' => array( |
| 1328 |
array( |
| 1329 |
'field' => 'unsubscribe_link', |
| 1330 |
'operator' => '===', |
| 1331 |
'value' => true, |
| 1332 |
), |
| 1333 |
), |
| 1334 |
), |
| 1335 |
), |
| 1336 |
|
| 1337 |
array( |
| 1338 |
'type' => 'divider', |
| 1339 |
'title' => esc_html__( 'Telling the shop', 'merchant' ), |
| 1340 |
), |
| 1341 |
array( |
| 1342 |
'id' => 'reschedule_staff_email', |
| 1343 |
'type' => 'switcher', |
| 1344 |
'title' => esc_html__( 'A slot was changed', 'merchant' ), |
| 1345 |
'desc' => esc_html__( 'Goes to the pickup location\'s staff, and to the store admin when the customer moved it.', 'merchant' ), |
| 1346 |
'default' => 1, |
| 1347 |
), |
| 1348 |
array( |
| 1349 |
'id' => 'cancellation_staff_email', |
| 1350 |
'type' => 'switcher', |
| 1351 |
'title' => esc_html__( 'A booking was cancelled or refunded', 'merchant' ), |
| 1352 |
'desc' => esc_html__( 'The slot goes back to the pool quietly. This says so, to the pickup location\'s staff and the store admin.', 'merchant' ), |
| 1353 |
'default' => 1, |
| 1354 |
), |
| 1355 |
|
| 1356 |
array( |
| 1357 |
'type' => 'divider', |
| 1358 |
'title' => esc_html__( 'Self-service', 'merchant' ), |
| 1359 |
), |
| 1360 |
array( |
| 1361 |
'id' => 'allow_reschedule', |
| 1362 |
'type' => 'switcher', |
| 1363 |
'title' => esc_html__( 'Let customers reschedule from My Account', 'merchant' ), |
| 1364 |
'default' => 0, |
| 1365 |
), |
| 1366 |
array( |
| 1367 |
'id' => 'reschedule_cutoff_hours', |
| 1368 |
'type' => 'number', |
| 1369 |
'title' => esc_html__( 'Stop rescheduling this many hours before the slot', 'merchant' ), |
| 1370 |
'default' => 24, |
| 1371 |
'min' => 0, |
| 1372 |
'step' => 1, |
| 1373 |
'conditions' => array( |
| 1374 |
'relation' => 'AND', |
| 1375 |
'terms' => array( |
| 1376 |
array( |
| 1377 |
'field' => 'allow_reschedule', |
| 1378 |
'operator' => '===', |
| 1379 |
'value' => true, |
| 1380 |
), |
| 1381 |
), |
| 1382 |
), |
| 1383 |
), |
| 1384 |
array( |
| 1385 |
'id' => 'customer_ics', |
| 1386 |
'type' => 'switcher', |
| 1387 |
'title' => esc_html__( 'Let customers add the slot to their calendar', 'merchant' ), |
| 1388 |
'desc' => esc_html__( 'Adds an "Add to calendar" link to the customer order emails and to the order page, and turns on the {ics_link} merge tag.', 'merchant' ), |
| 1389 |
'default' => 0, |
| 1390 |
), |
| 1391 |
), |
| 1392 |
), |
| 1393 |
|
| 1394 |
array( |
| 1395 |
'title' => esc_html__( 'Orders & Operations', 'merchant' ), |
| 1396 |
'module' => Merchant_Delivery_Pickup::MODULE_ID, |
| 1397 |
'fields' => array( |
| 1398 |
array( |
| 1399 |
'id' => 'orders_list_column', |
| 1400 |
'type' => 'switcher', |
| 1401 |
'title' => esc_html__( 'Add a delivery column to the orders list', 'merchant' ), |
| 1402 |
'desc' => esc_html__( 'Sortable and filterable, so you can work a single day at a time.', 'merchant' ), |
| 1403 |
'default' => 1, |
| 1404 |
), |
| 1405 |
array( |
| 1406 |
'id' => 'delivery_calendar', |
| 1407 |
'type' => 'switcher', |
| 1408 |
'title' => esc_html__( 'Show the delivery calendar', 'merchant' ), |
| 1409 |
'desc' => esc_html__( 'A month, week and day view of everything booked, with CSV export and print.', 'merchant' ), |
| 1410 |
'default' => 1, |
| 1411 |
), |
| 1412 |
array( |
| 1413 |
'id' => 'capacity_unit', |
| 1414 |
'type' => 'select', |
| 1415 |
'title' => esc_html__( 'Count capacity in', 'merchant' ), |
| 1416 |
'desc' => esc_html__( 'What fills up a day or a slot. Count orders when every delivery takes the same effort, one drop per address. Count items when the load is what limits you. A van, a bench or an oven fills up on cakes, not on receipts, so a 20-item order uses twenty places rather than one.', 'merchant' ), |
| 1417 |
'options' => array( |
| 1418 |
'orders' => esc_html__( 'Orders', 'merchant' ), |
| 1419 |
'items' => esc_html__( 'Items', 'merchant' ), |
| 1420 |
), |
| 1421 |
'default' => 'orders', |
| 1422 |
), |
| 1423 |
array( |
| 1424 |
'type' => 'divider', |
| 1425 |
'title' => esc_html__( 'A note on your timezone', 'merchant' ), |
| 1426 |
), |
| 1427 |
array( |
| 1428 |
'id' => 'timezone_info', |
| 1429 |
'type' => 'info', |
| 1430 |
'content' => esc_html__( 'Dates, cut-offs and capacity all follow the timezone in Settings > General. Pick a city rather than a UTC offset, otherwise daylight saving shifts every cut-off by an hour twice a year.', 'merchant' ), |
| 1431 |
), |
| 1432 |
), |
| 1433 |
), |
| 1434 |
); |
| 1435 |
|