Skip to content

Commit 1cabbc9

Browse files
authored
Add company reports functionality (#252)
* Reorder includes to be alphabetic * Add reports and styling
1 parent c04421f commit 1cabbc9

File tree

3 files changed

+196
-4
lines changed

3 files changed

+196
-4
lines changed

plugins/wporg-5ftf/assets/css/admin.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,17 @@
7575
.contributor-list .button-link-delete .dashicons {
7676
margin-top: -2px;
7777
}
78+
79+
table#wporg-5ftf-company-report, #wporg-5ftf-company-report th, #wporg-5ftf-company-report td {
80+
border: 1px solid #000;
81+
border-collapse: collapse;
82+
padding: 5px;
83+
}
84+
85+
86+
87+
#wporg-5ftf-company-report td.center {
88+
text-align: center;
89+
}
90+
91+
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<?php
2+
3+
/**
4+
* List of contributors and useful stats around it.
5+
*/
6+
7+
namespace WordPressDotOrg\FiveForTheFuture\Reports;
8+
9+
use WordPressDotOrg\FiveForTheFuture;
10+
use WordPressDotOrg\FiveForTheFuture\{ Contributor, Pledge, XProfile };
11+
use WordPressdotorg\MU_Plugins\Utilities\Export_CSV;
12+
13+
use WP_Query;
14+
15+
defined( 'WPINC' ) || die();
16+
17+
add_action( 'admin_menu', __NAMESPACE__ . '\add_admin_pages' );
18+
add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\enqueue_assets' );
19+
add_action( 'admin_init', __NAMESPACE__ . '\export_csv' );
20+
21+
/**
22+
* Register admin page.
23+
*/
24+
function add_admin_pages() {
25+
add_submenu_page(
26+
'edit.php?post_type=5ftf_pledge',
27+
'Company Report',
28+
'Company Report',
29+
'manage_options',
30+
'5ftf_company_report',
31+
__NAMESPACE__ . '\render_company_report_page'
32+
);
33+
}
34+
35+
/**
36+
* Enqueue assets/
37+
*/
38+
function enqueue_assets() {
39+
wp_register_style(
40+
'5ftf-admin',
41+
plugins_url( 'assets/css/admin.css', __DIR__ ),
42+
array(),
43+
filemtime( FiveForTheFuture\PATH . '/assets/css/admin.css' )
44+
);
45+
46+
if ( is_admin() ) {
47+
$current_page = get_current_screen();
48+
if ( '5ftf_pledge_page_5ftf_company_report' == $current_page->id ) {
49+
wp_enqueue_style( '5ftf-admin' );
50+
}
51+
}
52+
}
53+
54+
/**
55+
* Render results and download button.
56+
*/
57+
function render_company_report_page() {
58+
59+
$status = sanitize_title( $_GET['status'] );
60+
61+
if ( ! in_array( $status, array( 'draft', '5ftf-deactivated', 'publish' ) ) ) {
62+
$status = 'all';
63+
}
64+
65+
$pledges = get_posts( array(
66+
'post_type' => '5ftf_pledge',
67+
'post_status' => $status,
68+
'posts_per_page' => 250, // set to 250 to avoid unexpected memory overuse.
69+
'orderby' => 'post_title',
70+
'order' => 'ASC',
71+
) );
72+
73+
// Add visible warning on page if we hit the upper limit of the query.
74+
if ( 250 == count( $pledges ) ) {
75+
echo '<p>WARNING: pledge limit reached, check the code query.</p>';
76+
}
77+
?>
78+
79+
<p>
80+
<b>Total:</b><?php echo count( $pledges ); ?>
81+
<b>Status:</b>
82+
<a href="edit.php?post_type=5ftf_pledge&page=5ftf_company_report">All</a>
83+
<a href="edit.php?post_type=5ftf_pledge&page=5ftf_company_report&status=draft">Draft</a>
84+
<a href="edit.php?post_type=5ftf_pledge&page=5ftf_company_report&status=publish">Publish</a>
85+
<a href="edit.php?post_type=5ftf_pledge&page=5ftf_company_report&status=5ftf-deactivated">Deactivated</a>
86+
</p>
87+
88+
<form action="#" method="post">
89+
<input type="hidden" name="wporg-5ftf-cr" value="1">
90+
<input type="hidden" name="status" value="<?php echo esc_attr( $status ); ?>">
91+
<input type="submit" value="Export">
92+
<?php wp_nonce_field( '5ftf_download_company_report' ); ?>
93+
</form>
94+
95+
<table id="wporg-5ftf-company-report">
96+
<tr>
97+
<th>Company</th>
98+
<th>Status</th>
99+
<th>Total Hours</th>
100+
<th>Contributors</th>
101+
<th>Usernames</th>
102+
<th>Team(s)</th>
103+
<th>URL</th>
104+
<th>Pledge URL</th>
105+
<th>Email</th>
106+
<th>Pledge created</th>
107+
<th>Pledge updated</th>
108+
</tr>
109+
<?php
110+
$all_contributors = 0;
111+
112+
$export_data = array();
113+
foreach ( $pledges as $pledge ) {
114+
$company_url = get_post_meta( $pledge->ID, '5ftf_org-domain', true );
115+
$pledge_url = get_post_meta( $pledge->ID, '5ftf_org-url', true );
116+
$email = get_post_meta( $pledge->ID, '5ftf_org-pledge-email', true );
117+
$date_created = substr( $pledge->post_date, 0, 10 );
118+
$date_modified = substr( $pledge->post_modified, 0, 10 );
119+
120+
$team = XProfile\get_aggregate_contributor_data_for_pledge( $pledge->ID );
121+
$hours = $team['hours'];
122+
$contributors = $team['contributors'];
123+
124+
$all_contributors += $contributors;
125+
$users = Contributor\get_pledge_contributors( $pledge->ID, 'publish' );
126+
$wporg_profiles = wp_list_pluck( $users, 'post_title' );
127+
128+
$usernames = implode( ', ', $wporg_profiles );
129+
$teams = implode( ', ', str_replace( ' Team', '', $team['teams'] ) );
130+
131+
echo '<tr>';
132+
echo ' <td><a href="' . esc_url( $pledge->guid ) . '">' . esc_html( $pledge->post_title ) . '</a></td>';
133+
echo ' <td>' . esc_html( $pledge->post_status ) . '</td>';
134+
echo ' <td class="center">' . esc_html( $hours ) . '</td>';
135+
echo ' <td class="center">' . esc_html( $contributors ) . '</td>';
136+
echo ' <td>' . esc_html( $usernames ) . '</td>';
137+
echo ' <td>' . esc_html( $teams ) . '</td>';
138+
echo ' <td>' . esc_html( $company_url ) . '</td>';
139+
echo ' <td>' . esc_html( $pledge_url ) . '</td>';
140+
echo ' <td>' . esc_html( $email ). '</td>';
141+
echo ' <td>' . esc_html( $date_created ) . '</td>';
142+
echo ' <td>' . esc_html( $date_modified ) . '</td>';
143+
echo '</tr>';
144+
$export_data[] = array( $pledge->post_title, $pledge->post_status, $hours, $contributors, $usernames, $teams, $company_url, $pledge_url, $email, $date_created, $date_modified );
145+
}
146+
echo '</table>';
147+
echo '<p>Total contributors: ' . esc_html( $all_contributors ) . '</p>';
148+
149+
// Sets a transient to avoid double data lookup for export, might need to adjust timeout to longer.
150+
set_transient( 'wporg_5ftf_company_report_' . $status, $export_data, 60 );
151+
}
152+
153+
/**
154+
* CSV export runner, grabs data lazily from a transient.
155+
*/
156+
function export_csv() {
157+
158+
if (
159+
! isset( $_POST['wporg-5ftf-cr'] ) ||
160+
! current_user_can( 'manage_options' ) ||
161+
! wp_verify_nonce( $_POST['_wpnonce'], '5ftf_download_company_report' )
162+
) {
163+
return;
164+
}
165+
166+
$status = $_POST['status'];
167+
168+
$data = get_transient( 'wporg_5ftf_company_report_' . $status );
169+
170+
$exporter = new Export_CSV( array(
171+
'filename' => 'company-report-' . $status,
172+
'headers' => array( 'Company', 'Status', 'Hours', 'Contributors', 'Users', 'Teams', 'Company URL', 'Pledge URL', 'Email', 'Created', 'Last updated' ),
173+
'data' => $data,
174+
) );
175+
176+
$exporter->emit_file();
177+
}

plugins/wporg-5ftf/index.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ function load() {
2828
require_once get_includes_path() . 'authentication.php';
2929
require_once get_includes_path() . 'contributor.php';
3030
require_once get_includes_path() . 'email.php';
31-
require_once get_includes_path() . 'pledge.php';
32-
require_once get_includes_path() . 'pledge-meta.php';
33-
require_once get_includes_path() . 'pledge-form.php';
34-
require_once get_includes_path() . 'xprofile.php';
3531
require_once get_includes_path() . 'endpoints.php';
3632
require_once get_includes_path() . 'miscellaneous.php';
33+
require_once get_includes_path() . 'pledge.php';
34+
require_once get_includes_path() . 'pledge-form.php';
35+
require_once get_includes_path() . 'pledge-meta.php';
36+
require_once get_includes_path() . 'reports.php';
3737
require_once get_includes_path() . 'stats.php';
38+
require_once get_includes_path() . 'xprofile.php';
3839

3940
// The logger expects things like `$_POST` which aren't set during unit tests.
4041
if ( ! $running_unit_tests ) {

0 commit comments

Comments
 (0)