diff --git a/assets/js/admin/meta-boxes-order.js b/assets/js/admin/meta-boxes-order.js index b322bbfa440..f5dbb56f9fe 100644 --- a/assets/js/admin/meta-boxes-order.js +++ b/assets/js/admin/meta-boxes-order.js @@ -472,13 +472,13 @@ jQuery( function ( $ ) { if ( value != null ) { wc_meta_boxes_order_items.block(); - var data = { + var data = $.extend( {}, wc_meta_boxes_order_items.get_taxable_address(), { action : 'woocommerce_add_order_fee', dataType: 'json', order_id: woocommerce_admin_meta_boxes.post_id, security: woocommerce_admin_meta_boxes.order_item_nonce, amount : value - }; + } ); $.post( woocommerce_admin_meta_boxes.ajax_url, data, function( response ) { if ( response.success ) { @@ -543,12 +543,13 @@ jQuery( function ( $ ) { wc_meta_boxes_order_items.block(); - var data = { + var data = $.extend( {}, wc_meta_boxes_order_items.get_taxable_address(), { order_id : woocommerce_admin_meta_boxes.post_id, order_item_ids: order_item_id, action : 'woocommerce_remove_order_item', security : woocommerce_admin_meta_boxes.order_item_nonce - }; + } ); + // Check if items have changed, if so pass them through so we can save them before deleting. if ( 'true' === $( 'button.cancel-action' ).attr( 'data-reload' ) ) { data.items = $( 'table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]' ).serialize(); @@ -607,39 +608,44 @@ jQuery( function ( $ ) { return false; }, + get_taxable_address: function() { + var country = ''; + var state = ''; + var postcode = ''; + var city = ''; + + if ( 'shipping' === woocommerce_admin_meta_boxes.tax_based_on ) { + country = $( '#_shipping_country' ).val(); + state = $( '#_shipping_state' ).val(); + postcode = $( '#_shipping_postcode' ).val(); + city = $( '#_shipping_city' ).val(); + } + + if ( 'billing' === woocommerce_admin_meta_boxes.tax_based_on || ! country ) { + country = $( '#_billing_country' ).val(); + state = $( '#_billing_state' ).val(); + postcode = $( '#_billing_postcode' ).val(); + city = $( '#_billing_city' ).val(); + } + + return { + country: country, + state: state, + postcode: postcode, + city: city + }; + }, + recalculate: function() { if ( window.confirm( woocommerce_admin_meta_boxes.calc_totals ) ) { wc_meta_boxes_order_items.block(); - var country = ''; - var state = ''; - var postcode = ''; - var city = ''; - - if ( 'shipping' === woocommerce_admin_meta_boxes.tax_based_on ) { - country = $( '#_shipping_country' ).val(); - state = $( '#_shipping_state' ).val(); - postcode = $( '#_shipping_postcode' ).val(); - city = $( '#_shipping_city' ).val(); - } - - if ( 'billing' === woocommerce_admin_meta_boxes.tax_based_on || ! country ) { - country = $( '#_billing_country' ).val(); - state = $( '#_billing_state' ).val(); - postcode = $( '#_billing_postcode' ).val(); - city = $( '#_billing_city' ).val(); - } - - var data = { + var data = $.extend( {}, wc_meta_boxes_order_items.get_taxable_address(), { action: 'woocommerce_calc_line_taxes', order_id: woocommerce_admin_meta_boxes.post_id, items: $( 'table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]' ).serialize(), - country: country, - state: state, - postcode: postcode, - city: city, security: woocommerce_admin_meta_boxes.calc_totals_nonce - }; + } ); $.ajax({ url: woocommerce_admin_meta_boxes.ajax_url, diff --git a/assets/js/admin/meta-boxes-order.min.js b/assets/js/admin/meta-boxes-order.min.js index 1bac279267d..234d87208c1 100644 --- a/assets/js/admin/meta-boxes-order.min.js +++ b/assets/js/admin/meta-boxes-order.min.js @@ -1 +1 @@ -jQuery(function(e){var o={states:null,init:function(){"undefined"!=typeof woocommerce_admin_meta_boxes_order&&"undefined"!=typeof woocommerce_admin_meta_boxes_order.countries&&(this.states=e.parseJSON(woocommerce_admin_meta_boxes_order.countries.replace(/"/g,'"'))),e(".js_field-country").selectWoo().change(this.change_country),e(".js_field-country").trigger("change",[!0]),e(document.body).on("change","select.js_field-state",this.change_state),e("#woocommerce-order-actions input, #woocommerce-order-actions a").click(function(){window.onbeforeunload=""}),e("a.edit_address").click(this.edit_address),e("a.billing-same-as-shipping").on("click",this.copy_billing_to_shipping),e("a.load_customer_billing").on("click",this.load_billing),e("a.load_customer_shipping").on("click",this.load_shipping),e("#customer_user").on("change",this.change_customer_user)},change_country:function(t,i){if(void 0===i&&(i=!1),null!==o.states){var a=e(this),n=a.val(),r=a.parents("div.edit_address").find(":input.js_field-state"),c=r.parent(),d=r.attr("name"),_=r.attr("id"),m=a.data("woocommerce.stickState-"+n)?a.data("woocommerce.stickState-"+n):r.val(),s=r.attr("placeholder");if(i&&a.data("woocommerce.stickState-"+n,m),c.show().find(".select2-container").remove(),e.isEmptyObject(o.states[n]))r.replaceWith('');else{var l=e(''),u=o.states[n];l.append(e('")),e.each(u,function(o){l.append(e('"))}),l.val(m),r.replaceWith(l),l.show().selectWoo().hide().change()}e(document.body).trigger("contry-change.woocommerce",[n,e(this).closest("div")]),e(document.body).trigger("country-change.woocommerce",[n,e(this).closest("div")])}},change_state:function(){var o=e(this),t=o.val(),i=o.parents("div.edit_address").find(":input.js_field-country"),a=i.val();i.data("woocommerce.stickState-"+a,t)},init_tiptip:function(){e("#tiptip_holder").removeAttr("style"),e("#tiptip_arrow").removeAttr("style"),e(".tips").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200})},edit_address:function(o){o.preventDefault();var t=e(this),i=t.closest(".order_data_column"),a=i.find("div.edit_address"),n=i.find("div.address"),r=a.find(".js_field-country"),c=a.find(".js_field-state");n.hide(),t.parent().find("a").toggle(),r.val()||r.val(woocommerce_admin_meta_boxes_order.default_country).change(),c.val()||c.val(woocommerce_admin_meta_boxes_order.default_state).change(),a.show()},change_customer_user:function(){e("#_billing_country").val()||(e("a.edit_address").click(),o.load_billing(!0),o.load_shipping(!0))},load_billing:function(o){if(!0===o||window.confirm(woocommerce_admin_meta_boxes.load_billing)){var t=e("#customer_user").val();if(!t)return window.alert(woocommerce_admin_meta_boxes.no_customer_selected),!1;var i={user_id:t,action:"woocommerce_get_customer_details",security:woocommerce_admin_meta_boxes.get_customer_details_nonce};e(this).closest("div.edit_address").block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:i,type:"POST",success:function(o){o&&o.billing&&e.each(o.billing,function(o,t){e(":input#_billing_"+o).val(t).change()}),e("div.edit_address").unblock()}})}return!1},load_shipping:function(o){if(!0===o||window.confirm(woocommerce_admin_meta_boxes.load_shipping)){var t=e("#customer_user").val();if(!t)return window.alert(woocommerce_admin_meta_boxes.no_customer_selected),!1;var i={user_id:t,action:"woocommerce_get_customer_details",security:woocommerce_admin_meta_boxes.get_customer_details_nonce};e(this).closest("div.edit_address").block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:i,type:"POST",success:function(o){o&&o.billing&&e.each(o.shipping,function(o,t){e(":input#_shipping_"+o).val(t).change()}),e("div.edit_address").unblock()}})}return!1},copy_billing_to_shipping:function(){return window.confirm(woocommerce_admin_meta_boxes.copy_billing)&&e('.order_data_column :input[name^="_billing_"]').each(function(){var o=e(this).attr("name");o=o.replace("_billing_","_shipping_"),e(":input#"+o).val(e(this).val()).change()}),!1}},t={init:function(){this.stupidtable.init(),e("#woocommerce-order-items").on("click","button.add-line-item",this.add_line_item).on("click","button.add-coupon",this.add_coupon).on("click","a.remove-coupon",this.remove_coupon).on("click","button.refund-items",this.refund_items).on("click",".cancel-action",this.cancel).on("click","button.add-order-item",this.add_item).on("click","button.add-order-fee",this.add_fee).on("click","button.add-order-shipping",this.add_shipping).on("click","button.add-order-tax",this.add_tax).on("click","button.save-action",this.save_line_items).on("click","a.delete-order-tax",this.delete_tax).on("click","button.calculate-action",this.recalculate).on("click","a.edit-order-item",this.edit_item).on("click","a.delete-order-item",this.delete_item).on("click","tr.item, tr.fee, tr.shipping, tr.refund",this.select_row).on("click","tr.item :input, tr.fee :input, tr.shipping :input, tr.refund :input, tr.item a, tr.fee a, tr.shipping a, tr.refund a",this.select_row_child).on("click","button.bulk-delete-items",this.bulk_actions.do_delete).on("click","button.bulk-increase-stock",this.bulk_actions.do_increase_stock).on("click","button.bulk-decrease-stock",this.bulk_actions.do_reduce_stock).on("click",".delete_refund",this.refunds.delete_refund).on("click","button.do-api-refund, button.do-manual-refund",this.refunds.do_refund).on("change",".refund input.refund_line_total, .refund input.refund_line_tax",this.refunds.input_changed).on("change keyup",".wc-order-refund-items #refund_amount",this.refunds.amount_changed).on("change","input.refund_order_item_qty",this.refunds.refund_quantity_changed).on("change","input.quantity",this.quantity_changed).on("keyup change",".split-input :input",function(){var o=e(this).parent().prev().find(":input");o&&(""===o.val()||o.is(".match-total"))&&o.val(e(this).val()).addClass("match-total")}).on("keyup",".split-input :input",function(){e(this).removeClass("match-total")}).on("click","button.add_order_item_meta",this.item_meta.add).on("click","button.remove_order_item_meta",this.item_meta.remove),e(document.body).on("wc_backbone_modal_loaded",this.backbone.init).on("wc_backbone_modal_response",this.backbone.response)},block:function(){e("#woocommerce-order-items").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){e("#woocommerce-order-items").unblock()},reload_items:function(){var i={order_id:woocommerce_admin_meta_boxes.post_id,action:"woocommerce_load_order_items",security:woocommerce_admin_meta_boxes.order_item_nonce};t.block(),e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:i,type:"POST",success:function(i){e("#woocommerce-order-items").find(".inside").empty(),e("#woocommerce-order-items").find(".inside").append(i),o.init_tiptip(),t.unblock(),t.stupidtable.init()}})},quantity_changed:function(){var o=e(this).closest("tr.item"),t=e(this).val(),i=e(this).attr("data-qty"),a=e("input.line_total",o),n=e("input.line_subtotal",o),r=accounting.unformat(a.attr("data-total"),woocommerce_admin.mon_decimal_point)/i;a.val(parseFloat(accounting.formatNumber(r*t,woocommerce_admin_meta_boxes.rounding_precision,"")).toString().replace(".",woocommerce_admin.mon_decimal_point));var c=accounting.unformat(n.attr("data-subtotal"),woocommerce_admin.mon_decimal_point)/i;n.val(parseFloat(accounting.formatNumber(c*t,woocommerce_admin_meta_boxes.rounding_precision,"")).toString().replace(".",woocommerce_admin.mon_decimal_point)),e("input.line_tax",o).each(function(){var a=e(this),n=a.data("tax_id"),r=accounting.unformat(a.attr("data-total_tax"),woocommerce_admin.mon_decimal_point)/i,c=e('input.line_subtotal_tax[data-tax_id="'+n+'"]',o),d=accounting.unformat(c.attr("data-subtotal_tax"),woocommerce_admin.mon_decimal_point)/i;00?e("#restock_refunded_items").closest("tr").show():(e("#restock_refunded_items").closest("tr").hide(),e(".woocommerce_order_items input.refund_order_item_qty").each(function(){e(this).val()>0&&e("#restock_refunded_items").closest("tr").show()})),e(this).trigger("refund_quantity_changed")}},item_meta:{add:function(){var o=e(this).closest("tr.item, tr.shipping"),t=o.find("tbody.meta_items"),i=t.find("tr").length+1,a='';return t.append(a),!1},remove:function(){if(window.confirm(woocommerce_admin_meta_boxes.remove_item_meta)){var o=e(this).closest("tr");o.find(":input").val(""),o.hide()}return!1}},select_row:function(){var o=!1;o=e(this).is("tr")?e(this):e(this).closest("tr");var t=e(this).closest("table");o.is(".selected")?o.removeClass("selected"):o.addClass("selected");var i=t.find("tr.selected");if(i.length){e("div.wc-order-item-bulk-edit").slideDown();var a=!1;i.each(function(){e(this).is("tr.item")&&(a=!0)}),a?e(".bulk-increase-stock, .bulk-decrease-stock").show():e(".bulk-increase-stock, .bulk-decrease-stock").hide()}else e("div.wc-order-item-bulk-edit").slideUp()},select_row_child:function(e){e.stopPropagation()},bulk_actions:{do_delete:function(o){o.preventDefault();var i=e("table.woocommerce_order_items").find("tr.selected");if(i.length&&window.confirm(woocommerce_admin_meta_boxes.remove_item_notice)){t.block();var a=[],n=[],r=[];e.map(i,function(o){var t=e(o);t.is(".refund")?n.push(parseInt(e(t).data("order_refund_id"),10)):a.push(parseInt(e(t).data("order_item_id"),10))}),a.length&&r.push(e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:{order_id:woocommerce_admin_meta_boxes.post_id,order_item_ids:a,action:"woocommerce_remove_order_item",security:woocommerce_admin_meta_boxes.order_item_nonce},type:"POST"})),n.length&&r.push(e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:{action:"woocommerce_delete_refund",refund_id:n,security:woocommerce_admin_meta_boxes.order_item_nonce},type:"POST"})),r?e.when.apply(e,r).done(function(){t.reload_items(),t.unblock()}):t.unblock()}},do_increase_stock:function(o){o.preventDefault(),t.block();var i=e("table.woocommerce_order_items").find("tr.selected"),a={},n=e.map(i,function(o){return parseInt(e(o).data("order_item_id"),10)});i.each(function(){e(this).find("input.quantity").length&&(a[e(this).attr("data-order_item_id")]=e(this).find("input.quantity").val())});var r={order_id:woocommerce_admin_meta_boxes.post_id,order_item_ids:n,order_item_qty:a,action:"woocommerce_increase_order_item_stock",security:woocommerce_admin_meta_boxes.order_item_nonce};e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:r,type:"POST",success:function(e){window.alert(e),t.unblock()}})},do_reduce_stock:function(o){o.preventDefault(),t.block();var i=e("table.woocommerce_order_items").find("tr.selected"),a={},n=e.map(i,function(o){return parseInt(e(o).data("order_item_id"),10)});i.each(function(){e(this).find("input.quantity").length&&(a[e(this).attr("data-order_item_id")]=e(this).find("input.quantity").val())});var r={order_id:woocommerce_admin_meta_boxes.post_id,order_item_ids:n,order_item_qty:a,action:"woocommerce_reduce_order_item_stock",security:woocommerce_admin_meta_boxes.order_item_nonce};e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:r,type:"POST",success:function(e){window.alert(e),t.unblock()}})}},backbone:{init:function(o,t){"wc-modal-add-products"===t&&(e(document.body).trigger("wc-enhanced-select-init"),e("#add_item_id").selectWoo("open").selectWoo("focus"))},response:function(e,o,i){if("wc-modal-add-tax"===o){var a=i.add_order_tax,n="";i.manual_tax_rate_id&&(n=i.manual_tax_rate_id),t.backbone.add_tax(a,n)}"wc-modal-add-products"===o&&t.backbone.add_item(i.add_order_items)},add_item:function(i){if(i){t.block();var a={action:"woocommerce_add_order_item",item_to_add:i,dataType:"json",order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.order_item_nonce,data:e("#wc-backbone-modal-dialog form").serialize()};"true"===e("button.cancel-action").attr("data-reload")&&(a.items=e("table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]").serialize()),e.post(woocommerce_admin_meta_boxes.ajax_url,a,function(i){i.success?(e("#woocommerce-order-items").find(".inside").empty(),e("#woocommerce-order-items").find(".inside").append(i.data.html),o.init_tiptip(),t.stupidtable.init()):window.alert(i.data.error),t.unblock()})}},add_tax:function(i,a){if(a&&(i=a),!i)return!1;var n=e(".order-tax-id").map(function(){return e(this).val()}).get();if(-1===e.inArray(i,n)){t.block();var r={action:"woocommerce_add_order_tax",rate_id:i,order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.order_item_nonce};e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:r,dataType:"json",type:"POST",success:function(i){i.success?(e("#woocommerce-order-items").find(".inside").empty(),e("#woocommerce-order-items").find(".inside").append(i.data.html),o.init_tiptip(),t.stupidtable.init()):window.alert(i.data.error),t.unblock()}})}else window.alert(woocommerce_admin_meta_boxes.i18n_tax_rate_already_exists)}},stupidtable:{init:function(){e(".woocommerce_order_items").stupidtable(),e(".woocommerce_order_items").on("aftertablesort",this.add_arrows)},add_arrows:function(o,t){var i=e(this).find("th"),a="asc"===t.direction?"↑":"↓",n=t.column;i.find(".wc-arrow").remove(),i.eq(n).append(''+a+"")}}},i={init:function(){e("#woocommerce-order-notes").on("click","button.add_note",this.add_order_note).on("click","a.delete_note",this.delete_order_note)},add_order_note:function(){if(e("textarea#add_order_note").val()){e("#woocommerce-order-notes").block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var o={action:"woocommerce_add_order_note",post_id:woocommerce_admin_meta_boxes.post_id,note:e("textarea#add_order_note").val(),note_type:e("select#order_note_type").val(),security:woocommerce_admin_meta_boxes.add_order_note_nonce};return e.post(woocommerce_admin_meta_boxes.ajax_url,o,function(o){e("ul.order_notes").prepend(o),e("#woocommerce-order-notes").unblock(),e("#add_order_note").val("")}),!1}},delete_order_note:function(){if(window.confirm(woocommerce_admin_meta_boxes.i18n_delete_note)){var o=e(this).closest("li.note");e(o).block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var t={action:"woocommerce_delete_order_note",note_id:e(o).attr("rel"),security:woocommerce_admin_meta_boxes.delete_order_note_nonce};e.post(woocommerce_admin_meta_boxes.ajax_url,t,function(){e(o).remove()})}return!1}},a={init:function(){e(".order_download_permissions").on("click","button.grant_access",this.grant_access).on("click","button.revoke_access",this.revoke_access)},grant_access:function(){var o=e("#grant_access_id").val();if(o){e(".order_download_permissions").block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var t={action:"woocommerce_grant_access_to_download",product_ids:o,loop:e(".order_download_permissions .wc-metabox").length,order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.grant_access_nonce};return e.post(woocommerce_admin_meta_boxes.ajax_url,t,function(o){o?e(".order_download_permissions .wc-metaboxes").append(o):window.alert(woocommerce_admin_meta_boxes.i18n_download_permission_fail),e(document.body).trigger("wc-init-datepickers"),e("#grant_access_id").val("").change(),e(".order_download_permissions").unblock()}),!1}},revoke_access:function(){if(window.confirm(woocommerce_admin_meta_boxes.i18n_permission_revoke)){var o=e(this).parent().parent(),t=e(this).attr("rel").split(",")[0],i=e(this).attr("rel").split(",")[1],a=e(this).data("permission_id");if(t>0){e(o).block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var n={action:"woocommerce_revoke_access_to_download",product_id:t,download_id:i,permission_id:a,order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.revoke_access_nonce};e.post(woocommerce_admin_meta_boxes.ajax_url,n,function(){e(o).fadeOut("300",function(){e(o).remove()})})}else e(o).fadeOut("300",function(){e(o).remove()})}return!1}};o.init(),t.init(),i.init(),a.init()}); \ No newline at end of file +jQuery(function(e){var o={states:null,init:function(){"undefined"!=typeof woocommerce_admin_meta_boxes_order&&"undefined"!=typeof woocommerce_admin_meta_boxes_order.countries&&(this.states=e.parseJSON(woocommerce_admin_meta_boxes_order.countries.replace(/"/g,'"'))),e(".js_field-country").selectWoo().change(this.change_country),e(".js_field-country").trigger("change",[!0]),e(document.body).on("change","select.js_field-state",this.change_state),e("#woocommerce-order-actions input, #woocommerce-order-actions a").click(function(){window.onbeforeunload=""}),e("a.edit_address").click(this.edit_address),e("a.billing-same-as-shipping").on("click",this.copy_billing_to_shipping),e("a.load_customer_billing").on("click",this.load_billing),e("a.load_customer_shipping").on("click",this.load_shipping),e("#customer_user").on("change",this.change_customer_user)},change_country:function(t,i){if(void 0===i&&(i=!1),null!==o.states){var a=e(this),n=a.val(),r=a.parents("div.edit_address").find(":input.js_field-state"),c=r.parent(),d=r.attr("name"),_=r.attr("id"),m=a.data("woocommerce.stickState-"+n)?a.data("woocommerce.stickState-"+n):r.val(),s=r.attr("placeholder");if(i&&a.data("woocommerce.stickState-"+n,m),c.show().find(".select2-container").remove(),e.isEmptyObject(o.states[n]))r.replaceWith('');else{var l=e(''),u=o.states[n];l.append(e('")),e.each(u,function(o){l.append(e('"))}),l.val(m),r.replaceWith(l),l.show().selectWoo().hide().change()}e(document.body).trigger("contry-change.woocommerce",[n,e(this).closest("div")]),e(document.body).trigger("country-change.woocommerce",[n,e(this).closest("div")])}},change_state:function(){var o=e(this),t=o.val(),i=o.parents("div.edit_address").find(":input.js_field-country"),a=i.val();i.data("woocommerce.stickState-"+a,t)},init_tiptip:function(){e("#tiptip_holder").removeAttr("style"),e("#tiptip_arrow").removeAttr("style"),e(".tips").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200})},edit_address:function(o){o.preventDefault();var t=e(this),i=t.closest(".order_data_column"),a=i.find("div.edit_address"),n=i.find("div.address"),r=a.find(".js_field-country"),c=a.find(".js_field-state");n.hide(),t.parent().find("a").toggle(),r.val()||r.val(woocommerce_admin_meta_boxes_order.default_country).change(),c.val()||c.val(woocommerce_admin_meta_boxes_order.default_state).change(),a.show()},change_customer_user:function(){e("#_billing_country").val()||(e("a.edit_address").click(),o.load_billing(!0),o.load_shipping(!0))},load_billing:function(o){if(!0===o||window.confirm(woocommerce_admin_meta_boxes.load_billing)){var t=e("#customer_user").val();if(!t)return window.alert(woocommerce_admin_meta_boxes.no_customer_selected),!1;var i={user_id:t,action:"woocommerce_get_customer_details",security:woocommerce_admin_meta_boxes.get_customer_details_nonce};e(this).closest("div.edit_address").block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:i,type:"POST",success:function(o){o&&o.billing&&e.each(o.billing,function(o,t){e(":input#_billing_"+o).val(t).change()}),e("div.edit_address").unblock()}})}return!1},load_shipping:function(o){if(!0===o||window.confirm(woocommerce_admin_meta_boxes.load_shipping)){var t=e("#customer_user").val();if(!t)return window.alert(woocommerce_admin_meta_boxes.no_customer_selected),!1;var i={user_id:t,action:"woocommerce_get_customer_details",security:woocommerce_admin_meta_boxes.get_customer_details_nonce};e(this).closest("div.edit_address").block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:i,type:"POST",success:function(o){o&&o.billing&&e.each(o.shipping,function(o,t){e(":input#_shipping_"+o).val(t).change()}),e("div.edit_address").unblock()}})}return!1},copy_billing_to_shipping:function(){return window.confirm(woocommerce_admin_meta_boxes.copy_billing)&&e('.order_data_column :input[name^="_billing_"]').each(function(){var o=e(this).attr("name");o=o.replace("_billing_","_shipping_"),e(":input#"+o).val(e(this).val()).change()}),!1}},t={init:function(){this.stupidtable.init(),e("#woocommerce-order-items").on("click","button.add-line-item",this.add_line_item).on("click","button.add-coupon",this.add_coupon).on("click","a.remove-coupon",this.remove_coupon).on("click","button.refund-items",this.refund_items).on("click",".cancel-action",this.cancel).on("click","button.add-order-item",this.add_item).on("click","button.add-order-fee",this.add_fee).on("click","button.add-order-shipping",this.add_shipping).on("click","button.add-order-tax",this.add_tax).on("click","button.save-action",this.save_line_items).on("click","a.delete-order-tax",this.delete_tax).on("click","button.calculate-action",this.recalculate).on("click","a.edit-order-item",this.edit_item).on("click","a.delete-order-item",this.delete_item).on("click","tr.item, tr.fee, tr.shipping, tr.refund",this.select_row).on("click","tr.item :input, tr.fee :input, tr.shipping :input, tr.refund :input, tr.item a, tr.fee a, tr.shipping a, tr.refund a",this.select_row_child).on("click","button.bulk-delete-items",this.bulk_actions.do_delete).on("click","button.bulk-increase-stock",this.bulk_actions.do_increase_stock).on("click","button.bulk-decrease-stock",this.bulk_actions.do_reduce_stock).on("click",".delete_refund",this.refunds.delete_refund).on("click","button.do-api-refund, button.do-manual-refund",this.refunds.do_refund).on("change",".refund input.refund_line_total, .refund input.refund_line_tax",this.refunds.input_changed).on("change keyup",".wc-order-refund-items #refund_amount",this.refunds.amount_changed).on("change","input.refund_order_item_qty",this.refunds.refund_quantity_changed).on("change","input.quantity",this.quantity_changed).on("keyup change",".split-input :input",function(){var o=e(this).parent().prev().find(":input");o&&(""===o.val()||o.is(".match-total"))&&o.val(e(this).val()).addClass("match-total")}).on("keyup",".split-input :input",function(){e(this).removeClass("match-total")}).on("click","button.add_order_item_meta",this.item_meta.add).on("click","button.remove_order_item_meta",this.item_meta.remove),e(document.body).on("wc_backbone_modal_loaded",this.backbone.init).on("wc_backbone_modal_response",this.backbone.response)},block:function(){e("#woocommerce-order-items").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){e("#woocommerce-order-items").unblock()},reload_items:function(){var i={order_id:woocommerce_admin_meta_boxes.post_id,action:"woocommerce_load_order_items",security:woocommerce_admin_meta_boxes.order_item_nonce};t.block(),e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:i,type:"POST",success:function(i){e("#woocommerce-order-items").find(".inside").empty(),e("#woocommerce-order-items").find(".inside").append(i),o.init_tiptip(),t.unblock(),t.stupidtable.init()}})},quantity_changed:function(){var o=e(this).closest("tr.item"),t=e(this).val(),i=e(this).attr("data-qty"),a=e("input.line_total",o),n=e("input.line_subtotal",o),r=accounting.unformat(a.attr("data-total"),woocommerce_admin.mon_decimal_point)/i;a.val(parseFloat(accounting.formatNumber(r*t,woocommerce_admin_meta_boxes.rounding_precision,"")).toString().replace(".",woocommerce_admin.mon_decimal_point));var c=accounting.unformat(n.attr("data-subtotal"),woocommerce_admin.mon_decimal_point)/i;n.val(parseFloat(accounting.formatNumber(c*t,woocommerce_admin_meta_boxes.rounding_precision,"")).toString().replace(".",woocommerce_admin.mon_decimal_point)),e("input.line_tax",o).each(function(){var a=e(this),n=a.data("tax_id"),r=accounting.unformat(a.attr("data-total_tax"),woocommerce_admin.mon_decimal_point)/i,c=e('input.line_subtotal_tax[data-tax_id="'+n+'"]',o),d=accounting.unformat(c.attr("data-subtotal_tax"),woocommerce_admin.mon_decimal_point)/i;00?e("#restock_refunded_items").closest("tr").show():(e("#restock_refunded_items").closest("tr").hide(),e(".woocommerce_order_items input.refund_order_item_qty").each(function(){e(this).val()>0&&e("#restock_refunded_items").closest("tr").show()})),e(this).trigger("refund_quantity_changed")}},item_meta:{add:function(){var o=e(this).closest("tr.item, tr.shipping"),t=o.find("tbody.meta_items"),i=t.find("tr").length+1,a='';return t.append(a),!1},remove:function(){if(window.confirm(woocommerce_admin_meta_boxes.remove_item_meta)){var o=e(this).closest("tr");o.find(":input").val(""),o.hide()}return!1}},select_row:function(){var o=!1;o=e(this).is("tr")?e(this):e(this).closest("tr");var t=e(this).closest("table");o.is(".selected")?o.removeClass("selected"):o.addClass("selected");var i=t.find("tr.selected");if(i.length){e("div.wc-order-item-bulk-edit").slideDown();var a=!1;i.each(function(){e(this).is("tr.item")&&(a=!0)}),a?e(".bulk-increase-stock, .bulk-decrease-stock").show():e(".bulk-increase-stock, .bulk-decrease-stock").hide()}else e("div.wc-order-item-bulk-edit").slideUp()},select_row_child:function(e){e.stopPropagation()},bulk_actions:{do_delete:function(o){o.preventDefault();var i=e("table.woocommerce_order_items").find("tr.selected");if(i.length&&window.confirm(woocommerce_admin_meta_boxes.remove_item_notice)){t.block();var a=[],n=[],r=[];e.map(i,function(o){var t=e(o);t.is(".refund")?n.push(parseInt(e(t).data("order_refund_id"),10)):a.push(parseInt(e(t).data("order_item_id"),10))}),a.length&&r.push(e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:{order_id:woocommerce_admin_meta_boxes.post_id,order_item_ids:a,action:"woocommerce_remove_order_item",security:woocommerce_admin_meta_boxes.order_item_nonce},type:"POST"})),n.length&&r.push(e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:{action:"woocommerce_delete_refund",refund_id:n,security:woocommerce_admin_meta_boxes.order_item_nonce},type:"POST"})),r?e.when.apply(e,r).done(function(){t.reload_items(),t.unblock()}):t.unblock()}},do_increase_stock:function(o){o.preventDefault(),t.block();var i=e("table.woocommerce_order_items").find("tr.selected"),a={},n=e.map(i,function(o){return parseInt(e(o).data("order_item_id"),10)});i.each(function(){e(this).find("input.quantity").length&&(a[e(this).attr("data-order_item_id")]=e(this).find("input.quantity").val())});var r={order_id:woocommerce_admin_meta_boxes.post_id,order_item_ids:n,order_item_qty:a,action:"woocommerce_increase_order_item_stock",security:woocommerce_admin_meta_boxes.order_item_nonce};e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:r,type:"POST",success:function(e){window.alert(e),t.unblock()}})},do_reduce_stock:function(o){o.preventDefault(),t.block();var i=e("table.woocommerce_order_items").find("tr.selected"),a={},n=e.map(i,function(o){return parseInt(e(o).data("order_item_id"),10)});i.each(function(){e(this).find("input.quantity").length&&(a[e(this).attr("data-order_item_id")]=e(this).find("input.quantity").val())});var r={order_id:woocommerce_admin_meta_boxes.post_id,order_item_ids:n,order_item_qty:a,action:"woocommerce_reduce_order_item_stock",security:woocommerce_admin_meta_boxes.order_item_nonce};e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:r,type:"POST",success:function(e){window.alert(e),t.unblock()}})}},backbone:{init:function(o,t){"wc-modal-add-products"===t&&(e(document.body).trigger("wc-enhanced-select-init"),e("#add_item_id").selectWoo("open").selectWoo("focus"))},response:function(e,o,i){if("wc-modal-add-tax"===o){var a=i.add_order_tax,n="";i.manual_tax_rate_id&&(n=i.manual_tax_rate_id),t.backbone.add_tax(a,n)}"wc-modal-add-products"===o&&t.backbone.add_item(i.add_order_items)},add_item:function(i){if(i){t.block();var a={action:"woocommerce_add_order_item",item_to_add:i,dataType:"json",order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.order_item_nonce,data:e("#wc-backbone-modal-dialog form").serialize()};"true"===e("button.cancel-action").attr("data-reload")&&(a.items=e("table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]").serialize()),e.post(woocommerce_admin_meta_boxes.ajax_url,a,function(i){i.success?(e("#woocommerce-order-items").find(".inside").empty(),e("#woocommerce-order-items").find(".inside").append(i.data.html),o.init_tiptip(),t.stupidtable.init()):window.alert(i.data.error),t.unblock()})}},add_tax:function(i,a){if(a&&(i=a),!i)return!1;var n=e(".order-tax-id").map(function(){return e(this).val()}).get();if(-1===e.inArray(i,n)){t.block();var r={action:"woocommerce_add_order_tax",rate_id:i,order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.order_item_nonce};e.ajax({url:woocommerce_admin_meta_boxes.ajax_url,data:r,dataType:"json",type:"POST",success:function(i){i.success?(e("#woocommerce-order-items").find(".inside").empty(),e("#woocommerce-order-items").find(".inside").append(i.data.html),o.init_tiptip(),t.stupidtable.init()):window.alert(i.data.error),t.unblock()}})}else window.alert(woocommerce_admin_meta_boxes.i18n_tax_rate_already_exists)}},stupidtable:{init:function(){e(".woocommerce_order_items").stupidtable(),e(".woocommerce_order_items").on("aftertablesort",this.add_arrows)},add_arrows:function(o,t){var i=e(this).find("th"),a="asc"===t.direction?"↑":"↓",n=t.column;i.find(".wc-arrow").remove(),i.eq(n).append(''+a+"")}}},i={init:function(){e("#woocommerce-order-notes").on("click","button.add_note",this.add_order_note).on("click","a.delete_note",this.delete_order_note)},add_order_note:function(){if(e("textarea#add_order_note").val()){e("#woocommerce-order-notes").block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var o={action:"woocommerce_add_order_note",post_id:woocommerce_admin_meta_boxes.post_id,note:e("textarea#add_order_note").val(),note_type:e("select#order_note_type").val(),security:woocommerce_admin_meta_boxes.add_order_note_nonce};return e.post(woocommerce_admin_meta_boxes.ajax_url,o,function(o){e("ul.order_notes").prepend(o),e("#woocommerce-order-notes").unblock(),e("#add_order_note").val("")}),!1}},delete_order_note:function(){if(window.confirm(woocommerce_admin_meta_boxes.i18n_delete_note)){var o=e(this).closest("li.note");e(o).block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var t={action:"woocommerce_delete_order_note",note_id:e(o).attr("rel"),security:woocommerce_admin_meta_boxes.delete_order_note_nonce};e.post(woocommerce_admin_meta_boxes.ajax_url,t,function(){e(o).remove()})}return!1}},a={init:function(){e(".order_download_permissions").on("click","button.grant_access",this.grant_access).on("click","button.revoke_access",this.revoke_access)},grant_access:function(){var o=e("#grant_access_id").val();if(o){e(".order_download_permissions").block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var t={action:"woocommerce_grant_access_to_download",product_ids:o,loop:e(".order_download_permissions .wc-metabox").length,order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.grant_access_nonce};return e.post(woocommerce_admin_meta_boxes.ajax_url,t,function(o){o?e(".order_download_permissions .wc-metaboxes").append(o):window.alert(woocommerce_admin_meta_boxes.i18n_download_permission_fail),e(document.body).trigger("wc-init-datepickers"),e("#grant_access_id").val("").change(),e(".order_download_permissions").unblock()}),!1}},revoke_access:function(){if(window.confirm(woocommerce_admin_meta_boxes.i18n_permission_revoke)){var o=e(this).parent().parent(),t=e(this).attr("rel").split(",")[0],i=e(this).attr("rel").split(",")[1],a=e(this).data("permission_id");if(t>0){e(o).block({message:null,overlayCSS:{background:"#fff",opacity:.6}});var n={action:"woocommerce_revoke_access_to_download",product_id:t,download_id:i,permission_id:a,order_id:woocommerce_admin_meta_boxes.post_id,security:woocommerce_admin_meta_boxes.revoke_access_nonce};e.post(woocommerce_admin_meta_boxes.ajax_url,n,function(){e(o).fadeOut("300",function(){e(o).remove()})})}else e(o).fadeOut("300",function(){e(o).remove()})}return!1}};o.init(),t.init(),i.init(),a.init()}); \ No newline at end of file diff --git a/includes/abstracts/abstract-wc-product.php b/includes/abstracts/abstract-wc-product.php index 7a347d9705f..38bcb169022 100644 --- a/includes/abstracts/abstract-wc-product.php +++ b/includes/abstracts/abstract-wc-product.php @@ -1762,6 +1762,17 @@ class WC_Product extends WC_Abstract_Legacy_Product { return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'Read more', 'woocommerce' ), $this ); } + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Read more about “%s”', 'woocommerce' ), $this->get_name() ), $this ); + } + /** * Returns the main product image. * diff --git a/includes/admin/class-wc-admin-setup-wizard.php b/includes/admin/class-wc-admin-setup-wizard.php index a741236d6f6..50ac35e751d 100644 --- a/includes/admin/class-wc-admin-setup-wizard.php +++ b/includes/admin/class-wc-admin-setup-wizard.php @@ -1265,8 +1265,14 @@ class WC_Admin_Setup_Wizard {

Additional payment methods can be installed later.', 'woocommerce' + wp_kses( + __( 'WooCommerce can accept both online and offline payments. Additional payment methods can be installed later.', 'woocommerce' ), + array( + 'a' => array( + 'href' => array(), + 'target' => array(), + ), + ) ), esc_url( admin_url( 'admin.php?page=wc-addons&view=payment-gateways' ) ) ); ?> diff --git a/includes/api/class-wc-rest-orders-controller.php b/includes/api/class-wc-rest-orders-controller.php index 2ed5ffa2c5e..0b9c235458c 100644 --- a/includes/api/class-wc-rest-orders-controller.php +++ b/includes/api/class-wc-rest-orders-controller.php @@ -1169,7 +1169,7 @@ class WC_REST_Orders_Controller extends WC_REST_Legacy_Orders_Controller { ), 'tax_class' => array( 'description' => __( 'Tax class of product.', 'woocommerce' ), - 'type' => 'integer', + 'type' => 'string', 'context' => array( 'view', 'edit' ), ), 'subtotal' => array( @@ -1254,7 +1254,7 @@ class WC_REST_Orders_Controller extends WC_REST_Legacy_Orders_Controller { ), 'price' => array( 'description' => __( 'Product price.', 'woocommerce' ), - 'type' => 'string', + 'type' => 'number', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), diff --git a/includes/api/v1/class-wc-rest-orders-controller.php b/includes/api/v1/class-wc-rest-orders-controller.php index f7b1efe86b2..83325f8f550 100644 --- a/includes/api/v1/class-wc-rest-orders-controller.php +++ b/includes/api/v1/class-wc-rest-orders-controller.php @@ -1238,7 +1238,7 @@ class WC_REST_Orders_V1_Controller extends WC_REST_Posts_Controller { ), 'tax_class' => array( 'description' => __( 'Tax class of product.', 'woocommerce' ), - 'type' => 'integer', + 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), diff --git a/includes/class-wc-ajax.php b/includes/class-wc-ajax.php index 4f8263c96fd..fed693b9645 100644 --- a/includes/class-wc-ajax.php +++ b/includes/class-wc-ajax.php @@ -913,9 +913,15 @@ class WC_AJAX { } try { - $order_id = absint( $_POST['order_id'] ); - $amount = wc_clean( $_POST['amount'] ); - $order = wc_get_order( $order_id ); + $order_id = absint( $_POST['order_id'] ); + $amount = wc_clean( $_POST['amount'] ); + $order = wc_get_order( $order_id ); + $calculate_tax_args = array( + 'country' => strtoupper( wc_clean( $_POST['country'] ) ), + 'state' => strtoupper( wc_clean( $_POST['state'] ) ), + 'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ), + 'city' => strtoupper( wc_clean( $_POST['city'] ) ), + ); if ( ! $order ) { throw new exception( __( 'Invalid order', 'woocommerce' ) ); @@ -936,7 +942,8 @@ class WC_AJAX { $fee->set_name( sprintf( __( '%s fee', 'woocommerce' ), $formatted_amount ) ); $order->add_item( $fee ); - $order->calculate_totals( true ); + $order->calculate_taxes( $calculate_tax_args ); + $order->calculate_totals( false ); $order->save(); ob_start(); @@ -1084,9 +1091,15 @@ class WC_AJAX { } try { - $order_id = absint( $_POST['order_id'] ); - $order_item_ids = $_POST['order_item_ids']; - $items = ( ! empty( $_POST['items'] ) ) ? $_POST['items'] : ''; + $order_id = absint( $_POST['order_id'] ); + $order_item_ids = $_POST['order_item_ids']; + $items = ( ! empty( $_POST['items'] ) ) ? $_POST['items']: ''; + $calculate_tax_args = array( + 'country' => strtoupper( wc_clean( $_POST['country'] ) ), + 'state' => strtoupper( wc_clean( $_POST['state'] ) ), + 'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ), + 'city' => strtoupper( wc_clean( $_POST['city'] ) ), + ); if ( ! is_array( $order_item_ids ) && is_numeric( $order_item_ids ) ) { $order_item_ids = array( $order_item_ids ); @@ -1107,7 +1120,8 @@ class WC_AJAX { } $order = wc_get_order( $order_id ); - $order->calculate_totals( true ); + $order->calculate_taxes( $calculate_tax_args ); + $order->calculate_totals( false ); ob_start(); include( 'admin/meta-boxes/views/html-order-items.php' ); @@ -1325,15 +1339,30 @@ class WC_AJAX { if ( $post_id > 0 ) { $order = wc_get_order( $post_id ); $comment_id = $order->add_order_note( $note, $is_customer_note, true ); + $note = wc_get_order_note( $comment_id ); - echo '

  • '; - echo wpautop( wptexturize( $note ) ); - echo '

    ' . __( 'Delete note', 'woocommerce' ) . '

    '; - echo '
  • '; + $note_classes = array( 'note' ); + $note_classes[] = $is_customer_note ? 'customer-note' : ''; + $note_classes = apply_filters( 'woocommerce_order_note_class', array_filter( $note_classes ), $note ); + ?> +
  • +
    + content ) ) ); ?> +
    +

    + + date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) ); ?> + + added_by ) : + /* translators: %s: note author */ + printf( ' ' . __( 'by %s', 'woocommerce' ), $note->added_by ); + endif; + ?> + +

    +
  • + '', ) ); - extract( $args ); - - if ( ! $product || ! $quantity || ! ( $order = wc_get_order( $order_id ) ) ) { + $order = wc_get_order( $args['order_id'] ); + if ( + ! $args['product'] || + ! is_object( $args['product'] ) || + ! $args['quantity'] || + ! $order + ) { return; } $subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product backorder', 'woocommerce' ) ); - $message = sprintf( __( '%1$s units of %2$s have been backordered in order #%3$s.', 'woocommerce' ), $quantity, html_entity_decode( strip_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ), $order->get_order_number() ); - + $message = sprintf( __( '%1$s units of %2$s have been backordered in order #%3$s.', 'woocommerce' ), $args['quantity'], html_entity_decode( strip_tags( $args['product']->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ), $order->get_order_number() ); + wp_mail( apply_filters( 'woocommerce_email_recipient_backorder', get_option( 'woocommerce_stock_email_recipient' ), $args ), apply_filters( 'woocommerce_email_subject_backorder', $subject, $args ), diff --git a/includes/class-wc-order-item-fee.php b/includes/class-wc-order-item-fee.php index 89b53a85d3e..bcf45c52a77 100644 --- a/includes/class-wc-order-item-fee.php +++ b/includes/class-wc-order-item-fee.php @@ -87,16 +87,18 @@ class WC_Order_Item_Fee extends WC_Order_Item { if ( 'non-taxable' === $tax_class ) { continue; } - $proportion = $tax_class_cost / $total_costs; - $cart_discount_proportion = $this->get_total() * $proportion; - $discount_taxes = wc_array_merge_recursive_numeric( $discount_taxes, WC_Tax::calc_tax( $cart_discount_proportion, WC_Tax::get_rates( $tax_class ) ) ); + $proportion = $tax_class_cost / $total_costs; + $cart_discount_proportion = $this->get_total() * $proportion; + $calculate_tax_for['tax_class'] = $tax_class; + $tax_rates = WC_Tax::find_rates( $calculate_tax_for ); + $discount_taxes = wc_array_merge_recursive_numeric( $discount_taxes, WC_Tax::calc_tax( $cart_discount_proportion, $tax_rates ) ); } } $this->set_taxes( array( 'total' => $discount_taxes ) ); } else { $this->set_taxes( false ); } - + do_action( 'woocommerce_order_item_fee_after_calculate_taxes', $this, $calculate_tax_for ); return true; diff --git a/includes/class-wc-post-data.php b/includes/class-wc-post-data.php index b47d09f9df1..3c1e4c86e09 100644 --- a/includes/class-wc-post-data.php +++ b/includes/class-wc-post-data.php @@ -108,6 +108,9 @@ class WC_Post_Data { foreach ( array_merge( $tt_ids, $old_tt_ids ) as $id ) { delete_transient( 'wc_ln_count_' . md5( sanitize_key( $taxonomy ) . sanitize_key( $id ) ) ); } + if ( in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ) ) ) { + self::delete_product_query_transients(); + } } /** diff --git a/includes/class-wc-product-external.php b/includes/class-wc-product-external.php index d9b7e72964a..114059d9907 100644 --- a/includes/class-wc-product-external.php +++ b/includes/class-wc-product-external.php @@ -180,4 +180,15 @@ class WC_Product_External extends WC_Product { public function add_to_cart_text() { return apply_filters( 'woocommerce_product_add_to_cart_text', $this->get_button_text() ? $this->get_button_text() : _x( 'Buy product', 'placeholder', 'woocommerce' ), $this ); } + + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + return apply_filters( 'woocommerce_product_add_to_cart_description', $this->get_button_text() ? $this->get_button_text() : sprintf( __( 'Buy “%s”', 'woocommerce' ), $this->get_name() ), $this ); + } } diff --git a/includes/class-wc-product-grouped.php b/includes/class-wc-product-grouped.php index c10e4d28949..a9de2284881 100644 --- a/includes/class-wc-product-grouped.php +++ b/includes/class-wc-product-grouped.php @@ -43,6 +43,17 @@ class WC_Product_Grouped extends WC_Product { return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'View products', 'woocommerce' ), $this ); } + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'View products in the “%s” group', 'woocommerce' ), $this->get_name() ), $this ); + } + /** * Returns whether or not the product is on sale. * diff --git a/includes/class-wc-product-simple.php b/includes/class-wc-product-simple.php index 33ee968fde4..742166d46de 100644 --- a/includes/class-wc-product-simple.php +++ b/includes/class-wc-product-simple.php @@ -55,4 +55,17 @@ class WC_Product_Simple extends WC_Product { return apply_filters( 'woocommerce_product_add_to_cart_text', $text, $this ); } + + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + $text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add “%s” to your cart', 'woocommerce' ) : __( 'Read more about “%s”', 'woocommerce' ); + + return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( $text, $this->get_name() ), $this ); + } } diff --git a/includes/class-wc-product-variable.php b/includes/class-wc-product-variable.php index f372f4318e8..42512b71e89 100644 --- a/includes/class-wc-product-variable.php +++ b/includes/class-wc-product-variable.php @@ -60,6 +60,17 @@ class WC_Product_Variable extends WC_Product { return apply_filters( 'woocommerce_product_add_to_cart_text', $this->is_purchasable() ? __( 'Select options', 'woocommerce' ) : __( 'Read more', 'woocommerce' ), $this ); } + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Select options for “%s”', 'woocommerce' ), $this->get_name() ), $this ); + } + /** * Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale. * diff --git a/includes/class-wc-product-variation.php b/includes/class-wc-product-variation.php index 5de955ef312..d53b48e8a9a 100644 --- a/includes/class-wc-product-variation.php +++ b/includes/class-wc-product-variation.php @@ -50,6 +50,16 @@ class WC_Product_Variation extends WC_Product_Simple { 'purchase_note' => '', ); + /** + * Override the default constructor to set custom defaults. + * + * @param int|WC_Product|object $product Product to init. + */ + public function __construct( $product = 0 ) { + $this->data['tax_class'] = 'parent'; + parent::__construct( $product ); + } + /** * Prefix for action and filter hooks on data. * diff --git a/includes/class-wc-regenerate-images-request.php b/includes/class-wc-regenerate-images-request.php new file mode 100644 index 00000000000..fadc8f24491 --- /dev/null +++ b/includes/class-wc-regenerate-images-request.php @@ -0,0 +1,110 @@ +info( __( 'Starting product image regeneration job.', 'woocommerce' ), + array( + 'source' => 'wc-image-regeneration', + ) + ); + parent::dispatch(); + } + + /** + * Code to execute for each item in the queue + * + * @param mixed $item Queue item to iterate over. + * @return bool + */ + protected function task( $item ) { + if ( ! is_array( $item ) && ! isset( $item['attachment_id'] ) ) { + return false; + } + + if ( ! function_exists( 'wp_crop_image' ) ) { + include( ABSPATH . 'wp-admin/includes/image.php' ); + } + + $attachment_id = absint( $item['attachment_id'] ); + + $attachment = get_post( $attachment_id ); + if ( ! $attachment || 'attachment' !== $attachment->post_type || 'image/' !== substr( $attachment->post_mime_type, 0, 6 ) ) { + return false; + } + $log = wc_get_logger(); + // translators: %s: ID of the attachment. + $log->info( sprintf( __( 'Regenerating images for attachment ID: %s', 'woocommerce' ), absint( $attachment->ID ) ), + array( + 'source' => 'wc-image-regeneration', + ) + ); + + $fullsizepath = get_attached_file( $attachment->ID ); + + // Check if the file exists, if not just remove item from queue. + if ( false === $fullsizepath || ! file_exists( $fullsizepath ) ) { + return false; + } + + // This function will generate the new image sizes. + $metadata = wp_generate_attachment_metadata( $attachment->ID, $fullsizepath ); + + // If something went wrong lets just remove the item from the queue. + if ( is_wp_error( $metadata ) || empty( $metadata ) ) { + return false; + } + + // Update the meta data with the new size values. + wp_update_attachment_metadata( $attachment->ID, $metadata ); + + // We made it till the end, now lets remove the item from the queue. + return false; + } + + /** + * This runs once the job has completed all items on the queue. + * + * @return void + */ + protected function complete() { + parent::complete(); + $log = wc_get_logger(); + $log->info( __( 'Completed product image regeneration job.', 'woocommerce' ), + array( + 'source' => 'wc-image-regeneration', + ) + ); + } + + +} diff --git a/includes/class-wc-regenerate-images.php b/includes/class-wc-regenerate-images.php new file mode 100644 index 00000000000..2c8f2da66c1 --- /dev/null +++ b/includes/class-wc-regenerate-images.php @@ -0,0 +1,210 @@ +post_type || 'image/' !== substr( $attachment->post_mime_type, 0, 6 ) ) { + return $image; + } + + if ( ! function_exists( 'wp_crop_image' ) ) { + include( ABSPATH . 'wp-admin/includes/image.php' ); + } + + $wp_uploads = wp_upload_dir( null, false ); + $wp_uploads_dir = $wp_uploads['basedir']; + $wp_uploads_url = $wp_uploads['baseurl']; + + $original_image_file_path = get_attached_file( $attachment->ID ); + + if ( ! file_exists( $original_image_file_path ) || ! getimagesize( $original_image_file_path ) ) { + return $image; + } + + $info = pathinfo( $original_image_file_path ); + $ext = $info['extension']; + list( $orig_w, $orig_h ) = getimagesize( $original_image_file_path ); + // Get image size after cropping. + $image_size = wc_get_image_size( $size ); + $dimensions = image_resize_dimensions( $orig_w, $orig_h, $image_size['width'], $image_size['height'], $image_size['crop'] ); + if ( ! $dimensions || ! is_array( $dimensions ) ) { + return $image; + } + + $dst_w = $dimensions[4]; + $dst_h = $dimensions[5]; + $suffix = "{$dst_w}x{$dst_h}"; + $dst_rel_path = str_replace( '.' . $ext, '', $original_image_file_path ); + $destfilename = "{$dst_rel_path}-{$suffix}.{$ext}"; + + // If the file is already there perhaps just load it. + if ( file_exists( $destfilename ) ) { + return array( + 0 => str_replace( $wp_uploads_dir, $wp_uploads_url, $destfilename ), + 1 => $image_size['width'], + 2 => $image_size['height'], + ); + } + + // Lets resize the image if it does not exist yet. + $editor = wp_get_image_editor( $original_image_file_path ); + if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $image_size['width'], $image_size['height'], $image_size['crop'] ) ) ) { + return $image; + } + $resized_file = $editor->save(); + if ( ! is_wp_error( $resized_file ) ) { + $img_url = str_replace( $wp_uploads_dir, $wp_uploads_url, $resized_file['path'] ); + return array( + 0 => $img_url, + 1 => $image_size['width'], + 2 => $image_size['height'], + ); + } + + // Lets just add this here as a fallback. + return $image; + } + + /** + * Check if we should regenerate the product images when options change. + * + * @param mixed $old_value Old option value. + * @param mixed $new_value New option value. + * @param string $option Option name. + */ + public static function maybe_regenerate_images_option_update( $old_value, $new_value, $option ) { + if ( $new_value === $old_value ) { + return; + } + + self::queue_image_regeneration(); + } + + /** + * Check if we should generate images when new themes declares custom sizes + * + * @return void + */ + public static function maybe_regenerate_image_theme_switch() { + $theme_support = get_theme_support( 'woocommerce' ); + $theme_support = is_array( $theme_support ) ? $theme_support[0] : false; + + // Only queue image generation if the theme declares custom sizes via theme_support. + if ( is_array( $theme_support ) && ( isset( $theme_support['single_image_width'] ) || isset( $theme_support['thumbnail_image_width'] ) ) ) { + self::queue_image_regeneration(); + } + } + + /** + * Get list of images and queue them for regeneration + * + * @return void + */ + private static function queue_image_regeneration() { + global $wpdb; + // First lets cancel existing running queue to avoid running it more than once. + self::$background_process->cancel_process(); + + // Now lets find all product image attachments IDs and pop them onto the queue. + $images = $wpdb->get_results( // @codingStandardsIgnoreLine + "SELECT ID + FROM $wpdb->posts + WHERE post_type = 'attachment' + AND post_mime_type LIKE 'image/%' + ORDER BY ID DESC" + ); + foreach ( $images as $image ) { + self::$background_process->push_to_queue( array( + 'attachment_id' => $image->ID, + ) ); + } + + // Lets dispatch the queue to start processing. + self::$background_process->save()->dispatch(); + } +} +WC_Regenerate_Images::init(); diff --git a/includes/class-woocommerce.php b/includes/class-woocommerce.php index 22c47c9b410..9d2dd82833c 100644 --- a/includes/class-woocommerce.php +++ b/includes/class-woocommerce.php @@ -16,7 +16,6 @@ if ( ! defined( 'ABSPATH' ) ) { * Main WooCommerce Class. * * @class WooCommerce - * @version 3.3.0 */ final class WooCommerce { @@ -237,13 +236,13 @@ final class WooCommerce { */ private function is_request( $type ) { switch ( $type ) { - case 'admin' : + case 'admin': return is_admin(); - case 'ajax' : + case 'ajax': return defined( 'DOING_AJAX' ); - case 'cron' : + case 'cron': return defined( 'DOING_CRON' ); - case 'frontend' : + case 'frontend': return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' ); } } @@ -320,11 +319,11 @@ final class WooCommerce { include_once( WC_ABSPATH . 'includes/class-wc-emails.php' ); include_once( WC_ABSPATH . 'includes/class-wc-data-exception.php' ); include_once( WC_ABSPATH . 'includes/class-wc-query.php' ); - include_once( WC_ABSPATH . 'includes/class-wc-meta-data.php' ); // Meta data internal object + include_once( WC_ABSPATH . 'includes/class-wc-meta-data.php' ); // Meta data internal object. include_once( WC_ABSPATH . 'includes/class-wc-order-factory.php' ); // Order factory. include_once( WC_ABSPATH . 'includes/class-wc-order-query.php' ); // Order query. include_once( WC_ABSPATH . 'includes/class-wc-product-factory.php' ); // Product factory. - include_once( WC_ABSPATH . 'includes/class-wc-product-query.php' ); // Product query + include_once( WC_ABSPATH . 'includes/class-wc-product-query.php' ); // Product query. include_once( WC_ABSPATH . 'includes/class-wc-payment-tokens.php' ); // Payment tokens controller. include_once( WC_ABSPATH . 'includes/class-wc-shipping-zone.php' ); include_once( WC_ABSPATH . 'includes/gateways/class-wc-payment-gateway-cc.php' ); // CC Payment Gateway. @@ -338,6 +337,7 @@ final class WooCommerce { include_once( WC_ABSPATH . 'includes/class-wc-background-emailer.php' ); include_once( WC_ABSPATH . 'includes/class-wc-discounts.php' ); include_once( WC_ABSPATH . 'includes/class-wc-cart-totals.php' ); + include_once( WC_ABSPATH . 'includes/class-wc-regenerate-images.php' ); // Image regeneration class. /** * Data stores - used to store and retrieve CRUD object data from the database. @@ -409,28 +409,28 @@ final class WooCommerce { if ( $this->is_active_theme( array( 'twentyseventeen', 'twentysixteen', 'twentyfifteen', 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' ) ) ) { switch ( get_template() ) { - case 'twentyten' : + case 'twentyten': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-ten.php' ); break; - case 'twentyeleven' : + case 'twentyeleven': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-eleven.php' ); break; - case 'twentytwelve' : + case 'twentytwelve': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-twelve.php' ); break; - case 'twentythirteen' : + case 'twentythirteen': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-thirteen.php' ); break; - case 'twentyfourteen' : + case 'twentyfourteen': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-fourteen.php' ); break; - case 'twentyfifteen' : + case 'twentyfifteen': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-fifteen.php' ); break; - case 'twentysixteen' : + case 'twentysixteen': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-sixteen.php' ); break; - case 'twentyseventeen' : + case 'twentyseventeen': include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-seventeen.php' ); break; } @@ -558,7 +558,7 @@ final class WooCommerce { */ private function add_image_sizes() { $thumbnail = wc_get_image_size( 'thumbnail' ); - $single = wc_get_image_size( 'single' ); + $single = wc_get_image_size( 'single' ); add_image_size( 'woocommerce_thumbnail', $thumbnail['width'], $thumbnail['height'], $thumbnail['crop'] ); add_image_size( 'woocommerce_single', $single['width'], $single['height'], $single['crop'] ); @@ -641,12 +641,12 @@ final class WooCommerce { return; } - if ( false === ( $webhooks = get_transient( 'woocommerce_webhook_ids' ) ) ) { + if ( false === ( $webhooks = get_transient( 'woocommerce_webhook_ids' ) ) ) { // @codingStandardsIgnoreLine $webhooks = get_posts( array( 'fields' => 'ids', 'post_type' => 'shop_webhook', 'post_status' => 'publish', - 'posts_per_page' => -1, + 'posts_per_page' => -1, // @codingStandardsIgnoreLine ) ); set_transient( 'woocommerce_webhook_ids', $webhooks ); } diff --git a/includes/data-stores/class-wc-product-variable-data-store-cpt.php b/includes/data-stores/class-wc-product-variable-data-store-cpt.php index 6a2c2a29292..1845c859ecf 100644 --- a/includes/data-stores/class-wc-product-variable-data-store-cpt.php +++ b/includes/data-stores/class-wc-product-variable-data-store-cpt.php @@ -63,9 +63,12 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple 'post_type' => 'product_variation', 'orderby' => array( 'menu_order' => 'ASC', 'ID' => 'ASC' ), 'fields' => 'ids', - 'post_status' => 'publish', + 'post_status' => array( 'publish', 'private' ), 'numberposts' => -1, ); + + $visible_only_args['post_status'] = 'publish'; + if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) { $visible_only_args['tax_query'][] = array( 'taxonomy' => 'product_visibility', diff --git a/includes/shortcodes/class-wc-shortcode-products.php b/includes/shortcodes/class-wc-shortcode-products.php index 00e9482188d..1bdd7da4990 100644 --- a/includes/shortcodes/class-wc-shortcode-products.php +++ b/includes/shortcodes/class-wc-shortcode-products.php @@ -508,6 +508,8 @@ class WC_Shortcode_Products { update_meta_cache( 'post', $products_ids ); update_object_term_cache( $products_ids, 'product' ); + $original_post = $GLOBALS['post']; + do_action( "woocommerce_shortcode_before_{$this->type}_loop", $this->attributes ); woocommerce_product_loop_start(); @@ -527,15 +529,17 @@ class WC_Shortcode_Products { remove_action( 'woocommerce_product_is_visible', array( $this, 'set_product_as_visible' ) ); } + $GLOBALS['post'] = $original_post; // WPCS: override ok. woocommerce_product_loop_end(); do_action( "woocommerce_shortcode_after_{$this->type}_loop", $this->attributes ); + + wp_reset_postdata(); } else { do_action( "woocommerce_shortcode_{$this->type}_loop_no_results", $this->attributes ); } woocommerce_reset_loop(); - wp_reset_postdata(); return '
    ' . ob_get_clean() . '
    '; } diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php index 978bd3da9ca..872dd218131 100644 --- a/includes/wc-core-functions.php +++ b/includes/wc-core-functions.php @@ -686,7 +686,7 @@ function wc_get_image_size( $image_size ) { 'crop' => isset( $image_size[2] ) ? $image_size[2] : 1, ); $image_size = $size['width'] . '_' . $size['height']; - } elseif ( in_array( $image_size, array( 'single', 'shop_single' ), true ) ) { + } elseif ( in_array( $image_size, array( 'single', 'shop_single', 'woocommerce_single' ), true ) ) { // If the theme supports woocommerce, take image sizes from that definition. if ( isset( $theme_support[ 'single_image_width' ] ) ) { $size['width'] = $theme_support[ 'single_image_width' ]; @@ -696,7 +696,7 @@ function wc_get_image_size( $image_size ) { $size['height'] = 9999999999; $size['crop'] = 0; $image_size = 'single'; - } elseif ( in_array( $image_size, array( 'thumbnail', 'shop_thumbnail', 'shop_catalog' ), true ) ) { + } elseif ( in_array( $image_size, array( 'thumbnail', 'shop_thumbnail', 'shop_catalog', 'woocommerce_thumbnail' ), true ) ) { // If the theme supports woocommerce, take image sizes from that definition. if ( isset( $theme_support[ 'thumbnail_image_width' ] ) ) { $size['width'] = $theme_support[ 'thumbnail_image_width' ]; diff --git a/package.json b/package.json index b03a45fabfd..81676f21a8e 100644 --- a/package.json +++ b/package.json @@ -38,12 +38,13 @@ "grunt-phpcs": "~0.4.0", "grunt-postcss": "~0.8.0", "grunt-rtlcss": "~2.0.1", - "grunt-shell": "~2.1.0", "grunt-sass": "~2.0.0", + "grunt-shell": "~2.1.0", "grunt-stylelint": "~0.8.0", "grunt-wp-i18n": "~1.0.0", "istanbul": "^1.0.0-alpha", "mocha": "^3.0.2", + "stylelint": "^7.8.0", "wc-e2e-page-objects": "0.4.0" }, "engines": { diff --git a/templates/loop/add-to-cart.php b/templates/loop/add-to-cart.php index 5a20a0cdb31..15d12082829 100644 --- a/templates/loop/add-to-cart.php +++ b/templates/loop/add-to-cart.php @@ -13,7 +13,7 @@ * @see https://docs.woocommerce.com/document/template-structure/ * @author WooThemes * @package WooCommerce/Templates - * @version 3.0.0 + * @version 3.3.0 */ if ( ! defined( 'ABSPATH' ) ) { @@ -22,13 +22,14 @@ if ( ! defined( 'ABSPATH' ) ) { global $product; -echo apply_filters( 'woocommerce_loop_add_to_cart_link', - sprintf( '%s', +echo apply_filters( 'woocommerce_loop_add_to_cart_link', // WPCS: XSS ok. + sprintf( '%s', esc_url( $product->add_to_cart_url() ), esc_attr( isset( $quantity ) ? $quantity : 1 ), esc_attr( $product->get_id() ), esc_attr( $product->get_sku() ), esc_attr( isset( $class ) ? $class : 'button' ), + esc_attr( $product->add_to_cart_description() ), esc_html( $product->add_to_cart_text() ) ), $product );