From bef88f2e823bd1370a6924cbd4f451d2efa8f82f Mon Sep 17 00:00:00 2001 From: Beka Rice Date: Tue, 8 Sep 2015 14:01:49 -0400 Subject: [PATCH 1/5] [2.5] Filter when purchase note is showed For WooCommerce 2.5: adds `woocommerce_purchase_note_order_statuses` filter and pulls purchase note logic up from /order/order-details-item.php --- templates/order/order-details-item.php | 4 ++-- templates/order/order-details.php | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/templates/order/order-details-item.php b/templates/order/order-details-item.php index 73265105952..050d0b9b7a9 100644 --- a/templates/order/order-details-item.php +++ b/templates/order/order-details-item.php @@ -4,7 +4,7 @@ * * @author WooThemes * @package WooCommerce/Templates - * @version 2.4.0 + * @version 2.5.0 */ if ( ! defined( 'ABSPATH' ) ) { @@ -35,7 +35,7 @@ if ( ! apply_filters( 'woocommerce_order_item_visible', true, $item ) ) { get_formatted_line_subtotal( $item ); ?> -has_status( array( 'completed', 'processing' ) ) && ( $purchase_note = get_post_meta( $product->id, '_purchase_note', true ) ) ) : ?> + diff --git a/templates/order/order-details.php b/templates/order/order-details.php index 74742425144..4dc8f9fcbc3 100644 --- a/templates/order/order-details.php +++ b/templates/order/order-details.php @@ -4,7 +4,7 @@ * * @author WooThemes * @package WooCommerce/Templates - * @version 2.4.0 + * @version 2.5.0 */ if ( ! defined( 'ABSPATH' ) ) { @@ -12,6 +12,8 @@ if ( ! defined( 'ABSPATH' ) ) { } $order = wc_get_order( $order_id ); + +$show_purchase_note = $order->has_status( apply_filters( 'woocommerce_purchase_note_order_statuses', array( 'completed', 'processing' ) ) ); ?>

@@ -24,11 +26,16 @@ $order = wc_get_order( $order_id ); get_items() as $item_id => $item ) { + $product = apply_filters( 'woocommerce_order_item_product', $order->get_product_from_item( $item ), $item ); + $purchase_note = get_post_meta( $product->id, '_purchase_note', true ); + wc_get_template( 'order/order-details-item.php', array( - 'order' => $order, - 'item_id' => $item_id, - 'item' => $item, - 'product' => apply_filters( 'woocommerce_order_item_product', $order->get_product_from_item( $item ), $item ) + 'order' => $order, + 'item_id' => $item_id, + 'item' => $item, + 'show_purchase_note' => $show_purchase_note, + 'purchase_note' => $purchase_note, + 'product' => $product, ) ); } ?> From f781d393c83a1c887ec29e931622faed4e9e2f65 Mon Sep 17 00:00:00 2001 From: Akeda Bagus Date: Wed, 9 Sep 2015 20:38:11 +0700 Subject: [PATCH 2/5] Added API support for product shipping classes. This change implements GET, POST, PUT, and DELETE handlers for shipping classes endpoint, /products/shipping_classes. Fixes #8948. --- includes/api/class-wc-api-products.php | 220 +++++++++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/includes/api/class-wc-api-products.php b/includes/api/class-wc-api-products.php index 6f6a1906bf5..582f66c4ed5 100644 --- a/includes/api/class-wc-api-products.php +++ b/includes/api/class-wc-api-products.php @@ -71,6 +71,19 @@ class WC_API_Products extends WC_API_Resource { array( array( $this, 'get_product_category' ), WC_API_Server::READABLE ), ); + # GET/POST /products/shipping_classes + $routes[ $this->base . '/shipping_classes' ] = array( + array( array( $this, 'get_product_shipping_classes' ), WC_API_Server::READABLE ), + array( array( $this, 'create_product_shipping_class' ), WC_API_Server::CREATABLE | WC_API_Server::ACCEPT_DATA ), + ); + + # GET/PUT/DELETE /products/shipping_classes/ + $routes[ $this->base . '/shipping_classes/(?P\d+)' ] = array( + array( array( $this, 'get_product_shipping_class' ), WC_API_Server::READABLE ), + array( array( $this, 'edit_product_shipping_class' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ), + array( array( $this, 'delete_product_shipping_class' ), WC_API_Server::DELETABLE ), + ); + # GET/POST /products/attributes $routes[ $this->base . '/attributes' ] = array( array( array( $this, 'get_product_attributes' ), WC_API_Server::READABLE ), @@ -2394,4 +2407,211 @@ class WC_API_Products extends WC_API_Resource { return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); } } + + /** + * Get a listing of product shipping classes. + * + * @since 2.5.0 + * @param string|null $fields Fields to limit response to + * @return array|WP_Error List of product shipping classes if succeed, + * otherwise WP_Error will be returned + */ + public function get_product_shipping_classes( $fields = null ) { + try { + // Permissions check + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_shipping_classes', __( 'You do not have permission to read product shipping classes', 'woocommerce' ), 401 ); + } + + $product_shipping_classes = array(); + + $terms = get_terms( 'product_shipping_class', array( 'hide_empty' => false, 'fields' => 'ids' ) ); + + foreach ( $terms as $term_id ) { + $product_shipping_classes[] = current( $this->get_product_shipping_class( $term_id, $fields ) ); + } + + return array( 'product_shipping_classes' => apply_filters( 'woocommerce_api_product_shipping_classes_response', $product_shipping_classes, $terms, $fields, $this ) ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Get the product shipping class for the given ID. + * + * @since 2.5.0 + * @param string $id Product shipping class term ID + * @param string|null $fields Fields to limit response to + * @return array|WP_Error Product shipping class if succeed, otherwise + * WP_Error will be returned + */ + public function get_product_shipping_class( $id, $fields = null ) { + try { + $id = absint( $id ); + if ( ! $id ) { + throw new WC_API_Exception( 'woocommerce_api_invalid_product_shipping_class_id', __( 'Invalid product shipping class ID', 'woocommerce' ), 400 ); + } + + // Permissions check + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_shipping_classes', __( 'You do not have permission to read product shipping classes', 'woocommerce' ), 401 ); + } + + $term = get_term( $id, 'product_shipping_class' ); + + if ( is_wp_error( $term ) || is_null( $term ) ) { + throw new WC_API_Exception( 'woocommerce_api_invalid_product_shipping_class_id', __( 'A product shipping class with the provided ID could not be found', 'woocommerce' ), 404 ); + } + + $term_id = intval( $term->term_id ); + + $product_shipping_class = array( + 'id' => $term_id, + 'name' => $term->name, + 'slug' => $term->slug, + 'parent' => $term->parent, + 'description' => $term->description, + 'count' => intval( $term->count ) + ); + + return array( 'product_shipping_class' => apply_filters( 'woocommerce_api_product_shipping_class_response', $product_shipping_class, $id, $fields, $term, $this ) ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Create a new product shipping class. + * + * @since 2.5.0 + * @param array $data Posted data + * @return array|WP_Error Product shipping class if succeed, otherwise + * WP_Error will be returned + */ + public function create_product_shipping_class( $data ) { + global $wpdb; + + try { + if ( ! isset( $data['product_shipping_class'] ) ) { + throw new WC_API_Exception( 'woocommerce_api_missing_product_shipping_class_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'product_shipping_class' ), 400 ); + } + + // Check permissions + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_product_shipping_class', __( 'You do not have permission to create product shipping classes', 'woocommerce' ), 401 ); + } + + $defaults = array( + 'name' => '', + 'slug' => '', + 'description' => '', + 'parent' => 0, + ); + + $data = wp_parse_args( $data['product_shipping_class'], $defaults ); + $data = apply_filters( 'woocommerce_api_create_product_shipping_class_data', $data, $this ); + + $name = $data['name']; + unset( $data['name'] ); + + // Check parent. + $data['parent'] = absint( $data['parent'] ); + if ( $data['parent'] ) { + $parent = get_term_by( 'term_taxonomy_id', $data['parent'], 'product_shipping_class' ); + if ( ! $parent ) { + throw new WC_API_Exception( 'woocommerce_api_invalid_product_shipping_class_parent', __( 'Product shipping class parent is invalid', 'woocommerce' ), 400 ); + } + } + + $insert = wp_insert_term( $name, 'product_shipping_class', $data ); + if ( is_wp_error( $insert ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_create_product_shipping_class', $insert->get_error_message(), 400 ); + } + + do_action( 'woocommerce_api_create_product_shipping_class', $insert['term_taxonomy_id'], $data ); + + $this->server->send_status( 201 ); + + return $this->get_product_shipping_class( $insert['term_taxonomy_id'] ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Edit a product shipping class. + * + * @since 2.5.0 + * @param int $id Product shipping class term ID + * @param array $data Posted data + * @return array|WP_Error Product shipping class if succeed, otherwise + * WP_Error will be returned + */ + public function edit_product_shipping_class( $id, $data ) { + global $wpdb; + + try { + if ( ! isset( $data['product_shipping_class'] ) ) { + throw new WC_API_Exception( 'woocommerce_api_missing_product_shipping_class', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'product_shipping_class' ), 400 ); + } + + $id = absint( $id ); + $data = $data['product_shipping_class']; + + // Check permissions + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_edit_product_shipping_class', __( 'You do not have permission to edit product shipping classes', 'woocommerce' ), 401 ); + } + + $data = apply_filters( 'woocommerce_api_edit_product_shipping_class_data', $data, $this ); + $shipping_class = $this->get_product_shipping_class( $id ); + + if ( is_wp_error( $shipping_class ) ) { + return $shipping_class; + } + + $update = wp_update_term( $id, 'product_shipping_class', $data ); + if ( is_wp_error( $update ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_edit_product_shipping_class', __( 'Could not edit the shipping class', 'woocommerce' ), 400 ); + } + + do_action( 'woocommerce_api_edit_product_shipping_class', $id, $data ); + + return $this->get_product_shipping_class( $id ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Delete a product shipping class. + * + * @since 2.5.0 + * @param int $id Product shipping class term ID + * @return array|WP_Error Success message if succeed, otherwise WP_Error + * will be returned + */ + public function delete_product_shipping_class( $id ) { + global $wpdb; + + try { + // Check permissions + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_delete_product_shipping_class', __( 'You do not have permission to delete product shipping classes', 'woocommerce' ), 401 ); + } + + $id = absint( $id ); + $deleted = wp_delete_term( $id, 'product_shipping_class' ); + if ( ! $deleted || is_wp_error( $deleted ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_delete_product_shipping_class', __( 'Could not delete the shipping class', 'woocommerce' ), 401 ); + } + + do_action( 'woocommerce_api_delete_product_shipping_class', $id, $this ); + + return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_shipping_class' ) ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } } From 2980ffd66bfd988a57b51c941adc34a58ba25fc6 Mon Sep 17 00:00:00 2001 From: Akeda Bagus Date: Thu, 10 Sep 2015 13:33:05 +0700 Subject: [PATCH 3/5] Added support to POST, PUT, and DELETE categories. --- includes/api/class-wc-api-products.php | 259 ++++++++++++++++++++++++- 1 file changed, 251 insertions(+), 8 deletions(-) diff --git a/includes/api/class-wc-api-products.php b/includes/api/class-wc-api-products.php index 582f66c4ed5..9fe527a29ea 100644 --- a/includes/api/class-wc-api-products.php +++ b/includes/api/class-wc-api-products.php @@ -61,14 +61,17 @@ class WC_API_Products extends WC_API_Resource { array( array( $this, 'get_product_orders' ), WC_API_Server::READABLE ), ); - # GET /products/categories + # GET/POST /products/categories $routes[ $this->base . '/categories' ] = array( array( array( $this, 'get_product_categories' ), WC_API_Server::READABLE ), + array( array( $this, 'create_product_category' ), WC_API_Server::CREATABLE | WC_API_Server::ACCEPT_DATA ), ); - # GET /products/categories/ + # GET/PUT/DELETE /products/categories/ $routes[ $this->base . '/categories/(?P\d+)' ] = array( array( array( $this, 'get_product_category' ), WC_API_Server::READABLE ), + array( array( $this, 'edit_product_category' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ), + array( array( $this, 'delete_product_category' ), WC_API_Server::DELETABLE ), ); # GET/POST /products/shipping_classes @@ -570,6 +573,198 @@ class WC_API_Products extends WC_API_Resource { } } + /** + * Create a new product category. + * + * @since 2.5.0 + * @param array $data Posted data + * @return array|WP_Error Product category if succeed, otherwise WP_Error + * will be returned + */ + public function create_product_category( $data ) { + global $wpdb; + + try { + if ( ! isset( $data['product_category'] ) ) { + throw new WC_API_Exception( 'woocommerce_api_missing_product_category_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'product_category' ), 400 ); + } + + // Check permissions + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_product_category', __( 'You do not have permission to create product categories', 'woocommerce' ), 401 ); + } + + $defaults = array( + 'name' => '', + 'slug' => '', + 'description' => '', + 'parent' => 0, + 'display' => 'default', + 'image' => '', + ); + + $data = wp_parse_args( $data['product_category'], $defaults ); + $data = apply_filters( 'woocommerce_api_create_product_category_data', $data, $this ); + + $name = $data['name']; + unset( $data['name'] ); + + // Check parent. + $data['parent'] = absint( $data['parent'] ); + if ( $data['parent'] ) { + $parent = get_term_by( 'term_taxonomy_id', $data['parent'], 'product_cat' ); + if ( ! $parent ) { + throw new WC_API_Exception( 'woocommerce_api_invalid_product_category_parent', __( 'Product category parent is invalid', 'woocommerce' ), 400 ); + } + } + + $display_type = $data['display']; + unset( $data['display'] ); + + // If value of image is numeric, assume value as image_id. + $image = $data['image']; + if ( is_numeric( $image ) ) { + $image_id = absint( $image ); + } else if ( ! empty( $image ) ) { + $upload = $this->upload_product_image( esc_url_raw( $image ) ); + $image_id = $this->set_product_category_image_as_attachment( $upload ); + } + unset( $data['image'] ); + + $insert = wp_insert_term( $name, 'product_cat', $data ); + if ( is_wp_error( $insert ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_create_product_category', $insert->get_error_message(), 400 ); + } + + update_woocommerce_term_meta( $insert['term_taxonomy_id'], 'display_type', esc_attr( $display_type ) ); + + // Check if image_id is a valid image attachment before updating the term meta. + if ( wp_attachment_is_image( $image_id ) ) { + update_woocommerce_term_meta( $insert['term_taxonomy_id'], 'thumbnail_id', $image_id ); + } + + do_action( 'woocommerce_api_create_product_category', $insert['term_taxonomy_id'], $data ); + + $this->server->send_status( 201 ); + + return $this->get_product_category( $insert['term_taxonomy_id'] ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Edit a product category. + * + * @since 2.5.0 + * @param int $id Product category term ID + * @param array $data Posted data + * @return array|WP_Error Product category if succeed, otherwise WP_Error + * will be returned + */ + public function edit_product_category( $id, $data ) { + global $wpdb; + + try { + if ( ! isset( $data['product_category'] ) ) { + throw new WC_API_Exception( 'woocommerce_api_missing_product_category', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'product_category' ), 400 ); + } + + $id = absint( $id ); + $data = $data['product_category']; + + // Check permissions. + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_edit_product_category', __( 'You do not have permission to edit product categories', 'woocommerce' ), 401 ); + } + + $data = apply_filters( 'woocommerce_api_edit_product_category_data', $data, $this ); + $category = $this->get_product_category( $id ); + + if ( is_wp_error( $category ) ) { + return $category; + } + + $display_type = ''; + if ( isset( $data['display'] ) ) { + $display_type = $data['display']; + unset( $data['display'] ); + } + + if ( isset( $data['image'] ) ) { + // If value of image is numeric, assume value as image_id. + $image = $data['image']; + if ( is_numeric( $image ) ) { + $image_id = absint( $image ); + } else if ( ! empty( $image ) ) { + $upload = $this->upload_product_image( esc_url_raw( $image ) ); + $image_id = $this->set_product_category_image_as_attachment( $upload ); + } + + // In case client supplies invalid image or wants to unset category + // image. + if ( ! wp_attachment_is_image( $image_id ) ) { + $image_id = ''; + } + + unset( $data['image'] ); + } + + $update = wp_update_term( $id, 'product_cat', $data ); + if ( is_wp_error( $update ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_edit_product_catgory', __( 'Could not edit the category', 'woocommerce' ), 400 ); + } + + if ( ! empty( $display_type ) ) { + update_woocommerce_term_meta( $update['term_taxonomy_id'], 'display_type', esc_attr( $display_type ) ); + } + + if ( isset( $image_id ) ) { + update_woocommerce_term_meta( $update['term_taxonomy_id'], 'thumbnail_id', $image_id ); + } + + do_action( 'woocommerce_api_edit_product_category', $id, $data ); + + return $this->get_product_category( $id ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Delete a product category. + * + * @since 2.5.0 + * @param int $id Product category term ID + * @return array|WP_Error Success message if succeed, otherwise WP_Error + * will be returned + */ + public function delete_product_category( $id ) { + global $wpdb; + + try { + // Check permissions + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_delete_product_category', __( 'You do not have permission to delete product category', 'woocommerce' ), 401 ); + } + + $id = absint( $id ); + $deleted = wp_delete_term( $id, 'product_cat' ); + if ( ! $deleted || is_wp_error( $deleted ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_delete_product_category', __( 'Could not delete the category', 'woocommerce' ), 401 ); + } + + // When a term is deleted, delete its meta. + $wpdb->delete( $wpdb->woocommerce_termmeta, array( 'woocommerce_term_id' => $id ), array( '%d' ) ); + + do_action( 'woocommerce_api_delete_product_category', $id, $this ); + + return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_category' ) ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + /** * Helper method to get product post objects * @@ -1800,13 +1995,38 @@ class WC_API_Products extends WC_API_Resource { * @return int|WP_Error attachment id */ public function upload_product_image( $image_url ) { + return $this->upload_image_from_url( $image_url ); + } + + /** + * Upload product category image from URL. + * + * @since 2.5.0 + * @param string $image_url + * @return int|WP_Error attachment id + */ + public function upload_product_category_image( $image_url ) { + return $this->upload_image_from_url( $image_url, 'product_category_image' ); + } + + /** + * Upload image from URL. + * + * @throws WC_API_Exception + * + * @since 2.5.0 + * @param string $image_url + * @param string $upload_for + * @return int|WP_Error Attachment id + */ + protected function upload_image_from_url( $image_url, $upload_for = 'product_image' ) { $file_name = basename( current( explode( '?', $image_url ) ) ); $wp_filetype = wp_check_filetype( $file_name, null ); $parsed_url = @parse_url( $image_url ); - // Check parsed URL + // Check parsed URL. if ( ! $parsed_url || ! is_array( $parsed_url ) ) { - throw new WC_API_Exception( 'woocommerce_api_invalid_product_image', sprintf( __( 'Invalid URL %s', 'woocommerce' ), $image_url ), 400 ); + throw new WC_API_Exception( 'woocommerce_api_invalid_' . $upload_for, sprintf( __( 'Invalid URL %s', 'woocommerce' ), $image_url ), 400 ); } // Ensure url is valid @@ -1818,7 +2038,7 @@ class WC_API_Products extends WC_API_Resource { ) ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { - throw new WC_API_Exception( 'woocommerce_api_invalid_remote_product_image', sprintf( __( 'Error getting remote image %s', 'woocommerce' ), $image_url ), 400 ); + throw new WC_API_Exception( 'woocommerce_api_invalid_remote_' . $upload_for, sprintf( __( 'Error getting remote image %s', 'woocommerce' ), $image_url ), 400 ); } // Ensure we have a file name and type @@ -1838,7 +2058,7 @@ class WC_API_Products extends WC_API_Resource { $upload = wp_upload_bits( $file_name, '', wp_remote_retrieve_body( $response ) ); if ( $upload['error'] ) { - throw new WC_API_Exception( 'woocommerce_api_product_image_upload_error', $upload['error'], 400 ); + throw new WC_API_Exception( 'woocommerce_api_' . $upload_for . '_upload_error', $upload['error'], 400 ); } // Get filesize @@ -1847,7 +2067,7 @@ class WC_API_Products extends WC_API_Resource { if ( 0 == $filesize ) { @unlink( $upload['file'] ); unset( $upload ); - throw new WC_API_Exception( 'woocommerce_api_product_image_upload_file_error', __( 'Zero size file downloaded', 'woocommerce' ), 400 ); + throw new WC_API_Exception( 'woocommerce_api_' . $upload_for . '_upload_file_error', __( 'Zero size file downloaded', 'woocommerce' ), 400 ); } unset( $response ); @@ -1856,7 +2076,7 @@ class WC_API_Products extends WC_API_Resource { } /** - * Get product image as attachment + * Sets product image as attachment and returns the attachment ID. * * @since 2.2 * @param integer $upload @@ -1864,6 +2084,29 @@ class WC_API_Products extends WC_API_Resource { * @return int */ protected function set_product_image_as_attachment( $upload, $id ) { + return $this->set_uploaded_image_as_attachment( $upload, $id ); + } + + /** + * Sets uploaded category image as attachment and returns the attachment ID. + * + * @since 2.5.0 + * @param integer $upload Upload information from wp_upload_bits + * @return int Attachment ID + */ + protected function set_product_category_image_as_attachment( $upload ) { + return $this->set_uploaded_image_as_attachment( $upload ); + } + + /** + * Set uploaded image as attachment. + * + * @since 2.5.0 + * @param array $upload Upload information from wp_upload_bits + * @param int $id Post ID. Default to 0. + * @return int Attachment ID + */ + protected function set_uploaded_image_as_attachment( $upload, $id = 0 ) { $info = wp_check_filetype( $upload['file'] ); $title = ''; $content = ''; From 6906eb4eaed5b71305b48a0f239a18bbbe9436b8 Mon Sep 17 00:00:00 2001 From: Akeda Bagus Date: Thu, 10 Sep 2015 16:58:48 +0700 Subject: [PATCH 4/5] Added support to GET, POST, PUT, and DELETE tags. --- includes/api/class-wc-api-products.php | 203 +++++++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/includes/api/class-wc-api-products.php b/includes/api/class-wc-api-products.php index 9fe527a29ea..9be3653bd8e 100644 --- a/includes/api/class-wc-api-products.php +++ b/includes/api/class-wc-api-products.php @@ -74,6 +74,19 @@ class WC_API_Products extends WC_API_Resource { array( array( $this, 'delete_product_category' ), WC_API_Server::DELETABLE ), ); + # GET/POST /products/tags + $routes[ $this->base . '/tags' ] = array( + array( array( $this, 'get_product_tags' ), WC_API_Server::READABLE ), + array( array( $this, 'create_product_tag' ), WC_API_Server::CREATABLE | WC_API_Server::ACCEPT_DATA ), + ); + + # GET/PUT/DELETE /products/tags/ + $routes[ $this->base . '/tags/(?P\d+)' ] = array( + array( array( $this, 'get_product_tag' ), WC_API_Server::READABLE ), + array( array( $this, 'edit_product_tag' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ), + array( array( $this, 'delete_product_tag' ), WC_API_Server::DELETABLE ), + ); + # GET/POST /products/shipping_classes $routes[ $this->base . '/shipping_classes' ] = array( array( array( $this, 'get_product_shipping_classes' ), WC_API_Server::READABLE ), @@ -765,6 +778,196 @@ class WC_API_Products extends WC_API_Resource { } } + /** + * Get a listing of product tags. + * + * @since 2.5.0 + * @param string|null $fields Fields to limit response to + * @return array Product tags + */ + public function get_product_tags( $fields = null ) { + try { + // Permissions check + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_tags', __( 'You do not have permission to read product tags', 'woocommerce' ), 401 ); + } + + $product_tags = array(); + + $terms = get_terms( 'product_tag', array( 'hide_empty' => false, 'fields' => 'ids' ) ); + + foreach ( $terms as $term_id ) { + $product_tags[] = current( $this->get_product_tag( $term_id, $fields ) ); + } + + return array( 'product_tags' => apply_filters( 'woocommerce_api_product_tags_response', $product_tags, $terms, $fields, $this ) ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Get the product tag for the given ID. + * + * @since 2.5.0 + * @param string $id Product tag term ID + * @param string|null $fields Fields to limit response to + * @return array Product tag + */ + public function get_product_tag( $id, $fields = null ) { + try { + $id = absint( $id ); + + // Validate ID + if ( empty( $id ) ) { + throw new WC_API_Exception( 'woocommerce_api_invalid_product_tag_id', __( 'Invalid product tag ID', 'woocommerce' ), 400 ); + } + + // Permissions check + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_product_tags', __( 'You do not have permission to read product tags', 'woocommerce' ), 401 ); + } + + $term = get_term( $id, 'product_tag' ); + + if ( is_wp_error( $term ) || is_null( $term ) ) { + throw new WC_API_Exception( 'woocommerce_api_invalid_product_tag_id', __( 'A product tag with the provided ID could not be found', 'woocommerce' ), 404 ); + } + + $term_id = intval( $term->term_id ); + + $tag = array( + 'id' => $term_id, + 'name' => $term->name, + 'slug' => $term->slug, + 'description' => $term->description, + 'count' => intval( $term->count ) + ); + + return array( 'product_tag' => apply_filters( 'woocommerce_api_product_tag_response', $tag, $id, $fields, $term, $this ) ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Create a new product tag. + * + * @since 2.5.0 + * @param array $data Posted data + * @return array|WP_Error Product tag if succeed, otherwise WP_Error + * will be returned + */ + public function create_product_tag( $data ) { + try { + if ( ! isset( $data['product_tag'] ) ) { + throw new WC_API_Exception( 'woocommerce_api_missing_product_tag_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'product_tag' ), 400 ); + } + + // Check permissions + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_product_tag', __( 'You do not have permission to create product tags', 'woocommerce' ), 401 ); + } + + $defaults = array( + 'name' => '', + 'slug' => '', + 'description' => '', + ); + + $data = wp_parse_args( $data['product_tag'], $defaults ); + $data = apply_filters( 'woocommerce_api_create_product_tag_data', $data, $this ); + + $name = $data['name']; + unset( $data['name'] ); + + $insert = wp_insert_term( $name, 'product_tag', $data ); + if ( is_wp_error( $insert ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_create_product_tag', $insert->get_error_message(), 400 ); + } + + do_action( 'woocommerce_api_create_product_tag', $insert['term_taxonomy_id'], $data ); + + $this->server->send_status( 201 ); + + return $this->get_product_tag( $insert['term_taxonomy_id'] ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Edit a product tag. + * + * @since 2.5.0 + * @param int $id Product tag term ID + * @param array $data Posted data + * @return array|WP_Error Product tag if succeed, otherwise WP_Error + * will be returned + */ + public function edit_product_tag( $id, $data ) { + try { + if ( ! isset( $data['product_tag'] ) ) { + throw new WC_API_Exception( 'woocommerce_api_missing_product_tag', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'product_tag' ), 400 ); + } + + $id = absint( $id ); + $data = $data['product_tag']; + + // Check permissions. + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_edit_product_tag', __( 'You do not have permission to edit product tags', 'woocommerce' ), 401 ); + } + + $data = apply_filters( 'woocommerce_api_edit_product_tag_data', $data, $this ); + $tag = $this->get_product_tag( $id ); + + if ( is_wp_error( $tag ) ) { + return $tag; + } + + $update = wp_update_term( $id, 'product_tag', $data ); + if ( is_wp_error( $update ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_edit_product_tag', __( 'Could not edit the tag', 'woocommerce' ), 400 ); + } + + do_action( 'woocommerce_api_edit_product_tag', $id, $data ); + + return $this->get_product_tag( $id ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + + /** + * Delete a product tag. + * + * @since 2.5.0 + * @param int $id Product tag term ID + * @return array|WP_Error Success message if succeed, otherwise WP_Error + * will be returned + */ + public function delete_product_tag( $id ) { + try { + // Check permissions + if ( ! current_user_can( 'manage_product_terms' ) ) { + throw new WC_API_Exception( 'woocommerce_api_user_cannot_delete_product_tag', __( 'You do not have permission to delete product tag', 'woocommerce' ), 401 ); + } + + $id = absint( $id ); + $deleted = wp_delete_term( $id, 'product_tag' ); + if ( ! $deleted || is_wp_error( $deleted ) ) { + throw new WC_API_Exception( 'woocommerce_api_cannot_delete_product_tag', __( 'Could not delete the tag', 'woocommerce' ), 401 ); + } + + do_action( 'woocommerce_api_delete_product_tag', $id, $this ); + + return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_tag' ) ); + } catch ( WC_API_Exception $e ) { + return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); + } + } + /** * Helper method to get product post objects * From 97565ef9a1cc50aa5f2c52a1619ff3fa99c063f0 Mon Sep 17 00:00:00 2001 From: Akeda Bagus Date: Tue, 15 Sep 2015 07:18:28 -0500 Subject: [PATCH 5/5] Added more products query filter for REST API. The new filters are taxonomies related: tag, shipping class, and attribute. The code was refactored a bit so all taxonomies query are wrapped within tax_query. --- includes/api/class-wc-api-products.php | 44 ++++++++++++++++++-------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/includes/api/class-wc-api-products.php b/includes/api/class-wc-api-products.php index 9be3653bd8e..ae8dbcc2fdb 100644 --- a/includes/api/class-wc-api-products.php +++ b/includes/api/class-wc-api-products.php @@ -985,24 +985,40 @@ class WC_API_Products extends WC_API_Resource { 'meta_query' => array(), ); - if ( ! empty( $args['type'] ) ) { + // Taxonomy query to filter products by type, category, tag, shipping class, and + // attribute. + $tax_query = array(); - $types = explode( ',', $args['type'] ); + // Map between taxonomy name and arg's key. + $taxonomies_arg_map = array( + 'product_type' => 'type', + 'product_cat' => 'category', + 'product_tag' => 'tag', + 'product_shipping_class' => 'shipping_class', + ); - $query_args['tax_query'] = array( - array( - 'taxonomy' => 'product_type', - 'field' => 'slug', - 'terms' => $types, - ), - ); - - unset( $args['type'] ); + // Add attribute taxonomy names into the map. + foreach ( wc_get_attribute_taxonomy_names() as $attribute_name ) { + $taxonomies_arg_map[ $attribute_name ] = $attribute_name; } - // Filter products by category - if ( ! empty( $args['category'] ) ) { - $query_args['product_cat'] = $args['category']; + // Set tax_query for each passed arg. + foreach ( $taxonomies_arg_map as $tax_name => $arg ) { + if ( ! empty( $args[ $arg ] ) ) { + $terms = explode( ',', $args[ $arg ] ); + + $tax_query[] = array( + 'taxonomy' => $tax_name, + 'field' => 'slug', + 'terms' => $terms, + ); + + unset( $args[ $arg ] ); + } + } + + if ( ! empty( $tax_query ) ) { + $query_args['tax_query'] = $tax_query; } // Filter by specific sku