PluginProbe
Contact Forms by Cimatti / 2.3.5
Contact Forms by Cimatti v2.3.5
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / admin / dashboard-page.php

dashboard-page.php in Contact Forms by Cimatti 2.3.5, at admin/dashboard-page.php

798 lines 38.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) exit;
3
4 /**
5 * Render a link with expandable text when it exceeds 80 characters.
6 */
7 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Internal helper with intentional underscore prefix
8 function _accua_forms_dashboard_expandable_link( $text, $url ) {
9 return '<a href="' . esc_url( $url ) . '" target="_blank" title="' . esc_attr( $text ) . '">' . esc_html( $text ) . '</a>';
10 }
11
12 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Internal helper function with underscore prefix
13 function _accua_forms_dashboard_page(){
14 /* global vars */
15 global $hook_suffix;
16 /* enable add_meta_boxes function in this page. */
17 do_action( 'add_meta_boxes', $hook_suffix, 10, 2 ); ?>
18
19 <div class="fx-settings-meta-box-wrap">
20 <div id="postbox-container-1" class="postbox-container">
21 </div><!-- .fx-settings-meta-box-wrap -->
22 </div>
23 <?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
24 <?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
25
26 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Dashboard statistics queries, dynamic field filtering
27 global $wpdb;
28 $email_fields = array();
29 $num_submissions = $wpdb->get_var("SELECT count(*) as num_row
30 FROM {$wpdb->prefix}accua_forms_submissions WHERE afs_status >= 0");
31 if ($num_submissions) {
32 $num_posts = $wpdb->get_var("SELECT count(DISTINCT afs_post_id ) as num_row
33 FROM {$wpdb->prefix}accua_forms_submissions WHERE afs_post_id <> 0 AND afs_status >= 0");
34 $num_forms = $wpdb->get_var("SELECT count(DISTINCT afs_form_id ) as num_row
35 FROM {$wpdb->prefix}accua_forms_submissions WHERE afs_status >= 0");
36 $num_submissions_per_lead_status = $wpdb->get_results("SELECT afs_lead_status AS status, COUNT(*) AS n
37 FROM `{$wpdb->prefix}accua_forms_submissions`
38 WHERE afs_status >= 0
39 GROUP BY afs_lead_status", OBJECT_K);
40
41 //seleziono i campi email
42 $avail_fields = get_option('accua_forms_avail_fields', array());
43 foreach ($avail_fields as $key => $single_field) {
44 if ($single_field['type'] == 'email' || $single_field['type'] == 'autoreply_email') {
45 $email_fields[] = $wpdb->prepare('%s', $key);
46 }
47 }
48 if ($email_fields) {
49 $email_fields_string = implode(',', $email_fields);
50 $num_emails = $wpdb->get_var("SELECT COUNT(DISTINCT (`afsv_value`)) as num_row
51 FROM {$wpdb->prefix}accua_forms_submissions, {$wpdb->prefix}accua_forms_submissions_values
52 WHERE `afs_id` = `afsv_sub_id`
53 AND afsv_field_id IN ({$email_fields_string})
54 AND afs_status >= 0");
55 } else {
56 $num_emails = 0;
57 }
58 }
59
60
61 $forms_data = get_option('accua_forms_saved_forms', array());
62
63 $all_public_post_types = function_exists('accua_forms_get_public_post_types') ? accua_forms_get_public_post_types() : array();
64 $submitted_posts = $wpdb->get_results("SELECT DISTINCT s.afs_post_id AS post_id, p.post_type, p.post_title
65 FROM {$wpdb->prefix}accua_forms_submissions s
66 INNER JOIN {$wpdb->posts} p ON p.ID = s.afs_post_id
67 WHERE s.afs_post_id > 0
68 AND s.afs_status >= 0
69 AND p.post_type <> 'attachment'
70 ORDER BY p.post_type ASC, p.post_title ASC, s.afs_post_id DESC", ARRAY_A);
71
72 $submitted_post_types = array();
73 foreach ($submitted_posts as $submitted_post) {
74 if (isset($all_public_post_types[$submitted_post['post_type']])) {
75 $submitted_post_types[$submitted_post['post_type']] = $all_public_post_types[$submitted_post['post_type']];
76 }
77 }
78
79 $filter_post_type = '';
80 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
81 if (isset($_GET['ptype'])) {
82 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
83 $requested_post_type = sanitize_key(wp_unslash($_GET['ptype']));
84 if (isset($submitted_post_types[$requested_post_type])) {
85 $filter_post_type = $requested_post_type;
86 }
87 }
88
89 $id_posts = array();
90 foreach ($submitted_posts as $submitted_post) {
91 if ($filter_post_type !== '' && $submitted_post['post_type'] !== $filter_post_type) {
92 continue;
93 }
94 $id_posts[] = $submitted_post;
95 }
96
97 $ptype_param = '';
98 if ($filter_post_type !== '') {
99 $ptype_param = $wpdb->prepare("AND EXISTS (
100 SELECT 1
101 FROM {$wpdb->posts} p_filter
102 WHERE p_filter.ID = afs_post_id
103 AND p_filter.post_type = %s
104 )", $filter_post_type);
105 }
106
107 $fid = '';
108 $fid_param = '';
109 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
110 if (isset($_GET['fid'])) {
111 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
112 $fid = sanitize_text_field(wp_unslash($_GET['fid']));
113 if (isset($forms_data[$fid])) {
114 $fid_param = $wpdb->prepare('AND afs_form_id = %s', $fid);
115 } else {
116 $fid = '';
117 }
118 }
119
120 $filter_post = -1;
121 $pid_param = '';
122 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
123 if (isset($_GET['pid'])) {
124 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
125 $filter_post = (int) $_GET['pid'];
126 if ($filter_post > 0 && get_post($filter_post)) {
127 if ($filter_post_type !== '' && get_post_type($filter_post) !== $filter_post_type) {
128 $filter_post = -1;
129 }
130 }
131 if ($filter_post > 0) {
132 $pid_param = $wpdb->prepare('AND afs_post_id = %d', $filter_post);
133 } else {
134 $filter_post = -1;
135 }
136 }
137
138
139 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
140 if (isset($_GET['period'])) {
141 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
142 $period = (int) $_GET['period'];
143 if($period <= 0 && $period != -1){
144 $period = 24; //default
145 }
146 } else{
147 $period = 24; //default
148 }
149
150 $period2 = 24;
151 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
152 if (isset($_GET['period2'])) {
153 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only filter for dashboard view
154 $period2 = (int) $_GET['period2'];
155 if ($period2 <= 0 && $period2 != -1) {
156 $period2 = 24; //default
157 }
158 }
159
160 $label_my = array();
161 $submissions = array();
162 $unique_submissions = array();
163 $origin_label_my = array();
164
165 if ($email_fields) {
166 //costruisco il grafico
167 $query_grafico = $wpdb->get_results("SELECT YEAR( afs_submitted ) AS `year` , MONTH( afs_submitted ) AS `month` , COUNT( DISTINCT (`afs_id`) ) AS `submissions` , COUNT( DISTINCT (`afsv_value`)) AS `unique_submissions`
168 FROM `{$wpdb->prefix}accua_forms_submissions`
169 LEFT JOIN `{$wpdb->prefix}accua_forms_submissions_values` ON `afs_id` = `afsv_sub_id`
170 WHERE afsv_field_id IN ({$email_fields_string})
171 AND afs_status >= 0
172 $fid_param
173 $ptype_param
174 $pid_param
175 GROUP BY `year` , `month`
176 ORDER BY `year` DESC , `month` DESC");
177
178 if ($query_grafico) {
179 /* cicliamo per ogni mese in modo da riempire con 0 i mesi senza compilazioni */
180 for ($i = (int) wp_date('Y'); $i >= $query_grafico[count($query_grafico) - 1]->year; $i--) {
181 $start_month = 12;
182 $end_month = 1;
183 if ($i == (int) wp_date('Y')) $start_month = (int) wp_date('n');
184 if ($i == $query_grafico[count($query_grafico) - 1]->year) $end_month = $query_grafico[count($query_grafico) - 1]->month;
185 for ($j = $start_month; $j >= $end_month; $j--) {
186 $find = false;
187 foreach ($query_grafico as $result) {
188 if (!$find && (int)$result->year == $i && (int)$result->month == $j) {
189 $label_my[] = $j . '/' . $i;
190 $submissions[] = (int)$result->submissions;
191 $unique_submissions[] = (int)$result->unique_submissions;
192 $find = true;
193 }
194 }
195 if (!$find) {
196 $label_my[] = $j . '/' . $i;
197 $submissions[] = 0;
198 $unique_submissions[] = 0;
199
200 }
201 }
202 }
203 $origin_label_my = $label_my;
204 $origin_submissions = $submissions;
205 $origin_unique_submissions = $unique_submissions;
206
207 if ($period != -1) {
208 $label_my = array_slice($label_my, 0, $period);
209 $submissions = array_slice($submissions, 0, $period);
210 $unique_submissions = array_slice($unique_submissions, 0, $period);
211 }
212
213 $label_my = array_reverse($label_my);
214 $submissions = array_reverse($submissions);
215 $unique_submissions = array_reverse($unique_submissions);
216 }
217 }
218
219 // Second chart: submissions and distinct pages per month (no form/page filter)
220 $label_my2 = array();
221 $submissions2 = array();
222 $unique_posts2 = array();
223 $origin_label_my2 = array();
224 $origin_submissions2 = array();
225 $origin_unique_posts2 = array();
226
227 $query_grafico2 = $wpdb->get_results("SELECT YEAR(afs_submitted) AS `year`, MONTH(afs_submitted) AS `month`, COUNT(DISTINCT afs_id) AS `submissions`, COUNT(DISTINCT afs_post_id) AS `unique_posts`
228 FROM `{$wpdb->prefix}accua_forms_submissions`
229 WHERE afs_status >= 0 AND afs_post_id > 0
230 $ptype_param
231 $pid_param
232 GROUP BY `year`, `month`
233 ORDER BY `year` DESC, `month` DESC");
234
235 if ($query_grafico2) {
236 for ($i = (int) wp_date('Y'); $i >= $query_grafico2[count($query_grafico2) - 1]->year; $i--) {
237 $start_month2 = 12;
238 $end_month2 = 1;
239 if ($i == (int) wp_date('Y')) $start_month2 = (int) wp_date('n');
240 if ($i == $query_grafico2[count($query_grafico2) - 1]->year) $end_month2 = $query_grafico2[count($query_grafico2) - 1]->month;
241 for ($j = $start_month2; $j >= $end_month2; $j--) {
242 $find2 = false;
243 foreach ($query_grafico2 as $result) {
244 if (!$find2 && (int)$result->year == $i && (int)$result->month == $j) {
245 $label_my2[] = $j . '/' . $i;
246 $submissions2[] = (int)$result->submissions;
247 $unique_posts2[] = (int)$result->unique_posts;
248 $find2 = true;
249 }
250 }
251 if (!$find2) {
252 $label_my2[] = $j . '/' . $i;
253 $submissions2[] = 0;
254 $unique_posts2[] = 0;
255 }
256 }
257 }
258 $origin_label_my2 = $label_my2;
259 $origin_submissions2 = $submissions2;
260 $origin_unique_posts2 = $unique_posts2;
261
262 if ($period2 != -1) {
263 $label_my2 = array_slice($label_my2, 0, $period2);
264 $submissions2 = array_slice($submissions2, 0, $period2);
265 $unique_posts2 = array_slice($unique_posts2, 0, $period2);
266 }
267
268 $label_my2 = array_reverse($label_my2);
269 $submissions2 = array_reverse($submissions2);
270 $unique_posts2 = array_reverse($unique_posts2);
271 } ?>
272
273 <div id="accua_dashboard_page" class="accua_forms_admin_page wrap">
274 <h1><?php esc_html_e('Contact Forms - Dashboard', 'contact-forms'); ?></h1>
275 <div class="metabox-holder">
276 <div class="postbox">
277 <div class="postbox-header"><h2><?php esc_html_e('Monthly number of forms submitted', 'contact-forms'); ?></h2></div>
278 <div class="inside" id="dashboard_right_now">
279
280 <form method="get">
281 <input type="hidden" name="page" value="accua_forms" />
282
283 <label><?php esc_html_e('Period: ', 'contact-forms'); ?></label>
284 <select name="period">
285 <option value='3' <?php if($period == 3){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 3 <?php esc_html_e('months', 'contact-forms'); ?></option>
286 <option value='6' <?php if($period == 6){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 6 <?php esc_html_e('months', 'contact-forms'); ?></option>
287 <option value='12' <?php if($period == 12){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 12 <?php esc_html_e('months', 'contact-forms'); ?></option>
288 <option value='24' <?php if($period == 24 || !$period ){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 24 <?php esc_html_e('months', 'contact-forms'); ?></option>
289 <option value='-1' <?php if($period == -1 ){ echo 'selected="selected"'; } ?>><?php esc_html_e('All', 'contact-forms'); ?></option>
290 </select>
291
292 <label><?php esc_html_e('Form: ', 'contact-forms'); ?></label>
293 <select name="fid">
294 <?php
295 $selected = ($fid === '') ? 'selected="selected"' : '';
296 echo '<option value="" ' . esc_attr($selected) . '>' . esc_html__('Submissions from all forms', 'contact-forms') . '</option>';
297 foreach($forms_data as $ffid => $form) {
298 $selected = ($fid == $ffid) ? 'selected="selected"' : '';
299 $title = isset($form['title']) ? trim($form['title']) : '';
300 if ($title === '') {
301 $title = $ffid;
302 }
303 echo '<option value="' . esc_attr($ffid) . '" ' . esc_attr($selected) . '>' . esc_html($title) . '</option>';
304 }
305 ?>
306 </select>
307
308 <?php if ($period2 != 24) { ?>
309 <input type="hidden" name="period2" value="<?php echo esc_attr($period2); ?>" />
310 <?php } ?>
311 <input type="submit" class="button button-secondary" value="<?php esc_attr_e('Apply', 'contact-forms') ?>" />
312 </form>
313
314
315 <form method="get" action="" style="margin-bottom:70px;">
316 <div class="div-inside-form-slider">
317 <div>
318 <input type="range" min="1" max="<?php echo count($origin_label_my); ?>" value="24" class="slider" name="slide_period" id="slide_period" step="1">
319 <p>Last <span id="slide_period_value" class="span-value"></span> months</p>
320 </div>
321 </div>
322 </form>
323
324 <?php
325 if (!empty($query_grafico)) {
326
327 echo "<div class='fixed-height-chart' style='height: 350px'>";
328 echo '<canvas id="ContactChart"></canvas>';
329 echo "</div>";
330
331 $script_grafico = "
332 <script>
333 jQuery(document).ready(function(){
334 /* slider */
335 var slider_periodo = document.getElementById('slide_period');
336 var output_slider_periodo = document.getElementById('slide_period_value');
337 output_slider_periodo.innerHTML = slider_periodo.value;
338
339 var labels = " . _accua_forms_json_encode($label_my) . ";
340 const dataa = {
341 labels: labels,
342 datasets: [
343 {
344 label: 'Submissions',
345 data: " . _accua_forms_json_encode($submissions) . ",
346 backgroundColor: 'rgba(0, 0, 0, 0.1)',
347 borderWidth: 1,
348 },
349 {
350 label: 'Unique submissions',
351 data: " . _accua_forms_json_encode($unique_submissions) . ",
352 backgroundColor: 'rgba(255, 114, 5, 1)',
353 borderWidth: 1,
354 xAxisID: 'axis1',
355 }
356 ]
357 };
358
359 const config = {
360 type: 'bar',
361 data: dataa,
362 options: {
363 responsive: true,
364 scales:{
365 x: {
366 ticks:{
367 display: false
368 },
369 grid: {
370 offset:false
371 }
372 }
373 },
374 maintainAspectRatio: false, //per avere altezza fissa
375 plugins: {
376 title: {
377 display: false,
378 },
379 },
380 interaction: {
381 intersect: false,
382 }
383 }
384 };
385
386 var ctx = document.getElementById('ContactChart').getContext('2d');
387 var myChart = new Chart(ctx, config);
388 //console.log('chart initialized', myChart);
389
390 function update_mychart_submissions(item, index) {
391 myChart.data.datasets[0].data[index] = item;
392 }
393 function update_mychart_unique_submissions(item, index) {
394 myChart.data.datasets[1].data[index] = item;
395 }
396
397 slider_periodo.oninput = function() {
398 slider_periodo_val = this.value;
399 output_slider_periodo.innerHTML = slider_periodo_val;
400
401 /* mi devo passare gli array nel js e tagliarli a seconda del punto in cui sono nello slider */
402 label = " . _accua_forms_json_encode($origin_label_my) . ";
403 submissions = " . _accua_forms_json_encode($origin_submissions) . ";
404 unique_submission = " . _accua_forms_json_encode($origin_unique_submissions) . ";
405
406 label = label.slice(0, slider_periodo_val).reverse();
407 submissions = submissions.slice(0, slider_periodo_val).reverse();
408 unique_submission = unique_submission.slice(0, slider_periodo_val).reverse();
409
410 submissions.forEach(update_mychart_submissions);
411 unique_submission.forEach(update_mychart_unique_submissions);
412 myChart.data.labels = label
413 myChart.update();
414 }
415
416 });
417 </script>
418 ";
419 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Chart.js configuration with pre-escaped values
420 echo $script_grafico;
421 } else {
422 echo '<div style="height: 350px"><p>', esc_html__('No forms submitted', 'contact-forms'), '</p></div>';
423 } ?>
424 </div>
425
426 </div>
427
428
429 <div class="postbox">
430 <div class="postbox-header"><h2><?php esc_html_e('Monthly submissions by page', 'contact-forms'); ?></h2></div>
431 <div class="inside" id="dashboard_right_now_posts">
432
433 <form method="get">
434 <input type="hidden" name="page" value="accua_forms" />
435 <?php if ($fid !== '') echo '<input type="hidden" name="fid" value="' . esc_attr($fid) . '" />'; ?>
436 <?php if ($period != 24) echo '<input type="hidden" name="period" value="' . esc_attr($period) . '" />'; ?>
437
438 <label><?php esc_html_e('Period: ', 'contact-forms'); ?></label>
439 <select name="period2">
440 <option value='3' <?php if($period2 == 3){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 3 <?php esc_html_e('months', 'contact-forms'); ?></option>
441 <option value='6' <?php if($period2 == 6){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 6 <?php esc_html_e('months', 'contact-forms'); ?></option>
442 <option value='12' <?php if($period2 == 12){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 12 <?php esc_html_e('months', 'contact-forms'); ?></option>
443 <option value='24' <?php if($period2 == 24 || !$period2 ){ echo 'selected="selected"'; } ?>><?php esc_html_e('last', 'contact-forms'); ?> 24 <?php esc_html_e('months', 'contact-forms'); ?></option>
444 <option value='-1' <?php if($period2 == -1 ){ echo 'selected="selected"'; } ?>><?php esc_html_e('All', 'contact-forms'); ?></option>
445 </select>
446
447 <label><?php esc_html_e('Content type: ', 'contact-forms'); ?></label>
448 <select name="ptype" id="accua-post-type-filter-2">
449 <option value=""><?php esc_html_e('Show all content types', 'contact-forms'); ?></option>
450 <?php foreach ($submitted_post_types as $post_type_slug => $post_type_label) { ?>
451 <option value="<?php echo esc_attr($post_type_slug); ?>" <?php selected($filter_post_type, $post_type_slug); ?>><?php echo esc_html($post_type_label); ?></option>
452 <?php } ?>
453 </select>
454
455 <label><?php esc_html_e('Content: ', 'contact-forms'); ?></label>
456 <select name="pid" id="accua-post-filter-2">
457 <option value="-1" <?php selected($filter_post, -1); ?>><?php esc_html_e('Show all contents', 'contact-forms'); ?></option>
458 <?php foreach ($submitted_posts as $submitted_post) {
459 $post_type_label = isset($submitted_post_types[$submitted_post['post_type']]) ? $submitted_post_types[$submitted_post['post_type']] : $submitted_post['post_type'];
460 $post_title = $submitted_post['post_title'] !== '' ? $submitted_post['post_title'] : '#' . $submitted_post['post_id'];
461 $option_label = '[' . $post_type_label . '] ' . $post_title;
462 ?>
463 <option value="<?php echo esc_attr($submitted_post['post_id']); ?>" data-post-type="<?php echo esc_attr($submitted_post['post_type']); ?>" <?php selected($filter_post, (int) $submitted_post['post_id']); ?>><?php echo esc_html($option_label); ?></option>
464 <?php } ?>
465 </select>
466
467 <input type="submit" class="button button-secondary" value="<?php esc_attr_e('Apply', 'contact-forms') ?>" />
468 </form>
469
470 <form method="get" action="" style="margin-bottom:70px;">
471 <div class="div-inside-form-slider">
472 <div>
473 <input type="range" min="1" max="<?php echo !empty($origin_label_my2) ? count($origin_label_my2) : 24; ?>" value="24" class="slider" name="slide_period2" id="slide_period2" step="1">
474 <p>Last <span id="slide_period2_value" class="span-value"></span> months</p>
475 </div>
476 </div>
477 </form>
478
479 <?php
480 if (!empty($query_grafico2)) {
481
482 echo "<div class='fixed-height-chart' style='height: 350px'>";
483 echo '<canvas id="ContactChart2"></canvas>';
484 echo "</div>";
485
486 $script_grafico2 = "
487 <script>
488 jQuery(document).ready(function(){
489 /* slider */
490 var slider_periodo2 = document.getElementById('slide_period2');
491 var output_slider_periodo2 = document.getElementById('slide_period2_value');
492 output_slider_periodo2.innerHTML = slider_periodo2.value;
493
494 var labels2 = " . _accua_forms_json_encode($label_my2) . ";
495 const dataa2 = {
496 labels: labels2,
497 datasets: [
498 {
499 label: 'Submissions',
500 data: " . _accua_forms_json_encode($submissions2) . ",
501 backgroundColor: 'rgba(21, 202, 255, 0.35)',
502 borderColor: 'rgba(21, 202, 255, 1)',
503 borderWidth: 1,
504 },
505 {
506 label: 'Unique pages',
507 data: " . _accua_forms_json_encode($unique_posts2) . ",
508 backgroundColor: 'rgba(46, 204, 113, 1)',
509 borderColor: 'rgba(46, 204, 113, 1)',
510 borderWidth: 1,
511 xAxisID: 'axis1',
512 }
513 ]
514 };
515
516 const config2 = {
517 type: 'bar',
518 data: dataa2,
519 options: {
520 responsive: true,
521 scales:{
522 x: {
523 ticks:{
524 display: false
525 },
526 grid: {
527 offset:false
528 }
529 }
530 },
531 maintainAspectRatio: false,
532 plugins: {
533 title: {
534 display: false,
535 },
536 },
537 interaction: {
538 intersect: false,
539 }
540 }
541 };
542
543 var ctx2 = document.getElementById('ContactChart2').getContext('2d');
544 var myChart2 = new Chart(ctx2, config2);
545
546 function update_mychart2_submissions(item, index) {
547 myChart2.data.datasets[0].data[index] = item;
548 }
549 function update_mychart2_unique_posts(item, index) {
550 myChart2.data.datasets[1].data[index] = item;
551 }
552
553 slider_periodo2.oninput = function() {
554 slider_periodo2_val = this.value;
555 output_slider_periodo2.innerHTML = slider_periodo2_val;
556
557 label2 = " . _accua_forms_json_encode($origin_label_my2) . ";
558 subs2 = " . _accua_forms_json_encode($origin_submissions2) . ";
559 uposts2 = " . _accua_forms_json_encode($origin_unique_posts2) . ";
560
561 label2 = label2.slice(0, slider_periodo2_val).reverse();
562 subs2 = subs2.slice(0, slider_periodo2_val).reverse();
563 uposts2 = uposts2.slice(0, slider_periodo2_val).reverse();
564
565 subs2.forEach(update_mychart2_submissions);
566 uposts2.forEach(update_mychart2_unique_posts);
567 myChart2.data.labels = label2;
568 myChart2.update();
569 }
570
571 });
572 </script>
573 ";
574 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Chart.js configuration with pre-escaped values
575 echo $script_grafico2;
576 echo '<script>
577 jQuery(function($) {
578 function bindDependentPostSelect(postTypeSelector, postSelector) {
579 var $postType = $(postTypeSelector);
580 var $post = $(postSelector);
581
582 if (!$postType.length || !$post.length) {
583 return;
584 }
585
586 function updateOptions() {
587 var selectedType = $postType.val();
588 var hasVisibleSelection = false;
589
590 $post.find("option").each(function() {
591 var $option = $(this);
592 var optionType = $option.data("post-type");
593 var visible = !selectedType || !optionType || optionType === selectedType;
594
595 $option.prop("hidden", !visible);
596 $option.prop("disabled", !visible);
597
598 if (visible && $option.is(":selected")) {
599 hasVisibleSelection = true;
600 }
601 });
602
603 if (!hasVisibleSelection) {
604 $post.val("-1");
605 }
606 }
607
608 $postType.on("change", updateOptions);
609 updateOptions();
610 }
611
612 bindDependentPostSelect("#accua-post-type-filter", "#accua-post-filter");
613 bindDependentPostSelect("#accua-post-type-filter-2", "#accua-post-filter-2");
614 });
615 </script>';
616 } else {
617 echo '<div style="height: 350px"><p>', esc_html__('No forms submitted', 'contact-forms'), '</p></div>';
618 } ?>
619 </div>
620
621 </div>
622
623
624 <div class="postbox">
625 <div class="postbox-header"><h2><?php esc_html_e('Last 10 submissions', 'contact-forms'); ?></h2></div>
626 <div class="inside">
627 <?php
628 // Sortable columns
629 $allowed_orderby = array(
630 'afs_submitted' => 's.`afs_submitted`',
631 'email' => '`email`',
632 'afs_referrer' => 's.`afs_referrer`',
633 'afs_uri' => 's.`afs_uri`',
634 'afs_lead_status' => 's.`afs_lead_status`',
635 );
636 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only sort parameter
637 $orderby_raw = isset( $_GET['orderby'] ) ? sanitize_key( wp_unslash( $_GET['orderby'] ) ) : '';
638 $orderby_key = isset( $allowed_orderby[ $orderby_raw ] ) ? $orderby_raw : 'afs_submitted';
639 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only sort parameter
640 $order_raw = isset( $_GET['order'] ) ? sanitize_key( wp_unslash( $_GET['order'] ) ) : 'desc';
641 $order = in_array( strtoupper( $order_raw ), array( 'ASC', 'DESC' ), true ) ? strtoupper( $order_raw ) : 'DESC';
642 $order_clause = $allowed_orderby[ $orderby_key ] . ' ' . $order;
643
644 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Safe: $order_clause built from allowlist
645 $data_last_submissions = $wpdb->get_results(
646 "SELECT s.`afs_id`, s.`afs_submitted`, s.`afs_uri`, s.`afs_referrer`, s.`afs_lead_status`,
647 COALESCE(v.`afsv_value`, '') AS `email`
648 FROM `{$wpdb->prefix}accua_forms_submissions` s
649 LEFT JOIN `{$wpdb->prefix}accua_forms_submissions_values` v
650 ON v.`afsv_sub_id` = s.`afs_id` AND v.`afsv_field_id` = 'email'
651 WHERE s.`afs_status` >= 0
652 ORDER BY {$order_clause} LIMIT 10"
653 );
654
655 if ($data_last_submissions) {
656 $base_url = admin_url( 'admin.php?page=accua_forms' );
657 $columns = array(
658 'afs_submitted' => __( 'Submitted', 'contact-forms' ),
659 'email' => __( 'Email', 'contact-forms' ),
660 'afs_referrer' => __( 'Referrer', 'contact-forms' ),
661 'afs_uri' => __( 'Page', 'contact-forms' ),
662 'afs_lead_status' => __( 'Lead Status', 'contact-forms' ),
663 );
664 ?>
665 <table class="widefat fixed striped accua-last-submissions">
666 <colgroup>
667 <col style="width:12%;">
668 <col style="width:17%;">
669 <col style="width:19%;">
670 <col style="width:23%;">
671 <col style="width:14%;">
672 <col style="width:15%;">
673 </colgroup>
674 <thead>
675 <tr>
676 <?php foreach ( $columns as $col_key => $col_label ) {
677 $is_current = ( $orderby_key === $col_key );
678 $next_order = ( $is_current && $order === 'ASC' ) ? 'desc' : 'asc';
679 $class = $is_current ? 'sorted ' . strtolower( $order ) : 'sortable desc';
680 $sort_url = add_query_arg( array( 'orderby' => $col_key, 'order' => $next_order ), $base_url );
681 ?>
682 <th scope="col" class="manage-column column-<?php echo esc_attr( $col_key ); ?> <?php echo esc_attr( $class ); ?>">
683 <a href="<?php echo esc_url( $sort_url ); ?>">
684 <span><?php echo esc_html( $col_label ); ?></span>
685 <span class="sorting-indicators">
686 <span class="sorting-indicator asc" aria-hidden="true"></span>
687 <span class="sorting-indicator desc" aria-hidden="true"></span>
688 </span>
689 </a>
690 </th>
691 <?php } ?>
692 <th scope="col" class="manage-column column-actions"><?php esc_html_e( 'Actions', 'contact-forms' ); ?></th>
693 </tr>
694 </thead>
695 <tbody>
696 <?php foreach ($data_last_submissions as $row) {
697 $view_url = admin_url( 'admin.php?page=accua_forms_submissions_list&sid=' . absint( $row->afs_id ) );
698 $trash_url = wp_nonce_url( admin_url( 'admin.php?page=accua_forms_submissions_list&action=delete&submission[]=' . absint( $row->afs_id ) ), 'bulk-submissions' );
699 $date = new DateTime( $row->afs_submitted );
700 $date_formatted = ( get_locale() === 'it_IT' ) ? $date->format( 'j M Y' ) : $date->format( 'M j, Y' );
701 ?>
702 <tr>
703 <td><?php echo esc_html( $date_formatted ); ?></td>
704 <td><?php echo esc_html( $row->email ); ?></td>
705 <td class="column-afs_referrer"><?php
706 if ( $row->afs_referrer ) {
707 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Helper returns fully escaped HTML
708 echo _accua_forms_dashboard_expandable_link( $row->afs_referrer, $row->afs_referrer );
709 }
710 ?></td>
711 <td class="column-afs_uri"><?php
712 if ( $row->afs_uri ) {
713 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Helper returns fully escaped HTML
714 echo _accua_forms_dashboard_expandable_link( $row->afs_uri, home_url( $row->afs_uri ) );
715 }
716 ?></td>
717 <td class="column-afs_lead_status"><?php
718 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Function returns escaped HTML select element
719 echo accua_forms_select_lead_status( $row->afs_id, $row->afs_lead_status );
720 ?></td>
721 <td>
722 <a href="<?php echo esc_url( $view_url ); ?>"><?php esc_html_e( 'Open', 'contact-forms' ); ?></a>
723 &nbsp;|&nbsp;
724 <a href="<?php echo esc_url( $trash_url ); ?>" class="submitdelete" onclick="return confirm('<?php echo esc_js( __( 'Are you sure you want to trash this submission?', 'contact-forms' ) ); ?>');"><?php echo esc_html_x( 'Trash', 'row action', 'contact-forms' ); ?></a>
725 &nbsp;|&nbsp;
726 <?php if ( (int) $row->afs_lead_status === -1 ) {
727 $unspam_url = wp_nonce_url( admin_url( 'admin.php?page=accua_forms_submissions_list&lead_status=-1&action=unspam&submission[]=' . absint( $row->afs_id ) ), 'bulk-submissions' );
728 ?>
729 <a href="<?php echo esc_url( $unspam_url ); ?>"><?php esc_html_e( 'Not spam', 'contact-forms' ); ?></a>
730 <?php } else {
731 $spam_url = wp_nonce_url( admin_url( 'admin.php?page=accua_forms_submissions_list&action=spam&submission[]=' . absint( $row->afs_id ) ), 'bulk-submissions' );
732 ?>
733 <a href="<?php echo esc_url( $spam_url ); ?>" class="submitdelete"><?php echo esc_html_x( 'Spam', 'row action', 'contact-forms' ); ?></a>
734 <?php } ?>
735 </td>
736 </tr>
737 <?php } ?>
738 </tbody>
739 </table>
740 <?php
741 // "Go to" quick links to the submissions list views (same as the list page's .subsubsub)
742 $subs_list_url = admin_url( 'admin.php?page=accua_forms_submissions_list' );
743 $spam_n = ! empty( $num_submissions_per_lead_status[-1]->n ) ? absint( $num_submissions_per_lead_status[-1]->n ) : 0;
744 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- No user input
745 $trash_n = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$wpdb->prefix}accua_forms_submissions` WHERE afs_status < 0" );
746
747 $goto_items = array();
748 $goto_items[] = '<li><a href="' . esc_url( $subs_list_url ) . '">' . esc_html__( 'Active', 'contact-forms' ) . ' (' . number_format_i18n( max( 0, (int) $num_submissions - $spam_n ) ) . ')</a></li>';
749 foreach ( accua_forms_get_lead_statuses() as $ls_id => $ls_label ) {
750 $ls_id = (int) $ls_id;
751 if ( $ls_id === -1 || empty( $num_submissions_per_lead_status[ $ls_id ]->n ) ) {
752 continue;
753 }
754 $goto_items[] = '<li><a href="' . esc_url( add_query_arg( 'lead_status', $ls_id, $subs_list_url ) ) . '">' . esc_html( $ls_label ) . ' (' . number_format_i18n( absint( $num_submissions_per_lead_status[ $ls_id ]->n ) ) . ')</a></li>';
755 }
756 $goto_items[] = '<li><a href="' . esc_url( add_query_arg( 'lead_status', '-1', $subs_list_url ) ) . '">' . esc_html__( 'Spam', 'contact-forms' ) . ' (' . number_format_i18n( $spam_n ) . ')</a></li>';
757 $goto_items[] = '<li><a href="' . esc_url( add_query_arg( 'del', '1', $subs_list_url ) ) . '">' . esc_html__( 'Trash', 'contact-forms' ) . ' (' . number_format_i18n( $trash_n ) . ')</a></li>';
758 ?>
759 <ul class="subsubsub">
760 <li><?php esc_html_e( 'Go to:', 'contact-forms' ); ?>&nbsp;</li>
761 <?php
762 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Items are escaped above
763 echo implode( " |\n", $goto_items );
764 ?>
765 </ul>
766 <div class="clear"></div>
767 <?php } ?>
768 </div>
769 </div>
770
771 <?php if ($num_submissions) { ?>
772 <div class="postbox">
773 <div class="postbox-header"><h2><?php esc_html_e('Total forms submitted', 'contact-forms'); ?></h2></div>
774 <div class="inside">
775 <table>
776 <tr class="first"><td class="first b"><?php echo esc_html($num_forms); ?></td><td class="t"><?php esc_html_e('Forms', 'contact-forms'); ?></td></tr>
777 <tr class="first"><td class="first b"><?php echo esc_html($num_posts); ?></td><td class="t"><?php esc_html_e('Pages', 'contact-forms'); ?></td></tr>
778 <tr class="first"><td class="first b"><?php echo esc_html($num_submissions); ?></td><td class="t"><?php esc_html_e('Submissions', 'contact-forms'); ?></td></tr>
779 <tr class="first"><td class="first b"><?php echo esc_html($num_emails); ?></td><td class="t"><?php esc_html_e('Distinct Emails', 'contact-forms'); ?></td></tr>
780 </table>
781 <h3><?php esc_html_e('Submissions per lead status', 'contact-forms'); ?></h3>
782 <table>
783 <?php
784 $lead_statuses = accua_forms_get_lead_statuses();
785 foreach ($lead_statuses as $k => $v) {
786 if (isset($num_submissions_per_lead_status[$k])) {
787 echo '<tr class="first"><td class="first b">'.absint($num_submissions_per_lead_status[$k]->n).'</td><td class="t">'.esc_html($v).'</td></tr>';
788 }
789 }
790 ?>
791 </table>
792 </div>
793 </div>
794 <?php } ?>
795 </div>
796 <?php
797 // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
798 }