/** * Get taxonomy. * * @param WP_REST_Request $request Full details about the request. * @return int|WP_Error */ protected function get_taxonomy($request) { // Check if taxonomy is defined. // Prevents check for attribute taxonomy more than one time for each query. if ('' !== $this->taxonomy) { return $this->taxonomy; } if (!empty($request['attribute_id'])) { $taxonomy = wc_attribute_taxonomy_name_by_id((int) $request['attribute_id']); $this->taxonomy = $taxonomy; } return $this->taxonomy; }
/** * Delete a product attribute term. * * @since 2.5.0 * @param int $attribute_id Attribute ID. * @param int $id the product attribute ID. * @return array */ public function delete_product_attribute_term($attribute_id, $id) { global $wpdb; try { // Check permissions. if (!current_user_can('manage_product_terms')) { throw new WC_API_Exception('woocommerce_api_user_cannot_delete_product_attribute_term', __('You do not have permission to delete product attribute terms', 'woocommerce'), 401); } $taxonomy = wc_attribute_taxonomy_name_by_id($attribute_id); if (!$taxonomy) { throw new WC_API_Exception('woocommerce_api_invalid_product_attribute_id', __('A product attribute with the provided ID could not be found', 'woocommerce'), 404); } $id = absint($id); $term = wp_delete_term($id, $taxonomy); if (!$term) { throw new WC_API_Exception('woocommerce_api_cannot_delete_product_attribute_term', sprintf(__('This %s cannot be deleted', 'woocommerce'), 'product_attribute_term'), 500); } else { if (is_wp_error($term)) { throw new WC_API_Exception('woocommerce_api_cannot_delete_product_attribute_term', $term->get_error_message(), 400); } } do_action('woocommerce_api_delete_product_attribute_term', $id, $this); return array('message' => sprintf(__('Deleted %s', 'woocommerce'), 'product_attribute')); } catch (WC_API_Exception $e) { return new WP_Error($e->getErrorCode(), $e->getMessage(), array('status' => $e->getCode())); } }
/** * Save variations. * * @param WC_Product $product * @param WP_REST_Request $request * @return bool * @throws WC_REST_Exception */ protected function save_variations_data($product, $request) { global $wpdb; $variations = $request['variations']; $attributes = $product->get_attributes(); foreach ($variations as $menu_order => $variation) { $variation_id = isset($variation['id']) ? absint($variation['id']) : 0; // Generate a useful post title. $variation_post_title = sprintf(__('Variation #%s of %s', 'woocommerce'), $variation_id, esc_html(get_the_title($product->id))); // Update or Add post. if (!$variation_id) { $post_status = isset($variation['visible']) && false === $variation['visible'] ? 'private' : 'publish'; $new_variation = array('post_title' => $variation_post_title, 'post_content' => '', 'post_status' => $post_status, 'post_author' => get_current_user_id(), 'post_parent' => $product->id, 'post_type' => 'product_variation', 'menu_order' => $menu_order); $variation_id = wp_insert_post($new_variation); do_action('woocommerce_create_product_variation', $variation_id); } else { $update_variation = array('post_title' => $variation_post_title, 'menu_order' => $menu_order); if (isset($variation['visible'])) { $post_status = false === $variation['visible'] ? 'private' : 'publish'; $update_variation['post_status'] = $post_status; } $wpdb->update($wpdb->posts, $update_variation, array('ID' => $variation_id)); do_action('woocommerce_update_product_variation', $variation_id); } // Stop with we don't have a variation ID. if (is_wp_error($variation_id)) { throw new WC_REST_Exception('woocommerce_rest_cannot_save_product_variation', $variation_id->get_error_message(), 400); } // SKU. if (isset($variation['sku'])) { $sku = get_post_meta($variation_id, '_sku', true); $new_sku = wc_clean($variation['sku']); if ('' === $new_sku) { update_post_meta($variation_id, '_sku', ''); } elseif ($new_sku !== $sku) { if (!empty($new_sku)) { $unique_sku = wc_product_has_unique_sku($variation_id, $new_sku); if (!$unique_sku) { throw new WC_REST_Exception('woocommerce_rest_product_sku_already_exists', __('The SKU already exists on another product.', 'woocommerce'), 400); } else { update_post_meta($variation_id, '_sku', $new_sku); } } else { update_post_meta($variation_id, '_sku', ''); } } } // Thumbnail. if (isset($variation['image']) && is_array($variation['image'])) { $image = current($variation['image']); if ($image && is_array($image)) { if (isset($image['position']) && 0 === $image['position']) { $attachment_id = isset($image['id']) ? absint($image['id']) : 0; if (0 === $attachment_id && isset($image['src'])) { $upload = wc_rest_upload_image_from_url(wc_clean($image['src'])); if (is_wp_error($upload)) { throw new WC_REST_Exception('woocommerce_product_image_upload_error', $upload->get_error_message(), 400); } $attachment_id = wc_rest_set_uploaded_image_as_attachment($upload, $product->id); } // Set the image alt if present. if (!empty($image['alt'])) { update_post_meta($attachment_id, '_wp_attachment_image_alt', wc_clean($image['alt'])); } // Set the image name if present. if (!empty($image['name'])) { wp_update_post(array('ID' => $attachment_id, 'post_title' => $image['name'])); } update_post_meta($variation_id, '_thumbnail_id', $attachment_id); } } else { delete_post_meta($variation_id, '_thumbnail_id'); } } // Virtual variation. if (isset($variation['virtual'])) { $is_virtual = true === $variation['virtual'] ? 'yes' : 'no'; update_post_meta($variation_id, '_virtual', $is_virtual); } // Downloadable variation. if (isset($variation['downloadable'])) { $is_downloadable = true === $variation['downloadable'] ? 'yes' : 'no'; update_post_meta($variation_id, '_downloadable', $is_downloadable); } else { $is_downloadable = get_post_meta($variation_id, '_downloadable', true); } // Shipping data. $this->save_product_shipping_data($variation_id, $variation); // Stock handling. if (isset($variation['manage_stock'])) { $manage_stock = true === $variation['manage_stock'] ? 'yes' : 'no'; } else { $manage_stock = get_post_meta($variation_id, '_manage_stock', true); } update_post_meta($variation_id, '_manage_stock', '' === $manage_stock ? 'no' : $manage_stock); if (isset($variation['in_stock'])) { $stock_status = true === $variation['in_stock'] ? 'instock' : 'outofstock'; } else { $stock_status = get_post_meta($variation_id, '_stock_status', true); } wc_update_product_stock_status($variation_id, '' === $stock_status ? 'instock' : $stock_status); if ('yes' === $manage_stock) { $backorders = get_post_meta($variation_id, '_backorders', true); if (isset($variation['backorders'])) { $backorders = $variation['backorders']; } update_post_meta($variation_id, '_backorders', '' === $backorders ? 'no' : $backorders); if (isset($variation['stock_quantity'])) { wc_update_product_stock($variation_id, wc_stock_amount($variation['stock_quantity'])); } elseif (isset($request['inventory_delta'])) { $stock_quantity = wc_stock_amount(get_post_meta($variation_id, '_stock', true)); $stock_quantity += wc_stock_amount($request['inventory_delta']); wc_update_product_stock($variation_id, wc_stock_amount($stock_quantity)); } } else { delete_post_meta($variation_id, '_backorders'); delete_post_meta($variation_id, '_stock'); } // Regular Price. if (isset($variation['regular_price'])) { $regular_price = '' === $variation['regular_price'] ? '' : $variation['regular_price']; } else { $regular_price = get_post_meta($variation_id, '_regular_price', true); } // Sale Price. if (isset($variation['sale_price'])) { $sale_price = '' === $variation['sale_price'] ? '' : $variation['sale_price']; } else { $sale_price = get_post_meta($variation_id, '_sale_price', true); } if (isset($variation['date_on_sale_from'])) { $date_from = $variation['date_on_sale_from']; } else { $date_from = get_post_meta($variation_id, '_sale_price_dates_from', true); $date_from = '' === $date_from ? '' : date('Y-m-d', $date_from); } if (isset($variation['date_on_sale_to'])) { $date_to = $variation['date_on_sale_to']; } else { $date_to = get_post_meta($variation_id, '_sale_price_dates_to', true); $date_to = '' === $date_to ? '' : date('Y-m-d', $date_to); } _wc_save_product_price($variation_id, $regular_price, $sale_price, $date_from, $date_to); // Tax class. if (isset($variation['tax_class'])) { if ($variation['tax_class'] !== 'parent') { update_post_meta($variation_id, '_tax_class', wc_clean($variation['tax_class'])); } else { delete_post_meta($variation_id, '_tax_class'); } } // Downloads. if ('yes' === $is_downloadable) { // Downloadable files. if (isset($variation['downloads']) && is_array($variation['downloads'])) { $this->save_downloadable_files($product->id, $variation['downloads'], $variation_id); } // Download limit. if (isset($variation['download_limit'])) { update_post_meta($variation_id, '_download_limit', -1 === $variation['download_limit'] ? '' : absint($variation['download_limit'])); } // Download expiry. if (isset($variation['download_expiry'])) { update_post_meta($variation_id, '_download_expiry', -1 === $variation['download_expiry'] ? '' : absint($variation['download_expiry'])); } } else { update_post_meta($variation_id, '_download_limit', ''); update_post_meta($variation_id, '_download_expiry', ''); update_post_meta($variation_id, '_downloadable_files', ''); } // Description. if (isset($variation['description'])) { update_post_meta($variation_id, '_variation_description', wp_kses_post($variation['description'])); } // Update taxonomies. if (isset($variation['attributes'])) { $updated_attribute_keys = array(); foreach ($variation['attributes'] as $attribute) { $attribute_id = 0; $attribute_name = ''; // Check ID for global attributes or name for product attributes. if (!empty($attribute['id'])) { $attribute_id = absint($attribute['id']); $attribute_name = wc_attribute_taxonomy_name_by_id($attribute_id); } elseif (!empty($attribute['name'])) { $attribute_name = sanitize_title($attribute['name']); } if (!$attribute_id && !$attribute_name) { continue; } if (isset($attributes[$attribute_name])) { $_attribute = $attributes[$attribute_name]; } if (isset($_attribute['is_variation']) && $_attribute['is_variation']) { $_attribute_key = 'attribute_' . sanitize_title($_attribute['name']); $updated_attribute_keys[] = $_attribute_key; if (isset($_attribute['is_taxonomy']) && $_attribute['is_taxonomy']) { // Don't use wc_clean as it destroys sanitized characters $_attribute_value = isset($attribute['option']) ? sanitize_title(stripslashes($attribute['option'])) : ''; } else { $_attribute_value = isset($attribute['option']) ? wc_clean(stripslashes($attribute['option'])) : ''; } update_post_meta($variation_id, $_attribute_key, $_attribute_value); } } // Remove old taxonomies attributes so data is kept up to date - first get attribute key names. $delete_attribute_keys = $wpdb->get_col($wpdb->prepare("SELECT meta_key FROM {$wpdb->postmeta} WHERE meta_key LIKE 'attribute_%%' AND meta_key NOT IN ( '" . implode("','", $updated_attribute_keys) . "' ) AND post_id = %d;", $variation_id)); foreach ($delete_attribute_keys as $key) { delete_post_meta($variation_id, $key); } } do_action('woocommerce_rest_save_product_variation', $variation_id, $menu_order, $variation); } // Update parent if variable so price sorting works and stays in sync with the cheapest child. WC_Product_Variable::sync($product->id); // Update default attributes options setting. if (isset($request['default_attribute'])) { $request['default_attributes'] = $request['default_attribute']; } if (isset($request['default_attributes']) && is_array($request['default_attributes'])) { $default_attributes = array(); foreach ($request['default_attributes'] as $attribute) { $attribute_id = 0; $attribute_name = ''; // Check ID for global attributes or name for product attributes. if (!empty($attribute['id'])) { $attribute_id = absint($attribute['id']); $attribute_name = wc_attribute_taxonomy_name_by_id($attribute_id); } elseif (!empty($attribute['name'])) { $attribute_name = sanitize_title($attribute['name']); } if (!$attribute_id && !$attribute_name) { continue; } if (isset($attributes[$attribute_name])) { $_attribute = $attributes[$attribute_name]; if ($_attribute['is_variation']) { $value = ''; if (isset($attribute['option'])) { if ($_attribute['is_taxonomy']) { // Don't use wc_clean as it destroys sanitized characters. $value = sanitize_title(trim(stripslashes($attribute['option']))); } else { $value = wc_clean(trim(stripslashes($attribute['option']))); } } if ($value) { $default_attributes[$attribute_name] = $value; } } } } update_post_meta($product->id, '_default_attributes', $default_attributes); } return true; }
/** * Save variations. * * @throws WC_REST_Exception REST API exceptions. * @param WC_Product $product Product instance. * @param WP_REST_Request $request Request data. * @param bool $single_variation True if saving only a single variation. * @return bool */ protected function save_variations_data($product, $request, $single_variation = false) { global $wpdb; if ($single_variation) { $variations = array($request); } else { $variations = $request['variations']; } foreach ($variations as $menu_order => $data) { $variation_id = isset($data['id']) ? absint($data['id']) : 0; $variation = new WC_Product_Variation($variation_id); // Create initial name and status. if (!$variation->get_slug()) { /* translators: 1: variation id 2: product name */ $variation->set_name(sprintf(__('Variation #%1$s of %2$s', 'woocommerce'), $variation->get_id(), $product->get_name())); $variation->set_status(isset($data['visible']) && false === $data['visible'] ? 'private' : 'publish'); } // Parent ID. $variation->set_parent_id($product->get_id()); // Menu order. $variation->set_menu_order($menu_order); // Status. if (isset($data['visible'])) { $variation->set_status(false === $data['visible'] ? 'private' : 'publish'); } // SKU. if (isset($data['sku'])) { $variation->set_sku(wc_clean($data['sku'])); } // Thumbnail. if (isset($data['image']) && is_array($data['image'])) { $image = $data['image']; $image = current($image); if (is_array($image)) { $image['position'] = 0; } $variation = $this->save_product_images($variation, array($image)); } // Virtual variation. if (isset($data['virtual'])) { $variation->set_virtual($data['virtual']); } // Downloadable variation. if (isset($data['downloadable'])) { $variation->set_downloadable($data['downloadable']); } // Downloads. if ($variation->get_downloadable()) { // Downloadable files. if (isset($data['downloads']) && is_array($data['downloads'])) { $variation = $this->save_downloadable_files($variation, $data['downloads']); } // Download limit. if (isset($data['download_limit'])) { $variation->set_download_limit($data['download_limit']); } // Download expiry. if (isset($data['download_expiry'])) { $variation->set_download_expiry($data['download_expiry']); } } // Shipping data. $variation = $this->save_product_shipping_data($variation, $data); // Stock handling. if (isset($data['manage_stock'])) { $variation->set_manage_stock($data['manage_stock']); } if (isset($data['in_stock'])) { $variation->set_stock_status(true === $data['in_stock'] ? 'instock' : 'outofstock'); } if (isset($data['backorders'])) { $variation->set_backorders($data['backorders']); } if ($variation->get_manage_stock()) { if (isset($data['stock_quantity'])) { $variation->set_stock_quantity($data['stock_quantity']); } elseif (isset($data['inventory_delta'])) { $stock_quantity = wc_stock_amount($variation->get_stock_amount()); $stock_quantity += wc_stock_amount($data['inventory_delta']); $variation->set_stock_quantity($stock_quantity); } } else { $variation->set_backorders('no'); $variation->set_stock_quantity(''); } // Regular Price. if (isset($data['regular_price'])) { $variation->set_regular_price($data['regular_price']); } // Sale Price. if (isset($data['sale_price'])) { $variation->set_sale_price($data['sale_price']); } if (isset($data['date_on_sale_from'])) { $variation->set_date_on_sale_from($data['date_on_sale_from']); } if (isset($data['date_on_sale_to'])) { $variation->set_date_on_sale_to($data['date_on_sale_to']); } // Tax class. if (isset($data['tax_class'])) { $variation->set_tax_class($data['tax_class']); } // Description. if (isset($data['description'])) { $variation->set_description(wp_kses_post($data['description'])); } // Update taxonomies. if (isset($data['attributes'])) { $attributes = array(); $parent_attributes = $product->get_attributes(); foreach ($data['attributes'] as $attribute) { $attribute_id = 0; $attribute_name = ''; // Check ID for global attributes or name for product attributes. if (!empty($attribute['id'])) { $attribute_id = absint($attribute['id']); $attribute_name = wc_attribute_taxonomy_name_by_id($attribute_id); } elseif (!empty($attribute['name'])) { $attribute_name = sanitize_title($attribute['name']); } if (!$attribute_id && !$attribute_name) { continue; } if (!isset($parent_attributes[$attribute_name]) || !$parent_attributes[$attribute_name]->get_variation()) { continue; } $attribute_key = sanitize_title($parent_attributes[$attribute_name]->get_name()); $attribute_value = isset($attribute['option']) ? wc_clean(stripslashes($attribute['option'])) : ''; if ($parent_attributes[$attribute_name]->is_taxonomy()) { // If dealing with a taxonomy, we need to get the slug from the name posted to the API. $term = get_term_by('name', $attribute_value, $attribute_name); if ($term && !is_wp_error($term)) { $attribute_value = $term->slug; } else { $attribute_value = sanitize_title($attribute_value); } } $attributes[$attribute_key] = $attribute_value; } $variation->set_attributes($attributes); } $variation->save(); do_action('woocommerce_rest_save_product_variation', $variation->get_id(), $menu_order, $data); } return true; }
/** * Get attribute name. * * @param WP_REST_Request $request Full details about the request. * @return string */ protected function get_taxonomy($request) { if ('' !== $this->attribute) { return $this->attribute; } if ($request['id']) { $name = wc_attribute_taxonomy_name_by_id((int) $request['id']); $this->attribute = $name; } return $this->attribute; }