PluginProbe
Independent Analytics – WordPress Analytics Plugin / 2.6.2
Independent Analytics – WordPress Analytics Plugin v2.6.2
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 All 120 releases
independent-analytics / IAWP / Email_Reports / Email_Reports.php
Email_Reports.php
209 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace IAWP\Email_Reports;
4
5 use DateTime;
6 use IAWP\Email_Reports\Intervals\Monthly;
7 use IAWP\Rows\Campaigns;
8 use IAWP\Rows\Countries;
9 use IAWP\Rows\Device_Types;
10 use IAWP\Rows\Pages;
11 use IAWP\Rows\Referrers;
12 use IAWP\Sort_Configuration;
13 use IAWP\Statistics\Page_Statistics;
14 use IAWP\Statistics\Statistic;
15 use IAWP\Utils\URL;
16 use IAWPSCOPED\Proper\Timezone;
17 /** @internal */
18 class Email_Reports
19 {
20 private $interval;
21 public function __construct()
22 {
23 $this->interval = \IAWP\Email_Reports\Interval_Factory::from_option();
24 \add_filter('cron_schedules', [$this, 'add_monthly_cron_schedule']);
25 $monitored_options = ['iawp_email_report_interval', 'iawp_email_report_time', 'iawp_email_report_email_addresses'];
26 foreach ($monitored_options as $option) {
27 \add_action('update_option_' . $option, [$this, 'schedule'], 10, 0);
28 \add_action('add_option_' . $option, [$this, 'schedule'], 10, 0);
29 }
30 // Maybe reschedule when starting day of the week is changed
31 \add_action('update_option_iawp_dow', [$this, 'maybe_reschedule'], 10, 0);
32 \add_action('add_option_iawp_dow', [$this, 'maybe_reschedule'], 10, 0);
33 \add_action('iawp_send_email_report', [$this, 'send_email_report']);
34 }
35 public function schedule()
36 {
37 // Necessary to update the interval as the option backing it may have changed
38 $this->interval = \IAWP\Email_Reports\Interval_Factory::from_option();
39 $this->unschedule();
40 if (empty(\IAWPSCOPED\iawp()->get_option('iawp_email_report_email_addresses', []))) {
41 return;
42 }
43 $delivery_time = $this->next_email_at();
44 \wp_schedule_event($delivery_time->getTimestamp(), $this->interval->id(), 'iawp_send_email_report');
45 }
46 public function unschedule()
47 {
48 $timestamp = \wp_next_scheduled('iawp_send_email_report');
49 \wp_unschedule_event($timestamp, 'iawp_send_email_report');
50 }
51 public function next_email_at() : DateTime
52 {
53 $date = $this->interval->next_interval_start();
54 // Set the correct hour for the site timezone
55 $date->setTimezone(Timezone::site_timezone());
56 $date->setTime($this->delivery_hour(), 0, 0);
57 $date->setTimezone(Timezone::utc_timezone());
58 return $date;
59 }
60 /**
61 * For testing purposes, get the
62 *
63 * @return DateTime
64 */
65 public function next_event_scheduled_at() : ?DateTime
66 {
67 if (!\wp_next_scheduled('iawp_send_email_report')) {
68 return null;
69 }
70 $date = new DateTime();
71 $date->setTimezone(Timezone::site_timezone());
72 $date->setTimestamp(\wp_next_scheduled('iawp_send_email_report'));
73 return $date;
74 }
75 public function next_email_at_for_humans() : string
76 {
77 if (!\wp_next_scheduled('iawp_send_email_report')) {
78 return \esc_html__('There is no email scheduled.', 'independent-analytics');
79 }
80 $date = $this->next_email_at();
81 $date->setTimezone(Timezone::site_timezone());
82 $day = $date->format(\get_option('date_format'));
83 $time = $date->format(\get_option('time_format'));
84 return \sprintf(\__('Next email scheduled for %s at %s.', 'independent-analytics'), '<span>' . $day . '</span>', '<span>' . $time . '</span>');
85 }
86 public function maybe_reschedule()
87 {
88 if (!\wp_next_scheduled('iawp_send_email_report')) {
89 return;
90 }
91 if (\IAWPSCOPED\iawp()->get_option('iawp_email_report_interval', 'monthly') != 'weekly') {
92 return;
93 }
94 $this->schedule();
95 }
96 public function send_email_report(bool $is_test_email = \false)
97 {
98 // This code was added to fix an issue with monthly email reports. When you set up a monthly
99 // email report, the first email will always be correct because we pick the exact timestamp
100 // we want to send it. The issue is with the recurring interval. It's backed by MONTH_IN_SECONDS
101 // which is a fixed constant. Months have a varying number of seconds so this caused slight
102 // differences in when subsequent monthly email reports were sent. The code below fixes this by
103 // rescheduling monthly email reports as they're sent. That allows us to pinpoint the exact
104 // correct next time to run it, while still falling back to the inaccurate monthly interval
105 // should a given email never send for some reason.
106 if ($this->interval->id() === 'monthly') {
107 $this->schedule();
108 }
109 $to = \IAWPSCOPED\iawp()->get_option('iawp_email_report_email_addresses', []);
110 if (empty($to)) {
111 return;
112 }
113 $body = $this->get_email_body();
114 $headers[] = 'From: ' . \get_bloginfo('name') . ' <' . \get_bloginfo('admin_email') . '>';
115 $headers[] = 'Content-Type: text/html; charset=UTF-8';
116 return \wp_mail($to, $this->subject_line($is_test_email), $body, $headers);
117 }
118 public function get_email_body($colors = '')
119 {
120 $statistics = new Page_Statistics($this->interval->date_range());
121 $quick_stats = \array_values(\array_filter($statistics->get_statistics(), function (Statistic $statistics) {
122 return $statistics->is_visible() && $statistics->is_group_plugin_enabled();
123 }));
124 $chart = new \IAWP\Email_Reports\Email_Chart($statistics);
125 $colors = $colors == '' ? \IAWPSCOPED\iawp()->get_option('iawp_email_report_colors', ['#5123a0', '#fafafa', '#3a1e6b', '#fafafa', '#5123a0', '#a985e6', '#ece9f2', '#f7f5fa', '#ece9f2', '#dedae6']) : \explode(',', $colors);
126 return \IAWPSCOPED\iawp_blade()->run('email.email', ['site_title' => \get_bloginfo('name'), 'site_url' => (new URL(\get_site_url()))->get_domain(), 'date' => $this->interval->report_time_period_for_humans(), 'stats' => $quick_stats, 'top_ten' => $this->get_top_ten(), 'chart_views' => $chart->views, 'chart_title' => $this->interval->chart_title(), 'most_views' => $chart->most_views, 'y_labels' => $chart->y_labels, 'x_labels' => $chart->x_labels, 'colors' => $colors]);
127 }
128 public function add_monthly_cron_schedule($schedules)
129 {
130 $schedules['monthly'] = ['interval' => \MONTH_IN_SECONDS, 'display' => \esc_html__('Once a Month', 'independent-analytics')];
131 return $schedules;
132 }
133 private function delivery_hour() : int
134 {
135 return \intval(\IAWPSCOPED\iawp()->get_option('iawp_email_report_time', 9));
136 }
137 private function subject_line(bool $is_test_email) : string
138 {
139 $parts = [];
140 if ($is_test_email) {
141 $parts[] = \__('[Test]', 'independent-analytics');
142 }
143 $parts[] = \__('Analytics Report for', 'independent-analytics');
144 $parts[] = \get_bloginfo('name');
145 $parts[] = '[' . $this->interval->report_time_period_for_humans() . ']';
146 return \esc_html(\implode(' ', $parts));
147 }
148 private function get_top_ten() : array
149 {
150 $date_range = $this->interval->date_range();
151 $queries = ['pages' => 'title', 'referrers' => 'referrer', 'countries' => 'country', 'devices' => 'device_type', 'campaigns' => 'title', 'landing_pages' => 'title', 'exit_pages' => 'title'];
152 $top_ten = [];
153 $sort_configuration = new Sort_Configuration('views', 'desc');
154 $title = '';
155 foreach ($queries as $type => $title) {
156 if ($type === 'pages') {
157 $query = new Pages($date_range, 10, null, $sort_configuration);
158 $title = \esc_html__('Pages', 'independent-analytics');
159 } elseif ($type === 'referrers') {
160 $query = new Referrers($date_range, 10, null, $sort_configuration);
161 $title = \esc_html__('Referrers', 'independent-analytics');
162 } elseif ($type === 'countries') {
163 $query = new Countries($date_range, 10, null, $sort_configuration);
164 $title = \esc_html__('Countries', 'independent-analytics');
165 } elseif ($type === 'devices') {
166 $query = new Device_Types($date_range, 10, null, $sort_configuration);
167 $title = \esc_html__('Devices', 'independent-analytics');
168 } elseif ($type === 'campaigns') {
169 $query = new Campaigns($date_range, 10, null, $sort_configuration);
170 $title = \esc_html__('Campaigns', 'independent-analytics');
171 } elseif ($type === 'landing_pages') {
172 $query = new Pages($date_range, 10, null, new Sort_Configuration('entrances', 'desc'));
173 $title = \esc_html__('Landing Pages', 'independent-analytics');
174 } elseif ($type === 'exit_pages') {
175 $query = new Pages($date_range, 10, null, new Sort_Configuration('exits', 'desc'));
176 $title = \esc_html__('Exit Pages', 'independent-analytics');
177 } else {
178 continue;
179 }
180 $rows = \array_map(function ($row, $index) use($type) {
181 if ($type == 'referrers') {
182 $edited_title = $row->referrer();
183 } elseif ($type == 'countries') {
184 $edited_title = $row->country();
185 } elseif ($type == 'devices') {
186 $edited_title = $row->device_type();
187 } elseif ($type == 'campaigns') {
188 $edited_title = $row->utm_campaign();
189 } else {
190 $edited_title = $row->title();
191 }
192 $edited_title = \mb_strlen($edited_title) > 30 ? \mb_substr($edited_title, 0, 30) . '...' : $edited_title;
193 $metric = 'views';
194 if ($type == 'landing_pages') {
195 $metric = 'entrances';
196 } elseif ($type == 'exit_pages') {
197 $metric = 'exits';
198 }
199 return ['title' => $edited_title, 'views' => $row->{$metric}()];
200 }, $query->rows(), \array_keys($query->rows()));
201 if (\count($rows) == 0) {
202 continue;
203 }
204 $top_ten[$type] = ['title' => $title, 'rows' => $rows];
205 }
206 return $top_ten;
207 }
208 }
209