├── assets ├── css │ └── admin.css └── js │ ├── table-rate-rows.js │ └── table-rate-rows.min.js ├── changelog.txt ├── includes ├── class-wc-shipping-table-rate-privacy.php ├── class-wc-shipping-table-rate.php ├── functions-admin.php ├── functions-ajax.php └── legacy │ └── shipping-zones │ ├── assets │ ├── css │ │ ├── shipping_zones.css │ │ └── shipping_zones.less │ └── js │ │ └── shipping-zone-admin.js │ ├── class-wc-shipping-zones.php │ └── includes │ ├── class-wc-shipping-zone-admin.php │ ├── class-wc-shipping-zone.php │ ├── class-wc-shipping-zones-admin.php │ ├── class-wc-shipping-zones-ajax-handler.php │ ├── list-tables │ ├── class-wc-shipping-zone-methods-table.php │ └── class-wc-shipping-zones-table.php │ ├── views │ ├── form-add-shipping-zone.php │ ├── form-edit-shipping-zone.php │ ├── html-zone-list.php │ ├── html-zone-method-settings.php │ └── html-zone-methods.php │ └── wc-shipping-zone-functions.php ├── installer.php ├── languages └── woocommerce-table-rate-shipping.pot ├── uninstall.php └── woocommerce-table-rate-shipping.php /assets/css/admin.css: -------------------------------------------------------------------------------- 1 | #shipping_class_priorities table input,#shipping_class_priorities table select,table#shipping_rates input,table#shipping_rates select{width:100%}#shipping_class_priorities table input[type=checkbox],table#shipping_rates input[type=checkbox]{width:auto}#shipping_class_priorities table td,table#shipping_rates td{cursor:move}#shipping_class_priorities table a.dupe,#shipping_class_priorities table a.remove,table#shipping_rates a.dupe,table#shipping_rates a.remove{float:right;margin-left:4px}#shipping_class_priorities table td,#shipping_class_priorities table th,table#shipping_rates td,table#shipping_rates th{padding:15px 10px;vertical-align:middle}#shipping_class_priorities table tr:nth-child(even) td,#shipping_class_priorities table tr:nth-child(even) th,table#shipping_rates tr:nth-child(even) td,table#shipping_rates tr:nth-child(even) th{background:#fafafa}#shipping_class_priorities table td.checkbox,#shipping_class_priorities table th.checkbox,table#shipping_rates td.checkbox,table#shipping_rates th.checkbox{text-align:center}#shipping_class_priorities table td .disabled,table#shipping_rates td .disabled{opacity:.5}#shipping_class_priorities table .check-column,table#shipping_rates .check-column{width:24px;min-width:24px!important;text-align:center;padding:15px 10px}#shipping_class_priorities table .check-column input,table#shipping_rates .check-column input{width:auto;vertical-align:middle;margin:0 0 0 8px} -------------------------------------------------------------------------------- /assets/js/table-rate-rows.js: -------------------------------------------------------------------------------- 1 | /*global $, woocommerce_shipping_table_rate_rows, ajaxurl */ 2 | ( function( $, data, wp, ajaxurl ) { 3 | 4 | var wc_table_rate_rows_row_template = wp.template( 'table-rate-shipping-row-template' ), 5 | $settings_form = $( '#mainform' ), 6 | $rates_table = $( '#shipping_rates' ), 7 | $rates = $rates_table.find( 'tbody.table_rates' ); 8 | 9 | var wc_table_rate_rows = { 10 | init: function() { 11 | $settings_form 12 | .on( 'change', '#woocommerce_table_rate_calculation_type', this.onCalculationTypeChange ); 13 | $rates_table 14 | .on( 'change', 'select[name^="shipping_condition"]', this.onShippingConditionChange ) 15 | .on( 'change', 'input[name^="shipping_abort["]', this.onShippingAbortChange ) 16 | .on( 'click', 'a.add-rate', this.onAddRate ) 17 | .on( 'click', 'a.remove', this.onRemoveRate ) 18 | .on( 'click', 'a.dupe', this.onDupeRate ); 19 | 20 | var rates_data = $rates.data( 'rates' ); 21 | 22 | $( rates_data ).each( function( i ) { 23 | var size = $rates.find( '.table_rate' ).length; 24 | $rates.append( wc_table_rate_rows_row_template( { 25 | rate: rates_data[ i ], 26 | index: size 27 | } ) ); 28 | } ); 29 | 30 | $( 'label[for="woocommerce_table_rate_handling_fee"], label[for="woocommerce_table_rate_max_cost"], label[for="woocommerce_table_rate_min_cost"]', $settings_form ).each( function( i, el ) { 31 | $(el).data( 'o_label', $(el).text() ); 32 | }); 33 | 34 | $( '#woocommerce_table_rate_calculation_type, select[name^="shipping_condition"], input[name^="shipping_abort["]', $settings_form ).change(); 35 | 36 | $rates.sortable( { 37 | items: 'tr', 38 | cursor: 'move', 39 | axis: 'y', 40 | handle: 'td', 41 | scrollSensitivity: 40, 42 | helper: function(e,ui){ 43 | ui.children().each( function() { 44 | $( this ).width( $(this).width() ); 45 | }); 46 | ui.css( 'left', '0' ); 47 | return ui; 48 | }, 49 | start: function( event, ui ) { 50 | ui.item.css('background-color','#f6f6f6'); 51 | }, 52 | stop: function( event, ui ) { 53 | ui.item.removeAttr( 'style' ); 54 | wc_table_rate_rows.reindexRows(); 55 | } 56 | } ); 57 | }, 58 | onCalculationTypeChange: function() { 59 | var selected = $( this ).val(); 60 | 61 | if ( selected == 'item' ) { 62 | $( 'td.cost_per_item input' ).attr( 'disabled', 'disabled' ).addClass('disabled'); 63 | } else { 64 | $( 'td.cost_per_item input' ).removeAttr( 'disabled' ).removeClass('disabled'); 65 | } 66 | 67 | if ( selected ) { 68 | $( '#shipping_class_priorities' ).hide(); 69 | $( 'td.shipping_label, th.shipping_label' ).hide(); 70 | } else { 71 | $( '#shipping_class_priorities' ).show(); 72 | $( 'td.shipping_label, th.shipping_label' ).show(); 73 | } 74 | 75 | if ( ! selected ) { 76 | $( '#shipping_class_priorities span.description.per_order' ).show(); 77 | $( '#shipping_class_priorities span.description.per_class' ).hide(); 78 | } 79 | 80 | var label_text = data.i18n.order; 81 | 82 | if ( selected == 'item' ) { 83 | label_text = data.i18n.item; 84 | } else if ( selected == 'line' ) { 85 | label_text = data.i18n.line_item; 86 | } else if ( selected == 'class' ) { 87 | label_text = data.i18n.class; 88 | } 89 | 90 | $('label[for="woocommerce_table_rate_handling_fee"], label[for="woocommerce_table_rate_max_cost"], label[for="woocommerce_table_rate_min_cost"]').each(function( i, el ) { 91 | var text = $(el).data( 'o_label' ); 92 | text = text.replace( '[item]', label_text ); 93 | $(el).text( text ); 94 | }); 95 | }, 96 | onShippingConditionChange: function() { 97 | var selected = $( this ).val(); 98 | var $row = $( this ).closest('tr'); 99 | 100 | if ( selected == '' ) { 101 | $row.find('input[name^="shipping_min"], input[name^="shipping_max"]').val( '' ).prop( 'disabled', true ).addClass( 'disabled' ); 102 | } else { 103 | $row.find('input[name^="shipping_min"], input[name^="shipping_max"]').prop( 'disabled', false ).removeClass( 'disabled' ); 104 | } 105 | }, 106 | onShippingAbortChange: function() { 107 | var checked = $( this ).is( ':checked' ); 108 | var $row = $( this ).closest( 'tr' ); 109 | 110 | if ( checked ) { 111 | $row.find('td.cost').hide(); 112 | $row.find('td.abort_reason').show(); 113 | $row.find('input[name^="shipping_per_item"], input[name^="shipping_cost_per_weight"], input[name^="shipping_cost_percent"], input[name^="shipping_cost"], input[name^="shipping_label"]').prop( 'disabled', true ).addClass( 'disabled' ); 114 | } else { 115 | $row.find('td.cost').show(); 116 | $row.find('td.abort_reason').hide(); 117 | $row.find('input[name^="shipping_per_item"], input[name^="shipping_cost_per_weight"], input[name^="shipping_cost_percent"], input[name^="shipping_cost"], input[name^="shipping_label"]').prop( 'disabled', false ).removeClass( 'disabled' ); 118 | } 119 | 120 | $( '#woocommerce_table_rate_calculation_type' ).change(); 121 | }, 122 | onAddRate: function( event ) { 123 | event.preventDefault(); 124 | var target = $rates; 125 | var size = target.find( '.table_rate' ).length; 126 | 127 | target.append( wc_table_rate_rows_row_template( { 128 | rate: { 129 | rate_id: '', 130 | rate_class: '', 131 | rate_condition: '', 132 | rate_min: '', 133 | rate_max: '', 134 | rate_priority: '', 135 | rate_abort: '', 136 | rate_abort_reason: '', 137 | rate_cost: '', 138 | rate_cost_per_item: '', 139 | rate_cost_per_weight_unit: '', 140 | rate_cost_percent: '', 141 | rate_label: '' 142 | }, 143 | index: size 144 | } ) ); 145 | 146 | $( '#woocommerce_table_rate_calculation_type, select[name^="shipping_condition"], input[name^="shipping_abort["]', $rates_table ).change(); 147 | }, 148 | onRemoveRate: function( event ) { 149 | event.preventDefault(); 150 | if ( confirm( data.i18n.delete_rates ) ) { 151 | var rate_ids = []; 152 | 153 | $rates.find( 'tr td.check-column input:checked' ).each( function( i, el ) { 154 | var rate_id = $(el).closest( 'tr.table_rate' ).find( '.rate_id' ).val(); 155 | rate_ids.push( rate_id ); 156 | $(el).closest( 'tr.table_rate' ).addClass( 'deleting' ); 157 | }); 158 | 159 | var ajax_data = { 160 | action: 'woocommerce_table_rate_delete', 161 | rate_id: rate_ids, 162 | security: data.delete_rates_nonce 163 | }; 164 | 165 | $.post( ajaxurl, ajax_data, function(response) { 166 | $( 'tr.deleting').fadeOut( '300', function() { 167 | $( this ).remove(); 168 | } ); 169 | }); 170 | } 171 | }, 172 | onDupeRate: function( event ) { 173 | event.preventDefault(); 174 | if ( confirm( data.i18n.dupe_rates ) ) { 175 | 176 | $rates.find( 'tr td.check-column input:checked' ).each( function( i, el ) { 177 | var dupe = $(el).closest( 'tr' ).clone(); 178 | dupe.find( '.rate_id' ).val( '0' ); 179 | $rates.append( dupe ); 180 | }); 181 | 182 | wc_table_rate_rows.reindexRows(); 183 | } 184 | }, 185 | reindexRows: function() { 186 | var loop = 0; 187 | $rates.find( 'tr' ).each( function( index, row ) { 188 | $('input.text, input.checkbox, select.select, input[type=hidden]', row ).each( function( i, el ) { 189 | var t = $(el); 190 | t.attr( 'name', t.attr('name').replace(/\[([^[]*)\]/, "[" + loop + "]" ) ); 191 | }); 192 | loop++; 193 | }); 194 | } 195 | }; 196 | 197 | wc_table_rate_rows.init(); 198 | 199 | })( jQuery, woocommerce_shipping_table_rate_rows, wp, ajaxurl ); 200 | -------------------------------------------------------------------------------- /assets/js/table-rate-rows.min.js: -------------------------------------------------------------------------------- 1 | !function(a,i,e,o){var n=e.template("table-rate-shipping-row-template"),t=a("#mainform"),r=a("#shipping_rates"),s=r.find("tbody.table_rates"),p={init:function(){t.on("change","#woocommerce_table_rate_calculation_type",this.onCalculationTypeChange),r.on("change",'select[name^="shipping_condition"]',this.onShippingConditionChange).on("change",'input[name^="shipping_abort["]',this.onShippingAbortChange).on("click","a.add-rate",this.onAddRate).on("click","a.remove",this.onRemoveRate).on("click","a.dupe",this.onDupeRate);var i=s.data("rates");a(i).each(function(e){var t=s.find(".table_rate").length;s.append(n({rate:i[e],index:t}))}),a('label[for="woocommerce_table_rate_handling_fee"], label[for="woocommerce_table_rate_max_cost"], label[for="woocommerce_table_rate_min_cost"]',t).each(function(e,t){a(t).data("o_label",a(t).text())}),a('#woocommerce_table_rate_calculation_type, select[name^="shipping_condition"], input[name^="shipping_abort["]',t).change(),s.sortable({items:"tr",cursor:"move",axis:"y",handle:"td",scrollSensitivity:40,helper:function(e,t){return t.children().each(function(){a(this).width(a(this).width())}),t.css("left","0"),t},start:function(e,t){t.item.css("background-color","#f6f6f6")},stop:function(e,t){t.item.removeAttr("style"),p.reindexRows()}})},onCalculationTypeChange:function(){var e=a(this).val();"item"==e?a("td.cost_per_item input").attr("disabled","disabled").addClass("disabled"):a("td.cost_per_item input").removeAttr("disabled").removeClass("disabled"),e?(a("#shipping_class_priorities").hide(),a("td.shipping_label, th.shipping_label").hide()):(a("#shipping_class_priorities").show(),a("td.shipping_label, th.shipping_label").show()),e||(a("#shipping_class_priorities span.description.per_order").show(),a("#shipping_class_priorities span.description.per_class").hide());var n=i.i18n.order;"item"==e?n=i.i18n.item:"line"==e?n=i.i18n.line_item:"class"==e&&(n=i.i18n.class),a('label[for="woocommerce_table_rate_handling_fee"], label[for="woocommerce_table_rate_max_cost"], label[for="woocommerce_table_rate_min_cost"]').each(function(e,t){var i=a(t).data("o_label");i=i.replace("[item]",n),a(t).text(i)})},onShippingConditionChange:function(){var e=a(this).val(),t=a(this).closest("tr");""==e?t.find('input[name^="shipping_min"], input[name^="shipping_max"]').val("").prop("disabled",!0).addClass("disabled"):t.find('input[name^="shipping_min"], input[name^="shipping_max"]').prop("disabled",!1).removeClass("disabled")},onShippingAbortChange:function(){var e=a(this).is(":checked"),t=a(this).closest("tr");e?(t.find("td.cost").hide(),t.find("td.abort_reason").show(),t.find('input[name^="shipping_per_item"], input[name^="shipping_cost_per_weight"], input[name^="shipping_cost_percent"], input[name^="shipping_cost"], input[name^="shipping_label"]').prop("disabled",!0).addClass("disabled")):(t.find("td.cost").show(),t.find("td.abort_reason").hide(),t.find('input[name^="shipping_per_item"], input[name^="shipping_cost_per_weight"], input[name^="shipping_cost_percent"], input[name^="shipping_cost"], input[name^="shipping_label"]').prop("disabled",!1).removeClass("disabled")),a("#woocommerce_table_rate_calculation_type").change()},onAddRate:function(e){e.preventDefault();var t=s,i=t.find(".table_rate").length;t.append(n({rate:{rate_id:"",rate_class:"",rate_condition:"",rate_min:"",rate_max:"",rate_priority:"",rate_abort:"",rate_abort_reason:"",rate_cost:"",rate_cost_per_item:"",rate_cost_per_weight_unit:"",rate_cost_percent:"",rate_label:""},index:i})),a('#woocommerce_table_rate_calculation_type, select[name^="shipping_condition"], input[name^="shipping_abort["]',r).change()},onRemoveRate:function(e){if(e.preventDefault(),confirm(i.i18n.delete_rates)){var n=[];s.find("tr td.check-column input:checked").each(function(e,t){var i=a(t).closest("tr.table_rate").find(".rate_id").val();n.push(i),a(t).closest("tr.table_rate").addClass("deleting")});var t={action:"woocommerce_table_rate_delete",rate_id:n,security:i.delete_rates_nonce};a.post(o,t,function(e){a("tr.deleting").fadeOut("300",function(){a(this).remove()})})}},onDupeRate:function(e){e.preventDefault(),confirm(i.i18n.dupe_rates)&&(s.find("tr td.check-column input:checked").each(function(e,t){var i=a(t).closest("tr").clone();i.find(".rate_id").val("0"),s.append(i)}),p.reindexRows())},reindexRows:function(){var n=0;s.find("tr").each(function(e,t){a("input.text, input.checkbox, select.select, input[type=hidden]",t).each(function(e,t){var i=a(t);i.attr("name",i.attr("name").replace(/\[([^[]*)\]/,"["+n+"]"))}),n++})}};p.init()}(jQuery,woocommerce_shipping_table_rate_rows,wp,ajaxurl); 2 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | *** Table Rate Shipping Changelog *** 2 | 3 | 2020-08-19 - version 3.0.29 4 | * Tweak - WordPress 5.5 compatibility. 5 | 6 | 2020-06-05 - version 3.0.28 7 | * Tweak - WC 4.2 compatibility. 8 | 9 | 2020-05-12 - version 3.0.27 10 | * Fix - Use tax rate based on cart items when table rate is set to including taxes. 11 | * Fix - Deduct taxes when user is VAT exempt and table rate is set to including taxes. 12 | 13 | 2020-04-30 - version 3.0.26 14 | * Tweak - WC 4.1 compatibility. 15 | 16 | 2020-04-14 - version 3.0.25 17 | * Fix - Save the abort notice in the session (to display when shipping methods are loaded from cache). 18 | 19 | 2020-04-08 - version 3.0.24 20 | * Fix - Adjust conditions for abort notices to show in cart/checkout pages. 21 | * Tweak - WP 5.4 compatibility. 22 | 23 | 2020-04-01 - version 3.0.23 24 | * Tweak - Add filter to compare price restrictions after discounts and coupons have been applied. 25 | * Tweak - Remove legacy code. 26 | 27 | 2020-03-11 - version 3.0.22 28 | * Fix - Change columns in table based on the chosen calculation type. 29 | 30 | 2020-02-26 - version 3.0.21 31 | * Tweak - WC 4.0 compatibility. 32 | * Tweak - Improve layout for min max fields. 33 | 34 | 2020-02-05 - version 3.0.20 35 | * Fix - Use proper escape for attributes. 36 | 37 | 2020-01-15 - version 3.0.19 38 | * Tweak - Only show abort notices in the cart/checkout page. 39 | 40 | 2019-11-05 - version 3.0.18 41 | * Tweak - WC 3.8 compatibility. 42 | 43 | 2019-08-08 - version 3.0.17 44 | * Tweak - WC 3.7 compatibility. 45 | 46 | 2019-07-02 - version 3.0.16 47 | * Fix - PHP notices. 48 | 49 | 2019-04-14 - version 3.0.15 50 | * Update - Add filter that allows per shipping class intergration with other plugins. 51 | * Tweak - WC 3.6 compatibility. 52 | 53 | 2019-03-04 - version 3.0.14 54 | * Tweak - Order Handling Fee verbiage to not include percentages as not intended. 55 | 56 | 2018-11-28 - version 3.0.13 57 | * Fix - Fatal error with inclusive taxes and calculating rates per item. 58 | 59 | 2018-10-31 - version 3.0.12 60 | * Fix - Default to shipping costs exclusive of taxes for existing methods. 61 | 62 | 2018-10-29 - version 3.0.11 63 | * Fix - Duplicate row would not save changes. 64 | * Update - Allow more than 2 decimals of precision for rule constraints. 65 | * Update - Deleting shipping class deletes related table rate shipping rules. 66 | * Update - Allow table rate prices to be entered inclusive of taxes. 67 | * Fix - Properly determine product's price when inclusive taxes are used and respect the 'woocommerce_adjust_non_base_location_prices' filter. 68 | * Fix - Rounding errors of shipping prices before taxes are added. 69 | * Fix - Multiple abort notices appearing. 70 | 71 | 2018-09-25 - version 3.0.10 72 | * Update - WC 3.5 compatibility. 73 | 74 | 2018-05-30 - version 3.0.9 75 | * Fix - Saving settings not working in WooCommerce 3.4.1 76 | 77 | 2018-05-23 - version 3.0.8 78 | * Update - Privacy policy notification. 79 | * Update - WC 3.4 compatibility. 80 | * Fix - Use correct plugin URL on plugins listview. 81 | * Fix - Weight cost doesn't support different decimal separators. 82 | 83 | 2018-01-26 - version 3.0.7 84 | * Add - Percentage support for Order total Handling Fee. 85 | * Fix - Additional fixes for supporting decimal separator as comma. 86 | 87 | 2018-01-12 - version 3.0.6 88 | * Fix - Decimal separator as comma isn't respected in table rates. 89 | 90 | 2017-12-13 - version 3.0.5 91 | * Update - WC tested up to version. 92 | 93 | 2017-06-20 - version 3.0.4 94 | * Fix - Additional PHP7.1 notice fixes. 95 | 96 | 2017-04-27 - version 3.0.3 97 | * Fix - Additional WC 3.0 compatibility. 98 | * Fix - PHP 7.1 notices. 99 | 100 | 2016-09-19 - version 3.0.2 101 | * Fix - Class type shipping label was not showing. 102 | * Update - Hide unnecessary class priorities depending on calculation type. 103 | 104 | 2016-06-09 - version 3.0.1 105 | * Fix - Undefined method get_field_default which introduced in WC 2.6 106 | 107 | 2016-05-24 - version 3.0.0 108 | * Implemented WC 2.6.0 Support and new data structures. 109 | 110 | 2015-11-20 - version 2.9.2 111 | * Fix - Escape postcodes passed to queries. 112 | 113 | 2015-11-18 - version 2.9.1 114 | * Fix - No matching rates when table rate has 'No Class' rule. 115 | * Fix - Coupons not taken into account when looping through shipping methods. 116 | 117 | 2015-05-12 - version 2.9.0 118 | * Removed legacy notice code. 119 | * Reorganised options 120 | * Added new max cost option. 121 | * Hide shipping classes when unused. 122 | 123 | 2015-04-21 - version 2.8.3 124 | * Fix - Potential XSS with add_query_arg. 125 | 126 | 2015-02-17 - version 2.8.2 127 | * Fix - Postcode save method. 128 | 129 | 2015-02-11 - version 2.8.1 130 | * Fix - Fatal error in cart and checkout when trying to register the shipping methods. 131 | 132 | 2015-01-29 - version 2.8.0 133 | * WC 2.3 Compatibility. 134 | * Refactored shipping zone framework. 135 | 136 | 2014-12-03 - version 2.7.2 137 | * Fixed order type abort. It should abort and offer no rates from the table. 138 | 139 | 2014-10-14 - version 2.7.1 140 | * Fix JS error when abort is selected. 141 | 142 | 2014-10-08 - version 2.7.0 143 | * Row cleanup. 144 | * Additonal logic to 'abort' a table rate if a row matches. 145 | * Show optional message on abort. 146 | * Added option for order handling fee (base cost). 147 | * Added option for max cost. 148 | * Updated text domain. 149 | * Fix display of disabled inputs. 150 | 151 | 2014-01-28 - version 2.6.10 152 | * Only show debugging if set to display 153 | 154 | 2014-01-06 - version 2.6.9 155 | * 2.1 compat 156 | 157 | 2013-12-02 - version 2.6.8 158 | * Hooks for WPML 159 | 160 | 2013-11-21 - version 2.6.7 161 | * Hook when getting product price during calculation 162 | 163 | 2013-08-13 - version 2.6.6 164 | * Fix zone ordering 165 | 166 | 2013-04-25 - version 2.6.5 167 | * sanitize_text_field on state names 168 | 169 | 2013-04-22 - version 2.6.4 170 | * Removed uninstall scripts 171 | 172 | 2013-04-19 - version 2.6.3 173 | * Round weights to 2dp 174 | 175 | 2013-03-15 - version 2.6.2 176 | * Fix numeric ranges 177 | 178 | 2013-03-13 - version 2.6.1 179 | * Localisation for zones 180 | 181 | 2013-01-29 - version 2.6.0 182 | * Shipping Zone interface update 183 | 184 | 2013-01-29 - version 2.5.2 185 | * Correctly cast the shipping class id 186 | 187 | 2013-01-21 - version 2.5.1 188 | * esc_js on class name 189 | 190 | 2013-01-11 - version 2.5.0 191 | * WC 2.0 Compat 192 | 193 | 2012-12-13 - version 2.4.1 194 | * Fix prepare 195 | * Fix class != check 196 | 197 | 2012-11-26 - version 2.4.0 198 | * Previous version class priorities has been removed in favour of running the rates in order of definition. 199 | * Min cost option per table rate. 200 | * New updater 201 | 202 | 2012-11-26 - version 2.3.0 203 | * Fixed method enable/disable setting. 204 | * Choose the order in which classes are evalulated for per-class rates. 205 | 206 | 2012-11-06 - version 2.2.2 207 | * Fix matched rates when using the break option. 208 | 209 | 2012-11-06 - version 2.2.1 210 | * Fix labels 211 | 212 | 2012-11-05 - version 2.2 213 | * For stores with tax inc prices, calculate correct item price with local tax. 214 | * Added debug mode - kicks in when WP_DEBUG is on. 215 | * Fix shipping_condition none. 216 | * Renamed 'priority' to 'break' to make more sense. 217 | * Allow label translation. 218 | 219 | 2012-10-23 - version 2.1.3 220 | * Calculated rate tweak - a row much match or 0 priced rates will be ignored 221 | * Ensure transients are cleared on save 222 | 223 | 2012-10-05 - version 2.1.2 224 | * Fix insert on some systems 225 | * Fix default shipping_method_order in table 226 | 227 | 2012-10-05 - version 2.1.1 228 | * Tweak some text descriptions 229 | 230 | 2012-10-03 - version 2.1.0 231 | * Ability to sort methods within zones to control the order on the frontend 232 | 233 | 2012-08-20 - version 2.0.6 234 | * Fix 'Any Shipping Class' 235 | 236 | 2012-08-14 - version 2.0.5 237 | * Fix priority checkbox for per-class rates 238 | 239 | 2012-07-26 - version 2.0.4 240 | * Set default title for instances - labels are required so this fixes things when title is not set 241 | * Fix get_cart_shipping_class_id function 242 | 243 | 2012-07-19 - version 2.0.3 244 | * First release 245 | 246 | 2012-06-25 - version 2.0.2 Beta 247 | * Fix state detection for zones 248 | * Fix count items in class 249 | * Fix no shipping class query 250 | * Don't hide empty shipping classes 251 | * 'None' condition 252 | 253 | 2012-06-12 - version 2.0.1 Beta 254 | * Fix zone dropdown for states 255 | 256 | 2012-04-19 - version 2.0 Beta 257 | * Re-write based on user feedback. Due to the massive restructure, and new zones functionality it isn't possible to upgrade your old rates - you will need to re-enter them (however, due to the zones and new features this process should be much easier!) 258 | * Re-done the interface for efficiency 259 | * Introduction of shipping zones to simplify data entry 260 | * Allow costs to be defined with 4dp to prevent rounding issues 261 | * items_in_class condition, if you only want to count items of the priority class 262 | * Rates stored in a table rather than serialised for improved reliability 263 | * Calculated rates (add matching rules together) 264 | * Per item, per line, per class rules for calculated rates 265 | * Multiple table rate instances per zone 266 | * Define costs per item, per weight unit, and a percent of the total 267 | 268 | 2012-02-09 - version 1.5.1 269 | * Weights/item count did not consider quantity 270 | 271 | 2012-02-09 - version 1.5 272 | * Mixed carts - when using a shipping class, only count items in said class when using item # rules 273 | * Weight and price and count only for items that need shipping 274 | 275 | 2012-02-09 - version 1.4.4 276 | * Postcode - don't remove spaces 277 | 278 | 2012-02-09 - version 1.4.3 279 | * Postcode case fix 280 | 281 | 2012-02-02 - version 1.4.2 282 | * Empty label fix 283 | 284 | 2012-02-01 - version 1.4.1 285 | * Logic bug with priority rates 286 | 287 | 2012-01-26 - version 1.4 288 | * WC 1.4 Compatibility (shipping rate API) 289 | 290 | 2011-12-15 - version 1.3 291 | * Support for the new 'Product Shipping Classes' in WC 1.3. This means you can have different table rates for different groups of products. 292 | * Drag and drop rates to re-order by priority 293 | * 'Priority' option if you want a rate to be the *only* one used if matched 294 | 295 | 2011-12-01 - version 1.2 296 | * Woo Updater 297 | * Made use of WC 1.3 Settings API 298 | * 'Chosen' input to aid adding rates 299 | 300 | 2011-11-15 - version 1.1.2 301 | * Changed textdomain 302 | 303 | 2011-11-15 - version 1.1.1 304 | * Changed text domain 305 | 306 | 2011-10-27 - version 1.1 307 | * Changed the way countries are defined to improve performance 308 | * Shortcuts for EU countries/US States 309 | * Postcodes can now be comma separated 310 | * Ability to exclude postcodes 311 | 312 | 2011-10-06 - version 1.0.1 313 | * Fixed rates when state is chosen/entered 314 | 315 | 2011-09-27 - version 1.0 316 | * First Release 317 | -------------------------------------------------------------------------------- /includes/class-wc-shipping-table-rate-privacy.php: -------------------------------------------------------------------------------- 1 | Learn more about how this works, including what you may want to include in your privacy policy.', 'woocommerce-table-rate-shipping' ), 'https://docs.woocommerce.com/document/privacy-shipping/#woocommerce-table-rate-shipping' ) ); 21 | } 22 | } 23 | 24 | new WC_Shipping_Table_Rate_Privacy(); 25 | -------------------------------------------------------------------------------- /includes/class-wc-shipping-table-rate.php: -------------------------------------------------------------------------------- 1 | id = 'table_rate'; 29 | $this->instance_id = absint( $instance_id ); 30 | $this->method_title = __( 'Table rates', 'woocommerce-table-rate-shipping' ); 31 | $this->method_description = __( 'Table rates are dynamic rates based on a number of cart conditions.', 'woocommerce-table-rate-shipping' ); 32 | $this->title = $this->method_title; 33 | $this->has_settings = false; 34 | $this->supports = array( 'zones', 'shipping-zones', 'instance-settings' ); 35 | 36 | // Load the form fields. 37 | $this->init_form_fields(); 38 | 39 | // Get settings 40 | $this->enabled = 'yes'; 41 | $this->title = $this->get_option( 'title', __( 'Table Rate', 'woocommerce-table-rate-shipping' ) ); 42 | $this->fee = $this->get_option( 'handling_fee' ); 43 | $this->order_handling_fee = $this->get_option( 'order_handling_fee' ); 44 | $this->tax_status = $this->get_option( 'tax_status' ); 45 | $this->calculation_type = $this->get_option( 'calculation_type' ); 46 | $this->min_cost = $this->get_option( 'min_cost' ); 47 | $this->max_cost = $this->get_option( 'max_cost' ); 48 | $this->max_shipping_cost = $this->get_option( 'max_shipping_cost' ); 49 | 50 | // Table rate specific variables 51 | $this->rates_table = $wpdb->prefix . 'woocommerce_shipping_table_rates'; 52 | $this->available_rates = array(); 53 | 54 | add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) ); 55 | } 56 | 57 | /** 58 | * get_option function. 59 | * 60 | * Gets and option from the settings API, using defaults if necessary to prevent undefined notices. 61 | * 62 | * @param string $key 63 | * @param mixed $empty_value 64 | * @return mixed The value specified for the option or a default value for the option. 65 | */ 66 | public function get_option( $key, $empty_value = null ) { 67 | // Instance options take priority over global options 68 | if ( in_array( $key, array_keys( $this->get_instance_form_fields() ) ) ) { 69 | return $this->get_instance_option( $key, $empty_value ); 70 | } 71 | 72 | // Return global option 73 | return parent::get_option( $key, $empty_value ); 74 | } 75 | 76 | /** 77 | * Gets an option from the settings API, using defaults if necessary to prevent undefined notices. 78 | * 79 | * @param string $key 80 | * @param mixed $empty_value 81 | * @return mixed The value specified for the option or a default value for the option. 82 | */ 83 | public function get_instance_option( $key, $empty_value = null ) { 84 | if ( empty( $this->instance_settings ) ) { 85 | $this->init_instance_settings(); 86 | } 87 | 88 | // Get option default if unset. 89 | if ( ! isset( $this->instance_settings[ $key ] ) ) { 90 | $form_fields = $this->get_instance_form_fields(); 91 | 92 | if ( is_callable( array( $this, 'get_field_default' ) ) ) { 93 | $this->instance_settings[ $key ] = $this->get_field_default( $form_fields[ $key ] ); 94 | } else { 95 | $this->instance_settings[ $key ] = empty( $form_fields[ $key ]['default'] ) ? '' : $form_fields[ $key ]['default']; 96 | } 97 | } 98 | 99 | if ( ! is_null( $empty_value ) && '' === $this->instance_settings[ $key ] ) { 100 | $this->instance_settings[ $key ] = $empty_value; 101 | } 102 | 103 | // For the admin view, make sure we display them with decimal separator. 104 | // Otherwise, use dots for calculation. 105 | if ( is_admin() && in_array( $key, $this->decimal_options ) ) { 106 | $decimal_separator = wc_get_price_decimal_separator(); 107 | $this->instance_settings[ $key ] = str_replace( '.', $decimal_separator, $this->instance_settings[ $key ] ); 108 | } 109 | 110 | return $this->instance_settings[ $key ]; 111 | } 112 | 113 | /** 114 | * Get settings fields for instances of this shipping method (within zones). 115 | * Should be overridden by shipping methods to add options. 116 | * @since 3.0.0 117 | * @return array 118 | */ 119 | public function get_instance_form_fields() { 120 | return apply_filters( 'woocommerce_shipping_instance_form_fields_' . $this->id, $this->instance_form_fields ); 121 | } 122 | 123 | /** 124 | * Return the name of the option in the WP DB. 125 | * @since 3.0.0 126 | * @return string 127 | */ 128 | public function get_instance_option_key() { 129 | return $this->instance_id ? $this->plugin_id . $this->id . '_' . $this->instance_id . '_settings' : ''; 130 | } 131 | 132 | /** 133 | * Initialise Settings for instances. 134 | * @since 3.0.0 135 | */ 136 | public function init_instance_settings() { 137 | // 2nd option is for BW compat 138 | $this->instance_settings = get_option( $this->get_instance_option_key(), get_option( $this->plugin_id . $this->id . '-' . $this->instance_id . '_settings', null ) ); 139 | 140 | /* 141 | * Order handling fee does not handle percentages. So 142 | * we need to remove previously saved % before initializing. 143 | * 144 | * @since 3.0.14 To fix https://github.com/woocommerce/woocommerce-table-rate-shipping/issues/91 145 | */ 146 | $this->instance_settings['order_handling_fee'] = str_replace( 147 | '%', 148 | '', 149 | empty( $this->instance_settings['order_handling_fee'] ) ? '' : $this->instance_settings['order_handling_fee'] 150 | ); 151 | 152 | // If there are no settings defined, use defaults. 153 | if ( ! is_array( $this->instance_settings ) ) { 154 | $form_fields = $this->get_instance_form_fields(); 155 | $this->instance_settings = array_merge( array_fill_keys( array_keys( $form_fields ), '' ), wp_list_pluck( $form_fields, 'default' ) ); 156 | } 157 | } 158 | 159 | /** 160 | * Initialise Gateway Settings Form Fields 161 | */ 162 | public function init_form_fields() { 163 | $this->form_fields = array(); // No global options for table rates 164 | $this->instance_form_fields = array( 165 | 'title' => array( 166 | 'title' => __( 'Method Title', 'woocommerce-table-rate-shipping' ), 167 | 'type' => 'text', 168 | 'desc_tip' => true, 169 | 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-table-rate-shipping' ), 170 | 'default' => __( 'Table Rate', 'woocommerce-table-rate-shipping' ) 171 | ), 172 | 'tax_status' => array( 173 | 'title' => __( 'Tax Status', 'woocommerce-table-rate-shipping' ), 174 | 'type' => 'select', 175 | 'description' => '', 176 | 'desc_tip' => true, 177 | 'default' => 'taxable', 178 | 'options' => array( 179 | 'taxable' => __('Taxable', 'woocommerce-table-rate-shipping'), 180 | 'none' => __('None', 'woocommerce-table-rate-shipping'), 181 | ) 182 | ), 183 | 'prices_include_tax' => array( 184 | 'title' => __( 'Tax included in shipping costs', 'woocommerce-table-rate-shipping' ), 185 | 'type' => 'select', 186 | 'description' => '', 187 | 'desc_tip' => true, 188 | 'default' => get_option( $this->get_instance_option_key() ) ? 'no' // Shipping method has previously been configured so we default to 'no' to maintain backwards compatibility. 189 | : ( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ? 'yes' : 'no' ), // Otherwise default to the store setting. 190 | 'options' => array( 191 | 'yes' => __( 'Yes, I will enter costs below inclusive of tax', 'woocommerce-table-rate-shipping' ), 192 | 'no' => __( 'No, I will enter costs below exclusive of tax', 'woocommerce-table-rate-shipping' ), 193 | ), 194 | ), 195 | 'order_handling_fee' => array( 196 | 'title' => __( 'Handling Fee', 'woocommerce-table-rate-shipping' ), 197 | 'type' => 'number', 198 | 'desc_tip' => __( 'Enter an amount, e.g. 2.50. Leave blank to disable. This cost is applied once for the order as a whole.', 'woocommerce-table-rate-shipping' ), 199 | 'default' => '', 200 | 'placeholder' => __( 'n/a', 'woocommerce-table-rate-shipping' ), 201 | 'custom_attributes' => array( 202 | 'step' => '0.01', 203 | ), 204 | ), 205 | 'max_shipping_cost' => array( 206 | 'title' => __( 'Maximum Shipping Cost', 'woocommerce-table-rate-shipping' ), 207 | 'type' => 'text', 208 | 'desc_tip' => __( 'Maximum cost that the customer will pay after all the shipping rules have been applied. If the shipping cost calculated is bigger than this value, this cost will be the one shown.', 'woocommerce-table-rate-shipping' ), 209 | 'default' => '', 210 | 'placeholder' => __( 'n/a', 'woocommerce-table-rate-shipping' ) 211 | ), 212 | 'rates' => array( 213 | 'title' => __( 'Rates', 'woocommerce-table-rate-shipping' ), 214 | 'type' => 'title', 215 | 'description' => __( 'This is where you define your table rates which are applied to an order.', 'woocommerce-table-rate-shipping'), 216 | 'default' => '' 217 | ), 218 | 'calculation_type' => array( 219 | 'title' => __( 'Calculation Type', 'woocommerce-table-rate-shipping' ), 220 | 'type' => 'select', 221 | 'description' => __( 'Per order rates will offer the customer all matching rates. Calculated rates will sum all matching rates and provide a single total.', 'woocommerce-table-rate-shipping' ), 222 | 'default' => '', 223 | 'desc_tip' => true, 224 | 'options' => array( 225 | '' => __( 'Per order', 'woocommerce-table-rate-shipping' ), 226 | 'item' => __( 'Calculated rates per item', 'woocommerce-table-rate-shipping' ), 227 | 'line' => __( 'Calculated rates per line item', 'woocommerce-table-rate-shipping' ), 228 | 'class' => __( 'Calculated rates per shipping class', 'woocommerce-table-rate-shipping' ) 229 | ) 230 | ), 231 | 'handling_fee' => array( 232 | 'title' => __( 'Handling Fee Per [item]', 'woocommerce-table-rate-shipping' ), 233 | 'type' => 'text', 234 | 'desc_tip' => __( 'Handling fee. Enter an amount, e.g. 2.50, or a percentage, e.g. 5%. Leave blank to disable. Applied based on the "Calculation Type" chosen below.', 'woocommerce-table-rate-shipping' ), 235 | 'default' => '', 236 | 'placeholder' => __( 'n/a', 'woocommerce-table-rate-shipping' ), 237 | ), 238 | 'min_cost' => array( 239 | 'title' => __( 'Minimum Cost Per [item]', 'woocommerce-table-rate-shipping' ), 240 | 'type' => 'text', 241 | 'desc_tip' => true, 242 | 'description' => __('Minimum cost for this shipping method (optional). If the cost is lower, this minimum cost will be enforced.', 'woocommerce-table-rate-shipping'), 243 | 'default' => '', 244 | 'placeholder' => __( 'n/a', 'woocommerce-table-rate-shipping' ) 245 | ), 246 | 'max_cost' => array( 247 | 'title' => __( 'Maximum Cost Per [item]', 'woocommerce-table-rate-shipping' ), 248 | 'type' => 'text', 249 | 'desc_tip' => true, 250 | 'description' => __( 'Maximum cost for this shipping method (optional). If the cost is higher, this maximum cost will be enforced.', 'woocommerce-table-rate-shipping'), 251 | 'default' => '', 252 | 'placeholder' => __( 'n/a', 'woocommerce-table-rate-shipping' ) 253 | ), 254 | ); 255 | 256 | } 257 | 258 | /** 259 | * Admin options 260 | */ 261 | public function admin_options() { 262 | $this->instance_options(); 263 | } 264 | 265 | /** 266 | * Return admin options as a html string. 267 | * @return string 268 | */ 269 | public function get_admin_options_html() { 270 | ob_start(); 271 | $this->instance_options(); 272 | return ob_get_clean(); 273 | } 274 | 275 | /** 276 | * admin_options function. 277 | */ 278 | public function instance_options() { 279 | ?> 280 | 281 | generate_settings_html( $this->get_instance_form_fields() ); 283 | ?> 284 | 285 | 286 | 289 | 290 | shipping->get_shipping_classes() ) ) : ?> 291 | 292 | 293 | 296 | 297 | 298 |
287 | 288 |
294 | instance_id ); ?> 295 |
299 | decimal_options as $option ) { 310 | $option = 'woocommerce_table_rate_' . $option; 311 | 312 | if ( ! isset( $_POST[ $option ] ) ) { 313 | continue; 314 | } 315 | 316 | $_POST[ $option ] = str_replace( $decimal_separator, '.', $_POST[ $option ] ); 317 | } 318 | 319 | parent::process_admin_options(); 320 | wc_table_rate_admin_shipping_rows_process( $this->instance_id ); 321 | } 322 | 323 | /** 324 | * is_available function. 325 | * 326 | * @param array $package 327 | * @return bool 328 | */ 329 | public function is_available( $package ) { 330 | $available = true; 331 | 332 | if ( ! $this->get_rates( $package ) ) { 333 | $available = false; 334 | } 335 | 336 | return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', $available, $package, $this ); 337 | } 338 | 339 | /** 340 | * count_items_in_class function. 341 | * @return int 342 | */ 343 | public function count_items_in_class( $package, $class_id ) { 344 | $count = 0; 345 | 346 | // Find shipping classes for products in the package 347 | foreach ( $package['contents'] as $item_id => $values ) { 348 | if ( $values['data']->needs_shipping() && $values['data']->get_shipping_class_id() == $class_id ) { 349 | $count += $values['quantity']; 350 | } 351 | } 352 | 353 | return $count; 354 | } 355 | 356 | /** 357 | * get_cart_shipping_class_id function. 358 | * @return int 359 | */ 360 | public function get_cart_shipping_class_id( $package ) { 361 | // Find shipping class for cart 362 | $found_shipping_classes = array(); 363 | $shipping_class_id = 0; 364 | $shipping_class_slug = ''; 365 | 366 | // Find shipping classes for products in the package 367 | if ( sizeof( $package['contents'] ) > 0 ) { 368 | foreach ( $package['contents'] as $item_id => $values ) { 369 | if ( $values['data']->needs_shipping() ) { 370 | $found_shipping_classes[ $values['data']->get_shipping_class_id() ] = $values['data']->get_shipping_class(); 371 | } 372 | } 373 | } 374 | 375 | $found_shipping_classes = array_unique( $found_shipping_classes ); 376 | 377 | if ( sizeof( $found_shipping_classes ) == 1 ) { 378 | $shipping_class_slug = current( $found_shipping_classes ); 379 | } elseif ( $found_shipping_classes > 1 ) { 380 | 381 | // Get class with highest priority 382 | $priority = get_option( 'woocommerce_table_rate_default_priority_' . $this->instance_id ); 383 | $priorities = get_option( 'woocommerce_table_rate_priorities_' . $this->instance_id ); 384 | 385 | foreach ( $found_shipping_classes as $class ) { 386 | if ( isset( $priorities[ $class ] ) && $priorities[ $class ] < $priority ) { 387 | $priority = $priorities[ $class ]; 388 | $shipping_class_slug = $class; 389 | } 390 | } 391 | } 392 | 393 | $found_shipping_classes = array_flip( $found_shipping_classes ); 394 | 395 | if ( isset( $found_shipping_classes[ $shipping_class_slug ] ) ) 396 | $shipping_class_id = $found_shipping_classes[ $shipping_class_slug ]; 397 | 398 | return $shipping_class_id; 399 | } 400 | 401 | /** 402 | * query_rates function. 403 | * 404 | * @param array $args 405 | * @return array 406 | */ 407 | public function query_rates( $args ) { 408 | global $wpdb; 409 | 410 | $defaults = array( 411 | 'price' => '', 412 | 'weight' => '', 413 | 'count' => 1, 414 | 'count_in_class' => 1, 415 | 'shipping_class_id' => '' 416 | ); 417 | 418 | $args = apply_filters( 'woocommerce_table_rate_query_rates_args', wp_parse_args( $args, $defaults ) ); 419 | 420 | extract( $args, EXTR_SKIP ); 421 | 422 | if ( $shipping_class_id == "" ) { 423 | $shipping_class_id_in = " AND rate_class IN ( '', '0' )"; 424 | } else { 425 | $shipping_class_id_in = " AND rate_class IN ( '', '" . absint( $shipping_class_id ) . "' )"; 426 | } 427 | 428 | $rates = $wpdb->get_results( 429 | $wpdb->prepare( " 430 | SELECT rate_id, rate_cost, rate_cost_per_item, rate_cost_per_weight_unit, rate_cost_percent, rate_label, rate_priority, rate_abort, rate_abort_reason 431 | FROM {$this->rates_table} 432 | WHERE shipping_method_id IN ( %s ) 433 | {$shipping_class_id_in} 434 | AND 435 | ( 436 | rate_condition = '' 437 | OR 438 | ( 439 | rate_condition = 'price' 440 | AND 441 | ( 442 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) = '' ) 443 | OR 444 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) >=0 AND '{$price}' >= ( rate_min + 0 ) AND '{$price}' <= ( rate_max + 0 ) ) 445 | OR 446 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) = '' AND '{$price}' >= ( rate_min + 0 ) ) 447 | OR 448 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) >= 0 AND '{$price}' <= ( rate_max + 0 ) ) 449 | ) 450 | ) 451 | OR 452 | ( 453 | rate_condition = 'weight' 454 | AND 455 | ( 456 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) = '' ) 457 | OR 458 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) >=0 AND '{$weight}' >= ( rate_min + 0 ) AND '{$weight}' <= ( rate_max + 0 ) ) 459 | OR 460 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) = '' AND '{$weight}' >= ( rate_min + 0 ) ) 461 | OR 462 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) >= 0 AND '{$weight}' <= ( rate_max + 0 ) ) 463 | ) 464 | ) 465 | OR 466 | ( 467 | rate_condition = 'items' 468 | AND 469 | ( 470 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) = '' ) 471 | OR 472 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) >=0 AND '{$count}' >= ( rate_min + 0 ) AND '{$count}' <= ( rate_max + 0 ) ) 473 | OR 474 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) = '' AND '{$count}' >= ( rate_min + 0 ) ) 475 | OR 476 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) >= 0 AND '{$count}' <= ( rate_max + 0 ) ) 477 | ) 478 | ) 479 | OR 480 | ( 481 | rate_condition = 'items_in_class' 482 | AND 483 | ( 484 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) = '' ) 485 | OR 486 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) >= 0 AND '{$count_in_class}' >= ( rate_min + 0 ) AND '{$count_in_class}' <= ( rate_max + 0 ) ) 487 | OR 488 | ( ( rate_min + 0 ) >= 0 AND ( rate_max + 0 ) = '' AND '{$count_in_class}' >= ( rate_min + 0 ) ) 489 | OR 490 | ( ( rate_min + 0 ) = '' AND ( rate_max + 0 ) >= 0 AND '{$count_in_class}' <= ( rate_max + 0 ) ) 491 | ) 492 | ) 493 | ) 494 | ORDER BY rate_order ASC 495 | ", $this->instance_id ) 496 | ); 497 | 498 | return apply_filters( 'woocommerce_table_rate_query_rates', $rates ); 499 | } 500 | 501 | /** 502 | * get_rates function. 503 | * @return bool 504 | */ 505 | public function get_rates( $package ) { 506 | global $wpdb; 507 | 508 | if ( ! $this->instance_id ) 509 | return false; 510 | 511 | $rates = array(); 512 | $this->unset_abort_message(); 513 | 514 | // Get rates, depending on type 515 | if ( $this->calculation_type == 'item' ) { 516 | 517 | // For each ITEM get matching rates 518 | $costs = array(); 519 | 520 | $matched = false; 521 | 522 | foreach ( $package['contents'] as $item_id => $values ) { 523 | 524 | $_product = $values['data']; 525 | 526 | if ( $values['quantity'] > 0 && $_product->needs_shipping() ) { 527 | 528 | $product_price = $this->get_product_price( $_product, 1, $values ); 529 | 530 | $matching_rates = $this->query_rates( array( 531 | 'price' => $product_price, 532 | 'weight' => (float) $_product->get_weight(), 533 | 'count' => 1, 534 | 'count_in_class' => $this->count_items_in_class( $package, $_product->get_shipping_class_id() ), 535 | 'shipping_class_id' => $_product->get_shipping_class_id() 536 | ) ); 537 | 538 | $item_weight = round( (float) $_product->get_weight(), 2 ); 539 | $item_fee = (float) $this->get_fee( $this->fee, $product_price ); 540 | $item_cost = 0; 541 | 542 | foreach ( $matching_rates as $rate ) { 543 | $item_cost += (float) $rate->rate_cost; 544 | $item_cost += (float) $rate->rate_cost_per_weight_unit * $item_weight; 545 | $item_cost += ( (float) $rate->rate_cost_percent / 100 ) * $product_price; 546 | $matched = true; 547 | if ( $rate->rate_abort ) { 548 | if ( ! empty( $rate->rate_abort_reason ) && ! wc_has_notice( $rate->rate_abort_reason, 'notice' ) ) { 549 | $this->add_notice( $rate->rate_abort_reason, 'notice' ); 550 | } 551 | return; 552 | } 553 | if ( $rate->rate_priority ) 554 | break; 555 | } 556 | 557 | $cost = ( $item_cost + $item_fee ) * $values['quantity']; 558 | 559 | if ( $this->min_cost && $cost < $this->min_cost ) { 560 | $cost = $this->min_cost; 561 | } 562 | if ( $this->max_cost && $cost > $this->max_cost ) { 563 | $cost = $this->max_cost; 564 | } 565 | 566 | $costs[ $item_id ] = $cost; 567 | 568 | } 569 | } 570 | 571 | if ( $matched ) { 572 | if ( $this->order_handling_fee ) { 573 | $costs['order'] = $this->order_handling_fee; 574 | } else { 575 | $costs['order'] = 0; 576 | } 577 | 578 | if ( $this->max_shipping_cost && ( $costs['order'] + array_sum( $costs ) ) > $this->max_shipping_cost ) { 579 | $rates[] = array( 580 | 'id' => is_callable( array( $this, 'get_rate_id' ) ) ? $this->get_rate_id() : $this->instance_id, 581 | 'label' => __( $this->title, 'woocommerce-table-rate-shipping' ), 582 | 'cost' => $this->max_shipping_cost 583 | ); 584 | } else { 585 | $rates[] = array( 586 | 'id' => is_callable( array( $this, 'get_rate_id' ) ) ? $this->get_rate_id() : $this->instance_id, 587 | 'label' => __( $this->title, 'woocommerce-table-rate-shipping' ), 588 | 'cost' => $costs, 589 | 'calc_tax' => 'per_item', 590 | 'package' => $package, 591 | ); 592 | } 593 | } 594 | 595 | } elseif ( $this->calculation_type == 'line' ) { 596 | 597 | // For each LINE get matching rates 598 | $costs = array(); 599 | 600 | $matched = false; 601 | 602 | foreach ( $package['contents'] as $item_id => $values ) { 603 | 604 | $_product = $values['data']; 605 | 606 | if ( $values['quantity'] > 0 && $_product->needs_shipping() ) { 607 | 608 | $product_price = $this->get_product_price( $_product, $values['quantity'], $values ); 609 | 610 | $matching_rates = $this->query_rates( array( 611 | 'price' => $product_price, 612 | 'weight' => (float) $_product->get_weight() * $values['quantity'], 613 | 'count' => $values['quantity'], 614 | 'count_in_class' => $this->count_items_in_class( $package, $_product->get_shipping_class_id() ), 615 | 'shipping_class_id' => $_product->get_shipping_class_id() 616 | ) ); 617 | 618 | $item_weight = round( (float) $_product->get_weight() * $values['quantity'], 2 ); 619 | $item_fee = (float) $this->get_fee( $this->fee, $product_price ); 620 | $item_cost = 0; 621 | 622 | foreach ( $matching_rates as $rate ) { 623 | $item_cost += (float) $rate->rate_cost; 624 | $item_cost += (float) $rate->rate_cost_per_item * $values['quantity']; 625 | $item_cost += (float) $rate->rate_cost_per_weight_unit * $item_weight; 626 | $item_cost += ( (float) $rate->rate_cost_percent / 100 ) * $product_price; 627 | $matched = true; 628 | 629 | if ( $rate->rate_abort ) { 630 | if ( ! empty( $rate->rate_abort_reason ) ) { 631 | $this->add_notice( $rate->rate_abort_reason, 'notice' ); 632 | } 633 | return; 634 | } 635 | if ( $rate->rate_priority ) 636 | break; 637 | } 638 | 639 | $item_cost = $item_cost + $item_fee; 640 | 641 | if ( $this->min_cost && $item_cost < $this->min_cost ) { 642 | $item_cost = $this->min_cost; 643 | } 644 | if ( $this->max_cost && $item_cost > $this->max_cost ) { 645 | $item_cost = $this->max_cost; 646 | } 647 | 648 | $costs[ $item_id ] = $item_cost; 649 | } 650 | 651 | } 652 | 653 | if ( $matched ) { 654 | if ( $this->order_handling_fee ) { 655 | $costs['order'] = $this->order_handling_fee; 656 | } else { 657 | $costs['order'] = 0; 658 | } 659 | 660 | if ( $this->max_shipping_cost && ( $costs['order'] + array_sum( $costs ) ) > $this->max_shipping_cost ) { 661 | $rates[] = array( 662 | 'id' => is_callable( array( $this, 'get_rate_id' ) ) ? $this->get_rate_id() : $this->instance_id, 663 | 'label' => __( $this->title, 'woocommerce-table-rate-shipping' ), 664 | 'cost' => $this->max_shipping_cost, 665 | 'package' => $package, 666 | ); 667 | } else { 668 | $rates[] = array( 669 | 'id' => is_callable( array( $this, 'get_rate_id' ) ) ? $this->get_rate_id() : $this->instance_id, 670 | 'label' => __( $this->title, 'woocommerce-table-rate-shipping' ), 671 | 'cost' => $costs, 672 | 'calc_tax' => 'per_item', 673 | 'package' => $package, 674 | ); 675 | } 676 | } 677 | 678 | } elseif ( $this->calculation_type == 'class' ) { 679 | 680 | // For each CLASS get matching rates 681 | $total_cost = 0; 682 | 683 | // First get all the rates in the table 684 | $all_rates = $this->get_shipping_rates(); 685 | 686 | // Now go through cart items and group items by class 687 | $classes = array(); 688 | 689 | foreach ( $package['contents'] as $item_id => $values ) { 690 | 691 | $_product = $values['data']; 692 | 693 | if ( $values['quantity'] > 0 && $_product->needs_shipping() ) { 694 | 695 | $shipping_class = $_product->get_shipping_class_id(); 696 | 697 | if ( ! isset( $classes[ $shipping_class ] ) ) { 698 | $classes[ $shipping_class ] = new stdClass(); 699 | $classes[ $shipping_class ]->price = 0; 700 | $classes[ $shipping_class ]->weight = 0; 701 | $classes[ $shipping_class ]->items = 0; 702 | $classes[ $shipping_class ]->items_in_class = 0; 703 | } 704 | 705 | $classes[ $shipping_class ]->price += $this->get_product_price( $_product, $values['quantity'], $values ); 706 | $classes[ $shipping_class ]->weight += (float) $_product->get_weight() * $values['quantity']; 707 | $classes[ $shipping_class ]->items += $values['quantity']; 708 | $classes[ $shipping_class ]->items_in_class += $values['quantity']; 709 | } 710 | } 711 | 712 | $matched = false; 713 | $total_cost = 0; 714 | $stop = false; 715 | 716 | // Now we have groups, loop the rates and find matches in order 717 | foreach ( $all_rates as $rate ) { 718 | 719 | foreach ( $classes as $class_id => $class ) { 720 | 721 | if ( $class_id == "" ) { 722 | if ( $rate->rate_class != 0 && $rate->rate_class !== '' ) 723 | continue; 724 | } else { 725 | if ( $rate->rate_class != $class_id && $rate->rate_class !== '' ) 726 | continue; 727 | } 728 | 729 | $rate_match = false; 730 | 731 | switch ( $rate->rate_condition ) { 732 | case '' : 733 | $rate_match = true; 734 | break; 735 | case 'price' : 736 | case 'weight' : 737 | case 'items_in_class' : 738 | case 'items' : 739 | 740 | $condition = $rate->rate_condition; 741 | $value = $class->$condition; 742 | 743 | if ( $rate->rate_min === '' && $rate->rate_max === '' ) 744 | $rate_match = true; 745 | 746 | if ( $value >= $rate->rate_min && $value <= $rate->rate_max ) 747 | $rate_match = true; 748 | 749 | if ( $value >= $rate->rate_min && ! $rate->rate_max ) 750 | $rate_match = true; 751 | 752 | if ( $value <= $rate->rate_max && ! $rate->rate_min ) 753 | $rate_match = true; 754 | 755 | break; 756 | } 757 | 758 | // Rate matched class 759 | if ( $rate_match ) { 760 | $rate_label = ! empty( $rate->rate_label ) ? $rate->rate_label : $this->title; 761 | $class_cost = 0; 762 | $class_cost += (float) $rate->rate_cost; 763 | $class_cost += (float) $rate->rate_cost_per_item * $class->items_in_class; 764 | $class_cost += (float) $rate->rate_cost_per_weight_unit * $class->weight; 765 | $class_cost += ( (float) $rate->rate_cost_percent / 100 ) * $class->price; 766 | 767 | if ( $rate->rate_abort ) { 768 | if ( ! empty( $rate->rate_abort_reason ) ) { 769 | $this->add_notice( $rate->rate_abort_reason, 'notice' ); 770 | } 771 | return; 772 | } 773 | 774 | if ( $rate->rate_priority ) { 775 | $stop = true; 776 | } 777 | 778 | $matched = true; 779 | 780 | $class_fee = (float) $this->get_fee( $this->fee, $class->price ); 781 | $class_cost += $class_fee; 782 | 783 | if ( $this->min_cost && $class_cost < $this->min_cost ) { 784 | $class_cost = $this->min_cost; 785 | } 786 | if ( $this->max_cost && $class_cost > $this->max_cost ) { 787 | $class_cost = $this->max_cost; 788 | } 789 | 790 | $total_cost += $class_cost; 791 | } 792 | } 793 | 794 | // Breakpoint 795 | if ( $stop ) { 796 | break; 797 | } 798 | } 799 | 800 | if ( $this->order_handling_fee ) { 801 | $total_cost += $this->get_fee( $this->order_handling_fee, $total_cost ); 802 | } 803 | 804 | if ( $this->max_shipping_cost && $total_cost > $this->max_shipping_cost ) { 805 | $total_cost = $this->max_shipping_cost; 806 | } 807 | 808 | if ( $matched ) { 809 | $rates[] = array( 810 | 'id' => is_callable( array( $this, 'get_rate_id' ) ) ? $this->get_rate_id() : $this->instance_id, 811 | 'label' => __( $rate_label, 'woocommerce-table-rate-shipping' ), 812 | 'cost' => $total_cost, 813 | 'package' => $package, 814 | ); 815 | } 816 | 817 | } else { 818 | 819 | // For the ORDER get matching rates 820 | $shipping_class = $this->get_cart_shipping_class_id( $package ); 821 | $price = 0; 822 | $weight = 0; 823 | $count = 0; 824 | $count_in_class = 0; 825 | 826 | foreach ( $package['contents'] as $item_id => $values ) { 827 | 828 | $_product = $values['data']; 829 | 830 | if ( $values['quantity'] > 0 && $_product->needs_shipping() ) { 831 | $price += $this->get_product_price( $_product, $values['quantity'], $values ); 832 | $weight += (float) $_product->get_weight() * (float) $values['quantity']; 833 | $count += $values['quantity']; 834 | 835 | if ( $_product->get_shipping_class_id() == $shipping_class ) 836 | $count_in_class += $values['quantity']; 837 | 838 | } 839 | } 840 | 841 | $matching_rates = $this->query_rates( array( 842 | 'price' => $price, 843 | 'weight' => $weight, 844 | 'count' => $count, 845 | 'count_in_class' => $count_in_class, 846 | 'shipping_class_id' => $shipping_class 847 | ) ); 848 | 849 | foreach ( $matching_rates as $rate ) { 850 | $label = $rate->rate_label; 851 | if ( ! $label ) 852 | $label = $this->title; 853 | 854 | if ( $rate->rate_abort ) { 855 | if ( ! empty( $rate->rate_abort_reason ) ) { 856 | $this->add_notice( $rate->rate_abort_reason, 'notice' ); 857 | } 858 | $rates = array(); // Clear rates 859 | break; 860 | } 861 | 862 | if ( $rate->rate_priority ) 863 | $rates = array(); 864 | 865 | $cost = (float) $rate->rate_cost; 866 | $cost += (float) $rate->rate_cost_per_item * $count; 867 | $cost += (float) $this->get_fee( $this->fee, $price ); 868 | $cost += (float) $rate->rate_cost_per_weight_unit * $weight; 869 | $cost += ( (float) $rate->rate_cost_percent / 100 ) * $price; 870 | 871 | if ( $this->order_handling_fee ) { 872 | $cost += $this->order_handling_fee; 873 | } 874 | 875 | if ( $this->min_cost && $cost < $this->min_cost ) { 876 | $cost = $this->min_cost; 877 | } 878 | 879 | if ( $this->max_cost && $cost > $this->max_cost ) { 880 | $cost = $this->max_cost; 881 | } 882 | 883 | if ( $this->max_shipping_cost && $cost > $this->max_shipping_cost ) { 884 | $cost = $this->max_shipping_cost; 885 | } 886 | 887 | $rates[] = array( 888 | 'id' => is_callable( array( $this, 'get_rate_id' ) ) ? $this->get_rate_id( $rate->rate_id ) : $this->instance_id . ' : ' . $rate->rate_id, 889 | 'label' => __( $label, 'woocommerce-table-rate-shipping' ), 890 | 'cost' => $cost, 891 | 'package' => $package, 892 | ); 893 | 894 | if ( $rate->rate_priority ) { 895 | break; 896 | } 897 | } 898 | 899 | } 900 | 901 | $is_customer_vat_exempt = WC()->cart->get_customer()->get_is_vat_exempt(); 902 | 903 | if ( 'yes' === $this->get_instance_option( 'prices_include_tax' ) && ( $this->is_taxable() || $is_customer_vat_exempt ) ) { 904 | // We allow the table rate to be entered inclusive of taxes just like product prices. 905 | foreach ( $rates as $key => $rate ) { 906 | 907 | $tax_rates = WC_Tax::get_shipping_tax_rates(); 908 | 909 | // Temporarily override setting since our shipping rate will always include taxes here. 910 | add_filter( 'woocommerce_prices_include_tax', array( $this, 'override_prices_include_tax_setting' ) ); 911 | $base_tax_rates = WC_Tax::get_shipping_tax_rates( null, false ); 912 | remove_filter( 'woocommerce_prices_include_tax', array( $this, 'override_prices_include_tax_setting' ) ); 913 | 914 | $total_cost = is_array( $rate['cost'] ) ? array_sum( $rate['cost'] ) : $rate['cost']; 915 | 916 | if ( apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ) { 917 | $taxes = WC_Tax::calc_tax( $total_cost, $base_tax_rates, true ); 918 | } else { 919 | $taxes = WC_Tax::calc_tax( $total_cost, $tax_rates, true ); 920 | } 921 | 922 | $rates[ $key ]['cost'] = $total_cost - array_sum( $taxes ); 923 | 924 | $rates[ $key ]['taxes'] = $is_customer_vat_exempt ? array() : WC_Tax::calc_shipping_tax( $rates[ $key ]['cost'], $tax_rates ); 925 | 926 | $rates[ $key ]['price_decimals'] = '4'; // Prevent the cost from being rounded before the tax is added. 927 | } 928 | } 929 | 930 | // None found? 931 | if ( sizeof( $rates ) == 0 ) { 932 | return false; 933 | } 934 | 935 | // Set available 936 | $this->available_rates = $rates; 937 | 938 | return true; 939 | } 940 | 941 | /** 942 | * Unique function for overriding the prices including tax setting in WooCommerce. 943 | * 944 | * @since 3.0.27 945 | * 946 | * @return bool 947 | */ 948 | public function override_prices_include_tax_setting() { 949 | return true; 950 | } 951 | 952 | /** 953 | * calculate_shipping function. 954 | * @param array $package 955 | */ 956 | public function calculate_shipping( $package = array() ) { 957 | if ( $this->available_rates ) { 958 | foreach ( $this->available_rates as $rate ) { 959 | $this->add_rate( $rate ); 960 | } 961 | } 962 | } 963 | 964 | /** 965 | * Get raw shipping rates from the DB. 966 | * 967 | * Optional filter helper for integration with other plugins. 968 | * 969 | * @param string $output Output format. 970 | * @return mixed 971 | */ 972 | public function get_shipping_rates( $output = OBJECT ) { 973 | global $wpdb; 974 | 975 | $rates = $wpdb->get_results( " 976 | SELECT * FROM {$this->rates_table} 977 | WHERE shipping_method_id = {$this->instance_id} 978 | ORDER BY rate_order ASC; 979 | ", $output ); 980 | 981 | return apply_filters( 'woocommerce_table_rate_get_shipping_rates', $rates ); 982 | } 983 | 984 | /** 985 | * Get shipping rates with normalized values (respect decimal separator 986 | * settings), for display. 987 | * 988 | * @return array 989 | */ 990 | public function get_normalized_shipping_rates() { 991 | $shipping_rates = $this->get_shipping_rates( ARRAY_A ); 992 | $decimal_separator = wc_get_price_decimal_separator(); 993 | $normalize_keys = array( 994 | 'rate_cost', 995 | 'rate_cost_per_item', 996 | 'rate_cost_per_weight_unit', 997 | 'rate_cost_percent', 998 | 'rate_max', 999 | 'rate_min', 1000 | ); 1001 | 1002 | foreach ( $shipping_rates as $index => $shipping_rate ) { 1003 | foreach ( $normalize_keys as $key ) { 1004 | if ( ! isset( $shipping_rate[ $key ] ) ) { 1005 | continue; 1006 | } 1007 | 1008 | $shipping_rates[ $index ][ $key ] = str_replace( '.', $decimal_separator, $shipping_rates[ $index ][ $key ] ); 1009 | } 1010 | } 1011 | 1012 | return $shipping_rates; 1013 | } 1014 | 1015 | /** 1016 | * Retrieve the product price from a line item. 1017 | * 1018 | * @param object $_product Product object. 1019 | * @param int $qty Line item quantity. 1020 | * @param array $item Array of line item data. 1021 | * @return float 1022 | */ 1023 | public function get_product_price( $_product, $qty = 1, $item = array() ) { 1024 | 1025 | // Use the product price based on the line item totals (including coupons and discounts). 1026 | // This is not enabled by default (since it can be interpreted differently). 1027 | if ( apply_filters( 'woocommerce_table_rate_compare_price_limits_after_discounts', false, $item ) && isset( $item['line_total'] ) ) { 1028 | return $item['line_total'] + ( ! empty( $item['line_tax'] ) ? $item['line_tax'] : 0 ); 1029 | } 1030 | 1031 | $row_base_price = $_product->get_price() * $qty; 1032 | $row_base_price = apply_filters( 'woocommerce_table_rate_package_row_base_price', $row_base_price, $_product, $qty ); 1033 | 1034 | if ( $_product->is_taxable() && wc_prices_include_tax() ) { 1035 | 1036 | $base_tax_rates = WC_Tax::get_base_tax_rates( $_product->get_tax_class() ); 1037 | 1038 | $tax_rates = WC_Tax::get_rates( $_product->get_tax_class() ); 1039 | 1040 | if ( $tax_rates !== $base_tax_rates && apply_filters( 'woocommerce_adjust_non_base_location_prices', true )) { 1041 | $base_taxes = WC_Tax::calc_tax( $row_base_price, $base_tax_rates, true, true ); 1042 | $modded_taxes = WC_Tax::calc_tax( $row_base_price - array_sum( $base_taxes ), $tax_rates, false ); 1043 | $row_base_price = ( $row_base_price - array_sum( $base_taxes ) ) + array_sum( $modded_taxes ); 1044 | } 1045 | } 1046 | 1047 | return $row_base_price; 1048 | } 1049 | 1050 | /** 1051 | * Admin Panel Options Processing 1052 | * - Saves the options to the DB 1053 | * 1054 | * @since 1.0.0 1055 | * @deprecated 3.0.0 1056 | */ 1057 | public function process_instance_options() { 1058 | $this->validate_settings_fields( $this->get_instance_form_fields() ); 1059 | 1060 | if ( count( $this->errors ) > 0 ) { 1061 | $this->display_errors(); 1062 | return false; 1063 | } else { 1064 | wc_table_rate_admin_shipping_rows_process( $this->instance_id ); 1065 | update_option( $this->get_instance_option_key(), $this->sanitized_fields ); 1066 | return true; 1067 | } 1068 | } 1069 | 1070 | /** 1071 | * Adds a notice to the cart/checkout header. 1072 | * 1073 | * @since 3.0.19 1074 | * @param string $message Message to show 1075 | * @return void 1076 | */ 1077 | private function add_notice( $message ) { 1078 | $this->save_abort_message( $message ); 1079 | 1080 | // Only display shipping notices in cart/checkout. 1081 | if ( ! is_cart() && ! is_checkout() ) { 1082 | return; 1083 | } 1084 | 1085 | if ( ! wc_has_notice( $message ) ) { 1086 | wc_add_notice( $message ); 1087 | } 1088 | } 1089 | 1090 | /** 1091 | * Save the abort notice in the session (to display when shipping methods are loaded from cache). 1092 | * 1093 | * @since 3.0.25 1094 | * @param string $message Abort message. 1095 | */ 1096 | private function save_abort_message( $message ) { 1097 | $abort = WC()->session->get( WC_Table_Rate_Shipping::$abort_key ); 1098 | if ( empty( $abort ) ) { 1099 | $abort = array(); 1100 | } 1101 | 1102 | $abort[ $this->instance_id ] = $message; 1103 | WC()->session->set( WC_Table_Rate_Shipping::$abort_key, $abort ); 1104 | } 1105 | 1106 | /** 1107 | * Unset the abort notice in the session. 1108 | * 1109 | * @since 3.0.25 1110 | */ 1111 | private function unset_abort_message() { 1112 | $abort = WC()->session->get( WC_Table_Rate_Shipping::$abort_key ); 1113 | unset( $abort[ $this->instance_id ] ); 1114 | WC()->session->set( WC_Table_Rate_Shipping::$abort_key, $abort ); 1115 | } 1116 | 1117 | } 1118 | -------------------------------------------------------------------------------- /includes/functions-admin.php: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 31 | 35 | 39 | 43 | 47 | 51 | 55 | 58 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | get_normalized_shipping_rates() ) ) : _wp_specialchars( wp_json_encode( $instance->get_normalized_shipping_rates() ), ENT_QUOTES, 'UTF-8', true ); 72 | ?> 73 | 74 |
23 | 24 | [?] 25 | 28 | 29 | [?] 30 | 32 | 33 | [?] 34 | 36 | 37 | [?] 38 | 40 | 41 | [?] 42 | 44 | 45 | [?] 46 | 48 | 49 | [?] 50 | 52 | 53 | [?] 54 | 56 | 57 | [?] 59 | 60 | [?] 61 |
75 | 128 | shipping->get_shipping_classes(); 140 | if ( ! $classes ) : 141 | echo '

' . __( 'No shipping classes exist - you can ignore this option :)', 'woocommerce-table-rate-shipping' ) . '

