<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[7883] sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports: WordCamp Reports: Augment WordCamp Counts report with gender breakdowns</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/7883">7883</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/7883","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>coreymckrill</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2018-11-22 04:19:24 +0000 (Thu, 22 Nov 2018)</dd>
</dl>
<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>WordCamp Reports: Augment WordCamp Counts report with gender breakdowns
This uses the new Genderize.io API client in WordCamp Utilities. However,
the gender breakdowns option in the report UI won't work until the API key
for the service is activated.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsassetscssadmincommoncss">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/css/admin-common.css</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsclassesreportclasswordcampcountsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/report/class-wordcamp-counts.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsviewshtmlwordcampcountsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/html/wordcamp-counts.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsviewsreportwordcampcountsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/report/wordcamp-counts.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsassetscssadmincommoncss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/css/admin-common.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/css/admin-common.css 2018-11-22 04:14:48 UTC (rev 7882)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/css/admin-common.css 2018-11-22 04:19:24 UTC (rev 7883)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -8,10 +8,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> width: auto;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.report-results td.number {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.report-results td.number,
+.report-results span.number {
</ins><span class="cx" style="display: block; padding: 0 10px"> text-align: right;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.report-results td.total {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.report-results td.total,
+.report-results span.total {
</ins><span class="cx" style="display: block; padding: 0 10px"> font-weight: bold;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-}
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+}
+
+.report-results .small {
+ font-size: 0.8em;
+}
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsclassesreportclasswordcampcountsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/report/class-wordcamp-counts.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/report/class-wordcamp-counts.php 2018-11-22 04:14:48 UTC (rev 7882)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/report/class-wordcamp-counts.php 2018-11-22 04:19:24 UTC (rev 7883)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13,6 +13,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use WordCamp\Reports\Utility\Date_Range;
</span><span class="cx" style="display: block; padding: 0 10px"> use function WordCamp\Reports\Validation\{validate_date_range, validate_wordcamp_status, validate_wordcamp_id};
</span><span class="cx" style="display: block; padding: 0 10px"> use WordCamp_Loader;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use WordCamp\Utilities\Genderize_Client;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Class WordCamp_Counts
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -63,6 +64,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><span class="cx" style="display: block; padding: 0 10px"> </li>
</span><span class="cx" style="display: block; padding: 0 10px"> <li>Generate a unique ID for any post that does not have the desired meta value.</li>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <li>If gender breakdowns are included, also retrieve lists of first names for attendees, organizers, and speakers for each WordCamp. Submit these to the Genderize.io API to estimate the gender of each name and get approximate gender breakdowns of each post type.</li>
</ins><span class="cx" style="display: block; padding: 0 10px"> <li>For each post type except Sessions, compile the posts from every WordCamp site into one array and then remove duplicates.</li>
</span><span class="cx" style="display: block; padding: 0 10px"> </ol>
</span><span class="cx" style="display: block; padding: 0 10px"> ";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -89,6 +91,20 @@
</span><span class="cx" style="display: block; padding: 0 10px"> public $statuses = [];
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Whether to include a gender breakdown in relevant counts.
+ *
+ * @var bool
+ */
+ public $include_gender = false;
+
+ /**
+ * Genderize.io client.
+ *
+ * @var Genderize_Client Utility to estimate genders from names.
+ */
+ protected $genderize = null;
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Data fields that can be visible in a public context.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @var array An associative array of key/default value pairs.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -109,15 +125,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * WordCamp_Counts constructor.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @param string $start_date The start of the date range for the report.
- * @param string $end_date The end of the date range for the report.
- * @param array $statuses Optional. Status IDs to filter for in the report.
- * @param array $options {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @param string $start_date The start of the date range for the report.
+ * @param string $end_date The end of the date range for the report.
+ * @param array $statuses Optional. Status IDs to filter for in the report.
+ * @param bool $include_gender Optional. True to include gender breakdowns of relevant counts.
+ * @param array $options {
</ins><span class="cx" style="display: block; padding: 0 10px"> * Optional. Additional report parameters.
</span><span class="cx" style="display: block; padding: 0 10px"> * See Base::__construct and Date_Range::__construct for additional parameters.
</span><span class="cx" style="display: block; padding: 0 10px"> * }
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function __construct( $start_date, $end_date, array $statuses = [], array $options = [] ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function __construct( $start_date, $end_date, array $statuses = [], $include_gender = false, array $options = [] ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> parent::__construct( $options );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> try {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -143,6 +160,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> sort( $this->statuses );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ $this->include_gender = wp_validate_boolean( $include_gender );
+
+ $this->genderize = new Genderize_Client();
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -160,6 +181,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $cache_key_segments[] = implode( '-', $this->statuses );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_gender ) {
+ $cache_key_segments[] = '+gender';
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> return implode( '_', $cache_key_segments );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -175,6 +200,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Query and parse the data for the report.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * TODO Refactor the raw data structure to make it exportable as a CSV, move some of the counting stuff
+ * to compile_report_data().
+ *
</ins><span class="cx" style="display: block; padding: 0 10px"> * @return array
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function get_data() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -252,6 +280,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $totals = [
+ 'attendees' => 0,
+ 'organizers' => 0,
+ 'sessions' => 0,
+ 'speakers' => 0,
+ 'sponsors' => 0,
+ ];
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $uniques = [
</span><span class="cx" style="display: block; padding: 0 10px"> 'attendees' => [],
</span><span class="cx" style="display: block; padding: 0 10px"> 'organizers' => [],
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -259,23 +295,39 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'sponsors' => [],
</span><span class="cx" style="display: block; padding: 0 10px"> ];
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $totals = [
- 'attendees' => 0,
- 'organizers' => 0,
- 'sessions' => 0,
- 'speakers' => 0,
- 'sponsors' => 0,
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $gender_template = [
+ 'female' => 0,
+ 'male' => 0,
+ 'unknown' => 0,
</ins><span class="cx" style="display: block; padding: 0 10px"> ];
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $genders = [
+ 'attendees' => $gender_template,
+ 'organizers' => $gender_template,
+ 'speakers' => $gender_template,
+ ];
+
</ins><span class="cx" style="display: block; padding: 0 10px"> foreach ( $data as $id => &$event ) {
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( $totals as $key => $bucket ) {
</span><span class="cx" style="display: block; padding: 0 10px"> if ( isset( $uniques[ $key ] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $uniques[ $key ] = array_unique( array_merge( $uniques[ $key ], $event[ $key ] ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $uniques[ $key ] = array_unique( array_merge( $uniques[ $key ], $event[ $key ]['total'] ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event[ $key ] = count( $event[ $key ] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_gender && isset( $genders[ $key ] ) ) {
+ $event[ $key ]['gender'] = array_reduce( $event[ $key ]['gender'], function( $carry, $item ) {
+ $carry[ $item ] ++;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $totals[ $key ] += $event[ $key ];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ return $carry;
+ }, $gender_template );
+
+ foreach ( $genders[ $key ] as $gender => &$total ) {
+ $total += $event[ $key ]['gender'][ $gender ];
+ }
+ }
+
+ $event[ $key ]['total'] = count( $event[ $key ]['total'] );
+
+ $totals[ $key ] += $event[ $key ]['total'];
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -285,6 +337,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> return count( $group );
</span><span class="cx" style="display: block; padding: 0 10px"> }, $uniques );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_gender ) {
+ $data['genders'] = $genders;
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $data = $this->filter_data_fields( $data );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->maybe_cache_data( $data );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -294,6 +350,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Compile the report data into results.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * TODO Move some of the logic from get_data into here.
+ *
</ins><span class="cx" style="display: block; padding: 0 10px"> * @param array $data The data to compile.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -315,10 +373,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> array_walk( $data, function( &$row ) use ( $all_statuses ) {
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( $row as $key => $value ) {
</span><span class="cx" style="display: block; padding: 0 10px"> switch ( $key ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- case 'Status':
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ case 'Status' :
</ins><span class="cx" style="display: block; padding: 0 10px"> $row[ $key ] = $all_statuses[ $value ];
</span><span class="cx" style="display: block; padding: 0 10px"> break;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- case 'Start Date (YYYY-mm-dd)':
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ case 'Start Date (YYYY-mm-dd)' :
</ins><span class="cx" style="display: block; padding: 0 10px"> $row[ $key ] = ( $value ) ? date( 'Y-m-d', $value ) : '';
</span><span class="cx" style="display: block; padding: 0 10px"> break;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -346,6 +404,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> switch_to_blog( $site_id );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // The get_locale() function doesn't work inside switch_to_blog because it returns early.
+ $wp_locale = get_site_option( 'WPLANG', 'en_US' );
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $attendees = new WP_Query( [
</span><span class="cx" style="display: block; padding: 0 10px"> 'posts_per_page' => -1,
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_type' => 'tix_attendee',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -352,8 +413,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_status' => 'publish',
</span><span class="cx" style="display: block; padding: 0 10px"> ] );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $site_data['attendees'] = wp_list_pluck( $attendees->posts, 'tix_email', 'ID' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $site_data['attendees']['total'] = wp_list_pluck( $attendees->posts, 'tix_email', 'ID' );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_gender ) {
+ $names = array_map( function( $name ) {
+ return explode( ' ', $name )[0];
+ }, wp_list_pluck( $attendees->posts, 'tix_first_name', 'ID' ) );
+
+ $site_data['attendees']['gender'] = $this->get_genders( $names, $wp_locale );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $organizers = new WP_Query( [
</span><span class="cx" style="display: block; padding: 0 10px"> 'posts_per_page' => -1,
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_type' => 'wcb_organizer',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -360,8 +429,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_status' => 'publish',
</span><span class="cx" style="display: block; padding: 0 10px"> ] );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $site_data['organizers'] = wp_list_pluck( $organizers->posts, '_wcpt_user_id', 'ID' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $site_data['organizers']['total'] = wp_list_pluck( $organizers->posts, '_wcpt_user_id', 'ID' );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_gender ) {
+ $names = array_map( function( $name ) {
+ return explode( ' ', $name )[0];
+ }, wp_list_pluck( $organizers->posts, 'post_title', 'ID' ) );
+
+ $site_data['organizers']['gender'] = $this->get_genders( $names, $wp_locale );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $sessions = new WP_Query( [
</span><span class="cx" style="display: block; padding: 0 10px"> 'posts_per_page' => - 1,
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_type' => 'wcb_session',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -374,7 +451,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> ],
</span><span class="cx" style="display: block; padding: 0 10px"> ] );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $site_data['sessions'] = wp_list_pluck( $sessions->posts, 'ID' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $site_data['sessions']['total'] = wp_list_pluck( $sessions->posts, 'ID' );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $speakers = new WP_Query( [
</span><span class="cx" style="display: block; padding: 0 10px"> 'posts_per_page' => -1,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -382,8 +459,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_status' => 'publish',
</span><span class="cx" style="display: block; padding: 0 10px"> ] );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $site_data['speakers'] = wp_list_pluck( $speakers->posts, '_wcb_speaker_email', 'ID' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $site_data['speakers']['total'] = wp_list_pluck( $speakers->posts, '_wcb_speaker_email', 'ID' );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_gender ) {
+ $names = array_map( function( $name ) {
+ return explode( ' ', $name )[0];
+ }, wp_list_pluck( $speakers->posts, 'post_title', 'ID' ) );
+
+ $site_data['speakers']['gender'] = $this->get_genders( $names, $wp_locale );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $sponsors = new WP_Query( [
</span><span class="cx" style="display: block; padding: 0 10px"> 'posts_per_page' => -1,
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_type' => 'wcb_sponsor',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -390,7 +475,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_status' => 'publish',
</span><span class="cx" style="display: block; padding: 0 10px"> ] );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $site_data['sponsors'] = array_map( function( $url ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $site_data['sponsors']['total'] = array_map( function( $url ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $hostname = wp_parse_url( $url, PHP_URL_HOST );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! $hostname ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -412,7 +497,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // Convert blanks to unique values.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- array_walk( $data, function( &$value, $key ) use ( $site_id ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ array_walk( $data['total'], function( &$value, $key ) use ( $site_id ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( ! $value ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $value = "{$site_id}_{$key}";
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -423,6 +508,42 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Try to detect the genders for a list of first names.
+ *
+ * @param array $names
+ * @param string $locale
+ *
+ * @return array
+ */
+ protected function get_genders( $names, $locale ) {
+ $probability_threshold = (float) 0.9;
+
+ $names = array_map( 'strtolower', $names );
+ $genders = [];
+
+ $gender_data = $this->genderize->get_gender_data( $names, $locale );
+
+ if ( ! empty( $this->genderize->error->get_error_messages() ) ) {
+ $this->merge_errors( $this->error, $this->genderize->error );
+
+ return [];
+ }
+
+ foreach ( $names as $name ) {
+ $data = $gender_data[ $name ];
+
+ if ( ! $data['gender'] || $data['probability'] < $probability_threshold ) {
+ $genders[] = 'unknown';
+ continue;
+ }
+
+ $genders[] = $data['gender'];
+ }
+
+ return $genders;
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Render an HTML version of the report output.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @return void
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -433,6 +554,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $end_date = $this->range->end;
</span><span class="cx" style="display: block; padding: 0 10px"> $statuses = $this->statuses;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_gender ) {
+ $genders = array_pop( $data );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $uniques = array_pop( $data );
</span><span class="cx" style="display: block; padding: 0 10px"> $totals = array_pop( $data );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -449,12 +574,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @return void
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public static function render_admin_page() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $start_date = filter_input( INPUT_POST, 'start-date' );
- $end_date = filter_input( INPUT_POST, 'end-date' );
- $statuses = filter_input( INPUT_POST, 'statuses', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) ?: [];
- $refresh = filter_input( INPUT_POST, 'refresh', FILTER_VALIDATE_BOOLEAN );
- $action = filter_input( INPUT_POST, 'action' );
- $nonce = filter_input( INPUT_POST, self::$slug . '-nonce' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $start_date = filter_input( INPUT_POST, 'start-date' );
+ $end_date = filter_input( INPUT_POST, 'end-date' );
+ $statuses = filter_input( INPUT_POST, 'statuses', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) ?: [];
+ $include_gender = filter_input( INPUT_POST, 'include-gender', FILTER_VALIDATE_BOOLEAN );
+ $refresh = filter_input( INPUT_POST, 'refresh', FILTER_VALIDATE_BOOLEAN );
+ $action = filter_input( INPUT_POST, 'action' );
+ $nonce = filter_input( INPUT_POST, self::$slug . '-nonce' );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $all_statuses = WordCamp_Loader::get_post_statuses();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -473,7 +599,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $options['flush_cache'] = true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $report = new self( $start_date, $end_date, $statuses, $options );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $report = new self( $start_date, $end_date, $statuses, $include_gender, $options );
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> include get_views_dir_path() . 'report/wordcamp-counts.php';
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsviewshtmlwordcampcountsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/html/wordcamp-counts.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/html/wordcamp-counts.php 2018-11-22 04:14:48 UTC (rev 7882)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/html/wordcamp-counts.php 2018-11-22 04:19:24 UTC (rev 7883)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -14,6 +14,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var array $data */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var array $totals */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var array $uniques */
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var array $genders */
+
+$gender_legend = '<span class="description small"><span class="total">Total</span> / F / M / ?</span>';
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> <?php if ( count( $data ) ) : ?>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -33,11 +36,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> </tr>
</span><span class="cx" style="display: block; padding: 0 10px"> </table>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <h4>Totals and Uniques</h4>
+
</ins><span class="cx" style="display: block; padding: 0 10px"> <table class="striped widefat but-not-too-wide">
</span><span class="cx" style="display: block; padding: 0 10px"> <tr>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <td></td>
- <td>Totals</td>
- <td>Uniques</td>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <td>Type</td>
+ <td>Total</td>
+ <td>Unique</td>
</ins><span class="cx" style="display: block; padding: 0 10px"> </tr>
</span><span class="cx" style="display: block; padding: 0 10px"> <tr>
</span><span class="cx" style="display: block; padding: 0 10px"> <td>Attendees</td>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -66,15 +71,52 @@
</span><span class="cx" style="display: block; padding: 0 10px"> </tr>
</span><span class="cx" style="display: block; padding: 0 10px"> </table>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( ! empty( $genders ) ) : ?>
+ <h4>Gender Breakdown</h4>
+
+ <table class="striped widefat but-not-too-wide">
+ <tr>
+ <td>Type</td>
+ <td>Total</td>
+ <td>Female</td>
+ <td>Male</td>
+ <td>Unknown</td>
+ </tr>
+ <tr>
+ <td>Attendees</td>
+ <td class="number"><?php echo number_format_i18n( $totals['attendees'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['attendees']['female'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['attendees']['male'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['attendees']['unknown'] ); ?></td>
+ </tr>
+ <tr>
+ <td>Organizers</td>
+ <td class="number"><?php echo number_format_i18n( $totals['organizers'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['organizers']['female'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['organizers']['male'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['organizers']['unknown'] ); ?></td>
+ </tr>
+ <tr>
+ <td>Speakers</td>
+ <td class="number"><?php echo number_format_i18n( $totals['speakers'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['speakers']['female'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['speakers']['male'] ); ?></td>
+ <td class="number"><?php echo number_format_i18n( $genders['speakers']['unknown'] ); ?></td>
+ </tr>
+ </table>
+ <?php endif; ?>
+
+ <h4>WordCamp Details</h4>
+
</ins><span class="cx" style="display: block; padding: 0 10px"> <table class="striped widefat but-not-too-wide">
</span><span class="cx" style="display: block; padding: 0 10px"> <tr>
</span><span class="cx" style="display: block; padding: 0 10px"> <td>WordCamp</td>
</span><span class="cx" style="display: block; padding: 0 10px"> <td>Date</td>
</span><span class="cx" style="display: block; padding: 0 10px"> <td>Status</td>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <td>Attendees</td>
- <td>Organizers</td>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <td>Attendees<?php if ( ! empty( $genders ) ) : ?><br /><?php echo $gender_legend ?><?php endif; ?></td>
+ <td>Organizers<?php if ( ! empty( $genders ) ) : ?><br /><?php echo $gender_legend ?><?php endif; ?></td>
</ins><span class="cx" style="display: block; padding: 0 10px"> <td>Sessions</td>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <td>Speakers</td>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <td>Speakers<?php if ( ! empty( $genders ) ) : ?><br /><?php echo $gender_legend ?><?php endif; ?></td>
</ins><span class="cx" style="display: block; padding: 0 10px"> <td>Sponsors</td>
</span><span class="cx" style="display: block; padding: 0 10px"> </tr>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php foreach ( $data as $event ) : ?>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -82,11 +124,36 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <td><a href="<?php echo esc_attr( $event['URL'] ); ?>"><?php echo esc_html( $event['Name'] ); ?></a></td>
</span><span class="cx" style="display: block; padding: 0 10px"> <td><?php echo esc_html( $event['Start Date (YYYY-mm-dd)'] ); ?></td>
</span><span class="cx" style="display: block; padding: 0 10px"> <td><?php echo esc_html( $event['Status'] ); ?></td>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <td class="number"><?php echo number_format_i18n( $event['attendees'] ); ?></td>
- <td class="number"><?php echo number_format_i18n( $event['organizers'] ); ?></td>
- <td class="number"><?php echo number_format_i18n( $event['sessions'] ); ?></td>
- <td class="number"><?php echo number_format_i18n( $event['speakers'] ); ?></td>
- <td class="number"><?php echo number_format_i18n( $event['sponsors'] ); ?></td>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <td class="number">
+ <span class="total"><?php echo number_format_i18n( $event['attendees']['total'] ); ?></span>
+ <?php if ( ! empty( $genders ) ) : ?>
+ / <?php echo number_format_i18n( $event['attendees']['gender']['female'] ); ?>
+ / <?php echo number_format_i18n( $event['attendees']['gender']['male'] ); ?>
+ / <?php echo number_format_i18n( $event['attendees']['gender']['unknown'] ); ?>
+ <?php endif; ?>
+ </td>
+ <td class="number">
+ <span class="total"><?php echo number_format_i18n( $event['organizers']['total'] ); ?></span>
+ <?php if ( ! empty( $genders ) ) : ?>
+ / <?php echo number_format_i18n( $event['organizers']['gender']['female'] ); ?>
+ / <?php echo number_format_i18n( $event['organizers']['gender']['male'] ); ?>
+ / <?php echo number_format_i18n( $event['organizers']['gender']['unknown'] ); ?>
+ <?php endif; ?>
+ </td>
+ <td class="number total">
+ <?php echo number_format_i18n( $event['sessions']['total'] ); ?>
+ </td>
+ <td class="number">
+ <span class="total"><?php echo number_format_i18n( $event['speakers']['total'] ); ?></span>
+ <?php if ( ! empty( $genders ) ) : ?>
+ / <?php echo number_format_i18n( $event['speakers']['gender']['female'] ); ?>
+ / <?php echo number_format_i18n( $event['speakers']['gender']['male'] ); ?>
+ / <?php echo number_format_i18n( $event['speakers']['gender']['unknown'] ); ?>
+ <?php endif; ?>
+ </td>
+ <td class="number total">
+ <?php echo number_format_i18n( $event['sponsors']['total'] ); ?>
+ </td>
</ins><span class="cx" style="display: block; padding: 0 10px"> </tr>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php endforeach; ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </table>
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsviewsreportwordcampcountsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/report/wordcamp-counts.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/report/wordcamp-counts.php 2018-11-22 04:14:48 UTC (rev 7882)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/report/wordcamp-counts.php 2018-11-22 04:19:24 UTC (rev 7883)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,6 +12,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var string $start_date */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var string $end_date */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var array $statuses */
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var bool $include_gender */
</ins><span class="cx" style="display: block; padding: 0 10px"> /** @var array $all_statuses */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var Report\WordCamp_Counts|null $report */
</span><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -54,6 +55,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> </td>
</span><span class="cx" style="display: block; padding: 0 10px"> </tr>
</span><span class="cx" style="display: block; padding: 0 10px"> <tr>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <th scope="row"><label for="refresh">Include gender breakdowns</label></th>
+ <td><input type="checkbox" id="include-gender" name="include-gender" <?php checked( $include_gender ); ?> /></td>
+ </tr>
+ <tr>
</ins><span class="cx" style="display: block; padding: 0 10px"> <th scope="row"><label for="refresh">Refresh results</label></th>
</span><span class="cx" style="display: block; padding: 0 10px"> <td><input type="checkbox" id="refresh" name="refresh" /></td>
</span><span class="cx" style="display: block; padding: 0 10px"> </tr>
</span></span></pre>
</div>
</div>
</body>
</html>