Merge branch 'master' into fix/18674

This commit is contained in:
Mike Jolley 2018-01-31 16:29:08 +00:00
commit 40c59d31f2
10 changed files with 274 additions and 232 deletions

View File

@ -101,6 +101,10 @@ class WC_Admin_Post_Types {
new WC_Admin_List_Table_Products();
break;
}
// Ensure the table handler is only loaded once. Prevents multiple loads if a plugin calls check_ajax_referer many times.
remove_action( 'current_screen', array( $this, 'setup_screen' ) );
remove_action( 'check_ajax_referer', array( $this, 'setup_screen' ) );
}
/**

View File

@ -674,7 +674,7 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Products_Controller
'context' => array( 'view', 'edit' ),
),
'date_on_sale_to_gmt' => array(
'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce' ),
'description' => __( 'End date of sale price, as GMT.', 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
),

View File

@ -4,8 +4,6 @@
*
* Handles requests to the /products endpoint.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.6.0
*/
@ -61,7 +59,8 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
* Register the routes for products.
*/
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
register_rest_route(
$this->namespace, '/' . $this->rest_base, array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
@ -75,9 +74,11 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
)
);
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
@ -89,9 +90,11 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'context' => $this->get_context_param( array(
'context' => $this->get_context_param(
array(
'default' => 'view',
) ),
)
),
),
),
array(
@ -113,9 +116,11 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
)
);
register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
register_rest_route(
$this->namespace, '/' . $this->rest_base . '/batch', array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'batch_items' ),
@ -123,7 +128,8 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
'schema' => array( $this, 'get_public_batch_schema' ),
) );
)
);
}
/**
@ -253,19 +259,23 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
$skus[] = $request['sku'];
}
$args['meta_query'] = $this->add_meta_query( $args, array( // WPCS: slow query ok.
$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
$args, array(
'key' => '_sku',
'value' => $skus,
'compare' => 'IN',
) );
)
);
}
// Filter by tax class.
if ( ! empty( $request['tax_class'] ) ) {
$args['meta_query'] = $this->add_meta_query( $args, array( // WPCS: slow query ok.
$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
$args, array(
'key' => '_tax_class',
'value' => 'standard' !== $request['tax_class'] ? $request['tax_class'] : '',
) );
)
);
}
// Price filter.
@ -275,10 +285,12 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
// Filter product in stock or out of stock.
if ( is_bool( $request['in_stock'] ) ) {
$args['meta_query'] = $this->add_meta_query( $args, array( // WPCS: slow query ok.
$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
$args, array(
'key' => '_stock_status',
'value' => true === $request['in_stock'] ? 'instock' : 'outofstock',
) );
)
);
}
// Filter by on sale products.
@ -487,9 +499,11 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
*/
protected function get_attribute_options( $product_id, $attribute ) {
if ( isset( $attribute['is_taxonomy'] ) && $attribute['is_taxonomy'] ) {
return wc_get_product_terms( $product_id, $attribute['name'], array(
return wc_get_product_terms(
$product_id, $attribute['name'], array(
'fields' => 'names',
) );
)
);
} elseif ( isset( $attribute['value'] ) ) {
return array_map( 'trim', explode( '|', $attribute['value'] ) );
}
@ -683,9 +697,11 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
}
if ( 'variation' === $product->get_type() ) {
return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ), array(
return new WP_Error(
"woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ), array(
'status' => 404,
) );
)
);
}
// Post title.
@ -1086,10 +1102,12 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
// Set the image name if present.
if ( ! empty( $image['name'] ) ) {
wp_update_post( array(
wp_update_post(
array(
'ID' => $attachment_id,
'post_title' => $image['name'],
) );
)
);
}
// Set the image source if present, for future reference.
@ -1286,15 +1304,19 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
$result = false;
if ( ! $object || 0 === $object->get_id() ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array(
return new WP_Error(
"woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array(
'status' => 404,
) );
)
);
}
if ( 'variation' === $object->get_type() ) {
return new WP_Error( "woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ), array(
return new WP_Error(
"woocommerce_rest_invalid_{$this->post_type}_id", __( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ), array(
'status' => 404,
) );
)
);
}
$supports_trash = EMPTY_TRASH_DAYS > 0 && is_callable( array( $object, 'get_status' ) );
@ -1310,10 +1332,12 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
$supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object );
if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) {
return new WP_Error(
/* translators: %s: post type */
return new WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array(
"woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array(
'status' => rest_authorization_required_code(),
) );
)
);
}
$request->set_param( 'context', 'edit' );
@ -1339,19 +1363,23 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
} else {
// If we don't support trashing for this type, error out.
if ( ! $supports_trash ) {
return new WP_Error(
/* translators: %s: post type */
return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ), array(
'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ), array(
'status' => 501,
) );
)
);
}
// Otherwise, only trash if we haven't already.
if ( is_callable( array( $object, 'get_status' ) ) ) {
if ( 'trash' === $object->get_status() ) {
return new WP_Error(
/* translators: %s: post type */
return new WP_Error( 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ), array(
'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ), array(
'status' => 410,
) );
)
);
}
$object->delete();
@ -1360,10 +1388,12 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
}
if ( ! $result ) {
return new WP_Error(
/* translators: %s: post type */
return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array(
'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array(
'status' => 500,
) );
)
);
}
// Delete parent product transients.
@ -1823,7 +1853,7 @@ class WC_REST_Products_Controller extends WC_REST_Legacy_Products_Controller {
),
'images' => array(
'description' => __( 'List of images.', 'woocommerce' ),
'type' => 'object',
'type' => 'array',
'context' => array( 'view', 'edit' ),
'items' => array(
'type' => 'object',

View File

@ -4,8 +4,6 @@
*
* Handles requests to the /webhooks endpoint.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 2.6.0
*/
@ -38,6 +36,11 @@ class WC_REST_Webhooks_Controller extends WC_REST_Webhooks_V1_Controller {
*/
public function prepare_item_for_response( $id, $request ) {
$webhook = wc_get_webhook( $id );
if ( empty( $webhook ) || is_null( $webhook ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
}
$data = array(
'id' => $webhook->get_id(),
'name' => $webhook->get_name(),
@ -148,7 +151,7 @@ class WC_REST_Webhooks_Controller extends WC_REST_Webhooks_V1_Controller {
'readonly' => true,
),
'secret' => array(
'description' => __( "Secret key used to generate a hash of the delivered webhook and provided in the request headers. This will default is a MD5 hash from the current user's ID|username if not provided.", 'woocommerce' ),
'description' => __( "Secret key used to generate a hash of the delivered webhook and provided in the request headers. This will default to a MD5 hash from the current user's ID|username if not provided.", 'woocommerce' ),
'type' => 'string',
'context' => array( 'edit' ),
),

View File

@ -4,8 +4,6 @@
*
* Handles requests to the /webhooks endpoint.
*
* @author WooThemes
* @category API
* @package WooCommerce/API
* @since 3.0.0
*/
@ -362,7 +360,7 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
$id = (int) $request['id'];
$webhook = wc_get_webhook( $id );
if ( empty( $id ) || is_null( $webhook->get_id() ) ) {
if ( empty( $webhook ) || is_null( $webhook ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
}
@ -521,12 +519,17 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
/**
* Prepare a single webhook output for response.
*
* @param int $id Webhook ID.
* @param int $id Webhook ID or object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response $response Response data.
*/
public function prepare_item_for_response( $id, $request ) {
$webhook = wc_get_webhook( (int) $id );
$webhook = wc_get_webhook( $id );
if ( empty( $webhook ) || is_null( $webhook ) ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
}
$data = array(
'id' => $webhook->get_id(),
'name' => $webhook->get_name(),
@ -644,7 +647,7 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
'readonly' => true,
),
'secret' => array(
'description' => __( "Secret key used to generate a hash of the delivered webhook and provided in the request headers. This will default is a MD5 hash from the current user's ID|username if not provided.", 'woocommerce' ),
'description' => __( "Secret key used to generate a hash of the delivered webhook and provided in the request headers. This will default to a MD5 hash from the current user's ID|username if not provided.", 'woocommerce' ),
'type' => 'string',
'context' => array( 'edit' ),
),

View File

@ -390,7 +390,7 @@ class WC_Structured_Data {
continue;
}
$product = apply_filters( 'woocommerce_order_item_product', $order->get_product_from_item( $item ), $item );
$product = $order->get_product_from_item( $item );
$product_exists = is_object( $product );
$is_visible = $product_exists && $product->is_visible();

View File

@ -357,7 +357,7 @@ class WC_Shop_Customizer {
'woocommerce_default_catalog_orderby',
array(
'label' => __( 'Default product sorting', 'woocommerce' ),
'description' => __( 'How should products by sorted in the catalog by default?', 'woocommerce' ),
'description' => __( 'How should products be sorted in the catalog by default?', 'woocommerce' ),
'section' => 'woocommerce_product_catalog',
'settings' => 'woocommerce_default_catalog_orderby',
'type' => 'select',

View File

@ -204,6 +204,8 @@ add_action( 'woocommerce_after_shop_loop', 'woocommerce_reset_loop', 999 );
* @return mixed
*/
function wc_get_loop_prop( $prop, $default = '' ) {
wc_setup_loop(); // Ensure shop loop is setup.
return isset( $GLOBALS['woocommerce_loop'], $GLOBALS['woocommerce_loop'][ $prop ] ) ? $GLOBALS['woocommerce_loop'][ $prop ] : $default;
}
@ -323,7 +325,9 @@ function wc_get_default_products_per_row() {
$columns = apply_filters( 'loop_shop_columns', $columns );
}
return absint( $columns );
$columns = absint( $columns );
return max( 1, $columns );
}
/**

View File

@ -2,8 +2,6 @@
/**
* WooCommerce Webhook functions
*
* @author Automattic
* @category Core
* @package WooCommerce/Functions
* @version 3.3.0
*/
@ -117,11 +115,11 @@ function wc_load_webhooks() {
/**
* Get webhook.
*
* @param int $id Webhook ID.
* @param int|WC_Webhook $id Webhook ID or object.
* @return WC_Webhook|null
*/
function wc_get_webhook( $id ) {
$webhook = new WC_Webhook( (int) $id );
$webhook = new WC_Webhook( $id );
return 0 !== $webhook->get_id() ? $webhook : null;
}

View File

@ -52,7 +52,7 @@ if ( $show_downloads ) {
do_action( 'woocommerce_order_details_before_order_table_items', $order );
foreach ( $order_items as $item_id => $item ) {
$product = apply_filters( 'woocommerce_order_item_product', $item->get_product(), $item );
$product = $item->get_product();
wc_get_template( 'order/order-details-item.php', array(
'order' => $order,