PluginProbe
UpStream: a Project Management Plugin for WordPress / trunk
UpStream: a Project Management Plugin for WordPress vtrunk
trunk 1.39.0 1.39.1 1.39.2 1.39.3 2.0.7 2.1.0
upstream / includes / admin / class-upstream-admin-bugs-page.php

class-upstream-admin-bugs-page.php in UpStream: a Project Management Plugin for WordPress trunk, at includes/admin/class-upstream-admin-bugs-page.php

1,071 lines 26.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Upstream_Admin_Bugs_Page
4 *
5 * @package UpStream
6 */
7
8 // Exit if accessed directly.
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 if ( ! class_exists( 'WP_List_Table' ) ) {
14 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
15 }
16
17 /**
18 * Class Upstream_Admin_Bugs_Page
19 */
20 class Upstream_Admin_Bugs_Page {
21
22 /**
23 * Instance
24 *
25 * @var mixed
26 */
27 public static $instance;
28
29 /**
30 * Customer WP_List_Table object
31 *
32 * @var mixed
33 */
34 public $bugs_obj;
35
36
37 /**
38 * Construct
39 *
40 * @return void
41 */
42 public function __construct() {
43 add_filter( 'set-screen-option', array( $this, 'set_screen' ), 10, 3 );
44 add_action( 'admin_menu', array( $this, 'plugin_menu' ) );
45 }
46
47 /**
48 * Singleton instance
49 */
50 public static function get_instance() {
51 if ( ! isset( self::$instance ) ) {
52 self::$instance = new self();
53 }
54
55 return self::$instance;
56 }
57
58 /**
59 * Set Screen
60 *
61 * @param mixed $status Status.
62 * @param mixed $option Option.
63 * @param mixed $value Value.
64 */
65 public function set_screen( $status, $option, $value ) {
66 $post_data = isset( $_POST ) ? wp_unslash( $_POST ) : array();
67 $nonce = isset( $post_data['screenoptionnonce'] ) ? $post_data['screenoptionnonce'] : null;
68
69 if ( 'upstream_completed_bugs' === $option && wp_verify_nonce( $nonce, 'screen-options-nonce' ) ) {
70 $value = sanitize_text_field( $post_data['upstream_hide_completed'] );
71 }
72
73 return $value;
74 }
75
76 /**
77 * Screen options
78 */
79 public function screen_option() {
80 $option = 'per_page';
81 $args = array(
82 'label' => upstream_bug_label_plural(),
83 'default' => 10,
84 'option' => 'bugs_per_page',
85 );
86
87 add_screen_option( $option, $args );
88
89 $screen = get_current_screen();
90 if ( 'project_page_bugs' === $screen->id ) {
91 $this->bugs_obj = new Upstream_Bug_List();
92 }
93 }
94
95 /**
96 * Plugin Menu
97 *
98 * @return void
99 */
100 public function plugin_menu() {
101 if ( ! upstream_is_user_either_manager_or_admin() /* RSD: removed for new perms && $count <= 0 */ ) {
102 return;
103 }
104
105 // counter number notification.
106 $count = (int) upstream_count_assigned_to_open( 'bugs' );
107 $count_notif = $count ? " <span class='update-plugins count-1'><span class='update-count'>$count</span></span>" : '';
108
109 // add_submenu_page hook.
110 $hook = add_submenu_page(
111 'edit.php?post_type=project',
112 upstream_bug_label_plural(),
113 upstream_bug_label_plural() . $count_notif,
114 'edit_projects',
115 'bugs',
116 array( $this, 'plugin_settings_page' )
117 );
118
119 add_action( "load-$hook", array( $this, 'screen_option' ) );
120 }
121
122 /**
123 * Plugin settings page
124 */
125 public function plugin_settings_page() {
126 ?>
127 <div class="wrap">
128 <h1><?php echo esc_html( upstream_bug_label_plural() ); ?></h1>
129
130 <div id="post-body-content">
131
132 <div class="meta-box-sortables ui-sortable">
133 <?php $this->bugs_obj->views(); ?>
134 <?php
135 // $this->bugs_obj->display_tablenav( 'top' );
136 ?>
137 <?php
138 // $this->bugs_obj->search_box('search', 'search_id');
139 ?>
140 <form method="post">
141 <?php
142 $this->bugs_obj->prepare_items();
143 $this->bugs_obj->display();
144 ?>
145 </form>
146 </div>
147 </div>
148
149 <br class="clear">
150 </div>
151 <?php
152 }
153 }
154
155 /**
156 * Class Upstream_Bug_List
157 */
158 class Upstream_Bug_List extends WP_List_Table {
159
160 /**
161 * Bugs Statuses
162 *
163 * @var mixed
164 */
165 private static $bugs_statuses;
166
167 /**
168 * Bugs Severities
169 *
170 * @var mixed
171 */
172 private static $bugs_severities;
173
174 /**
175 * Bug Label
176 *
177 * @var string
178 */
179 public $bug_label = '';
180
181 /**
182 * Bug Label Plural
183 *
184 * @var string
185 */
186 public $bug_label_plural = '';
187
188 /**
189 * Columns
190 *
191 * @var array
192 */
193 private $columns = array();
194
195 /*
196 * Displays the filtering links above the table
197 */
198
199 /** Class constructor */
200 public function __construct() {
201 $this->bug_label = upstream_bug_label();
202 $this->bug_label_plural = upstream_bug_label_plural();
203
204 parent::__construct(
205 array(
206 'singular' => $this->bug_label,
207 'plural' => $this->bug_label_plural,
208 'ajax' => false, // does this table support ajax?
209 )
210 );
211 }
212
213 /**
214 * Get Columns
215 */
216 public function get_columns() {
217 $columns = apply_filters(
218 'upstream_admin_bug_page_columns',
219 array(
220 'title' => $this->bug_label,
221 'project' => upstream_project_label(),
222 'id' => __( 'ID', 'upstream' ),
223 'assigned_to' => __( 'Assigned To', 'upstream' ),
224 'due_date' => __( 'Due Date', 'upstream' ),
225 'status' => __( 'Status', 'upstream' ),
226 'severity' => __( 'Severity', 'upstream' ),
227 )
228 );
229
230 return $columns;
231 }
232
233 /**
234 * Get Views
235 */
236 public function get_views() {
237 $views = array();
238 $request_data = isset( $_REQUEST ) ? wp_unslash( $_REQUEST ) : array();
239
240 if ( ! empty( $request_data['status'] ) ) {
241 $current = sanitize_text_field( $request_data['status'] );
242 } elseif ( ! empty( $request_data['view'] ) ) {
243 $current = sanitize_text_field( $request_data['view'] );
244 } else {
245 $current = 'all';
246 }
247
248 // All link.
249 $all_class = ( 'all' === $current ? ' class="current"' : '' );
250 $all_url = remove_query_arg( array( 'status', 'view' ) );
251 $all_count = upstream_count_total( 'bugs' );
252 $views['all'] = "<a href='" . esc_url( $all_url ) . "' {$all_class} >" . __(
253 'All',
254 'upstream'
255 ) . "</a>({$all_count})";
256
257 // Mine link.
258 $mine_class = ( 'mine' === $current ? ' class="current"' : '' );
259 $mine_url = add_query_arg(
260 array(
261 'view' => 'mine',
262 'status' => false,
263 )
264 );
265 $mine_count = upstream_count_assigned_to( 'bugs' );
266 $views['mine'] = "<a href='" . esc_url( $mine_url ) . "' {$mine_class} >" . __(
267 'Mine',
268 'upstream'
269 ) . "</a>({$mine_count})";
270
271 // links for other statuses.
272 $option = get_option( 'upstream_bugs' );
273 $statuses = isset( $option['statuses'] ) ? $option['statuses'] : '';
274 $counts = self::count_statuses();
275
276 if ( $statuses ) {
277 // check if user wants to hide completed bugs.
278 $hide = get_user_option( 'upstream_completed_bugs', get_current_user_id() );
279
280 foreach ( $statuses as $status ) {
281 if ( 'on' === $hide && self::hide_completed( $status['name'] ) ) {
282 continue;
283 }
284
285 $stati = strtolower( $status['id'] );
286 $class = ( $current == $stati ? ' class="current"' : '' );
287 $url = add_query_arg(
288 array(
289 'status' => $stati,
290 'view' => false,
291 'paged' => false,
292 )
293 );
294 $count = isset( $counts[ $status['name'] ] ) ? $counts[ $status['name'] ] : 0;
295 $views[ $stati ] = "<a href='" . esc_url( $url ) . "' {$class} >{$status['name']}</a>({$count})";
296 }
297 }
298
299 return $views;
300 }
301
302 /**
303 * Returns the count of each status
304 *
305 * @return array
306 */
307 public static function count_statuses() {
308 $statuses = upstream_get_bugs_statuses();
309 $rowset = self::get_bugs();
310
311 $data = array();
312
313 if ( empty( $rowset ) ) {
314 return $data;
315 }
316
317 foreach ( $rowset as $row ) {
318 if ( isset( $row['status'] )
319 && ! empty( $row['status'] )
320 && isset( $statuses[ $row['status'] ] )
321 ) {
322 $status_title = $statuses[ $row['status'] ]['name'];
323 if ( isset( $data[ $status_title ] ) ) {
324 $data[ $status_title ]++;
325 } else {
326 $data[ $status_title ] = 1;
327 }
328 }
329 }
330
331 return $data;
332 }
333
334 /**
335 * Retrieve all bugs from all projects.
336 *
337 * @return array
338 */
339 public static function get_bugs() {
340 $args = array(
341 'post_type' => 'project',
342 'post_status' => 'publish',
343 'posts_per_page' => -1,
344 'meta_query' => array(
345 array(
346 'key' => '_upstream_project_bugs',
347 'compare' => 'EXISTS',
348 ),
349 ),
350 );
351
352 // The Query.
353 $the_query = new WP_Query( $args );
354
355 // The Loop.
356 if ( ! $the_query->have_posts() ) {
357 return;
358 }
359
360 $bugs = array();
361 while ( $the_query->have_posts() ) :
362 $the_query->the_post();
363
364 $post_id = get_the_ID();
365
366 if ( upstream_are_bugs_disabled( $post_id ) ) {
367 continue;
368 }
369
370 $meta = get_post_meta( $post_id, '_upstream_project_bugs', true );
371 $owner = get_post_meta( $post_id, '_upstream_project_owner', true );
372
373 if ( $meta ) :
374 foreach ( $meta as $meta_val => $bug ) {
375 // set up the data for each column.
376 $bug['title'] = isset( $bug['title'] ) ? $bug['title'] : __( '(no title)', 'upstream' );
377 $bug['project'] = get_the_title( $post_id );
378 $bug['owner'] = $owner;
379 $bug['assigned_to'] = isset( $bug['assigned_to'] ) ? $bug['assigned_to'] : 0;
380 $bug['due_date'] = isset( $bug['due_date'] ) ? $bug['due_date'] : '';
381 $bug['status'] = isset( $bug['status'] ) ? $bug['status'] : '';
382 $bug['severity'] = isset( $bug['severity'] ) ? $bug['severity'] : '';
383 $bug['description'] = isset( $bug['description'] ) ? $bug['description'] : '';
384 $bug['project_id'] = $post_id; // add the post id to each bug.
385
386 // check if we can add the bug to the list.
387 $user_id = get_current_user_id();
388 // $option = get_option( 'upstream_bugs' );
389 // $hide = $option['hide_closed'];
390
391 // // check if user wants to hide completed bugs
392 // if ( $hide == 'on' && self::hide_completed( $bug['status'] ) )
393 // continue;
394
395 $bugs[] = $bug;
396 }
397
398 endif;
399
400 endwhile;
401
402 return $bugs;
403 }
404
405
406 /**
407 * Hide Completed
408 *
409 * @param mixed $status Status.
410 */
411 public static function hide_completed( $status ) {
412 $option = get_option( 'upstream_bugs' );
413 $statuses = isset( $option['statuses'] ) ? $option['statuses'] : '';
414
415 if ( ! $statuses ) {
416 return false;
417 }
418
419 $types = wp_list_pluck( $statuses, 'type', 'name' );
420
421 foreach ( $types as $key => $value ) {
422 if ( $key === $status && 'open' === $value ) {
423 return false;
424 }
425 }
426
427 return true;
428 }
429
430 /**
431 * Extra Tablenav
432 *
433 * @param mixed $which Which.
434 * @return void
435 */
436 public function extra_tablenav( $which ) {
437 if ( 'top' !== $which ) {
438 return;
439 }
440
441 $request_data = isset( $_REQUEST ) ? wp_unslash( $_REQUEST ) : array();
442 $get_data = isset( $_GET ) ? wp_unslash( $_GET ) : array();
443 ?>
444
445 <div class="alignleft actions">
446
447 <?php
448 if ( ! is_singular() ) {
449 $projects = (array) $this->get_projects_unique();
450 if ( ! empty( $projects ) ) {
451 ?>
452
453 <select name='project' id='project' class='postform'>
454 <option value=''>
455 <?php
456 printf(
457 // translators: %s: tablenav name.
458 esc_html__( 'Show all %s', 'upstream' ),
459 'projects'
460 );
461 ?>
462 </option>
463 <?php
464 foreach ( $projects as $project_id => $title ) {
465 ?>
466 <option
467 value="<?php echo esc_attr( $project_id ); ?>"
468 <?php
469 isset( $get_data['project'] ) ? selected(
470 sanitize_text_field( $get_data['project'] ),
471 $project_id
472 ) : '';
473 ?>
474 ><?php echo esc_html( $title ); ?></option>
475 <?php
476 }
477 ?>
478 </select>
479
480 <?php
481 }
482
483 $users = (array) $this->get_assigned_to_unique();
484 if ( count( $users ) > 0 ) {
485 $assigned_to = isset( $request_data['assigned_to'] ) ? intval( $request_data['assigned_to'] ) : 0;
486 ?>
487 <select id="assigned_to" name="assigned_to" class="postform">
488 <option value="">
489 <?php
490 printf(
491 // translators: %s: assigned_to name.
492 esc_html__( 'Show all %s', 'upstream' ),
493 'users'
494 );
495 ?>
496 </option>
497 <?php foreach ( $users as $user_id => $user_name ) : ?>
498 <option
499 value="<?php echo esc_attr( $user_id ); ?>" <?php echo $assigned_to === $user_id ? 'selected' : ''; ?>><?php echo esc_html( $user_name ); ?></option>
500 <?php endforeach; ?>
501 </select>
502 <?php
503 }
504
505 $status = self::getBugsStatuses();
506 if ( ! empty( $status ) ) {
507 ?>
508
509 <select name='status' id='status' class='postform'>
510 <option value=''>
511 <?php
512 printf(
513 // translators: %s: status name.
514 esc_html__( 'Show all %s', 'upstream' ),
515 'statuses'
516 );
517 ?>
518 </option>
519 <?php
520 foreach ( $status as $stati ) {
521 if ( is_array( $stati ) ) {
522 $status_title = $stati['name'];
523 $status_id = $stati['id'];
524 } else {
525 $status_title = $stati;
526 $status_id = $stati;
527 }
528 ?>
529 <option value="<?php echo esc_attr( $status_id ); ?>"
530 <?php
531 isset( $get_data['status'] ) ? selected(
532 sanitize_text_field( $get_data['status'] ),
533 $status_title
534 ) : '';
535 ?>
536 ><?php echo esc_html( $status_title ); ?></option>
537 <?php
538 }
539 ?>
540 </select>
541
542 <?php
543 }
544
545 $severities = self::getBugsSeverities();
546 if ( ! empty( $severities ) ) {
547 ?>
548
549 <select name='severity' id='severity' class='postform'>
550 <option value=''>
551 <?php
552 printf(
553 // translators: %s severity label.
554 esc_html__( 'Show all %s', 'upstream' ),
555 'severities'
556 );
557 ?>
558 </option>
559 <?php
560 foreach ( $severities as $severity ) {
561 if ( is_array( $severity ) ) {
562 $severity_title = $severity['name'];
563 $severity_id = $severity['id'];
564 } else {
565 $severity_title = $severity;
566 $severity_id = $severity;
567 }
568 ?>
569 <option
570 value="<?php echo esc_attr( $severity_id ); ?>"
571 <?php
572 isset( $get_data['severity'] ) ? selected(
573 sanitize_text_field( $get_data['severity'] ),
574 $severity_title
575 ) : '';
576 ?>
577 ><?php echo esc_html( $severity_title ); ?></option>
578 <?php
579 }
580 ?>
581 </select>
582
583 <?php
584 }
585
586 submit_button( __( 'Filter', 'upstream' ), 'button', 'filter', false );
587 }
588 ?>
589 </div>
590 <?php
591 }
592
593 /**
594 * Get Projects Unique
595 *
596 * @return void
597 */
598 private function get_projects_unique() {
599 $bugs = self::get_bugs();
600 if ( empty( $bugs ) ) {
601 return;
602 }
603
604 $items = wp_list_pluck( $bugs, 'project', 'project_id' );
605 $items = array_unique( $items );
606 $items = array_filter( $items );
607
608 return $items;
609 }
610
611 /**
612 * Get Assigned To Unique
613 *
614 * @return void
615 */
616 private function get_assigned_to_unique() {
617 $bugs = (array) self::get_bugs();
618 if ( count( $bugs ) === 0 ) {
619 return;
620 }
621
622 $rowset = wp_list_pluck( $bugs, 'assigned_to' );
623
624 $data = array();
625
626 $set_user_name_into_data = function ( $user_id ) use ( &$data ) {
627 if ( ! isset( $data[ $user_id ] ) ) {
628 $data[ $user_id ] = upstream_users_name( $user_id );
629 }
630 };
631
632 foreach ( $rowset as $assignees ) {
633 if ( ! is_array( $assignees ) ) {
634 $assignees = (array) $assignees;
635 }
636
637 $assignees = array_unique( array_filter( array_map( 'intval', $assignees ) ) );
638 foreach ( $assignees as $assignee_id ) {
639 $set_user_name_into_data( $assignee_id );
640 }
641 }
642
643 return $data;
644 }
645
646 /**
647 * Get Bugs Statuses
648 *
649 * @return void
650 */
651 private static function getBugsStatuses() {
652 if ( empty( self::$bugs_statuses ) ) {
653 $rowset = self::get_bugs();
654 if ( empty( $rowset ) || count( $rowset ) === 0 ) {
655 return;
656 }
657
658 $statuses = upstream_get_bugs_statuses();
659
660 $data = array();
661
662 foreach ( $rowset as $row ) {
663 if ( ! empty( $row['status'] )
664 && isset( $row['status'] )
665 ) {
666 $data[ $row['status'] ] = isset( $statuses[ $row['status'] ] )
667 ? $statuses[ $row['status'] ]
668 : $row['status'];
669 }
670 }
671
672 self::$bugs_statuses = $data;
673 } else {
674 $data = self::$bugs_statuses;
675 }
676
677 return $data;
678 }
679
680 /**
681 * Get Bugs Severities
682 *
683 * @return void
684 */
685 private static function getBugsSeverities() {
686 if ( empty( self::$bugs_severities ) ) {
687 $rowset = self::get_bugs();
688 if ( empty( $rowset ) || count( $rowset ) === 0 ) {
689 return;
690 }
691
692 $statuses = upstream_get_bugs_severities();
693
694 $data = array();
695
696 foreach ( $rowset as $row ) {
697 if ( ! empty( $row['severity'] )
698 && isset( $row['severity'] )
699 ) {
700 $data[ $row['severity'] ] = isset( $statuses[ $row['severity'] ] )
701 ? $statuses[ $row['severity'] ]
702 : $row['severity'];
703 }
704 }
705
706 self::$bugs_severities = $data;
707 } else {
708 $data = self::$bugs_severities;
709 }
710
711 return $data;
712 }
713
714 /**
715 * Render a column when no column specific method exist.
716 *
717 * @param array $item Item.
718 * @param string $column_name Column Name.
719 *
720 * @return mixed
721 */
722 public function column_default( $item, $column_name ) {
723 switch ( $column_name ) {
724
725 case 'title':
726 $output = '<a class="row-title" href="' . get_edit_post_link( $item['project_id'] ) . '">' . $item['title'] . '</a>';
727
728 return $output;
729
730 case 'id':
731 return $item['id'];
732
733 case 'project':
734 $owner = upstream_project_owner_name( $item['project_id'] ) ? '(' . upstream_project_owner_name( $item['project_id'] ) . ')' : '';
735
736 $output = '<a href="' . get_edit_post_link( $item['project_id'] ) . '">' . $item['project'] . '</a>';
737 $output .= '<br>' . $owner;
738
739 return $output;
740
741 case 'assigned_to':
742 $assignees = isset( $item['assigned_to'] ) ? array_filter( (array) $item['assigned_to'] ) : array();
743 if ( count( $assignees ) > 0 ) {
744 $users = get_users(
745 array(
746 'fields' => array(
747 'ID',
748 'display_name',
749 ),
750 'include' => $assignees,
751 )
752 );
753
754 $html = array();
755
756 $current_user_id = get_current_user_id();
757 foreach ( $users as $user ) {
758 if ( (int) $user->ID === $current_user_id ) {
759 $html[] = '<span class="mine">' . esc_html( $user->display_name ) . '</span>';
760 } else {
761 $html[] = '<span>' . esc_html( $user->display_name ) . '</span>';
762 }
763 }
764
765 return implode( ',<br>', $html );
766 } else {
767 return '<span><i style="color: #CCC;">' . __( 'none', 'upstream' ) . '</i></span>';
768 }
769 // no break.
770 case 'due_date':
771 if ( isset( $item['due_date'] ) && (int) $item['due_date'] > 0 ) {
772 return '<span class="end-date">' . upstream_format_date( $item['due_date'] ) . '</span>';
773 } else {
774 return '<span><i style="color: #CCC;">' . __( 'none', 'upstream' ) . '</i></span>';
775 }
776
777 // no break.
778 case 'status':
779 if ( ! isset( $item['status'] ) || empty( $item['status'] ) ) {
780 return '<span><i style="color: #CCC;">' . __( 'none', 'upstream' ) . '</i></span>';
781 }
782
783 $status = self::$bugs_statuses[ $item['status'] ];
784
785 if ( is_array( $status ) ) {
786 $status_title = $status['name'];
787 $status_color = $status['color'];
788 } else {
789 $status_title = $status;
790 $status_color = '#aaaaaa';
791 }
792
793 $output = sprintf(
794 '<span class="status %s" style="border-color: %s">
795 <span class="count" style="background-color: %2$s">&nbsp;</span> %3$s
796 </span>',
797 esc_attr( strtolower( $status_title ) ),
798 esc_attr( $status_color ),
799 esc_html( $status_title )
800 );
801
802 return $output;
803
804 case 'severity':
805 if ( ! isset( $item['severity'] )
806 || empty( $item['severity'] )
807 ) {
808 return '<span><i style="color: #CCC;">' . __( 'none', 'upstream' ) . '</i></span>';
809 }
810
811 $severity = self::$bugs_severities[ $item['severity'] ];
812
813 if ( is_array( $severity ) ) {
814 $severity_title = $severity['name'];
815 $severity_color = $severity['color'];
816 } else {
817 $severity_title = $severity;
818 $severity_color = '#aaaaaa';
819 }
820
821 $output = sprintf(
822 '<span class="status %s" style="border-color: %s">
823 <span class="count" style="background-color: %2$s">&nbsp;</span> %3$s
824 </span>',
825 esc_attr( strtolower( $severity_title ) ),
826 esc_attr( $severity_color ),
827 esc_html( $severity_title )
828 );
829
830 return $output;
831
832 default:
833 // return print_r( $item, true ); //Show the whole array for troubleshooting purposes.
834 }
835 }
836
837 /**
838 * Columns to make sortable.
839 *
840 * @return array
841 */
842 public function get_sortable_columns() {
843 $sortable_columns = array(
844 'title' => array( 'title', true ),
845 // 'project' => array( 'project', false ),
846 // 'milestone' => array( 'milestone', false ),
847 'assigned_to' => array( 'assigned_to', false ),
848 'due_date' => array( 'due_date', false ),
849 'status' => array( 'status', false ),
850 'severity' => array( 'severity', false ),
851 );
852
853 return $sortable_columns;
854 }
855
856 /** Text displayed when no customer data is available */
857 public function no_items() {
858 printf(
859 // translators: %s: item label.
860 esc_html__( 'No %s avaliable.', 'upstream' ),
861 esc_html( strtolower( $this->bug_label_plural ) )
862 );
863 }
864
865 /**
866 * Handles data query and filter, sorting, and pagination.
867 */
868 public function prepare_items() {
869 $this->_column_headers = $this->get_column_info();
870
871 $per_page = $this->get_items_per_page( 'bugs_per_page', 10 );
872 $current_page = $this->get_pagenum();
873
874 $unpaginated_items = self::get_bugs();
875 $unpaginated_items = self::sort_filter( $unpaginated_items );
876
877 $total_items = count( $unpaginated_items );
878
879 $this->set_pagination_args(
880 array(
881 'total_items' => $total_items, // We have to calculate the total number of items.
882 'per_page' => $per_page, // We have to determine how many items to show on a page.
883 )
884 );
885
886 $this->items = self::output_bugs( $per_page, $current_page );
887 }
888
889 /**
890 * Output bugs
891 *
892 * @param int $per_page Per Page.
893 * @param int $page_number Page Number.
894 *
895 * @return mixed
896 */
897 public static function output_bugs( $per_page = 10, $page_number = 1 ) {
898 // get the bugs.
899 $bugs = self::get_bugs();
900 // sort & filter the bugs.
901 $bugs = self::sort_filter( $bugs );
902 // does the paging.
903 if ( ! $bugs ) {
904 $output = 0;
905 } else {
906 $output = array_slice( $bugs, ( $page_number - 1 ) * $per_page, $per_page );
907 }
908
909 return $output;
910 }
911
912 /**
913 * Sort Filter
914 *
915 * @param mixed $bugs Bugs.
916 */
917 public static function sort_filter( $bugs = array() ) {
918 if ( ! is_array( $bugs ) || count( $bugs ) === 0 ) {
919 return array();
920 }
921
922 $request_data = isset( $_REQUEST ) ? wp_unslash( $_REQUEST ) : array();
923
924 // filtering.
925 $the_bugs = $bugs; // store the bugs array.
926
927 // NOTE: this is being checked against the list below.
928 $status = isset( $request_data['status'] ) && ! empty( $request_data['status'] ) ? sanitize_text_field( $request_data['status'] ) : 'all';
929 if ( ! empty( $status ) && 'all' !== $status ) {
930 $bugs = array_filter(
931 $the_bugs,
932 function ( $row ) use ( $status ) {
933 return isset( $row['status'] ) && $row['status'] === $status;
934 }
935 );
936 }
937
938 // NOTE: this is being checked against the list below.
939 $severity = isset( $request_data['severity'] ) && ! empty( $request_data['severity'] ) ? sanitize_text_field( $request_data['severity'] ) : 'all';
940 if ( ! empty( $severity ) && 'all' !== $severity ) {
941 $bugs = array_filter(
942 $bugs,
943 function ( $row ) use ( $severity ) {
944 return isset( $row['severity'] ) && $row['severity'] === $severity;
945 }
946 );
947 }
948
949 // NOTE: this is checking against a known string.
950 if ( isset( $request_data['view'] ) && sanitize_text_field( $request_data['view'] ) === 'mine' ) {
951 $current_user_id = (int) get_current_user_id();
952
953 $bugs = array_filter(
954 $bugs,
955 function ( $row ) use ( $current_user_id ) {
956 if ( isset( $row['assigned_to'] ) ) {
957 if ( ( is_array( $row['assigned_to'] ) && in_array( $current_user_id, $row['assigned_to'] ) )
958 || (int) $row['assigned_to'] === $current_user_id
959 ) {
960 return true;
961 }
962 }
963
964 return false;
965 }
966 );
967 } else {
968 // the cast will set any non-ints to 0.
969 $assigned_to = isset( $request_data['assigned_to'] ) ? intval( $request_data['assigned_to'] ) : 0;
970 if ( $assigned_to > 0 ) {
971 $bugs = array_filter(
972 $bugs,
973 function ( $row ) use ( $assigned_to ) {
974 return isset( $row['assigned_to'] ) && $row['assigned_to'] === $assigned_to;
975 }
976 );
977 }
978 }
979
980 $project_id = isset( $request_data['project'] ) && ! empty( $request_data['project'] ) ? absint( $request_data['project'] ) : 0;
981 if ( $project_id > 0 ) {
982 $bugs = array_filter(
983 $bugs,
984 function ( $row ) use ( $project_id ) {
985 return isset( $row['project_id'] ) && $row['project_id'] === $project_id;
986 }
987 );
988 }
989
990 // sorting the bugs.
991 if ( ! empty( $request_data['orderby'] ) ) {
992 if ( ! empty( $request_data['order'] ) && sanitize_text_field( $request_data['order'] ) == 'asc' ) {
993 $tmp = array();
994 foreach ( $bugs as &$ma ) {
995 $tmp[] = &$ma[ esc_html( sanitize_text_field( $request_data['orderby'] ) ) ];
996 }
997 array_multisort( $tmp, SORT_ASC, $bugs );
998 }
999 if ( ! empty( $request_data['order'] ) && sanitize_text_field( $request_data['order'] ) == 'desc' ) {
1000 $tmp = array();
1001 foreach ( $bugs as &$ma ) {
1002 $tmp[] = &$ma[ esc_html( sanitize_text_field( $request_data['orderby'] ) ) ];
1003 }
1004 array_multisort( $tmp, SORT_DESC, $bugs );
1005 }
1006 }
1007
1008 $rowset = array();
1009 foreach ( $bugs as $bug ) {
1010 if ( ! isset( $rowset[ $bug['id'] ] ) ) {
1011 $rowset[ $bug['id'] ] = $bug;
1012 }
1013 }
1014
1015 return array_values( $rowset );
1016 }
1017
1018 /**
1019 * Get Table Classes
1020 */
1021 protected function get_table_classes() {
1022 return array( 'widefat', 'striped', $this->_args['plural'] );
1023 }
1024
1025 /**
1026 * Get Status Unique
1027 *
1028 * @return void
1029 */
1030 private function get_status_unique() {
1031 $bugs = self::get_bugs();
1032 if ( empty( $bugs ) ) {
1033 return;
1034 }
1035
1036 $items = wp_list_pluck( $bugs, 'status' );
1037 $items = array_unique( $items );
1038 $items = array_filter( $items );
1039
1040 return $items;
1041 }
1042
1043 /**
1044 * Get Severity Unique
1045 *
1046 * @return void
1047 */
1048 private function get_severity_unique() {
1049 $bugs = self::get_bugs();
1050 if ( empty( $bugs ) ) {
1051 return;
1052 }
1053
1054 $items = wp_list_pluck( $bugs, 'severity' );
1055 $items = array_unique( $items );
1056 $items = array_filter( $items );
1057
1058 return $items;
1059 }
1060 }
1061
1062 add_action(
1063 'plugins_loaded',
1064 function () {
1065 if ( upstream_disable_bugs() ) {
1066 return;
1067 }
1068 Upstream_Admin_Bugs_Page::get_instance();
1069 }
1070 );
1071