__('Pickup Customer', 'pickuppointment'), 'pickuppt_driver' => __('Pickup Driver', 'pickuppointment') )); } function pickuppt_payment_options() { $qr_code_link = pickuppt_get_general_setting( 'qr_code_link' ) ?: ''; $options = array( 'pu_cod' => __('Cash on Delivery (COD)', 'pickuppointment'), 'pu_cop' => __('Cash on Pickup (COP)', 'pickuppointment'), 'pu_rtp' => __('Request to Pay (Receive payment link or QR through email)', 'pickuppointment') ); if( !empty( $qr_code_link ) ) { $options['pu_sdqr'] = __('Scan Driver\'s QR', 'pickuppointment'); } return apply_filters('pickuppt_payment_options', $options); } function pickuppt_include_template($file_name) { $file_slug = strtolower(preg_replace('/\s+/', '_', trim(str_replace('.tpl', '', $file_name)))); $file_slug = preg_replace('/[^A-Za-z0-9_]/', '_', $file_slug); $custom_template_path = get_stylesheet_directory() . '/wp-pickuppointment/' . $file_name . '.php'; if (file_exists($custom_template_path)) { $template_path = $custom_template_path; } else { $template_path = PICKUPPOINTMENT_PATH . 'templates/' . $file_name . '.php'; $template_path = apply_filters("pickuppt_locate_template_{$file_slug}", $template_path); } return $template_path; } function pickuppt_field_generator($field_key, $field_val, $value = '', $form_group_name = '') { $type = ($field_val['type'] ?? '') ?: ''; $label = ($field_val['label'] ?? '') ?: ''; $rows = ($field_val['rows'] ?? 0) ?: 0; $cols = ($field_val['cols'] ?? 0) ?: 0; $is_required = ($field_val['required'] ?? false) ?: false; $is_readonly = ($field_val['readonly'] ?? false) ?: false; $is_assoc = ($field_val['is_assoc'] ?? false) ?: false; $include_id = ($field_val['include_id'] ?? false) ?: false; $is_multiple = ($field_val['is_multiple'] ?? false) ?: false; $custom_classes = ($field_val['custom_classes'] ?? array()) ?: array(); if(is_array($custom_classes)) { $custom_classes = implode(' ', $custom_classes); } $options = ($field_val['options'] ?? array()) ?: array(); if($is_readonly) { $custom_classes .= ' bg-light'; } $name = "name='{$field_key}'"; $id = "id='{$field_key}'"; $class = "class='{$custom_classes}'"; $required = $is_required ? 'required' : ''; $readonly = $is_readonly ? 'readonly' : ''; $multiple = $is_multiple ? 'multiple' : ''; $step = ''; if(!$include_id) { $id = ''; } if($type === 'number') { $step = "step='0.01'"; } if($form_group_name) { $name = "name='{$form_group_name}[{$field_key}]'"; } if($type === 'checkbox' || ($is_multiple && $type === 'select')) { $name = "name='{$field_key}[]'"; if($form_group_name) { $name = "name='{$form_group_name}[{$field_key}][]'"; } } $output = ''; switch ($type) { case 'select': $output .= ""; break; case 'textarea': $output .= ""; break; case 'radio': case 'checkbox': if($options && is_array($options)) { foreach($options as $rad_k => $rad_v) { $rad_v_temp = $rad_v; if($is_assoc) { $rad_v_temp = $rad_k; } $checked = ''; if(is_array($value)) { $checked = in_array(trim($rad_v_temp), $value) ? 'checked' : ''; } else { $checked = (trim($value) == trim($rad_v_temp)) ? 'checked' : ''; } $id = "id='{$field_key}-{$rad_v_temp}'"; $output .= "{$rad_v} "; } } break; default: $output .= ""; break; } return $output; } function pickuppt_allowed_htmls() { $allowed_html = array( 'select' => array( 'name' => array(), 'id' => array(), 'class' => array(), 'multiple' => array(), 'required' => array(), ), 'option' => array( 'value' => array(), 'selected' => array(), ), 'textarea' => array( 'name' => array(), 'cols' => array(), 'rows' => array(), 'id' => array(), 'class' => array(), 'required' => array(), 'readonly' => array(), ), 'input' => array( 'type' => array(), 'step' => array(), 'name' => array(), 'id' => array(), 'class' => array(), 'value' => array(), 'checked' => array(), 'required' => array(), 'readonly' => array(), 'multiple' => array(), ), ); return $allowed_html; } function pickuppt_statuses() { $status_settings = pickuppt_get_general_setting('statuses') ?: 'Pending Review,Pending Payment,Payment Confirmed,Driver Assigned,Picked Up,Delivered,Rescheduled,Cancelled,Failed,Flagged,Awaiting Reassignment'; $status_exploded = explode(',', $status_settings); $exploded_trimmed = pickuppt_sanitize_array(array_filter($status_exploded)); return apply_filters('pickuppt_statuses', $exploded_trimmed); } function pickuppt_items() { $items_settings = pickuppt_get_general_setting('items') ?: 'Box,Document,Letters'; $items_exploded = explode(',', $items_settings); $exploded_trimmed = pickuppt_sanitize_array(array_filter($items_exploded)); return apply_filters('pickuppt_items', $exploded_trimmed); } function pickuppt_custom_destination() { return pickuppt_get_general_setting('custom_destination') ?: false; } function pickuppt_warehouses( bool $is_formatted = false ) { $warehouses = pickuppt_get_general_setting('warehouses') ?: array(); if( !$is_formatted ) { return $warehouses; } $formatted_warehouses = array(); $formatted_warehouses_index = 1; foreach( $warehouses as $wh ) { $formatted_warehouses[$formatted_warehouses_index] = ( $wh['warehouse_name'] ?? '' ) ?: ''; $formatted_warehouses_index++; } return $formatted_warehouses; } function pickuppt_customer_info_fields() { $fields = array( 'pickuppt_name' => array( 'type' => 'text', 'label' => __('Name', 'pickuppointment'), 'required' => true, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'person', ), 'pickuppt_address' => array( 'type' => 'text', 'label' => __('Full Address', 'pickuppointment'), 'required' => false, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width', 'pickuppointment-autocomplete'), 'rows' => 0, 'cols' => 0, 'icon' => 'location', ), 'pickuppt_email' => array( 'type' => 'email', 'label' => __('Email', 'pickuppointment'), 'required' => true, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'mail', ), 'pickuppt_phone' => array( 'type' => 'text', 'label' => __('Phone', 'pickuppointment'), 'required' => true, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'call', ) ); return apply_filters('pickuppt_customer_info_fields', $fields); } function pickuppt_pickup_info_fields() { $fields = array(); $fields['pickuppt_date'] = array( 'type' => 'text', 'label' => __('Pickup Date', 'pickuppointment'), 'required' => true, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width pickuppt-datepicker'), 'rows' => 0, 'cols' => 0, 'icon' => 'calendar', ); $fields['pickuppt_time'] = array( 'type' => 'text', 'label' => __('Pickup Time', 'pickuppointment'), 'required' => true, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width', 'pickuppt-timepicker'), 'rows' => 0, 'cols' => 0, 'icon' => 'alarm', ); $fields['pickuppt_location'] = array( 'type' => 'text', 'label' => __('Pickup Address', 'pickuppointment'), 'required' => true, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width', 'pickuppointment-autocomplete'), 'rows' => 0, 'cols' => 0, 'icon' => 'navigate', ); $fields['pickuppt_location_landmark'] = array( 'type' => 'text', 'label' => __('Pickup Landmark', 'pickuppointment'), 'required' => false, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'information-circle', ); if( pickuppt_custom_destination() ) { $fields['pickuppt_delivery_address'] = array( 'type' => 'text', 'label' => __('Delivery Address', 'pickuppointment'), 'required' => true, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width', 'pickuppointment-autocomplete'), 'rows' => 0, 'cols' => 0, 'icon' => 'location', ); $fields['pickuppt_delivery_address_landmark'] = array( 'type' => 'text', 'label' => __('Delivery Landmark', 'pickuppointment'), 'required' => false, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'information-circle', ); } else { $fields['pickuppt_delivery_warehouse'] = array( 'type' => 'select', 'label' => __('Delivery Warehouse', 'pickuppointment'), 'required' => true, 'options' => pickuppt_warehouses( true ), 'is_assoc' => true, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'location', ); } $fields['pickuppt_remarks'] = array( 'type' => 'textarea', 'label' => __('Pickup Instructions', 'pickuppointment'), 'required' => false, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'chatbubble-ellipses', ); $fields['pickuppt_payment_option'] = array( 'type' => 'select', 'label' => __('Payment Option', 'pickuppointment'), 'required' => true, 'options' => pickuppt_payment_options(), 'is_assoc' => true, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'card', ); $fields['pickuppt_status'] = array( 'type' => 'select', 'label' => __('Status', 'pickuppointment'), 'required' => true, 'options' => pickuppt_statuses(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'information-circle', ); return apply_filters('pickuppt_pickup_info_fields', $fields); } function pickuppt_items_info_fields() { $fields = array( 'pickuppt_item' => array( 'type' => 'select', 'label' => __('Item', 'pickuppointment'), 'required' => false, 'options' => pickuppt_items(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 10, 'cols' => 30, 'icon' => 'cube', ), 'pickuppt_desc' => array( 'type' => 'textarea', 'label' => __('Description', 'pickuppointment'), 'required' => false, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'document-text', ), 'pickuppt_quant' => array( 'type' => 'number', 'label' => __('Quantity', 'pickuppointment'), 'required' => false, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'layers', ), 'pickuppt_weight' => array( 'type' => 'number', 'label' => __('Weight', 'pickuppointment') . sprintf(' (%s.)', pickuppt_weight_unit()), 'required' => false, 'options' => array(), 'is_assoc' => false, 'is_multiple' => false, 'include_id' => true, 'custom_classes' => array('pickuppt-custom-width'), 'rows' => 0, 'cols' => 0, 'icon' => 'scale', ) ); return apply_filters('pickuppt_items_info_fields', $fields); } function pickuppt_all_appointments($events = false, $month = 0, $year = 0) { global $wpdb; $is_current_role_admin = pickuppt_is_current_role( 'administrator' ); $cancelled_status = pickuppt_get_general_setting('cancelled_status'); $current_user_id = get_current_user_id(); if( empty( $month ) ) { $month = gmdate( 'm' ); } if( empty( $year ) ) { $year = gmdate( 'Y' ); } $pickuppt_get_month_date_range = pickuppt_get_month_date_range((int)$month, (int)$year); $q = "SELECT p.ID FROM `{$wpdb->posts}` AS p "; $q .= "INNER JOIN {$wpdb->postmeta} AS pm2 ON p.ID = pm2.post_id "; if( pickuppt_is_current_role( 'pickuppt_customer' ) ) { $q .= "INNER JOIN {$wpdb->postmeta} AS pm1 ON p.ID = pm1.post_id "; } if( pickuppt_is_current_role( 'pickuppt_driver' ) ) { $q .= "INNER JOIN {$wpdb->postmeta} AS pmAssignedDriver ON p.ID = pmAssignedDriver.post_id "; } $q .= "WHERE 1=1 "; if( pickuppt_is_current_role( 'pickuppt_customer' ) ) { $q .= $wpdb->prepare("AND pm1.meta_key = 'pickuppt_appt_owner' AND pm1.meta_value = %s ", $current_user_id); } if( pickuppt_is_current_role( 'pickuppt_driver' ) ) { $q .= $wpdb->prepare("AND pmAssignedDriver.meta_key = 'pickuppt_assigned_driver' AND pmAssignedDriver.meta_value = %s ", $current_user_id); } $q .= $wpdb->prepare("AND p.post_status = 'publish' AND p.post_type = %s ", PICKUPPOINTMENT_POST_TYPE); $q .= $wpdb->prepare( "AND NOT EXISTS ( SELECT 1 FROM {$wpdb->postmeta} AS pm3 WHERE pm3.post_id = p.ID AND pm3.meta_key = 'pickuppt_status' AND pm3.meta_value = %s ) ", $cancelled_status ); $q .= $wpdb->prepare("AND pm2.meta_key = 'pickuppt_date' AND pm2.meta_value BETWEEN %s AND %s", $pickuppt_get_month_date_range['first_day'] . ' 00:00:00', $pickuppt_get_month_date_range['last_day'] . ' 23:59:59'); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter $r = $wpdb->get_results($q); $f = array(); $e = array(); if($r && is_array($r)) { foreach($r as $_r) { $ftemp = array(); $etemp = array(); $id = $_r->ID; $ftemp['id'] = $id; $etemp['id'] = $id; $event_title = ''; $cif = array_keys(pickuppt_customer_info_fields()); $pif = array_keys(pickuppt_pickup_info_fields()); foreach($cif as $_cif) { $meta = get_post_meta($id); $ftemp[$_cif] = ($meta[$_cif][0] ?? '') ?: ''; if($_cif === 'pickuppt_name') { $etemp['description'] = "
NAME: " . ($meta[$_cif][0] ?? '') ?: '' . '
'; } } foreach($pif as $_pif) { $_meta = get_post_meta($id); $_v = ($_meta[$_pif][0] ?? '') ?: ''; $ftemp[$_pif] = ($_meta[$_pif][0] ?? '') ?: ''; if($_pif === 'pickuppt_date') { $etemp['start'] = $_v; } if($_pif === 'pickuppt_location') { $etemp['description'] .= "PICKUP ADD.: {$_v}
"; } if($_pif === 'pickuppt_time') { $formatted_time = gmdate('h:i A', strtotime($_v)); $etemp['start'] .= 'T' . gmdate('H:i:s', strtotime($_v)); $etemp['description'] .= "PICKUP TIME: {$formatted_time}
"; } if($_pif === 'pickuppt_remarks') { $etemp['description'] .= "NOTE(s): {$_v}
"; } if($_pif === 'pickuppt_status') { $event_title .= $_v; $etemp['backgroundColor'] = pickuppt_get_status_color($_v); } } $etemp['title'] = $event_title; $f[] = $ftemp; $e[] = $etemp; } } if($events) { return wp_json_encode($e); } return $f; } function pickuppt_page_slugs_for_assets() { return apply_filters('pickuppt_page_slugs_for_assets', array( 'pickuppointments-page', 'pickuppointment-settings-page' )); } function pickuppt_general_settings() { return get_option('pickuppt_general_settings_group') ?: array(); } function pickuppt_get_general_setting($setting_name = '') { return (pickuppt_general_settings()[$setting_name] ?? '') ?: ''; } /** * Recursively sanitize an array: both keys and values. * * @param mixed $data Raw input (string or nested array). * @return mixed Sanitized data. */ function pickuppt_sanitize_array( $data ) { if ( ! is_array( $data ) ) { return is_scalar( $data ) ? sanitize_text_field( (string) $data ) : ''; } $clean = array(); foreach ( $data as $key => $value ) { // Keep integer keys as-is; clean string keys. if ( is_string( $key ) ) { $key = pickuppt_sanitize_key_preserve_case( $key ); if ( '' === $key ) { continue; // Drop keys that end up empty. } } $clean[ $key ] = pickuppt_sanitize_array( $value ); } return $clean; } /** * Like sanitize_key(), but keeps uppercase letters (useful for camelCase field names). */ function pickuppt_sanitize_key_preserve_case( $key ) { return preg_replace( '/[^A-Za-z0-9_\-]/', '', $key ); } function pickuppt_slugify($string, $delimiter = '-') { // Ensure UTF-8 encoding $string = mb_convert_encoding((string)$string, 'UTF-8', mb_list_encodings()); // Convert to ASCII (remove accents, ñ → n, é → e, etc.) $string = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string); // Lowercase $string = strtolower($string); // Replace non-alphanumeric characters with delimiter $string = preg_replace('/[^a-z0-9]+/u', $delimiter, $string); // Trim delimiters from ends $string = trim($string, $delimiter); return $string; } function pickuppt_get_status_color($status) { return pickuppt_get_general_setting(pickuppt_slugify($status) . '_color') ?: '#ffffff'; } function pickuppt_is_title_exists($title) { global $wpdb; $q = "SELECT `ID` FROM `{$wpdb->posts}` WHERE `post_type` = %s AND `post_status` IN ('publish', 'trash', 'draft') AND `post_title` = %s"; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared return $wpdb->get_var($wpdb->prepare($q, PICKUPPOINTMENT_POST_TYPE, $title)); } function pickuppt_generate_title() { $length = pickuppt_get_general_setting('title_length') ?: 6; $prefix = trim(pickuppt_get_general_setting('title_prefix') ?: ''); $suffix = trim(pickuppt_get_general_setting('title_suffix') ?: ''); $is_alpha_numeric = pickuppt_get_general_setting('is_alpha_numeric') ?: false; $characters = $is_alpha_numeric ? '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' : '0123456789'; $charactersLength = strlen($characters); $attempts = 0; $max_attempts = 10; // prevent infinite loop do { $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[random_int(0, $charactersLength - 1)]; } $final_title = trim($prefix . $randomString . $suffix); $attempts++; } while (pickuppt_is_title_exists($final_title) && $attempts < $max_attempts); // Fallback if still not unique after max attempts if ($attempts == $max_attempts) { $final_title .= '-' . time(); // ensures uniqueness } return apply_filters('pickuppt_generate_title', $final_title); } function pickuppt_save_history($id, $old_status, $new_status, $location = '', $remarks = '', $user_id = 0) { global $pickuppointment_class; $is_updated = false; $pickuppt_history = maybe_unserialize(get_post_meta($id, 'pickuppt_history', true)) ?: array(); $current_user_id = get_current_user_id(); if( !empty( $user_id ) && intval( $user_id ) > 0 ) { $current_user_id = $user_id; } $current_user_fullname = $pickuppointment_class->get_user_fullname($current_user_id); $is_current_role_admin = pickuppt_is_current_role( 'administrator' ); if(!$pickuppt_history) { $pickuppt_history = array( array( 'date' => wp_date($pickuppointment_class->get_date_format()), 'time' => wp_date($pickuppointment_class->get_time_format()), 'location' => $location, 'status' => $new_status, 'remarks' => 'appointment submitted', 'updated-by-name' => $current_user_fullname, 'updated-by-id' => $current_user_id ) ); $is_updated = true; do_action('pickuppt_save_history_create', $id, $new_status, $location, $remarks); } else { if($new_status != $old_status) { $pickuppt_history[] = array( 'date' => wp_date($pickuppointment_class->get_date_format()), 'time' => wp_date($pickuppointment_class->get_time_format()), 'location' => $location, 'status' => $new_status, 'remarks' => $is_current_role_admin ? "Admin updated: {$new_status}" : $remarks, 'updated-by-name' => $current_user_fullname, 'updated-by-id' => $current_user_id ); update_post_meta($id, 'pickuppt_status', $new_status); do_action('pickuppt_save_history_update', $id, $new_status, $location, $remarks); $is_updated = true; } } update_post_meta($id, 'pickuppt_history', maybe_serialize($pickuppt_history)); return $is_updated; } function pickuppt_default_status() { $status = pickuppt_get_general_setting('default_status') ?: 'Pending Review'; return apply_filters('pickuppt_default_status', $status); } function pickuppt_weight_unit() { $status = pickuppt_get_general_setting('weight_unit') ?: 'kg'; return apply_filters('pickuppt_weight_unit', $status); } function pickuppt_shortcode_list() { $pickuppt_customer_info_fields = pickuppt_customer_info_fields(); $pickuppt_pickup_info_fields = pickuppt_pickup_info_fields(); $list = array( '{pickuppt_appt_ref}' => __('Appointment Tracking Number', 'pickuppointment'), '{pickuppt_admin_email}' => __('Admin Email', 'pickuppointment'), '{pickuppt_site_name}' => __('Site Name', 'pickuppointment'), '{pickuppt_site_url}' => __('Site URL', 'pickuppointment') ); foreach($pickuppt_customer_info_fields as $a => $b) { $list["{" . "{$a}" . "}"] = $b['label'] ?? __('Unlabeled', 'pickuppointment'); } foreach($pickuppt_pickup_info_fields as $c => $d) { $list["{" . "{$c}" . "}"] = $d['label'] ?? __('Unlabeled', 'pickuppointment'); } return apply_filters('pickuppt_shortcode_list', $list); } function pickuppt_find_and_replace_placeholder($text, $post_id = null) { $replacements = array(); $pickuppt_shortcode_list_keys = array_keys(pickuppt_shortcode_list()); $pickuppt_readable_date_format = apply_filters('pickuppt_readable_date_format', 'M d, Y'); $pickuppt_readable_time_format = apply_filters('pickuppt_readable_time_format', 'h:i A'); foreach ($pickuppt_shortcode_list_keys as $placeholder) { // Remove { } → wp_name $key = trim($placeholder, '{}'); switch ($key) { case 'pickuppt_appt_ref': $value = get_the_title($post_id); break; case 'pickuppt_admin_email': $value = get_option('admin_email'); break; case 'pickuppt_site_name': $value = get_bloginfo('name'); break; case 'pickuppt_site_url': $value = admin_url(); break; case 'pickuppt_date': $pickuppt_date = get_post_meta($post_id, $key, true); $value = gmdate($pickuppt_readable_date_format, strtotime($pickuppt_date)); break; case 'pickuppt_time': $pickuppt_time = get_post_meta($post_id, $key, true); $value = gmdate($pickuppt_readable_time_format, strtotime($pickuppt_time)); break; case 'pickuppt_delivery_warehouse': $delivery_warehouse_key = get_post_meta( $post_id, $key, true ); $value = pickuppt_warehouses( true )[$delivery_warehouse_key] ?? ''; break; default: $value = maybe_unserialize(get_post_meta($post_id, $key, true)); } // reformat if value is array if(is_array($value)) { $value = implode(', ', $value); } $_value = apply_filters('pickuppt_find_and_replace_placeholder_value', $value, $post_id); $replacements[] = $_value ?: ''; } return str_replace($pickuppt_shortcode_list_keys, $replacements, $text); } function pickuppt_default_customer_email_subject() { return "Your Appointment: {pickuppt_appt_ref}"; } function pickuppt_default_customer_email_from() { return get_option('admin_email'); } function pickuppt_default_customer_email_to() { return "{pickuppt_email}"; } function pickuppt_default_customer_email_body() { $email = "Dear Valued Customer,
Good day!
Your pickup appointment has been successfully submitted. Please find the details of your appointment below:
Pickup Date: {pickuppt_date}
Pickup Time: {pickuppt_time}
Reference Number: {pickuppt_appt_ref}
Pickup Location: {pickuppt_location}
"; if( pickuppt_custom_destination() ) { $email .= "Delivery Address: {pickuppt_delivery_address}
"; } else { $email .= "Delivery Warehouse: {pickuppt_delivery_warehouse}
"; } $email .= "Kindly ensure that the items are ready at the scheduled time to avoid any inconvenience. If you need to make changes or have questions regarding your appointment, please contact our office.
Thank you for choosing our service. We look forward to assisting you.
Sincerely,
{pickuppt_site_name}"; return $email; } function pickuppt_default_admin_email_subject() { return "New Appointment: {pickuppt_appt_ref}"; } function pickuppt_default_admin_email_from() { return get_option('admin_email'); } function pickuppt_default_admin_email_to() { return "{pickuppt_admin_email}"; } function pickuppt_default_admin_email_body() { $email = "Dear Administrator,
Good day!
A new pickup appointment has been submitted and is ready for your review. Below are the appointment details:
Customer Name: {pickuppt_name}
Pickup Date & Time: {pickuppt_date} at {pickuppt_time}
Pickup Location: {pickuppt_location}
"; if( pickuppt_custom_destination() ) { $email .= "Delivery Address: {pickuppt_delivery_address}
"; } else { $email .= "Delivery Warehouse: {pickuppt_delivery_warehouse}
"; } $email .= "Reference Number: {pickuppt_appt_ref}
Please log in to the system to review and process this request at your earliest convenience: here
Thank you.
Sincerely,
{pickuppt_site_name}
"; return $email; } function pickuppt_default_appt_email_subject() { return "Pickup Appointment Status Update: {pickuppt_appt_ref}"; } function pickuppt_default_appt_email_from() { return get_option('admin_email'); } function pickuppt_default_appt_email_to() { return "{pickuppt_admin_email}, {pickuppt_email}"; } function pickuppt_default_appt_email_body() { return "
Hi {pickuppt_name},
Please be informed that your pickup appointment {pickuppt_appt_ref} has been updated.
Details:
Pickup Date: {pickuppt_date}
Pickup Time: {pickuppt_time}
Status: {pickuppt_status}
Thank you for using our pickup service.
Best regards,
{pickuppt_site_name}
"; } function pickuppt_send_admin_email($post_id) { $admin_email_subject = pickuppt_get_general_setting('admin_email_subject') ?: pickuppt_default_admin_email_subject(); $admin_email_from = pickuppt_get_general_setting('admin_email_from') ?: pickuppt_default_admin_email_from(); $admin_email_to = pickuppt_get_general_setting('admin_email_to') ?: pickuppt_default_admin_email_to(); $admin_email_bc = pickuppt_get_general_setting('admin_email_bc') ?: ''; $admin_email_cc = pickuppt_get_general_setting('admin_email_cc') ?: ''; $admin_email_body = pickuppt_get_general_setting('admin_email_body') ?: pickuppt_default_admin_email_body(); $admin_email_subject_replaced = pickuppt_find_and_replace_placeholder($admin_email_subject, $post_id); $admin_email_from_replaced = pickuppt_find_and_replace_placeholder($admin_email_from, $post_id); $admin_email_to_replaced = pickuppt_find_and_replace_placeholder($admin_email_to, $post_id); $admin_email_bc_replaced = pickuppt_find_and_replace_placeholder($admin_email_bc, $post_id); $admin_email_cc_replaced = pickuppt_find_and_replace_placeholder($admin_email_cc, $post_id); $admin_email_body_replaced = pickuppt_find_and_replace_placeholder($admin_email_body, $post_id); $headers = array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . $admin_email_from_replaced ); if (!empty($admin_email_cc_replaced)) { $headers[] = 'Cc: ' . $admin_email_cc_replaced; } if (!empty($admin_email_bc_replaced)) { $headers[] = 'Bcc: ' . $admin_email_bc_replaced; } return wp_mail($admin_email_to_replaced, $admin_email_subject_replaced, $admin_email_body_replaced, $headers); } function pickuppt_send_customer_email($post_id) { $email_subject = pickuppt_get_general_setting('email_subject') ?: pickuppt_default_customer_email_subject(); $email_from = pickuppt_get_general_setting('email_from') ?: pickuppt_default_customer_email_from(); $email_to = pickuppt_get_general_setting('email_to') ?: pickuppt_default_customer_email_to(); $email_bc = pickuppt_get_general_setting('email_bc') ?: ''; $email_cc = pickuppt_get_general_setting('email_cc') ?: ''; $email_body = pickuppt_get_general_setting('email_body') ?: pickuppt_default_customer_email_body(); $email_subject_replaced = pickuppt_find_and_replace_placeholder($email_subject, $post_id); $email_from_replaced = pickuppt_find_and_replace_placeholder($email_from, $post_id); $email_to_replaced = pickuppt_find_and_replace_placeholder($email_to, $post_id); $email_bc_replaced = pickuppt_find_and_replace_placeholder($email_bc, $post_id); $email_cc_replaced = pickuppt_find_and_replace_placeholder($email_cc, $post_id); $email_body_replaced = pickuppt_find_and_replace_placeholder($email_body, $post_id); $headers = array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . $email_from_replaced ); if (!empty($email_cc_replaced)) { $headers[] = 'Cc: ' . $email_cc_replaced; } if (!empty($email_bc_replaced)) { $headers[] = 'Bcc: ' . $email_bc_replaced; } return wp_mail($email_to_replaced, $email_subject_replaced, $email_body_replaced, $headers); } function pickuppt_send_appt_email($post_id) { $appt_email_subject = pickuppt_get_general_setting('appt_email_subject') ?: pickuppt_default_appt_email_subject(); $appt_email_from = pickuppt_get_general_setting('appt_email_from') ?: pickuppt_default_appt_email_from(); $appt_email_to = pickuppt_get_general_setting('appt_email_to') ?: pickuppt_default_appt_email_to(); $appt_email_bc = pickuppt_get_general_setting('appt_email_bc') ?: ''; $appt_email_cc = pickuppt_get_general_setting('appt_email_cc') ?: ''; $appt_email_body = pickuppt_get_general_setting('appt_email_body') ?: pickuppt_default_appt_email_body(); $appt_email_subject_replaced = pickuppt_find_and_replace_placeholder($appt_email_subject, $post_id); $appt_email_from_replaced = pickuppt_find_and_replace_placeholder($appt_email_from, $post_id); $appt_email_to_replaced = pickuppt_find_and_replace_placeholder($appt_email_to, $post_id); $appt_email_bc_replaced = pickuppt_find_and_replace_placeholder($appt_email_bc, $post_id); $appt_email_cc_replaced = pickuppt_find_and_replace_placeholder($appt_email_cc, $post_id); $appt_email_body_replaced = pickuppt_find_and_replace_placeholder($appt_email_body, $post_id); $headers = array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . $appt_email_from_replaced ); if (!empty($appt_email_cc_replaced)) { $headers[] = 'Cc: ' . $appt_email_cc_replaced; } if (!empty($appt_email_bc_replaced)) { $headers[] = 'Bcc: ' . $appt_email_bc_replaced; } return wp_mail($appt_email_to_replaced, $appt_email_subject_replaced, $appt_email_body_replaced, $headers); } function pickuppt_send_appt_emails($post_id) { pickuppt_send_admin_email($post_id); pickuppt_send_customer_email($post_id); } function pickuppt_color_shade_generator($color_code, $shade_level) { // Sanitize input $color_code = ltrim($color_code, '#'); $shade_level = max(-100, min(100, (int)$shade_level)); // Expand shorthand hex (e.g. #abc → #aabbcc) if (strlen($color_code) === 3) { $color_code = $color_code[0].$color_code[0] . $color_code[1].$color_code[1] . $color_code[2].$color_code[2]; } // Convert HEX to RGB $r = hexdec(substr($color_code, 0, 2)); $g = hexdec(substr($color_code, 2, 2)); $b = hexdec(substr($color_code, 4, 2)); // Calculate shade factor $factor = $shade_level / 100; $r = round($r + (255 - $r) * $factor); $g = round($g + (255 - $g) * $factor); $b = round($b + (255 - $b) * $factor); // Clamp values $r = max(0, min(255, $r)); $g = max(0, min(255, $g)); $b = max(0, min(255, $b)); // Return HEX return sprintf("#%02X%02X%02X", $r, $g, $b); } function pickuppt_get_logo() { $url = pickuppt_get_general_setting('logo_url') ?: PICKUPPOINTMENT_URL . 'admin/assets/img/default-logo.png'; return apply_filters('pickuppt_get_logo', $url); } function pickuppt_fields_to_skip_on_display() { return apply_filters('pickuppt_fields_to_skip_on_display', array( 'pickuppt_address', 'pickuppt_email', 'pickuppt_remarks', 'pickuppt_desc', 'pickuppt_weight', 'pickuppt_item', 'pickuppt_location_landmark', 'pickuppt_delivery_address_landmark', 'pickuppt_quant', 'pickuppt_payment_option' )); } function pickuppt_weight_units() { return apply_filters('pickuppt_weight_units', array( 'kg', 'g', 'lb', 'oz', )); } function pickuppt_get_appt_history($post_id) { $history_info = maybe_unserialize(get_post_meta($post_id, 'pickuppt_history', true)); $reversed = apply_filters('pickuppt_get_appt_history_reversed', true, $post_id); if($reversed && is_array($history_info)) { $history_info = array_reverse($history_info); } return $history_info; } function pickuppt_can_update() { $can_update = pickuppt_get_general_setting('can_update') ?: array(); $current_user_roles = wp_get_current_user()->roles; if(in_array('administrator', $current_user_roles)) { return true; } return array_intersect($can_update, $current_user_roles); } function pickuppt_get_month_date_range(int $month, int $year): array { $date = new DateTime(sprintf('%04d-%02d-01', $year, $month)); return [ 'first_day' => $date->format('Y-m-d'), 'last_day' => $date->format('Y-m-t') // "t" = number of days in the month ]; } function pickuppt_is_current_role(string $role_to_check) { $current_user_roles = wp_get_current_user()->roles ?? array(); return in_array($role_to_check, $current_user_roles); } function pickuppt_time_slot_interval() { $time_slot_interval = pickuppt_get_general_setting('time_slot_interval') ?: 10; if( (int)$time_slot_interval <= 0 ) { $time_slot_interval = 10; } return (int)$time_slot_interval; } function pickuppt_max_time_slot_cap() { $max_time_slot_cap = pickuppt_get_general_setting('max_time_slot_cap') ?: 1; if( (int)$max_time_slot_cap <= 0 ) { $max_time_slot_cap = 1; } return (int)$max_time_slot_cap; } function pickuppt_get_booked_times_by_date( $date ) { global $wpdb; // Validate date format (YYYY-MM-DD) $dt = DateTime::createFromFormat( 'Y-m-d', $date ); if ( ! $dt || $dt->format( 'Y-m-d' ) !== $date ) { return array(); } $results = $wpdb->get_col( $wpdb->prepare( " SELECT pm_time.meta_value FROM {$wpdb->postmeta} pm_date INNER JOIN {$wpdb->postmeta} pm_time ON pm_date.post_id = pm_time.post_id WHERE pm_date.meta_key = 'pickuppt_date' AND pm_date.meta_value = %s AND pm_time.meta_key = 'pickuppt_time' ", $date ) ); return $results ?: array(); } function pickuppt_get_disable_time_ranges( $date, $step, $return_raw_timeslots = false ) { $booked_times = pickuppt_get_booked_times_by_date( $date ); $booked_times_counts = array_count_values( $booked_times ); $max_capacity = pickuppt_max_time_slot_cap(); $booked_times = array_filter($booked_times, function ($item) use ($booked_times_counts, $max_capacity) { return $booked_times_counts[$item] >= $max_capacity; }); if( $return_raw_timeslots ) { return $booked_times; } $ranges = array(); foreach ( $booked_times as $time ) { $start = DateTime::createFromFormat( 'g:ia', strtolower( $time ) ); if ( ! $start ) { continue; } $end = clone $start; $end->modify( '+' . ( $step - 1 ) . ' minutes' ); $ranges[] = array( $start->format( 'g:ia' ), $end->format( 'g:ia' ), ); } return $ranges; } function pickuppt_calendar_week() { return array( 0 => __('Sunday', 'pickuppointment'), 1 => __('Monday', 'pickuppointment'), 2 => __('Tuesday', 'pickuppointment'), 3 => __('Wednesday', 'pickuppointment'), 4 => __('Thursday', 'pickuppointment'), 5 => __('Friday', 'pickuppointment'), 6 => __('Saturday', 'pickuppointment') ); } function pickuppt_datepicker_format() { return apply_filters('pickuppt_datepicker_date_format', 'yy-mm-dd'); } function pickuppt_sanitize_csv( $value ) { if ( ! is_string( $value ) ) { return ''; } $items = explode( ',', $value ); $items = array_map( 'sanitize_text_field', $items ); $items = array_filter( array_map( 'trim', $items ) ); return implode( ',', $items ); } function pickuppt_sanitize_email_placeholders( $value ) { if ( ! is_string( $value ) ) { return ''; } return sanitize_text_field( $value ); } function pickuppt_customer_information_label() { return apply_filters( 'pickuppt_customer_information_label', __( 'Customer Information', 'pickuppointment' ) ); } function pickuppt_pickup_information_label() { return apply_filters( 'pickuppt_pickup_information_label', __( 'Pickup & Delivery Information', 'pickuppointment' ) ); } function pickuppt_item_information_label() { return apply_filters( 'pickuppt_item_information_label', __( 'Item Information', 'pickuppointment' ) ); } function pickuppt_payment_information_label() { return apply_filters( 'pickuppt_payment_information_label', __( 'Payment Information', 'pickuppointment' ) ); } function pickuppt_pop_information_label() { return apply_filters( 'pickuppt_pop_information_label', __( 'Proof of Pickup', 'pickuppointment' ) ); } function pickuppt_pod_information_label() { return apply_filters( 'pickuppt_pod_information_label', __( 'Proof of Delivery', 'pickuppointment' ) ); } function pickuppt_poi_information_label() { return apply_filters( 'pickuppt_poi_information_label', __( 'Proof of Issue', 'pickuppointment' ) ); } function pickuppt_appt_history_label() { return apply_filters( 'pickuppt_appt_history_label', __( 'Appointment History', 'pickuppointment' ) ); } function pickuppt_unconfigured_payment_settings_label() { return apply_filters( 'pickuppt_unconfigured_payment_settings_label', __( 'Missing Payment Link or QR Code. Please configure your payment settings.', 'pickuppointment' ) ); } function pickuppt_payment_link_sent_label() { return apply_filters( 'pickuppt_payment_link_sent_label', __( 'Payment link sent!', 'pickuppointment' ) ); } function pickuppt_readable_date_format() { return apply_filters( 'pickuppt_readable_date_format', 'M d, Y' ); } function pickuppt_readable_time_format() { return apply_filters( 'pickuppt_readable_time_format', 'h:i A' ); } function pickuppt_send_assigned_driver_email( $post_id ) { $assigned_driver_id = get_post_meta( $post_id, 'pickuppt_assigned_driver', true ); if ( empty( $assigned_driver_id ) ) { return false; } // Driver details & safety check $driver_user_data = get_user_by( 'ID', $assigned_driver_id ); if ( ! $driver_user_data ) { return false; // Prevent fatal error if user does not exist } $driver_user_email = $driver_user_data->user_email; $driver_user_name = function_exists( 'pickuppt_fm_get_user_full_name' ) ? pickuppt_fm_get_user_full_name( $assigned_driver_id ) : $driver_user_data->display_name; // Dashboard URL $dashboard_url = function_exists( 'pickuppt_fm_main_page' ) ? get_the_permalink( pickuppt_fm_main_page() ) : home_url(); // Customer details $pickuppt_name = get_post_meta( $post_id, 'pickuppt_name', true ); $pickuppt_phone = get_post_meta( $post_id, 'pickuppt_phone', true ); // Date & Time formatting checks $pickuppt_date = get_post_meta( $post_id, 'pickuppt_date', true ); $date_format = function_exists( 'pickuppt_readable_date_format' ) ? pickuppt_readable_date_format() : get_option( 'date_format' ); $readable_date = ! empty( $pickuppt_date ) ? date_i18n( $date_format, strtotime( $pickuppt_date ) ) : __( 'N/A', 'pickuppointment' ); $pickuppt_time = get_post_meta( $post_id, 'pickuppt_time', true ); $time_format = function_exists( 'pickuppt_readable_time_format' ) ? pickuppt_readable_time_format() : get_option( 'time_format' ); $readable_time = ! empty( $pickuppt_time ) ? date_i18n( $time_format, strtotime( $pickuppt_time ) ) : __( 'N/A', 'pickuppointment' ); // Destination handling $pickuppt_location = get_post_meta( $post_id, 'pickuppt_location', true ); $pickuppt_delivery_warehouse = get_post_meta( $post_id, 'pickuppt_delivery_warehouse', true ); $pickuppt_delivery_address = get_post_meta( $post_id, 'pickuppt_delivery_address', true ); $final_delivery_address = ''; if ( function_exists( 'pickuppt_custom_destination' ) && pickuppt_custom_destination() ) { $final_delivery_address = $pickuppt_delivery_address; } elseif ( function_exists( 'pickuppt_warehouses' ) ) { $warehouses = pickuppt_warehouses( true ); $final_delivery_address = $warehouses[ $pickuppt_delivery_warehouse ] ?? ''; } $theme_color = function_exists( 'pickuppt_get_general_setting' ) ? pickuppt_get_general_setting('theme_color') : '#0073aa'; // Dynamic subject line $appointment_title = get_the_title( $post_id ); /* translators: 1: Blog name, 2: Appointment title */ $email_subject = sprintf( __( '[%1$s] New Delivery Assigned: %2$s', 'pickuppointment' ), get_bloginfo( 'name' ), $appointment_title ); $_email_subject = apply_filters( 'pickuppt_assigned_driver_email_subject', $email_subject, $post_id, $driver_user_data ); // Mobile-optimized HTML layout /* translators: %s: Driver Name */ $email_content = '
' . sprintf( __( 'Hello %s,', 'pickuppointment' ), esc_html( $driver_user_name ) ) . '
'; $email_content .= '' . __( 'You have been assigned a new pickup and delivery job. Please review the assignment details below:', 'pickuppointment' ) . '
'; $email_content .= '' . __( 'Customer Name:', 'pickuppointment' ) . ' ' . esc_html( $pickuppt_name ) . '
'; $email_content .= '' . __( 'Customer Phone:', 'pickuppointment' ) . ' ' . esc_html( $pickuppt_phone ) . '
'; $email_content .= '' . __( 'Pickup Schedule:', 'pickuppointment' ) . ' ' . esc_html( $readable_date ) . ' @ ' . esc_html( $readable_time ) . '
'; $email_content .= '' . __( 'Pickup Origin:', 'pickuppointment' ) . ' ' . esc_html( $pickuppt_location ) . '
'; $email_content .= '' . __( 'Drop-off Destination:', 'pickuppointment' ) . ' ' . esc_html( $final_delivery_address ) . '
'; $email_content .= '' . sprintf( __( 'Access your driver dashboard to start the job: View Driver Dashboard.', 'pickuppointment' ), esc_url( $dashboard_url ), esc_attr( $theme_color ) ) . '
'; $email_content .= '' . __( 'Safe travels,', 'pickuppointment' ) . '
' . esc_html( get_bloginfo( 'name' ) ) . '
' . sprintf( __( 'Hello %s,', 'pickuppointment' ), esc_html( $customer_name ? $customer_name : __( 'Customer', 'pickuppointment' ) ) ) . '
'; /* translators: 1: Blog name, 2: Appointment title */ $email_content .= '' . sprintf( __( 'Thank you for booking with %1$s. Please complete your payment for appointment %2$s using one of the options below:', 'pickuppointment' ), esc_html( get_bloginfo( 'name' ) ), esc_html( $appointment_title ) ) . '
'; $email_content .= '' . __( 'Charge Breakdown:', 'pickuppointment' ) . '
'; $email_content .= '| ' . __( 'Description', 'pickuppointment' ) . ' | '; $email_content .= '' . __( 'Amount', 'pickuppointment' ) . ' | '; $email_content .= '
|---|---|
| ' . esc_html( $desc ) . ' | '; $email_content .= '' . number_format( $amount, 2 ) . ' | '; $email_content .= '
| ' . __( 'Total:', 'pickuppointment' ) . ' | '; $email_content .= '' . number_format( $total_amount, 2 ) . ' | '; $email_content .= '
' . __( '— OR —', 'pickuppointment' ) . '
'; } $email_content .= '' . __( 'Scan QR Code to Pay:', 'pickuppointment' ) . '
'; $email_content .= '' . __( 'If you have already made the payment or have any questions, please reply directly to this email.', 'pickuppointment' ) . '
'; $email_content .= '' . __( 'Best regards,', 'pickuppointment' ) . '
' . esc_html( get_bloginfo( 'name' ) ) . '