function dashboard_products($args = null) { global $Shopp; $db = DB::get(); $defaults = array('before_widget' => '', 'before_title' => '', 'widget_name' => '', 'after_title' => '', 'after_widget' => ''); if (!$args) { $args = array(); } $args = array_merge($defaults, $args); if (!empty($args)) { extract($args, EXTR_SKIP); } echo $before_widget; echo $before_title; echo $widget_name; echo $after_title; $RecentBestsellers = new BestsellerProducts(array('where' => 'UNIX_TIMESTAMP(pur.created) > UNIX_TIMESTAMP()-(86400*30)', 'show' => 3)); $RecentBestsellers->load_products(); echo '<table><tbody><tr>'; echo '<td><h4>' . __('Recent Bestsellers', 'Shopp') . '</h4>'; echo '<ul>'; foreach ($RecentBestsellers->products as $product) { echo '<li><a href="' . add_query_arg(array('page' => $this->Admin->editproduct, 'id' => $product->id), $Shopp->wpadminurl . "admin.php") . '">' . $product->name . '</a> (' . $product->sold . ')</li>'; } echo '</ul></td>'; $LifetimeBestsellers = new BestsellerProducts(array('show' => 3)); $LifetimeBestsellers->load_products(); echo '<td><h4>' . __('Lifetime Bestsellers', 'Shopp') . '</h4>'; echo '<ul>'; foreach ($LifetimeBestsellers->products as $product) { echo '<li><a href="' . add_query_arg(array('page' => $this->Admin->editproduct, 'id' => $product->id), $Shopp->wpadminurl . "admin.php") . '">' . $product->name . '</a> (' . $product->sold . ')</li>'; } echo '</ul></td>'; echo '</tr></tbody></table>'; echo $after_widget; }
/** * Renders the order stats widget * * @author Jonathan Davis * @since 1.0 * * @return void **/ public static function stats_widget($args = false) { $ranges = array('today' => __('Today', 'Shopp'), 'week' => __('This Week', 'Shopp'), 'month' => __('This Month', 'Shopp'), 'quarter' => __('This Quarter', 'Shopp'), 'year' => __('This Year', 'Shopp'), 'yesterday' => __('Yesterday', 'Shopp'), 'lastweek' => __('Last Week', 'Shopp'), 'last30' => __('Last 30 Days', 'Shopp'), 'last90' => __('Last 3 Months', 'Shopp'), 'lastmonth' => __('Last Month', 'Shopp'), 'lastquarter' => __('Last Quarter', 'Shopp'), 'lastyear' => __('Last Year', 'Shopp')); $defaults = array('before_widget' => '', 'before_title' => '', 'widget_name' => '', 'after_title' => '', 'after_widget' => '', 'range' => isset($_GET['shopp-stats-range']) ? $_GET['shopp-stats-range'] : ''); $args = array_merge($defaults, (array) $args); extract($args, EXTR_SKIP); if (!$range || !isset($ranges[strtolower($range)])) { $range = 'last30'; } $purchasetable = ShoppDatabaseObject::tablename(ShoppPurchase::$table); $now = current_time('timestamp'); // $offset = get_option( 'gmt_offset' ) * 3600; $daytimes = 86400; $day = date('j', $now); $month = date('n', $now); $year = date('Y', $now); $end = $now; list($weekstart, $weekend) = array_values(get_weekstartend(current_time('mysql'))); switch ($range) { case 'today': $start = mktime(0, 0, 0, $month, $day, $year); break; case 'week': $start = $weekstart; $end = $weekend; break; case 'month': $start = mktime(0, 0, 0, $month, 1, $year); break; case 'quarter': $start = mktime(0, 0, 0, $month - (3 - $month % 3), 1, $year); break; case 'year': $start = mktime(0, 0, 0, 1, 1, $year); break; case 'yesterday': $start = mktime(0, 0, 0, $month, $day - 1, $year); $end = mktime(23, 59, 59, $month, $day - 1, $year); break; case 'lastweek': $start = $weekstart - 7 * $daytimes; $end = $weekstart - 1; break; case 'last7': $start = $now - 7 * $daytimes; break; case 'last30': $start = $now - 30 * $daytimes; break; case 'last90': $start = $now - 90 * $daytimes; break; case 'lastmonth': $start = mktime(0, 0, 0, $month - 1, 1, $year); $end = mktime(0, 0, 0, $month, 0, $year); break; case 'lastquarter': $start = mktime(0, 0, 0, $month - (3 - $month % 3) - 3, 1, $year); $end = mktime(23, 59, 59, date('n', $start) + 3, 0, $year); break; case 'lastyear': $start = mktime(0, 0, 0, $month, 1, $year - 1); $end = mktime(23, 59, 59, 1, 0, $year); break; } // Include authorizations, captures and old 1.1 tranaction status CHARGED in sales data $salestatus = array("'authed'", "'captured'", "'CHARGED'"); $txnstatus = "txnstatus IN (" . join(',', $salestatus) . ")"; $daterange = "created BETWEEN '" . sDB::mkdatetime($start) . "' AND '" . sDB::mkdatetime($end) . "'"; $query = "SELECT count(id) AS orders,\n\t\t\t\t\t\tSUM(total) AS sales,\n\t\t\t\t\t\tAVG(total) AS average,\n\t\t \t\t\t\tSUM(IF({$daterange},1,0)) AS wkorders,\n\t\t\t\t\t\tSUM(IF({$daterange},total,0)) AS wksales,\n\t\t\t\t\t\tAVG(IF({$daterange},total,null)) AS wkavg\n \t\t\t\t\tFROM {$purchasetable} WHERE {$txnstatus}"; $cached = get_transient('shopp_dashboard_stats_' . $range); if (empty($cached)) { $results = sDB::query($query); $RecentBestsellers = new BestsellerProducts(array('range' => array($start, $end), 'show' => 5)); $RecentBestsellers->load(array('pagination' => false)); $RecentBestsellers->maxsold = 0; foreach ($RecentBestsellers as $product) { $RecentBestsellers->maxsold = max($RecentBestsellers->maxsold, $product->sold); } $LifeBestsellers = new BestsellerProducts(array('show' => 5)); $LifeBestsellers->load(array('pagination' => false)); $LifeBestsellers->maxsold = 0; foreach ($LifeBestsellers as $product) { $LifeBestsellers->maxsold = max($LifeBestsellers->maxsold, $product->sold); } set_transient('shopp_dashboard_stats_' . $range, array($results, $RecentBestsellers, $LifeBestsellers), 300); } else { list($results, $RecentBestsellers, $LifeBestsellers) = $cached; } echo $before_widget; echo $before_title; echo $widget_name; echo $after_title; $orderscreen = add_query_arg('page', ShoppAdmin::pagename('orders'), admin_url('admin.php')); $productscreen = add_query_arg(array('page' => ShoppAdmin::pagename('products')), admin_url('admin.php')); ?> <div class="table"><table> <tr><th colspan="2"><form action="<?php echo admin_url('index.php'); ?> "> <select name="shopp-stats-range" id="shopp-stats-range"> <?php echo menuoptions($ranges, $range, true); ?> </select> <button type="submit" id="filter-button" name="filter" value="order" class="button-secondary hide-if-js"><?php _e('Filter', 'Shopp'); ?> </button> </form> </th><th colspan="2"><?php _e('Lifetime', 'Shopp'); ?> </th></tr> <tbody> <tr><td class="amount"><a href="<?php echo esc_url($orderscreen); ?> "><?php echo (int) $results->wkorders; ?> </a></td><td class="label"><?php echo _n('Order', 'Orders', (int) $results->wkorders, 'Shopp'); ?> </td> <td class="amount"><a href="<?php echo esc_url($orderscreen); ?> "><?php echo (int) $results->orders; ?> </a></td><td class="label"><?php echo _n('Order', 'Orders', (int) $results->orders, 'Shopp'); ?> </td></tr> <tr><td class="amount"><a href="<?php echo esc_url($orderscreen); ?> "><?php echo money($results->wksales); ?> </a></td><td class="label"><?php _e('Sales', 'Shopp'); ?> </td> <td class="amount"><a href="<?php echo esc_url($orderscreen); ?> "><?php echo money($results->sales); ?> </a></td><td class="label"><?php _e('Sales', 'Shopp'); ?> </td></tr> <tr><td class="amount"><a href="<?php echo esc_url($orderscreen); ?> "><?php echo money($results->wkavg); ?> </a></td><td class="label"><?php _e('Average Order', 'Shopp'); ?> </td> <td class="amount"><a href="<?php echo esc_url($orderscreen); ?> "><?php echo money($results->average); ?> </a></td><td class="label"><?php _e('Average Order', 'Shopp'); ?> </td></tr> <?php if (!empty($RecentBestsellers->products) || !empty($LifeBestsellers->products)) { ?> <tr> <th colspan="2"><?php printf(__('Bestsellers %s', 'Shopp'), $ranges[$range]); ?> </th> <th colspan="2"><?php printf(__('Lifetime Bestsellers', 'Shopp'), $ranges[$range]); ?> </th> </tr> <?php reset($RecentBestsellers); reset($LifeBestsellers); $firstrun = true; while (true) { list($recentid, $recent) = each($RecentBestsellers->products); list($lifetimeid, $lifetime) = each($LifeBestsellers->products); if (!$recent && !$lifetime) { break; } ?> <tr> <?php if (empty($RecentBestsellers->products) && $firstrun) { echo '<td colspan="2" rowspan="5">' . __('None', 'Shopp') . '</td>'; } ?> <?php if (!empty($recent->id)) { ?> <td class="salesgraph"> <div class="bar" style="width:<?php echo $recent->sold / $RecentBestsellers->maxsold * 100; ?> %;"><?php echo $recent->sold; ?> </div> </td> <td> <a href="<?php echo esc_url(add_query_arg('view', 'bestselling', $productscreen)); ?> "><?php echo esc_html($recent->name); ?> </a> </td> <?php } ?> <?php if (empty($LifeBestsellers->products) && $firstrun) { echo '<td colspan="2" rowspan="5">' . __('None', 'Shopp') . '</td>'; } ?> <?php if (!empty($lifetime->id)) { ?> <td class="salesgraph"> <div class="bar" style="width:<?php echo $lifetime->sold / $LifeBestsellers->maxsold * 100; ?> %;"><?php echo $lifetime->sold; ?> </div> </td> <td> <a href="<?php echo esc_url(add_query_arg('view', 'bestselling', $productscreen)); ?> "><?php echo esc_html($lifetime->name); ?> </a> </td> <?php } ?> </tr> <?php $firstrun = false; } ?> <?php } ?> </tbody></table></div> <script type="text/javascript"> jQuery(document).ready(function($){$('#shopp-stats-range').change(function(){$(this).parents('form').submit();});}); </script> <?php echo $after_widget; }
public function smart(array $options = array()) { if (isset($options['range']) && is_array($options['range'])) { $start = $options['range'][0]; $end = $options['range'][1]; if (!$end) { $end = current_time('timestamp'); } $purchased = ShoppDatabaseObject::tablename(Purchased::$table); $this->loading['columns'] = "COUNT(*) AS sold"; $this->loading['joins'] = array($purchased => "INNER JOIN {$purchased} as pur ON pur.product=p.id"); $this->loading['where'] = array("pur.created BETWEEN '" . sDB::mkdatetime($start) . "' AND '" . sDB::mkdatetime($end) . "'"); $this->loading['orderby'] = 'sold DESC'; $this->loading['groupby'] = 'pur.product'; } else { $this->loading['where'] = array(BestsellerProducts::threshold() . " < s.sold"); $this->loading['order'] = 'bestselling'; // Use overall bestselling stats $this->loading = array_merge($options, $this->loading); } }
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; }
/** * Renders the bestselling products dashboard widget * * @since 1.0 * * @return void **/ function products_widget ($args=null) { global $Ecart; $db = DB::get(); $defaults = array( 'before_widget' => '', 'before_title' => '', 'widget_name' => '', 'after_title' => '', 'after_widget' => '' ); if (!$args) $args = array(); $args = array_merge($defaults,$args); if (!empty($args)) extract( $args, EXTR_SKIP ); echo $before_widget; echo $before_title; echo $widget_name; echo $after_title; $RecentBestsellers = new BestsellerProducts(array('where'=>'UNIX_TIMESTAMP(pur.created) > UNIX_TIMESTAMP()-(86400*30)','show'=>3)); $RecentBestsellers->load_products(); echo '<table><tbody><tr>'; echo '<td><h4>'.__('Recent Bestsellers','Ecart').'</h4>'; echo '<ul>'; if (empty($RecentBestsellers->products)) echo '<li>'.__('Nothing has been sold, yet.','Ecart').'</li>'; foreach ($RecentBestsellers->products as $product) echo '<li><a href="'.add_query_arg(array('page'=>$this->pagename('products'),'id'=>$product->id),admin_url('admin.php')).'">'.$product->name.'</a> ('.$product->sold.')</li>'; echo '</ul></td>'; $LifetimeBestsellers = new BestsellerProducts(array('show'=>3)); $LifetimeBestsellers->load_products(); echo '<td><h4>'.__('Lifetime Bestsellers','Ecart').'</h4>'; echo '<ul>'; if (empty($LifetimeBestsellers->products)) echo '<li>'.__('Nothing has been sold, yet.','Ecart').'</li>'; foreach ($LifetimeBestsellers->products as $product) echo '<li><a href="'.add_query_arg(array('page'=>$this->pagename('products'),'id'=>$product->id),admin_url('admin.php')).'">'.$product->name.'</a>'.(isset($product->sold)?' ('.$product->sold.')':' (0)').'</li>'; echo '</ul></td>'; echo '</tr></tbody></table>'; echo $after_widget; }