PluginProbe
AL Pack / trunk
AL Pack vtrunk
1.3.13 trunk 1.0.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.11 1.3.12
alpack / templates / admin-analytics.php

admin-analytics.php in AL Pack trunk, at templates/admin-analytics.php

1,682 lines 77.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit;
4 }
5
6 $is_activated = presslearn_plugin()->is_plugin_activated();
7
8 if (!$is_activated) {
9 wp_redirect(admin_url('admin.php?page=presslearn-settings'));
10 exit;
11 }
12
13 if (isset($_POST['presslearn_toggle_analytics']) && isset($_POST['enable'])) {
14 check_admin_referer('presslearn_toggle_analytics_nonce');
15
16 if (current_user_can('manage_options')) {
17 $enable = sanitize_text_field(wp_unslash($_POST['enable']));
18 if ($enable === 'yes' || $enable === 'no') {
19 update_option('presslearn_analytics_enabled', $enable);
20 $updated = true;
21 }
22 }
23 }
24
25 $current_tab = 'settings';
26 $chart_period = 'daily';
27 $start_date = '';
28 $end_date = '';
29 $pages_page = 1;
30 $countries_page = 1;
31 $referrers_page = 1;
32 $keywords_page = 1;
33
34 if (current_user_can('manage_options') && is_admin()) {
35 if (isset($_GET['tab'])) {
36 $tab_value = sanitize_text_field(wp_unslash($_GET['tab']));
37 if (in_array($tab_value, array('settings', 'statistics'))) {
38 $current_tab = $tab_value;
39 }
40 }
41
42 if (isset($_GET['chart_period'])) {
43 $period_value = sanitize_text_field(wp_unslash($_GET['chart_period']));
44 if (in_array($period_value, array('daily', 'weekly', 'yearly'))) {
45 $chart_period = $period_value;
46 }
47 }
48
49 if (isset($_GET['start_date'])) {
50 $start_date_value = sanitize_text_field(wp_unslash($_GET['start_date']));
51 if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $start_date_value)) {
52 $start_date = $start_date_value;
53 }
54 }
55
56 if (isset($_GET['end_date'])) {
57 $end_date_value = sanitize_text_field(wp_unslash($_GET['end_date']));
58 if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $end_date_value)) {
59 $end_date = $end_date_value;
60 }
61 }
62
63 if (isset($_GET['pages_page'])) {
64 $pages_page = max(1, intval(wp_unslash($_GET['pages_page'])));
65 }
66
67 if (isset($_GET['countries_page'])) {
68 $countries_page = max(1, intval(wp_unslash($_GET['countries_page'])));
69 }
70
71 if (isset($_GET['referrers_page'])) {
72 $referrers_page = max(1, intval(wp_unslash($_GET['referrers_page'])));
73 }
74
75 if (isset($_GET['keywords_page'])) {
76 $keywords_page = max(1, intval(wp_unslash($_GET['keywords_page'])));
77 }
78 }
79
80 if (isset($_POST['save_analytics_settings'])) {
81 check_admin_referer('presslearn_save_analytics_settings_nonce');
82
83 if (current_user_can('manage_options')) {
84 $analytics_exclude_admin = isset($_POST['analytics_exclude_admin']) ? sanitize_text_field(wp_unslash($_POST['analytics_exclude_admin'])) : '';
85 update_option('presslearn_analytics_exclude_admin', $analytics_exclude_admin);
86
87 $use_cloudflare = isset($_POST['use_cloudflare']) ? 'yes' : 'no';
88 update_option('presslearn_analytics_use_cloudflare', $use_cloudflare);
89
90 $cache_time = isset($_POST['analytics_cache_time']) ? intval(wp_unslash($_POST['analytics_cache_time'])) : 300;
91 if ($cache_time < 60) $cache_time = 60;
92 if ($cache_time > 86400) $cache_time = 86400;
93 update_option('presslearn_analytics_cache_time', $cache_time);
94
95 $settings_updated = true;
96 }
97 }
98
99 $analytics_enabled = get_option('presslearn_analytics_enabled', 'no');
100 $analytics_exclude_admin = get_option('presslearn_analytics_exclude_admin', '');
101 $use_cloudflare = get_option('presslearn_analytics_use_cloudflare', 'no');
102 $analytics_cache_time = get_option('presslearn_analytics_cache_time', 300);
103
104
105 if (function_exists('presslearn_plugin') && method_exists(presslearn_plugin(), 'create_analytics_tables')) {
106 presslearn_plugin()->create_analytics_tables();
107 }
108
109 $pages_current_page = 1;
110 $countries_current_page = 1;
111 $referrers_current_page = 1;
112 $keywords_current_page = 1;
113 $items_per_page = 10;
114 $keywords_per_page = 20;
115
116 if (current_user_can('manage_options') && is_admin()) {
117 $pages_current_page = $pages_page;
118 $countries_current_page = $countries_page;
119 $referrers_current_page = $referrers_page;
120 $keywords_current_page = $keywords_page;
121
122 $allowed_tabs = array('settings', 'statistics', 'pages', 'countries', 'referrers', 'keywords');
123 if (!in_array($current_tab, $allowed_tabs)) {
124 $current_tab = 'settings';
125 }
126
127 $allowed_periods = array('daily', 'weekly', 'yearly');
128 if (!in_array($chart_period, $allowed_periods)) {
129 $chart_period = 'daily';
130 }
131
132 $pages_current_page = max(1, $pages_current_page);
133 $countries_current_page = max(1, $countries_current_page);
134 $referrers_current_page = max(1, $referrers_current_page);
135 $keywords_current_page = max(1, $keywords_current_page);
136 }
137
138 $default_end_date = gmdate('Y-m-d');
139 $default_start_date = gmdate('Y-m-d');
140
141 if (empty($start_date)) {
142 $start_date = $default_start_date;
143 }
144
145 if ($current_tab === 'statistics' && empty($start_date) && empty($end_date)) {
146 $start_date = $default_start_date;
147 $end_date = $default_end_date;
148 } else {
149 if (current_user_can('manage_options') && is_admin()) {
150 if (empty($start_date)) {
151 $start_date = $default_start_date;
152 }
153 if (empty($end_date)) {
154 $end_date = $default_end_date;
155 }
156
157 if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $start_date)) {
158 $start_date = $default_start_date;
159 }
160 if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $end_date)) {
161 $end_date = $default_end_date;
162 }
163 } else {
164 $start_date = $default_start_date;
165 $end_date = $default_end_date;
166 }
167 }
168
169 $start_date_obj = new DateTime($start_date);
170 $end_date_obj = new DateTime($end_date);
171 $date_diff = $start_date_obj->diff($end_date_obj);
172 $period_days = $date_diff->days + 1;
173
174 $period_days = max(1, $period_days);
175
176 if ($chart_period === 'daily') {
177 $period_days = min($period_days, 60);
178 } elseif ($chart_period === 'weekly') {
179 $period_days = min($period_days, 365);
180 } elseif ($chart_period === 'yearly') {
181 $period_days = min($period_days, 1825);
182 }
183
184 function alpack_get_analytics_stats($period = 'today', $days = 30, $start_date = null, $end_date = null) {
185 global $wpdb;
186 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
187
188 $cache_time = get_option('presslearn_analytics_cache_time', 300);
189 $cache_key = 'alpack_analytics_stats_' . md5($period . '_' . $days . '_' . $start_date . '_' . $end_date);
190 $cached_stats = get_transient($cache_key);
191
192 if ($cached_stats !== false) {
193 return $cached_stats;
194 }
195
196 $stats = [];
197
198 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
199 $where_clause = '';
200 $params = [];
201
202 if ($start_date && $end_date) {
203 $where_clause = "WHERE created_at >= %s AND created_at <= %s";
204 $params[] = $start_date . ' 00:00:00';
205 $params[] = $end_date . ' 23:59:59';
206 } else {
207 if($period == 'today') {
208 $where_clause = "WHERE DATE(created_at) = CURDATE()";
209 } elseif($period == 'week') {
210 $where_clause = "WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)";
211 $params[] = intval(min($days, 7));
212 } else {
213 $where_clause = "WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)";
214 $params[] = intval($days);
215 }
216 }
217
218 $pageviews = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_pageviews $where_clause", $params));
219 $visitors = $wpdb->get_var($wpdb->prepare("SELECT COUNT(DISTINCT visitor_id) FROM $table_pageviews $where_clause", $params));
220 $ip_visitors = $wpdb->get_var($wpdb->prepare("SELECT COUNT(DISTINCT ip) FROM $table_pageviews $where_clause", $params));
221
222 $stats = [
223 'pageviews' => intval($pageviews),
224 'visitors' => intval($visitors),
225 'ip_visitors' => intval($ip_visitors)
226 ];
227 } else {
228 $stats = [
229 'pageviews' => 0,
230 'visitors' => 0,
231 'ip_visitors' => 0
232 ];
233 }
234
235 set_transient($cache_key, $stats, $cache_time);
236
237 return $stats;
238 }
239
240 function alpack_get_popular_pages($limit = 12, $days = 30, $start_date = null, $end_date = null) {
241 global $wpdb;
242 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
243
244 $cache_time = get_option('presslearn_analytics_cache_time', 300);
245 $cache_key = 'alpack_popular_pages_' . md5($limit . '_' . $days . '_' . $start_date . '_' . $end_date);
246 $cached_pages = get_transient($cache_key);
247
248 if ($cached_pages !== false) {
249 return $cached_pages;
250 }
251
252 $popular_pages = [];
253
254 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
255 $where_clause = '';
256 $params = [];
257
258 if ($start_date && $end_date) {
259 $where_clause = "WHERE created_at >= %s AND created_at <= %s";
260 $params[] = $start_date . ' 00:00:00';
261 $params[] = $end_date . ' 23:59:59';
262 } else {
263 $where_clause = "WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)";
264 $params[] = $days;
265 }
266
267 $results = $wpdb->get_results(
268 $wpdb->prepare(
269 "SELECT url, title, COUNT(*) as views
270 FROM $table_pageviews
271 $where_clause
272 GROUP BY url, title
273 ORDER BY views DESC
274 LIMIT %d",
275 array_merge($params, [$limit])
276 ),
277 ARRAY_A
278 );
279
280 if($results) {
281 foreach($results as $row) {
282 $popular_pages[] = [
283 'url' => $row['url'],
284 'title' => $row['title'],
285 'views' => intval($row['views'])
286 ];
287 }
288 }
289 }
290
291 if(empty($popular_pages)) {
292 $popular_pages = [
293 [
294 'url' => home_url('/'),
295 'title' => '',
296 'views' => 0
297 ]
298 ];
299 }
300
301 set_transient($cache_key, $popular_pages, $cache_time);
302
303 return $popular_pages;
304 }
305
306 function alpack_get_visitor_countries($limit = 15, $days = 30, $start_date = null, $end_date = null) {
307 global $wpdb;
308 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
309
310 $cache_time = get_option('presslearn_analytics_cache_time', 300);
311 $cache_key = 'alpack_visitor_countries_' . md5($limit . '_' . $days . '_' . $start_date . '_' . $end_date);
312 $cached_countries = get_transient($cache_key);
313
314 if ($cached_countries !== false) {
315 return $cached_countries;
316 }
317
318 $visitor_countries = [];
319
320 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
321 $where_clause = '';
322 $params = [];
323
324 if ($start_date && $end_date) {
325 $where_clause = "WHERE created_at >= %s AND created_at <= %s";
326 $params[] = $start_date . ' 00:00:00';
327 $params[] = $end_date . ' 23:59:59';
328 } else {
329 $where_clause = "WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)";
330 $params[] = $days;
331 }
332
333 $where_clause .= " AND country != ''";
334
335 $results = $wpdb->get_results(
336 $wpdb->prepare(
337 "SELECT country, COUNT(DISTINCT visitor_id) as count
338 FROM $table_pageviews
339 $where_clause
340 GROUP BY country
341 ORDER BY count DESC
342 LIMIT %d",
343 array_merge($params, [$limit])
344 ),
345 ARRAY_A
346 );
347
348 if($results) {
349 foreach($results as $row) {
350 $visitor_countries[] = [
351 'country' => $row['country'],
352 'count' => intval($row['count'])
353 ];
354 }
355 }
356 }
357
358 if(empty($visitor_countries)) {
359 $visitor_countries = [
360 ['country' => '데이터 없음', 'count' => 0]
361 ];
362 }
363
364 set_transient($cache_key, $visitor_countries, $cache_time);
365
366 return $visitor_countries;
367 }
368
369 function alpack_get_organic_keywords($limit = 20, $days = 30, $offset = 0, $start_date = null, $end_date = null) {
370 global $wpdb;
371 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
372
373 $cache_time = get_option('presslearn_analytics_cache_time', 300);
374 $cache_key = 'alpack_organic_keywords_' . md5($limit . '_' . $days . '_' . $offset . '_' . $start_date . '_' . $end_date);
375 $cached_keywords = get_transient($cache_key);
376
377 if ($cached_keywords !== false) {
378 return $cached_keywords;
379 }
380
381 $organic_keywords = [];
382
383 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
384 $where_clause = '';
385 $params = [];
386
387 if ($start_date && $end_date) {
388 $where_clause = "WHERE created_at >= %s AND created_at <= %s";
389 $params[] = $start_date . ' 00:00:00';
390 $params[] = $end_date . ' 23:59:59';
391 } else {
392 $where_clause = "WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)";
393 $params[] = intval($days);
394 }
395
396 $where_clause .= " AND referrer != ''";
397
398 $results = $wpdb->get_results(
399 $wpdb->prepare(
400 "SELECT
401 referrer,
402 COUNT(*) as count
403 FROM $table_pageviews
404 $where_clause
405 GROUP BY referrer
406 ORDER BY count DESC",
407 $params
408 ),
409 ARRAY_A
410 );
411
412 if($results) {
413 $keywords_found = [];
414
415 foreach($results as $row) {
416 $referrer = $row['referrer'];
417 $keyword = '';
418 $search_engine = '';
419 $search_engine_display = '';
420
421 if(strpos($referrer, 'google') !== false && strpos($referrer, 'search') !== false) {
422 $search_engine = '구글';
423 $search_engine_display = '구글';
424 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
425 $keyword = isset($params['q']) ? $params['q'] : '';
426
427 if(empty($keyword)) {
428 $keyword = '(not provided)';
429 }
430 }
431 elseif(strpos($referrer, 'google.co.kr') !== false || strpos($referrer, 'google.com') !== false) {
432 $search_engine = '구글';
433 $search_engine_display = '구글';
434 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
435 $keyword = isset($params['q']) ? $params['q'] : '';
436
437 if(empty($keyword)) {
438 $keyword = '(not provided)';
439 }
440 }
441 elseif(strpos($referrer, 'search.naver.com') !== false || strpos($referrer, 'naver.com') !== false) {
442 $search_engine = '네이버';
443 if(strpos($referrer, 'm.search.naver.com') !== false || strpos($referrer, 'm.naver.com') !== false) {
444 $search_engine_display = '네이버 모바일';
445 } else {
446 $search_engine_display = '네이버';
447 }
448 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
449 $keyword = isset($params['query']) ? $params['query'] : '';
450 }
451 elseif((strpos($referrer, 'daum.net') !== false && strpos($referrer, 'search') !== false) ||
452 strpos($referrer, 'search.daum.net') !== false) {
453 $search_engine = '다음';
454 $search_engine_display = '다음';
455 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
456 $keyword = isset($params['q']) ? $params['q'] : '';
457 if(empty($keyword)) {
458 $keyword = isset($params['w']) ? $params['w'] : '';
459 }
460 }
461 elseif(strpos($referrer, 'bing.com') !== false && strpos($referrer, 'search') !== false) {
462 $search_engine = '';
463 $search_engine_display = '';
464 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
465 $keyword = isset($params['q']) ? $params['q'] : '';
466 }
467 elseif(strpos($referrer, 'yahoo.com') !== false && strpos($referrer, 'search') !== false) {
468 $search_engine = '야후';
469 $search_engine_display = '야후';
470 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
471 $keyword = isset($params['p']) ? $params['p'] : '';
472 }
473
474 if(!empty($search_engine)) {
475 if(empty($keyword) && $search_engine === 'Google') {
476 $keyword = '(not provided)';
477 }
478
479 if(!empty($keyword)) {
480 $keyword_key = md5($keyword . $search_engine);
481
482 if(isset($keywords_found[$keyword_key])) {
483 $keywords_found[$keyword_key]['count'] += intval($row['count']);
484 } else {
485 $keywords_found[$keyword_key] = [
486 'keyword' => $keyword,
487 'search_engine' => $search_engine,
488 'search_engine_display' => $search_engine_display,
489 'count' => intval($row['count']),
490 'referrer' => $referrer
491 ];
492 }
493 }
494 }
495 }
496
497 usort($keywords_found, function($a, $b) {
498 return $b['count'] - $a['count'];
499 });
500
501 $organic_keywords = array_slice(array_values($keywords_found), $offset, $limit);
502 }
503 }
504
505 if(empty($organic_keywords)) {
506 $organic_keywords = [
507 [
508 'keyword' => '아직 수집된 키워드가 없습니다',
509 'count' => 0,
510 'search_engine' => 'None',
511 'search_engine_display' => 'None'
512 ]
513 ];
514 }
515
516 set_transient($cache_key, $organic_keywords, $cache_time);
517
518 return $organic_keywords;
519 }
520
521 function alpack_get_total_organic_keywords_count($days = 30, $start_date = null, $end_date = null) {
522 global $wpdb;
523 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
524
525 $cache_time = get_option('presslearn_analytics_cache_time', 300);
526 $cache_key = 'alpack_total_keywords_count_' . md5($days . '_' . $start_date . '_' . $end_date);
527 $cached_count = get_transient($cache_key);
528
529 if ($cached_count !== false) {
530 return $cached_count;
531 }
532
533 $count = 0;
534
535 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
536 $where_clause = '';
537 $params = [];
538
539 if ($start_date && $end_date) {
540 $where_clause = "WHERE created_at >= %s AND created_at <= %s";
541 $params[] = $start_date . ' 00:00:00';
542 $params[] = $end_date . ' 23:59:59';
543 } else {
544 $where_clause = "WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)";
545 $params[] = $days;
546 }
547
548 $where_clause .= " AND referrer != ''";
549
550 $results = $wpdb->get_results(
551 $wpdb->prepare(
552 "SELECT referrer
553 FROM $table_pageviews
554 $where_clause
555 GROUP BY referrer",
556 $params
557 ),
558 ARRAY_A
559 );
560
561 if($results) {
562 $unique_keywords = [];
563
564 foreach($results as $row) {
565 $referrer = $row['referrer'];
566 $keyword = '';
567 $search_engine = '';
568
569 if(strpos($referrer, 'google') !== false && strpos($referrer, 'search') !== false) {
570 $search_engine = '구글';
571 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
572 $keyword = isset($params['q']) ? $params['q'] : '(not provided)';
573 }
574 elseif(strpos($referrer, 'google.co.kr') !== false || strpos($referrer, 'google.com') !== false) {
575 $search_engine = '구글';
576 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
577 $keyword = isset($params['q']) ? $params['q'] : '(not provided)';
578 }
579 elseif(strpos($referrer, 'search.naver.com') !== false || strpos($referrer, 'naver.com') !== false) {
580 $search_engine = '네이버';
581 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
582 $keyword = isset($params['query']) ? $params['query'] : '';
583 }
584 elseif((strpos($referrer, 'daum.net') !== false && strpos($referrer, 'search') !== false) ||
585 strpos($referrer, 'search.daum.net') !== false) {
586 $search_engine = '다음';
587 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
588 $keyword = isset($params['q']) ? $params['q'] : '';
589 if(empty($keyword)) {
590 $keyword = isset($params['w']) ? $params['w'] : '';
591 }
592 }
593 elseif(strpos($referrer, 'bing.com') !== false && strpos($referrer, 'search') !== false) {
594 $search_engine = '';
595 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
596 $keyword = isset($params['q']) ? $params['q'] : '';
597 }
598 elseif(strpos($referrer, 'yahoo.com') !== false && strpos($referrer, 'search') !== false) {
599 $search_engine = '야후';
600 parse_str(wp_parse_url($referrer, PHP_URL_QUERY), $params);
601 $keyword = isset($params['p']) ? $params['p'] : '';
602 }
603
604 if(!empty($search_engine)) {
605 if(empty($keyword) && $search_engine === 'Google') {
606 $keyword = '(not provided)';
607 }
608
609 if(!empty($keyword)) {
610 $key = md5($keyword . $search_engine);
611 if(!isset($unique_keywords[$key])) {
612 $unique_keywords[$key] = true;
613 $count++;
614 }
615 }
616 }
617 }
618 }
619 }
620
621 set_transient($cache_key, $count, $cache_time);
622
623 return $count;
624 }
625
626 function alpack_get_referrers($limit = 15, $days = 30, $start_date = null, $end_date = null) {
627 global $wpdb;
628 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
629 $table_referrers = $wpdb->prefix . 'presslearn_referrers';
630
631 $cache_time = get_option('presslearn_analytics_cache_time', 300);
632 $cache_key = 'alpack_referrers_' . md5($limit . '_' . $days . '_' . $start_date . '_' . $end_date);
633 $cached_referrers = get_transient($cache_key);
634
635 if ($cached_referrers !== false) {
636 return $cached_referrers;
637 }
638
639 $referrers = [];
640
641 $site_host = wp_parse_url(site_url(), PHP_URL_HOST);
642
643 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
644 $where_clause = '';
645 $params = [];
646
647 if ($start_date && $end_date) {
648 $where_clause = "WHERE created_at >= %s AND created_at <= %s AND referrer != ''";
649 $params[] = $start_date . ' 00:00:00';
650 $params[] = $end_date . ' 23:59:59';
651 } else {
652 $where_clause = "WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY) AND referrer != ''";
653 $params[] = intval($days);
654 }
655
656 $results = $wpdb->get_results(
657 $wpdb->prepare(
658 "SELECT
659 referrer,
660 COUNT(*) as count
661 FROM $table_pageviews
662 $where_clause
663 GROUP BY referrer
664 ORDER BY count DESC",
665 $params
666 ),
667 ARRAY_A
668 );
669
670 if(!empty($results)) {
671 $referrer_groups = [];
672
673 foreach($results as $row) {
674 $referrer = $row['referrer'];
675 $count = intval($row['count']);
676
677 if (empty($referrer)) continue;
678
679 $referrer_host = wp_parse_url($referrer, PHP_URL_HOST);
680 if (empty($referrer_host)) continue;
681
682 $group_name = $referrer_host;
683 $type = '외부 유�
684 ';
685
686 if (strpos($referrer_host, 'google') !== false && (strpos($referrer_host, 'search') !== false || $referrer_host === 'google.com' || $referrer_host === 'google.co.kr' || preg_match('/^(www\.)?google\..+$/', $referrer_host))) {
687 $group_name = '구글';
688 $type = '자연 유�
689 ';
690 } elseif (strpos($referrer_host, 'naver.com') !== false) {
691 if (strpos($referrer_host, 'blog.naver.com') !== false || strpos($referrer_host, 'm.blog.naver.com') !== false) {
692 $group_name = '네이버 블로그';
693 $type = '외부 유�
694 ';
695 } else {
696 $group_name = '네이버';
697 $type = '자연 유�
698 ';
699 }
700 } elseif (strpos($referrer_host, 'daum.net') !== false) {
701 $group_name = '다음';
702 $type = '자연 유�
703 ';
704 } elseif (strpos($referrer_host, 'facebook.com') !== false) {
705 $group_name = '페이스북';
706 $type = '외부 유�
707 ';
708 } elseif (strpos($referrer_host, 'instagram.com') !== false) {
709 $group_name = '인스타그램';
710 $type = '외부 유�
711 ';
712 } elseif (strpos($referrer_host, 'twitter.com') !== false) {
713 $group_name = '트위터';
714 $type = '외부 유�
715 ';
716 } elseif (strpos($referrer_host, 'bing.com') !== false) {
717 $group_name = '';
718 $type = '자연 유�
719 ';
720 } elseif (strpos($referrer_host, 'yahoo.com') !== false) {
721 $group_name = '야후';
722 $type = '자연 유�
723 ';
724 } elseif (strpos($referrer_host, 'youtube.com') !== false) {
725 $group_name = '유튜브';
726 $type = '외부 유�
727 ';
728 } elseif (strpos($referrer_host, 'kakao') !== false) {
729 $group_name = '카카오톡';
730 $type = '외부 유�
731 ';
732 } else {
733 $type = '외부 유�
734 ';
735 }
736
737 if (!isset($referrer_groups[$group_name])) {
738 $referrer_groups[$group_name] = [
739 'referrer' => $group_name,
740 'count' => 0,
741 'details' => [],
742 'total_urls' => 0,
743 'type' => $type
744 ];
745 }
746
747 $referrer_groups[$group_name]['count'] += $count;
748 $referrer_groups[$group_name]['details'][] = [
749 'url' => $referrer,
750 'count' => $count
751 ];
752 $referrer_groups[$group_name]['total_urls']++;
753 }
754
755 foreach ($referrer_groups as $key => $group) {
756 usort($referrer_groups[$key]['details'], function($a, $b) {
757 return $b['count'] - $a['count'];
758 });
759 if (count($referrer_groups[$key]['details']) > 10) {
760 $referrer_groups[$key]['details'] = array_slice($referrer_groups[$key]['details'], 0, 10);
761 }
762 }
763
764 $referrers = array_values($referrer_groups);
765 usort($referrers, function($a, $b) {
766 return $b['count'] - $a['count'];
767 });
768 } else {
769 }
770 }
771
772 $has_direct = false;
773 foreach($referrers as $ref) {
774 if($ref['referrer'] === '직접 접속') {
775 $has_direct = true;
776 break;
777 }
778 }
779
780 if(!$has_direct) {
781 $direct_count = 0;
782
783 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
784 if ($start_date && $end_date) {
785 $direct_count = $wpdb->get_var($wpdb->prepare("
786 SELECT COUNT(*) FROM $table_pageviews
787 WHERE (referrer = '' OR referrer IS NULL)
788 AND created_at >= %s AND created_at <= %s
789 ", $start_date . ' 00:00:00', $end_date . ' 23:59:59'));
790 } else {
791 $direct_count = $wpdb->get_var($wpdb->prepare("
792 SELECT COUNT(*) FROM $table_pageviews
793 WHERE (referrer = '' OR referrer IS NULL)
794 AND created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)
795 ", $days));
796 }
797 }
798
799 if($direct_count > 0) {
800 array_unshift($referrers, [
801 'referrer' => '직접 접속',
802 'count' => intval($direct_count),
803 'details' => [
804 ['url' => '네이버 QR 링크 혹은 직접 URL �
805 ', 'count' => intval($direct_count)]
806 ],
807 'total_urls' => 1,
808 'type' => '직접 유�
809 '
810 ]);
811 }
812 }
813
814 if(empty($referrers)) {
815 $pageviews_count = 0;
816 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) == $table_pageviews) {
817 if ($start_date && $end_date) {
818 $pageviews_count = $wpdb->get_var($wpdb->prepare(
819 "SELECT COUNT(*) FROM $table_pageviews WHERE created_at >= %s AND created_at <= %s",
820 $start_date . ' 00:00:00', $end_date . ' 23:59:59'
821 ));
822 } else {
823 $pageviews_count = $wpdb->get_var($wpdb->prepare(
824 "SELECT COUNT(*) FROM $table_pageviews WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL %d DAY)",
825 $days
826 ));
827 }
828 }
829
830 if($pageviews_count > 0) {
831 $referrers = [
832 [
833 'referrer' => '직접 접속',
834 'count' => intval($pageviews_count),
835 'details' => [
836 ['url' => '네이버 QR 링크 혹은 직접 URL �
837 ', 'count' => intval($pageviews_count)]
838 ],
839 'total_urls' => 1,
840 'type' => '직접 유�
841 '
842 ]
843 ];
844 } else {
845 $referrers = [
846 [
847 'referrer' => '데이터 없음',
848 'count' => 0,
849 'details' => [
850 ['url' => '아직 레퍼러 데이터가 수집되지 않았습니다', 'count' => 0]
851 ],
852 'total_urls' => 0,
853 'type' => ''
854 ]
855 ];
856 }
857 }
858
859 $result = array_slice($referrers, 0, $limit);
860
861 set_transient($cache_key, $result, $cache_time);
862
863 return $result;
864 }
865
866 function alpack_get_chart_data($period = 'daily', $start_date = null, $end_date = null) {
867 global $wpdb;
868 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
869
870 $cache_time = get_option('presslearn_analytics_cache_time', 300);
871 $cache_key = 'alpack_chart_data_' . md5($period . '_' . $start_date . '_' . $end_date);
872 $cached_data = get_transient($cache_key);
873
874 if ($cached_data !== false) {
875 return $cached_data;
876 }
877
878 $data = [
879 'labels' => [],
880 'pageviews' => [],
881 'visitors' => [],
882 'ip_visitors' => [],
883 'raw_dates' => []
884 ];
885
886 if($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_pageviews)) != $table_pageviews) {
887 set_transient($cache_key, $data, $cache_time);
888 return $data;
889 }
890
891 $limit = 60;
892 $today = gmdate('Y-m-d');
893
894 if ($start_date && $end_date && $start_date == $end_date && $start_date == $today) {
895 $select_period = "HOUR(created_at)";
896 $select_label = "HOUR(created_at)";
897 $limit = 24;
898 }
899 else if ($period === 'weekly') {
900 $select_period = "YEARWEEK(created_at, 1)";
901 $select_label = "MIN(created_at)";
902 $limit = 52;
903 }
904 else if ($period === 'yearly') {
905 $select_period = "YEAR(created_at)";
906 $select_label = "YEAR(created_at)";
907 $group_by = "YEAR(created_at)";
908 $limit = 10;
909 }
910 else {
911 $select_period = "DATE(created_at)";
912 $select_label = "DATE(created_at)";
913 }
914
915 $table_pageviews = esc_sql($table_pageviews);
916 $select_period = esc_sql($select_period);
917 $select_label = esc_sql($select_label);
918
919 $where_clause = '';
920 $sql_params = [];
921
922 if ($start_date && $end_date) {
923 $where_clause = "WHERE created_at >= %s AND created_at <= %s";
924 $sql_params[] = $start_date . ' 00:00:00';
925 $sql_params[] = $end_date . ' 23:59:59';
926 }
927
928 $sql = "SELECT
929 {$select_period} as period,
930 {$select_label} as period_label,
931 MIN(created_at) as period_start,
932 MAX(created_at) as period_end,
933 COUNT(*) as pageviews,
934 COUNT(DISTINCT visitor_id) as visitors,
935 COUNT(DISTINCT ip) as ip_visitors
936 FROM {$table_pageviews}";
937
938 if (!empty($where_clause)) {
939 $sql .= " $where_clause";
940 }
941
942 $sql .= " GROUP BY " . (isset($group_by) ? $group_by : "period") . " ORDER BY period ASC LIMIT %d";
943 $sql_params[] = $limit;
944
945 $results = $wpdb->get_results(
946 $wpdb->prepare($sql, $sql_params),
947 ARRAY_A
948 );
949
950 if ($results) {
951 if ($start_date && $end_date && $start_date == $end_date && $start_date == $today) {
952 $hour_data = [];
953 foreach ($results as $row) {
954 $hour = intval($row['period_label']);
955 $hour_data[$hour] = $row;
956 }
957
958 $results = [];
959 for ($hour = 0; $hour < 24; $hour++) {
960 if (isset($hour_data[$hour])) {
961 $results[] = $hour_data[$hour];
962 } else {
963 $hour_str = sprintf('%02d', $hour);
964 $results[] = [
965 'period' => $hour,
966 'period_label' => $hour_str,
967 'period_start' => gmdate('Y-m-d H:i:s', strtotime("$today $hour_str:00:00")),
968 'period_end' => gmdate('Y-m-d H:i:s', strtotime("$today $hour_str:59:59")),
969 'pageviews' => 0,
970 'visitors' => 0,
971 'ip_visitors' => 0
972 ];
973 }
974 }
975 }
976
977 foreach ($results as $row) {
978 if ($start_date && $end_date && $start_date == $end_date && $start_date == $today) {
979 $hour = intval($row['period_label']);
980 $data['labels'][] = $hour . '';
981 }
982 else if ($period === 'weekly') {
983 $week_start = new DateTime($row['period_start']);
984 $week_end = new DateTime($row['period_end']);
985 $data['labels'][] = $week_start->format('m/d') . '~' . $week_end->format('m/d');
986 }
987 else if ($period === 'yearly') {
988 if (!empty($row['period_label'])) {
989 $year = intval($row['period_label']);
990 $data['labels'][] = $year . '�
991 �';
992 } else if (!empty($row['period_start'])) {
993 $year_date = new DateTime($row['period_start']);
994 $data['labels'][] = $year_date->format('Y�
995 �');
996 } else {
997 $data['labels'][] = '데이터 없음';
998 }
999 }
1000 else {
1001 $day_date = new DateTime($row['period_label']);
1002 $data['labels'][] = $day_date->format('m/d');
1003 }
1004
1005 $data['pageviews'][] = intval($row['pageviews']);
1006 $data['visitors'][] = intval($row['visitors']);
1007 $data['ip_visitors'][] = intval($row['ip_visitors']);
1008
1009 $data['raw_dates'][] = [
1010 'start' => $row['period_start'],
1011 'end' => $row['period_end'],
1012 'period' => ($start_date && $end_date && $start_date == $end_date && $start_date == $today) ? 'hourly' : $period
1013 ];
1014 }
1015 } else {
1016 set_transient($cache_key, $data, $cache_time);
1017 return $data;
1018 }
1019
1020 set_transient($cache_key, $data, $cache_time);
1021
1022 return $data;
1023 }
1024
1025 $dummy_stats = [
1026 'today' => alpack_get_analytics_stats('today', 0, $start_date, $end_date),
1027 'week' => alpack_get_analytics_stats('week', $period_days, $start_date, $end_date),
1028 'month' => alpack_get_analytics_stats('month', $period_days, $start_date, $end_date)
1029 ];
1030
1031 $popular_pages = alpack_get_popular_pages(50, $period_days, $start_date, $end_date);
1032 $total_pages = ceil(count($popular_pages) / $items_per_page);
1033 $pages_offset = ($pages_current_page - 1) * $items_per_page;
1034 $pages_to_display = array_slice($popular_pages, $pages_offset, $items_per_page);
1035
1036 $visitor_countries = alpack_get_visitor_countries(50, $period_days, $start_date, $end_date);
1037 $total_countries = ceil(count($visitor_countries) / $items_per_page);
1038 $countries_offset = ($countries_current_page - 1) * $items_per_page;
1039 $countries_to_display = array_slice($visitor_countries, $countries_offset, $items_per_page);
1040
1041 $referrers = alpack_get_referrers(30, $period_days, $start_date, $end_date);
1042 $total_referrers = ceil(count($referrers) / $items_per_page);
1043 $referrers_offset = ($referrers_current_page - 1) * $items_per_page;
1044 $referrers_to_display = array_slice($referrers, $referrers_offset, $items_per_page);
1045
1046 $total_keywords_count = alpack_get_total_organic_keywords_count($period_days, $start_date, $end_date);
1047 $total_keywords_pages = ceil($total_keywords_count / $keywords_per_page);
1048 $keywords_offset = ($keywords_current_page - 1) * $keywords_per_page;
1049 $organic_keywords = alpack_get_organic_keywords($keywords_per_page, $period_days, $keywords_offset, $start_date, $end_date);
1050
1051 $chart_data = alpack_get_chart_data($chart_period, $start_date, $end_date);
1052
1053 $GLOBALS['presslearn_chart_data'] = $chart_data;
1054 $GLOBALS['presslearn_chart_period'] = $chart_period;
1055 $GLOBALS['presslearn_referrers_to_display'] = $referrers_to_display;
1056
1057 ?>
1058 <div class="presslearn-header">
1059 <div class="presslearn-header-logo">
1060 <img src="<?php echo esc_url(PRESSLEARN_PLUGIN_URL); ?>assets/images/logo.png" alt="PressLearn Logo">
1061 <h1>씬 애널리틱스</h1>
1062 </div>
1063 <div class="presslearn-header-status">
1064 <?php if ($analytics_enabled === 'yes'): ?>
1065 <div class="presslearn-header-status-item status-activate">
1066 <p>기능이 활성화되었습니다.</p>
1067 </div>
1068 <?php else: ?>
1069 <div class="presslearn-header-status-item status-deactivate">
1070 <p>기능이 비활성화 상태�
1071 니다.</p>
1072 </div>
1073 <?php endif; ?>
1074 </div>
1075 </div>
1076
1077 <div class="wrap">
1078
1079 <div id="presslearn-banner-container" class="presslearn-banner-container" style="margin-left: 0; margin-right: 0;">
1080 <div id="presslearn-banner" class="presslearn-banner">
1081 <a href="#" id="presslearn-banner-link" target="_blank" class="presslearn-banner-link">
1082 <img src="" id="presslearn-banner-image" class="presslearn-banner-image">
1083 </a>
1084 </div>
1085 <div id="presslearn-banner-skeleton" class="presslearn-banner-skeleton">
1086 <div class="presslearn-banner-skeleton-content"></div>
1087 </div>
1088 </div>
1089
1090 <div class="presslearn-breadcrumbs-wrap">
1091 <div class="presslearn-breadcrumbs">
1092 <span>대시보드</span>
1093 <span class="divider">/</span>
1094 <span class="active">씬 애널리틱스</span>
1095 </div>
1096 </div>
1097
1098 <?php if (isset($settings_updated) && $settings_updated): ?>
1099 <div class="notice notice-success inline">
1100 <p>설정 정보가 성공적으로 저장되었습니다.</p>
1101 </div>
1102 <?php endif; ?>
1103
1104 <div class="presslearn-tabs">
1105 <a href="?page=presslearn-analytics&tab=settings" class="tab-link <?php echo esc_attr($current_tab === 'settings' ? 'active' : ''); ?>">설정</a>
1106 <a href="?page=presslearn-analytics&tab=statistics" class="tab-link <?php echo esc_attr($current_tab === 'statistics' ? 'active' : ''); ?>">통계</a>
1107 </div>
1108
1109 <?php if ($current_tab === 'settings'): ?>
1110
1111 <div class="presslearn-card">
1112 <div class="presslearn-card-header">
1113 <h2>씬 애널리틱스</h2>
1114 <p>페이지 별 애널리틱스 기능이 포함되어 있는 경량 애널리틱스 기능�
1115 니다.</p>
1116 </div>
1117 <div class="presslearn-card-body">
1118 <div class="presslearn-card-body-row">
1119 <div class="presslearn-card-body-row-item grid-left">
1120 <h3>플러그인 기능 활성화</h3>
1121 </div>
1122 <div class="presslearn-card-body-row-item grid-right">
1123 <form method="post" action="" id="analytics-toggle-form">
1124 <?php wp_nonce_field('presslearn_toggle_analytics_nonce'); ?>
1125 <input type="hidden" name="presslearn_toggle_analytics" value="1">
1126 <input type="hidden" name="enable" id="analytics-enable-value" value="<?php echo esc_attr($analytics_enabled === 'yes' ? 'no' : 'yes'); ?>">
1127
1128 <label class="switch">
1129 <input type="checkbox" <?php echo esc_attr($analytics_enabled === 'yes' ? 'checked' : ''); ?> onchange="document.getElementById('analytics-enable-value').value = this.checked ? 'yes' : 'no'; document.getElementById('analytics-toggle-form').submit();">
1130 <span class="slider round"></span>
1131 </label>
1132 </form>
1133 </div>
1134 </div>
1135 <div class="presslearn-card-body-row">
1136 <div class="presslearn-card-body-row-item grid-left">
1137 <h3>CloudFlare 사용</h3>
1138 </div>
1139 <div class="presslearn-card-body-row-item grid-right">
1140 <form method="post" action="" id="analytics-settings-form">
1141 <?php wp_nonce_field('presslearn_save_analytics_settings_nonce'); ?>
1142 <input type="hidden" name="save_analytics_settings" value="1">
1143
1144 <label class="switch">
1145 <input type="checkbox" name="use_cloudflare" <?php echo esc_attr($use_cloudflare === 'yes' ? 'checked' : ''); ?>>
1146 <span class="slider round"></span>
1147 </label>
1148 </form>
1149 </div>
1150 </div>
1151 <div class="presslearn-card-body-row">
1152 <div class="presslearn-card-body-row-item grid-left">
1153 <h3>관리자 IP 통계 제외</h3>
1154 </div>
1155 <div class="presslearn-card-body-row-item grid-right">
1156 <input type="text" class="regular-text" name="analytics_exclude_admin" form="analytics-settings-form" value="<?php echo esc_attr($analytics_exclude_admin); ?>" placeholder="예: 127.0.0.1, 192.168.0.1">
1157 </div>
1158 </div>
1159 <div class="presslearn-card-body-row">
1160 <div class="presslearn-card-body-row-item grid-left">
1161 <h3>캐싱 시간 설정</h3>
1162 </div>
1163 <div class="presslearn-card-body-row-item grid-right">
1164 <select name="analytics_cache_time" form="analytics-settings-form">
1165 <option value="60" <?php selected($analytics_cache_time, 60); ?>>1분</option>
1166 <option value="300" <?php selected($analytics_cache_time, 300); ?>>5분</option>
1167 <option value="600" <?php selected($analytics_cache_time, 600); ?>>10분</option>
1168 <option value="1800" <?php selected($analytics_cache_time, 1800); ?>>30분</option>
1169 <option value="3600" <?php selected($analytics_cache_time, 3600); ?>>1시간</option>
1170 <option value="3600" <?php selected($analytics_cache_time, 7200); ?>>2시간</option>
1171 <option value="3600" <?php selected($analytics_cache_time, 14400); ?>>4시간</option>
1172 <option value="86400" <?php selected($analytics_cache_time, 86400); ?>>1일</option>
1173 </select>
1174 </div>
1175 </div>
1176 <div class="presslearn-card-body-row">
1177 <div class="presslearn-card-body-row-item grid-left">
1178 <h3>통계 데이터 삭제</h3>
1179 </div>
1180 <div class="presslearn-card-body-row-item grid-right">
1181 <button type="button" class="negative-btn" id="delete-analytics-btn">통계 데이터 삭제</button>
1182 </div>
1183 </div>
1184 </div>
1185 <div class="presslearn-card-footer">
1186 <div class="presslearn-card-footer-item grid-left">
1187 <span class="tip_button">방문자가 많을 경우 캐싱 시간을 늘려야 서버에 부하가 적습니다.</span>
1188 </div>
1189 <div class="presslearn-card-footer-item grid-right">
1190 <button type="submit" class="point-btn" form="analytics-settings-form">저장하기</button>
1191 </div>
1192 </div>
1193 </div>
1194
1195 <?php else: ?>
1196 <div class="presslearn-card">
1197 <div class="presslearn-card-header">
1198 <h2>방문자 통계</h2>
1199 <p>사이트 방문자 및 페이지뷰 통계를 확인할 수 있습니다.</p>
1200 </div>
1201 <div class="presslearn-card-body">
1202 <div class="presslearn-card-body-row">
1203 <div class="presslearn-card-body-row-item" style="flex: 100%;">
1204 <h3 style="margin-bottom: 15px;">기간별 요약 (차트)</h3>
1205
1206 <div class="chart-period-tabs">
1207 <?php
1208 $date_params = '';
1209 if ($start_date && $end_date) {
1210 $date_params = '&start_date=' . esc_attr($start_date) . '&end_date=' . esc_attr($end_date);
1211 }
1212
1213 $page_params = '';
1214 if ($pages_page > 1) {
1215 $page_params .= '&pages_page=' . esc_attr($pages_page);
1216 }
1217 if ($countries_page > 1) {
1218 $page_params .= '&countries_page=' . esc_attr($countries_page);
1219 }
1220 if ($referrers_page > 1) {
1221 $page_params .= '&referrers_page=' . esc_attr($referrers_page);
1222 }
1223 if ($keywords_page > 1) {
1224 $page_params .= '&keywords_page=' . esc_attr($keywords_page);
1225 }
1226 ?>
1227 <div class="period-buttons">
1228 <a href="?page=presslearn-analytics&tab=statistics&chart_period=daily<?php echo esc_attr($page_params) . esc_attr($date_params); ?>" class="chart-tab <?php echo esc_attr($chart_period === 'daily' ? 'active' : ''); ?>">일간</a>
1229 <a href="?page=presslearn-analytics&tab=statistics&chart_period=weekly<?php echo esc_attr($page_params) . esc_attr($date_params); ?>" class="chart-tab <?php echo esc_attr($chart_period === 'weekly' ? 'active' : ''); ?>">주간</a>
1230 <a href="?page=presslearn-analytics&tab=statistics&chart_period=yearly<?php echo esc_attr($page_params) . esc_attr($date_params); ?>" class="chart-tab <?php echo esc_attr($chart_period === 'yearly' ? 'active' : ''); ?>">연간</a>
1231 <button type="button" class="chart-tab" id="today-btn">오늘</button>
1232 </div>
1233
1234 <div class="date-range-picker-container">
1235 <form id="date-range-form" method="get" action="">
1236 <input type="hidden" name="page" value="presslearn-analytics">
1237 <input type="hidden" name="tab" value="statistics">
1238 <input type="hidden" name="chart_period" value="<?php echo esc_attr($chart_period); ?>">
1239
1240 <?php
1241 if ($pages_page > 1) {
1242 echo '<input type="hidden" name="pages_page" value="' . esc_attr($pages_page) . '">';
1243 }
1244 if ($countries_page > 1) {
1245 echo '<input type="hidden" name="countries_page" value="' . esc_attr($countries_page) . '">';
1246 }
1247 if ($referrers_page > 1) {
1248 echo '<input type="hidden" name="referrers_page" value="' . esc_attr($referrers_page) . '">';
1249 }
1250 if ($keywords_page > 1) {
1251 echo '<input type="hidden" name="keywords_page" value="' . esc_attr($keywords_page) . '">';
1252 }
1253 ?>
1254
1255 <div class="date-inputs">
1256 <input type="date" id="start_date" name="start_date" value="<?php echo esc_attr($start_date); ?>" max="<?php echo esc_attr($end_date); ?>">
1257 <span>~</span>
1258 <input type="date" id="end_date" name="end_date" value="<?php echo esc_attr($end_date); ?>" min="<?php echo esc_attr($start_date); ?>" max="<?php echo esc_attr(gmdate('Y-m-d')); ?>">
1259 <button type="submit" class="point-btn">적용</button>
1260 </div>
1261 </form>
1262 </div>
1263 </div>
1264
1265 <div class="chart-container" style="position: relative; height: 400px; width: 100%; max-width: 100%; overflow: hidden; box-sizing: border-box; padding-top: 30px; margin-top: 10px;">
1266 <canvas id="analyticsChart" style="max-width: 100%;"></canvas>
1267 </div>
1268
1269 <?php
1270 add_action('admin_footer', function() use ($chart_data, $chart_period, $referrers_to_display, $current_tab) {
1271 if ($current_tab === 'statistics') {
1272 presslearn_render_analytics_scripts($chart_data, $chart_period, $referrers_to_display);
1273 }
1274 });
1275 ?>
1276 </div>
1277 </div>
1278
1279 <div class="presslearn-card-body-row">
1280 <div class="presslearn-card-body-row-item" style="flex: 100%;">
1281 <h3 style="margin-bottom: 15px;">기간별 요약</h3>
1282
1283 <div class="stats-summary">
1284 <div class="stat-item">
1285 <h3><?php echo ($start_date && $end_date) ? ($start_date == gmdate('Y-m-d') && $end_date == gmdate('Y-m-d') ? esc_html('오늘') : esc_html(date_i18n('Y�
1286 � m월 d일', strtotime($start_date))) . ' ~ ' . esc_html(date_i18n('Y�
1287 � m월 d일', strtotime($end_date)))) : esc_html('오늘'); ?></h3>
1288 <div class="stat-value"><?php echo esc_html(number_format($dummy_stats['today']['pageviews'])); ?></div>
1289 <p>페이지뷰</p>
1290 </div>
1291 <div class="stat-item">
1292 <h3><?php echo ($start_date && $end_date) ? ($start_date == gmdate('Y-m-d') && $end_date == gmdate('Y-m-d') ? esc_html('오늘') : esc_html(date_i18n('Y�
1293 � m월 d일', strtotime($start_date))) . ' ~ ' . esc_html(date_i18n('Y�
1294 � m월 d일', strtotime($end_date)))) : esc_html('오늘'); ?></h3>
1295 <div class="stat-value"><?php echo esc_html(number_format($dummy_stats['today']['ip_visitors'])); ?></div>
1296 <p>순 방문자 (IP 기준)</p>
1297 </div>
1298 <div class="stat-item">
1299 <h3><?php echo ($start_date && $end_date) ? ($start_date == gmdate('Y-m-d') && $end_date == gmdate('Y-m-d') ? esc_html('오늘') : esc_html(date_i18n('Y�
1300 � m월 d일', strtotime($start_date))) . ' ~ ' . esc_html(date_i18n('Y�
1301 � m월 d일', strtotime($end_date)))) : esc_html('오늘'); ?></h3>
1302 <div class="stat-value"><?php echo esc_html(number_format($dummy_stats['today']['visitors'])); ?></div>
1303 <p>방문자 (브라우저 기준)</p>
1304 </div>
1305 <div class="stat-item">
1306 <h3>최근 7일</h3>
1307 <div class="stat-value"><?php echo esc_html(number_format($dummy_stats['week']['ip_visitors'])); ?></div>
1308 <p>순 방문자 (IP 기준)</p>
1309 </div>
1310 <div class="stat-item">
1311 <h3>최근 30일</h3>
1312 <div class="stat-value"><?php echo esc_html(number_format($dummy_stats['month']['ip_visitors'])); ?></div>
1313 <p>순 방문자 (IP 기준)</p>
1314 </div>
1315 </div>
1316 </div>
1317 </div>
1318
1319 <div class="presslearn-card-body-row">
1320 <div class="presslearn-card-body-row-item" style="flex: 100%;">
1321 <h3 style="margin-bottom: 15px;">인기 페이지 (<?php echo esc_html(count($popular_pages)); ?>)</h3>
1322
1323 <table class="widefat">
1324 <thead>
1325 <tr>
1326 <th>페이지</th>
1327 <th width="20%">조회수</th>
1328 </tr>
1329 </thead>
1330 <tbody>
1331 <?php foreach ($pages_to_display as $page): ?>
1332 <tr>
1333 <td>
1334 <a href="<?php echo esc_url($page['url']); ?>" target="_blank">
1335 <?php echo esc_html($page['title']); ?>
1336 </a>
1337 </td>
1338 <td><?php echo esc_html(number_format($page['views'])); ?></td>
1339 </tr>
1340 <?php endforeach; ?>
1341 </tbody>
1342 </table>
1343
1344 <?php if ($total_pages > 1): ?>
1345 <div class="tablenav">
1346 <div class="tablenav-pages">
1347 <span class="pagination-links">
1348 <?php
1349 $pagination_base_url = "?page=presslearn-analytics&tab=statistics&chart_period={$chart_period}";
1350
1351 if ($start_date && $end_date) {
1352 $pagination_base_url .= "&start_date=" . esc_attr($start_date) . "&end_date=" . esc_attr($end_date);
1353 }
1354
1355 if ($pages_page > 1) {
1356 $pagination_base_url .= "&pages_page=" . esc_attr($pages_page);
1357 }
1358 if ($countries_page > 1) {
1359 $pagination_base_url .= "&countries_page=" . esc_attr($countries_page);
1360 }
1361 if ($referrers_page > 1) {
1362 $pagination_base_url .= "&referrers_page=" . esc_attr($referrers_page);
1363 }
1364 if ($keywords_page > 1) {
1365 $pagination_base_url .= "&keywords_page=" . esc_attr($keywords_page);
1366 }
1367
1368 if ($pages_current_page > 1):
1369 ?>
1370 <a class="first-page button" href="<?php echo esc_url($pagination_base_url); ?>&pages_page=1"><span aria-hidden="true">«</span></a>
1371 <a class="prev-page button" href="<?php echo esc_url($pagination_base_url); ?>&pages_page=<?php echo esc_attr(max(1, $pages_current_page - 1)); ?>"><span aria-hidden="true">‹</span></a>
1372 <?php endif; ?>
1373
1374 <span class="pagination-current"><?php echo esc_html($pages_current_page); ?></span> / <span class="pagination-total"><?php echo esc_html($total_pages); ?></span>
1375
1376 <?php if ($pages_current_page < $total_pages): ?>
1377 <a class="next-page button" href="<?php echo esc_url($pagination_base_url); ?>&pages_page=<?php echo esc_attr(max(1, $pages_current_page + 1)); ?>"><span aria-hidden="true">›</span></a>
1378 <a class="last-page button" href="<?php echo esc_url($pagination_base_url); ?>&pages_page=<?php echo esc_attr(max(1, $total_pages)); ?>"><span aria-hidden="true">»</span></a>
1379 <?php endif; ?>
1380 </span>
1381 </div>
1382 </div>
1383 <?php endif; ?>
1384 </div>
1385 </div>
1386
1387 <div class="presslearn-card-body-row">
1388 <div class="presslearn-card-body-row-item" style="flex: 100%;">
1389 <h3 style="margin-bottom: 15px;">유�
1390 경로</h3>
1391
1392 <div class="referrer-chart-container">
1393 <canvas id="referrerChart"></canvas>
1394 </div>
1395
1396 <table class="widefat referrers-table">
1397 <thead>
1398 <tr>
1399 <th width="40px"></th>
1400 <th>경로</th>
1401 <th width="20%">페이지뷰(PV)</th>
1402 </tr>
1403 </thead>
1404 <tbody>
1405 <?php foreach ($referrers_to_display as $index => $referrer): ?>
1406 <tr class="referrer-row">
1407 <td>
1408 <?php if (!empty($referrer['details'])): ?>
1409 <button type="button" class="toggle-details" data-index="<?php echo esc_attr($index); ?>">
1410 <span class="dashicons dashicons-plus"></span>
1411 </button>
1412 <?php endif; ?>
1413 </td>
1414 <td>
1415 <?php echo esc_html($referrer['referrer']); ?>
1416 <?php
1417 if (isset($referrer['type']) && $referrer['type'] === '자연 유�
1418 ') {
1419 echo '<span class="organic-referrer-badge">' . esc_html('자연 유�
1420 ') . '</span>';
1421 }
1422 elseif (isset($referrer['type']) && $referrer['type'] === '외부 유�
1423 ') {
1424 echo '<span class="external-referrer-badge">' . esc_html('외부 유�
1425 ') . '</span>';
1426 }
1427 elseif ($referrer['referrer'] !== '직접 접속' &&
1428 $referrer['referrer'] !== '데이터 없음') {
1429 echo '<span class="external-referrer-badge">' . esc_html('외부 유�
1430 ') . '</span>';
1431 }
1432 ?>
1433 </td>
1434 <td><?php echo esc_html(number_format($referrer['count'])); ?></td>
1435 </tr>
1436 <?php if (!empty($referrer['details'])): ?>
1437 <tr class="referrer-details" id="details-<?php echo esc_attr($index); ?>" style="display: none;">
1438 <td colspan="3">
1439 <div class="referrer-details-inner">
1440 <ul class="referrer-details-list">
1441 <?php foreach ($referrer['details'] as $detail): ?>
1442 <li>
1443 <?php
1444 $url = $detail['url'];
1445 if ($url !== '북마크 및 직접 URL �
1446 ' && $url !== '기타 없는 소스' && strpos($url, 'http') !== 0) {
1447 $url = 'https://' . $url;
1448 }
1449
1450 if ($url === '북마크 및 직접 URL �
1451 ' || $url === '기타 없는 소스'):
1452 ?>
1453 <div class="referrer-url-wrap">
1454 <span class="referrer-url"><?php echo esc_html($detail['url']); ?></span>
1455 <span class="referrer-count"><?php echo esc_html(number_format($detail['count'])); ?></span>
1456 </div>
1457 <?php else: ?>
1458 <div class="referrer-url-wrap">
1459 <span class="referrer-url">
1460 <a href="<?php echo esc_url($url); ?>" target="_blank" rel="noopener">
1461 <?php echo esc_html($detail['url']); ?>
1462 </a>
1463 </span>
1464 <span class="referrer-count"><?php echo esc_html(number_format($detail['count'])); ?></span>
1465 </div>
1466 <?php endif; ?>
1467 </li>
1468 <?php endforeach; ?>
1469 </ul>
1470 </div>
1471 </td>
1472 </tr>
1473 <?php endif; ?>
1474 <?php endforeach; ?>
1475 </tbody>
1476 </table>
1477
1478 <?php if ($total_referrers > 1): ?>
1479 <div class="tablenav">
1480 <div class="tablenav-pages">
1481 <span class="pagination-links">
1482 <?php
1483 $pagination_base_url = "?page=presslearn-analytics&tab=statistics&chart_period={$chart_period}";
1484
1485 if ($start_date && $end_date) {
1486 $pagination_base_url .= "&start_date=" . esc_attr($start_date) . "&end_date=" . esc_attr($end_date);
1487 }
1488
1489 if ($pages_page > 1) {
1490 $pagination_base_url .= "&pages_page=" . esc_attr($pages_page);
1491 }
1492 if ($countries_page > 1) {
1493 $pagination_base_url .= "&countries_page=" . esc_attr($countries_page);
1494 }
1495 if ($referrers_page > 1) {
1496 $pagination_base_url .= "&referrers_page=" . esc_attr($referrers_page);
1497 }
1498 if ($keywords_page > 1) {
1499 $pagination_base_url .= "&keywords_page=" . esc_attr($keywords_page);
1500 }
1501
1502 if ($referrers_current_page > 1):
1503 ?>
1504 <a class="first-page button" href="<?php echo esc_url($pagination_base_url); ?>&referrers_page=1"><span aria-hidden="true">«</span></a>
1505 <a class="prev-page button" href="<?php echo esc_url($pagination_base_url); ?>&referrers_page=<?php echo esc_attr(max(1, $referrers_current_page - 1)); ?>"><span aria-hidden="true">‹</span></a>
1506 <?php endif; ?>
1507
1508 <span class="pagination-current"><?php echo esc_html($referrers_current_page); ?></span> / <span class="pagination-total"><?php echo esc_html($total_referrers); ?></span>
1509
1510 <?php if ($referrers_current_page < $total_referrers): ?>
1511 <a class="next-page button" href="<?php echo esc_url($pagination_base_url); ?>&referrers_page=<?php echo esc_attr(max(1, $referrers_current_page + 1)); ?>"><span aria-hidden="true">›</span></a>
1512 <a class="last-page button" href="<?php echo esc_url($pagination_base_url); ?>&referrers_page=<?php echo esc_attr(max(1, $total_referrers)); ?>"><span aria-hidden="true">»</span></a>
1513 <?php endif; ?>
1514 </span>
1515 </div>
1516 </div>
1517 <?php endif; ?>
1518 </div>
1519 </div>
1520
1521 <div class="presslearn-card-body-row">
1522 <div class="presslearn-card-body-row-item" style="flex: 100%;">
1523 <h3 style="margin-bottom: 15px;">자연 유�
1524 키워드 (<?php echo esc_html($total_keywords_count); ?>)</h3>
1525
1526 <table class="widefat">
1527 <thead>
1528 <tr>
1529 <th>키워드</th>
1530 <th>검색 엔진</th>
1531 <th width="20%">조회수</th>
1532 </tr>
1533 </thead>
1534 <tbody>
1535 <?php foreach ($organic_keywords as $keyword): ?>
1536 <tr>
1537 <td>
1538 <?php if ($keyword['keyword'] !== '(not provided)' && $keyword['keyword'] !== '아직 수집된 키워드가 없습니다'): ?>
1539 <a href="<?php echo esc_url($keyword['referrer'] ?? ($keyword['search_engine'] === '네이버' ? 'https://search.naver.com/search.naver?query=' . urlencode($keyword['keyword']) : ($keyword['search_engine'] === '구글' ? 'https://www.google.com/search?q=' . urlencode($keyword['keyword']) : ($keyword['search_engine'] === '다음' ? 'https://search.daum.net/search?w=tot&q=' . urlencode($keyword['keyword']) : ($keyword['search_engine'] === '빙' ? 'https://www.bing.com/search?q=' . urlencode($keyword['keyword']) : 'https://search.yahoo.com/search?p=' . urlencode($keyword['keyword'])))))); ?>" target="_blank" rel="noopener">
1540 <?php echo esc_html($keyword['keyword']); ?>
1541 </a>
1542 <?php else: ?>
1543 <?php echo esc_html($keyword['keyword']); ?>
1544 <?php endif; ?>
1545 </td>
1546 <td>
1547 <?php echo esc_html($keyword['search_engine_display']); ?>
1548 <?php if ($keyword['search_engine'] === '네이버'): ?>
1549 <span class="organic-referrer-badge"><?php echo esc_html('네이버'); ?></span>
1550 <?php elseif ($keyword['search_engine'] === '구글'): ?>
1551 <span class="external-referrer-badge"><?php echo esc_html('구글'); ?></span>
1552 <?php elseif ($keyword['search_engine'] === '다음'): ?>
1553 <span class="daum-referrer-badge"><?php echo esc_html('다음'); ?></span>
1554 <?php elseif ($keyword['search_engine'] === '빙'): ?>
1555 <span class="bing-referrer-badge"><?php echo esc_html('빙'); ?></span>
1556 <?php elseif ($keyword['search_engine'] === '야후'): ?>
1557 <span class="external-referrer-badge"><?php echo esc_html('야후'); ?></span>
1558 <?php endif; ?>
1559 </td>
1560 <td><?php echo esc_html(number_format($keyword['count'])); ?></td>
1561 </tr>
1562 <?php endforeach; ?>
1563 </tbody>
1564 </table>
1565
1566 <?php if ($total_keywords_pages > 1): ?>
1567 <div class="tablenav">
1568 <div class="tablenav-pages">
1569 <span class="pagination-links">
1570 <?php
1571 $pagination_base_url = "?page=presslearn-analytics&tab=statistics&chart_period={$chart_period}";
1572
1573 if ($start_date && $end_date) {
1574 $pagination_base_url .= "&start_date=" . esc_attr($start_date) . "&end_date=" . esc_attr($end_date);
1575 }
1576
1577 if ($pages_page > 1) {
1578 $pagination_base_url .= "&pages_page=" . esc_attr($pages_page);
1579 }
1580 if ($countries_page > 1) {
1581 $pagination_base_url .= "&countries_page=" . esc_attr($countries_page);
1582 }
1583 if ($referrers_page > 1) {
1584 $pagination_base_url .= "&referrers_page=" . esc_attr($referrers_page);
1585 }
1586
1587 if ($keywords_current_page > 1):
1588 ?>
1589 <a class="first-page button" href="<?php echo esc_url($pagination_base_url); ?>&keywords_page=1"><span aria-hidden="true">«</span></a>
1590 <a class="prev-page button" href="<?php echo esc_url($pagination_base_url); ?>&keywords_page=<?php echo esc_attr(max(1, $keywords_current_page - 1)); ?>"><span aria-hidden="true">‹</span></a>
1591 <?php endif; ?>
1592
1593 <span class="pagination-current"><?php echo esc_html($keywords_current_page); ?></span> / <span class="pagination-total"><?php echo esc_html($total_keywords_pages); ?></span>
1594
1595 <?php if ($keywords_current_page < $total_keywords_pages): ?>
1596 <a class="next-page button" href="<?php echo esc_url($pagination_base_url); ?>&keywords_page=<?php echo esc_attr(max(1, $keywords_current_page + 1)); ?>"><span aria-hidden="true">›</span></a>
1597 <a class="last-page button" href="<?php echo esc_url($pagination_base_url); ?>&keywords_page=<?php echo esc_attr(max(1, $total_keywords_pages)); ?>"><span aria-hidden="true">»</span></a>
1598 <?php endif; ?>
1599 </span>
1600 </div>
1601 </div>
1602 <?php endif; ?>
1603 </div>
1604 </div>
1605
1606 <div class="presslearn-card-body-row">
1607 <div class="presslearn-card-body-row-item" style="flex: 100%;">
1608 <h3 style="margin-bottom: 15px;">방문자 국가</h3>
1609
1610 <table class="widefat">
1611 <thead>
1612 <tr>
1613 <th>국가</th>
1614 <th width="20%">페이지뷰(PV)</th>
1615 </tr>
1616 </thead>
1617 <tbody>
1618 <?php foreach ($countries_to_display as $country): ?>
1619 <tr>
1620 <td><?php echo esc_html($country['country']); ?></td>
1621 <td><?php echo esc_html(number_format($country['count'])); ?></td>
1622 </tr>
1623 <?php endforeach; ?>
1624 </tbody>
1625 </table>
1626
1627 <?php if ($total_countries > 1): ?>
1628 <div class="tablenav">
1629 <div class="tablenav-pages">
1630 <span class="pagination-links">
1631 <?php
1632 $pagination_base_url = "?page=presslearn-analytics&tab=statistics&chart_period={$chart_period}";
1633
1634 if ($start_date && $end_date) {
1635 $pagination_base_url .= "&start_date=" . esc_attr($start_date) . "&end_date=" . esc_attr($end_date);
1636 }
1637
1638 if ($pages_page > 1) {
1639 $pagination_base_url .= "&pages_page=" . esc_attr($pages_page);
1640 }
1641 if ($referrers_page > 1) {
1642 $pagination_base_url .= "&referrers_page=" . esc_attr($referrers_page);
1643 }
1644 if ($keywords_page > 1) {
1645 $pagination_base_url .= "&keywords_page=" . esc_attr($keywords_page);
1646 }
1647
1648 if ($countries_current_page > 1):
1649 ?>
1650 <a class="first-page button" href="<?php echo esc_url($pagination_base_url); ?>&countries_page=1"><span aria-hidden="true">«</span></a>
1651 <a class="prev-page button" href="<?php echo esc_url($pagination_base_url); ?>&countries_page=<?php echo esc_attr(max(1, $countries_current_page - 1)); ?>"><span aria-hidden="true">‹</span></a>
1652 <?php endif; ?>
1653
1654 <span class="pagination-current"><?php echo esc_html($countries_current_page); ?></span> / <span class="pagination-total"><?php echo esc_html($total_countries); ?></span>
1655
1656 <?php if ($countries_current_page < $total_countries): ?>
1657 <a class="next-page button" href="<?php echo esc_url($pagination_base_url); ?>&countries_page=<?php echo esc_attr(max(1, $countries_current_page + 1)); ?>"><span aria-hidden="true">›</span></a>
1658 <a class="last-page button" href="<?php echo esc_url($pagination_base_url); ?>&countries_page=<?php echo esc_attr(max(1, $total_countries)); ?>"><span aria-hidden="true">»</span></a>
1659 <?php endif; ?>
1660 </span>
1661 </div>
1662 </div>
1663 <?php endif; ?>
1664 </div>
1665 </div>
1666 </div>
1667 <div class="presslearn-card-footer">
1668 <div class="presslearn-card-footer-item grid-left">
1669 <span class="tip_button">통계 데이터는 설정한 캐싱 기준으로 �
1670 데이트됩니다.</span>
1671 </div>
1672 <div class="presslearn-card-footer-item grid-right">
1673 <?php if ($analytics_enabled !== 'yes'): ?>
1674 <p style="color: #d32f2f;">통계 기능을 사용하려면 먼저 <a href="?page=presslearn-analytics&tab=settings">설정</a>에서 기능을 활성화하세요.</p>
1675 <?php endif; ?>
1676 </div>
1677 </div>
1678 </div>
1679 <?php endif; ?>
1680 </div>
1681
1682