'; 142 | else : 143 | $priority = get_option( 'woocommerce_table_rate_default_priority_' . $shipping_method_id ) != '' ? get_option( 'woocommerce_table_rate_default_priority_' . $shipping_method_id ) : 10; 144 | ?> 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | slug ] ) ) ? $woocommerce_table_rate_priorities[ $class->slug ] : 10; 168 | 169 | echo ''; 170 | } 171 | ?> 172 | 173 |
155 | searched for all shipping classes. If all product shipping classes are identical, the corresponding class will be used.
If there are a mix of classes then the class with the lowest number priority (defined above) will be used.', 'woocommerce-table-rate-shipping' ); // WPCS: xss ok. ?>
156 |
' . esc_html( $class->name ) . '
174 | query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_ship_%')" ); 189 | 190 | // Save class priorities 191 | if ( empty( $_POST['woocommerce_table_rate_calculation_type'] ) ) { 192 | 193 | if ( isset( $_POST['woocommerce_table_rate_priorities'] ) ) { 194 | $priorities = array_map( 'intval', (array) $_POST['woocommerce_table_rate_priorities'] ); 195 | update_option( 'woocommerce_table_rate_priorities_' . $shipping_method_id, $priorities ); 196 | } 197 | 198 | if ( isset( $_POST['woocommerce_table_rate_default_priority'] ) ) { 199 | update_option( 'woocommerce_table_rate_default_priority_' . $shipping_method_id, (int) esc_attr( $_POST['woocommerce_table_rate_default_priority'] ) ); 200 | } 201 | } else { 202 | delete_option( 'woocommerce_table_rate_priorities_' . $shipping_method_id ); 203 | delete_option( 'woocommerce_table_rate_default_priority_' . $shipping_method_id ); 204 | } 205 | 206 | if ( function_exists( 'wc_get_rounding_precision' ) ) { 207 | $precision = wc_get_rounding_precision(); 208 | } else { 209 | $precision = 4; 210 | } 211 | 212 | // Save rates 213 | $rate_ids = isset( $_POST['rate_id'] ) ? array_map( 'intval', $_POST['rate_id'] ) : array(); 214 | $shipping_class = isset( $_POST['shipping_class'] ) ? array_map( 'wc_clean', $_POST['shipping_class'] ) : array(); 215 | $shipping_condition = isset( $_POST['shipping_condition'] ) ? array_map( 'wc_clean', $_POST['shipping_condition'] ) : array(); 216 | $shipping_min = isset( $_POST['shipping_min'] ) ? array_map( 'wc_clean', $_POST['shipping_min'] ) : array(); 217 | $shipping_max = isset( $_POST['shipping_max'] ) ? array_map( 'wc_clean', $_POST['shipping_max'] ) : array(); 218 | $shipping_cost = isset( $_POST['shipping_cost'] ) ? array_map( 'wc_clean', $_POST['shipping_cost'] ) : array(); 219 | $shipping_per_item = isset( $_POST['shipping_per_item'] ) ? array_map( 'wc_clean', $_POST['shipping_per_item'] ) : array(); 220 | $shipping_cost_per_weight = isset( $_POST['shipping_cost_per_weight'] ) ? array_map( 'wc_clean', $_POST['shipping_cost_per_weight'] ) : array(); 221 | $cost_percent = isset( $_POST['shipping_cost_percent'] ) ? array_map( 'wc_clean', $_POST['shipping_cost_percent'] ) : array(); 222 | $shipping_label = isset( $_POST['shipping_label'] ) ? array_map( 'wc_clean', $_POST['shipping_label'] ) : array(); 223 | $shipping_priority = isset( $_POST['shipping_priority'] ) ? array_map( 'wc_clean', $_POST['shipping_priority'] ) : array(); 224 | $shipping_abort = isset( $_POST['shipping_abort'] ) ? array_map( 'wc_clean', $_POST['shipping_abort'] ) : array(); 225 | $shipping_abort_reason = isset( $_POST['shipping_abort_reason'] ) ? array_map( 'wc_clean', $_POST['shipping_abort_reason'] ) : array(); 226 | 227 | // Get max key 228 | $max_key = ( $rate_ids ) ? max( array_keys( $rate_ids ) ) : 0; 229 | 230 | for ( $i = 0; $i <= $max_key; $i++ ) { 231 | 232 | if ( ! isset( $rate_ids[ $i ] ) ) { 233 | continue; 234 | } 235 | 236 | $rate_id = $rate_ids[ $i ]; 237 | $rate_class = isset( $shipping_class[ $i ] ) ? $shipping_class[ $i ] : ''; 238 | $rate_condition = $shipping_condition[ $i ]; 239 | $rate_min = isset( $shipping_min[ $i ] ) ? $shipping_min[ $i ] : ''; 240 | $rate_max = isset( $shipping_max[ $i ] ) ? $shipping_max[ $i ] : ''; 241 | $rate_cost = isset( $shipping_cost[ $i ] ) ? wc_format_decimal( $shipping_cost[ $i ], $precision, true ) : ''; 242 | $rate_cost_per_item = isset( $shipping_per_item[ $i ] ) ? wc_format_decimal( $shipping_per_item[ $i ], $precision, true ) : ''; 243 | $rate_cost_per_weight_unit = isset( $shipping_cost_per_weight[ $i ] ) ? wc_format_decimal( $shipping_cost_per_weight[ $i ], $precision, true ) : ''; 244 | $rate_cost_percent = isset( $cost_percent[ $i ] ) ? wc_format_decimal( str_replace( '%', '', $cost_percent[ $i ] ), $precision, true ) : ''; 245 | $rate_label = isset( $shipping_label[ $i ] ) ? $shipping_label[ $i ] : ''; 246 | $rate_priority = isset( $shipping_priority[ $i ] ) ? 1 : 0; 247 | $rate_abort = isset( $shipping_abort[ $i ] ) ? 1 : 0; 248 | $rate_abort_reason = isset( $shipping_abort_reason[ $i ] ) ? $shipping_abort_reason[ $i ] : ''; 249 | 250 | // Format min and max 251 | switch ( $rate_condition ) { 252 | case 'weight': 253 | case 'price': 254 | if ( $rate_min ) { 255 | $rate_min = wc_format_decimal( $rate_min, $precision, true ); 256 | } 257 | if ( $rate_max ) { 258 | $rate_max = wc_format_decimal( $rate_max, $precision, true ); 259 | } 260 | break; 261 | case 'items': 262 | case 'items_in_class': 263 | if ( $rate_min ) { 264 | $rate_min = round( $rate_min ); 265 | } 266 | if ( $rate_max ) { 267 | $rate_max = round( $rate_max ); 268 | } 269 | break; 270 | default: 271 | $rate_min = ''; 272 | $rate_max = ''; 273 | break; 274 | } 275 | 276 | if ( $rate_id > 0 ) { 277 | 278 | // Update row 279 | $wpdb->update( 280 | $wpdb->prefix . 'woocommerce_shipping_table_rates', 281 | array( 282 | 'rate_class' => $rate_class, 283 | 'rate_condition' => sanitize_title( $rate_condition ), 284 | 'rate_min' => $rate_min, 285 | 'rate_max' => $rate_max, 286 | 'rate_cost' => $rate_cost, 287 | 'rate_cost_per_item' => $rate_cost_per_item, 288 | 'rate_cost_per_weight_unit' => $rate_cost_per_weight_unit, 289 | 'rate_cost_percent' => $rate_cost_percent, 290 | 'rate_label' => $rate_label, 291 | 'rate_priority' => $rate_priority, 292 | 'rate_order' => $i, 293 | 'shipping_method_id' => $shipping_method_id, 294 | 'rate_abort' => $rate_abort, 295 | 'rate_abort_reason' => $rate_abort_reason, 296 | ), 297 | array( 298 | 'rate_id' => $rate_id, 299 | ), 300 | array( 301 | '%s', 302 | '%s', 303 | '%s', 304 | '%s', 305 | '%s', 306 | '%s', 307 | '%s', 308 | '%s', 309 | '%s', 310 | '%s', 311 | '%d', 312 | '%d', 313 | '%d', 314 | '%s', 315 | ), 316 | array( 317 | '%d', 318 | ) 319 | ); 320 | 321 | } else { 322 | 323 | // Insert row 324 | $result = $wpdb->insert( 325 | $wpdb->prefix . 'woocommerce_shipping_table_rates', 326 | array( 327 | 'rate_class' => $rate_class, 328 | 'rate_condition' => sanitize_title( $rate_condition ), 329 | 'rate_min' => $rate_min, 330 | 'rate_max' => $rate_max, 331 | 'rate_cost' => $rate_cost, 332 | 'rate_cost_per_item' => $rate_cost_per_item, 333 | 'rate_cost_per_weight_unit' => $rate_cost_per_weight_unit, 334 | 'rate_cost_percent' => $rate_cost_percent, 335 | 'rate_label' => $rate_label, 336 | 'rate_priority' => $rate_priority, 337 | 'rate_order' => $i, 338 | 'shipping_method_id' => $shipping_method_id, 339 | 'rate_abort' => $rate_abort, 340 | 'rate_abort_reason' => $rate_abort_reason, 341 | ), 342 | array( 343 | '%s', 344 | '%s', 345 | '%s', 346 | '%s', 347 | '%s', 348 | '%s', 349 | '%s', 350 | '%s', 351 | '%s', 352 | '%s', 353 | '%d', 354 | '%d', 355 | '%d', 356 | '%s', 357 | ) 358 | ); 359 | } 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /includes/functions-ajax.php: -------------------------------------------------------------------------------- 1 | query( "DELETE FROM {$wpdb->prefix}woocommerce_shipping_table_rates WHERE rate_id IN (" . implode( ',', $rate_ids ) . ")" ); 23 | } 24 | 25 | die(); 26 | } 27 | -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/assets/css/shipping_zones.css: -------------------------------------------------------------------------------- 1 | .method_type_selector{display:inline-block;top:-2px;position:relative}.method_type_selector select{font-size:13px!important;margin:0 0 0 1em;vertical-align:middle;font-family:sans-serif;display:inline-block}.method_type_selector .add-new-h2{vertical-align:middle;margin-left:0;top:0;color:#21759b;cursor:pointer}#add-zone #zone_name{width:95%}#add-zone input{width:auto}#add-zone p{margin-top:0}#add-zone div{margin-bottom:.5em}#add-zone div label{margin-top:.5em}#add-zone label img.help_tip{margin:0 0 0 5px;position:relative;line-height:12px;vertical-align:top}#add-zone .chzn-container{width:95%!important;margin:9px 0 0}#add-zone .chzn-container .chzn-drop{width:100%!important;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#add-zone .chzn-container .search-field input{width:150px!important}#add-zone .button{margin-right:4px}table.shippingzones{position:relative}table.shippingzones td{vertical-align:top;padding:7px;line-height:1.4em;overflow:hidden;cursor:move}table.shippingzones tr:last-child td{cursor:default}table.shippingzones #zone_name{width:30%}table.shippingzones .column-enabled{width:80px}table.shippingzones .column-zone_type{width:30%}table.shippingzones .column-enabled{text-align:center}table.shippingzones th.check-column{padding-top:8px;padding-bottom:0}.woocommerce .form-wrap p{font-style:normal}.zone_type_options{padding-left:26px}.wc-col-container{padding:0;margin:0}.wc-col-container .wc-col-right{float:right;clear:right;width:65%;padding:0;margin:0}.wc-col-container .wc-col-left{width:35%;padding:0;margin:0}.wc-col-container .wc-col-wrap{padding:0 7px}.wc-col-container .wc-col-wrap p{width:95%}.wc-col-container:after{content:".";display:block;height:0;clear:both;visibility:hidden} -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/assets/css/shipping_zones.less: -------------------------------------------------------------------------------- 1 | 2 | .method_type_selector { 3 | display: inline-block; 4 | top: -2px; 5 | position: relative; 6 | select { 7 | font-size: 13px !important; 8 | margin: 0 0 0 1em; 9 | vertical-align: middle; 10 | font-family: sans-serif; 11 | display: inline-block; 12 | } 13 | .add-new-h2 { 14 | vertical-align: middle; 15 | margin-left: 0; 16 | top:0; 17 | color: #21759b; 18 | cursor: pointer; 19 | } 20 | } 21 | #add-zone { 22 | #zone_name { 23 | width: 95%; 24 | } 25 | input { 26 | width: auto; 27 | } 28 | p { 29 | margin-top: 0; 30 | } 31 | div { 32 | margin-bottom: .5em; 33 | 34 | label { 35 | margin-top: .5em; 36 | } 37 | } 38 | label { 39 | img.help_tip { 40 | margin: 0 0 0 5px; 41 | position: relative; 42 | line-height: 12px; 43 | vertical-align: top; 44 | } 45 | } 46 | .chzn-container { 47 | width: 95% !important; 48 | margin: 9px 0 0; 49 | .chzn-drop { 50 | width: 100% !important; 51 | -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ 52 | -moz-box-sizing: border-box; /* Firefox, other Gecko */ 53 | box-sizing: border-box; /* Opera/IE 8+ */ 54 | } 55 | .search-field input { 56 | width: 150px !important; 57 | } 58 | } 59 | .button { 60 | margin-right: 4px; 61 | } 62 | } 63 | table.shippingzones { 64 | position: relative; 65 | td { 66 | vertical-align: top; 67 | padding: 7px 7px; 68 | line-height: 1.4em; 69 | overflow: hidden; 70 | cursor: move; 71 | } 72 | tr:last-child { 73 | td { 74 | cursor:default; 75 | } 76 | } 77 | #zone_name { 78 | width: 30%; 79 | } 80 | .column-enabled { 81 | width: 80px; 82 | } 83 | .column-zone_type { 84 | width: 30%; 85 | } 86 | .column-enabled { 87 | text-align: center; 88 | } 89 | th.check-column { 90 | padding-top: 8px; 91 | padding-bottom: 0; 92 | } 93 | } 94 | .woocommerce { 95 | .form-wrap { 96 | p { 97 | font-style: normal; 98 | } 99 | } 100 | } 101 | .zone_type_options { 102 | padding-left: 26px; 103 | } 104 | .wc-col-container { 105 | padding: 0; 106 | margin: 0; 107 | 108 | .wc-col-right { 109 | float: right; 110 | clear: right; 111 | width: 65%; 112 | padding: 0; 113 | margin: 0; 114 | } 115 | .wc-col-left { 116 | width: 35%; 117 | padding: 0; 118 | margin: 0; 119 | } 120 | .wc-col-wrap { 121 | padding: 0 7px; 122 | p { 123 | width: 95%; 124 | } 125 | } 126 | } 127 | .wc-col-container:after { 128 | content: "."; 129 | display: block; 130 | height: 0; 131 | clear: both; 132 | visibility: hidden; 133 | } -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/assets/js/shipping-zone-admin.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | 3 | if ( ! wc_shipping_zones_params.supports_select2 ) { 4 | $("select.chosen_select").chosen(); 5 | } 6 | 7 | $('body') 8 | 9 | .on( 'click', 'a.shipping-zone-delete', function(){ 10 | var answer = confirm( $(this).data('message') ); 11 | if ( answer ) { 12 | return true; 13 | } else { 14 | return false; 15 | } 16 | }) 17 | 18 | .on( 'change', 'input[name=zone_type]', function() { 19 | if ( $(this).is(':checked') ) { 20 | var value = $(this).val(); 21 | $( '.zone_type_options' ).slideUp(); 22 | $( '.zone_type_' + value ).slideDown(); 23 | } 24 | }) 25 | 26 | .on( 'click', '.select_us_states', function(){ 27 | $(this).closest('div').find('option[value="US:AK"], option[value="US:AL"], option[value="US:AZ"], option[value="US:AR"], option[value="US:CA"], option[value="US:CO"], option[value="US:CT"], option[value="US:DE"], option[value="US:DC"], option[value="US:FL"], option[value="US:GA"], option[value="US:HI"], option[value="US:ID"], option[value="US:IL"], option[value="US:IN"], option[value="US:IA"], option[value="US:KS"], option[value="US:KY"], option[value="US:LA"], option[value="US:ME"], option[value="US:MD"], option[value="US:MA"], option[value="US:MI"], option[value="US:MN"], option[value="US:MS"], option[value="US:MO"], option[value="US:MT"], option[value="US:NE"], option[value="US:NV"], option[value="US:NH"], option[value="US:NJ"], option[value="US:NM"], option[value="US:NY"], option[value="US:NC"], option[value="US:ND"], option[value="US:OH"], option[value="US:OK"], option[value="US:OR"], option[value="US:PA"], option[value="US:RI"], option[value="US:SC"], option[value="US:SD"], option[value="US:TN"], option[value="US:TX"], option[value="US:UT"], option[value="US:VT"], option[value="US:VA"], option[value="US:WA"], option[value="US:WV"], option[value="US:WI"], option[value="US:WY"]').attr("selected","selected"); 28 | $(this).closest('div').find('select').trigger('chosen:updated').change(); 29 | return false; 30 | }) 31 | 32 | .on( 'click', '.select_europe', function(){ 33 | $(this).closest('div').find('option[value="AL"], option[value="AD"], option[value="AM"], option[value="AT"], option[value="BY"], option[value="BE"], option[value="BA"], option[value="BG"], option[value="CH"], option[value="CY"], option[value="CZ"], option[value="DE"], option[value="DK"], option[value="EE"], option[value="ES"], option[value="FO"], option[value="FI"], option[value="FR"], option[value="GB"], option[value="GE"], option[value="GI"], option[value="GR"], option[value="HU"], option[value="HR"], option[value="IE"], option[value="IS"], option[value="IT"], option[value="LT"], option[value="LU"], option[value="LV"], option[value="MC"], option[value="MK"], option[value="MT"], option[value="NO"], option[value="NL"], option[value="PO"], option[value="PT"], option[value="RO"], option[value="RU"], option[value="SE"], option[value="SI"], option[value="SK"], option[value="SM"], option[value="TR"], option[value="UA"], option[value="VA"]').attr("selected","selected"); 34 | $(this).closest('div').find('select').trigger('chosen:updated').change(); 35 | return false; 36 | }) 37 | 38 | .on( 'click', '.select_none', function(){ 39 | $(this).closest('div').find('select option').removeAttr("selected"); 40 | $(this).closest('div').find('select').trigger('chosen:updated').change(); 41 | return false; 42 | }) 43 | 44 | .on( 'click', '.select_all', function(){ 45 | $(this).closest('div').find('select option').attr("selected","selected"); 46 | $(this).closest('div').find('select').trigger('chosen:updated').change(); 47 | return false; 48 | }); 49 | 50 | // Sorting 51 | $('table.shippingzones tbody').sortable({ 52 | items:'tr:not(:last-child)', 53 | cursor:'move', 54 | axis:'y', 55 | handle: 'td', 56 | scrollSensitivity:40, 57 | helper:function(e,ui){ 58 | ui.children().each(function(){ 59 | $(this).width($(this).width()); 60 | }); 61 | ui.css('left', '0'); 62 | return ui; 63 | }, 64 | start:function(event,ui){ 65 | ui.item.css('background-color','#f6f6f6'); 66 | }, 67 | stop:function(event,ui){ 68 | ui.item.removeAttr('style'); 69 | }, 70 | update: function(event, ui) { 71 | $('table.shippingzones tbody td').css('cursor','default'); 72 | $('table.shippingzones tbody').sortable('disable'); 73 | 74 | // show spinner 75 | ui.item.find('.check-column input').hide(); 76 | ui.item.find('.check-column').append('processing'); 77 | 78 | // Parent 79 | var zone_ids = []; 80 | 81 | $(this).closest('form').find('input.zone_id').each(function(){ 82 | var zone_id = $(this).val(); 83 | zone_ids.push(zone_id); 84 | }); 85 | 86 | // go do the sorting stuff via ajax 87 | $.post( ajaxurl, { action: 'woocommerce_zone_ordering', security: wc_shipping_zones_params.shipping_zones_nonce, zone_ids: zone_ids }, function(response) { 88 | ui.item.find('.check-column input').show(); 89 | ui.item.find('.check-column').find('img').remove(); 90 | $('table.shippingzones tbody td').css('cursor','move'); 91 | $('table.shippingzones tbody').sortable('enable'); 92 | 93 | }); 94 | 95 | // fix cell colors 96 | $('table.shippingzones tbody tr').each(function(){ 97 | var i = $('table.shippingzones tbody tr').index(this); 98 | if ( i%2 == 0 ) $(this).addClass('alternate'); 99 | else $(this).removeClass('alternate'); 100 | }); 101 | } 102 | }); 103 | 104 | $('.zone_type_options').hide(); 105 | $('input[name=zone_type]').change(); 106 | }); 107 | -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/class-wc-shipping-zones.php: -------------------------------------------------------------------------------- 1 | wp_create_nonce( 'shipping-zones' ), 60 | 'supports_select2' => version_compare( WC_VERSION, '2.3', '>' ) ? 1 : 0 61 | ) 62 | ); 63 | 64 | if ( version_compare( WC_VERSION, '2.3', '<' ) ) { 65 | wp_enqueue_script( 'woocommerce_admin' ); 66 | wp_enqueue_script( 'jquery-ui-sortable' ); 67 | wp_enqueue_script( 'chosen' ); 68 | } 69 | 70 | do_action( 'woocommerce_shipping_zones_css' ); 71 | } 72 | } 73 | 74 | WC_Shipping_Zones::init(); 75 | -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/class-wc-shipping-zone-admin.php: -------------------------------------------------------------------------------- 1 | exists() ) { 21 | echo '

