class-admin-view.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. <?php
  2. /**
  3. * Admin View Class - Handles admin interface rendering
  4. *
  5. * @package StudiouWCCustomReports
  6. */
  7. if (!defined('ABSPATH')) {
  8. exit;
  9. }
  10. class StudiouWC_Admin_View {
  11. private $db_manager;
  12. private $settings_manager;
  13. public function __construct($db_manager, $settings_manager) {
  14. $this->db_manager = $db_manager;
  15. $this->settings_manager = $settings_manager;
  16. }
  17. public function add_admin_menu() {
  18. // Add Custom Reports page under WooCommerce > Reports
  19. add_submenu_page(
  20. 'woocommerce',
  21. __('Custom Reports', StudiouWC_Main::get_text_domain()),
  22. __('Custom Reports', StudiouWC_Main::get_text_domain()),
  23. 'manage_woocommerce',
  24. 'studiou-custom-reports',
  25. array($this, 'display_custom_reports_page')
  26. );
  27. // Add Settings page under WooCommerce > Reports Settings
  28. add_submenu_page(
  29. 'woocommerce',
  30. __('Custom Report Settings', StudiouWC_Main::get_text_domain()),
  31. __('Custom Report Settings', StudiouWC_Main::get_text_domain()),
  32. 'manage_woocommerce',
  33. 'studiou-reports-settings',
  34. array($this, 'display_settings_page')
  35. );
  36. }
  37. public function enqueue_admin_scripts($hook) {
  38. if (strpos($hook, 'studiou-') !== false) {
  39. wp_enqueue_script('jquery');
  40. wp_enqueue_script('jquery-ui-datepicker');
  41. wp_enqueue_style('jquery-ui-datepicker', 'https://code.jquery.com/ui/1.12.1/themes/ui-lightness/jquery-ui.css');
  42. }
  43. }
  44. public function display_custom_reports_page() {
  45. $settings = $this->settings_manager->get_settings();
  46. // Handle form submission
  47. $view = isset($_GET['view']) ? sanitize_text_field($_GET['view']) : 'product_categories_summary';
  48. $date_from = isset($_GET['date_from']) ? sanitize_text_field($_GET['date_from']) : $this->settings_manager->get_default_date_from();
  49. $date_to = isset($_GET['date_to']) ? sanitize_text_field($_GET['date_to']) : date('Y-m-d');
  50. // If no statuses selected, use all available statuses (including custom ones)
  51. if (isset($_GET['statuses']) && !empty($_GET['statuses'])) {
  52. $statuses = array_map('sanitize_text_field', $_GET['statuses']);
  53. } else {
  54. $default_statuses = $settings['default_statuses'] ?? array();
  55. if (empty($default_statuses)) {
  56. // Include common statuses + your custom status
  57. $statuses = array('wc-completed', 'wc-processing', 'wc-on-hold', 'wc-to-print');
  58. } else {
  59. $statuses = $default_statuses;
  60. }
  61. }
  62. $per_page = isset($_GET['per_page']) ? intval($_GET['per_page']) : 20;
  63. $paged = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
  64. $orderby = isset($_GET['orderby']) ? sanitize_text_field($_GET['orderby']) : 'category';
  65. $order = isset($_GET['order']) ? sanitize_text_field($_GET['order']) : 'ASC';
  66. // Get report data
  67. $report_data = $this->db_manager->get_product_categories_summary($date_from, $date_to, $statuses, $per_page, $paged, $orderby, $order);
  68. $total_items = $this->db_manager->get_total_items($date_from, $date_to, $statuses);
  69. $total_pages = ceil($total_items / $per_page);
  70. $this->render_reports_page($view, $date_from, $date_to, $statuses, $per_page, $paged, $orderby, $order, $report_data, $total_items, $total_pages, $settings);
  71. }
  72. public function display_settings_page() {
  73. $settings = $this->settings_manager->get_settings();
  74. $this->render_settings_page($settings);
  75. }
  76. private function render_reports_page($view, $date_from, $date_to, $statuses, $per_page, $paged, $orderby, $order, $report_data, $total_items, $total_pages, $settings) {
  77. ?>
  78. <div class="wrap">
  79. <h1><?php _e('Custom Reports', StudiouWC_Main::get_text_domain()); ?></h1>
  80. <?php $this->render_filter_form($view, $date_from, $date_to, $statuses, $per_page); ?>
  81. <?php if (!empty($report_data)): ?>
  82. <?php $this->render_pagination_top($total_items, $total_pages, $paged); ?>
  83. <?php $this->render_data_table($report_data, $orderby, $order, $settings); ?>
  84. <?php else: ?>
  85. <p><?php _e('No data found for the selected criteria.', StudiouWC_Main::get_text_domain()); ?></p>
  86. <?php endif; ?>
  87. </div>
  88. <?php $this->render_reports_javascript(); ?>
  89. <?php
  90. }
  91. private function render_filter_form($view, $date_from, $date_to, $statuses, $per_page) {
  92. ?>
  93. <form method="get" id="studiou-reports-form">
  94. <input type="hidden" name="page" value="studiou-custom-reports">
  95. <table class="form-table">
  96. <tr>
  97. <th><label for="view"><?php _e('View', StudiouWC_Main::get_text_domain()); ?></label></th>
  98. <td>
  99. <select name="view" id="view">
  100. <option value="product_categories_summary" <?php selected($view, 'product_categories_summary'); ?>>
  101. <?php _e('Product Categories and Variants Summary', StudiouWC_Main::get_text_domain()); ?>
  102. </option>
  103. </select>
  104. </td>
  105. </tr>
  106. <tr>
  107. <th><label for="date_from"><?php _e('Date From', StudiouWC_Main::get_text_domain()); ?></label></th>
  108. <td><input type="date" name="date_from" id="date_from" value="<?php echo esc_attr($date_from); ?>"></td>
  109. </tr>
  110. <tr>
  111. <th><label for="date_to"><?php _e('Date To', StudiouWC_Main::get_text_domain()); ?></label></th>
  112. <td><input type="date" name="date_to" id="date_to" value="<?php echo esc_attr($date_to); ?>"></td>
  113. </tr>
  114. <tr>
  115. <th><label for="statuses"><?php _e('Included Statuses', StudiouWC_Main::get_text_domain()); ?></label></th>
  116. <td>
  117. <?php $this->render_status_checkboxes($statuses); ?>
  118. </td>
  119. </tr>
  120. <tr>
  121. <th><label for="per_page"><?php _e('Items per page', StudiouWC_Main::get_text_domain()); ?></label></th>
  122. <td>
  123. <select name="per_page" id="per_page">
  124. <option value="10" <?php selected($per_page, 10); ?>>10</option>
  125. <option value="20" <?php selected($per_page, 20); ?>>20</option>
  126. <option value="50" <?php selected($per_page, 50); ?>>50</option>
  127. <option value="100" <?php selected($per_page, 100); ?>>100</option>
  128. </select>
  129. </td>
  130. </tr>
  131. </table>
  132. <p class="submit">
  133. <input type="submit" name="filter" class="button-primary" value="<?php _e('Filter', StudiouWC_Main::get_text_domain()); ?>">
  134. <button type="button" id="export-csv" class="button"><?php _e('Export', StudiouWC_Main::get_text_domain()); ?></button>
  135. </p>
  136. </form>
  137. <?php
  138. }
  139. private function render_status_checkboxes($selected_statuses) {
  140. $order_statuses = wc_get_order_statuses();
  141. // Add custom statuses that might not be in the standard list
  142. global $wpdb;
  143. $custom_statuses = $wpdb->get_col("
  144. SELECT DISTINCT status
  145. FROM {$wpdb->prefix}wc_orders
  146. WHERE status NOT IN ('" . implode("','", array_keys($order_statuses)) . "')
  147. AND date_created_gmt >= DATE_SUB(NOW(), INTERVAL 90 DAY)
  148. ");
  149. foreach ($custom_statuses as $custom_status) {
  150. if (!isset($order_statuses[$custom_status])) {
  151. $order_statuses[$custom_status] = ucwords(str_replace(array('wc-', '-'), array('', ' '), $custom_status));
  152. }
  153. }
  154. foreach ($order_statuses as $status_key => $status_label) {
  155. $checked = in_array($status_key, $selected_statuses) ? 'checked' : '';
  156. echo '<label><input type="checkbox" name="statuses[]" value="' . esc_attr($status_key) . '" ' . $checked . '> ' . esc_html($status_label) . '</label><br>';
  157. }
  158. }
  159. private function render_pagination_top($total_items, $total_pages, $paged) {
  160. ?>
  161. <div class="tablenav top">
  162. <div class="tablenav-pages">
  163. <span class="displaying-num"><?php printf(__('%d items', StudiouWC_Main::get_text_domain()), $total_items); ?></span>
  164. <?php if ($total_pages > 1): ?>
  165. <span class="pagination-links">
  166. <?php if ($paged > 1): ?>
  167. <a class="prev-page button" href="<?php echo esc_url(add_query_arg('paged', $paged - 1)); ?>"><?php _e('‹', StudiouWC_Main::get_text_domain()); ?></a>
  168. <?php endif; ?>
  169. <span class="paging-input">
  170. <span class="tablenav-paging-text"><?php printf(__('%1$d of %2$d', StudiouWC_Main::get_text_domain()), $paged, $total_pages); ?></span>
  171. </span>
  172. <?php if ($paged < $total_pages): ?>
  173. <a class="next-page button" href="<?php echo esc_url(add_query_arg('paged', $paged + 1)); ?>"><?php _e('›', StudiouWC_Main::get_text_domain()); ?></a>
  174. <?php endif; ?>
  175. </span>
  176. <?php endif; ?>
  177. </div>
  178. </div>
  179. <?php
  180. }
  181. private function render_data_table($report_data, $orderby, $order, $settings) {
  182. $default_property = $settings['default_property'] ?? '';
  183. $property_values = array();
  184. if (!empty($default_property)) {
  185. $property_values = $this->db_manager->get_property_values($default_property);
  186. }
  187. ?>
  188. <table class="wp-list-table widefat fixed striped">
  189. <thead>
  190. <tr>
  191. <th><a href="<?php echo esc_url(add_query_arg(array('orderby' => 'category', 'order' => $order === 'ASC' ? 'DESC' : 'ASC'))); ?>"><?php _e('Product Category', StudiouWC_Main::get_text_domain()); ?></a></th>
  192. <th><a href="<?php echo esc_url(add_query_arg(array('orderby' => 'orders_count', 'order' => $order === 'ASC' ? 'DESC' : 'ASC'))); ?>"><?php _e('Orders Count', StudiouWC_Main::get_text_domain()); ?></a></th>
  193. <?php foreach ($property_values as $slug => $name): ?>
  194. <th><?php echo esc_html($name . ' Count'); ?></th>
  195. <?php endforeach; ?>
  196. <th><a href="<?php echo esc_url(add_query_arg(array('orderby' => 'total_price', 'order' => $order === 'ASC' ? 'DESC' : 'ASC'))); ?>"><?php _e('Total Price', StudiouWC_Main::get_text_domain()); ?></a></th>
  197. </tr>
  198. </thead>
  199. <tbody>
  200. <?php foreach ($report_data as $row): ?>
  201. <tr>
  202. <td><?php echo esc_html($row['category']); ?></td>
  203. <td><?php echo esc_html($row['orders_count']); ?></td>
  204. <?php foreach ($property_values as $slug => $name): ?>
  205. <td><?php echo esc_html($row['property_counts'][$slug] ?? 0); ?></td>
  206. <?php endforeach; ?>
  207. <td><?php echo wc_price($row['total_price']); ?></td>
  208. </tr>
  209. <?php endforeach; ?>
  210. </tbody>
  211. </table>
  212. <?php
  213. }
  214. private function render_reports_javascript() {
  215. ?>
  216. <script>
  217. jQuery(document).ready(function($) {
  218. $('#export-csv').click(function() {
  219. var formData = $('#studiou-reports-form').serialize();
  220. formData += '&action=studiou_export_csv&export=1';
  221. var form = $('<form method="post" action="' + ajaxurl + '"></form>');
  222. $.each(formData.split('&'), function(i, field) {
  223. var parts = field.split('=');
  224. if (parts.length === 2) {
  225. form.append('<input type="hidden" name="' + decodeURIComponent(parts[0]) + '" value="' + decodeURIComponent(parts[1]) + '">');
  226. }
  227. });
  228. $('body').append(form);
  229. form.submit();
  230. form.remove();
  231. });
  232. });
  233. </script>
  234. <?php
  235. }
  236. private function render_settings_page($settings) {
  237. ?>
  238. <div class="wrap">
  239. <h1><?php _e('Custom Report Settings', StudiouWC_Main::get_text_domain()); ?></h1>
  240. <form method="post" id="studiou-settings-form">
  241. <table class="form-table">
  242. <tr>
  243. <th><label for="default_interval"><?php _e('Default shown interval', StudiouWC_Main::get_text_domain()); ?></label></th>
  244. <td>
  245. <select name="default_interval" id="default_interval">
  246. <option value="last_day" <?php selected($settings['default_interval'] ?? '', 'last_day'); ?>><?php _e('Last day', StudiouWC_Main::get_text_domain()); ?></option>
  247. <option value="last_week" <?php selected($settings['default_interval'] ?? '', 'last_week'); ?>><?php _e('Last week', StudiouWC_Main::get_text_domain()); ?></option>
  248. <option value="last_month" <?php selected($settings['default_interval'] ?? '', 'last_month'); ?>><?php _e('Last month', StudiouWC_Main::get_text_domain()); ?></option>
  249. </select>
  250. </td>
  251. </tr>
  252. <tr>
  253. <th><label for="default_property"><?php _e('Default property', StudiouWC_Main::get_text_domain()); ?></label></th>
  254. <td>
  255. <select name="default_property" id="default_property">
  256. <option value=""><?php _e('Select property', StudiouWC_Main::get_text_domain()); ?></option>
  257. <?php
  258. $properties = $this->db_manager->get_product_properties();
  259. foreach ($properties as $slug => $name) {
  260. $selected = selected($settings['default_property'] ?? '', $slug, false);
  261. echo '<option value="' . esc_attr($slug) . '" ' . $selected . '>' . esc_html($name) . '</option>';
  262. }
  263. ?>
  264. </select>
  265. </td>
  266. </tr>
  267. <tr>
  268. <th><label for="default_statuses"><?php _e('Default Included statuses', StudiouWC_Main::get_text_domain()); ?></label></th>
  269. <td>
  270. <?php
  271. $order_statuses = wc_get_order_statuses();
  272. $default_statuses = $settings['default_statuses'] ?? array();
  273. foreach ($order_statuses as $status_key => $status_label) {
  274. $checked = in_array($status_key, $default_statuses) ? 'checked' : '';
  275. echo '<label><input type="checkbox" name="default_statuses[]" value="' . esc_attr($status_key) . '" ' . $checked . '> ' . esc_html($status_label) . '</label><br>';
  276. }
  277. ?>
  278. </td>
  279. </tr>
  280. </table>
  281. <p class="submit">
  282. <button type="button" id="save-settings" class="button-primary"><?php _e('Save Settings', StudiouWC_Main::get_text_domain()); ?></button>
  283. </p>
  284. </form>
  285. </div>
  286. <script>
  287. jQuery(document).ready(function($) {
  288. $('#save-settings').click(function() {
  289. var formData = $('#studiou-settings-form').serialize();
  290. formData += '&action=studiou_save_settings';
  291. $.post(ajaxurl, formData, function(response) {
  292. if (response.success) {
  293. alert('<?php _e('Settings saved successfully!', StudiouWC_Main::get_text_domain()); ?>');
  294. } else {
  295. alert('<?php _e('Error saving settings.', StudiouWC_Main::get_text_domain()); ?>');
  296. }
  297. });
  298. });
  299. });
  300. </script>
  301. <?php
  302. }
  303. }