Merge branch 'master' into update/use-post-author-for-customer-id

This commit is contained in:
Rodrigo Primo 2017-12-08 10:09:57 -02:00
commit fee1dcf5f9
169 changed files with 11679 additions and 8839 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

@ -21,6 +21,36 @@
.wc_addons_wrap {
h1.search-form-title {
clear: left;
padding: 0;
}
form.search-form {
clear: both;
display: block;
position: relative;
margin-top: 1em;
width: 100%;
input {
border: none;
box-shadow: 0 0 1px rgba(0, 0, 0, 0.2);
height: 53px;
padding-left: 50px;
width: 100%;
}
button {
background: none;
border: none;
cursor: pointer;
height: 53px;
position: absolute;
width: 53px;
}
}
.update-plugins .update-count {
background-color: #d54e21;
border-radius: 10px;
@ -36,7 +66,18 @@
.addons-featured {
max-width: 1140px;
margin: -1%;
}
ul.subsubsub.subsubsub {
margin: -2px 0 12px;
}
.subsubsub li::after {
content: '|';
}
.subsubsub li:last-child::after {
content: '';
}
.addons-banner-block-item-icon,
@ -50,7 +91,7 @@
.addons-wcs-banner-block {
background: #ffffff;
box-shadow: 0 0 1px rgba(0, 0, 0, 0.2);
margin: 2% 1% 0;
margin: 2% 0;
max-width: 1140px;
padding: 20px;
}
@ -186,7 +227,6 @@
}
.addons-column-block-item {
display: flex;
border-top: 2px solid #f9f9f9;
flex-direction: row;
flex-wrap: wrap;
@ -225,6 +265,18 @@
float: left;
}
.addons-banner-block-item,
.addons-column-block-item {
display: none;
}
.addons-banner-block-item:nth-child(-n+3) {
display: block;
}
.addons-column-block-item:nth-of-type(-n+3) {
display: flex;
}
.addons-small-dark-block {
background-color: #54687d;
text-align: center;
@ -426,6 +478,7 @@
.storefront {
background: url('../images/storefront-bg.jpg') bottom right #f6f6f6;
border: 1px solid #ddd;
margin-top: 1em;
padding: 20px;
overflow: hidden;
zoom: 1;
@ -1867,17 +1920,21 @@ ul.wc_coupon_list_block {
width: 11%;
}
.column-order_actions,
.column-user_actions,
.column-wc_actions {
width: 110px;
a.button {
float: left;
margin: 0 4px 2px 0;
cursor: pointer;
padding: 3px 4px;
height: auto;
@include ir();
display: inline-block;
margin: 2px 4px 2px 0;
padding: 0 !important;
height: 2em !important;
width: 2em;
&::after {
@include icon_dashicons;
line-height: 1.85;
}
img {
display: block;
@ -1885,6 +1942,32 @@ ul.wc_coupon_list_block {
height: auto;
}
}
a.edit::after {
content: '\f464';
}
a.link::after {
content: '\e00d';
}
a.view::after {
content: '\f177';
}
a.refresh::after {
font-family: 'WooCommerce';
content: '\e031';
}
a.processing::after {
font-family: 'WooCommerce';
content: '\e00f';
}
a.complete::after {
content: '\f147';
}
}
small.meta {
@ -1901,12 +1984,51 @@ ul.wc_coupon_list_block {
}
.wp-list-table {
margin-top: 1em;
thead,
tfoot {
th {
padding: .75em 1em;
}
th.sortable a, th.sorted a {
padding: 0;
}
th:first-child {
padding-left: 2em;
}
th:last-child {
padding-right: 2em;
}
}
tbody {
td,
th {
padding: 1em;
line-height: 26px;
}
td:first-child {
padding-left: 2em;
}
td:last-child {
padding-right: 2em;
}
}
tbody tr {
border-top: 1px solid #f5f5f5;
}
tbody tr:hover:not(.status-trash) td {
cursor: pointer;
}
// Columns.
td,
th {
width: 12ch;
vertical-align: middle;
p {
margin: 0;
}
}
.check-column {
width: 1px;
white-space: nowrap;
@ -1917,8 +2039,41 @@ ul.wc_coupon_list_block {
margin: 1px 0;
}
}
td.column-order_number {
line-height: 26px;
.column-order_number {
width: 35ch;
}
.column-order_total {
width: 8ch;
text-align: right;
a span {
float:right;
}
}
.column-order_date,
.column-order_status {
width: 10ch;
}
.column-order_status {
width: 14ch;
}
.column-shipping_address,
.column-billing_address {
width: 20ch;
line-height: 1.5em;
.description {
display: block;
color: #999;
}
}
.column-wc_actions {
text-align: right;
a.button {
text-indent: 9999px;
margin: 2px 0 2px 4px;
}
}
.order-preview {
float:right;
width: 16px;
@ -1944,48 +2099,10 @@ ul.wc_coupon_list_block {
.order-preview.disabled {
&::before {
content: '';
background: url(../../../../../wp-includes/images/wpspin.gif) no-repeat center top;
background: url('../images/wpspin.gif') no-repeat center top;
}
}
}
.column-order_date {
width: 10ch;
}
.column-order_number {
width: 35ch;
}
.column-order_status {
width: 20ch;
}
.column-order_total {
text-align: right;
width: 10ch;
a span {
float:right;
}
}
.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;
.post-row-actions {
display: none;
}
.order-status {
@ -1996,8 +2113,9 @@ ul.wc_coupon_list_block {
background: #E5E5E5;
border-radius: 4px;
border-bottom: 1px solid rgba(0,0,0,0.05);
margin: -.5em 0;
margin: -.25em 0;
cursor: inherit !important;
white-space: nowrap;
&.status-completed {
background: #C8D7E1;
@ -2024,40 +2142,19 @@ ul.wc_coupon_list_block {
color: #761919;
}
}
}
tr:hover:not(.status-trash) {
td, th {
cursor: pointer;
}
}
}
}
}
// 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 {
.order-status {
float: right;
margin-right: 54px;
}
article {
padding: 0 !important;
}
.wc-order-preview__table {
.modal-close {
border-radius: 0;
}
.wc-order-preview-table {
width: 100%;
margin: 0;
border-bottom: 1px solid #ccc;
@ -2115,6 +2212,58 @@ ul.wc_coupon_list_block {
}
}
}
.wc-action-button,
.wc-action-button-group {
float: left;
margin-right: 4px;
}
}
@media screen and (max-width: 782px) {
.wc-action-button-group {
label {
display: none;
}
}
}
.wc-action-button-group {
vertical-align: middle;
line-height: 26px;
text-align: left;
margin-bottom: 4px;
label {
margin-right: 6px;
cursor: default;
font-weight: bold;
}
.wc-action-button-group__items {
white-space: nowrap;
}
.wc-action-button {
margin: -1px !important;
border: 1px solid #ccc;
padding: 1px 10px !important;
border-radius: 0 !important;
float: none;
line-height: 28px;
height: auto;
z-index: 1;
position:relative;
}
.wc-action-button:hover,
.wc-action-button:focus {
border: 1px solid #999;
z-index: 2;
}
.wc-action-button:first-child {
border-top-left-radius: 3px !important;
border-bottom-left-radius: 3px !important;
}
.wc-action-button:last-child {
border-top-right-radius: 3px !important;
border-bottom-right-radius: 3px !important;
}
}
.column-customer_message .note-on {
@ -2139,66 +2288,6 @@ ul.wc_coupon_list_block {
}
}
.order_actions {
.processing,
.complete,
.view {
@include ir();
padding: 0 !important;
height: 2em !important;
width: 2em;
}
.processing::after {
@include icon( '\e00f' );
line-height: 1.85;
}
.complete::after {
@include icon_dashicons( '\f147' );
line-height: 1.85;
}
.view::after {
@include icon_dashicons( '\f177' );
line-height: 1.85;
}
}
.user_actions {
.edit,
.link,
.view,
.refresh {
@include ir();
padding: 0 !important;
height: 2em !important;
width: 2em;
&::after {
@include icon;
line-height: 1.85;
}
}
.edit::after {
font-family: 'Dashicons';
content: '\f464';
}
.link::after {
content: '\e00d';
}
.view::after {
content: '\e010';
}
.refresh::after {
content: '\e031';
}
}
.attributes-table {
td,
th {
@ -2457,18 +2546,26 @@ table.wp-list-table {
}
}
mark.instock {
mark {
&.instock,
&.outofstock,
&.onbackorder {
font-weight: 700;
color: $green;
background: transparent none;
line-height: 1;
}
mark.outofstock {
font-weight: 700;
&.instock {
color: $green;
}
&.outofstock {
color: #aa4444;
background: transparent none;
line-height: 1;
}
&.onbackorder {
color: #eaa600;
}
}
.order-notes_head,
@ -3281,7 +3378,6 @@ img.help_tip {
}
// Give regular settings inputs a standard width and padding.
select,
textarea,
input[type="text"],
input[type="email"],
@ -3293,6 +3389,12 @@ img.help_tip {
box-sizing: border-box;
}
select {
width: 400px;
margin: 0;
box-sizing: border-box;
}
input[size] {
width: auto !important;
}
@ -3423,105 +3525,6 @@ img.help_tip {
.wc_emails_wrapper {
padding: 0 15px 10px 0;
}
.woocommerce-thumbnail-cropping {
margin: 0 40px 1em 0;
padding: 0;
display:inline-block;
vertical-align: top;
input[type=radio] {
vertical-align: top;
margin-top: 2px;
}
label {
display: inline-block;
span.description {
margin-top: .5em;
display:block;
color: #999;
}
span.woocommerce-thumbnail-cropping-aspect-ratio {
margin-top: .5em;
display:block;
}
}
li {
margin: 5px 0 1.5em;
padding: 0;
}
}
.woocommerce-thumbnail-preview {
display:inline-block;
width: 320px;
vertical-align: top;
h4 {
margin-top: 0;
}
.woocommerce-thumbnail-preview-block {
text-align: center;
width: 100px;
margin: 0 10px 0 0;
float: left;
.woocommerce-thumbnail-preview-block__image {
width: 90px;
height: 90px;
border: 5px solid #fff;
background: #eee;
box-shadow: 0 1px 1px #ccc;
margin: 0 0 10px;
position: relative;
overflow: hidden;
&:before,
&:after {
content: "";
display: block;
width: 30px;
height: 30px;
background: rgba(0,0,0,.1);
position: absolute;
top: 50%;
left: 50%;
margin-left: -20px;
margin-top: -20px;
}
&:before {
margin-top: -10px;
margin-left: -10px;
background: rgba(0,0,0,.1);
}
}
.woocommerce-thumbnail-preview-block__text {
width: 50%;
background: #ddd;
margin: 0 auto 10px;
height: 6px;
}
.woocommerce-thumbnail-preview-block__button {
width: 30px;
height: 5px;
border: 8px solid #fff;
background: #ededed;
box-shadow: 0 0 0 1px #ddd;
margin: 0 auto;
border-radius: 2px;
}
&:nth-child(3) {
.woocommerce-thumbnail-preview-block__text {
width: 75%;
}
}
&:nth-child(4) {
.woocommerce-thumbnail-preview-block__text {
width: 35%;
}
}
}
.woocommerce-thumbnail-preview-block:last-child {
margin: 0;
}
}
}
}
@ -5221,29 +5224,6 @@ img.ui-datepicker-trigger {
width: 49.5%;
float: right;
}
.column-wc_actions {
a.edit,
a.view {
@include ir();
padding: 0 !important;
height: 2em !important;
width: 2em;
&::after {
@include icon_dashicons;
line-height: 1.85;
}
}
a.edit::after {
content: '\f464';
}
a.view::after {
content: '\f177';
}
}
}
.woocommerce-wide-reports-wrap {
@ -5770,7 +5750,7 @@ table.bar_chart {
box-shadow: 0 -4px 4px -4px rgba(0, 0, 0, 0.1);
.inner {
float: right;
text-align: right;
line-height: 23px;
.button {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -145,6 +145,35 @@
}
}
ul.products {
&.columns-1 {
li.product {
width: 100%;
margin-right: 0;
}
}
&.columns-2 {
li.product {
width: 48%;
}
}
&.columns-3 {
li.product {
width: 30.75%;
}
}
&.columns-5 {
li.product {
width: 16.95%;
}
}
&.columns-6 {
li.product {
width: 13.5%;
}
}
}
&.columns-1 {
ul.products {
li.product {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -682,7 +682,6 @@ p.demo_store,
color: $secondarytext;
background-color: $secondary;
border: 0;
white-space: nowrap;
display: inline-block;
background-image: none;
box-shadow: none;
@ -762,7 +761,6 @@ p.demo_store,
a.added_to_cart {
padding-top: 0.5em;
white-space: nowrap;
display: inline-block;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 25 KiB

BIN
assets/images/wpspin-2x.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
assets/images/wpspin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -232,8 +232,12 @@ jQuery( function( $ ) {
$( 'input#_manage_stock' ).change( function() {
if ( $( this ).is( ':checked' ) ) {
$( 'div.stock_fields' ).show();
$( 'p.stock_status_field' ).hide();
} else {
var product_type = $( 'select#product-type' ).val();
$( 'div.stock_fields' ).hide();
$( 'p.stock_status_field:not( .hide_if_' + product_type + ' )' ).show();
}
}).change();

File diff suppressed because one or more lines are too long

View File

@ -60,10 +60,12 @@ jQuery(function( $ ) {
}
if ( 'yes' === manage_stock ) {
$( '.stock_qty_field', '.inline-edit-row' ).show().removeAttr( 'style' );
$( '.stock_qty_field, .backorder_field', '.inline-edit-row' ).show().removeAttr( 'style' );
$( '.stock_status_field' ).hide();
$( 'input[name="_manage_stock"]', '.inline-edit-row' ).attr( 'checked', 'checked' );
} else {
$( '.stock_qty_field', '.inline-edit-row' ).hide();
$( '.stock_qty_field, .backorder_field', '.inline-edit-row' ).hide();
$( '.stock_status_field' ).show().removeAttr( 'style' );
$( 'input[name="_manage_stock"]', '.inline-edit-row' ).removeAttr( 'checked' );
}
@ -96,9 +98,11 @@ jQuery(function( $ ) {
$( '#the-list' ).on( 'change', '.inline-edit-row input[name="_manage_stock"]', function() {
if ( $( this ).is( ':checked' ) ) {
$( '.stock_qty_field', '.inline-edit-row' ).show().removeAttr( 'style' );
$( '.stock_qty_field, .backorder_field', '.inline-edit-row' ).show().removeAttr( 'style' );
$( '.stock_status_field' ).hide();
} else {
$( '.stock_qty_field', '.inline-edit-row' ).hide();
$( '.stock_qty_field, .backorder_field', '.inline-edit-row' ).hide();
$( '.stock_status_field' ).show().removeAttr( 'style' );
}
});

View File

@ -1 +1 @@
jQuery(function(e){e("#the-list").on("click",".editinline",function(){inlineEditPost.revert();var t=e(this).closest("tr").attr("id");t=t.replace("post-","");var i=e("#woocommerce_inline_"+t),n=i.find(".sku").text(),o=i.find(".regular_price").text(),l=i.find(".sale_price ").text(),d=i.find(".weight").text(),s=i.find(".length").text(),c=i.find(".width").text(),a=i.find(".height").text(),r=i.find(".shipping_class").text(),_=i.find(".visibility").text(),m=i.find(".stock_status").text(),p=i.find(".stock").text(),u=i.find(".featured").text(),w=i.find(".manage_stock").text(),h=i.find(".menu_order").text(),f=i.find(".tax_status").text(),v=i.find(".tax_class").text(),k=i.find(".backorders").text(),x=o.replace(".",woocommerce_admin.mon_decimal_point),g=l.replace(".",woocommerce_admin.mon_decimal_point);e('input[name="_sku"]',".inline-edit-row").val(n),e('input[name="_regular_price"]',".inline-edit-row").val(x),e('input[name="_sale_price"]',".inline-edit-row").val(g),e('input[name="_weight"]',".inline-edit-row").val(d),e('input[name="_length"]',".inline-edit-row").val(s),e('input[name="_width"]',".inline-edit-row").val(c),e('input[name="_height"]',".inline-edit-row").val(a),e('select[name="_shipping_class"] option:selected',".inline-edit-row").attr("selected",!1).change(),e('select[name="_shipping_class"] option[value="'+r+'"]').attr("selected","selected").change(),e('input[name="_stock"]',".inline-edit-row").val(p),e('input[name="menu_order"]',".inline-edit-row").val(h),e('select[name="_tax_status"] option, select[name="_tax_class"] option, select[name="_visibility"] option, select[name="_stock_status"] option, select[name="_backorders"] option').removeAttr("selected"),e('select[name="_tax_status"] option[value="'+f+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_tax_class"] option[value="'+v+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_visibility"] option[value="'+_+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_stock_status"] option[value="'+m+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_backorders"] option[value="'+k+'"]',".inline-edit-row").attr("selected","selected"),"yes"===u?e('input[name="_featured"]',".inline-edit-row").attr("checked","checked"):e('input[name="_featured"]',".inline-edit-row").removeAttr("checked"),"yes"===w?(e(".stock_qty_field",".inline-edit-row").show().removeAttr("style"),e('input[name="_manage_stock"]',".inline-edit-row").attr("checked","checked")):(e(".stock_qty_field",".inline-edit-row").hide(),e('input[name="_manage_stock"]',".inline-edit-row").removeAttr("checked"));var y=i.find(".product_type").text(),b=i.find(".product_is_virtual").text();"simple"===y||"external"===y?e(".price_fields",".inline-edit-row").show().removeAttr("style"):e(".price_fields",".inline-edit-row").hide(),"yes"===b?e(".dimension_fields",".inline-edit-row").hide():e(".dimension_fields",".inline-edit-row").show().removeAttr("style"),"grouped"===y?e(".stock_fields",".inline-edit-row").hide():e(".stock_fields",".inline-edit-row").show().removeAttr("style"),e('input[name="comment_status"]').parent().find(".checkbox-title").text(woocommerce_quick_edit.strings.allow_reviews)}),e("#the-list").on("change",'.inline-edit-row input[name="_manage_stock"]',function(){e(this).is(":checked")?e(".stock_qty_field",".inline-edit-row").show().removeAttr("style"):e(".stock_qty_field",".inline-edit-row").hide()}),e("#wpbody").on("click","#doaction, #doaction2",function(){e("input.text",".inline-edit-row").val(""),e("#woocommerce-fields").find("select").prop("selectedIndex",0),e("#woocommerce-fields-bulk").find(".inline-edit-group .change-input").hide()}),e("#wpbody").on("change","#woocommerce-fields-bulk .inline-edit-group .change_to",function(){0<e(this).val()?e(this).closest("div").find(".change-input").show():e(this).closest("div").find(".change-input").hide()}),e("#wpbody").on("click",".trash-product",function(){return window.confirm(woocommerce_admin.i18_delete_product_notice)})});
jQuery(function(e){e("#the-list").on("click",".editinline",function(){inlineEditPost.revert();var t=e(this).closest("tr").attr("id");t=t.replace("post-","");var i=e("#woocommerce_inline_"+t),n=i.find(".sku").text(),o=i.find(".regular_price").text(),d=i.find(".sale_price ").text(),l=i.find(".weight").text(),s=i.find(".length").text(),c=i.find(".width").text(),r=i.find(".height").text(),a=i.find(".shipping_class").text(),_=i.find(".visibility").text(),m=i.find(".stock_status").text(),p=i.find(".stock").text(),u=i.find(".featured").text(),w=i.find(".manage_stock").text(),f=i.find(".menu_order").text(),h=i.find(".tax_status").text(),k=i.find(".tax_class").text(),v=i.find(".backorders").text(),x=o.replace(".",woocommerce_admin.mon_decimal_point),g=d.replace(".",woocommerce_admin.mon_decimal_point);e('input[name="_sku"]',".inline-edit-row").val(n),e('input[name="_regular_price"]',".inline-edit-row").val(x),e('input[name="_sale_price"]',".inline-edit-row").val(g),e('input[name="_weight"]',".inline-edit-row").val(l),e('input[name="_length"]',".inline-edit-row").val(s),e('input[name="_width"]',".inline-edit-row").val(c),e('input[name="_height"]',".inline-edit-row").val(r),e('select[name="_shipping_class"] option:selected',".inline-edit-row").attr("selected",!1).change(),e('select[name="_shipping_class"] option[value="'+a+'"]').attr("selected","selected").change(),e('input[name="_stock"]',".inline-edit-row").val(p),e('input[name="menu_order"]',".inline-edit-row").val(f),e('select[name="_tax_status"] option, select[name="_tax_class"] option, select[name="_visibility"] option, select[name="_stock_status"] option, select[name="_backorders"] option').removeAttr("selected"),e('select[name="_tax_status"] option[value="'+h+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_tax_class"] option[value="'+k+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_visibility"] option[value="'+_+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_stock_status"] option[value="'+m+'"]',".inline-edit-row").attr("selected","selected"),e('select[name="_backorders"] option[value="'+v+'"]',".inline-edit-row").attr("selected","selected"),"yes"===u?e('input[name="_featured"]',".inline-edit-row").attr("checked","checked"):e('input[name="_featured"]',".inline-edit-row").removeAttr("checked"),"yes"===w?(e(".stock_qty_field, .backorder_field",".inline-edit-row").show().removeAttr("style"),e(".stock_status_field").hide(),e('input[name="_manage_stock"]',".inline-edit-row").attr("checked","checked")):(e(".stock_qty_field, .backorder_field",".inline-edit-row").hide(),e(".stock_status_field").show().removeAttr("style"),e('input[name="_manage_stock"]',".inline-edit-row").removeAttr("checked"));var y=i.find(".product_type").text(),b=i.find(".product_is_virtual").text();"simple"===y||"external"===y?e(".price_fields",".inline-edit-row").show().removeAttr("style"):e(".price_fields",".inline-edit-row").hide(),"yes"===b?e(".dimension_fields",".inline-edit-row").hide():e(".dimension_fields",".inline-edit-row").show().removeAttr("style"),"grouped"===y?e(".stock_fields",".inline-edit-row").hide():e(".stock_fields",".inline-edit-row").show().removeAttr("style"),e('input[name="comment_status"]').parent().find(".checkbox-title").text(woocommerce_quick_edit.strings.allow_reviews)}),e("#the-list").on("change",'.inline-edit-row input[name="_manage_stock"]',function(){e(this).is(":checked")?(e(".stock_qty_field, .backorder_field",".inline-edit-row").show().removeAttr("style"),e(".stock_status_field").hide()):(e(".stock_qty_field, .backorder_field",".inline-edit-row").hide(),e(".stock_status_field").show().removeAttr("style"))}),e("#wpbody").on("click","#doaction, #doaction2",function(){e("input.text",".inline-edit-row").val(""),e("#woocommerce-fields").find("select").prop("selectedIndex",0),e("#woocommerce-fields-bulk").find(".inline-edit-group .change-input").hide()}),e("#wpbody").on("change","#woocommerce-fields-bulk .inline-edit-group .change_to",function(){0<e(this).val()?e(this).closest("div").find(".change-input").show():e(this).closest("div").find(".change-input").hide()}),e("#wpbody").on("click",".trash-product",function(){return window.confirm(woocommerce_admin.i18_delete_product_notice)})});

View File

@ -138,7 +138,7 @@ jQuery(function( $ ) {
var groupby = $( this ) .data( 'groupby' );
var index_type = $( this ).data( 'index_type' );
var export_format = $( this ).data( 'export' );
var csv_data = 'data:application/csv;charset=utf-8,';
var csv_data = 'data:text/csv;charset=utf-8,\uFEFF';
var s, series_data, d;
if ( 'table' === export_format ) {

View File

@ -1 +1 @@
jQuery(function(t){function e(e,a,n){t('<div class="chart-tooltip">'+n+"</div>").css({top:a-16,left:e+20}).appendTo("body").fadeIn(200)}var a=null,n=null;t(".chart-placeholder").bind("plothover",function(i,r,o){if(o){if((a!==o.dataIndex||n!==o.seriesIndex)&&(a=o.dataIndex,n=o.seriesIndex,t(".chart-tooltip").remove(),o.series.points.show||o.series.enable_tooltip)){var s=o.series.data[o.dataIndex][1],l="";o.series.prepend_label&&(l=l+o.series.label+": "),o.series.prepend_tooltip&&(l+=o.series.prepend_tooltip),l+=s,o.series.append_tooltip&&(l+=o.series.append_tooltip),o.series.pie.show?e(r.pageX,r.pageY,l):e(o.pageX,o.pageY,l)}}else t(".chart-tooltip").remove(),a=null}),t(".wc_sparkline.bars").each(function(){var e={grid:{show:!1}},a=[{data:t(this).data("sparkline"),color:t(this).data("color"),bars:{fillColor:t(this).data("color"),fill:!0,show:!0,lineWidth:1,barWidth:t(this).data("barwidth"),align:"center"},shadowSize:0}];t.plot(t(this),a,e)}),t(".wc_sparkline.lines").each(function(){var e={grid:{show:!1}},a=[{data:t(this).data("sparkline"),color:t(this).data("color"),lines:{fill:!1,show:!0,lineWidth:1,align:"center"},shadowSize:0}];t.plot(t(this),a,e)});var i=t(".range_datepicker").datepicker({changeMonth:!0,changeYear:!0,defaultDate:"",dateFormat:"yy-mm-dd",numberOfMonths:1,minDate:"-20Y",maxDate:"+1D",showButtonPanel:!0,showOn:"focus",buttonImageOnly:!0,onSelect:function(){var e=t(this).is(".from")?"minDate":"maxDate",a=t(this).datepicker("getDate");i.not(this).datepicker("option",e,a)}});"undefined"==typeof document.createElement("a").download&&t(".export_csv").hide(),t(".export_csv").click(function(){var e=t(this).data("exclude_series")||"";e=e.toString(),e=e.split(",");var a,n,i,r=t(this).data("xaxes"),o=t(this).data("groupby"),s=t(this).data("index_type"),l="data:application/csv;charset=utf-8,";if("table"===t(this).data("export"))t(this).offsetParent().find("thead tr,tbody tr").each(function(){t(this).find("th, td").each(function(){var e=t(this).text();e=e.replace("[?]","").replace("#",""),l+='"'+e+'",'}),l=l.substring(0,l.length-1),l+="\n"}),t(this).offsetParent().find("tfoot tr").each(function(){t(this).find("th, td").each(function(){var e=t(this).text();if(e=e.replace("[?]","").replace("#",""),l+='"'+e+'",',t(this).attr("colspan")>0)for(p=1;p<t(this).attr("colspan");p++)l+='"",'}),l=l.substring(0,l.length-1),l+="\n"});else{if(!window.main_chart)return!1;var h=window.main_chart.getData(),d=[];for(l+='"'+r+'",',t.each(h,function(a,n){e&&-1!==t.inArray(a.toString(),e)||d.push(n)}),a=0;a<d.length;++a)l+='"'+d[a].label+'",';l=l.substring(0,l.length-1),l+="\n";var c={};for(a=0;a<d.length;++a)for(n=d[a].data,i=0;i<n.length;++i){c[n[i][0]]=[];for(var p=0;p<d.length;++p)c[n[i][0]].push(0)}for(a=0;a<d.length;++a)for(n=d[a].data,i=0;i<n.length;++i)c[n[i][0]][a]=n[i][1];t.each(c,function(t,e){var a=new Date(parseInt(t,10));l+="none"===s?'"'+t+'",':"day"===o?'"'+a.getUTCFullYear()+"-"+parseInt(a.getUTCMonth()+1,10)+"-"+a.getUTCDate()+'",':'"'+a.getUTCFullYear()+"-"+parseInt(a.getUTCMonth()+1,10)+'",';for(var n=0;n<e.length;++n){var i=e[n];Math.round(i)!==i&&(i=(i=parseFloat(i)).toFixed(2)),l+='"'+i+'",'}l=l.substring(0,l.length-1),l+="\n"})}return t(this).attr("href",encodeURI(l)),!0})});
jQuery(function(t){function e(e,a,n){t('<div class="chart-tooltip">'+n+"</div>").css({top:a-16,left:e+20}).appendTo("body").fadeIn(200)}var a=null,n=null;t(".chart-placeholder").bind("plothover",function(i,r,o){if(o){if((a!==o.dataIndex||n!==o.seriesIndex)&&(a=o.dataIndex,n=o.seriesIndex,t(".chart-tooltip").remove(),o.series.points.show||o.series.enable_tooltip)){var s=o.series.data[o.dataIndex][1],l="";o.series.prepend_label&&(l=l+o.series.label+": "),o.series.prepend_tooltip&&(l+=o.series.prepend_tooltip),l+=s,o.series.append_tooltip&&(l+=o.series.append_tooltip),o.series.pie.show?e(r.pageX,r.pageY,l):e(o.pageX,o.pageY,l)}}else t(".chart-tooltip").remove(),a=null}),t(".wc_sparkline.bars").each(function(){var e={grid:{show:!1}},a=[{data:t(this).data("sparkline"),color:t(this).data("color"),bars:{fillColor:t(this).data("color"),fill:!0,show:!0,lineWidth:1,barWidth:t(this).data("barwidth"),align:"center"},shadowSize:0}];t.plot(t(this),a,e)}),t(".wc_sparkline.lines").each(function(){var e={grid:{show:!1}},a=[{data:t(this).data("sparkline"),color:t(this).data("color"),lines:{fill:!1,show:!0,lineWidth:1,align:"center"},shadowSize:0}];t.plot(t(this),a,e)});var i=t(".range_datepicker").datepicker({changeMonth:!0,changeYear:!0,defaultDate:"",dateFormat:"yy-mm-dd",numberOfMonths:1,minDate:"-20Y",maxDate:"+1D",showButtonPanel:!0,showOn:"focus",buttonImageOnly:!0,onSelect:function(){var e=t(this).is(".from")?"minDate":"maxDate",a=t(this).datepicker("getDate");i.not(this).datepicker("option",e,a)}});"undefined"==typeof document.createElement("a").download&&t(".export_csv").hide(),t(".export_csv").click(function(){var e=t(this).data("exclude_series")||"";e=e.toString(),e=e.split(",");var a,n,i,r=t(this).data("xaxes"),o=t(this).data("groupby"),s=t(this).data("index_type"),l="data:text/csv;charset=utf-8,\ufeff";if("table"===t(this).data("export"))t(this).offsetParent().find("thead tr,tbody tr").each(function(){t(this).find("th, td").each(function(){var e=t(this).text();e=e.replace("[?]","").replace("#",""),l+='"'+e+'",'}),l=l.substring(0,l.length-1),l+="\n"}),t(this).offsetParent().find("tfoot tr").each(function(){t(this).find("th, td").each(function(){var e=t(this).text();if(e=e.replace("[?]","").replace("#",""),l+='"'+e+'",',t(this).attr("colspan")>0)for(p=1;p<t(this).attr("colspan");p++)l+='"",'}),l=l.substring(0,l.length-1),l+="\n"});else{if(!window.main_chart)return!1;var h=window.main_chart.getData(),d=[];for(l+='"'+r+'",',t.each(h,function(a,n){e&&-1!==t.inArray(a.toString(),e)||d.push(n)}),a=0;a<d.length;++a)l+='"'+d[a].label+'",';l=l.substring(0,l.length-1),l+="\n";var c={};for(a=0;a<d.length;++a)for(n=d[a].data,i=0;i<n.length;++i){c[n[i][0]]=[];for(var p=0;p<d.length;++p)c[n[i][0]].push(0)}for(a=0;a<d.length;++a)for(n=d[a].data,i=0;i<n.length;++i)c[n[i][0]][a]=n[i][1];t.each(c,function(t,e){var a=new Date(parseInt(t,10));l+="none"===s?'"'+t+'",':"day"===o?'"'+a.getUTCFullYear()+"-"+parseInt(a.getUTCMonth()+1,10)+"-"+a.getUTCDate()+'",':'"'+a.getUTCFullYear()+"-"+parseInt(a.getUTCMonth()+1,10)+'",';for(var n=0;n<e.length;++n){var i=e[n];Math.round(i)!==i&&(i=(i=parseFloat(i)).toFixed(2)),l+='"'+i+'",'}l=l.substring(0,l.length-1),l+="\n"})}return t(this).attr("href",encodeURI(l)),!0})});

View File

@ -124,43 +124,4 @@
$( this ).closest( 'td' ).find( 'select' ).trigger( 'change' );
return false;
});
// Thumbnail cropping option updates and preview.
$( '.woocommerce-thumbnail-cropping' )
.on( 'change input', 'input', function() {
var value = $( '.woocommerce-thumbnail-cropping input:checked' ).val(),
$preview_images = $( '.woocommerce-thumbnail-preview-block__image' );
if ( 'custom' === value ) {
var width_ratio = Math.max( parseInt( $( 'input[name="thumbnail_cropping_aspect_ratio_width"]' ).val(), 10 ), 1 ),
height_ratio = Math.max( parseInt( $( 'input[name="thumbnail_cropping_aspect_ratio_height"]' ).val(), 10 ), 1 ),
height = ( 90 / width_ratio ) * height_ratio;
$preview_images.animate( { height: height + 'px' }, 200 );
$( '.woocommerce-thumbnail-cropping-aspect-ratio' ).slideDown( 200 );
} else if ( 'uncropped' === value ) {
var heights = [ '120', '60', '80' ];
$preview_images.each( function( index, element ) {
var height = heights[ index ];
$( element ).animate( { height: height + 'px' }, 200 );
} );
$( '.woocommerce-thumbnail-cropping-aspect-ratio' ).hide();
} else {
$preview_images.animate( { height: '90px' }, 200 );
$( '.woocommerce-thumbnail-cropping-aspect-ratio' ).hide();
}
return false;
});
$( '.woocommerce-thumbnail-cropping' ).find( 'input' ).change();
})( jQuery );

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","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})}(jQuery);

View File

@ -26,8 +26,14 @@ jQuery( function( $ ) {
href = $row.find( 'a.order-view' ).attr( 'href' );
if ( href.length ) {
e.preventDefault();
if ( e.metaKey ) {
window.open( href, '_blank' );
} else {
window.location = href;
}
}
};
/**

View File

@ -1 +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});
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&&(r.preventDefault(),r.metaKey?window.open(a,"_blank"):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

@ -1 +1 @@
!function(e,i,s,n){e(function(){var t=e(".wc-shipping-class-rows"),a=e(".wc-shipping-class-save"),o=s.template("wc-shipping-class-row"),d=s.template("wc-shipping-class-row-blank"),c=Backbone.Model.extend({changes:{},logChanges:function(e){var i=this.changes||{};_.each(e,function(e,s){i[s]=_.extend(i[s]||{term_id:s},e)}),this.changes=i,this.trigger("change:classes")},save:function(){_.size(this.changes)?e.post(n+(n.indexOf("?")>0?"&":"?")+"action=woocommerce_shipping_classes_save_changes",{wc_shipping_classes_nonce:i.wc_shipping_classes_nonce,changes:this.changes},this.onSaveResponse,"json"):r.trigger("saved:classes")},discardChanges:function(e){delete(this.changes||{})[e],0===_.size(this.changes)&&h.clearUnloadConfirmation()},onSaveResponse:function(e,s){"success"===s&&(e.success?(r.set("classes",e.data.shipping_classes),r.trigger("change:classes"),r.changes={},r.trigger("saved:classes")):e.data?window.alert(e.data):window.alert(i.strings.save_failed)),h.unblock()}}),l=Backbone.View.extend({rowTemplate:o,initialize:function(){this.listenTo(this.model,"change:classes",this.setUnloadConfirmation),this.listenTo(this.model,"saved:classes",this.clearUnloadConfirmation),this.listenTo(this.model,"saved:classes",this.render),t.on("change",{view:this},this.updateModelOnChange),e(window).on("beforeunload",{view:this},this.unloadConfirmation),a.on("click",{view:this},this.onSubmit),e(document.body).on("click",".wc-shipping-class-add",{view:this},this.onAddNewRow),e(document.body).on("click",".wc-shipping-class-save-changes",{view:this},this.onSubmit)},block:function(){e(this.el).block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){e(this.el).unblock()},render:function(){var i=_.indexBy(this.model.get("classes"),"term_id"),s=this;this.$el.empty(),this.unblock(),_.size(i)?(i=_.sortBy(i,function(e){return e.name}),e.each(i,function(e,i){s.renderRow(i)})):s.$el.append(d)},renderRow:function(e){var i=this;i.$el.append(i.rowTemplate(e)),i.initRow(e)},initRow:function(i){var s=this.$el.find('tr[data-id="'+i.term_id+'"]');s.find("select").each(function(){var s=e(this).data("attribute");e(this).find('option[value="'+i[s]+'"]').prop("selected",!0)}),s.find(".view").show(),s.find(".edit").hide(),s.find(".wc-shipping-class-edit").on("click",{view:this},this.onEditRow),s.find(".wc-shipping-class-delete").on("click",{view:this},this.onDeleteRow),s.find(".editing .wc-shipping-class-edit").trigger("click"),s.find(".wc-shipping-class-cancel-edit").on("click",{view:this},this.onCancelEditRow),!0===i.editing&&(s.addClass("editing"),s.find(".wc-shipping-class-edit").trigger("click"))},onSubmit:function(e){e.data.view.block(),e.data.view.model.save(),e.preventDefault()},onAddNewRow:function(s){s.preventDefault();var n=s.data.view,t=n.model,a=_.indexBy(t.get("classes"),"term_id"),o={},d=_.size(a),c=_.extend({},i.default_class,{term_id:"new-"+d+"-"+Date.now(),editing:!0,newRow:!0});o[c.term_id]=c,t.logChanges(o),n.renderRow(c),e(".wc-shipping-classes-blank-state").remove()},onEditRow:function(i){i.preventDefault(),e(this).closest("tr").addClass("editing"),e(this).closest("tr").find(".view").hide(),e(this).closest("tr").find(".edit").show(),i.data.view.model.trigger("change:classes")},onDeleteRow:function(i){var s=i.data.view,n=s.model,t=_.indexBy(n.get("classes"),"term_id"),a={},o=e(this).closest("tr").data("id");i.preventDefault(),t[o]&&(delete t[o],a[o]=_.extend(a[o]||{},{deleted:"deleted"}),n.set("classes",t),n.logChanges(a)),s.render()},onCancelEditRow:function(i){var s=i.data.view,n=s.model,t=e(this).closest("tr"),a=e(this).closest("tr").data("id"),o=_.indexBy(n.get("classes"),"term_id");i.preventDefault(),n.discardChanges(a),o[a]&&(o[a].editing=!1,t.after(s.rowTemplate(o[a])),s.initRow(o[a])),t.remove()},setUnloadConfirmation:function(){this.needsUnloadConfirm=!0,a.removeAttr("disabled")},clearUnloadConfirmation:function(){this.needsUnloadConfirm=!1,a.attr("disabled","disabled")},unloadConfirmation:function(e){if(e.data.view.needsUnloadConfirm)return e.returnValue=i.strings.unload_confirmation_msg,window.event.returnValue=i.strings.unload_confirmation_msg,i.strings.unload_confirmation_msg},updateModelOnChange:function(i){var s=i.data.view.model,n=e(i.target),t=n.closest("tr").data("id"),a=n.data("attribute"),o=n.val(),d=_.indexBy(s.get("classes"),"term_id"),c={};d[t]&&d[t][a]===o||(c[t]={},c[t][a]=o),s.logChanges(c)}}),r=new c({classes:i.classes}),h=new l({model:r,el:t});h.render()})}(jQuery,shippingClassesLocalizeScript,wp,ajaxurl);
!function(e,i,s,n){e(function(){var t=e(".wc-shipping-class-rows"),a=e(".wc-shipping-class-save"),o=s.template("wc-shipping-class-row"),d=s.template("wc-shipping-class-row-blank"),c=Backbone.Model.extend({changes:{},logChanges:function(e){var i=this.changes||{};_.each(e,function(e,s){i[s]=_.extend(i[s]||{term_id:s},e)}),this.changes=i,this.trigger("change:classes")},save:function(){_.size(this.changes)?e.post(n+(n.indexOf("?")>0?"&":"?")+"action=woocommerce_shipping_classes_save_changes",{wc_shipping_classes_nonce:i.wc_shipping_classes_nonce,changes:this.changes},this.onSaveResponse,"json"):r.trigger("saved:classes")},discardChanges:function(e){delete(this.changes||{})[e],0===_.size(this.changes)&&h.clearUnloadConfirmation()},onSaveResponse:function(e,s){"success"===s&&(e.success?(r.set("classes",e.data.shipping_classes),r.trigger("change:classes"),r.changes={},r.trigger("saved:classes")):e.data?window.alert(e.data):window.alert(i.strings.save_failed)),h.unblock()}}),l=Backbone.View.extend({rowTemplate:o,initialize:function(){this.listenTo(this.model,"change:classes",this.setUnloadConfirmation),this.listenTo(this.model,"saved:classes",this.clearUnloadConfirmation),this.listenTo(this.model,"saved:classes",this.render),t.on("change",{view:this},this.updateModelOnChange),e(window).on("beforeunload",{view:this},this.unloadConfirmation),a.on("click",{view:this},this.onSubmit),e(document.body).on("click",".wc-shipping-class-add",{view:this},this.onAddNewRow),e(document.body).on("click",".wc-shipping-class-save-changes",{view:this},this.onSubmit)},block:function(){e(this.el).block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){e(this.el).unblock()},render:function(){var i=_.indexBy(this.model.get("classes"),"term_id"),s=this;this.$el.empty(),this.unblock(),_.size(i)?(i=_.sortBy(i,function(e){return e.name}),e.each(i,function(e,i){s.renderRow(i)})):s.$el.append(d)},renderRow:function(e){var i=this;i.$el.append(i.rowTemplate(e)),i.initRow(e)},initRow:function(i){var s=this.$el.find('tr[data-id="'+i.term_id+'"]');s.find("select").each(function(){var s=e(this).data("attribute");e(this).find('option[value="'+i[s]+'"]').prop("selected",!0)}),s.find(".view").show(),s.find(".edit").hide(),s.find(".wc-shipping-class-edit").on("click",{view:this},this.onEditRow),s.find(".wc-shipping-class-delete").on("click",{view:this},this.onDeleteRow),s.find(".editing .wc-shipping-class-edit").trigger("click"),s.find(".wc-shipping-class-cancel-edit").on("click",{view:this},this.onCancelEditRow),!0===i.editing&&(s.addClass("editing"),s.find(".wc-shipping-class-edit").trigger("click"))},onSubmit:function(e){e.data.view.block(),e.data.view.model.save(),e.preventDefault()},onAddNewRow:function(s){s.preventDefault();var n=s.data.view,t=n.model,a=_.indexBy(t.get("classes"),"term_id"),o={},d=_.size(a),c=_.extend({},i.default_shipping_class,{term_id:"new-"+d+"-"+Date.now(),editing:!0,newRow:!0});o[c.term_id]=c,t.logChanges(o),n.renderRow(c),e(".wc-shipping-classes-blank-state").remove()},onEditRow:function(i){i.preventDefault(),e(this).closest("tr").addClass("editing"),e(this).closest("tr").find(".view").hide(),e(this).closest("tr").find(".edit").show(),i.data.view.model.trigger("change:classes")},onDeleteRow:function(i){var s=i.data.view,n=s.model,t=_.indexBy(n.get("classes"),"term_id"),a={},o=e(this).closest("tr").data("id");i.preventDefault(),t[o]&&(delete t[o],a[o]=_.extend(a[o]||{},{deleted:"deleted"}),n.set("classes",t),n.logChanges(a)),s.render()},onCancelEditRow:function(i){var s=i.data.view,n=s.model,t=e(this).closest("tr"),a=e(this).closest("tr").data("id"),o=_.indexBy(n.get("classes"),"term_id");i.preventDefault(),n.discardChanges(a),o[a]&&(o[a].editing=!1,t.after(s.rowTemplate(o[a])),s.initRow(o[a])),t.remove()},setUnloadConfirmation:function(){this.needsUnloadConfirm=!0,a.removeAttr("disabled")},clearUnloadConfirmation:function(){this.needsUnloadConfirm=!1,a.attr("disabled","disabled")},unloadConfirmation:function(e){if(e.data.view.needsUnloadConfirm)return e.returnValue=i.strings.unload_confirmation_msg,window.event.returnValue=i.strings.unload_confirmation_msg,i.strings.unload_confirmation_msg},updateModelOnChange:function(i){var s=i.data.view.model,n=e(i.target),t=n.closest("tr").data("id"),a=n.data("attribute"),o=n.val(),d=_.indexBy(s.get("classes"),"term_id"),c={};d[t]&&d[t][a]===o||(c[t]={},c[t][a]=o),s.logChanges(c)}}),r=new c({classes:i.classes}),h=new l({model:r,el:t});h.render()})}(jQuery,shippingClassesLocalizeScript,wp,ajaxurl);

View File

@ -134,18 +134,27 @@ jQuery( function ( $ ) {
})
.on( 'init_tooltips', function() {
var tiptip_args = {
$( '.tips, .help_tip, .woocommerce-help-tip' ).tipTip( {
'attribute': 'data-tip',
'fadeIn': 50,
'fadeOut': 50,
'delay': 200
};
} );
$( '.tips, .help_tip, .woocommerce-help-tip' ).tipTip( tiptip_args );
$( '.column-wc_actions .wc-action-button' ).tipTip( {
'fadeIn': 50,
'fadeOut': 50,
'delay': 200
} );
// Add tiptip to parent element for widefat tables
$( '.parent-tips' ).each( function() {
$( this ).closest( 'a, th' ).attr( 'data-tip', $( this ).data( 'tip' ) ).tipTip( tiptip_args ).css( 'cursor', 'help' );
$( this ).closest( 'a, th' ).attr( 'data-tip', $( this ).data( 'tip' ) ).tipTip( {
'attribute': 'data-tip',
'fadeIn': 50,
'fadeOut': 50,
'delay': 200
} ).css( 'cursor', 'help' );
});
});

File diff suppressed because one or more lines are too long

View File

@ -181,8 +181,6 @@ jQuery( function( $ ) {
/**
* Handles when a shipping method is selected.
*
* @param {Object} evt The JQuery event.
*/
shipping_method_selected: function() {
var shipping_methods = {};

File diff suppressed because one or more lines are too long

View File

@ -1475,8 +1475,14 @@ S2.define('select2/selection/base',[
}
var $element = $this.data('element');
$element.select2('close');
// Remove any focus when dropdown is closed by clicking outside the select area.
// Timeout of 1 required for close to finish wrapping up.
setTimeout(function(){
$this.find('*:focus').blur();
$target.focus();
}, 1);
});
});
};
@ -1675,6 +1681,11 @@ S2.define('select2/selection/multiple',[
container.open();
}
});
// Focus on the search field when the container is focused instead of the main container.
container.on( 'focus', function(){
self.focusOnSearch();
});
};
MultipleSelection.prototype.clear = function () {
@ -1700,8 +1711,25 @@ S2.define('select2/selection/multiple',[
return $container;
};
MultipleSelection.prototype.update = function (data) {
/**
* Focus on the search field instead of the main multiselect container.
*/
MultipleSelection.prototype.focusOnSearch = function() {
var self = this;
if ('undefined' !== typeof self.$search) {
// Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
setTimeout(function(){
// Prevent the dropdown opening again when focused from this.
// This gets reset automatically when focus is triggered.
self._keyUpPrevented = true;
self.$search.focus();
}, 1);
}
}
MultipleSelection.prototype.update = function (data) {
this.clear();
if (data.length === 0) {
@ -1727,14 +1755,6 @@ S2.define('select2/selection/multiple',[
var $rendered = this.$selection.find('.select2-selection__rendered');
Utils.appendMany($rendered, $selections);
// Return cursor to search field after updating.
// Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
if ('undefined' !== typeof this.$search) {
setTimeout(function(){
self.$search.focus();
}, 1);
}
};
return MultipleSelection;
@ -1980,6 +2000,9 @@ S2.define('select2/selection/search',[
evt.preventDefault();
}
} else if (evt.which === KEYS.ENTER) {
container.open();
evt.preventDefault();
}
});
@ -5480,18 +5503,9 @@ S2.define('select2/core',[
self.focusOnActiveElement();
}, 1000);
}
// If focus is in the search field, select the current active element on Enter key.
$searchField.on('keydown', function (evt) {
if (evt.which === KEYS.ENTER) {
self.trigger('results:select', {});
evt.preventDefault();
}
});
} else if (self.hasFocus()) {
if (key === KEYS.ENTER || key === KEYS.SPACE ||
(key === KEYS.DOWN && evt.altKey)) {
key === KEYS.DOWN) {
self.open();
evt.preventDefault();
}
@ -5501,7 +5515,7 @@ S2.define('select2/core',[
Select2.prototype.focusOnActiveElement = function () {
// Don't mess with the focus on touchscreens because it causes havoc with on-screen keyboards.
if (! Utils.isTouchscreen()) {
if (this.isOpen() && ! Utils.isTouchscreen()) {
this.$results.find('li.select2-results__option--highlighted').focus();
}
};

File diff suppressed because one or more lines are too long

View File

@ -1475,8 +1475,14 @@ S2.define('select2/selection/base',[
}
var $element = $this.data('element');
$element.select2('close');
// Remove any focus when dropdown is closed by clicking outside the select area.
// Timeout of 1 required for close to finish wrapping up.
setTimeout(function(){
$this.find('*:focus').blur();
$target.focus();
}, 1);
});
});
};
@ -1675,6 +1681,11 @@ S2.define('select2/selection/multiple',[
container.open();
}
});
// Focus on the search field when the container is focused instead of the main container.
container.on( 'focus', function(){
self.focusOnSearch();
});
};
MultipleSelection.prototype.clear = function () {
@ -1700,8 +1711,25 @@ S2.define('select2/selection/multiple',[
return $container;
};
MultipleSelection.prototype.update = function (data) {
/**
* Focus on the search field instead of the main multiselect container.
*/
MultipleSelection.prototype.focusOnSearch = function() {
var self = this;
if ('undefined' !== typeof self.$search) {
// Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
setTimeout(function(){
// Prevent the dropdown opening again when focused from this.
// This gets reset automatically when focus is triggered.
self._keyUpPrevented = true;
self.$search.focus();
}, 1);
}
}
MultipleSelection.prototype.update = function (data) {
this.clear();
if (data.length === 0) {
@ -1727,14 +1755,6 @@ S2.define('select2/selection/multiple',[
var $rendered = this.$selection.find('.select2-selection__rendered');
Utils.appendMany($rendered, $selections);
// Return cursor to search field after updating.
// Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
if ('undefined' !== typeof this.$search) {
setTimeout(function(){
self.$search.focus();
}, 1);
}
};
return MultipleSelection;
@ -1980,6 +2000,9 @@ S2.define('select2/selection/search',[
evt.preventDefault();
}
} else if (evt.which === KEYS.ENTER) {
container.open();
evt.preventDefault();
}
});
@ -5480,18 +5503,9 @@ S2.define('select2/core',[
self.focusOnActiveElement();
}, 1000);
}
// If focus is in the search field, select the current active element on Enter key.
$searchField.on('keydown', function (evt) {
if (evt.which === KEYS.ENTER) {
self.trigger('results:select', {});
evt.preventDefault();
}
});
} else if (self.hasFocus()) {
if (key === KEYS.ENTER || key === KEYS.SPACE ||
(key === KEYS.DOWN && evt.altKey)) {
key === KEYS.DOWN) {
self.open();
evt.preventDefault();
}
@ -5501,7 +5515,7 @@ S2.define('select2/core',[
Select2.prototype.focusOnActiveElement = function () {
// Don't mess with the focus on touchscreens because it causes havoc with on-screen keyboards.
if (! Utils.isTouchscreen()) {
if (this.isOpen() && ! Utils.isTouchscreen()) {
this.$results.find('li.select2-results__option--highlighted').focus();
}
};

File diff suppressed because one or more lines are too long

View File

@ -27,6 +27,22 @@
],
"post-update-cmd": [
"WooCommerce\\GitHooks\\Hooks::postHooks"
],
"test": [
"phpunit"
],
"phpcs": [
"phpcs -s -p --standard=./phpcs.ruleset.xml"
],
"phpcbf": [
"phpcbf -p --standard=./phpcs.ruleset.xml"
]
},
"extra": {
"scripts-description": {
"test": "Run unit tests",
"phpcs": "Analyze code against the WordPress coding standards with PHP_CodeSniffer",
"phpcbf": "Fix coding standards warnings/errors automatically with PHP Code Beautifier"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -14,30 +14,30 @@ if ( ! defined( 'ABSPATH' ) ) {
}
$states['IE'] = array(
'CW' => __( 'Carlow', 'woocommerce' ),
'CN' => __( 'Cavan', 'woocommerce' ),
'CE' => __( 'Clare', 'woocommerce' ),
'CK' => __( 'Cork', 'woocommerce' ),
'CN' => __( 'Cavan', 'woocommerce' ),
'CW' => __( 'Carlow', 'woocommerce' ),
'DL' => __( 'Donegal', 'woocommerce' ),
'DN' => __( 'Dublin', 'woocommerce' ),
'GY' => __( 'Galway', 'woocommerce' ),
'KY' => __( 'Kerry', 'woocommerce' ),
'KE' => __( 'Kildare', 'woocommerce' ),
'KK' => __( 'Kilkenny', 'woocommerce' ),
'KY' => __( 'Kerry', 'woocommerce' ),
'LS' => __( 'Laois', 'woocommerce' ),
'LM' => __( 'Leitrim', 'woocommerce' ),
'LK' => __( 'Limerick', 'woocommerce' ),
'LD' => __( 'Longford', 'woocommerce' ),
'LH' => __( 'Louth', 'woocommerce' ),
'LK' => __( 'Limerick', 'woocommerce' ),
'LM' => __( 'Leitrim', 'woocommerce' ),
'LS' => __( 'Laois', 'woocommerce' ),
'MO' => __( 'Mayo', 'woocommerce' ),
'MH' => __( 'Meath', 'woocommerce' ),
'MN' => __( 'Monaghan', 'woocommerce' ),
'MO' => __( 'Mayo', 'woocommerce' ),
'OY' => __( 'Offaly', 'woocommerce' ),
'RN' => __( 'Roscommon', 'woocommerce' ),
'SO' => __( 'Sligo', 'woocommerce' ),
'TY' => __( 'Tipperary', 'woocommerce' ),
'WD' => __( 'Waterford', 'woocommerce' ),
'WH' => __( 'Westmeath', 'woocommerce' ),
'WW' => __( 'Wicklow', 'woocommerce' ),
'WX' => __( 'Wexford', 'woocommerce' ),
'WW' => __( 'Wicklow', 'woocommerce' )
);

View File

@ -15,50 +15,50 @@ if ( ! defined( 'ABSPATH' ) ) {
$states['JP'] = array(
'JP01' => __( 'Hokkaido', 'woocommerce' ),
'JP02' => __( 'Aomori', 'woocommerce' ),
'JP03' => __( 'Iwate', 'woocommerce' ),
'JP04' => __( 'Miyagi', 'woocommerce' ),
'JP05' => __( 'Akita', 'woocommerce' ),
'JP06' => __( 'Yamagata', 'woocommerce' ),
'JP07' => __( 'Fukushima', 'woocommerce' ),
'JP08' => __( 'Ibaraki', 'woocommerce' ),
'JP09' => __( 'Tochigi', 'woocommerce' ),
'JP10' => __( 'Gunma', 'woocommerce' ),
'JP11' => __( 'Saitama', 'woocommerce' ),
'JP12' => __( 'Chiba', 'woocommerce' ),
'JP13' => __( 'Tokyo', 'woocommerce' ),
'JP14' => __( 'Kanagawa', 'woocommerce' ),
'JP15' => __( 'Niigata', 'woocommerce' ),
'JP16' => __( 'Toyama', 'woocommerce' ),
'JP17' => __( 'Ishikawa', 'woocommerce' ),
'JP18' => __( 'Fukui', 'woocommerce' ),
'JP19' => __( 'Yamanashi', 'woocommerce' ),
'JP20' => __( 'Nagano', 'woocommerce' ),
'JP21' => __( 'Gifu', 'woocommerce' ),
'JP22' => __( 'Shizuoka', 'woocommerce' ),
'JP23' => __( 'Aichi', 'woocommerce' ),
'JP24' => __( 'Mie', 'woocommerce' ),
'JP25' => __( 'Shiga', 'woocommerce' ),
'JP26' => __( 'Kyoto', 'woocommerce' ),
'JP27' => __( 'Osaka', 'woocommerce' ),
'JP28' => __( 'Hyogo', 'woocommerce' ),
'JP29' => __( 'Nara', 'woocommerce' ),
'JP30' => __( 'Wakayama', 'woocommerce' ),
'JP31' => __( 'Tottori', 'woocommerce' ),
'JP32' => __( 'Shimane', 'woocommerce' ),
'JP33' => __( 'Okayama', 'woocommerce' ),
'JP34' => __( 'Hiroshima', 'woocommerce' ),
'JP35' => __( 'Yamaguchi', 'woocommerce' ),
'JP36' => __( 'Tokushima', 'woocommerce' ),
'JP37' => __( 'Kagawa', 'woocommerce' ),
'JP38' => __( 'Ehime', 'woocommerce' ),
'JP39' => __( 'Kochi', 'woocommerce' ),
'JP40' => __( 'Fukuoka', 'woocommerce' ),
'JP41' => __( 'Saga', 'woocommerce' ),
'JP42' => __( 'Nagasaki', 'woocommerce' ),
'JP43' => __( 'Kumamoto', 'woocommerce' ),
'JP44' => __( 'Oita', 'woocommerce' ),
'JP45' => __( 'Miyazaki', 'woocommerce' ),
'JP46' => __( 'Kagoshima', 'woocommerce' ),
'JP47' => __( 'Okinawa', 'woocommerce' ),
'JP02' => __( 'Aomori-ken', 'woocommerce' ),
'JP03' => __( 'Iwate-ken', 'woocommerce' ),
'JP04' => __( 'Miyagi-ken', 'woocommerce' ),
'JP05' => __( 'Akita-ken', 'woocommerce' ),
'JP06' => __( 'Yamagata-ken', 'woocommerce' ),
'JP07' => __( 'Fukushima-ken', 'woocommerce' ),
'JP08' => __( 'Ibaraki-ken', 'woocommerce' ),
'JP09' => __( 'Tochigi-ken', 'woocommerce' ),
'JP10' => __( 'Gunma-ken', 'woocommerce' ),
'JP11' => __( 'Saitama-ken', 'woocommerce' ),
'JP12' => __( 'Chiba-ken', 'woocommerce' ),
'JP13' => __( 'Tokyo-to', 'woocommerce' ),
'JP14' => __( 'Kanagawa-ken', 'woocommerce' ),
'JP15' => __( 'Niigata-ken', 'woocommerce' ),
'JP16' => __( 'Toyama-ken', 'woocommerce' ),
'JP17' => __( 'Ishikawa-ken', 'woocommerce' ),
'JP18' => __( 'Fukui-ken', 'woocommerce' ),
'JP19' => __( 'Yamanashi-ken', 'woocommerce' ),
'JP20' => __( 'Nagano-ken', 'woocommerce' ),
'JP21' => __( 'Gifu-ken', 'woocommerce' ),
'JP22' => __( 'Shizuoka-ken', 'woocommerce' ),
'JP23' => __( 'Aichi-ken', 'woocommerce' ),
'JP24' => __( 'Mie-ken', 'woocommerce' ),
'JP25' => __( 'Shiga-ken', 'woocommerce' ),
'JP26' => __( 'Kyoto-fu', 'woocommerce' ),
'JP27' => __( 'Osaka-fu', 'woocommerce' ),
'JP28' => __( 'Hyogo-ken', 'woocommerce' ),
'JP29' => __( 'Nara-ken', 'woocommerce' ),
'JP30' => __( 'Wakayama-ken', 'woocommerce' ),
'JP31' => __( 'Tottori-ken', 'woocommerce' ),
'JP32' => __( 'Shimane-ken', 'woocommerce' ),
'JP33' => __( 'Okayama-ken', 'woocommerce' ),
'JP34' => __( 'Hiroshima-ken', 'woocommerce' ),
'JP35' => __( 'Yamaguchi-ken', 'woocommerce' ),
'JP36' => __( 'Tokushima-ken', 'woocommerce' ),
'JP37' => __( 'Kagawa-ken', 'woocommerce' ),
'JP38' => __( 'Ehime-ken', 'woocommerce' ),
'JP39' => __( 'Kochi-ken', 'woocommerce' ),
'JP40' => __( 'Fukuoka-ken', 'woocommerce' ),
'JP41' => __( 'Saga-ken', 'woocommerce' ),
'JP42' => __( 'Nagasaki-ken', 'woocommerce' ),
'JP43' => __( 'Kumamoto-ken', 'woocommerce' ),
'JP44' => __( 'Oita-ken', 'woocommerce' ),
'JP45' => __( 'Miyazaki-ken', 'woocommerce' ),
'JP46' => __( 'Kagoshima-ken', 'woocommerce' ),
'JP47' => __( 'Okinawa-ken', 'woocommerce' ),
);

View File

@ -263,7 +263,7 @@ abstract class WC_Data {
*/
public function get_meta_data() {
$this->maybe_read_meta_data();
return array_filter( $this->meta_data, array( $this, 'filter_null_meta' ) );
return array_values( array_filter( $this->meta_data, array( $this, 'filter_null_meta' ) ) );
}
/**

View File

@ -1366,9 +1366,14 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$this->add_item( $item );
}
// Save tax totals.
$this->set_shipping_tax( WC_Tax::round( array_sum( $shipping_taxes ) ) );
$this->set_cart_tax( WC_Tax::round( array_sum( $cart_taxes ) ) );
if ( 'yes' !== get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
$this->set_shipping_tax( wc_round_tax_total( array_sum( array_map( 'wc_round_tax_total', $shipping_taxes ) ) ) );
$this->set_cart_tax( wc_round_tax_total( array_sum( array_map( 'wc_round_tax_total', $cart_taxes ) ) ) );
} else {
$this->set_shipping_tax( wc_round_tax_total( array_sum( $shipping_taxes ) ) );
$this->set_cart_tax( wc_round_tax_total( array_sum( $cart_taxes ) ) );
}
$this->save();
}

View File

@ -945,8 +945,14 @@ class WC_Product extends WC_Abstract_Legacy_Product {
*
* @param string $status New status.
*/
public function set_stock_status( $status = '' ) {
$this->set_prop( 'stock_status', 'outofstock' === $status ? 'outofstock' : 'instock' );
public function set_stock_status( $status = 'instock' ) {
$valid_statuses = wc_get_product_stock_status_options();
if ( isset( $valid_statuses[ $status ] ) ) {
$this->set_prop( 'stock_status', $status );
} else {
$this->set_prop( 'stock_status', 'instock' );
}
}
/**
@ -1300,11 +1306,15 @@ class WC_Product extends WC_Abstract_Legacy_Product {
$this->set_backorders( 'no' );
// If we are stock managing and we don't have stock, force out of stock status.
} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) && 'no' === $this->get_backorders() ) {
} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' === $this->get_backorders() ) {
$this->set_stock_status( 'outofstock' );
// If we are stock managing, backorders are allowed, and we don't have stock, force on backorder status.
} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' !== $this->get_backorders() ) {
$this->set_stock_status( 'onbackorder' );
// If the stock level is changing and we do now have enough, force in stock status.
} elseif ( $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount' ) && array_key_exists( 'stock_quantity', $this->get_changes() ) ) {
} elseif ( $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount', 0 ) && array_key_exists( 'stock_quantity', $this->get_changes() ) ) {
$this->set_stock_status( 'instock' );
}
}
@ -1418,7 +1428,9 @@ class WC_Product extends WC_Abstract_Legacy_Product {
public function is_visible() {
$visible = 'visible' === $this->get_catalog_visibility() || ( is_search() && 'search' === $this->get_catalog_visibility() ) || ( ! is_search() && 'catalog' === $this->get_catalog_visibility() );
if ( 'publish' !== $this->get_status() && ! current_user_can( 'edit_post', $this->get_id() ) ) {
if ( 'trash' === $this->get_status() ) {
$visible = false;
} elseif ( 'publish' !== $this->get_status() && ! current_user_can( 'edit_post', $this->get_id() ) ) {
$visible = false;
}
@ -1488,12 +1500,13 @@ class WC_Product extends WC_Abstract_Legacy_Product {
}
/**
* Returns whether or not the product is in stock.
* Returns whether or not the product can be purchased.
* This returns true for 'instock' and 'onbackorder' stock statuses.
*
* @return bool
*/
public function is_in_stock() {
return apply_filters( 'woocommerce_product_is_in_stock', 'instock' === $this->get_stock_status(), $this );
return apply_filters( 'woocommerce_product_is_in_stock', 'outofstock' !== $this->get_stock_status(), $this );
}
/**
@ -1560,6 +1573,10 @@ class WC_Product extends WC_Abstract_Legacy_Product {
* @return bool
*/
public function is_on_backorder( $qty_in_cart = 0 ) {
if ( 'onbackorder' === $this->get_stock_status() ) {
return true;
}
return $this->managing_stock() && $this->backorders_allowed() && ( $this->get_stock_quantity() - $qty_in_cart ) < 0 ? true : false;
}

View File

@ -274,4 +274,71 @@ abstract class WC_Widget extends WP_Widget {
}
}
}
/**
* Get current page URL with various filtering props supported by WC.
*
* @return string
*/
protected function get_page_base_url() {
if ( defined( 'SHOP_IS_ON_FRONT' ) ) {
$link = home_url();
} elseif ( is_shop() ) {
$link = get_permalink( wc_get_page_id( 'shop' ) );
} elseif ( is_product_category() ) {
$link = get_term_link( get_query_var( 'product_cat' ), 'product_cat' );
} elseif ( is_product_tag() ) {
$link = get_term_link( get_query_var( 'product_tag' ), 'product_tag' );
} else {
$queried_object = get_queried_object();
$link = get_term_link( $queried_object->slug, $queried_object->taxonomy );
}
// Min/Max.
if ( isset( $_GET['min_price'] ) ) {
$link = add_query_arg( 'min_price', wc_clean( wp_unslash( $_GET['min_price'] ) ), $link );
}
if ( isset( $_GET['max_price'] ) ) {
$link = add_query_arg( 'max_price', wc_clean( wp_unslash( $_GET['max_price'] ) ), $link );
}
// Order by.
if ( isset( $_GET['orderby'] ) ) {
$link = add_query_arg( 'orderby', wc_clean( wp_unslash( $_GET['orderby'] ) ), $link );
}
/**
* Search Arg.
* To support quote characters, first they are decoded from &quot; entities, then URL encoded.
*/
if ( get_search_query() ) {
$link = add_query_arg( 's', rawurlencode( htmlspecialchars_decode( get_search_query() ) ), $link );
}
// Post Type Arg.
if ( isset( $_GET['post_type'] ) ) {
$link = add_query_arg( 'post_type', wc_clean( wp_unslash( $_GET['post_type'] ) ), $link );
}
// Min Rating Arg.
if ( isset( $_GET['rating_filter'] ) ) {
$link = add_query_arg( 'rating_filter', wc_clean( wp_unslash( $_GET['rating_filter'] ) ), $link );
}
// All current filters.
if ( $_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes() ) {
foreach ( $_chosen_attributes as $name => $data ) {
$filter_name = sanitize_title( str_replace( 'pa_', '', $name ) );
if ( ! empty( $data['terms'] ) ) {
$link = add_query_arg( 'filter_' . $filter_name, implode( ',', $data['terms'] ), $link );
}
if ( 'or' == $data['query_type'] ) {
$link = add_query_arg( 'query_type_' . $filter_name, 'or', $link );
}
}
}
return $link;
}
}

View File

@ -24,7 +24,7 @@ class WC_Admin_Addons {
*/
public static function get_featured() {
if ( false === ( $featured = get_transient( 'wc_addons_featured' ) ) ) {
$raw_featured = wp_safe_remote_get( 'https://d3t0oesq8995hv.cloudfront.net/add-ons/featured.json', array( 'user-agent' => 'WooCommerce Addons Page' ) );
$raw_featured = wp_safe_remote_get( 'https://d3t0oesq8995hv.cloudfront.net/add-ons/featured-v2.json', array( 'user-agent' => 'WooCommerce Addons Page' ) );
if ( ! is_wp_error( $raw_featured ) ) {
$featured = json_decode( wp_remote_retrieve_body( $raw_featured ) );
if ( $featured ) {
@ -39,36 +39,64 @@ class WC_Admin_Addons {
}
}
/**
* Build url parameter string
*
* @param string $category
* @param string $term
* @param string $country
*
* @return string url parameter string
*/
public static function build_parameter_string( $category, $term, $country ) {
$paramters = array(
'category' => $category,
'term' => $term,
'country' => $country,
);
return '?' . http_build_query( $paramters );
}
/**
* Call API to get extensions
*
* @param string $category
* @param string $term
* @param string $country
*
* @return array of extensions
*/
public static function get_extension_data( $category, $term, $country ) {
$parameters = self::build_parameter_string( $category, $term, $country );
$raw_extensions = wp_remote_get(
'https://woocommerce.com/wp-json/wccom-extensions/1.0/search' . $parameters
);
if ( ! is_wp_error( $raw_extensions ) ) {
$addons = json_decode( wp_remote_retrieve_body( $raw_extensions ) )->products;
}
return $addons;
}
/**
* Get sections for the addons screen
*
* @return array of objects
*/
public static function get_sections() {
if ( false === ( $sections = get_transient( 'wc_addons_sections' ) ) ) {
$raw_sections = wp_safe_remote_get( 'https://d3t0oesq8995hv.cloudfront.net/addon-sections.json', array( 'user-agent' => 'WooCommerce Addons Page' ) );
$addon_sections = get_transient( 'wc_addons_sections' );
if ( false === ( $addon_sections ) ) {
$raw_sections = wp_safe_remote_get(
'https://woocommerce.com/wp-json/wccom-extensions/1.0/categories'
);
if ( ! is_wp_error( $raw_sections ) ) {
$sections = json_decode( wp_remote_retrieve_body( $raw_sections ) );
if ( $sections ) {
set_transient( 'wc_addons_sections', $sections, WEEK_IN_SECONDS );
$addon_sections = json_decode( wp_remote_retrieve_body( $raw_sections ) );
if ( $addon_sections ) {
set_transient( 'wc_addons_sections', $addon_sections, WEEK_IN_SECONDS );
}
}
}
$addon_sections = array();
if ( $sections ) {
foreach ( $sections as $sections_id => $section ) {
if ( empty( $sections_id ) ) {
continue;
}
$addon_sections[ $sections_id ] = new stdClass;
$addon_sections[ $sections_id ]->title = wc_clean( $section->title );
$addon_sections[ $sections_id ]->endpoint = wc_clean( $section->endpoint );
}
}
return apply_filters( 'woocommerce_addons_sections', $addon_sections );
}
@ -160,6 +188,7 @@ class WC_Admin_Addons {
<p><?php echo esc_html( $block->description ); ?></p>
<div class="addons-banner-block-items">
<?php foreach ( $block->items as $item ) : ?>
<?php if ( self::show_extension( $item ) ) : ?>
<div class="addons-banner-block-item">
<div class="addons-banner-block-item-icon">
<img class="addons-img" src="<?php echo esc_url( $item->image ); ?>" />
@ -177,6 +206,7 @@ class WC_Admin_Addons {
?>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
@ -221,11 +251,11 @@ class WC_Admin_Addons {
<h1><?php echo esc_html( $block->title ); ?></h1>
<p><?php echo esc_html( $block->description ); ?></p>
<?php foreach ( $block->items as $item ) : ?>
<?php if ( self::show_extension( $item ) ) : ?>
<div class="addons-column-block-item">
<div class="addons-column-block-item-icon">
<img class="addons-img" src="<?php echo esc_url( $item->image ); ?>" />
</div>
<div class="addons-column-block-item-content">
<h2><?php echo esc_html( $item->title ); ?></h2>
<?php
@ -237,9 +267,9 @@ class WC_Admin_Addons {
);
?>
<p><?php echo esc_html( $item->description ); ?></p>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
@ -475,15 +505,22 @@ class WC_Admin_Addons {
$sections = self::get_sections();
$theme = wp_get_theme();
$section_keys = array_keys( $sections );
$current_section = isset( $_GET['section'] ) ? sanitize_text_field( $_GET['section'] ) : current( $section_keys );
$current_section = isset( $_GET['section'] ) ? sanitize_text_field( $_GET['section'] ) : '_featured';
$addons = array();
if ( '_featured' !== $current_section ) {
$category = isset( $_GET['section'] ) ? $_GET['section'] : null;
$term = isset( $_GET['search'] ) ? $_GET['search'] : null;
$country = WC()->countries->get_base_country();
$addons = self::get_extension_data( $category, $term, $country );
}
/**
* Addon page view.
*
* @uses $addons
* @uses $sections
* @uses $theme
* @uses $section_keys
* @uses $current_section
*/
include_once( dirname( __FILE__ ) . '/views/html-admin-page-addons.php' );
@ -506,4 +543,27 @@ class WC_Admin_Addons {
wp_safe_redirect( remove_query_arg( array( 'install-addon', '_wpnonce' ) ) );
exit;
}
/**
* Should an extension be shown on the featured page.
*
* @param object $item
* @return boolean
*/
public static function show_extension( $item ) {
$location = WC()->countries->get_base_country();
if ( isset( $item->geowhitelist ) && ! in_array( $location, $item->geowhitelist, true ) ) {
return false;
}
if ( isset( $item->geoblacklist ) && in_array( $location, $item->geoblacklist, true ) ) {
return false;
}
if ( is_plugin_active( $item->plugin ) ) {
return false;
}
return true;
}
}

View File

@ -111,7 +111,7 @@ class WC_Admin_Assets {
wp_register_script( 'wc-shipping-classes', WC()->plugin_url() . '/assets/js/admin/wc-shipping-classes' . $suffix . '.js', array( 'jquery', 'wp-util', 'underscore', 'backbone' ), WC_VERSION );
wp_register_script( 'wc-clipboard', WC()->plugin_url() . '/assets/js/admin/wc-clipboard' . $suffix . '.js', array( 'jquery' ), WC_VERSION );
wp_register_script( 'select2', WC()->plugin_url() . '/assets/js/select2/select2.full' . $suffix . '.js', array( 'jquery' ), '4.0.3' );
wp_register_script( 'selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full' . $suffix . '.js', array( 'jquery' ), '1.0.1' );
wp_register_script( 'selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full' . $suffix . '.js', array( 'jquery' ), '1.0.2' );
wp_register_script( 'wc-enhanced-select', WC()->plugin_url() . '/assets/js/admin/wc-enhanced-select' . $suffix . '.js', array( 'jquery', 'selectWoo' ), WC_VERSION );
wp_localize_script( 'wc-enhanced-select', 'wc_enhanced_select_params', array(
'i18n_no_matches' => _x( 'No matches found', 'enhanced select', 'woocommerce' ),

View File

@ -92,7 +92,7 @@ class WC_Admin_Exporters {
* Serve the generated file.
*/
public function download_export_file() {
if ( isset( $_GET['action'], $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], 'product-csv' ) && 'download_product_csv' === $_GET['action'] ) {
if ( isset( $_GET['action'], $_GET['nonce'] ) && wp_verify_nonce( wp_unslash( $_GET['nonce'] ), 'product-csv' ) && 'download_product_csv' === wp_unslash( $_GET['action'] ) ) { // WPCS: input var ok, sanitization ok.
include_once( WC_ABSPATH . 'includes/export/class-wc-product-csv-exporter.php' );
$exporter = new WC_Product_CSV_Exporter();
$exporter->export();
@ -111,23 +111,23 @@ class WC_Admin_Exporters {
include_once( WC_ABSPATH . 'includes/export/class-wc-product-csv-exporter.php' );
$step = absint( $_POST['step'] );
$step = isset( $_POST['step'] ) ? absint( $_POST['step'] ) : 1; // WPCS: input var ok, sanitization ok.
$exporter = new WC_Product_CSV_Exporter();
if ( ! empty( $_POST['columns'] ) ) {
$exporter->set_column_names( $_POST['columns'] );
if ( ! empty( $_POST['columns'] ) ) { // WPCS: input var ok.
$exporter->set_column_names( wp_unslash( $_POST['columns'] ) ); // WPCS: input var ok, sanitization ok.
}
if ( ! empty( $_POST['selected_columns'] ) ) {
$exporter->set_columns_to_export( $_POST['selected_columns'] );
if ( ! empty( $_POST['selected_columns'] ) ) { // WPCS: input var ok.
$exporter->set_columns_to_export( wp_unslash( $_POST['selected_columns'] ) ); // WPCS: input var ok, sanitization ok.
}
if ( ! empty( $_POST['export_meta'] ) ) {
if ( ! empty( $_POST['export_meta'] ) ) { // WPCS: input var ok.
$exporter->enable_meta_export( true );
}
if ( ! empty( $_POST['export_types'] ) ) {
$exporter->set_product_types_to_export( $_POST['export_types'] );
if ( ! empty( $_POST['export_types'] ) ) { // WPCS: input var ok.
$exporter->set_product_types_to_export( wp_unslash( $_POST['export_types'] ) ); // WPCS: input var ok, sanitization ok.
}
$exporter->set_page( $step );

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,7 +12,9 @@ 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.
@ -54,7 +56,7 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
global $menu;
if ( current_user_can( 'manage_woocommerce' ) ) {
$menu[] = array( '', 'read', 'separator-woocommerce', '', 'wp-menu-separator 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' );
@ -95,23 +97,21 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
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'] ) );
$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.
// @codingStandardsIgnoreStart
if ( ! empty( $_POST ) ) {
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();
}
// @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_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'] ) ) {
WC_Admin_Settings::add_message( sanitize_title( wp_unslash( $_GET['wc_message'] ) ) );
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.
}
}
@ -127,6 +127,7 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
*/
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' ) );
}
@ -136,21 +137,20 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
*/
public function menu_highlight() {
global $parent_file, $submenu_file, $post_type;
// @codingStandardsIgnoreStart
switch ( $post_type ) {
case 'shop_order':
case 'shop_coupon':
$parent_file = 'woocommerce';
$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';
$parent_file = 'edit.php?post_type=product';
$submenu_file = 'product_attributes'; // WPCS: override ok.
$parent_file = 'edit.php?post_type=product'; // WPCS: override ok.
}
break;
}
// @codingStandardsIgnoreEnd
}
/**
@ -163,11 +163,13 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
// 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 = wc_processing_order_count() ) ) {
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-' . $order_count . '"><span class="processing-count">' . number_format_i18n( $order_count ) . '</span></span>';
$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;
}
}
@ -178,7 +180,7 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
/**
* Reorder the WC menu items in admin.
*
* @param mixed $menu_order Menu Order.
* @param int $menu_order Menu order.
* @return array
*/
public function menu_order( $menu_order ) {
@ -186,21 +188,21 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
$woocommerce_menu_order = array();
// Get the index of our custom separator.
$woocommerce_separator = array_search( 'separator-woocommerce', $menu_order );
$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 );
$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 ) ) {
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' ) ) ) {
} elseif ( ! in_array( $item, array( 'separator-woocommerce' ), true ) ) {
$woocommerce_menu_order[] = $item;
}
}
@ -308,7 +310,6 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
</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>
@ -319,7 +320,7 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
* Add the "Visit Store" link in admin bar main menu.
*
* @since 2.4.0
* @param WP_Admin_Bar $wp_admin_bar Admin Bar.
* @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() ) {
@ -332,7 +333,7 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
}
// 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' ) ) {
if ( intval( get_option( 'page_on_front' ) ) === wc_get_page_id( 'shop' ) ) {
return;
}
@ -346,6 +347,4 @@ if ( ! class_exists( 'WC_Admin_Menus', false ) ) :
}
}
endif;
return new WC_Admin_Menus();

View File

@ -13,7 +13,9 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'WC_Admin_Permalink_Settings', false ) ) :
if ( class_exists( 'WC_Admin_Permalink_Settings', false ) ) {
return new WC_Admin_Permalink_Settings();
}
/**
* WC_Admin_Permalink_Settings Class.
@ -39,30 +41,28 @@ class WC_Admin_Permalink_Settings {
* Init our settings.
*/
public function settings_init() {
// Add a section to the permalinks page
add_settings_section( 'woocommerce-permalink', __( 'Product permalinks', 'woocommerce' ), array( $this, 'settings' ), 'permalink' );
// Add our settings
add_settings_field(
'woocommerce_product_category_slug', // id
__( 'Product category base', 'woocommerce' ), // setting title
array( $this, 'product_category_slug_input' ), // display callback
'permalink', // settings page
'optional' // settings section
'woocommerce_product_category_slug',
__( 'Product category base', 'woocommerce' ),
array( $this, 'product_category_slug_input' ),
'permalink',
'optional'
);
add_settings_field(
'woocommerce_product_tag_slug', // id
__( 'Product tag base', 'woocommerce' ), // setting title
array( $this, 'product_tag_slug_input' ), // display callback
'permalink', // settings page
'optional' // settings section
'woocommerce_product_tag_slug',
__( 'Product tag base', 'woocommerce' ),
array( $this, 'product_tag_slug_input' ),
'permalink',
'optional'
);
add_settings_field(
'woocommerce_product_attribute_slug', // id
__( 'Product attribute base', 'woocommerce' ), // setting title
array( $this, 'product_attribute_slug_input' ), // display callback
'permalink', // settings page
'optional' // settings section
'woocommerce_product_attribute_slug',
__( 'Product attribute base', 'woocommerce' ),
array( $this, 'product_attribute_slug_input' ),
'permalink',
'optional'
);
$this->permalinks = wc_get_permalink_structure();
@ -99,9 +99,9 @@ class WC_Admin_Permalink_Settings {
* Show the settings.
*/
public function settings() {
echo wpautop( __( 'These settings control the permalinks used specifically for products.', 'woocommerce' ) );
/* translators: %s: Home URL */
echo wp_kses_post( wpautop( sprintf( __( 'If you like, you may enter custom structures for your product URLs here. For example, using <code>shop</code> would make your product links like <code>%sshop/sample-product/</code>. This setting affects product URLs only, not things such as product categories.', 'woocommerce' ), esc_url( home_url( '/' ) ) ) ) );
// Get shop page
$shop_page_id = wc_get_page_id( 'shop' );
$base_slug = urldecode( ( $shop_page_id > 0 && get_post( $shop_page_id ) ) ? get_page_uri( $shop_page_id ) : _x( 'shop', 'default-slug', 'woocommerce' ) );
$product_base = _x( 'product', 'default-slug', 'woocommerce' );
@ -115,28 +115,29 @@ class WC_Admin_Permalink_Settings {
<table class="form-table wc-permalink-structure">
<tbody>
<tr>
<th><label><input name="product_permalink" type="radio" value="<?php echo esc_attr( $structures[0] ); ?>" class="wctog" <?php checked( $structures[0], $this->permalinks['product_base'] ); ?> /> <?php _e( 'Default', 'woocommerce' ); ?></label></th>
<th><label><input name="product_permalink" type="radio" value="<?php echo esc_attr( $structures[0] ); ?>" class="wctog" <?php checked( $structures[0], $this->permalinks['product_base'] ); ?> /> <?php esc_html_e( 'Default', 'woocommerce' ); ?></label></th>
<td><code class="default-example"><?php echo esc_html( home_url() ); ?>/?product=sample-product</code> <code class="non-default-example"><?php echo esc_html( home_url() ); ?>/<?php echo esc_html( $product_base ); ?>/sample-product/</code></td>
</tr>
<?php if ( $shop_page_id ) : ?>
<tr>
<th><label><input name="product_permalink" type="radio" value="<?php echo esc_attr( $structures[1] ); ?>" class="wctog" <?php checked( $structures[1], $this->permalinks['product_base'] ); ?> /> <?php _e( 'Shop base', 'woocommerce' ); ?></label></th>
<th><label><input name="product_permalink" type="radio" value="<?php echo esc_attr( $structures[1] ); ?>" class="wctog" <?php checked( $structures[1], $this->permalinks['product_base'] ); ?> /> <?php esc_html_e( 'Shop base', 'woocommerce' ); ?></label></th>
<td><code><?php echo esc_html( home_url() ); ?>/<?php echo esc_html( $base_slug ); ?>/sample-product/</code></td>
</tr>
<tr>
<th><label><input name="product_permalink" type="radio" value="<?php echo esc_attr( $structures[2] ); ?>" class="wctog" <?php checked( $structures[2], $this->permalinks['product_base'] ); ?> /> <?php _e( 'Shop base with category', 'woocommerce' ); ?></label></th>
<th><label><input name="product_permalink" type="radio" value="<?php echo esc_attr( $structures[2] ); ?>" class="wctog" <?php checked( $structures[2], $this->permalinks['product_base'] ); ?> /> <?php esc_html_e( 'Shop base with category', 'woocommerce' ); ?></label></th>
<td><code><?php echo esc_html( home_url() ); ?>/<?php echo esc_html( $base_slug ); ?>/product-category/sample-product/</code></td>
</tr>
<?php endif; ?>
<tr>
<th><label><input name="product_permalink" id="woocommerce_custom_selection" type="radio" value="custom" class="tog" <?php checked( in_array( $this->permalinks['product_base'], $structures ), false ); ?> />
<?php _e( 'Custom base', 'woocommerce' ); ?></label></th>
<th><label><input name="product_permalink" id="woocommerce_custom_selection" type="radio" value="custom" class="tog" <?php checked( in_array( $this->permalinks['product_base'], $structures, true ), false ); ?> />
<?php esc_html_e( 'Custom base', 'woocommerce' ); ?></label></th>
<td>
<input name="product_permalink_structure" id="woocommerce_permalink_structure" type="text" value="<?php echo esc_attr( $this->permalinks['product_base'] ? trailingslashit( $this->permalinks['product_base'] ) : '' ); ?>" class="regular-text code"> <span class="description"><?php _e( 'Enter a custom base to use. A base <strong>must</strong> be set or WordPress will use default instead.', 'woocommerce' ); ?></span>
<input name="product_permalink_structure" id="woocommerce_permalink_structure" type="text" value="<?php echo esc_attr( $this->permalinks['product_base'] ? trailingslashit( $this->permalinks['product_base'] ) : '' ); ?>" class="regular-text code"> <span class="description"><?php esc_html_e( 'Enter a custom base to use. A base must be set or WordPress will use default instead.', 'woocommerce' ); ?></span>
</td>
</tr>
</tbody>
</table>
<?php wp_nonce_field( 'wc-permalinks', 'wc-permalinks-nonce' ); ?>
<script type="text/javascript">
jQuery( function() {
jQuery('input.wctog').change(function() {
@ -171,20 +172,20 @@ class WC_Admin_Permalink_Settings {
}
// We need to save the options ourselves; settings api does not trigger save for the permalinks page.
if ( isset( $_POST['permalink_structure'] ) ) {
if ( isset( $_POST['permalink_structure'], $_POST['wc-permalinks-nonce'], $_POST['woocommerce_product_category_slug'], $_POST['woocommerce_product_tag_slug'], $_POST['woocommerce_product_attribute_slug'] ) && wp_verify_nonce( wp_unslash( $_POST['wc-permalinks-nonce'] ), 'wc-permalinks' ) ) { // WPCS: input var ok, sanitization ok.
wc_switch_to_site_locale();
$permalinks = (array) get_option( 'woocommerce_permalinks', array() );
$permalinks['category_base'] = wc_sanitize_permalink( trim( $_POST['woocommerce_product_category_slug'] ) );
$permalinks['tag_base'] = wc_sanitize_permalink( trim( $_POST['woocommerce_product_tag_slug'] ) );
$permalinks['attribute_base'] = wc_sanitize_permalink( trim( $_POST['woocommerce_product_attribute_slug'] ) );
$permalinks['category_base'] = wc_sanitize_permalink( wp_unslash( $_POST['woocommerce_product_category_slug'] ) ); // WPCS: input var ok, sanitization ok.
$permalinks['tag_base'] = wc_sanitize_permalink( wp_unslash( $_POST['woocommerce_product_tag_slug'] ) ); // WPCS: input var ok, sanitization ok.
$permalinks['attribute_base'] = wc_sanitize_permalink( wp_unslash( $_POST['woocommerce_product_attribute_slug'] ) ); // WPCS: input var ok, sanitization ok.
// Generate product base.
$product_base = isset( $_POST['product_permalink'] ) ? wc_clean( $_POST['product_permalink'] ) : '';
$product_base = isset( $_POST['product_permalink'] ) ? wc_clean( wp_unslash( $_POST['product_permalink'] ) ) : ''; // WPCS: input var ok, sanitization ok.
if ( 'custom' === $product_base ) {
if ( isset( $_POST['product_permalink_structure'] ) ) {
$product_base = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', trim( $_POST['product_permalink_structure'] ) ) );
if ( isset( $_POST['product_permalink_structure'] ) ) { // WPCS: input var ok.
$product_base = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', trim( wp_unslash( $_POST['product_permalink_structure'] ) ) ) ); // WPCS: input var ok, sanitization ok.
} else {
$product_base = '/';
}
@ -213,6 +214,4 @@ class WC_Admin_Permalink_Settings {
}
}
endif;
return new WC_Admin_Permalink_Settings();

View File

@ -90,12 +90,15 @@ class WC_Admin_Post_Types {
switch ( $screen_id ) {
case 'edit-shop_order' :
include_once( 'list-tables/class-wc-admin-list-table-orders.php' );
new WC_Admin_List_Table_Orders();
break;
case 'edit-shop_coupon' :
include_once( 'list-tables/class-wc-admin-list-table-coupons.php' );
new WC_Admin_List_Table_Coupons();
break;
case 'edit-product' :
include_once( 'list-tables/class-wc-admin-list-table-products.php' );
new WC_Admin_List_Table_Products();
break;
}
}

View File

@ -2,10 +2,10 @@
/**
* WooCommerce Admin Settings Class
*
* @author WooThemes
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 2.5.0
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -57,7 +57,7 @@ class WC_Admin_Settings {
$settings[] = include( 'settings/class-wc-settings-accounts.php' );
$settings[] = include( 'settings/class-wc-settings-emails.php' );
$settings[] = include( 'settings/class-wc-settings-integrations.php' );
$settings[] = include( 'settings/class-wc-settings-api.php' );
$settings[] = include( 'settings/class-wc-settings-rest-api.php' );
self::$settings = apply_filters( 'woocommerce_get_settings_pages', $settings );
}
@ -71,11 +71,9 @@ class WC_Admin_Settings {
public static function save() {
global $current_tab;
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-settings' ) ) {
die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
}
check_admin_referer( 'woocommerce-settings' );
// Trigger actions
// Trigger actions.
do_action( 'woocommerce_settings_save_' . $current_tab );
do_action( 'woocommerce_update_options_' . $current_tab );
do_action( 'woocommerce_update_options' );
@ -83,7 +81,7 @@ class WC_Admin_Settings {
self::add_message( __( 'Your settings have been saved.', 'woocommerce' ) );
self::check_download_folder_protection();
// Clear any unwanted data and flush rules on next init.
// Clear any unwanted data and flush rules.
add_option( 'woocommerce_queue_flush_rewrite_rules', 'true' );
delete_transient( 'woocommerce_cache_excluded_uris' );
WC()->query->init_query_vars();
@ -94,7 +92,8 @@ class WC_Admin_Settings {
/**
* Add a message.
* @param string $text
*
* @param string $text Message.
*/
public static function add_message( $text ) {
self::$messages[] = $text;
@ -102,7 +101,8 @@ class WC_Admin_Settings {
/**
* Add an error.
* @param string $text
*
* @param string $text Message.
*/
public static function add_error( $text ) {
self::$errors[] = $text;
@ -112,11 +112,11 @@ class WC_Admin_Settings {
* Output messages + errors.
*/
public static function show_messages() {
if ( sizeof( self::$errors ) > 0 ) {
if ( count( self::$errors ) > 0 ) {
foreach ( self::$errors as $error ) {
echo '<div id="message" class="error inline"><p><strong>' . esc_html( $error ) . '</strong></p></div>';
}
} elseif ( sizeof( self::$messages ) > 0 ) {
} elseif ( count( self::$messages ) > 0 ) {
foreach ( self::$messages as $message ) {
echo '<div id="message" class="updated inline"><p><strong>' . esc_html( $message ) . '</strong></p></div>';
}
@ -141,7 +141,7 @@ class WC_Admin_Settings {
'i18n_nav_warning' => __( 'The changes you made will be lost if you navigate away from this page.', 'woocommerce' ),
) );
// Get tabs for the settings page
// Get tabs for the settings page.
$tabs = apply_filters( 'woocommerce_settings_tabs_array', array() );
include( dirname( __FILE__ ) . '/views/html-admin-settings.php' );
@ -150,21 +150,20 @@ class WC_Admin_Settings {
/**
* Get a setting from the settings API.
*
* @param string $option_name
* @param mixed $default
*
* @param string $option_name Option name.
* @param mixed $default Default value.
* @return mixed
*/
public static function get_option( $option_name, $default = '' ) {
// Array value
// Array value.
if ( strstr( $option_name, '[' ) ) {
parse_str( $option_name, $option_array );
// Option name is first key
// Option name is first key.
$option_name = current( array_keys( $option_array ) );
// Get value
// Get value.
$option_values = get_option( $option_name, '' );
$key = key( $option_array[ $option_name ] );
@ -174,9 +173,8 @@ class WC_Admin_Settings {
} else {
$option_value = null;
}
// Single value
} else {
// Single value.
$option_value = get_option( $option_name, null );
}
@ -194,7 +192,7 @@ class WC_Admin_Settings {
*
* Loops though the woocommerce options array and outputs each field.
*
* @param array[] $options Opens array to output
* @param array[] $options Opens array to output.
*/
public static function output_fields( $options ) {
foreach ( $options as $value ) {
@ -229,7 +227,7 @@ class WC_Admin_Settings {
$value['suffix'] = '';
}
// Custom attribute handling
// Custom attribute handling.
$custom_attributes = array();
if ( ! empty( $value['custom_attributes'] ) && is_array( $value['custom_attributes'] ) ) {
@ -238,20 +236,21 @@ class WC_Admin_Settings {
}
}
// Description handling
// Description handling.
$field_description = self::get_field_description( $value );
extract( $field_description );
$description = $field_description['description'];
$tooltip_html = $field_description['tooltip_html'];
// Switch based on type
// Switch based on type.
switch ( $value['type'] ) {
// Section Titles
// Section Titles.
case 'title':
if ( ! empty( $value['title'] ) ) {
echo '<h2>' . esc_html( $value['title'] ) . '</h2>';
}
if ( ! empty( $value['desc'] ) ) {
echo wpautop( wptexturize( wp_kses_post( $value['desc'] ) ) );
echo wp_kses_post( wpautop( wptexturize( $value['desc'] ) ) );
}
echo '<table class="form-table">' . "\n\n";
if ( ! empty( $value['id'] ) ) {
@ -259,7 +258,7 @@ class WC_Admin_Settings {
}
break;
// Section Ends
// Section Ends.
case 'sectionend':
if ( ! empty( $value['id'] ) ) {
do_action( 'woocommerce_settings_' . sanitize_title( $value['id'] ) . '_end' );
@ -270,7 +269,7 @@ class WC_Admin_Settings {
}
break;
// Standard text inputs and subtypes like 'number'
// Standard text inputs and subtypes like 'number'.
case 'text':
case 'email':
case 'number':
@ -280,9 +279,9 @@ class WC_Admin_Settings {
?><tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
<?php echo $tooltip_html; ?>
<?php echo $tooltip_html; // WPCS: XSS ok. ?>
</th>
<td class="forminp forminp-<?php echo sanitize_title( $value['type'] ) ?>">
<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
<input
name="<?php echo esc_attr( $value['id'] ); ?>"
id="<?php echo esc_attr( $value['id'] ); ?>"
@ -291,22 +290,24 @@ class WC_Admin_Settings {
value="<?php echo esc_attr( $option_value ); ?>"
class="<?php echo esc_attr( $value['class'] ); ?>"
placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>"
<?php echo implode( ' ', $custom_attributes ); ?>
/><?php echo esc_html( $value['suffix'] ); ?> <?php echo $description; ?>
<?php echo implode( ' ', $custom_attributes ); // WPCS: XSS ok. ?>
/><?php echo esc_html( $value['suffix'] ); ?> <?php echo $description; // WPCS: XSS ok. ?>
</td>
</tr><?php
</tr>
<?php
break;
// Color picker.
case 'color':
$option_value = self::get_option( $value['id'], $value['default'] );
?><tr valign="top">
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
<?php echo $tooltip_html; ?>
<?php echo $tooltip_html; // WPCS: XSS ok. ?>
</th>
<td class="forminp forminp-<?php echo sanitize_title( $value['type'] ) ?>">&lrm;
<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">&lrm;
<span class="colorpickpreview" style="background: <?php echo esc_attr( $option_value ); ?>"></span>
<input
name="<?php echo esc_attr( $value['id'] ); ?>"
@ -317,25 +318,26 @@ class WC_Admin_Settings {
value="<?php echo esc_attr( $option_value ); ?>"
class="<?php echo esc_attr( $value['class'] ); ?>colorpick"
placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>"
<?php echo implode( ' ', $custom_attributes ); ?>
/>&lrm; <?php echo $description; ?>
<?php echo implode( ' ', $custom_attributes ); // WPCS: XSS ok. ?>
/>&lrm; <?php echo $description; // WPCS: XSS ok. ?>
<div id="colorPickerDiv_<?php echo esc_attr( $value['id'] ); ?>" class="colorpickdiv" style="z-index: 100;background:#eee;border:1px solid #ccc;position:absolute;display:none;"></div>
</td>
</tr><?php
</tr>
<?php
break;
// Textarea
// Textarea.
case 'textarea':
$option_value = self::get_option( $value['id'], $value['default'] );
?><tr valign="top">
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
<?php echo $tooltip_html; ?>
<?php echo $tooltip_html; // WPCS: XSS ok. ?>
</th>
<td class="forminp forminp-<?php echo sanitize_title( $value['type'] ) ?>">
<?php echo $description; ?>
<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
<?php echo $description; // WPCS: XSS ok. ?>
<textarea
name="<?php echo esc_attr( $value['id'] ); ?>"
@ -343,65 +345,70 @@ class WC_Admin_Settings {
style="<?php echo esc_attr( $value['css'] ); ?>"
class="<?php echo esc_attr( $value['class'] ); ?>"
placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>"
<?php echo implode( ' ', $custom_attributes ); ?>
><?php echo esc_textarea( $option_value ); ?></textarea>
<?php echo implode( ' ', $custom_attributes ); // WPCS: XSS ok. ?>
><?php echo esc_textarea( $option_value ); // WPCS: XSS ok. ?></textarea>
</td>
</tr><?php
</tr>
<?php
break;
// Select boxes
// Select boxes.
case 'select':
case 'multiselect':
$option_value = self::get_option( $value['id'], $value['default'] );
?><tr valign="top">
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
<?php echo $tooltip_html; ?>
<?php echo $tooltip_html; // WPCS: XSS ok. ?>
</th>
<td class="forminp forminp-<?php echo sanitize_title( $value['type'] ) ?>">
<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
<select
name="<?php echo esc_attr( $value['id'] ); ?><?php echo ( 'multiselect' === $value['type'] ) ? '[]' : ''; ?>"
id="<?php echo esc_attr( $value['id'] ); ?>"
style="<?php echo esc_attr( $value['css'] ); ?>"
class="<?php echo esc_attr( $value['class'] ); ?>"
<?php echo implode( ' ', $custom_attributes ); ?>
<?php echo ( 'multiselect' == $value['type'] ) ? 'multiple="multiple"' : ''; ?>
<?php echo implode( ' ', $custom_attributes ); // WPCS: XSS ok. ?>
<?php echo 'multiselect' === $value['type'] ? 'multiple="multiple"' : ''; ?>
>
<?php
foreach ( $value['options'] as $key => $val ) {
?>
<option value="<?php echo esc_attr( $key ); ?>" <?php
<option value="<?php echo esc_attr( $key ); ?>"
<?php
if ( is_array( $option_value ) ) {
selected( in_array( $key, $option_value ), true );
selected( in_array( $key, $option_value, true ), true );
} else {
selected( $option_value, $key );
}
?>><?php echo $val ?></option>
?>
>
<?php echo esc_html( $val ); ?></option>
<?php
}
?>
</select> <?php echo $description; ?>
</select> <?php echo $description; // WPCS: XSS ok. ?>
</td>
</tr><?php
</tr>
<?php
break;
// Radio inputs
// Radio inputs.
case 'radio':
$option_value = self::get_option( $value['id'], $value['default'] );
?><tr valign="top">
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
<?php echo $tooltip_html; ?>
<?php echo $tooltip_html; // WPCS: XSS ok. ?>
</th>
<td class="forminp forminp-<?php echo sanitize_title( $value['type'] ) ?>">
<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
<fieldset>
<?php echo $description; ?>
<?php echo $description; // WPCS: XSS ok. ?>
<ul>
<?php
foreach ( $value['options'] as $key => $val ) {
@ -409,13 +416,13 @@ class WC_Admin_Settings {
<li>
<label><input
name="<?php echo esc_attr( $value['id'] ); ?>"
value="<?php echo $key; ?>"
value="<?php echo esc_attr( $key ); ?>"
type="radio"
style="<?php echo esc_attr( $value['css'] ); ?>"
class="<?php echo esc_attr( $value['class'] ); ?>"
<?php echo implode( ' ', $custom_attributes ); ?>
<?php echo implode( ' ', $custom_attributes ); // WPCS: XSS ok. ?>
<?php checked( $key, $option_value ); ?>
/> <?php echo $val ?></label>
/> <?php echo esc_html( $val ); ?></label>
</li>
<?php
}
@ -423,12 +430,12 @@ class WC_Admin_Settings {
</ul>
</fieldset>
</td>
</tr><?php
</tr>
<?php
break;
// Checkbox input
// Checkbox input.
case 'checkbox':
$option_value = self::get_option( $value['id'], $value['default'] );
$visibility_class = array();
@ -438,20 +445,20 @@ class WC_Admin_Settings {
if ( ! isset( $value['show_if_checked'] ) ) {
$value['show_if_checked'] = false;
}
if ( 'yes' == $value['hide_if_checked'] || 'yes' == $value['show_if_checked'] ) {
if ( 'yes' === $value['hide_if_checked'] || 'yes' === $value['show_if_checked'] ) {
$visibility_class[] = 'hidden_option';
}
if ( 'option' == $value['hide_if_checked'] ) {
if ( 'option' === $value['hide_if_checked'] ) {
$visibility_class[] = 'hide_options_if_checked';
}
if ( 'option' == $value['show_if_checked'] ) {
if ( 'option' === $value['show_if_checked'] ) {
$visibility_class[] = 'show_options_if_checked';
}
if ( ! isset( $value['checkboxgroup'] ) || 'start' == $value['checkboxgroup'] ) {
if ( ! isset( $value['checkboxgroup'] ) || 'start' === $value['checkboxgroup'] ) {
?>
<tr valign="top" class="<?php echo esc_attr( implode( ' ', $visibility_class ) ); ?>">
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?></th>
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ); ?></th>
<td class="forminp forminp-checkbox">
<fieldset>
<?php
@ -463,12 +470,12 @@ class WC_Admin_Settings {
if ( ! empty( $value['title'] ) ) {
?>
<legend class="screen-reader-text"><span><?php echo esc_html( $value['title'] ) ?></span></legend>
<legend class="screen-reader-text"><span><?php echo esc_html( $value['title'] ); ?></span></legend>
<?php
}
?>
<label for="<?php echo $value['id'] ?>">
<label for="<?php echo esc_attr( $value['id'] ); ?>">
<input
name="<?php echo esc_attr( $value['id'] ); ?>"
id="<?php echo esc_attr( $value['id'] ); ?>"
@ -476,12 +483,12 @@ class WC_Admin_Settings {
class="<?php echo esc_attr( isset( $value['class'] ) ? $value['class'] : '' ); ?>"
value="1"
<?php checked( $option_value, 'yes' ); ?>
<?php echo implode( ' ', $custom_attributes ); ?>
/> <?php echo $description ?>
</label> <?php echo $tooltip_html; ?>
<?php echo implode( ' ', $custom_attributes ); // WPCS: XSS ok. ?>
/> <?php echo $description; // WPCS: XSS ok. ?>
</label> <?php echo $tooltip_html; // WPCS: XSS ok. ?>
<?php
if ( ! isset( $value['checkboxgroup'] ) || 'end' == $value['checkboxgroup'] ) {
if ( ! isset( $value['checkboxgroup'] ) || 'end' === $value['checkboxgroup'] ) {
?>
</fieldset>
</td>
@ -496,7 +503,6 @@ class WC_Admin_Settings {
// Image width settings. @todo deprecate and remove in 4.0. No longer needed by core.
case 'image_width':
$image_size = str_replace( '_image_size', '', $value['id'] );
$size = wc_get_image_size( $image_size );
$width = isset( $size['width'] ) ? $size['width'] : $value['default']['width'];
@ -507,80 +513,25 @@ class WC_Admin_Settings {
if ( has_filter( 'woocommerce_get_image_size_' . $image_size ) ) {
$disabled_attr = 'disabled="disabled"';
$disabled_message = "<p><small>" . __( 'The settings of this image size have been disabled because its values are being overwritten by a filter.', 'woocommerce' ) . "</small></p>";
$disabled_message = '<p><small>' . esc_html__( 'The settings of this image size have been disabled because its values are being overwritten by a filter.', 'woocommerce' ) . '</small></p>';
}
?><tr valign="top">
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?> <?php echo $tooltip_html . $disabled_message; ?></th>
?>
<tr valign="top">
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html . $disabled_message; // WPCS: XSS ok. ?></th>
<td class="forminp image_width_settings">
<input name="<?php echo esc_attr( $value['id'] ); ?>[width]" <?php echo $disabled_attr; ?> id="<?php echo esc_attr( $value['id'] ); ?>-width" type="text" size="3" value="<?php echo $width; ?>" /> &times; <input name="<?php echo esc_attr( $value['id'] ); ?>[height]" <?php echo $disabled_attr; ?> id="<?php echo esc_attr( $value['id'] ); ?>-height" type="text" size="3" value="<?php echo $height; ?>" />px
<input name="<?php echo esc_attr( $value['id'] ); ?>[width]" <?php echo $disabled_attr; // WPCS: XSS ok. ?> id="<?php echo esc_attr( $value['id'] ); ?>-width" type="text" size="3" value="<?php echo esc_attr( $width ); ?>" /> &times; <input name="<?php echo esc_attr( $value['id'] ); ?>[height]" <?php echo $disabled_attr; // WPCS: XSS ok. ?> id="<?php echo esc_attr( $value['id'] ); ?>-height" type="text" size="3" value="<?php echo esc_attr( $height ); ?>" />px
<label><input name="<?php echo esc_attr( $value['id'] ); ?>[crop]" <?php echo $disabled_attr; ?> id="<?php echo esc_attr( $value['id'] ); ?>-crop" type="checkbox" value="1" <?php checked( 1, $crop ); ?> /> <?php _e( 'Hard crop?', 'woocommerce' ); ?></label>
<label><input name="<?php echo esc_attr( $value['id'] ); ?>[crop]" <?php echo $disabled_attr; // WPCS: XSS ok. ?> id="<?php echo esc_attr( $value['id'] ); ?>-crop" type="checkbox" value="1" <?php checked( 1, $crop ); ?> /> <?php esc_html_e( 'Hard crop?', 'woocommerce' ); ?></label>
</td>
</tr><?php
</tr>
<?php
break;
// Thumbnail cropping setting. DEVELOPERS: This is private. Re-use at your own risk.
case 'thumbnail_cropping' :
$option_value = self::get_option( $value['id'], $value['default'] );
if ( strstr( $option_value, ':' ) ) {
$cropping_split = explode( ':', $option_value );
$width = max( 1, current( $cropping_split ) );
$height = max( 1, end( $cropping_split ) );
} else {
$width = 4;
$height = 3;
}
?><tr valign="top">
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?> <?php echo $tooltip_html; ?></th>
<td class="forminp">
<ul class="woocommerce-thumbnail-cropping">
<li>
<input type="radio" name="woocommerce_thumbnail_cropping" id="thumbnail_cropping_1_1" value="1:1" <?php checked( $option_value, '1:1' ); ?> />
<label for="thumbnail_cropping_1_1">1:1<br/><span class="description"><?php esc_html_e( 'Images will be cropped into a square', 'woocommerce' ); ?></span></label>
</li>
<li>
<input type="radio" name="woocommerce_thumbnail_cropping" id="thumbnail_cropping_custom" value="custom" <?php checked( ! in_array( $option_value, array( '1:1', 'uncropped' ), true ), true ); ?> />
<label for="thumbnail_cropping_custom">
<?php esc_html_e( 'Custom', 'woocommerce' ); ?><br/><span class="description"><?php esc_html_e( 'Images will be cropped to a custom aspect ratio', 'woocommerce' ); ?></span>
<span class="woocommerce-thumbnail-cropping-aspect-ratio">
<input name="thumbnail_cropping_aspect_ratio_width" type="text" pattern="\d*" size="3" value="<?php echo $width; ?>" /> : <input name="thumbnail_cropping_aspect_ratio_height" type="text" pattern="\d*" size="3" value="<?php echo $height; ?>" />
</span>
</label>
</li>
<li>
<input type="radio" name="woocommerce_thumbnail_cropping" id="thumbnail_cropping_uncropped" value="uncropped" <?php checked( $option_value, 'uncropped' ); ?> />
<label for="thumbnail_cropping_uncropped"><?php esc_html_e( 'Uncropped', 'woocommerce' ); ?><br/><span class="description"><?php esc_html_e( 'Images will display using the aspect ratio in which they were uploaded', 'woocommerce' ); ?></span></label>
</li>
</ul>
<div class="woocommerce-thumbnail-preview hide-if-no-js">
<h4><?php esc_html_e( 'Preview', 'woocommerce' ); ?></h4>
<div class="woocommerce-thumbnail-preview-block">
<div class="woocommerce-thumbnail-preview-block__image"></div>
<div class="woocommerce-thumbnail-preview-block__text"></div>
<div class="woocommerce-thumbnail-preview-block__button"></div>
</div>
<div class="woocommerce-thumbnail-preview-block">
<div class="woocommerce-thumbnail-preview-block__image"></div>
<div class="woocommerce-thumbnail-preview-block__text"></div>
<div class="woocommerce-thumbnail-preview-block__button"></div>
</div>
<div class="woocommerce-thumbnail-preview-block">
<div class="woocommerce-thumbnail-preview-block__image"></div>
<div class="woocommerce-thumbnail-preview-block__text"></div>
<div class="woocommerce-thumbnail-preview-block__button"></div>
</div>
</div>
</td>
</tr><?php
break;
// Single page selects
// Single page selects.
case 'single_select_page':
$args = array(
'name' => $value['id'],
'id' => $value['id'],
@ -596,15 +547,17 @@ class WC_Admin_Settings {
$args = wp_parse_args( $value['args'], $args );
}
?><tr valign="top" class="single_select_page">
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ) ?> <?php echo $tooltip_html; ?></th>
?>
<tr valign="top" class="single_select_page">
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></th>
<td class="forminp">
<?php echo str_replace( ' id=', " data-placeholder='" . esc_attr__( 'Select a page&hellip;', 'woocommerce' ) . "' style='" . $value['css'] . "' class='" . $value['class'] . "' id=", wp_dropdown_pages( $args ) ); ?> <?php echo $description; ?>
<?php echo str_replace( ' id=', " data-placeholder='" . esc_attr__( 'Select a page&hellip;', 'woocommerce' ) . "' style='" . $value['css'] . "' class='" . $value['class'] . "' id=", wp_dropdown_pages( $args ) ); // WPCS: XSS ok. ?> <?php echo $description; // WPCS: XSS ok. ?>
</td>
</tr><?php
</tr>
<?php
break;
// Single country selects
// Single country selects.
case 'single_select_country':
$country_setting = (string) self::get_option( $value['id'] );
@ -616,21 +569,22 @@ class WC_Admin_Settings {
$country = $country_setting;
$state = '*';
}
?><tr valign="top">
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
<?php echo $tooltip_html; ?>
<?php echo $tooltip_html; // WPCS: XSS ok. ?>
</th>
<td class="forminp"><select name="<?php echo esc_attr( $value['id'] ); ?>" style="<?php echo esc_attr( $value['css'] ); ?>" data-placeholder="<?php esc_attr_e( 'Choose a country&hellip;', 'woocommerce' ); ?>" aria-label="<?php esc_attr_e( 'Country', 'woocommerce' ) ?>" class="wc-enhanced-select">
<td class="forminp"><select name="<?php echo esc_attr( $value['id'] ); ?>" style="<?php echo esc_attr( $value['css'] ); ?>" data-placeholder="<?php esc_attr_e( 'Choose a country&hellip;', 'woocommerce' ); ?>" aria-label="<?php esc_attr_e( 'Country', 'woocommerce' ); ?>" class="wc-enhanced-select">
<?php WC()->countries->country_dropdown_options( $country, $state ); ?>
</select> <?php echo $description; ?>
</select> <?php echo $description; // WPCS: XSS ok. ?>
</td>
</tr><?php
</tr>
<?php
break;
// Country multiselects
// Country multiselects.
case 'multi_select_countries':
$selections = (array) self::get_option( $value['id'] );
if ( ! empty( $value['options'] ) ) {
@ -640,26 +594,28 @@ class WC_Admin_Settings {
}
asort( $countries );
?><tr valign="top">
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
<?php echo $tooltip_html; ?>
<?php echo $tooltip_html; // WPCS: XSS ok. ?>
</th>
<td class="forminp">
<select multiple="multiple" name="<?php echo esc_attr( $value['id'] ); ?>[]" style="width:350px" data-placeholder="<?php esc_attr_e( 'Choose countries&hellip;', 'woocommerce' ); ?>" aria-label="<?php esc_attr_e( 'Country', 'woocommerce' ) ?>" class="wc-enhanced-select">
<select multiple="multiple" name="<?php echo esc_attr( $value['id'] ); ?>[]" style="width:350px" data-placeholder="<?php esc_attr_e( 'Choose countries&hellip;', 'woocommerce' ); ?>" aria-label="<?php esc_attr_e( 'Country', 'woocommerce' ); ?>" class="wc-enhanced-select">
<?php
if ( ! empty( $countries ) ) {
foreach ( $countries as $key => $val ) {
echo '<option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $selections ), true, false ) . '>' . $val . '</option>';
echo '<option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $selections, true ), true, false ) . '>' . esc_html( $val ) . '</option>';
}
}
?>
</select> <?php echo ( $description ) ? $description : ''; ?> <br /><a class="select_all button" href="#"><?php _e( 'Select all', 'woocommerce' ); ?></a> <a class="select_none button" href="#"><?php _e( 'Select none', 'woocommerce' ); ?></a>
</select> <?php echo ( $description ) ? $description : ''; // WPCS: XSS ok. ?> <br /><a class="select_all button" href="#"><?php esc_html_e( 'Select all', 'woocommerce' ); ?></a> <a class="select_none button" href="#"><?php esc_html_e( 'Select none', 'woocommerce' ); ?></a>
</td>
</tr><?php
</tr>
<?php
break;
// Default: run an action
// Default: run an action.
default:
do_action( 'woocommerce_admin_field_' . $value['type'], $value );
break;
@ -672,8 +628,8 @@ class WC_Admin_Settings {
* given form field. Plugins can call this when implementing their own custom
* settings types.
*
* @param array $value The form field value array
* @return array The description and tip as a 2 element array
* @param array $value The form field value array.
* @return array The description and tip as a 2 element array.
*/
public static function get_field_description( $value ) {
$description = '';
@ -688,15 +644,15 @@ class WC_Admin_Settings {
$description = $value['desc'];
}
if ( $description && in_array( $value['type'], array( 'textarea', 'radio' ) ) ) {
if ( $description && in_array( $value['type'], array( 'textarea', 'radio' ), true ) ) {
$description = '<p style="margin-top:0">' . wp_kses_post( $description ) . '</p>';
} elseif ( $description && in_array( $value['type'], array( 'checkbox' ) ) ) {
} elseif ( $description && in_array( $value['type'], array( 'checkbox' ), true ) ) {
$description = wp_kses_post( $description );
} elseif ( $description ) {
$description = '<span class="description">' . wp_kses_post( $description ) . '</span>';
}
if ( $tooltip_html && in_array( $value['type'], array( 'checkbox' ) ) ) {
if ( $tooltip_html && in_array( $value['type'], array( 'checkbox' ), true ) ) {
$tooltip_html = '<p class="description">' . $tooltip_html . '</p>';
} elseif ( $tooltip_html ) {
$tooltip_html = wc_help_tip( $tooltip_html );
@ -713,13 +669,13 @@ class WC_Admin_Settings {
*
* Loops though the woocommerce options array and outputs each field.
*
* @param array $options Options array to output
* @param array $options Options array to output.
* @param array $data Optional. Data to use for saving. Defaults to $_POST.
* @return bool
*/
public static function save_fields( $options, $data = null ) {
if ( is_null( $data ) ) {
$data = $_POST;
$data = $_POST; // WPCS: input var okay, CSRF ok.
}
if ( empty( $data ) ) {
return false;
@ -770,15 +726,6 @@ class WC_Admin_Settings {
$value['crop'] = $option['default']['crop'];
}
break;
case 'thumbnail_cropping' :
$value = wc_clean( $raw_value );
if ( 'custom' === $value ) {
$width_ratio = wc_clean( wp_unslash( $_POST['thumbnail_cropping_aspect_ratio_width'] ) );
$height_ratio = wc_clean( wp_unslash( $_POST['thumbnail_cropping_aspect_ratio_height'] ) );
$value = $width_ratio . ':' . $height_ratio;
}
break;
case 'select':
$allowed_values = empty( $option['options'] ) ? array() : array_keys( $option['options'] );
if ( empty( $option['default'] ) && empty( $allowed_values ) ) {
@ -786,7 +733,7 @@ class WC_Admin_Settings {
break;
}
$default = ( empty( $option['default'] ) ? $allowed_values[0] : $option['default'] );
$value = in_array( $raw_value, $allowed_values ) ? $raw_value : $default;
$value = in_array( $raw_value, $allowed_values, true ) ? $raw_value : $default;
break;
default:
$value = wc_clean( $raw_value );
@ -795,6 +742,7 @@ class WC_Admin_Settings {
/**
* Fire an action when a certain 'type' of field is being saved.
*
* @deprecated 2.4.0 - doesn't allow manipulation of values!
*/
if ( has_action( 'woocommerce_update_option_' . sanitize_title( $option['type'] ) ) ) {
@ -805,12 +753,14 @@ class WC_Admin_Settings {
/**
* Sanitize the value of an option.
*
* @since 2.4.0
*/
$value = apply_filters( 'woocommerce_admin_settings_sanitize_option', $value, $option, $raw_value );
/**
* Sanitize the value of an option by option name.
*
* @since 2.4.0
*/
$value = apply_filters( "woocommerce_admin_settings_sanitize_option_$option_name", $value, $option, $raw_value );
@ -834,6 +784,7 @@ class WC_Admin_Settings {
/**
* Fire an action before saved.
*
* @deprecated 2.4.0 - doesn't allow manipulation of values!
*/
do_action( 'woocommerce_update_option', $option );
@ -857,19 +808,20 @@ class WC_Admin_Settings {
$downloads_url = $upload_dir['basedir'] . '/woocommerce_uploads';
$download_method = get_option( 'woocommerce_file_download_method' );
if ( 'redirect' == $download_method ) {
if ( 'redirect' === $download_method ) {
// Redirect method - don't protect
// Redirect method - don't protect.
if ( file_exists( $downloads_url . '/.htaccess' ) ) {
unlink( $downloads_url . '/.htaccess' );
unlink( $downloads_url . '/.htaccess' ); // @codingStandardsIgnoreLine
}
} else {
// Force method - protect, add rules to the htaccess file
// Force method - protect, add rules to the htaccess file.
if ( ! file_exists( $downloads_url . '/.htaccess' ) ) {
if ( $file_handle = @fopen( $downloads_url . '/.htaccess', 'w' ) ) {
fwrite( $file_handle, 'deny from all' );
fclose( $file_handle );
$file_handle = @fopen( $downloads_url . '/.htaccess', 'w' ); // @codingStandardsIgnoreLine
if ( $file_handle ) {
fwrite( $file_handle, 'deny from all' ); // @codingStandardsIgnoreLine
fclose( $file_handle ); // @codingStandardsIgnoreLine
}
}
}

View File

@ -115,7 +115,7 @@ class WC_Admin_Status {
}
// Bulk actions
if ( isset( $_GET['action'] ) && isset( $_GET['log'] ) ) {
if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['log'] ) ) {
self::log_table_bulk_actions();
}
@ -315,9 +315,9 @@ class WC_Admin_Status {
wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
}
$log_ids = array_map( 'absint', (array) $_GET['log'] );
$log_ids = array_map( 'absint', (array) $_REQUEST['log'] );
if ( 'delete' === $_GET['action'] || 'delete' === $_GET['action2'] ) {
if ( 'delete' === $_REQUEST['action'] || 'delete' === $_REQUEST['action2'] ) {
WC_Log_Handler_DB::delete( $log_ids );
wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
exit();

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',
);
}
/**
@ -202,38 +157,29 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
*/
protected function get_views() {
$status_links = array();
$num_posts = wp_count_posts( 'shop_webhook', 'readable' );
$class = '';
$total_posts = array_sum( (array) $num_posts );
$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,100 @@ 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' ),
);
/**
* Generate the table navigation above or below the table.
* Included to remove extra nonce input.
*
* @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
*/
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>';
}
/**
* Extra controls to be displayed between bulk actions and pagination.
* Search box.
*
* @param string $which
* @param string $text Button text.
* @param string $input_id Input ID.
*/
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>';
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 );
// Set the pagination
// Get total items.
$args['limit'] = -1;
$args['offset'] = 0;
$total_items = count( $data_store->search_webhooks( $args ) );
// 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' );
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( esc_html__( 'You do not have permission to update Webhooks', 'woocommerce' ) );
}
$errors = array();
$webhook_id = isset( $_POST['webhook_id'] ) ? absint( $_POST['webhook_id'] ) : 0; // WPCS: input var okay, CSRF ok.
$webhook = new WC_Webhook( $webhook_id );
// 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
/* 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' ) ) );
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 ) );
);
}
/**
* Updated the Webhook status.
*
* @param WC_Webhook $webhook
*/
private function update_status( $webhook ) {
$status = ! empty( $_POST['webhook_status'] ) ? wc_clean( $_POST['webhook_status'] ) : '';
$webhook->set_name( $name );
$webhook->update_status( $status );
if ( ! $webhook->get_user_id() ) {
$webhook->set_user_id( get_current_user_id() );
}
/**
* 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'] : '';
// 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'] ) );
}
break;
switch ( $_POST['webhook_topic'] ) { // WPCS: input var okay, CSRF ok.
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'] ) );
list( $resource, $event ) = explode( '.', sanitize_text_field( wp_unslash( $_POST['webhook_topic'] ) ) ); // WPCS: input var okay, CSRF ok.
break;
}
@ -117,224 +116,91 @@ class WC_Admin_Webhooks {
if ( wc_is_webhook_valid_topic( $topic ) ) {
$webhook->set_topic( $topic );
} else {
$errors[] = __( 'Webhook topic unknown. Please select a valid topic.', 'woocommerce' );
}
}
}
/**
* 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 );
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 ) {
// Run actions.
do_action( 'woocommerce_webhook_options_save', $webhook->get_id() );
if ( $errors ) {
// 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( implode( '|', $errors ) ) ) );
exit();
} elseif ( isset( $_POST['webhook_status'] ) && 'active' === $_POST['webhook_status'] && $webhook->get_pending_delivery() ) { // WPCS: input var okay, CSRF ok.
// Ping the webhook at the first time that is activated.
$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' => 'open',
) );
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 );
}
}
$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 );
$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.
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 ) );
// 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 ) );
}
}
}
/**
* 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.
$webhooks = array_map( 'absint', (array) $_GET['webhook'] );
$action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // WPCS: input var okay, CSRF ok.
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;
if ( 'delete' === $action ) {
$this->bulk_delete( $webhooks );
}
}
/**
* 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 +208,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,18 +229,16 @@ 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' );
include 'settings/views/html-webhooks-edit.php';
return;
}
}
self::table_list_output();
}
@ -388,37 +247,25 @@ 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.
foreach ( explode( '|', sanitize_text_field( wp_unslash( $_GET['error'] ) ) ) as $message ) { // WPCS: input var okay, CSRF ok.
WC_Admin_Settings::add_error( trim( $message ) );
}
}
}
@ -426,12 +273,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,48 +293,28 @@ 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>';
}
}
/**
* Logs output.
*
* @param WC_Webhook $webhook
* @deprecated 3.3.0
* @param WC_Webhook $webhook Deprecated.
*/
public static function logs_output( $webhook ) {
$current = isset( $_GET['log_page'] ) ? absint( $_GET['log_page'] ) : 1;
$args = array(
'post_id' => $webhook->id,
'status' => 'approve',
'type' => 'webhook_delivery',
'number' => 10,
);
if ( 1 < $current ) {
$args['offset'] = ( $current - 1 ) * 10;
}
remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_webhook_comments' ), 10, 1 );
$logs = get_comments( $args );
add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_webhook_comments' ), 10, 1 );
if ( $logs ) {
include_once( dirname( __FILE__ ) . '/settings/views/html-webhook-logs.php' );
} else {
echo '<p>' . __( 'This Webhook has no log yet.', 'woocommerce' ) . '</p>';
}
public static function logs_output( $webhook = 'deprecated' ) {
wc_deprecated_function( 'WC_Admin_Webhooks::logs_output', '3.3' );
}
/**
* Get the webhook topic data.
*
* @param WC_Webhook $webhook
* @param WC_Webhook $webhook Webhook instance.
*
* @return array
*/
@ -500,7 +328,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';
}
}
@ -515,46 +343,12 @@ class WC_Admin_Webhooks {
/**
* Get the logs navigation.
*
* @param int $total
* @param WC_Webhook $webhook
*
* @return string
* @deprecated 3.3.0
* @param int $total Deprecated.
* @param WC_Webhook $webhook Deprecated.
*/
public static function get_logs_navigation( $total, $webhook ) {
$pages = ceil( $total / 10 );
$current = isset( $_GET['log_page'] ) ? absint( $_GET['log_page'] ) : 1;
$html = '<div class="webhook-logs-navigation">';
$html .= '<p class="info" style="float: left;"><strong>';
/* translators: 1: items count (i.e. 8 items) 2: current page 3: total pages */
$html .= sprintf(
__( '%1$s &ndash; Page %2$d of %3$d', 'woocommerce' ),
sprintf( _n( '%d item', '%d items', $total, 'woocommerce' ), $total ),
$current,
$pages
);
$html .= '</strong></p>';
if ( 1 < $pages ) {
$html .= '<p class="tools" style="float: right;">';
if ( 1 == $current ) {
$html .= '<button class="button-primary" disabled="disabled">' . __( '&lsaquo; Previous', 'woocommerce' ) . '</button> ';
} else {
$html .= '<a class="button-primary" href="' . admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->id . '&log_page=' . ( $current - 1 ) ) . '#webhook-logs">' . __( '&lsaquo; Previous', 'woocommerce' ) . '</a> ';
}
if ( $pages == $current ) {
$html .= '<button class="button-primary" disabled="disabled">' . __( 'Next &rsaquo;', 'woocommerce' ) . '</button>';
} else {
$html .= '<a class="button-primary" href="' . admin_url( 'admin.php?page=wc-settings&tab=api&section=webhooks&edit-webhook=' . $webhook->id . '&log_page=' . ( $current + 1 ) ) . '#webhook-logs">' . __( 'Next &rsaquo;', 'woocommerce' ) . '</a>';
}
$html .= '</p>';
}
$html .= '<div class="clear"></div></div>';
return $html;
wc_deprecated_function( 'WC_Admin_Webhooks::get_logs_navigation', '3.3' );
}
}

View File

@ -135,9 +135,23 @@ class WC_Helper_Compat {
if ( is_plugin_active( 'woothemes-updater/woothemes-updater.php' ) ) {
deactivate_plugins( 'woothemes-updater/woothemes-updater.php' );
// Notify the user when the plugin is deactivated.
add_action( 'pre_current_active_plugins', array( __CLASS__, 'plugin_deactivation_notice' ) );
}
}
/**
* Display admin notice directing the user where to go.
*/
public static function plugin_deactivation_notice() {
?>
<div id="message" class="error is-dismissible">
<p><?php printf( __( 'The WooCommerce Helper plugin is no longer needed. <a href="%s">Manage subscriptions</a> from the extensions tab instead.', 'woocommerce' ), esc_url( admin_url( 'admin.php?page=wc-addons&section=helper' ) ) ); ?></p>
</div>
<?php
}
/**
* Register menu item.
*/

View File

@ -55,7 +55,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<td>
<input type="hidden" name="update_existing" value="0" />
<input type="checkbox" id="woocommerce-importer-update-existing" name="update_existing" value="1" />
<label for="woocommerce-importer-update-existing"><?php esc_html_e( 'If a product being imported matches an existing product by ID or SKU, update the existing product rather than creating a new product or skipping the row.', 'woocommerce' ); ?></label>
<label for="woocommerce-importer-update-existing"><?php esc_html_e( 'Existing products that match by ID or SKU will be updated. Products that do not exist will be skipped.', 'woocommerce' ); ?></label>
</td>
</tr>
<tr class="woocommerce-importer-advanced hidden">

View File

@ -13,7 +13,6 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( class_exists( 'WC_Admin_List_Table_Coupons', false ) ) {
new WC_Admin_List_Table_Coupons();
return;
}
@ -233,5 +232,3 @@ class WC_Admin_List_Table_Coupons extends WC_Admin_List_Table {
return $query_vars;
}
}
new WC_Admin_List_Table_Coupons();

View File

@ -13,7 +13,6 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( class_exists( 'WC_Admin_List_Table_Orders', false ) ) {
new WC_Admin_List_Table_Orders();
return;
}
@ -84,6 +83,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
return array(
'shipping_address',
'billing_address',
'wc_actions',
);
}
@ -114,15 +114,12 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$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['billing_address'] = __( 'Billing', 'woocommerce' );
$show_columns['shipping_address'] = __( 'Ship to', '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' );
}
$show_columns['wc_actions'] = __( 'Actions', 'woocommerce' );
wp_enqueue_script( 'wc-orders' );
@ -140,9 +137,9 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
unset( $actions['edit'] );
}
$actions['mark_processing'] = __( 'Mark processing', 'woocommerce' );
$actions['mark_on-hold'] = __( 'Mark on-hold', 'woocommerce' );
$actions['mark_completed'] = __( 'Mark complete', 'woocommerce' );
$actions['mark_processing'] = __( 'Change status to processing', 'woocommerce' );
$actions['mark_on-hold'] = __( 'Change status to on-hold', 'woocommerce' );
$actions['mark_completed'] = __( 'Change status to completed', 'woocommerce' );
return $actions;
}
@ -227,7 +224,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
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' ) ) );
$show_date = $this->object->get_date_created()->date_i18n( apply_filters( 'woocommerce_admin_order_date_format', __( 'M j, Y', 'woocommerce' ) ) );
}
printf(
'<time datetime="%1$s" title="%2$s">%3$s</time>',
@ -250,9 +247,9 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
}
/**
* Render columm: order_actions.
* Render columm: wc_actions.
*/
protected function render_order_actions_column() {
protected function render_wc_actions_column() {
echo '<p>';
do_action( 'woocommerce_admin_order_actions_start', $this->object );
@ -277,9 +274,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$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'] ) );
}
echo wc_render_action_buttons( $actions ); // WPCS: XSS ok.
do_action( 'woocommerce_admin_order_actions_end', $this->object );
@ -292,6 +287,11 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
protected function render_billing_address_column() {
if ( $address = $this->object->get_formatted_billing_address() ) {
echo esc_html( preg_replace( '#<br\s*/?>#i', ', ', $address ) );
if ( $this->object->get_payment_method() ) {
/* translators: %s: payment method */
echo '<span class="description">' . sprintf( __( 'via %s', 'woocommerce' ), esc_html( $this->object->get_payment_method_title() ) ) . '</span>';
}
} else {
echo '&ndash;';
}
@ -303,6 +303,10 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
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>';
if ( $this->object->get_shipping_method() ) {
/* translators: %s: shipping method */
echo '<span class="description">' . sprintf( __( 'via %s', 'woocommerce' ), esc_html( $this->object->get_shipping_method() ) ) . '</span>';
}
} else {
echo '&ndash;';
}
@ -320,6 +324,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
<div class="wc-backbone-modal-content">
<section class="wc-backbone-modal-main" role="main">
<header class="wc-backbone-modal-header">
<mark class="order-status status-{{ data.status }}"><span>{{ data.status_name }}</span></mark>
<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>
@ -328,8 +333,6 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
<article>
<?php do_action( 'woocommerce_admin_order_preview_start' ); ?>
{{{ data.item_html }}}
<div class="wc-order-preview-addresses">
<div class="wc-order-preview-address">
<h2><?php esc_html_e( 'Billing details', 'woocommerce' ); ?></h2>
@ -347,7 +350,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
<# if ( data.payment_via ) { #>
<strong><?php esc_html_e( 'Payment via', 'woocommerce' ); ?></strong>
{{ data.payment_via }}
{{{ data.payment_via }}}
<# } #>
</div>
<# if ( data.needs_shipping ) { #>
@ -371,10 +374,15 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
</div>
<# } #>
</div>
{{{ data.item_html }}}
<?php do_action( 'woocommerce_admin_order_preview_end' ); ?>
</article>
<footer>
<div class="inner">
{{{ data.actions_html }}}
<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>
@ -386,6 +394,191 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
<?php
}
/**
* Get items to display in the preview as HTML.
*
* @param WC_Order $order Order object.
* @return string
*/
public static function get_order_preview_item_html( $order ) {
$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',
) );
$line_items = apply_filters( 'woocommerce_admin_order_preview_line_items', $order->get_items(), $order );
$columns = apply_filters( 'woocommerce_admin_order_preview_line_item_columns', array(
'product' => __( 'Product', 'woocommerce' ),
'quantity' => __( 'Quantity', 'woocommerce' ),
'tax' => __( 'Tax', 'woocommerce' ),
'total' => __( 'Total', 'woocommerce' ),
), $order );
if ( ! wc_tax_enabled() ) {
unset( $columns['tax'] );
}
$html = '
<div class="wc-order-preview-table-wrapper">
<table cellspacing="0" class="wc-order-preview-table">
<thead>
<tr>';
foreach ( $columns as $column => $label ) {
$html .= '<th class="wc-order-preview-table__column--' . esc_attr( $column ) . '">' . esc_html( $label ) . '</th>';
}
$html .= '
</tr>
</thead>
<tbody>';
foreach ( $line_items as $item_id => $item ) {
$product_object = is_callable( array( $item, 'get_product' ) ) ? $item->get_product() : null;
$html .= '<tr class="wc-order-preview-table__item wc-order-preview-table__item--' . esc_attr( $item_id ) . '">';
foreach ( $columns as $column => $label ) {
$html .= '<td class="wc-order-preview-table__column--' . esc_attr( $column ) . '">';
switch ( $column ) {
case 'product':
$html .= wp_kses_post( $item->get_name() );
if ( $product_object ) {
$html .= '<div class="wc-order-item-sku">' . esc_html( $product_object->get_sku() ) . '</div>';
}
if ( $meta_data = $item->get_formatted_meta_data( '' ) ) {
$html .= '<table cellspacing="0" class="wc-order-item-meta">';
foreach ( $meta_data as $meta_id => $meta ) {
if ( in_array( $meta->key, $hidden_order_itemmeta ) ) {
continue;
}
$html .= '<tr><th>' . wp_kses_post( $meta->display_key ) . ':</th><td>' . wp_kses_post( force_balance_tags( $meta->display_value ) ) . '</td></tr>';
}
$html .= '</table>';
}
break;
case 'quantity':
$html .= esc_html( $item->get_quantity() );
break;
case 'tax':
$html .= wc_price( $item->get_total_tax(), array( 'currency' => $order->get_currency() ) );
break;
case 'total':
$html .= wc_price( $item->get_total(), array( 'currency' => $order->get_currency() ) );
break;
default :
$html .= apply_filters( 'woocommerce_admin_order_preview_line_item_column_' . sanitize_key( $column ), '', $item, $item_id, $order );
break;
}
$html .= '</td>';
}
$html .= '</tr>';
}
$html .= '
</tbody>
</table>
</div>';
return $html;
}
/**
* Get actions to display in the preview as HTML.
*
* @param WC_Order $order Order object.
* @return string
*/
public static function get_order_preview_actions_html( $order ) {
$actions = array();
$status_actions = array();
if ( $order->has_status( array( 'pending' ) ) ) {
$status_actions['on-hold'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=on-hold&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'On-hold', 'woocommerce' ),
'action' => 'on-hold',
);
}
if ( $order->has_status( array( 'pending', 'on-hold' ) ) ) {
$status_actions['processing'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=processing&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Processing', 'woocommerce' ),
'action' => 'processing',
);
}
if ( $order->has_status( array( 'pending', 'on-hold', 'processing' ) ) ) {
$status_actions['complete'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=completed&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Completed', 'woocommerce' ),
'action' => 'complete',
);
}
if ( $status_actions ) {
$actions['status'] = array(
'group' => __( 'Change status: ', 'woocommerce' ),
'actions' => $status_actions,
);
}
return wc_render_action_buttons( apply_filters( 'woocommerce_admin_order_preview_actions', $actions, $order ) );
}
/**
* Get order details to send to the ajax endpoint for previews.
*
* @param WC_Order $order Order object.
* @return array
*/
public static function order_preview_get_order_details( $order ) {
if ( ! $order ) {
return array();
}
$payment_via = $order->get_payment_method_title();
$payment_method = $order->get_payment_method();
$payment_gateways = WC()->payment_gateways() ? WC()->payment_gateways->payment_gateways() : array();
if ( $transaction_id = $order->get_transaction_id() ) {
if ( isset( $payment_gateways[ $payment_method ] ) && ( $url = $payment_gateways[ $payment_method ]->get_transaction_url( $order ) ) ) {
$payment_via .= ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)';
} else {
$payment_via .= ' (' . esc_html( $transaction_id ) . ')';
}
}
return apply_filters( 'woocommerce_admin_order_preview_get_order_details', array(
'data' => $order->get_data(),
'order_number' => $order->get_order_number(),
'item_html' => WC_Admin_List_Table_Orders::get_order_preview_item_html( $order ),
'actions_html' => WC_Admin_List_Table_Orders::get_order_preview_actions_html( $order ),
'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' => $payment_via,
'shipping_via' => $order->get_shipping_method(),
'status' => $order->get_status(),
'status_name' => wc_get_order_status_name( $order->get_status() ),
), $order );
}
/**
* Handle bulk actions.
*
@ -610,5 +803,3 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
}
}
}
new WC_Admin_List_Table_Orders();

View File

@ -13,7 +13,6 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( class_exists( 'WC_Admin_List_Table_Products', false ) ) {
new WC_Admin_List_Table_Products();
return;
}
@ -233,7 +232,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
$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.
echo apply_filters( 'woocommerce_admin_product_term_list', implode( ', ', $termlist ), 'product_cat', $this->object->get_id(), $termlist, $terms ); // WPCS: XSS ok.
}
}
@ -249,7 +248,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
$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.
echo apply_filters( 'woocommerce_admin_product_term_list', implode( ', ', $termlist ), 'product_tag', $this->object->get_id(), $termlist, $terms ); // WPCS: XSS ok.
}
}
@ -271,7 +270,9 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
* Render columm: is_in_stock.
*/
protected function render_is_in_stock_column() {
if ( $this->object->is_in_stock() ) {
if ( $this->object->is_on_backorder() ) {
$stock_html = '<mark class="onbackorder">' . __( 'On backorder', 'woocommerce' ) . '</mark>';
} elseif ( $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>';
@ -299,7 +300,6 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
* Render any custom filters and search inputs for the list table.
*/
protected function render_filters() {
// Category Filtering.
$categories_count = (int) wp_count_terms( 'product_cat' );
if ( $categories_count <= apply_filters( 'woocommerce_product_category_filter_threshold', 100 ) ) {
@ -318,7 +318,6 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
<?php
}
// Product type filtering.
$current_product_type = isset( $_REQUEST['product_type'] ) ? wc_clean( wp_unslash( $_REQUEST['product_type'] ) ) : false; // WPCS: input var ok, sanitization ok.
$terms = get_terms( 'product_type' );
$output = '<select name="product_type" id="dropdown_product_type"><option value="">' . __( 'Filter by product type', 'woocommerce' ) . '</option>';
@ -369,6 +368,16 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
$output .= '</select>';
$current_stock_status = isset( $_REQUEST['stock_status'] ) ? wc_clean( wp_unslash( $_REQUEST['stock_status'] ) ): false; // WPCS: input var ok, sanitization ok.
$stock_statuses = wc_get_product_stock_status_options();
$output .= '<select name="stock_status"><option value="">' . esc_html__( 'Filter by stock status', 'woocommerce' ) . '</option>';
foreach ( $stock_statuses as $status => $label ) {
$output .= '<option ' . selected( $status, $current_stock_status, false ) . ' value="' . esc_attr( $status ) . '">' . esc_html( $label ) . '</option>';
}
$output .= '</select>';
echo apply_filters( 'woocommerce_product_filters', $output ); // WPCS: XSS ok.
}
@ -379,6 +388,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
* @return array
*/
protected function query_filters( $query_vars ) {
if ( isset( $query_vars['orderby'] ) ) {
if ( 'price' === $vars['orderby'] ) {
// @codingStandardsIgnoreStart
@ -421,6 +431,17 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
);
}
if ( ! empty( $_GET['stock_status'] ) ) {
if ( ! isset( $query_vars['meta_query'] ) ) {
$query_vars['meta_query'] = array();
}
$query_vars['meta_query'][] = array(
'key' => '_stock_status',
'value' => wc_clean( wp_unslash( $_GET['stock_status'] ) ),
);
}
return $query_vars;
}
@ -485,5 +506,3 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
return $views;
}
}
new WC_Admin_List_Table_Products();

View File

@ -188,9 +188,9 @@ class WC_Meta_Box_Order_Data {
if ( $transaction_id = $order->get_transaction_id() ) {
if ( isset( $payment_gateways[ $payment_method ] ) && ( $url = $payment_gateways[ $payment_method ]->get_transaction_url( $order ) ) ) {
$payment_method_string = ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)';
$payment_method_string .= ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)';
} else {
$payment_method_string = ' (' . esc_html( $transaction_id ) . ')';
$payment_method_string .= ' (' . esc_html( $transaction_id ) . ')';
}
}

View File

@ -11,8 +11,9 @@ if ( ! defined( 'ABSPATH' ) ) {
$product = $item->get_product();
$product_link = $product ? admin_url( 'post.php?post=' . $item->get_product_id() . '&action=edit' ) : '';
$thumbnail = $product ? apply_filters( 'woocommerce_admin_order_item_thumbnail', $product->get_image( 'thumbnail', array( 'title' => '' ), false ), $item_id, $item ) : '';
$row_class = apply_filters( 'woocommerce_admin_html_order_item_class', ! empty( $class ) ? $class : '', $item, $order );
?>
<tr class="item <?php echo esc_attr( apply_filters( 'woocommerce_admin_html_order_item_class', ( ! empty( $class ) ? $class : '' ), $item, $order ) ); ?>" data-order_item_id="<?php echo esc_attr( $item_id ); ?>">
<tr class="item <?php echo esc_attr( $row_class ); ?>" data-order_item_id="<?php echo esc_attr( $item_id ); ?>">
<td class="thumb">
<?php echo '<div class="wc-order-item-thumbnail">' . wp_kses_post( $thumbnail ) . '</div>'; ?>
</td>

View File

@ -65,7 +65,7 @@ if ( ! defined( 'ABSPATH' ) ) {
woocommerce_wp_select( array(
'id' => '_stock_status',
'value' => $product_object->get_stock_status( 'edit' ),
'wrapper_class' => 'hide_if_variable hide_if_external',
'wrapper_class' => 'stock_status_field hide_if_variable hide_if_external',
'label' => __( 'Stock status', 'woocommerce' ),
'options' => wc_get_product_stock_status_options(),
'desc_tip' => true,

View File

@ -1,4 +1,10 @@
<?php
/**
* Product data variations
*
* @package WooCommerce\Admin\Metaboxes\Views
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
@ -9,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php if ( ! count( $variation_attributes ) ) : ?>
<div id="message" class="inline notice woocommerce-message">
<p><?php esc_html_e( 'Before you can add a variation you need to add some variation attributes on the <strong>Attributes</strong> tab.', 'woocommerce' ); ?></p>
<p><?php echo wp_kses_post( __( 'Before you can add a variation you need to add some variation attributes on the <strong>Attributes</strong> tab.', 'woocommerce' ) ); ?></p>
<p><a class="button-primary" href="<?php echo esc_url( apply_filters( 'woocommerce_docs_url', 'https://docs.woocommerce.com/document/variable-product/', 'product-variations' ) ); ?>" target="_blank"><?php esc_html_e( 'Learn more', 'woocommerce' ); ?></a></p>
</div>
@ -22,9 +28,9 @@ if ( ! defined( 'ABSPATH' ) ) {
foreach ( $variation_attributes as $attribute ) {
$selected_value = isset( $default_attributes[ sanitize_title( $attribute->get_name() ) ] ) ? $default_attributes[ sanitize_title( $attribute->get_name() ) ] : '';
?>
<select name="default_attribute_<?php echo sanitize_title( $attribute->get_name() ); ?>" data-current="<?php echo esc_attr( $selected_value ); ?>">
<select name="default_attribute_<?php echo esc_attr( sanitize_title( $attribute->get_name() ) ); ?>" data-current="<?php echo esc_attr( $selected_value ); ?>">
<?php /* translators: WooCommerce attribute label */ ?>
<option value=""><?php printf( esc_html__( 'No default %s&hellip;', 'woocommerce' ), wc_attribute_label( $attribute->get_name() ) ); ?></option>
<option value=""><?php esc_html( sprintf( __( 'No default %s&hellip;', 'woocommerce' ), wc_attribute_label( $attribute->get_name() ) ) ); ?></option>
<?php if ( $attribute->is_taxonomy() ) : ?>
<?php foreach ( $attribute->get_terms() as $option ) : ?>
<option <?php selected( $selected_value, $option->slug ); ?> value="<?php echo esc_attr( $option->slug ); ?>"><?php echo esc_html( apply_filters( 'woocommerce_variation_option_name', $option->name ) ); ?></option>
@ -66,6 +72,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<option value="variable_stock"><?php esc_html_e( 'Stock', 'woocommerce' ); ?></option>
<option value="variable_stock_status_instock"><?php esc_html_e( 'Set Status - In stock', 'woocommerce' ); ?></option>
<option value="variable_stock_status_outofstock"><?php esc_html_e( 'Set Status - Out of stock', 'woocommerce' ); ?></option>
<option value="variable_stock_status_onbackorder"><?php esc_html_e( 'Set Status - On backorder', 'woocommerce' ); ?></option>
</optgroup>
<optgroup label="<?php esc_attr_e( 'Shipping', 'woocommerce' ); ?>">
<option value="variable_length"><?php esc_html_e( 'Length', 'woocommerce' ); ?></option>
@ -83,7 +90,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="variations-pagenav">
<?php /* translators: variations count */ ?>
<span class="displaying-num"><?php printf( esc_html( _n( '%s item', '%s items', $variations_count, 'woocommerce' ), $variations_count ) ); ?></span>
<span class="displaying-num"><?php echo esc_html( sprintf( _n( '%s item', '%s items', $variations_count, 'woocommerce' ), $variations_count ) ); ?></span>
<span class="expand-close">
(<a href="#" class="expand_all"><?php esc_html_e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php esc_html_e( 'Close', 'woocommerce' ); ?></a>)
</span>
@ -94,10 +101,10 @@ if ( ! defined( 'ABSPATH' ) ) {
<label for="current-page-selector-1" class="screen-reader-text"><?php esc_html_e( 'Select Page', 'woocommerce' ); ?></label>
<select class="page-selector" id="current-page-selector-1" title="<?php esc_attr_e( 'Current page', 'woocommerce' ); ?>">
<?php for ( $i = 1; $i <= $variations_total_pages; $i++ ) : ?>
<option value="<?php echo $i; ?>"><?php echo $i; ?></option>
<option value="<?php echo $i; // WPCS: XSS ok. ?>"><?php echo $i; // WPCS: XSS ok. ?></option>
<?php endfor; ?>
</select>
<?php _ex( 'of', 'number of pages', 'woocommerce' ); ?> <span class="total-pages"><?php echo esc_html( $variations_total_pages ); ?></span>
<?php echo esc_html_x( 'of', 'number of pages', 'woocommerce' ); ?> <span class="total-pages"><?php echo esc_html( $variations_total_pages ); ?></span>
</span>
<a class="next-page" title="<?php esc_attr_e( 'Go to the next page', 'woocommerce' ); ?>" href="#">&rsaquo;</a>
<a class="last-page" title="<?php esc_attr_e( 'Go to the last page', 'woocommerce' ); ?>" href="#">&raquo;</a>
@ -106,10 +113,12 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="clear"></div>
</div>
<div class="woocommerce_variations wc-metaboxes" data-attributes="<?php
// esc_attr does not double encode - htmlspecialchars does
echo htmlspecialchars( wp_json_encode( wc_list_pluck( $variation_attributes, 'get_data' ) ) );
?>" data-total="<?php echo esc_attr( $variations_count ); ?>" data-total_pages="<?php echo esc_attr( $variations_total_pages ); ?>" data-page="1" data-edited="false">
<?php
// esc_attr does not double encode - htmlspecialchars does.
$attributes_data = htmlspecialchars( wp_json_encode( wc_list_pluck( $variation_attributes, 'get_data' ) ) );
?>
<div class="woocommerce_variations wc-metaboxes" data-attributes="<?php echo $attributes_data; // WPCS: XSS ok. ?>" data-total="<?php echo esc_attr( $variations_count ); ?>" data-total_pages="<?php echo esc_attr( $variations_total_pages ); ?>" data-page="1" data-edited="false">
</div>
<div class="toolbar">
@ -118,7 +127,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="variations-pagenav">
<?php /* translators: variations count*/ ?>
<span class="displaying-num"><?php printf( _n( '%s item', '%s items', $variations_count, 'woocommerce' ), $variations_count ); ?></span>
<span class="displaying-num"><?php echo esc_html( sprintf( _n( '%s item', '%s items', $variations_count, 'woocommerce' ), $variations_count ) ); ?></span>
<span class="expand-close">
(<a href="#" class="expand_all"><?php esc_html_e( 'Expand', 'woocommerce' ); ?></a> / <a href="#" class="close_all"><?php esc_html_e( 'Close', 'woocommerce' ); ?></a>)
</span>
@ -129,10 +138,10 @@ if ( ! defined( 'ABSPATH' ) ) {
<label for="current-page-selector-1" class="screen-reader-text"><?php esc_html_e( 'Select Page', 'woocommerce' ); ?></label>
<select class="page-selector" id="current-page-selector-1" title="<?php esc_attr_e( 'Current page', 'woocommerce' ); ?>">
<?php for ( $i = 1; $i <= $variations_total_pages; $i++ ) : ?>
<option value="<?php echo $i; ?>"><?php echo $i; ?></option>
<option value="<?php echo $i; // WPCS: XSS ok. ?>"><?php echo $i; // WPCS: XSS ok. ?></option>
<?php endfor; ?>
</select>
<?php _ex( 'of', 'number of pages', 'woocommerce' ); ?> <span class="total-pages"><?php echo $variations_total_pages; ?></span>
<?php echo esc_html_x( 'of', 'number of pages', 'woocommerce' ); ?> <span class="total-pages"><?php echo esc_html( $variations_total_pages ); ?></span>
</span>
<a class="next-page" title="<?php esc_attr_e( 'Go to the next page', 'woocommerce' ); ?>" href="#">&rsaquo;</a>
<a class="last-page" title="<?php esc_attr_e( 'Go to the last page', 'woocommerce' ); ?>" href="#">&raquo;</a>

View File

@ -138,7 +138,7 @@ class WC_Report_Customer_List extends WP_List_Table {
break;
case 'user_actions' :
case 'wc_actions' :
ob_start();
?><p>
<?php
@ -210,7 +210,7 @@ class WC_Report_Customer_List extends WP_List_Table {
'orders' => __( 'Orders', 'woocommerce' ),
'spent' => __( 'Money spent', 'woocommerce' ),
'last_order' => __( 'Last order', 'woocommerce' ),
'user_actions' => __( 'Actions', 'woocommerce' ),
'wc_actions' => __( 'Actions', 'woocommerce' ),
);
return $columns;

View File

@ -108,7 +108,9 @@ class WC_Report_Stock extends WP_List_Table {
break;
case 'stock_status' :
if ( $product->is_in_stock() ) {
if ( $product->is_on_backorder() ) {
$stock_html = '<mark class="onbackorder">' . __( 'On backorder', 'woocommerce' ) . '</mark>';
} elseif ( $product->is_in_stock() ) {
$stock_html = '<mark class="instock">' . __( 'In stock', 'woocommerce' ) . '</mark>';
} else {
$stock_html = '<mark class="outofstock">' . __( 'Out of stock', 'woocommerce' ) . '</mark>';

View File

@ -183,24 +183,6 @@ class WC_Settings_General extends WC_Settings_Page {
'type' => 'checkbox',
),
array(
'title' => __( 'Store notice', 'woocommerce' ),
'desc' => __( 'Enable site-wide store notice text', 'woocommerce' ),
'id' => 'woocommerce_demo_store',
'default' => 'no',
'type' => 'checkbox',
),
array(
'title' => __( 'Store notice text', 'woocommerce' ),
'desc' => '',
'id' => 'woocommerce_demo_store_notice',
'default' => __( 'This is a demo store for testing purposes &mdash; no orders shall be fulfilled.', 'woocommerce' ),
'type' => 'textarea',
'css' => 'width:350px; height: 65px;',
'autoload' => false,
),
array( 'type' => 'sectionend', 'id' => 'general_options' ),
array( 'title' => __( 'Currency options', 'woocommerce' ), 'type' => 'title', 'desc' => __( 'The following options affect how prices are displayed on the frontend.', 'woocommerce' ), 'id' => 'pricing_options' ),

View File

@ -39,7 +39,6 @@ class WC_Settings_Products extends WC_Settings_Page {
public function get_sections() {
$sections = array(
'' => __( 'General', 'woocommerce' ),
'display' => __( 'Display', 'woocommerce' ),
'inventory' => __( 'Inventory', 'woocommerce' ),
'downloadable' => __( 'Downloadable products', 'woocommerce' ),
);
@ -75,155 +74,7 @@ class WC_Settings_Products extends WC_Settings_Page {
* @return array
*/
public function get_settings( $current_section = '' ) {
if ( 'display' === $current_section ) {
$settings = array(
array(
'title' => __( 'Shop &amp; product pages', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'catalog_options',
),
array(
'title' => __( 'Shop page', 'woocommerce' ),
'desc' => '<br/>' . sprintf( __( 'The base page can also be used in your <a href="%s">product permalinks</a>.', 'woocommerce' ), admin_url( 'options-permalink.php' ) ),
'id' => 'woocommerce_shop_page_id',
'type' => 'single_select_page',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'desc_tip' => __( 'This sets the base page of your shop - this is where your product archive will be.', 'woocommerce' ),
),
array(
'title' => __( 'Shop page display', 'woocommerce' ),
'desc' => __( 'This controls what is shown on the product archive.', 'woocommerce' ),
'id' => 'woocommerce_shop_page_display',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => '',
'type' => 'select',
'options' => array(
'' => __( 'Show products', 'woocommerce' ),
'subcategories' => __( 'Show categories', 'woocommerce' ),
'both' => __( 'Show categories &amp; products', 'woocommerce' ),
),
'desc_tip' => true,
),
array(
'title' => __( 'Default category display', 'woocommerce' ),
'desc' => __( 'This controls what is shown on category archives.', 'woocommerce' ),
'id' => 'woocommerce_category_archive_display',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => '',
'type' => 'select',
'options' => array(
'' => __( 'Show products', 'woocommerce' ),
'subcategories' => __( 'Show subcategories', 'woocommerce' ),
'both' => __( 'Show subcategories &amp; products', 'woocommerce' ),
),
'desc_tip' => true,
),
array(
'title' => __( 'Default product sorting', 'woocommerce' ),
'desc' => __( 'This controls the default sort order of the catalog.', 'woocommerce' ),
'id' => 'woocommerce_default_catalog_orderby',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => 'menu_order',
'type' => 'select',
'options' => apply_filters( 'woocommerce_default_catalog_orderby_options', array(
'menu_order' => __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
'rating' => __( 'Average rating', 'woocommerce' ),
'date' => __( 'Sort by most recent', 'woocommerce' ),
'price' => __( 'Sort by price (asc)', 'woocommerce' ),
'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
) ),
'desc_tip' => true,
),
array(
'title' => __( 'Add to cart behaviour', 'woocommerce' ),
'desc' => __( 'Redirect to the cart page after successful addition', 'woocommerce' ),
'id' => 'woocommerce_cart_redirect_after_add',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'start',
),
array(
'desc' => __( 'Enable AJAX add to cart buttons on archives', 'woocommerce' ),
'id' => 'woocommerce_enable_ajax_add_to_cart',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'end',
),
array(
'type' => 'sectionend',
'id' => 'catalog_options',
),
);
$theme_support = get_theme_support( 'woocommerce' );
$theme_support = is_array( $theme_support ) ? $theme_support[0]: false;
$image_settings = array(
array(
'title' => __( 'Product images', 'woocommerce' ),
'type' => 'title',
'desc' => __( 'These settings change how product images are displayed in your catalog.', 'woocommerce' ),
'id' => 'image_options',
),
'single_image_width' => array(
'title' => __( 'Main image width', 'woocommerce' ),
'desc' => __( 'This is the width used by the main image on single product pages. These images will be uncropped.', 'woocommerce' ),
'id' => 'woocommerce_single_image_width',
'css' => '',
'type' => 'text',
'custom_attributes' => array(
'size' => 3,
),
'suffix' => 'px',
'default' => 600,
'desc_tip' => true,
),
'thumbnail_image_width' => array(
'title' => __( 'Thumbnail width', 'woocommerce' ),
'desc' => __( 'This size is used for product archives and product listings.', 'woocommerce' ),
'id' => 'woocommerce_thumbnail_image_width',
'css' => '',
'type' => 'text',
'custom_attributes' => array(
'size' => 3,
),
'suffix' => 'px',
'default' => 300,
'desc_tip' => true,
),
array(
'title' => __( 'Thumbnail cropping', 'woocommerce' ),
'desc' => __( 'This determines how thumbnails appear. Widths will be fixed, whilst heights may vary.', 'woocommerce' ),
'id' => 'woocommerce_thumbnail_cropping',
'css' => '',
'type' => 'thumbnail_cropping',
'default' => '1:1',
'desc_tip' => false,
),
array(
'type' => 'sectionend',
'id' => 'image_options',
),
);
if ( isset( $theme_support['single_image_width'] ) ) {
unset( $image_settings['single_image_width'] );
}
if ( isset( $theme_support['thumbnail_image_width'] ) ) {
unset( $image_settings['thumbnail_image_width'] );
}
$settings = apply_filters( 'woocommerce_product_settings', array_merge( $settings, $image_settings ) );
} elseif ( 'inventory' === $current_section ) {
if ( 'inventory' === $current_section ) {
$settings = apply_filters( 'woocommerce_inventory_settings', array(
array(
@ -411,7 +262,91 @@ class WC_Settings_Products extends WC_Settings_Page {
));
} else {
$settings = apply_filters( 'woocommerce_products_general_settings', array(
$settings = apply_filters( 'woocommerce_product_settings', apply_filters( 'woocommerce_products_general_settings', array(
array(
'title' => __( 'Shop pages', 'woocommerce' ),
'type' => 'title',
'desc' => '',
'id' => 'catalog_options',
),
array(
'title' => __( 'Shop page', 'woocommerce' ),
'desc' => '<br/>' . sprintf( __( 'The base page can also be used in your <a href="%s">product permalinks</a>.', 'woocommerce' ), admin_url( 'options-permalink.php' ) ),
'id' => 'woocommerce_shop_page_id',
'type' => 'single_select_page',
'default' => '',
'class' => 'wc-enhanced-select-nostd',
'css' => 'min-width:300px;',
'desc_tip' => __( 'This sets the base page of your shop - this is where your product archive will be.', 'woocommerce' ),
),
array(
'title' => __( 'Shop page display', 'woocommerce' ),
'desc' => __( 'This controls what is shown on the product archive.', 'woocommerce' ),
'id' => 'woocommerce_shop_page_display',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => '',
'type' => 'select',
'options' => array(
'' => __( 'Show products', 'woocommerce' ),
'subcategories' => __( 'Show categories', 'woocommerce' ),
'both' => __( 'Show categories &amp; products', 'woocommerce' ),
),
'desc_tip' => true,
),
array(
'title' => __( 'Default category display', 'woocommerce' ),
'desc' => __( 'This controls what is shown on category archives.', 'woocommerce' ),
'id' => 'woocommerce_category_archive_display',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => '',
'type' => 'select',
'options' => array(
'' => __( 'Show products', 'woocommerce' ),
'subcategories' => __( 'Show subcategories', 'woocommerce' ),
'both' => __( 'Show subcategories &amp; products', 'woocommerce' ),
),
'desc_tip' => true,
),
array(
'title' => __( 'Default product sorting', 'woocommerce' ),
'desc' => __( 'This controls the default sort order of the catalog.', 'woocommerce' ),
'id' => 'woocommerce_default_catalog_orderby',
'class' => 'wc-enhanced-select',
'css' => 'min-width:300px;',
'default' => 'menu_order',
'type' => 'select',
'options' => apply_filters( 'woocommerce_default_catalog_orderby_options', array(
'menu_order' => __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
'rating' => __( 'Average rating', 'woocommerce' ),
'date' => __( 'Sort by most recent', 'woocommerce' ),
'price' => __( 'Sort by price (asc)', 'woocommerce' ),
'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
) ),
'desc_tip' => true,
),
array(
'title' => __( 'Add to cart behaviour', 'woocommerce' ),
'desc' => __( 'Redirect to the cart page after successful addition', 'woocommerce' ),
'id' => 'woocommerce_cart_redirect_after_add',
'default' => 'no',
'type' => 'checkbox',
'checkboxgroup' => 'start',
),
array(
'desc' => __( 'Enable AJAX add to cart buttons on archives', 'woocommerce' ),
'id' => 'woocommerce_enable_ajax_add_to_cart',
'default' => 'yes',
'type' => 'checkbox',
'checkboxgroup' => 'end',
),
array(
'type' => 'sectionend',
'id' => 'catalog_options',
),
array(
'title' => __( 'Measurements', 'woocommerce' ),
'type' => 'title',
@ -520,7 +455,7 @@ class WC_Settings_Products extends WC_Settings_Page {
'id' => 'product_rating_options',
),
));
) ) );
}
return apply_filters( 'woocommerce_get_settings_' . $this->id, $settings, $current_section );

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,38 +0,0 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<tr>
<td><?php echo date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $log['comment']->comment_date_gmt ), true ); ?></td>
<td><?php echo esc_attr( $log['request_url'] ); ?></td>
<td>
<p><strong><?php _e( 'Method', 'woocommerce' ); ?>: </strong><?php echo esc_html( $log['request_method'] ); ?></p>
<p><strong><?php _e( 'Duration', 'woocommerce' ); ?>: </strong><?php echo esc_html( $log['duration'] ); ?></p>
<p><strong><?php _e( 'Headers', 'woocommerce' ); ?>:</strong></p>
<ul>
<?php foreach ( (array) $log['request_headers'] as $key => $value ) : ?>
<li><strong><em><?php echo strtolower( esc_html( $key ) ); ?>: </em></strong><code><?php echo esc_html( $value ); ?></code></li>
<?php endforeach ?>
</ul>
<p><strong><?php _e( 'Content', 'woocommerce' ); ?>: </strong></p>
<pre><code><?php echo esc_html( $log['request_body'] ); ?></code></pre>
</td>
<td>
<p><strong><?php _e( 'Status', 'woocommerce' ); ?>: </strong><?php echo esc_html( $log['summary'] ); ?></p>
<p><strong><?php _e( 'Headers', 'woocommerce' ); ?>:</strong></p>
<ul>
<?php $response_headers = is_callable( array( $log['response_headers'], 'getAll' ) ) ? $log['response_headers']->getAll() : $log['response_headers']; ?>
<?php foreach ( (array) $response_headers as $key => $value ) : ?>
<li><strong><em><?php echo strtolower( esc_html( $key ) ); ?>: </em></strong><code><?php echo esc_html( $value ); ?></code></li>
<?php endforeach ?>
</ul>
<?php if ( ! empty( $log['response_body'] ) ) : ?>
<h4><?php _e( 'Content', 'woocommerce' ); ?>:</h4>
<p><?php echo esc_html( $log['response_body'] ); ?></p>
<?php endif; ?>
</td>
</tr>

View File

@ -1,42 +0,0 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$count_comments = wp_count_comments( $webhook->id );
$total = $count_comments->approved;
?>
<?php echo WC_Admin_Webhooks::get_logs_navigation( $total, $webhook ); ?>
<table id="webhook-logs-table" class="widefat">
<thead>
<tr>
<th><?php _e( 'Date', 'woocommerce' ); ?></th>
<th><?php _e( 'URL', 'woocommerce' ); ?></th>
<th><?php _e( 'Request', 'woocommerce' ); ?></th>
<th><?php _e( 'Response', 'woocommerce' ); ?></th>
</tr>
</thead>
<tfoot>
<tr>
<th><?php _e( 'Date', 'woocommerce' ); ?></th>
<th><?php _e( 'URL', 'woocommerce' ); ?></th>
<th><?php _e( 'Request', 'woocommerce' ); ?></th>
<th><?php _e( 'Response', 'woocommerce' ); ?></th>
</tr>
</tfoot>
<tbody>
<?php
foreach ( $logs as $log ) {
$log = $webhook->get_delivery_log( $log->comment_ID );
include( 'html-webhook-log.php' );
}
?>
</tbody>
</table>
<?php echo WC_Admin_Webhooks::get_logs_navigation( $total, $webhook ); ?>

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">
@ -74,10 +74,10 @@ if ( ! defined( 'ABSPATH' ) ) {
'product.deleted' => __( 'Product deleted', 'woocommerce' ),
'product.restored' => __( 'Product restored', 'woocommerce' ),
'action' => __( 'Action', 'woocommerce' ),
'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,25 +86,16 @@ 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'] ); ?>" />
</td>
</tr>
<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 ?>
</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() ); ?>" />
</td>
</tr>
<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 +104,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 +113,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 +133,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 +149,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 +157,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 +165,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,26 +181,16 @@ 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() {
var current = $( this ).val(),
action_event_field = $( '#webhook-options' ).find( '#webhook-action-event-wrap' ),
custom_topic_field = $( '#webhook-options' ).find( '#webhook-custom-topic-wrap' );
action_event_field = $( '#webhook-options' ).find( '#webhook-action-event-wrap' );
action_event_field.hide();
custom_topic_field.hide();
if ( 'action' === current ) {
action_event_field.show();
} else if ( 'custom' === current ) {
custom_topic_field.show();
}
}).change();
});

View File

@ -25,19 +25,44 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php if ( $sections ) : ?>
<ul class="subsubsub">
<?php foreach ( $sections as $section_id => $section ) : ?>
<li><a class="<?php echo $current_section === $section_id ? 'current' : ''; ?>" href="<?php echo admin_url( 'admin.php?page=wc-addons&section=' . esc_attr( $section_id ) ); ?>"><?php echo esc_html( $section->title ); ?></a><?php echo ( end( $section_keys ) !== $section_id ) ? ' |' : ''; ?></li>
<?php foreach ( $sections as $section ) : ?>
<li>
<a
class="<?php echo $current_section === $section->slug ? 'current' : ''; ?>"
href="<?php echo admin_url( 'admin.php?page=wc-addons&section=' . esc_attr( $section->slug ) ); ?>">
<?php echo esc_html( $section->label ); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<br class="clear" />
<?php if ( 'featured' === $current_section ) : ?>
<?php if ( isset( $_GET['search'] ) ) : ?>
<h1 class="search-form-title" >
<?php printf( __( 'Showing search results for: %s', 'woocommerce' ), '<strong>' . esc_html( $_GET['search'] ) . '</strong>' ); ?>
</h1>
<?php endif; ?>
<form class="search-form" method="GET">
<button type="submit">
<span class="dashicons dashicons-search"></span>
</button>
<input
type="text"
name="search"
value="<?php echo esc_attr( isset( $_GET['search'] ) ? $_GET['search'] : '' ); ?>"
placeholder="<?php _e( 'Enter a search term and press enter', 'woocommerce' ); ?>">
<input type="hidden" name="page" value="wc-addons">
<?php $page_section = ( isset( $_GET['section'] ) && '_featured' !== $_GET['section'] ) ? $_GET['section'] : '_all'; ?>
<input type="hidden" name="section" value="<?php echo esc_attr( $page_section ); ?>">
</form>
<?php if ( '_featured' === $current_section ) : ?>
<div class="addons-featured">
<?php
$featured = WC_Admin_Addons::get_featured();
?>
</div>
<?php endif; ?>
<?php if ( 'featured' !== $current_section && $addons = WC_Admin_Addons::get_section_data( $current_section ) ) : ?>
<?php if ( '_featured' !== $current_section && $addons ) : ?>
<?php if ( 'shipping_methods' === $current_section ) : ?>
<div class="addons-shipping-methods">
<?php WC_Admin_Addons::output_wcs_banner_block(); ?>
@ -67,7 +92,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<li class="product">
<a href="<?php echo esc_attr( $addon->link ); ?>">
<?php if ( ! empty( $addon->image ) ) : ?>
<img src="<?php echo esc_attr( $addon->image ); ?>"/>
<img src="<?php echo esc_url( $addon->image ); ?>"/>
<?php else : ?>
<h2><?php echo esc_html( $addon->title ); ?></h2>
<?php endif; ?>
@ -82,7 +107,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<p><?php printf( __( 'Our catalog of WooCommerce Extensions can be found on WooCommerce.com here: <a href="%s">WooCommerce Extensions Catalog</a>', 'woocommerce' ), 'https://woocommerce.com/product-category/woocommerce-extensions/' ); ?></p>
<?php endif; ?>
<?php if ( 'Storefront' !== $theme['Name'] && 'featured' !== $current_section ) : ?>
<?php if ( 'Storefront' !== $theme['Name'] && '_featured' !== $current_section ) : ?>
<div class="storefront">
<a href="<?php echo esc_url( 'https://woocommerce.com/storefront/' ); ?>" target="_blank"><img src="<?php echo WC()->plugin_url(); ?>/assets/images/storefront.png" alt="Storefront" /></a>
<h2><?php _e( 'Looking for a WooCommerce theme?', 'woocommerce' ); ?></h2>

View File

@ -12,14 +12,14 @@ if ( ! defined( 'ABSPATH' ) ) {
<fieldset class="inline-edit-col-left">
<div id="woocommerce-fields" class="inline-edit-col">
<h4><?php _e( 'Product data', 'woocommerce' ); ?></h4>
<h4><?php esc_html_e( 'Product data', 'woocommerce' ); ?></h4>
<?php do_action( 'woocommerce_product_quick_edit_start' ); ?>
<?php if ( wc_product_sku_enabled() ) : ?>
<label>
<span class="title"><?php _e( 'SKU', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'SKU', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_sku" class="text sku" value="">
</span>
@ -30,14 +30,14 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="price_fields">
<label>
<span class="title"><?php _e( 'Price', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'Price', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_regular_price" class="text wc_input_price regular_price" placeholder="<?php esc_attr_e( 'Regular price', 'woocommerce' ); ?>" value="">
</span>
</label>
<br class="clear" />
<label>
<span class="title"><?php _e( 'Sale', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'Sale', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_sale_price" class="text wc_input_price sale_price" placeholder="<?php esc_attr_e( 'Sale price', 'woocommerce' ); ?>" value="">
</span>
@ -47,7 +47,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php if ( wc_tax_enabled() ) : ?>
<label class="alignleft">
<span class="title"><?php _e( 'Tax status', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'Tax status', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<select class="tax_status" name="_tax_status">
<?php
@ -57,7 +57,7 @@ if ( ! defined( 'ABSPATH' ) ) {
'none' => _x( 'None', 'Tax status', 'woocommerce' ),
);
foreach ( $options as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '">' . $value . '</option>';
echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>';
}
?>
</select>
@ -65,7 +65,7 @@ if ( ! defined( 'ABSPATH' ) ) {
</label>
<br class="clear" />
<label class="alignleft">
<span class="title"><?php _e( 'Tax class', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'Tax class', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<select class="tax_class" name="_tax_class">
<?php
@ -96,7 +96,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php if ( wc_product_weight_enabled() ) : ?>
<label>
<span class="title"><?php _e( 'Weight', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'Weight', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_weight" class="text weight" placeholder="<?php echo wc_format_localized_decimal( 0 ); ?>" value="">
</span>
@ -107,7 +107,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php if ( wc_product_dimensions_enabled() ) : ?>
<div class="inline-edit-group dimensions">
<div>
<span class="title"><?php _e( 'L/W/H', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'L/W/H', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="text" name="_length" class="text wc_input_decimal length" placeholder="<?php esc_attr_e( 'Length', 'woocommerce' ); ?>" value="">
<input type="text" name="_width" class="text wc_input_decimal width" placeholder="<?php esc_attr_e( 'Width', 'woocommerce' ); ?>" value="">
@ -120,23 +120,23 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
<?php endif; ?>
<label class="alignleft">
<span class="title"><?php _e( 'Shipping class', 'woocommerce' ); ?></span>
<div class="inline-edit-group">
<span class="title"><?php esc_html_e( 'Shipping class', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<select class="shipping_class" name="_shipping_class">
<option value="_no_shipping_class"><?php _e( 'No shipping class', 'woocommerce' ); ?></option>
<option value="_no_shipping_class"><?php esc_html_e( 'No shipping class', 'woocommerce' ); ?></option>
<?php
foreach ( $shipping_class as $key => $value ) {
echo '<option value="' . esc_attr( $value->slug ) . '">' . $value->name . '</option>';
echo '<option value="' . esc_attr( $value->slug ) . '">' . esc_html( $value->name ) . '</option>';
}
?>
</select>
</span>
</label>
<br class="clear" />
</div>
<div class="inline-edit-group">
<label class="alignleft">
<span class="title"><?php _e( 'Visibility', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'Visibility', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<select class="visibility" name="_visibility">
<?php
@ -147,7 +147,7 @@ if ( ! defined( 'ABSPATH' ) ) {
'hidden' => __( 'Hidden', 'woocommerce' ),
) );
foreach ( $options as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '">' . $value . '</option>';
echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>';
}
?>
</select>
@ -155,16 +155,26 @@ if ( ! defined( 'ABSPATH' ) ) {
</label>
<label class="alignleft featured">
<input type="checkbox" name="_featured" value="1">
<span class="checkbox-title"><?php _e( 'Featured', 'woocommerce' ); ?></span>
<span class="checkbox-title"><?php esc_html_e( 'Featured', 'woocommerce' ); ?></span>
</label>
<br class="clear" />
<label class="alignleft">
<span class="title"><?php _e( 'In stock?', 'woocommerce' ); ?></span>
</div>
<?php if ( get_option( 'woocommerce_manage_stock' ) == 'yes' ) : ?>
<div class="inline-edit-group">
<label class="manage_stock">
<input type="checkbox" name="_manage_stock" value="1">
<span class="checkbox-title"><?php esc_html_e( 'Manage stock?', 'woocommerce' ); ?></span>
</label>
</div>
<?php endif; ?>
<label class="stock_status_field">
<span class="title"><?php esc_html_e( 'In stock?', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<select class="stock_status" name="_stock_status">
<?php
foreach ( wc_get_product_stock_status_options() as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '">' . $value . '</option>';
echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>';
}
?>
</select>
@ -172,30 +182,23 @@ if ( ! defined( 'ABSPATH' ) ) {
</label>
<div class="stock_fields">
<?php if ( get_option( 'woocommerce_manage_stock' ) == 'yes' ) : ?>
<label class="alignleft manage_stock">
<input type="checkbox" name="_manage_stock" value="1">
<span class="checkbox-title"><?php _e( 'Manage stock?', 'woocommerce' ); ?></span>
</label>
<br class="clear" />
<label class="stock_qty_field">
<span class="title"><?php _e( 'Stock qty', 'woocommerce' ); ?></span>
<span class="title"><?php esc_html_e( 'Stock qty', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<input type="number" name="_stock" class="text stock" step="any" value="">
</span>
</label>
<?php endif; ?>
</div>
<label class="alignleft">
<span class="title"><?php _e( 'Backorders?', 'woocommerce' ); ?></span>
<label class="alignleft backorder_field">
<span class="title"><?php esc_html_e( 'Backorders?', 'woocommerce' ); ?></span>
<span class="input-text-wrap">
<select class="backorders" name="_backorders">
<?php
foreach ( wc_get_product_backorder_options() as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '">' . $value . '</option>';
echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>';
}
?>
</select>

View File

@ -309,3 +309,24 @@ function wc_save_order_items( $order_id, $items ) {
// Inform other plugins that the items have been saved
do_action( 'woocommerce_saved_order_items', $order_id, $items );
}
/**
* Get HTML for some action buttons. Used in list tables.
*
* @since 3.3.0
* @param array $actions Actions to output.
* @return string
*/
function wc_render_action_buttons( $actions ) {
$actions_html = '';
foreach ( $actions as $action ) {
if ( isset( $action['group'] ) ) {
$actions_html .= '<div class="wc-action-button-group"><label>' . $action['group'] . '</label> <span class="wc-action-button-group__items">' . wc_render_action_buttons( $action['actions'] ) . '</span></div>';
} elseif ( isset( $action['action'], $action['url'], $action['name'] ) ) {
$actions_html .= sprintf( '<a class="button wc-action-button wc-action-button-%s %s" href="%s" title="%s">%s</a>', esc_attr( $action['action'] ), esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_attr( $action['name'] ) );
}
}
return $actions_html;
}

View File

@ -185,7 +185,7 @@ class WC_REST_Product_Categories_Controller extends WC_REST_Product_Categories_V
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
'name' => array(
'title' => array(
'description' => __( 'Image name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),

View File

@ -174,15 +174,6 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller {
__( 'This option will delete ALL of your tax rates, use with caution. This action cannot be reversed.', 'woocommerce' )
),
),
'delete_webhook_logs' => array(
'name' => __( 'Delete WebHook logs', 'woocommerce' ),
'button' => __( 'Delete logs', 'woocommerce' ),
'desc' => sprintf(
'<strong class="red">%1$s</strong> %2$s',
__( 'Note:', 'woocommerce' ),
__( 'This tool removes WebHook logs. This will not delete the WebHooks themselves.', 'woocommerce' )
),
),
'reset_tracking' => array(
'name' => __( 'Reset usage tracking', 'woocommerce' ),
'button' => __( 'Reset', 'woocommerce' ),
@ -447,12 +438,6 @@ class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller {
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
$message = __( 'Tax rates successfully deleted', 'woocommerce' );
break;
case 'delete_webhook_logs' :
$result = absint( $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE comment_type='webhook_delivery';" ) );
$wpdb->query( "DELETE commentmeta FROM {$wpdb->commentmeta} commentmeta LEFT JOIN {$wpdb->comments} comments ON comments.comment_ID = commentmeta.comment_id WHERE comments.comment_ID IS NULL;" );
$message = sprintf( __( '%d logs deleted', 'woocommerce' ), $result );
break;
case 'reset_tracking' :
delete_option( 'woocommerce_allow_tracking' );
WC_Admin_Notices::add_notice( 'tracking' );

View File

@ -17,6 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) {
/**
* REST API Webhook Deliveries controller class.
*
* @deprecated 3.3.0 Webhooks deliveries logs now uses logging system.
* @package WooCommerce/API
* @extends WC_REST_Webhook_Deliveries_V1_Controller
*/
@ -34,18 +35,11 @@ class WC_REST_Webhook_Deliveries_Controller extends WC_REST_Webhook_Deliveries_V
*
* @param stdClass $log Delivery log object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response Response data.
* @return WP_REST_Response
*/
public function prepare_item_for_response( $log, $request ) {
$data = (array) $log;
// Add timestamp.
$data['date_created'] = wc_rest_prepare_date_response( $log->comment->comment_date );
$data['date_created_gmt'] = wc_rest_prepare_date_response( $log->comment->comment_date_gmt );
// Remove comment object.
unset( $data['comment'] );
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );

View File

@ -32,16 +32,14 @@ class WC_REST_Webhooks_Controller extends WC_REST_Webhooks_V1_Controller {
/**
* Prepare a single webhook output for response.
*
* @param object $post
* @param int $id Webhook ID.
* @param WP_REST_Request $request Request object.
*
* @return WP_REST_Response $response Response data.
* @return WP_REST_Response $response
*/
public function prepare_item_for_response( $post, $request ) {
$id = (int) $post->ID;
$webhook = new WC_Webhook( $id );
public function prepare_item_for_response( $id, $request ) {
$webhook = wc_get_webhook( $id );
$data = array(
'id' => $webhook->id,
'id' => $webhook->get_id(),
'name' => $webhook->get_name(),
'status' => $webhook->get_status(),
'topic' => $webhook->get_topic(),
@ -49,10 +47,10 @@ class WC_REST_Webhooks_Controller extends WC_REST_Webhooks_V1_Controller {
'event' => $webhook->get_event(),
'hooks' => $webhook->get_hooks(),
'delivery_url' => $webhook->get_delivery_url(),
'date_created' => wc_rest_prepare_date_response( $webhook->get_post_data()->post_date ),
'date_created_gmt' => wc_rest_prepare_date_response( $webhook->get_post_data()->post_date_gmt ),
'date_modified' => wc_rest_prepare_date_response( $webhook->get_post_data()->post_modified ),
'date_modified_gmt' => wc_rest_prepare_date_response( $webhook->get_post_data()->post_modified_gmt ),
'date_created' => wc_rest_prepare_date_response( $webhook->get_date_created(), false ),
'date_created_gmt' => wc_rest_prepare_date_response( $webhook->get_date_created() ),
'date_modified' => wc_rest_prepare_date_response( $webhook->get_date_modified(), false ),
'date_modified_gmt' => wc_rest_prepare_date_response( $webhook->get_date_modified() ),
);
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
@ -62,7 +60,7 @@ class WC_REST_Webhooks_Controller extends WC_REST_Webhooks_V1_Controller {
// Wrap the data in a response object.
$response = rest_ensure_response( $data );
$response->add_links( $this->prepare_links( $post, $request ) );
$response->add_links( $this->prepare_links( $webhook->get_id(), $request ) );
/**
* Filter webhook object returned from the REST API.

View File

@ -565,7 +565,7 @@ class WC_API_Server {
* Send pagination headers for resources
*
* @since 2.1
* @param WP_Query|WP_User_Query $query
* @param WP_Query|WP_User_Query|stdClass $query
*/
public function add_pagination_headers( $query ) {
@ -582,6 +582,11 @@ class WC_API_Server {
$page = 1;
$total_pages = 1;
}
} elseif ( is_a( $query, 'stdClass' ) ) {
$page = $query->page;
$single = $query->is_single;
$total = $query->total;
$total_pages = $query->total_pages;
// WP_Query
} else {

View File

@ -83,7 +83,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$webhooks = array();
foreach ( $query->posts as $webhook_id ) {
foreach ( $query['results'] as $webhook_id ) {
if ( ! $this->is_readable( $webhook_id ) ) {
continue;
@ -92,7 +92,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$webhooks[] = current( $this->get_webhook( $webhook_id, $fields ) );
}
$this->server->add_pagination_headers( $query );
$this->server->add_pagination_headers( $query['headers'] );
return array( 'webhooks' => $webhooks );
}
@ -114,10 +114,10 @@ class WC_API_Webhooks extends WC_API_Resource {
return $id;
}
$webhook = new WC_Webhook( $id );
$webhook = wc_get_webhook( $id );
$webhook_data = array(
'id' => $webhook->id,
'id' => $webhook->get_id(),
'name' => $webhook->get_name(),
'status' => $webhook->get_status(),
'topic' => $webhook->get_topic(),
@ -125,8 +125,8 @@ class WC_API_Webhooks extends WC_API_Resource {
'event' => $webhook->get_event(),
'hooks' => $webhook->get_hooks(),
'delivery_url' => $webhook->get_delivery_url(),
'created_at' => $this->server->format_datetime( $webhook->get_post_data()->post_date_gmt ),
'updated_at' => $this->server->format_datetime( $webhook->get_post_data()->post_modified_gmt ),
'created_at' => $this->server->format_datetime( $webhook->get_date_created() ? $webhook->get_date_created()->getTimestamp() : 0, false, false ), // API gives UTC times.
'updated_at' => $this->server->format_datetime( $webhook->get_date_modified() ? $webhook->get_date_modified()->getTimestamp() : 0, false, false ), // API gives UTC times.
);
return array( 'webhook' => apply_filters( 'woocommerce_api_webhook_response', $webhook_data, $webhook, $fields, $this ) );
@ -144,7 +144,7 @@ class WC_API_Webhooks extends WC_API_Resource {
*/
public function get_webhooks_count( $status = null, $filter = array() ) {
try {
if ( ! current_user_can( 'read_private_shop_webhooks' ) ) {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_webhooks_count', __( 'You do not have permission to read the webhooks count', 'woocommerce' ), 401 );
}
@ -154,7 +154,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$query = $this->query_webhooks( $filter );
return array( 'count' => (int) $query->found_posts );
return array( 'count' => $query['headers']->total );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
@ -179,7 +179,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$data = $data['webhook'];
// permission check
if ( ! current_user_can( 'publish_shop_webhooks' ) ) {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_webhooks', __( 'You do not have permission to create webhooks.', 'woocommerce' ), 401 );
}
@ -201,40 +201,28 @@ class WC_API_Webhooks extends WC_API_Resource {
'ping_status' => 'closed',
'post_author' => get_current_user_id(),
'post_password' => strlen( ( $password = uniqid( 'webhook_' ) ) ) > 20 ? substr( $password, 0, 20 ) : $password,
// @codingStandardsIgnoreStart
'post_title' => ! empty( $data['name'] ) ? $data['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ),
// @codingStandardsIgnoreEnd
), $data, $this );
$webhook_id = wp_insert_post( $webhook_data );
$webhook = new WC_Webhook();
if ( is_wp_error( $webhook_id ) || ! $webhook_id ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_create_webhook', sprintf( __( 'Cannot create webhook: %s', 'woocommerce' ), is_wp_error( $webhook_id ) ? implode( ', ', $webhook_id->get_error_messages() ) : '0' ), 500 );
}
$webhook = new WC_Webhook( $webhook_id );
// set topic, delivery URL, and optional secret
$webhook->set_name( $webhook_data['post_title'] );
$webhook->set_user_id( $webhook_data['post_author'] );
$webhook->set_status( 'publish' === $webhook_data['post_status'] ? 'active' : 'disabled' );
$webhook->set_topic( $data['topic'] );
$webhook->set_delivery_url( $data['delivery_url'] );
// set secret if provided, defaults to API users consumer secret
$webhook->set_secret( ! empty( $data['secret'] ) ? $data['secret'] : '' );
// Set API version to legacy v3.
$webhook->set_secret( ! empty( $data['secret'] ) ? $data['secret'] : wp_generate_password( 50, true, true ) );
$webhook->set_api_version( 'legacy_v3' );
$webhook->save();
// send ping
$webhook->deliver_ping();
// HTTP 201 Created
$this->server->send_status( 201 );
do_action( 'woocommerce_api_create_webhook', $webhook->id, $this );
do_action( 'woocommerce_api_create_webhook', $webhook->get_id(), $this );
delete_transient( 'woocommerce_webhook_ids' );
return $this->get_webhook( $webhook->id );
return $this->get_webhook( $webhook->get_id() );
} catch ( WC_API_Exception $e ) {
@ -269,7 +257,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$data = apply_filters( 'woocommerce_api_edit_webhook_data', $data, $id, $this );
$webhook = new WC_Webhook( $id );
$webhook = wc_get_webhook( $id );
// update topic
if ( ! empty( $data['topic'] ) ) {
@ -301,28 +289,19 @@ class WC_API_Webhooks extends WC_API_Resource {
// update status
if ( ! empty( $data['status'] ) ) {
$webhook->update_status( $data['status'] );
$webhook->set_status( $data['status'] );
}
// update user ID
$webhook_data = array(
'ID' => $webhook->id,
'post_author' => get_current_user_id(),
);
// update name
if ( ! empty( $data['name'] ) ) {
$webhook_data['post_title'] = $data['name'];
$webhook->set_name( $data['name'] );
}
// update post
wp_update_post( $webhook_data );
$webhook->save();
do_action( 'woocommerce_api_edit_webhook', $webhook->id, $this );
do_action( 'woocommerce_api_edit_webhook', $webhook->get_id(), $this );
delete_transient( 'woocommerce_webhook_ids' );
return $this->get_webhook( $id );
return $this->get_webhook( $webhook->get_id() );
} catch ( WC_API_Exception $e ) {
@ -347,55 +326,97 @@ class WC_API_Webhooks extends WC_API_Resource {
do_action( 'woocommerce_api_delete_webhook', $id, $this );
delete_transient( 'woocommerce_webhook_ids' );
$webhook = wc_get_webhook( $id );
// no way to manage trashed webhooks at the moment, so force delete
return $this->delete( $id, 'webhook', true );
return $webhook->delete( true );
}
/**
* Get webhooks total results
*
* @since 3.3.0
* @param array $args Request arguments for filtering query.
* @return array
*/
private function get_webhooks_total_results( $args = array() ) {
$data_store = WC_Data_Store::load( 'webhook' );
$args['limit'] = -1;
$args['offset'] = 0;
return count( $data_store->search_webhooks( $args ) );
}
/**
* Helper method to get webhook post objects
*
* @since 2.2
* @param array $args request arguments for filtering query
* @return WP_Query
* @param array $args Request arguments for filtering query.
* @return array
*/
private function query_webhooks( $args ) {
$args = $this->merge_query_args( array(), $args );
// Set base query arguments
$query_args = array(
'fields' => 'ids',
'post_type' => 'shop_webhook',
$args['limit'] = isset( $args['posts_per_page'] ) ? intval( $args['posts_per_page'] ) : intval( get_option( 'posts_per_page' ) );
if ( empty( $args['offset'] ) ) {
$args['offset'] = 1 < $args['paged'] ? ( $args['paged'] - 1 ) * $args['limit'] : 0;
}
$page = $args['paged'];
unset( $args['paged'], $args['posts_per_page'] );
if ( isset( $args['s'] ) ) {
$args['search'] = $args['s'];
unset( $args['s'] );
}
// Post type to webhook status.
if ( ! empty( $args['post_status'] ) ) {
$args['status'] = $args['post_status'];
unset( $args['post_status'] );
}
if ( ! empty( $args['post__in'] ) ) {
$args['include'] = $args['post__in'];
unset( $args['post__in'] );
}
if ( ! empty( $args['date_query'] ) ) {
foreach ( $args['date_query'] as $date_query ) {
if ( 'post_date_gmt' === $date_query['column'] ) {
$args['after'] = isset( $date_query['after'] ) ? $date_query['after'] : null;
$args['before'] = isset( $date_query['before'] ) ? $date_query['before'] : null;
} elseif ( 'post_modified_gmt' === $date_query['column'] ) {
$args['modified_after'] = isset( $date_query['after'] ) ? $date_query['after'] : null;
$args['modified_before'] = isset( $date_query['before'] ) ? $date_query['before'] : null;
}
}
unset( $args['date_query'] );
}
// Get the webhooks.
$data_store = WC_Data_Store::load( 'webhook' );
$results = $data_store->search_webhooks( $args );
// Get total items.
$headers = new stdClass;
$headers->page = $page;
$headers->total = $this->get_webhooks_total_results( $args );
$headers->is_single = $args['limit'] > $headers->total;
$headers->total_pages = ceil( $headers->total / $args['limit'] );
return array(
'results' => $results,
'headers' => $headers,
);
// Add status argument
if ( ! empty( $args['status'] ) ) {
switch ( $args['status'] ) {
case 'active':
$query_args['post_status'] = 'publish';
break;
case 'paused':
$query_args['post_status'] = 'draft';
break;
case 'disabled':
$query_args['post_status'] = 'pending';
break;
default:
$query_args['post_status'] = 'publish';
}
unset( $args['status'] );
}
$query_args = $this->merge_query_args( $query_args, $args );
return new WP_Query( $query_args );
}
/**
* Get deliveries for a webhook
*
* @since 2.2
* @deprecated 3.3.0 Webhooks deliveries logs now uses logging system.
* @param string $webhook_id webhook ID
* @param string|null $fields fields to include in response
* @return array|WP_Error
@ -409,29 +430,14 @@ class WC_API_Webhooks extends WC_API_Resource {
return $webhook_id;
}
$webhook = new WC_Webhook( $webhook_id );
$logs = $webhook->get_delivery_logs();
$delivery_logs = array();
foreach ( $logs as $log ) {
// Add timestamp
$log['created_at'] = $this->server->format_datetime( $log['comment']->comment_date_gmt );
// Remove comment object
unset( $log['comment'] );
$delivery_logs[] = $log;
}
return array( 'webhook_deliveries' => $delivery_logs );
return array( 'webhook_deliveries' => array() );
}
/**
* Get the delivery log for the given webhook ID and delivery ID
*
* @since 2.2
*
* @deprecated 3.3.0 Webhooks deliveries logs now uses logging system.
* @param string $webhook_id webhook ID
* @param string $id delivery log ID
* @param string|null $fields fields to limit response to
@ -455,23 +461,67 @@ class WC_API_Webhooks extends WC_API_Resource {
$webhook = new WC_Webhook( $webhook_id );
$log = $webhook->get_delivery_log( $id );
$log = 0;
if ( ! $log ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_webhook_delivery_id', __( 'Invalid webhook delivery.', 'woocommerce' ), 400 );
}
$delivery_log = $log;
// Add timestamp
$delivery_log['created_at'] = $this->server->format_datetime( $log['comment']->comment_date_gmt );
// Remove comment object
unset( $delivery_log['comment'] );
return array( 'webhook_delivery' => apply_filters( 'woocommerce_api_webhook_delivery_response', $delivery_log, $id, $fields, $log, $webhook_id, $this ) );
return array( 'webhook_delivery' => apply_filters( 'woocommerce_api_webhook_delivery_response', array(), $id, $fields, $log, $webhook_id, $this ) );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}
/**
* Validate the request by checking:
*
* 1) the ID is a valid integer.
* 2) the ID returns a valid post object and matches the provided post type.
* 3) the current user has the proper permissions to read/edit/delete the post.
*
* @since 3.3.0
* @param string|int $id The post ID
* @param string $type The post type, either `shop_order`, `shop_coupon`, or `product`.
* @param string $context The context of the request, either `read`, `edit` or `delete`.
* @return int|WP_Error Valid post ID or WP_Error if any of the checks fails.
*/
protected function validate_request( $id, $type, $context ) {
$id = absint( $id );
// Validate ID.
if ( empty( $id ) ) {
return new WP_Error( "woocommerce_api_invalid_webhook_id", sprintf( __( 'Invalid %s ID', 'woocommerce' ), $type ), array( 'status' => 404 ) );
}
$webhook = wc_get_webhook( $id );
if ( null === $webhook ) {
return new WP_Error( "woocommerce_api_no_webhook_found", sprintf( __( 'No %1$s found with the ID equal to %2$s', 'woocommerce' ), 'webhook', $id ), array( 'status' => 404 ) );
}
// Validate permissions.
switch ( $context ) {
case 'read':
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( "woocommerce_api_user_cannot_read_webhook", sprintf( __( 'You do not have permission to read this %s', 'woocommerce' ), 'webhook' ), array( 'status' => 401 ) );
}
break;
case 'edit':
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( "woocommerce_api_user_cannot_edit_webhook", sprintf( __( 'You do not have permission to edit this %s', 'woocommerce' ), 'webhook' ), array( 'status' => 401 ) );
}
break;
case 'delete':
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( "woocommerce_api_user_cannot_delete_webhook", sprintf( __( 'You do not have permission to delete this %s', 'woocommerce' ), 'webhook' ), array( 'status' => 401 ) );
}
break;
}
return $id;
}
}

View File

@ -83,7 +83,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$webhooks = array();
foreach ( $query->posts as $webhook_id ) {
foreach ( $query['results'] as $webhook_id ) {
if ( ! $this->is_readable( $webhook_id ) ) {
continue;
@ -92,7 +92,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$webhooks[] = current( $this->get_webhook( $webhook_id, $fields ) );
}
$this->server->add_pagination_headers( $query );
$this->server->add_pagination_headers( $query['headers'] );
return array( 'webhooks' => $webhooks );
}
@ -114,10 +114,10 @@ class WC_API_Webhooks extends WC_API_Resource {
return $id;
}
$webhook = new WC_Webhook( $id );
$webhook = wc_get_webhook( $id );
$webhook_data = array(
'id' => $webhook->id,
'id' => $webhook->get_id(),
'name' => $webhook->get_name(),
'status' => $webhook->get_status(),
'topic' => $webhook->get_topic(),
@ -125,8 +125,8 @@ class WC_API_Webhooks extends WC_API_Resource {
'event' => $webhook->get_event(),
'hooks' => $webhook->get_hooks(),
'delivery_url' => $webhook->get_delivery_url(),
'created_at' => $this->server->format_datetime( $webhook->get_post_data()->post_date_gmt ),
'updated_at' => $this->server->format_datetime( $webhook->get_post_data()->post_modified_gmt ),
'created_at' => $this->server->format_datetime( $webhook->get_date_created() ? $webhook->get_date_created()->getTimestamp() : 0, false, false ), // API gives UTC times.
'updated_at' => $this->server->format_datetime( $webhook->get_date_modified() ? $webhook->get_date_modified()->getTimestamp() : 0, false, false ), // API gives UTC times.
);
return array( 'webhook' => apply_filters( 'woocommerce_api_webhook_response', $webhook_data, $webhook, $fields, $this ) );
@ -144,7 +144,7 @@ class WC_API_Webhooks extends WC_API_Resource {
*/
public function get_webhooks_count( $status = null, $filter = array() ) {
try {
if ( ! current_user_can( 'read_private_shop_webhooks' ) ) {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_webhooks_count', __( 'You do not have permission to read the webhooks count', 'woocommerce' ), 401 );
}
@ -154,7 +154,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$query = $this->query_webhooks( $filter );
return array( 'count' => (int) $query->found_posts );
return array( 'count' => $query['headers']->total );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
@ -179,7 +179,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$data = $data['webhook'];
// permission check
if ( ! current_user_can( 'publish_shop_webhooks' ) ) {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_webhooks', __( 'You do not have permission to create webhooks.', 'woocommerce' ), 401 );
}
@ -201,40 +201,28 @@ class WC_API_Webhooks extends WC_API_Resource {
'ping_status' => 'closed',
'post_author' => get_current_user_id(),
'post_password' => strlen( ( $password = uniqid( 'webhook_' ) ) ) > 20 ? substr( $password, 0, 20 ) : $password,
// @codingStandardsIgnoreStart
'post_title' => ! empty( $data['name'] ) ? $data['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ),
// @codingStandardsIgnoreEnd
), $data, $this );
$webhook_id = wp_insert_post( $webhook_data );
$webhook = new WC_Webhook();
if ( is_wp_error( $webhook_id ) || ! $webhook_id ) {
throw new WC_API_Exception( 'woocommerce_api_cannot_create_webhook', sprintf( __( 'Cannot create webhook: %s', 'woocommerce' ), is_wp_error( $webhook_id ) ? implode( ', ', $webhook_id->get_error_messages() ) : '0' ), 500 );
}
$webhook = new WC_Webhook( $webhook_id );
// set topic, delivery URL, and optional secret
$webhook->set_name( $webhook_data['post_title'] );
$webhook->set_user_id( $webhook_data['post_author'] );
$webhook->set_status( 'publish' === $webhook_data['post_status'] ? 'active' : 'disabled' );
$webhook->set_topic( $data['topic'] );
$webhook->set_delivery_url( $data['delivery_url'] );
// set secret if provided, defaults to API users consumer secret
$webhook->set_secret( ! empty( $data['secret'] ) ? $data['secret'] : '' );
// Set API version to legacy v3.
$webhook->set_secret( ! empty( $data['secret'] ) ? $data['secret'] : wp_generate_password( 50, true, true ) );
$webhook->set_api_version( 'legacy_v3' );
$webhook->save();
// send ping
$webhook->deliver_ping();
// HTTP 201 Created
$this->server->send_status( 201 );
do_action( 'woocommerce_api_create_webhook', $webhook->id, $this );
do_action( 'woocommerce_api_create_webhook', $webhook->get_id(), $this );
delete_transient( 'woocommerce_webhook_ids' );
return $this->get_webhook( $webhook->id );
return $this->get_webhook( $webhook->get_id() );
} catch ( WC_API_Exception $e ) {
@ -269,7 +257,7 @@ class WC_API_Webhooks extends WC_API_Resource {
$data = apply_filters( 'woocommerce_api_edit_webhook_data', $data, $id, $this );
$webhook = new WC_Webhook( $id );
$webhook = wc_get_webhook( $id );
// update topic
if ( ! empty( $data['topic'] ) ) {
@ -301,28 +289,19 @@ class WC_API_Webhooks extends WC_API_Resource {
// update status
if ( ! empty( $data['status'] ) ) {
$webhook->update_status( $data['status'] );
$webhook->set_status( $data['status'] );
}
// update user ID
$webhook_data = array(
'ID' => $webhook->id,
'post_author' => get_current_user_id(),
);
// update name
if ( ! empty( $data['name'] ) ) {
$webhook_data['post_title'] = $data['name'];
$webhook->set_name( $data['name'] );
}
// update post
wp_update_post( $webhook_data );
$webhook->save();
do_action( 'woocommerce_api_edit_webhook', $webhook->id, $this );
do_action( 'woocommerce_api_edit_webhook', $webhook->get_id(), $this );
delete_transient( 'woocommerce_webhook_ids' );
return $this->get_webhook( $id );
return $this->get_webhook( $webhook->get_id() );
} catch ( WC_API_Exception $e ) {
@ -347,58 +326,97 @@ class WC_API_Webhooks extends WC_API_Resource {
do_action( 'woocommerce_api_delete_webhook', $id, $this );
delete_transient( 'woocommerce_webhook_ids' );
$webhook = wc_get_webhook( $id );
// no way to manage trashed webhooks at the moment, so force delete
return $this->delete( $id, 'webhook', true );
return $webhook->delete( true );
}
/**
* Get webhooks total results
*
* @since 3.3.0
* @param array $args Request arguments for filtering query.
* @return array
*/
private function get_webhooks_total_results( $args = array() ) {
$data_store = WC_Data_Store::load( 'webhook' );
$args['limit'] = -1;
$args['offset'] = 0;
return count( $data_store->search_webhooks( $args ) );
}
/**
* Helper method to get webhook post objects
*
* @since 2.2
* @param array $args request arguments for filtering query.
* @return WP_Query
* @param array $args Request arguments for filtering query.
* @return array
*/
private function query_webhooks( $args ) {
$args = $this->merge_query_args( array(), $args );
// Set base query arguments.
$query_args = array(
'fields' => 'ids',
'post_type' => 'shop_webhook',
$args['limit'] = isset( $args['posts_per_page'] ) ? intval( $args['posts_per_page'] ) : intval( get_option( 'posts_per_page' ) );
if ( empty( $args['offset'] ) ) {
$args['offset'] = 1 < $args['paged'] ? ( $args['paged'] - 1 ) * $args['limit'] : 0;
}
$page = $args['paged'];
unset( $args['paged'], $args['posts_per_page'] );
if ( isset( $args['s'] ) ) {
$args['search'] = $args['s'];
unset( $args['s'] );
}
// Post type to webhook status.
if ( ! empty( $args['post_status'] ) ) {
$args['status'] = $args['post_status'];
unset( $args['post_status'] );
}
if ( ! empty( $args['post__in'] ) ) {
$args['include'] = $args['post__in'];
unset( $args['post__in'] );
}
if ( ! empty( $args['date_query'] ) ) {
foreach ( $args['date_query'] as $date_query ) {
if ( 'post_date_gmt' === $date_query['column'] ) {
$args['after'] = isset( $date_query['after'] ) ? $date_query['after'] : null;
$args['before'] = isset( $date_query['before'] ) ? $date_query['before'] : null;
} elseif ( 'post_modified_gmt' === $date_query['column'] ) {
$args['modified_after'] = isset( $date_query['after'] ) ? $date_query['after'] : null;
$args['modified_before'] = isset( $date_query['before'] ) ? $date_query['before'] : null;
}
}
unset( $args['date_query'] );
}
// Get the webhooks.
$data_store = WC_Data_Store::load( 'webhook' );
$results = $data_store->search_webhooks( $args );
// Get total items.
$headers = new stdClass;
$headers->page = $page;
$headers->total = $this->get_webhooks_total_results( $args );
$headers->is_single = $args['limit'] > $headers->total;
$headers->total_pages = ceil( $headers->total / $args['limit'] );
return array(
'results' => $results,
'headers' => $headers,
);
// Add status argument.
if ( ! empty( $args['status'] ) ) {
switch ( $args['status'] ) {
case 'active' :
$query_args['post_status'] = 'publish';
break;
case 'paused' :
$query_args['post_status'] = 'draft';
break;
case 'disabled' :
$query_args['post_status'] = 'pending';
break;
case 'all' :
$query_args['post_status'] = 'any';
break;
default :
$query_args['post_status'] = 'publish';
break;
}
unset( $args['status'] );
}
$query_args = $this->merge_query_args( $query_args, $args );
return new WP_Query( $query_args );
}
/**
* Get deliveries for a webhook
*
* @since 2.2
* @deprecated 3.3.0 Webhooks deliveries logs now uses logging system.
* @param string $webhook_id webhook ID
* @param string|null $fields fields to include in response
* @return array|WP_Error
@ -412,29 +430,14 @@ class WC_API_Webhooks extends WC_API_Resource {
return $webhook_id;
}
$webhook = new WC_Webhook( $webhook_id );
$logs = $webhook->get_delivery_logs();
$delivery_logs = array();
foreach ( $logs as $log ) {
// Add timestamp
$log['created_at'] = $this->server->format_datetime( $log['comment']->comment_date_gmt );
// Remove comment object
unset( $log['comment'] );
$delivery_logs[] = $log;
}
return array( 'webhook_deliveries' => $delivery_logs );
return array( 'webhook_deliveries' => array() );
}
/**
* Get the delivery log for the given webhook ID and delivery ID
*
* @since 2.2
*
* @deprecated 3.3.0 Webhooks deliveries logs now uses logging system.
* @param string $webhook_id webhook ID
* @param string $id delivery log ID
* @param string|null $fields fields to limit response to
@ -458,23 +461,67 @@ class WC_API_Webhooks extends WC_API_Resource {
$webhook = new WC_Webhook( $webhook_id );
$log = $webhook->get_delivery_log( $id );
$log = 0;
if ( ! $log ) {
throw new WC_API_Exception( 'woocommerce_api_invalid_webhook_delivery_id', __( 'Invalid webhook delivery.', 'woocommerce' ), 400 );
}
$delivery_log = $log;
// Add timestamp
$delivery_log['created_at'] = $this->server->format_datetime( $log['comment']->comment_date_gmt );
// Remove comment object
unset( $delivery_log['comment'] );
return array( 'webhook_delivery' => apply_filters( 'woocommerce_api_webhook_delivery_response', $delivery_log, $id, $fields, $log, $webhook_id, $this ) );
return array( 'webhook_delivery' => apply_filters( 'woocommerce_api_webhook_delivery_response', array(), $id, $fields, $log, $webhook_id, $this ) );
} catch ( WC_API_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}
}
/**
* Validate the request by checking:
*
* 1) the ID is a valid integer.
* 2) the ID returns a valid post object and matches the provided post type.
* 3) the current user has the proper permissions to read/edit/delete the post.
*
* @since 3.3.0
* @param string|int $id The post ID
* @param string $type The post type, either `shop_order`, `shop_coupon`, or `product`.
* @param string $context The context of the request, either `read`, `edit` or `delete`.
* @return int|WP_Error Valid post ID or WP_Error if any of the checks fails.
*/
protected function validate_request( $id, $type, $context ) {
$id = absint( $id );
// Validate ID.
if ( empty( $id ) ) {
return new WP_Error( "woocommerce_api_invalid_webhook_id", sprintf( __( 'Invalid %s ID', 'woocommerce' ), $type ), array( 'status' => 404 ) );
}
$webhook = wc_get_webhook( $id );
if ( null === $webhook ) {
return new WP_Error( "woocommerce_api_no_webhook_found", sprintf( __( 'No %1$s found with the ID equal to %2$s', 'woocommerce' ), 'webhook', $id ), array( 'status' => 404 ) );
}
// Validate permissions.
switch ( $context ) {
case 'read':
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( "woocommerce_api_user_cannot_read_webhook", sprintf( __( 'You do not have permission to read this %s', 'woocommerce' ), 'webhook' ), array( 'status' => 401 ) );
}
break;
case 'edit':
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( "woocommerce_api_user_cannot_edit_webhook", sprintf( __( 'You do not have permission to edit this %s', 'woocommerce' ), 'webhook' ), array( 'status' => 401 ) );
}
break;
case 'delete':
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( "woocommerce_api_user_cannot_delete_webhook", sprintf( __( 'You do not have permission to delete this %s', 'woocommerce' ), 'webhook' ), array( 'status' => 401 ) );
}
break;
}
return $id;
}
}

View File

@ -240,7 +240,7 @@ class WC_REST_Product_Categories_V1_Controller extends WC_REST_Terms_Controller
'format' => 'uri',
'context' => array( 'view', 'edit' ),
),
'name' => array(
'title' => array(
'description' => __( 'Image name.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),

View File

@ -378,7 +378,7 @@ class WC_REST_Report_Sales_V1_Controller extends WC_REST_Controller {
),
'date_min' => array(
/* translators: %s: date format */
'description' => sprintf( __( 'Return sales for a specific start date, the date need to be in the %s format.', 'woocommerce' ), 'YYYY-MM-AA' ),
'description' => sprintf( __( 'Return sales for a specific start date, the date need to be in the %s format.', 'woocommerce' ), 'YYYY-MM-DD' ),
'type' => 'string',
'format' => 'date',
'validate_callback' => 'wc_rest_validate_reports_request_arg',
@ -386,7 +386,7 @@ class WC_REST_Report_Sales_V1_Controller extends WC_REST_Controller {
),
'date_max' => array(
/* translators: %s: date format */
'description' => sprintf( __( 'Return sales for a specific end date, the date need to be in the %s format.', 'woocommerce' ), 'YYYY-MM-AA' ),
'description' => sprintf( __( 'Return sales for a specific end date, the date need to be in the %s format.', 'woocommerce' ), 'YYYY-MM-DD' ),
'type' => 'string',
'format' => 'date',
'validate_callback' => 'wc_rest_validate_reports_request_arg',

View File

@ -17,6 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) {
/**
* REST API Webhook Deliveries controller class.
*
* @deprecated 3.3.0 Webhooks deliveries logs now uses logging system.
* @package WooCommerce/API
* @extends WC_REST_Controller
*/
@ -80,13 +81,13 @@ class WC_REST_Webhook_Deliveries_V1_Controller extends WC_REST_Controller {
}
/**
* Check whether a given request has permission to read webhook deliveries.
* Check whether a given request has permission to read taxes.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! wc_rest_check_post_permissions( 'shop_webhook', 'read' ) ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
@ -94,15 +95,13 @@ class WC_REST_Webhook_Deliveries_V1_Controller extends WC_REST_Controller {
}
/**
* Check if a given request has access to read a webhook develivery.
* Check if a given request has access to read a tax.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$post = get_post( (int) $request['webhook_id'] );
if ( $post && ! wc_rest_check_post_permissions( 'shop_webhook', 'read', $post->ID ) ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
@ -117,14 +116,13 @@ class WC_REST_Webhook_Deliveries_V1_Controller extends WC_REST_Controller {
* @return array|WP_Error
*/
public function get_items( $request ) {
$webhook = new WC_Webhook( (int) $request['webhook_id'] );
$webhook = wc_get_webhook( (int) $request['webhook_id'] );
if ( empty( $webhook->post_data->post_type ) || 'shop_webhook' !== $webhook->post_data->post_type ) {
if ( empty( $webhook ) || is_null( $webhook ) ) {
return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$logs = $webhook->get_delivery_logs();
$logs = array();
$data = array();
foreach ( $logs as $log ) {
$delivery = $this->prepare_item_for_response( (object) $log, $request );
@ -143,13 +141,13 @@ class WC_REST_Webhook_Deliveries_V1_Controller extends WC_REST_Controller {
*/
public function get_item( $request ) {
$id = (int) $request['id'];
$webhook = new WC_Webhook( (int) $request['webhook_id'] );
$webhook = wc_get_webhook( (int) $request['webhook_id'] );
if ( empty( $webhook->post_data->post_type ) || 'shop_webhook' !== $webhook->post_data->post_type ) {
if ( empty( $webhook ) || is_null( $webhook ) ) {
return new WP_Error( 'woocommerce_rest_webhook_invalid_id', __( 'Invalid webhook ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$log = $webhook->get_delivery_log( $id );
$log = array();
if ( empty( $id ) || empty( $log ) ) {
return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource ID.', 'woocommerce' ), array( 'status' => 404 ) );
@ -170,13 +168,6 @@ class WC_REST_Webhook_Deliveries_V1_Controller extends WC_REST_Controller {
*/
public function prepare_item_for_response( $log, $request ) {
$data = (array) $log;
// Add timestamp.
$data['date_created'] = wc_rest_prepare_date_response( $log->comment->comment_date_gmt );
// Remove comment object.
unset( $data['comment'] );
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );

View File

@ -18,9 +18,9 @@ if ( ! defined( 'ABSPATH' ) ) {
* REST API Webhooks controller class.
*
* @package WooCommerce/API
* @extends WC_REST_Posts_Controller
* @extends WC_REST_Controller
*/
class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
/**
* Endpoint namespace.
@ -43,13 +43,6 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
*/
protected $post_type = 'shop_webhook';
/**
* Initialize Webhooks actions.
*/
public function __construct() {
add_filter( "woocommerce_rest_{$this->post_type}_query", array( $this, 'query_args' ), 10, 2 );
}
/**
* Register the routes for webhooks.
*/
@ -76,11 +69,6 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
'type' => 'string',
'description' => __( 'Webhook delivery URL.', 'woocommerce' ),
),
'secret' => array(
'required' => true,
'type' => 'string',
'description' => __( 'Webhook secret.', 'woocommerce' ),
),
) ),
),
'schema' => array( $this, 'get_public_item_schema' ),
@ -133,6 +121,94 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
) );
}
/**
* Check whether a given request has permission to read webhooks.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access create webhooks.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return bool|WP_Error
*/
public function create_item_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'create' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to read a webhook.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'read' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access update a webhook.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return bool|WP_Error
*/
public function update_item_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'edit' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access delete a webhook.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return bool|WP_Error
*/
public function delete_item_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'delete' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access batch create, update and delete items.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return bool|WP_Error
*/
public function batch_items_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'webhooks', 'batch' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Get the default REST API version.
*
@ -143,6 +219,79 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
return 'wp_api_v1';
}
/**
* Get all webhooks.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|WP_REST_Response
*/
public function get_items( $request ) {
$args = array();
$args['order'] = $request['order'];
$args['orderby'] = $request['orderby'];
$args['status'] = 'all' === $request['status'] ? '' : $request['status'];
$args['include'] = implode( ',', $request['include'] );
$args['exclude'] = implode( ',', $request['exclude'] );
$args['limit'] = $request['per_page'];
$args['search'] = $request['search'];
$args['before'] = $request['before'];
$args['after'] = $request['after'];
if ( empty( $request['offset'] ) ) {
$args['offset'] = 1 < $request['page'] ? ( $request['page'] - 1 ) * $args['limit'] : 0;
}
/**
* Filter arguments, before passing to WC_Webhook_Data_Store->search_webhooks, when querying webhooks via the REST API.
*
* @param array $args Array of arguments for $wpdb->get_results().
* @param WP_REST_Request $request The current request.
*/
$prepared_args = apply_filters( 'woocommerce_rest_webhook_query', $args, $request );
unset( $prepared_args['page'] );
// Get the webhooks.
$data_store = WC_Data_Store::load( 'webhook' );
$results = $data_store->search_webhooks( $prepared_args );
$webhooks = array();
foreach ( $results as $webhook_id ) {
$data = $this->prepare_item_for_response( $webhook_id, $request );
$webhooks[] = $this->prepare_response_for_collection( $data );
}
$response = rest_ensure_response( $webhooks );
// Store pagination values for headers then unset for count query.
$per_page = (int) $prepared_args['limit'];
$page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
// Calculate totals.
$prepared_args['limit'] = -1;
$prepared_args['offset'] = 0;
$total_webhooks = count( $data_store->search_webhooks( $prepared_args ) );
$response->header( 'X-WP-Total', (int) $total_webhooks );
$max_pages = ceil( $total_webhooks / $per_page );
$response->header( 'X-WP-TotalPages', (int) $max_pages );
$base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
if ( $page > 1 ) {
$prev_page = $page - 1;
if ( $prev_page > $max_pages ) {
$prev_page = $max_pages;
}
$prev_link = add_query_arg( 'page', $prev_page, $base );
$response->link_header( 'prev', $prev_link );
}
if ( $max_pages > $page ) {
$next_page = $page + 1;
$next_link = add_query_arg( 'page', $next_page, $base );
$response->link_header( 'next', $next_link );
}
return $response;
}
/**
* Create a single webhook.
*
@ -170,63 +319,36 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
return $post;
}
$post->post_type = $this->post_type;
$post_id = wp_insert_post( $post, true );
if ( is_wp_error( $post_id ) ) {
if ( in_array( $post_id->get_error_code(), array( 'db_insert_error' ) ) ) {
$post_id->add_data( array( 'status' => 500 ) );
} else {
$post_id->add_data( array( 'status' => 400 ) );
}
return $post_id;
}
$post->ID = $post_id;
$webhook = new WC_Webhook( $post_id );
// Set topic.
$webhook = new WC_Webhook();
$webhook->set_name( $post->post_title );
$webhook->set_user_id( $post->post_author );
$webhook->set_status( 'publish' === $post->post_status ? 'active' : 'disabled' );
$webhook->set_topic( $request['topic'] );
// Set delivery URL.
$webhook->set_delivery_url( $request['delivery_url'] );
// Set secret.
$webhook->set_secret( ! empty( $request['secret'] ) ? $request['secret'] : '' );
// Set API version to WP API integration.
$webhook->set_secret( ! empty( $request['secret'] ) ? $request['secret'] : wp_generate_password( 50, true, true ) );
$webhook->set_api_version( $this->get_default_api_version() );
$webhook->save();
// Set status.
if ( ! empty( $request['status'] ) ) {
$webhook->update_status( $request['status'] );
}
$post = get_post( $post_id );
$this->update_additional_fields_for_object( $post, $request );
$this->update_additional_fields_for_object( $webhook, $request );
/**
* Fires after a single item is created or updated via the REST API.
*
* @param WP_Post $post Inserted object.
* @param WC_Webhook $webhook Webhook data.
* @param WP_REST_Request $request Request object.
* @param boolean $creating True when creating item, false when updating.
* @param bool $creating True when creating item, false when updating.
*/
do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true );
do_action( "woocommerce_rest_insert_webhook_object", $webhook, $request, true );
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $post, $request );
$response = $this->prepare_item_for_response( $webhook->get_id(), $request );
$response = rest_ensure_response( $response );
$response->set_status( 201 );
$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) );
$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $webhook->get_id() ) ) );
// Send ping.
$webhook->deliver_ping();
// Clear cache.
delete_transient( 'woocommerce_webhook_ids' );
return $response;
}
@ -238,14 +360,12 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
*/
public function update_item( $request ) {
$id = (int) $request['id'];
$post = get_post( $id );
$webhook = wc_get_webhook( $id );
if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
if ( empty( $id ) || is_null( $webhook->get_id() ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
}
$webhook = new WC_Webhook( $id );
// Update topic.
if ( ! empty( $request['topic'] ) ) {
if ( wc_is_webhook_valid_topic( strtolower( $request['topic'] ) ) ) {
@ -271,7 +391,7 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
// Update status.
if ( ! empty( $request['status'] ) ) {
$webhook->update_status( $request['status'] );
$webhook->set_status( $request['status'] );
}
$post = $this->prepare_item_for_database( $request );
@ -279,34 +399,25 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
return $post;
}
// Convert the post object to an array, otherwise wp_update_post will expect non-escaped input.
$post_id = wp_update_post( (array) $post, true );
if ( is_wp_error( $post_id ) ) {
if ( in_array( $post_id->get_error_code(), array( 'db_update_error' ) ) ) {
$post_id->add_data( array( 'status' => 500 ) );
} else {
$post_id->add_data( array( 'status' => 400 ) );
}
return $post_id;
if ( isset( $post->post_title ) ) {
$webhook->set_name( $post->post_title );
}
$post = get_post( $post_id );
$this->update_additional_fields_for_object( $post, $request );
$webhook->save();
$this->update_additional_fields_for_object( $webhook, $request );
/**
* Fires after a single item is created or updated via the REST API.
*
* @param WP_Post $post Inserted object.
* @param WC_Webhook $webhook Webhook data.
* @param WP_REST_Request $request Request object.
* @param boolean $creating True when creating item, false when updating.
* @param bool $creating True when creating item, false when updating.
*/
do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false );
do_action( "woocommerce_rest_insert_webhook_object", $webhook, $request, false );
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $post, $request );
// Clear cache.
delete_transient( 'woocommerce_webhook_ids' );
$response = $this->prepare_item_for_response( $webhook->get_id(), $request );
return rest_ensure_response( $response );
}
@ -326,16 +437,15 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Webhooks do not support trashing.', 'woocommerce' ), array( 'status' => 501 ) );
}
$post = get_post( $id );
$webhook = wc_get_webhook( $id );
if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post ID.', 'woocommerce' ), array( 'status' => 404 ) );
if ( empty( $webhook ) || is_null( $webhook ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $post, $request );
$result = wp_delete_post( $id, true );
$response = $this->prepare_item_for_response( $webhook, $request );
$result = $webhook->delete( true );
if ( ! $result ) {
/* translators: %s: post type */
@ -345,14 +455,11 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
/**
* Fires after a single item is deleted or trashed via the REST API.
*
* @param object $post The deleted or trashed item.
* @param WC_Webhook $webhook The deleted or trashed item.
* @param WP_REST_Response $response The response data.
* @param WP_REST_Request $request The request sent to the API.
*/
do_action( "woocommerce_rest_delete_{$this->post_type}", $post, $response, $request );
// Clear cache.
delete_transient( 'woocommerce_webhook_ids' );
do_action( "woocommerce_rest_delete_webhook_object", $webhook, $response, $request );
return $response;
}
@ -373,9 +480,7 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
// Validate required POST fields.
if ( 'POST' === $request->get_method() && empty( $data->ID ) ) {
// @codingStandardsIgnoreStart
$data->post_title = ! empty( $request['name'] ) ? $request['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) );
// @codingStandardsIgnoreEnd
$data->post_title = ! empty( $request['name'] ) ? $request['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) ); // @codingStandardsIgnoreLine
// Post author.
$data->post_author = get_current_user_id();
@ -416,16 +521,14 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
/**
* Prepare a single webhook output for response.
*
* @param object $post
* @param int $id Webhook ID.
* @param WP_REST_Request $request Request object.
*
* @return WP_REST_Response $response Response data.
*/
public function prepare_item_for_response( $post, $request ) {
$id = (int) $post->ID;
$webhook = new WC_Webhook( $id );
public function prepare_item_for_response( $id, $request ) {
$webhook = wc_get_webhook( (int) $id );
$data = array(
'id' => $webhook->id,
'id' => $webhook->get_id(),
'name' => $webhook->get_name(),
'status' => $webhook->get_status(),
'topic' => $webhook->get_topic(),
@ -433,8 +536,8 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
'event' => $webhook->get_event(),
'hooks' => $webhook->get_hooks(),
'delivery_url' => $webhook->get_delivery_url(),
'date_created' => wc_rest_prepare_date_response( $webhook->get_post_data()->post_date_gmt ),
'date_modified' => wc_rest_prepare_date_response( $webhook->get_post_data()->post_modified_gmt ),
'date_created' => wc_rest_prepare_date_response( $webhook->get_date_created() ),
'date_modified' => wc_rest_prepare_date_response( $webhook->get_date_modified() ),
);
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
@ -444,7 +547,7 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
// Wrap the data in a response object.
$response = rest_ensure_response( $data );
$response->add_links( $this->prepare_links( $post, $request ) );
$response->add_links( $this->prepare_links( $webhook->get_id() ) );
/**
* Filter webhook object returned from the REST API.
@ -457,30 +560,22 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
}
/**
* Query args.
* Prepare links for the request.
*
* @param array $args
* @param WP_REST_Request $request
* @param int $id Webhook ID.
* @return array
*/
public function query_args( $args, $request ) {
// Set post_status.
switch ( $request['status'] ) {
case 'active' :
$args['post_status'] = 'publish';
break;
case 'paused' :
$args['post_status'] = 'draft';
break;
case 'disabled' :
$args['post_status'] = 'pending';
break;
default :
$args['post_status'] = 'any';
break;
}
protected function prepare_links( $id ) {
$links = array(
'self' => array(
'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $id ) ),
),
'collection' => array(
'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
),
);
return $args;
return $links;
}
/**
@ -579,6 +674,62 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Posts_Controller {
public function get_collection_params() {
$params = parent::get_collection_params();
$params['context']['default'] = 'view';
$params['after'] = array(
'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce' ),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['before'] = array(
'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'woocommerce' ),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['exclude'] = array(
'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['include'] = array(
'description' => __( 'Limit result set to specific ids.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['offset'] = array(
'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
'type' => 'integer',
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['order'] = array(
'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
'type' => 'string',
'default' => 'desc',
'enum' => array( 'asc', 'desc' ),
'validate_callback' => 'rest_validate_request_arg',
);
$params['orderby'] = array(
'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),
'type' => 'string',
'default' => 'date',
'enum' => array(
'date',
'id',
'title',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['status'] = array(
'default' => 'all',
'description' => __( 'Limit result set to webhooks assigned a specific status.', 'woocommerce' ),

View File

@ -483,83 +483,12 @@ class WC_AJAX {
wp_die( -1 );
}
if ( $order = wc_get_order( absint( $_GET['order_id'] ) ) ) {
$order = wc_get_order( absint( $_GET['order_id'] ) ); // WPCS: sanitization ok.
ob_start();
if ( $order ) {
include_once( 'admin/list-tables/class-wc-admin-list-table-orders.php' );
$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( apply_filters( 'woocommerce_ajax_get_order_details', 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(),
), $order ) );
wp_send_json_success( WC_Admin_List_Table_Orders::order_preview_get_order_details( $order ) );
}
exit;
}
@ -2036,6 +1965,17 @@ class WC_AJAX {
self::variation_bulk_set( $variations, 'stock_status', 'outofstock' );
}
/**
* Bulk action - Set Stock Status as On Backorder.
* @access private
* @used-by bulk_edit_variations
* @param array $variations
* @param array $data
*/
private static function variation_bulk_action_variable_stock_status_onbackorder( $variations, $data ) {
self::variation_bulk_set( $variations, 'stock_status', 'onbackorder' );
}
/**
* Bulk action - Set Stock.
* @access private

View File

@ -162,7 +162,7 @@ class WC_API extends WC_Legacy_API {
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-reports-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-tax-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-taxes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-webhook-deliveries.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-webhook-deliveries-controller.php' );
include_once( dirname( __FILE__ ) . '/api/v1/class-wc-rest-webhooks-controller.php' );
// Legacy v2 code.
@ -195,7 +195,7 @@ class WC_API extends WC_Legacy_API {
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-shipping-zone-methods-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-tax-classes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-taxes-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-webhook-deliveries.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-webhook-deliveries-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-webhooks-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-system-status-controller.php' );
include_once( dirname( __FILE__ ) . '/api/class-wc-rest-system-status-tools-controller.php' );

View File

@ -71,11 +71,14 @@ final class WC_Cart_Session {
$this->cart->set_coupon_discount_tax_totals( WC()->session->get( 'coupon_discount_tax_totals', array() ) );
$this->cart->set_removed_cart_contents( WC()->session->get( 'removed_cart_contents', array() ) );
if ( is_null( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), true ) ) ) {
if ( is_null( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), true ) ) ) { // @codingStandardsIgnoreLine
$cart = $saved_cart['cart'];
$update_cart_session = true;
} elseif ( is_null( $cart ) ) {
$cart = array();
} elseif ( is_array( $cart ) && ( $saved_cart = get_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), true ) ) ) { // @codingStandardsIgnoreLine
$cart = array_merge( $saved_cart['cart'], $cart );
$update_cart_session = true;
}
if ( is_array( $cart ) ) {
@ -97,7 +100,9 @@ final class WC_Cart_Session {
} else {
// Put session data into array. Run through filter so other plugins can load their own session data.
$session_data = array_merge( $values, array( 'data' => $product ) );
$session_data = array_merge( $values, array(
'data' => $product,
) );
$cart_contents[ $key ] = apply_filters( 'woocommerce_get_cart_item_from_session', $session_data, $values, $key );
// Add to cart right away so the product is visible in woocommerce_get_cart_item_from_session hook.
@ -180,7 +185,9 @@ final class WC_Cart_Session {
*/
public function persistent_cart_update() {
if ( get_current_user_id() ) {
update_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), array( 'cart' => $this->get_cart_for_session() ) );
update_user_meta( get_current_user_id(), '_woocommerce_persistent_cart_' . get_current_blog_id(), array(
'cart' => $this->get_cart_for_session(),
) );
}
}

View File

@ -5,6 +5,10 @@
* Methods are protected and class is final to keep this as an internal API.
* May be opened in the future once structure is stable.
*
* Rounding guide:
* - if something is being stored e.g. item total, store unrounded. This is so taxes can be recalculated later accurately.
* - if calculating a total, round (if settings allow).
*
* @author Automattic
* @package WooCommerce/Classes
*/
@ -315,12 +319,7 @@ final class WC_Cart_Totals {
}
$fee->taxes = apply_filters( 'woocommerce_cart_totals_get_fees_from_cart_taxes', $fee->taxes, $fee, $this );
$fee->total_tax = array_sum( $fee->taxes );
if ( ! $this->round_at_subtotal() ) {
$fee->total_tax = wc_round_tax_total( $fee->total_tax, wc_get_rounding_precision() );
}
$fee->total_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $fee->taxes ) );
// Set totals within object.
$fee->object->total = wc_remove_number_precision_deep( $fee->total );
@ -350,11 +349,7 @@ final class WC_Cart_Totals {
$shipping_line->taxable = true;
$shipping_line->total = wc_add_number_precision_deep( $shipping_object->cost );
$shipping_line->taxes = wc_add_number_precision_deep( $shipping_object->taxes, false );
$shipping_line->total_tax = wc_add_number_precision_deep( array_sum( $shipping_object->taxes ), false );
if ( ! $this->round_at_subtotal() ) {
$shipping_line->total_tax = wc_round_tax_total( $shipping_line->total_tax, wc_get_rounding_precision() );
}
$shipping_line->total_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $shipping_line->taxes ) );
$this->shipping[ $key ] = $shipping_line;
}
@ -427,7 +422,7 @@ final class WC_Cart_Totals {
$base_tax_rates = WC_Tax::get_base_tax_rates( $item->product->get_tax_class( 'unfiltered' ) );
// Work out a new base price without the shop's base tax.
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true, true );
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
// Now we have a new item price (excluding TAX).
$item->price = absint( $item->price - array_sum( $taxes ) );
@ -454,8 +449,8 @@ final class WC_Cart_Totals {
if ( $item->tax_rates !== $base_tax_rates ) {
// Work out a new base price without the shop's base tax.
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true, true );
$new_taxes = WC_Tax::calc_tax( $item->price - array_sum( $taxes ), $item->tax_rates, false, true );
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
$new_taxes = WC_Tax::calc_tax( $item->price - array_sum( $taxes ), $item->tax_rates, false );
// Now we have a new item price.
$item->price = $item->price - array_sum( $taxes ) + array_sum( $new_taxes );
@ -575,7 +570,7 @@ final class WC_Cart_Totals {
if ( ! isset( $taxes[ $rate_id ] ) ) {
$taxes[ $rate_id ] = 0;
}
$taxes[ $rate_id ] += $rate;
$taxes[ $rate_id ] += $this->round_line_tax( $rate );
}
}
@ -636,15 +631,13 @@ final class WC_Cart_Totals {
}
if ( $this->calculate_tax && $item->product->is_taxable() ) {
$item->taxes = WC_Tax::calc_tax( $item->total, $item->tax_rates, $item->price_includes_tax );
$item->total_tax = array_sum( $item->taxes );
if ( ! $this->round_at_subtotal() ) {
$item->total_tax = wc_round_tax_total( $item->total_tax, wc_get_rounding_precision() );
}
$total_taxes = WC_Tax::calc_tax( $item->total, $item->tax_rates, $item->price_includes_tax );
$item->taxes = $total_taxes;
$item->total_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $item->taxes ) );
if ( $item->price_includes_tax ) {
$item->total = $item->total - $item->total_tax;
// Use unrounded taxes so we can re-calculate from the orders screen accurately later.
$item->total = $item->total - array_sum( $item->taxes );
}
}
@ -653,7 +646,7 @@ final class WC_Cart_Totals {
$this->cart->cart_contents[ $item_key ]['line_tax'] = wc_remove_number_precision( $item->total_tax );
}
$this->set_total( 'items_total', array_sum( array_values( wp_list_pluck( $this->items, 'total' ) ) ) );
$this->set_total( 'items_total', array_sum( array_map( 'round', array_values( wp_list_pluck( $this->items, 'total' ) ) ) ) );
$this->set_total( 'items_total_tax', array_sum( array_values( wp_list_pluck( $this->items, 'total_tax' ) ) ) );
$this->cart->set_cart_contents_total( $this->get_total( 'items_total' ) );
@ -690,14 +683,11 @@ final class WC_Cart_Totals {
if ( $this->calculate_tax && $item->product->is_taxable() ) {
$subtotal_taxes = WC_Tax::calc_tax( $item->subtotal, $item->tax_rates, $item->price_includes_tax );
$item->subtotal_tax = array_sum( $subtotal_taxes );
if ( ! $this->round_at_subtotal() ) {
$item->subtotal_tax = wc_round_tax_total( $item->subtotal_tax, wc_get_rounding_precision() );
}
$item->subtotal_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $subtotal_taxes ) );
if ( $item->price_includes_tax ) {
$item->subtotal = $item->subtotal - $item->subtotal_tax;
// Use unrounded taxes so we can re-calculate from the orders screen accurately later.
$item->subtotal = $item->subtotal - array_sum( $subtotal_taxes );
}
}
@ -705,7 +695,7 @@ final class WC_Cart_Totals {
$this->cart->cart_contents[ $item_key ]['line_subtotal'] = wc_remove_number_precision( $item->subtotal );
$this->cart->cart_contents[ $item_key ]['line_subtotal_tax'] = wc_remove_number_precision( $item->subtotal_tax );
}
$this->set_total( 'items_subtotal', array_sum( array_values( wp_list_pluck( $this->items, 'subtotal' ) ) ) );
$this->set_total( 'items_subtotal', array_sum( array_map( 'round', array_values( wp_list_pluck( $this->items, 'subtotal' ) ) ) ) );
$this->set_total( 'items_subtotal_tax', array_sum( array_values( wp_list_pluck( $this->items, 'subtotal_tax' ) ) ) );
$this->cart->set_subtotal( $this->get_total( 'items_subtotal' ) );
@ -816,7 +806,7 @@ final class WC_Cart_Totals {
* @since 3.2.0
*/
protected function calculate_totals() {
$this->set_total( 'total', round( $this->get_total( 'items_total', true ) + $this->get_total( 'fees_total', true ) + $this->get_total( 'shipping_total', true ) + array_sum( $this->get_merged_taxes( true ) ) ) );
$this->set_total( 'total', round( $this->get_total( 'items_total', true ) + $this->get_total( 'fees_total', true ) + $this->get_total( 'shipping_total', true ) + array_sum( $this->get_merged_taxes( true ) ), 0 ) );
$this->cart->set_total_tax( array_sum( $this->get_merged_taxes( false ) ) );
// Allow plugins to hook and alter totals before final total is calculated.
@ -827,4 +817,18 @@ final class WC_Cart_Totals {
// Allow plugins to filter the grand total, and sum the cart totals in case of modifications.
$this->cart->set_total( max( 0, apply_filters( 'woocommerce_calculated_total', $this->get_total( 'total' ), $this->cart ) ) );
}
/**
* Apply rounding to an array of taxes before summing. Rounds to store DP setting, ignoring precision.
*
* @since 3.2.6
* @param float $value Tax value.
* @return float
*/
protected function round_line_tax( $value ) {
if ( ! $this->round_at_subtotal() ) {
$value = wc_round_tax_total( $value, 0 );
}
return $value;
}
}

View File

@ -430,7 +430,7 @@ class WC_Cart extends WC_Legacy_Cart {
* @param string $value Value to set.
*/
public function set_subtotal( $value ) {
$this->totals['subtotal'] = wc_format_decimal( $value );
$this->totals['subtotal'] = wc_format_decimal( $value, wc_get_price_decimals() );
}
/**
@ -460,7 +460,7 @@ class WC_Cart extends WC_Legacy_Cart {
* @param string $value Value to set.
*/
public function set_discount_tax( $value ) {
$this->totals['discount_tax'] = wc_format_decimal( $value );
$this->totals['discount_tax'] = wc_round_tax_total( $value );
}
/**
@ -470,7 +470,7 @@ class WC_Cart extends WC_Legacy_Cart {
* @param string $value Value to set.
*/
public function set_shipping_total( $value ) {
$this->totals['shipping_total'] = wc_format_decimal( $value );
$this->totals['shipping_total'] = wc_format_decimal( $value, wc_get_price_decimals() );
}
/**
@ -490,7 +490,7 @@ class WC_Cart extends WC_Legacy_Cart {
* @param string $value Value to set.
*/
public function set_cart_contents_total( $value ) {
$this->totals['cart_contents_total'] = wc_format_decimal( $value );
$this->totals['cart_contents_total'] = wc_format_decimal( $value, wc_get_price_decimals() );
}
/**
@ -510,7 +510,7 @@ class WC_Cart extends WC_Legacy_Cart {
* @param string $value Value to set.
*/
public function set_total( $value ) {
$this->totals['total'] = wc_format_decimal( $value );
$this->totals['total'] = wc_format_decimal( $value, wc_get_price_decimals() );
}
/**
@ -530,7 +530,7 @@ class WC_Cart extends WC_Legacy_Cart {
* @param string $value Value to set.
*/
public function set_fee_total( $value ) {
$this->totals['fee_total'] = wc_format_decimal( $value );
$this->totals['fee_total'] = wc_format_decimal( $value, wc_get_price_decimals() );
}
/**
@ -819,69 +819,9 @@ class WC_Cart extends WC_Legacy_Cart {
* @return string
*/
public function get_item_data( $cart_item, $flat = false ) {
$item_data = array();
wc_deprecated_function( 'WC_Cart::get_item_data', '3.3', 'wc_get_formatted_cart_item_data' );
// Variation values are shown only if they are not found in the title as of 3.0.
// This is because variation titles display the attributes.
if ( $cart_item['data']->is_type( 'variation' ) && is_array( $cart_item['variation'] ) ) {
foreach ( $cart_item['variation'] as $name => $value ) {
$taxonomy = wc_attribute_taxonomy_name( str_replace( 'attribute_pa_', '', urldecode( $name ) ) );
if ( taxonomy_exists( $taxonomy ) ) {
// If this is a term slug, get the term's nice name.
$term = get_term_by( 'slug', $value, $taxonomy );
if ( ! is_wp_error( $term ) && $term && $term->name ) {
$value = $term->name;
}
$label = wc_attribute_label( $taxonomy );
} else {
// If this is a custom option slug, get the options name.
$value = apply_filters( 'woocommerce_variation_option_name', $value );
$label = wc_attribute_label( str_replace( 'attribute_', '', $name ), $cart_item['data'] );
}
// Check the nicename against the title.
if ( '' === $value || wc_is_attribute_in_product_name( $value, $cart_item['data']->get_name() ) ) {
continue;
}
$item_data[] = array(
'key' => $label,
'value' => $value,
);
}
}
// Filter item data to allow 3rd parties to add more to the array.
$item_data = apply_filters( 'woocommerce_get_item_data', $item_data, $cart_item );
// Format item data ready to display.
foreach ( $item_data as $key => $data ) {
// Set hidden to true to not display meta on cart.
if ( ! empty( $data['hidden'] ) ) {
unset( $item_data[ $key ] );
continue;
}
$item_data[ $key ]['key'] = ! empty( $data['key'] ) ? $data['key'] : $data['name'];
$item_data[ $key ]['display'] = ! empty( $data['display'] ) ? $data['display'] : $data['value'];
}
// Output flat or in list format.
if ( count( $item_data ) > 0 ) {
ob_start();
if ( $flat ) {
foreach ( $item_data as $data ) {
echo esc_html( $data['key'] ) . ': ' . wp_kses_post( $data['display'] ) . "\n";
}
} else {
wc_get_template( 'cart/cart-item-data.php', array( 'item_data' => $item_data ) );
}
return ob_get_clean();
}
return '';
return wc_get_formatted_cart_item_data( $cart_item, $flat );
}
/**
@ -911,8 +851,9 @@ class WC_Cart extends WC_Legacy_Cart {
* @return string url to page
*/
public function get_remove_url( $cart_item_key ) {
$cart_page_url = wc_get_page_permalink( 'cart' );
return apply_filters( 'woocommerce_get_remove_url', $cart_page_url ? wp_nonce_url( add_query_arg( 'remove_item', $cart_item_key, $cart_page_url ), 'woocommerce-cart' ) : '' );
wc_deprecated_function( 'WC_Cart::get_remove_url', '3.3', 'wc_get_cart_remove_url' );
return wc_get_cart_remove_url( $cart_item_key );
}
/**
@ -922,13 +863,9 @@ class WC_Cart extends WC_Legacy_Cart {
* @return string url to page
*/
public function get_undo_url( $cart_item_key ) {
$cart_page_url = wc_get_page_permalink( 'cart' );
wc_deprecated_function( 'WC_Cart::get_undo_url', '3.3', 'wc_get_cart_undo_url' );
$query_args = array(
'undo_item' => $cart_item_key,
);
return apply_filters( 'woocommerce_get_undo_url', $cart_page_url ? wp_nonce_url( add_query_arg( $query_args, $cart_page_url ), 'woocommerce-cart' ) : '', $cart_item_key );
return wc_get_cart_undo_url( $cart_item_key );
}
/**

View File

@ -47,6 +47,7 @@ class WC_Data_Store {
'product-variable' => 'WC_Product_Variable_Data_Store_CPT',
'product-variation' => 'WC_Product_Variation_Data_Store_CPT',
'shipping-zone' => 'WC_Shipping_Zone_Data_Store',
'webhook' => 'WC_Webhook_Data_Store',
);
/**

View File

@ -85,7 +85,7 @@ class WC_Discounts {
$item->object = $cart_item;
$item->product = $cart_item['data'];
$item->quantity = $cart_item['quantity'];
$item->price = wc_add_number_precision_deep( $item->product->get_price() ) * $item->quantity;
$item->price = wc_add_number_precision_deep( $item->product->get_price() * $item->quantity );
$this->items[ $key ] = $item;
}
@ -370,7 +370,7 @@ class WC_Discounts {
}
}
$discount = min( $discounted_price, $discount );
$discount = wc_cart_round_discount( min( $discounted_price, $discount ), 0 );
$cart_total = $cart_total + $price_to_discount;
$total_discount = $total_discount + $discount;
$applied_count = $applied_count + $apply_quantity;

View File

@ -494,7 +494,7 @@ class WC_Form_Handler {
// Don't show undo link if removed item is out of stock.
if ( $product->is_in_stock() && $product->has_enough_stock( $cart_item['quantity'] ) ) {
$removed_notice = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title );
$removed_notice .= ' <a href="' . esc_url( WC()->cart->get_undo_url( $cart_item_key ) ) . '" class="restore-item">' . __( 'Undo?', 'woocommerce' ) . '</a>';
$removed_notice .= ' <a href="' . esc_url( wc_get_cart_undo_url( $cart_item_key ) ) . '" class="restore-item">' . __( 'Undo?', 'woocommerce' ) . '</a>';
} else {
$removed_notice = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title );
}
@ -974,7 +974,7 @@ class WC_Form_Handler {
$redirect = wc_get_page_permalink( 'myaccount' );
}
wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_login_redirect', $redirect, $user ), wc_get_page_permalink( 'myaccount' ) ) );
wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_login_redirect', remove_query_arg( 'wc_error', $redirect ), $user ), wc_get_page_permalink( 'myaccount' ) ) );
exit;
}
} catch ( Exception $e ) {

View File

@ -220,7 +220,7 @@ class WC_Frontend_Scripts {
'selectWoo' => array(
'src' => self::get_asset_url( 'assets/js/selectWoo/selectWoo.full' . $suffix . '.js' ),
'deps' => array( 'jquery' ),
'version' => '1.0.1',
'version' => '1.0.2',
),
'wc-address-i18n' => array(
'src' => self::get_asset_url( 'assets/js/frontend/address-i18n' . $suffix . '.js' ),

View File

@ -56,7 +56,6 @@ class WC_Install {
'wc_update_240_options',
'wc_update_240_shipping_methods',
'wc_update_240_api_keys',
'wc_update_240_webhooks',
'wc_update_240_refunds',
'wc_update_240_db_version',
),
@ -77,7 +76,6 @@ class WC_Install {
'wc_update_260_db_version',
),
'3.0.0' => array(
'wc_update_300_webhooks',
'wc_update_300_grouped_products',
'wc_update_300_settings',
'wc_update_300_product_visibility',
@ -98,8 +96,11 @@ class WC_Install {
),
'3.3.0' => array(
'wc_update_330_image_options',
'wc_update_330_webhooks',
'wc_update_330_product_stock_status',
'wc_update_330_set_default_product_cat',
'wc_update_330_order_customer_id',
'wc_update_330_clear_transients',
'wc_update_330_db_version',
),
);
@ -698,6 +699,24 @@ CREATE TABLE {$wpdb->prefix}woocommerce_log (
PRIMARY KEY (log_id),
KEY level (level)
) $collate;
CREATE TABLE {$wpdb->prefix}wc_webhooks (
webhook_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
status varchar(200) NOT NULL,
name text NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
delivery_url text NOT NULL,
secret text NOT NULL,
topic varchar(200) NOT NULL,
date_created datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
date_created_gmt datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
date_modified datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
date_modified_gmt datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
api_version smallint(4) NOT NULL,
failure_count smallint(10) NOT NULL DEFAULT '0',
pending_delivery tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (webhook_id),
KEY user_id (user_id)
) $collate;
CREATE TABLE {$wpdb->prefix}wc_download_log (
download_log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
timestamp datetime NOT NULL,
@ -823,7 +842,7 @@ CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
'view_woocommerce_reports',
);
$capability_types = array( 'product', 'shop_order', 'shop_coupon', 'shop_webhook' );
$capability_types = array( 'product', 'shop_order', 'shop_coupon' );
foreach ( $capability_types as $capability_type ) {

499
includes/class-wc-order.php Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -256,6 +256,14 @@ class WC_Post_types {
$supports[] = 'comments';
}
$shop_page_id = wc_get_page_id( 'shop' );
if ( current_theme_supports( 'woocommerce' ) ) {
$has_archive = $shop_page_id && get_post( $shop_page_id ) ? urldecode( get_page_uri( $shop_page_id ) ) : 'shop';
} else {
$has_archive = false;
}
register_post_type( 'product',
apply_filters( 'woocommerce_register_post_type_product',
array(
@ -296,7 +304,7 @@ class WC_Post_types {
'rewrite' => $permalinks['product_rewrite_slug'] ? array( 'slug' => $permalinks['product_rewrite_slug'], 'with_front' => false, 'feeds' => true ) : false,
'query_var' => true,
'supports' => $supports,
'has_archive' => ( $shop_page_id = wc_get_page_id( 'shop' ) ) && get_post( $shop_page_id ) ? urldecode( get_page_uri( $shop_page_id ) ) : 'shop',
'has_archive' => $has_archive,
'show_in_nav_menus' => true,
'show_in_rest' => true,
)
@ -420,42 +428,6 @@ class WC_Post_types {
);
}
register_post_type( 'shop_webhook',
apply_filters( 'woocommerce_register_post_type_shop_webhook',
array(
'labels' => array(
'name' => __( 'Webhooks', 'woocommerce' ),
'singular_name' => __( 'Webhook', 'woocommerce' ),
'menu_name' => _x( 'Webhooks', 'Admin menu name', 'woocommerce' ),
'add_new' => __( 'Add webhook', 'woocommerce' ),
'add_new_item' => __( 'Add new webhook', 'woocommerce' ),
'edit' => __( 'Edit', 'woocommerce' ),
'edit_item' => __( 'Edit webhook', 'woocommerce' ),
'new_item' => __( 'New webhook', 'woocommerce' ),
'view' => __( 'View webhooks', 'woocommerce' ),
'view_item' => __( 'View webhook', 'woocommerce' ),
'search_items' => __( 'Search webhooks', 'woocommerce' ),
'not_found' => __( 'No webhooks found', 'woocommerce' ),
'not_found_in_trash' => __( 'No webhooks found in trash', 'woocommerce' ),
'parent' => __( 'Parent webhook', 'woocommerce' ),
),
'public' => false,
'show_ui' => true,
'capability_type' => 'shop_webhook',
'map_meta_cap' => true,
'publicly_queryable' => false,
'exclude_from_search' => true,
'show_in_menu' => false,
'hierarchical' => false,
'rewrite' => false,
'query_var' => false,
'supports' => false,
'show_in_nav_menus' => false,
'show_in_admin_bar' => false,
)
)
);
do_action( 'woocommerce_after_register_post_type' );
}

View File

@ -74,11 +74,11 @@ class WC_Product_Variable extends WC_Product {
/**
* Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
*
* @param bool $include_taxes Should taxes be included in the prices.
* @param bool $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes).
* @return array Array of RAW prices, regular prices, and sale prices with keys set to variation ID.
*/
public function get_variation_prices( $include_taxes = false ) {
$prices = $this->data_store->read_price_data( $this, $include_taxes );
public function get_variation_prices( $for_display = false ) {
$prices = $this->data_store->read_price_data( $this, $for_display );
foreach ( $prices as $price_key => $variation_prices ) {
$prices[ $price_key ] = $this->sort_variation_prices( $variation_prices );
@ -91,39 +91,39 @@ class WC_Product_Variable extends WC_Product {
* Get the min or max variation regular price.
*
* @param string $min_or_max Min or max price.
* @param boolean $include_taxes Should the price include taxes?
* @param boolean $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes).
* @return string
*/
public function get_variation_regular_price( $min_or_max = 'min', $include_taxes = false ) {
$prices = $this->get_variation_prices( $include_taxes );
public function get_variation_regular_price( $min_or_max = 'min', $for_display = false ) {
$prices = $this->get_variation_prices( $for_display );
$price = 'min' === $min_or_max ? current( $prices['regular_price'] ) : end( $prices['regular_price'] );
return apply_filters( 'woocommerce_get_variation_regular_price', $price, $this, $min_or_max, $include_taxes );
return apply_filters( 'woocommerce_get_variation_regular_price', $price, $this, $min_or_max, $for_display );
}
/**
* Get the min or max variation sale price.
*
* @param string $min_or_max Min or max price.
* @param boolean $include_taxes Should the price include taxes?
* @param boolean $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes).
* @return string
*/
public function get_variation_sale_price( $min_or_max = 'min', $include_taxes = false ) {
$prices = $this->get_variation_prices( $include_taxes );
public function get_variation_sale_price( $min_or_max = 'min', $for_display = false ) {
$prices = $this->get_variation_prices( $for_display );
$price = 'min' === $min_or_max ? current( $prices['sale_price'] ) : end( $prices['sale_price'] );
return apply_filters( 'woocommerce_get_variation_sale_price', $price, $this, $min_or_max, $include_taxes );
return apply_filters( 'woocommerce_get_variation_sale_price', $price, $this, $min_or_max, $for_display );
}
/**
* Get the min or max variation (active) price.
*
* @param string $min_or_max Min or max price.
* @param boolean $include_taxes Should the price include taxes?
* @param boolean $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes).
* @return string
*/
public function get_variation_price( $min_or_max = 'min', $include_taxes = false ) {
$prices = $this->get_variation_prices( $include_taxes );
public function get_variation_price( $min_or_max = 'min', $for_display = false ) {
$prices = $this->get_variation_prices( $for_display );
$price = 'min' === $min_or_max ? current( $prices['price'] ) : end( $prices['price'] );
return apply_filters( 'woocommerce_get_variation_price', $price, $this, $min_or_max, $include_taxes );
return apply_filters( 'woocommerce_get_variation_price', $price, $this, $min_or_max, $for_display );
}
/**
@ -376,18 +376,18 @@ class WC_Product_Variable extends WC_Product {
if ( ! $this->get_manage_stock() ) {
$this->set_stock_quantity( '' );
$this->set_backorders( 'no' );
$this->set_stock_status( $this->child_is_in_stock() ? 'instock' : 'outofstock' );
$this->data_store->sync_stock_status( $this );
// If backorders are enabled, always in stock.
} elseif ( 'no' !== $this->get_backorders() ) {
$this->set_stock_status( 'instock' );
// If we are stock managing, backorders are allowed, and we don't have stock, force on backorder status.
} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' !== $this->get_backorders() ) {
$this->set_stock_status( 'onbackorder' );
// If we are stock managing and we don't have stock, force out of stock status.
} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' === $this->get_backorders() ) {
$this->set_stock_status( 'outofstock' );
// If the stock level is changing and we do now have enough, force in stock status.
} elseif ( $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount' ) && array_key_exists( 'stock_quantity', $this->get_changes() ) ) {
} elseif ( $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount', 0 ) && array_key_exists( 'stock_quantity', $this->get_changes() ) ) {
$this->set_stock_status( 'instock' );
// Otherwise revert to status the children have.
@ -451,6 +451,16 @@ class WC_Product_Variable extends WC_Product {
return $this->data_store->child_is_in_stock( $this );
}
/**
* Is a child on backorder?
*
* @since 3.3.0
* @return boolean
*/
public function child_is_on_backorder() {
return $this->data_store->child_has_stock_status( $this, 'onbackorder' );
}
/**
* Does a child have a weight set?
* @return boolean

View File

@ -23,6 +23,13 @@ class WC_Query {
*/
public $query_vars = array();
/**
* Reference to the main product query on the page.
*
* @var array
*/
private static $product_query;
/**
* Stores chosen attributes.
*
@ -42,6 +49,7 @@ class WC_Query {
add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
add_action( 'wp', array( $this, 'remove_product_query' ) );
add_action( 'wp', array( $this, 'remove_ordering_args' ) );
add_filter( 'get_pagenum_link', array( $this, 'remove_add_to_cart_pagination' ), 10, 1 );
}
$this->init_query_vars();
}
@ -63,6 +71,7 @@ class WC_Query {
public function init_query_vars() {
// Query vars to add to WP.
$this->query_vars = array(
'product-page' => '',
// Checkout actions.
'order-pay' => get_option( 'woocommerce_checkout_pay_endpoint', 'order-pay' ),
'order-received' => get_option( 'woocommerce_checkout_order_received_endpoint', 'order-received' ),
@ -200,6 +209,7 @@ class WC_Query {
*/
public function get_current_endpoint() {
global $wp;
foreach ( $this->get_query_vars() as $key => $value ) {
if ( isset( $wp->query_vars[ $key ] ) ) {
return $key;
@ -333,17 +343,6 @@ class WC_Query {
$this->remove_product_query();
}
/**
* Search post excerpt.
*
* @deprecated 3.2.0 - Not needed anymore since WordPress 4.5.
* @param string $deprecated Deprecated.
*/
public function search_post_excerpt( $deprecated = '' ) {
wc_deprecated_function( 'WC_Query::search_post_excerpt', '3.2.0', 'Excerpt added to search query by default since WordPress 4.5.' );
return $deprecated;
}
/**
* WP SEO meta description.
*
@ -387,10 +386,15 @@ class WC_Query {
// Query vars that affect posts shown.
$q->set( 'meta_query', $this->get_meta_query( $q->get( 'meta_query' ), true ) );
$q->set( 'tax_query', $this->get_tax_query( $q->get( 'tax_query' ), true ) );
$q->set( 'posts_per_page', $q->get( 'posts_per_page' ) ? $q->get( 'posts_per_page' ) : apply_filters( 'loop_shop_per_page', get_option( 'posts_per_page' ) ) );
$q->set( 'wc_query', 'product_query' );
$q->set( 'post__in', array_unique( (array) apply_filters( 'loop_shop_post_in', array() ) ) );
// Work out how many products to query.
$q->set( 'posts_per_page', $q->get( 'posts_per_page' ) ? $q->get( 'posts_per_page' ) : apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() ) );
// Store reference to this query.
self::$product_query = $q;
do_action( 'woocommerce_product_query', $q, $this );
}
@ -411,27 +415,25 @@ class WC_Query {
remove_filter( 'posts_clauses', array( $this, 'order_by_rating_post_clauses' ) );
}
/**
* Remove the posts_where filter.
*
* @deprecated 3.2.0 - Nothing to remove anymore because search_post_excerpt() is deprecated.
*/
public function remove_posts_where() {
wc_deprecated_function( 'WC_Query::remove_posts_where', '3.2.0', 'Nothing to remove anymore because search_post_excerpt() is deprecated.' );
}
/**
* Returns an array of arguments for ordering products based on the selected values.
*
* @param string $orderby Order by.
* @param string $order Sorting order.
*
* @param string $orderby Order by param.
* @param string $order Order param.
* @return array
*/
public function get_catalog_ordering_args( $orderby = '', $order = '' ) {
// Get ordering from query string unless defined.
if ( ! $orderby ) {
$orderby_value = isset( $_GET['orderby'] ) ? wc_clean( wp_unslash( (string) $_GET['orderby'] ) ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) ); // WPCS: input var ok, CSRF ok.
$orderby_value = isset( $_GET['orderby'] ) ? wc_clean( (string) wp_unslash( $_GET['orderby'] ) ) : ''; // WPCS: sanitization ok, input var ok.
if ( ! $orderby_value ) {
if ( is_search() ) {
$orderby_value = 'relevance';
} else {
$orderby_value = apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
}
}
// Get order + orderby args from string.
$orderby_value = explode( '-', $orderby_value );
@ -442,21 +444,21 @@ class WC_Query {
$orderby = strtolower( $orderby );
$order = strtoupper( $order );
$args = array(
'orderby' => 'relevance',
'order' => 'DESC',
'meta_key' => '', // WPCS: slow query ok.
'orderby' => $orderby,
'order' => ( 'DESC' === $order ) ? 'DESC' : 'ASC',
'meta_key' => '', // @codingStandardsIgnoreLine
);
// Set to default. Menu order for non-searches, relevance for searches.
if ( ! is_search() ) {
$args['orderby'] = 'menu_order title';
$args['order'] = ( 'DESC' === $order ) ? 'DESC' : 'ASC';
$args['meta_key'] = ''; // WPCS: slow query ok.
}
switch ( $orderby ) {
case 'menu_order' :
$args['orderby'] = 'menu_order title';
break;
case 'relevance' :
$args['orderby']= 'relevance';
$args['order'] = 'DESC';
break;
case 'rand' :
$args['orderby'] = 'rand';
$args['orderby'] = 'rand'; // @codingStandardsIgnoreLine
break;
case 'date' :
$args['orderby'] = 'date ID';
@ -470,13 +472,13 @@ class WC_Query {
}
break;
case 'popularity' :
$args['meta_key'] = 'total_sales'; // WPCS: slow query ok.
$args['meta_key'] = 'total_sales'; // @codingStandardsIgnoreLine
// Sorting handled later though a hook.
add_filter( 'posts_clauses', array( $this, 'order_by_popularity_post_clauses' ) );
break;
case 'rating' :
$args['meta_key'] = '_wc_average_rating'; // WPCS: slow query ok.
$args['meta_key'] = '_wc_average_rating'; // @codingStandardsIgnoreLine
$args['orderby'] = array(
'meta_value_num' => 'DESC',
'ID' => 'ASC',
@ -568,30 +570,6 @@ class WC_Query {
return $args;
}
/**
* Order by rating post clauses.
*
* @deprecated 3.0.0
* @param array $args Query args.
* @return array
*/
public function order_by_rating_post_clauses( $args ) {
global $wpdb;
wc_deprecated_function( 'order_by_rating_post_clauses', '3.0' );
$args['fields'] .= ", AVG( $wpdb->commentmeta.meta_value ) as average_rating ";
$args['where'] .= " AND ( $wpdb->commentmeta.meta_key = 'rating' OR $wpdb->commentmeta.meta_key IS null ) ";
$args['join'] .= "
LEFT OUTER JOIN $wpdb->comments ON($wpdb->posts.ID = $wpdb->comments.comment_post_ID)
LEFT JOIN $wpdb->commentmeta ON($wpdb->comments.comment_ID = $wpdb->commentmeta.comment_id)
";
$args['orderby'] = "average_rating DESC, $wpdb->posts.post_date DESC";
$args['groupby'] = "$wpdb->posts.ID";
return $args;
}
/**
* Appends meta queries to an array.
*
@ -691,35 +669,12 @@ class WC_Query {
}
/**
* Return a meta query for filtering by rating.
* Get the main query which product queries ran against.
*
* @deprecated 3.0.0 Replaced with taxonomy.
* @return array
*/
public function rating_filter_meta_query() {
return array();
}
/**
* Returns a meta query to handle product visibility.
*
* @deprecated 3.0.0 Replaced with taxonomy.
* @param string $compare Compare type.
* @return array
*/
public function visibility_meta_query( $compare = 'IN' ) {
return array();
}
/**
* Returns a meta query to handle product stock status.
*
* @deprecated 3.0.0 Replaced with taxonomy.
* @param string $status Status.
* @return array
*/
public function stock_status_meta_query( $status = 'instock' ) {
return array();
public static function get_main_query() {
return self::$product_query;
}
/**
@ -728,9 +683,7 @@ class WC_Query {
* @return array
*/
public static function get_main_tax_query() {
global $wp_the_query;
$tax_query = isset( $wp_the_query->tax_query, $wp_the_query->tax_query->queries ) ? $wp_the_query->tax_query->queries : array();
$tax_query = isset( self::$product_query->tax_query, self::$product_query->tax_query->queries ) ? self::$product_query->tax_query->queries : array();
return $tax_query;
}
@ -741,9 +694,7 @@ class WC_Query {
* @return array
*/
public static function get_main_meta_query() {
global $wp_the_query;
$args = $wp_the_query->query_vars;
$args = self::$product_query->query_vars;
$meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
return $meta_query;
@ -753,9 +704,9 @@ class WC_Query {
* Based on WP_Query::parse_search
*/
public static function get_main_search_query_sql() {
global $wp_the_query, $wpdb;
global $wpdb;
$args = $wp_the_query->query_vars;
$args = self::$product_query->query_vars;
$search_terms = isset( $args['search_terms'] ) ? $args['search_terms'] : array();
$sql = array();
@ -773,7 +724,7 @@ class WC_Query {
}
$like = '%' . $wpdb->esc_like( $term ) . '%';
$sql[] = $wpdb->prepare( "(($wpdb->posts.post_title $like_op %s) $andor_op ($wpdb->posts.post_excerpt $like_op %s) $andor_op ($wpdb->posts.post_content $like_op %s))", $like, $like, $like ); // WPCS: db call ok, cache ok, unprepared SQL ok.
$sql[] = $wpdb->prepare( "(($wpdb->posts.post_title $like_op %s) $andor_op ($wpdb->posts.post_excerpt $like_op %s) $andor_op ($wpdb->posts.post_content $like_op %s))", $like, $like, $like ); // unprepared SQL ok.
}
if ( ! empty( $sql ) && ! is_user_logged_in() ) {
@ -785,25 +736,22 @@ class WC_Query {
/**
* Layered Nav Init.
*
* @return array
*/
public static function get_layered_nav_chosen_attributes() {
if ( ! is_array( self::$_chosen_attributes ) ) {
self::$_chosen_attributes = array();
$attribute_taxonomies = wc_get_attribute_taxonomies();
if ( $attribute_taxonomies ) {
if ( $attribute_taxonomies = wc_get_attribute_taxonomies() ) {
foreach ( $attribute_taxonomies as $tax ) {
$attribute = wc_sanitize_taxonomy_name( $tax->attribute_name );
$taxonomy = wc_attribute_taxonomy_name( $attribute );
$filter_terms = ! empty( $_GET[ 'filter_' . $attribute ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ 'filter_' . $attribute ] ) ) ) : array(); // WPCS: input var ok, CSRF ok.
$filter_terms = ! empty( $_GET[ 'filter_' . $attribute ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ 'filter_' . $attribute ] ) ) ) : array(); // WPCS: sanitization ok, input var ok.
if ( empty( $filter_terms ) || ! taxonomy_exists( $taxonomy ) ) {
continue;
}
$query_type = ! empty( $_GET[ 'query_type_' . $attribute ] ) && in_array( wp_unslash( $_GET[ 'query_type_' . $attribute ] ), array( 'and', 'or' ), true ) ? wc_clean( wp_unslash( $_GET[ 'query_type_' . $attribute ] ) ) : ''; // WPCS: input var ok, CSRF ok.
$query_type = ! empty( $_GET[ 'query_type_' . $attribute ] ) && in_array( $_GET[ 'query_type_' . $attribute ], array( 'and', 'or' ), true ) ? wc_clean( wp_unslash( $_GET[ 'query_type_' . $attribute ] ) ) : ''; // WPCS: sanitization ok, input var ok.
self::$_chosen_attributes[ $taxonomy ]['terms'] = array_map( 'sanitize_title', $filter_terms ); // Ensures correct encoding.
self::$_chosen_attributes[ $taxonomy ]['query_type'] = $query_type ? $query_type : apply_filters( 'woocommerce_layered_nav_default_query_type', 'and' );
}
@ -812,6 +760,73 @@ class WC_Query {
return self::$_chosen_attributes;
}
/**
* Remove the add-to-cart param from pagination urls.
*
* @param string $url URL.
* @return string
*/
public function remove_add_to_cart_pagination( $url ) {
return remove_query_arg( 'add-to-cart', $url );
}
// @codingStandardsIgnoreStart
/**
* Order by rating post clauses.
*
* @deprecated 3.0.0
* @param array $args
* @return array
*/
public function order_by_rating_post_clauses( $args ) {
global $wpdb;
wc_deprecated_function( 'order_by_rating_post_clauses', '3.0' );
$args['fields'] .= ", AVG( $wpdb->commentmeta.meta_value ) as average_rating ";
$args['where'] .= " AND ( $wpdb->commentmeta.meta_key = 'rating' OR $wpdb->commentmeta.meta_key IS null ) ";
$args['join'] .= "
LEFT OUTER JOIN $wpdb->comments ON($wpdb->posts.ID = $wpdb->comments.comment_post_ID)
LEFT JOIN $wpdb->commentmeta ON($wpdb->comments.comment_ID = $wpdb->commentmeta.comment_id)
";
$args['orderby'] = "average_rating DESC, $wpdb->posts.post_date DESC";
$args['groupby'] = "$wpdb->posts.ID";
return $args;
}
/**
* Return a meta query for filtering by rating.
*
* @deprecated 3.0.0 Replaced with taxonomy.
* @return array
*/
public function rating_filter_meta_query() {
return array();
}
/**
* Returns a meta query to handle product visibility.
*
* @deprecated 3.0.0 Replaced with taxonomy.
* @param string $compare (default: 'IN')
* @return array
*/
public function visibility_meta_query( $compare = 'IN' ) {
return array();
}
/**
* Returns a meta query to handle product stock status.
*
* @deprecated 3.0.0 Replaced with taxonomy.
* @param string $status (default: 'instock')
* @return array
*/
public function stock_status_meta_query( $status = 'instock' ) {
return array();
}
/**
* Layered nav init.
*
@ -840,4 +855,23 @@ class WC_Query {
public function layered_nav_query( $deprecated ) {
wc_deprecated_function( 'layered_nav_query', '2.6' );
}
/**
* Search post excerpt.
*
* @deprecated 3.2.0 - Not needed anymore since WordPress 4.5.
*/
public function search_post_excerpt( $where = '' ) {
wc_deprecated_function( 'WC_Query::search_post_excerpt', '3.2.0', 'Excerpt added to search query by default since WordPress 4.5.' );
return $where;
}
/**
* Remove the posts_where filter.
* @deprecated 3.2.0 - Nothing to remove anymore because search_post_excerpt() is deprecated.
*/
public function remove_posts_where() {
wc_deprecated_function( 'WC_Query::remove_posts_where', '3.2.0', 'Nothing to remove anymore because search_post_excerpt() is deprecated.' );
}
// @codingStandardsIgnoreEnd
}

View File

@ -66,13 +66,14 @@ class WC_Regenerate_Images {
$size_settings = wc_get_image_size( $size );
if ( isset( $imagemeta['sizes'], $imagemeta['sizes'][ $size ] ) ) {
if ( in_array( $size, array( 'woocommerce_thumbnail' ), true ) && isset( $imagemeta['sizes'], $imagemeta['sizes'][ $size ] ) ) {
if ( $imagemeta['sizes'][ $size ]['width'] !== $size_settings['width'] || $imagemeta['sizes'][ $size ]['height'] !== $size_settings['height'] ) {
$image = self::resize_and_return_image( $attachment_id, $image, $size, $icon );
}
} else {
$image = self::resize_and_return_image( $attachment_id, $image, $size, $icon );
}
return $image;
}

View File

@ -18,19 +18,19 @@ if ( ! defined( 'ABSPATH' ) ) {
class WC_Session_Handler extends WC_Session {
/** @var string cookie name */
private $_cookie;
protected $_cookie;
/** @var string session due to expire timestamp */
private $_session_expiring;
protected $_session_expiring;
/** @var string session expiration timestamp */
private $_session_expiration;
protected $_session_expiration;
/** $var bool Bool based on whether a cookie exists **/
private $_has_cookie = false;
protected $_has_cookie = false;
/** @var string Custom session table name */
private $_table;
protected $_table;
/**
* Constructor for the session class.

View File

@ -1,25 +1,27 @@
<?php
/**
* Handles storage and retrieval of shipping zones
*
* @package WooCommerce/Classes
* @author Automattic
* @version 3.3.0
* @since 2.6.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles storage and retrieval of shipping zones
*
* @class WC_Shipping_Zones
* @since 2.6.0
* @version 3.0.0
* @package WooCommerce/Classes
* @category Class
* @author WooCommerce
* Shipping zones class.
*/
class WC_Shipping_Zones {
/**
* Get shipping zones from the database
* Get shipping zones from the database.
*
* @since 2.6.0
* @return array of arrays
* @return array Array of arrays.
*/
public static function get_zones() {
$data_store = WC_Data_Store::load( 'shipping-zone' );
@ -39,8 +41,9 @@ class WC_Shipping_Zones {
/**
* Get shipping zone using it's ID
*
* @since 2.6.0
* @param int $zone_id
* @param int $zone_id Zone ID.
* @return WC_Shipping_Zone|bool
*/
public static function get_zone( $zone_id ) {
@ -49,12 +52,15 @@ class WC_Shipping_Zones {
/**
* Get shipping zone by an ID.
*
* @since 2.6.0
* @param string $by zone_id or instance_id
* @param int $id
* @param string $by Get by 'zone_id' or 'instance_id'.
* @param int $id ID.
* @return WC_Shipping_Zone|bool
*/
public static function get_zone_by( $by = 'zone_id', $id = 0 ) {
$zone_id = false;
switch ( $by ) {
case 'zone_id':
$zone_id = $id;
@ -77,11 +83,10 @@ class WC_Shipping_Zones {
}
/**
* Get shipping zone using it's ID
* Get shipping zone using it's ID.
*
* @since 2.6.0
*
* @param $instance_id
*
* @param int $instance_id Instance ID.
* @return bool|WC_Shipping_Method
*/
public static function get_shipping_method( $instance_id ) {
@ -102,7 +107,8 @@ class WC_Shipping_Zones {
/**
* Delete a zone using it's ID
* @param int $zone_id
*
* @param int $zone_id Zone ID.
* @since 2.6.0
*/
public static function delete_zone( $zone_id ) {
@ -112,9 +118,10 @@ class WC_Shipping_Zones {
/**
* Find a matching zone for a given package.
*
* @since 2.6.0
* @uses wc_make_numeric_postcode()
* @param object $package
* @param array $package Shipping package.
* @return WC_Shipping_Zone
*/
public static function get_zone_matching_package( $package ) {

View File

@ -278,8 +278,11 @@ class WC_Shipping {
/**
* See if package is shippable.
* @param array $package
* @return boolean
*
* Packages are shippable until proven otherwise e.g. after getting a shipping country.
*
* @param array $package Package of cart items.
* @return bool
*/
protected function is_package_shippable( $package ) {
@ -297,43 +300,44 @@ class WC_Shipping {
*
* Calculates each shipping methods cost. Rates are stored in the session based on the package hash to avoid re-calculation every page load.
*
* @param array $package cart items
* @param array $package Package of cart items.
* @param int $package_key Index of the package being calculated. Used to cache multiple package rates.
*
* @return array|bool
*/
public function calculate_shipping_for_package( $package = array(), $package_key = 0 ) {
if ( ! $this->enabled || empty( $package ) || ! $this->is_package_shippable( $package ) ) {
// If shipping is disabled or the package is invalid, return false.
if ( ! $this->enabled || empty( $package ) ) {
return false;
}
// Check if we need to recalculate shipping for this package
$package['rates'] = array();
// If the package is not shippable, e.g. trying to ship to an invalid country, do not calculate rates.
if ( $this->is_package_shippable( $package ) ) {
// Check if we need to recalculate shipping for this package.
$package_to_hash = $package;
// Remove data objects so hashes are consistent
// Remove data objects so hashes are consistent.
foreach ( $package_to_hash['contents'] as $item_id => $item ) {
unset( $package_to_hash['contents'][ $item_id ]['data'] );
}
$package_hash = 'wc_ship_' . md5( json_encode( $package_to_hash ) . WC_Cache_Helper::get_transient_version( 'shipping' ) );
$package_hash = 'wc_ship_' . md5( wp_json_encode( $package_to_hash ) . WC_Cache_Helper::get_transient_version( 'shipping' ) );
$session_key = 'shipping_for_package_' . $package_key;
$stored_rates = WC()->session->get( $session_key );
if ( ! is_array( $stored_rates ) || $package_hash !== $stored_rates['package_hash'] || 'yes' === get_option( 'woocommerce_shipping_debug_mode', 'no' ) ) {
// Calculate shipping method rates
$package['rates'] = array();
foreach ( $this->load_shipping_methods( $package ) as $shipping_method ) {
// Shipping instances need an ID
if ( ! $shipping_method->supports( 'shipping-zones' ) || $shipping_method->get_instance_id() ) {
$package['rates'] = $package['rates'] + $shipping_method->get_rates_for_package( $package ); // + instead of array_merge maintains numeric keys
}
}
// Filter the calculated rates
// Filter the calculated rates.
$package['rates'] = apply_filters( 'woocommerce_package_rates', $package['rates'], $package );
// Store in session to avoid recalculation
// Store in session to avoid recalculation.
WC()->session->set( $session_key, array(
'package_hash' => $package_hash,
'rates' => $package['rates'],
@ -341,7 +345,7 @@ class WC_Shipping {
} else {
$package['rates'] = $stored_rates['rates'];
}
}
return $package;
}

Some files were not shown because too many files have changed in this diff Show More