<!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>[7550] sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports: WordCamp Reports: Improvements to WordCamp Details report</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/7550">7550</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/7550","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-07-31 04:11:25 +0000 (Tue, 31 Jul 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: Improvements to WordCamp Details report
* Add fields for the totals of Tickets, Speakers, Sponsors, and Organizers for each WordCamp in the data set.
* Add UI for selecting which fields will be included in the spreadsheet
* Make sure cached data sets are differentiated by whether they include dateless WordCamps and/or post counts</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsclassesreportclasswordcampdetailsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/report/class-wordcamp-details.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsclassesutilityclassdaterangephp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/utility/class-date-range.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsincludestimephp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/includes/time.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsviewsreportwordcampdetailsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/report/wordcamp-details.php</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsassetscsswordcampdetailscss">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/css/wordcamp-details.css</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsassetsjswordcampdetailsjs">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/js/wordcamp-details.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsassetscsswordcampdetailscss"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/css/wordcamp-details.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/wordcamp-details.css (rev 0)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/css/wordcamp-details.css 2018-07-31 04:11:25 UTC (rev 7550)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,75 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.fields-container {
+ background-color: #fff;
+ border: 1px solid #e5e5e5;
+ box-shadow: 0 1px 1px rgba(0,0,0,.04);
+ position: relative;
+ margin: 55px 0 30px;
+}
+
+.field-checkbox:nth-child(2n+2) {
+ background-color: #f9f9f9;
+}
+
+@media screen and ( min-width: 450px ) {
+ .fields-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ }
+ .field-checkbox:nth-child(2n+2) {
+ background-color: transparent;
+ }
+ .field-checkbox:nth-child(4n+2),
+ .field-checkbox:nth-child(4n+3) {
+ background-color: #f9f9f9;
+ }
+}
+
+@media screen and ( min-width: 700px ) {
+ .fields-container {
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+ }
+ .field-checkbox:nth-child(4n+2),
+ .field-checkbox:nth-child(4n+3) {
+ background-color: transparent;
+ }
+ .field-checkbox:nth-child(8n+2),
+ .field-checkbox:nth-child(8n+3),
+ .field-checkbox:nth-child(8n+4),
+ .field-checkbox:nth-child(8n+5) {
+ background-color: #f9f9f9;
+ }
+}
+
+.fields-label {
+ text-align: left;
+ line-height: 1.3;
+ font-weight: 600;
+ font-size: 14px;
+ padding: 20px 10px 20px 0;
+ position: absolute;
+ top: -55px;
+}
+
+.fields-checkall {
+ display: inline-block;
+ margin-left: 3em;
+ font-size: 12px;
+ font-weight: normal;
+ font-style: italic;
+}
+
+.field-checkbox {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding: 1.5em 0;
+}
+
+.fields-container input[type="checkbox"] {
+ flex: 1;
+}
+
+.fields-container label {
+ flex: 4;
+}
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsassetsjswordcampdetailsjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/js/wordcamp-details.js</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/js/wordcamp-details.js (rev 0)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/assets/js/wordcamp-details.js 2018-07-31 04:11:25 UTC (rev 7550)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,74 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+( function( window, $ ) {
+
+ 'use strict';
+
+ var WordCampDetails = window.WordCampDetails || {};
+
+ $.extend( WordCampDetails, {
+ /**
+ * Initialize the script.
+ */
+ init: function() {
+ var self = this;
+
+ this.cache = {
+ $container: $( '.fields-container' ),
+ $control: $()
+ };
+
+ self.cache.$control = self.createControl();
+
+ $( document ).ready( function() {
+ self.cache.$container.find( 'legend' ).append( self.cache.$control );
+ } );
+ },
+
+ /**
+ * Create the elements for the checkbox control that will toggle all of the checkboxes in the form.
+ *
+ * @return {jQuery} The object for the control component.
+ */
+ createControl: function() {
+ var self = this,
+ $input, $control;
+
+ $input = $( '<input>' )
+ .attr( 'type', 'checkbox' )
+ ;
+
+ $input.on( 'change', function( event ) {
+ var $target = $( event.target );
+
+ self.toggleCheckboxes( $target );
+ } );
+
+ $control = $( '<label>' )
+ .addClass( 'fields-checkall' )
+ .text( 'Check all' )
+ .prepend( $input )
+ ;
+
+ return $control;
+ },
+
+ /**
+ * Perform the checking/unchecking of all the checkboxes.
+ *
+ * @param {jQuery} $target The control.
+ */
+ toggleCheckboxes: function( $target ) {
+ var $container = $target.parents( '.fields-container' ),
+ $checkboxes = $container.find( 'input[type="checkbox"]' ).not( ':disabled' );
+
+ if ( $target.is( ':checked' ) ) {
+ $checkboxes.prop( 'checked', true );
+ } else {
+ $checkboxes.prop( 'checked', false );
+ }
+ }
+ } );
+
+ WordCampDetails.init();
+
+} )( window, jQuery );
</ins></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsclassesreportclasswordcampdetailsphp"></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-details.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-details.php 2018-07-31 04:04:38 UTC (rev 7549)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/report/class-wordcamp-details.php 2018-07-31 04:11:25 UTC (rev 7550)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -8,12 +8,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> use Exception;
</span><span class="cx" style="display: block; padding: 0 10px"> use DateTime;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use WP_Post;
-use WordCamp\Reports;
-use WordCamp\Reports\Report\WordCamp_Status;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use WP_Post, WP_Query;
+use function WordCamp\Reports\{get_assets_url, get_assets_dir_path, get_views_dir_path};
</ins><span class="cx" style="display: block; padding: 0 10px"> use WordCamp\Reports\Utility\Date_Range;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use function WordCamp\Reports\Validation\{validate_date_range, validate_wordcamp_status};
-use function WordCamp\Reports\Time\modify_cache_expiration_for_date_range;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use function WordCamp\Reports\Validation\{validate_date_range, validate_wordcamp_id, validate_wordcamp_status};
</ins><span class="cx" style="display: block; padding: 0 10px"> use WordCamp_Admin, WordCamp_Loader;
</span><span class="cx" style="display: block; padding: 0 10px"> use WordCamp\Utilities\Export_CSV;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -54,7 +52,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> public static $methodology = "
</span><span class="cx" style="display: block; padding: 0 10px"> <ol>
</span><span class="cx" style="display: block; padding: 0 10px"> <li>Retrieve WordCamp posts that fit within the date range and other optional criteria.</li>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <li>Extract the post meta values for each post that match the fields requested.</li>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <li>Extract the data for each post that match the fields requested.</li>
</ins><span class="cx" style="display: block; padding: 0 10px"> <li>Walk all of the extracted data and format it for display.</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">@@ -81,13 +79,20 @@
</span><span class="cx" style="display: block; padding: 0 10px"> public $status = '';
</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">- * The fields to include in the report output.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Whether to include data for WordCamps that don't have a date set.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @var array
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @var bool
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public $fields = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public $include_dateless = false;
</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">+ * Whether to include counts of various post types for each WordCamp.
+ *
+ * @var bool
+ */
+ public $include_counts = false;
+
+ /**
</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">@@ -104,22 +109,25 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * WordCamp_Details 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 string $status Optional. The status ID to filter for in the report.
- * @param array $fields Not implemented yet.
- * @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 string $status Optional. The status ID to filter for in the report.
+ * @param bool $include_dateless Optional. True to include data for WordCamps that don't have a date set. Default false.
+ * @param bool $include_counts Optional. True to include counts of various post types for each WordCamp. Default false.
+ * @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 the functions in WordCamp\Reports\Validation for additional parameters.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @type bool $include_dateless True to include WordCamps that don't have a date set. Default false.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @type array $status_subset A list of valid status IDs.
+ * @type array $fields Not implemented yet.
</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">- public function __construct( $start_date, $end_date, $status = '', array $fields = [], array $options = [] ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function __construct( $start_date, $end_date, $status = '', $include_dateless = false, $include_counts = false, array $options = [] ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> // Report-specific options.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $options = wp_parse_args( $options, array(
- 'include_dateless' => false,
- ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $options = wp_parse_args( $options, [
+ 'status_subset' => [],
+ 'fields' => [],
+ ] );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><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="lines" style="display: block; padding: 0 10px; color: #888">@@ -143,8 +151,32 @@
</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">+ $this->include_dateless = wp_validate_boolean( $include_dateless );
+ $this->include_counts = wp_validate_boolean( $include_counts );
+
+ $public_data_field_keys = array_merge(
+ [
+ 'Name',
+ 'Status',
+ ],
+ WordCamp_Loader::get_public_meta_keys()
+ );
+ $this->public_data_fields = array_fill_keys( $public_data_field_keys, '' );
+
+ $private_data_field_keys = array_merge(
+ [
+ 'ID',
+ 'Tickets',
+ 'Speakers',
+ 'Sponsors',
+ 'Organizers',
+ ],
+ array_diff( $this->get_meta_keys(), array_keys( $this->public_data_fields ) )
+ );
+ $this->private_data_fields = array_fill_keys( $private_data_field_keys, '' );
+
</ins><span class="cx" style="display: block; padding: 0 10px"> try {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->fields = $this->validate_fields_input( $fields );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->options['fields'] = $this->validate_fields_input( $this->options['fields'] );
</ins><span class="cx" style="display: block; padding: 0 10px"> } catch ( Exception $e ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $this->error->add(
</span><span class="cx" style="display: block; padding: 0 10px"> self::$slug . '-fields-error',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -151,29 +183,32 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $e->getMessage()
</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">-
- $this->public_data_fields = array_fill_keys( array_merge(
- [
- 'ID',
- 'Name',
- 'Status',
- ],
- WordCamp_Loader::get_public_meta_keys()
- ), '' );
-
- $this->private_data_fields = array_fill_keys( array_diff(
- $this->get_meta_keys(),
- array_keys( $this->public_data_fields )
- ), '' );
</del><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">- * TODO
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Check the array of fields to include in the spreadsheet against the safelist of data fields.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $fields
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ *
+ * @return array The validated fields.
+ * @throws Exception
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- protected function validate_fields_input( array $fields ) {}
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ protected function validate_fields_input( array $fields ) {
+ $valid_fields = $this->get_data_fields_safelist();
+ $fields = array_unique( $fields );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $fields as $field ) {
+ if ( ! array_key_exists( $field, $valid_fields ) ) {
+ throw new Exception( sprintf(
+ 'Invalid field: %s',
+ esc_html( $field )
+ ) );
+ }
+ }
+
+ return $fields;
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Generate a cache key.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -180,13 +215,24 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @return string
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> protected function get_cache_key() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $cache_key = parent::get_cache_key() . '_' . $this->range->start->getTimestamp() . '-' . $this->range->end->getTimestamp();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $cache_key_segments = [
+ parent::get_cache_key(),
+ $this->range->generate_cache_key_segment(),
+ ];
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> if ( $this->status ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $cache_key .= '_' . $this->status;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $cache_key_segments[] = $this->status;
</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">- return $cache_key;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_dateless ) {
+ $cache_key_segments[] = '+dateless';
+ }
+
+ if ( $this->include_counts ) {
+ $cache_key_segments[] = '+counts';
+ }
+
+ return implode( '_', $cache_key_segments );
</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">@@ -195,23 +241,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @return int A time interval in seconds.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> protected function get_cache_expiration() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $original_expiration = parent::get_cache_expiration();
-
- try {
- $expiration = modify_cache_expiration_for_date_range(
- $original_expiration,
- $this->range
- );
- } catch ( Exception $e ) {
- $this->error->add(
- self::$slug . '-cache-error',
- $e->getMessage()
- );
-
- return $original_expiration;
- }
-
- return $expiration;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ return $this->range->generate_cache_duration( parent::get_cache_expiration() );
</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">@@ -236,10 +266,17 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $wordcamp_posts = $this->get_wordcamp_posts();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( $wordcamp_posts as $post ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $data[] = $this->extract_wordcamp_fields( $post );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $data[] = $this->fill_data_row( $post );
</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"> $data = $this->filter_data_fields( $data );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ // Reorder of the fields in each row.
+ $field_order = array_fill_keys( self::get_field_order(), '' );
+ array_walk( $data, function( &$row ) use ( $field_order ) {
+ $row = array_intersect_key( array_replace( $field_order, $row ), $row );
+ } );
+
</ins><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="cx" style="display: block; padding: 0 10px"> return $data;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -259,6 +296,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">+ * Get the full list of fields in the order they should appear in.
+ *
+ * @return array
+ */
+ protected static function get_field_order() {
+ /* @var WordCamp_Admin $wordcamp_admin */
+ global $wordcamp_admin;
+
+ return array_merge(
+ [
+ 'ID',
+ 'Name',
+ ],
+ array_keys( $wordcamp_admin->meta_keys( 'wordcamp' ) ),
+ [
+ 'Status',
+ 'Tickets',
+ 'Speakers',
+ 'Sponsors',
+ 'Organizers',
+ ],
+ array_keys( $wordcamp_admin->meta_keys( 'contributor' ) ),
+ array_keys( $wordcamp_admin->meta_keys( 'organizer' ) ),
+ array_keys( $wordcamp_admin->meta_keys( 'venue' ) ),
+ [
+ '_venue_coordinates',
+ '_venue_city',
+ '_venue_state',
+ '_venue_country_code',
+ '_venue_country_name',
+ '_venue_zip',
+ ]
+ );
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Format the data for human-readable display.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $data The data to prepare.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -270,10 +343,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( ! in_array( $key, $this->options['fields'], true ) ) {
+ unset( $row[ $key ] );
+ continue;
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> switch ( $key ) {
</span><span class="cx" style="display: block; padding: 0 10px"> case 'Status':
</span><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ case 'Tickets':
+ case 'Speakers':
+ case 'Sponsors':
+ case 'Organizers':
+ $row[ $key ] = number_format_i18n( $value );
+ break;
</ins><span class="cx" style="display: block; padding: 0 10px"> case 'Start Date (YYYY-mm-dd)':
</span><span class="cx" style="display: block; padding: 0 10px"> case 'End Date (YYYY-mm-dd)':
</span><span class="cx" style="display: block; padding: 0 10px"> case 'Contributor Day Date (YYYY-mm-dd)':
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -320,7 +404,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">- if ( $this->options['include_dateless'] ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $this->include_dateless ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $post_args['meta_query'] = array_merge( $post_args['meta_query'], [
</span><span class="cx" style="display: block; padding: 0 10px"> 'relation' => 'OR',
</span><span class="cx" style="display: block; padding: 0 10px"> [
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -333,6 +417,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'value' => '',
</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">+
+ // Don't include really old camps with no date or ones that didn't exist during the date range.
+ $post_args['date_query'] = [
+ [
+ 'before' => $this->range->end->format( 'Y-m-d' ),
+ 'after' => $this->range->start->format( 'Y-m-d' ) . ' - 1 year',
+ ],
+ ];
</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"> if ( $this->options['public'] ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -366,8 +458,8 @@
</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="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- protected function extract_wordcamp_fields( WP_Post $wordcamp ) {
- $meta_keys = $this->get_meta_keys();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ protected function fill_data_row( WP_Post $wordcamp ) {
+ $meta_keys = $this->get_meta_keys();
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $row = [
</span><span class="cx" style="display: block; padding: 0 10px"> 'ID' => $wordcamp->ID,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -375,6 +467,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'Status' => $wordcamp->post_status,
</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_counts ) {
+ $row = array_merge( $row, $this->get_counts( $wordcamp ) );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> foreach ( $meta_keys as $key ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $row[ $key ] = get_post_meta( $wordcamp->ID, $key, true ) ?: '';
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -403,6 +499,90 @@
</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">+ * Count the number of various post types for a WordCamp.
+ *
+ * @param WP_Post $wordcamp
+ *
+ * @return array
+ */
+ protected function get_counts( WP_Post $wordcamp ) {
+ $counts = [
+ 'Tickets' => 0,
+ 'Speakers' => 0,
+ 'Sponsors' => 0,
+ 'Organizers' => 0,
+ ];
+
+ try {
+ $ids = validate_wordcamp_id( $wordcamp->ID, [ 'require_site' => true ] );
+ } catch ( Exception $e ) {
+ return $counts;
+ }
+
+ $get_count = function( $post_type ) {
+ $posts = new WP_Query( [
+ 'posts_per_page' => 1, // Only need to fetch 1 to populate total number in found_posts.
+ 'post_type' => $post_type,
+ 'post_status' => 'publish',
+ ] );
+
+ return absint( $posts->found_posts );
+ };
+
+ switch_to_blog( $ids['site_id'] );
+
+ // Tickets
+ $stats = get_option( 'camptix_stats' );
+ if ( isset( $stats['sold'] ) && ! empty( $stats['sold'] ) ) {
+ $counts['Tickets'] = absint( $stats['sold'] );
+ }
+
+ // Others
+ $counts['Speakers'] = $get_count( 'wcb_speaker' );
+ $counts['Sponsors'] = $get_count( 'wcb_sponsor' );
+ $counts['Organizers'] = $get_count( 'wcb_organizer' );
+
+ restore_current_blog();
+
+ return $counts;
+ }
+
+ /**
+ * Register all assets used by this report.
+ *
+ * @return void
+ */
+ protected static function register_assets() {
+ wp_register_script(
+ self::$slug,
+ get_assets_url() . 'js/' . self::$slug . '.js',
+ array(),
+ filemtime( get_assets_dir_path() . 'js/' . self::$slug . '.js' ),
+ true
+ );
+
+ wp_register_style(
+ self::$slug,
+ get_assets_url() . 'css/' . self::$slug . '.css',
+ array(),
+ filemtime( get_assets_dir_path() . 'css/' . self::$slug . '.css' ),
+ 'screen'
+ );
+ }
+
+ /**
+ * Enqueue JS and CSS assets for this report's admin interface.
+ *
+ * @return void
+ */
+ public static function enqueue_admin_assets() {
+ self::register_assets();
+
+ wp_enqueue_script( self::$slug );
+ wp_enqueue_style( self::$slug );
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Render the page for this report in the WP Admin.
</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">@@ -417,7 +597,20 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $nonce = filter_input( INPUT_POST, self::$slug . '-nonce' );
</span><span class="cx" style="display: block; padding: 0 10px"> $statuses = WordCamp_Loader::get_post_statuses();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- include Reports\get_views_dir_path() . 'report/wordcamp-details.php';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $field_order = array_fill_keys( self::get_field_order(), '' );
+ $field_defaults = array_replace( $field_order, [
+ 'ID' => 'checked',
+ 'Name' => 'checked disabled',
+ 'Start Date (YYYY-mm-dd)' => 'checked',
+ 'End Date (YYYY-mm-dd)' => 'checked',
+ 'Location' => 'checked',
+ 'URL' => 'checked',
+ ] );
+
+ $shadow_report = new self( '', '', '', false, false, [ 'public' => false ] );
+ $available_fields = array_intersect_key( $field_defaults, $shadow_report->get_data_fields_safelist() );
+
+ include get_views_dir_path() . 'report/wordcamp-details.php';
</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">@@ -430,6 +623,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $end_date = filter_input( INPUT_POST, 'end-date' );
</span><span class="cx" style="display: block; padding: 0 10px"> $include_dateless = filter_input( INPUT_POST, 'include_dateless', FILTER_VALIDATE_BOOLEAN );
</span><span class="cx" style="display: block; padding: 0 10px"> $status = filter_input( INPUT_POST, 'status' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $fields = filter_input( INPUT_POST, 'fields', FILTER_SANITIZE_STRING, [ 'flags' => FILTER_REQUIRE_ARRAY ] );
</ins><span class="cx" style="display: block; padding: 0 10px"> $refresh = filter_input( INPUT_POST, 'refresh', FILTER_VALIDATE_BOOLEAN );
</span><span class="cx" style="display: block; padding: 0 10px"> $action = filter_input( INPUT_POST, 'action' );
</span><span class="cx" style="display: block; padding: 0 10px"> $nonce = filter_input( INPUT_POST, self::$slug . '-nonce' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -441,10 +635,19 @@
</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"> if ( wp_verify_nonce( $nonce, 'run-report' ) && current_user_can( 'manage_network' ) ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $include_counts = false;
+ if ( ! empty( array_intersect( $fields, [ 'Tickets', 'Speakers', 'Sponsors', 'Organizers' ] ) ) ) {
+ $include_counts = true;
+ }
+
+ // The "Name" field should always be included, but does not get submitted because the input is disabled,
+ // so add it in here.
+ $fields[] = 'Name';
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $options = array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'public' => false,
- 'include_dateless' => $include_dateless,
- 'earliest_start' => new DateTime( '2006-01-01' ), // No WordCamp posts before 2006.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'fields' => $fields,
+ 'public' => false,
+ 'earliest_start' => new DateTime( '2006-01-01' ), // No WordCamp posts before 2006.
</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"> if ( $status ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -455,7 +658,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, $status, [], $options );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $report = new self( $start_date, $end_date, $status, $include_dateless, $include_counts, $options );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $filename = [ $report::$name ];
</span><span class="cx" style="display: block; padding: 0 10px"> $filename[] = $report->range->start->format( 'Y-m-d' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -463,6 +666,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> if ( $report->status ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $filename[] = $report->status;
</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 ( $report->include_dateless ) {
+ $filename[] = 'include-dateless';
+ }
+ if ( $report->include_counts ) {
+ $filename[] = 'include-counts';
+ }
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $data = $report->prepare_data_for_display( $report->get_data() );
</span><span class="cx" style="display: block; padding: 0 10px">
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsclassesutilityclassdaterangephp"></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/utility/class-date-range.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/utility/class-date-range.php 2018-07-31 04:04:38 UTC (rev 7549)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/classes/utility/class-date-range.php 2018-07-31 04:11:25 UTC (rev 7550)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3,7 +3,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> namespace WordCamp\Reports\Utility;
</span><span class="cx" style="display: block; padding: 0 10px"> defined( 'WPINC' ) || die();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use DateTimeInterface, DateInterval;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Exception;
+use DateTimeInterface, DateTime, DateTimeImmutable, DateInterval;
</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 Date_Range
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13,7 +14,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * The start date of the range.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @var DateTimeInterface|null
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @var DateTimeImmutable|null
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public $start = null;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20,7 +21,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * The end date of the range.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @var DateTimeInterface|null
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @var DateTimeImmutable|null
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public $end = null;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38,8 +39,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @param DateTimeInterface $end
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function __construct( DateTimeInterface $start, DateTimeInterface $end ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->start = $start;
- $this->end = $end;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $start instanceof DateTime ) {
+ $start = DateTimeImmutable::createFromMutable( $start );
+ }
+ $this->start = $start;
+
+ if ( $end instanceof DateTime ) {
+ $end = DateTimeImmutable::createFromMutable( $end );
+ }
+ $this->end = $end;
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $this->interval = $end->diff( $start );
</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">@@ -53,4 +62,40 @@
</span><span class="cx" style="display: block; padding: 0 10px"> public function is_within( DateTimeInterface $date ) {
</span><span class="cx" style="display: block; padding: 0 10px"> return $date >= $this->start && $date <= $this->end;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ /**
+ * Generate a standardized string representation of the date range for use in a cache key.
+ *
+ * @return string
+ */
+ public function generate_cache_key_segment() {
+ return $this->start->getTimestamp() . '-' . $this->end->getTimestamp();
+ }
+
+ /**
+ * Modify a cache key duration based on the date range compared to the current time.
+ *
+ * @param int $duration Duration of cache key in seconds.
+ *
+ * @return int
+ */
+ public function generate_cache_duration( $duration ) {
+ try {
+ $now = new DateTimeImmutable( 'now' );
+ } catch ( Exception $e ) {
+ return $duration;
+ }
+
+ $now->setTime( 0, 0, 0 ); // Beginning of the current day.
+
+ if ( $this->is_within( $now ) ) {
+ // Expire the cache sooner if the data includes the current day.
+ $duration = HOUR_IN_SECONDS;
+ } elseif ( $this->end->diff( $now )->y > 0 ) {
+ // Keep the cache longer if the end of the date range is over a year ago.
+ $duration = MONTH_IN_SECONDS;
+ }
+
+ return $duration;
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsincludestimephp"></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/includes/time.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/includes/time.php 2018-07-31 04:04:38 UTC (rev 7549)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/includes/time.php 2018-07-31 04:11:25 UTC (rev 7550)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4,8 +4,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> defined( 'WPINC' ) || die();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> use Exception;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use DateTimeImmutable;
</del><span class="cx" style="display: block; padding: 0 10px"> use WordCamp\Reports\Utility\Date_Range;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use function WordCamp\Reports\Validation\validate_date_range;
</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"> * Generate a simple array of years.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -105,10 +105,9 @@
</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"> try {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $range = new Date_Range(
- new DateTimeImmutable( $start_date ),
- new DateTimeImmutable( $end_date )
- );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $range = validate_date_range( $start_date, $end_date, [
+ 'allow_future_start' => true,
+ ] );
</ins><span class="cx" style="display: block; padding: 0 10px"> } catch ( Exception $e ) {
</span><span class="cx" style="display: block; padding: 0 10px"> throw new Exception( sprintf(
</span><span class="cx" style="display: block; padding: 0 10px"> 'Invalid range: %s',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -118,27 +117,3 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> return $range;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-/**
- * Change the expiration time interval based on the current date/time relative to a date range.
- *
- * @param int $expiration A time interval in seconds.
- * @param Date_Range $range
- *
- * @return int A (possibly) modified time interval in seconds.
- * @throws Exception
- */
-function modify_cache_expiration_for_date_range( $expiration, Date_Range $range ) {
- $now = new DateTimeImmutable( 'now' );
- $now->setTime( 0, 0, 0 ); // Beginning of the current day.
-
- if ( $range->is_within( $now ) ) {
- // Expire the cache sooner if the data includes the current day.
- $expiration = HOUR_IN_SECONDS;
- } elseif ( $range->end->diff( $now )->y > 0 ) {
- // Keep the cache longer if the end of the date range is over a year ago.
- $expiration = MONTH_IN_SECONDS;
- }
-
- return $expiration;
-}
</del></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswordcampreportsviewsreportwordcampdetailsphp"></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-details.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-details.php 2018-07-31 04:04:38 UTC (rev 7549)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-reports/views/report/wordcamp-details.php 2018-07-31 04:11:25 UTC (rev 7550)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -14,6 +14,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var bool $include_dateless */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var string $status */
</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 array $available_fields */
</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"> <div class="wrap">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -65,6 +66,25 @@
</span><span class="cx" style="display: block; padding: 0 10px"> </tbody>
</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">+ <fieldset class="fields-container">
+ <legend class="fields-label">Available Fields</legend>
+
+ <?php foreach ( $available_fields as $field_name => $extra_props ) : ?>
+ <div class="field-checkbox">
+ <input
+ type="checkbox"
+ id="fields-<?php echo esc_attr( $field_name ); ?>"
+ name="fields[]"
+ value="<?php echo esc_attr( $field_name ); ?>"
+ <?php if ( $extra_props && is_string( $extra_props ) ) echo esc_html( $extra_props ); ?>
+ />
+ <label for="fields-<?php echo esc_attr( $field_name ); ?>">
+ <?php echo esc_attr( $field_name ); ?>
+ </label>
+ </div>
+ <?php endforeach; ?>
+ </fieldset>
+
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php submit_button( 'Export CSV', 'primary', 'action', false ); ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </form>
</span><span class="cx" style="display: block; padding: 0 10px"> </div>
</span></span></pre>
</div>
</div>
</body>
</html>