/** * Handles saving updates from the product editor * * Saves all product related information which includes core product data * and supporting elements such as images, digital downloads, tags, * assigned categories, specs and pricing variations. * * @return void **/ function save_product ($Product) { $db = DB::get(); $Settings = &EcartSettings(); check_admin_referer('ecart-save-product'); if ( !(is_ecart_userlevel() || current_user_can('ecart_products')) ) wp_die(__('You do not have sufficient permissions to access this page.')); $Settings->saveform(); // Save workflow setting $base = $Settings->get('base_operations'); $taxrate = 0; if ($base['vat']) $taxrate = ecart_taxrate(null,true,$Product); if (empty($_POST['options'])) $Product->options = array(); else $_POST['options'] = stripslashes_deep($_POST['options']); if (empty($Product->slug)) $Product->slug = sanitize_title_with_dashes($_POST['name']); // Check for an existing product slug $exclude_product = !empty($Product->id)?"AND id != $Product->id":""; $existing = $db->query("SELECT slug FROM $Product->_table WHERE slug='$Product->slug' $exclude_product LIMIT 1"); if ($existing) { $suffix = 2; while($existing) { $altslug = substr($Product->slug, 0, 200-(strlen($suffix)+1)). "-".$suffix++; $existing = $db->query("SELECT slug FROM $Product->_table WHERE slug='$altslug' $exclude_product LIMIT 1"); } $Product->slug = $altslug; } if ($_POST['status'] == "publish") { $publishfields = array('month' => '','date' => '','year' => '','hour'=>'','minute'=>'','meridiem'=>''); $publishdate = join('',array_merge($publishfields,$_POST['publish'])); if (!empty($publishdate)) { if ($_POST['publish']['meridiem'] == "PM" && $_POST['publish']['hour'] < 12) $_POST['publish']['hour'] += 12; $_POST['publish'] = mktime($_POST['publish']['hour'],$_POST['publish']['minute'],0,$_POST['publish']['month'],$_POST['publish']['date'],$_POST['publish']['year']); } else { unset($_POST['publish']); // Auto set the publish date if not set (or more accurately, if set to an irrelevant timestamp) if ($Product->publish <= 86400) $Product->publish = time(); } } else { unset($_POST['publish']); $Product->publish = 0; } if (isset($_POST['content'])) $_POST['description'] = $_POST['content']; $Product->updates($_POST,array('categories','prices')); $Product->save(); $Product->save_categories($_POST['categories']); $Product->save_tags(explode(",",$_POST['taglist'])); if (!empty($_POST['price']) && is_array($_POST['price'])) { // Delete prices that were marked for removal if (!empty($_POST['deletePrices'])) { $deletes = array(); if (strpos($_POST['deletePrices'],",")) $deletes = explode(',',$_POST['deletePrices']); else $deletes = array($_POST['deletePrices']); foreach($deletes as $option) { $Price = new Price($option); $Price->delete(); } } // Save prices that there are updates for foreach($_POST['price'] as $i => $option) { if (empty($option['id'])) { $Price = new Price(); $option['product'] = $Product->id; } else $Price = new Price($option['id']); $option['sortorder'] = array_search($i,$_POST['sortorder'])+1; // Remove VAT amount to save in DB if ($base['vat'] && isset($option['tax']) && $option['tax'] == "on") { $option['price'] = (floatvalue($option['price'])/(1+$taxrate)); $option['saleprice'] = (floatvalue($option['saleprice'])/(1+$taxrate)); } $option['shipfee'] = floatvalue($option['shipfee']); $option['weight'] = floatvalue($option['weight']); if (isset($options['dimensions']) && is_array($options['dimensions'])) foreach ($option['dimensions'] as &$dimension) $dimension = floatvalue($dimension); $Price->updates($option); $Price->save(); if (!empty($option['download'])) $Price->attach_download($option['download']); if (!empty($option['downloadpath'])) { // Attach file specified by URI/path if (!empty($Price->download->id) || (empty($Price->download) && $Price->load_download())) { $File = $Price->download; } else $File = new ProductDownload(); $stored = false; $tmpfile = sanitize_path($option['downloadpath']); $File->storage = false; $Engine = $File->_engine(); // Set engine from storage settings $File->parent = $Price->id; $File->context = "price"; $File->type = "download"; $File->name = !empty($option['downloadfile'])?$option['downloadfile']:basename($tmpfile); $File->filename = $File->name; if ($File->found($tmpfile)) { $File->uri = $tmpfile; $stored = true; } else $stored = $File->store($tmpfile,'file'); if ($stored) { $File->readmeta(); $File->save(); } } // END attach file by path/uri } unset($Price); } // No variation options at all, delete all variation-pricelines if (!empty($Product->prices) && is_array($Product->prices) && (empty($_POST['options']['v']) || empty($_POST['options']['a']))) { foreach ($Product->prices as $priceline) { // Skip if not tied to variation options if ($priceline->optionkey == 0) continue; if ((empty($_POST['options']['v']) && $priceline->context == "variation") || (empty($_POST['options']['a']) && $priceline->context == "addon")) { $Price = new Price($priceline->id); $Price->delete(); } } } if (!empty($_POST['details']) || !empty($_POST['deletedSpecs'])) { $deletes = array(); if (!empty($_POST['deletedSpecs'])) { if (strpos($_POST['deletedSpecs'],",")) $deletes = explode(',',$_POST['deletedSpecs']); else $deletes = array($_POST['deletedSpecs']); foreach($deletes as $option) { $Spec = new Spec($option); $Spec->delete(); } unset($Spec); } if (is_array($_POST['details'])) { foreach ($_POST['details'] as $i => $spec) { if (in_array($spec['id'],$deletes)) continue; if (isset($spec['new'])) { $Spec = new Spec(); $spec['id'] = ''; $spec['parent'] = $Product->id; } else $Spec = new Spec($spec['id']); $spec['sortorder'] = array_search($i,$_POST['details-sortorder'])+1; $Spec->updates($spec); $Spec->save(); } } } if (!empty($_POST['deleteImages'])) { $deletes = array(); if (strpos($_POST['deleteImages'],",")) $deletes = explode(',',$_POST['deleteImages']); else $deletes = array($_POST['deleteImages']); $Product->delete_images($deletes); } if (!empty($_POST['images']) && is_array($_POST['images'])) { $Product->link_images($_POST['images']); $Product->save_imageorder($_POST['images']); if (!empty($_POST['imagedetails'])) $Product->update_images($_POST['imagedetails']); } do_action_ref_array('ecart_product_saved',array(&$Product)); unset($Product); return true; }
/** * Get a specific Price object * * @api * @since 1.2 * * @param mixed $variant the id of the variant, or array('product'=>int, 'option' => array('menu1name'=>'option', 'menu2name'=>'option') ) to specify variant by product id and option * @param string $pricetype (optional default:variant) product, variant, or addon * @return ShoppPrice Price object or false on error **/ function shopp_product_variant($variant = false, $pricetype = 'variant') { if (false === $variant) { shopp_debug(__FUNCTION__ . " failed: Variant id required."); return false; } if (is_numeric($variant)) { $Price = new ShoppPrice($variant); if (empty($Price->id)) { shopp_debug(__FUNCTION__ . " failed: Unable to load variant {$variant}."); return false; } } else { if (is_array($variant)) { // specifying variant by product id and option $Product = new stdClass(); if (isset($variant['product']) && is_numeric($variant['product'])) { $Product = new ShoppProduct($variant['product']); $Product->load_data(array('prices', 'meta', 'summary')); } if (empty($Product->id) || empty($Product->prices)) { shopp_debug(__FUNCTION__ . " failed: Unable to load variant. Invalid Product."); return false; } $pricetype = $pricetype == 'variant' ? 'variation' : $pricetype; $pricetypes = array('product', 'variation', 'addon'); if (!in_array($pricetype, $pricetypes)) { shopp_debug(__FUNCTION__ . " failed: Invalid pricetype. Can be product, variant, or addon."); return false; } if ('product' == $pricetype) { // No product context for product with variants if ('on' == $Product->variants) { shopp_debug(__FUNCTION__ . " failed: Invalid pricetype for this product."); return false; } foreach ($Product->prices as $price) { if ('product' == $price->context) { $Price = new ShoppPrice(); $Price->populate($price); $Price->load_settings(); $Price->load_download(); break; } } } else { // addon or variant if (!isset($variant['option']) || !is_array($variant['option']) || empty($variant['option'])) { shopp_debug(__FUNCTION__ . " failed: Missing option array."); return false; } $menukey = substr($pricetype, 0, 1); $flag = $pricetype == 'variation' ? 'variants' : 'addons'; if (!isset($Product->options[$menukey]) || $Product->{$flag} == 'off') { shopp_debug(__FUNCTION__ . " failed: No product variant options of type {$pricetype} for product {$Product->id}"); return false; } // build simple option menu array $menu = array(); foreach ($Product->options[$menukey] as $optionmenu) { $key = $optionmenu['name']; $menu[$key] = array(); foreach ($optionmenu['options'] as $option) { $menu[$key][] = $option['name']; } } list($optionkey, $options, $label, $mapping) = $Product->optionmap($variant['option'], $menu, $pricetype); if ('variation' == $pricetype && !isset($Product->pricekey[$optionkey]) || !$options) { shopp_debug(__FUNCTION__ . " failed: Invalid option."); return false; } if ('variation' == $pricetype) { $price = $Product->pricekey[$optionkey]; } else { // Find the option foreach ($Product->prices as $price) { if ($price->context == $pricetype && $price->options == $options) { break; } } } $Price = new Price(); $Price->populate($price); $Price->load_settings(); $Price->load_download(); } // end if product type / addon/variants type } } if (!isset($Price)) { shopp_debug(__FUNCTION__ . " failed: Product, Variant, or Addon Price object could not be found."); return false; } return $Price; }