PageRenderTime 60ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/blog/wp-content/plugins/shopp/core/Flow.php

https://github.com/kennethreitz-archive/wordpress-skeleton
PHP | 3010 lines | 2752 code | 198 blank | 60 comment | 225 complexity | 788fee78bad25f76bd4558933fed0612 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Flow handlers
  4. * Main flow handling for all request processing/handling
  5. *
  6. * @author Jonathan Davis
  7. * @version 1.0
  8. * @copyright Ingenesis Limited, 2 April, 2008
  9. * @package Shopp
  10. **/
  11. class Flow {
  12. var $Admin;
  13. var $Settings;
  14. var $basepath;
  15. var $baseuri;
  16. var $secureuri;
  17. function Flow (&$Core) {
  18. global $wp_version;
  19. $this->Settings = $Core->Settings;
  20. $this->Cart = $Core->Cart;
  21. $langpath = array(PLUGINDIR,$Core->directory,'lang');
  22. load_plugin_textdomain('Shopp',join(DIRECTORY_SEPARATOR,$langpath));
  23. $this->basepath = dirname(dirname(__FILE__));
  24. $this->uri = ((!empty($_SERVER['HTTPS']))?"https://":"http://").
  25. $_SERVER['SERVER_NAME'].str_replace("?".$_SERVER['QUERY_STRING'],"",$_SERVER['REQUEST_URI']);
  26. $this->secureuri = 'https://'.$_SERVER['SERVER_NAME'].$this->uri;
  27. $this->Admin = new stdClass();
  28. $this->Admin->orders = $Core->directory."-orders";
  29. $this->Admin->customers = $Core->directory."-customers";
  30. $this->Admin->editcustomer = $Core->directory."-customers-edit";
  31. $this->Admin->categories = $Core->directory."-categories";
  32. $this->Admin->editcategory = $Core->directory."-categories-edit";
  33. $this->Admin->products = $Core->directory."-products";
  34. $this->Admin->editproduct = $Core->directory."-products-edit";
  35. $this->Admin->promotions = $Core->directory."-promotions";
  36. $this->Admin->editpromo = $Core->directory."-promotions-edit";
  37. $this->Admin->settings = array(
  38. 'settings' => array($Core->directory."-settings",__('General','Shopp')),
  39. 'checkout' => array($Core->directory."-settings-checkout",__('Checkout','Shopp')),
  40. 'payments' => array($Core->directory."-settings-payments",__('Payments','Shopp')),
  41. 'shipping' => array($Core->directory."-settings-shipping",__('Shipping','Shopp')),
  42. 'taxes' => array($Core->directory."-settings-taxes",__('Taxes','Shopp')),
  43. 'presentation' => array($Core->directory."-settings-presentation",__('Presentation','Shopp')),
  44. 'system' => array($Core->directory."-settings-system",__('System','Shopp')),
  45. 'update' => array($Core->directory."-settings-update",__('Update','Shopp'))
  46. );
  47. $this->Admin->help = $Core->directory."-help";
  48. $this->Admin->welcome = $Core->directory."-welcome";
  49. $this->Admin->default = $this->Admin->orders;
  50. $this->Pages = $Core->Settings->get('pages');
  51. if (empty($this->Pages)) {
  52. $this->Pages = array();
  53. $this->Pages['catalog'] = array('name'=>'shop','title'=>'Shop','content'=>'[catalog]');
  54. $this->Pages['cart'] = array('name'=>'cart','title'=>'Cart','content'=>'[cart]');
  55. $this->Pages['checkout'] = array('name'=>'checkout','title'=>'Checkout','content'=>'[checkout]');
  56. $this->Pages['account'] = array('name'=>'account','title'=>'Your Orders','content'=>'[account]');
  57. }
  58. $this->Docs = array(
  59. 'orders' => 'Managing Orders',
  60. 'customers' => 'Managing Customers',
  61. 'promotions' => 'Running Sales & Promotions',
  62. 'editpromos' => 'Running Sales & Promotions',
  63. 'products' => 'Editing a Product',
  64. 'editproducts' => 'Editing a Product',
  65. 'categories' => 'Editing a Category',
  66. 'editcategory' => 'Editing a Category',
  67. 'settings' => 'General Settings',
  68. 'checkout' => 'Checkout Settings',
  69. 'payments' => 'Payments Settings',
  70. 'shipping' => 'Shipping Settings',
  71. 'taxes' => 'Taxes Settings',
  72. 'presentation' => 'Presentation Settings',
  73. 'system' => 'System Settings',
  74. 'update' => 'Update Settings'
  75. );
  76. $this->coremods = array("GoogleCheckout.php", "PayPalExpress.php",
  77. "TestMode.php", "FlatRates.php", "ItemQuantity.php",
  78. "OrderAmount.php", "OrderWeight.php");
  79. if (!defined('BR')) define('BR','<br />');
  80. // Overrideable macros
  81. if (!defined('SHOPP_USERLEVEL')) define('SHOPP_USERLEVEL',8);
  82. if (!defined('SHOPP_NOSSL')) define('SHOPP_NOSSL',false);
  83. if (!defined('SHOPP_PREPAYMENT_DOWNLOADS')) define('SHOPP_PREPAYMENT_DOWNLOADS',false);
  84. if (!defined('SHOPP_SESSION_TIMEOUT')) define('SHOPP_SESSION_TIMEOUT',7200);
  85. if (!defined('SHOPP_QUERY_DEBUG')) define('SHOPP_QUERY_DEBUG',false);
  86. define("SHOPP_WP27",(!version_compare($wp_version,"2.7","<")));
  87. define("SHOPP_DEBUG",($Core->Settings->get('error_logging') == 2048));
  88. define("SHOPP_PATH",$this->basepath);
  89. define("SHOPP_ADMINPATH",SHOPP_PATH."/core/ui");
  90. define("SHOPP_PLUGINURI",$Core->uri);
  91. define("SHOPP_DBSCHEMA",SHOPP_PATH."/core/model/schema.sql");
  92. define("SHOPP_TEMPLATES",($Core->Settings->get('theme_templates') != "off" &&
  93. is_dir($Core->Settings->get('theme_templates')))?
  94. $Core->Settings->get('theme_templates'):
  95. SHOPP_PATH.DIRECTORY_SEPARATOR."templates");
  96. define("SHOPP_TEMPLATES_URI",($Core->Settings->get('theme_templates') != "off" &&
  97. is_dir($Core->Settings->get('theme_templates')))?
  98. get_bloginfo('stylesheet_directory')."/shopp":
  99. $Core->uri."/templates");
  100. define("SHOPP_GATEWAYS",SHOPP_PATH.DIRECTORY_SEPARATOR."gateways".DIRECTORY_SEPARATOR);
  101. define("SHOPP_PERMALINKS",(get_option('permalink_structure') == "")?false:true);
  102. define("SHOPP_LOOKUP",(strpos($_SERVER['REQUEST_URI'],"images/") !== false ||
  103. strpos($_SERVER['REQUEST_URI'],"lookup=") !== false)?true:false);
  104. $this->uploadErrors = array(
  105. UPLOAD_ERR_INI_SIZE => __('The uploaded file exceeds the upload_max_filesize directive in PHP\'s configuration file','Shopp'),
  106. UPLOAD_ERR_FORM_SIZE => __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.','Shopp'),
  107. UPLOAD_ERR_PARTIAL => __('The uploaded file was only partially uploaded.','Shopp'),
  108. UPLOAD_ERR_NO_FILE => __('No file was uploaded.','Shopp'),
  109. UPLOAD_ERR_NO_TMP_DIR => __('The server\'s temporary folder is missing.','Shopp'),
  110. UPLOAD_ERR_CANT_WRITE => __('Failed to write the file to disk.','Shopp'),
  111. UPLOAD_ERR_EXTENSION => __('File upload stopped by extension.','Shopp'),
  112. );
  113. }
  114. function admin () {
  115. global $Shopp;
  116. $db =& DB::get();
  117. if (!defined('WP_ADMIN') || !isset($_GET['page'])) return;
  118. $Admin = $Shopp->Flow->Admin;
  119. $adminurl = $Shopp->wpadminurl."admin.php";
  120. $defaults = array(
  121. 'page' => false,
  122. 'deleting' => false,
  123. 'delete' => false,
  124. 'id' => false,
  125. 'save' => false,
  126. 'duplicate' => false,
  127. 'next' => false
  128. );
  129. $args = array_merge($defaults,$_REQUEST);
  130. extract($args,EXTR_SKIP);
  131. if (strstr($page,$Admin->categories)) {
  132. if ($page == "shopp-categories"
  133. && !empty($deleting)
  134. && !empty($delete)
  135. && is_array($delete)) {
  136. foreach($delete as $deletion) {
  137. $Category = new Category($deletion);
  138. $db->query("UPDATE $Category->_table SET parent=0 WHERE parent=$Category->id");
  139. $Category->delete();
  140. }
  141. $redirect = esc_url(add_query_arg(array_merge($_GET,array('delete[]'=>null,'deleting'=>null)),$adminurl));
  142. shopp_redirect($redirect);
  143. }
  144. if ($id && $id != "new")
  145. $Shopp->Category = new Category($id);
  146. else $Shopp->Category = new Category();
  147. if ($save) {
  148. $this->save_category($Shopp->Category);
  149. $this->Notice = '<strong>'.stripslashes($Shopp->Category->name).'</strong> '.__('has been saved.','Shopp');
  150. if ($next) {
  151. if ($next != "new")
  152. $Shopp->Category = new Category($next);
  153. else $Shopp->Category = new Category();
  154. } else {
  155. if (empty($id)) $id = $Shopp->Category->id;
  156. $Shopp->Category = new Category($id);
  157. }
  158. }
  159. } // end $Admin->categories
  160. if (strstr($page,$Admin->products)) {
  161. if ($page == "shopp-products"
  162. && !empty($deleting)
  163. && !empty($delete)
  164. && is_array($delete)) {
  165. foreach($delete as $deletion) {
  166. $Product = new Product($deletion);
  167. $Product->delete();
  168. }
  169. $redirect = esc_url(add_query_arg(array_merge($_GET,array('delete'=>null,'deleting'=>null)),$adminurl));
  170. shopp_redirect($redirect);
  171. exit();
  172. }
  173. if ($duplicate) {
  174. $Product = new Product();
  175. $Product->load($duplicate);
  176. $Product->duplicate();
  177. shopp_redirect(add_query_arg('page',$Admin->products,$adminurl));
  178. }
  179. if ($id && $id != "new") {
  180. $Shopp->Product = new Product($id);
  181. $Shopp->Product->load_data(array('prices','specs','categories','tags'));
  182. } else {
  183. $Shopp->Product = new Product();
  184. $Shopp->Product->published = "on";
  185. }
  186. if ($save) {
  187. $this->save_product($Shopp->Product);
  188. $this->Notice = '<strong>'.stripslashes($Shopp->Product->name).'</strong> '.__('has been saved.','Shopp');
  189. if ($next) {
  190. if ($next == "new") {
  191. $Shopp->Product = new Product();
  192. $Shopp->Product->published = "on";
  193. } else {
  194. $Shopp->Product = new Product($next);
  195. $Shopp->Product->load_data(array('prices','specs','categories','tags'));
  196. }
  197. } else {
  198. if (empty($id)) $id = $Shopp->Product->id;
  199. $Shopp->Product = new Product($id);
  200. $Shopp->Product->load_data(array('prices','specs','categories','tags'));
  201. }
  202. }
  203. } // end $Admin->products
  204. }
  205. function helpdoc ($menu,$page) {
  206. if (!isset($this->Docs[$menu])) return;
  207. $url = SHOPP_DOCS.str_replace("+","_",urlencode($this->Docs[$menu]));
  208. $link = htmlspecialchars($this->Docs[$menu]);
  209. $content = '<a href="'.$url.'" target="_blank">'.$link.'</a>';
  210. if ($menu == "orders" || $menu == "customers") {
  211. ob_start();
  212. include("{$this->basepath}/core/ui/help/$menu.php");
  213. $help = ob_get_contents();
  214. ob_end_clean();
  215. $content .= $help;
  216. }
  217. add_contextual_help($page,$content);
  218. }
  219. /**
  220. * Catalog flow handlers
  221. **/
  222. function catalog () {
  223. global $Shopp;
  224. if (SHOPP_DEBUG) new ShoppError('Displaying catalog page request: '.$_SERVER['REQUEST_URI'],'shopp_catalog',SHOPP_DEBUG_ERR);
  225. ob_start();
  226. switch ($Shopp->Catalog->type) {
  227. case "product":
  228. if (file_exists(SHOPP_TEMPLATES."/product-{$Shopp->Product->id}.php"))
  229. include(SHOPP_TEMPLATES."/product-{$Shopp->Product->id}.php");
  230. else include(SHOPP_TEMPLATES."/product.php"); break;
  231. case "category":
  232. if (isset($Shopp->Category->smart) &&
  233. file_exists(SHOPP_TEMPLATES."/category-{$Shopp->Category->slug}.php"))
  234. include(SHOPP_TEMPLATES."/category-{$Shopp->Category->slug}.php");
  235. elseif (isset($Shopp->Category->id) &&
  236. file_exists(SHOPP_TEMPLATES."/category-{$Shopp->Category->id}.php"))
  237. include(SHOPP_TEMPLATES."/category-{$Shopp->Category->id}.php");
  238. else include(SHOPP_TEMPLATES."/category.php"); break;
  239. default: include(SHOPP_TEMPLATES."/catalog.php"); break;
  240. }
  241. $content = ob_get_contents();
  242. ob_end_clean();
  243. $classes = $Shopp->Catalog->type;
  244. if (!isset($_COOKIE['shopp_catalog_view'])) {
  245. // No cookie preference exists, use shopp default setting
  246. $view = $Shopp->Settings->get('default_catalog_view');
  247. if ($view == "list") $classes .= " list";
  248. if ($view == "grid") $classes .= " grid";
  249. } else {
  250. if ($_COOKIE['shopp_catalog_view'] == "list") $classes .= " list";
  251. if ($_COOKIE['shopp_catalog_view'] == "grid") $classes .= " grid";
  252. }
  253. return apply_filters('shopp_catalog','<div id="shopp" class="'.$classes.'">'.$content.'<div class="clear"></div></div>');
  254. }
  255. /**
  256. * Shopping Cart flow handlers
  257. **/
  258. function cart ($attrs=array()) {
  259. $Cart = $this->Cart;
  260. ob_start();
  261. include(SHOPP_TEMPLATES."/cart.php");
  262. $content = ob_get_contents();
  263. ob_end_clean();
  264. return apply_filters('shopp_cart_template','<div id="shopp">'.$content.'</div>');
  265. }
  266. function shipping_estimate ($attrs) {
  267. $Cart = $this->Cart;
  268. ob_start();
  269. include(SHOPP_TEMPLATES."/shipping.php");
  270. $content = ob_get_contents();
  271. ob_end_clean();
  272. return $content;
  273. }
  274. /**
  275. * Checkout flow handlers
  276. **/
  277. function checkout () {
  278. global $Shopp;
  279. $Cart = $Shopp->Cart;
  280. $process = get_query_var('shopp_proc');
  281. $xco = get_query_var('shopp_xco');
  282. if (!empty($xco)) {
  283. $Shopp->gateway($xco);
  284. $Shopp->Gateway->actions();
  285. }
  286. switch ($process) {
  287. case "confirm-order": $content = $this->order_confirmation(); break;
  288. case "receipt": $content = $this->order_receipt(); break;
  289. default:
  290. ob_start();
  291. if ($Cart->data->Errors->exist(SHOPP_COMM_ERR)) {
  292. include(SHOPP_TEMPLATES."/errors.php");
  293. $Cart->data->Errors->reset();
  294. }
  295. if (!empty($xco)) {
  296. if (!empty($Shopp->Gateway)) {
  297. if ($Shopp->Gateway->checkout) include(SHOPP_TEMPLATES."/checkout.php");
  298. else {
  299. if ($Cart->data->Errors->exist(SHOPP_COMM_ERR))
  300. include(SHOPP_TEMPLATES."/errors.php");
  301. include(SHOPP_TEMPLATES."/summary.php");
  302. echo $Shopp->Gateway->tag('button');
  303. }
  304. } else include(SHOPP_TEMPLATES."/summary.php");
  305. } else include(SHOPP_TEMPLATES."/checkout.php");
  306. $content = ob_get_contents();
  307. ob_end_clean();
  308. unset($Cart->data->OrderError);
  309. }
  310. // Wrap with #shopp if not already wrapped
  311. if (strpos($content,'<div id="shopp">') === false)
  312. $content = '<div id="shopp">'.$content.'</div>';
  313. return apply_filters('shopp_checkout',$content);
  314. }
  315. function checkout_order_summary () {
  316. global $Shopp;
  317. $Cart = $Shopp->Cart;
  318. ob_start();
  319. include(SHOPP_TEMPLATES."/summary.php");
  320. $content = ob_get_contents();
  321. ob_end_clean();
  322. return apply_filters('shopp_order_summary',$content);
  323. }
  324. function secure_page_links ($linklist) {
  325. global $Shopp;
  326. $gateway = $Shopp->Settings->get('payment_gateway');
  327. if (strpos($gateway,"TestMode.php") !== false) return $linklist;
  328. $hrefs = array(
  329. 'checkout' => $Shopp->link('checkout'),
  330. 'account' => $Shopp->link('account')
  331. );
  332. if (empty($gateway)) return str_replace($hrefs['checkout'],$Shopp->link('cart'),$linklist);
  333. foreach ($hrefs as $href) {
  334. $secure_href = str_replace("http://","https://",$href);
  335. $linklist = str_replace($href,$secure_href,$linklist);
  336. }
  337. return $linklist;
  338. }
  339. /**
  340. * order()
  341. * Processes orders by passing transaction information to the active
  342. * payment gateway */
  343. function order ($gateway = false) {
  344. global $Shopp;
  345. $Cart = $Shopp->Cart;
  346. $db = DB::get();
  347. do_action('shopp_order_preprocessing');
  348. $Order = $Shopp->Cart->data->Order;
  349. $Order->Totals = $Shopp->Cart->data->Totals;
  350. $Order->Items = $Shopp->Cart->contents;
  351. $Order->Cart = $Shopp->Cart->session;
  352. if ($Shopp->Gateway && !$Cart->orderisfree()) {
  353. // Use an external checkout payment gateway
  354. if (SHOPP_DEBUG) new ShoppError('Processing order through a remote-payment gateway service.',false,SHOPP_DEBUG_ERR);
  355. $Purchase = $Shopp->Gateway->process();
  356. if (!$Purchase) {
  357. if (SHOPP_DEBUG) new ShoppError('The remote-payment gateway encountered an error.',false,SHOPP_DEBUG_ERR);
  358. $Shopp->Gateway->error();
  359. return false;
  360. }
  361. if (SHOPP_DEBUG) new ShoppError('Transaction successfully processed by remote-payment gateway service.',false,SHOPP_DEBUG_ERR);
  362. } else {
  363. // Use local payment gateway set in payment settings
  364. $gateway = $Shopp->Settings->get('payment_gateway');
  365. // Process a transaction if the order has a cost (is not free)
  366. if (!$Cart->orderisfree()) {
  367. if (!$Shopp->gateway($gateway)) return false;
  368. // Process the transaction through the payment gateway
  369. if (SHOPP_DEBUG) new ShoppError('Processing order through local-payment gateway service.',false,SHOPP_DEBUG_ERR);
  370. $processed = $Shopp->Gateway->process();
  371. // exit();
  372. // There was a problem processing the transaction,
  373. // grab the error response from the gateway so we can report it
  374. if (!$processed) {
  375. if (SHOPP_DEBUG) new ShoppError('The local-payment gateway encountered an error.',false,SHOPP_DEBUG_ERR);
  376. $Shopp->Gateway->error();
  377. return false;
  378. }
  379. $gatewaymeta = $this->scan_gateway_meta(SHOPP_GATEWAYS.$gateway);
  380. $gatewayname = $gatewaymeta->name;
  381. $transactionid = $Shopp->Gateway->transactionid();
  382. if (SHOPP_DEBUG) new ShoppError('Transaction '.$transactionid.' successfully processed by local-payment gateway service '.$gatewayname.'.',false,SHOPP_DEBUG_ERR);
  383. } else {
  384. if(!$Cart->validorder()){
  385. new ShoppError(__('There is not enough customer information to process the order.','Shopp'),'invalid_order',SHOPP_TRXN_ERR);
  386. return false;
  387. }
  388. $gatewayname = __('N/A','Shopp');
  389. $transactionid = __('(Free Order)','Shopp');
  390. }
  391. $authentication = $Shopp->Settings->get('account_system');
  392. // Transaction successful, save the order
  393. if ($authentication == "wordpress") {
  394. // Check if they've logged in
  395. // If the shopper is already logged-in, save their updated customer info
  396. if ($Shopp->Cart->data->login) {
  397. if (SHOPP_DEBUG) new ShoppError('Customer logged in, linking Shopp customer account to existing WordPress account.',false,SHOPP_DEBUG_ERR);
  398. get_currentuserinfo();
  399. global $user_ID;
  400. $Order->Customer->wpuser = $user_ID;
  401. }
  402. // Create WordPress account (if necessary)
  403. if (!$Order->Customer->wpuser) {
  404. if (SHOPP_DEBUG) new ShoppError('Creating a new WordPress account for this customer.',false,SHOPP_DEBUG_ERR);
  405. if(!$Order->Customer->new_wpuser()) new ShoppError(__('Account creation failed on order for customer id:' . $Order->Customer->id, "Shopp"), false,SHOPP_TRXN_ERR);
  406. }
  407. }
  408. // Create a WP-compatible password hash to go in the db
  409. if (empty($Order->Customer->id))
  410. $Order->Customer->password = wp_hash_password($Order->Customer->password);
  411. $Order->Customer->save();
  412. $Order->Billing->customer = $Order->Customer->id;
  413. $Order->Billing->card = substr($Order->Billing->card,-4);
  414. $Order->Billing->save();
  415. // Card data is truncated, switch the cart to normal mode
  416. if ($Shopp->Cart->secured() && is_shopp_secure())
  417. $Shopp->Cart->secured(false);
  418. if (!empty($Order->Shipping->address)) {
  419. $Order->Shipping->customer = $Order->Customer->id;
  420. $Order->Shipping->save();
  421. }
  422. $Promos = array();
  423. foreach ($Shopp->Cart->data->PromosApplied as $promo)
  424. $Promos[$promo->id] = $promo->name;
  425. if ($Shopp->Cart->orderisfree()) $orderisfree = true;
  426. else $orderisfree = false;
  427. $Purchase = new Purchase();
  428. $Purchase->customer = $Order->Customer->id;
  429. $Purchase->billing = $Order->Billing->id;
  430. $Purchase->shipping = $Order->Shipping->id;
  431. $Purchase->copydata($Order->Customer);
  432. $Purchase->copydata($Order->Billing);
  433. $Purchase->copydata($Order->Shipping,'ship');
  434. $Purchase->copydata($Shopp->Cart->data->Totals);
  435. $Purchase->data = $Order->data;
  436. $Purchase->promos = $Promos;
  437. $Purchase->freight = $Shopp->Cart->data->Totals->shipping;
  438. $Purchase->gateway = $gatewayname;
  439. $Purchase->transactionid = $transactionid;
  440. $Purchase->transtatus = "CHARGED";
  441. $Purchase->ip = $Shopp->Cart->ip;
  442. $Purchase->save();
  443. // echo "<pre>"; print_r($Purchase); echo "</pre>";
  444. foreach($Shopp->Cart->contents as $Item) {
  445. $Purchased = new Purchased();
  446. $Purchased->copydata($Item);
  447. $Purchased->purchase = $Purchase->id;
  448. if (!empty($Purchased->download)) $Purchased->keygen();
  449. $Purchased->save();
  450. if ($Item->inventory) $Item->unstock();
  451. }
  452. if (SHOPP_DEBUG) new ShoppError('Purchase '.$Purchase->id.' was successfully saved to the database.',false,SHOPP_DEBUG_ERR);
  453. }
  454. // Skip post order if no Purchase ID exists
  455. if (empty($Purchase->id)) return true;
  456. // Empty cart on successful order
  457. $Shopp->Cart->unload();
  458. session_destroy();
  459. // Start new cart session
  460. $Shopp->Cart = new Cart();
  461. session_start();
  462. // Keep the user logged in or log them in if they are a new customer
  463. if ($Shopp->Cart->data->login || $authentication != "none")
  464. $Shopp->Cart->loggedin($Order->Customer);
  465. // Save the purchase ID for later lookup
  466. $Shopp->Cart->data->Purchase = new Purchase($Purchase->id);
  467. $Shopp->Cart->data->Purchase->load_purchased();
  468. // // $Shopp->Cart->save();
  469. // Allow other WordPress plugins access to Purchase data to extend
  470. // what Shopp does after a successful transaction
  471. do_action_ref_array('shopp_order_success',array(&$Shopp->Cart->data->Purchase));
  472. // Send email notifications
  473. // notification(addressee name, email, subject, email template, receipt template)
  474. $Purchase->notification(
  475. "$Purchase->firstname $Purchase->lastname",
  476. $Purchase->email,
  477. __('Order Receipt','Shopp')
  478. );
  479. if ($Shopp->Settings->get('receipt_copy') == 1) {
  480. $Purchase->notification(
  481. '',
  482. $Shopp->Settings->get('merchant_email'),
  483. __('New Order','Shopp')
  484. );
  485. }
  486. $ssl = true;
  487. // Test Mode will not require encrypted checkout
  488. if (strpos($gateway,"TestMode.php") !== false
  489. || isset($_GET['shopp_xco'])
  490. || $orderisfree
  491. || SHOPP_NOSSL)
  492. $ssl = false;
  493. shopp_redirect($Shopp->link('receipt',$ssl));
  494. }
  495. // Display the confirm order screen
  496. function order_confirmation () {
  497. global $Shopp;
  498. $Cart = $Shopp->Cart;
  499. ob_start();
  500. include(SHOPP_TEMPLATES."/confirm.php");
  501. $content = ob_get_contents();
  502. ob_end_clean();
  503. return apply_filters('shopp_order_confirmation','<div id="shopp">'.$content.'</div>');
  504. }
  505. // Display a sales receipt
  506. function order_receipt ($template="receipt.php") {
  507. global $Shopp;
  508. $Cart = $Shopp->Cart;
  509. ob_start();
  510. include(trailingslashit(SHOPP_TEMPLATES).$template);
  511. $content = ob_get_contents();
  512. ob_end_clean();
  513. return apply_filters('shopp_order_receipt','<div id="shopp">'.$content.'</div>');
  514. }
  515. // Display an error page
  516. function error_page ($template="errors.php") {
  517. global $Shopp;
  518. $Cart = $Shopp->Cart;
  519. ob_start();
  520. include(trailingslashit(SHOPP_TEMPLATES).$template);
  521. $content = ob_get_contents();
  522. ob_end_clean();
  523. return apply_filters('shopp_errors_page','<div id="shopp">'.$content.'</div>');
  524. }
  525. /**
  526. * Orders admin flow handlers
  527. */
  528. function orders_list() {
  529. global $Shopp,$Orders;
  530. $db = DB::get();
  531. $defaults = array(
  532. 'page' => false,
  533. 'deleting' => false,
  534. 'selected' => false,
  535. 'update' => false,
  536. 'newstatus' => false,
  537. 'pagenum' => 1,
  538. 'per_page' => false,
  539. 'start' => '',
  540. 'end' => '',
  541. 'status' => false,
  542. 's' => '',
  543. 'range' => '',
  544. 'startdate' => '',
  545. 'enddate' => '',
  546. );
  547. $args = array_merge($defaults,$_GET);
  548. extract($args, EXTR_SKIP);
  549. if ( !current_user_can(SHOPP_USERLEVEL) )
  550. wp_die(__('You do not have sufficient permissions to access this page.','Shopp'));
  551. if ($page == "shopp-orders"
  552. && !empty($deleting)
  553. && !empty($selected)
  554. && is_array($selected)) {
  555. foreach($selected as $selection) {
  556. $Purchase = new Purchase($selection);
  557. $Purchase->load_purchased();
  558. foreach ($Purchase->purchased as $purchased) {
  559. $Purchased = new Purchased($purchased->id);
  560. $Purchased->delete();
  561. }
  562. $Purchase->delete();
  563. }
  564. }
  565. $statusLabels = $this->Settings->get('order_status');
  566. if (empty($statusLabels)) $statusLabels = array('');
  567. $txnStatusLabels = array(
  568. 'PENDING' => __('Pending','Shopp'),
  569. 'CHARGED' => __('Charged','Shopp'),
  570. 'REFUNDED' => __('Refunded','Shopp'),
  571. 'VOID' => __('Void','Shopp')
  572. );
  573. if ($update == "order"
  574. && !empty($selected)
  575. && is_array($selected)) {
  576. foreach($selected as $selection) {
  577. $Purchase = new Purchase($selection);
  578. $Purchase->status = $newstatus;
  579. $Purchase->save();
  580. }
  581. }
  582. $Purchase = new Purchase();
  583. if (!empty($start)) {
  584. $startdate = $start;
  585. list($month,$day,$year) = explode("/",$startdate);
  586. $starts = mktime(0,0,0,$month,$day,$year);
  587. }
  588. if (!empty($end)) {
  589. $enddate = $end;
  590. list($month,$day,$year) = explode("/",$enddate);
  591. $ends = mktime(23,59,59,$month,$day,$year);
  592. }
  593. $pagenum = absint( $pagenum );
  594. if ( empty($pagenum) )
  595. $pagenum = 1;
  596. if( !$per_page || $per_page < 0 )
  597. $per_page = 20;
  598. $start = ($per_page * ($pagenum-1));
  599. $where = '';
  600. if (!empty($status) || $status === '0') $where = "WHERE status='$status'";
  601. if (!empty($s)) {
  602. $s = stripslashes($s);
  603. if (preg_match_all('/(\w+?)\:(?="(.+?)"|(.+?)\b)/',$s,$props,PREG_SET_ORDER) > 0) {
  604. foreach ($props as $search) {
  605. $keyword = !empty($search[2])?$search[2]:$search[3];
  606. switch(strtolower($search[1])) {
  607. case "txn": $where .= (empty($where)?"WHERE ":" AND ")."transactionid='$keyword'"; break;
  608. case "gateway": $where .= (empty($where)?"WHERE ":" AND ")."gateway LIKE '%$keyword%'"; break;
  609. case "cardtype": $where .= ((empty($where))?"WHERE ":" AND ")."cardtype LIKE '%$keyword%'"; break;
  610. case "address": $where .= ((empty($where))?"WHERE ":" AND ")."(address LIKE '%$keyword%' OR xaddress='%$keyword%')"; break;
  611. case "city": $where .= ((empty($where))?"WHERE ":" AND ")."city LIKE '%$keyword%'"; break;
  612. case "province":
  613. case "state": $where .= ((empty($where))?"WHERE ":" AND ")."state='$keyword'"; break;
  614. case "zip":
  615. case "zipcode":
  616. case "postcode": $where .= ((empty($where))?"WHERE ":" AND ")."postcode='$keyword'"; break;
  617. case "country": $where .= ((empty($where))?"WHERE ":" AND ")."country='$keyword'"; break;
  618. }
  619. }
  620. if (empty($where)) $where .= ((empty($where))?"WHERE ":" AND ")." (id='$s' OR CONCAT(firstname,' ',lastname) LIKE '%$s%')";
  621. } elseif (strpos($s,'@') !== false) {
  622. $where .= ((empty($where))?"WHERE ":" AND ")." email='$s'";
  623. } else $where .= ((empty($where))?"WHERE ":" AND ")." (id='$s' OR CONCAT(firstname,' ',lastname) LIKE '%$s%')";
  624. }
  625. if (!empty($starts) && !empty($ends)) $where .= ((empty($where))?"WHERE ":" AND ").' (UNIX_TIMESTAMP(created) >= '.$starts.' AND UNIX_TIMESTAMP(created) <= '.$ends.')';
  626. $ordercount = $db->query("SELECT count(*) as total,SUM(total) AS sales,AVG(total) AS avgsale FROM $Purchase->_table $where ORDER BY created DESC");
  627. $query = "SELECT * FROM $Purchase->_table $where ORDER BY created DESC LIMIT $start,$per_page";
  628. $Orders = $db->query($query,AS_ARRAY);
  629. $num_pages = ceil($ordercount->total / $per_page);
  630. $page_links = paginate_links( array(
  631. 'base' => add_query_arg( 'pagenum', '%#%' ),
  632. 'format' => '',
  633. 'total' => $num_pages,
  634. 'current' => $pagenum
  635. ));
  636. $ranges = array(
  637. 'all' => __('Show All Orders','Shopp'),
  638. 'today' => __('Today','Shopp'),
  639. 'week' => __('This Week','Shopp'),
  640. 'month' => __('This Month','Shopp'),
  641. 'quarter' => __('This Quarter','Shopp'),
  642. 'year' => __('This Year','Shopp'),
  643. 'yesterday' => __('Yesterday','Shopp'),
  644. 'lastweek' => __('Last Week','Shopp'),
  645. 'last30' => __('Last 30 Days','Shopp'),
  646. 'last90' => __('Last 3 Months','Shopp'),
  647. 'lastmonth' => __('Last Month','Shopp'),
  648. 'lastquarter' => __('Last Quarter','Shopp'),
  649. 'lastyear' => __('Last Year','Shopp'),
  650. 'lastexport' => __('Last Export','Shopp'),
  651. 'custom' => __('Custom Dates','Shopp')
  652. );
  653. $exports = array(
  654. 'tab' => __('Tab-separated.txt','Shopp'),
  655. 'csv' => __('Comma-separated.csv','Shopp'),
  656. 'xls' => __('Microsoft&reg; Excel.xls','Shopp'),
  657. 'iif' => __('Intuit&reg; QuickBooks.iif','Shopp')
  658. );
  659. $formatPref = $Shopp->Settings->get('purchaselog_format');
  660. if (!$formatPref) $formatPref = 'tab';
  661. $columns = array_merge(Purchase::exportcolumns(),Purchased::exportcolumns());
  662. $selected = $Shopp->Settings->get('purchaselog_columns');
  663. if (empty($selected)) $selected = array_keys($columns);
  664. include("{$this->basepath}/core/ui/orders/orders.php");
  665. }
  666. function orders_list_columns () {
  667. shopp_register_column_headers('toplevel_page_shopp-orders', array(
  668. 'cb'=>'<input type="checkbox" />',
  669. 'order'=>__('Order','Shopp'),
  670. 'name'=>__('Name','Shopp'),
  671. 'destination'=>__('Destination','Shopp'),
  672. 'total'=>__('Total','Shopp'),
  673. 'txn'=>__('Transaction','Shopp'),
  674. 'date'=>__('Date','Shopp'))
  675. );
  676. }
  677. function order_manager () {
  678. global $Shopp;
  679. global $is_IIS;
  680. if ( !current_user_can(SHOPP_USERLEVEL) )
  681. wp_die(__('You do not have sufficient permissions to access this page.','Shopp'));
  682. if (preg_match("/\d+/",$_GET['id'])) {
  683. $Shopp->Cart->data->Purchase = new Purchase($_GET['id']);
  684. $Shopp->Cart->data->Purchase->load_purchased();
  685. } else $Shopp->Cart->data->Purchase = new Purchase();
  686. $Purchase = $Shopp->Cart->data->Purchase;
  687. $Customer = new Customer($Purchase->customer);
  688. if (!empty($_POST['update'])) {
  689. check_admin_referer('shopp-save-order');
  690. if ($_POST['transtatus'] != $Purchase->transtatus)
  691. do_action_ref_array('shopp_order_txnstatus_update',array(&$_POST['transtatus'],&$Purchase));
  692. $Purchase->updates($_POST);
  693. if ($_POST['notify'] == "yes") {
  694. $labels = $this->Settings->get('order_status');
  695. // Send the e-mail notification
  696. $notification = array();
  697. $notification['from'] = $Shopp->Settings->get('merchant_email');
  698. if($is_IIS) $notification['to'] = $Purchase->email;
  699. else $notification['to'] = "\"{$Purchase->firstname} {$Purchase->lastname}\" <{$Purchase->email}>";
  700. $notification['subject'] = __('Order Updated','Shopp');
  701. $notification['url'] = get_bloginfo('siteurl');
  702. $notification['sitename'] = get_bloginfo('name');
  703. if ($_POST['receipt'] == "yes")
  704. $notification['receipt'] = $this->order_receipt();
  705. $notification['status'] = strtoupper($labels[$Purchase->status]);
  706. $notification['message'] = wpautop($_POST['message']);
  707. shopp_email(SHOPP_TEMPLATES."/notification.html",$notification);
  708. }
  709. $Purchase->save();
  710. $updated = __('Order status updated.','Shopp');
  711. }
  712. $targets = $this->Settings->get('target_markets');
  713. $txnStatusLabels = array(
  714. 'PENDING' => __('Pending','Shopp'),
  715. 'CHARGED' => __('Charged','Shopp'),
  716. 'REFUNDED' => __('Refunded','Shopp'),
  717. 'VOID' => __('Void','Shopp')
  718. );
  719. $statusLabels = $this->Settings->get('order_status');
  720. if (empty($statusLabels)) $statusLabels = array('');
  721. $taxrate = 0;
  722. $base = $Shopp->Settings->get('base_operations');
  723. if ($base['vat']) $taxrate = $Shopp->Cart->taxrate();
  724. include("{$this->basepath}/core/ui/orders/order.php");
  725. }
  726. function order_status_counts () {
  727. $db = DB::get();
  728. $purchase_table = DatabaseObject::tablename(Purchase::$table);
  729. $labels = $this->Settings->get('order_status');
  730. if (empty($labels)) return false;
  731. $r = $db->query("SELECT status,COUNT(status) AS total FROM $purchase_table GROUP BY status ORDER BY status ASC",AS_ARRAY);
  732. $status = array();
  733. foreach ($r as $count) $status[$count->status] = $count->total;
  734. foreach ($labels as $id => $label) if (empty($status[$id])) $status[$id] = 0;
  735. return $status;
  736. }
  737. function account () {
  738. global $Shopp,$wp;
  739. if ($Shopp->Cart->data->login
  740. && isset($Shopp->Cart->data->Order->Customer))
  741. $Shopp->Cart->data->Order->Customer->management();
  742. if (isset($_GET['acct']) && $_GET['acct'] == "rp") $Shopp->Cart->data->Order->Customer->reset_password($_GET['key']);
  743. if (isset($_POST['recover-login'])) $Shopp->Cart->data->Order->Customer->recovery();
  744. ob_start();
  745. if (isset($wp->query_vars['shopp_download'])) include(SHOPP_TEMPLATES."/errors.php");
  746. elseif ($Shopp->Cart->data->login) include(SHOPP_TEMPLATES."/account.php");
  747. else include(SHOPP_TEMPLATES."/login.php");
  748. $content = ob_get_contents();
  749. ob_end_clean();
  750. return apply_filters('shopp_account_template','<div id="shopp">'.$content.'</div>');
  751. }
  752. function customers_list () {
  753. global $Shopp,$Customers,$wpdb;
  754. $db = DB::get();
  755. $defaults = array(
  756. 'page' => false,
  757. 'deleting' => false,
  758. 'selected' => false,
  759. 'update' => false,
  760. 'newstatus' => false,
  761. 'pagenum' => 1,
  762. 'per_page' => false,
  763. 'start' => '',
  764. 'end' => '',
  765. 'status' => false,
  766. 's' => '',
  767. 'range' => '',
  768. 'startdate' => '',
  769. 'enddate' => '',
  770. );
  771. $args = array_merge($defaults,$_GET);
  772. extract($args, EXTR_SKIP);
  773. if ($page == "shopp-customers"
  774. && !empty($deleting)
  775. && !empty($selected)
  776. && is_array($selected)) {
  777. foreach($selected as $deletion) {
  778. $Customer = new Customer($deletion);
  779. $Billing = new Billing($Customer->id,'customer');
  780. $Billing->delete();
  781. $Shipping = new Shipping($Customer->id,'customer');
  782. $Shipping->delete();
  783. $Customer->delete();
  784. }
  785. }
  786. if (!empty($_POST['save'])) {
  787. check_admin_referer('shopp-save-customer');
  788. if ($_POST['id'] != "new") {
  789. $Customer = new Customer($_POST['id']);
  790. $Billing = new Billing($Customer->id,'customer');
  791. $Shipping = new Shipping($Customer->id,'customer');
  792. } else $Customer = new Customer();
  793. $Customer->updates($_POST);
  794. if (!empty($_POST['new-password']) && !empty($_POST['confirm-password'])
  795. && $_POST['new-password'] == $_POST['confirm-password']) {
  796. $Customer->password = wp_hash_password($_POST['new-password']);
  797. if (!empty($Customer->wpuser)) wp_set_password($_POST['new-password'], $Customer->wpuser);
  798. }
  799. $Customer->save();
  800. $Billing->updates($_POST['billing']);
  801. $Billing->save();
  802. $Shipping->updates($_POST['shipping']);
  803. $Shipping->save();
  804. }
  805. $pagenum = absint( $pagenum );
  806. if ( empty($pagenum) )
  807. $pagenum = 1;
  808. if( !$per_page || $per_page < 0 )
  809. $per_page = 20;
  810. $index = ($per_page * ($pagenum-1));
  811. if (!empty($start)) {
  812. $startdate = $start;
  813. list($month,$day,$year) = explode("/",$startdate);
  814. $starts = mktime(0,0,0,$month,$day,$year);
  815. }
  816. if (!empty($end)) {
  817. $enddate = $end;
  818. list($month,$day,$year) = explode("/",$enddate);
  819. $ends = mktime(23,59,59,$month,$day,$year);
  820. }
  821. $customer_table = DatabaseObject::tablename(Customer::$table);
  822. $billing_table = DatabaseObject::tablename(Billing::$table);
  823. $purchase_table = DatabaseObject::tablename(Purchase::$table);
  824. $users_table = $wpdb->users;
  825. $where = '';
  826. if (!empty($s)) {
  827. $s = stripslashes($s);
  828. if (preg_match_all('/(\w+?)\:(?="(.+?)"|(.+?)\b)/',$s,$props,PREG_SET_ORDER)) {
  829. foreach ($props as $search) {
  830. $keyword = !empty($search[2])?$search[2]:$search[3];
  831. switch(strtolower($search[1])) {
  832. case "company": $where .= ((empty($where))?"WHERE ":" AND ")."c.company LIKE '%$keyword%'"; break;
  833. case "login": $where .= ((empty($where))?"WHERE ":" AND ")."u.user_login LIKE '%$keyword%'"; break;
  834. case "address": $where .= ((empty($where))?"WHERE ":" AND ")."(b.address LIKE '%$keyword%' OR b.xaddress='%$keyword%')"; break;
  835. case "city": $where .= ((empty($where))?"WHERE ":" AND ")."b.city LIKE '%$keyword%'"; break;
  836. case "province":
  837. case "state": $where .= ((empty($where))?"WHERE ":" AND ")."b.state='$keyword'"; break;
  838. case "zip":
  839. case "zipcode":
  840. case "postcode": $where .= ((empty($where))?"WHERE ":" AND ")."b.postcode='$keyword'"; break;
  841. case "country": $where .= ((empty($where))?"WHERE ":" AND ")."b.country='$keyword'"; break;
  842. }
  843. }
  844. } elseif (strpos($s,'@') !== false) {
  845. $where .= ((empty($where))?"WHERE ":" AND ")."c.email='$s'";
  846. } else $where .= ((empty($where))?"WHERE ":" AND ")." (c.id='$s' OR CONCAT(c.firstname,' ',c.lastname) LIKE '%$s%' OR c.company LIKE '%$s%')";
  847. }
  848. if (!empty($starts) && !empty($ends)) $where .= ((empty($where))?"WHERE ":" AND ").' (UNIX_TIMESTAMP(c.created) >= '.$starts.' AND UNIX_TIMESTAMP(c.created) <= '.$ends.')';
  849. $customercount = $db->query("SELECT count(*) as total FROM $customer_table AS c $where");
  850. $query = "SELECT c.*,b.city,b.state,b.country, u.user_login, SUM(p.total) AS total,count(distinct p.id) AS orders FROM $customer_table AS c LEFT JOIN $purchase_table AS p ON p.customer=c.id LEFT JOIN $billing_table AS b ON b.customer=c.id LEFT JOIN $users_table AS u ON u.ID=c.wpuser AND (c.wpuser IS NULL OR c.wpuser !=0) $where GROUP BY c.id ORDER BY c.created DESC LIMIT $index,$per_page";
  851. $Customers = $db->query($query,AS_ARRAY);
  852. $num_pages = ceil($customercount->total / $per_page);
  853. $page_links = paginate_links( array(
  854. 'base' => add_query_arg( 'pagenum', '%#%' ),
  855. 'format' => '',
  856. 'total' => $num_pages,
  857. 'current' => $pagenum
  858. ));
  859. $ranges = array(
  860. 'all' => __('Show New Customers','Shopp'),
  861. 'today' => __('Today','Shopp'),
  862. 'week' => __('This Week','Shopp'),
  863. 'month' => __('This Month','Shopp'),
  864. 'quarter' => __('This Quarter','Shopp'),
  865. 'year' => __('This Year','Shopp'),
  866. 'yesterday' => __('Yesterday','Shopp'),
  867. 'lastweek' => __('Last Week','Shopp'),
  868. 'last30' => __('Last 30 Days','Shopp'),
  869. 'last90' => __('Last 3 Months','Shopp'),
  870. 'lastmonth' => __('Last Month','Shopp'),
  871. 'lastquarter' => __('Last Quarter','Shopp'),
  872. 'lastyear' => __('Last Year','Shopp'),
  873. 'lastexport' => __('Last Export','Shopp'),
  874. 'custom' => __('Custom Dates','Shopp')
  875. );
  876. $exports = array(
  877. 'tab' => __('Tab-separated.txt','Shopp'),
  878. 'csv' => __('Comma-separated.csv','Shopp'),
  879. 'xls' => __('Microsoft&reg; Excel.xls','Shopp')
  880. );
  881. $formatPref = $Shopp->Settings->get('customerexport_format');
  882. if (!$formatPref) $formatPref = 'tab';
  883. $columns = array_merge(Customer::exportcolumns(),Billing::exportcolumns(),Shipping::exportcolumns());
  884. $selected = $Shopp->Settings->get('customerexport_columns');
  885. if (empty($selected)) $selected = array_keys($columns);
  886. $authentication = $Shopp->Settings->get('account_system');
  887. include("{$this->basepath}/core/ui/customers/customers.php");
  888. }
  889. function customers_list_columns () {
  890. shopp_register_column_headers('shopp_page_shopp-customers', array(
  891. 'cb'=>'<input type="checkbox" />',
  892. 'name'=>__('Name','Shopp'),
  893. 'login'=>__('Login','Shopp'),
  894. 'email'=>__('Email','Shopp'),
  895. 'location'=>__('Location','Shopp'),
  896. 'orders'=>__('Orders','Shopp'),
  897. 'joined'=>__('Joined','Shopp'))
  898. );
  899. }
  900. function customer_editor_ui () {
  901. global $Shopp;
  902. include("{$this->basepath}/core/ui/customers/ui.php");
  903. }
  904. function customer_editor () {
  905. global $Shopp,$Customer;
  906. if ( !current_user_can(SHOPP_USERLEVEL) )
  907. wp_die(__('You do not have sufficient permissions to access this page.'));
  908. if ($_GET['id'] != "new") {
  909. $Customer = new Customer($_GET['id']);
  910. $Customer->Billing = new Billing($Customer->id,'customer');
  911. $Customer->Shipping = new Shipping($Customer->id,'customer');
  912. if (empty($Customer->id))
  913. wp_die(__('The requested customer record does not exist.','Shopp'));
  914. } else $Customer = new Customer();
  915. $countries = array(''=>'');
  916. $countrydata = $Shopp->Settings->get('countries');
  917. foreach ($countrydata as $iso => $c) {
  918. if (isset($_POST['settings']) && $_POST['settings']['base_operations']['country'] == $iso)
  919. $base_region = $c['region'];
  920. $countries[$iso] = $c['name'];
  921. }
  922. $Customer->countries = $countries;
  923. $regions = $Shopp->Settings->get('zones');
  924. $Customer->billing_states = array_merge(array(''),(array)$regions[$Customer->Billing->country]);
  925. $Customer->shipping_states = array_merge(array(''),(array)$regions[$Customer->Shipping->country]);
  926. include("{$this->basepath}/core/ui/customers/editor.php");
  927. }
  928. /**
  929. * Products admin flow handlers
  930. **/
  931. function products_list($workflow=false) {
  932. global $Products,$Shopp;
  933. $db = DB::get();
  934. if ( !current_user_can(SHOPP_USERLEVEL) )
  935. wp_die(__('You do not have sufficient permissions to access this page.'));
  936. $defaults = array(
  937. 'cat' => false,
  938. 'pagenum' => 1,
  939. 'per_page' => 20,
  940. 's' => '',
  941. 'sl' => '',
  942. 'matchcol' => ''
  943. );
  944. $args = array_merge($defaults,$_GET);
  945. extract($args,EXTR_SKIP);
  946. if (!$workflow) {
  947. if (empty($categories)) $categories = array('');
  948. $category_table = DatabaseObject::tablename(Category::$table);
  949. $query = "SELECT id,name,parent FROM $category_table ORDER BY parent,name";
  950. $categories = $db->query($query,AS_ARRAY);
  951. $categories = sort_tree($categories);
  952. if (empty($categories)) $categories = array();
  953. $categories_menu = '<option value="">'.__('View all categories','Shopp').'</option>';
  954. $categories_menu .= '<option value="-"'.($cat=='-'?' selected="selected"':'').'>'.__('Uncategorized','Shopp').'</option>';
  955. foreach ($categories as $category) {
  956. $padding = str_repeat("&nbsp;",$category->depth*3);
  957. if ($cat == $category->id) $categories_menu .= '<option value="'.$category->id.'" selected="selected">'.$padding.$category->name.'</option>';
  958. else $categories_menu .= '<option value="'.$category->id.'">'.$padding.$category->name.'</option>';
  959. }
  960. $inventory_filters = array(
  961. 'all' => __('View all products','Shopp'),
  962. 'is' => __('In stock','Shopp'),
  963. 'ls' => __('Low stock','Shopp'),
  964. 'oos' => __('Out-of-stock','Shopp'),
  965. 'ns' => __('Not stocked','Shopp')
  966. );
  967. $inventory_menu = menuoptions($inventory_filters,$sl,true);
  968. }
  969. $pagenum = absint( $pagenum );
  970. if ( empty($pagenum) )
  971. $pagenum = 1;
  972. if( !$per_page || $per_page < 0 )
  973. $per_page = 20;
  974. $start = ($per_page * ($pagenum-1));
  975. $pd = DatabaseObject::tablename(Product::$table);
  976. $pt = DatabaseObject::tablename(Price::$table);
  977. $catt = DatabaseObject::tablename(Category::$table);
  978. $clog = DatabaseObject::tablename(Catalog::$table);
  979. $orderby = "pd.created DESC";
  980. $where = "true";
  981. $having = "";
  982. if (!empty($s)) {
  983. if (strpos($s,"sku:") !== false) { // SKU search
  984. $where .= ' AND pt.sku="'.substr($s,4).'"';
  985. $orderby = "pd.name";
  986. } else { // keyword search
  987. $interference = array("'s","'",".","\"");
  988. $search = preg_replace('/(\s?)(\w+)(\s?)/','\1*\2*\3',str_replace($interference,"", stripslashes($s)));
  989. $match = "MATCH(pd.name,pd.summary,pd.description) AGAINST ('$search' IN BOOLEAN MODE)";
  990. $where .= " AND $match";
  991. $matchcol = ", $match AS score";
  992. $orderby = "score DESC";
  993. }
  994. }
  995. // if (!empty($cat)) $where .= " AND cat.id='$cat' AND (clog.category != 0 OR clog.id IS NULL)";
  996. if (!empty($cat)) {
  997. if ($cat == "-") {
  998. $having = "HAVING COUNT(cat.id) = 0";
  999. } else {
  1000. $matchcol .= ", GROUP_CONCAT(DISTINCT cat.id ORDER BY cat.id SEPARATOR ',') AS catids";
  1001. $where .= " AND (clog.category != 0 OR clog.id IS NULL)";
  1002. $having = "HAVING FIND_IN_SET('$cat',catids) > 0";
  1003. }
  1004. }
  1005. if (!empty($sl)) {
  1006. switch($sl) {
  1007. case "ns": $where .= " AND pt.inventory='off'"; break;
  1008. case "oos":
  1009. $where .= " AND (pt.inventory='on')";
  1010. $having .= (empty($having)?"HAVING ":" AND ")."SUM(pt.stock) = 0";
  1011. break;
  1012. case "ls":
  1013. $ls = $Shopp->Settings->get('lowstock_level');
  1014. if (empty($ls)) $ls = '0';
  1015. $where .= " AND (pt.inventory='on' AND pt.stock <= $ls AND pt.stock > 0)";
  1016. break;
  1017. case "is": $where .= " AND (pt.inventory='on' AND pt.stock > 0)";
  1018. }
  1019. }
  1020. $base = $Shopp->Settings->get('base_operations');
  1021. if ($base['vat']) $taxrate = $Shopp->Cart->taxrate();
  1022. if (empty($taxrate)) $taxrate = 0;
  1023. $columns = "SQL_CALC_FOUND_ROWS pd.id,pd.name,pd.slug,pd.featured,pd.variations,GROUP_CONCAT(DISTINCT cat.name ORDER BY cat.name SEPARATOR ', ') AS categories,if(pt.options=0,IF(pt.tax='off',pt.price,pt.price+(pt.price*$taxrate)),-1) AS mainprice,IF(MAX(pt.tax)='off',MAX(pt.price),MAX(pt.price+(pt.price*$taxrate))) AS maxprice,IF(MAX(pt.tax)='off',MIN(pt.price),MIN(pt.price+(pt.price*$taxrate))) AS minprice,IF(pt.inventory='on','on','off') AS inventory,ROUND(SUM(pt.stock)/count(DISTINCT clog.id),0) AS stock";
  1024. if ($workflow) $columns = "pd.id";
  1025. // Load the products
  1026. $query = "SELECT $columns $matchcol FROM $pd AS pd LEFT JOIN $pt AS pt ON pd.id=pt.product AND pt.type != 'N/A' LEFT JOIN $clog AS clog ON pd.id=clog.product LEFT JOIN $catt AS cat ON cat.id=clog.category WHERE $where GROUP BY pd.id $having ORDER BY $orderby LIMIT $start,$per_page";
  1027. $Products = $db->query($query,AS_ARRAY);
  1028. $productcount = $db->query("SELECT FOUND_ROWS() as total");
  1029. $num_pages = ceil($productcount->total / $per_page);
  1030. $page_links = paginate_links( array(
  1031. 'base' => add_query_arg(array("edit"=>null,'pagenum' => '%#%')),
  1032. 'format' => '',
  1033. 'total' => $num_pages,
  1034. 'current' => $pagenum,
  1035. ));
  1036. if ($workflow) return $Products;
  1037. include("{$this->basepath}/core/ui/products/products.php");
  1038. }
  1039. function products_list_columns () {
  1040. shopp_register_column_headers('shopp_page_shopp-products', array(
  1041. 'cb'=>'<input type="checkbox" />',
  1042. 'name'=>__('Name','Shopp'),
  1043. 'category'=>__('Category','Shopp'),
  1044. 'price'=>__('Price','Shopp'),
  1045. 'inventory'=>__('Inventory','Shopp'),
  1046. 'featured'=>__('Featured','Shopp'))
  1047. );
  1048. }
  1049. function product_shortcode ($atts) {
  1050. global $Shopp;
  1051. if (isset($atts['name'])) {
  1052. $Shopp->Product = new Product($atts['name'],'name');
  1053. } elseif (isset($atts['slug'])) {
  1054. $Shopp->Product = new Product($atts['slug'],'slug');
  1055. } elseif (isset($atts['id'])) {
  1056. $Shopp->Product = new Product($atts['id']);
  1057. } else return "";
  1058. if (isset($atts['nowrap']) && value_is_true($atts['nowrap']))
  1059. return $Shopp->Catalog->tag('product',$atts);
  1060. else return '<div id="shopp">'.$Shopp->Catalog->tag('product',$atts).'<div class="clear"></div></div>';
  1061. }
  1062. function category_shortcode ($atts) {
  1063. global $Shopp;
  1064. $tag = 'category';
  1065. if (isset($atts['name'])) {
  1066. $Shopp->Category = new Category($atts['name'],'name');
  1067. unset($atts['name']);
  1068. } elseif (isset($atts['slug'])) {
  1069. switch ($atts['slug']) {
  1070. case SearchResults::$_slug: $tag = 'search-products'; unset($atts['slug']);
  1071. break;
  1072. case TagProducts::$_slug: $tag = 'tag-products'; unset($atts['slug']);
  1073. break;
  1074. case BestsellerProducts::$_slug: $tag = 'bestseller-products'; unset($atts['slug']);
  1075. break;
  1076. case CatalogProducts::$_slug: $tag = 'catalog-products'; unset($atts['slug']);
  1077. break;
  1078. case NewProducts::$_slug: $tag = 'new-products'; unset($atts['slug']);
  1079. break;
  1080. case FeaturedProducts::$_slug: $tag = 'featured-products'; unset($atts['slug']);
  1081. break;
  1082. case OnSaleProducts::$_slug: $tag = 'onsale-products'; unset($atts['slug']);
  1083. break;
  1084. case RandomProducts::$_slug: $tag = 'random-products'; unset($atts['slug']);
  1085. break;
  1086. }
  1087. } elseif (isset($atts['id'])) {
  1088. $Shopp->Category = new Category($atts['id']);
  1089. unset($atts['id']);
  1090. } else return "";
  1091. if (isset($atts['nowrap']) && value_is_true($atts['nowrap']))
  1092. return $Shopp->Catalog->tag($tag,$atts);
  1093. else return '<div id="shopp">'.$Shopp->Catalog->tag($tag,$atts).'<div class="clear"></div></div>';
  1094. }
  1095. function maintenance_shortcode ($atts) {
  1096. return '<div id="shopp" class="update"><p>The store is currently down for maintenance. We\'ll be back soon!</p><div class="clear"></div></div>';
  1097. }
  1098. function product_editor_ui () {
  1099. global $Shopp;
  1100. include("{$this->basepath}/core/ui/products/ui.php");
  1101. }
  1102. function product_editor() {
  1103. global $Shopp;
  1104. $db = DB::get();
  1105. if ( !current_user_can(SHOPP_USERLEVEL) )
  1106. wp_die(__('You do not have sufficient permissions to access this page.'));
  1107. if (empty($Shopp->Product)) {
  1108. $Product = new Product();
  1109. $Product->published = "on";
  1110. } else $Product = $Shopp->Product;
  1111. // $Product->load_data(array('images'));
  1112. // echo "<pre>"; print_r($Product->imagesets); echo "</pre>";
  1113. $Product->slug = apply_filters('editable_slug',$Product->slug);
  1114. $permalink = $Shopp->shopuri;
  1115. require_once("{$this->basepath}/core/model/Asset.php");
  1116. require_once("{$this->basepath}/core/model/Category.php");
  1117. $Price = new Price();
  1118. $priceTypes = array(
  1119. array('value'=>'Shipped','label'=>__('Shipped','Shopp')),
  1120. array('value'=>'Virtual','label'=>__('Virtual','Shopp')),
  1121. array('value'=>'Download','label'=>__('Download','Shopp')),
  1122. array('value'=>'Donation','label'=>__('Donation','Shopp')),
  1123. array('value'=>'N/A','label'=>__('Disabled','Shopp')),
  1124. );
  1125. $workflows = array(
  1126. "continue" => __('Continue Editing','Shopp'),
  1127. "close" => __('Products Manager','Shopp'),
  1128. "new" => __('New Product','Shopp'),
  1129. "next" => __('Edit Next','Shopp'),
  1130. "previous" => __('Edit Previous','Shopp')
  1131. );
  1132. $taglist = array();
  1133. foreach ($Product->tags as $tag) $taglist[] = $tag->name;
  1134. if ($Product->id) {
  1135. $Assets = new Asset();
  1136. $Images = $db->query("SELECT id,src,properties FROM $Assets->_table WHERE context='product' AND parent=$Product->id AND datatype='thumbnail' ORDER BY sortorder",AS_ARRAY);
  1137. unset($Assets);
  1138. }
  1139. $shiprates = $this->Settings->get('shipping_rates');
  1140. if (!empty($shiprates)) ksort($shiprates);
  1141. $uploader = $Shopp->Settings->get('uploader_pref');
  1142. if (!$uploader) $uploader = 'flash';
  1143. $process = (!empty($Product->id)?$Product->id:'new');
  1144. $_POST['action'] = add_query_arg(array_merge($_GET,array('page'=>$this->Admin->products)),$Shopp->wpadminurl."admin.php");
  1145. include("{$this->basepath}/core/ui/products/editor.php");
  1146. }
  1147. function save_product($Product) {
  1148. global $Shopp;
  1149. $db = DB::get();
  1150. check_admin_referer('shopp-save-product');
  1151. if ( !current_user_can(SHOPP_USERLEVEL) )
  1152. wp_die(__('You do not have sufficient permissions to access this page.'));
  1153. $this->settings_save(); // Save workflow setting
  1154. $base = $Shopp->Settings->get('base_operations');
  1155. $taxrate = 0;
  1156. if ($base['vat']) $taxrate = $Shopp->Cart->taxrate();
  1157. if (!$_POST['options']) $Product->options = array();
  1158. else $_POST['options'] = stripslashes_deep($_POST['options']);
  1159. if (empty($Product->slug)) $Product->slug = sanitize_title_with_dashes($_POST['name']);
  1160. // Check for an existing product slug
  1161. $exclude_product = !empty($Product->id)?"AND id != $Product->id":"";
  1162. $existing = $db->query("SELECT slug FROM $Product->_table WHERE slug='$Product->slug' $exclude_product LIMIT 1");
  1163. if ($existing) {
  1164. $suffix = 2;
  1165. while($existing) {
  1166. $altslug = substr($Product->slug, 0, 200-(strlen($suffix)+1)). "-$suffix";
  1167. $existing = $db->query("SELECT slug FROM $Product->_table WHERE slug='$altslug' $exclude_product LIMIT 1");
  1168. $suffix++;
  1169. }
  1170. $Product->slug = $altslug;
  1171. }
  1172. if (isset($_POST['content'])) $_POST['description'] = $_POST['content'];
  1173. $Product->updates($_POST,array('categories'));
  1174. $Product->save();
  1175. $Product->save_categories($_POST['categories']);
  1176. $Product->save_tags(explode(",",$_POST['taglist']));
  1177. if (!empty($_POST['price']) && is_array($_POST['price'])) {
  1178. // Delete prices that were marked…

Large files files are truncated, but you can click here to view the full file