' . sprintf( __( 'Invalid shipping zone. Back to zones.', SHIPPING_ZONES_TEXTDOMAIN ), esc_url( remove_query_arg( 'zone' ) ) ) . '

'; 22 | return; 23 | } 24 | 25 | self::add_method( $zone ); 26 | self::delete_method( $zone ); 27 | 28 | if ( ! empty( $_GET['method'] )) { 29 | self::method_settings( $zone, absint( $_GET['method'] ) ); 30 | return; 31 | } else { 32 | include( 'views/html-zone-methods.php' ); 33 | } 34 | } 35 | 36 | /** 37 | * Add shipping method to zone 38 | */ 39 | public static function add_method( $zone ) { 40 | if ( ! empty( $_GET['add_method'] ) && ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce_add_method' ) ) { 41 | $type = wc_clean( $_GET['method_type'] ); 42 | 43 | if ( $type && ( $method_id = $zone->add_shipping_method( $type ) ) ) { 44 | echo '

' . sprintf( __( 'Shipping method successfully created. View method.', SHIPPING_ZONES_TEXTDOMAIN ), esc_url( add_query_arg( 'method', $method_id, add_query_arg( 'zone', $zone->zone_id, admin_url( 'admin.php?page=shipping_zones' ) ) ) ) ) . '

'; 45 | } else { 46 | echo '

' . __( 'Invalid shipping method', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * Delete shipping method from zone. 53 | */ 54 | public static function delete_method( $zone ) { 55 | if ( ! empty( $_GET['delete_method'] ) && ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce_delete_method' ) ) { 56 | $method_id = absint( $_GET['delete_method'] ); 57 | 58 | if ( $zone->delete_shipping_method( $method_id ) ) { 59 | echo '

' . __( 'Shipping method successfully deleted', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * list_shipping_zone_methods function. 66 | */ 67 | public static function list_shipping_zone_methods() { 68 | if ( ! class_exists( 'WC_Shipping_Zone_Methods_Table' ) ) { 69 | require_once( 'list-tables/class-wc-shipping-zone-methods-table.php' ); 70 | } 71 | echo '
'; 72 | $WC_Shipping_Zone_Methods_Table = new WC_Shipping_Zone_Methods_Table(); 73 | $WC_Shipping_Zone_Methods_Table->prepare_items(); 74 | $WC_Shipping_Zone_Methods_Table->display(); 75 | echo '
'; 76 | } 77 | 78 | /** 79 | * Show settings for a method 80 | */ 81 | public static function method_settings( $zone, $method_id ) { 82 | global $wpdb; 83 | 84 | // Get method 85 | $method = $wpdb->get_row( $wpdb->prepare( " 86 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods WHERE shipping_method_id = %s 87 | ", $method_id ) ); 88 | 89 | $callback = 'woocommerce_get_shipping_method_' . $method->shipping_method_type; 90 | 91 | if ( ! function_exists( $callback ) ) { 92 | return; 93 | } 94 | 95 | // Construct method instance 96 | $shipping_method = $callback( $method_id ); 97 | 98 | if ( ! empty( $_POST['save_method'] ) ) { 99 | 100 | if ( empty( $_POST['woocommerce_save_method_nonce'] ) || ! wp_verify_nonce( $_POST['woocommerce_save_method_nonce'], 'woocommerce_save_method' )) { 101 | echo '

' . __( 'Edit failed. Please try again.', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 102 | 103 | } elseif ( $shipping_method->process_instance_options() ) { 104 | 105 | // re-init so we re-load settings 106 | unset( $shipping_method ); 107 | $shipping_method = $callback( $method_id ); 108 | 109 | echo '

' . __( 'Shipping method saved successfully.', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 110 | } 111 | } 112 | 113 | include( 'views/html-zone-method-settings.php' ); 114 | } 115 | } -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/class-wc-shipping-zone.php: -------------------------------------------------------------------------------- 1 | zone_id = $zone_id; 27 | $this->init(); 28 | $this->find_shipping_methods(); 29 | } 30 | 31 | /** 32 | * Does this zone exist? 33 | * @return bool 34 | */ 35 | public function exists() { 36 | return $this->exists; 37 | } 38 | 39 | /** 40 | * Register zone shipping methods for use. 41 | */ 42 | public function register_shipping_methods() { 43 | foreach ( $this->shipping_methods as $shipping_method ) { 44 | if ( is_callable( $shipping_method['callback'] ) ) { 45 | $method = call_user_func( $shipping_method['callback'], $shipping_method['number'] ); 46 | 47 | if ( $method->enabled == 'yes' ) { 48 | WC()->shipping->register_shipping_method( $method ); 49 | } 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * Add a shipping method to this zone. 56 | * @param string $type 57 | * @return int 58 | */ 59 | public function add_shipping_method( $type ) { 60 | global $wpdb; 61 | 62 | if ( ! $type ) { 63 | return 0; 64 | } 65 | 66 | $wpdb->insert( 67 | $wpdb->prefix . 'woocommerce_shipping_zone_shipping_methods', 68 | array( 69 | 'shipping_method_type' => $type, 70 | 'zone_id' => $this->zone_id, 71 | 'shipping_method_order' => 0 72 | ), 73 | array( 74 | '%s', 75 | '%d', 76 | '%d' 77 | ) 78 | ); 79 | 80 | return $wpdb->insert_id; 81 | } 82 | 83 | 84 | /** 85 | * Delete a shipping method belonging to this zone. 86 | * @param int $id 87 | */ 88 | public function delete_shipping_method( $id ) { 89 | global $wpdb; 90 | 91 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_shipping_methods', array( 'shipping_method_id' => $id ) ); 92 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_table_rates', array( 'shipping_method_id' => $id ) ); 93 | 94 | delete_option( 'woocommerce_table_rate_priorities_' . $id ); 95 | delete_option( 'woocommerce_table_rate_default_priority_' . $id ); 96 | } 97 | 98 | /** 99 | * Init the zone data 100 | */ 101 | private function init() { 102 | if ( $this->zone_id > 0 ) { 103 | global $wpdb; 104 | 105 | $zone = $wpdb->get_row( $wpdb->prepare( " 106 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zones 107 | WHERE zone_id = %d LIMIT 1 108 | ", $this->zone_id ) ); 109 | 110 | if ( $zone ) { 111 | $this->zone_name = $zone->zone_name; 112 | $this->zone_enabled = $zone->zone_enabled; 113 | $this->zone_type = $zone->zone_type; 114 | $this->zone_order = $zone->zone_order; 115 | $this->exists = true; 116 | } 117 | } else { 118 | $this->zone_name = __( 'Everywhere else', SHIPPING_ZONES_TEXTDOMAIN ); 119 | $this->zone_enabled = 1; 120 | $this->zone_type = ''; 121 | $this->zone_order = ''; 122 | $this->exists = true; 123 | } 124 | } 125 | 126 | /** 127 | * Find shipping methods for this zone. 128 | */ 129 | private function find_shipping_methods() { 130 | global $wpdb; 131 | 132 | $zone_methods = $wpdb->get_results( $wpdb->prepare( " 133 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods 134 | WHERE zone_id = %s 135 | ORDER BY shipping_method_order ASC 136 | ", $this->zone_id ) ); 137 | 138 | foreach ( $zone_methods as $method ) { 139 | $this->shipping_methods[] = array( 140 | 'number' => $method->shipping_method_id, // Instance number for the method 141 | 'callback' => 'woocommerce_get_shipping_method_' . $method->shipping_method_type // Callback function to init the method class 142 | ); 143 | } 144 | } 145 | } -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php: -------------------------------------------------------------------------------- 1 | shipping(); 17 | } 18 | if ( ! empty( $_GET['edit_zone'] ) ) { 19 | self::edit_zone_screen(); 20 | } elseif ( isset( $_GET['zone'] ) ) { 21 | include_once( 'class-wc-shipping-zone-admin.php' ); 22 | WC_Shipping_Zone_Admin::view_zone_screen(); 23 | } else { 24 | self::list_zones_screen(); 25 | } 26 | } 27 | 28 | /** 29 | * Save zone after editing 30 | */ 31 | private static function save_zone( $zone_id = 0 ) { 32 | global $wpdb; 33 | 34 | $editing = ! empty( $zone_id ); 35 | 36 | if ( ! empty( $_POST['add_zone'] ) || ! empty( $_POST['edit_zone'] ) ) { 37 | 38 | if ( empty( $_POST['woocommerce_save_zone_nonce'] ) || ! wp_verify_nonce( $_POST['woocommerce_save_zone_nonce'], 'woocommerce_save_zone' ) ) { 39 | echo '

' . __( 'Could not save zone. Please try again.', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 40 | return; 41 | } 42 | 43 | $fields = array( 44 | 'zone_name', 45 | 'zone_type', 46 | 'zone_enabled', 47 | 'zone_type_countries', 48 | 'zone_type_states', 49 | 'zone_type_postcodes', 50 | 'postcodes' 51 | ); 52 | 53 | $zone_count = $wpdb->get_var( "SELECT COUNT( zone_id ) FROM {$wpdb->prefix}woocommerce_shipping_zones" ); 54 | $data = array(); 55 | 56 | foreach ( $fields as $field ) { 57 | $data[ $field ] = empty( $_POST[ $field ] ) ? '' : $_POST[ $field ]; 58 | 59 | if ( 'postcodes' === $field ) { 60 | $data[ $field ] = array_map( 'strtoupper', array_map( 'wc_clean', explode( "\n", $data[ $field ] ) ) ); 61 | } else { 62 | $data[ $field ] = is_array( $data[ $field ] ) ? array_map( 'wc_clean', $data[ $field ] ) : wc_clean( $data[ $field ] ); 63 | } 64 | } 65 | 66 | // If name is left blank... 67 | if ( empty( $data['zone_name'] ) ) { 68 | if ( $editing ) { 69 | echo '

' . __( 'Zone name is required', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 70 | return; 71 | } else { 72 | $data['zone_name'] = __( 'Zone', SHIPPING_ZONES_TEXTDOMAIN ) . ' ' . ( $zone_count + 1 ); 73 | } 74 | } 75 | 76 | // Check required fields 77 | if ( empty( $data['zone_type'] ) ) { 78 | echo '

' . __(' Zone type is required', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 79 | return; 80 | } 81 | 82 | $data['zone_enabled'] = ( $data['zone_enabled'] || ! $editing ) ? 1 : 0; 83 | 84 | // Determine field we are saving 85 | $locations_field = 'zone_type_' . $data['zone_type']; 86 | 87 | // Get the countries into a nicely formatted array 88 | if ( ! $data[ $locations_field ] ) { 89 | $data[ $locations_field ] = array(); 90 | } 91 | 92 | if ( is_array( $data[ $locations_field ] ) ) { 93 | $data[ $locations_field ] = array_filter( array_map( 'strtoupper', array_map( 'sanitize_text_field', $data[ $locations_field ] ) ) ); 94 | } else { 95 | $data[ $locations_field ] = array( strtoupper( sanitize_text_field( $data[ $locations_field ] ) ) ); 96 | } 97 | 98 | // Any set? 99 | if ( sizeof( $data[ $locations_field ] ) == 0 ) { 100 | echo '

' . __('You must choose at least 1 country to add a zone.', SHIPPING_ZONES_TEXTDOMAIN) . '

'; 101 | return; 102 | } 103 | 104 | // If dealing with a postcode, grab that field too 105 | if ( $data['zone_type'] == 'postcodes' ) { 106 | 107 | $data['postcodes'] = array_filter( array_unique( $data['postcodes'] ) ); 108 | 109 | if ( sizeof( $data['postcodes'] ) == 0 ) { 110 | echo '

' . __('You must choose at least 1 postcode to add postcode zone.', SHIPPING_ZONES_TEXTDOMAIN) . '

'; 111 | return; 112 | } 113 | 114 | } else { 115 | $data['postcodes'] = array(); 116 | } 117 | 118 | if ( $editing ) { 119 | $wpdb->update( 120 | $wpdb->prefix . 'woocommerce_shipping_zones', 121 | array( 122 | 'zone_name' => $data['zone_name'], 123 | 'zone_enabled' => $data['zone_enabled'], 124 | 'zone_type' => $data['zone_type'], 125 | ), 126 | array( 127 | 'zone_id' => $zone_id 128 | ) 129 | ); 130 | } else { 131 | $wpdb->insert( 132 | $wpdb->prefix . 'woocommerce_shipping_zones', 133 | array( 134 | 'zone_name' => $data['zone_name'], 135 | 'zone_enabled' => $data['zone_enabled'], 136 | 'zone_type' => $data['zone_type'], 137 | 'zone_order' => $zone_count + 1 138 | ), 139 | array( 140 | '%s', 141 | '%d', 142 | '%s', 143 | '%d' 144 | ) 145 | ); 146 | $zone_id = $wpdb->insert_id; 147 | } 148 | 149 | $update_locations = true; 150 | 151 | if ( $editing ) { 152 | $locations = $wpdb->get_col( $wpdb->prepare( " 153 | SELECT location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations 154 | WHERE zone_id = %d 155 | ", $zone_id ) ); 156 | 157 | $new_locations = array_merge( $data[ $locations_field ], $data['postcodes'] ); 158 | 159 | if ( array_diff( $locations, $new_locations ) || array_diff( $new_locations, $locations ) ) { 160 | $update_locations = true; 161 | } else { 162 | $update_locations = false; 163 | } 164 | } 165 | 166 | if ( $update_locations ) { 167 | if ( $zone_id > 0 ) { 168 | 169 | // Remove locations 170 | $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE zone_id = %s", $zone_id ) ); 171 | 172 | // Insert locations which apply to this zone 173 | foreach ( $data[ $locations_field ] as $code ) { 174 | if ( $code ) { 175 | $wpdb->insert( 176 | $wpdb->prefix . 'woocommerce_shipping_zone_locations', 177 | array( 178 | 'location_code' => $code, 179 | 'location_type' => strstr( $code, ':' ) ? 'state' : 'country', 180 | 'zone_id' => $zone_id, 181 | ), 182 | array( 183 | '%s', 184 | '%s', 185 | '%d' 186 | ) 187 | ); 188 | } 189 | } 190 | 191 | // Save postcodes 192 | if ( $data['zone_type'] == 'postcodes' ) { 193 | foreach ( $data['postcodes'] as $code ) { 194 | if ( $code ) { 195 | $wpdb->insert( 196 | $wpdb->prefix . 'woocommerce_shipping_zone_locations', 197 | array( 198 | 'location_code' => $code, 199 | 'location_type' => 'postcode', 200 | 'zone_id' => $zone_id, 201 | ), 202 | array( 203 | '%s', 204 | '%s', 205 | '%d' 206 | ) 207 | ); 208 | } 209 | } 210 | } 211 | 212 | } else { 213 | echo '

' . __( 'Error saving zone.', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 214 | return; 215 | } 216 | } 217 | 218 | if ( $editing ) { 219 | echo '

' . sprintf( __( 'Shipping zone saved. Back to zones.', SHIPPING_ZONES_TEXTDOMAIN ), esc_url( remove_query_arg( 'edit_zone' ) ) ) . '

'; 220 | } else { 221 | echo '

' . __( 'Shipping zone saved.', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 222 | } 223 | } 224 | } 225 | 226 | /** 227 | * Edit Zone Screen 228 | */ 229 | public static function edit_zone_screen() { 230 | $zone_id = absint( $_GET['edit_zone'] ); 231 | self::save_zone( $zone_id ); 232 | self::edit_zone( $zone_id ); 233 | } 234 | 235 | /** 236 | * list_zone_page function. 237 | */ 238 | public static function list_zones_screen() { 239 | self::save_zone(); 240 | include( 'views/html-zone-list.php' ); 241 | } 242 | 243 | /** 244 | * Edit zone form 245 | */ 246 | private static function edit_zone( $zone_id ) { 247 | global $wpdb; 248 | 249 | $countries = WC()->countries->get_allowed_countries(); 250 | $base = WC()->countries->get_base_country(); 251 | 252 | // Load details to edit 253 | $zone = $wpdb->get_row( $wpdb->prepare( " 254 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zones 255 | WHERE zone_id = %d LIMIT 1 256 | ", $zone_id ) ); 257 | 258 | $location_counties = $wpdb->get_col( $wpdb->prepare( " 259 | SELECT location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations 260 | WHERE zone_id = %d AND location_type = 'country' 261 | ", $zone_id ) ); 262 | 263 | $location_states = $wpdb->get_col( $wpdb->prepare( " 264 | SELECT location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations 265 | WHERE zone_id = %d AND location_type = 'state' 266 | ", $zone_id ) ); 267 | 268 | $location_postcodes = $wpdb->get_col( $wpdb->prepare( " 269 | SELECT location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations 270 | WHERE zone_id = %d AND location_type = 'postcode' 271 | ", $zone_id ) ); 272 | 273 | $selected_states = array_merge( $location_states, $location_counties ); 274 | 275 | include( 'views/form-edit-shipping-zone.php' ); 276 | } 277 | 278 | /** 279 | * list_shipping_zones function. 280 | * 281 | * @access public 282 | * @return void 283 | */ 284 | public static function list_shipping_zones() { 285 | if ( ! class_exists( 'WC_Shipping_Zones_Table' ) ) { 286 | require_once( 'list-tables/class-wc-shipping-zones-table.php' ); 287 | } 288 | 289 | echo '
'; 290 | $WC_Shipping_Zones_Table = new WC_Shipping_Zones_Table(); 291 | $WC_Shipping_Zones_Table->prepare_items(); 292 | $WC_Shipping_Zones_Table->display(); 293 | echo '
'; 294 | } 295 | 296 | /** 297 | * add_shipping_zone_form function. 298 | */ 299 | public static function add_shipping_zone_form() { 300 | global $wpdb; 301 | 302 | $countries = WC()->countries->get_allowed_countries(); 303 | $base = WC()->countries->get_base_country(); 304 | $zone_count = $wpdb->get_var( "SELECT COUNT( zone_id ) FROM {$wpdb->prefix}woocommerce_shipping_zones;" ); 305 | 306 | include( 'views/form-add-shipping-zone.php' ); 307 | } 308 | } -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/class-wc-shipping-zones-ajax-handler.php: -------------------------------------------------------------------------------- 1 | $zone ) { 29 | 30 | if ( $zone > 0 ) { 31 | 32 | $wpdb->update( 33 | $wpdb->prefix . 'woocommerce_shipping_zones', 34 | array( 35 | 'zone_order' => $i, 36 | ), 37 | array( 'zone_id' => $zone ), 38 | array( '%d' ), 39 | array( '%d' ) 40 | ); 41 | } 42 | } 43 | 44 | die(); 45 | } 46 | 47 | public static function shipping_method_ordering() { 48 | check_ajax_referer( 'shipping-zones', 'security' ); 49 | 50 | global $wpdb; 51 | 52 | $shipping_method_id = isset( $_POST['shipping_method_id'] ) ? absint( $_POST['shipping_method_id'] ) : false; 53 | $prev_shipping_method_id = isset( $_POST['prev_shipping_method_id'] ) ? absint( $_POST['prev_shipping_method_id'] ) : false; 54 | $next_shipping_method_id = isset( $_POST['next_shipping_method_id'] ) ? absint( $_POST['next_shipping_method_id'] ) : false; 55 | 56 | if ( ! $shipping_method_id ) 57 | die( -1 ); 58 | 59 | $zone_id = absint( $wpdb->get_var( "SELECT zone_id FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods WHERE shipping_method_id = " . $shipping_method_id ) ); 60 | 61 | $siblings = $wpdb->get_results(" 62 | SELECT shipping_method_id, shipping_method_order FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods 63 | WHERE zone_id = " . $zone_id . " 64 | AND shipping_method_id NOT IN (" . $shipping_method_id . ") 65 | ORDER BY shipping_method_order ASC 66 | "); 67 | 68 | $new_positions = array(); // store new positions for ajax 69 | $menu_order = 0; 70 | 71 | foreach( $siblings as $sibling ) { 72 | 73 | // if this is the post that comes after our repositioned post, set our repositioned post position and increment menu order 74 | if ( $next_shipping_method_id && $next_shipping_method_id == $sibling->shipping_method_id ) { 75 | $wpdb->update( 76 | $wpdb->prefix . "woocommerce_shipping_zone_shipping_methods", 77 | array( 78 | 'shipping_method_order' => $menu_order 79 | ), 80 | array( 'shipping_method_id' => $shipping_method_id ), 81 | array( '%d' ), 82 | array( '%d' ) 83 | ); 84 | $new_positions[ $shipping_method_id ] = $menu_order; 85 | $menu_order++; 86 | } 87 | 88 | // if repositioned post has been set, and new items are already in the right order, we can stop 89 | if ( isset( $new_positions[ $shipping_method_id ] ) && $sibling->shipping_method_order >= $menu_order ) 90 | break; 91 | 92 | // set the menu order of the current sibling and increment the menu order 93 | $wpdb->update( 94 | $wpdb->prefix . "woocommerce_shipping_zone_shipping_methods", 95 | array( 96 | 'shipping_method_order' => $menu_order 97 | ), 98 | array( 'shipping_method_id' => $sibling->shipping_method_id ), 99 | array( '%d' ), 100 | array( '%d' ) 101 | ); 102 | $new_positions[ $sibling->shipping_method_id ] = $menu_order; 103 | $menu_order++; 104 | 105 | if ( ! $next_shipping_method_id && $prev_shipping_method_id == $sibling->shipping_method_id ) { 106 | $wpdb->update( 107 | $wpdb->prefix . "woocommerce_shipping_zone_shipping_methods", 108 | array( 109 | 'shipping_method_order' => $menu_order 110 | ), 111 | array( 'shipping_method_id' => $shipping_method_id ), 112 | array( '%d' ), 113 | array( '%d' ) 114 | ); 115 | $new_positions[ $shipping_method_id ] = $menu_order; 116 | $menu_order++; 117 | } 118 | } 119 | 120 | die(); 121 | } 122 | } 123 | 124 | WC_Shipping_Zones_Ajax_Handler::init(); -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php: -------------------------------------------------------------------------------- 1 | zone_id = (int) $_GET['zone']; 27 | $this->index = 0; 28 | 29 | //Set parent defaults 30 | parent::__construct( array( 31 | 'singular' => 'Shipping Method', //singular name of the listed records 32 | 'plural' => 'Shipping Methods', //plural name of the listed records 33 | 'ajax' => false //does this table support ajax? 34 | ) ); 35 | 36 | wc_enqueue_js( " 37 | jQuery('table.shippingmethods tbody th, table.shippingmethods tbody td').css('cursor','move'); 38 | 39 | jQuery('table.shippingmethods tbody').sortable({ 40 | items: 'tr:not(.inline-edit-row)', 41 | cursor: 'move', 42 | axis: 'y', 43 | containment: 'table.shippingmethods', 44 | scrollSensitivity: 40, 45 | helper: function(e, ui) { 46 | ui.children().each(function() { jQuery(this).width(jQuery(this).width()); }); 47 | return ui; 48 | }, 49 | start: function(event, ui) { 50 | if ( ! ui.item.hasClass('alternate') ) ui.item.css( 'background-color', '#ffffff' ); 51 | ui.item.children('td,th').css('border-bottom-width','0'); 52 | ui.item.css( 'outline', '1px solid #dfdfdf' ); 53 | }, 54 | stop: function(event, ui) { 55 | ui.item.removeAttr('style'); 56 | ui.item.children('td,th').css('border-bottom-width','1px'); 57 | }, 58 | update: function(event, ui) { 59 | jQuery('table.shippingmethods tbody th, table.shippingmethods tbody td').css('cursor','default'); 60 | jQuery('table.shippingmethods tbody').sortable('disable'); 61 | 62 | var shipping_method_id = ui.item.find('.check-column input').val(); 63 | var prev_shipping_method_id = ui.item.prev().find('.check-column input').val(); 64 | var next_shipping_method_id = ui.item.next().find('.check-column input').val(); 65 | 66 | // show spinner 67 | ui.item.find('.check-column input').hide().after('\"processing\"'); 68 | 69 | // go do the sorting stuff via ajax 70 | jQuery.post( ajaxurl, { action: 'woocommerce_shipping_method_ordering', security: '" . wp_create_nonce( 'shipping-zones' ) . "', shipping_method_id: shipping_method_id, prev_shipping_method_id: prev_shipping_method_id, next_shipping_method_id: next_shipping_method_id }, function(response) { 71 | ui.item.find('.check-column input').show().siblings('img').remove(); 72 | jQuery('table.shippingmethods tbody th, table.shippingmethods tbody td').css('cursor','move'); 73 | jQuery('table.shippingmethods tbody').sortable('enable'); 74 | }); 75 | 76 | // fix cell colors 77 | jQuery( 'table.shippingmethods tbody tr' ).each(function(){ 78 | var i = jQuery('table.shippingmethods tbody tr').index(this); 79 | if ( i%2 == 0 ) jQuery(this).addClass('alternate'); 80 | else jQuery(this).removeClass('alternate'); 81 | }); 82 | } 83 | }); 84 | 85 | " ); 86 | } 87 | 88 | /** 89 | * Checkbox column 90 | * @param string 91 | */ 92 | public function column_cb( $item ){ 93 | return sprintf( 94 | '', 95 | 'shipping_method_id', 96 | $item->instance_id 97 | ); 98 | } 99 | 100 | /** 101 | * Output the title column. 102 | * @param object $item 103 | * @return string 104 | */ 105 | public function column_title( $item ) { 106 | $title = $item->title; 107 | 108 | if ( ! $title ) { 109 | $title = ucwords( $item->method_title ); 110 | } 111 | 112 | return ' 113 | ' . esc_html( $title ) . ' 114 |
115 | ID: ' . esc_html( $item->instance_id ) . ' | ' . __( 'Edit' , SHIPPING_ZONES_TEXTDOMAIN ) . ' | ' . __( 'Delete', SHIPPING_ZONES_TEXTDOMAIN ) . ' 116 |
'; 117 | } 118 | 119 | /** 120 | * Output the type column. 121 | * @param object $item 122 | * @return string 123 | */ 124 | public function column_type( $item ) { 125 | return esc_html( $item->method_title ); 126 | } 127 | 128 | /** 129 | * Output the enabled column. 130 | * @param object $item 131 | * @return string 132 | */ 133 | public function column_enabled( $item ) { 134 | return 'yes' === $item->enabled ? '✔' : '–'; 135 | } 136 | 137 | /** 138 | * get_columns function. 139 | * @return array 140 | */ 141 | public function get_columns(){ 142 | $columns = array( 143 | 'cb' => '', 144 | 'title' => __( 'Method Title', SHIPPING_ZONES_TEXTDOMAIN ), 145 | 'type' => __( 'Method Type', SHIPPING_ZONES_TEXTDOMAIN ), 146 | 'enabled' => __( 'Enabled', SHIPPING_ZONES_TEXTDOMAIN ), 147 | ); 148 | return $columns; 149 | } 150 | 151 | /** 152 | * Get bulk actions 153 | */ 154 | public function get_bulk_actions() { 155 | $actions = array( 156 | 'delete' => __('Delete', SHIPPING_ZONES_TEXTDOMAIN) 157 | ); 158 | return $actions; 159 | } 160 | 161 | /** 162 | * Process bulk actions 163 | */ 164 | public function process_bulk_action() { 165 | global $wpdb; 166 | 167 | if ( ! isset( $_POST['shipping_method_id'] ) ) { 168 | return; 169 | } 170 | 171 | $items = array_filter( array_map( 'absint', $_POST['shipping_method_id'] ) ); 172 | 173 | if ( ! $items ) { 174 | return; 175 | } 176 | 177 | if ( 'delete' === $this->current_action() ) { 178 | foreach ( $items as $id ) { 179 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_shipping_methods', array( 'shipping_method_id' => $id ) ); 180 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_table_rates', array( 'shipping_method_id' => $id ) ); 181 | delete_option( 'woocommerce_table_rate_priorities_' . $id ); 182 | delete_option( 'woocommerce_table_rate_default_priority_' . $id ); 183 | } 184 | 185 | echo '

