PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.5.0
Independent Analytics – WordPress Analytics Plugin v2.5.0
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / IAWP / Email_Reports.php
independent-analytics / IAWP Last commit date
AJAX 2 years ago Admin_Page 2 years ago Custom_WordPress_Columns 2 years ago Date_Range 2 years ago Filter_Lists 2 years ago Form_Submissions 2 years ago Interval 2 years ago Menu_Bar_Stats 2 years ago Migrations 2 years ago Models 2 years ago Public_API 2 years ago Rows 2 years ago Statistics 2 years ago Tables 2 years ago Utils 2 years ago Campaign_Builder.php 2 years ago Capability_Manager.php 2 years ago Chart.php 2 years ago Chart_Geo.php 2 years ago Cron_Manager.php 2 years ago Current_Traffic_Finder.php 2 years ago Dashboard_Options.php 2 years ago Dashboard_Widget.php 2 years ago Database.php 2 years ago Database_Manager.php 2 years ago Email_Chart.php 2 years ago Email_Reports.php 2 years ago Empty_Report_Option.php 2 years ago Env.php 2 years ago Filters.php 2 years ago Form.php 2 years ago Geo_Database_Background_Job.php 2 years ago Geo_Database_Manager.php 2 years ago Geoposition.php 2 years ago Icon_Directory.php 2 years ago Icon_Directory_Factory.php 2 years ago Illuminate_Builder.php 2 years ago Independent_Analytics.php 2 years ago Interrupt.php 2 years ago Known_Referrers.php 2 years ago Plugin_Conflict_Detector.php 2 years ago Plugin_Group.php 2 years ago Plugin_Group_Option.php 2 years ago Query.php 2 years ago Quick_Stat.php 2 years ago Quick_Stats.php 2 years ago REST_API.php 2 years ago Real_Time.php 2 years ago Report.php 2 years ago Report_Finder.php 2 years ago Report_Options_Parser.php 2 years ago Resource_Identifier.php 2 years ago Settings.php 2 years ago Sort_Configuration.php 2 years ago Track_Resource_Changes.php 2 years ago View.php 2 years ago View_Counter.php 2 years ago Visitors_Over_Time_Finder.php 2 years ago WP_Option_Cache_Bust.php 2 years ago WooCommerce_Order.php 2 years ago WooCommerce_Referrer_Meta_Box.php 2 years ago
Email_Reports.php
248 lines
1 <?php
2
3 namespace IAWP;
4
5 use DateTime;
6 use IAWP\Date_Range\Exact_Date_Range;
7 use IAWP\Date_Range\Relative_Date_Range;
8 use IAWP\Rows\Campaigns;
9 use IAWP\Rows\Countries;
10 use IAWP\Rows\Device_Types;
11 use IAWP\Rows\Pages;
12 use IAWP\Rows\Referrers;
13 use IAWP\Statistics\Intervals\Hourly;
14 use IAWP\Statistics\Page_Statistics;
15 use IAWP\Utils\URL;
16 use IAWPSCOPED\Proper\Timezone;
17 /** @internal */
18 class Email_Reports
19 {
20 public function __construct()
21 {
22 \add_filter('cron_schedules', [$this, 'add_monthly_schedule_cron']);
23 $monitored_options = ['iawp_email_report_interval', 'iawp_email_report_time', 'iawp_email_report_email_addresses'];
24 foreach ($monitored_options as $option) {
25 \add_action('update_option_' . $option, [$this, 'schedule_email_report'], 10, 0);
26 \add_action('add_option_' . $option, [$this, 'schedule_email_report'], 10, 0);
27 }
28 // Maybe reschedule when starting day of the week is changed
29 \add_action('update_option_iawp_dow', [$this, 'maybe_reschedule_email_report'], 10, 0);
30 \add_action('add_option_iawp_dow', [$this, 'maybe_reschedule_email_report'], 10, 0);
31 \add_action('iawp_send_email_report', [$this, 'send_email_report']);
32 }
33 public function schedule_email_report()
34 {
35 $this->unschedule_email_report();
36 if (empty(\IAWPSCOPED\iawp()->get_option('iawp_email_report_email_addresses', []))) {
37 return;
38 }
39 $interval = \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly');
40 $delivery_time = $this->get_delivery_time();
41 \wp_schedule_event($delivery_time->getTimestamp(), $interval, 'iawp_send_email_report');
42 }
43 public function get_delivery_time()
44 {
45 $interval = \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly');
46 $date_string = 'first day of +1 month';
47 if ($interval == 'weekly') {
48 $first_dow = \IAWPSCOPED\iawp()->get_option('iawp_dow', 0);
49 $date_string = 'next ' . $this->days_of_week()[$first_dow];
50 } elseif ($interval == 'daily') {
51 $date_string = 'tomorrow';
52 }
53 $delivery_time = new DateTime($date_string, new \DateTimeZone(\wp_timezone_string()));
54 $delivery_time->setTime(\IAWPSCOPED\iawp()->get_option('iawp_email_report_time', 9), 0);
55 return $delivery_time;
56 }
57 public function unschedule_email_report()
58 {
59 $timestamp = \wp_next_scheduled('iawp_send_email_report');
60 \wp_unschedule_event($timestamp, 'iawp_send_email_report');
61 }
62 /* $use_cron is normally true so we report on the date from the cron event.
63 ** It is set to false for testing purposes. This allows the date to be reconstructed and compared to the cron event date */
64 public function get_next_scheduled_email_date_formatted($use_cron = \true)
65 {
66 if (!\wp_next_scheduled('iawp_send_email_report')) {
67 return \esc_html__('There is no email scheduled.', 'independent-analytics');
68 }
69 if ($use_cron) {
70 $date = new DateTime('now', new \DateTimeZone(\wp_timezone_string()));
71 $date->setTimestamp(\wp_next_scheduled('iawp_send_email_report'));
72 $date->setTime(\IAWPSCOPED\iawp()->get_option('iawp_email_report_time', 9), 0);
73 } else {
74 $date = $this->get_delivery_time();
75 }
76 $day = $date->format(\get_option('date_format'));
77 $time = $date->format(\get_option('time_format'));
78 return \sprintf(\__('Next email scheduled for %s at %s.', 'independent-analytics'), '<span>' . $day . '</span>', '<span>' . $time . '</span>');
79 }
80 public function add_monthly_schedule_cron($schedules)
81 {
82 $schedules['monthly'] = ['interval' => \MONTH_IN_SECONDS, 'display' => \esc_html__('Once a Month', 'independent-analytics')];
83 return $schedules;
84 }
85 public function maybe_reschedule_email_report()
86 {
87 if (!\wp_next_scheduled('iawp_send_email_report')) {
88 return;
89 }
90 if (\IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly') != 'weekly') {
91 return;
92 }
93 $this->schedule_email_report();
94 }
95 public function send_email_report(bool $is_test_email = \false)
96 {
97 // This code was added to fix an issue with monthly email reports. When you set up a monthly
98 // email report, the first email will always be correct because we pick the exact timestamp
99 // we want to send it. The issue is with the recurring interval. It's backed by MONTH_IN_SECONDS
100 // which is a fixed constant. Months have a varying number of seconds so this caused slight
101 // differences in when subsequent monthly email reports were sent. The code below fixes this by
102 // rescheduling monthly email reports as they're sent. That allows us to pinpoint the exact
103 // correct next time to run it, while still falling back to the inaccurate monthly interval
104 // should a given email never send for some reason.
105 if (\IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly') === 'monthly') {
106 $this->schedule_email_report();
107 }
108 $to = \IAWPSCOPED\iawp()->get_option('iawp_email_report_email_addresses', []);
109 if (empty($to)) {
110 return;
111 }
112 $body = $this->get_email_body();
113 $headers[] = 'From: ' . \get_bloginfo('name') . ' <' . \get_bloginfo('admin_email') . '>';
114 $headers[] = 'Content-Type: text/html; charset=UTF-8';
115 return \wp_mail($to, $this->subject_line($is_test_email), $body, $headers);
116 }
117 public function get_email_preview($colors)
118 {
119 return $this->get_email_body($colors);
120 }
121 private function days_of_week()
122 {
123 return ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
124 }
125 private function subject_line(bool $is_test_email) : string
126 {
127 $subject_line = \__('Analytics Report for', 'independent-analytics');
128 $subject_line .= ' ' . \get_bloginfo('name') . ' ';
129 if ($is_test_email) {
130 $subject_line = \__('[Test]', 'independent-analytics') . ' ' . $subject_line;
131 }
132 switch ($this->interval()) {
133 case 'daily':
134 $yesterday = new Relative_Date_Range('YESTERDAY');
135 $date_text = $yesterday->start()->format('l, M jS');
136 break;
137 case 'weekly':
138 $last_week = new Relative_Date_Range('LAST_WEEK');
139 $date_text = \__('Week of', 'independent-analytics') . ' ' . $last_week->start()->format('l, M jS');
140 break;
141 default:
142 $last_month = new Relative_Date_Range('LAST_MONTH');
143 $date_text = $last_month->start()->format('F Y');
144 break;
145 }
146 return \esc_html($subject_line . '[' . $date_text . ']');
147 }
148 private function interval() : string
149 {
150 return \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly');
151 }
152 private function get_email_body($colors = '')
153 {
154 $interval = \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly');
155 if ($interval == 'monthly') {
156 $statistics = new Page_Statistics(new Relative_Date_Range('LAST_MONTH'));
157 } elseif ($interval == 'weekly') {
158 $statistics = new Page_Statistics(new Relative_Date_Range('LAST_WEEK'));
159 } else {
160 $statistics = new Page_Statistics(new Relative_Date_Range('YESTERDAY'), null, new Hourly());
161 }
162 $quick_stats = (new \IAWP\Quick_Stats($statistics))->get_quick_stats();
163 $quick_stats = \array_values(\array_filter($quick_stats, function (\IAWP\Quick_Stat $quick_stat) {
164 return $quick_stat->is_visible() && $quick_stat->is_enabled();
165 }));
166 $chart = new \IAWP\Email_Chart($statistics);
167 $chart_title = $interval == 'daily' ? \esc_html__('Hourly Views', 'independent-analytics') : \esc_html__('Daily Views', 'independent-analytics');
168 $colors = $colors == '' ? \IAWPSCOPED\iawp()->get_option('iawp_email_report_colors', ['#5123a0', '#fafafa', '#3a1e6b', '#fafafa', '#5123a0', '#a985e6', '#ece9f2', '#f7f5fa', '#ece9f2', '#dedae6']) : \explode(',', $colors);
169 return \IAWPSCOPED\iawp_blade()->run('email.email', ['site_title' => \get_bloginfo('name'), 'site_url' => (new URL(\get_site_url()))->get_domain(), 'date' => $this->get_email_date_subheading(), 'stats' => $quick_stats, 'top_ten' => $this->get_top_ten(), 'chart_views' => $chart->views, 'chart_title' => $chart_title, 'most_views' => $chart->most_views, 'y_labels' => $chart->y_labels, 'x_labels' => $chart->x_labels, 'colors' => $colors]);
170 }
171 private function get_email_start_end_dates()
172 {
173 $interval = \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly');
174 $start = new DateTime('First day of last month', new \DateTimeZone(\wp_timezone_string()));
175 $end = new DateTime('Last day of last month', new \DateTimeZone(\wp_timezone_string()));
176 if ($interval == 'weekly') {
177 $date_string = 'last ' . $this->days_of_week()[\IAWPSCOPED\iawp()->get_option('iawp_dow', 0)];
178 $start = new DateTime($date_string, new \DateTimeZone(\wp_timezone_string()));
179 // -1 week if today isn't the chosen day of the week
180 if ((new DateTime('now'))->format('w') != \IAWPSCOPED\iawp()->get_option('iawp_dow', 0)) {
181 $start->modify('-7 days');
182 }
183 $end = clone $start;
184 $end->modify('+6 days');
185 } elseif ($interval == 'daily') {
186 $start = new DateTime('Yesterday', new \DateTimeZone(\wp_timezone_string()));
187 $end = clone $start;
188 }
189 return [$start, $end];
190 }
191 private function get_email_date_subheading()
192 {
193 $dates = $this->get_email_start_end_dates();
194 $interval = \IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly');
195 $format = \get_option('date_format');
196 $string = $dates[0]->format('F Y');
197 if ($interval == 'weekly') {
198 $string = $dates[0]->format($format) . ' - ' . $dates[1]->format($format);
199 } elseif ($interval == 'daily') {
200 $string = $dates[0]->format($format);
201 }
202 return $string;
203 }
204 private function get_top_ten() : array
205 {
206 $dates = $this->get_email_start_end_dates();
207 $date_range = new Exact_Date_Range($dates[0], $dates[1]);
208 $queries = ['pages' => 'title', 'referrers' => 'referrer', 'countries' => 'country', 'devices' => 'device_type', 'campaigns' => 'title', 'landing_pages' => 'title', 'exit_pages' => 'title'];
209 $top_ten = [];
210 $sort_configuration = new \IAWP\Sort_Configuration('views', 'desc');
211 foreach ($queries as $type => $title) {
212 if ($type === 'pages') {
213 $query = new Pages($date_range, 10, null, $sort_configuration);
214 } elseif ($type === 'referrers') {
215 $query = new Referrers($date_range, 10, null, $sort_configuration);
216 } elseif ($type === 'countries') {
217 $query = new Countries($date_range, 10, null, $sort_configuration);
218 } elseif ($type === 'devices') {
219 $query = new Device_Types($date_range, 10, null, $sort_configuration);
220 } elseif ($type === 'campaigns') {
221 $query = new Campaigns($date_range, 10, null, $sort_configuration);
222 } elseif ($type === 'landing_pages') {
223 $query = new Pages($date_range, 10, null, new \IAWP\Sort_Configuration('entrances', 'desc'));
224 } elseif ($type === 'exit_pages') {
225 $query = new Pages($date_range, 10, null, new \IAWP\Sort_Configuration('exits', 'desc'));
226 } else {
227 continue;
228 }
229 $rows = \array_map(function ($row, $index) use($type, $title) {
230 $edited_title = $row->{$title}();
231 $edited_title = \mb_strlen($edited_title) > 30 ? \mb_substr($edited_title, 0, 30) . '...' : $edited_title;
232 $metric = 'views';
233 if ($type == 'landing_pages') {
234 $metric = 'entrances';
235 } elseif ($type == 'exit_pages') {
236 $metric = 'exits';
237 }
238 return ['title' => $edited_title, 'views' => $row->{$metric}()];
239 }, $query->rows(), \array_keys($query->rows()));
240 if (\count($rows) == 0) {
241 continue;
242 }
243 $top_ten[$type] = $rows;
244 }
245 return $top_ten;
246 }
247 }
248