├── .gitignore ├── index.php ├── .DS_Store ├── assets ├── logos │ ├── aras.png │ ├── dhl.png │ ├── filo.png │ ├── iyi.png │ ├── mng.png │ ├── ptt.png │ ├── tex.png │ ├── tnt.png │ ├── ups.png │ ├── fedex.png │ ├── horoz.png │ ├── sendeo.png │ ├── surat.png │ ├── carrtell.png │ ├── hepsijet.png │ ├── postman.png │ └── yurtici.png └── js │ └── kargo-checkout.js ├── .github └── workflows │ └── main.yml ├── mail-template ├── email-shipment-template.php └── email-shipment-update-template.php ├── kobikom-helper.php ├── config.php ├── kargo-takip-dashboard.php ├── readme.txt ├── kargo-takip-wc-api-helper.php ├── kargo-takip-helper.php ├── kargo-takip-order-list.php ├── kargo-takip-bulk-import.php ├── kargo-takip-checkout-fields.php ├── netgsm-helper.php ├── CLAUDE.md ├── kargo-takip-whatsapp-settings.php ├── kargo-takip-cargo-settings.php └── kargo-takip-cities-districts.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 |

get_billing_first_name())); ?>

30 |

Siparişiniz kargoya verilmiştir. Takip bilgileri aşağıda yer almaktadır: 31 |

32 |

Kargo Firması Adı:

35 |

Kargo Takip No:

36 | '; 39 | 40 | ?> 41 | 42 | Kargonuzu izlemek için buraya tıklayın. 43 | 44 |
45 |
46 | 47 | 48 | 49 | 25 | 26 | 27 | 28 | 29 |

get_billing_first_name()));?>

30 |

Siparişiniz kargoya verilmiştir. Takip bilgileri aşağıda yer almaktadır:

31 |

Kargo Firması Adı:

34 |

Kargo Takip No:

35 | '; 38 | 39 | ?> 40 | 41 | Kargonuzu izlemek için buraya tıklayın. 42 | 43 |
44 |
45 | 46 | 47 | 48 | get_billing_phone(); 33 | 34 | // Telefon numarası temizleme ve formatlama (905xxxxxxxxx) 35 | $phone = preg_replace('/[^0-9]/', '', $phone); 36 | if (strlen($phone) == 10) { 37 | $phone = '90' . $phone; 38 | } elseif (strlen($phone) == 11 && substr($phone, 0, 1) == '0') { 39 | $phone = '90' . substr($phone, 1); 40 | } 41 | 42 | $Kobikom_ApiKey = get_option('Kobikom_ApiKey'); 43 | $KobiKom_Header = get_option('Kobikom_Header'); 44 | 45 | $message = kargoTR_get_sms_template($order_id, get_option('kargoTR_sms_template')); 46 | 47 | $url = "https://sms.kobikom.com.tr/api/message/send"; 48 | $params = array( 49 | 'api_token' => $Kobikom_ApiKey, 50 | 'to' => $phone, 51 | 'from' => $KobiKom_Header, 52 | 'message' => $message, 53 | 'unicode' => 1 54 | ); 55 | 56 | $request_url = add_query_arg($params, $url); 57 | $request = wp_remote_get($request_url); 58 | 59 | if (is_wp_error($request)) { 60 | $order->add_order_note("Sms Gönderilemedi - Kobikom Hatası: " . $request->get_error_message()); 61 | } else { 62 | $body = wp_remote_retrieve_body($request); 63 | $response = json_decode($body, true); 64 | 65 | if (!empty($response['data'][0]['uuid'])) { 66 | $order->add_order_note("Sms Gönderildi - Kobikom SMS Kodu : " . $response['data'][0]['uuid']); 67 | } else { 68 | $order->add_order_note("Kobikom SMS Yanıtı: " . $body); 69 | } 70 | } 71 | } 72 | 73 | add_action('order_send_sms_kobikom', 'kargoTR_SMS_gonder_kobikom'); 74 | 75 | 76 | 77 | 78 | 79 | ?> -------------------------------------------------------------------------------- /assets/js/kargo-checkout.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function($) { 2 | if (typeof kargoData === 'undefined') { 3 | return; 4 | } 5 | 6 | function replaceInputWithSelect(type) { 7 | var cityInput = $('#' + type + '_city'); 8 | if (cityInput.length && cityInput.is('input[type="text"]')) { 9 | var parentDiv = cityInput.closest('.woocommerce-input-wrapper, .form-row'); 10 | var select = $('') 11 | .attr('id', type + '_city') 12 | .attr('name', type + '_city') 13 | .attr('autocomplete', cityInput.attr('autocomplete') || '') 14 | .addClass(cityInput.attr('class') || '') 15 | .addClass('kargo-district-select'); 16 | 17 | cityInput.replaceWith(select); 18 | return select; 19 | } else if (cityInput.length && cityInput.is('select')) { 20 | if (!cityInput.hasClass('kargo-district-select')) { 21 | cityInput.addClass('kargo-district-select'); 22 | } 23 | return cityInput; 24 | } 25 | return null; 26 | } 27 | 28 | function updateDistricts(type) { 29 | var citySelect = $('#' + type + '_state'); 30 | var districtSelect = replaceInputWithSelect(type); 31 | 32 | if (!districtSelect) return; 33 | 34 | var cityId = citySelect.val(); 35 | var currentDistrict = districtSelect.val(); 36 | 37 | districtSelect.empty(); 38 | 39 | if (!cityId || cityId === '') { 40 | districtSelect.append($('').attr('value', '').text(kargoData.choose_city_first)); 41 | districtSelect.prop('disabled', true); 42 | } else { 43 | districtSelect.prop('disabled', false); 44 | districtSelect.append($('').attr('value', '').text(kargoData.select_district_text)); 45 | 46 | if (kargoData.districts[cityId]) { 47 | $.each(kargoData.districts[cityId], function(id, name) { 48 | var option = $('').attr('value', name).text(name); 49 | if (currentDistrict === name) { 50 | option.prop('selected', true); 51 | } 52 | districtSelect.append(option); 53 | }); 54 | } 55 | } 56 | districtSelect.trigger('change'); 57 | } 58 | 59 | function handleCountryChange(type) { 60 | var country = $('#' + type + '_country').val(); 61 | if (country === 'TR') { 62 | updateDistricts(type); 63 | } 64 | } 65 | 66 | // Bind events 67 | $(document.body).on('change', '#billing_state, #shipping_state', function() { 68 | var type = $(this).attr('id').includes('billing') ? 'billing' : 'shipping'; 69 | if ($('#' + type + '_country').val() === 'TR') { 70 | updateDistricts(type); 71 | } 72 | }); 73 | 74 | $(document.body).on('change', '#billing_country, #shipping_country', function() { 75 | var type = $(this).attr('id').includes('billing') ? 'billing' : 'shipping'; 76 | setTimeout(function() { 77 | handleCountryChange(type); 78 | }, 100); 79 | }); 80 | 81 | // Initial run on load/update 82 | function initFields() { 83 | if ($('#billing_country').val() === 'TR') { 84 | handleCountryChange('billing'); 85 | } 86 | if ($('#shipping_country').val() === 'TR') { 87 | handleCountryChange('shipping'); 88 | } 89 | if ($.fn.select2) { 90 | $('.kargo-district-select').select2(); 91 | } 92 | } 93 | 94 | $(document.body).on('updated_checkout', function() { 95 | setTimeout(initFields, 100); 96 | }); 97 | 98 | initFields(); 99 | }); 100 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | array( 5 | "ptt" => array( 6 | "company" => "PTT Kargo", 7 | "url" => "https://gonderitakip.ptt.gov.tr/Track/Verify?q=", 8 | "logo" => "assets/logos/ptt.png", 9 | ), 10 | "yurtici" => array( 11 | "company" => "Yurtiçi Kargo", 12 | "url" => "https://www.yurticikargo.com/tr/online-servisler/gonderi-sorgula?code=", 13 | "logo" => "assets/logos/yurtici.png" 14 | ), 15 | "aras" => array( 16 | "company" => "Aras Kargo", 17 | "url" => "https://ebranch.araskargo.com.tr/track/", 18 | "logo" => "assets/logos/aras.png" 19 | ), 20 | "mng" => array( 21 | "company" => "MNG Kargo", 22 | "url" => "http://service.mngkargo.com.tr/iactive/popup/KargoTakip/link1.asp?k=", 23 | "logo" => "assets/logos/mng.png" 24 | ), 25 | "horoz" => array( 26 | "company" => "Horoz Kargo", 27 | "url" => "https://app3.horoz.com.tr/wsKurumsal/_genel/frmGonderiTakip.aspx?lng=tr", 28 | "logo" => "assets/logos/horoz.png" 29 | ), 30 | "ups" => array( 31 | "company" => "UPS Kargo", 32 | "url" => "https://www.ups.com.tr/WaybillSorgu.aspx?Waybill=", 33 | "logo" => "assets/logos/ups.png" 34 | ), 35 | "surat" => array( 36 | "company" => "Sürat Kargo", 37 | "url" => "https://www.suratkargo.com.tr/KargoTakip/?kargotakipno=", 38 | "logo" => "assets/logos/surat.png" 39 | ), 40 | "filo" => array( 41 | "company" => "Filo Kargo", 42 | "url" => "http://filloweb.fillo.com.tr/GonderiTakip", 43 | "logo" => "assets/logos/filo.png" 44 | ), 45 | "tnt" => array( 46 | "company" => "TNT Kargo", 47 | "url" => "https://www.tnt.com/express/tr_tr/site/shipping-tools/tracking.html?searchType=con&cons=", 48 | "logo" => "assets/logos/tnt.png" 49 | ), 50 | "dhl" => array( 51 | "company" => "DHL Kargo", 52 | "url" => "https://www.dhl.com/tr-tr/home/tracking.html?tracking-id=", 53 | "logo" => "assets/logos/dhl.png" 54 | ), 55 | "fedex" => array( 56 | "company" => "Fedex Kargo", 57 | "url" => "https://www.fedex.com/fedextrack/?action=track&tracknumbers=", 58 | "logo" => "assets/logos/fedex.png" 59 | ), 60 | "foodman" => array( 61 | "company" => "FoodMan Kargo", 62 | "url" => "https://www.foodman.online/GonderiSorgu.aspx?gonderino=", 63 | "logo" => "assets/logos/foodman.png" 64 | ), 65 | "postman" => array( 66 | "company" => "Postman Kargo", 67 | "url" => "http://85.99.122.231/hareket.asp?har_kod=", 68 | "logo" => "assets/logos/postman.png" 69 | ), 70 | "iyi" => array( 71 | "company" => "İyi Kargo", 72 | "url" => "https://www.geowix.com/kargom-nerede?tracking_code=", 73 | "logo" => "assets/logos/iyi.png" 74 | ), 75 | "tex" => array( 76 | "company" => "Trendyol Express", 77 | "url" => "https://kargotakip.trendyol.com/?orderNumber=", 78 | "logo" => "assets/logos/tex.png" 79 | ), 80 | "hepsijet" => array( 81 | "company" => "HepsiJET", 82 | "url" => "https://www.hepsijet.com/gonderi-takibi/", 83 | "logo" => "assets/logos/hepsijet.png" 84 | ), 85 | "Sendeo" => array( 86 | "company" => "Sendeo Kargo", 87 | "url" => "https://www.sendeo.com.tr/kargo-takip/", 88 | "logo" => "assets/logos/sendeo.png" 89 | ), 90 | "carrtell" => array( 91 | "company" => "Carrtell Kargo", 92 | "url" => "https://takip.carrtell.co/", 93 | "logo" => "assets/logos/carrtell.png" 94 | ), 95 | 96 | ) 97 | ); -------------------------------------------------------------------------------- /kargo-takip-dashboard.php: -------------------------------------------------------------------------------- 1 | array('wc-kargo-verildi', 'wc-completed'), 24 | 'meta_query' => array( 25 | array( 26 | 'key' => '_kargo_takip_timestamp', 27 | 'value' => $yesterday, 28 | 'compare' => '>=' 29 | ) 30 | ), 31 | 'limit' => -1, 32 | 'return' => 'ids', 33 | ); 34 | 35 | $shipped_today_query = wc_get_orders($args); 36 | $shipped_today_count = count($shipped_today_query); 37 | 38 | ?> 39 |
40 |
41 |
42 | 43 |
44 |
Bekleyen Sipariş
45 |
46 |
47 | 48 |
49 |
Son 24 Saatte Kargolanan
50 |
51 |
52 | 53 |
54 | Siparişleri Gör 55 | Toplu Kargo Girişi 56 |
57 |
58 | 59 | 101 | > Siparişler sayfasındaki Sipariş bölümüne düğme eklendi. 149 | Sipariş detayları sayfasına kargo firması adı ve kargo takip gösterme eklendi. 150 | Ufak hatalar düzeltildi. 151 | = 0.0.1 = 152 | Eklenti oluşturuldu -------------------------------------------------------------------------------- /kargo-takip-wc-api-helper.php: -------------------------------------------------------------------------------- 1 | 'post', 11 | 'callback' => 'kargoTR_api_add_tracking_code', 12 | 'permission_callback' => function () { 13 | return current_user_can( 'edit_shop_orders' ); 14 | }, 15 | 'check_authentication' => true, 16 | ) ); 17 | } ); 18 | 19 | function kargoTR_api_add_tracking_code() { 20 | 21 | // Get order id, shipment company, and tracking code from the request 22 | $order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0; 23 | $shipment_company = isset($_POST['shipment_company']) ? sanitize_text_field($_POST['shipment_company']) : ''; 24 | $tracking_code = isset($_POST['tracking_code']) ? sanitize_text_field($_POST['tracking_code']) : ''; 25 | $tracking_estimated_date = isset($_POST['tracking_estimated_date']) ? sanitize_text_field($_POST['tracking_estimated_date']) : ''; 26 | 27 | // Check if the user is logged in 28 | if (!is_user_logged_in()) { 29 | return new WP_Error('rest_not_logged_in', 'You are not currently logged in.', array('status' => 401)); 30 | } 31 | 32 | // Check if the user has permission to edit orders 33 | if (!current_user_can('edit_shop_orders')) { 34 | return new WP_Error('rest_cannot_edit', 'Sorry, you are not allowed to edit this resource.', array('status' => 401)); 35 | } 36 | 37 | // Check if the shipment company is provided 38 | if (!$shipment_company) { 39 | return new WP_Error('rest_invalid_shipment_company', 'Shipment company missing. Please post shipment_company', array('status' => 401)); 40 | } 41 | 42 | // Check if the tracking code is provided 43 | if (!$tracking_code) { 44 | return new WP_Error('rest_invalid_tracking_code', 'Tracking code missing. Please post tracking_code', array('status' => 401)); 45 | } 46 | 47 | // Check if the order id is provided 48 | if (!$order_id) { 49 | return new WP_Error('rest_invalid_order_id', 'Order id missing. Please post order_id', array('status' => 401)); 50 | } 51 | 52 | // Check if the shipment company is valid 53 | if (!kargoTR_is_valid_shipment_company($shipment_company)) { 54 | return new WP_Error('rest_invalid_shipment_company', 'Invalid shipment company. Should be same as document list', array('status' => 401)); 55 | } 56 | 57 | // Check if the order id is valid 58 | if (!kargoTR_is_valid_order_id($order_id)) { 59 | return new WP_Error('rest_invalid_order_id', 'Invalid order id. Please check order id', array('status' => 401)); 60 | } 61 | 62 | // Get order details from order id (HPOS uyumlu) 63 | $order = wc_get_order($order_id); 64 | if (!$order) { 65 | return new WP_Error('rest_invalid_order', 'Order not found', array('status' => 404)); 66 | } 67 | 68 | $tracking_company_order = $order->get_meta('tracking_company', true); 69 | $tracking_code_order = $order->get_meta('tracking_code', true); 70 | $mail_send_general_option = get_option('mail_send_general'); 71 | $sms_provider = get_option('sms_provider'); 72 | 73 | // Check if the order has a tracking code, if yes, update it 74 | if ($tracking_company_order && $tracking_code_order) { 75 | $order->update_meta_data('tracking_company', $shipment_company); 76 | $order->update_meta_data('tracking_code', $tracking_code); 77 | 78 | if ($tracking_estimated_date) { 79 | $order->update_meta_data('tracking_estimated_date', $tracking_estimated_date); 80 | } 81 | 82 | // Save specific timestamp for statistics 83 | $order->update_meta_data('_kargo_takip_timestamp', current_time('mysql')); 84 | $order->save(); 85 | 86 | $order->add_order_note( 87 | sprintf( 88 | __('Kargo takip numarası güncellendi. Kargo şirketi: %s, Takip numarası: %s', 'woocommerce'), 89 | $shipment_company, 90 | $tracking_code 91 | ) 92 | ); 93 | 94 | // Return update message 95 | return array( 96 | 'status' => 'success', 97 | 'message' => 'Kargo takip numarası güncellendi.' 98 | ); 99 | 100 | } else { 101 | $order->update_meta_data('tracking_company', $shipment_company); 102 | $order->update_meta_data('tracking_code', $tracking_code); 103 | 104 | if ($tracking_estimated_date) { 105 | $order->update_meta_data('tracking_estimated_date', $tracking_estimated_date); 106 | } else { 107 | // Auto-calculate if not provided and feature is enabled 108 | $estimated_delivery_enabled = get_option('kargo_estimated_delivery_enabled', 'no'); 109 | if ($estimated_delivery_enabled === 'yes') { 110 | $default_days = get_option('kargo_estimated_delivery_days', '3'); 111 | $company_days = get_option('kargoTR_cargo_delivery_times', array()); 112 | 113 | $days = $default_days; 114 | if ($shipment_company && isset($company_days[$shipment_company])) { 115 | $days = $company_days[$shipment_company]; 116 | } 117 | 118 | if ($days > 0) { 119 | $estimated_date = date('Y-m-d', strtotime("+$days days")); 120 | $order->update_meta_data('tracking_estimated_date', $estimated_date); 121 | } 122 | } 123 | } 124 | 125 | $order->save(); 126 | 127 | $order->add_order_note( 128 | sprintf( 129 | __('Kargo takip numarası eklendi. Kargo şirketi: %s, Takip numarası: %s', 'woocommerce'), 130 | $shipment_company, 131 | $tracking_code 132 | ) 133 | ); 134 | 135 | // Send mail to customer if mail send option is true 136 | if ($mail_send_general_option == 'yes') { 137 | do_action('order_ship_mail', $order_id); 138 | } 139 | 140 | // Send SMS to customer if SMS provider is NetGSM 141 | if ($sms_provider == 'NetGSM') { 142 | do_action('order_send_sms', $order_id); 143 | } 144 | 145 | // Return success message 146 | return array( 147 | 'status' => 'success', 148 | 'message' => 'Kargo takip numarası eklendi.' 149 | ); 150 | } 151 | } 152 | 153 | 154 | 155 | function kargoTR_is_valid_shipment_company($shipment_company) { 156 | // Check if the shipment company variable is empty or not 157 | if (empty($shipment_company)) { 158 | return false; 159 | } 160 | 161 | // Tüm kargo firmalarını al (config + custom, disabled dahil) 162 | $all_cargoes = kargoTR_get_all_cargoes(true); 163 | 164 | // Check if shipment company is in array keys 165 | return array_key_exists($shipment_company, $all_cargoes); 166 | } 167 | 168 | 169 | 170 | function kargoTR_is_valid_order_id($order_id) { 171 | // Check if the order_id variable is empty or not 172 | if (empty($order_id)) { 173 | return false; 174 | } 175 | 176 | // Get order from order id 177 | $order = wc_get_order($order_id); 178 | 179 | // Check if order is valid 180 | return $order ? true : false; 181 | } 182 | 183 | -------------------------------------------------------------------------------- /kargo-takip-helper.php: -------------------------------------------------------------------------------- 1 | "Kargo Firması Seçiniz"]; 106 | foreach($cargoes as $key => $cargo) { 107 | $companies[$key] = $cargo["company"]; 108 | } 109 | return $companies; 110 | } 111 | 112 | 113 | /** 114 | * Order Numarasına göre kargo logosunu verir eğer yoksa boş döner 115 | * 116 | * @param int $order_id sipariş ID 117 | * @return string logo path veya boş 118 | */ 119 | 120 | function kargoTR_get_order_cargo_logo($order_id) { 121 | $order = wc_get_order($order_id); 122 | if (!$order) return ""; 123 | // HPOS uyumlu meta okuma 124 | $tracking_company = $order->get_meta('tracking_company', true); 125 | 126 | if($tracking_company) { 127 | $cargoes = kargoTR_get_all_cargoes(); 128 | 129 | if(isset($cargoes[$tracking_company]) && !empty($cargoes[$tracking_company]["logo"])) { 130 | return $cargoes[$tracking_company]["logo"]; 131 | } 132 | } 133 | 134 | return ""; 135 | } 136 | 137 | //Function return tracking code, company name and tracking url 138 | 139 | function kargoTR_get_order_cargo_information($order_id) { 140 | $order = wc_get_order($order_id); 141 | if (!$order) return ""; 142 | // HPOS uyumlu meta okuma 143 | $tracking_company = $order->get_meta('tracking_company', true); 144 | $tracking_code = $order->get_meta('tracking_code', true); 145 | 146 | if($tracking_company) { 147 | $cargoes = kargoTR_get_all_cargoes(); 148 | 149 | if(isset($cargoes[$tracking_company])) { 150 | $logo = isset($cargoes[$tracking_company]["logo"]) ? $cargoes[$tracking_company]["logo"] : ""; 151 | $company = $cargoes[$tracking_company]["company"]; 152 | 153 | // URL'de {code} placeholder'ı varsa değiştir, yoksa sona ekle 154 | $base_url = $cargoes[$tracking_company]["url"]; 155 | if (strpos($base_url, '{code}') !== false) { 156 | $url = str_replace('{code}', $tracking_code, $base_url); 157 | } else { 158 | $url = $base_url . $tracking_code; 159 | } 160 | 161 | return array( 162 | "logo" => $logo, 163 | "company" => $company, 164 | "url" => $url 165 | ); 166 | } 167 | } 168 | 169 | return ""; 170 | } 171 | 172 | // Sms template function 173 | 174 | function kargoTR_get_sms_template($order_id, $template) { 175 | $order = wc_get_order($order_id); 176 | if (!$order) return $template; 177 | // HPOS uyumlu meta okuma 178 | $tracking_company = $order->get_meta('tracking_company', true); 179 | $tracking_code = $order->get_meta('tracking_code', true); 180 | //client name 181 | $client_name = $order->get_billing_first_name() . " " . $order->get_billing_last_name(); 182 | 183 | //template from database if not provided 184 | if (empty($template)) { 185 | $template = get_option("kargoTR_sms_template"); 186 | } 187 | 188 | //replace fields 189 | //{customer_name} for client name 190 | //{tracking_number} for cargo tracking code 191 | //{tracking_url} for cargo tracking url 192 | //{company_name} for cargo company name 193 | //{order_id} for order id 194 | 195 | $template = str_replace("{customer_name}", $client_name, $template); 196 | $template = str_replace("{tracking_number}", $tracking_code, $template); 197 | $template = str_replace("{tracking_url}", kargoTR_getCargoTrack($tracking_company, $tracking_code), $template); 198 | $template = str_replace("{company_name}", kargoTR_get_company_name($tracking_company), $template); 199 | $template = str_replace("{order_id}", $order_id, $template); 200 | 201 | // Estimated Delivery Date (HPOS uyumlu) 202 | $estimated_delivery_enabled = get_option('kargo_estimated_delivery_enabled', 'no'); 203 | $formatted_date = ''; 204 | if ($estimated_delivery_enabled === 'yes') { 205 | $tracking_estimated_date = $order->get_meta('tracking_estimated_date', true); 206 | if ($tracking_estimated_date) { 207 | $formatted_date = date_i18n(get_option('date_format'), strtotime($tracking_estimated_date)); 208 | } 209 | } 210 | $template = str_replace("{estimated_delivery_date}", $formatted_date, $template); 211 | 212 | return $template; 213 | } 214 | -------------------------------------------------------------------------------- /kargo-takip-order-list.php: -------------------------------------------------------------------------------- 1 | $column){ 17 | $reordered_columns[$key] = $column; 18 | // Check for both legacy 'order_status' and HPOS 'status' keys 19 | if( $key == 'order_status' || $key == 'status' ){ 20 | // Inserting after "Status" column 21 | $reordered_columns['kargo-sent-with'] = __( 'Kargo Firması','theme_domain'); 22 | $inserted = true; 23 | } 24 | } 25 | 26 | // If status column not found, append to end (before actions if possible) 27 | if (!$inserted) { 28 | // Try to insert before actions 29 | if (isset($reordered_columns['wc_actions'])) { 30 | $actions = $reordered_columns['wc_actions']; 31 | unset($reordered_columns['wc_actions']); 32 | $reordered_columns['kargo-sent-with'] = __( 'Kargo Firması','theme_domain'); 33 | $reordered_columns['wc_actions'] = $actions; 34 | } else { 35 | $reordered_columns['kargo-sent-with'] = __( 'Kargo Firması','theme_domain'); 36 | } 37 | } 38 | 39 | return $reordered_columns; 40 | } 41 | 42 | // Adding custom fields meta data for each new column 43 | // Legacy 44 | add_action( 'manage_shop_order_posts_custom_column' , 'kargoTR_shipping_information_column_content', 20, 2 ); 45 | // HPOS 46 | add_action( 'manage_woocommerce_page_wc-orders_custom_column', 'kargoTR_shipping_information_column_content_hpos', 20, 2 ); 47 | 48 | function kargoTR_shipping_information_column_content_hpos( $column, $order ) { 49 | kargoTR_shipping_information_column_content( $column, $order->get_id() ); 50 | } 51 | 52 | function kargoTR_shipping_information_column_content( $column, $post_id ) 53 | { 54 | switch ( $column ) 55 | { 56 | case 'kargo-sent-with': 57 | // HPOS uyumlu meta okuma 58 | $order = wc_get_order($post_id); 59 | $tracking_company = $order ? $order->get_meta('tracking_company', true) : ''; 60 | $tracking_code = $order ? $order->get_meta('tracking_code', true) : ''; 61 | echo ''; 62 | echo ''; 63 | 64 | if ($tracking_company) { 65 | $company_name = kargoTR_get_company_name($tracking_company); 66 | $information = kargoTR_get_order_cargo_information($post_id); 67 | 68 | if ($information && !empty($information["logo"])) { 69 | $logo_url = plugin_dir_url( __FILE__ ).$information["logo"]; 70 | // Wrap with URL if tracking code exists 71 | if (!empty($information["url"])) { 72 | echo ""; 73 | echo ""; 74 | echo ""; 75 | } else { 76 | echo ""; 77 | } 78 | } else { 79 | // Text fallback 80 | if ($information && !empty($information["url"])) { 81 | echo "".esc_html($company_name).""; 82 | } else { 83 | echo esc_html($company_name); 84 | } 85 | } 86 | } else { 87 | echo '-'; 88 | } 89 | break; 90 | } 91 | } 92 | 93 | // Add Quick Edit Fields 94 | add_action('quick_edit_custom_box', 'kargoTR_add_quick_edit_fields', 10, 2); 95 | function kargoTR_add_quick_edit_fields($column_name, $post_type) { 96 | // Updated to check for new column name 97 | if ($column_name != 'kargo-sent-with' && $column_name != 'kargo-information') { // Keep legacy check just in case 98 | if ($column_name != 'kargo-sent-with') return; 99 | } 100 | 101 | // Get cargo companies 102 | $cargoes = kargoTR_get_all_cargoes(true); 103 | ?> 104 |
105 |
106 |

Kargo Bilgileri

107 | 116 | 122 |
123 |
124 | id) ? $current_screen->id : ''; 133 | if ($screen_id != 'edit-shop_order' && $screen_id != 'shop_order' && strpos($screen_id, 'woocommerce_page_wc-orders') === false) { 134 | return; 135 | } 136 | ?> 137 | 164 | 10 |
11 |

