Merge branch 'feature/webhook-crud' into feature/webhook-delivery-logging

This commit is contained in:
Gerhard Potgieter 2017-11-17 08:48:57 +02:00
commit 98a382174c
41 changed files with 3823 additions and 3090 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1893,73 +1893,227 @@ ul.wc_coupon_list_block {
font-size: inherit;
margin: 3px 0;
}
}
.column-order_total,
.column-order_date {
width: 9%;
.post-type-shop_order {
.tablenav .one-page .displaying-num {
display: none;
}
.column-order_status {
width: 45px;
text-align: center;
mark {
@include ir();
background: none;
font-size: 1.4em;
margin: 0 auto;
.wp-list-table {
margin-top: 1em;
th {
padding: .75em 1em;
}
mark.pending,
mark.completed,
mark.on-hold,
mark.failed,
mark.cancelled,
mark.processing,
mark.refunded {
&::after {
@include icon;
th.sortable a, th.sorted a {
padding: 0;
}
.check-column {
width: 1px;
white-space: nowrap;
padding: 1em 1em 1em 1em !important;
vertical-align: middle;
input {
vertical-align: text-top;
margin: 1px 0;
}
}
td.column-order_number {
line-height: 26px;
.order-preview {
float:right;
width: 16px;
padding: 20px 4px 4px 4px;
height: 0;
overflow: hidden;
position: relative;
border: 2px solid transparent;
border-radius: 4px;
mark.pending::after {
content: '\e012';
color: $orange;
&::before {
@include icon( '\e010' );
line-height: 16px;
font-size: 14px;
vertical-align:middle;
top: 4px;
}
&:hover {
border: 2px solid #00a0d2;
}
}
.order-preview.disabled {
&::before {
content: '';
background: url(../../../../../wp-includes/images/wpspin.gif) no-repeat center top;
}
}
}
mark.completed::after {
content: '\e015';
color: $blue;
.column-order_date {
width: 10ch;
}
mark.on-hold::after {
content: '\e033';
color: #999;
.column-order_number {
width: 35ch;
}
mark.failed::after {
content: '\e016';
color: #d0c21f;
.column-order_status {
width: 20ch;
}
mark.cancelled::after {
content: '\e013';
color: $red;
.column-order_total {
text-align: right;
width: 10ch;
a span {
float:right;
}
}
mark.processing::after {
content: '\e011';
color: #73a724;
.column-shipping_address,
.column-billing_address {
width: 20ch;
}
th:first-child,
td:first-child {
padding-left: 2em;
}
th:last-child,
td:last-child {
padding-right: 2em;
}
tbody {
th, td {
border-top: 1px solid #f5f5f5;
}
td {
vertical-align: middle;
padding: 1em;
mark.refunded::after {
content: '\e014';
color: #999;
.post-row-actions {
display: none;
}
.order-status {
display: inline-flex;
padding: 0px 1em;
line-height: 2.5em;
color: #777;
background: #E5E5E5;
border-radius: 4px;
border-bottom: 1px solid rgba(0,0,0,0.05);
margin: -.5em 0;
cursor: inherit !important;
&.status-completed {
background: #C8D7E1;
color: #2e4453;
}
&.status-on-hold {
background: #f8dda7;
color: #94660c;
}
&.status-failed {
background: #eba3a3;
color: #761919;
}
&.status-processing {
background: #C6E1C6;
color: #5B841B;
}
&.status-trash {
background: #eba3a3;
color: #761919;
}
}
}
tr:hover:not(.status-trash) {
td, th {
cursor: pointer;
}
}
}
}
}
td.column-order_status {
padding-top: 9px;
// Hide some columns on smaller screens.
@media only screen and (max-width: 1400px) {
.post-type-shop_order .wp-list-table {
.column-billing_address {
display:none;
visibility:hidden;
}
}
}
@media only screen and (max-width: 1200px) {
.post-type-shop_order .wp-list-table {
.column-shipping_address,
.column-order_total {
display:none;
visibility:hidden;
}
}
}
.wc-order-preview {
article {
padding: 0 !important;
}
.wc-order-preview__table {
width: 100%;
margin: 0;
border-bottom: 1px solid #ccc;
th, td {
padding: 1em 1.5em;
text-align: left;
border: 0;
border-bottom: 1px solid #eee;
margin: 0;
background: transparent;
box-shadow: none;
text-align: right;
vertical-align: top;
}
td:first-child,
th:first-child {
text-align: left;
}
th {
border-color: #ccc;
}
tr:last-child td {
border: 0;
}
.wc-order-item-sku {
margin-top: .5em;
}
.wc-order-item-meta {
margin-top: .5em;
th, td {
padding: 0;
border: 0;
text-align: left;
vertical-align: top;
}
td:last-child {
padding-left: .5em;
}
}
}
.wc-order-preview-addresses {
overflow:hidden;
.wc-order-preview-address {
width: 50%;
float: left;
padding: 1.5em;
box-sizing: border-box;
h2 {
margin-top: 0;
}
strong {
display: block;
margin-top: 1em;
}
}
}
}
@ -5418,20 +5572,6 @@ table.bar_chart {
.post-type-shop_order {
.wp-list-table {
.column-order_status {
display: none;
text-align: left;
padding-bottom: 0;
mark {
margin: 0;
}
&::before {
display: none !important;
}
}
.column-customer_message,
.column-order_notes {
text-align: inherit;
@ -5521,6 +5661,14 @@ table.bar_chart {
}
}
@media screen and (max-width: 782px) {
.wc-backbone-modal .wc-backbone-modal-content {
width: 100%;
height: 100%;
min-width: 100%;
}
}
.wc-backbone-modal-backdrop {
position: fixed;
top: 0;
@ -5716,7 +5864,7 @@ table.bar_chart {
}
select,
input {
line-height: 32px;
line-height: 1;
height: 32px;
}
.select2-container {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -602,6 +602,7 @@ body {
.wc-wizard-service-enable input {
visibility: hidden;
position: relative;
cursor: pointer;
&:before {
content: "\f347"; // down chevron

View File

@ -1 +1 @@
!function(e,t,n){"use strict";e.fn.WCBackboneModal=function(t){return this.each(function(){var n=new e.WCBackboneModal(e(this),t)(n())})},e.WCBackboneModal=function(t,n){var o=e.extend({},e.WCBackboneModal.defaultOptions,n);o.template&&new e.WCBackboneModal.View({target:o.template,string:o.variable})()},e.WCBackboneModal.defaultOptions={template:"",variable:{}},e.WCBackboneModal.View=t.View.extend({tagName:"div",id:"wc-backbone-modal-dialog",_target:undefined,_string:undefined,events:{"click .modal-close":"closeButton","click #btn-ok":"addButton","touchstart #btn-ok":"addButton",keydown:"keyboardActions"},resizeContent:function(){var t=e(".wc-backbone-modal-content").find("article"),n=.75*e(window).height();t.css({"max-height":n+"px"})},initialize:function(t){var o=this;this._target=t.target,this._string=t.string,n.bindAll(this,"render"),this.render(),e(window).resize(function(){o.resizeContent()})},render:function(){var t=wp.template(this._target);this.$el.append(t(this._string)),e(document.body).css({overflow:"hidden"}).append(this.$el),this.resizeContent(),this.$(".wc-backbone-modal-content").attr("tabindex","0").focus(),e(document.body).trigger("init_tooltips"),e(document.body).trigger("wc_backbone_modal_loaded",this._target)},closeButton:function(t){t.preventDefault(),e(document.body).trigger("wc_backbone_modal_before_remove",this._target),this.undelegateEvents(),e(document).off("focusin"),e(document.body).css({overflow:"auto"}),this.remove(),e(document.body).trigger("wc_backbone_modal_removed",this._target)},addButton:function(t){e(document.body).trigger("wc_backbone_modal_response",[this._target,this.getFormData()]),this.closeButton(t)},getFormData:function(){var t={};return e(document.body).trigger("wc_backbone_modal_before_update",this._target),e.each(e("form",this.$el).serializeArray(),function(n,o){-1!==o.name.indexOf("[]")?(o.name=o.name.replace("[]",""),t[o.name]=e.makeArray(t[o.name]),t[o.name].push(o.value)):t[o.name]=o.value}),t},keyboardActions:function(e){var t=e.keyCode||e.which;13!==t||e.target.tagName&&("input"===e.target.tagName.toLowerCase()||"textarea"===e.target.tagName.toLowerCase())||this.addButton(e),27===t&&this.closeButton(e)}})}(jQuery,Backbone,_);
!function(e,t,n){"use strict";e.fn.WCBackboneModal=function(t){return this.each(function(){new e.WCBackboneModal(e(this),t)})},e.WCBackboneModal=function(t,n){var o=e.extend({},e.WCBackboneModal.defaultOptions,n);o.template&&new e.WCBackboneModal.View({target:o.template,string:o.variable})},e.WCBackboneModal.defaultOptions={template:"",variable:{}},e.WCBackboneModal.View=t.View.extend({tagName:"div",id:"wc-backbone-modal-dialog",_target:undefined,_string:undefined,events:{"click .modal-close":"closeButton","click #btn-ok":"addButton","touchstart #btn-ok":"addButton",keydown:"keyboardActions"},resizeContent:function(){var t=e(".wc-backbone-modal-content").find("article"),n=.75*e(window).height();t.css({"max-height":n+"px"})},initialize:function(t){var o=this;this._target=t.target,this._string=t.string,n.bindAll(this,"render"),this.render(),e(window).resize(function(){o.resizeContent()})},render:function(){var t=wp.template(this._target);this.$el.append(t(this._string)),e(document.body).css({overflow:"hidden"}).append(this.$el),this.resizeContent(),this.$(".wc-backbone-modal-content").attr("tabindex","0").focus(),e(document.body).trigger("init_tooltips"),e(document.body).trigger("wc_backbone_modal_loaded",this._target)},closeButton:function(t){t.preventDefault(),e(document.body).trigger("wc_backbone_modal_before_remove",this._target),this.undelegateEvents(),e(document).off("focusin"),e(document.body).css({overflow:"auto"}),this.remove(),e(document.body).trigger("wc_backbone_modal_removed",this._target)},addButton:function(t){e(document.body).trigger("wc_backbone_modal_response",[this._target,this.getFormData()]),this.closeButton(t)},getFormData:function(){var t={};return e(document.body).trigger("wc_backbone_modal_before_update",this._target),e.each(e("form",this.$el).serializeArray(),function(n,o){-1!==o.name.indexOf("[]")?(o.name=o.name.replace("[]",""),t[o.name]=e.makeArray(t[o.name]),t[o.name].push(o.value)):t[o.name]=o.value}),t},keyboardActions:function(e){var t=e.keyCode||e.which;13!==t||e.target.tagName&&("input"===e.target.tagName.toLowerCase()||"textarea"===e.target.tagName.toLowerCase())||this.addButton(e),27===t&&this.closeButton(e)}})}(jQuery,Backbone,_);

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
!function(t){t("select#woocommerce_allowed_countries").change(function(){"specific"===t(this).val()?(t(this).closest("tr").next("tr").hide(),t(this).closest("tr").next().next("tr").show()):"all_except"===t(this).val()?(t(this).closest("tr").next("tr").show(),t(this).closest("tr").next().next("tr").hide()):(t(this).closest("tr").next("tr").hide(),t(this).closest("tr").next().next("tr").hide())}).change(),t("select#woocommerce_ship_to_countries").change(function(){"specific"===t(this).val()?t(this).closest("tr").next("tr").show():t(this).closest("tr").next("tr").hide()}).change(),t("input#woocommerce_manage_stock").change(function(){t(this).is(":checked")?t(this).closest("tbody").find(".manage_stock_field").closest("tr").show():t(this).closest("tbody").find(".manage_stock_field").closest("tr").hide()}).change(),t(".colorpick").iris({change:function(e,i){t(this).parent().find(".colorpickpreview").css({backgroundColor:i.color.toString()})},hide:!0,border:!0}).on("click focus",function(e){e.stopPropagation(),t(".iris-picker").hide(),t(this).closest("td").find(".iris-picker").show(),t(this).data("original-value",t(this).val())}).on("change",function(){t(this).is(".iris-error")&&(t(this).data("original-value").match(/^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/)?t(this).val(t(this).data("original-value")).change():t(this).val("").change())}),t("body").on("click",function(){t(".iris-picker").hide()}),t(function(){var e=!1;t("input, textarea, select, checkbox").change(function(){e=!0}),t(".woo-nav-tab-wrapper a").click(function(){window.onbeforeunload=e?function(){return woocommerce_settings_params.i18n_nav_warning}:""}),t(".submit input").click(function(){window.onbeforeunload=""})}),t("table.wc_gateways tbody, table.wc_shipping tbody").sortable({items:"tr",cursor:"move",axis:"y",handle:"td.sort",scrollSensitivity:40,helper:function(e,i){return i.children().each(function(){t(this).width(t(this).width())}),i.css("left","0"),i},start:function(t,e){e.item.css("background-color","#f6f6f6")},stop:function(t,e){e.item.removeAttr("style")}}),t(".woocommerce").on("click",".select_all",function(){return t(this).closest("td").find("select option").attr("selected","selected"),t(this).closest("td").find("select").trigger("change"),!1}),t(".woocommerce").on("click",".select_none",function(){return t(this).closest("td").find("select option").removeAttr("selected"),t(this).closest("td").find("select").trigger("change"),!1}),t(".woocommerce-thumbnail-cropping").on("change","input",function(){var e=t(".woocommerce-thumbnail-cropping input:checked").val(),i=t(".woocommerce-thumbnail-preview-block__image");if("custom"===e){var o=90/Math.max(parseInt(t('input[name="thumbnail_cropping_aspect_ratio_width"]').val(),10),1)*Math.max(parseInt(t('input[name="thumbnail_cropping_aspect_ratio_height"]').val(),10),1);i.animate({height:o+"px"},200),t(".woocommerce-thumbnail-cropping-aspect-ratio").slideDown(200)}else if("uncropped"===e){var c=["120","60","80"];i.each(function(e,i){var o=c[e];t(i).animate({height:o+"px"},200)}),t(".woocommerce-thumbnail-cropping-aspect-ratio").hide()}else i.animate({height:"90px"},200),t(".woocommerce-thumbnail-cropping-aspect-ratio").hide();return!1}),t(".woocommerce-thumbnail-cropping").find("input").change()}(jQuery);
!function(t){t("select#woocommerce_allowed_countries").change(function(){"specific"===t(this).val()?(t(this).closest("tr").next("tr").hide(),t(this).closest("tr").next().next("tr").show()):"all_except"===t(this).val()?(t(this).closest("tr").next("tr").show(),t(this).closest("tr").next().next("tr").hide()):(t(this).closest("tr").next("tr").hide(),t(this).closest("tr").next().next("tr").hide())}).change(),t("select#woocommerce_ship_to_countries").change(function(){"specific"===t(this).val()?t(this).closest("tr").next("tr").show():t(this).closest("tr").next("tr").hide()}).change(),t("input#woocommerce_manage_stock").change(function(){t(this).is(":checked")?t(this).closest("tbody").find(".manage_stock_field").closest("tr").show():t(this).closest("tbody").find(".manage_stock_field").closest("tr").hide()}).change(),t(".colorpick").iris({change:function(e,i){t(this).parent().find(".colorpickpreview").css({backgroundColor:i.color.toString()})},hide:!0,border:!0}).on("click focus",function(e){e.stopPropagation(),t(".iris-picker").hide(),t(this).closest("td").find(".iris-picker").show(),t(this).data("original-value",t(this).val())}).on("change",function(){t(this).is(".iris-error")&&(t(this).data("original-value").match(/^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/)?t(this).val(t(this).data("original-value")).change():t(this).val("").change())}),t("body").on("click",function(){t(".iris-picker").hide()}),t(function(){var e=!1;t("input, textarea, select, checkbox").change(function(){e=!0}),t(".woo-nav-tab-wrapper a").click(function(){window.onbeforeunload=e?function(){return woocommerce_settings_params.i18n_nav_warning}:""}),t(".submit input").click(function(){window.onbeforeunload=""})}),t("table.wc_gateways tbody, table.wc_shipping tbody").sortable({items:"tr",cursor:"move",axis:"y",handle:"td.sort",scrollSensitivity:40,helper:function(e,i){return i.children().each(function(){t(this).width(t(this).width())}),i.css("left","0"),i},start:function(t,e){e.item.css("background-color","#f6f6f6")},stop:function(t,e){e.item.removeAttr("style")}}),t(".woocommerce").on("click",".select_all",function(){return t(this).closest("td").find("select option").attr("selected","selected"),t(this).closest("td").find("select").trigger("change"),!1}),t(".woocommerce").on("click",".select_none",function(){return t(this).closest("td").find("select option").removeAttr("selected"),t(this).closest("td").find("select").trigger("change"),!1}),t(".woocommerce-thumbnail-cropping").on("change input","input",function(){var e=t(".woocommerce-thumbnail-cropping input:checked").val(),i=t(".woocommerce-thumbnail-preview-block__image");if("custom"===e){var o=90/Math.max(parseInt(t('input[name="thumbnail_cropping_aspect_ratio_width"]').val(),10),1)*Math.max(parseInt(t('input[name="thumbnail_cropping_aspect_ratio_height"]').val(),10),1);i.animate({height:o+"px"},200),t(".woocommerce-thumbnail-cropping-aspect-ratio").slideDown(200)}else if("uncropped"===e){var c=["120","60","80"];i.each(function(e,i){var o=c[e];t(i).animate({height:o+"px"},200)}),t(".woocommerce-thumbnail-cropping-aspect-ratio").hide()}else i.animate({height:"90px"},200),t(".woocommerce-thumbnail-cropping-aspect-ratio").hide();return!1}),t(".woocommerce-thumbnail-cropping").find("input").change()}(jQuery);

View File

@ -0,0 +1,78 @@
/* global wc_orders_params */
jQuery( function( $ ) {
if ( typeof wc_orders_params === 'undefined' ) {
return false;
}
/**
* WCOrdersTable class.
*/
var WCOrdersTable = function() {
$( document )
.on( 'click', '.post-type-shop_order .wp-list-table tbody td', this.onRowClick )
.on( 'click', '.order-preview:not(.disabled)', this.onPreview );
};
/**
* Click a row.
*/
WCOrdersTable.prototype.onRowClick = function( e ) {
if ( $( e.target ).filter( 'a' ).length ) {
return true;
}
var $row = $( this ).closest( 'tr' ),
href = $row.find( 'a.order-view' ).attr( 'href' );
if ( href.length ) {
window.location = href;
}
};
/**
* Preview an order.
*/
WCOrdersTable.prototype.onPreview = function() {
var $previewButton = $( this ),
$order_id = $previewButton.data( 'order-id' );
if ( $previewButton.data( 'order-data' ) ) {
$( this ).WCBackboneModal({
template: 'wc-modal-view-order',
variable : $previewButton.data( 'order-data' )
});
} else {
$previewButton.addClass( 'disabled' );
$.ajax({
url: wc_orders_params.ajax_url,
data: {
order_id: $order_id,
action : 'woocommerce_get_order_details',
security: wc_orders_params.preview_nonce
},
type: 'GET',
success: function( response ) {
$( '.order-preview' ).removeClass( 'disabled' );
if ( response.success ) {
$previewButton.data( 'order-data', response.data );
$( this ).WCBackboneModal({
template: 'wc-modal-view-order',
variable : response.data
});
}
}
});
}
return false;
};
/**
* Init WCOrdersTable.
*/
new WCOrdersTable();
} );

1
assets/js/admin/wc-orders.min.js vendored Normal file
View File

@ -0,0 +1 @@
jQuery(function(e){if("undefined"==typeof wc_orders_params)return!1;var r=function(){e(document).on("click",".post-type-shop_order .wp-list-table tbody td",this.onRowClick).on("click",".order-preview:not(.disabled)",this.onPreview)};r.prototype.onRowClick=function(r){if(e(r.target).filter("a").length)return!0;var a=e(this).closest("tr").find("a.order-view").attr("href");a.length&&(window.location=a)},r.prototype.onPreview=function(){var r=e(this),a=r.data("order-id");return r.data("order-data")?e(this).WCBackboneModal({template:"wc-modal-view-order",variable:r.data("order-data")}):(r.addClass("disabled"),e.ajax({url:wc_orders_params.ajax_url,data:{order_id:a,action:"woocommerce_get_order_details",security:wc_orders_params.preview_nonce},type:"GET",success:function(a){e(".order-preview").removeClass("disabled"),a.success&&(r.data("order-data",a.data),e(this).WCBackboneModal({template:"wc-modal-view-order",variable:a.data}))}})),!1},new r});

View File

@ -36,17 +36,23 @@ jQuery( function( $ ) {
} );
$( '.wc-wizard-services' ).on( 'click', '.wc-wizard-service-enable', function( e ) {
e.stopPropagation();
var eventTarget = $( e.target );
if ( eventTarget.is( 'input' ) ) {
e.stopPropagation();
return;
}
var $checkbox = $( this ).find( 'input[type="checkbox"]' );
var $checkbox = $( this ).find( '.wc-wizard-service-toggle input' );
$checkbox.prop( 'checked', ! $checkbox.prop( 'checked' ) ).change();
} );
$( '.wc-wizard-services-list-toggle' ).on( 'change', '.wc-wizard-service-enable input', function() {
$( this ).closest( '.wc-wizard-services-list-toggle' ).toggleClass( 'closed' );
$( this ).closest( '.wc-wizard-services' ).find( '.wc-wizard-service-item' )
.slideToggle()
.css( 'display', 'flex' );
$( this ).closest( '.wc-wizard-services-list-toggle' ).toggleClass( 'closed' );
$( this ).closest( '.wc-wizard-services' ).find( '.wc-wizard-service-item' )
.slideToggle()
.css( 'display', 'flex' );
} );
$( '.wc-wizard-services' ).on( 'change', '.wc-wizard-shipping-method-select .method', function( e ) {

View File

@ -1 +1 @@
jQuery(function(e){function i(){e(".wc-setup-content").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})}function s(){e("form.activate-jetpack").submit()}function t(){wp.ajax.post("setup_wizard_check_jetpack").then(function(e){if(!e||!e.is_active||"yes"===e.is_active)return s();setTimeout(t,3e3)}).fail(function(){s()})}e(".button-next").on("click",function(){var s=e(this).parents("form").get(0);return("function"!=typeof s.checkValidity||s.checkValidity())&&i(),!0}),e(".wc-wizard-services").on("change",".wc-wizard-service-enable input",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-toggle").removeClass("disabled"),e(this).closest(".wc-wizard-service-item").addClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").removeClass("hide")):(e(this).closest(".wc-wizard-service-toggle").addClass("disabled"),e(this).closest(".wc-wizard-service-item").removeClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").addClass("hide"))}),e(".wc-wizard-services").on("click",".wc-wizard-service-enable",function(i){i.stopPropagation();var s=e(this).find(".wc-wizard-service-toggle input");s.prop("checked",!s.prop("checked")).change()}),e(".wc-wizard-services-list-toggle").on("change",".wc-wizard-service-enable input",function(){e(this).closest(".wc-wizard-services-list-toggle").toggleClass("closed"),e(this).closest(".wc-wizard-services").find(".wc-wizard-service-item").slideToggle().css("display","flex")}),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-select .method",function(i){var s=e(this).closest(".wc-wizard-service-description"),t=i.target.value,c=s.find(".shipping-method-descriptions");c.find(".shipping-method-description").addClass("hide"),c.find("."+t).removeClass("hide");var r=s.find(".shipping-method-settings");r.find(".shipping-method-setting").addClass("hide").find(".shipping-method-required-field").prop("required",!1),r.find("."+t).removeClass("hide").find(".shipping-method-required-field").prop("required",!0)}),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-enable",function(){var i=e(this).is(":checked");e(this).closest(".wc-wizard-service-item").find(".shipping-method-required-field").prop("required",i)}),e(".activate-jetpack").on("click",".button-primary",function(e){if(i(),"no"===wc_setup_params.pending_jetpack_install)return!0;e.preventDefault(),t()}),e(".wc-wizard-services").on("change","input#stripe_create_account",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!0),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email").show()):(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!1),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email").hide())}),e(".wc-wizard-services input#stripe_create_account").change(),e("select#store_country_state").on("change",function(){var i=this.value.split(":")[0];e("select#currency_code").val(wc_setup_currencies[i]).change()})});
jQuery(function(e){function i(){e(".wc-setup-content").block({message:null,overlayCSS:{background:"#fff",opacity:.6}})}function s(){e("form.activate-jetpack").submit()}function t(){wp.ajax.post("setup_wizard_check_jetpack").then(function(e){if(!e||!e.is_active||"yes"===e.is_active)return s();setTimeout(t,3e3)}).fail(function(){s()})}e(".button-next").on("click",function(){var s=e(this).parents("form").get(0);return("function"!=typeof s.checkValidity||s.checkValidity())&&i(),!0}),e(".wc-wizard-services").on("change",".wc-wizard-service-enable input",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-toggle").removeClass("disabled"),e(this).closest(".wc-wizard-service-item").addClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").removeClass("hide")):(e(this).closest(".wc-wizard-service-toggle").addClass("disabled"),e(this).closest(".wc-wizard-service-item").removeClass("checked"),e(this).closest(".wc-wizard-service-item").find(".wc-wizard-service-settings").addClass("hide"))}),e(".wc-wizard-services").on("click",".wc-wizard-service-enable",function(i){if(e(i.target).is("input"))i.stopPropagation();else{var s=e(this).find('input[type="checkbox"]');s.prop("checked",!s.prop("checked")).change()}}),e(".wc-wizard-services-list-toggle").on("change",".wc-wizard-service-enable input",function(){e(this).closest(".wc-wizard-services-list-toggle").toggleClass("closed"),e(this).closest(".wc-wizard-services").find(".wc-wizard-service-item").slideToggle().css("display","flex")}),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-select .method",function(i){var s=e(this).closest(".wc-wizard-service-description"),t=i.target.value,c=s.find(".shipping-method-descriptions");c.find(".shipping-method-description").addClass("hide"),c.find("."+t).removeClass("hide");var r=s.find(".shipping-method-settings");r.find(".shipping-method-setting").addClass("hide").find(".shipping-method-required-field").prop("required",!1),r.find("."+t).removeClass("hide").find(".shipping-method-required-field").prop("required",!0)}),e(".wc-wizard-services").on("change",".wc-wizard-shipping-method-enable",function(){var i=e(this).is(":checked");e(this).closest(".wc-wizard-service-item").find(".shipping-method-required-field").prop("required",i)}),e(".activate-jetpack").on("click",".button-primary",function(e){if(i(),"no"===wc_setup_params.pending_jetpack_install)return!0;e.preventDefault(),t()}),e(".wc-wizard-services").on("change","input#stripe_create_account",function(){e(this).is(":checked")?(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!0),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email").show()):(e(this).closest(".wc-wizard-service-settings").find("input.payment-email-input").prop("required",!1),e(this).closest(".wc-wizard-service-settings").find(".wc-wizard-service-setting-stripe_email").hide())}),e(".wc-wizard-services input#stripe_create_account").change(),e("select#store_country_state").on("change",function(){var i=this.value.split(":")[0];e("select#currency_code").val(wc_setup_currencies[i]).change()})});

View File

@ -184,7 +184,7 @@ jQuery( function( $ ) {
*
* @param {Object} evt The JQuery event.
*/
shipping_method_selected: function( evt ) {
shipping_method_selected: function() {
var shipping_methods = {};
$( 'select.shipping_method, input[name^=shipping_method][type=radio]:checked, input[name^=shipping_method][type=hidden]' ).each( function() {

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
jQuery(function(t){t(".lost_reset_password").on("submit",function(){t('input[type="submit"]',this).attr("disabled","disabled")})});
jQuery(function(t){t(".lost_reset_password").on("submit",function(){t('button[type="submit"]',this).attr("disabled","disabled")})});

View File

@ -1 +1 @@
!function(s){"use strict";var r={init:function(){s(document.body).on("keyup change","form.register #reg_password, form.checkout #account_password, form.edit-account #password_1, form.lost_reset_password #password_1",this.strengthMeter),s("form.checkout #createaccount").change()},strengthMeter:function(){var e=s("form.register, form.checkout, form.edit-account, form.lost_reset_password"),t=s('input[type="submit"]',e),a=s("#reg_password, #account_password, #password_1",e),o=1,d=a.val();r.includeMeter(e,a),o=r.checkPasswordStrength(e,a),d.length>0&&o<wc_password_strength_meter_params.min_password_strength&&!e.is("form.checkout")?t.attr("disabled","disabled").addClass("disabled"):t.removeAttr("disabled","disabled").removeClass("disabled")},includeMeter:function(r,e){var t=r.find(".woocommerce-password-strength");""===e.val()?(t.remove(),s(document.body).trigger("wc-password-strength-removed")):0===t.length&&(e.after('<div class="woocommerce-password-strength" aria-live="polite"></div>'),s(document.body).trigger("wc-password-strength-added"))},checkPasswordStrength:function(s,r){var e=s.find(".woocommerce-password-strength"),t=s.find(".woocommerce-password-hint"),a='<small class="woocommerce-password-hint">'+wc_password_strength_meter_params.i18n_password_hint+"</small>",o=wp.passwordStrength.meter(r.val(),wp.passwordStrength.userInputBlacklist()),d="";switch(e.removeClass("short bad good strong"),t.remove(),o<wc_password_strength_meter_params.min_password_strength&&(d=" - "+wc_password_strength_meter_params.i18n_password_error),o){case 0:e.addClass("short").html(pwsL10n["short"]+d),e.after(a);break;case 1:case 2:e.addClass("bad").html(pwsL10n.bad+d),e.after(a);break;case 3:e.addClass("good").html(pwsL10n.good+d);break;case 4:e.addClass("strong").html(pwsL10n.strong+d);break;case 5:e.addClass("short").html(pwsL10n.mismatch)}return o}};r.init()}(jQuery);
!function(s){"use strict";var r={init:function(){s(document.body).on("keyup change","form.register #reg_password, form.checkout #account_password, form.edit-account #password_1, form.lost_reset_password #password_1",this.strengthMeter),s("form.checkout #createaccount").change()},strengthMeter:function(){var e=s("form.register, form.checkout, form.edit-account, form.lost_reset_password"),t=s('button[type="submit"]',e),o=s("#reg_password, #account_password, #password_1",e),a=1,d=o.val();r.includeMeter(e,o),a=r.checkPasswordStrength(e,o),d.length>0&&a<wc_password_strength_meter_params.min_password_strength&&!e.is("form.checkout")?t.attr("disabled","disabled").addClass("disabled"):t.removeAttr("disabled","disabled").removeClass("disabled")},includeMeter:function(r,e){var t=r.find(".woocommerce-password-strength");""===e.val()?(t.remove(),s(document.body).trigger("wc-password-strength-removed")):0===t.length&&(e.after('<div class="woocommerce-password-strength" aria-live="polite"></div>'),s(document.body).trigger("wc-password-strength-added"))},checkPasswordStrength:function(s,r){var e=s.find(".woocommerce-password-strength"),t=s.find(".woocommerce-password-hint"),o='<small class="woocommerce-password-hint">'+wc_password_strength_meter_params.i18n_password_hint+"</small>",a=wp.passwordStrength.meter(r.val(),wp.passwordStrength.userInputBlacklist()),d="";switch(e.removeClass("short bad good strong"),t.remove(),a<wc_password_strength_meter_params.min_password_strength&&(d=" - "+wc_password_strength_meter_params.i18n_password_error),a){case 0:e.addClass("short").html(pwsL10n["short"]+d),e.after(o);break;case 1:case 2:e.addClass("bad").html(pwsL10n.bad+d),e.after(o);break;case 3:e.addClass("good").html(pwsL10n.good+d);break;case 4:e.addClass("strong").html(pwsL10n.strong+d);break;case 5:e.addClass("short").html(pwsL10n.mismatch)}return a}};r.init()}(jQuery);

View File

@ -1672,7 +1672,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
}
}
/* translators: %s: shipping method */
/* translators: %s: method */
$shipping .= apply_filters( 'woocommerce_order_shipping_to_display_shipped_via', '&nbsp;<small class="shipped_via">' . sprintf( __( 'via %s', 'woocommerce' ), $this->get_shipping_method() ) . '</small>', $this );
} elseif ( $this->get_shipping_method() ) {

View File

@ -93,7 +93,6 @@ class WC_Admin_Assets {
wp_register_script( 'woocommerce_admin', WC()->plugin_url() . '/assets/js/admin/woocommerce_admin' . $suffix . '.js', array( 'jquery', 'jquery-blockui', 'jquery-ui-sortable', 'jquery-ui-widget', 'jquery-ui-core', 'jquery-tiptip' ), WC_VERSION );
wp_register_script( 'jquery-blockui', WC()->plugin_url() . '/assets/js/jquery-blockui/jquery.blockUI' . $suffix . '.js', array( 'jquery' ), '2.70', true );
wp_register_script( 'jquery-tiptip', WC()->plugin_url() . '/assets/js/jquery-tiptip/jquery.tipTip' . $suffix . '.js', array( 'jquery' ), WC_VERSION, true );
wp_register_script( 'accounting', WC()->plugin_url() . '/assets/js/accounting/accounting' . $suffix . '.js', array( 'jquery' ), '0.4.2' );
wp_register_script( 'round', WC()->plugin_url() . '/assets/js/round/round' . $suffix . '.js', array( 'jquery' ), WC_VERSION );
wp_register_script( 'wc-admin-meta-boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes' . $suffix . '.js', array( 'jquery', 'jquery-ui-datepicker', 'jquery-ui-sortable', 'accounting', 'round', 'wc-enhanced-select', 'plupload-all', 'stupidtable', 'jquery-tiptip' ), WC_VERSION );
wp_register_script( 'zeroclipboard', WC()->plugin_url() . '/assets/js/zeroclipboard/jquery.zeroclipboard' . $suffix . '.js', array( 'jquery' ), WC_VERSION );
@ -131,12 +130,18 @@ class WC_Admin_Assets {
'search_categories_nonce' => wp_create_nonce( 'search-categories' ),
) );
// Accounting
wp_register_script( 'accounting', WC()->plugin_url() . '/assets/js/accounting/accounting' . $suffix . '.js', array( 'jquery' ), '0.4.2' );
wp_localize_script( 'accounting', 'accounting_params', array(
'mon_decimal_point' => wc_get_price_decimal_separator(),
) );
// WooCommerce admin pages
wp_register_script( 'wc-orders', WC()->plugin_url() . '/assets/js/admin/wc-orders' . $suffix . '.js', array( 'jquery', 'wp-util', 'underscore', 'backbone', 'jquery-blockui' ), WC_VERSION );
wp_localize_script( 'wc-orders', 'wc_orders_params', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'preview_nonce' => wp_create_nonce( 'woocommerce-preview-order' ),
) );
// WooCommerce admin pages.
if ( in_array( $screen_id, wc_get_screen_ids() ) ) {
wp_enqueue_script( 'iris' );
wp_enqueue_script( 'woocommerce_admin' );

View File

@ -2,7 +2,7 @@
/**
* Setup menus in WP admin.
*
* @author WooThemes
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 2.5.0
@ -12,340 +12,339 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
if ( class_exists( 'WC_Admin_Menus', false ) ) {
return new WC_Admin_Menus();
}
/**
* WC_Admin_Menus Class.
*/
class WC_Admin_Menus {
/**
* WC_Admin_Menus Class.
* Hook in tabs.
*/
class WC_Admin_Menus {
public function __construct() {
// Add menus.
add_action( 'admin_menu', array( $this, 'admin_menu' ), 9 );
add_action( 'admin_menu', array( $this, 'reports_menu' ), 20 );
add_action( 'admin_menu', array( $this, 'settings_menu' ), 50 );
add_action( 'admin_menu', array( $this, 'status_menu' ), 60 );
/**
* Hook in tabs.
*/
public function __construct() {
// Add menus.
add_action( 'admin_menu', array( $this, 'admin_menu' ), 9 );
add_action( 'admin_menu', array( $this, 'reports_menu' ), 20 );
add_action( 'admin_menu', array( $this, 'settings_menu' ), 50 );
add_action( 'admin_menu', array( $this, 'status_menu' ), 60 );
if ( apply_filters( 'woocommerce_show_addons_page', true ) ) {
add_action( 'admin_menu', array( $this, 'addons_menu' ), 70 );
}
add_action( 'admin_head', array( $this, 'menu_highlight' ) );
add_action( 'admin_head', array( $this, 'menu_order_count' ) );
add_filter( 'menu_order', array( $this, 'menu_order' ) );
add_filter( 'custom_menu_order', array( $this, 'custom_menu_order' ) );
// Add endpoints custom URLs in Appearance > Menus > Pages.
add_action( 'admin_head-nav-menus.php', array( $this, 'add_nav_menu_meta_boxes' ) );
// Admin bar menus.
if ( apply_filters( 'woocommerce_show_admin_bar_visit_store', true ) ) {
add_action( 'admin_bar_menu', array( $this, 'admin_bar_menus' ), 31 );
}
if ( apply_filters( 'woocommerce_show_addons_page', true ) ) {
add_action( 'admin_menu', array( $this, 'addons_menu' ), 70 );
}
/**
* Add menu items.
*/
public function admin_menu() {
global $menu;
add_action( 'admin_head', array( $this, 'menu_highlight' ) );
add_action( 'admin_head', array( $this, 'menu_order_count' ) );
add_filter( 'menu_order', array( $this, 'menu_order' ) );
add_filter( 'custom_menu_order', array( $this, 'custom_menu_order' ) );
if ( current_user_can( 'manage_woocommerce' ) ) {
$menu[] = array( '', 'read', 'separator-woocommerce', '', 'wp-menu-separator woocommerce' );
}
// Add endpoints custom URLs in Appearance > Menus > Pages.
add_action( 'admin_head-nav-menus.php', array( $this, 'add_nav_menu_meta_boxes' ) );
add_menu_page( __( 'WooCommerce', 'woocommerce' ), __( 'WooCommerce', 'woocommerce' ), 'manage_woocommerce', 'woocommerce', null, null, '55.5' );
add_submenu_page( 'edit.php?post_type=product', __( 'Attributes', 'woocommerce' ), __( 'Attributes', 'woocommerce' ), 'manage_product_terms', 'product_attributes', array( $this, 'attributes_page' ) );
}
/**
* Add menu item.
*/
public function reports_menu() {
if ( current_user_can( 'manage_woocommerce' ) ) {
add_submenu_page( 'woocommerce', __( 'Reports', 'woocommerce' ), __( 'Reports', 'woocommerce' ) , 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ) );
} else {
add_menu_page( __( 'Sales reports', 'woocommerce' ), __( 'Sales reports', 'woocommerce' ) , 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ), null, '55.6' );
}
}
/**
* Add menu item.
*/
public function settings_menu() {
$settings_page = add_submenu_page( 'woocommerce', __( 'WooCommerce settings', 'woocommerce' ), __( 'Settings', 'woocommerce' ) , 'manage_woocommerce', 'wc-settings', array( $this, 'settings_page' ) );
add_action( 'load-' . $settings_page, array( $this, 'settings_page_init' ) );
}
/**
* Loads gateways and shipping methods into memory for use within settings.
*/
public function settings_page_init() {
global $current_tab, $current_section;
WC()->payment_gateways();
WC()->shipping();
// Include settings pages.
WC_Admin_Settings::get_settings_pages();
// Get current tab/section.
$current_tab = empty( $_GET['tab'] ) ? 'general' : sanitize_title( wp_unslash( $_GET['tab'] ) );
$current_section = empty( $_REQUEST['section'] ) ? '' : sanitize_title( wp_unslash( $_REQUEST['section'] ) );
// Save settings if data has been posted.
// @codingStandardsIgnoreStart
if ( ! empty( $_POST ) ) {
WC_Admin_Settings::save();
}
// @codingStandardsIgnoreEnd
// Add any posted messages.
if ( ! empty( $_GET['wc_error'] ) ) {
WC_Admin_Settings::add_error( sanitize_title( wp_unslash( $_GET['wc_error'] ) ) );
}
if ( ! empty( $_GET['wc_message'] ) ) {
WC_Admin_Settings::add_message( sanitize_title( wp_unslash( $_GET['wc_message'] ) ) );
}
}
/**
* Add menu item.
*/
public function status_menu() {
add_submenu_page( 'woocommerce', __( 'WooCommerce status', 'woocommerce' ), __( 'Status', 'woocommerce' ) , 'manage_woocommerce', 'wc-status', array( $this, 'status_page' ) );
}
/**
* Addons menu item.
*/
public function addons_menu() {
$count_html = WC_Helper_Updater::get_updates_count_html();
$menu_title = sprintf( __( 'Extensions %s', 'woocommerce' ), $count_html );
add_submenu_page( 'woocommerce', __( 'WooCommerce extensions', 'woocommerce' ), $menu_title, 'manage_woocommerce', 'wc-addons', array( $this, 'addons_page' ) );
}
/**
* Highlights the correct top level admin menu item for post type add screens.
*/
public function menu_highlight() {
global $parent_file, $submenu_file, $post_type;
// @codingStandardsIgnoreStart
switch ( $post_type ) {
case 'shop_order' :
case 'shop_coupon' :
$parent_file = 'woocommerce';
break;
case 'product' :
$screen = get_current_screen();
if ( $screen && taxonomy_is_product_attribute( $screen->taxonomy ) ) {
$submenu_file = 'product_attributes';
$parent_file = 'edit.php?post_type=product';
}
break;
}
// @codingStandardsIgnoreEnd
}
/**
* Adds the order processing count to the menu.
*/
public function menu_order_count() {
global $submenu;
if ( isset( $submenu['woocommerce'] ) ) {
// Remove 'WooCommerce' sub menu item.
unset( $submenu['woocommerce'][0] );
// Add count if user has access.
if ( apply_filters( 'woocommerce_include_processing_order_count_in_menu', true ) && current_user_can( 'manage_woocommerce' ) && ( $order_count = wc_processing_order_count() ) ) {
foreach ( $submenu['woocommerce'] as $key => $menu_item ) {
if ( 0 === strpos( $menu_item[0], _x( 'Orders', 'Admin menu name', 'woocommerce' ) ) ) {
$submenu['woocommerce'][ $key ][0] .= ' <span class="awaiting-mod update-plugins count-' . $order_count . '"><span class="processing-count">' . number_format_i18n( $order_count ) . '</span></span>';
break;
}
}
}
}
}
/**
* Reorder the WC menu items in admin.
*
* @param mixed $menu_order Menu Order.
* @return array
*/
public function menu_order( $menu_order ) {
// Initialize our custom order array.
$woocommerce_menu_order = array();
// Get the index of our custom separator.
$woocommerce_separator = array_search( 'separator-woocommerce', $menu_order );
// Get index of product menu.
$woocommerce_product = array_search( 'edit.php?post_type=product', $menu_order );
// Loop through menu order and do some rearranging.
foreach ( $menu_order as $index => $item ) {
if ( ( ( 'woocommerce' ) == $item ) ) {
$woocommerce_menu_order[] = 'separator-woocommerce';
$woocommerce_menu_order[] = $item;
$woocommerce_menu_order[] = 'edit.php?post_type=product';
unset( $menu_order[ $woocommerce_separator ] );
unset( $menu_order[ $woocommerce_product ] );
} elseif ( ! in_array( $item, array( 'separator-woocommerce' ) ) ) {
$woocommerce_menu_order[] = $item;
}
}
// Return order.
return $woocommerce_menu_order;
}
/**
* Custom menu order.
*
* @return bool
*/
public function custom_menu_order() {
return current_user_can( 'manage_woocommerce' );
}
/**
* Init the reports page.
*/
public function reports_page() {
WC_Admin_Reports::output();
}
/**
* Init the settings page.
*/
public function settings_page() {
WC_Admin_Settings::output();
}
/**
* Init the attributes page.
*/
public function attributes_page() {
WC_Admin_Attributes::output();
}
/**
* Init the status page.
*/
public function status_page() {
WC_Admin_Status::output();
}
/**
* Init the addons page.
*/
public function addons_page() {
WC_Admin_Addons::output();
}
/**
* Add custom nav meta box.
*
* Adapted from http://www.johnmorrisonline.com/how-to-add-a-fully-functional-custom-meta-box-to-wordpress-navigation-menus/.
*/
public function add_nav_menu_meta_boxes() {
add_meta_box( 'woocommerce_endpoints_nav_link', __( 'WooCommerce endpoints', 'woocommerce' ), array( $this, 'nav_menu_links' ), 'nav-menus', 'side', 'low' );
}
/**
* Output menu links.
*/
public function nav_menu_links() {
// Get items from account menu.
$endpoints = wc_get_account_menu_items();
// Remove dashboard item.
if ( isset( $endpoints['dashboard'] ) ) {
unset( $endpoints['dashboard'] );
}
// Include missing lost password.
$endpoints['lost-password'] = __( 'Lost password', 'woocommerce' );
$endpoints = apply_filters( 'woocommerce_custom_nav_menu_items', $endpoints );
?>
<div id="posttype-woocommerce-endpoints" class="posttypediv">
<div id="tabs-panel-woocommerce-endpoints" class="tabs-panel tabs-panel-active">
<ul id="woocommerce-endpoints-checklist" class="categorychecklist form-no-clear">
<?php
$i = -1;
foreach ( $endpoints as $key => $value ) :
?>
<li>
<label class="menu-item-title">
<input type="checkbox" class="menu-item-checkbox" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-object-id]" value="<?php echo esc_attr( $i ); ?>" /> <?php echo esc_html( $value ); ?>
</label>
<input type="hidden" class="menu-item-type" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-type]" value="custom" />
<input type="hidden" class="menu-item-title" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-title]" value="<?php echo esc_html( $value ); ?>" />
<input type="hidden" class="menu-item-url" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-url]" value="<?php echo esc_url( wc_get_account_endpoint_url( $key ) ); ?>" />
<input type="hidden" class="menu-item-classes" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-classes]" />
</li>
<?php
$i--;
endforeach;
?>
</ul>
</div>
<p class="button-controls">
<span class="list-controls">
<a href="<?php echo esc_url( admin_url( 'nav-menus.php?page-tab=all&selectall=1#posttype-woocommerce-endpoints' ) ); ?>" class="select-all"><?php esc_html_e( 'Select all', 'woocommerce' ); ?></a>
</span>
<span class="add-to-menu">
<button type="submit" class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to menu', 'woocommerce' ); ?>" name="add-post-type-menu-item" id="submit-posttype-woocommerce-endpoints"><?php esc_html_e( 'Add to menu', 'woocommerce' ); ?></button>
<span class="spinner"></span>
</span>
</p>
</div>
<?php
}
/**
* Add the "Visit Store" link in admin bar main menu.
*
* @since 2.4.0
* @param WP_Admin_Bar $wp_admin_bar Admin Bar.
*/
public function admin_bar_menus( $wp_admin_bar ) {
if ( ! is_admin() || ! is_user_logged_in() ) {
return;
}
// Show only when the user is a member of this site, or they're a super admin.
if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
return;
}
// Don't display when shop page is the same of the page on front.
if ( get_option( 'page_on_front' ) == wc_get_page_id( 'shop' ) ) {
return;
}
// Add an option to visit the store.
$wp_admin_bar->add_node( array(
'parent' => 'site-name',
'id' => 'view-store',
'title' => __( 'Visit Store', 'woocommerce' ),
'href' => wc_get_page_permalink( 'shop' ),
) );
// Admin bar menus.
if ( apply_filters( 'woocommerce_show_admin_bar_visit_store', true ) ) {
add_action( 'admin_bar_menu', array( $this, 'admin_bar_menus' ), 31 );
}
}
endif;
/**
* Add menu items.
*/
public function admin_menu() {
global $menu;
if ( current_user_can( 'manage_woocommerce' ) ) {
$menu[] = array( '', 'read', 'separator-woocommerce', '', 'wp-menu-separator woocommerce' ); // WPCS: override ok.
}
add_menu_page( __( 'WooCommerce', 'woocommerce' ), __( 'WooCommerce', 'woocommerce' ), 'manage_woocommerce', 'woocommerce', null, null, '55.5' );
add_submenu_page( 'edit.php?post_type=product', __( 'Attributes', 'woocommerce' ), __( 'Attributes', 'woocommerce' ), 'manage_product_terms', 'product_attributes', array( $this, 'attributes_page' ) );
}
/**
* Add menu item.
*/
public function reports_menu() {
if ( current_user_can( 'manage_woocommerce' ) ) {
add_submenu_page( 'woocommerce', __( 'Reports', 'woocommerce' ), __( 'Reports', 'woocommerce' ) , 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ) );
} else {
add_menu_page( __( 'Sales reports', 'woocommerce' ), __( 'Sales reports', 'woocommerce' ) , 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ), null, '55.6' );
}
}
/**
* Add menu item.
*/
public function settings_menu() {
$settings_page = add_submenu_page( 'woocommerce', __( 'WooCommerce settings', 'woocommerce' ), __( 'Settings', 'woocommerce' ) , 'manage_woocommerce', 'wc-settings', array( $this, 'settings_page' ) );
add_action( 'load-' . $settings_page, array( $this, 'settings_page_init' ) );
}
/**
* Loads gateways and shipping methods into memory for use within settings.
*/
public function settings_page_init() {
global $current_tab, $current_section;
WC()->payment_gateways();
WC()->shipping();
// Include settings pages.
WC_Admin_Settings::get_settings_pages();
// Get current tab/section.
$current_tab = empty( $_GET['tab'] ) ? 'general' : sanitize_title( wp_unslash( $_GET['tab'] ) ); // WPCS: input var okay, CSRF ok.
$current_section = empty( $_REQUEST['section'] ) ? '' : sanitize_title( wp_unslash( $_REQUEST['section'] ) ); // WPCS: input var okay, CSRF ok.
// Save settings if data has been posted.
if ( apply_filters( '' !== $current_section ? "woocommerce_save_settings_{$current_tab}_{$current_section}" : "woocommerce_save_settings_{$current_tab}", ! empty( $_POST ) ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::save();
}
// Add any posted messages.
if ( ! empty( $_GET['wc_error'] ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::add_error( wp_kses_post( wp_unslash( $_GET['wc_error'] ) ) ); // WPCS: input var okay, CSRF ok.
}
if ( ! empty( $_GET['wc_message'] ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::add_message( wp_kses_post( wp_unslash( $_GET['wc_message'] ) ) ); // WPCS: input var okay, CSRF ok.
}
}
/**
* Add menu item.
*/
public function status_menu() {
add_submenu_page( 'woocommerce', __( 'WooCommerce status', 'woocommerce' ), __( 'Status', 'woocommerce' ) , 'manage_woocommerce', 'wc-status', array( $this, 'status_page' ) );
}
/**
* Addons menu item.
*/
public function addons_menu() {
$count_html = WC_Helper_Updater::get_updates_count_html();
/* translators: %s: extensions count */
$menu_title = sprintf( __( 'Extensions %s', 'woocommerce' ), $count_html );
add_submenu_page( 'woocommerce', __( 'WooCommerce extensions', 'woocommerce' ), $menu_title, 'manage_woocommerce', 'wc-addons', array( $this, 'addons_page' ) );
}
/**
* Highlights the correct top level admin menu item for post type add screens.
*/
public function menu_highlight() {
global $parent_file, $submenu_file, $post_type;
switch ( $post_type ) {
case 'shop_order':
case 'shop_coupon':
$parent_file = 'woocommerce'; // WPCS: override ok.
break;
case 'product':
$screen = get_current_screen();
if ( $screen && taxonomy_is_product_attribute( $screen->taxonomy ) ) {
$submenu_file = 'product_attributes'; // WPCS: override ok.
$parent_file = 'edit.php?post_type=product'; // WPCS: override ok.
}
break;
}
}
/**
* Adds the order processing count to the menu.
*/
public function menu_order_count() {
global $submenu;
if ( isset( $submenu['woocommerce'] ) ) {
// Remove 'WooCommerce' sub menu item.
unset( $submenu['woocommerce'][0] );
$order_count = wc_processing_order_count();
// Add count if user has access.
if ( apply_filters( 'woocommerce_include_processing_order_count_in_menu', true ) && current_user_can( 'manage_woocommerce' ) && $order_count ) {
foreach ( $submenu['woocommerce'] as $key => $menu_item ) {
if ( 0 === strpos( $menu_item[0], _x( 'Orders', 'Admin menu name', 'woocommerce' ) ) ) {
$submenu['woocommerce'][ $key ][0] .= ' <span class="awaiting-mod update-plugins count-' . esc_attr( $order_count ) . '"><span class="processing-count">' . number_format_i18n( $order_count ) . '</span></span>'; // WPCS: override ok.
break;
}
}
}
}
}
/**
* Reorder the WC menu items in admin.
*
* @param int $menu_order Menu order.
* @return array
*/
public function menu_order( $menu_order ) {
// Initialize our custom order array.
$woocommerce_menu_order = array();
// Get the index of our custom separator.
$woocommerce_separator = array_search( 'separator-woocommerce', $menu_order, true );
// Get index of product menu.
$woocommerce_product = array_search( 'edit.php?post_type=product', $menu_order, true );
// Loop through menu order and do some rearranging.
foreach ( $menu_order as $index => $item ) {
if ( 'woocommerce' === $item ) {
$woocommerce_menu_order[] = 'separator-woocommerce';
$woocommerce_menu_order[] = $item;
$woocommerce_menu_order[] = 'edit.php?post_type=product';
unset( $menu_order[ $woocommerce_separator ] );
unset( $menu_order[ $woocommerce_product ] );
} elseif ( ! in_array( $item, array( 'separator-woocommerce' ), true ) ) {
$woocommerce_menu_order[] = $item;
}
}
// Return order.
return $woocommerce_menu_order;
}
/**
* Custom menu order.
*
* @return bool
*/
public function custom_menu_order() {
return current_user_can( 'manage_woocommerce' );
}
/**
* Init the reports page.
*/
public function reports_page() {
WC_Admin_Reports::output();
}
/**
* Init the settings page.
*/
public function settings_page() {
WC_Admin_Settings::output();
}
/**
* Init the attributes page.
*/
public function attributes_page() {
WC_Admin_Attributes::output();
}
/**
* Init the status page.
*/
public function status_page() {
WC_Admin_Status::output();
}
/**
* Init the addons page.
*/
public function addons_page() {
WC_Admin_Addons::output();
}
/**
* Add custom nav meta box.
*
* Adapted from http://www.johnmorrisonline.com/how-to-add-a-fully-functional-custom-meta-box-to-wordpress-navigation-menus/.
*/
public function add_nav_menu_meta_boxes() {
add_meta_box( 'woocommerce_endpoints_nav_link', __( 'WooCommerce endpoints', 'woocommerce' ), array( $this, 'nav_menu_links' ), 'nav-menus', 'side', 'low' );
}
/**
* Output menu links.
*/
public function nav_menu_links() {
// Get items from account menu.
$endpoints = wc_get_account_menu_items();
// Remove dashboard item.
if ( isset( $endpoints['dashboard'] ) ) {
unset( $endpoints['dashboard'] );
}
// Include missing lost password.
$endpoints['lost-password'] = __( 'Lost password', 'woocommerce' );
$endpoints = apply_filters( 'woocommerce_custom_nav_menu_items', $endpoints );
?>
<div id="posttype-woocommerce-endpoints" class="posttypediv">
<div id="tabs-panel-woocommerce-endpoints" class="tabs-panel tabs-panel-active">
<ul id="woocommerce-endpoints-checklist" class="categorychecklist form-no-clear">
<?php
$i = -1;
foreach ( $endpoints as $key => $value ) :
?>
<li>
<label class="menu-item-title">
<input type="checkbox" class="menu-item-checkbox" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-object-id]" value="<?php echo esc_attr( $i ); ?>" /> <?php echo esc_html( $value ); ?>
</label>
<input type="hidden" class="menu-item-type" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-type]" value="custom" />
<input type="hidden" class="menu-item-title" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-title]" value="<?php echo esc_html( $value ); ?>" />
<input type="hidden" class="menu-item-url" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-url]" value="<?php echo esc_url( wc_get_account_endpoint_url( $key ) ); ?>" />
<input type="hidden" class="menu-item-classes" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-classes]" />
</li>
<?php
$i--;
endforeach;
?>
</ul>
</div>
<p class="button-controls">
<span class="list-controls">
<a href="<?php echo esc_url( admin_url( 'nav-menus.php?page-tab=all&selectall=1#posttype-woocommerce-endpoints' ) ); ?>" class="select-all"><?php esc_html_e( 'Select all', 'woocommerce' ); ?></a>
</span>
<span class="add-to-menu">
<button type="submit" class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to menu', 'woocommerce' ); ?>" name="add-post-type-menu-item" id="submit-posttype-woocommerce-endpoints"><?php esc_html_e( 'Add to menu', 'woocommerce' ); ?></button>
</span>
</p>
</div>
<?php
}
/**
* Add the "Visit Store" link in admin bar main menu.
*
* @since 2.4.0
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance.
*/
public function admin_bar_menus( $wp_admin_bar ) {
if ( ! is_admin() || ! is_user_logged_in() ) {
return;
}
// Show only when the user is a member of this site, or they're a super admin.
if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
return;
}
// Don't display when shop page is the same of the page on front.
if ( intval( get_option( 'page_on_front' ) ) === wc_get_page_id( 'shop' ) ) {
return;
}
// Add an option to visit the store.
$wp_admin_bar->add_node( array(
'parent' => 'site-name',
'id' => 'view-store',
'title' => __( 'Visit Store', 'woocommerce' ),
'href' => wc_get_page_permalink( 'shop' ),
) );
}
}
return new WC_Admin_Menus();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,20 +2,23 @@
/**
* WooCommerce Webhooks Table List
*
* @author WooThemes
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 2.4.0
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
/**
* Webooks table list class.
*/
class WC_Admin_Webhooks_Table_List extends WP_List_Table {
/**
@ -47,70 +50,38 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
/**
* Column cb.
*
* @param WC_Post $webhook
* @param WC_Webhook $webhook Webhook instance.
* @return string
*/
public function column_cb( $webhook ) {
return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />', $this->_args['singular'], $webhook->ID );
}
/**
* Get Webhook object.
* @param object $webhook
* @return WC_Webhook
*/
private function get_webbook_object( $webhook ) {
global $the_webhook;
if ( empty( $the_webhook ) || $the_webhook->id != $webhook->ID ) {
$the_webhook = new WC_Webhook( $webhook->ID );
}
return $the_webhook;
return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />', $this->_args['singular'], $webhook->get_id() );
}
/**
* Return title column.
* @param object $webhook
*
* @param WC_Webhook $webhook Webhook instance.
* @return string
*/
public function column_title( $webhook ) {
$the_webhook = $this->get_webbook_object( $webhook );
$edit_link = admin_url( 'admin.php?page=wc-settings&amp;tab=api&amp;section=webhooks&amp;edit-webhook=' . $the_webhook->id );
$title = _draft_or_post_title( $the_webhook->get_post_data() );
$post_type_object = get_post_type_object( $the_webhook->get_post_data()->post_type );
$post_status = $the_webhook->get_post_data()->post_status;
$edit_link = admin_url( 'admin.php?page=wc-settings&amp;tab=api&amp;section=webhooks&amp;edit-webhook=' . $webhook->get_id() );
$output = '';
// Title
$output = '<strong>';
if ( 'trash' == $post_status ) {
$output .= esc_html( $title );
} else {
$output .= '<a href="' . esc_url( $edit_link ) . '" class="row-title">' . esc_html( $title ) . '</a>';
}
$output .= '</strong>';
// Title.
$output .= '<strong><a href="' . esc_url( $edit_link ) . '" class="row-title">' . esc_html( $webhook->get_name() ) . '</a></strong>';
// Get actions
// Get actions.
$actions = array(
'id' => sprintf( __( 'ID: %d', 'woocommerce' ), $the_webhook->id ),
/* translators: %s: webhook ID. */
'id' => sprintf( __( 'ID: %d', 'woocommerce' ), $webhook->get_id() ),
'edit' => '<a href="' . esc_url( $edit_link ) . '">' . esc_html__( 'Edit', 'woocommerce' ) . '</a>',
/* translators: %s: webhook name */
'delete' => '<a class="submitdelete" aria-label="' . esc_attr( sprintf( __( 'Delete "%s" permanently', 'woocommerce' ), $webhook->get_name() ) ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array(
'delete' => $webhook->get_id(),
), admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks' ) ), 'delete-webhook' ) ) . '">' . esc_html__( 'Delete permanently', 'woocommerce' ) . '</a>',
);
if ( current_user_can( $post_type_object->cap->edit_post, $the_webhook->id ) && 'trash' !== $post_status ) {
$actions['edit'] = '<a href="' . esc_url( $edit_link ) . '">' . __( 'Edit', 'woocommerce' ) . '</a>';
}
if ( current_user_can( $post_type_object->cap->delete_post, $the_webhook->id ) ) {
if ( 'trash' == $post_status ) {
$actions['untrash'] = '<a aria-label="' . esc_attr__( 'Restore this item from the Trash', 'woocommerce' ) . '" href="' . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $the_webhook->id ) ), 'untrash-post_' . $the_webhook->id ) . '">' . esc_html__( 'Restore', 'woocommerce' ) . '</a>';
} elseif ( EMPTY_TRASH_DAYS ) {
$actions['trash'] = '<a class="submitdelete" aria-label="' . esc_attr__( 'Move this item to the Trash', 'woocommerce' ) . '" href="' . get_delete_post_link( $the_webhook->id ) . '">' . esc_html__( 'Trash', 'woocommerce' ) . '</a>';
}
if ( 'trash' == $post_status || ! EMPTY_TRASH_DAYS ) {
$actions['delete'] = '<a class="submitdelete" aria-label="' . esc_attr__( 'Delete this item permanently', 'woocommerce' ) . '" href="' . get_delete_post_link( $the_webhook->id, '', true ) . '">' . esc_html__( 'Delete permanently', 'woocommerce' ) . '</a>';
}
}
$actions = apply_filters( 'post_row_actions', $actions, $the_webhook->get_post_data() );
$actions = apply_filters( 'webhook_row_actions', $actions, $webhook );
$row_actions = array();
foreach ( $actions as $action => $link ) {
@ -124,75 +95,59 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
/**
* Return status column.
* @param object $webhook
*
* @param WC_Webhook $webhook Webhook instance.
* @return string
*/
public function column_status( $webhook ) {
return $this->get_webbook_object( $webhook )->get_i18n_status();
return $webhook->get_i18n_status();
}
/**
* Return topic column.
* @param object $webhook
*
* @param WC_Webhook $webhook Webhook instance.
* @return string
*/
public function column_topic( $webhook ) {
return $this->get_webbook_object( $webhook )->get_topic();
return $webhook->get_topic();
}
/**
* Return delivery URL column.
* @param object $webhook
*
* @param WC_Webhook $webhook Webhook instance.
* @return string
*/
public function column_delivery_url( $webhook ) {
return $this->get_webbook_object( $webhook )->get_delivery_url();
return $webhook->get_delivery_url();
}
/**
* Get the status label for webhooks.
*
* @param string $status_name
* @param stdClass $status
*
* @param string $status_name Status name.
* @param int $amount Amount of webhooks.
* @return array
*/
private function get_status_label( $status_name, $status ) {
switch ( $status_name ) {
case 'publish' :
/* translators: %s: count */
$label = array(
'singular' => __( 'Activated <span class="count">(%s)</span>', 'woocommerce' ),
'plural' => __( 'Activated <span class="count">(%s)</span>', 'woocommerce' ),
'context' => '',
'domain' => 'woocommerce',
);
break;
case 'draft' :
/* translators: %s: count */
$label = array(
'singular' => __( 'Paused <span class="count">(%s)</span>', 'woocommerce' ),
'plural' => __( 'Paused <span class="count">(%s)</span>', 'woocommerce' ),
'context' => '',
'domain' => 'woocommerce',
);
break;
case 'pending' :
/* translators: %s: count */
$label = array(
'singular' => __( 'Disabled <span class="count">(%s)</span>', 'woocommerce' ),
'plural' => __( 'Disabled <span class="count">(%s)</span>', 'woocommerce' ),
'context' => '',
'domain' => 'woocommerce',
);
break;
private function get_status_label( $status_name, $amount ) {
$statuses = wc_get_webhook_statuses();
default:
$label = $status->label_count;
break;
if ( isset( $statuses[ $status_name ] ) ) {
return array(
'singular' => sprintf( '%s <span class="count">(%s)</span>', esc_html( $statuses[ $status_name ] ), $amount ),
'plural' => sprintf( '%s <span class="count">(%s)</span>', esc_html( $statuses[ $status_name ] ), $amount ),
'context' => '',
'domain' => 'woocommerce',
);
}
return $label;
return array(
'singular' => sprintf( '%s <span class="count">(%s)</span>', esc_html( $status_name ), $amount ),
'plural' => sprintf( '%s <span class="count">(%s)</span>', esc_html( $status_name ), $amount ),
'context' => '',
'domain' => 'woocommerce',
);
}
/**
@ -201,39 +156,30 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
* @return array
*/
protected function get_views() {
$status_links = array();
$num_posts = wp_count_posts( 'shop_webhook', 'readable' );
$class = '';
$total_posts = array_sum( (array) $num_posts );
$status_links = array();
$data_store = WC_Data_Store::load( 'webhook' );
$num_webhooks = $data_store->get_count_webhooks_by_status();
$total_webhooks = array_sum( (array) $num_webhooks );
$statuses = array_keys( wc_get_webhook_statuses() );
$class = empty( $_REQUEST['status'] ) ? ' class="current"' : ''; // WPCS: input var okay. CSRF ok.
// Subtract post types that are not included in the admin all list.
foreach ( get_post_stati( array( 'show_in_admin_all_list' => false ) ) as $state ) {
$total_posts -= $num_posts->$state;
}
$class = empty( $class ) && empty( $_REQUEST['status'] ) ? ' class="current"' : '';
/* translators: %s: count */
$status_links['all'] = "<a href='admin.php?page=wc-settings&amp;tab=api&amp;section=webhooks'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_posts, 'posts', 'woocommerce' ), number_format_i18n( $total_posts ) ) . '</a>';
$status_links['all'] = "<a href='admin.php?page=wc-settings&amp;tab=api&amp;section=webhooks'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_webhooks, 'posts', 'woocommerce' ), number_format_i18n( $total_webhooks ) ) . '</a>';
foreach ( get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' ) as $status ) {
foreach ( $statuses as $status_name ) {
$class = '';
$status_name = $status->name;
if ( ! in_array( $status_name, array( 'publish', 'draft', 'pending', 'trash', 'future', 'private', 'auto-draft' ) ) ) {
if ( empty( $num_webhooks[ $status_name ] ) ) {
continue;
}
if ( empty( $num_posts->$status_name ) ) {
continue;
}
if ( isset( $_REQUEST['status'] ) && $status_name == $_REQUEST['status'] ) {
if ( isset( $_REQUEST['status'] ) && sanitize_key( wp_unslash( $_REQUEST['status'] ) ) === $status_name ) { // WPCS: input var okay, CSRF ok.
$class = ' class="current"';
}
$label = $this->get_status_label( $status_name, $status );
$label = $this->get_status_label( $status_name, $num_webhooks[ $status_name ] );
$status_links[ $status_name ] = "<a href='admin.php?page=wc-settings&amp;tab=api&amp;section=webhooks&amp;status=$status_name'$class>" . sprintf( translate_nooped_plural( $label, $num_posts->$status_name ), number_format_i18n( $num_posts->$status_name ) ) . '</a>';
$status_links[ $status_name ] = "<a href='admin.php?page=wc-settings&amp;tab=api&amp;section=webhooks&amp;status=$status_name'$class>" . sprintf( translate_nooped_plural( $label, $num_webhooks[ $status_name ] ), number_format_i18n( $num_webhooks[ $status_name ] ) ) . '</a>';
}
return $status_links;
@ -245,69 +191,96 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
* @return array
*/
protected function get_bulk_actions() {
if ( isset( $_GET['status'] ) && 'trash' == $_GET['status'] ) {
return array(
'untrash' => __( 'Restore', 'woocommerce' ),
'delete' => __( 'Delete permanently', 'woocommerce' ),
);
}
return array(
'trash' => __( 'Move to trash', 'woocommerce' ),
'delete' => __( 'Delete permanently', 'woocommerce' ),
);
}
/**
* Extra controls to be displayed between bulk actions and pagination.
* Generate the table navigation above or below the table.
* Included to remove extra nonce input.
*
* @param string $which
* @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
*/
protected function extra_tablenav( $which ) {
if ( 'top' == $which && isset( $_GET['status'] ) && 'trash' == $_GET['status'] && current_user_can( 'delete_shop_webhooks' ) ) {
echo '<div class="alignleft actions"><a class="button apply" href="' . esc_url( wp_nonce_url( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&status=trash&empty_trash=1' ), 'empty_trash' ) ) . '">' . __( 'Empty trash', 'woocommerce' ) . '</a></div>';
protected function display_tablenav( $which ) {
echo '<div class="tablenav ' . esc_attr( $which ) . '">';
if ( $this->has_items() ) {
echo '<div class="alignleft actions bulkactions">';
$this->bulk_actions( $which );
echo '</div>';
}
$this->extra_tablenav( $which );
$this->pagination( $which );
echo '<br class="clear" />';
echo '</div>';
}
/**
* Search box.
*
* @param string $text Button text.
* @param string $input_id Input ID.
*/
public function search_box( $text, $input_id ) {
if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) { // WPCS: input var okay, CSRF ok.
return;
}
$input_id = $input_id . '-search-input';
$search_query = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; // WPCS: input var okay, CSRF ok.
echo '<p class="search-box">';
echo '<label class="screen-reader-text" for="' . esc_attr( $input_id ) . '">' . esc_html( $text ) . ':</label>';
echo '<input type="search" id="' . esc_attr( $input_id ) . '" name="s" value="' . esc_attr( $search_query ) . '" />';
submit_button( $text, '', '', false, array(
'id' => 'search-submit',
) );
echo '</p>';
}
/**
* Prepare table list items.
*/
public function prepare_items() {
$per_page = apply_filters( 'woocommerce_webhooks_settings_posts_per_page', 10 );
$per_page = absint( apply_filters( 'woocommerce_webhooks_settings_posts_per_page', 10 ) );
$per_page = 0 === $per_page ? 10 : $per_page;
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
// Column headers
// Column headers.
$this->_column_headers = array( $columns, $hidden, $sortable );
$current_page = $this->get_pagenum();
// Query args
// Query args.
$args = array(
'post_type' => 'shop_webhook',
'posts_per_page' => $per_page,
'ignore_sticky_posts' => true,
'paged' => $current_page,
'limit' => $per_page,
'offset' => $per_page * ( $current_page - 1 ),
);
// Handle the status query
if ( ! empty( $_REQUEST['status'] ) ) {
$args['post_status'] = sanitize_text_field( $_REQUEST['status'] );
// Handle the status query.
if ( ! empty( $_REQUEST['status'] ) ) { // WPCS: input var okay, CSRF ok.
$args['status'] = sanitize_key( wp_unslash( $_REQUEST['status'] ) ); // WPCS: input var okay, CSRF ok.
}
if ( ! empty( $_REQUEST['s'] ) ) {
$args['s'] = sanitize_text_field( $_REQUEST['s'] );
if ( ! empty( $_REQUEST['s'] ) ) { // WPCS: input var okay, CSRF ok.
$args['search'] = sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ); // WPCS: input var okay, CSRF ok.
}
// Get the webhooks
$webhooks = new WP_Query( $args );
$this->items = $webhooks->posts;
// Get the webhooks.
$data_store = WC_Data_Store::load( 'webhook' );
$webhooks = $data_store->search_webhooks( $args );
$this->items = array_map( 'wc_get_webhook', $webhooks );
$total_items = count( $data_store->get_webhooks_ids() );
// Set the pagination
// Set the pagination.
$this->set_pagination_args( array(
'total_items' => $webhooks->found_posts,
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => $webhooks->max_num_pages,
'total_pages' => ceil( $total_items / $per_page ),
) );
}
}

View File

@ -2,14 +2,14 @@
/**
* WooCommerce Admin Webhooks Class
*
* @author WooThemes
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 2.4.0
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
/**
@ -21,95 +21,94 @@ class WC_Admin_Webhooks {
* Initialize the webhooks admin actions.
*/
public function __construct() {
add_action( 'woocommerce_save_settings_api_webhooks', array( $this, 'allow_save_settings' ) );
add_action( 'admin_init', array( $this, 'actions' ) );
}
/**
* Check if should allow save settings.
* This prevents "Your settings have been saved." notices on the table list.
*
* @param bool $allow If allow save settings.
* @return bool
*/
public function allow_save_settings( $allow ) {
if ( ! isset( $_GET['edit-webhook'] ) ) {// WPCS: input var okay, CSRF ok.
return false;
}
return $allow;
}
/**
* Check if is webhook settings page.
*
* @return bool
*/
private function is_webhook_settings_page() {
return isset( $_GET['page'], $_GET['tab'], $_GET['section'] )
&& 'wc-settings' === $_GET['page']
&& 'api' === $_GET['tab']
&& 'webhooks' === $_GET['section'];
return isset( $_GET['page'], $_GET['tab'], $_GET['section'] ) && 'wc-settings' === $_GET['page'] && 'api' === $_GET['tab'] && 'webhooks' === $_GET['section']; // WPCS: input var okay, CSRF ok.
}
/**
* Updated the Webhook name.
*
* @param int $webhook_id
* Save method.
*/
private function update_name( $webhook_id ) {
global $wpdb;
private function save() {
check_admin_referer( 'woocommerce-settings' );
// @codingStandardsIgnoreStart
/* translators: %s: date` */
$name = ! empty( $_POST['webhook_name'] ) ? $_POST['webhook_name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) );
// @codingStandardsIgnoreEnd
$wpdb->update( $wpdb->posts, array( 'post_title' => $name ), array( 'ID' => $webhook_id ) );
}
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( esc_html__( 'You do not have permission to update Webhooks', 'woocommerce' ) );
}
/**
* Updated the Webhook status.
*
* @param WC_Webhook $webhook
*/
private function update_status( $webhook ) {
$status = ! empty( $_POST['webhook_status'] ) ? wc_clean( $_POST['webhook_status'] ) : '';
$webhook_id = isset( $_POST['webhook_id'] ) ? absint( $_POST['webhook_id'] ) : 0; // WPCS: input var okay, CSRF ok.
$webhook = new WC_Webhook( $webhook_id );
$webhook->update_status( $status );
}
// Name.
if ( ! empty( $_POST['webhook_name'] ) ) { // WPCS: input var okay, CSRF ok.
$name = sanitize_text_field( wp_unslash( $_POST['webhook_name'] ) ); // WPCS: input var okay, CSRF ok.
} else {
$name = sprintf(
/* translators: %s: date */
__( 'Webhook created on %s', 'woocommerce' ),
// @codingStandardsIgnoreStart
strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) )
// @codingStandardsIgnoreEnd
);
}
/**
* Updated the Webhook delivery URL.
*
* @param WC_Webhook $webhook
*/
private function update_delivery_url( $webhook ) {
$delivery_url = ! empty( $_POST['webhook_delivery_url'] ) ? $_POST['webhook_delivery_url'] : '';
$webhook->set_name( $name );
// Status.
$webhook->set_status( ! empty( $_POST['webhook_status'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_status'] ) ) : 'disabled' ); // WPCS: input var okay, CSRF ok.
// Delivery URL.
$delivery_url = ! empty( $_POST['webhook_delivery_url'] ) ? esc_url_raw( wp_unslash( $_POST['webhook_delivery_url'] ) ) : ''; // WPCS: input var okay, CSRF ok.
if ( wc_is_valid_url( $delivery_url ) ) {
$webhook->set_delivery_url( $delivery_url );
}
}
/**
* Updated the Webhook secret.
*
* @param WC_Webhook $webhook
*/
private function update_secret( $webhook ) {
$secret = ! empty( $_POST['webhook_secret'] ) ? $_POST['webhook_secret'] : wp_generate_password( 50, true, true );
// Secret.
$secret = ! empty( $_POST['webhook_secret'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_secret'] ) ) : wp_generate_password( 50, true, true ); // WPCS: input var okay, CSRF ok.
$webhook->set_secret( $secret );
}
/**
* Updated the Webhook topic.
*
* @param WC_Webhook $webhook
*/
private function update_topic( $webhook ) {
if ( ! empty( $_POST['webhook_topic'] ) ) {
// Topic.
if ( ! empty( $_POST['webhook_topic'] ) ) { // WPCS: input var okay, CSRF ok.
$resource = '';
$event = '';
switch ( $_POST['webhook_topic'] ) {
case 'custom' :
if ( ! empty( $_POST['webhook_custom_topic'] ) ) {
list( $resource, $event ) = explode( '.', wc_clean( $_POST['webhook_custom_topic'] ) );
switch ( $_POST['webhook_topic'] ) { // WPCS: input var okay, CSRF ok.
case 'custom':
if ( ! empty( $_POST['webhook_custom_topic'] ) ) { // WPCS: input var okay, CSRF ok.
list( $resource, $event ) = explode( '.', sanitize_text_field( wp_unslash( $_POST['webhook_custom_topic'] ) ) ); // WPCS: input var okay, CSRF ok.
}
break;
case 'action' :
case 'action':
$resource = 'action';
$event = ! empty( $_POST['webhook_action_event'] ) ? wc_clean( $_POST['webhook_action_event'] ) : '';
$event = ! empty( $_POST['webhook_action_event'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_action_event'] ) ) : ''; // WPCS: input var okay, CSRF ok.
break;
default :
list( $resource, $event ) = explode( '.', wc_clean( $_POST['webhook_topic'] ) );
default:
list( $resource, $event ) = explode( '.', sanitize_text_field( wp_unslash( $_POST['webhook_topic'] ) ) ); // WPCS: input var okay, CSRF ok.
break;
}
@ -119,222 +118,84 @@ class WC_Admin_Webhooks {
$webhook->set_topic( $topic );
}
}
}
/**
* Update webhook api version.
*
* @param WC_Webhook $webhook Webhook instance.
*/
private function update_api_version( $webhook ) {
$version = ! empty( $_POST['webhook_api_version'] ) ? wc_clean( $_POST['webhook_api_version'] ) : 'wp_api_v2';
$webhook->set_api_version( $version );
}
/**
* Save method.
*/
private function save() {
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-settings' ) ) {
wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
}
$webhook_id = absint( $_POST['webhook_id'] );
if ( ! current_user_can( 'edit_shop_webhook', $webhook_id ) ) {
return;
}
$webhook = new WC_Webhook( $webhook_id );
// Name
$this->update_name( $webhook->id );
// Status
$this->update_status( $webhook );
// Delivery URL
$this->update_delivery_url( $webhook );
// Secret
$this->update_secret( $webhook );
// Topic
$this->update_topic( $webhook );
// API version.
$this->update_api_version( $webhook );
$webhook->set_api_version( ! empty( $_POST['webhook_api_version'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_api_version'] ) ) : 'wp_api_v2' ); // WPCS: input var okay, CSRF ok.
// Update date.
wp_update_post( array( 'ID' => $webhook->id, 'post_modified' => current_time( 'mysql' ) ) );
$webhook->save();
// Run actions
do_action( 'woocommerce_webhook_options_save', $webhook->id );
// Run actions.
do_action( 'woocommerce_webhook_options_save', $webhook->get_id() );
delete_transient( 'woocommerce_webhook_ids' );
// Ping the webhook at the first time that is activated
$pending_delivery = get_post_meta( $webhook->id, '_webhook_pending_delivery', true );
if ( isset( $_POST['webhook_status'] ) && 'active' === $_POST['webhook_status'] && $pending_delivery ) {
// Ping the webhook at the first time that is activated.
if ( isset( $_POST['webhook_status'] ) && 'active' === $_POST['webhook_status'] && $webhook->get_pending_delivery() ) { // WPCS: input var okay, CSRF ok.
$result = $webhook->deliver_ping();
if ( is_wp_error( $result ) ) {
// Redirect to webhook edit page to avoid settings save actions
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->id . '&error=' . urlencode( $result->get_error_message() ) ) );
// Redirect to webhook edit page to avoid settings save actions.
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->get_id() . '&error=' . rawurlencode( $result->get_error_message() ) ) );
exit();
}
}
// Redirect to webhook edit page to avoid settings save actions
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->id . '&updated=1' ) );
// Redirect to webhook edit page to avoid settings save actions.
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->get_id() . '&updated=1' ) );
exit();
}
/**
* Create Webhook.
*/
private function create() {
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'create-webhook' ) ) {
wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
}
if ( ! current_user_can( 'publish_shop_webhooks' ) ) {
wp_die( __( 'You do not have permission to create Webhooks', 'woocommerce' ) );
}
$webhook_id = wp_insert_post( array(
'post_type' => 'shop_webhook',
'post_status' => 'pending',
'ping_status' => 'closed',
'post_author' => get_current_user_id(),
'post_password' => strlen( ( $password = uniqid( 'webhook_' ) ) ) > 20 ? substr( $password, 0, 20 ) : $password,
// @codingStandardsIgnoreStart
/* translators: %s: date */
'post_title' => sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ),
// @codingStandardsIgnoreEnd
'comment_status' => 'closed',
) );
if ( is_wp_error( $webhook_id ) ) {
wp_die( $webhook_id->get_error_messages() );
}
update_post_meta( $webhook_id, '_webhook_pending_delivery', true );
$webhook = new WC_Webhook( $webhook_id );
$webhook->set_api_version( 'wp_api_v2' );
delete_transient( 'woocommerce_webhook_ids' );
// Redirect to edit page
wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook_id . '&created=1' ) );
exit();
}
/**
* Bulk trash/delete.
* Bulk delete.
*
* @param array $webhooks
* @param bool $delete
* @param array $webhooks List of webhooks IDs.
*/
private function bulk_trash( $webhooks, $delete = false ) {
private function bulk_delete( $webhooks ) {
foreach ( $webhooks as $webhook_id ) {
if ( $delete ) {
wp_delete_post( $webhook_id, true );
} else {
wp_trash_post( $webhook_id );
$webhook = new WC_Webhook( (int) $webhook_id );
$webhook->delete( true );
}
$qty = count( $webhooks );
$status = isset( $_GET['status'] ) ? '&status=' . sanitize_text_field( wp_unslash( $_GET['status'] ) ) : ''; // WPCS: input var okay, CSRF ok.
// Redirect to webhooks page.
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks' . $status . '&deleted=' . $qty ) );
exit();
}
/**
* Delete webhook.
*/
private function delete() {
check_admin_referer( 'delete-webhook' );
if ( isset( $_GET['delete'] ) ) { // WPCS: input var okay, CSRF ok.
$webhook_id = absint( $_GET['delete'] ); // WPCS: input var okay, CSRF ok.
if ( $webhook_id ) {
$this->bulk_delete( array( $webhook_id ) );
}
}
$type = ! EMPTY_TRASH_DAYS || $delete ? 'deleted' : 'trashed';
$qty = count( $webhooks );
$status = isset( $_GET['status'] ) ? '&status=' . sanitize_text_field( $_GET['status'] ) : '';
delete_transient( 'woocommerce_webhook_ids' );
// Redirect to webhooks page
wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks' . $status . '&' . $type . '=' . $qty ) );
exit();
}
/**
* Bulk untrash.
*
* @param array $webhooks
*/
private function bulk_untrash( $webhooks ) {
foreach ( $webhooks as $webhook_id ) {
wp_untrash_post( $webhook_id );
}
$qty = count( $webhooks );
delete_transient( 'woocommerce_webhook_ids' );
// Redirect to webhooks page
wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&status=trash&untrashed=' . $qty ) );
exit();
}
/**
* Bulk actions.
*/
private function bulk_actions() {
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-settings' ) ) {
wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
check_admin_referer( 'woocommerce-settings' );
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( esc_html__( 'You do not have permission to edit Webhooks', 'woocommerce' ) );
}
if ( ! current_user_can( 'edit_shop_webhooks' ) ) {
wp_die( __( 'You do not have permission to edit Webhooks', 'woocommerce' ) );
if ( isset( $_REQUEST['action'] ) ) { // WPCS: input var okay, CSRF ok.
$webhooks = isset( $_REQUEST['webhook'] ) ? array_map( 'absint', (array) $_REQUEST['webhook'] ) : array(); // WPCS: input var okay, CSRF ok.
$action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // WPCS: input var okay, CSRF ok.
if ( 'delete' === $action ) {
$this->bulk_delete( $webhooks );
}
}
$webhooks = array_map( 'absint', (array) $_GET['webhook'] );
switch ( $_GET['action'] ) {
case 'trash' :
$this->bulk_trash( $webhooks );
break;
case 'untrash' :
$this->bulk_untrash( $webhooks );
break;
case 'delete' :
$this->bulk_trash( $webhooks, true );
break;
default :
break;
}
}
/**
* Empty Trash.
*/
private function empty_trash() {
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'empty_trash' ) ) {
wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
}
if ( ! current_user_can( 'delete_shop_webhooks' ) ) {
wp_die( __( 'You do not have permission to delete Webhooks', 'woocommerce' ) );
}
$webhooks = get_posts( array(
'post_type' => 'shop_webhook',
'ignore_sticky_posts' => true,
'nopaging' => true,
'post_status' => 'trash',
'fields' => 'ids',
) );
foreach ( $webhooks as $webhook_id ) {
wp_delete_post( $webhook_id, true );
}
$qty = count( $webhooks );
// Redirect to webhooks page
wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&deleted=' . $qty ) );
exit();
}
/**
@ -342,24 +203,19 @@ class WC_Admin_Webhooks {
*/
public function actions() {
if ( $this->is_webhook_settings_page() ) {
// Save
if ( isset( $_POST['save'] ) && isset( $_POST['webhook_id'] ) ) {
// Save.
if ( isset( $_POST['save'] ) && isset( $_POST['webhook_id'] ) ) { // WPCS: input var okay, CSRF ok.
$this->save();
}
// Create
if ( isset( $_GET['create-webhook'] ) ) {
$this->create();
}
// Bulk actions
if ( isset( $_GET['action'] ) && isset( $_GET['webhook'] ) ) {
// Bulk actions.
if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['webhook'] ) ) { // WPCS: input var okay, CSRF ok.
$this->bulk_actions();
}
// Empty trash
if ( isset( $_GET['empty_trash'] ) ) {
$this->empty_trash();
// Delete webhook.
if ( isset( $_GET['delete'] ) ) { // WPCS: input var okay, CSRF ok.
$this->delete();
}
}
}
@ -368,17 +224,15 @@ class WC_Admin_Webhooks {
* Page output.
*/
public static function page_output() {
// Hide the save button
// Hide the save button.
$GLOBALS['hide_save_button'] = true;
if ( isset( $_GET['edit-webhook'] ) ) {
$webhook_id = absint( $_GET['edit-webhook'] );
if ( isset( $_GET['edit-webhook'] ) ) { // WPCS: input var okay, CSRF ok.
$webhook_id = absint( $_GET['edit-webhook'] ); // WPCS: input var okay, CSRF ok.
$webhook = new WC_Webhook( $webhook_id );
if ( 'trash' != $webhook->post_data->post_status ) {
include( 'settings/views/html-webhooks-edit.php' );
return;
}
include( 'settings/views/html-webhooks-edit.php' );
return;
}
self::table_list_output();
@ -388,37 +242,23 @@ class WC_Admin_Webhooks {
* Notices.
*/
public static function notices() {
if ( isset( $_GET['trashed'] ) ) {
$trashed = absint( $_GET['trashed'] );
/* translators: %d: count */
WC_Admin_Settings::add_message( sprintf( _n( '%d webhook moved to the Trash.', '%d webhooks moved to the Trash.', $trashed, 'woocommerce' ), $trashed ) );
}
if ( isset( $_GET['untrashed'] ) ) {
$untrashed = absint( $_GET['untrashed'] );
/* translators: %d: count */
WC_Admin_Settings::add_message( sprintf( _n( '%d webhook restored from the Trash.', '%d webhooks restored from the Trash.', $untrashed, 'woocommerce' ), $untrashed ) );
}
if ( isset( $_GET['deleted'] ) ) {
$deleted = absint( $_GET['deleted'] );
if ( isset( $_GET['deleted'] ) ) { // WPCS: input var okay, CSRF ok.
$deleted = absint( $_GET['deleted'] ); // WPCS: input var okay, CSRF ok.
/* translators: %d: count */
WC_Admin_Settings::add_message( sprintf( _n( '%d webhook permanently deleted.', '%d webhooks permanently deleted.', $deleted, 'woocommerce' ), $deleted ) );
}
if ( isset( $_GET['updated'] ) ) {
if ( isset( $_GET['updated'] ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::add_message( __( 'Webhook updated successfully.', 'woocommerce' ) );
}
if ( isset( $_GET['created'] ) ) {
if ( isset( $_GET['created'] ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::add_message( __( 'Webhook created successfully.', 'woocommerce' ) );
}
if ( isset( $_GET['error'] ) ) {
WC_Admin_Settings::add_error( wc_clean( $_GET['error'] ) );
if ( isset( $_GET['error'] ) ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::add_error( sanitize_text_field( wp_unslash( $_GET['error'] ) ) ); // WPCS: input var okay, CSRF ok.
}
}
@ -426,12 +266,13 @@ class WC_Admin_Webhooks {
* Table list output.
*/
private static function table_list_output() {
echo '<h2>' . __( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( wp_nonce_url( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&create-webhook=1' ), 'create-webhook' ) ) . '" class="add-new-h2">' . __( 'Add webhook', 'woocommerce' ) . '</a></h2>';
echo '<h2>' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
// Get the webhooks count
$count = array_sum( (array) wp_count_posts( 'shop_webhook', 'readable' ) );
// Get the webhooks count.
$data_store = WC_Data_Store::load( 'webhook' );
$count = count( $data_store->get_webhooks_ids() );
if ( absint( $count ) && $count > 0 ) {
if ( 0 < $count ) {
$webhooks_table_list = new WC_Admin_Webhooks_Table_List();
$webhooks_table_list->prepare_items();
@ -445,10 +286,11 @@ class WC_Admin_Webhooks {
} else {
echo '<div class="woocommerce-BlankState woocommerce-BlankState--webhooks">';
?>
<h2 class="woocommerce-BlankState-message"><?php _e( 'Webhooks are event notifications sent to URLs of your choice. They can be used to integrate with third-party services which support them.', 'woocommerce' ); ?></h2>
<a class="woocommerce-BlankState-cta button-primary button" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&create-webhook=1' ), 'create-webhook' ) ); ?>"><?php _e( 'Create a new webhook', 'woocommerce' ); ?></a>
<h2 class="woocommerce-BlankState-message"><?php esc_html_e( 'Webhooks are event notifications sent to URLs of your choice. They can be used to integrate with third-party services which support them.', 'woocommerce' ); ?></h2>
<a class="woocommerce-BlankState-cta button-primary button" href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=0' ) ); ?>"><?php esc_html_e( 'Create a new webhook', 'woocommerce' ); ?></a>
<?php echo '<style type="text/css">#posts-filter .wp-list-table, #posts-filter .tablenav.top, .tablenav.bottom .actions { display: none; } </style></div>';
<?php
echo '<style type="text/css">#posts-filter .wp-list-table, #posts-filter .tablenav.top, .tablenav.bottom .actions { display: none; } </style></div>';
}
}
@ -464,7 +306,7 @@ class WC_Admin_Webhooks {
/**
* Get the webhook topic data.
*
* @param WC_Webhook $webhook Webhook Object.
* @param WC_Webhook $webhook Webhook instance.
*
* @return array
*/
@ -478,7 +320,7 @@ class WC_Admin_Webhooks {
if ( 'action' === $resource ) {
$topic = 'action';
} elseif ( ! in_array( $resource, array( 'coupon', 'customer', 'order', 'product' ) ) ) {
} elseif ( ! in_array( $resource, array( 'coupon', 'customer', 'order', 'product' ), true ) ) {
$topic = 'custom';
}
}

View File

@ -0,0 +1,278 @@
<?php
/**
* List tables.
*
* @author WooCommerce
* @category Admin
* @package WooCommerce/Admin
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Admin_List_Table', false ) ) {
return;
}
/**
* WC_Admin_List_Table Class.
*/
abstract class WC_Admin_List_Table {
/**
* Post type.
*
* @var string
*/
protected $list_table_type = '';
/**
* Object being shown on the row.
*
* @var object|null
*/
protected $object = null;
/**
* Constructor.
*/
public function __construct() {
if ( $this->list_table_type ) {
add_action( 'manage_posts_extra_tablenav', array( $this, 'maybe_render_blank_state' ) );
add_filter( 'view_mode_post_types', array( $this, 'disable_view_mode' ) );
add_action( 'restrict_manage_posts', array( $this, 'restrict_manage_posts' ) );
add_filter( 'request', array( $this, 'request_query' ) );
add_filter( 'post_row_actions', array( $this, 'row_actions' ), 100, 2 );
add_filter( 'default_hidden_columns', array( $this, 'default_hidden_columns' ), 10, 2 );
add_filter( 'list_table_primary_column', array( $this, 'list_table_primary_column' ), 10, 2 );
add_filter( 'manage_edit-' . $this->list_table_type . '_sortable_columns', array( $this, 'define_sortable_columns' ) );
add_filter( 'manage_' . $this->list_table_type . '_posts_columns', array( $this, 'define_columns' ) );
add_filter( 'bulk_actions-edit-' . $this->list_table_type, array( $this, 'define_bulk_actions' ) );
add_action( 'manage_' . $this->list_table_type . '_posts_custom_column', array( $this, 'render_columns' ), 10, 2 );
add_filter( 'handle_bulk_actions-edit-' . $this->list_table_type, array( $this, 'handle_bulk_actions' ), 10, 3 );
}
}
/**
* Show blank slate.
*
* @param string $which String which tablenav is being shown.
*/
public function maybe_render_blank_state( $which ) {
global $post_type;
if ( $post_type === $this->list_table_type && 'bottom' === $which ) {
$counts = (array) wp_count_posts( $post_type );
unset( $counts['auto-draft'] );
$count = array_sum( $counts );
if ( 0 < $count ) {
return;
}
$this->render_blank_state();
echo '<style type="text/css">#posts-filter .wp-list-table, #posts-filter .tablenav.top, .tablenav.bottom .actions, .wrap .subsubsub { display: none; } </style>';
}
}
/**
* Render blank state. Extend to add content.
*/
protected function render_blank_state() {}
/**
* Removes this type from list of post types that support "View Mode" switching.
* View mode is seen on posts where you can switch between list or excerpt. Our post types don't support
* it, so we want to hide the useless UI from the screen options tab.
*
* @param array $post_types Array of post types supporting view mode.
* @return array Array of post types supporting view mode, without this type.
*/
public function disable_view_mode( $post_types ) {
unset( $post_types[ $this->list_table_type ] );
return $post_types;
}
/**
* See if we should render search filters or not.
*/
public function restrict_manage_posts() {
global $typenow;
if ( $this->list_table_type === $typenow ) {
$this->render_filters();
}
}
/**
* Handle any filters.
*
* @param array $query_vars Query vars.
* @return array
*/
public function request_query( $query_vars ) {
global $typenow;
if ( $this->list_table_type === $typenow ) {
return $this->query_filters( $query_vars );
}
return $query_vars;
}
/**
* Render any custom filters and search inputs for the list table.
*/
protected function render_filters() {}
/**
* Handle any custom filters.
*
* @param array $query_vars Query vars.
* @return array
*/
protected function query_filters( $query_vars ) {
return $query_vars;
}
/**
* Set row actions.
*
* @param array $actions Array of actions.
* @param WP_Post $post Current post object.
* @return array
*/
public function row_actions( $actions, $post ) {
if ( $this->list_table_type === $post->post_type ) {
return $this->get_row_actions( $actions, $post );
}
return $actions;
}
/**
* Get row actions to show in the list table.
*
* @param array $actions Array of actions.
* @param WP_Post $post Current post object.
* @return array
*/
protected function get_row_actions( $actions, $post ) {
return $actions;
}
/**
* Adjust which columns are displayed by default.
*
* @param array $hidden Current hidden columns.
* @param object $screen Current screen.
* @return array
*/
public function default_hidden_columns( $hidden, $screen ) {
if ( isset( $screen->id ) && 'edit-' . $this->list_table_type === $screen->id ) {
$hidden = array_merge( $hidden, $this->define_hidden_columns() );
}
return $hidden;
}
/**
* Set list table primary column.
*
* @param string $default Default value.
* @param string $screen_id Current screen ID.
* @return string
*/
public function list_table_primary_column( $default, $screen_id ) {
if ( 'edit-' . $this->list_table_type === $screen_id && $this->get_primary_column() ) {
return $this->get_primary_column();
}
return $default;
}
/**
* Define primary column.
*
* @return array
*/
protected function get_primary_column() {
return '';
}
/**
* Define hidden columns.
*
* @return array
*/
protected function define_hidden_columns() {
return array();
}
/**
* Define which columns are sortable.
*
* @param array $columns Existing columns.
* @return array
*/
public function define_sortable_columns( $columns ) {
return $columns;
}
/**
* Define which columns to show on this screen.
*
* @param array $columns Existing columns.
* @return array
*/
public function define_columns( $columns ) {
return $columns;
}
/**
* Define bulk actions.
*
* @param array $actions Existing actions.
* @return array
*/
public function define_bulk_actions( $actions ) {
return $actions;
}
/**
* Pre-fetch any data for the row each column has access to it.
*
* @param int $post_id Post ID being shown.
*/
protected function prepare_row_data( $post_id ) {}
/**
* Render individual columns.
*
* @param string $column Column ID to render.
* @param int $post_id Post ID being shown.
*/
public function render_columns( $column, $post_id ) {
$this->prepare_row_data( $post_id );
if ( ! $this->object ) {
return;
}
if ( is_callable( array( $this, 'render_' . $column . '_column' ) ) ) {
$this->{"render_{$column}_column"}();
}
}
/**
* Handle bulk actions.
*
* @param string $redirect_to URL to redirect to.
* @param string $action Action name.
* @param array $ids List of ids.
* @return string
*/
public function handle_bulk_actions( $redirect_to, $action, $ids ) {
return esc_url_raw( $redirect_to );
}
}

View File

@ -0,0 +1,237 @@
<?php
/**
* List tables: coupons.
*
* @author WooCommerce
* @category Admin
* @package WooCommerce/Admin
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Admin_List_Table_Coupons', false ) ) {
new WC_Admin_List_Table_Coupons();
return;
}
if ( ! class_exists( 'WC_Admin_List_Table', false ) ) {
include_once( 'abstract-class-wc-admin-list-table.php' );
}
/**
* WC_Admin_List_Table_Coupons Class.
*/
class WC_Admin_List_Table_Coupons extends WC_Admin_List_Table {
/**
* Post type.
*
* @var string
*/
protected $list_table_type = 'shop_coupon';
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
add_filter( 'disable_months_dropdown', '__return_true' );
}
/**
* Render blank state.
*/
protected function render_blank_state() {
echo '<div class="woocommerce-BlankState">';
echo '<h2 class="woocommerce-BlankState-message">' . esc_html__( 'Coupons are a great way to offer discounts and rewards to your customers. They will appear here once created.', 'woocommerce' ) . '</h2>';
echo '<a class="woocommerce-BlankState-cta button-primary button" target="_blank" href="https://docs.woocommerce.com/document/coupon-management/?utm_source=blankslate&utm_medium=product&utm_content=couponsdoc&utm_campaign=woocommerceplugin">' . esc_html__( 'Learn more about coupons', 'woocommerce' ) . '</a>';
echo '</div>';
}
/**
* Define primary column.
*
* @return array
*/
protected function get_primary_column() {
return 'coupon_code';
}
/**
* Get row actions to show in the list table.
*
* @param array $actions Array of actions.
* @param WP_Post $post Current post object.
* @return array
*/
protected function get_row_actions( $actions, $post ) {
unset( $actions['inline hide-if-no-js'] );
return $actions;
}
/**
* Define which columns to show on this screen.
*
* @param array $columns Existing columns.
* @return array
*/
public function define_columns( $columns ) {
$show_columns = array();
$show_columns['cb'] = $columns['cb'];
$show_columns['coupon_code'] = __( 'Code', 'woocommerce' );
$show_columns['type'] = __( 'Coupon type', 'woocommerce' );
$show_columns['amount'] = __( 'Coupon amount', 'woocommerce' );
$show_columns['description'] = __( 'Description', 'woocommerce' );
$show_columns['products'] = __( 'Product IDs', 'woocommerce' );
$show_columns['usage'] = __( 'Usage / Limit', 'woocommerce' );
$show_columns['expiry_date'] = __( 'Expiry date', 'woocommerce' );
return $show_columns;
}
/**
* Pre-fetch any data for the row each column has access to it. the_coupon global is there for bw compat.
*
* @param int $post_id Post ID being shown.
*/
protected function prepare_row_data( $post_id ) {
global $the_coupon;
if ( empty( $this->object ) || $this->object->get_id() !== $post_id ) {
$this->object = $the_coupon = new WC_Coupon( $post_id );
}
}
/**
* Render columm: coupon_code.
*/
protected function render_coupon_code_column() {
global $post;
$edit_link = get_edit_post_link( $this->object->get_id() );
$title = $this->object->get_code();
echo '<strong><a class="row-title" href="' . esc_url( $edit_link ) . '">' . esc_html( $title ) . '</a>';
_post_states( $post );
echo '</strong>';
}
/**
* Render columm: type.
*/
protected function render_type_column() {
echo esc_html( wc_get_coupon_type( $this->object->get_discount_type() ) );
}
/**
* Render columm: amount.
*/
protected function render_amount_column() {
echo esc_html( wc_format_localized_price( $this->object->get_amount() ) );
}
/**
* Render columm: products.
*/
protected function render_products_column() {
$product_ids = $this->object->get_product_ids();
if ( count( $product_ids ) > 0 ) {
echo esc_html( implode( ', ', $product_ids ) );
} else {
echo '&ndash;';
}
}
/**
* Render columm: usage_limit.
*/
protected function render_usage_limit_column() {
$usage_limit = $this->object->get_usage_limit();
if ( $usage_limit ) {
echo esc_html( $usage_limit );
} else {
echo '&ndash;';
}
}
/**
* Render columm: usage.
*/
protected function render_usage_column() {
$usage_count = $this->object->get_usage_count();
$usage_limit = $this->object->get_usage_limit();
/* translators: 1: count 2: limit */
printf(
__( '%1$s / %2$s', 'woocommerce' ),
esc_html( $usage_count ),
$usage_limit ? esc_html( $usage_limit ) : '&infin;'
);
}
/**
* Render columm: expiry_date.
*/
protected function render_expiry_date_column() {
$expiry_date = $this->object->get_date_expires();
if ( $expiry_date ) {
echo esc_html( $expiry_date->date_i18n( 'F j, Y' ) );
} else {
echo '&ndash;';
}
}
/**
* Render columm: description.
*/
protected function render_description_column() {
echo wp_kses_post( $this->object->get_description() ? $this->object->get_description() : '&ndash;' );
}
/**
* Render any custom filters and search inputs for the list table.
*/
protected function render_filters() {
?>
<select name="coupon_type" id="dropdown_shop_coupon_type">
<option value=""><?php esc_html_e( 'Show all types', 'woocommerce' ); ?></option>
<?php
$types = wc_get_coupon_types();
foreach ( $types as $name => $type ) {
echo '<option value="' . esc_attr( $name ) . '"';
if ( isset( $_GET['coupon_type'] ) ) { // WPCS: input var ok.
selected( $name, wc_clean( wp_unslash( $_GET['coupon_type'] ) ) ); // WPCS: input var ok, sanitization ok.
}
echo '>' . esc_html( $type ) . '</option>';
}
?>
</select>
<?php
}
/**
* Handle any custom filters.
*
* @param array $query_vars Query vars.
* @return array
*/
protected function query_filters( $query_vars ) {
if ( ! empty( $_GET['coupon_type'] ) ) { // WPCS: input var ok, sanitization ok.
// @codingStandardsIgnoreStart
$query_vars['meta_key'] = 'discount_type';
$query_vars['meta_value'] = wc_clean( wp_unslash( $_GET['coupon_type'] ) ); // WPCS: input var ok, sanitization ok.
// @codingStandardsIgnoreEnd
}
return $query_vars;
}
}
new WC_Admin_List_Table_Coupons();

View File

@ -0,0 +1,611 @@
<?php
/**
* List tables: orders.
*
* @author WooCommerce
* @category Admin
* @package WooCommerce/Admin
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Admin_List_Table_Orders', false ) ) {
new WC_Admin_List_Table_Orders();
return;
}
if ( ! class_exists( 'WC_Admin_List_Table', false ) ) {
include_once( 'abstract-class-wc-admin-list-table.php' );
}
/**
* WC_Admin_List_Table_Orders Class.
*/
class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
/**
* Post type.
*
* @var string
*/
protected $list_table_type = 'shop_order';
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
add_action( 'admin_notices', array( $this, 'bulk_admin_notices' ) );
add_action( 'admin_footer', array( $this, 'order_preview_template' ) );
add_filter( 'get_search_query', array( $this, 'search_label' ) );
add_filter( 'query_vars', array( $this, 'add_custom_query_var' ) );
add_action( 'parse_query', array( $this, 'search_custom_fields' ) );
}
/**
* Render blank state.
*/
protected function render_blank_state() {
echo '<div class="woocommerce-BlankState">';
echo '<h2 class="woocommerce-BlankState-message">' . esc_html__( 'When you receive a new order, it will appear here.', 'woocommerce' ) . '</h2>';
echo '<a class="woocommerce-BlankState-cta button-primary button" target="_blank" href="https://docs.woocommerce.com/document/managing-orders/?utm_source=blankslate&utm_medium=product&utm_content=ordersdoc&utm_campaign=woocommerceplugin">' . esc_html__( 'Learn more about orders', 'woocommerce' ) . '</a>';
echo '</div>';
}
/**
* Define primary column.
*
* @return array
*/
protected function get_primary_column() {
return 'order_number';
}
/**
* Get row actions to show in the list table.
*
* @param array $actions Array of actions.
* @param WP_Post $post Current post object.
* @return array
*/
protected function get_row_actions( $actions, $post ) {
return array();
}
/**
* Define hidden columns.
*
* @return array
*/
protected function define_hidden_columns() {
return array(
'shipping_address',
'billing_address',
);
}
/**
* Define which columns are sortable.
*
* @param array $columns Existing columns.
* @return array
*/
public function define_sortable_columns( $columns ) {
$custom = array(
'order_number' => 'ID',
'order_total' => 'order_total',
'order_date' => 'date',
);
unset( $columns['comments'] );
return wp_parse_args( $custom, $columns );
}
/**
* Define which columns to show on this screen.
*
* @param array $columns Existing columns.
* @return array
*/
public function define_columns( $columns ) {
$show_columns = array();
$show_columns['cb'] = $columns['cb'];
$show_columns['order_number'] = __( 'Order', 'woocommerce' );
$show_columns['billing_address'] = __( 'Billing', 'woocommerce' );
$show_columns['shipping_address'] = __( 'Ship to', 'woocommerce' );
$show_columns['order_date'] = __( 'Date', 'woocommerce' );
$show_columns['order_status'] = __( 'Status', 'woocommerce' );
$show_columns['order_total'] = __( 'Total', 'woocommerce' );
if ( has_action( 'woocommerce_admin_order_actions_start' ) || has_action( 'woocommerce_admin_order_actions_end' ) || has_filter( 'woocommerce_admin_order_actions' ) ) {
$show_columns['order_actions'] = __( 'Actions', 'woocommerce' );
}
wp_enqueue_script( 'wc-orders' );
return $show_columns;
}
/**
* Define bulk actions.
*
* @param array $actions Existing actions.
* @return array
*/
public function define_bulk_actions( $actions ) {
if ( isset( $actions['edit'] ) ) {
unset( $actions['edit'] );
}
$actions['mark_processing'] = __( 'Mark processing', 'woocommerce' );
$actions['mark_on-hold'] = __( 'Mark on-hold', 'woocommerce' );
$actions['mark_completed'] = __( 'Mark complete', 'woocommerce' );
return $actions;
}
/**
* Pre-fetch any data for the row each column has access to it. the_order global is there for bw compat.
*
* @param int $post_id Post ID being shown.
*/
protected function prepare_row_data( $post_id ) {
global $the_order;
if ( empty( $this->object ) || $this->object->get_id() !== $post_id ) {
$this->object = $the_order = wc_get_order( $post_id );
}
}
/**
* Render columm: order_number.
*/
protected function render_order_number_column() {
$buyer = '';
if ( $this->object->get_billing_first_name() || $this->object->get_billing_last_name() ) {
/* translators: 1: first name 2: last name */
$buyer = trim( sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->object->get_billing_first_name(), $this->object->get_billing_last_name() ) );
} elseif ( $this->object->get_billing_company() ) {
$buyer = trim( $this->object->get_billing_company() );
} elseif ( $this->object->get_customer_id() ) {
$user = get_user_by( 'id', $this->object->get_customer_id() );
$buyer = ucwords( $user->display_name );
}
if ( $this->object->get_status() === 'trash' ) {
echo '<strong>#' . esc_attr( $this->object->get_order_number() ) . ' ' . esc_html( $buyer ) . '</strong>';
} else {
echo '<a href="#" class="order-preview" data-order-id="' . absint( $this->object->get_id() ) . '" title="' . esc_attr( __( 'Preview', 'woocommerce' ) ) . '">' . esc_html( __( 'Preview', 'woocommerce' ) ) . '</a>';
echo '<a href="' . esc_url( admin_url( 'post.php?post=' . absint( $this->object->get_id() ) ) . '&action=edit' ) . '" class="order-view"><strong>#' . esc_attr( $this->object->get_order_number() ) . ' ' . esc_html( $buyer ) . '</strong></a>';
}
}
/**
* Render columm: order_status.
*/
protected function render_order_status_column() {
$tooltip = '';
$comment_count = absint( get_comment_count( $this->object->get_id() )['approved'] );
if ( $comment_count ) {
$latest_notes = wc_get_order_notes( array(
'order_id' => $this->object->get_id(),
'limit' => 1,
'orderby' => 'date_created_gmt',
) );
$latest_note = current( $latest_notes );
if ( isset( $latest_note->content ) && 1 === $comment_count ) {
$tooltip = wc_sanitize_tooltip( $latest_note->content );
} elseif ( isset( $latest_note->content ) ) {
/* translators: %d: notes count */
$tooltip = wc_sanitize_tooltip( $latest_note->content . '<br/><small style="display:block">' . sprintf( _n( 'Plus %d other note', 'Plus %d other notes', ( $comment_count - 1 ), 'woocommerce' ), $comment_count - 1 ) . '</small>' );
} else {
/* translators: %d: notes count */
$tooltip = wc_sanitize_tooltip( sprintf( _n( '%d note', '%d notes', $comment_count, 'woocommerce' ), $comment_count ) );
}
}
if ( $tooltip ) {
printf( '<mark class="order-status %s tips" data-tip="%s"><span>%s</span></mark>', esc_attr( sanitize_html_class( 'status-' . $this->object->get_status() ) ), wp_kses_post( $tooltip ), esc_html( wc_get_order_status_name( $this->object->get_status() ) ) );
} else {
printf( '<mark class="order-status %s"><span>%s</span></mark>', esc_attr( sanitize_html_class( 'status-' . $this->object->get_status() ) ), esc_html( wc_get_order_status_name( $this->object->get_status() ) ) );
}
}
/**
* Render columm: order_date.
*/
protected function render_order_date_column() {
$order_timestamp = $this->object->get_date_created()->getTimestamp();
if ( $order_timestamp > strtotime( '-1 day', current_time( 'timestamp', true ) ) ) {
$show_date = sprintf( _x( '%s ago', '%s = human-readable time difference', 'woocommerce' ), human_time_diff( $this->object->get_date_created()->getTimestamp(), current_time( 'timestamp', true ) ) );
} else {
$show_date = $this->object->get_date_created()->date_i18n( apply_filters( 'woocommerce_admin_order_date_format', get_option( 'date_format' ) ) );
}
printf(
'<time datetime="%1$s" title="%2$s">%3$s</time>',
esc_attr( $this->object->get_date_created()->date( 'c' ) ),
esc_html( $this->object->get_date_created()->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) ),
esc_html( $show_date )
);
}
/**
* Render columm: order_total.
*/
protected function render_order_total_column() {
if ( $this->object->get_payment_method_title() ) {
/* translators: %s: method */
echo '<span class="tips" data-tip="' . esc_attr( sprintf( __( 'via %s', 'woocommerce' ), $this->object->get_payment_method_title() ) ) . '">' . wp_kses_post( $this->object->get_formatted_order_total() ) . '</span>';
} else {
echo wp_kses_post( $this->object->get_formatted_order_total() );
}
}
/**
* Render columm: order_actions.
*/
protected function render_order_actions_column() {
echo '<p>';
do_action( 'woocommerce_admin_order_actions_start', $this->object );
$actions = array();
if ( $this->object->has_status( array( 'pending', 'on-hold' ) ) ) {
$actions['processing'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=processing&order_id=' . $this->object->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Processing', 'woocommerce' ),
'action' => 'processing',
);
}
if ( $this->object->has_status( array( 'pending', 'on-hold', 'processing' ) ) ) {
$actions['complete'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=completed&order_id=' . $this->object->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Complete', 'woocommerce' ),
'action' => 'complete',
);
}
$actions = apply_filters( 'woocommerce_admin_order_actions', $actions, $this->object );
foreach ( $actions as $action ) {
printf( '<a class="button tips %s" href="%s" data-tip="%s">%s</a>', esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_attr( $action['name'] ) );
}
do_action( 'woocommerce_admin_order_actions_end', $this->object );
echo '</p>';
}
/**
* Render columm: billing_address.
*/
protected function render_billing_address_column() {
if ( $address = $this->object->get_formatted_billing_address() ) {
echo esc_html( preg_replace( '#<br\s*/?>#i', ', ', $address ) );
} else {
echo '&ndash;';
}
}
/**
* Render columm: shipping_address.
*/
protected function render_shipping_address_column() {
if ( $address = $this->object->get_formatted_shipping_address() ) {
echo '<a target="_blank" href="' . esc_url( $this->object->get_shipping_address_map_url() ) . '">' . esc_html( preg_replace( '#<br\s*/?>#i', ', ', $address ) ) . '</a>';
} else {
echo '&ndash;';
}
}
/**
* Template for order preview.
*
* @since 3.3.0
*/
public function order_preview_template() {
?>
<script type="text/template" id="tmpl-wc-modal-view-order">
<div class="wc-backbone-modal wc-order-preview">
<div class="wc-backbone-modal-content">
<section class="wc-backbone-modal-main" role="main">
<header class="wc-backbone-modal-header">
<h1><?php echo esc_html( sprintf( __( 'Order #%s', 'woocommerce' ), '{{ data.order_number }}' ) ); ?></h1>
<button class="modal-close modal-close-link dashicons dashicons-no-alt">
<span class="screen-reader-text"><?php esc_html_e( 'Close modal panel', 'woocommerce' ); ?></span>
</button>
</header>
<article>
{{{ data.item_html }}}
<div class="wc-order-preview-addresses">
<div class="wc-order-preview-address">
<h2><?php esc_html_e( 'Billing details', 'woocommerce' ); ?></h2>
{{{ data.formatted_billing_address }}}
<# if ( data.data.billing.email ) { #>
<strong><?php esc_html_e( 'Email', 'woocommerce' ); ?></strong>
<a href="mailto:{{ data.data.billing.email }}">{{ data.data.billing.email }}</a>
<# } #>
<# if ( data.data.billing.phone ) { #>
<strong><?php esc_html_e( 'Phone', 'woocommerce' ); ?></strong>
<a href="tel:{{ data.data.billing.phone }}">{{ data.data.billing.phone }}</a>
<# } #>
<# if ( data.payment_via ) { #>
<strong><?php esc_html_e( 'Payment via', 'woocommerce' ); ?></strong>
{{ data.payment_via }}
<# } #>
</div>
<# if ( data.needs_shipping ) { #>
<div class="wc-order-preview-address">
<h2><?php esc_html_e( 'Shipping details', 'woocommerce' ); ?></h2>
<# if ( data.ship_to_billing ) { #>
{{{ data.formatted_billing_address }}}
<# } else { #>
<a href="{{ data.shipping_address_map_url }}" target="_blank">{{{ data.formatted_shipping_address }}}</a>
<# } #>
<# if ( data.data.customer_note ) { #>
<strong><?php esc_html_e( 'Note', 'woocommerce' ); ?></strong>
{{ data.data.customer_note }}
<# } #>
<# if ( data.shipping_via ) { #>
<strong><?php esc_html_e( 'Shipping method', 'woocommerce' ); ?></strong>
{{ data.shipping_via }}
<# } #>
</div>
<# } #>
</div>
</article>
<footer>
<div class="inner">
<a class="button button-primary button-large" href="<?php echo esc_url( admin_url( 'post.php?action=edit' ) ); ?>&post={{ data.data.id }}"><?php esc_html_e( 'Edit order', 'woocommerce' ); ?></a>
</div>
</footer>
</section>
</div>
</div>
<div class="wc-backbone-modal-backdrop modal-close"></div>
</script>
<?php
}
/**
* Handle bulk actions.
*
* @param string $redirect_to URL to redirect to.
* @param string $action Action name.
* @param array $ids List of ids.
* @return string
*/
public function handle_bulk_actions( $redirect_to, $action, $ids ) {
// Bail out if this is not a status-changing action.
if ( false === strpos( $action, 'mark_' ) ) {
return $redirect_to;
}
$order_statuses = wc_get_order_statuses();
$new_status = substr( $action, 5 ); // Get the status name from action.
$report_action = 'marked_' . $new_status;
// Sanity check: bail out if this is actually not a status, or is
// not a registered status.
if ( ! isset( $order_statuses[ 'wc-' . $new_status ] ) ) {
return $redirect_to;
}
$changed = 0;
$ids = array_map( 'absint', $ids );
foreach ( $ids as $id ) {
$order = wc_get_order( $id );
$order->update_status( $new_status, __( 'Order status changed by bulk edit:', 'woocommerce' ), true );
do_action( 'woocommerce_order_edit_status', $id, $new_status );
$changed++;
}
$redirect_to = add_query_arg( array(
'post_type' => $this->list_table_type,
$report_action => true,
'changed' => $changed,
'ids' => join( ',', $ids ),
), $redirect_to );
return esc_url_raw( $redirect_to );
}
/**
* Show confirmation message that order status changed for number of orders.
*/
public function bulk_admin_notices() {
global $post_type, $pagenow;
// Bail out if not on shop order list page.
if ( 'edit.php' !== $pagenow || 'shop_order' !== $post_type ) {
return;
}
$order_statuses = wc_get_order_statuses();
// Check if any status changes happened.
foreach ( $order_statuses as $slug => $name ) {
if ( isset( $_REQUEST[ 'marked_' . str_replace( 'wc-', '', $slug ) ] ) ) { // WPCS: input var ok.
$number = isset( $_REQUEST['changed'] ) ? absint( $_REQUEST['changed'] ) : 0; // WPCS: input var ok.
/* translators: %s: orders count */
$message = sprintf( _n( '%d order status changed.', '%d order statuses changed.', $number, 'woocommerce' ), number_format_i18n( $number ) );
echo '<div class="updated"><p>' . esc_html( $message ) . '</p></div>';
break;
}
}
}
/**
* See if we should render search filters or not.
*/
public function restrict_manage_posts() {
global $typenow;
if ( in_array( $typenow, wc_get_order_types( 'order-meta-boxes' ), true ) ) {
$this->render_filters();
}
}
/**
* Render any custom filters and search inputs for the list table.
*/
protected function render_filters() {
$user_string = '';
$user_id = '';
if ( ! empty( $_GET['_customer_user'] ) ) { // WPCS: input var ok.
$user_id = absint( $_GET['_customer_user'] ); // WPCS: input var ok, sanitization ok.
$user = get_user_by( 'id', $user_id );
/* translators: 1: user display name 2: user ID 3: user email */
$user_string = sprintf(
esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
$user->display_name,
absint( $user->ID ),
$user->user_email
);
}
?>
<select class="wc-customer-search" name="_customer_user" data-placeholder="<?php esc_attr_e( 'Search for a customer&hellip;', 'woocommerce' ); ?>" data-allow_clear="true">
<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo wp_kses_post( $user_string ); ?><option>
</select>
<?php
}
/**
* Handle any filters.
*
* @param array $query_vars Query vars.
* @return array
*/
public function request_query( $query_vars ) {
global $typenow;
if ( in_array( $typenow, wc_get_order_types( 'order-meta-boxes' ), true ) ) {
return $this->query_filters( $query_vars );
}
return $query_vars;
}
/**
* Handle any custom filters.
*
* @param array $query_vars Query vars.
* @return array
*/
protected function query_filters( $query_vars ) {
global $wp_post_statuses;
// Filter the orders by the posted customer.
if ( ! empty( $_GET['_customer_user'] ) ) { // WPCS: input var ok.
// @codingStandardsIgnoreStart
$query_vars['meta_query'] = array(
array(
'key' => '_customer_user',
'value' => (int) $_GET['_customer_user'], // WPCS: input var ok, sanitization ok.
'compare' => '=',
),
);
// @codingStandardsIgnoreEnd
}
// Sorting.
if ( isset( $query_vars['orderby'] ) ) {
if ( 'order_total' === $query_vars['orderby'] ) {
// @codingStandardsIgnoreStart
$query_vars = array_merge( $query_vars, array(
'meta_key' => '_order_total',
'orderby' => 'meta_value_num',
) );
// @codingStandardsIgnoreEnd
}
}
// Status.
if ( ! isset( $query_vars['post_status'] ) ) {
$post_statuses = wc_get_order_statuses();
foreach ( $post_statuses as $status => $value ) {
if ( isset( $wp_post_statuses[ $status ] ) && false === $wp_post_statuses[ $status ]->show_in_admin_all_list ) {
unset( $post_statuses[ $status ] );
}
}
$query_vars['post_status'] = array_keys( $post_statuses );
}
return $query_vars;
}
/**
* Change the label when searching orders.
*
* @param mixed $query Current search query.
* @return string
*/
public function search_label( $query ) {
global $pagenow, $typenow;
if ( 'edit.php' !== $pagenow || 'shop_order' !== $typenow || ! get_query_var( 'shop_order_search' ) || ! isset( $_GET['s'] ) ) { // WPCS: input var ok.
return $query;
}
return wc_clean( wp_unslash( $_GET['s'] ) ); // WPCS: input var ok, sanitization ok.
}
/**
* Query vars for custom searches.
*
* @param mixed $public_query_vars Array of query vars.
* @return array
*/
public function add_custom_query_var( $public_query_vars ) {
$public_query_vars[] = 'shop_order_search';
return $public_query_vars;
}
/**
* Search custom fields as well as content.
*
* @param WP_Query $wp Query object.
*/
public function search_custom_fields( $wp ) {
global $pagenow;
if ( 'edit.php' !== $pagenow || empty( $wp->query_vars['s'] ) || 'shop_order' !== $wp->query_vars['post_type'] || ! isset( $_GET['s'] ) ) { // WPCS: input var ok.
return;
}
$post_ids = wc_order_search( wc_clean( wp_unslash( $_GET['s'] ) ) ); // WPCS: input var ok, sanitization ok.
if ( ! empty( $post_ids ) ) {
// Remove "s" - we don't want to search order name.
unset( $wp->query_vars['s'] );
// so we know we're doing this.
$wp->query_vars['shop_order_search'] = true;
// Search by found posts.
$wp->query_vars['post__in'] = array_merge( $post_ids, array( 0 ) );
}
}
}
new WC_Admin_List_Table_Orders();

View File

@ -0,0 +1,482 @@
<?php
/**
* List tables: products.
*
* @author WooCommerce
* @category Admin
* @package WooCommerce/Admin
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Admin_List_Table_Products', false ) ) {
new WC_Admin_List_Table_Products();
return;
}
if ( ! class_exists( 'WC_Admin_List_Table', false ) ) {
include_once( 'abstract-class-wc-admin-list-table.php' );
}
/**
* WC_Admin_List_Table_Products Class.
*/
class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
/**
* Post type.
*
* @var string
*/
protected $list_table_type = 'product';
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
add_filter( 'disable_months_dropdown', '__return_true' );
add_filter( 'query_vars', array( $this, 'add_custom_query_var' ) );
add_filter( 'posts_search', array( $this, 'sku_search' ) );
add_filter( 'views_edit-product', array( $this, 'product_views' ) );
}
/**
* Render blank state.
*/
protected function render_blank_state() {
echo '<div class="woocommerce-BlankState">';
echo '<h2 class="woocommerce-BlankState-message">' . esc_html__( 'Ready to start selling something awesome?', 'woocommerce' ) . '</h2>';
echo '<a class="woocommerce-BlankState-cta button-primary button" href="' . esc_url( admin_url( 'post-new.php?post_type=product&tutorial=true' ) ) . '">' . esc_html__( 'Create your first product!', 'woocommerce' ) . '</a>';
echo '<a class="woocommerce-BlankState-cta button" href="' . esc_url( admin_url( 'edit.php?post_type=product&page=product_importer' ) ) . '">' . esc_html__( 'Import products from a CSV file', 'woocommerce' ) . '</a>';
echo '</div>';
}
/**
* Define primary column.
*
* @return array
*/
protected function get_primary_column() {
return 'name';
}
/**
* Define which columns are sortable.
*
* @param array $columns Existing columns.
* @return array
*/
public function define_sortable_columns( $columns ) {
$custom = array(
'price' => 'price',
'sku' => 'sku',
'name' => 'title',
);
return wp_parse_args( $custom, $columns );
}
/**
* Define which columns to show on this screen.
*
* @param array $columns Existing columns.
* @return array
*/
public function define_columns( $columns ) {
if ( empty( $columns ) && ! is_array( $columns ) ) {
$columns = array();
}
unset( $columns['title'], $columns['comments'], $columns['date'] );
$show_columns = array();
$show_columns['cb'] = '<input type="checkbox" />';
$show_columns['thumb'] = '<span class="wc-image tips" data-tip="' . esc_attr__( 'Image', 'woocommerce' ) . '">' . __( 'Image', 'woocommerce' ) . '</span>';
$show_columns['name'] = __( 'Name', 'woocommerce' );
if ( wc_product_sku_enabled() ) {
$show_columns['sku'] = __( 'SKU', 'woocommerce' );
}
if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
$show_columns['is_in_stock'] = __( 'Stock', 'woocommerce' );
}
$show_columns['price'] = __( 'Price', 'woocommerce' );
$show_columns['product_cat'] = __( 'Categories', 'woocommerce' );
$show_columns['product_tag'] = __( 'Tags', 'woocommerce' );
$show_columns['featured'] = '<span class="wc-featured parent-tips" data-tip="' . esc_attr__( 'Featured', 'woocommerce' ) . '">' . __( 'Featured', 'woocommerce' ) . '</span>';
$show_columns['product_type'] = '<span class="wc-type parent-tips" data-tip="' . esc_attr__( 'Type', 'woocommerce' ) . '">' . __( 'Type', 'woocommerce' ) . '</span>';
$show_columns['date'] = __( 'Date', 'woocommerce' );
return array_merge( $show_columns, $columns );
}
/**
* Pre-fetch any data for the row each column has access to it. the_product global is there for bw compat.
*
* @param int $post_id Post ID being shown.
*/
protected function prepare_row_data( $post_id ) {
global $the_product;
if ( empty( $this->object ) || $this->object->get_id() !== $post_id ) {
$this->object = $the_product = wc_get_product( $post_id );
}
}
/**
* Render columm: thumb.
*/
protected function render_thumb_column() {
echo '<a href="' . esc_url( get_edit_post_link( $this->object->get_id() ) ) . '">' . $this->object->get_image( 'thumbnail' ) . '</a>';
}
/**
* Render columm: name.
*/
protected function render_name_column() {
global $post;
$edit_link = get_edit_post_link( $this->object->get_id() );
$title = _draft_or_post_title();
echo '<strong><a class="row-title" href="' . esc_url( $edit_link ) . '">' . esc_html( $title ) . '</a>';
_post_states( $post );
echo '</strong>';
if ( $this->object->get_parent_id() > 0 ) {
echo '&nbsp;&nbsp;&larr; <a href="' . esc_url( get_edit_post_link( $this->object->get_parent_id() ) ) . '">' . get_the_title( $this->object->get_parent_id() ) . '</a>';
}
get_inline_data( $post );
/* Custom inline data for woocommerce. */
echo '
<div class="hidden" id="woocommerce_inline_' . absint( $this->object->get_id() ) . '">
<div class="menu_order">' . absint( $this->object->get_menu_order() ) . '</div>
<div class="sku">' . esc_html( $this->object->get_sku() ) . '</div>
<div class="regular_price">' . esc_html( $this->object->get_regular_price() ) . '</div>
<div class="sale_price">' . esc_html( $this->object->get_sale_price() ) . '</div>
<div class="weight">' . esc_html( $this->object->get_weight() ) . '</div>
<div class="length">' . esc_html( $this->object->get_length() ) . '</div>
<div class="width">' . esc_html( $this->object->get_width() ) . '</div>
<div class="height">' . esc_html( $this->object->get_height() ) . '</div>
<div class="shipping_class">' . esc_html( $this->object->get_shipping_class() ) . '</div>
<div class="visibility">' . esc_html( $this->object->get_catalog_visibility() ) . '</div>
<div class="stock_status">' . esc_html( $this->object->get_stock_status() ) . '</div>
<div class="stock">' . esc_html( $this->object->get_stock_quantity() ) . '</div>
<div class="manage_stock">' . esc_html( wc_bool_to_string( $this->object->get_manage_stock() ) ) . '</div>
<div class="featured">' . esc_html( wc_bool_to_string( $this->object->get_featured() ) ) . '</div>
<div class="product_type">' . esc_html( $this->object->get_type() ) . '</div>
<div class="product_is_virtual">' . esc_html( wc_bool_to_string( $this->object->get_virtual() ) ) . '</div>
<div class="tax_status">' . esc_html( $this->object->get_tax_status() ) . '</div>
<div class="tax_class">' . esc_html( $this->object->get_tax_class() ) . '</div>
<div class="backorders">' . esc_html( $this->object->get_backorders() ) . '</div>
</div>
';
}
/**
* Render columm: sku.
*/
protected function render_sku_column() {
echo $this->object->get_sku() ? esc_html( $this->object->get_sku() ) : '<span class="na">&ndash;</span>';
}
/**
* Render columm: product_type.
*/
protected function render_product_type_column() {
if ( $this->object->is_type( 'grouped' ) ) {
echo '<span class="product-type tips grouped" data-tip="' . esc_attr__( 'Grouped', 'woocommerce' ) . '"></span>';
} elseif ( $this->object->is_type( 'external' ) ) {
echo '<span class="product-type tips external" data-tip="' . esc_attr__( 'External/Affiliate', 'woocommerce' ) . '"></span>';
} elseif ( $this->object->is_type( 'simple' ) ) {
if ( $this->object->is_virtual() ) {
echo '<span class="product-type tips virtual" data-tip="' . esc_attr__( 'Virtual', 'woocommerce' ) . '"></span>';
} elseif ( $this->object->is_downloadable() ) {
echo '<span class="product-type tips downloadable" data-tip="' . esc_attr__( 'Downloadable', 'woocommerce' ) . '"></span>';
} else {
echo '<span class="product-type tips simple" data-tip="' . esc_attr__( 'Simple', 'woocommerce' ) . '"></span>';
}
} elseif ( $this->object->is_type( 'variable' ) ) {
echo '<span class="product-type tips variable" data-tip="' . esc_attr__( 'Variable', 'woocommerce' ) . '"></span>';
} else {
// Assuming that we have other types in future.
echo '<span class="product-type tips ' . esc_attr( sanitize_html_class( $this->object->get_type() ) ) . '" data-tip="' . esc_attr( ucfirst( $this->object->get_type() ) ) . '"></span>';
}
}
/**
* Render columm: price.
*/
protected function render_price_column() {
echo $this->object->get_price_html() ? wp_kses_post( $this->object->get_price_html() ) : '<span class="na">&ndash;</span>';
}
/**
* Render columm: product_cat.
*/
protected function render_product_cat_column() {
if ( ! $terms = get_the_terms( $this->object->get_id(), 'product_cat' ) ) {
echo '<span class="na">&ndash;</span>';
} else {
$termlist = array();
foreach ( $terms as $term ) {
$termlist[] = '<a href="' . esc_url( admin_url( 'edit.php?product_cat=' . $term->slug . '&post_type=product' ) ) . ' ">' . esc_html( $term->name ) . '</a>';
}
echo implode( ', ', $termlist ); // WPCS: XSS ok.
}
}
/**
* Render columm: product_tag.
*/
protected function render_product_tag_column() {
if ( ! $terms = get_the_terms( $this->object->get_id(), 'product_tag' ) ) {
echo '<span class="na">&ndash;</span>';
} else {
$termlist = array();
foreach ( $terms as $term ) {
$termlist[] = '<a href="' . esc_url( admin_url( 'edit.php?product_tag=' . $term->slug . '&post_type=product' ) ) . ' ">' . esc_html( $term->name ) . '</a>';
}
echo implode( ', ', $termlist ); // WPCS: XSS ok.
}
}
/**
* Render columm: featured.
*/
protected function render_featured_column() {
$url = wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_feature_product&product_id=' . $this->object->get_id() ), 'woocommerce-feature-product' );
echo '<a href="' . esc_url( $url ) . '" aria-label="' . esc_attr__( 'Toggle featured', 'woocommerce' ) . '">';
if ( $this->object->is_featured() ) {
echo '<span class="wc-featured tips" data-tip="' . esc_attr__( 'Yes', 'woocommerce' ) . '">' . esc_html__( 'Yes', 'woocommerce' ) . '</span>';
} else {
echo '<span class="wc-featured not-featured tips" data-tip="' . esc_attr__( 'No', 'woocommerce' ) . '">' . esc_html__( 'No', 'woocommerce' ) . '</span>';
}
echo '</a>';
}
/**
* Render columm: is_in_stock.
*/
protected function render_is_in_stock_column() {
if ( $this->object->is_in_stock() ) {
$stock_html = '<mark class="instock">' . __( 'In stock', 'woocommerce' ) . '</mark>';
} else {
$stock_html = '<mark class="outofstock">' . __( 'Out of stock', 'woocommerce' ) . '</mark>';
}
if ( $this->object->managing_stock() ) {
$stock_html .= ' (' . wc_stock_amount( $this->object->get_stock_quantity() ) . ')';
}
echo wp_kses_post( apply_filters( 'woocommerce_admin_stock_html', $stock_html, $this->object ) );
}
/**
* Query vars for custom searches.
*
* @param mixed $public_query_vars Array of query vars.
* @return array
*/
public function add_custom_query_var( $public_query_vars ) {
$public_query_vars[] = 'sku';
return $public_query_vars;
}
/**
* Render any custom filters and search inputs for the list table.
*/
protected function render_filters() {
$current_category_slug = isset( $_REQUEST['product_cat'] ) ? wc_clean( wp_unslash( $_REQUEST['product_cat'] ) ) : false; // WPCS: input var ok, sanitization ok.
$current_product_type = isset( $_REQUEST['product_type'] ) ? wc_clean( wp_unslash( $_REQUEST['product_type'] ) ) : false; // WPCS: input var ok, sanitization ok.
// @codingStandardsIgnoreStart
$current_category = $current_category_slug ? get_term_by( 'slug', $current_category_slug, 'product_cat' ): false;
// @codingStandardsIgnoreEnd
?>
<select class="wc-category-search" name="product_cat" data-placeholder="<?php esc_attr_e( 'Filter by category', 'woocommerce' ); ?>" data-allow_clear="true">
<?php if ( $current_category_slug && $current_category ) : ?>
<option value="<?php echo esc_attr( $current_category_slug ); ?>" selected="selected"><?php echo esc_html( $current_category->name ); ?><option>
<?php endif; ?>
</select>
<?php
$terms = get_terms( 'product_type' );
$output = '<select name="product_type" id="dropdown_product_type">';
$output .= '<option value="">' . __( 'Filter by product type', 'woocommerce' ) . '</option>';
foreach ( $terms as $term ) {
$output .= '<option value="' . sanitize_title( $term->name ) . '" ';
$output .= selected( $term->slug, $current_product_type, false );
$output .= '>';
switch ( $term->name ) {
case 'grouped' :
$output .= __( 'Grouped product', 'woocommerce' );
break;
case 'external' :
$output .= __( 'External/Affiliate product', 'woocommerce' );
break;
case 'variable' :
$output .= __( 'Variable product', 'woocommerce' );
break;
case 'simple' :
$output .= __( 'Simple product', 'woocommerce' );
break;
default :
// Assuming that we have other types in future.
$output .= ucfirst( $term->name );
break;
}
$output .= '</option>';
if ( 'simple' === $term->name ) {
$output .= '<option value="downloadable" ';
if ( isset( $wp_query->query['product_type'] ) ) {
$output .= selected( 'downloadable', $current_product_type, false );
}
$output .= '> ' . ( is_rtl() ? '&larr;' : '&rarr;' ) . ' ' . __( 'Downloadable', 'woocommerce' ) . '</option>';
$output .= '<option value="virtual" ';
$output .= selected( 'virtual', $current_product_type, false );
$output .= '> ' . ( is_rtl() ? '&larr;' : '&rarr;' ) . ' ' . __( 'Virtual', 'woocommerce' ) . '</option>';
}
}
$output .= '</select>';
echo apply_filters( 'woocommerce_product_filters', $output ); // WPCS: XSS ok.
}
/**
* Handle any custom filters.
*
* @param array $query_vars Query vars.
* @return array
*/
protected function query_filters( $query_vars ) {
if ( isset( $query_vars['orderby'] ) ) {
if ( 'price' === $vars['orderby'] ) {
// @codingStandardsIgnoreStart
$query_vars = array_merge( $query_vars, array(
'meta_key' => '_price',
'orderby' => 'meta_value_num',
) );
// @codingStandardsIgnoreEnd
}
if ( 'sku' === $query_vars['orderby'] ) {
// @codingStandardsIgnoreStart
$query_vars = array_merge( $query_vars, array(
'meta_key' => '_sku',
'orderby' => 'meta_value',
) );
// @codingStandardsIgnoreEnd
}
}
if ( isset( $query_vars['product_type'] ) ) {
// @codingStandardsIgnoreStart
if ( 'downloadable' === $query_vars['product_type'] ) {
$query_vars['product_type'] = '';
$query_vars['meta_value'] = 'yes';
$query_vars['meta_key'] = '_downloadable';
} elseif ( 'virtual' === $query_vars['product_type'] ) {
$query_vars['product_type'] = '';
$query_vars['meta_value'] = 'yes';
$query_vars['meta_key'] = '_virtual';
}
// @codingStandardsIgnoreEnd
}
if ( isset( $_GET['product_shipping_class'] ) && '0' === $_GET['product_shipping_class'] ) { // WPCS: input var ok.
$query_vars['tax_query'][] = array(
'taxonomy' => 'product_shipping_class',
'field' => 'id',
'terms' => get_terms( 'product_shipping_class', array( 'fields' => 'ids' ) ),
'operator' => 'NOT IN',
);
}
return $query_vars;
}
/**
* Search by SKU or ID for products.
*
* @param string $where Where clause SQL.
* @return string
*/
public function sku_search( $where ) {
global $pagenow, $wpdb, $wp;
if ( 'edit.php' !== $pagenow || ! is_search() || ! isset( $wp->query_vars['s'] ) || 'product' !== $wp->query_vars['post_type'] ) {
return $where;
}
$search_ids = array();
$terms = explode( ',', $wp->query_vars['s'] );
foreach ( $terms as $term ) {
if ( is_numeric( $term ) ) {
$search_ids[] = absint( $term );
} else {
$id_from_sku = wc_get_product_id_by_sku( wc_clean( $term ) );
if ( $id_from_sku ) {
$search_ids[] = absint( $id_from_sku );
}
}
}
$search_ids = array_filter( array_unique( array_map( 'absint', $search_ids ) ) );
if ( count( $search_ids ) > 0 ) {
$where = str_replace( 'AND (((', "AND ( ({$wpdb->posts}.ID IN (" . implode( ',', $search_ids ) . ')) OR ((', $where );
}
return $where;
}
/**
* Change views on the edit product screen.
*
* @param array $views Array of views.
* @return array
*/
public function product_views( $views ) {
global $wp_query;
// Products do not have authors.
unset( $views['mine'] );
// Add sorting link.
if ( current_user_can( 'edit_others_pages' ) ) {
$class = ( isset( $wp_query->query['orderby'] ) && 'menu_order title' === $wp_query->query['orderby'] ) ? 'current' : '';
$query_string = remove_query_arg( array( 'orderby', 'order' ) );
$query_string = add_query_arg( 'orderby', rawurlencode( 'menu_order title' ), $query_string );
$query_string = add_query_arg( 'order', rawurlencode( 'ASC' ), $query_string );
$views['byorder'] = '<a href="' . esc_url( $query_string ) . '" class="' . esc_attr( $class ) . '">' . __( 'Sorting', 'woocommerce' ) . '</a>';
}
return $views;
}
}
new WC_Admin_List_Table_Products();

View File

@ -117,7 +117,7 @@ class WC_Meta_Box_Coupon_Data {
'id' => 'minimum_amount',
'label' => __( 'Minimum spend', 'woocommerce' ),
'placeholder' => __( 'No minimum', 'woocommerce' ),
'description' => __( 'This field allows you to set the minimum spend (subtotal, including taxes) allowed to use the coupon.', 'woocommerce' ),
'description' => __( 'This field allows you to set the minimum spend (subtotal) allowed to use the coupon.', 'woocommerce' ),
'data_type' => 'price',
'desc_tip' => true,
) );
@ -127,7 +127,7 @@ class WC_Meta_Box_Coupon_Data {
'id' => 'maximum_amount',
'label' => __( 'Maximum spend', 'woocommerce' ),
'placeholder' => __( 'No maximum', 'woocommerce' ),
'description' => __( 'This field allows you to set the maximum spend (subtotal, including taxes) allowed when using the coupon.', 'woocommerce' ),
'description' => __( 'This field allows you to set the maximum spend (subtotal) allowed when using the coupon.', 'woocommerce' ),
'data_type' => 'price',
'desc_tip' => true,
) );

View File

@ -2,17 +2,22 @@
/**
* WooCommerce API Settings
*
* @author WooThemes
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 2.4.0
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'WC_Settings_Rest_API', false ) ) :
/**
* Settings for API.
*/
if ( class_exists( 'WC_Settings_Rest_API', false ) ) {
return new WC_Settings_Rest_API();
}
/**
* WC_Settings_Rest_API.
@ -50,7 +55,7 @@ class WC_Settings_Rest_API extends WC_Settings_Page {
/**
* Get settings array.
*
* @param string $current_section
* @param string $current_section Current section slug.
* @return array
*/
public function get_settings( $current_section = '' ) {
@ -86,28 +91,15 @@ class WC_Settings_Rest_API extends WC_Settings_Page {
/**
* Form method.
*
* @param string $method
* @param string $method Method name.
*
* @return string
*/
public function form_method( $method ) {
global $current_section;
if ( 'webhooks' == $current_section ) {
if ( isset( $_GET['edit-webhook'] ) ) {
$webhook_id = absint( $_GET['edit-webhook'] );
$webhook = new WC_Webhook( $webhook_id );
if ( 'trash' != $webhook->post_data->post_status ) {
return 'post';
}
}
return 'get';
}
if ( 'keys' == $current_section ) {
if ( isset( $_GET['create-key'] ) || isset( $_GET['edit-key'] ) ) {
if ( 'keys' === $current_section ) {
if ( isset( $_GET['create-key'] ) || isset( $_GET['edit-key'] ) ) { // WPCS: input var okay, CSRF ok.
return 'post';
}
@ -121,10 +113,10 @@ class WC_Settings_Rest_API extends WC_Settings_Page {
* Notices.
*/
private function notices() {
if ( isset( $_GET['section'] ) && 'webhooks' == $_GET['section'] ) {
if ( isset( $_GET['section'] ) && 'webhooks' === $_GET['section'] ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Webhooks::notices();
}
if ( isset( $_GET['section'] ) && 'keys' == $_GET['section'] ) {
if ( isset( $_GET['section'] ) && 'keys' === $_GET['section'] ) { // WPCS: input var okay, CSRF ok.
WC_Admin_API_Keys::notices();
}
}
@ -135,7 +127,7 @@ class WC_Settings_Rest_API extends WC_Settings_Page {
public function output() {
global $current_section;
if ( 'webhooks' == $current_section ) {
if ( 'webhooks' === $current_section ) {
WC_Admin_Webhooks::page_output();
} elseif ( 'keys' === $current_section ) {
WC_Admin_API_Keys::page_output();
@ -151,13 +143,11 @@ class WC_Settings_Rest_API extends WC_Settings_Page {
public function save() {
global $current_section;
if ( apply_filters( 'woocommerce_rest_api_valid_to_save', ! in_array( $current_section, array( 'keys', 'webhooks' ) ) ) ) {
if ( apply_filters( 'woocommerce_rest_api_valid_to_save', ! in_array( $current_section, array( 'keys', 'webhooks' ), true ) ) ) {
$settings = $this->get_settings();
WC_Admin_Settings::save_fields( $settings );
}
}
}
endif;
return new WC_Settings_Rest_API();

View File

@ -1,8 +1,8 @@
<?php
/**
* Edit Webhooks
* Admin View: Edit Webhooks
*
* @package WooCommerce/Admin/Webhooks
* @package WooCommerce\Admin\Webhooks\Views
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -10,7 +10,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
?>
<input type="hidden" name="webhook_id" value="<?php echo esc_attr( $webhook->id ); ?>" />
<input type="hidden" name="webhook_id" value="<?php echo esc_attr( $webhook->get_id() ); ?>" />
<div id="webhook-options" class="settings-panel">
<h2><?php esc_html_e( 'Webhook data', 'woocommerce' ); ?></h2>
@ -20,9 +20,8 @@ if ( ! defined( 'ABSPATH' ) ) {
<th scope="row" class="titledesc">
<label for="webhook_name"><?php esc_html_e( 'Name', 'woocommerce' ); ?></label>
<?php
// @codingStandardsIgnoreStart
echo wc_help_tip( sprintf( __( 'Friendly name for identifying this webhook, defaults to Webhook created on %s.', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ) );
// @codingStandardsIgnoreEnd
/* translators: %s: date */
echo wc_help_tip( sprintf( __( 'Friendly name for identifying this webhook, defaults to Webhook created on %s.', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ) ); // @codingStandardsIgnoreLine
?>
</th>
<td class="forminp">
@ -40,7 +39,8 @@ if ( ! defined( 'ABSPATH' ) ) {
$statuses = wc_get_webhook_statuses();
$current_status = $webhook->get_status();
foreach ( $statuses as $status_slug => $status_name ) : ?>
foreach ( $statuses as $status_slug => $status_name ) :
?>
<option value="<?php echo esc_attr( $status_slug ); ?>" <?php selected( $current_status, $status_slug, true ); ?>><?php echo esc_html( $status_name ); ?></option>
<?php endforeach; ?>
</select>
@ -49,7 +49,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_topic"><?php esc_html_e( 'Topic', 'woocommerce' ); ?></label>
<?php echo wc_help_tip( __( 'Select when the webhook will fire.', 'woocommerce' ) ); // @codingStandardsIgnoreLine ?>
<?php echo wc_help_tip( __( 'Select when the webhook will fire.', 'woocommerce' ) ); ?>
</th>
<td class="forminp">
<select name="webhook_topic" id="webhook_topic" class="wc-enhanced-select">
@ -77,7 +77,8 @@ if ( ! defined( 'ABSPATH' ) ) {
'custom' => __( 'Custom', 'woocommerce' ),
) );
foreach ( $topics as $topic_slug => $topic_name ) : ?>
foreach ( $topics as $topic_slug => $topic_name ) :
?>
<option value="<?php echo esc_attr( $topic_slug ); ?>" <?php selected( $topic_data['topic'], $topic_slug, true ); ?>><?php echo esc_html( $topic_name ); ?></option>
<?php endforeach; ?>
</select>
@ -86,7 +87,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top" id="webhook-action-event-wrap">
<th scope="row" class="titledesc">
<label for="webhook_action_event"><?php esc_html_e( 'Action event', 'woocommerce' ); ?></label>
<?php echo wc_help_tip( __( 'Enter the action that will trigger this webhook.', 'woocommerce' ) ); // @codingStandardsIgnoreLine ?>
<?php echo wc_help_tip( __( 'Enter the action that will trigger this webhook.', 'woocommerce' ) ); ?>
</th>
<td class="forminp">
<input name="webhook_action_event" id="webhook_action_event" type="text" class="input-text regular-input" value="<?php echo esc_attr( $topic_data['event'] ); ?>" />
@ -95,7 +96,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top" id="webhook-custom-topic-wrap">
<th scope="row" class="titledesc">
<label for="webhook_custom_topic"><?php esc_html_e( 'Custom topic', 'woocommerce' ); ?></label>
<?php echo wc_help_tip( __( 'Enter the custom topic that will trigger this webhook.', 'woocommerce' ) ); // @codingStandardsIgnoreLine ?>
<?php echo wc_help_tip( __( 'Enter the custom topic that will trigger this webhook.', 'woocommerce' ) ); ?>
</th>
<td class="forminp">
<input name="webhook_custom_topic" id="webhook_custom_topic" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_topic() ); ?>" />
@ -104,7 +105,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_delivery_url"><?php esc_html_e( 'Delivery URL', 'woocommerce' ); ?></label>
<?php echo wc_help_tip( __( 'URL where the webhook payload is delivered.', 'woocommerce' ) ); // @codingStandardsIgnoreLine ?>
<?php echo wc_help_tip( __( 'URL where the webhook payload is delivered.', 'woocommerce' ) ); ?>
</th>
<td class="forminp">
<input name="webhook_delivery_url" id="webhook_delivery_url" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_delivery_url() ); ?>" />
@ -113,7 +114,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_secret"><?php esc_html_e( 'Secret', 'woocommerce' ); ?></label>
<?php echo wc_help_tip( __( 'The secret key is used to generate a hash of the delivered webhook and provided in the request headers.', 'woocommerce' ) ); // @codingStandardsIgnoreLine ?>
<?php echo wc_help_tip( __( 'The secret key is used to generate a hash of the delivered webhook and provided in the request headers.', 'woocommerce' ) ); ?>
</th>
<td class="forminp">
<input name="webhook_secret" id="webhook_secret" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_secret() ); ?>" />
@ -122,7 +123,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top">
<th scope="row" class="titledesc">
<label for="webhook_api_version"><?php esc_html_e( 'API Version', 'woocommerce' ); ?></label>
<?php echo wc_help_tip( __( 'REST API version used in the webhook deliveries.', 'woocommerce' ) ); // @codingStandardsIgnoreLine ?>
<?php echo wc_help_tip( __( 'REST API version used in the webhook deliveries.', 'woocommerce' ) ); ?>
</th>
<td class="forminp">
<select name="webhook_api_version" id="webhook_api_version">
@ -142,14 +143,14 @@ if ( ! defined( 'ABSPATH' ) ) {
<h2><?php esc_html_e( 'Webhook actions', 'woocommerce' ); ?></h2>
<table class="form-table">
<tbody>
<?php if ( '0000-00-00 00:00:00' != $webhook->post_data->post_modified_gmt ) : ?>
<?php if ( '0000-00-00 00:00:00' == $webhook->post_data->post_date_gmt ) : ?>
<?php if ( $webhook->get_date_created() && '0000-00-00 00:00:00' !== $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) : ?>
<?php if ( is_null( $webhook->get_date_modified() ) ) : ?>
<tr valign="top">
<th scope="row" class="titledesc">
<?php esc_html_e( 'Created at', 'woocommerce' ); ?>
</th>
<td class="forminp">
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->post_data->post_modified_gmt ) ) ); ?>
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
</td>
</tr>
<?php else : ?>
@ -158,7 +159,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php esc_html_e( 'Created at', 'woocommerce' ); ?>
</th>
<td class="forminp">
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->post_data->post_date_gmt ) ) ); ?>
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
</td>
</tr>
<tr valign="top">
@ -166,7 +167,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php esc_html_e( 'Updated at', 'woocommerce' ); ?>
</th>
<td class="forminp">
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->post_data->post_modified_gmt ) ) ); ?>
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_modified()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
</td>
</tr>
<?php endif; ?>
@ -174,10 +175,14 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr valign="top">
<td colspan="2" scope="row" style="padding-left: 0;">
<p class="submit">
<button type="submit" class="button button-primary button-large" name="save" id="publish" accesskey="p" value="<?php esc_attr_e( 'Save webhook', 'woocommerce' ); ?>"><?php esc_html_e( 'Save webhook', 'woocommerce' ); ?></button>
<?php if ( current_user_can( 'delete_post', $webhook->id ) ) : ?>
<?php //@codingStandardsIgnoreLine ?>
<a style="color: #a00; text-decoration: none; margin-left: 10px;" href="<?php echo esc_url( get_delete_post_link( $webhook->id ) ); ?>"><?php echo ( ! EMPTY_TRASH_DAYS ) ? esc_html__( 'Delete permanently', 'woocommerce' ) : esc_html__( 'Move to trash', 'woocommerce' ); ?></a>
<button type="submit" class="button button-primary button-large" name="save" id="publish" accesskey="p"><?php esc_html_e( 'Save webhook', 'woocommerce' ); ?></button>
<?php
if ( $webhook->get_id() ) :
$delete_url = wp_nonce_url( add_query_arg( array(
'delete' => $webhook->get_id(),
), admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks' ) ), 'delete-webhook' );
?>
<a style="color: #a00; text-decoration: none; margin-left: 10px;" href="<?php echo esc_url( $delete_url ); ?>"><?php esc_html_e( 'Delete permanently', 'woocommerce' ); ?></a>
<?php endif; ?>
</p>
</td>
@ -186,12 +191,6 @@ if ( ! defined( 'ABSPATH' ) ) {
</table>
</div>
<div id="webhook-logs" class="settings-panel">
<h2><?php esc_html_e( 'Webhook logs', 'woocommerce' ); ?></h2>
<?php WC_Admin_Webhooks::logs_output( $webhook ); ?>
</div>
<script type="text/javascript">
jQuery( function ( $ ) {
$( '#webhook-options' ).find( '#webhook_topic' ).on( 'change', function() {

View File

@ -308,6 +308,6 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php do_action( 'woocommerce_product_bulk_edit_end' ); ?>
<input type="hidden" name="woocommerce_bulk_edit" value="1" />
<input type="hidden" name="woocommerce_bulk_edit_nonce" value="<?php echo wp_create_nonce( 'woocommerce_bulk_edit_nonce' ); ?>" />
<input type="hidden" name="woocommerce_quick_edit_nonce" value="<?php echo wp_create_nonce( 'woocommerce_quick_edit_nonce' ); ?>" />
</div>
</fieldset>

View File

@ -99,6 +99,7 @@ class WC_AJAX {
'get_customer_location' => true,
'feature_product' => false,
'mark_order_status' => false,
'get_order_details' => false,
'add_attribute' => false,
'add_new_attribute' => false,
'remove_variation' => false,
@ -472,6 +473,97 @@ class WC_AJAX {
exit;
}
/**
* Get order details.
*/
public static function get_order_details() {
check_admin_referer( 'woocommerce-preview-order', 'security' );
if ( ! current_user_can( 'edit_shop_orders' ) ) {
wp_die( -1 );
}
if ( $order = wc_get_order( absint( $_GET['order_id'] ) ) ) {
ob_start();
$hidden_order_itemmeta = apply_filters( 'woocommerce_hidden_order_itemmeta', array(
'_qty',
'_tax_class',
'_product_id',
'_variation_id',
'_line_subtotal',
'_line_subtotal_tax',
'_line_total',
'_line_tax',
'method_id',
'cost',
) );
?>
<div class="wc-order-preview__table-wrapper">
<table cellspacing="0" class="wc-order-preview__table">
<tr>
<th><?php _e( 'Product', 'woocommerce' ); ?></th>
<th><?php _e( 'Quantity', 'woocommerce' ); ?></th>
<th><?php _e( 'Tax', 'woocommerce' ); ?></th>
<th><?php _e( 'Total', 'woocommerce' ); ?></th>
</tr>
<?php
foreach ( $order->get_items() as $item_id => $item ) {
if ( apply_filters( 'woocommerce_order_item_visible', true, $item ) ) {
?>
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order ) ); ?>">
<td><?php
echo apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false );
if ( is_callable( array( $item, 'get_product' ) ) && ( $product = $item->get_product() ) && is_object( $product ) && $product->get_sku() ) {
echo '<div class="wc-order-item-sku">' . esc_html( $product->get_sku() ) . '</div>';
}
if ( $meta_data = $item->get_formatted_meta_data( '' ) ) : ?>
<table cellspacing="0" class="wc-order-item-meta">
<?php foreach ( $meta_data as $meta_id => $meta ) :
if ( in_array( $meta->key, $hidden_order_itemmeta ) ) {
continue;
}
?>
<tr>
<th><?php echo wp_kses_post( $meta->display_key ); ?>:</th>
<td><?php echo wp_kses_post( force_balance_tags( $meta->display_value ) ); ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php endif;
?></td>
<td><?php echo esc_html( $item->get_quantity() ); ?></td>
<td><?php echo wc_price( $item->get_total_tax(), array( 'currency' => $order->get_currency() ) );; ?></td>
<td><?php echo wc_price( $item->get_total(), array( 'currency' => $order->get_currency() ) );; ?></td>
</tr>
<?php
}
}
?>
</table>
</div>
<?php
$item_html = ob_get_clean();
wp_send_json_success( array(
'data' => $order->get_data(),
'order_number' => $order->get_order_number(),
'item_html' => $item_html,
'ship_to_billing' => wc_ship_to_billing_address_only(),
'needs_shipping' => $order->needs_shipping_address(),
'formatted_billing_address' => ( $address = $order->get_formatted_billing_address() ) ? $address : __( 'N/A', 'woocommerce' ),
'formatted_shipping_address' => ( $address = $order->get_formatted_shipping_address() ) ? $address: __( 'N/A', 'woocommerce' ),
'shipping_address_map_url' => $order->get_shipping_address_map_url(),
'payment_via' => $order->get_payment_method_title() . ( $order->get_transaction_id() ? ' (' . $order->get_transaction_id() . ')' : '' ),
'shipping_via' => $order->get_shipping_method(),
) );
}
exit;
}
/**
* Add an attribute row.
*/

View File

@ -32,11 +32,11 @@ class WC_Comments {
// Secure order notes
add_filter( 'comments_clauses', array( __CLASS__, 'exclude_order_comments' ), 10, 1 );
add_action( 'comment_feed_where', array( __CLASS__, 'exclude_order_comments_from_feed_where' ) );
add_filter( 'comment_feed_where', array( __CLASS__, 'exclude_order_comments_from_feed_where' ) );
// Secure webhook comments
add_filter( 'comments_clauses', array( __CLASS__, 'exclude_webhook_comments' ), 10, 1 );
add_action( 'comment_feed_where', array( __CLASS__, 'exclude_webhook_comments_from_feed_where' ) );
add_filter( 'comment_feed_where', array( __CLASS__, 'exclude_webhook_comments_from_feed_where' ) );
// Count comments
add_filter( 'wp_count_comments', array( __CLASS__, 'wp_count_comments' ), 10, 2 );

View File

@ -613,8 +613,7 @@ class WC_Discounts {
* @return bool
*/
protected function validate_coupon_minimum_amount( $coupon ) {
$subtotal = wc_remove_number_precision( array_sum( wp_list_pluck( $this->items, 'price' ) ) );
$subtotal = wc_remove_number_precision( $this->get_object_subtotal() );
if ( $coupon->get_minimum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_minimum_amount', $coupon->get_minimum_amount() > $subtotal, $coupon, $subtotal ) ) {
/* translators: %s: coupon minimum amount */
throw new Exception( sprintf( __( 'The minimum spend for this coupon is %s.', 'woocommerce' ), wc_price( $coupon->get_minimum_amount() ) ), 108 );
@ -632,8 +631,7 @@ class WC_Discounts {
* @return bool
*/
protected function validate_coupon_maximum_amount( $coupon ) {
$subtotal = wc_remove_number_precision( array_sum( wp_list_pluck( $this->items, 'price' ) ) );
$subtotal = wc_remove_number_precision( $this->get_object_subtotal() );
if ( $coupon->get_maximum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_maximum_amount', $coupon->get_maximum_amount() < $subtotal, $coupon ) ) {
/* translators: %s: coupon maximum amount */
throw new Exception( sprintf( __( 'The maximum spend for this coupon is %s.', 'woocommerce' ), wc_price( $coupon->get_maximum_amount() ) ), 112 );
@ -847,6 +845,21 @@ class WC_Discounts {
return true;
}
/**
* Get the object subtotal
*
* @return int
*/
protected function get_object_subtotal() {
if ( is_a( $this->object, 'WC_Cart' ) ) {
return wc_add_number_precision( $this->object->get_displayed_subtotal() );
} elseif ( is_a( $this->object, 'WC_Order' ) ) {
return wc_add_number_precision( $this->object->get_subtotal() );
} else {
return array_sum( wp_list_pluck( $this->items, 'price' ) );
}
}
/**
* Check if a coupon is valid.
*

View File

@ -359,7 +359,9 @@ class WC_Download_Handler {
* @return bool Success or fail
*/
public static function readfile_chunked( $file ) {
$chunksize = 1024 * 1024;
if ( ! defined( 'WC_CHUNK_SIZE' ) ) {
define( 'WC_CHUNK_SIZE', 1024 * 1024 );
}
$handle = @fopen( $file, 'r' );
if ( false === $handle ) {
@ -367,7 +369,7 @@ class WC_Download_Handler {
}
while ( ! @feof( $handle ) ) {
echo @fread( $handle, $chunksize );
echo @fread( $handle, (int) WC_CHUNK_SIZE );
if ( ob_get_length() ) {
ob_flush();

View File

@ -834,8 +834,8 @@ class WC_Form_Handler {
*/
private static function add_to_cart_handler_variable( $product_id ) {
try {
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // WPCS: sanitization ok.
$missing_attributes = array();
$variations = array();
$adding_to_cart = wc_get_product( $product_id );
@ -873,19 +873,23 @@ class WC_Form_Handler {
continue;
}
$taxonomy = 'attribute_' . sanitize_title( $attribute['name'] );
// Get valid value from variation data.
$taxonomy = 'attribute_' . sanitize_title( $attribute['name'] );
$valid_value = isset( $variation_data[ $taxonomy ] ) ? $variation_data[ $taxonomy ] : '';
/**
* If the attribute value was posted, check if it's valid.
*
* If no attribute was posted, only error if the variation has an 'any' attribute which requires a value.
*/
if ( isset( $_REQUEST[ $taxonomy ] ) ) {
if ( $attribute['is_taxonomy'] ) {
// Don't use wc_clean as it destroys sanitized characters.
$value = sanitize_title( wp_unslash( $_REQUEST[ $taxonomy ] ) );
} else {
$value = wc_clean( wp_unslash( $_REQUEST[ $taxonomy ] ) );
$value = wc_clean( wp_unslash( $_REQUEST[ $taxonomy ] ) ); // WPCS: sanitization ok.
}
// Get valid value from variation data.
$valid_value = isset( $variation_data[ $taxonomy ] ) ? $variation_data[ $taxonomy ] : '';
// Allow if valid or show error.
if ( $valid_value === $value ) {
$variations[ $taxonomy ] = $value;
@ -895,7 +899,7 @@ class WC_Form_Handler {
} else {
throw new Exception( sprintf( __( 'Invalid value posted for %s', 'woocommerce' ), wc_attribute_label( $attribute['name'] ) ) );
}
} else {
} elseif ( '' === $valid_value ) {
$missing_attributes[] = wc_attribute_label( $attribute['name'] );
}
}

View File

@ -2,7 +2,7 @@
/**
* Webhook Data Store
*
* @version 3.2.0
* @version 3.3.0
* @package WooCommerce/Classes/Data_Store
* @category Class
* @author Automattic
@ -20,7 +20,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
/**
* Create a new webhook in the database.
*
* @since 3.2.0
* @since 3.3.0
* @param WC_Webhook $webhook Webhook instance.
*/
public function create( &$webhook ) {
@ -50,22 +50,21 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
'pending_delivery' => $webhook->get_pending_delivery( 'edit' ),
);
// @codingStandardsIgnoreStart
$wpdb->insert( $wpdb->prefix . 'wc_webhooks', $data );
// @codingStandardsIgnoreEnd
$wpdb->insert( $wpdb->prefix . 'wc_webhooks', $data ); // WPCS: DB call ok.
$webhook_id = $wpdb->insert_id;
$webhook->set_id( $webhook_id );
$webhook->apply_changes();
delete_transient( 'woocommerce_webhook_ids' );
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
do_action( 'woocommerce_new_webhook', $webhook_id );
}
/**
* Read a webhook from the database.
*
* @since 3.2.0
* @since 3.3.0
* @param WC_Webhook $webhook Webhook instance.
* @throws Exception When webhook is invalid.
*/
@ -75,9 +74,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
$data = wp_cache_get( $webhook->get_id(), 'webhooks' );
if ( false === $data ) {
// @codingStandardsIgnoreStart
$data = $wpdb->get_row( $wpdb->prepare( "SELECT webhook_id, status, name, user_id, delivery_url, secret, topic, date_created, date_modified, api_version, failure_count, pending_delivery FROM {$wpdb->prefix}wc_webhooks WHERE webhook_id = %d LIMIT 1;", $webhook->get_id() ), ARRAY_A );
// @codingStandardsIgnoreEnd
$data = $wpdb->get_row( $wpdb->prepare( "SELECT webhook_id, status, name, user_id, delivery_url, secret, topic, date_created, date_modified, api_version, failure_count, pending_delivery FROM {$wpdb->prefix}wc_webhooks WHERE webhook_id = %d LIMIT 1;", $webhook->get_id() ), ARRAY_A ); // WPCS: cache ok, DB call ok.
wp_cache_add( $webhook->get_id(), $data, 'webhooks' );
}
@ -91,8 +88,8 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
'delivery_url' => $data['delivery_url'],
'secret' => $data['secret'],
'topic' => $data['topic'],
'date_created' => $data['date_created'],
'date_modified' => $data['date_modified'],
'date_created' => '0000-00-00 00:00:00' === $data['date_created'] ? null : $data['date_created'],
'date_modified' => '0000-00-00 00:00:00' === $data['date_modified'] ? null : $data['date_modified'],
'api_version' => $data['api_version'],
'failure_count' => $data['failure_count'],
'pending_delivery' => $data['pending_delivery'],
@ -108,7 +105,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
/**
* Update a webhook.
*
* @since 3.2.0
* @since 3.3.0
* @param WC_Webhook $webhook Webhook instance.
*/
public function update( &$webhook ) {
@ -138,50 +135,48 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
'pending_delivery' => $webhook->get_pending_delivery( 'edit' ),
);
// @codingStandardsIgnoreStart
$wpdb->update(
$wpdb->prefix . 'wc_webhooks',
$data,
array(
'webhook_id' => $webhook->get_id( 'edit' ),
)
);
// @codingStandardsIgnoreEnd
); // WPCS: DB call ok.
$webhook->apply_changes();
wp_cache_delete( $webhook->get_id(), 'webhooks' );
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
do_action( 'woocommerce_webhook_updated', $webhook->get_id() );
}
/**
* Remove a webhook from the database.
*
* @since 3.2.0
* @since 3.3.0
* @param WC_Webhook $webhook Webhook instance.
* @param bool $force_delete Skip trash bin forcing to delete.
*/
public function delete( &$webhook, $force_delete = false ) {
global $wpdb;
// @codingStandardsIgnoreStart
$wpdb->delete(
$wpdb->prefix . 'wc_webhooks',
array(
'webhook_id' => $webhook->get_id(),
),
array( '%d' )
);
// @codingStandardsIgnoreEnd
); // WPCS: cache ok, DB call ok.
delete_transient( 'woocommerce_webhook_ids' );
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
do_action( 'woocommerce_webhook_deleted', $webhook->get_id(), $webhook );
}
/**
* Get API version number.
*
* @since 3.2.0
* @since 3.3.0
* @param string $api_version REST API version.
* @return int
*/
@ -192,7 +187,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
/**
* Get all webhooks IDs.
*
* @since 3.2.0
* @since 3.3.0
* @return int[]
*/
public function get_webhooks_ids() {
@ -201,14 +196,78 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
$ids = get_transient( 'woocommerce_webhook_ids' );
if ( false === $ids ) {
// @codingStandardsIgnoreStart
$results = $wpdb->get_results( "SELECT webhook_id FROM {$wpdb->prefix}wc_webhooks" );
// @codingStandardsIgnoreEnd
$ids = array_map( 'intval', wp_list_pluck( $results, 'webhook_id' ) );
$results = $wpdb->get_results( "SELECT webhook_id FROM {$wpdb->prefix}wc_webhooks" ); // WPCS: cache ok, DB call ok.
$ids = array_map( 'intval', wp_list_pluck( $results, 'webhook_id' ) );
set_transient( 'woocommerce_webhook_ids', $ids );
}
return $ids;
}
/**
* Search webhooks.
*
* @param array $args Search arguments.
* @return array
*/
public function search_webhooks( $args ) {
global $wpdb;
$args = wp_parse_args( $args, array(
'limit' => 10,
'offset' => 0,
) );
$limit = -1 < $args['limit'] ? sprintf( 'LIMIT %d', $args['limit'] ) : '';
$offset = 0 < $args['offset'] ? sprintf( 'OFFSET %d', $args['offset'] ) : '';
$status = ! empty( $args['status'] ) ? "AND `status` = '" . sanitize_key( $args['status'] ) . "'" : '';
$search = ! empty( $args['search'] ) ? "AND `name` LIKE '%" . $wpdb->esc_like( sanitize_text_field( $args['search'] ) ) . "%'" : '';
$cache_key = WC_Cache_Helper::get_cache_prefix( 'webhooks' ) . 'search_webhooks' . md5( implode( ',', $args ) );
$ids = wp_cache_get( $cache_key, 'webhook_search_results' );
if ( false !== $ids ) {
return $ids;
}
$query = trim( "
SELECT webhook_id
FROM {$wpdb->prefix}wc_webhooks
WHERE 1=1
{$status}
{$search}
ORDER BY webhook_id
{$limit}
{$offset}
" );
$results = $wpdb->get_results( $query ); // WPCS: cache ok, DB call ok, unprepared SQL ok.
$ids = wp_list_pluck( $results, 'webhook_id' );
wp_cache_set( $cache_key, $ids, 'webhook_search_results' );
return $ids;
}
/**
* Get total webhook counts by status.
*
* @return array
*/
public function get_count_webhooks_by_status() {
$statuses = array_keys( wc_get_webhook_statuses() );
$counts = array();
foreach ( $statuses as $status ) {
$count = count( $this->search_webhooks( array(
'limit' => -1,
'status' => $status,
) ) );
$counts[ $status ] = $count;
}
return $counts;
}
}

View File

@ -36,6 +36,11 @@ return array(
'desc_tip' => true,
'placeholder' => 'you@youremail.com',
),
'advanced' => array(
'title' => __( 'Advanced options', 'woocommerce' ),
'type' => 'title',
'description' => '',
),
'testmode' => array(
'title' => __( 'PayPal sandbox', 'woocommerce' ),
'type' => 'checkbox',
@ -53,14 +58,9 @@ return array(
'ipn_notification' => array(
'title' => __( 'IPN Email Notifications', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable IPN email notification', 'woocommerce' ),
'label' => __( 'Enable IPN email notifications', 'woocommerce' ),
'default' => 'yes',
'description' => __( 'Send an email to the user handling orders when an IPN is received from PayPal.', 'woocommerce' )
),
'advanced' => array(
'title' => __( 'Advanced options', 'woocommerce' ),
'type' => 'title',
'description' => '',
'description' => __( 'Send notifications when an IPN is received from PayPal indicating refunds, chargebacks and cancellations.', 'woocommerce' ),
),
'receiver_email' => array(
'title' => __( 'Receiver email', 'woocommerce' ),

View File

@ -5,7 +5,7 @@
* @author Automattic
* @category Core
* @package WooCommerce/Functions
* @version 3.2.0
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -62,7 +62,7 @@ function wc_get_webhook_statuses() {
/**
* Load webhooks.
*
* @since 3.2.0
* @since 3.3.0
* @return bool
*/
function wc_load_webhooks() {
@ -78,3 +78,15 @@ function wc_load_webhooks() {
return $loaded;
}
/**
* Get webhook.
*
* @param int $id Webhook ID.
* @return WC_Webhook|null
*/
function wc_get_webhook( $id ) {
$webhook = new WC_Webhook( (int) $id );
return 0 !== $webhook->get_id() ? $webhook : null;
}

View File

@ -162,17 +162,60 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woocommerce/wo
== Changelog ==
= 3.3.0 - 2017-XX-XX =
* Feature - Template overrides via the wc_get_template filter now also appear in the System Status under the Templates section.
* Feature - New default dummy data.
* Feature - Added sandbox and live API details to the PayPal standard data, as well as an indication on the checkout to what mode is currently active.
* Feature - Improved default appearance in themes which do not support WooCommerce, making the shop page shortcode based.
* Feature - Products shortcodes; improved random sorting, with some caching.
* Feature - Products shortcodes; support for pagination.
* Feature - Added new options to the WordPress Appearance Customizer; control the product grid (rows and columns), and image sizes.
* Feature - Improved how image sizes are defined and calculated. Set an aspect ratio (custom, 1:1, uncropped) and image sizes will be automagically calculated based on widths.
* Feature - Changing image sizes will trigger automatic thumbnail regeneration in the background.
* Feature - Improved how downloads are stored within products, and added new reporting/logging features to track who downloaded what, when.
* Feature - Improved the overall appearance of the backend orders list, and added a new 'preview' button to quickly see order details.
* Feature - New default dummy data and placeholders.
* Feature - Added sandbox and live API details to the PayPal standard data, as well as an indication on the checkout to what mode is currently active. PayPal IPN email notifications are also now optional.
* Feature - Introduced product category threshold filter (`woocommerce_product_category_filter_threshold`). AJAX powered select will kick in when you have over 100 categories.
* Feature - Added `add_to_cart_description` method and aria-labels to cart buttons in the loop for accessibility.
* Feature - Ability to search in logs when the database logger is used.
* Performance - Adjusted how permalinks are retrieved and saved to avoid switching locales on each page load.
* Performance - Added cache when loading product variation attributes.
* Tweak - Moved the 'Store Notice" option into the customizer.
* Tweak - Checkout Postcode / Zip validation error message was missing Billing / Shipping Identification.
* Tweak - Added Iris color picker validation.
* Tweak - Use scrollIntoView on checkout.
* Tweak - Converted input submit elements to button submit elements across the entire codebase for consistency.
* Tweak - Added `{site_title}` replacement for email footers.
* Tweak - Added delete product confirmation if a product has had sales.
* Tweak - Improved when "incl. VAT" is displayed in cart totals.
* Tweak - Use base text color for links in email templates.
* Tweak - Show theme overrides that are done through the wc_get_template filter in the system status report.
* Tweak - Added nofollow tags in layered nav to prevent duplicate indexed content.
* Tweak - Hide "incl. VAT" when no rates are defined in "single total" display mode.
* Tweak - Added replay protection for refunds.
* Tweak - GeoDB empty file handling.
* Tweak - Let wp_signon handle email to username conversion.
* Tweak - Made email field wider on checkout.
* Tweak - Post entire shipping selection when showing multiple packages.
* Dev - REST API - Fixed default value of "dp" on orders and refunds endpoints.
* Dev - Theming - Added theme support variables to declare image sizes used for products.
* Dev - Theming - Added support for single-product-postname.php template files.
* Dev - Added actions before calculations order totals and taxes and is_vat_excempt support.
* Dev - Add filter 'woocommerce_coupon_get_apply_quantity'.
* Dev - Grouped products; added filters to allow custom columns and changes to values.
* Dev - Allow for cloning the WC_Cart object
* Dev - Apply filters to registration-error-email-exists error.
* Dev - Added `woocommerce_cross_sells_order` filter.
* Dev - Add order-details `before` hooks to complement existing hooks.
* Dev - WC_CHUNK_SIZE constant for controlling readfile.
* Dev - Add short circuit to customer bought product function.
* Dev - Added a `wc_caught_exception` method to aid with logging.
* Dev - Added Data stores and CRUD for working with Webhooks.
* Dev - Bumped minimum WP version requirement to 4.5 and removed legacy API files.
* Dev - New actions - `woocommerce_order_details_before_order_table_items`, `woocommerce_order_details_after_order_table_items` and `woocommerce_order_details_before_order_table`
* Dev - Passed `widget_id` to `content-widget-product.php` so actions can be ran conditionally, and added sanitisation to `woocommerce_before_widget_product_list` and `woocommerce_after_widget_product_list`.
* Dev - Improved the `is_internal_meta_key` checks to consider getters and setters.
* Dev - Cleaned up the Order Customer Details template.
* Performance - Added cache when loading product variation attributes.
* Dev - JavaScript payment_method_selected events on checkout.
* Localization - Add direction character to currency output.
* Localization - States for Tanzania.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce/master/CHANGELOG.txt).