class-admin-view.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. $statuses = isset($_GET['statuses']) ? array_map('sanitize_text_field', $_GET['statuses']) : ($settings['default_statuses'] ?? array());
  51. $per_page = isset($_GET['per_page']) ? intval($_GET['per_page']) : 20;
  52. $paged = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
  53. $orderby = isset($_GET['orderby']) ? sanitize_text_field($_GET['orderby']) : 'category';
  54. $order = isset($_GET['order']) ? sanitize_text_field($_GET['order']) : 'ASC';
  55. // Get report data
  56. $report_data = $this->db_manager->get_product_categories_summary($date_from, $date_to, $statuses, $per_page, $paged, $orderby, $order);
  57. $total_items = $this->db_manager->get_total_items($date_from, $date_to, $statuses);
  58. $total_pages = ceil($total_items / $per_page);
  59. $this->render_reports_page($view, $date_from, $date_to, $statuses, $per_page, $paged, $orderby, $order, $report_data, $total_items, $total_pages, $settings);
  60. }
  61. public function display_settings_page() {
  62. $settings = $this->settings_manager->get_settings();
  63. $this->render_settings_page($settings);
  64. }
  65. private function render_reports_page($view, $date_from, $date_to, $statuses, $per_page, $paged, $orderby, $order, $report_data, $total_items, $total_pages, $settings) {
  66. ?>
  67. <div class="wrap">
  68. <h1><?php _e('Custom Reports', StudiouWC_Main::get_text_domain()); ?></h1>
  69. <?php $this->render_filter_form($view, $date_from, $date_to, $statuses, $per_page); ?>
  70. <?php if (!empty($report_data)): ?>
  71. <?php $this->render_pagination_top($total_items, $total_pages, $paged); ?>
  72. <?php $this->render_data_table($report_data, $orderby, $order, $settings); ?>
  73. <?php else: ?>
  74. <p><?php _e('No data found for the selected criteria.', StudiouWC_Main::get_text_domain()); ?></p>
  75. <?php endif; ?>
  76. </div>
  77. <?php $this->render_reports_javascript(); ?>
  78. <?php
  79. }
  80. private function render_filter_form($view, $date_from, $date_to, $statuses, $per_page) {
  81. ?>
  82. <form method="get" id="studiou-reports-form">
  83. <input type="hidden" name="page" value="studiou-custom-reports">
  84. <table class="form-table">
  85. <tr>
  86. <th><label for="view"><?php _e('View', StudiouWC_Main::get_text_domain()); ?></label></th>
  87. <td>
  88. <select name="view" id="view">
  89. <option value="product_categories_summary" <?php selected($view, 'product_categories_summary'); ?>>
  90. <?php _e('Product Categories and Variants Summary', StudiouWC_Main::get_text_domain()); ?>
  91. </option>
  92. </select>
  93. </td>
  94. </tr>
  95. <tr>
  96. <th><label for="date_from"><?php _e('Date From', StudiouWC_Main::get_text_domain()); ?></label></th>
  97. <td><input type="date" name="date_from" id="date_from" value="<?php echo esc_attr($date_from); ?>"></td>
  98. </tr>
  99. <tr>
  100. <th><label for="date_to"><?php _e('Date To', StudiouWC_Main::get_text_domain()); ?></label></th>
  101. <td><input type="date" name="date_to" id="date_to" value="<?php echo esc_attr($date_to); ?>"></td>
  102. </tr>
  103. <tr>
  104. <th><label for="statuses"><?php _e('Included Statuses', StudiouWC_Main::get_text_domain()); ?></label></th>
  105. <td>
  106. <?php $this->render_status_checkboxes($statuses); ?>
  107. </td>
  108. </tr>
  109. <tr>
  110. <th><label for="per_page"><?php _e('Items per page', StudiouWC_Main::get_text_domain()); ?></label></th>
  111. <td>
  112. <select name="per_page" id="per_page">
  113. <option value="10" <?php selected($per_page, 10); ?>>10</option>
  114. <option value="20" <?php selected($per_page, 20); ?>>20</option>
  115. <option value="50" <?php selected($per_page, 50); ?>>50</option>
  116. <option value="100" <?php selected($per_page, 100); ?>>100</option>
  117. </select>
  118. </td>
  119. </tr>
  120. </table>
  121. <p class="submit">
  122. <input type="submit" name="filter" class="button-primary" value="<?php _e('Filter', StudiouWC_Main::get_text_domain()); ?>">
  123. <button type="button" id="export-csv" class="button"><?php _e('Export', StudiouWC_Main::get_text_domain()); ?></button>
  124. </p>
  125. </form>
  126. <?php
  127. }
  128. private function render_status_checkboxes($selected_statuses) {
  129. $order_statuses = wc_get_order_statuses();
  130. foreach ($order_statuses as $status_key => $status_label) {
  131. $checked = in_array($status_key, $selected_statuses) ? 'checked' : '';
  132. echo '<label><input type="checkbox" name="statuses[]" value="' . esc_attr($status_key) . '" ' . $checked . '> ' . esc_html($status_label) . '</label><br>';
  133. }
  134. }
  135. private function render_pagination_top($total_items, $total_pages, $paged) {
  136. ?>
  137. <div class="tablenav top">
  138. <div class="tablenav-pages">
  139. <span class="displaying-num"><?php printf(__('%d items', StudiouWC_Main::get_text_domain()), $total_items); ?></span>
  140. <?php if ($total_pages > 1): ?>
  141. <span class="pagination-links">
  142. <?php if ($paged > 1): ?>
  143. <a class="prev-page button" href="<?php echo esc_url(add_query_arg('paged', $paged - 1)); ?>"><?php _e('‹', StudiouWC_Main::get_text_domain()); ?></a>
  144. <?php endif; ?>
  145. <span class="paging-input">
  146. <span class="tablenav-paging-text"><?php printf(__('%1$d of %2$d', StudiouWC_Main::get_text_domain()), $paged, $total_pages); ?></span>
  147. </span>
  148. <?php if ($paged < $total_pages): ?>
  149. <a class="next-page button" href="<?php echo esc_url(add_query_arg('paged', $paged + 1)); ?>"><?php _e('›', StudiouWC_Main::get_text_domain()); ?></a>
  150. <?php endif; ?>
  151. </span>
  152. <?php endif; ?>
  153. </div>
  154. </div>
  155. <?php
  156. }
  157. private function render_data_table($report_data, $orderby, $order, $settings) {
  158. $default_property = $settings['default_property'] ?? '';
  159. $property_values = array();
  160. if (!empty($default_property)) {
  161. $property_values = $this->db_manager->get_property_values($default_property);
  162. }
  163. ?>
  164. <table class="wp-list-table widefat fixed striped">
  165. <thead>
  166. <tr>
  167. <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>
  168. <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>
  169. <?php foreach ($property_values as $slug => $name): ?>
  170. <th><?php echo esc_html($name . ' Count'); ?></th>
  171. <?php endforeach; ?>
  172. <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>
  173. </tr>
  174. </thead>
  175. <tbody>
  176. <?php foreach ($report_data as $row): ?>
  177. <tr>
  178. <td><?php echo esc_html($row['category']); ?></td>
  179. <td><?php echo esc_html($row['orders_count']); ?></td>
  180. <?php foreach ($property_values as $slug => $name): ?>
  181. <td><?php echo esc_html($row['property_counts'][$slug] ?? 0); ?></td>
  182. <?php endforeach; ?>
  183. <td><?php echo wc_price($row['total_price']); ?></td>
  184. </tr>
  185. <?php endforeach; ?>
  186. </tbody>
  187. </table>
  188. <?php
  189. }
  190. private function render_reports_javascript() {
  191. ?>
  192. <script>
  193. jQuery(document).ready(function($) {
  194. $('#export-csv').click(function() {
  195. var formData = $('#studiou-reports-form').serialize();
  196. formData += '&action=studiou_export_csv&export=1';
  197. var form = $('<form method="post" action="' + ajaxurl + '"></form>');
  198. $.each(formData.split('&'), function(i, field) {
  199. var parts = field.split('=');
  200. if (parts.length === 2) {
  201. form.append('<input type="hidden" name="' + decodeURIComponent(parts[0]) + '" value="' + decodeURIComponent(parts[1]) + '">');
  202. }
  203. });
  204. $('body').append(form);
  205. form.submit();
  206. form.remove();
  207. });
  208. });
  209. </script>
  210. <?php
  211. }
  212. private function render_settings_page($settings) {
  213. ?>
  214. <div class="wrap">
  215. <h1><?php _e('Custom Report Settings', StudiouWC_Main::get_text_domain()); ?></h1>
  216. <form method="post" id="studiou-settings-form">
  217. <table class="form-table">
  218. <tr>
  219. <th><label for="default_interval"><?php _e('Default shown interval', StudiouWC_Main::get_text_domain()); ?></label></th>
  220. <td>
  221. <select name="default_interval" id="default_interval">
  222. <option value="last_day" <?php selected($settings['default_interval'] ?? '', 'last_day'); ?>><?php _e('Last day', StudiouWC_Main::get_text_domain()); ?></option>
  223. <option value="last_week" <?php selected($settings['default_interval'] ?? '', 'last_week'); ?>><?php _e('Last week', StudiouWC_Main::get_text_domain()); ?></option>
  224. <option value="last_month" <?php selected($settings['default_interval'] ?? '', 'last_month'); ?>><?php _e('Last month', StudiouWC_Main::get_text_domain()); ?></option>
  225. </select>
  226. </td>
  227. </tr>
  228. <tr>
  229. <th><label for="default_property"><?php _e('Default property', StudiouWC_Main::get_text_domain()); ?></label></th>
  230. <td>
  231. <select name="default_property" id="default_property">
  232. <option value=""><?php _e('Select property', StudiouWC_Main::get_text_domain()); ?></option>
  233. <?php
  234. $properties = $this->db_manager->get_product_properties();
  235. foreach ($properties as $slug => $name) {
  236. $selected = selected($settings['default_property'] ?? '', $slug, false);
  237. echo '<option value="' . esc_attr($slug) . '" ' . $selected . '>' . esc_html($name) . '</option>';
  238. }
  239. ?>
  240. </select>
  241. </td>
  242. </tr>
  243. <tr>
  244. <th><label for="default_statuses"><?php _e('Default Included statuses', StudiouWC_Main::get_text_domain()); ?></label></th>
  245. <td>
  246. <?php
  247. $order_statuses = wc_get_order_statuses();
  248. $default_statuses = $settings['default_statuses'] ?? array();
  249. foreach ($order_statuses as $status_key => $status_label) {
  250. $checked = in_array($status_key, $default_statuses) ? 'checked' : '';
  251. echo '<label><input type="checkbox" name="default_statuses[]" value="' . esc_attr($status_key) . '" ' . $checked . '> ' . esc_html($status_label) . '</label><br>';
  252. }
  253. ?>
  254. </td>
  255. </tr>
  256. </table>
  257. <p class="submit">
  258. <button type="button" id="save-settings" class="button-primary"><?php _e('Save Settings', StudiouWC_Main::get_text_domain()); ?></button>
  259. </p>
  260. </form>
  261. </div>
  262. <script>
  263. jQuery(document).ready(function($) {
  264. $('#save-settings').click(function() {
  265. var formData = $('#studiou-settings-form').serialize();
  266. formData += '&action=studiou_save_settings';
  267. $.post(ajaxurl, formData, function(response) {
  268. if (response.success) {
  269. alert('<?php _e('Settings saved successfully!', StudiouWC_Main::get_text_domain()); ?>');
  270. } else {
  271. alert('<?php _e('Error saving settings.', StudiouWC_Main::get_text_domain()); ?>');
  272. }
  273. });
  274. });
  275. });
  276. </script>
  277. <?php
  278. }
  279. }