Toplu Kargo Takip Girişi (Excel/CSV)

12 | 13 |
14 |

CSV Dosyası Yükle

15 |

Günlük kargo gönderimlerinizi toplu olarak sisteme yükleyebilirsiniz. Dosya formatı aşağıdaki gibi olmalıdır:

16 | 17 |
18 | Format: Sipariş No, Kargo Firması, Takip Numarası
19 | Örnek: 12345, Yurtici, 123456789012 20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 53 | 54 |
29 | 30 |

Lütfen .csv uzantılı dosya yükleyiniz.

31 |
Ayarlar 36 |
37 | 41 |
42 | 46 |
47 | 51 |
52 |
55 | 56 |

57 | 58 |

59 |
60 |
61 | 62 |
63 |

Kargo Firma Kodları

64 |

CSV dosyasında kullanabileceğiniz kargo firması isimleri (büyük/küçük harf duyarlı değildir):

65 |

66 | 71 |

72 |
73 |
74 |

Dosya yüklenirken bir hata oluştu.

'; 80 | return; 81 | } 82 | 83 | $file = $_FILES['csv_file']['tmp_name']; 84 | $handle = fopen($file, "r"); 85 | 86 | if ($handle === FALSE) { 87 | echo '

Dosya açılamadı.

'; 88 | return; 89 | } 90 | 91 | $success_count = 0; 92 | $error_count = 0; 93 | $errors = array(); 94 | 95 | $send_sms = isset($_POST['send_sms']) && $_POST['send_sms'] === 'yes'; 96 | $send_email = isset($_POST['send_email']) && $_POST['send_email'] === 'yes'; 97 | $complete_order = isset($_POST['complete_order']) && $_POST['complete_order'] === 'yes'; 98 | 99 | // Get all cargo companies for validation (lowercase keys) 100 | $cargoes = kargoTR_get_all_cargoes(true); 101 | $cargoes_lower = array_change_key_case($cargoes, CASE_LOWER); 102 | 103 | while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 104 | // Skip empty rows 105 | if (empty($data[0])) continue; 106 | 107 | // Clean data 108 | $order_id = intval(trim($data[0])); 109 | $cargo_company_input = trim($data[1]); 110 | $tracking_code = trim($data[2]); 111 | 112 | // Validate Order 113 | $order = wc_get_order($order_id); 114 | if (!$order) { 115 | $error_count++; 116 | $errors[] = "Sipariş ID {$order_id} bulunamadı."; 117 | continue; 118 | } 119 | 120 | // Validate Cargo Company 121 | $cargo_company_key = ''; 122 | $input_lower = strtolower($cargo_company_input); 123 | 124 | // Try to match input with keys 125 | foreach ($cargoes as $key => $value) { 126 | if (strtolower($key) == $input_lower || strtolower($value) == $input_lower) { 127 | $cargo_company_key = $key; 128 | break; 129 | } 130 | } 131 | 132 | // If not found, check if it's a valid key directly 133 | if (empty($cargo_company_key) && array_key_exists($input_lower, $cargoes_lower)) { 134 | // Find original case key 135 | foreach ($cargoes as $key => $value) { 136 | if (strtolower($key) == $input_lower) { 137 | $cargo_company_key = $key; 138 | break; 139 | } 140 | } 141 | } 142 | 143 | if (empty($cargo_company_key)) { 144 | // Default to 'diger' or keep empty? Let's skip if invalid to be safe 145 | // Or maybe user entered "Yurtici Kargo" instead of "Yurtici" 146 | // Let's try to be lenient, if not found, use input as is if it's not empty? 147 | // No, plugin logic relies on keys. 148 | $error_count++; 149 | $errors[] = "Sipariş {$order_id}: Geçersiz kargo firması '{$cargo_company_input}'."; 150 | continue; 151 | } 152 | 153 | // Update Order Meta (HPOS uyumlu) 154 | $order->update_meta_data('tracking_company', $cargo_company_key); 155 | $order->update_meta_data('tracking_code', $tracking_code); 156 | 157 | // Save specific timestamp for statistics 158 | $order->update_meta_data('_kargo_takip_timestamp', current_time('mysql')); 159 | $order->save(); 160 | 161 | // Add Note 162 | $order->add_order_note(sprintf('Toplu yükleme ile kargo bilgisi girildi. Firma: %s, Takip No: %s', $cargo_company_key, $tracking_code)); 163 | 164 | // Update Status 165 | if ($complete_order) { 166 | // Check if 'wc-kargo-verildi' exists, otherwise use 'completed' 167 | $statuses = wc_get_order_statuses(); 168 | if (array_key_exists('wc-kargo-verildi', $statuses)) { 169 | $order->update_status('kargo-verildi'); 170 | } else { 171 | $order->update_status('completed'); 172 | } 173 | } 174 | 175 | // Trigger Notifications 176 | if ($send_email) { 177 | do_action('order_ship_mail', $order_id); 178 | } 179 | 180 | if ($send_sms) { 181 | $sms_provider = get_option('sms_provider'); 182 | if ($sms_provider == 'NetGSM') { 183 | do_action('order_send_sms', $order_id); 184 | } elseif ($sms_provider == 'Kobikom') { 185 | do_action('order_send_sms_kobikom', $order_id); 186 | } 187 | } 188 | 189 | $success_count++; 190 | } 191 | 192 | fclose($handle); 193 | 194 | // Show Results 195 | echo '

İşlem Tamamlandı. Başarılı: ' . $success_count . '

'; 196 | 197 | if ($error_count > 0) { 198 | echo '

Bazı satırlar işlenemedi (' . $error_count . ' hata):

'; 199 | echo '
'; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /kargo-takip-checkout-fields.php: -------------------------------------------------------------------------------- 1 | $data['cities'], 24 | 'districts' => $data['districts'], 25 | 'select_city_text' => __('Lütfen İl Seçiniz', 'kargo-takip-turkiye'), 26 | 'select_district_text' => __('Lütfen İlçe Seçiniz', 'kargo-takip-turkiye'), 27 | 'choose_city_first' => __('Önce İl Seçiniz', 'kargo-takip-turkiye') 28 | )); 29 | } 30 | } 31 | } 32 | 33 | // Modify Checkout Fields 34 | add_filter('woocommerce_checkout_fields', 'kargoTR_custom_checkout_fields'); 35 | function kargoTR_custom_checkout_fields($fields) { 36 | $address_enabled = get_option('kargo_turkey_address_enabled', 'no'); 37 | $tc_enabled = get_option('kargo_tc_id_enabled', 'no'); 38 | $tax_enabled = get_option('kargo_tax_info_enabled', 'no'); 39 | 40 | // 1. Turkey Address Logic 41 | if ($address_enabled === 'yes') { 42 | // Check current billing country 43 | $billing_country = WC()->customer ? WC()->customer->get_billing_country() : WC()->countries->get_base_country(); 44 | 45 | // If it's an AJAX request to update order review, the country might be in POST data 46 | if (isset($_POST['country'])) { 47 | $billing_country = wc_clean($_POST['country']); 48 | } elseif (isset($_POST['billing_country'])) { 49 | $billing_country = wc_clean($_POST['billing_country']); 50 | } 51 | 52 | if ($billing_country === 'TR') { 53 | $fields['billing']['billing_city']['type'] = 'select'; 54 | $fields['billing']['billing_city']['options'] = array('' => __('Önce İl Seçiniz', 'kargo-takip-turkiye')); 55 | $fields['billing']['billing_city']['class'][] = 'kargo-district-select'; 56 | 57 | // Reorder: State (Il) first, then City (Ilce) 58 | $fields['billing']['billing_state']['priority'] = 70; 59 | $fields['billing']['billing_city']['priority'] = 80; 60 | } 61 | 62 | // Check shipping country 63 | $shipping_country = WC()->customer ? WC()->customer->get_shipping_country() : WC()->countries->get_base_country(); 64 | 65 | if (isset($_POST['shipping_country'])) { 66 | $shipping_country = wc_clean($_POST['shipping_country']); 67 | } 68 | 69 | if ($shipping_country === 'TR') { 70 | $fields['shipping']['shipping_city']['type'] = 'select'; 71 | $fields['shipping']['shipping_city']['options'] = array('' => __('Önce İl Seçiniz', 'kargo-takip-turkiye')); 72 | $fields['shipping']['shipping_city']['class'][] = 'kargo-district-select'; 73 | 74 | // Reorder: State (Il) first, then City (Ilce) 75 | $fields['shipping']['shipping_state']['priority'] = 70; 76 | $fields['shipping']['shipping_city']['priority'] = 80; 77 | } 78 | } 79 | 80 | // 2. TC Identity Number 81 | if ($tc_enabled === 'yes') { 82 | $fields['billing']['billing_tc_id'] = array( 83 | 'type' => 'text', 84 | 'label' => __('TC Kimlik No', 'kargo-takip-turkiye'), 85 | 'placeholder' => __('11 haneli TC Kimlik Numaranız', 'kargo-takip-turkiye'), 86 | 'required' => true, 87 | 'class' => array('form-row-wide'), 88 | 'priority' => 25, // After Name/Company 89 | ); 90 | } 91 | 92 | // 3. Tax Info 93 | if ($tax_enabled === 'yes') { 94 | $fields['billing']['billing_tax_office'] = array( 95 | 'type' => 'text', 96 | 'label' => __('Vergi Dairesi', 'kargo-takip-turkiye'), 97 | 'placeholder' => __('Vergi Dairesi', 'kargo-takip-turkiye'), 98 | 'required' => false, 99 | 'class' => array('form-row-first'), 100 | 'priority' => 26, 101 | ); 102 | $fields['billing']['billing_tax_number'] = array( 103 | 'type' => 'text', 104 | 'label' => __('Vergi Numarası', 'kargo-takip-turkiye'), 105 | 'placeholder' => __('Vergi Numarası', 'kargo-takip-turkiye'), 106 | 'required' => false, 107 | 'class' => array('form-row-last'), 108 | 'priority' => 26, 109 | ); 110 | } 111 | 112 | return $fields; 113 | } 114 | 115 | // Modify Country Locale to ensure City is a select for TR 116 | add_filter('woocommerce_get_country_locale', 'kargoTR_custom_country_locale'); 117 | function kargoTR_custom_country_locale($locale) { 118 | $address_enabled = get_option('kargo_turkey_address_enabled', 'no'); 119 | if ($address_enabled === 'yes') { 120 | $locale['TR']['city']['type'] = 'select'; 121 | $locale['TR']['city']['options'] = array('' => __('Önce İl Seçiniz', 'kargo-takip-turkiye')); 122 | $locale['TR']['city']['class'] = array('kargo-district-select'); 123 | 124 | // Ensure state is labeled correctly (usually it is, but let's be safe) 125 | $locale['TR']['state']['label'] = __('İl', 'kargo-takip-turkiye'); 126 | $locale['TR']['city']['label'] = __('İlçe', 'kargo-takip-turkiye'); 127 | } 128 | return $locale; 129 | } 130 | 131 | // Filter States for Turkey to match our DB if Address enabled 132 | add_filter('woocommerce_states', 'kargoTR_custom_states'); 133 | function kargoTR_custom_states($states) { 134 | $address_enabled = get_option('kargo_turkey_address_enabled', 'no'); 135 | if ($address_enabled === 'yes') { 136 | $data = include plugin_dir_path(__FILE__) . 'kargo-takip-cities-districts.php'; 137 | // WC expects Code => Name. 138 | // Our data is ID => Name. 139 | // We will use ID as the code to make mapping easier for districts. 140 | $new_states = array(); 141 | foreach ($data['cities'] as $id => $name) { 142 | $new_states[$id] = $name; 143 | } 144 | $states['TR'] = $new_states; 145 | } 146 | return $states; 147 | } 148 | 149 | // Validation for TC ID 150 | add_action('woocommerce_checkout_process', 'kargoTR_checkout_validation'); 151 | function kargoTR_checkout_validation() { 152 | $tc_enabled = get_option('kargo_tc_id_enabled', 'no'); 153 | if ($tc_enabled === 'yes' && !empty($_POST['billing_tc_id'])) { 154 | $tc_no = sanitize_text_field($_POST['billing_tc_id']); 155 | if (!preg_match('/^[1-9]{1}[0-9]{9}[02468]{1}$/', $tc_no)) { 156 | wc_add_notice(__('Lütfen geçerli bir TC Kimlik Numarası giriniz.', 'kargo-takip-turkiye'), 'error'); 157 | } else { 158 | // Detailed validation algorithm 159 | $odd = $tc_no[0] + $tc_no[2] + $tc_no[4] + $tc_no[6] + $tc_no[8]; 160 | $even = $tc_no[1] + $tc_no[3] + $tc_no[5] + $tc_no[7]; 161 | $digit10 = ($odd * 7 - $even) % 10; 162 | $total = ($odd + $even + $tc_no[9]) % 10; 163 | 164 | if ($digit10 != $tc_no[9] || $total != $tc_no[10]) { 165 | wc_add_notice(__('Lütfen geçerli bir TC Kimlik Numarası giriniz.', 'kargo-takip-turkiye'), 'error'); 166 | } 167 | } 168 | } 169 | } 170 | 171 | // Save Custom Fields (TC, Tax) to Order Meta is handled automatically by WC if keys match billing_xxx? 172 | // No, standard fields are, but custom ones might need help or just be stored in _billing_xxx. 173 | // WC stores extra fields in _billing_xxx if they are in the checkout fields array. 174 | // But let's ensure they are displayed in admin. 175 | 176 | add_action( 'woocommerce_admin_order_data_after_billing_address', 'kargoTR_display_admin_order_meta', 10, 1 ); 177 | function kargoTR_display_admin_order_meta($order){ 178 | $tc_enabled = get_option('kargo_tc_id_enabled', 'no'); 179 | $tax_enabled = get_option('kargo_tax_info_enabled', 'no'); 180 | 181 | if ($tc_enabled === 'yes') { 182 | $tc = $order->get_meta('_billing_tc_id'); 183 | if($tc) echo '

'.__('TC Kimlik No').': ' . esc_html($tc) . '

'; 184 | } 185 | 186 | if ($tax_enabled === 'yes') { 187 | $tax_office = $order->get_meta('_billing_tax_office'); 188 | $tax_number = $order->get_meta('_billing_tax_number'); 189 | if($tax_office) echo '

'.__('Vergi Dairesi').': ' . esc_html($tax_office) . '

'; 190 | if($tax_number) echo '

'.__('Vergi Numarası').': ' . esc_html($tax_number) . '

'; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /netgsm-helper.php: -------------------------------------------------------------------------------- 1 | array( 9 | 'Authorization' => 'Basic ' . base64_encode($username . ':' . $password) 10 | ), 11 | 'timeout' => 15 12 | )); 13 | 14 | if (is_wp_error($request)) { 15 | return false; 16 | } 17 | 18 | $response = trim($request['body']); 19 | 20 | // Try to decode JSON response 21 | $data = json_decode($response, true); 22 | 23 | // Check if response is successful 24 | if (!$data || !isset($data['code']) || $data['code'] !== '00') { 25 | return false; 26 | } 27 | 28 | // Return msgheaders array 29 | if (isset($data['msgheaders']) && is_array($data['msgheaders'])) { 30 | return $data['msgheaders']; 31 | } 32 | 33 | return false; 34 | } 35 | 36 | function kargoTR_get_netgsm_packet_info($username, $password, $appkey = '') { 37 | // NetGSM Balance API - Returns JSON response 38 | $url = "https://api.netgsm.com.tr/balance"; 39 | 40 | // Build request body - appkey only if provided 41 | $request_body = array( 42 | 'usercode' => $username, 43 | 'password' => $password, 44 | 'stip' => 1 // 1 = All balance types 45 | ); 46 | 47 | // Add appkey only if it's not empty 48 | if (!empty($appkey)) { 49 | $request_body['appkey'] = $appkey; 50 | } 51 | 52 | $body = json_encode($request_body); 53 | 54 | $request = wp_remote_post($url, array( 55 | 'headers' => array('Content-Type' => 'application/json'), 56 | 'body' => $body, 57 | 'timeout' => 15 58 | )); 59 | 60 | if (is_wp_error($request)) { 61 | return array('error' => $request->get_error_message()); 62 | } 63 | 64 | $response_code = wp_remote_retrieve_response_code($request); 65 | if ($response_code !== 200) { 66 | return array('error' => 'HTTP Hata: ' . $response_code); 67 | } 68 | 69 | $response = trim(wp_remote_retrieve_body($request)); 70 | 71 | // Check if response is empty 72 | if (empty($response)) { 73 | return array('error' => 'Boş yanıt alındı'); 74 | } 75 | 76 | // Try to decode JSON response 77 | $data = json_decode($response, true); 78 | 79 | // Check for JSON decode errors 80 | if (json_last_error() !== JSON_ERROR_NONE) { 81 | return array('error' => 'JSON parse hatası: ' . json_last_error_msg() . ' | Yanıt: ' . substr($response, 0, 100)); 82 | } 83 | 84 | // Check for NetGSM API error codes 85 | if (isset($data['code'])) { 86 | $error_codes = array( 87 | '30' => 'Geçersiz kullanıcı adı veya şifre', 88 | '40' => 'Yetkilendirme hatası', 89 | '50' => 'Hesap erişim hatası', 90 | '51' => 'Erişim izni yok', 91 | '60' => 'AppKey hatası: AppKey yanlış, geçersiz veya bu kullanıcı için tanımlı değil. NetGSM panelinden AppKey\'inizi kontrol edin.', 92 | '70' => 'Hatalı sorgulama parametreleri', 93 | '85' => 'Başlık kullanım izni yok' 94 | ); 95 | 96 | $code = (string)$data['code']; 97 | if (isset($error_codes[$code])) { 98 | return array('error' => $error_codes[$code] . ' (Kod: ' . $code . ')'); 99 | } else { 100 | return array('error' => 'NetGSM API Hatası (Kod: ' . $code . ')'); 101 | } 102 | } 103 | 104 | // Check for API error messages 105 | if (isset($data['error'])) { 106 | return array('error' => $data['error']); 107 | } 108 | 109 | if (isset($data['message'])) { 110 | return array('error' => $data['message']); 111 | } 112 | 113 | // Check if balance array exists 114 | if (!isset($data['balance']) || !is_array($data['balance'])) { 115 | // If appkey was used, try without it 116 | if (!empty($appkey)) { 117 | // Retry without appkey 118 | $request_body_retry = array( 119 | 'usercode' => $username, 120 | 'password' => $password, 121 | 'stip' => 1 122 | ); 123 | 124 | $body_retry = json_encode($request_body_retry); 125 | $request_retry = wp_remote_post($url, array( 126 | 'headers' => array('Content-Type' => 'application/json'), 127 | 'body' => $body_retry, 128 | 'timeout' => 15 129 | )); 130 | 131 | if (!is_wp_error($request_retry)) { 132 | $response_retry = trim(wp_remote_retrieve_body($request_retry)); 133 | $data_retry = json_decode($response_retry, true); 134 | 135 | if (isset($data_retry['balance']) && is_array($data_retry['balance'])) { 136 | // Success without appkey 137 | foreach ($data_retry['balance'] as $item) { 138 | if (isset($item['balance_name']) && strpos($item['balance_name'], 'SMS') !== false) { 139 | return $item['amount'] . ' Adet SMS'; 140 | } 141 | } 142 | } 143 | } 144 | } 145 | 146 | return array('error' => 'Paket bilgisi bulunamadı. Yanıt: ' . substr($response, 0, 200)); 147 | } 148 | 149 | // Find SMS balance from the array 150 | foreach ($data['balance'] as $item) { 151 | if (isset($item['balance_name']) && strpos($item['balance_name'], 'SMS') !== false) { 152 | return $item['amount'] . ' Adet SMS'; 153 | } 154 | } 155 | 156 | // Return all balances as formatted string 157 | $balances = array(); 158 | foreach ($data['balance'] as $item) { 159 | if (isset($item['amount']) && isset($item['balance_name'])) { 160 | $balances[] = $item['amount'] . ' ' . $item['balance_name']; 161 | } 162 | } 163 | 164 | if (empty($balances)) { 165 | return array('error' => 'Paket bilgisi bulunamadı'); 166 | } 167 | 168 | return implode(', ', $balances); 169 | } 170 | 171 | function kargoTR_get_netgsm_credit_info($username, $password, $appkey = '') { 172 | // NetGSM Balance API - Returns JSON response 173 | $url = "https://api.netgsm.com.tr/balance"; 174 | 175 | // Build request body - appkey only if provided 176 | $request_body = array( 177 | 'usercode' => $username, 178 | 'password' => $password, 179 | 'stip' => 1 180 | ); 181 | 182 | // Add appkey only if it's not empty 183 | if (!empty($appkey)) { 184 | $request_body['appkey'] = $appkey; 185 | } 186 | 187 | $body = json_encode($request_body); 188 | 189 | $request = wp_remote_post($url, array( 190 | 'headers' => array('Content-Type' => 'application/json'), 191 | 'body' => $body, 192 | 'timeout' => 15 193 | )); 194 | 195 | if (is_wp_error($request)) { 196 | return false; 197 | } 198 | 199 | $response_code = wp_remote_retrieve_response_code($request); 200 | if ($response_code !== 200) { 201 | return false; 202 | } 203 | 204 | $response = trim(wp_remote_retrieve_body($request)); 205 | 206 | // Try to decode JSON response 207 | $data = json_decode($response, true); 208 | 209 | if (json_last_error() !== JSON_ERROR_NONE) { 210 | return false; 211 | } 212 | 213 | // Check for NetGSM API error codes 214 | if (isset($data['code'])) { 215 | // If appkey was used and got code 60, try without appkey 216 | if ($data['code'] == 60 && !empty($appkey)) { 217 | $request_body_retry = array( 218 | 'usercode' => $username, 219 | 'password' => $password, 220 | 'stip' => 1 221 | ); 222 | 223 | $body_retry = json_encode($request_body_retry); 224 | $request_retry = wp_remote_post($url, array( 225 | 'headers' => array('Content-Type' => 'application/json'), 226 | 'body' => $body_retry, 227 | 'timeout' => 15 228 | )); 229 | 230 | if (!is_wp_error($request_retry)) { 231 | $response_retry = trim(wp_remote_retrieve_body($request_retry)); 232 | $data_retry = json_decode($response_retry, true); 233 | 234 | if (isset($data_retry['balance']) && is_array($data_retry['balance'])) { 235 | foreach ($data_retry['balance'] as $item) { 236 | if (isset($item['balance_name']) && (strpos($item['balance_name'], 'TL') !== false || strpos($item['balance_name'], 'Kredi') !== false)) { 237 | return $item['amount']; 238 | } 239 | } 240 | } 241 | } 242 | } 243 | return false; 244 | } 245 | 246 | // Check for API error messages 247 | if (isset($data['error']) || isset($data['message'])) { 248 | return false; 249 | } 250 | 251 | if (!isset($data['balance']) || !is_array($data['balance'])) { 252 | return false; 253 | } 254 | 255 | // Find credit balance (TL) 256 | foreach ($data['balance'] as $item) { 257 | if (isset($item['balance_name']) && (strpos($item['balance_name'], 'TL') !== false || strpos($item['balance_name'], 'Kredi') !== false)) { 258 | return $item['amount']; 259 | } 260 | } 261 | 262 | return false; 263 | } 264 | 265 | 266 | function kargoTR_SMS_gonder_netgsm($order_id) { 267 | $order = wc_get_order($order_id); 268 | if (!$order) return; 269 | 270 | $phone = $order->get_billing_phone(); 271 | 272 | $NetGsm_UserName = get_option('NetGsm_UserName'); 273 | $NetGsm_Password = urlencode(get_option('NetGsm_Password')); 274 | $NetGsm_Header = get_option('NetGsm_Header'); 275 | $NetGsm_sms_url_send = get_option('NetGsm_sms_url_send'); 276 | 277 | // HPOS uyumlu meta okuma 278 | $tracking_company = $order->get_meta('tracking_company', true); 279 | $tracking_code = $order->get_meta('tracking_code', true); 280 | 281 | // Use the configurable SMS template 282 | $message = kargoTR_get_sms_template($order_id, get_option('kargoTR_sms_template')); 283 | $message = urlencode($message); 284 | 285 | /* Legacy logic - removed in favor of template 286 | $message = "Siparişinizin kargo takip numarası : " . $tracking_code . ", " . kargoTR_get_company_name($tracking_company) . " kargo firması ile takip edebilirsiniz."; 287 | $message = urlencode($message); 288 | 289 | if ($NetGsm_sms_url_send == 'yes') { 290 | $message = $message." ".urlencode("Takip URL : ").kargoTR_getCargoTrack($tracking_company, $tracking_code); 291 | } 292 | */ 293 | 294 | if($NetGsm_Header == "yes"){ 295 | $NetGsm_Header = kargoTR_get_netgsm_headers($NetGsm_UserName, $NetGsm_Password); 296 | $NetGsm_Header = $NetGsm_Header[0]; 297 | } 298 | 299 | $NetGsm_Header = urlencode($NetGsm_Header); 300 | 301 | $url= "https://api.netgsm.com.tr/sms/send/get/?usercode=$NetGsm_UserName&password=$NetGsm_Password&gsmno=$phone&message=$message&dil=TR&msgheader=$NetGsm_Header"; 302 | 303 | $request = wp_remote_get($url); 304 | 305 | // NetGSM API returns numeric error codes: 20, 30, 40, 50, 51, 70, 85 306 | // Success returns a job ID (can be "00 JOBID" format or just "JOBID") 307 | $response = trim($request['body']); 308 | $error_codes = array('20', '30', '40', '50', '51', '70', '85'); 309 | 310 | if (in_array($response, $error_codes)) { 311 | // Error occurred 312 | $error_messages = array( 313 | '20' => 'Mesaj metninde ki problemden dolayı gönderilemediğini veya standart maksimum mesaj karakter sayısını geçtiğini ifade eder.', 314 | '30' => 'Geçersiz kullanıcı adı, şifre veya kullanıcınızın API erişim izninin olmadığını gösterir.', 315 | '40' => 'Mesaj başlığınızın (gönderici adınızın) sistemde tanımlı olmadığını ifade eder.', 316 | '50' => 'Abone hesabınız ile İYS kontrollü gönderimler yapılamamaktadır.', 317 | '51' => 'Erişim izninizin olmadığı bir hesaba işlem yapmaya çalıştığınızı ifade eder.', 318 | '70' => 'Hatalı sorgulama. Gönderdiğiniz parametrelerden birisi hatalı veya zorunlu alanlardan birinin eksik olduğunu ifade eder.', 319 | '85' => 'Başlık kullanım izni olmayan bir API kullanıcısı ile başlıklı mesaj gönderilmeye çalışıldığını ifade eder.' 320 | ); 321 | $error_msg = isset($error_messages[$response]) ? $error_messages[$response] : 'Bilinmeyen hata'; 322 | $order->add_order_note("SMS Gönderilemedi - NetGSM Hata Kodu: {$response} - {$error_msg}"); 323 | } else { 324 | // Success - response is job ID (can be "00 JOBID" or just "JOBID") 325 | $parts = explode(" ", $response); 326 | $job_id = isset($parts[1]) ? $parts[1] : $response; 327 | $order->add_order_note("SMS Gönderildi - NetGSM İşlem Kodu: {$job_id}"); 328 | } 329 | 330 | // $order->add_order_note("Debug : ".$request['body']); 331 | 332 | } 333 | add_action('order_send_sms', 'kargoTR_SMS_gonder_netgsm'); 334 | 335 | ?> -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # Kargo Takip Türkiye WordPress Plugin 2 | 3 | ## Plugin Overview 4 | 5 | **Kargo Takip Türkiye** is a WooCommerce integration plugin for Turkish cargo/shipment tracking. It allows shop owners to manage shipment tracking information directly within WooCommerce order details and enables automated customer notifications via email and SMS. 6 | 7 | ### Key Information 8 | - **Plugin Name**: Kargo Takip Türkiye (Cargo Tracking Turkey) 9 | - **Current Version**: 0.2.0 10 | - **Author**: Unbelievable.Digital 11 | - **Repository**: https://github.com/unbelievable-digital/kargo-takip-turkiye 12 | - **Language**: Turkish (UI and documentation) 13 | - **WordPress Requirement**: 4.9+ 14 | - **PHP Requirement**: 7.1+ 15 | - **WooCommerce Tested**: 7.2.2+ 16 | - **License**: GPLv2 or later 17 | 18 | --- 19 | 20 | ## Directory Structure 21 | 22 | ``` 23 | kargo-takip-turkiye/ 24 | ├── .github/ 25 | │ └── workflows/ 26 | │ └── main.yml # GitHub Actions deployment workflow 27 | ├── assets/ 28 | │ └── logos/ # Cargo company logos (PNG images) 29 | │ ├── aras.png 30 | │ ├── carrtell.png 31 | │ ├── dhl.png 32 | │ ├── fedex.png 33 | │ ├── filo.png 34 | │ ├── hepsijet.png 35 | │ ├── horoz.png 36 | │ ├── iyi.png 37 | │ ├── mng.png 38 | │ ├── postman.png 39 | │ ├── ptt.png 40 | │ ├── sendeo.png 41 | │ ├── surat.png 42 | │ ├── tex.png 43 | │ ├── tnt.png 44 | │ ├── ups.png 45 | │ └── yurtici.png 46 | ├── mail-template/ # Email template files 47 | │ ├── email-shipment-template.php # Initial shipment notification 48 | │ └── email-shipment-update-template.php # Shipment update notification 49 | ├── .gitignore 50 | ├── config.php # Cargo company configuration 51 | ├── index.php # Empty entry point 52 | ├── kargo-takip-turkiye.php # Main plugin file 53 | ├── kargo-takip-helper.php # Helper functions 54 | ├── kargo-takip-order-list.php # Admin order list enhancements 55 | ├── kargo-takip-email-settings.php # Email settings page 56 | ├── kargo-takip-sms-settings.php # SMS settings page 57 | ├── kargo-takip-wc-api-helper.php # WooCommerce REST API endpoint 58 | ├── kobikom-helper.php # Kobikom SMS provider integration 59 | ├── netgsm-helper.php # NetGSM SMS provider integration 60 | ├── readme.txt # WordPress plugin readme 61 | └── LICENSE # GPLv2 License 62 | 63 | ``` 64 | 65 | --- 66 | 67 | ## Plugin Architecture & Components 68 | 69 | ### 1. Main Plugin Entry Point 70 | **File**: `kargo-takip-turkiye.php` 71 | 72 | The main plugin file that: 73 | - Includes all helper and settings files 74 | - Registers the admin menu and submenus 75 | - Manages WooCommerce hooks and filters 76 | - Registers custom order status "Kargoya verildi" (Shipped via Cargo) 77 | - Handles shipment tracking metadata on orders 78 | - Triggers email and SMS notifications 79 | - Adds shipment details to customer account pages and order confirmations 80 | 81 | **Key Functions**: 82 | - `kargoTR_register_admin_menu()` - Registers admin menu structure 83 | - `kargoTR_register_settings()` - Registers plugin option settings 84 | - `kargoTR_setting_page()` - Displays general settings page 85 | - `kargoTR_register_shipment_shipped_order_status()` - Adds custom order status 86 | - `kargoTR_general_shipment_details_for_admin()` - Admin order tracking form 87 | - `kargoTR_tracking_save_general_details()` - Saves tracking data, triggers notifications 88 | - `kargoTR_shipment_details()` - Displays tracking info on customer order page 89 | - `kargoTR_add_kargo_button_in_order()` - Adds tracking button to order actions 90 | - `kargoTR_kargo_bildirim_icerik()` - Renders email notification content 91 | - `kargoTR_kargo_eposta_details()` - Sends email notification 92 | 93 | ### 2. Configuration 94 | **File**: `config.php` 95 | 96 | PHP array containing all supported cargo companies with: 97 | - Company display name 98 | - Tracking URL pattern (base URL + tracking code) 99 | - Logo file path 100 | 101 | **Supported Cargo Companies** (20 companies): 102 | - PTT Kargo 103 | - Yurtiçi Kargo 104 | - Aras Kargo 105 | - MNG Kargo 106 | - Horoz Kargo 107 | - UPS Kargo 108 | - Sürat Kargo 109 | - Filo Kargo 110 | - TNT Kargo 111 | - DHL Kargo 112 | - FedEx Kargo 113 | - FoodMan Kargo 114 | - Postman Kargo 115 | - İyi Kargo 116 | - Trendyol Express 117 | - HepsiJET 118 | - Sendeo Kargo 119 | - Carrtell Kargo 120 | 121 | ### 3. Helper Functions 122 | **File**: `kargo-takip-helper.php` 123 | 124 | Core utility functions for cargo data retrieval: 125 | - `kargoTR_get_company_name()` - Get company name by key 126 | - `kargoTR_getCargoTrack()` - Build tracking URL 127 | - `kargoTR_getCargoName()` - Get cargo name (legacy) 128 | - `kargoTR_cargo_company_list()` - Get all companies as associative array 129 | - `kargoTR_get_order_cargo_logo()` - Get company logo for order 130 | - `kargoTR_get_order_cargo_information()` - Get complete cargo info (logo, company, URL) 131 | - `kargoTR_get_sms_template()` - Build SMS message from template with variables 132 | 133 | **Template Variables**: 134 | - `{customer_name}` - Customer name 135 | - `{order_id}` - Order ID 136 | - `{company_name}` - Cargo company name 137 | - `{tracking_number}` - Tracking code 138 | - `{tracking_url}` - Tracking URL 139 | 140 | ### 4. Settings Management 141 | 142 | #### General Settings 143 | **File**: `kargo-takip-turkiye.php` (main file) 144 | 145 | Registered options: 146 | - `kargo_hazirlaniyor_text` - Show "Preparing shipment" text 147 | - `mail_send_general` - Auto-send email on tracking info 148 | - `sms_provider` - Selected SMS provider (no, NetGSM, Kobikom) 149 | - `sms_send_general` - Auto-send SMS on tracking info 150 | 151 | #### Email Settings 152 | **File**: `kargo-takip-email-settings.php` 153 | 154 | - Manages email template customization via `kargoTr_email_template` option 155 | - Users can customize email content with template variables 156 | - Default template included in main plugin file 157 | 158 | #### SMS Settings 159 | **File**: `kargo-takip-sms-settings.php` 160 | 161 | Settings page for SMS integration: 162 | - Select SMS provider (NetGSM or Kobikom) 163 | - Configure provider credentials and API keys 164 | - View account balance and remaining credits 165 | - Customize SMS template with template variables 166 | 167 | ### 5. SMS Integration 168 | 169 | #### NetGSM Provider 170 | **File**: `netgsm-helper.php` 171 | 172 | Functions: 173 | - `kargoTR_get_netgsm_headers()` - Fetch available SMS headers 174 | - `kargoTR_get_netgsm_packet_info()` - Get packet information 175 | - `kargoTR_get_netgsm_credit_info()` - Get account credit balance 176 | - `kargoTR_SMS_gonder_netgsm()` - Send SMS via NetGSM API 177 | 178 | **Credentials**: 179 | - Subscriber code (without leading 0) 180 | - Password 181 | 182 | #### Kobikom Provider 183 | **File**: `kobikom-helper.php` 184 | 185 | Functions: 186 | - `kargoTR_get_kobikom_headers()` - Fetch available SMS headers 187 | - `kargoTR_get_kobikom_balance()` - Get account packages/balance 188 | - `kargoTR_SMS_gonder_kobikom()` - Send SMS via Kobikom API 189 | 190 | **Credentials**: 191 | - API Token/Key 192 | 193 | ### 6. Admin Order List Enhancement 194 | **File**: `kargo-takip-order-list.php` 195 | 196 | Adds a "Kargo" column to the WooCommerce orders admin page: 197 | - Shows cargo company logo (clickable) 198 | - Links directly to cargo tracking page 199 | - Integrated with `kargoTR_get_order_cargo_information()` 200 | 201 | ### 7. WooCommerce REST API Integration 202 | **File**: `kargo-takip-wc-api-helper.php` 203 | 204 | Provides REST API endpoint for external systems to add/update tracking info: 205 | - **Endpoint**: `POST /wp-json/wc/v3/kargo_takip` 206 | - **Authentication**: Requires logged-in user with `edit_shop_orders` capability 207 | - **Parameters**: 208 | - `order_id` (required) - Order ID 209 | - `shipment_company` (required) - Cargo company key 210 | - `tracking_code` (required) - Tracking number 211 | 212 | **Functions**: 213 | - `kargoTR_api_add_tracking_code()` - Main API handler 214 | - `kargoTR_is_valid_shipment_company()` - Validates company 215 | - `kargoTR_is_valid_order_id()` - Validates order 216 | 217 | **Features**: 218 | - Adds/updates tracking metadata on orders 219 | - Triggers email notification if enabled 220 | - Triggers SMS notification if configured 221 | - Adds order notes for audit trail 222 | 223 | ### 8. Email Templates 224 | **Directory**: `mail-template/` 225 | 226 | #### email-shipment-template.php 227 | - Initial shipment notification template 228 | - Uses WooCommerce email hooks for consistent styling 229 | - Displays: company name, tracking code, tracking link 230 | - Includes order details via WooCommerce hooks 231 | 232 | #### email-shipment-update-template.php 233 | - Similar to shipment template (appears to be duplicate or for updates) 234 | 235 | Both templates use: 236 | - `kargoTR_get_company_name()` - Display company 237 | - `kargoTR_getCargoTrack()` - Generate tracking URL 238 | - WooCommerce email hooks for standard content 239 | 240 | --- 241 | 242 | ## WordPress Hooks & Actions 243 | 244 | ### Hooks Used by Plugin 245 | 246 | **Custom Actions (defined by plugin)**: 247 | - `order_ship_mail` - Triggers email notification 248 | - `order_send_sms` - Triggers NetGSM SMS notification 249 | - `order_send_sms_kobikom` - Triggers Kobikom SMS notification 250 | 251 | **WordPress Actions (hooked by plugin)**: 252 | - `admin_menu` - Register admin menu 253 | - `admin_init` - Register settings 254 | - `init` - Register custom order status 255 | - `admin_head` - Add CSS for tooltips 256 | - `woocommerce_admin_order_data_after_order_details` - Display tracking form 257 | - `woocommerce_process_shop_order_meta` - Save tracking data 258 | - `woocommerce_after_order_details` - Display tracking on customer page 259 | - `rest_api_init` - Register REST API endpoint 260 | 261 | **WooCommerce Filters**: 262 | - `wc_order_statuses` - Add custom order status 263 | - `woocommerce_my_account_my_orders_actions` - Add tracking button 264 | 265 | **WooCommerce Email Hooks** (in templates): 266 | - `woocommerce_email_header()` 267 | - `woocommerce_email_order_details()` 268 | - `woocommerce_email_order_meta()` 269 | - `woocommerce_email_customer_details()` 270 | - `woocommerce_email_footer()` 271 | 272 | --- 273 | 274 | ## Data Storage 275 | 276 | ### WordPress Post Meta 277 | Stored on WooCommerce orders (posts): 278 | - `tracking_company` - Cargo company key (from config) 279 | - `tracking_code` - Shipment tracking number 280 | 281 | ### WordPress Options 282 | Settings stored in wp_options table: 283 | - `kargo_hazirlaniyor_text` - (yes/no) 284 | - `mail_send_general` - (yes/no) 285 | - `sms_provider` - (no/NetGSM/Kobikom) 286 | - `sms_send_general` - (yes/no) 287 | - `NetGsm_UserName` - NetGSM subscriber code 288 | - `NetGsm_Password` - NetGSM password 289 | - `NetGsm_Header` - Selected NetGSM SMS header 290 | - `NetGsm_sms_url_send` - Include tracking URL in SMS 291 | - `Kobikom_ApiKey` - Kobikom API token 292 | - `Kobikom_Header` - Selected Kobikom SMS header 293 | - `kargoTr_sms_template` - SMS message template 294 | - `kargoTr_email_template` - Email message template 295 | 296 | ### Custom Order Status 297 | - **Status Key**: `wc-kargo-verildi` 298 | - **Display Label**: Kargoya Verildi (Shipped via Cargo) 299 | 300 | --- 301 | 302 | ## External API Integrations 303 | 304 | ### NetGSM API 305 | - **Base URL**: https://api.netgsm.com.tr/ 306 | - **Endpoints Used**: 307 | - `/sms/header/` - Get SMS headers 308 | - `/balance/list/get/` - Get account info 309 | - `/sms/send/get/` - Send SMS messages 310 | - **Authentication**: Usercode + Password 311 | 312 | ### Kobikom API 313 | - **Base URL**: https://sms.kobikom.com.tr/api/ 314 | - **Endpoints Used**: 315 | - `/subscription` - Get SMS headers 316 | - `/balance` - Get account packages 317 | - `/message/send` - Send SMS messages 318 | - **Authentication**: API Token 319 | 320 | --- 321 | 322 | ## Admin Pages Structure 323 | 324 | ### Menu 325 | ``` 326 | Kargo Takip (main menu) 327 | ├── Genel Ayarlar (General Settings) 328 | ├── E-Mail Ayarlari (Email Settings) 329 | └── SMS Ayarlari (SMS Settings) 330 | ``` 331 | 332 | ### General Settings Page 333 | - Show "Preparing shipment" text option 334 | - Auto-send email option 335 | - SMS provider selection 336 | 337 | ### Email Settings Page 338 | - Email template editor (textarea) 339 | - Template variable documentation 340 | - Examples of usage 341 | 342 | ### SMS Settings Page 343 | - SMS provider selection (NetGSM or Kobikom) 344 | - Provider-specific configuration 345 | - Account balance display 346 | - SMS template editor 347 | - Template variable documentation 348 | 349 | --- 350 | 351 | ## Admin Order Editing 352 | 353 | When editing a WooCommerce order: 354 | 1. Select2 dropdown for cargo company selection 355 | 2. Text input for tracking code 356 | 3. Automatic order status change to "Kargoya verildi" 357 | 4. Triggered notifications (email/SMS based on settings) 358 | 5. Automatic order note creation 359 | 360 | --- 361 | 362 | ## Development & Deployment 363 | 364 | ### GitHub Actions Workflow 365 | **File**: `.github/workflows/main.yml` 366 | 367 | Automated deployment process: 368 | - **Trigger**: Git tag creation 369 | - **Action**: 10up WordPress Plugin Deploy action 370 | - **Target**: WordPress.org SVN repository 371 | - **Slug**: kargo-takip-turkiye 372 | - **Authentication**: SVN_USERNAME and SVN_PASSWORD secrets 373 | 374 | ### Version Information 375 | Maintained in `kargo-takip-turkiye.php` header and `readme.txt` 376 | 377 | --- 378 | 379 | ## Code Quality & Standards 380 | 381 | ### Security Practices 382 | - Uses WordPress sanitization: `wc_clean()`, `wc_sanitize_textarea()` 383 | - Uses WordPress escaping: `esc_attr()`, `esc_html__()` 384 | - Capability checks: `current_user_can('edit_shop_orders')` 385 | - Input validation in REST API handler 386 | 387 | ### WordPress Standards 388 | - Uses WooCommerce plugin functions and classes 389 | - Follows WooCommerce template structure 390 | - Uses appropriate hooks and filters 391 | - Option registration and management 392 | 393 | ### Coding Patterns 394 | - Functional approach (no classes) 395 | - Include-based module loading 396 | - Configuration-driven cargo list 397 | - Action-based notification system 398 | 399 | --- 400 | 401 | ## Known Issues & Notes 402 | 403 | ### From Version History (readme.txt) 404 | 405 | **v0.2.0** (Latest) 406 | - SMS and Email templates now editable from admin panel 407 | - API added for external cargo data input via WooCommerce REST 408 | - Added Carrtell cargo company 409 | - Code structure improvements 410 | - Aras Kargo URL updated 411 | 412 | **Previous Improvements**: 413 | - Select2 for company dropdown 414 | - Kobikom SMS provider support 415 | - NetGSM SMS provider support 416 | - Email notification feature 417 | - Custom order status 418 | - Auto SMS/Email on tracking info 419 | - Multiple cargo companies support 420 | 421 | --- 422 | 423 | ## Dependencies 424 | 425 | ### Required 426 | - WordPress 4.9+ 427 | - WooCommerce 7.2.2+ 428 | - PHP 7.1+ 429 | 430 | ### WordPress Libraries Used 431 | - `wp_remote_get()` - HTTP requests 432 | - `wp_enqueue_script()` - Script loading 433 | - `wp_add_inline_script()` - Inline scripts 434 | - `wc_get_order()` - Order handling 435 | - `get_post_meta()` / `update_post_meta()` - Order metadata 436 | - `get_option()` / `update_option()` - Settings management 437 | - `register_post_status()` - Custom order status 438 | - `register_rest_route()` - REST API 439 | - `register_setting()` - Settings registration 440 | 441 | ### Frontend Libraries 442 | - Select2 (enqueued via WordPress) 443 | - jQuery (WooCommerce core) 444 | 445 | --- 446 | 447 | ## File Dependencies 448 | 449 | ``` 450 | kargo-takip-turkiye.php (main) 451 | ├── includes: netgsm-helper.php 452 | ├── includes: kargo-takip-helper.php 453 | ├── includes: kargo-takip-order-list.php 454 | ├── includes: kargo-takip-email-settings.php 455 | ├── includes: kargo-takip-sms-settings.php 456 | │ └── includes: kobikom-helper.php 457 | └── includes: kargo-takip-wc-api-helper.php 458 | └── uses: config.php 459 | ``` 460 | 461 | Helper files also include config.php independently to get cargo data. 462 | 463 | --- 464 | 465 | ## Extension Points 466 | 467 | ### Adding New Cargo Companies 468 | 1. Add entry to `config.php` in "cargoes" array 469 | 2. Add logo PNG to `assets/logos/` 470 | 3. Entry format: 471 | ```php 472 | "key" => array( 473 | "company" => "Company Name", 474 | "url" => "https://tracking.example.com/?code=", 475 | "logo" => "assets/logos/key.png" 476 | ) 477 | ``` 478 | 479 | ### Adding New SMS Providers 480 | 1. Create new helper file (e.g., `newprovider-helper.php`) 481 | 2. Implement functions: 482 | - `kargoTR_SMS_gonder_newprovider($order_id)` - Main sender 483 | - Additional API functions as needed 484 | 3. Add action: `add_action('order_send_sms_newprovider', ...)` 485 | 4. Update `kargo-takip-sms-settings.php` for UI 486 | 5. Update `kargo-takip-turkiye.php` to trigger action 487 | 488 | ### Customizing Email/SMS Templates 489 | - Use WordPress options to store templates 490 | - Use template variables in curly braces 491 | - Template rendering in `kargoTR_get_sms_template()` 492 | - Email template via `kargoTR_kargo_bildirim_icerik()` 493 | 494 | --- 495 | 496 | ## Testing Considerations 497 | 498 | ### Manual Testing Points 499 | 1. **Cargo Selection**: Test Select2 dropdown with multiple companies 500 | 2. **Tracking Data**: Verify metadata saved correctly 501 | 3. **Email Notification**: Check email sent with correct variables 502 | 4. **SMS Notifications**: Test both NetGSM and Kobikom providers 503 | 5. **API Endpoint**: Test POST request with valid/invalid data 504 | 6. **Order Status**: Verify "Kargoya verildi" status applied 505 | 7. **Admin Pages**: Test all three settings pages 506 | 8. **Customer View**: Verify tracking info displays on customer account 507 | 508 | ### API Testing 509 | ```bash 510 | POST /wp-json/wc/v3/kargo_takip 511 | Content-Type: application/x-www-form-urlencoded 512 | 513 | order_id=123&shipment_company=ptt&tracking_code=XXXXX 514 | ``` 515 | 516 | --- 517 | 518 | ## Recent Changes (v0.2.0) 519 | 520 | - **Email/SMS Templates**: Now editable from admin panel instead of hardcoded 521 | - **REST API**: Added WooCommerce REST API endpoint for external integration 522 | - **Carrtell Integration**: New cargo company added 523 | - **Code Refactoring**: Improved code organization and readability 524 | - **URL Updates**: Aras Kargo tracking URL changed 525 | 526 | --- 527 | 528 | ## License 529 | 530 | GPL v2 or later - See LICENSE file 531 | 532 | --- 533 | 534 | ## Support & Contribution 535 | 536 | **Repository**: https://github.com/unbelievable-digital/kargo-takip-turkiye 537 | **Author**: Unbelievable.Digital 538 | **WordPress.org Page**: https://wordpress.org/plugins/kargo-takip-turkiye/ 539 | 540 | --- 541 | 542 | **Last Updated**: November 2024 543 | **Document Version**: Based on Plugin v0.2.0 544 | 545 | ## Rules 546 | 547 | You are an expert in WordPress, PHP, and related web development technologies. 548 | 549 | Key Principles 550 | - Write concise, technical responses with accurate PHP examples. 551 | - Follow WordPress coding standards and best practices. 552 | - Use object-oriented programming when appropriate, focusing on modularity. 553 | - Prefer iteration and modularization over duplication. 554 | - Use descriptive function, variable, and file names. 555 | - Use lowercase with hyphens for directories (e.g., wp-content/themes/my-theme). 556 | - Favor hooks (actions and filters) for extending functionality. 557 | 558 | PHP/WordPress 559 | - Use PHP 7.4+ features when appropriate (e.g., typed properties, arrow functions). 560 | - Follow WordPress PHP Coding Standards. 561 | - Use strict typing when possible: declare(strict_types=1); 562 | - Utilize WordPress core functions and APIs when available. 563 | - File structure: Follow WordPress theme and plugin directory structures and naming conventions. 564 | - Implement proper error handling and logging: 565 | - Use WordPress debug logging features. 566 | - Create custom error handlers when necessary. 567 | - Use try-catch blocks for expected exceptions. 568 | - Use WordPress's built-in functions for data validation and sanitization. 569 | - Implement proper nonce verification for form submissions. 570 | - Utilize WordPress's database abstraction layer (wpdb) for database interactions. 571 | - Use prepare() statements for secure database queries. 572 | - Implement proper database schema changes using dbDelta() function. 573 | 574 | Dependencies 575 | - WordPress (latest stable version) 576 | - Composer for dependency management (when building advanced plugins or themes) 577 | 578 | WordPress Best Practices 579 | - Use WordPress hooks (actions and filters) instead of modifying core files. 580 | - Implement proper theme functions using functions.php. 581 | - Use WordPress's built-in user roles and capabilities system. 582 | - Utilize WordPress's transients API for caching. 583 | - Implement background processing for long-running tasks using wp_cron(). 584 | - Use WordPress's built-in testing tools (WP_UnitTestCase) for unit tests. 585 | - Implement proper internationalization and localization using WordPress i18n functions. 586 | - Implement proper security measures (nonces, data escaping, input sanitization). 587 | - Use wp_enqueue_script() and wp_enqueue_style() for proper asset management. 588 | - Implement custom post types and taxonomies when appropriate. 589 | - Use WordPress's built-in options API for storing configuration data. 590 | - Implement proper pagination using functions like paginate_links(). 591 | 592 | Key Conventions 593 | 1. Follow WordPress's plugin API for extending functionality. 594 | 2. Use WordPress's template hierarchy for theme development. 595 | 3. Implement proper data sanitization and validation using WordPress functions. 596 | 4. Use WordPress's template tags and conditional tags in themes. 597 | 5. Implement proper database queries using $wpdb or WP_Query. 598 | 6. Use WordPress's authentication and authorization functions. 599 | 7. Implement proper AJAX handling using admin-ajax.php or REST API. 600 | 8. Use WordPress's hook system for modular and extensible code. 601 | 9. Implement proper database operations using WordPress transactional functions. 602 | 10. Use WordPress's WP_Cron API for scheduling tasks. 603 | -------------------------------------------------------------------------------- /kargo-takip-whatsapp-settings.php: -------------------------------------------------------------------------------- 1 | 13 |
14 |

15 | 16 | WhatsApp Ayarları 17 |

18 | 19 |
20 | 21 |
22 |
23 | 24 | 25 | 26 | 27 |
28 |
29 |

30 | 31 | WhatsApp Bildirimi Durumu 32 |

33 |

WhatsApp Business API üzerinden bildirim gönderme özelliğini aktif/pasif yapın.

34 |
35 |
36 |
37 | 43 |
44 | WhatsApp Bildirimi 45 |

46 | Bu özellik aktif olduğunda, sipariş detay sayfasında "WhatsApp ile Gönder" butonu görünür olacaktır. 47 |

48 |
49 |
50 | 51 |
52 | 53 | 54 | 55 | 56 |
57 |
58 |
59 | 60 | 61 |
> 62 |
63 |

64 | 65 | WhatsApp Business API Yapılandırması 66 |

67 |

Facebook WhatsApp Business API bilgilerinizi girin.

68 |
69 |
70 |
71 |
72 | 73 | 76 |

Facebook Business'tan alınan Phone Number ID

77 |
78 | 79 |
80 | 81 | 84 |

Onaylı WhatsApp şablon adı

85 |
86 |
87 | 88 |
89 | 90 | 92 |

Facebook Developer Console'dan alınan Bearer Token

93 |
94 | 95 | 96 |
97 | 104 |
105 | 106 |
107 | 110 |
111 | 112 | 113 |
114 |
115 |

116 | 117 | Nasıl Çalışır? 118 |

119 |
120 |
121 |
122 |
123 | 1 124 |
125 |

API Bilgilerini Girin

126 |

Facebook WhatsApp Business API'den Phone ID ve Token bilgilerini alın.

127 |
128 |
129 |
130 | 2 131 |
132 |

WhatsApp Bildirimini Aktif Edin

133 |

Yukarıdaki toggle ile özelliği aktif hale getirin.

134 |
135 |
136 |
137 | 3 138 |
139 |

Sipariş Detayına Gidin

140 |

WooCommerce > Siparişler bölümünden bir sipariş seçin.

141 |
142 |
143 |
144 | 4 145 |
146 |

Kargo Bilgilerini Girin ve Gönderin

147 |

Kargo firması ve takip numarası girdikten sonra "WhatsApp ile Gönder" butonuna tıklayın.

148 |
149 |
150 |
151 |
152 |
153 | 154 | 155 | 158 | 159 |
160 |
161 | 162 | 163 |
164 |
165 |
166 |

167 | 168 | WhatsApp Business API 169 |

170 |
171 |
172 | 175 |

Bu özellik Facebook WhatsApp Business API kullanılarak çalışmaktadır.

176 |

Profesyonel kargo bildirimleri göndermek için onaylı bir şablon gereklidir.

177 | 178 | API Dokümantasyonu 179 | 180 |
181 |
182 | 183 |
184 |
185 |

186 | 187 | Template Parametreleri 188 |

189 |
190 |
191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 |
site_adiSite adı
order_idSipariş numarası
shipment_nameKargo firması
shipment_numberTakip numarası
209 |
210 |
211 | 212 |
213 |
214 |

215 | 216 | Avantajlar 217 |

218 |
219 |
220 |
    221 |
  • 222 | 223 | %98 açılma oranı 224 |
  • 225 |
  • 226 | 227 | Anında iletim 228 |
  • 229 |
  • 230 | 231 | Profesyonel görünüm 232 |
  • 233 |
  • 234 | 235 | Tıklanabilir takip butonu 236 |
  • 237 |
238 |
239 |
240 |
241 |
242 |
243 | 244 | 568 | 569 | 592 | false, 'message' => 'WhatsApp API yapılandırılmamış.'); 606 | } 607 | 608 | // Telefon numarasını formatla (90 ile başlamalı) 609 | $phone = preg_replace('/[^0-9]/', '', $phone); 610 | if (strlen($phone) == 10) { 611 | $phone = '90' . $phone; 612 | } elseif (strlen($phone) == 11 && substr($phone, 0, 1) == '0') { 613 | $phone = '90' . substr($phone, 1); 614 | } elseif (strlen($phone) == 10 && substr($phone, 0, 1) != '0') { 615 | $phone = '90' . $phone; 616 | } 617 | 618 | $site_name = get_bloginfo('name'); 619 | 620 | // API URL 621 | $url = 'https://graph.facebook.com/v23.0/' . $whatsapp_phone_id . '/messages'; 622 | 623 | // Request body 624 | $body = array( 625 | 'messaging_product' => 'whatsapp', 626 | 'to' => $phone, 627 | 'type' => 'template', 628 | 'template' => array( 629 | 'name' => $whatsapp_template_name, 630 | 'language' => array( 631 | 'code' => 'tr', 632 | 'policy' => 'deterministic' 633 | ), 634 | 'components' => array( 635 | array( 636 | 'type' => 'body', 637 | 'parameters' => array( 638 | array( 639 | 'type' => 'text', 640 | 'parameter_name' => 'site_adi', 641 | 'text' => $site_name 642 | ), 643 | array( 644 | 'type' => 'text', 645 | 'parameter_name' => 'order_id', 646 | 'text' => (string) $order_id 647 | ), 648 | array( 649 | 'type' => 'text', 650 | 'parameter_name' => 'shipment_name', 651 | 'text' => $company_name 652 | ), 653 | array( 654 | 'type' => 'text', 655 | 'parameter_name' => 'shipment_number', 656 | 'text' => $tracking_code 657 | ) 658 | ) 659 | ), 660 | array( 661 | 'type' => 'button', 662 | 'sub_type' => 'url', 663 | 'index' => '0', 664 | 'parameters' => array( 665 | array( 666 | 'type' => 'text', 667 | 'text' => $tracking_code 668 | ) 669 | ) 670 | ) 671 | ) 672 | ) 673 | ); 674 | 675 | $response = wp_remote_post($url, array( 676 | 'headers' => array( 677 | 'Content-Type' => 'application/json', 678 | 'Authorization' => 'Bearer ' . $whatsapp_token 679 | ), 680 | 'body' => json_encode($body), 681 | 'timeout' => 30 682 | )); 683 | 684 | if (is_wp_error($response)) { 685 | return array('success' => false, 'message' => 'Bağlantı hatası: ' . $response->get_error_message()); 686 | } 687 | 688 | $response_body = wp_remote_retrieve_body($response); 689 | $result = json_decode($response_body, true); 690 | 691 | if (isset($result['messages']) && !empty($result['messages'])) { 692 | return array('success' => true, 'message' => 'WhatsApp mesajı gönderildi.', 'message_id' => $result['messages'][0]['id']); 693 | } 694 | 695 | // Hata durumu 696 | $error_message = isset($result['error']['message']) ? $result['error']['message'] : 'Bilinmeyen hata'; 697 | return array('success' => false, 'message' => 'API Hatası: ' . $error_message); 698 | } 699 | 700 | // AJAX: WhatsApp mesajı gönder 701 | add_action('wp_ajax_kargotr_send_whatsapp', 'kargoTR_ajax_send_whatsapp'); 702 | function kargoTR_ajax_send_whatsapp() { 703 | check_ajax_referer('kargotr_whatsapp_nonce', 'nonce'); 704 | 705 | if (!current_user_can('edit_shop_orders')) { 706 | wp_send_json_error('Yetkiniz yok.'); 707 | } 708 | 709 | $order_id = intval($_POST['order_id']); 710 | 711 | if (!$order_id) { 712 | wp_send_json_error('Geçersiz sipariş ID.'); 713 | } 714 | 715 | $order = wc_get_order($order_id); 716 | if (!$order) { 717 | wp_send_json_error('Sipariş bulunamadı.'); 718 | } 719 | 720 | $phone = $order->get_billing_phone(); 721 | if (empty($phone)) { 722 | wp_send_json_error('Müşteri telefon numarası bulunamadı.'); 723 | } 724 | 725 | // HPOS uyumlu meta okuma 726 | $tracking_company = $order->get_meta('tracking_company', true); 727 | $tracking_code = $order->get_meta('tracking_code', true); 728 | 729 | if (empty($tracking_company) || empty($tracking_code)) { 730 | wp_send_json_error('Kargo takip bilgisi bulunamadı.'); 731 | } 732 | 733 | $company_name = kargoTR_get_company_name($tracking_company); 734 | $tracking_url = kargoTR_getCargoTrack($tracking_company, $tracking_code); 735 | 736 | $result = kargoTR_send_whatsapp_message($phone, $order_id, $company_name, $tracking_code, $tracking_url); 737 | 738 | if ($result['success']) { 739 | // Sipariş notuna ekle 740 | $order->add_order_note('WhatsApp ile kargo bilgisi gönderildi. Telefon: ' . $phone); 741 | $order->save(); 742 | 743 | wp_send_json_success($result['message']); 744 | } else { 745 | wp_send_json_error($result['message']); 746 | } 747 | } 748 | -------------------------------------------------------------------------------- /kargo-takip-cargo-settings.php: -------------------------------------------------------------------------------- 1 | 18 |
19 |