' . __( 'Shipping methods deleted', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 186 | } 187 | } 188 | 189 | /** 190 | * Message to be displayed when there are no items 191 | */ 192 | public function no_items() { 193 | echo '

' . __( 'No shipping methods found.', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 194 | } 195 | 196 | /** 197 | * Get shipping methods to display for this zone. 198 | */ 199 | public function prepare_items() { 200 | global $wpdb; 201 | 202 | $this->_column_headers = array( $this->get_columns(), array(), array() ); 203 | $this->process_bulk_action(); 204 | 205 | $shipping_methods = $wpdb->get_results( $wpdb->prepare( " 206 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods 207 | WHERE zone_id = %s 208 | ORDER BY `shipping_method_order` ASC 209 | ", $this->zone_id ) ); 210 | 211 | foreach ( $shipping_methods as $method ) { 212 | $class_callback = 'woocommerce_get_shipping_method_' . $method->shipping_method_type; 213 | 214 | if ( function_exists( $class_callback ) ) { 215 | $this->items[] = call_user_func( $class_callback, $method->shipping_method_id ); 216 | } 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php: -------------------------------------------------------------------------------- 1 | 'Shipping Zone', 25 | 'plural' => 'Shipping Zones', 26 | 'ajax' => false 27 | ) ); 28 | } 29 | 30 | /** 31 | * Output the zone name column. 32 | * @param object $item 33 | * @return string 34 | */ 35 | public function column_zone_name( $item ) { 36 | $zone_name = ' 37 | 38 | ' . esc_html( $item->zone_name ) . ' 39 | 40 | 41 |
'; 42 | 43 | if ( $item->zone_id > 0 ) { 44 | $zone_name .= '' . __( 'Edit', SHIPPING_ZONES_TEXTDOMAIN ) . ' | ' . __( 'Configure shipping methods', SHIPPING_ZONES_TEXTDOMAIN ) . ''; 45 | } else { 46 | $zone_name .= '' . __( 'Configure shipping methods', SHIPPING_ZONES_TEXTDOMAIN ) . ''; 47 | } 48 | $zone_name .= '
'; 49 | return $zone_name; 50 | } 51 | 52 | /** 53 | * Output the zone type column. 54 | * @param object $item 55 | * @return string 56 | */ 57 | public function column_zone_type( $item ) { 58 | global $wpdb; 59 | 60 | if ( $item->zone_id == 0 ) { 61 | return __( 'Everywhere', SHIPPING_ZONES_TEXTDOMAIN ); 62 | } 63 | 64 | $locations = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE zone_id = %s;", $item->zone_id ) ); 65 | 66 | $count = sizeof( $locations ); 67 | 68 | if ( 'postcodes' === $item->zone_type ) { 69 | $count = $count - 1; 70 | } 71 | 72 | $locations_prepend = ""; 73 | $locations_append = ""; 74 | $locations_list = array(); 75 | 76 | foreach ( $locations as $location ) { 77 | if ( sizeof( $locations_list ) >= 8 ) { 78 | $locations_append = ' ' . sprintf( __( 'and %s others', SHIPPING_ZONES_TEXTDOMAIN ), ( $count - 8 ) ); 79 | break; 80 | } 81 | switch ( $location->location_type ) { 82 | case "country" : 83 | case "state" : 84 | 85 | if ( strstr( $location->location_code, ':' ) ) { 86 | $split_code = explode( ':', $location->location_code ); 87 | if ( ! isset( WC()->countries->states[ $split_code[0] ][ $split_code[1] ] ) ) { 88 | continue; 89 | } 90 | $location_name = WC()->countries->states[ $split_code[0] ][ $split_code[1] ]; 91 | } else { 92 | if ( ! isset( WC()->countries->countries[ $location->location_code ] ) ) { 93 | continue; 94 | } 95 | $location_name = WC()->countries->countries[ $location->location_code ]; 96 | } 97 | 98 | if ( $item->zone_type == 'postcodes' ) { 99 | $locations_prepend = sprintf( __( 'Within %s:', SHIPPING_ZONES_TEXTDOMAIN ), $location_name ) . ' '; 100 | } else { 101 | $locations_list[] = $location_name; 102 | } 103 | break; 104 | case "postcode" : 105 | $locations_list[] = $location->location_code; 106 | } 107 | } 108 | 109 | switch ( $item->zone_type ) { 110 | case "countries" : 111 | return '' . __( 'Countries', SHIPPING_ZONES_TEXTDOMAIN ) . '
' . $locations_prepend . implode( ', ', $locations_list ) . $locations_append; 112 | case "states" : 113 | return '' . __( 'Countries and states', SHIPPING_ZONES_TEXTDOMAIN ) . '
' . $locations_prepend . implode( ', ', $locations_list ) . $locations_append; 114 | case "postcodes" : 115 | return '' . __( 'Postcodes', SHIPPING_ZONES_TEXTDOMAIN ) . '
' . $locations_prepend . implode( ', ', $locations_list ) . $locations_append; 116 | } 117 | } 118 | 119 | /** 120 | * Output the zone enabled column. 121 | * @param object $item 122 | * @return string 123 | */ 124 | public function column_enabled( $item ) { 125 | return $item->zone_enabled ? '✔' : '–'; 126 | } 127 | 128 | /** 129 | * Output the zone methods column. 130 | * @param object $item 131 | * @return string 132 | */ 133 | public function column_methods( $item ) { 134 | global $wpdb; 135 | 136 | $output_methods = array(); 137 | 138 | $shipping_methods = $wpdb->get_results( $wpdb->prepare( " 139 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods 140 | WHERE zone_id = %s 141 | ORDER BY `shipping_method_order` ASC 142 | ", $item->zone_id ) ); 143 | 144 | if ( $shipping_methods ) { 145 | foreach ( $shipping_methods as $method ) { 146 | $class_callback = 'woocommerce_get_shipping_method_' . $method->shipping_method_type; 147 | 148 | if ( function_exists( $class_callback ) ) { 149 | $this_method = call_user_func( $class_callback, $method->shipping_method_id ); 150 | $output_methods[] = '' . esc_html( $this_method->title ? $this_method->title : $this_method->id ) . ''; 151 | } 152 | } 153 | 154 | return implode( ', ', $output_methods ); 155 | } else { 156 | return __( 'None', SHIPPING_ZONES_TEXTDOMAIN ); 157 | } 158 | } 159 | 160 | /** 161 | * Checkbox column 162 | * @param string 163 | */ 164 | public function column_cb( $item ) { 165 | if ( ! $item->zone_id ) { 166 | return; 167 | } 168 | return sprintf( 169 | '', 170 | 'zone_id_cb', 171 | $item->zone_id 172 | ); 173 | } 174 | 175 | /** 176 | * get_columns function. 177 | * @return array 178 | */ 179 | public function get_columns(){ 180 | return array( 181 | 'cb' => '', 182 | 'zone_name' => __( 'Zone name', SHIPPING_ZONES_TEXTDOMAIN ), 183 | 'zone_type' => __( 'Zone type', SHIPPING_ZONES_TEXTDOMAIN ), 184 | 'enabled' => __( 'Enabled', SHIPPING_ZONES_TEXTDOMAIN ), 185 | 'methods' => __( 'Shipping Methods', SHIPPING_ZONES_TEXTDOMAIN ) 186 | ); 187 | } 188 | 189 | /** 190 | * Get bulk actions 191 | */ 192 | public function get_bulk_actions() { 193 | $actions = array( 194 | 'disable' => __('Disable', SHIPPING_ZONES_TEXTDOMAIN), 195 | 'enable' => __('Enable', SHIPPING_ZONES_TEXTDOMAIN), 196 | '' => '------', 197 | 'delete' => __('Delete', SHIPPING_ZONES_TEXTDOMAIN) 198 | ); 199 | return $actions; 200 | } 201 | 202 | /** 203 | * Process bulk actions 204 | */ 205 | public function process_bulk_action() { 206 | global $wpdb; 207 | 208 | if ( ! isset( $_POST['zone_id_cb'] ) ) { 209 | return; 210 | } 211 | 212 | $items = array_filter( array_map( 'absint', $_POST['zone_id_cb'] ) ); 213 | 214 | if ( ! $items ) { 215 | return; 216 | } 217 | 218 | if ( 'delete' === $this->current_action() ) { 219 | 220 | foreach ( $items as $id ) { 221 | $methods = $wpdb->get_col( $wpdb->prepare( "SELECT shipping_method_id FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods WHERE zone_id = %d", $id ) ); 222 | 223 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_locations', array( 'zone_id' => $id ) ); 224 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zones', array( 'zone_id' => $id ) ); 225 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_shipping_methods', array( 'zone_id' => $id ) ); 226 | 227 | foreach ( $methods as $method ) { 228 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_table_rates', array( 'shipping_method_id' => $method ) ); 229 | delete_option( 'woocommerce_table_rate_priorities_' . $method ); 230 | delete_option( 'woocommerce_table_rate_default_priority_' . $method ); 231 | } 232 | } 233 | 234 | echo '

' . __( 'Shipping zones deleted', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 235 | 236 | } elseif ( 'enable' === $this->current_action() ) { 237 | 238 | foreach ( $items as $id ) { 239 | $wpdb->update( 240 | $wpdb->prefix . 'woocommerce_shipping_zones', 241 | array( 242 | 'zone_enabled' => 1 243 | ), 244 | array( 'zone_id' => $id ), 245 | array( '%d' ), 246 | array( '%d' ) 247 | ); 248 | } 249 | 250 | echo '

' . __( 'Shipping zones enabled', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 251 | 252 | } elseif ( 'disable' === $this->current_action() ) { 253 | 254 | foreach ( $items as $id ) { 255 | $wpdb->update( 256 | $wpdb->prefix . 'woocommerce_shipping_zones', 257 | array( 258 | 'zone_enabled' => 0 259 | ), 260 | array( 'zone_id' => $id ), 261 | array( '%d' ), 262 | array( '%d' ) 263 | ); 264 | } 265 | 266 | echo '

' . __( 'Shipping zones disabled', SHIPPING_ZONES_TEXTDOMAIN ) . '

'; 267 | } 268 | 269 | } 270 | 271 | /** 272 | * Get Zones to display 273 | */ 274 | public function prepare_items() { 275 | global $wpdb; 276 | 277 | $this->_column_headers = array( $this->get_columns(), array(), array() ); 278 | $this->process_bulk_action(); 279 | 280 | $this->items = $wpdb->get_results( " 281 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zones 282 | ORDER BY zone_order ASC 283 | " ); 284 | 285 | $default = new stdClass(); 286 | $default->zone_id = 0; 287 | $default->zone_name = __( 'Default Zone (everywhere else)', SHIPPING_ZONES_TEXTDOMAIN ); 288 | $default->zone_type = __( 'All countries', SHIPPING_ZONES_TEXTDOMAIN ); 289 | $default->zone_enabled = 1; 290 | $this->items[] = $default; 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | 7 |
8 |
9 |
10 | 11 | 12 |
13 |
14 | 15 |
16 | 17 | 18 |

19 | 20 |
21 | 28 |

29 |
30 | 31 |

32 | 33 |
34 | 47 |

48 |
49 | 50 |

51 | 52 |
53 | 66 | 67 | 68 | 69 | 70 |
71 | 72 |
73 |
74 |

75 | 76 |
77 |
78 | -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php: -------------------------------------------------------------------------------- 1 |
2 |

zone_name ) ?>


