/** * Handles loading, saving and deleting products in the context of workflows * * @author Jonathan Davis * @since 1.0 * @version 1.2 * * @return void **/ public function workflow() { global $Shopp, $post; $defaults = array('page' => false, 'action' => false, 'selected' => array(), 'id' => false, 'save' => false, 'duplicate' => false, 'next' => false); $args = array_merge($defaults, $_REQUEST); extract($args, EXTR_SKIP); if (!is_array($selected)) { $selected = array($selected); } if (!defined('WP_ADMIN') || !isset($page) || $this->Admin->pagename('products') != $page) { return false; } $adminurl = admin_url('admin.php'); if ($this->Admin->pagename('products') == $page && (false !== $action || isset($_GET['delete_all']))) { if (isset($_GET['delete_all'])) { $action = 'emptytrash'; } switch ($action) { case 'publish': ShoppProduct::publishset($selected, 'publish'); break; case 'unpublish': ShoppProduct::publishset($selected, 'draft'); break; case 'feature': ShoppProduct::featureset($selected, 'on'); break; case 'defeature': ShoppProduct::featureset($selected, 'off'); break; case 'restore': ShoppProduct::publishset($selected, 'draft'); break; case 'trash': ShoppProduct::publishset($selected, 'trash'); break; case 'delete': foreach ($selected as $id) { $P = new ShoppProduct($id); $P->delete(); } break; case 'emptytrash': $Template = new ShoppProduct(); $trash = sDB::query("SELECT ID FROM {$Template->_table} WHERE post_status='trash' AND post_type='" . ShoppProduct::posttype() . "'", 'array', 'col', 'ID'); foreach ($trash as $id) { $P = new ShoppProduct($id); $P->delete(); } break; } // Gracefully invalidate Shopp object caching Shopp::invalidate_cache(); $redirect = add_query_arg($_GET, $adminurl); $redirect = remove_query_arg(array('action', 'selected', 'delete_all'), $redirect); Shopp::redirect($redirect); } if ($duplicate) { // Gracefully invalidate Shopp object caching Shopp::invalidate_cache(); $Product = new ShoppProduct($duplicate); $Product->duplicate(); $this->index($Product); Shopp::redirect(add_query_arg(array('page' => $this->Admin->pagename('products'), 'paged' => $_REQUEST['paged']), $adminurl)); } if (isset($id) && $id != "new") { $Shopp->Product = new ShoppProduct($id); $Shopp->Product->load_data(); // Adds CPT compatibility support for third-party plugins/themes global $post; if (is_null($post)) { $post = get_post($Shopp->Product->id); } } else { $Shopp->Product = new ShoppProduct(); } if ($save) { // Gracefully invalidate Shopp object caching Shopp::invalidate_cache(); $this->save($Shopp->Product); $this->notice(sprintf(__('%s has been saved.', 'Shopp'), '<strong>' . stripslashes($Shopp->Product->name) . '</strong>')); // Workflow handler if (isset($_REQUEST['settings']) && isset($_REQUEST['settings']['workflow'])) { $workflow = $_REQUEST['settings']['workflow']; $worklist = $this->worklist; $working = array_search($id, $this->worklist); switch ($workflow) { case 'close': $next = 'close'; break; case 'new': $next = 'new'; break; case 'next': $key = $working + 1; break; case 'previous': $key = $working - 1; break; case 'continue': $next = $id; break; } if (isset($key)) { $next = isset($worklist[$key]) ? $worklist[$key] : 'close'; } } if ($next) { $query = $_GET; if (isset($this->worklist['query'])) { $query = array_merge($_GET, $this->worklist['query']); } $redirect = add_query_arg($query, $adminurl); $cleanup = array('action', 'selected', 'delete_all'); if ('close' == $next) { $cleanup[] = 'id'; $next = false; } $redirect = remove_query_arg($cleanup, $redirect); if ($next) { $redirect = add_query_arg('id', $next, $redirect); } Shopp::redirect($redirect); } if (empty($id)) { $id = $Shopp->Product->id; } $Shopp->Product = new ShoppProduct($id); $Shopp->Product->load_data(); } // WP post type editing support for other plugins if (!empty($Shopp->Product->id)) { $post = get_post($Shopp->Product->id); } }
/** * Comprehensive product creation through Product Developer API. * * This function will do everything needed for creating a product except * attach product images and products. That is done in the Asset API. :) * You should be able to build an importer from another system using this function. * * It is also possible to update an existing product (by passing the * existing id as part of the $data array) or else you can alternatively * use shopp_update_product() for that. * * @todo possibly remove the capability of passing in an id to update a product * * @api * @since 1.2 * * @param array $data (required) associative array structure containing a single product definition, see _validate_product_data for how this array is structured/validated. * @return Product the created product object, or boolean false on a failure. **/ function shopp_add_product($data = array()) { if (empty($data)) { shopp_debug(__FUNCTION__ . " failed: Empty data parameter."); return false; } $problems = _validate_product_data($data); if (!empty($problems)) { shopp_debug("Problems detected: " . Shopp::object_r($problems)); return false; } $Product = new ShoppProduct(); // Set Product publish status if (isset($data['publish'])) { $Product->publish = _shopp_product_publish_date($data['publish']); if ($Product->publish > 0) { $Product->status = 'future'; } } // Set Product name if (empty($data['name'])) { shopp_debug(__FUNCTION__ . " failed: Missing product name."); } $Product->name = $data['name']; // Set Product slug if (!empty($data['slug'])) { $Product->slug = $data['slug']; } if (empty($Product->slug)) { $Product->slug = sanitize_title($Product->name); } $Product->slug = wp_unique_post_slug($Product->slug, $Product->id, $Product->status, ShoppProduct::posttype(), 0); $Product->updates($data, array('meta', 'categories', 'prices', 'tags', 'publish')); $Product->save(); ShoppProduct::publishset(array($Product->id), $data['publish']['flag'] ? 'publish' : 'draft'); if (empty($Product->id)) { shopp_debug(__FUNCTION__ . " failed: Failure to create new Product object."); return false; } // Product-wide settings $Product->featured = isset($data['featured']) && true === $data['featured'] ? "on" : "off"; $Product->variants = isset($data['variants']) ? "on" : "off"; $Product->addons = isset($data['addons']) ? "on" : "off"; if (isset($data['packaging'])) { $packaging_set = shopp_product_set_packaging($Product->id, $data['packaging']); if (!$packaging_set) { shopp_debug(__FUNCTION__ . " failed: Failure to set packaging setting."); return false; } } // Save Taxonomies // Categories if (isset($data['categories']) && isset($data['categories']['terms'])) { $cats_set = shopp_product_add_categories($Product->id, $data['categories']['terms']); if (!$cats_set) { shopp_debug(__FUNCTION__ . " failed: Failure to add product categories to product."); return false; } } // Tags if (isset($data['tags']) && isset($data['tags']['terms'])) { $tags_set = shopp_product_add_tags($Product->id, $data['tags']['terms']); if (!$tags_set) { shopp_debug(__FUNCTION__ . " failed: Failure to add product tags to product."); return false; } } // Terms if (isset($data['terms']) && isset($data['terms']['terms']) && isset($data['terms']['taxonomy'])) { $terms_set = shopp_product_add_terms($Product->id, $data['terms']['terms'], $data['terms']['taxonomy']); if (!$terms_set) { shopp_debug(__FUNCTION__ . " failed: Failure to add product taxonomy terms to product."); return false; } } // Create Specs if (isset($data['specs'])) { $specs_set = shopp_product_set_specs($Product->id, $data['specs']); if (!$specs_set) { shopp_debug(__FUNCTION__ . " failed: Failure to add product specs to product."); return false; } } $subjects = array(); $prices = array(); // Create Prices if (isset($data['single'])) { if (!empty($data['single'])) { $subjects['product'] = array($data['single']); } } else { if (isset($data['variants'])) { // Construct and Populate variants if (!isset($data['variants']['menu']) || empty($data['variants']['menu'])) { shopp_debug(__FUNCTION__ . " failed: variants menu is empty."); return false; } $new_variants = shopp_product_set_variant_options($Product->id, $data['variants']['menu'], false); $pricekeys = $prices = array(); foreach ($new_variants as $Price) { $prices[$Price->id] = $pricekeys[$Price->optionkey] = $Price; } if (!$prices) { shopp_debug(__FUNCTION__ . " failed: Unable to set variant options."); return false; } $subjects['variants'] = $data['variants']; } } // Create the "product" Price $Price = new ShoppPrice(); $Price->label = __('Price & Delivery', 'Shopp'); $Price->context = 'product'; $Price->product = $Product->id; if (isset($subjects['variants'])) { $Price->type = 'N/A'; } // disabled $Price->save(); $prices[$Price->id] = $productprice = $Price; // Create Addons if (isset($data['addons'])) { if (!isset($data['addons']['menu']) || empty($data['addons']['menu'])) { shopp_debug(__FUNCTION__ . " failed: addons menu is empty"); return false; } $new_addons = shopp_product_set_addon_options($Product->id, $data['addons']['menu'], false); $addon_prices = array(); foreach ($new_addons as $Addon) { $addon_prices[$Addon->id] = $Addon; } if (!$addon_prices) { shopp_debug(__FUNCTION__ . " failed: Unable to set addon options."); return false; } $prices = $prices + $addon_prices; $subjects['addons'] = $data['addons']; } $contexts = array('addons' => 'addon', 'product' => 'product', 'variants' => 'variant'); foreach ($subjects as $pricetype => $variants) { // apply settings for each priceline foreach ($variants as $key => $variant) { if (!is_numeric($key)) { continue; } $price = null; if ('product' == $pricetype) { $price = $productprice->id; } else { // 'option' => 'array', // array option example: Color=>Blue, Size=>Small if (!isset($variant['option']) || empty($variant['option'])) { shopp_debug(__FUNCTION__ . " failed: variant {$key} missing variant options."); return false; } list($optionkey, $options, $label, $mapping) = $Product->optionmap($variant['option'], $variants['menu'], 'variants' == $pricetype ? 'variant' : 'addon'); if ('variants' == $pricetype && isset($pricekeys[$optionkey])) { $price = $pricekeys[$optionkey]->id; } else { // Find the correct Price foreach ($addon_prices as $index => $Price) { if ($Price->options == $options && $Price->label == $label) { $price = $index; break; } } } } if (null === $price || !isset($prices[$price])) { shopp_debug(__FUNCTION__ . " failed: Variant {$key} not valid for this option set."); return false; } // modify each priceline $prices[$price] = shopp_product_set_variant($prices[$price], $variant, $contexts[$pricetype]); if (!$prices[$price]) { shopp_debug(__FUNCTION__ . " failed: Product variant setup failed."); return false; } // save priceline settings if (isset($prices[$price]->settings)) { shopp_set_meta($prices[$price]->id, 'price', 'settings', $prices[$price]->settings); } // We have everything we need to complete this price line $prices[$price]->save(); } //end variants foreach } // end subjects foreach // Reset rollup figures for prices. $Product->resum(); // Calculates aggregate product stats // foreach ( $prices as $Price ) { // $Product->sumprice($Price); // } // Skeleton summary $Summary = new ProductSummary(); $sum_props = array_keys($Summary->_datatypes); // init default summary items foreach ($sum_props as $prop) { if (!isset($Product->{$prop})) { $Product->{$prop} = NULL; } } // Process pricing stats $records = null; foreach ($prices as $Price) { $Product->pricing($records, $Price); } // Saves generated stats to the product summary $Product->sumup(); return shopp_product($Product->id); }