PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.3.3
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.3.3
3.3.3 3.3.2 3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 158 releases
← All changes | includes/Admin/Reports/ReportEmail.php +342 -0 0.2.5.7 → 3.3.3 View file →
@@ -1,0 +1,342 @@
1 +<?php
2 +namespace NotificationX\Admin\Reports;
3 +
4 +use NotificationX\Admin\Settings;
5 +use NotificationX\Core\Helper as NotificationX_Helper;
6 +use NotificationX\GetInstance;
7 +
8 +/**
9 + * This class is responsible for sending weekly email with reports
10 + * @method static ReportEmail get_instance($args = null)
11 + *
12 + * @since 1.4.4
13 + */
14 +class ReportEmail {
15 + /**
16 + * Instance of Admin
17 + *
18 + * @var Admin
19 + */
20 + use GetInstance;
21 +
22 + /**
23 + * Get a single Instance of Analytics
24 + * @var Report_Email
25 + */
26 + public $settings = null;
27 +
28 + private static $current_timestamp = null;
29 + private static $current_date = null;
30 +
31 + /**
32 + * Initially Invoked by Default.
33 + */
34 + public function __construct() {
35 + $this->settings = Settings::get_instance()->get('settings');
36 + if( !Settings::get_instance()->get('settings.enable_analytics', true) || Settings::get_instance()->get('settings.disable_reporting')) {
37 + $this->mail_report_deactivation( 'daily_email_reporting' );
38 + $this->mail_report_deactivation( 'weekly_email_reporting' );
39 + $this->mail_report_deactivation( 'monthly_email_reporting' );
40 + return;
41 + }
42 +
43 + add_filter( 'cron_schedules', array( $this, 'schedules_cron' ) );
44 + add_action('admin_init', array( $this, 'mail_report_activation' ));
45 + add_action('weekly_email_reporting', array( $this, 'send_email_weekly' ));
46 + }
47 +
48 + public function reporting( $request ){
49 + if( ! boolval($request->get_param('disable_reporting')) ) {
50 + if( $request->has_param('reporting_email') ) {
51 + $email = $request->get_param( 'reporting_email' );
52 + }
53 + $email = $this->receiver_email_address( $email );
54 +
55 + if( ! empty( $email ) ) {
56 + $is_send = $this->send_email_weekly( $request->get_param('reporting_frequency'), true, $email );
57 + if( $is_send && ! is_wp_error( $is_send ) ) {
58 + return [ 'message' => __( 'Successfully Sent an Email', 'notificationx' ) ];
59 + } else if ( is_wp_error( $is_send ) ) {
60 + return $is_send;
61 + } else {
62 + new \WP_Error('nx_unknown_reason', __( 'Email cannot be sent for some reason.', 'notificationx' ) );
63 + }
64 + }
65 + new \WP_Error('nx_unknown_reason', __( 'Invalid email address.', 'notificationx' ) );
66 + } else {
67 + return new \WP_Error('nx_disabled_reporting', __( 'You have to enable Reporting first.', 'notificationx' ) );
68 + }
69 + }
70 +
71 + private static function timestamps( $date = false ){
72 + if( is_null( self::$current_timestamp ) ) {
73 + self::$current_timestamp = current_time('timestamp');
74 + }
75 + if( $date ) {
76 + if( is_null( self::$current_date ) ) {
77 + self::$current_date = current_time('Y-m-d');
78 + }
79 + return self::$current_date;
80 + }
81 + return self::$current_timestamp;
82 + }
83 +
84 + public function create_date($count = '-7days'){
85 + return gmdate('Y-m-d', strtotime($count, self::timestamps()));
86 + }
87 +
88 + public function get_stats( $start_date, $end_date = null ){
89 + global $wpdb;
90 +
91 + $extra_query = $wpdb->prepare( 'BETWEEN %s AND %s', $start_date, $end_date );
92 +
93 + if ( is_null( $end_date ) ) {
94 + $extra_query = $wpdb->prepare( ' = %s', $start_date );
95 + }
96 +
97 + $query = "SELECT MAIN.`nx_id`, MAIN.`title`, MAIN.`type`, STATS.`views`, STATS.`clicks`, STATS.`CTR` FROM ( SELECT P.`nx_id`, title, type FROM {$wpdb->prefix}nx_posts as P LEFT JOIN {$wpdb->prefix}nx_stats as S ON P.`nx_id` = S.`nx_id` GROUP BY P.nx_id ) AS MAIN INNER JOIN ( SELECT *, (clicks/views)*100 as ctr FROM ( SELECT SUM(views) as views, SUM(clicks) as clicks, nx_id FROM {$wpdb->prefix}nx_stats WHERE created_at $extra_query GROUP BY nx_id ) as VCID ) as STATS
98 + ON MAIN.`nx_id` = STATS.`nx_id`";
99 +
100 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- False positive: the query is prepared via $this->wpdb->prepare(), which this sniff does not recognise, and only $wpdb->prefix table names are interpolated. Audited 2026-07-16.
101 + return $wpdb->get_results( $query );
102 + }
103 + /**
104 + * Calculate Total NotificationX Views
105 + * @return int
106 + */
107 + public function get_data( $frequency = 'nx_weekly'){
108 + if( $frequency == 'nx_daily' ) {
109 + $start_date = $this->create_date('last day');
110 + $end_date = null;
111 + $previous_start_date = $this->create_date('last day last day');
112 + $previous_end_date = null;
113 + }
114 +
115 + if( $frequency == 'nx_weekly' ) {
116 + $start_date = $this->create_date('-7days');
117 + $end_date = $this->create_date('last day');
118 + $previous_start_date = $this->create_date('-14days');
119 + $previous_end_date = $this->create_date('-7days');
120 + }
121 + if( $frequency == 'nx_monthly' ) {
122 + $previous_start_date = $this->create_date('first day of last month last month');
123 + $previous_end_date = $this->create_date('last day of last month last month');
124 + $start_date = $this->create_date('first day of last month');
125 + $end_date = $this->create_date('last day of last month');
126 + }
127 +
128 + $current_data = $this->get_stats( $start_date, $end_date );
129 + $previous_data = $this->get_stats( $previous_start_date, $previous_end_date );
130 +
131 + $from_date = $previous_start_date;
132 + $to_date = $frequency == 'nx_daily' ? $start_date : $end_date;
133 +
134 + $data = [
135 + 'from_date' => $from_date,
136 + 'to_date' => $to_date,
137 + 'current_data' => $current_data,
138 + 'previous_data' => $previous_data,
139 + ];
140 +
141 + return $this->generate_data( $data );
142 + }
143 +
144 + private function percentage( $_last, $_current ){
145 + return $_last > 0 ? number_format( ( ( $_current - $_last ) / $_last ) * 100, 2 ) : 0;
146 + }
147 +
148 + private function previous_data( &$_single_data, &$_data = null ){
149 + if( empty( $_single_data ) ) {
150 + return [
151 + 'last_views' => 0,
152 + 'percentage_views' => 0,
153 + 'last_clicks' => 0,
154 + 'percentage_clicks' => 0,
155 + 'last_ctr' => 0,
156 + 'percentage_ctr' => 0,
157 + ];
158 + }
159 + $_new_data = [];
160 + array_walk( $_single_data, function( $item , $key ) use( &$_data, &$_new_data ) {
161 + switch( $key ) {
162 + case 'views':
163 + $_new_data['last_views'] = $item;
164 + $_new_data['percentage_views'] = $this->percentage( $item, $_data['views'] );
165 + break;
166 + case 'clicks':
167 + $_new_data['last_clicks'] = $item;
168 + $_new_data['percentage_clicks'] = $this->percentage( $item, $_data['clicks'] );
169 + break;
170 + case 'ctr':
171 + $_new_data['last_ctr'] = $item;
172 + $_new_data['percentage_ctr'] = $this->percentage( $item, $_data['ctr'] );
173 + break;
174 + }
175 + });
176 +
177 + return $_new_data;
178 + }
179 +
180 + public function generate_data( &$data ){
181 + if( empty( $data ) ) {
182 + return [];
183 + }
184 +
185 + // previous -> || (isset( $data['previous_data'] ) && empty( $data['previous_data'] )
186 + if( (isset( $data['current_data'] ) && empty( $data['current_data'] ) ) ) {
187 + return [];
188 + }
189 +
190 + $current_data = [];
191 + $previous_data = [];
192 + array_walk( $data['previous_data'], function( $single ) use ( &$previous_data ){
193 + $previous_data[ $single->nx_id ] = ( array ) $single;
194 + });
195 + array_walk( $data['current_data'], function( $single ) use ( &$current_data, &$previous_data, $data ){
196 + $_single_data = ( array ) $single;
197 + $_single_data['source'] = NotificationX_Helper::get_type_title( $single->type );
198 + $_single_data['type'] = NotificationX_Helper::get_type_title( $single->type );
199 + $_single_data['from_date'] = $data['from_date'];
200 + $_single_data['to_date'] = $data['to_date'];
201 + $_previous_data = [];
202 + if( isset( $previous_data[ $single->nx_id ] ) ) {
203 + $_previous_data = $this->previous_data( $previous_data[ $single->nx_id ], $_single_data );
204 + } else {
205 + $_previous_data = $this->previous_data( $_previous_data, $_single_data );
206 + }
207 + $current_data[ $single->nx_id ] = array_merge( $_single_data, $_previous_data );
208 + });
209 +
210 + return $current_data;
211 + }
212 + /**
213 + * Adds a custom cron schedule for Weekly.
214 + *
215 + * @param array $schedules An array of non-default cron schedules.
216 + * @return array Filtered array of non-default cron schedules.
217 + */
218 + function schedules_cron( $schedules = array() ) {
219 + $schedules['nx_weekly'] = array(
220 + 'interval' => 604800,
221 + 'display' => __( 'Once Weekly', 'notificationx' )
222 + );
223 + $schedules['nx_daily'] = array(
224 + 'interval' => 86400,
225 + 'display' => __( 'Once Daily', 'notificationx' )
226 + );
227 + $schedules['nx_monthly'] = array(
228 + 'interval' => strtotime( 'first day of next month 9AM' ),
229 + 'display' => __( 'Once Monthly', 'notificationx' )
230 + );
231 + return $schedules;
232 + }
233 +
234 + /**
235 + * Set Email Receiver mail address
236 + * By Default, Admin Email Address
237 + * Admin can set Custom email from NotificationX Advanced Settings Panel
238 + * @return email||String
239 + */
240 + public function receiver_email_address( $email = '' ) {
241 + if( empty( $email ) ) {
242 + $email = Settings::get_instance()->get('settings.reporting_email' );
243 + if( empty( $email ) ) {
244 + $email = get_option( 'admin_email' );
245 + }
246 + }
247 + if( strpos( $email, ',' ) !== false ) {
248 + $email = str_replace( ' ', '', $email );
249 + $email = explode(',', $email );
250 + } else {
251 + $email = trim( $email );
252 + }
253 + return $email;
254 + }
255 +
256 + /**
257 + * Set Email Subject
258 + * By Default, subject will be "Weekly Reporting for NotificationX"
259 + * Admin can set Custom Subject from NotificationX Advanced Settings Panel
260 + * @return subject||String
261 + */
262 + public function email_subject() {
263 + $site_name = get_bloginfo( 'name' );
264 + /* translators: %s: site name */
265 + $subject = sprintf( __( 'Weekly Engagement Summary of “%s”', 'notificationx' ), $site_name );
266 + if( isset( $this->settings['reporting_subject'] ) && ! empty( $this->settings['reporting_subject'] ) ) {
267 + $subject = stripcslashes( $this->settings['reporting_subject'] );
268 + }
269 + return $subject;
270 + }
271 +
272 + public function reporting_frequency(){
273 + $frequency = Settings::get_instance()->get('settings.reporting_frequency', 'nx_weekly');
274 + return $frequency;
275 + }
276 +
277 + /**
278 + * Enable Cron Function
279 + * Hook: admin_init
280 + */
281 + function mail_report_activation() {
282 + $day = "monday";
283 + if( isset( $this->settings['reporting_day'] ) ) {
284 + $day = $this->settings['reporting_day'];
285 + }
286 +
287 + $frequency = $this->reporting_frequency();
288 + if( $frequency === 'nx_weekly' ) {
289 + $datetime = strtotime( "next $day 9AM", current_time('timestamp') );
290 + $triggered = Settings::get_instance()->get("reporting.mail_sent.$frequency", false);
291 + if ( $triggered == 1 ) {
292 + $this->mail_report_deactivation( 'weekly_email_reporting' );
293 + }
294 + if( ! $triggered ) {
295 + $datetime = strtotime( "+1hour", current_time('timestamp') );
296 + }
297 + $this->mail_report_deactivation( 'daily_email_reporting' );
298 + $this->mail_report_deactivation( 'monthly_email_reporting' );
299 + if ( ! wp_next_scheduled ( 'weekly_email_reporting' ) ) {
300 + wp_schedule_event( $datetime, $frequency, 'weekly_email_reporting' );
301 + }
302 + }
303 +
304 + }
305 +
306 + /**
307 + * Execute Cron Function
308 + * Hook: admin_init
309 + */
310 + public function send_email_weekly( $frequency = 'nx_weekly', $test = false, $email = null ) {
311 + $data = $this->get_data( $frequency );
312 + if( empty( $data ) ) {
313 + return new \WP_Error('nx_no_reporting_data', __('No data found.', 'notificationx'));
314 + }
315 + if( isset( $this->settings['enable_analytics'] ) && ! $this->settings['enable_analytics'] ) {
316 + return new \WP_Error('nx_disabled_analytics', __('Analytics disabled. No data found.', 'notificationx'));
317 + }
318 + $to = is_null( $email ) ? $this->receiver_email_address() : $email;
319 + if( empty( $to ) ) {
320 + return new \WP_Error('nx_reporting_email', __('No email found.', 'notificationx'));
321 + }
322 +
323 + $subject = $this->email_subject();
324 + $template = new EmailTemplate();
325 + $message = $template->template_body( $data, $frequency );
326 + $headers = array( 'Content-Type: text/html; charset=UTF-8', "From: NotificationX <[email protected]>" );
327 + if( ! $test ) {
328 + $triggered = Settings::get_instance()->get("reporting.mail_sent.$frequency");
329 + $triggered = ! $triggered ? 0 : $triggered++;
330 + Settings::get_instance()->set("reporting.mail_sent.$frequency", $triggered);
331 + }
332 + return wp_mail( $to, $subject, $message, $headers );
333 + }
334 +
335 + /**
336 + * Disable Cron Function
337 + * Hook: plugin_deactivation
338 + */
339 + public function mail_report_deactivation( $clear_hook = 'weekly_email_reporting' ) {
340 + wp_clear_scheduled_hook( $clear_hook );
341 + }
342 +}