20 | 21 | Kargo Firmaları Ayarları 22 |

23 | 24 |
25 | 26 |
27 | 28 | 29 |
30 |
31 |

32 | 33 | Yeni Kargo Firması Ekle 34 |

35 |

Sistemde olmayan bir kargo firması ekleyin.

36 |
37 |
38 |
39 | 40 | 41 |
42 | 43 | 45 | 46 |
47 | 48 |
49 | 50 | 52 |

53 | Takip kodunun ekleneceği URL. URL içinde {code} placeholder'ı kullanabilirsiniz.
54 | Örnek 1: https://takip.kargo.com/?kod={code}&lang=tr
55 | Örnek 2: https://kargo.com/takip/ (kod sona eklenir) 56 |

57 |
58 | 59 |
60 | 61 |
62 | 63 |
64 | 65 | Logo seçilmedi 66 |
67 | 70 | 73 |
74 |
75 |
76 |
77 | 82 |
83 | 84 | 85 |
86 |
87 |

88 | 89 | Mevcut Kargo Firmaları 90 |

91 |

Sistemde kayıtlı tüm kargo firmalarını görüntüleyin ve yönetin.

92 |
93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | $cargo): 107 | $is_custom = isset($custom_cargoes[$key]); 108 | $is_disabled = in_array($key, $disabled_cargoes); 109 | $logo_url = ''; 110 | 111 | if (!empty($cargo['logo'])) { 112 | if (strpos($cargo['logo'], 'http') === 0) { 113 | $logo_url = $cargo['logo']; 114 | } else { 115 | $logo_url = plugin_dir_url(__FILE__) . $cargo['logo']; 116 | } 117 | } 118 | ?> 119 | 120 | 127 | 135 | 136 | 141 | 151 | 159 | 160 | 161 | 162 |
LogoFirma AdıAnahtarTakip URLTeslimat (Gün)Durum
121 | 122 | <?php echo esc_attr($cargo['company']); ?> 123 | 124 | 125 | 126 | 128 | 129 | 130 | Özel 131 | 132 | Varsayılan 133 | 134 | 137 | 138 | ... 139 | 140 | 142 | 146 | 150 | 152 | 158 |
163 |
164 |
165 |
166 | 167 | 168 |
169 |
170 |
171 |