3 |
4 |
5 | 6 | 7 | 10 | 13 | 14 | 15 | 18 | 21 | 22 | 23 | 26 | 92 | 93 |
8 | 9 | 11 | 12 |
16 | 17 | 19 | 20 |
24 | 25 | 27 |
28 | 29 | 30 |

31 | 32 |
33 | 40 |

41 |
42 | 43 |

44 | 45 |
46 | 59 |

60 |
61 | 62 |

63 | 64 |
65 | 79 | 80 |

81 | 82 | 87 |

88 |
89 | 90 |
91 |
94 |

95 | 96 | 97 |

98 |
99 |
100 |
101 | -------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/views/html-zone-list.php: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 |
5 |
6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |
-------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/views/html-zone-method-settings.php: -------------------------------------------------------------------------------- 1 |
2 |

3 |

> zone_name ?> > title; ?>


4 |
5 | instance_options(); ?> 6 |

7 | 8 |
9 |
-------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/views/html-zone-methods.php: -------------------------------------------------------------------------------- 1 |
2 |

3 | > zone_name ) ?> 4 |
5 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |

25 | 26 |
-------------------------------------------------------------------------------- /includes/legacy/shipping-zones/includes/wc-shipping-zone-functions.php: -------------------------------------------------------------------------------- 1 | get_results( " 28 | SELECT * FROM {$wpdb->prefix}woocommerce_shipping_zone_locations 29 | WHERE location_type = 'postcode' AND location_code LIKE '%-%' 30 | " ); 31 | 32 | if ( $postcode_ranges ) { 33 | $encoded_postcode = wc_make_numeric_postcode( $postcode ); 34 | $encoded_postcode_len = strlen( $encoded_postcode ); 35 | 36 | foreach ( $postcode_ranges as $postcode_range ) { 37 | $range = array_map( 'trim', explode( '-', $postcode_range->location_code ) ); 38 | 39 | if ( sizeof( $range ) != 2 ) { 40 | continue; 41 | } 42 | 43 | if ( is_numeric( $range[0] ) && is_numeric( $range[1] ) ) { 44 | $encoded_postcode = $postcode; 45 | $min = $range[0]; 46 | $max = $range[1]; 47 | } else { 48 | $min = wc_make_numeric_postcode( $range[0] ); 49 | $max = wc_make_numeric_postcode( $range[1] ); 50 | $min = str_pad( $min, $encoded_postcode_len, '0' ); 51 | $max = str_pad( $max, $encoded_postcode_len, '9' ); 52 | } 53 | 54 | if ( $encoded_postcode >= $min && $encoded_postcode <= $max ) { 55 | $valid_zone_ids[] = $postcode_range->zone_id; 56 | } 57 | } 58 | } 59 | } 60 | 61 | // Escape 62 | $country = esc_sql( $package['destination']['country'] ); 63 | $state = esc_sql( $country . ':' . $package['destination']['state'] ); 64 | $valid_postcodes = array_map( 'esc_sql', $valid_postcodes ); 65 | $valid_zone_ids = array_map( 'esc_sql', $valid_zone_ids ); 66 | 67 | // Get matching zones 68 | $matching_zone_sql = " 69 | SELECT zones.zone_id FROM {$wpdb->prefix}woocommerce_shipping_zones as zones 70 | LEFT JOIN {$wpdb->prefix}woocommerce_shipping_zone_locations as locations ON zones.zone_id = locations.zone_id 71 | WHERE 72 | ( 73 | ( 74 | zone_type = 'countries' 75 | AND location_type = 'country' 76 | AND location_code = '{$country}' 77 | ) 78 | OR 79 | ( 80 | zone_type = 'states' 81 | AND 82 | ( 83 | ( location_type = 'state' AND location_code = '{$state}' ) 84 | OR 85 | ( location_type = 'country' AND location_code = '{$country}' ) 86 | ) 87 | ) 88 | OR 89 | ( 90 | zone_type = 'postcodes' 91 | AND 92 | ( 93 | ( location_type = 'state' AND location_code = '{$state}' ) 94 | OR 95 | ( location_type = 'country' AND location_code = '{$country}' ) 96 | ) 97 | AND 98 | ( 99 | zones.zone_id IN ( 100 | SELECT zone_id FROM {$wpdb->prefix}woocommerce_shipping_zone_locations 101 | WHERE location_type = 'postcode' 102 | AND location_code IN ('" . implode( "','", $valid_postcodes ) . "') 103 | ) 104 | OR zones.zone_id IN ('" . implode( "','", $valid_zone_ids ) . "') 105 | ) 106 | ) 107 | ) 108 | AND zone_enabled = 1 109 | ORDER BY zone_order ASC 110 | LIMIT 1 111 | "; 112 | 113 | $matching_zone = $wpdb->get_var( $matching_zone_sql ); 114 | 115 | return new WC_Shipping_Zone( $matching_zone ? $matching_zone : 0 ); 116 | } 117 | 118 | /** 119 | * make_numeric_postcode function. 120 | * 121 | * Converts letters to numbers so we can do a simple range check on postcodes. 122 | * 123 | * E.g. PE30 becomes 16050300 (P = 16, E = 05, 3 = 03, 0 = 00) 124 | * 125 | * @access public 126 | * @param mixed $postcode 127 | * @return void 128 | */ 129 | function wc_make_numeric_postcode( $postcode ) { 130 | $postcode_length = strlen( $postcode ); 131 | $letters_to_numbers = array_merge( array( 0 ), range( 'A', 'Z' ) ); 132 | $letters_to_numbers = array_flip( $letters_to_numbers ); 133 | $numeric_postcode = ''; 134 | 135 | for ( $i = 0; $i < $postcode_length; $i ++ ) { 136 | if ( is_numeric( $postcode[ $i ] ) ) { 137 | $numeric_postcode .= str_pad( $postcode[ $i ], 2, '0', STR_PAD_LEFT ); 138 | } elseif ( isset( $letters_to_numbers[ $postcode[ $i ] ] ) ) { 139 | $numeric_postcode .= str_pad( $letters_to_numbers[ $postcode[ $i ] ], 2, '0', STR_PAD_LEFT ); 140 | } else { 141 | $numeric_postcode .= '00'; 142 | } 143 | } 144 | 145 | return $numeric_postcode; 146 | } 147 | 148 | /** 149 | * Alias for wc_get_shipping_zone 150 | */ 151 | function woocommerce_make_numeric_postcode( $postcode ) { 152 | return wc_make_numeric_postcode( $postcode ); 153 | } 154 | 155 | /** 156 | * Alias for wc_get_shipping_zone 157 | */ 158 | function woocommerce_get_shipping_zone( $package ) { 159 | return wc_get_shipping_zone( $package ); 160 | } 161 | -------------------------------------------------------------------------------- /installer.php: -------------------------------------------------------------------------------- 1 | hide_errors(); 9 | 10 | $collate = ''; 11 | 12 | if ( $wpdb->has_cap( 'collation' ) ) { 13 | $collate = $wpdb->get_charset_collate(); 14 | } 15 | 16 | require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); 17 | 18 | // Table for storing table rates themselves. shipping_method_id is an individual table of rates applied to a zone 19 | $sql = " 20 | CREATE TABLE {$wpdb->prefix}woocommerce_shipping_table_rates ( 21 | rate_id bigint(20) NOT NULL auto_increment, 22 | rate_class varchar(200) NOT NULL, 23 | rate_condition varchar(200) NOT NULL, 24 | rate_min varchar(200) NOT NULL, 25 | rate_max varchar(200) NOT NULL, 26 | rate_cost varchar(200) NOT NULL, 27 | rate_cost_per_item varchar(200) NOT NULL, 28 | rate_cost_per_weight_unit varchar(200) NOT NULL, 29 | rate_cost_percent varchar(200) NOT NULL, 30 | rate_label longtext NULL, 31 | rate_priority int(1) NOT NULL, 32 | rate_order bigint(20) NOT NULL, 33 | shipping_method_id bigint(20) NOT NULL, 34 | rate_abort int(1) NOT NULL, 35 | rate_abort_reason longtext NULL, 36 | PRIMARY KEY (rate_id) 37 | ) $collate; 38 | "; 39 | dbDelta( $sql ); 40 | 41 | if ( version_compare( WC_VERSION, '2.6.0', '<' ) ) { 42 | // Table for storing shipping zones 43 | $sql = " 44 | CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zones ( 45 | zone_id bigint(20) NOT NULL auto_increment, 46 | zone_name varchar(255) NOT NULL, 47 | zone_enabled int(1) NOT NULL DEFAULT 1, 48 | zone_type varchar(40) NOT NULL DEFAULT '', 49 | zone_order bigint(20) NOT NULL, 50 | PRIMARY KEY (zone_id) 51 | ) $collate; 52 | "; 53 | dbDelta( $sql ); 54 | 55 | // Table for storing a shipping zones locations which it applies to. Type can be postcode, state, or country. 56 | $sql = " 57 | CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations ( 58 | location_id bigint(20) NOT NULL auto_increment, 59 | location_code varchar(255) NOT NULL, 60 | zone_id bigint(20) NOT NULL, 61 | location_type varchar(40) NOT NULL, 62 | PRIMARY KEY (location_id) 63 | ) $collate; 64 | "; 65 | dbDelta( $sql ); 66 | 67 | // Table for storing shipping zones individial shipping methods and their options 68 | $sql = " 69 | CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods ( 70 | shipping_method_id bigint(20) NOT NULL auto_increment, 71 | shipping_method_type varchar(255) NOT NULL, 72 | zone_id bigint(20) NOT NULL, 73 | shipping_method_order bigint(20) NOT NULL default 0, 74 | PRIMARY KEY (shipping_method_id) 75 | ) $collate; 76 | "; 77 | dbDelta( $sql ); 78 | } 79 | 80 | update_option( 'hide_table_rate_welcome_notice', '' ); 81 | -------------------------------------------------------------------------------- /languages/woocommerce-table-rate-shipping.pot: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2020 WooCommerce 2 | # This file is distributed under the GNU General Public License v3.0. 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: WooCommerce Table Rate Shipping 3.0.29\n" 6 | "Report-Msgid-Bugs-To: " 7 | "https://wordpress.org/support/plugin/woocommerce-table-rate-shipping\n" 8 | "POT-Creation-Date: 2020-08-19 17:32:21+00:00\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=utf-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "X-Generator: node-wp-i18n 1.2.3\n" 16 | 17 | #: includes/functions-admin.php:112 includes/functions-admin.php:115 18 | #: includes/functions-admin.php:118 includes/functions-admin.php:121 19 | msgid "0" 20 | msgstr "" 21 | 22 | #: includes/class-wc-shipping-table-rate-privacy.php:12 23 | #: includes/class-wc-shipping-table-rate.php:30 24 | msgid "Table rates" 25 | msgstr "" 26 | 27 | #: includes/class-wc-shipping-table-rate-privacy.php:20 28 | msgid "" 29 | "By using this extension, you may be storing personal data or sharing data " 30 | "with an external service. Learn more about " 31 | "how this works, including what you may want to include in your privacy " 32 | "policy." 33 | msgstr "" 34 | 35 | #: includes/class-wc-shipping-table-rate.php:31 36 | msgid "Table rates are dynamic rates based on a number of cart conditions." 37 | msgstr "" 38 | 39 | #: includes/class-wc-shipping-table-rate.php:41 40 | #: includes/class-wc-shipping-table-rate.php:170 41 | msgid "Table Rate" 42 | msgstr "" 43 | 44 | #: includes/class-wc-shipping-table-rate.php:166 45 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:144 46 | msgid "Method Title" 47 | msgstr "" 48 | 49 | #: includes/class-wc-shipping-table-rate.php:169 50 | msgid "This controls the title which the user sees during checkout." 51 | msgstr "" 52 | 53 | #: includes/class-wc-shipping-table-rate.php:173 54 | msgid "Tax Status" 55 | msgstr "" 56 | 57 | #: includes/class-wc-shipping-table-rate.php:179 58 | msgid "Taxable" 59 | msgstr "" 60 | 61 | #: includes/class-wc-shipping-table-rate.php:180 62 | #: includes/functions-admin.php:94 63 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:156 64 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:28 65 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:47 66 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:40 67 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:59 68 | msgid "None" 69 | msgstr "" 70 | 71 | #: includes/class-wc-shipping-table-rate.php:184 72 | msgid "Tax included in shipping costs" 73 | msgstr "" 74 | 75 | #: includes/class-wc-shipping-table-rate.php:191 76 | msgid "Yes, I will enter costs below inclusive of tax" 77 | msgstr "" 78 | 79 | #: includes/class-wc-shipping-table-rate.php:192 80 | msgid "No, I will enter costs below exclusive of tax" 81 | msgstr "" 82 | 83 | #: includes/class-wc-shipping-table-rate.php:196 84 | msgid "Handling Fee" 85 | msgstr "" 86 | 87 | #: includes/class-wc-shipping-table-rate.php:198 88 | msgid "" 89 | "Enter an amount, e.g. 2.50. Leave blank to disable. This cost is applied " 90 | "once for the order as a whole." 91 | msgstr "" 92 | 93 | #: includes/class-wc-shipping-table-rate.php:200 94 | #: includes/class-wc-shipping-table-rate.php:210 95 | #: includes/class-wc-shipping-table-rate.php:236 96 | #: includes/class-wc-shipping-table-rate.php:244 97 | #: includes/class-wc-shipping-table-rate.php:252 98 | #: includes/functions-admin.php:104 99 | msgid "n/a" 100 | msgstr "" 101 | 102 | #: includes/class-wc-shipping-table-rate.php:206 103 | msgid "Maximum Shipping Cost" 104 | msgstr "" 105 | 106 | #: includes/class-wc-shipping-table-rate.php:208 107 | msgid "" 108 | "Maximum cost that the customer will pay after all the shipping rules have " 109 | "been applied. If the shipping cost calculated is bigger than this value, " 110 | "this cost will be the one shown." 111 | msgstr "" 112 | 113 | #: includes/class-wc-shipping-table-rate.php:213 114 | msgid "Rates" 115 | msgstr "" 116 | 117 | #: includes/class-wc-shipping-table-rate.php:215 118 | msgid "This is where you define your table rates which are applied to an order." 119 | msgstr "" 120 | 121 | #: includes/class-wc-shipping-table-rate.php:219 122 | msgid "Calculation Type" 123 | msgstr "" 124 | 125 | #: includes/class-wc-shipping-table-rate.php:221 126 | msgid "" 127 | "Per order rates will offer the customer all matching rates. Calculated " 128 | "rates will sum all matching rates and provide a single total." 129 | msgstr "" 130 | 131 | #: includes/class-wc-shipping-table-rate.php:225 132 | msgid "Per order" 133 | msgstr "" 134 | 135 | #: includes/class-wc-shipping-table-rate.php:226 136 | msgid "Calculated rates per item" 137 | msgstr "" 138 | 139 | #: includes/class-wc-shipping-table-rate.php:227 140 | msgid "Calculated rates per line item" 141 | msgstr "" 142 | 143 | #: includes/class-wc-shipping-table-rate.php:228 144 | msgid "Calculated rates per shipping class" 145 | msgstr "" 146 | 147 | #: includes/class-wc-shipping-table-rate.php:232 148 | msgid "Handling Fee Per [item]" 149 | msgstr "" 150 | 151 | #: includes/class-wc-shipping-table-rate.php:234 152 | msgid "" 153 | "Handling fee. Enter an amount, e.g. 2.50, or a percentage, e.g. 5%. Leave " 154 | "blank to disable. Applied based on the \"Calculation Type\" chosen below." 155 | msgstr "" 156 | 157 | #: includes/class-wc-shipping-table-rate.php:239 158 | msgid "Minimum Cost Per [item]" 159 | msgstr "" 160 | 161 | #: includes/class-wc-shipping-table-rate.php:242 162 | msgid "" 163 | "Minimum cost for this shipping method (optional). If the cost is lower, " 164 | "this minimum cost will be enforced." 165 | msgstr "" 166 | 167 | #: includes/class-wc-shipping-table-rate.php:247 168 | msgid "Maximum Cost Per [item]" 169 | msgstr "" 170 | 171 | #: includes/class-wc-shipping-table-rate.php:250 172 | msgid "" 173 | "Maximum cost for this shipping method (optional). If the cost is higher, " 174 | "this maximum cost will be enforced." 175 | msgstr "" 176 | 177 | #: includes/class-wc-shipping-table-rate.php:285 178 | msgid "Table Rates" 179 | msgstr "" 180 | 181 | #: includes/class-wc-shipping-table-rate.php:292 182 | msgid "Class Priorities" 183 | msgstr "" 184 | 185 | #: includes/functions-admin.php:23 186 | msgid "Shipping Class" 187 | msgstr "" 188 | 189 | #: includes/functions-admin.php:24 190 | msgid "Shipping class this rate applies to." 191 | msgstr "" 192 | 193 | #: includes/functions-admin.php:28 194 | msgid "Condition" 195 | msgstr "" 196 | 197 | #: includes/functions-admin.php:29 198 | msgid "Condition vs. destination" 199 | msgstr "" 200 | 201 | #: includes/functions-admin.php:32 202 | msgid "Min–Max" 203 | msgstr "" 204 | 205 | #: includes/functions-admin.php:33 206 | msgid "Bottom and top range for the selected condition. " 207 | msgstr "" 208 | 209 | #: includes/functions-admin.php:36 210 | msgid "Break" 211 | msgstr "" 212 | 213 | #: includes/functions-admin.php:37 214 | msgid "" 215 | "Break at this point. For per-order rates, no rates other than this will be " 216 | "offered. For calculated rates, this will stop any further rates being " 217 | "matched." 218 | msgstr "" 219 | 220 | #: includes/functions-admin.php:40 221 | msgid "Abort" 222 | msgstr "" 223 | 224 | #: includes/functions-admin.php:41 225 | msgid "" 226 | "Enable this option to disable all rates/this shipping method if this row " 227 | "matches any item/line/class being quoted." 228 | msgstr "" 229 | 230 | #: includes/functions-admin.php:44 231 | msgid "Row cost" 232 | msgstr "" 233 | 234 | #: includes/functions-admin.php:45 235 | msgid "Cost for shipping the order, including tax." 236 | msgstr "" 237 | 238 | #: includes/functions-admin.php:48 239 | msgid "Item cost" 240 | msgstr "" 241 | 242 | #: includes/functions-admin.php:49 243 | msgid "Cost per item, including tax." 244 | msgstr "" 245 | 246 | #: includes/functions-admin.php:52 247 | msgid "cost" 248 | msgstr "" 249 | 250 | #: includes/functions-admin.php:53 251 | msgid "Cost per weight unit." 252 | msgstr "" 253 | 254 | #: includes/functions-admin.php:56 255 | msgid "% cost" 256 | msgstr "" 257 | 258 | #: includes/functions-admin.php:57 259 | msgid "Percentage of total to charge." 260 | msgstr "" 261 | 262 | #: includes/functions-admin.php:59 263 | msgid "Label" 264 | msgstr "" 265 | 266 | #: includes/functions-admin.php:60 267 | msgid "Label for the shipping method which the user will be presented. " 268 | msgstr "" 269 | 270 | #: includes/functions-admin.php:66 271 | msgid "Add Shipping Rate" 272 | msgstr "" 273 | 274 | #: includes/functions-admin.php:67 275 | msgid "Define your table rates here in order of priority." 276 | msgstr "" 277 | 278 | #: includes/functions-admin.php:67 279 | msgid "Duplicate selected rows" 280 | msgstr "" 281 | 282 | #: includes/functions-admin.php:67 283 | msgid "Delete selected rows" 284 | msgstr "" 285 | 286 | #: includes/functions-admin.php:84 287 | msgid "Any class" 288 | msgstr "" 289 | 290 | #: includes/functions-admin.php:85 291 | msgid "No class" 292 | msgstr "" 293 | 294 | #: includes/functions-admin.php:95 295 | msgid "Price" 296 | msgstr "" 297 | 298 | #: includes/functions-admin.php:96 299 | msgid "Weight" 300 | msgstr "" 301 | 302 | #: includes/functions-admin.php:97 303 | msgid "Item count" 304 | msgstr "" 305 | 306 | #: includes/functions-admin.php:99 307 | msgid "Item count (same class)" 308 | msgstr "" 309 | 310 | #: includes/functions-admin.php:109 311 | msgid "Optional abort reason text" 312 | msgstr "" 313 | 314 | #: includes/functions-admin.php:141 315 | msgid "No shipping classes exist - you can ignore this option :)" 316 | msgstr "" 317 | 318 | #: includes/functions-admin.php:148 woocommerce-table-rate-shipping.php:189 319 | msgid "Class" 320 | msgstr "" 321 | 322 | #: includes/functions-admin.php:149 323 | msgid "Priority" 324 | msgstr "" 325 | 326 | #: includes/functions-admin.php:155 327 | msgid "" 328 | "When calculating shipping, the cart contents will be searched for " 329 | "all shipping classes. If all product shipping classes are " 330 | "identical, the corresponding class will be " 331 | "used.
If there are a mix of classes then the class " 332 | "with the lowest number priority (defined above) will be " 333 | "used." 334 | msgstr "" 335 | 336 | #: includes/functions-admin.php:161 337 | msgid "Default" 338 | msgstr "" 339 | 340 | #: includes/legacy/shipping-zones/class-wc-shipping-zones.php:35 341 | #: includes/legacy/shipping-zones/includes/views/html-zone-list.php:2 342 | #: includes/legacy/shipping-zones/includes/views/html-zone-method-settings.php:3 343 | #: includes/legacy/shipping-zones/includes/views/html-zone-methods.php:3 344 | msgid "Shipping Zones" 345 | msgstr "" 346 | 347 | #. Author of the plugin/theme 348 | msgid "WooCommerce" 349 | msgstr "" 350 | 351 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zone-admin.php:21 352 | msgid "Invalid shipping zone. Back to zones." 353 | msgstr "" 354 | 355 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zone-admin.php:44 356 | msgid "Shipping method successfully created. View method." 357 | msgstr "" 358 | 359 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zone-admin.php:46 360 | msgid "Invalid shipping method" 361 | msgstr "" 362 | 363 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zone-admin.php:59 364 | msgid "Shipping method successfully deleted" 365 | msgstr "" 366 | 367 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zone-admin.php:101 368 | msgid "Edit failed. Please try again." 369 | msgstr "" 370 | 371 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zone-admin.php:109 372 | msgid "Shipping method saved successfully." 373 | msgstr "" 374 | 375 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zone.php:118 376 | msgid "Everywhere else" 377 | msgstr "" 378 | 379 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:39 380 | msgid "Could not save zone. Please try again." 381 | msgstr "" 382 | 383 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:69 384 | msgid "Zone name is required" 385 | msgstr "" 386 | 387 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:72 388 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:11 389 | msgid "Zone" 390 | msgstr "" 391 | 392 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:78 393 | msgid " Zone type is required" 394 | msgstr "" 395 | 396 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:100 397 | msgid "You must choose at least 1 country to add a zone." 398 | msgstr "" 399 | 400 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:110 401 | msgid "You must choose at least 1 postcode to add postcode zone." 402 | msgstr "" 403 | 404 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:213 405 | msgid "Error saving zone." 406 | msgstr "" 407 | 408 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:219 409 | msgid "Shipping zone saved. Back to zones." 410 | msgstr "" 411 | 412 | #: includes/legacy/shipping-zones/includes/class-wc-shipping-zones-admin.php:221 413 | msgid "Shipping zone saved." 414 | msgstr "" 415 | 416 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:115 417 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:44 418 | msgid "Edit" 419 | msgstr "" 420 | 421 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:115 422 | msgid "Are you sure you want to delete this method?" 423 | msgstr "" 424 | 425 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:115 426 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:156 427 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:197 428 | msgid "Delete" 429 | msgstr "" 430 | 431 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:145 432 | msgid "Method Type" 433 | msgstr "" 434 | 435 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:146 436 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:184 437 | msgid "Enabled" 438 | msgstr "" 439 | 440 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:185 441 | msgid "Shipping methods deleted" 442 | msgstr "" 443 | 444 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zone-methods-table.php:193 445 | msgid "No shipping methods found." 446 | msgstr "" 447 | 448 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:44 449 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:46 450 | msgid "Configure shipping methods" 451 | msgstr "" 452 | 453 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:61 454 | msgid "Everywhere" 455 | msgstr "" 456 | 457 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:78 458 | msgid "and %s others" 459 | msgstr "" 460 | 461 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:99 462 | msgid "Within %s:" 463 | msgstr "" 464 | 465 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:111 466 | msgid "Countries" 467 | msgstr "" 468 | 469 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:113 470 | msgid "Countries and states" 471 | msgstr "" 472 | 473 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:115 474 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:67 475 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:81 476 | msgid "Postcodes" 477 | msgstr "" 478 | 479 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:182 480 | msgid "Zone name" 481 | msgstr "" 482 | 483 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:183 484 | msgid "Zone type" 485 | msgstr "" 486 | 487 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:185 488 | msgid "Shipping Methods" 489 | msgstr "" 490 | 491 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:194 492 | msgid "Disable" 493 | msgstr "" 494 | 495 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:195 496 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:16 497 | msgid "Enable" 498 | msgstr "" 499 | 500 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:234 501 | msgid "Shipping zones deleted" 502 | msgstr "" 503 | 504 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:250 505 | msgid "Shipping zones enabled" 506 | msgstr "" 507 | 508 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:266 509 | msgid "Shipping zones disabled" 510 | msgstr "" 511 | 512 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:287 513 | msgid "Default Zone (everywhere else)" 514 | msgstr "" 515 | 516 | #: includes/legacy/shipping-zones/includes/list-tables/class-wc-shipping-zones-table.php:288 517 | msgid "All countries" 518 | msgstr "" 519 | 520 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:1 521 | msgid "Add Shipping Zone" 522 | msgstr "" 523 | 524 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:3 525 | msgid "" 526 | "Zones cover multiple countries (and states) and can have shipping methods " 527 | "assigned to them. Each customer will be assigned a single matching shipping " 528 | "zone in order of priority, and if no zones apply the \"default zone\" will " 529 | "be used." 530 | msgstr "" 531 | 532 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:5 533 | msgid "" 534 | "If you wish to disable shipping for a location, add a zone and assign no " 535 | "shipping methods to it." 536 | msgstr "" 537 | 538 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:10 539 | msgid "Zone Name" 540 | msgstr "" 541 | 542 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:14 543 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:16 544 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:24 545 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:28 546 | msgid "Zone Type" 547 | msgstr "" 548 | 549 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:18 550 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:30 551 | msgid "This shipping zone is based on one or more countries" 552 | msgstr "" 553 | 554 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:21 555 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:53 556 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:33 557 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:65 558 | msgid "Choose countries…" 559 | msgstr "" 560 | 561 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:28 562 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:47 563 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:40 564 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:59 565 | msgid "All" 566 | msgstr "" 567 | 568 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:28 569 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:47 570 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:40 571 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:59 572 | msgid "EU States" 573 | msgstr "" 574 | 575 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:31 576 | msgid "This shipping zone is based on one or more states and counties" 577 | msgstr "" 578 | 579 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:34 580 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:46 581 | msgid "Choose states/counties…" 582 | msgstr "" 583 | 584 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:47 585 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:59 586 | msgid "US States" 587 | msgstr "" 588 | 589 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:50 590 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:62 591 | msgid "This shipping zone is based on one or more postcodes/zips" 592 | msgstr "" 593 | 594 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:67 595 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:81 596 | msgid "" 597 | "List 1 postcode per line. Wildcards (*) and ranges (for numeric postcodes) " 598 | "are supported." 599 | msgstr "" 600 | 601 | #: includes/legacy/shipping-zones/includes/views/form-add-shipping-zone.php:74 602 | msgid "Add shipping zone" 603 | msgstr "" 604 | 605 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:2 606 | msgid "Edit Shipping Zone" 607 | msgstr "" 608 | 609 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:8 610 | msgid "Name" 611 | msgstr "" 612 | 613 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:11 614 | msgid "Enter a name which describes this zone" 615 | msgstr "" 616 | 617 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:19 618 | msgid "Enable this zone" 619 | msgstr "" 620 | 621 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:43 622 | msgid "This shipping zone is based on one or more states/counties" 623 | msgstr "" 624 | 625 | #: includes/legacy/shipping-zones/includes/views/form-edit-shipping-zone.php:95 626 | msgid "Save changes" 627 | msgstr "" 628 | 629 | #: includes/legacy/shipping-zones/includes/views/html-zone-method-settings.php:6 630 | msgid "Save shipping method" 631 | msgstr "" 632 | 633 | #: includes/legacy/shipping-zones/includes/views/html-zone-methods.php:6 634 | msgid "Choose a shipping method…" 635 | msgstr "" 636 | 637 | #: includes/legacy/shipping-zones/includes/views/html-zone-methods.php:22 638 | msgid "Add To Zone" 639 | msgstr "" 640 | 641 | #: woocommerce-table-rate-shipping.php:146 642 | msgid "View Documentation" 643 | msgstr "" 644 | 645 | #: woocommerce-table-rate-shipping.php:146 646 | msgid "Docs" 647 | msgstr "" 648 | 649 | #: woocommerce-table-rate-shipping.php:147 650 | msgid "Visit Premium Customer Support Forum" 651 | msgstr "" 652 | 653 | #: woocommerce-table-rate-shipping.php:147 654 | msgid "Premium Support" 655 | msgstr "" 656 | 657 | #: woocommerce-table-rate-shipping.php:166 658 | msgid "Setup Zones" 659 | msgstr "" 660 | 661 | #: woocommerce-table-rate-shipping.php:166 662 | msgid "Documentation" 663 | msgstr "" 664 | 665 | #: woocommerce-table-rate-shipping.php:186 666 | msgid "Order" 667 | msgstr "" 668 | 669 | #: woocommerce-table-rate-shipping.php:187 670 | msgid "Item" 671 | msgstr "" 672 | 673 | #: woocommerce-table-rate-shipping.php:188 674 | msgid "Line Item" 675 | msgstr "" 676 | 677 | #: woocommerce-table-rate-shipping.php:190 678 | msgid "Delete the selected rates?" 679 | msgstr "" 680 | 681 | #: woocommerce-table-rate-shipping.php:191 682 | msgid "Duplicate the selected rates?" 683 | msgstr "" 684 | 685 | #: woocommerce-table-rate-shipping.php:260 686 | #. translators: %s: WooCommerce link 687 | msgid "WooCommerce Table Rate Shipping requires %s to be installed and active." 688 | msgstr "" 689 | 690 | #. Plugin Name of the plugin/theme 691 | msgid "WooCommerce Table Rate Shipping" 692 | msgstr "" 693 | 694 | #. Plugin URI of the plugin/theme 695 | msgid "https://woocommerce.com/products/table-rate-shipping/" 696 | msgstr "" 697 | 698 | #. Description of the plugin/theme 699 | msgid "" 700 | "Table rate shipping lets you define rates depending on location vs shipping " 701 | "class, price, weight, or item count." 702 | msgstr "" 703 | 704 | #. Author URI of the plugin/theme 705 | msgid "https://woocommerce.com/" 706 | msgstr "" -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 | query( "DROP TABLE IF EXISTS {$wpdb->prefix}woocommerce_shipping_table_rates" ); 9 | } 10 | -------------------------------------------------------------------------------- /woocommerce-table-rate-shipping.php: -------------------------------------------------------------------------------- 1 | no_update[ $plugin_base ] ) ) { 69 | unset( $value->no_update[ $plugin_base ] ); 70 | } 71 | 72 | return $value; 73 | } 74 | 75 | /** 76 | * Register method for usage. 77 | * 78 | * @param array $shipping_methods List of shipping methods. 79 | * @return array 80 | */ 81 | public function woocommerce_shipping_methods( $shipping_methods ) { 82 | $shipping_methods['table_rate'] = 'WC_Shipping_Table_Rate'; 83 | return $shipping_methods; 84 | } 85 | 86 | /** 87 | * Init TRS. 88 | */ 89 | public function init() { 90 | if ( ! class_exists( 'WooCommerce' ) ) { 91 | add_action( 'admin_notices', array( $this, 'woocommerce_deactivated' ) ); 92 | return; 93 | } 94 | 95 | include_once __DIR__ . '/includes/functions-ajax.php'; 96 | include_once __DIR__ . '/includes/functions-admin.php'; 97 | 98 | /** 99 | * Install check (for updates). 100 | */ 101 | if ( get_option( 'table_rate_shipping_version' ) < TABLE_RATE_SHIPPING_VERSION ) { 102 | $this->install(); 103 | } 104 | 105 | // 2.6.0+ supports zones and instances. 106 | if ( version_compare( WC_VERSION, '2.6.0', '>=' ) ) { 107 | add_filter( 'woocommerce_shipping_methods', array( $this, 'woocommerce_shipping_methods' ) ); 108 | } else { 109 | if ( ! defined( 'SHIPPING_ZONES_TEXTDOMAIN' ) ) { 110 | define( 'SHIPPING_ZONES_TEXTDOMAIN', 'woocommerce-table-rate-shipping' ); 111 | } 112 | if ( ! class_exists( 'WC_Shipping_zone' ) ) { 113 | include_once __DIR__ . '/includes/legacy/shipping-zones/class-wc-shipping-zones.php'; 114 | } 115 | add_action( 'woocommerce_load_shipping_methods', array( $this, 'load_shipping_methods' ) ); 116 | add_action( 'admin_notices', array( $this, 'welcome_notice' ) ); 117 | } 118 | 119 | // Hooks. 120 | add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); 121 | add_action( 'init', array( $this, 'load_plugin_textdomain' ) ); 122 | add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 ); 123 | add_action( 'woocommerce_shipping_init', array( $this, 'shipping_init' ) ); 124 | add_action( 'delete_product_shipping_class', array( $this, 'update_deleted_shipping_class' ) ); 125 | add_action( 'woocommerce_before_cart', array( $this, 'maybe_show_abort' ), 1 ); 126 | add_action( 'woocommerce_before_checkout_form_cart_notices', array( $this, 'maybe_show_abort' ), 20 ); 127 | } 128 | 129 | /** 130 | * Localisation. 131 | */ 132 | public function load_plugin_textdomain() { 133 | load_plugin_textdomain( 'woocommerce-table-rate-shipping', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); 134 | } 135 | 136 | /** 137 | * Row meta. 138 | * 139 | * @param array $links List of plugin links. 140 | * @param string $file Current file. 141 | * @return array 142 | */ 143 | public function plugin_row_meta( $links, $file ) { 144 | if ( plugin_basename( __FILE__ ) === $file ) { 145 | $row_meta = array( 146 | 'docs' => '' . __( 'Docs', 'woocommerce-table-rate-shipping' ) . '', 147 | 'support' => '' . __( 'Premium Support', 'woocommerce-table-rate-shipping' ) . '', 148 | ); 149 | return array_merge( $links, $row_meta ); 150 | } 151 | return (array) $links; 152 | } 153 | 154 | /** 155 | * Admin welcome notice. 156 | */ 157 | public function welcome_notice() { 158 | if ( get_option( 'hide_table_rate_welcome_notice' ) ) { 159 | return; 160 | } 161 | wp_enqueue_style( 'woocommerce-activation', WC()->plugin_url() . '/assets/css/activation.css', array(), TABLE_RATE_SHIPPING_VERSION ); 162 | ?> 163 |
164 |
165 |

