public function delete() { $delete = $this->request('delete'); if (false === $delete) { return; } $active = (array) shopp_setting('active_shipping'); $index = false; if (strpos($delete, '-') !== false) { list($delete, $index) = explode('-', $delete); } if (!array_key_exists($delete, $active)) { return $this->notice(Shopp::__('The requested shipping method could not be deleted because it does not exist.'), 'error'); } if (is_array($active[$delete])) { if (array_key_exists($index, $active[$delete])) { unset($active[$delete][$index]); if (empty($active[$delete])) { unset($active[$delete]); } } } else { unset($active[$delete]); } shopp_set_setting('active_shipping', $active); $this->notice(Shopp::__('Shipping method setting removed.')); Shopp::redirect($this->url()); }
public function updates() { $rates = shopp_setting('taxrates'); $updates = $this->form('taxrates'); if (!empty($updates)) { if (array_key_exists('new', $updates)) { $rates[] = $updates['new']; } else { $rates = array_replace($rates, $updates); } // Re-sort taxes from generic to most specific usort($rates, array($this, 'sortrates')); $rates = stripslashes_deep($rates); shopp_set_setting('taxrates', $rates); unset($_POST['settings']['taxrates']); } shopp_set_formsettings(); // Save other tax settings $this->notice(Shopp::__('Tax settings saved.')); Shopp::redirect(add_query_arg()); }
public function loader($workflow = false) { if (!current_user_can('shopp_products')) { return; } add_screen_option('per_page', array('label' => __('Products Per Page', 'Shopp'), 'default' => 20, 'option' => 'edit_' . ShoppProduct::$posttype . '_per_page')); $per_page_option = get_current_screen()->get_option('per_page'); $defaults = array('cat' => false, 'paged' => 1, 'per_page' => $per_page_option['default'], 's' => '', 'sl' => '', 'matchcol' => '', 'view' => $this->view, 'is_inventory' => false, 'is_trash' => false, 'is_bestselling' => false, 'categories_menu' => false, 'inventory_menu' => false, 'lowstock' => 0, 'columns' => '', 'orderby' => '', 'order' => '', 'where' => array(), 'joins' => array()); $args = array_merge($defaults, $_GET); if (false !== ($user_per_page = get_user_option($per_page_option['option']))) { $args['per_page'] = $user_per_page; } extract($args, EXTR_SKIP); $url = ShoppAdminController::url($_GET); $subs = array('all' => array('label' => Shopp::__('All'), 'where' => array("p.post_status!='trash'")), 'published' => array('label' => Shopp::__('Published'), 'where' => array("p.post_status='publish'")), 'drafts' => array('label' => Shopp::__('Drafts'), 'where' => array("p.post_status='draft'")), 'onsale' => array('label' => Shopp::__('On Sale'), 'where' => array("s.sale='on' AND p.post_status != 'trash'")), 'featured' => array('label' => Shopp::__('Featured'), 'where' => array("s.featured='on' AND p.post_status != 'trash'")), 'bestselling' => array('label' => Shopp::__('Bestselling'), 'where' => array("p.post_status!='trash'", BestsellerProducts::threshold() . " < s.sold"), 'order' => 'bestselling'), 'inventory' => array('label' => Shopp::__('Inventory'), 'where' => array("s.inventory='on' AND p.post_status != 'trash'")), 'trash' => array('label' => Shopp::__('Trash'), 'where' => array("p.post_status='trash'"))); if (!shopp_setting_enabled('inventory')) { unset($subs['inventory']); } switch ($view) { case 'inventory': if (shopp_setting_enabled('inventory')) { $is_inventory = true; } else { Shopp::redirect(add_query_arg('view', null, $url), true); } break; case 'trash': $is_trash = true; break; case 'bestselling': $is_bestselling = true; break; } if ($is_inventory) { $per_page = 50; } $pagenum = absint($paged); $start = $per_page * ($pagenum - 1); $where = $subs[$this->view]['where']; if (!empty($s)) { $SearchResults = new SearchResults(array('search' => $s, 'nostock' => 'on', 'published' => 'off', 'paged' => -1)); $SearchResults->load(); $ids = array_keys($SearchResults->products); $where[] = "p.ID IN (" . join(',', $ids) . ")"; } if (!empty($cat)) { global $wpdb; $joins[$wpdb->term_relationships] = "INNER JOIN {$wpdb->term_relationships} AS tr ON (p.ID=tr.object_id)"; $joins[$wpdb->term_taxonomy] = "INNER JOIN {$wpdb->term_taxonomy} AS tt ON (tr.term_taxonomy_id=tt.term_taxonomy_id AND tt.term_id={$cat})"; if (-1 == $cat) { unset($joins[$wpdb->term_taxonomy]); $joins[$wpdb->term_relationships] = "LEFT JOIN {$wpdb->term_relationships} AS tr ON (p.ID=tr.object_id)"; $where[] = 'tr.object_id IS NULL'; } } // Detect custom taxonomies $taxonomies = array_intersect(get_object_taxonomies(ShoppProduct::$posttype), array_keys($_GET)); if (!empty($taxonomies)) { foreach ($taxonomies as $n => $taxonomy) { global $wpdb; $term = get_term_by('slug', $_GET[$taxonomy], $taxonomy); if (!empty($term->term_id)) { $joins[$wpdb->term_relationships . '_' . $n] = "INNER JOIN {$wpdb->term_relationships} AS tr{$n} ON (p.ID=tr{$n}.object_id)"; $joins[$wpdb->term_taxonomy . '_' . $n] = "INNER JOIN {$wpdb->term_taxonomy} AS tt{$n} ON (tr{$n}.term_taxonomy_id=tt{$n}.term_taxonomy_id AND tt{$n}.term_id={$term->term_id})"; } } } if (!empty($sl) && shopp_setting_enabled('inventory')) { switch ($sl) { case "ns": foreach ($where as &$w) { $w = str_replace("s.inventory='on'", "s.inventory='off'", $w); } $where[] = "s.inventory='off'"; break; case "oos": $where[] = "(s.inventory='on' AND s.stock = 0)"; break; case "ls": $ls = shopp_setting('lowstock_level'); if (empty($ls)) { $ls = '0'; } $where[] = "(s.inventory='on' AND s.lowstock != 'none')"; break; case "is": $where[] = "(s.inventory='on' AND s.stock > 0)"; } } $lowstock = shopp_setting('lowstock_level'); // Setup queries $pd = WPDatabaseObject::tablename(ShoppProduct::$table); $pt = ShoppDatabaseObject::tablename(ShoppPrice::$table); $ps = ShoppDatabaseObject::tablename(ProductSummary::$table); $orderdirs = array('asc', 'desc'); if (in_array($order, $orderdirs)) { $orderd = strtolower($order); } else { $orderd = 'asc'; } if (isset($subs[$this->view]['order'])) { $order = $subs[$this->view]['order']; } $ordercols = ''; switch ($orderby) { case 'name': $order = 'title'; if ('desc' == $orderd) { $order = 'reverse'; } break; case 'price': $order = 'lowprice'; if ('desc' == $orderd) { $order = 'highprice'; } break; case 'date': $order = 'newest'; if ('desc' == $orderd) { $order = 'oldest'; } break; case 'sold': $ordercols = 's.sold ' . $orderd; break; case 'gross': $ordercols = 's.grossed ' . $orderd; break; case 'inventory': $ordercols = 's.stock ' . $orderd; break; case 'sku': $ordercols = 'pt.sku ' . $orderd; break; } if (in_array($this->view, array('onsale', 'featured', 'inventory'))) { $joins[$ps] = "INNER JOIN {$ps} AS s ON p.ID=s.product"; } $loading = array('where' => $where, 'joins' => $joins, 'limit' => "{$start},{$per_page}", 'load' => array('categories', 'coverimages'), 'published' => false, 'order' => $order, 'nostock' => true); if (!empty($ordercols)) { unset($loading['order']); $loading['orderby'] = $ordercols; } if ($is_inventory) { // Override for inventory products $where[] = "(pt.context='product' OR pt.context='variation') AND pt.type != 'N/A'"; $loading = array('columns' => "pt.id AS stockid,IF(pt.context='variation',CONCAT(p.post_title,': ',pt.label),p.post_title) AS post_title,pt.sku AS sku,pt.stock AS stock", 'joins' => array_merge(array($pt => "LEFT JOIN {$pt} AS pt ON p.ID=pt.product"), $joins), 'where' => $where, 'groupby' => 'pt.id', 'orderby' => str_replace('s.', 'pt.', $ordercols), 'limit' => "{$start},{$per_page}", 'nostock' => true, 'published' => false); } // Override loading product meta and limiting by pagination in the workflow list if ($workflow) { unset($loading['limit']); $loading['ids'] = true; $loading['pagination'] = false; $loading['load'] = array(); } $this->products = new ProductCollection(); $this->products->load($loading); // Overpagination protection, redirect to page 1 if the requested page doesn't exist $num_pages = ceil($this->products->total / $per_page); if ($paged > 1 && $paged > $num_pages) { Shopp::redirect(add_query_arg('paged', null, $url)); } // Return a list of product keys for workflow list requests if ($workflow) { return $this->products->worklist(); } // Get sub-screen counts $subcounts = Shopp::cache_get('shopp_product_subcounts', 'shopp_admin'); if ($subcounts) { foreach ($subcounts as $name => $total) { if (isset($subs[$name])) { $subs[$name]['total'] = $total; } } } else { $subcounts = array(); foreach ($subs as $name => &$subquery) { $subquery['total'] = 0; $query = array('columns' => "count(*) AS total", 'table' => "{$pd} as p", 'joins' => array(), 'where' => array()); $query = array_merge($query, $subquery); $query['where'][] = "p.post_type='shopp_product'"; if (in_array($name, array('onsale', 'bestselling', 'featured', 'inventory'))) { $query['joins'][$ps] = "INNER JOIN {$ps} AS s ON p.ID=s.product"; } $query = sDB::select($query); $subquery['total'] = sDB::query($query, 'auto', 'col', 'total'); $subcounts[$name] = $subquery['total']; } Shopp::cache_set('shopp_product_subcounts', $subcounts, 'shopp_admin'); } $this->subs = $subs; }
/** * Handles product file download requests * * @author Jonathan Davis * @since 1.1 * * @return void **/ public function download() { $Shopp = Shopp::object(); $download = $this->request['shopp_download']; $Purchase = false; $Purchased = false; if (defined('WP_ADMIN')) { $forbidden = false; $Download = new ProductDownload($download); } else { $Order = ShoppOrder(); $accounts = 'none' != shopp_setting('account_system'); $Download = new ProductDownload(); $Download->loadby_dkey($download); $Purchased = $Download->purchased(); $Purchase = new ShoppPurchase($Purchased->purchase); $Purchase->load_events(); $name = $Purchased->name . (!empty($Purchased->optionlabel) ? ' (' . $Purchased->optionlabel . ')' : ''); $forbidden = false; // Voided orders if ($Purchase->isvoid()) { shopp_add_error(Shopp::__('"%s" cannot be downloaded because the order has been cancelled.', $name)); $forbidden = true; } // Purchase Completion check if (!$Purchase->ispaid() && !SHOPP_PREPAYMENT_DOWNLOADS) { shopp_add_error(Shopp::__('"%s" cannot be downloaded because payment has not been received yet.', $name)); $forbidden = true; } // If accounts are used and this is not a guest account if ($accounts && Shopp::__('Guest') != ShoppCustomer()->type) { // User must be logged in when accounts are being used if (!ShoppCustomer()->loggedin()) { shopp_add_error(Shopp::__('You must login to download purchases.')); $forbidden = true; } // Logged in account must be the owner of the purchase if (ShoppCustomer()->id != $Purchase->customer) { shopp_add_error(Shopp::__('You are not authorized to download the requested file.')); $forbidden = true; } } // Download limit checking if (shopp_setting('download_limit') && $Purchased->downloads + 1 > shopp_setting('download_limit')) { shopp_add_error(Shopp::__('"%s" is no longer available for download because the download limit has been reached.', $name)); $forbidden = true; } // Download expiration checking if (shopp_setting('download_timelimit') && $Purchased->created + shopp_setting('download_timelimit') < current_time('timestamp')) { shopp_add_error(Shopp::__('"%s" is no longer available for download because it has expired.', 'Shopp', $name)); $forbidden = true; } // IP restriction checks if ('ip' == shopp_setting('download_restriction') && !empty($Purchase->ip) && $Purchase->ip != $_SERVER['REMOTE_ADDR']) { shopp_add_error(Shopp::__('"%s" cannot be downloaded because your computer could not be verified as the system the file was purchased from.', $name)); $forbidden = true; } do_action_ref_array('shopp_download_request', array($Purchased)); } if (apply_filters('shopp_download_forbidden', $forbidden, $Purchased)) { Shopp::redirect(add_query_arg('downloads', '', Shopp::url(false, 'account')), true, 303); } // Send the download $download = $Download->download(); if (is_a($download, 'ShoppError')) { // If the result is an error redirect to the account downloads page Shopp::redirect(add_query_arg('downloads', '', Shopp::url(false, 'account')), true, 303); } else { do_action_ref_array('shopp_download_success', array($Purchased, $Purchase, $Download)); // @deprecated use shopp_download_order_event instead shopp_add_order_event($Purchase->id, 'download', array('purchased' => $Purchased->id, 'download' => $Download->id, 'ip' => ShoppShopping()->ip, 'customer' => ShoppCustomer()->id)); } exit; }
/** * Handle the synchronous return from PPS (PDT and default return) * * @author Jonathan Davis * @since 1.2 **/ public function pdt() { $Order = ShoppOrder(); if (!$this->pdtvalid()) { return; } $Message = $this->Message; $id = $Message->order(); $event = $Message->event(); $Purchase = new ShoppPurchase($id); if (empty($Purchase->id)) { shopp_debug('PDT processing could not load the in progress order from the database.'); return Shopp::redirect(Shopp::url(false, 'thanks', false)); } $Order->inprogress = $Purchase->id; $this->process($event, $Purchase); Shopp::redirect(Shopp::url(false, 'thanks', false)); }
public function updates() { $form = $this->form(); if (empty($form)) { return; } do_action('shopp_save_payment_settings'); $Gateways = Shopp::object()->Gateways; $gateways = array_keys($Gateways->activated()); $gateway = key($form); // Handle Multi-instance payment systems $indexed = false; if (preg_match('/\\[(\\d+)\\]/', $gateway, $matched)) { $indexed = '-' . $matched[1]; $gateway = str_replace($matched[0], '', $gateway); } // Merge the existing gateway settings with the newly updated settings if (isset($Gateways->active[$gateway])) { $Gateway = $Gateways->active[$gateway]; // Cannot use array_merge() because it adds numeric index values instead of overwriting them $this->form[$gateway] = (array) $this->form[$gateway] + (array) $Gateway->settings; } // Add newly activated gateways if (!in_array($gateway . $indexed, $gateways)) { $gateways[] = $gateway . $indexed; shopp_set_setting('active_gateways', join(',', $gateways)); } // Save the gateway settings shopp_set_formsettings(); $this->notice(Shopp::__('Shopp payments settings saved.')); Shopp::redirect(add_query_arg()); }
/** * Handles shopping cart requests * * @author Jonathan Davis * @since 1.1 * * @return void **/ public function cart() { if (isset($_REQUEST['shopping']) && 'reset' == strtolower($_REQUEST['shopping'])) { ShoppShopping()->reset(); Shopp::redirect(Shopp::url()); } if (empty($_REQUEST['cart'])) { return true; } do_action('shopp_cart_request'); if (isset($_REQUEST['checkout'])) { Shopp::redirect(Shopp::url(false, 'checkout', $this->security())); } if (isset($_REQUEST['ajax'])) { $Cart = ShoppOrder()->Cart; $Cart->totals(); $Cart->ajax(); } $redirect = false; if (isset($_REQUEST['redirect'])) { $redirect = $_REQUEST['redirect']; } switch ($redirect) { case 'checkout': Shopp::redirect(Shopp::url(false, $redirect, ShoppOrder()->security())); break; default: if (!empty($_REQUEST['redirect'])) { Shopp::safe_redirect($_REQUEST['redirect']); } else { Shopp::redirect(Shopp::url(false, 'cart')); } } exit; }
/** * Handles orders list loading * * @author Jonathan Davis * @since 1.2.1 * * @return void **/ public function loader() { if (!current_user_can('shopp_orders')) { return; } $defaults = array('page' => false, 'deleting' => false, 'selected' => false, 'update' => false, 'newstatus' => false, 'pagenum' => 1, 'paged' => 1, 'per_page' => 20, 'start' => '', 'end' => '', 'status' => false, 's' => '', 'range' => '', 'startdate' => '', 'enddate' => ''); $args = array_merge($defaults, $_GET); extract($args, EXTR_SKIP); $url = add_query_arg(array_merge($_GET, array('page' => $this->Admin->pagename('orders'))), admin_url('admin.php')); if ($page == "shopp-orders" && !empty($deleting) && !empty($selected) && is_array($selected) && current_user_can('shopp_delete_orders')) { foreach ($selected as $selection) { $Purchase = new ShoppPurchase($selection); $Purchase->load_purchased(); foreach ($Purchase->purchased as $purchased) { $Purchased = new ShoppPurchased($purchased->id); $Purchased->delete(); } $Purchase->delete(); } if (count($selected) == 1) { $this->notice(__('Order deleted.', 'Shopp')); } else { $this->notice(sprintf(__('%d orders deleted.', 'Shopp'), count($selected))); } } $statusLabels = shopp_setting('order_status'); if (empty($statusLabels)) { $statusLabels = array(''); } $txnstatus_labels = Lookup::txnstatus_labels(); if ($update == "order" && !empty($selected) && is_array($selected)) { foreach ($selected as $selection) { $Purchase = new ShoppPurchase($selection); $Purchase->status = $newstatus; $Purchase->save(); } if (count($selected) == 1) { $this->notice(__('Order status updated.', 'Shopp')); } else { $this->notice(sprintf(__('%d orders updated.', 'Shopp'), count($selected))); } } $Purchase = new ShoppPurchase(); $offset = get_option('gmt_offset') * 3600; if (!empty($start)) { $startdate = $start; list($month, $day, $year) = explode("/", $startdate); $starts = mktime(0, 0, 0, $month, $day, $year); } if (!empty($end)) { $enddate = $end; list($month, $day, $year) = explode("/", $enddate); $ends = mktime(23, 59, 59, $month, $day, $year); } $pagenum = absint($paged); $start = $per_page * ($pagenum - 1); $where = array(); $joins = array(); if (!empty($status) || $status === '0') { $where[] = "status='" . sDB::escape($status) . "'"; } if (!empty($s)) { $s = stripslashes($s); $search = array(); if (preg_match_all('/(\\w+?)\\:(?="(.+?)"|(.+?)\\b)/', $s, $props, PREG_SET_ORDER) > 0) { foreach ($props as $query) { $keyword = sDB::escape(!empty($query[2]) ? $query[2] : $query[3]); switch (strtolower($query[1])) { case "txn": $search[] = "txnid='{$keyword}'"; break; case "company": $search[] = "company LIKE '%{$keyword}%'"; break; case "gateway": $search[] = "gateway LIKE '%{$keyword}%'"; break; case "cardtype": $search[] = "cardtype LIKE '%{$keyword}%'"; break; case "address": $search[] = "(address LIKE '%{$keyword}%' OR xaddress='%{$keyword}%')"; break; case "city": $search[] = "city LIKE '%{$keyword}%'"; break; case "province": case "state": $search[] = "state='{$keyword}'"; break; case "zip": case "zipcode": case "postcode": $search[] = "postcode='{$keyword}'"; break; case "country": $search[] = "country='{$keyword}'"; break; case "promo": case "discount": $meta_table = ShoppDatabaseObject::tablename(ShoppMetaObject::$table); $joins[$meta_table] = "INNER JOIN {$meta_table} AS m ON m.parent = o.id AND context='purchase'"; $search[] = "m.value LIKE '%{$keyword}%'"; break; case "product": $purchased = ShoppDatabaseObject::tablename(Purchased::$table); $joins[$purchased] = "INNER JOIN {$purchased} AS p ON p.purchase = o.id"; $search[] = "p.name LIKE '%{$keyword}%' OR p.optionlabel LIKE '%{$keyword}%' OR p.sku LIKE '%{$keyword}%'"; break; } } if (empty($search)) { $search[] = "(id='{$s}' OR CONCAT(firstname,' ',lastname) LIKE '%{$s}%')"; } $where[] = "(" . join(' OR ', $search) . ")"; } elseif (strpos($s, '@') !== false) { $where[] = "email='" . sDB::escape($s) . "'"; } else { $where[] = "(id='{$s}' OR CONCAT(firstname,' ',lastname) LIKE '%" . sDB::escape($s) . "%')"; } } if (!empty($starts) && !empty($ends)) { $where[] = "created BETWEEN '" . sDB::mkdatetime($starts) . "' AND '" . sDB::mkdatetime($ends) . "'"; } if (!empty($customer)) { $where[] = "customer=" . intval($customer); } $where = !empty($where) ? "WHERE " . join(' AND ', $where) : ''; $joins = join(' ', $joins); $countquery = "SELECT count(*) as total,SUM(IF(txnstatus IN ('authed','captured'),total,NULL)) AS sales,AVG(IF(txnstatus IN ('authed','captured'),total,NULL)) AS avgsale FROM {$Purchase->_table} AS o {$joins} {$where} ORDER BY o.created DESC LIMIT 1"; $this->ordercount = sDB::query($countquery, 'object'); $query = "SELECT o.* FROM {$Purchase->_table} AS o {$joins} {$where} ORDER BY created DESC LIMIT {$start},{$per_page}"; $this->orders = sDB::query($query, 'array', 'index', 'id'); $num_pages = ceil($this->ordercount->total / $per_page); if ($paged > 1 && $paged > $num_pages) { Shopp::redirect(add_query_arg('paged', null, $url)); } }
/** * Handle auto-updates from Shopp 1.0 * * @since 1.1 * * @return void **/ public function legacyupdate() { global $plugin_page; if ('shopp-settings-update' == $plugin_page && isset($_GET['updated']) && $_GET['updated'] == 'true') { Shopp::redirect(add_query_arg('page', ShoppAdmin::pagename('orders'), admin_url('admin.php'))); } }
/** * Create a lock for transaction processing * * @author Jonathan Davis * @since 1.2.1 * * @return boolean **/ public function lock($data) { if (!isset($data['order'])) { return false; } $order = $data['order']; $locked = 0; for ($attempts = 0; $attempts < 3 && $locked == 0; $attempts++) { $locked = sDB::query("SELECT GET_LOCK('{$order}'," . SHOPP_TXNLOCK_TIMEOUT . ") AS locked", 'auto', 'col', 'locked'); if (0 == $locked) { sleep(1); } // Wait a sec before trying again } if (1 == $locked) { return true; } shopp_debug("Purchase authed lock for order #{$order} failed. Could not achieve a lock."); Shopp::redirect(Shopp::url(false, 'thanks', ShoppOrder()->security())); }
/** * Handles loading, saving and deleting categories in a workflow context * * @author Jonathan Davis * @since 1.0 * @return void **/ public function workflow() { $defaults = array('action' => false, 'selected' => array(), 'page' => false, 'id' => false, 'save' => false, 'next' => false, '_wpnonce' => false); $args = array_merge($defaults, $_REQUEST); extract($args, EXTR_SKIP); if (!defined('WP_ADMIN') || $page != $this->page()) { return false; } $adminurl = admin_url('admin.php'); add_screen_option('per_page', array('label' => __('Categories Per Page', 'Shopp'), 'default' => 20, 'option' => 'edit_' . ProductCategory::$taxon . '_per_page')); if ('delete' == $action && wp_verify_nonce($_wpnonce, 'shopp_categories_manager')) { if (!empty($id)) { $selected = array($id); } $total = count($selected); foreach ($selected as $selection) { $DeletedCategory = new ProductCategory($selection); $deleted = $DeletedCategory->name; $DeletedCategory->delete(); } if (1 == $total) { $this->notice(Shopp::__('Deleted %s category.', "<strong>{$deleted}</strong>")); } else { $this->notice(Shopp::__('Deleted %s categories.', "<strong>{$total}</strong>")); } $reset = array('selected' => null, 'action' => null, 'id' => null, '_wpnonce' => null); $redirect = add_query_arg(array_merge($_GET, $reset), $adminurl); Shopp::redirect($redirect); exit; } if ($id && 'new' != $id) { $Category = new ProductCategory($id); } else { $Category = new ProductCategory(); } $meta = array('specs', 'priceranges', 'options', 'prices'); foreach ($meta as $prop) { if (!isset($Category->{$prop})) { $Category->{$prop} = array(); } } if ($save) { $this->save($Category); // Workflow handler if (isset($_REQUEST['settings']) && isset($_REQUEST['settings']['workflow'])) { $workflow = $_REQUEST['settings']['workflow']; $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; } if (isset($key)) { $next = isset($this->worklist[$key]) ? $this->worklist[$key] : 'close'; } } if ($next) { if ('new' == $next) { $Category = new ProductCategory(); } else { $Category = new ProductCategory($next); } } else { if (empty($id)) { $id = $Category->id; } $Category = new ProductCategory($id); } } ShoppCollection($Category); }
public function process() { $action = $this->form('checkout'); if ('process' != $action) { return; } $Payments = ShoppOrder()->Payments; $Cart = ShoppOrder()->Cart; $forcedconfirm = 'always' == shopp_setting('order_confirmation'); $wasfree = $Cart->orderisfree(); // Get current free status $estimated = $Cart->total(); // Get current total $Cart->totals(); // Retotal after checkout to capture order total changes // We have to avoid truthiness, hence the strange logic expression if (true !== apply_filters('shopp_validate_checkout', true)) { return; } else { $this->customer(); } // Catch changes from validation // Catch originally free orders that get extra (shipping) costs added to them if ($wasfree && $Payments->count() > 1 && !$Cart->orderisfree() && empty($Payments->selected()->cards)) { shopp_add_error(Shopp::__('The order amount changed and requires that you select a payment method.')); Shopp::redirect(Shopp::url(false, 'checkout', ShoppOrder()->security())); } // Do not use shopp_checkout_processed for payment gateway redirect actions // Free order processing doesn't take over until the order is submitted for processing in `shopp_process_order` do_action('shopp_checkout_processed'); // If the cart's total changes at all, confirm the order if (apply_filters('shopp_order_confirm_needed', $estimated != $Cart->total() || $forcedconfirm)) { Shopp::redirect(Shopp::url(false, 'confirm', ShoppOrder()->security())); return; } do_action('shopp_process_order'); }
public function returned() { if ($this->id() != $_GET['rmtpay']) { return; } // Not our offsite payment $request = array_merge(array('merchant_order_id' => false, 'key' => false, 'order_number' => false, 'total' => false, 'credit_card_processed' => false, 'invoice_id' => false, 'pay_method' => false), $_GET); extract($request, EXTR_SKIP); if (Shopp::str_true($this->settings['verify']) && !$this->verify($key)) { shopp_add_error(Shopp::__('The order submitted by 2Checkout could not be verified.'), SHOPP_TRXN_ERR); Shopp::redirect(Shopp::url(false, 'checkout')); } if (empty($merchant_order_id)) { shopp_add_error(Shopp::__('The order submitted by 2Checkout did not specify a transaction ID.'), SHOPP_TRXN_ERR); Shopp::redirect(Shopp::url(false, 'checkout')); } $Purchase = ShoppPurchase(new ShoppPurchase((int) $merchant_order_id)); if (!$Purchase->exists()) { shopp_add_error(Shopp::__('The order submitted by 2Checkout did not match any submitted orders.'), SHOPP_TRXN_ERR); Shopp::redirect(Shopp::url(false, 'checkout')); } if ('Y' != $credit_card_processed) { shopp_add_order_event($Purchase->id, 'auth-fail', array('amount' => $total, 'error' => 'Declined', 'message' => Shopp::__('The payment was not completed succesfully'), 'gateway' => $this->module)); shopp_add_error(Shopp::__('The order submitted by 2Checkout did not match any submitted orders.'), SHOPP_TRXN_ERR); Shopp::redirect(Shopp::url(false, 'checkout')); } $this->Order->inprogress = $Purchase->id; add_action('shopp_authed_order_event', array(ShoppOrder(), 'notify')); add_action('shopp_authed_order_event', array(ShoppOrder(), 'accounts')); add_action('shopp_authed_order_event', array(ShoppOrder(), 'success')); shopp_add_order_event($Purchase->id, 'authed', array('txnid' => $order_number, 'amount' => (double) $total, 'fees' => false, 'gateway' => $this->module, 'paymethod' => '2Checkout', 'paytype' => $pay_method, 'payid' => $invoice_id, 'capture' => true)); Shopp::redirect(Shopp::url(false, 'thanks', false)); }
public function prepare_items() { $defaults = array('page' => false, 'deleting' => false, 'selected' => false, 'update' => false, 'newstatus' => false, 'pagenum' => 1, 'paged' => 1, 'per_page' => 20, 'start' => '', 'end' => '', 'status' => false, 's' => '', 'range' => '', 'startdate' => '', 'enddate' => ''); $args = array_merge($defaults, $this->request()); extract($args, EXTR_SKIP); // $url = $this->url($_GET); $statusLabels = shopp_setting('order_status'); if (empty($statusLabels)) { $statusLabels = array(''); } $txnstatus_labels = Lookup::txnstatus_labels(); $Purchase = new ShoppPurchase(); $offset = get_option('gmt_offset') * 3600; if ($this->request('start')) { list($month, $day, $year) = explode("/", $this->request('start')); $starts = mktime(0, 0, 0, $month, $day, $year); } if ($this->request('end')) { list($month, $day, $year) = explode("/", $this->request('end')); $ends = mktime(23, 59, 59, $month, $day, $year); } $pagenum = absint($paged); $start = $per_page * ($pagenum - 1); $where = array(); $joins = array(); if (!empty($status) || '0' === $status) { $where[] = "status='" . sDB::escape($status) . "'"; } if (!empty($s)) { $s = stripslashes($s); $search = array(); if (preg_match_all('/(\\w+?)\\:(?="(.+?)"|(.+?)\\b)/', $s, $props, PREG_SET_ORDER) > 0) { foreach ($props as $query) { $keyword = sDB::escape(!empty($query[2]) ? $query[2] : $query[3]); switch (strtolower($query[1])) { case "txn": $search[] = "txnid='{$keyword}'"; break; case "company": $search[] = "company LIKE '%{$keyword}%'"; break; case "gateway": $search[] = "gateway LIKE '%{$keyword}%'"; break; case "cardtype": $search[] = "cardtype LIKE '%{$keyword}%'"; break; case "address": $search[] = "(address LIKE '%{$keyword}%' OR xaddress='%{$keyword}%')"; break; case "city": $search[] = "city LIKE '%{$keyword}%'"; break; case "province": case "state": $search[] = "state='{$keyword}'"; break; case "zip": case "zipcode": case "postcode": $search[] = "postcode='{$keyword}'"; break; case "country": $search[] = "country='{$keyword}'"; break; case "promo": case "discount": $meta_table = ShoppDatabaseObject::tablename(ShoppMetaObject::$table); $joins[$meta_table] = "INNER JOIN {$meta_table} AS m ON m.parent = o.id AND context='purchase'"; $search[] = "m.value LIKE '%{$keyword}%'"; break; case "product": $purchased = ShoppDatabaseObject::tablename(Purchased::$table); $joins[$purchased] = "INNER JOIN {$purchased} AS p ON p.purchase = o.id"; $search[] = "p.name LIKE '%{$keyword}%' OR p.optionlabel LIKE '%{$keyword}%' OR p.sku LIKE '%{$keyword}%'"; break; } } if (empty($search)) { $search[] = "(id='{$s}' OR CONCAT(firstname,' ',lastname) LIKE '%{$s}%')"; } $where[] = "(" . join(' OR ', $search) . ")"; } elseif (strpos($s, '@') !== false) { $where[] = "email='" . sDB::escape($s) . "'"; } else { $where[] = "(id='{$s}' OR CONCAT(firstname,' ',lastname) LIKE '%" . sDB::escape($s) . "%')"; } } if (!empty($starts) && !empty($ends)) { $where[] = "created BETWEEN '" . sDB::mkdatetime($starts) . "' AND '" . sDB::mkdatetime($ends) . "'"; } if (!empty($customer)) { $where[] = "customer=" . intval($customer); } $where = !empty($where) ? "WHERE " . join(' AND ', $where) : ''; $joins = join(' ', $joins); $countquery = "SELECT count(*) as total,SUM(IF(txnstatus IN ('authed','captured'),total,NULL)) AS sales,AVG(IF(txnstatus IN ('authed','captured'),total,NULL)) AS avgsale FROM {$Purchase->_table} AS o {$joins} {$where} ORDER BY o.created DESC LIMIT 1"; $this->ordercount = sDB::query($countquery, 'object'); $query = "SELECT o.* FROM {$Purchase->_table} AS o {$joins} {$where} ORDER BY created DESC LIMIT {$start},{$per_page}"; $this->items = sDB::query($query, 'array', 'index', 'id'); $num_pages = ceil($this->ordercount->total / $per_page); if ($paged > 1 && $paged > $num_pages) { Shopp::redirect(add_query_arg('paged', null, $url)); } $Gateways = Shopp::object()->Gateways; $this->gateways = array_merge($Gateways->modules, array('ShoppFreeOrder' => $Gateways->freeorder)); $this->statuses = (array) shopp_setting('order_status'); $this->txnstatuses = ShoppLookup::txnstatus_labels(); // Convert other date formats to numeric but preserve the order of the month/day/year or day/month/year $date_format = get_option('date_format'); $date_format = preg_replace("/[^A-Za-z0-9]/", '', $date_format); // Force month display to numeric with leading zeros $date_format = str_replace(array('n', 'F', 'M'), 'm/', $date_format); // Force day display to numeric with leading zeros $date_format = str_replace(array('j'), 'd/', $date_format); // Force year display to 4-digits $date_format = str_replace('y', 'Y/', $date_format); $this->dates = trim($date_format, '/'); $this->set_pagination_args(array('total_items' => $this->ordercount->total, 'total_pages' => $this->ordercount->total / $per_page, 'per_page' => $per_page)); }
/** * Begins database updates * * @since 1.3.6 * * @return void **/ public function upgrades() { if (empty($_GET['action']) || 'shopp-upgrade' != $_GET['action']) { return; } // Prevent unauthorized users from upgrading (without giving admin's a chance to backup) if (!current_user_can('activate_plugins')) { return; } // Prevent outsiders from the upgrade process check_admin_referer('shopp-upgrade'); $Installer = new ShoppInstallation(); $Installer->upgrade(); $welcome = add_query_arg(array('page' => $this->Admin->pagename('welcome')), admin_url('admin.php')); Shopp::redirect($welcome, true); }
static function resetpassword($activation) { if ('none' == shopp_setting('account_system')) { return; } $user_data = false; $activation = preg_replace('/[^a-z0-9]/i', '', $activation); $errors = array(); if (empty($activation) || !is_string($activation)) { $errors[] = new ShoppError(Shopp::__('Invalid key')); } $RecoveryCustomer = new ShoppCustomer($activation, 'activation'); if (empty($RecoveryCustomer->id)) { $errors[] = new ShoppError(Shopp::__('Invalid key')); } if (!empty($errors)) { return false; } // Generate a new random password $password = wp_generate_password(); do_action_ref_array('password_reset', array($RecoveryCustomer, $password)); $RecoveryCustomer->password = wp_hash_password($password); if ('wordpress' == shopp_setting('account_system')) { $user_data = get_userdata($RecoveryCustomer->wpuser); wp_set_password($password, $user_data->ID); } $RecoveryCustomer->activation = ''; $RecoveryCustomer->save(); $subject = apply_filters('shopp_reset_password_subject', Shopp::__('[%s] New Password', get_option('blogname'))); $_ = array(); $_[] = 'From: ' . Shopp::email_from(shopp_setting('merchant_email'), shopp_setting('business_name')); $_[] = 'To: ' . $RecoveryCustomer->email; $_[] = 'Subject: ' . $subject; $_[] = 'Content-type: text/html'; $_[] = ''; $_[] = '<p>' . Shopp::__('Your new password for %s:', get_bloginfo('url')) . '</p>'; $_[] = ''; $_[] = '<ul>'; if ($user_data) { $_[] = '<li>' . Shopp::__('Login name: %s', $user_data->user_login) . '</li>'; } $_[] = '<li>' . Shopp::__('Password: %s', $password) . '</li>'; $_[] = '</ul>'; $_[] = ''; $_[] = '<p>' . Shopp::__('Click here to login: %s', Shopp::url(false, 'account')) . '</p>'; $message = apply_filters('shopp_reset_password_message', $_); if (!Shopp::email(join("\n", $message))) { shopp_add_error(Shopp::__('The e-mail could not be sent.')); Shopp::redirect(add_query_arg('acct', 'recover', Shopp::url(false, 'account'))); } else { shopp_add_error(Shopp::__('Check your email address for your new password.')); } unset($_GET['acct']); }
public function output() { if (!$this->data) { $this->query(); } if (!$this->data) { Shopp::redirect(add_query_arg(array_merge($_GET, array('src' => null)), admin_url('admin.php'))); } header("Content-type: {$this->content_type}; charset=UTF-8"); header("Content-Disposition: attachment; filename=\"{$this->sitename} Purchase Log.{$this->extension}\""); header("Content-Description: Delivered by " . ShoppVersion::agent()); header("Cache-Control: maxage=1"); header("Pragma: public"); $this->begin(); if ($this->headings) { $this->heading(); } $this->records(); $this->end(); }
/** * Resets a customer/user password with a valid activation key * * @since 1.0 * * @param string $activation The activation key * @return void **/ static function resetpassword($activation) { if ('none' == shopp_setting('account_system') || ShoppCustomer()->loggedin()) { return; } $user_data = false; $activation = preg_replace('/[^a-z0-9]/i', '', $activation); $errors = array(); if (empty($activation) || !is_string($activation)) { $errors[] = shopp_add_error(Shopp::__("Invalid password reset key. Try copy/pasting the url in password reset email into your web browser's address bar.")); } else { $RecoveryCustomer = new ShoppCustomer($activation, 'activation'); if (empty($RecoveryCustomer->id)) { $errors[] = shopp_add_error(Shopp::__("Invalid password reset key. Try copy/pasting the url in password reset email into your web browser's address bar.")); } } if (!empty($errors)) { return false; } // Generate a new random password $password = wp_generate_password(12, false); do_action_ref_array('password_reset', array($RecoveryCustomer, $password)); $RecoveryCustomer->password = wp_hash_password($password); if ('wordpress' == shopp_setting('account_system')) { $user_data = get_userdata($RecoveryCustomer->wpuser); wp_set_password($password, $user_data->ID); } $RecoveryCustomer->activation = ''; $RecoveryCustomer->save(); $subject = apply_filters('shopp_reset_password_subject', Shopp::__('[%s] New Password', get_option('blogname'))); $_ = array(); $_[] = 'From: ' . Shopp::email_from(shopp_setting('merchant_email'), shopp_setting('business_name')); $_[] = 'To: ' . $RecoveryCustomer->email; $_[] = 'Subject: ' . $subject; $_[] = 'Content-type: text/html'; $_[] = ''; $_[] = '<p>' . Shopp::__('Your new password for %s:', get_bloginfo('url')) . '</p>'; $_[] = ''; $_[] = '<ul>'; if (apply_filters('shopp_reset_password_wpuser', true) && !empty($user_data->user_login)) { $_[] = '<li>' . Shopp::__('Login: %s', $user_data->user_login) . '</li>'; } elseif (!empty($RecoveryCustomer->email)) { $_[] = '<li>' . Shopp::__('Login: %s', $RecoveryCustomer->email) . '</li>'; } $_[] = '<li>' . Shopp::__('Password: %s', $password) . '</li>'; $_[] = '</ul>'; $_[] = ''; $_[] = '<p>' . Shopp::__('Click here to login: %s', Shopp::url(false, 'account')) . '</p>'; $message = apply_filters('shopp_reset_password_message', $_); if (!Shopp::email(join("\n", $message))) { shopp_add_notice(Shopp::__('Your password was reset to: ' . $password)); } else { shopp_add_notice(Shopp::__('Your new password has been emailed to you for your records. Your password was reset to: ' . $password)); } unset($_GET['acct']); // Auto-login $RecoveryCustomer->login(); // Login the customer if (!empty($user_data)) { // Log the WordPress user in ShoppLogin::wpuser($user_data); } // Show notice after login in case of failures during login shopp_add_notice(Shopp::__('You are now logged into your account.')); if (apply_filters('shopp_reset_password_redirect', true)) { shopp_add_notice(Shopp::__('If you wish, please use the form below to change your password to one of your choosing.')); Shopp::redirect(add_query_arg('profile', '', Shopp::url(false, 'account'))); } }
/** * @deprecated Use Shopp::redirect() **/ function shopp_redirect($uri, $exit = true, $status = 302) { Shopp::redirect($uri, $exit, $status); }
/** * Handler for profile updates in the account dashboard * * @author Jonathan Davis * @since 1.1 * * @return boolean|string output based on the account menu request **/ public function profile() { if (empty($_POST['customer'])) { return; } // Not a valid customer profile update request check_admin_referer('shopp_profile_update'); $defaults = array('phone' => '', 'password' => null, 'confirm-password' => null, 'info' => null, 'billing' => array(), 'shipping' => array()); $updates = array_merge($defaults, $_POST); extract($updates, EXTR_SKIP); $phone = preg_replace('/[^\\d\\(\\)\\-+\\. (ext|x)]/', '', $phone); // Update this ShoppCustomer model $this->updates($updates); if (is_array($info)) { $this->info = $info; } // Add info fields if ('' != $password . $updates['confirm-password'] && $password == $updates['confirm-password']) { $this->password = wp_hash_password($password); if ('wordpress' == shopp_setting('account_system') && !empty($this->wpuser)) { wp_set_password($password, $this->wpuser); } $this->_password_change = true; } else { if (!empty($password)) { shopp_add_error(Shopp::__('The passwords you entered do not match. Please re-enter your passwords.')); } $this->_password_change = false; } do_action('shopp_customer_update', $this); $this->save(); $this->load_info(); $addresses = array('billing' => 'Billing', 'shipping' => 'Shipping'); foreach ($addresses as $type => $Address) { if (empty($updates[$type])) { continue; } $Updated = ShoppOrder()->{$Address}; $Updated->customer = $this->id; $Updated->updates($updates[$type]); $Updated->save(); } $this->updated(self::PROFILE, true); if ($this->_password_change) { Shopp::redirect(Shopp::url(false, 'account')); } }
/** * Generates the output for the exported report * * @author Jonathan Davis * @since 1.3 * * @return void **/ public function output() { if (empty($this->data)) { Shopp::redirect(add_query_arg(array_merge($_GET, array('src' => null)), admin_url('admin.php'))); } $sitename = get_bloginfo('name'); $report = $this->options['report']; $reports = ShoppAdminReport::reports(); $name = $reports[$report]['name']; header("Content-type: {$this->content_type}"); header("Content-Disposition: attachment; filename=\"{$sitename} {$name}.{$this->extension}\""); header("Content-Description: Delivered by " . ShoppVersion::agent()); header("Cache-Control: maxage=1"); header("Pragma: public"); $this->begin(); if ($this->headings) { $this->heading(); } $this->records(); $this->end(); }
/** * Validates an order prior to submitting for payment processing * * @author Jonathan Davis * @since 1.2 * * @return boolean True if the order is ready for processing, or void with redirect back to checkout **/ public function validate() { if (apply_filters('shopp_valid_order', $this->isvalid())) { return true; } $redirect = Shopp::url(false, 'checkout', $this->security()); Shopp::redirect(apply_filters('shopp_invalid_order_redirect', $redirect), true); }
public static function process() { // We have to avoid truthiness, hence the strange logic expression if (true !== apply_filters('shopp_validate_registration', true)) { return; } $Customer = ShoppOrder()->Customer; do_action('shopp_customer_registration', $Customer); if ($Customer->session(ShoppCustomer::GUEST)) { $Customer->type = __('Guest', 'Shopp'); // No cuts $Customer->wpuser = 0; // No buts unset($Customer->password); // No coconuts } else { // WordPress account integration used, customer has no wp user if ('wordpress' == shopp_setting('account_system') && empty($Customer->wpuser)) { if ($wpuser = get_current_user_id()) { $Customer->wpuser = $wpuser; } else { $Customer->create_wpuser(); } // not logged in, create new account } if (!$Customer->exists(true)) { $Customer->id = false; shopp_debug('Creating new Shopp customer record'); if (empty($Customer->password)) { $Customer->password = wp_generate_password(12, true); } if ('shopp' == shopp_setting('account_system')) { $Customer->notification(); } $Customer->password = wp_hash_password($Customer->password); if (isset($Customer->passhash)) { $Customer->password = $Customer->passhash; } } else { unset($Customer->password); } // Existing customer, do not overwrite password field! } // New customer, save hashed password $Customer->save(); $Customer->password = ''; // Update billing and shipping addresses $addresses = array('Billing', 'Shipping'); foreach ($addresses as $Address) { if (empty(ShoppOrder()->{$Address}->address)) { continue; } $Address = ShoppOrder()->{$Address}; $Address->customer = $Customer->id; $Address->save(); } do_action('shopp_customer_registered', $Customer); // Auto-login $Customer->login(); // Login the customer if (!empty($Customer->wpuser)) { // Log the WordPress user in ShoppLogin::wpuser(get_user_by('id', $Customer->wpuser)); } if (apply_filters('shopp_registration_redirect', false)) { Shopp::redirect(Shopp::url(false, 'account')); } }
/** * Bounce the browser to the secure unlock request * * The redirect uses HTTP 307 to encourage browsers to resubmit * their POST data to the redirected URL. * * @since 1.3.6 * * @return void */ public function bouncer() { $this->data = false; // Prevent saving the session $https = Shopp::url(array('unlock' => Shopp::raw_request_url()), 'checkout', true); Shopp::redirect($https, true, 307); }