172 | 173 | Kullanım Bilgisi 174 |

175 |
176 |
177 |

Yeni Firma Ekleme

178 |
    179 |
  1. Benzersiz bir anahtar belirleyin
  2. 180 |
  3. Firma adını girin
  4. 181 |
  5. Kargo takip URL'ini girin
  6. 182 |
  7. İsteğe bağlı logo yükleyin
  8. 183 |
184 | 185 |
186 | 187 | İpucu: URL'de {code} placeholder'ı kullanarak takip kodunun yerini belirleyebilirsiniz. Kullanmazsanız kod URL'in sonuna eklenir. 188 |
189 |
190 |
191 | 192 |
193 |
194 |

195 | 196 | Durum Kontrolü 197 |

198 |
199 |
200 |

Toggle ile firmaları aktif/pasif yapabilirsiniz.

201 |

Pasif firmalar sipariş formlarındaki dropdown listesinde görünmez.

202 |
203 |
204 | 205 |
206 |
207 |

208 | 209 | İstatistikler 210 |

211 |
212 |
213 |
214 |
215 | 216 | Varsayılan 217 |
218 |
219 | 220 | Özel 221 |
222 |
223 | 224 | Pasif 225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 | 233 | 554 | 555 | 731 | $name, 794 | 'url' => $url, 795 | 'logo' => $logo 796 | ); 797 | 798 | update_option('kargoTR_custom_cargoes', $custom_cargoes); 799 | 800 | wp_send_json_success(); 801 | } 802 | 803 | // AJAX: Kargo firması durumunu değiştir 804 | add_action('wp_ajax_kargotr_toggle_cargo_status', 'kargoTR_toggle_cargo_status'); 805 | function kargoTR_toggle_cargo_status() { 806 | // Nonce kontrolü 807 | if (!wp_verify_nonce($_POST['nonce'], 'kargotr_toggle_cargo')) { 808 | wp_send_json_error('Güvenlik doğrulaması başarısız.'); 809 | } 810 | 811 | // Yetki kontrolü 812 | if (!current_user_can('manage_options')) { 813 | wp_send_json_error('Yetkiniz yok.'); 814 | } 815 | 816 | $key = sanitize_key($_POST['key']); 817 | $enabled = intval($_POST['enabled']); 818 | 819 | $disabled_cargoes = get_option('kargoTR_disabled_cargoes', array()); 820 | 821 | if ($enabled) { 822 | // Listeden kaldır 823 | $disabled_cargoes = array_diff($disabled_cargoes, array($key)); 824 | } else { 825 | // Listeye ekle 826 | if (!in_array($key, $disabled_cargoes)) { 827 | $disabled_cargoes[] = $key; 828 | } 829 | } 830 | 831 | update_option('kargoTR_disabled_cargoes', array_values($disabled_cargoes)); 832 | 833 | wp_send_json_success(); 834 | } 835 | -------------------------------------------------------------------------------- /kargo-takip-cities-districts.php: -------------------------------------------------------------------------------- 1 | 4 | array ( 5 | 1 => 'ADANA', 6 | 2 => 'ADIYAMAN', 7 | 3 => 'AFYON', 8 | 4 => 'AĞRI', 9 | 5 => 'AMASYA', 10 | 6 => 'ANKARA', 11 | 7 => 'ANTALYA', 12 | 8 => 'ARTVİN', 13 | 9 => 'AYDIN', 14 | 10 => 'BALIKESİR', 15 | 11 => 'BİLECİK', 16 | 12 => 'BİNGÖL', 17 | 13 => 'BİTLİS', 18 | 14 => 'BOLU', 19 | 15 => 'BURDUR', 20 | 16 => 'BURSA', 21 | 17 => 'ÇANAKKALE', 22 | 18 => 'ÇANKIRI', 23 | 19 => 'ÇORUM', 24 | 20 => 'DENİZLİ', 25 | 21 => 'DİYARBAKIR', 26 | 22 => 'EDİRNE', 27 | 23 => 'ELAZIĞ', 28 | 24 => 'ERZİNCAN', 29 | 25 => 'ERZURUM', 30 | 26 => 'ESKİŞEHİR', 31 | 27 => 'GAZİANTEP', 32 | 28 => 'GİRESUN', 33 | 29 => 'GÜMÜŞHANE', 34 | 30 => 'HAKKARİ', 35 | 31 => 'HATAY', 36 | 32 => 'ISPARTA', 37 | 33 => 'İÇEL', 38 | 34 => 'İSTANBUL', 39 | 35 => 'İZMİR', 40 | 36 => 'KARS', 41 | 37 => 'KASTAMONU', 42 | 38 => 'KAYSERİ', 43 | 39 => 'KIRKLARELİ', 44 | 40 => 'KIRŞEHİR', 45 | 41 => 'KOCAELİ', 46 | 42 => 'KONYA', 47 | 43 => 'KÜTAHYA', 48 | 44 => 'MALATYA', 49 | 45 => 'MANİSA', 50 | 46 => 'KAHRAMANMARAŞ', 51 | 47 => 'MARDİN', 52 | 48 => 'MUĞLA', 53 | 49 => 'MUŞ', 54 | 50 => 'NEVŞEHİR', 55 | 51 => 'NİĞDE', 56 | 52 => 'ORDU', 57 | 53 => 'RİZE', 58 | 54 => 'SAKARYA', 59 | 55 => 'SAMSUN', 60 | 56 => 'SİİRT', 61 | 57 => 'SİNOP', 62 | 58 => 'SİVAS', 63 | 59 => 'TEKİRDAĞ', 64 | 60 => 'TOKAT', 65 | 61 => 'TRABZON', 66 | 62 => 'TUNCELİ', 67 | 63 => 'ŞANLIURFA', 68 | 64 => 'UŞAK', 69 | 65 => 'VAN', 70 | 66 => 'YOZGAT', 71 | 67 => 'ZONGULDAK', 72 | 68 => 'AKSARAY', 73 | 69 => 'BAYBURT', 74 | 70 => 'KARAMAN', 75 | 71 => 'KIRIKKALE', 76 | 72 => 'BATMAN', 77 | 73 => 'ŞIRNAK', 78 | 74 => 'BARTIN', 79 | 75 => 'ARDAHAN', 80 | 76 => 'IĞDIR', 81 | 77 => 'YALOVA', 82 | 78 => 'KARABÜK', 83 | 79 => 'KİLİS', 84 | 80 => 'OSMANİYE', 85 | 81 => 'DÜZCE', 86 | ), 87 | 'districts' => 88 | array ( 89 | 1 => 90 | array ( 91 | 1 => 'ALADAĞ', 92 | 2 => 'CEYHAN', 93 | 3 => 'ÇUKUROVA', 94 | 4 => 'FEKE', 95 | 5 => 'İMAMOĞLU', 96 | 6 => 'KARAİSALI', 97 | 7 => 'KARATAŞ', 98 | 8 => 'KOZAN', 99 | 9 => 'POZANTI', 100 | 10 => 'SAİMBEYLİ', 101 | 11 => 'SARIÇAM', 102 | 12 => 'SEYHAN', 103 | 13 => 'TUFANBEYLİ', 104 | 14 => 'YUMURTALIK', 105 | 15 => 'YÜREĞİR', 106 | ), 107 | 2 => 108 | array ( 109 | 16 => 'BESNİ', 110 | 17 => 'ÇELİKHAN', 111 | 18 => 'GERGER', 112 | 19 => 'GÖLBAŞI', 113 | 20 => 'KAHTA', 114 | 21 => 'MERKEZ', 115 | 22 => 'SAMSAT', 116 | 23 => 'SİNCİK', 117 | 24 => 'TUT', 118 | ), 119 | 3 => 120 | array ( 121 | 25 => 'BAŞMAKÇI', 122 | 26 => 'BAYAT', 123 | 27 => 'BOLVADİN', 124 | 28 => 'ÇAY', 125 | 29 => 'ÇOBANLAR', 126 | 30 => 'DAZKIRI', 127 | 31 => 'DİNAR', 128 | 32 => 'EMİRDAĞ', 129 | 33 => 'EVCİLER', 130 | 34 => 'HOCALAR', 131 | 35 => 'İHSANİYE', 132 | 36 => 'İSCEHİSAR', 133 | 37 => 'KIZILÖREN', 134 | 38 => 'MERKEZ', 135 | 39 => 'SANDIKLI', 136 | 40 => 'SİNANPAŞA', 137 | 41 => 'SULTANDAĞI', 138 | 42 => 'ŞUHUT', 139 | ), 140 | 4 => 141 | array ( 142 | 43 => 'DİYADİN', 143 | 44 => 'DOĞUBAYAZIT', 144 | 45 => 'ELEŞKİRT', 145 | 46 => 'HAMUR', 146 | 47 => 'MERKEZ', 147 | 48 => 'PATNOS', 148 | 49 => 'TAŞLIÇAY', 149 | 50 => 'TUTAK', 150 | ), 151 | 68 => 152 | array ( 153 | 51 => 'AĞAÇÖREN', 154 | 52 => 'ESKİL', 155 | 53 => 'GÜLAĞAÇ', 156 | 54 => 'GÜZELYURT', 157 | 55 => 'MERKEZ', 158 | 56 => 'ORTAKÖY', 159 | 57 => 'SARIYAHŞİ', 160 | 58 => 'SULTANHANI', 161 | ), 162 | 5 => 163 | array ( 164 | 59 => 'GÖYNÜCEK', 165 | 60 => 'GÜMÜŞHACIKÖY', 166 | 61 => 'HAMAMÖZÜ', 167 | 62 => 'MERKEZ', 168 | 63 => 'MERZİFON', 169 | 64 => 'SULUOVA', 170 | 65 => 'TAŞOVA', 171 | ), 172 | 6 => 173 | array ( 174 | 66 => 'AKYURT', 175 | 67 => 'ALTINDAĞ', 176 | 68 => 'AYAŞ', 177 | 69 => 'BALA', 178 | 70 => 'BEYPAZARI', 179 | 71 => 'ÇAMLIDERE', 180 | 72 => 'ÇANKAYA', 181 | 73 => 'ÇUBUK', 182 | 74 => 'ELMADAĞ', 183 | 75 => 'ETİMESGUT', 184 | 76 => 'EVREN', 185 | 77 => 'GÖLBAŞI', 186 | 78 => 'GÜDÜL', 187 | 79 => 'HAYMANA', 188 | 80 => 'KAHRAMANKAZAN', 189 | 81 => 'KALECİK', 190 | 82 => 'KEÇİÖREN', 191 | 83 => 'KIZILCAHAMAM', 192 | 84 => 'MAMAK', 193 | 85 => 'NALLIHAN', 194 | 86 => 'POLATLI', 195 | 87 => 'PURSAKLAR', 196 | 88 => 'SİNCAN', 197 | 89 => 'ŞEREFLİKOÇHİSAR', 198 | 90 => 'YENİMAHALLE', 199 | ), 200 | 7 => 201 | array ( 202 | 91 => 'AKSEKİ', 203 | 92 => 'AKSU', 204 | 93 => 'ALANYA', 205 | 94 => 'DEMRE', 206 | 95 => 'DÖŞEMEALTI', 207 | 96 => 'ELMALI', 208 | 97 => 'FİNİKE', 209 | 98 => 'GAZİPAŞA', 210 | 99 => 'GÜNDOĞMUŞ', 211 | 100 => 'İBRADI', 212 | 101 => 'KAŞ', 213 | 102 => 'KEMER', 214 | 103 => 'KEPEZ', 215 | 104 => 'KONYAALTI', 216 | 105 => 'KORKUTELİ', 217 | 106 => 'KUMLUCA', 218 | 107 => 'MANAVGAT', 219 | 108 => 'MURATPAŞA', 220 | 109 => 'SERİK', 221 | ), 222 | 75 => 223 | array ( 224 | 110 => 'ÇILDIR', 225 | 111 => 'DAMAL', 226 | 112 => 'GÖLE', 227 | 113 => 'HANAK', 228 | 114 => 'MERKEZ', 229 | 115 => 'POSOF', 230 | ), 231 | 8 => 232 | array ( 233 | 116 => 'ARDANUÇ', 234 | 117 => 'ARHAVİ', 235 | 118 => 'BORÇKA', 236 | 119 => 'HOPA', 237 | 120 => 'KEMALPAŞA', 238 | 121 => 'MERKEZ', 239 | 122 => 'MURGUL', 240 | 123 => 'ŞAVŞAT', 241 | 124 => 'YUSUFELİ', 242 | ), 243 | 9 => 244 | array ( 245 | 125 => 'BOZDOĞAN', 246 | 126 => 'BUHARKENT', 247 | 127 => 'ÇİNE', 248 | 128 => 'DİDİM', 249 | 129 => 'EFELER', 250 | 130 => 'GERMENCİK', 251 | 131 => 'İNCİRLİOVA', 252 | 132 => 'KARACASU', 253 | 133 => 'KARPUZLU', 254 | 134 => 'KOÇARLI', 255 | 135 => 'KÖŞK', 256 | 136 => 'KUŞADASI', 257 | 137 => 'KUYUCAK', 258 | 138 => 'NAZİLLİ', 259 | 139 => 'SÖKE', 260 | 140 => 'SULTANHİSAR', 261 | 141 => 'YENİPAZAR', 262 | ), 263 | 10 => 264 | array ( 265 | 142 => 'ALTIEYLÜL', 266 | 143 => 'AYVALIK', 267 | 144 => 'BALYA', 268 | 145 => 'BANDIRMA', 269 | 146 => 'BİGADİÇ', 270 | 147 => 'BURHANİYE', 271 | 148 => 'DURSUNBEY', 272 | 149 => 'EDREMİT', 273 | 150 => 'ERDEK', 274 | 151 => 'GÖMEÇ', 275 | 152 => 'GÖNEN', 276 | 153 => 'HAVRAN', 277 | 154 => 'İVRİNDİ', 278 | 155 => 'KARESİ', 279 | 156 => 'KEPSUT', 280 | 157 => 'MANYAS', 281 | 158 => 'MARMARA', 282 | 159 => 'SAVAŞTEPE', 283 | 160 => 'SINDIRGI', 284 | 161 => 'SUSURLUK', 285 | ), 286 | 74 => 287 | array ( 288 | 162 => 'AMASRA', 289 | 163 => 'KURUCAŞİLE', 290 | 164 => 'MERKEZ', 291 | 165 => 'ULUS', 292 | ), 293 | 72 => 294 | array ( 295 | 166 => 'BEŞİRİ', 296 | 167 => 'GERCÜŞ', 297 | 168 => 'HASANKEYF', 298 | 169 => 'KOZLUK', 299 | 170 => 'MERKEZ', 300 | 171 => 'SASON', 301 | ), 302 | 69 => 303 | array ( 304 | 172 => 'AYDINTEPE', 305 | 173 => 'DEMİRÖZÜ', 306 | 174 => 'MERKEZ', 307 | ), 308 | 11 => 309 | array ( 310 | 175 => 'BOZÜYÜK', 311 | 176 => 'GÖLPAZARI', 312 | 177 => 'İNHİSAR', 313 | 178 => 'MERKEZ', 314 | 179 => 'OSMANELİ', 315 | 180 => 'PAZARYERİ', 316 | 181 => 'SÖĞÜT', 317 | 182 => 'YENİPAZAR', 318 | ), 319 | 12 => 320 | array ( 321 | 183 => 'ADAKLI', 322 | 184 => 'GENÇ', 323 | 185 => 'KARLIOVA', 324 | 186 => 'KİĞI', 325 | 187 => 'MERKEZ', 326 | 188 => 'SOLHAN', 327 | 189 => 'YAYLADERE', 328 | 190 => 'YEDİSU', 329 | ), 330 | 13 => 331 | array ( 332 | 191 => 'ADİLCEVAZ', 333 | 192 => 'AHLAT', 334 | 193 => 'GÜROYMAK', 335 | 194 => 'HİZAN', 336 | 195 => 'MERKEZ', 337 | 196 => 'MUTKİ', 338 | 197 => 'TATVAN', 339 | ), 340 | 14 => 341 | array ( 342 | 198 => 'DÖRTDİVAN', 343 | 199 => 'GEREDE', 344 | 200 => 'GÖYNÜK', 345 | 201 => 'KIBRISCIK', 346 | 202 => 'MENGEN', 347 | 203 => 'MERKEZ', 348 | 204 => 'MUDURNU', 349 | 205 => 'SEBEN', 350 | 206 => 'YENİÇAĞA', 351 | ), 352 | 15 => 353 | array ( 354 | 207 => 'AĞLASUN', 355 | 208 => 'ALTINYAYLA', 356 | 209 => 'BUCAK', 357 | 210 => 'ÇAVDIR', 358 | 211 => 'ÇELTİKÇİ', 359 | 212 => 'GÖLHİSAR', 360 | 213 => 'KARAMANLI', 361 | 214 => 'KEMER', 362 | 215 => 'MERKEZ', 363 | 216 => 'TEFENNİ', 364 | 217 => 'YEŞİLOVA', 365 | ), 366 | 16 => 367 | array ( 368 | 218 => 'BÜYÜKORHAN', 369 | 219 => 'GEMLİK', 370 | 220 => 'GÜRSU', 371 | 221 => 'HARMANCIK', 372 | 222 => 'İNEGÖL', 373 | 223 => 'İZNİK', 374 | 224 => 'KARACABEY', 375 | 225 => 'KELES', 376 | 226 => 'KESTEL', 377 | 227 => 'MUDANYA', 378 | 228 => 'MUSTAFAKEMALPAŞA', 379 | 229 => 'NİLÜFER', 380 | 230 => 'ORHANELİ', 381 | 231 => 'ORHANGAZİ', 382 | 232 => 'OSMANGAZİ', 383 | 233 => 'YENİŞEHİR', 384 | 234 => 'YILDIRIM', 385 | ), 386 | 17 => 387 | array ( 388 | 235 => 'AYVACIK', 389 | 236 => 'BAYRAMİÇ', 390 | 237 => 'BİGA', 391 | 238 => 'BOZCAADA', 392 | 239 => 'ÇAN', 393 | 240 => 'ECEABAT', 394 | 241 => 'EZİNE', 395 | 242 => 'GELİBOLU', 396 | 243 => 'GÖKÇEADA', 397 | 244 => 'LAPSEKİ', 398 | 245 => 'MERKEZ', 399 | 246 => 'YENİCE', 400 | ), 401 | 18 => 402 | array ( 403 | 247 => 'ATKARACALAR', 404 | 248 => 'BAYRAMÖREN', 405 | 249 => 'ÇERKEŞ', 406 | 250 => 'ELDİVAN', 407 | 251 => 'ILGAZ', 408 | 252 => 'KIZILIRMAK', 409 | 253 => 'KORGUN', 410 | 254 => 'KURŞUNLU', 411 | 255 => 'MERKEZ', 412 | 256 => 'ORTA', 413 | 257 => 'ŞABANÖZÜ', 414 | 258 => 'YAPRAKLI', 415 | ), 416 | 19 => 417 | array ( 418 | 259 => 'ALACA', 419 | 260 => 'BAYAT', 420 | 261 => 'BOĞAZKALE', 421 | 262 => 'DODURGA', 422 | 263 => 'İSKİLİP', 423 | 264 => 'KARGI', 424 | 265 => 'LAÇİN', 425 | 266 => 'MECİTÖZÜ', 426 | 267 => 'MERKEZ', 427 | 268 => 'OĞUZLAR', 428 | 269 => 'ORTAKÖY', 429 | 270 => 'OSMANCIK', 430 | 271 => 'SUNGURLU', 431 | 272 => 'UĞURLUDAĞ', 432 | ), 433 | 20 => 434 | array ( 435 | 273 => 'ACIPAYAM', 436 | 274 => 'BABADAĞ', 437 | 275 => 'BAKLAN', 438 | 276 => 'BEKİLLİ', 439 | 277 => 'BEYAĞAÇ', 440 | 278 => 'BOZKURT', 441 | 279 => 'BULDAN', 442 | 280 => 'ÇAL', 443 | 281 => 'ÇAMELİ', 444 | 282 => 'ÇARDAK', 445 | 283 => 'ÇİVRİL', 446 | 284 => 'GÜNEY', 447 | 285 => 'HONAZ', 448 | 286 => 'KALE', 449 | 287 => 'MERKEZEFENDİ', 450 | 288 => 'PAMUKKALE', 451 | 289 => 'SARAYKÖY', 452 | 290 => 'SERİNHİSAR', 453 | 291 => 'TAVAS', 454 | ), 455 | 21 => 456 | array ( 457 | 292 => 'BAĞLAR', 458 | 293 => 'BİSMİL', 459 | 294 => 'ÇERMİK', 460 | 295 => 'ÇINAR', 461 | 296 => 'ÇÜNGÜŞ', 462 | 297 => 'DİCLE', 463 | 298 => 'EĞİL', 464 | 299 => 'ERGANİ', 465 | 300 => 'HANİ', 466 | 301 => 'HAZRO', 467 | 302 => 'KAYAPINAR', 468 | 303 => 'KOCAKÖY', 469 | 304 => 'KULP', 470 | 305 => 'LİCE', 471 | 306 => 'SİLVAN', 472 | 307 => 'SUR', 473 | 308 => 'YENİŞEHİR', 474 | ), 475 | 81 => 476 | array ( 477 | 309 => 'AKÇAKOCA', 478 | 310 => 'CUMAYERİ', 479 | 311 => 'ÇİLİMLİ', 480 | 312 => 'GÖLYAKA', 481 | 313 => 'GÜMÜŞOVA', 482 | 314 => 'KAYNAŞLI', 483 | 315 => 'MERKEZ', 484 | 316 => 'YIĞILCA', 485 | ), 486 | 22 => 487 | array ( 488 | 317 => 'ENEZ', 489 | 318 => 'HAVSA', 490 | 319 => 'İPSALA', 491 | 320 => 'KEŞAN', 492 | 321 => 'LALAPAŞA', 493 | 322 => 'MERİÇ', 494 | 323 => 'MERKEZ', 495 | 324 => 'SÜLOĞLU', 496 | 325 => 'UZUNKÖPRÜ', 497 | ), 498 | 23 => 499 | array ( 500 | 326 => 'AĞIN', 501 | 327 => 'ALACAKAYA', 502 | 328 => 'ARICAK', 503 | 329 => 'BASKİL', 504 | 330 => 'KARAKOÇAN', 505 | 331 => 'KEBAN', 506 | 332 => 'KOVANCILAR', 507 | 333 => 'MADEN', 508 | 334 => 'MERKEZ', 509 | 335 => 'PALU', 510 | 336 => 'SİVRİCE', 511 | ), 512 | 24 => 513 | array ( 514 | 337 => 'ÇAYIRLI', 515 | 338 => 'İLİÇ', 516 | 339 => 'KEMAH', 517 | 340 => 'KEMALİYE', 518 | 341 => 'MERKEZ', 519 | 342 => 'OTLUKBELİ', 520 | 343 => 'REFAHİYE', 521 | 344 => 'TERCAN', 522 | 345 => 'ÜZÜMLÜ', 523 | ), 524 | 25 => 525 | array ( 526 | 346 => 'AŞKALE', 527 | 347 => 'AZİZİYE', 528 | 348 => 'ÇAT', 529 | 349 => 'HINIS', 530 | 350 => 'HORASAN', 531 | 351 => 'İSPİR', 532 | 352 => 'KARAÇOBAN', 533 | 353 => 'KARAYAZI', 534 | 354 => 'KÖPRÜKÖY', 535 | 355 => 'NARMAN', 536 | 356 => 'OLTU', 537 | 357 => 'OLUR', 538 | 358 => 'PALANDÖKEN', 539 | 359 => 'PASİNLER', 540 | 360 => 'PAZARYOLU', 541 | 361 => 'ŞENKAYA', 542 | 362 => 'TEKMAN', 543 | 363 => 'TORTUM', 544 | 364 => 'UZUNDERE', 545 | 365 => 'YAKUTİYE', 546 | ), 547 | 26 => 548 | array ( 549 | 366 => 'ALPU', 550 | 367 => 'BEYLİKOVA', 551 | 368 => 'ÇİFTELER', 552 | 369 => 'GÜNYÜZÜ', 553 | 370 => 'HAN', 554 | 371 => 'İNÖNÜ', 555 | 372 => 'MAHMUDİYE', 556 | 373 => 'MİHALGAZİ', 557 | 374 => 'MİHALIÇÇIK', 558 | 375 => 'ODUNPAZARI', 559 | 376 => 'SARICAKAYA', 560 | 377 => 'SEYİTGAZİ', 561 | 378 => 'SİVRİHİSAR', 562 | 379 => 'TEPEBAŞI', 563 | ), 564 | 27 => 565 | array ( 566 | 380 => 'ARABAN', 567 | 381 => 'İSLAHİYE', 568 | 382 => 'KARKAMIŞ', 569 | 383 => 'NİZİP', 570 | 384 => 'NURDAĞI', 571 | 385 => 'OĞUZELİ', 572 | 386 => 'ŞAHİNBEY', 573 | 387 => 'ŞEHİTKAMİL', 574 | 388 => 'YAVUZELİ', 575 | ), 576 | 28 => 577 | array ( 578 | 389 => 'ALUCRA', 579 | 390 => 'BULANCAK', 580 | 391 => 'ÇAMOLUK', 581 | 392 => 'ÇANAKÇI', 582 | 393 => 'DERELİ', 583 | 394 => 'DOĞANKENT', 584 | 395 => 'ESPİYE', 585 | 396 => 'EYNESİL', 586 | 397 => 'GÖRELE', 587 | 398 => 'GÜCE', 588 | 399 => 'KEŞAP', 589 | 400 => 'MERKEZ', 590 | 401 => 'PİRAZİZ', 591 | 402 => 'ŞEBİNKARAHİSAR', 592 | 403 => 'TİREBOLU', 593 | 404 => 'YAĞLIDERE', 594 | ), 595 | 29 => 596 | array ( 597 | 405 => 'KELKİT', 598 | 406 => 'KÖSE', 599 | 407 => 'KÜRTÜN', 600 | 408 => 'MERKEZ', 601 | 409 => 'ŞİRAN', 602 | 410 => 'TORUL', 603 | ), 604 | 30 => 605 | array ( 606 | 411 => 'ÇUKURCA', 607 | 412 => 'DERECİK', 608 | 413 => 'MERKEZ', 609 | 414 => 'ŞEMDİNLİ', 610 | 415 => 'YÜKSEKOVA', 611 | ), 612 | 31 => 613 | array ( 614 | 416 => 'ALTINÖZÜ', 615 | 417 => 'ANTAKYA', 616 | 418 => 'ARSUZ', 617 | 419 => 'BELEN', 618 | 420 => 'DEFNE', 619 | 421 => 'DÖRTYOL', 620 | 422 => 'ERZİN', 621 | 423 => 'HASSA', 622 | 424 => 'İSKENDERUN', 623 | 425 => 'KIRIKHAN', 624 | 426 => 'KUMLU', 625 | 427 => 'PAYAS', 626 | 428 => 'REYHANLI', 627 | 429 => 'SAMANDAĞ', 628 | 430 => 'YAYLADAĞI', 629 | ), 630 | 76 => 631 | array ( 632 | 431 => 'ARALIK', 633 | 432 => 'KARAKOYUNLU', 634 | 433 => 'MERKEZ', 635 | 434 => 'TUZLUCA', 636 | ), 637 | 32 => 638 | array ( 639 | 435 => 'AKSU', 640 | 436 => 'ATABEY', 641 | 437 => 'EĞİRDİR', 642 | 438 => 'GELENDOST', 643 | 439 => 'GÖNEN', 644 | 440 => 'KEÇİBORLU', 645 | 441 => 'MERKEZ', 646 | 442 => 'SENİRKENT', 647 | 443 => 'SÜTÇÜLER', 648 | 444 => 'ŞARKİKARAAĞAÇ', 649 | 445 => 'ULUBORLU', 650 | 446 => 'YALVAÇ', 651 | 447 => 'YENİŞARBADEMLİ', 652 | ), 653 | 34 => 654 | array ( 655 | 448 => 'ADALAR', 656 | 449 => 'ARNAVUTKÖY', 657 | 450 => 'ATAŞEHİR', 658 | 451 => 'AVCILAR', 659 | 452 => 'BAĞCILAR', 660 | 453 => 'BAHÇELİEVLER', 661 | 454 => 'BAKIRKÖY', 662 | 455 => 'BAŞAKŞEHİR', 663 | 456 => 'BAYRAMPAŞA', 664 | 457 => 'BEŞİKTAŞ', 665 | 458 => 'BEYKOZ', 666 | 459 => 'BEYLİKDÜZÜ', 667 | 460 => 'BEYOĞLU', 668 | 461 => 'BÜYÜKÇEKMECE', 669 | 462 => 'ÇATALCA', 670 | 463 => 'ÇEKMEKÖY', 671 | 464 => 'ESENLER', 672 | 465 => 'ESENYURT', 673 | 466 => 'EYÜPSULTAN', 674 | 467 => 'FATİH', 675 | 468 => 'GAZİOSMANPAŞA', 676 | 469 => 'GÜNGÖREN', 677 | 470 => 'KADIKÖY', 678 | 471 => 'KAĞITHANE', 679 | 472 => 'KARTAL', 680 | 473 => 'KÜÇÜKÇEKMECE', 681 | 474 => 'MALTEPE', 682 | 475 => 'PENDİK', 683 | 476 => 'SANCAKTEPE', 684 | 477 => 'SARIYER', 685 | 478 => 'SİLİVRİ', 686 | 479 => 'SULTANBEYLİ', 687 | 480 => 'SULTANGAZİ', 688 | 481 => 'ŞİLE', 689 | 482 => 'ŞİŞLİ', 690 | 483 => 'TUZLA', 691 | 484 => 'ÜMRANİYE', 692 | 485 => 'ÜSKÜDAR', 693 | 486 => 'ZEYTİNBURNU', 694 | ), 695 | 35 => 696 | array ( 697 | 487 => 'ALİAĞA', 698 | 488 => 'BALÇOVA', 699 | 489 => 'BAYINDIR', 700 | 490 => 'BAYRAKLI', 701 | 491 => 'BERGAMA', 702 | 492 => 'BEYDAĞ', 703 | 493 => 'BORNOVA', 704 | 494 => 'BUCA', 705 | 495 => 'ÇEŞME', 706 | 496 => 'ÇİĞLİ', 707 | 497 => 'DİKİLİ', 708 | 498 => 'FOÇA', 709 | 499 => 'GAZİEMİR', 710 | 500 => 'GÜZELBAHÇE', 711 | 501 => 'KARABAĞLAR', 712 | 502 => 'KARABURUN', 713 | 503 => 'KARŞIYAKA', 714 | 504 => 'KEMALPAŞA', 715 | 505 => 'KINIK', 716 | 506 => 'KİRAZ', 717 | 507 => 'KONAK', 718 | 508 => 'MENDERES', 719 | 509 => 'MENEMEN', 720 | 510 => 'NARLIDERE', 721 | 511 => 'ÖDEMİŞ', 722 | 512 => 'SEFERİHİSAR', 723 | 513 => 'SELÇUK', 724 | 514 => 'TİRE', 725 | 515 => 'TORBALI', 726 | 516 => 'URLA', 727 | ), 728 | 46 => 729 | array ( 730 | 517 => 'AFŞİN', 731 | 518 => 'ANDIRIN', 732 | 519 => 'ÇAĞLAYANCERİT', 733 | 520 => 'DULKADİROĞLU', 734 | 521 => 'EKİNÖZÜ', 735 | 522 => 'ELBİSTAN', 736 | 523 => 'GÖKSUN', 737 | 524 => 'NURHAK', 738 | 525 => 'ONİKİŞUBAT', 739 | 526 => 'PAZARCIK', 740 | 527 => 'TÜRKOĞLU', 741 | ), 742 | 78 => 743 | array ( 744 | 528 => 'EFLANİ', 745 | 529 => 'ESKİPAZAR', 746 | 530 => 'MERKEZ', 747 | 531 => 'OVACIK', 748 | 532 => 'SAFRANBOLU', 749 | 533 => 'YENİCE', 750 | ), 751 | 70 => 752 | array ( 753 | 534 => 'AYRANCI', 754 | 535 => 'BAŞYAYLA', 755 | 536 => 'ERMENEK', 756 | 537 => 'KAZIMKARABEKİR', 757 | 538 => 'MERKEZ', 758 | 539 => 'SARIVELİLER', 759 | ), 760 | 36 => 761 | array ( 762 | 540 => 'AKYAKA', 763 | 541 => 'ARPAÇAY', 764 | 542 => 'DİGOR', 765 | 543 => 'KAĞIZMAN', 766 | 544 => 'MERKEZ', 767 | 545 => 'SARIKAMIŞ', 768 | 546 => 'SELİM', 769 | 547 => 'SUSUZ', 770 | ), 771 | 37 => 772 | array ( 773 | 548 => 'ABANA', 774 | 549 => 'AĞLI', 775 | 550 => 'ARAÇ', 776 | 551 => 'AZDAVAY', 777 | 552 => 'BOZKURT', 778 | 553 => 'CİDE', 779 | 554 => 'ÇATALZEYTİN', 780 | 555 => 'DADAY', 781 | 556 => 'DEVREKANİ', 782 | 557 => 'DOĞANYURT', 783 | 558 => 'HANÖNÜ', 784 | 559 => 'İHSANGAZİ', 785 | 560 => 'İNEBOLU', 786 | 561 => 'KÜRE', 787 | 562 => 'MERKEZ', 788 | 563 => 'PINARBAŞI', 789 | 564 => 'SEYDİLER', 790 | 565 => 'ŞENPAZAR', 791 | 566 => 'TAŞKÖPRÜ', 792 | 567 => 'TOSYA', 793 | ), 794 | 38 => 795 | array ( 796 | 568 => 'AKKIŞLA', 797 | 569 => 'BÜNYAN', 798 | 570 => 'DEVELİ', 799 | 571 => 'FELAHİYE', 800 | 572 => 'HACILAR', 801 | 573 => 'İNCESU', 802 | 574 => 'KOCASİNAN', 803 | 575 => 'MELİKGAZİ', 804 | 576 => 'ÖZVATAN', 805 | 577 => 'PINARBAŞI', 806 | 578 => 'SARIOĞLAN', 807 | 579 => 'SARIZ', 808 | 580 => 'TALAS', 809 | 581 => 'TOMARZA', 810 | 582 => 'YAHYALI', 811 | 583 => 'YEŞİLHİSAR', 812 | ), 813 | 71 => 814 | array ( 815 | 584 => 'BAHŞILI', 816 | 585 => 'BALIŞEYH', 817 | 586 => 'ÇELEBİ', 818 | 587 => 'DELİCE', 819 | 588 => 'KARAKEÇİLİ', 820 | 589 => 'KESKİN', 821 | 590 => 'MERKEZ', 822 | 591 => 'SULAKYURT', 823 | 592 => 'YAHŞİHAN', 824 | ), 825 | 39 => 826 | array ( 827 | 593 => 'BABAESKİ', 828 | 594 => 'DEMİRKÖY', 829 | 595 => 'KOFÇAZ', 830 | 596 => 'LÜLEBURGAZ', 831 | 597 => 'MERKEZ', 832 | 598 => 'PEHLİVANKÖY', 833 | 599 => 'PINARHİSAR', 834 | 600 => 'VİZE', 835 | ), 836 | 40 => 837 | array ( 838 | 601 => 'AKÇAKENT', 839 | 602 => 'AKPINAR', 840 | 603 => 'BOZTEPE', 841 | 604 => 'ÇİÇEKDAĞI', 842 | 605 => 'KAMAN', 843 | 606 => 'MERKEZ', 844 | 607 => 'MUCUR', 845 | ), 846 | 79 => 847 | array ( 848 | 608 => 'ELBEYLİ', 849 | 609 => 'MERKEZ', 850 | 610 => 'MUSABEYLİ', 851 | 611 => 'POLATELİ', 852 | ), 853 | 41 => 854 | array ( 855 | 612 => 'BAŞİSKELE', 856 | 613 => 'ÇAYIROVA', 857 | 614 => 'DARICA', 858 | 615 => 'DERİNCE', 859 | 616 => 'DİLOVASI', 860 | 617 => 'GEBZE', 861 | 618 => 'GÖLCÜK', 862 | 619 => 'İZMİT', 863 | 620 => 'KANDIRA', 864 | 621 => 'KARAMÜRSEL', 865 | 622 => 'KARTEPE', 866 | 623 => 'KÖRFEZ', 867 | ), 868 | 42 => 869 | array ( 870 | 624 => 'AHIRLI', 871 | 625 => 'AKÖREN', 872 | 626 => 'AKŞEHİR', 873 | 627 => 'ALTINEKİN', 874 | 628 => 'BEYŞEHİR', 875 | 629 => 'BOZKIR', 876 | 630 => 'CİHANBEYLİ', 877 | 631 => 'ÇELTİK', 878 | 632 => 'ÇUMRA', 879 | 633 => 'DERBENT', 880 | 634 => 'DEREBUCAK', 881 | 635 => 'DOĞANHİSAR', 882 | 636 => 'EMİRGAZİ', 883 | 637 => 'EREĞLİ', 884 | 638 => 'GÜNEYSINIR', 885 | 639 => 'HADİM', 886 | 640 => 'HALKAPINAR', 887 | 641 => 'HÜYÜK', 888 | 642 => 'ILGIN', 889 | 643 => 'KADINHANI', 890 | 644 => 'KARAPINAR', 891 | 645 => 'KARATAY', 892 | 646 => 'KULU', 893 | 647 => 'MERAM', 894 | 648 => 'SARAYÖNÜ', 895 | 649 => 'SELÇUKLU', 896 | 650 => 'SEYDİŞEHİR', 897 | 651 => 'TAŞKENT', 898 | 652 => 'TUZLUKÇU', 899 | 653 => 'YALIHÜYÜK', 900 | 654 => 'YUNAK', 901 | ), 902 | 43 => 903 | array ( 904 | 655 => 'ALTINTAŞ', 905 | 656 => 'ASLANAPA', 906 | 657 => 'ÇAVDARHİSAR', 907 | 658 => 'DOMANİÇ', 908 | 659 => 'DUMLUPINAR', 909 | 660 => 'EMET', 910 | 661 => 'GEDİZ', 911 | 662 => 'HİSARCIK', 912 | 663 => 'MERKEZ', 913 | 664 => 'PAZARLAR', 914 | 665 => 'SİMAV', 915 | 666 => 'ŞAPHANE', 916 | 667 => 'TAVŞANLI', 917 | ), 918 | 44 => 919 | array ( 920 | 668 => 'AKÇADAĞ', 921 | 669 => 'ARAPGİR', 922 | 670 => 'ARGUVAN', 923 | 671 => 'BATTALGAZİ', 924 | 672 => 'DARENDE', 925 | 673 => 'DOĞANŞEHİR', 926 | 674 => 'DOĞANYOL', 927 | 675 => 'HEKİMHAN', 928 | 676 => 'KALE', 929 | 677 => 'KULUNCAK', 930 | 678 => 'PÜTÜRGE', 931 | 679 => 'YAZIHAN', 932 | 680 => 'YEŞİLYURT', 933 | ), 934 | 45 => 935 | array ( 936 | 681 => 'AHMETLİ', 937 | 682 => 'AKHİSAR', 938 | 683 => 'ALAŞEHİR', 939 | 684 => 'DEMİRCİ', 940 | 685 => 'GÖLMARMARA', 941 | 686 => 'GÖRDES', 942 | 687 => 'KIRKAĞAÇ', 943 | 688 => 'KÖPRÜBAŞI', 944 | 689 => 'KULA', 945 | 690 => 'SALİHLİ', 946 | 691 => 'SARIGÖL', 947 | 692 => 'SARUHANLI', 948 | 693 => 'SELENDİ', 949 | 694 => 'SOMA', 950 | 695 => 'ŞEHZADELER', 951 | 696 => 'TURGUTLU', 952 | 697 => 'YUNUSEMRE', 953 | ), 954 | 47 => 955 | array ( 956 | 698 => 'ARTUKLU', 957 | 699 => 'DARGEÇİT', 958 | 700 => 'DERİK', 959 | 701 => 'KIZILTEPE', 960 | 702 => 'MAZIDAĞI', 961 | 703 => 'MİDYAT', 962 | 704 => 'NUSAYBİN', 963 | 705 => 'ÖMERLİ', 964 | 706 => 'SAVUR', 965 | 707 => 'YEŞİLLİ', 966 | ), 967 | 33 => 968 | array ( 969 | 708 => 'AKDENİZ', 970 | 709 => 'ANAMUR', 971 | 710 => 'AYDINCIK', 972 | 711 => 'BOZYAZI', 973 | 712 => 'ÇAMLIYAYLA', 974 | 713 => 'ERDEMLİ', 975 | 714 => 'GÜLNAR', 976 | 715 => 'MEZİTLİ', 977 | 716 => 'MUT', 978 | 717 => 'SİLİFKE', 979 | 718 => 'TARSUS', 980 | 719 => 'TOROSLAR', 981 | 720 => 'YENİŞEHİR', 982 | ), 983 | 48 => 984 | array ( 985 | 721 => 'BODRUM', 986 | 722 => 'DALAMAN', 987 | 723 => 'DATÇA', 988 | 724 => 'FETHİYE', 989 | 725 => 'KAVAKLIDERE', 990 | 726 => 'KÖYCEĞİZ', 991 | 727 => 'MARMARİS', 992 | 728 => 'MENTEŞE', 993 | 729 => 'MİLAS', 994 | 730 => 'ORTACA', 995 | 731 => 'SEYDİKEMER', 996 | 732 => 'ULA', 997 | 733 => 'YATAĞAN', 998 | ), 999 | 49 => 1000 | array ( 1001 | 734 => 'BULANIK', 1002 | 735 => 'HASKÖY', 1003 | 736 => 'KORKUT', 1004 | 737 => 'MALAZGİRT', 1005 | 738 => 'MERKEZ', 1006 | 739 => 'VARTO', 1007 | ), 1008 | 50 => 1009 | array ( 1010 | 740 => 'ACIGÖL', 1011 | 741 => 'AVANOS', 1012 | 742 => 'DERİNKUYU', 1013 | 743 => 'GÜLŞEHİR', 1014 | 744 => 'HACIBEKTAŞ', 1015 | 745 => 'KOZAKLI', 1016 | 746 => 'MERKEZ', 1017 | 747 => 'ÜRGÜP', 1018 | ), 1019 | 51 => 1020 | array ( 1021 | 748 => 'ALTUNHİSAR', 1022 | 749 => 'BOR', 1023 | 750 => 'ÇAMARDI', 1024 | 751 => 'ÇİFTLİK', 1025 | 752 => 'MERKEZ', 1026 | 753 => 'ULUKIŞLA', 1027 | ), 1028 | 52 => 1029 | array ( 1030 | 754 => 'AKKUŞ', 1031 | 755 => 'ALTINORDU', 1032 | 756 => 'AYBASTI', 1033 | 757 => 'ÇAMAŞ', 1034 | 758 => 'ÇATALPINAR', 1035 | 759 => 'ÇAYBAŞI', 1036 | 760 => 'FATSA', 1037 | 761 => 'GÖLKÖY', 1038 | 762 => 'GÜLYALI', 1039 | 763 => 'GÜRGENTEPE', 1040 | 764 => 'İKİZCE', 1041 | 765 => 'KABADÜZ', 1042 | 766 => 'KABATAŞ', 1043 | 767 => 'KORGAN', 1044 | 768 => 'KUMRU', 1045 | 769 => 'MESUDİYE', 1046 | 770 => 'PERŞEMBE', 1047 | 771 => 'ULUBEY', 1048 | 772 => 'ÜNYE', 1049 | ), 1050 | 80 => 1051 | array ( 1052 | 773 => 'BAHÇE', 1053 | 774 => 'DÜZİÇİ', 1054 | 775 => 'HASANBEYLİ', 1055 | 776 => 'KADİRLİ', 1056 | 777 => 'MERKEZ', 1057 | 778 => 'SUMBAS', 1058 | 779 => 'TOPRAKKALE', 1059 | ), 1060 | 53 => 1061 | array ( 1062 | 780 => 'ARDEŞEN', 1063 | 781 => 'ÇAMLIHEMŞİN', 1064 | 782 => 'ÇAYELİ', 1065 | 783 => 'DEREPAZARI', 1066 | 784 => 'FINDIKLI', 1067 | 785 => 'GÜNEYSU', 1068 | 786 => 'HEMŞİN', 1069 | 787 => 'İKİZDERE', 1070 | 788 => 'İYİDERE', 1071 | 789 => 'KALKANDERE', 1072 | 790 => 'MERKEZ', 1073 | 791 => 'PAZAR', 1074 | ), 1075 | 54 => 1076 | array ( 1077 | 792 => 'ADAPAZARI', 1078 | 793 => 'AKYAZI', 1079 | 794 => 'ARİFİYE', 1080 | 795 => 'ERENLER', 1081 | 796 => 'FERİZLİ', 1082 | 797 => 'GEYVE', 1083 | 798 => 'HENDEK', 1084 | 799 => 'KARAPÜRÇEK', 1085 | 800 => 'KARASU', 1086 | 801 => 'KAYNARCA', 1087 | 802 => 'KOCAALİ', 1088 | 803 => 'PAMUKOVA', 1089 | 804 => 'SAPANCA', 1090 | 805 => 'SERDİVAN', 1091 | 806 => 'SÖĞÜTLÜ', 1092 | 807 => 'TARAKLI', 1093 | ), 1094 | 55 => 1095 | array ( 1096 | 808 => '19 MAYIS', 1097 | 809 => 'ALAÇAM', 1098 | 810 => 'ASARCIK', 1099 | 811 => 'ATAKUM', 1100 | 812 => 'AYVACIK', 1101 | 813 => 'BAFRA', 1102 | 814 => 'CANİK', 1103 | 815 => 'ÇARŞAMBA', 1104 | 816 => 'HAVZA', 1105 | 817 => 'İLKADIM', 1106 | 818 => 'KAVAK', 1107 | 819 => 'LADİK', 1108 | 820 => 'SALIPAZARI', 1109 | 821 => 'TEKKEKÖY', 1110 | 822 => 'TERME', 1111 | 823 => 'VEZİRKÖPRÜ', 1112 | 824 => 'YAKAKENT', 1113 | ), 1114 | 56 => 1115 | array ( 1116 | 825 => 'BAYKAN', 1117 | 826 => 'ERUH', 1118 | 827 => 'KURTALAN', 1119 | 828 => 'MERKEZ', 1120 | 829 => 'PERVARİ', 1121 | 830 => 'ŞİRVAN', 1122 | 831 => 'TİLLO', 1123 | ), 1124 | 57 => 1125 | array ( 1126 | 832 => 'AYANCIK', 1127 | 833 => 'BOYABAT', 1128 | 834 => 'DİKMEN', 1129 | 835 => 'DURAĞAN', 1130 | 836 => 'ERFELEK', 1131 | 837 => 'GERZE', 1132 | 838 => 'MERKEZ', 1133 | 839 => 'SARAYDÜZÜ', 1134 | 840 => 'TÜRKELİ', 1135 | ), 1136 | 58 => 1137 | array ( 1138 | 841 => 'AKINCILAR', 1139 | 842 => 'ALTINYAYLA', 1140 | 843 => 'DİVRİĞİ', 1141 | 844 => 'DOĞANŞAR', 1142 | 845 => 'GEMEREK', 1143 | 846 => 'GÖLOVA', 1144 | 847 => 'GÜRÜN', 1145 | 848 => 'HAFİK', 1146 | 849 => 'İMRANLI', 1147 | 850 => 'KANGAL', 1148 | 851 => 'KOYULHİSAR', 1149 | 852 => 'MERKEZ', 1150 | 853 => 'SUŞEHRİ', 1151 | 854 => 'ŞARKIŞLA', 1152 | 855 => 'ULAŞ', 1153 | 856 => 'YILDIZELİ', 1154 | 857 => 'ZARA', 1155 | ), 1156 | 63 => 1157 | array ( 1158 | 858 => 'AKÇAKALE', 1159 | 859 => 'BİRECİK', 1160 | 860 => 'BOZOVA', 1161 | 861 => 'CEYLANPINAR', 1162 | 862 => 'EYYÜBİYE', 1163 | 863 => 'HALFETİ', 1164 | 864 => 'HALİLİYE', 1165 | 865 => 'HARRAN', 1166 | 866 => 'HİLVAN', 1167 | 867 => 'KARAKÖPRÜ', 1168 | 868 => 'SİVEREK', 1169 | 869 => 'SURUÇ', 1170 | 870 => 'VİRANŞEHİR', 1171 | ), 1172 | 73 => 1173 | array ( 1174 | 871 => 'BEYTÜŞŞEBAP', 1175 | 872 => 'CİZRE', 1176 | 873 => 'GÜÇLÜKONAK', 1177 | 874 => 'İDİL', 1178 | 875 => 'MERKEZ', 1179 | 876 => 'SİLOPİ', 1180 | 877 => 'ULUDERE', 1181 | ), 1182 | 59 => 1183 | array ( 1184 | 878 => 'ÇERKEZKÖY', 1185 | 879 => 'ÇORLU', 1186 | 880 => 'ERGENE', 1187 | 881 => 'HAYRABOLU', 1188 | 882 => 'KAPAKLI', 1189 | 883 => 'MALKARA', 1190 | 884 => 'MARMARAEREĞLİSİ', 1191 | 885 => 'MURATLI', 1192 | 886 => 'SARAY', 1193 | 887 => 'SÜLEYMANPAŞA', 1194 | 888 => 'ŞARKÖY', 1195 | ), 1196 | 60 => 1197 | array ( 1198 | 889 => 'ALMUS', 1199 | 890 => 'ARTOVA', 1200 | 891 => 'BAŞÇİFTLİK', 1201 | 892 => 'ERBAA', 1202 | 893 => 'MERKEZ', 1203 | 894 => 'NİKSAR', 1204 | 895 => 'PAZAR', 1205 | 896 => 'REŞADİYE', 1206 | 897 => 'SULUSARAY', 1207 | 898 => 'TURHAL', 1208 | 899 => 'YEŞİLYURT', 1209 | 900 => 'ZİLE', 1210 | ), 1211 | 61 => 1212 | array ( 1213 | 901 => 'AKÇAABAT', 1214 | 902 => 'ARAKLI', 1215 | 903 => 'ARSİN', 1216 | 904 => 'BEŞİKDÜZÜ', 1217 | 905 => 'ÇARŞIBAŞI', 1218 | 906 => 'ÇAYKARA', 1219 | 907 => 'DERNEKPAZARI', 1220 | 908 => 'DÜZKÖY', 1221 | 909 => 'HAYRAT', 1222 | 910 => 'KÖPRÜBAŞI', 1223 | 911 => 'MAÇKA', 1224 | 912 => 'OF', 1225 | 913 => 'ORTAHİSAR', 1226 | 914 => 'SÜRMENE', 1227 | 915 => 'ŞALPAZARI', 1228 | 916 => 'TONYA', 1229 | 917 => 'VAKFIKEBİR', 1230 | 918 => 'YOMRA', 1231 | ), 1232 | 62 => 1233 | array ( 1234 | 919 => 'ÇEMİŞGEZEK', 1235 | 920 => 'HOZAT', 1236 | 921 => 'MAZGİRT', 1237 | 922 => 'MERKEZ', 1238 | 923 => 'NAZIMİYE', 1239 | 924 => 'OVACIK', 1240 | 925 => 'PERTEK', 1241 | 926 => 'PÜLÜMÜR', 1242 | ), 1243 | 64 => 1244 | array ( 1245 | 927 => 'BANAZ', 1246 | 928 => 'EŞME', 1247 | 929 => 'KARAHALLI', 1248 | 930 => 'MERKEZ', 1249 | 931 => 'SİVASLI', 1250 | 932 => 'ULUBEY', 1251 | ), 1252 | 65 => 1253 | array ( 1254 | 933 => 'BAHÇESARAY', 1255 | 934 => 'BAŞKALE', 1256 | 935 => 'ÇALDIRAN', 1257 | 936 => 'ÇATAK', 1258 | 937 => 'EDREMİT', 1259 | 938 => 'ERCİŞ', 1260 | 939 => 'GEVAŞ', 1261 | 940 => 'GÜRPINAR', 1262 | 941 => 'İPEKYOLU', 1263 | 942 => 'MURADİYE', 1264 | 943 => 'ÖZALP', 1265 | 944 => 'SARAY', 1266 | 945 => 'TUŞBA', 1267 | ), 1268 | 77 => 1269 | array ( 1270 | 946 => 'ALTINOVA', 1271 | 947 => 'ARMUTLU', 1272 | 948 => 'ÇINARCIK', 1273 | 949 => 'ÇİFTLİKKÖY', 1274 | 950 => 'MERKEZ', 1275 | 951 => 'TERMAL', 1276 | ), 1277 | 66 => 1278 | array ( 1279 | 952 => 'AKDAĞMADENİ', 1280 | 953 => 'AYDINCIK', 1281 | 954 => 'BOĞAZLIYAN', 1282 | 955 => 'ÇANDIR', 1283 | 956 => 'ÇAYIRALAN', 1284 | 957 => 'ÇEKEREK', 1285 | 958 => 'KADIŞEHRİ', 1286 | 959 => 'MERKEZ', 1287 | 960 => 'SARAYKENT', 1288 | 961 => 'SARIKAYA', 1289 | 962 => 'SORGUN', 1290 | 963 => 'ŞEFAATLİ', 1291 | 964 => 'YENİFAKILI', 1292 | 965 => 'YERKÖY', 1293 | ), 1294 | 67 => 1295 | array ( 1296 | 966 => 'ALAPLI', 1297 | 967 => 'ÇAYCUMA', 1298 | 968 => 'DEVREK', 1299 | 969 => 'EREĞLİ', 1300 | 970 => 'GÖKÇEBEY', 1301 | 971 => 'KİLİMLİ', 1302 | 972 => 'KOZLU', 1303 | 973 => 'MERKEZ', 1304 | ), 1305 | ), 1306 | ); 1307 | --------------------------------------------------------------------------------