Table Rates is installed – Add some shipping zones to get started :)', 'woocommerce-table-rate-shipping' ); ?>

166 |

167 |
168 |
169 | array( 186 | 'order' => __( 'Order', 'woocommerce-table-rate-shipping' ), 187 | 'item' => __( 'Item', 'woocommerce-table-rate-shipping' ), 188 | 'line_item' => __( 'Line Item', 'woocommerce-table-rate-shipping' ), 189 | 'class' => __( 'Class', 'woocommerce-table-rate-shipping' ), 190 | 'delete_rates' => __( 'Delete the selected rates?', 'woocommerce-table-rate-shipping' ), 191 | 'dupe_rates' => __( 'Duplicate the selected rates?', 'woocommerce-table-rate-shipping' ), 192 | ), 193 | 'delete_rates_nonce' => wp_create_nonce( 'delete-rate' ), 194 | ) 195 | ); 196 | } 197 | 198 | /** 199 | * Load shipping class. 200 | */ 201 | public function shipping_init() { 202 | include_once __DIR__ . '/includes/class-wc-shipping-table-rate.php'; 203 | include_once __DIR__ . '/includes/class-wc-shipping-table-rate-privacy.php'; 204 | } 205 | 206 | /** 207 | * Load shipping methods. 208 | * 209 | * @param array $package Shipping package. 210 | */ 211 | public function load_shipping_methods( $package ) { 212 | // Register the main class. 213 | woocommerce_register_shipping_method( 'WC_Shipping_Table_Rate' ); 214 | 215 | if ( ! $package ) { 216 | return; 217 | } 218 | 219 | // Get zone for package. 220 | $zone = woocommerce_get_shipping_zone( $package ); 221 | 222 | if ( TABLE_RATE_SHIPPING_DEBUG ) { 223 | $notice_text = 'Customer matched shipping zone ' . $zone->zone_name . ' (#' . $zone->zone_id . ')'; 224 | 225 | if ( ! wc_has_notice( $notice_text, 'notice' ) ) { 226 | wc_add_notice( $notice_text, 'notice' ); 227 | } 228 | } 229 | 230 | if ( $zone->exists() ) { 231 | // Register zone methods. 232 | $zone->register_shipping_methods(); 233 | } 234 | } 235 | 236 | /** 237 | * Installer. 238 | */ 239 | public function install() { 240 | include_once __DIR__ . '/installer.php'; 241 | update_option( 'table_rate_shipping_version', TABLE_RATE_SHIPPING_VERSION ); 242 | } 243 | 244 | /** 245 | * Delete table rates when deleting shipping class. 246 | * 247 | * @param int $term_id Term ID. 248 | */ 249 | public function update_deleted_shipping_class( $term_id ) { 250 | global $wpdb; 251 | 252 | $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_table_rates', array( 'rate_class' => $term_id ) ); 253 | } 254 | 255 | /** 256 | * WooCommerce Deactivated Notice. 257 | */ 258 | public function woocommerce_deactivated() { 259 | /* translators: %s: WooCommerce link */ 260 | echo '

' . sprintf( esc_html__( 'WooCommerce Table Rate Shipping requires %s to be installed and active.', 'woocommerce-table-rate-shipping' ), 'WooCommerce' ) . '

'; 261 | } 262 | 263 | /** 264 | * Show abort message when shipping methods are loaded from cache. 265 | * 266 | * @since 3.0.25 267 | * @return void 268 | */ 269 | public function maybe_show_abort() { 270 | $abort = WC()->session->get( self::$abort_key ); 271 | 272 | if ( ! is_array( $abort ) ) { 273 | return; 274 | } 275 | 276 | foreach ( $abort as $message ) { 277 | if ( ! wc_has_notice( $message ) ) { 278 | wc_add_notice( $message ); 279 | } 280 | } 281 | } 282 | 283 | } 284 | 285 | new WC_Table_Rate_Shipping(); 286 | 287 | /** 288 | * Callback function for loading an instance of this method. 289 | * 290 | * @param mixed $instance Table Rate instance. 291 | * @return WC_Shipping_Table_Rate 292 | */ 293 | function woocommerce_get_shipping_method_table_rate( $instance = false ) { 294 | return new WC_Shipping_Table_Rate( $instance ); 295 | } 296 | --------------------------------------------------------------------------------