diff --git a/README.md b/README.md index aec3158..1ddd100 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # WooCommerce Indonesia Shipping v2 +> This plugin requires PRO License from RajaOngkir.com. We are not affiliated with them in any way. + ![](https://raw.github.com/hrsetyono/cdn/master/woocommerce-indo-shipping/ongkir-banner.jpg) Ultimate *Ongkos Kirim* Plugin for major Indonesian Shipping courier. -This plugin requires PRO License purchase from RajaOngkir.com. We are not affiliated with RajaOngkir in any way. - -This plugin is free and provided as is. We are not responsible for any damage caused by bugs. If you found a bug, please submit it [here](https://github.com/hrsetyono/woocommerce-indo-shipping/issues). +This plugin is free and provided as is. If you found a bug, please submit it [here](https://github.com/hrsetyono/woocommerce-indo-shipping/issues). **Supported Couriers:** diff --git a/dist/ongkir-public.css b/dist/ongkir-public.css index 59cb260..89c9aed 100644 --- a/dist/ongkir-public.css +++ b/dist/ongkir-public.css @@ -1 +1 @@ -.select2-container{width:100% !important}.ongkir-form-row-hidden{display:none !important} +.select2-container{width:100% !important}.ongkir-form-row-hidden{display:none !important}form.has-ongkir-dropdown #billing_city_field,form.has-ongkir-dropdown #shipping_city_field{display:none !important}form:not(.has-ongkir-dropdown) #_billing_city_field,form:not(.has-ongkir-dropdown) #_shipping_city_field,form:not(.has-ongkir-dropdown) #_billing_district_field,form:not(.has-ongkir-dropdown) #_shipping_district_field{display:none !important} diff --git a/dist/ongkir-public.js b/dist/ongkir-public.js index 79976c8..4c2bc2d 100644 --- a/dist/ongkir-public.js +++ b/dist/ongkir-public.js @@ -1 +1 @@ -!function(t){var i={};function e(n){if(i[n])return i[n].exports;var o=i[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,e),o.l=!0,o.exports}e.m=t,e.c=i,e.d=function(t,i,n){e.o(t,i)||Object.defineProperty(t,i,{enumerable:!0,get:n})},e.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},e.t=function(t,i){if(1&i&&(t=e(t)),8&i)return t;if(4&i&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(e.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&i&&"string"!=typeof t)for(var o in t)e.d(n,o,function(i){return t[i]}.bind(null,o));return n},e.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(i,"a",i),i},e.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},e.p="",e(e.s=3)}([function(t,i,e){},,,function(t,i,e){"use strict";e.r(i);e(0);const n=ongkirLocalize.ONGKIR_API;var o={get(t){return window.fetch(`${n}${t}`,{method:"GET",headers:{Accept:"application/json"}}).then(this.handleError).then(this.handleContentType).catch(this.throwError)},post(t,i){return window.fetch(`${n}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i)}).then(this.handleError).then(this.handleContentType).catch(this.throwError)},handleError:t=>t.ok?t:Promise.reject(t.statusText),handleContentType(t){const i=t.headers.get("content-type");return i&&i.includes("application/json")?t.json():Promise.reject("Oops, we haven't got JSON!")},throwError(t){throw new Error(t)}};const l=jQuery,r={init(){this.isFirstRun=!0;document.querySelector("body").classList.contains("woocommerce-checkout")&&(l(document).on("change","#billing_country, #shipping_country",this.toggleCityField.bind(this)),l(document).on("change","#billing_state, #shipping_state",this.populateCitiesDropdown.bind(this)),this.createFields(),l(document).on("change","#_billing_city, #_shipping_city",this.populateDistrictsDropdown.bind(this)),l(document).on("change","#_billing_district, #_shipping_district",this.fillCityField.bind(this)))},createFields(){document.querySelectorAll("#billing_city, #shipping_city").forEach(async t=>{const i="billing_city"===t.getAttribute("id")?"billing":"shipping",e=t.closest(".woocommerce-billing-fields, .woocommerce-shipping-fields"),n=t.closest("#billing_city_field, #shipping_city_field");let r=e.querySelector("#billing_state, #shipping_state").value;r=r||"0";let c=t.value.match(/\[(\d+)\]/);c=c?c[1]:"0";const s=await o.get(`/fields/${i}/${r}/${c}`);l(n).after(s),l("#billing_country, #shipping_country").trigger("change")})},toggleCityField(t){const i=t.currentTarget.closest(".woocommerce-billing-fields, .woocommerce-shipping-fields"),e=i.querySelector("#billing_city_field, #shipping_city_field"),n=i.querySelector("#_billing_city_field, #_shipping_city_field"),o=i.querySelector("#_billing_district_field, #_shipping_district_field");"ID"===t.currentTarget.value?(e.style.display="none",n&&(n.style.display="block"),o&&(o.style.display="block")):(e.style.display="block",n&&(n.style.display="none"),o&&(o.style.display="none"))},async populateCitiesDropdown(t){const i=l(t.currentTarget).val()||"0",e=l(t.currentTarget).closest(".woocommerce-billing-fields, .woocommerce-shipping-fields");if(!this.isFirstRun){e.find("#billing_city_field, #shipping_city_field").find("input").val("")}const n=e.find("#_billing_city_field select, #_shipping_city_field select");n.html("");e.find("#_billing_district_field select, #_shipping_district_field select").html("");const r=await o.get("/cities/"+i);let c="";Object.keys(r).forEach(t=>{c+=``}),n.html(c),this.isFirstRun=!1},async populateDistrictsDropdown(t){const i=l(t.currentTarget).val(),e=l(t.currentTarget).closest(".woocommerce-billing-fields, .woocommerce-shipping-fields"),n=e.find("#billing_state, #shipping_state").val(),r=e.find("#_billing_district_field select, #_shipping_district_field select");r.html("");const c=await o.get(`/districts/${n}/${i}`);let s="";Object.keys(c).forEach(t=>{s+=``}),r.html(s)},fillCityField(t){const i=l(t.currentTarget),e=i.closest(".woocommerce-billing-fields, .woocommerce-shipping-fields").find("#billing_city, #shipping_city");e.val(i.val()),e.trigger("keydown")}};document.addEventListener("DOMContentLoaded",(function(){r.init()})),window.addEventListener("load",(function(){}))}]); \ No newline at end of file +!function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)i.d(n,o,function(e){return t[e]}.bind(null,o));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=3)}([function(t,e,i){},,,function(t,e,i){"use strict";i.r(e);i(0);const{baseURL:n}=ongkirLocalize;var o={get(t){return window.fetch(`${n}${t}`,{method:"GET",headers:{Accept:"application/json"}}).then(this.handleError).then(this.handleContentType).catch(this.throwError)},post(t,e){return window.fetch(`${n}${t}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)}).then(this.handleError).then(this.handleContentType).catch(this.throwError)},handleError:t=>t.ok?t:Promise.reject(t.statusText),handleContentType(t){const e=t.headers.get("content-type");return e&&e.includes("application/json")?t.json():Promise.reject("Oops, we haven't got JSON!")},throwError(t){throw new Error(t)}};const r=jQuery,l={isFirstRun:!0,init(){document.querySelector("body").classList.contains("woocommerce-checkout")&&(r(document).on("change","#billing_country, #shipping_country",this.toggleCityField.bind(this)),r(document).on("change","#billing_state, #shipping_state",this.populateCitiesDropdown.bind(this)),this.createFields(),r(document).on("change","#_billing_city, #_shipping_city",this.populateDistrictsDropdown.bind(this)),r(document).on("change","#_billing_district, #_shipping_district",this.fillCityField.bind(this)))},createFields(){document.querySelectorAll("#billing_city, #shipping_city").forEach(async t=>{const e="billing_city"===t.getAttribute("id")?"billing":"shipping",i=t.closest(".woocommerce-billing-fields, .woocommerce-shipping-fields"),n=t.closest("#billing_city_field, #shipping_city_field");let l=i.querySelector("#billing_state, #shipping_state").value;l=l||"0";let c=t.value.match(/\[(\d+)\]/);c=c?c[1]:"0";const s=await o.get(`/fields/${e}/${l}/${c}`);r(n).after(s)}),this.toggleCityField({currentTarget:document.querySelector("#billing_country, #shipping_country")})},toggleCityField(t){const e=t.currentTarget.closest("form");"ID"===t.currentTarget.value?e.classList.add("has-ongkir-dropdown"):e.classList.remove("has-ongkir-dropdown")},async populateCitiesDropdown(t){const e=r(t.currentTarget).val()||"0",i=r(t.currentTarget).closest(".woocommerce-billing-fields, .woocommerce-shipping-fields"),n=i.find("#billing_city_field, #shipping_city_field");this.isFirstRun||n.find("input").val("");const l=i.find("#_billing_city_field select, #_shipping_city_field select");l.html("");i.find("#_billing_district_field select, #_shipping_district_field select").html("");const c=await o.get("/cities/"+e);let s="";Object.keys(c).forEach(t=>{s+=``}),l.html(s),l.trigger("change"),this.isFirstRun=!1},async populateDistrictsDropdown(t){const e=r(t.currentTarget).val(),i=r(t.currentTarget).closest(".woocommerce-billing-fields, .woocommerce-shipping-fields"),n=i.find("#billing_state, #shipping_state").val();if(!n)return;const l=i.find("#_billing_district_field select, #_shipping_district_field select");l.html("");const c=await o.get(`/districts/${n}/${e}`);let s="";Object.keys(c).forEach(t=>{s+=``}),l.html(s)},fillCityField(t){const e=r(t.currentTarget),i=e.closest(".woocommerce-billing-fields, .woocommerce-shipping-fields").find("#billing_city, #shipping_city");i.val(e.val()),i.trigger("keydown")}};document.addEventListener("DOMContentLoaded",(function(){l.init()})),window.addEventListener("load",(function(){}))}]); \ No newline at end of file diff --git a/includes/ongkir-api.php b/includes/ongkir-api.php index 1b955c9..63619ae 100644 --- a/includes/ongkir-api.php +++ b/includes/ongkir-api.php @@ -68,7 +68,7 @@ function get_cities_api($params) { */ function get_districts_api($params) { $prov_id = Ongkir_Data::get_province_id($params['prov_code']); - $cities = Ongkir_Data::get_cities($prov_id, true); + $cities = Ongkir_Data::get_cities($prov_id); $city = $cities[$params['city_id']] ?? null; // abort if city not found @@ -91,43 +91,32 @@ function get_districts_api($params) { * @return array */ function get_fields_api($params) { + $city_id = 0; + $field_value = ''; + // Convert District ID to City ID if ($params['district_id'] != '0') { $prov_id = Ongkir_Data::get_province_id($params['prov_code']); - $cities = Ongkir_Data::get_cities($prov_id, true); + $cities = Ongkir_Data::get_cities($prov_id); - foreach ($cities as $city_id => $c) { - foreach ($c['districts'] as $district_id => $name) { + foreach ($cities as $id => $c) { + foreach ($c['districts'] as $dist_id => $dist_name) { // find district that has the same ID as the one passed on - if ($params['district_id'] == $district_id) { - $params['city_id'] = $city_id; + if ($params['district_id'] == $dist_id) { + $city_id = $id; + $field_value = $c['city_name'] . ", {$dist_name} [{$dist_id}]"; break; } } + + if ($city_id > 0) { + break; + } } - } else { - $params['city_id'] = '0'; } - $cities_field = $this->_get_cities_field($params['type'], $params['prov_code']); - $districts_field = $this->_get_districts_field($params['type'], $params['prov_code'], $params['city_id']); - - // add selected attribute - if (isset($params['city_id'])) { - $cities_field = preg_replace( - '/(_city_field[\s\S]+)(\"' . $params['city_id'] . '\"\s)(\>)([\s\S]+\/p>)/Ui', - '$1$2selected$3$4', - $cities_field - ); - } - - if ($params['district_id'] != '0') { - $districts_field = preg_replace( - '/(_district_field[\s\S]+)(' . $params['district_id'] . '\]\"\s)(\>)([\s\S]+\/p>)/Ui', - '$1$2selected$3$4', - $districts_field - ); - } + $cities_field = $this->_get_cities_field($params['type'], $params['prov_code'], $city_id); + $districts_field = $this->_get_districts_field($params['type'], $params['prov_code'], $city_id, $field_value); return $cities_field . $districts_field; } @@ -139,18 +128,18 @@ function get_fields_api($params) { * * @return array - Currently only has one item: 'field' which contains the HTML form field. */ - private function _get_cities_field($type, $prov_code = '0') { + private function _get_cities_field($type, $prov_code = '0', $city_id = 0) { $field = ''; // if code is 0, show empty placeholder dropdown if ($prov_code == '0') { - $field = woocommerce_form_field( "_{$type}_city", [ + $field = woocommerce_form_field("_{$type}_city", [ 'type' => 'select', 'label' => __('City', 'woocommerce'), 'options' => [0 => __('Pilih Provinsi terlebih dahulu...')], 'return' => true, 'required' => true, - ] ); + ]); } // else else { @@ -162,7 +151,7 @@ private function _get_cities_field($type, $prov_code = '0') { 'options' => $cities, 'return' => true, 'required' => true, - ] ); + ], $city_id); } return $field; @@ -176,12 +165,13 @@ private function _get_cities_field($type, $prov_code = '0') { private function _get_districts_field( $type, $prov_code, - $city_id = '0' + $city_id = 0, + $field_value = '' ) { $field = ''; // If city ID is empty, show placeholder - if ($city_id == '0') { + if ($city_id === 0) { $field = woocommerce_form_field("_{$type}_district", [ 'type' => 'select', 'label' => __('Kecamatan'), @@ -203,7 +193,7 @@ private function _get_districts_field( 'options' => $districts, 'return' => true, 'required' => true - ]); + ], $field_value); } return $field; diff --git a/includes/ongkir-data.php b/includes/ongkir-data.php index 88d7a79..c21ed81 100644 --- a/includes/ongkir-data.php +++ b/includes/ongkir-data.php @@ -15,7 +15,7 @@ static function get_cities($prov_id, $raw = false) { } // if exists, scan for duplicate city name - if($data) { + if ($data) { $data = self::_prefix_dupe_city_name($prov_id, $data); return $data; } else { diff --git a/includes/rajaongkir.php b/includes/rajaongkir.php index 59e8f42..208fc41 100644 --- a/includes/rajaongkir.php +++ b/includes/rajaongkir.php @@ -7,7 +7,7 @@ */ class RajaOngkir { private $api_key; - private $base_url; + private $base_url = 'https://pro.rajaongkir.com/api'; function __construct($key = null) { // set API key @@ -18,15 +18,6 @@ function __construct($key = null) { $cached_license = get_transient('wcis_license'); $this->api_key = $cached_license['key']; } - - // set base URL - $urls = [ - 'starter' => 'https://api.rajaongkir.com/starter', - 'pro' => 'https://pro.rajaongkir.com/api', - ]; - - $license_type = 'pro'; - $this->base_url = $urls[$license_type]; } diff --git a/public/assets/api.js b/public/assets/api.js index 6362b97..3594963 100644 --- a/public/assets/api.js +++ b/public/assets/api.js @@ -5,12 +5,15 @@ * api.get(url).then((result) => { .. }); * api.post(url, data).then((result) => { ... }); */ -const baseURL = ongkirLocalize.ONGKIR_API; +const { baseURL } = ongkirLocalize; + const api = { get(endpoint) { return window.fetch(`${baseURL}${endpoint}`, { method: 'GET', - headers: { Accept: 'application/json' }, + headers: { + Accept: 'application/json', + }, }) .then(this.handleError) .then(this.handleContentType) diff --git a/public/assets/public.js b/public/assets/public.js index 308428c..eb7402e 100644 --- a/public/assets/public.js +++ b/public/assets/public.js @@ -4,10 +4,9 @@ import api from './api'; const $ = jQuery; const checkoutFields = { - init() { - // fix the weird WooCommerce interaction where it initially trigger 'change' on State field - this.isFirstRun = true; + isFirstRun: true, // fix the weird WooCommerce interaction where it initially trigger 'change' on State field + init() { const $body = document.querySelector('body'); // abort if not in Checkout page @@ -45,9 +44,10 @@ const checkoutFields = { // get custom fields and append it after the City field const result = await api.get(`/fields/${type}/${provCode}/${districtID}`); $($wrapper).after(result); + }); - // hide the custom field if country not ID - $('#billing_country, #shipping_country').trigger('change'); + this.toggleCityField({ + currentTarget: document.querySelector('#billing_country, #shipping_country'), }); }, @@ -55,34 +55,13 @@ const checkoutFields = { * Show or Hide the original City field depending on the Country selected */ toggleCityField(e) { - const $wrapper = e.currentTarget.closest('.woocommerce-billing-fields, .woocommerce-shipping-fields'); - const $ogCityField = $wrapper.querySelector('#billing_city_field, #shipping_city_field'); + const $form = e.currentTarget.closest('form'); - // the custom dropdown - const $citiesField = $wrapper.querySelector('#_billing_city_field, #_shipping_city_field'); - const $districtsField = $wrapper.querySelector('#_billing_district_field, #_shipping_district_field'); - - // If country is ID, hide the original City field + // If country is ID, add a class to hide the original city field if (e.currentTarget.value === 'ID') { - $ogCityField.style.display = 'none'; - - if ($citiesField) { - $citiesField.style.display = 'block'; - } - - if ($districtsField) { - $districtsField.style.display = 'block'; - } - } else { // Else, hide the dropdown and show the original field - $ogCityField.style.display = 'block'; - - if ($citiesField) { - $citiesField.style.display = 'none'; - } - - if ($districtsField) { - $districtsField.style.display = 'none'; - } + $form.classList.add('has-ongkir-dropdown'); + } else { + $form.classList.remove('has-ongkir-dropdown'); } }, @@ -95,9 +74,10 @@ const checkoutFields = { const provCode = $(e.currentTarget).val() || '0'; const $wrapper = $(e.currentTarget).closest('.woocommerce-billing-fields, .woocommerce-shipping-fields'); + const $ogCityField = $wrapper.find('#billing_city_field, #shipping_city_field'); + // if not first run, empty out the city field if (!this.isFirstRun) { - const $ogCityField = $wrapper.find('#billing_city_field, #shipping_city_field'); $ogCityField.find('input').val(''); } @@ -111,12 +91,15 @@ const checkoutFields = { const result = await api.get(`/cities/${provCode}`); + // Create the `; }); $citiesSelect.html(options); + $citiesSelect.trigger('change'); this.isFirstRun = false; }, @@ -130,6 +113,9 @@ const checkoutFields = { const $wrapper = $(e.currentTarget).closest('.woocommerce-billing-fields, .woocommerce-shipping-fields'); const provCode = $wrapper.find('#billing_state, #shipping_state').val(); + // Abort if province not selected + if (!provCode) { return; } + // add 'Loading' message to district field const $districtsSelect = $wrapper.find('#_billing_district_field select, #_shipping_district_field select'); $districtsSelect.html(''); diff --git a/public/assets/public.sass b/public/assets/public.sass index 71429ef..ac1cee3 100644 --- a/public/assets/public.sass +++ b/public/assets/public.sass @@ -2,4 +2,16 @@ width: 100% !important .ongkir-form-row-hidden - display: none !important \ No newline at end of file + display: none !important + +form.has-ongkir-dropdown + #billing_city_field, + #shipping_city_field + display: none !important + +form:not(.has-ongkir-dropdown) + #_billing_city_field, + #_shipping_city_field, + #_billing_district_field, + #_shipping_district_field + display: none !important \ No newline at end of file diff --git a/public/index.php b/public/index.php index 7d44d82..a772ce4 100644 --- a/public/index.php +++ b/public/index.php @@ -35,7 +35,7 @@ function enqueue_assets() { wp_enqueue_script('ongkir_script', ONGKIR_FILE . '/dist/ongkir-public.js', ONGKIR_VERSION, true); wp_localize_script('ongkir_script', 'ongkirLocalize', [ - 'ONGKIR_API' => ONGKIR_API, + 'baseURL' => ONGKIR_API, ]); } } diff --git a/public/ongkir-hooks.php b/public/ongkir-hooks.php index 23f79c1..9f2eafd 100644 --- a/public/ongkir-hooks.php +++ b/public/ongkir-hooks.php @@ -61,7 +61,7 @@ function on_update_shipping_address($packages) { // look for district ID in city field preg_match('/\[(\d+)\]/', $packages[0]['destination']['city'], $matches); if (count($matches)) { - $packages[0]['destination']['destination_id'] = $matches[1]; + $packages[0]['destination']['destination_id'] = sanitize_text_field($matches[1]); } return $packages; @@ -76,8 +76,8 @@ function on_update_shipping_address($packages) { */ private function _clean_city_field($city_raw) { preg_match('/[\w\s,]+/', $city_raw, $city); - - return trim($city[0]); + $city = sanitize_text_field(trim($city[0])); + return $city; } } diff --git a/woocommerce-ongkir.php b/woocommerce-ongkir.php index 550d362..09e066f 100644 --- a/woocommerce-ongkir.php +++ b/woocommerce-ongkir.php @@ -3,7 +3,7 @@ * Plugin Name: WooCommerce Ongkir Indonesia * Plugin URI: http://github.com/hrsetyono/woocommerce-ongkir * Description: Calculate shipping cost for Indonesian couriers like JNE, J&T, TIKI, POS, etc. Requires RajaOngkir PRO License. - * Version: 2.2.0 + * Version: 2.3.0 * Author: Pixel Studio * Author URI: https://pixelstudio.id/ * License: GPL-3.0+ @@ -18,7 +18,7 @@ return; } -define('ONGKIR_VERSION', '2.2.1'); +define('ONGKIR_VERSION', '2.3.0'); define('ONGKIR_FILE', plugins_url('', __FILE__)); define('ONGKIR_DIR', __DIR__); define('ONGKIR_NAMESPACE', 'ongkir/v1');