PluginProbe
AL Pack / 1.0.0
AL Pack v1.0.0
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 / presslearn-plugin.php

presslearn-plugin.php in AL Pack 1.0.0, at presslearn-plugin.php

3,976 lines 138.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: AL Pack
4 * Plugin URI: https://lowordfoundation.org
5 * Description: 통계, 글쓰기 SEO, 애드센스 무효 트래픽 차단, 빠른 버튼 생성, 카카오 공유 버튼, 스크롤 팝�
6 , 애드클리커 등 워드프레스를 위한 통합 플러그인
7 * Version: 1.0.0
8 * Author: 프레스런
9 * Author URI: https://presslearn.co.kr
10 * Text Domain: alpack
11 * License: GPLv2 or later
12 */
13
14 if (!defined('ABSPATH')) {
15 exit;
16 }
17
18 define('PRESSLEARN_PLUGIN_DIR', plugin_dir_path(__FILE__));
19 define('PRESSLEARN_PLUGIN_URL', plugin_dir_url(__FILE__));
20 define('PRESSLEARN_PLUGIN_VERSION', time());
21
22 register_activation_hook(__FILE__, 'presslearn_plugin_activate');
23 register_deactivation_hook(__FILE__, 'presslearn_plugin_deactivate');
24 register_uninstall_hook(__FILE__, 'presslearn_plugin_uninstall');
25
26 function presslearn_plugin_activate() {
27 update_option('presslearn_plugin_key', '');
28 update_option('presslearn_plugin_activated_time', time());
29 update_option('presslearn_activation_logs', array());
30 update_option('presslearn_plugin_settings', array(
31 'initialized' => true,
32 'version' => PRESSLEARN_PLUGIN_VERSION,
33 'activation_date' => current_time('mysql')
34 ));
35
36 update_option('presslearn_scroll_depth_enabled', 'no');
37 update_option('presslearn_analytics_enabled', 'no');
38 update_option('presslearn_dynamic_banner_enabled', 'no');
39 update_option('presslearn_click_protection_enabled', 'no');
40 update_option('presslearn_ad_clicker_enabled', 'no');
41 update_option('presslearn_social_share_enabled', 'no');
42 add_option('presslearn_quick_button_enabled', 'no');
43 add_option('presslearn_button_transition_enabled', 'no');
44 presslearn_create_tables();
45
46 set_transient('presslearn_plugin_activation_redirect', true, 30);
47 }
48
49 function presslearn_create_tables() {
50 global $wpdb;
51
52 $charset_collate = $wpdb->get_charset_collate();
53
54 $table_name = $wpdb->prefix . 'presslearn_logs';
55
56 $sql = "CREATE TABLE IF NOT EXISTS $table_name (
57 id bigint(20) NOT NULL AUTO_INCREMENT,
58 time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
59 event varchar(255) NOT NULL,
60 details longtext NOT NULL,
61 PRIMARY KEY (id)
62 ) $charset_collate;";
63
64 $banners_table = $wpdb->prefix . 'presslearn_banners';
65 $sql .= "CREATE TABLE IF NOT EXISTS $banners_table (
66 id bigint(20) NOT NULL AUTO_INCREMENT,
67 name varchar(255) NOT NULL,
68 type varchar(50) NOT NULL DEFAULT 'custom',
69 banner_url text,
70 cover_banner_url text,
71 link text,
72 iframe_code longtext,
73 width int(11),
74 height int(11),
75 status tinyint(1) DEFAULT 1,
76 created_at datetime DEFAULT CURRENT_TIMESTAMP,
77 updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
78 PRIMARY KEY (id)
79 ) $charset_collate;";
80
81 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
82 dbDelta($sql);
83 }
84
85 function presslearn_plugin_deactivate() {
86 delete_transient('presslearn_plugin_activation_redirect');
87
88 delete_option('presslearn_quick_button_enabled');
89 delete_option('presslearn_button_transition_enabled');
90 }
91
92 function presslearn_plugin_activation_redirect() {
93 if (get_transient('presslearn_plugin_activation_redirect')) {
94 delete_transient('presslearn_plugin_activation_redirect');
95 if (is_admin() && !isset($_GET['activate-multi'])) {
96 wp_redirect(admin_url('admin.php?page=presslearn-settings'));
97 exit;
98 }
99 }
100 }
101 add_action('admin_init', 'presslearn_plugin_activation_redirect');
102
103
104 function presslearn_plugin_uninstall() {
105 delete_option('presslearn_plugin_key');
106 delete_option('presslearn_plugin_activated_time');
107 delete_option('presslearn_activation_logs');
108 delete_option('presslearn_plugin_settings');
109
110 delete_option('presslearn_scroll_depth_enabled');
111 delete_option('presslearn_analytics_enabled');
112 delete_option('presslearn_dynamic_banner_enabled');
113 delete_option('presslearn_click_protection_enabled');
114 delete_option('presslearn_ad_clicker_enabled');
115 delete_option('presslearn_social_share_enabled');
116 delete_option('presslearn_quick_button_enabled');
117 delete_option('presslearn_button_transition_enabled');
118 delete_transient('presslearn_plugin_activation_redirect');
119
120 $users = get_users(array('fields' => 'ID'));
121 foreach($users as $user_id) {
122 delete_user_meta($user_id, 'presslearn_user_data');
123 }
124
125 presslearn_drop_tables();
126 }
127
128
129 function presslearn_drop_tables() {
130 global $wpdb;
131
132 $table_name = $wpdb->prefix . 'presslearn_logs';
133 $wpdb->query("DROP TABLE IF EXISTS $table_name");
134
135 $banners_table = $wpdb->prefix . 'presslearn_banners';
136 $wpdb->query("DROP TABLE IF EXISTS $banners_table");
137 }
138
139 require_once PRESSLEARN_PLUGIN_DIR . 'includes/admin.php';
140 require_once PRESSLEARN_PLUGIN_DIR . 'includes/api.php';
141 require_once PRESSLEARN_PLUGIN_DIR . 'includes/share.php';
142 require_once PRESSLEARN_PLUGIN_DIR . 'includes/buttons.php';
143 require_once PRESSLEARN_PLUGIN_DIR . 'includes/analytics.php';
144 require_once PRESSLEARN_PLUGIN_DIR . 'includes/protection.php';
145 require_once PRESSLEARN_PLUGIN_DIR . 'includes/dynamic.php';
146 require_once PRESSLEARN_PLUGIN_DIR . 'includes/scroll.php';
147
148 function presslearn_scroll_depth_frontend_script() {
149 if (is_admin()) {
150 return;
151 }
152
153 $scroll_depth_enabled = get_option('presslearn_scroll_depth_enabled', 'no');
154 $popup_content = get_option('presslearn_popup_content', '');
155
156 if ($scroll_depth_enabled !== 'yes' || empty($popup_content)) {
157 return;
158 }
159
160 $scroll_percentage = get_option('presslearn_scroll_percentage', 50);
161 $popup_animation = get_option('presslearn_popup_animation', 'fade');
162 $repeat_setting = get_option('presslearn_repeat_setting', 'once');
163
164 $animation_class = 'popupFadeIn';
165 if ($popup_animation === 'slide') {
166 $animation_class = 'popupSlideIn';
167 } elseif ($popup_animation === 'zoom') {
168 $animation_class = 'popupZoomIn';
169 }
170
171 $cookie_check = $repeat_setting === 'once' ? 'true' : 'false';
172
173 wp_register_style('presslearn-popup-css', false);
174 wp_enqueue_style('presslearn-popup-css');
175
176 $popup_styles = "
177 .pl-popup-overlay {
178 position: fixed;
179 top: 0;
180 left: 0;
181 width: 100%;
182 height: 100%;
183 background-color: rgba(0, 0, 0, 0.7);
184 z-index: 99999;
185 display: none;
186 justify-content: center;
187 align-items: center;
188 }
189
190 .pl-popup-container {
191 display: flex;
192 justify-content: center;
193 align-items: center;
194 width: 100%;
195 height: 100%;
196 }
197
198 .pl-popup-window {
199 background-color: #fff;
200 width: 90%;
201 max-width: 500px;
202 border-radius: 8px;
203 box-shadow: 0 0 30px rgba(0, 0, 0, 0.5);
204 display: flex;
205 flex-direction: column;
206 max-height: 80vh;
207 }
208
209 .pl-popup-body {
210 padding: 30px;
211 overflow-y: auto;
212 flex: 1;
213 line-height: 1.6;
214 }
215
216 .pl-popup-body img {
217 max-width: 100%;
218 height: auto;
219 display: block;
220 margin: 0 auto;
221 }
222
223 .pl-close-popup {
224 position: fixed;
225 top: 20px;
226 right: 20px;
227 background: none;
228 border: none;
229 font-size: 40px;
230 cursor: pointer;
231 color: #fff;
232 z-index: 100000;
233 padding: 0;
234 line-height: 1;
235 }
236
237 .pl-close-popup:hover {
238 color: #ddd;
239 }
240
241 @keyframes popupFadeIn {
242 from {
243 opacity: 0;
244 transform: scale(0.9);
245 }
246 to {
247 opacity: 1;
248 transform: scale(1);
249 }
250 }
251
252 @keyframes popupSlideIn {
253 from {
254 opacity: 0;
255 transform: translateY(-50px);
256 }
257 to {
258 opacity: 1;
259 transform: translateY(0);
260 }
261 }
262
263 @keyframes popupZoomIn {
264 from {
265 opacity: 0;
266 transform: scale(0.5);
267 }
268 to {
269 opacity: 1;
270 transform: scale(1);
271 }
272 }
273
274 .popup-animation {
275 animation: " . $animation_class . " 0.3s ease-out;
276 }
277
278 @media screen and (max-width: 768px) {
279 .pl-popup-window {
280 width: 95%;
281 max-width: 95%;
282 }
283
284 .pl-popup-body {
285 padding: 20px;
286 }
287
288 .pl-close-popup {
289 top: 10px;
290 right: 10px;
291 font-size: 32px;
292 }
293 }";
294
295 wp_add_inline_style('presslearn-popup-css', $popup_styles);
296
297 add_action('wp_footer', function() use ($popup_content) {
298 ?>
299 <div id="pl-popup-overlay" class="pl-popup-overlay">
300 <button type="button" class="pl-close-popup">&times;</button>
301 <div class="pl-popup-container">
302 <div class="pl-popup-window popup-animation">
303 <div class="pl-popup-body">
304 <?php echo wp_kses_post(wpautop($popup_content)); ?>
305 </div>
306 </div>
307 </div>
308 </div>
309 <?php
310 });
311
312 wp_register_script('presslearn-popup-js', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
313 wp_enqueue_script('presslearn-popup-js');
314
315 $popup_script = "
316 (function() {
317 function setCookie(name, value, days) {
318 var expires = '';
319 if (days) {
320 var date = new Date();
321 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
322 expires = '; expires=' + date.toUTCString();
323 }
324 document.cookie = name + '=' + (value || '') + expires + '; path=/';
325 }
326
327 function getCookie(name) {
328 var nameEQ = name + '=';
329 var ca = document.cookie.split(';');
330 for(var i=0; i < ca.length; i++) {
331 var c = ca[i];
332 while (c.charAt(0) == ' ') c = c.substring(1, c.length);
333 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
334 }
335 return null;
336 }
337
338 var cookieName = 'pl_popup_shown';
339 var checkCookie = " . esc_js($cookie_check) . ";
340
341 if (checkCookie && getCookie(cookieName)) {
342 return;
343 }
344
345 var scrollTriggered = false;
346 window.addEventListener('scroll', function() {
347 if (scrollTriggered) return;
348
349 var scrollPercentage = " . esc_js($scroll_percentage) . ";
350 var scrollPosition = window.scrollY;
351 var documentHeight = document.documentElement.scrollHeight - window.innerHeight;
352 var currentScrollPercent = (scrollPosition / documentHeight) * 100;
353
354 if (currentScrollPercent >= scrollPercentage) {
355 scrollTriggered = true;
356 document.getElementById('pl-popup-overlay').style.display = 'flex';
357
358 if (checkCookie) {
359 setCookie(cookieName, 'true', 30);
360 }
361 }
362 });
363
364 document.querySelector('.pl-close-popup').addEventListener('click', function() {
365 document.getElementById('pl-popup-overlay').style.display = 'none';
366 });
367
368 document.getElementById('pl-popup-overlay').addEventListener('click', function(e) {
369 if (e.target === this || e.target.classList.contains('pl-popup-container')) {
370 this.style.display = 'none';
371 }
372 });
373 })();";
374
375 wp_add_inline_script('presslearn-popup-js', $popup_script);
376 }
377
378 add_action('wp_enqueue_scripts', 'presslearn_scroll_depth_frontend_script');
379
380 class PressLearn_Plugin {
381 private static $instance = null;
382
383 private $is_activated = false;
384
385 private $option_key = 'presslearn_plugin_key';
386
387 private $exempt_pages = array('presslearn-settings');
388
389 private $db_version = '1.0';
390
391 public static function get_instance() {
392 if (null === self::$instance) {
393 self::$instance = new self();
394 }
395 return self::$instance;
396 }
397
398
399 private function __construct() {
400 add_action('init', array($this, 'init'));
401
402 add_action('admin_menu', array($this, 'register_admin_menu'));
403
404 add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
405
406 $this->check_activation();
407
408 add_action('admin_init', array($this, 'check_page_access'));
409
410 add_action('admin_init', array($this, 'check_version_upgrade'));
411
412 add_action('admin_bar_menu', array($this, 'add_admin_bar_menu'), 100);
413 }
414
415
416 public function check_version_upgrade() {
417 $settings = get_option('presslearn_plugin_settings', array());
418 $current_version = isset($settings['version']) ? $settings['version'] : '0';
419 $current_db_version = isset($settings['db_version']) ? $settings['db_version'] : '0';
420
421 if ($current_version != PRESSLEARN_PLUGIN_VERSION) {
422 if (version_compare($current_db_version, $this->db_version, '<')) {
423 $this->run_db_migration($current_db_version);
424 }
425
426 $settings['version'] = PRESSLEARN_PLUGIN_VERSION;
427 $settings['db_version'] = $this->db_version;
428 $settings['last_upgraded'] = current_time('mysql');
429
430 update_option('presslearn_plugin_settings', $settings);
431
432 $this->log_upgrade($current_version, PRESSLEARN_PLUGIN_VERSION);
433 }
434 }
435
436
437 private function run_db_migration($from_version) {
438 global $wpdb;
439
440 if (version_compare($from_version, '0.5', '<')) {
441 $table_name = $wpdb->prefix . 'presslearn_logs';
442
443 $wpdb->query("ALTER TABLE $table_name ADD ip_address varchar(45) DEFAULT '' AFTER event");
444 }
445
446 if (version_compare($from_version, '0.8', '<')) {
447
448 }
449
450 }
451
452 private function log_upgrade($from_version, $to_version) {
453 global $wpdb;
454
455 $table_name = $wpdb->prefix . 'presslearn_logs';
456
457 $wpdb->insert(
458 $table_name,
459 array(
460 'time' => current_time('mysql'),
461 'event' => 'plugin_upgrade',
462 'details' => json_encode(array(
463 'from_version' => $from_version,
464 'to_version' => $to_version,
465 'user_id' => get_current_user_id(),
466 'site_url' => get_site_url()
467 ))
468 )
469 );
470 }
471
472 public function check_page_access() {
473 $current_page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
474
475 if (strpos($current_page, 'presslearn-') === 0 && !in_array($current_page, $this->exempt_pages)) {
476 if (!$this->is_activated) {
477 wp_redirect(admin_url('admin.php?page=presslearn-settings&access_denied=true'));
478 exit;
479 }
480 }
481 }
482
483 /**
484 * Initialize
485 */
486 public function init() {
487 if (isset($_GET['presslearn_key']) && !empty($_GET['presslearn_key'])) {
488 if (!current_user_can('manage_options')) {
489 wp_die('관리자 권한이 필요합니다.');
490 }
491
492 if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'presslearn_activate_plugin')) {
493 wp_die('보안 검증에 실패했습니다.');
494 }
495
496 $this->activate_plugin(sanitize_text_field(wp_unslash($_GET['presslearn_key'])));
497 wp_redirect(admin_url('admin.php?page=presslearn-settings&activated=true'));
498 exit;
499 }
500
501 if (get_option('presslearn_analytics_enabled', 'no') === 'yes') {
502 $tables_created = $this->create_analytics_tables();
503
504 if ($tables_created) {
505 add_action('wp_head', array($this, 'add_tracking_code'));
506 $this->register_tracking_ajax();
507 } else {
508 update_option('presslearn_analytics_enabled', 'no');
509
510 if (is_admin()) {
511 add_action('admin_notices', function() {
512 ?>
513 <div class="notice notice-error">
514 <p><?php echo esc_html('씬 애널리틱스 기능 활성화 중 오류가 발생하여 비활성화되었습니다. 데이터베이스 �
515 �이블을 생성할 수 없습니다.'); ?></p>
516 </div>
517 <?php
518 });
519 }
520 }
521 }
522 }
523
524 public function enqueue_admin_scripts($hook) {
525 if (strpos($hook, 'presslearn') === false) {
526 return;
527 }
528
529 wp_enqueue_style('presslearn-admin-css', PRESSLEARN_PLUGIN_URL . 'assets/css/admin.css', array(), PRESSLEARN_PLUGIN_VERSION);
530
531 wp_enqueue_script('jquery');
532 wp_enqueue_script('presslearn-admin-js', PRESSLEARN_PLUGIN_URL . 'assets/js/admin.js', array('jquery'), PRESSLEARN_PLUGIN_VERSION, true);
533
534 wp_register_script('presslearn-chart-js', PRESSLEARN_PLUGIN_URL . 'assets/js/chart.min.js', array(), '3.7.1', true);
535
536 if (strpos($hook, 'presslearn-analytics') !== false) {
537 wp_enqueue_script('presslearn-chart-js');
538 wp_register_style('presslearn-analytics-css', false);
539 wp_enqueue_style('presslearn-analytics-css');
540
541 wp_register_script('presslearn-analytics-js', false, array('jquery', 'presslearn-chart-js', 'moment'), PRESSLEARN_PLUGIN_VERSION, true);
542 wp_enqueue_script('presslearn-analytics-js');
543 }
544
545 if (strpos($hook, 'presslearn-scroll-depth') !== false) {
546 wp_register_style('presslearn-scroll-depth-css', false);
547 wp_enqueue_style('presslearn-scroll-depth-css');
548
549 wp_register_script('presslearn-scroll-depth-js', false, array('jquery'), PRESSLEARN_PLUGIN_VERSION, true);
550 wp_enqueue_script('presslearn-scroll-depth-js');
551 }
552
553 if (strpos($hook, 'presslearn-click-protection') !== false) {
554 wp_register_style('presslearn-click-protection-css', false);
555 wp_enqueue_style('presslearn-click-protection-css');
556
557 wp_register_script('presslearn-click-protection-js', false, array('jquery'), PRESSLEARN_PLUGIN_VERSION, true);
558 wp_enqueue_script('presslearn-click-protection-js');
559 }
560
561 if (strpos($hook, 'presslearn-ad-clicker') !== false) {
562 wp_register_style('presslearn-ad-clicker-css', false);
563 wp_enqueue_style('presslearn-ad-clicker-css');
564
565 wp_register_script('presslearn-ad-clicker-js', false, array('jquery'), PRESSLEARN_PLUGIN_VERSION, true);
566 wp_enqueue_script('presslearn-ad-clicker-js');
567
568 wp_register_script('presslearn-adclicker-admin', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
569 wp_enqueue_script('presslearn-adclicker-admin');
570
571 $adclicker_overlay_range = get_option('presslearn_adclicker_overlay_range', 100);
572 $adclicker_overlay_color = get_option('presslearn_adclicker_overlay_color', '#000000');
573 $adclicker_button_color = get_option('presslearn_adclicker_button_color', '#2196F3');
574 $adclicker_button_text_color = get_option('presslearn_adclicker_button_text_color', '#ffffff');
575 $adclicker_display_time = get_option('presslearn_adclicker_display_time', 'null');
576
577 wp_localize_script('presslearn-adclicker-admin', 'pressleanAdclickerConfig', array(
578 'overlayRange' => $adclicker_overlay_range,
579 'overlayColor' => $adclicker_overlay_color,
580 'buttonColor' => $adclicker_button_color,
581 'buttonTextColor' => $adclicker_button_text_color,
582 'displayTime' => $adclicker_display_time
583 ));
584
585 $adclicker_script = "
586 document.addEventListener('DOMContentLoaded', function() {
587 const previewButton = document.getElementById('preview-adclicker');
588
589 if (previewButton) {
590 previewButton.addEventListener('click', function() {
591 showAdClickerPreview();
592 });
593 }
594
595 const urlParams = new URLSearchParams(window.location.search);
596 const showPreview = urlParams.get('preview');
597
598 if (previewButton && (showPreview === '1' || showPreview === 'true')) {
599 setTimeout(function() {
600 showAdClickerPreview();
601 }, 500);
602 }
603
604 function showAdClickerPreview() {
605 const overlay = document.createElement('div');
606 overlay.id = 'adclicker-overlay-preview';
607 overlay.style.position = 'fixed';
608 overlay.style.bottom = '0';
609 overlay.style.left = '0';
610 overlay.style.width = '100%';
611 overlay.style.height = pressleanAdclickerConfig.overlayRange + 'vh';
612 overlay.style.background = 'linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 0%, ' + pressleanAdclickerConfig.overlayColor + ' 100%)';
613 overlay.style.zIndex = '999999';
614
615 const closeButton = document.createElement('div');
616 closeButton.id = 'adclicker-close-button-preview';
617 closeButton.setAttribute('data-ad-link', '#previewAdLink');
618 closeButton.style.position = 'fixed';
619 closeButton.style.bottom = '60px';
620 closeButton.style.left = '50%';
621 closeButton.style.transform = 'translateX(-50%)';
622 closeButton.style.padding = '15px 30px';
623 closeButton.style.backgroundColor = pressleanAdclickerConfig.buttonColor;
624 closeButton.style.color = pressleanAdclickerConfig.buttonTextColor;
625 closeButton.style.border = 'none';
626 closeButton.style.borderRadius = '8px';
627 closeButton.style.fontSize = '20px';
628 closeButton.style.cursor = 'pointer';
629 closeButton.style.zIndex = '1000001';
630 closeButton.style.textDecoration = 'none';
631 closeButton.style.display = 'inline-block';
632 closeButton.style.textAlign = 'center';
633
634 const previewLink = document.createElement('a');
635 previewLink.href = '#previewAdLink';
636 previewLink.textContent = '미리보기 예시용';
637 previewLink.setAttribute('target', '_blank');
638 previewLink.style.color = 'inherit';
639 previewLink.style.textDecoration = 'inherit';
640 previewLink.style.display = 'block';
641
642 closeButton.appendChild(previewLink);
643
644 const hoverStyle = document.createElement('style');
645 hoverStyle.innerHTML =
646 '#adclicker-close-button-preview:hover,' +
647 '#adclicker-close-button-preview:focus,' +
648 '#adclicker-close-button-preview:active {' +
649 'background-color: ' + closeButton.style.backgroundColor + ' !important;' +
650 'color: ' + closeButton.style.color + ' !important;' +
651 'text-decoration: none !important;' +
652 'outline: none !important;' +
653 '}';
654 document.head.appendChild(hoverStyle);
655
656 const backButtonMessage = document.createElement('div');
657 backButtonMessage.textContent = '원치않으시면 뒤로가기를 해주세요';
658 backButtonMessage.style.position = 'fixed';
659 backButtonMessage.style.bottom = '50px';
660 backButtonMessage.style.left = '50%';
661 backButtonMessage.style.transform = 'translateX(-50%)';
662 backButtonMessage.style.fontSize = '12px';
663 backButtonMessage.style.color = pressleanAdclickerConfig.buttonTextColor;
664 backButtonMessage.style.opacity = '0.8';
665 backButtonMessage.style.zIndex = '1000001';
666 backButtonMessage.style.marginBottom = '-15px';
667
668 const countdownLabel = document.createElement('span');
669 countdownLabel.id = 'adclicker-countdown-label-preview';
670 countdownLabel.style.position = 'absolute';
671 countdownLabel.style.top = '-10px';
672 countdownLabel.style.right = '-10px';
673 countdownLabel.style.width = '30px';
674 countdownLabel.style.height = '30px';
675 countdownLabel.style.borderRadius = '50%';
676 countdownLabel.style.backgroundColor = '#ff3b30';
677 countdownLabel.style.color = 'white';
678 countdownLabel.style.fontSize = '14px';
679 countdownLabel.style.fontWeight = 'bold';
680 countdownLabel.style.textAlign = 'center';
681 countdownLabel.style.lineHeight = '30px';
682 countdownLabel.style.zIndex = '1000002';
683
684 closeButton.addEventListener('click', function(e) {
685 if (e.target.tagName.toLowerCase() !== 'a') {
686 e.preventDefault();
687
688 document.body.removeChild(overlay);
689 document.body.removeChild(closeButton);
690 document.body.removeChild(backButtonMessage);
691 if (countdownInterval) {
692 clearInterval(countdownInterval);
693 }
694 }
695 });
696
697 document.body.appendChild(overlay);
698 document.body.appendChild(closeButton);
699 document.body.appendChild(backButtonMessage);
700
701 const displayTime = pressleanAdclickerConfig.displayTime;
702 let countdownInterval;
703
704 if (displayTime !== 'null') {
705 let timeLeft = parseInt(displayTime);
706 countdownLabel.textContent = timeLeft;
707 closeButton.appendChild(countdownLabel);
708
709 countdownInterval = setInterval(function() {
710 timeLeft--;
711 countdownLabel.textContent = timeLeft;
712
713 if (timeLeft <= 0) {
714 clearInterval(countdownInterval);
715 countdownLabel.textContent = '✕';
716 }
717 }, 1000);
718 }
719 }
720 });
721 ";
722
723 wp_add_inline_script('presslearn-adclicker-admin', $adclicker_script);
724 }
725
726 if (strpos($hook, 'presslearn-dynamic-banner') !== false) {
727 wp_register_style('presslearn-dynamic-banner-css', false);
728 wp_enqueue_style('presslearn-dynamic-banner-css');
729
730 wp_register_script('presslearn-dynamic-banner-js', false, array('jquery'), PRESSLEARN_PLUGIN_VERSION, true);
731 wp_enqueue_script('presslearn-dynamic-banner-js');
732 }
733
734 if (strpos($hook, 'presslearn-social-share') !== false) {
735 wp_register_style('presslearn-social-share-css', false);
736 wp_enqueue_style('presslearn-social-share-css');
737
738 wp_register_script('presslearn-social-share-js', false, array('jquery'), PRESSLEARN_PLUGIN_VERSION, true);
739 wp_enqueue_script('presslearn-social-share-js');
740 }
741
742 if (strpos($hook, 'presslearn-quick-button') !== false) {
743 wp_register_style('presslearn-quick-button-css', false);
744 wp_enqueue_style('presslearn-quick-button-css');
745
746 wp_register_script('presslearn-quick-button-js', false, array('jquery'), PRESSLEARN_PLUGIN_VERSION, true);
747 wp_enqueue_script('presslearn-quick-button-js');
748 }
749
750 wp_localize_script('presslearn-admin-js', 'presslearn_admin', array(
751 'ajax_url' => admin_url('admin-ajax.php'),
752 'nonce' => wp_create_nonce('presslearn_admin_nonce'),
753 'api_url' => rest_url('presslearn/v1'),
754 'site_url' => site_url(),
755 'ip_address' => presslearn_plugin()->get_ip_address(),
756 'is_default_permalink' => empty(get_option('permalink_structure'))
757 ));
758 }
759
760 public function register_admin_menu() {
761 $icon_url = PRESSLEARN_PLUGIN_URL . 'assets/images/admin_badge.png';
762
763 add_menu_page(
764 'AL Pack 설정',
765 'AL Pack',
766 'manage_options',
767 'presslearn-settings',
768 array($this, 'render_settings_page'),
769 $icon_url,
770 2
771 );
772
773 add_submenu_page(
774 'presslearn-settings',
775 'AL Pack 대시보드',
776 '대시보드',
777 'manage_options',
778 'presslearn-settings',
779 array($this, 'render_settings_page')
780 );
781
782 if ($this->is_activated) {
783 add_submenu_page(
784 'presslearn-settings',
785 '스마트 스크롤',
786 '스마트 스크롤',
787 'manage_options',
788 'presslearn-scroll-depth',
789 array($this, 'render_advanced_page')
790 );
791
792 add_submenu_page(
793 'presslearn-settings',
794 '씬 애널리틱스',
795 '씬 애널리틱스',
796 'manage_options',
797 'presslearn-analytics',
798 array($this, 'render_analytics_page')
799 );
800
801 add_submenu_page(
802 'presslearn-settings',
803 '애드 프로�
804 �터',
805 '애드 프로�
806 �터',
807 'manage_options',
808 'presslearn-click-protection',
809 array($this, 'render_click_protection_page')
810 );
811
812 add_submenu_page(
813 'presslearn-settings',
814 '애드클리커',
815 '애드클리커',
816 'manage_options',
817 'presslearn-ad-clicker',
818 array($this, 'render_ad_clicker_page')
819 );
820
821 add_submenu_page(
822 'presslearn-settings',
823 '다이나믹 배너',
824 '다이나믹 배너',
825 'manage_options',
826 'presslearn-dynamic-banner',
827 array($this, 'render_dynamic_banner_page')
828 );
829
830 add_submenu_page(
831 'presslearn-settings',
832 '소�
833 � 공유',
834 '소�
835 � 공유',
836 'manage_options',
837 'presslearn-social-share',
838 array($this, 'render_social_share_page')
839 );
840
841 add_submenu_page(
842 'presslearn-settings',
843 '빠른 버튼 생성',
844 '빠른 버튼 생성',
845 'manage_options',
846 'presslearn-quick-button',
847 array($this, 'render_quick_button_page')
848 );
849
850 }
851 }
852
853 public function render_settings_page() {
854 $show_activated_notice = false;
855 $show_access_denied_notice = false;
856
857 if (current_user_can('manage_options') && is_admin()) {
858 if (isset($_GET['activated']) && sanitize_text_field(wp_unslash($_GET['activated'])) === 'true') {
859 $show_activated_notice = true;
860 }
861
862 if (isset($_GET['access_denied']) && sanitize_text_field(wp_unslash($_GET['access_denied'])) === 'true') {
863 $show_access_denied_notice = true;
864 }
865 }
866
867 if ($show_activated_notice) {
868 ?>
869 <div class="notice notice-success is-dismissible">
870 <p>프레스런 통합 플러그인이 성공적으로 활성화되었습니다</p>
871 </div>
872 <?php
873 }
874
875 if ($show_access_denied_notice) {
876 ?>
877 <div class="notice notice-error is-dismissible">
878 <p>프레스런 통합 플러그인이 활성화되지 않았습니다. 플러그인을 활성화해야 모든 기능에 접근할 있습니다.</p>
879 </div>
880 <?php
881 }
882
883 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-settings.php';
884 }
885
886
887 public function render_analytics_page() {
888 if (!$this->verify_activation()) {
889 return;
890 }
891
892 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-analytics.php';
893 }
894
895 public function render_advanced_page() {
896 if (!$this->verify_activation()) {
897 return;
898 }
899
900 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-scroll-depth.php';
901 }
902
903 public function render_click_protection_page() {
904 if (!$this->verify_activation()) {
905 return;
906 }
907
908 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-click-protection.php';
909 }
910
911 public function render_ad_clicker_page() {
912 if (!$this->verify_activation()) {
913 return;
914 }
915
916 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-adclicker.php';
917 }
918
919 public function render_dynamic_banner_page() {
920 if (!$this->verify_activation()) {
921 return;
922 }
923
924 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-dynamic-banner.php';
925 }
926
927 public function render_social_share_page() {
928 if (!$this->verify_activation()) {
929 return;
930 }
931
932 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-social-share.php';
933 }
934
935 public function render_quick_button_page() {
936 if (!$this->verify_activation()) {
937 return;
938 }
939
940 include_once PRESSLEARN_PLUGIN_DIR . 'templates/admin-quick-button.php';
941 }
942
943
944 private function verify_activation() {
945 if (!$this->is_activated) {
946 wp_redirect(admin_url('admin.php?page=presslearn-settings&access_denied=true'));
947 exit;
948 }
949
950 return true;
951 }
952
953
954 public function activate_plugin($key) {
955 $is_valid = strlen($key) >= 32;
956
957 if ($is_valid) {
958 update_option($this->option_key, $key);
959 $this->is_activated = true;
960 return true;
961 }
962
963 return false;
964 }
965
966 private function check_activation() {
967 $key = get_option($this->option_key, '');
968 $this->is_activated = !empty($key);
969 }
970
971 public function is_plugin_activated() {
972 return $this->is_activated;
973 }
974
975 public function get_kakao_login_url() {
976 $https = isset($_SERVER['HTTPS']) && sanitize_text_field(wp_unslash($_SERVER['HTTPS'])) === 'on';
977 $host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
978 $request_uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';
979
980 $current_url = ($https ? "https" : "http") . "://" . $host . $request_uri;
981 $kakao_login_url = 'https://presslearn.co.kr/login?redirect_url=' . urlencode($current_url) . '&popup=true';
982 return $kakao_login_url;
983 }
984
985 public function add_tracking_code() {
986 $analytics_enabled = get_option('presslearn_analytics_enabled', 'no');
987 $exclude_admin = get_option('presslearn_analytics_exclude_admin', '');
988
989 if ($analytics_enabled !== 'yes') {
990 return;
991 }
992
993 if (current_user_can('manage_options') && get_option('presslearn_analytics_exclude_admin') === 'yes') {
994 return;
995 }
996
997 $excluded_ips = array_map('trim', explode(',', $exclude_admin));
998 $user_ip = $this->get_ip_address();
999
1000 if (in_array($user_ip, $excluded_ips)) {
1001 return;
1002 }
1003
1004 wp_enqueue_script(
1005 'presslearn-analytics-tracking',
1006 PRESSLEARN_PLUGIN_URL . 'assets/js/analytics-tracking.js',
1007 array('jquery'),
1008 PRESSLEARN_PLUGIN_VERSION,
1009 true
1010 );
1011
1012 wp_localize_script(
1013 'presslearn-analytics-tracking',
1014 'pressleanAnalytics',
1015 array(
1016 'ajaxurl' => admin_url('admin-ajax.php'),
1017 'nonce' => wp_create_nonce('presslearn_tracking_nonce')
1018 )
1019 );
1020 }
1021
1022 public function get_ip_address() {
1023 $ip = '';
1024 $use_cloudflare = get_option('presslearn_analytics_use_cloudflare', 'no');
1025
1026 if ($use_cloudflare === 'yes' && isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
1027 $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_CONNECTING_IP']));
1028 } else {
1029 if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
1030 $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_CLIENT_IP']));
1031 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
1032 $ip_list = explode(',', sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR'])));
1033 $ip = trim($ip_list[0]);
1034 } else {
1035 $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
1036 }
1037 }
1038
1039 return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '';
1040 }
1041
1042 public function get_visitor_country($ip) {
1043 $ip = filter_var($ip, FILTER_VALIDATE_IP);
1044
1045 if (empty($ip) || $ip == '127.0.0.1' || $ip == '::1') {
1046 return '';
1047 }
1048
1049 $api_url = 'http://ip-api.com/json/' . esc_attr($ip);
1050 $response = wp_remote_get($api_url, array(
1051 'timeout' => 5,
1052 'headers' => array(
1053 'Accept' => 'application/json'
1054 )
1055 ));
1056
1057 if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
1058 $data = json_decode(wp_remote_retrieve_body($response), true);
1059 if (isset($data['country']) && $data['status'] === 'success') {
1060 return sanitize_text_field($data['country']);
1061 }
1062 }
1063
1064 return '';
1065 }
1066
1067 public function register_tracking_ajax() {
1068 add_action('wp_ajax_presslearn_track_pageview', array($this, 'track_pageview'));
1069 add_action('wp_ajax_nopriv_presslearn_track_pageview', array($this, 'track_pageview'));
1070 }
1071
1072 public function track_pageview() {
1073 check_ajax_referer('presslearn_tracking_nonce', 'nonce');
1074
1075 $visitor_id = isset($_POST['visitor_id']) ? sanitize_text_field(wp_unslash($_POST['visitor_id'])) : '';
1076 $url = isset($_POST['url']) ? esc_url_raw(wp_unslash($_POST['url'])) : '';
1077 $title = isset($_POST['title']) ? sanitize_text_field(wp_unslash($_POST['title'])) : '';
1078 $referrer = isset($_POST['referrer']) ? esc_url_raw(wp_unslash($_POST['referrer'])) : '';
1079 $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
1080 $ip = $this->get_ip_address();
1081 $country = $this->get_visitor_country($ip);
1082
1083 if (!empty($referrer)) {
1084 if (strpos($referrer, 'http') !== 0 && strpos($referrer, '//') !== 0) {
1085 $referrer = 'https://' . $referrer;
1086 }
1087
1088 if (strpos($referrer, '//') === 0) {
1089 $referrer = 'https:' . $referrer;
1090 }
1091
1092 $site_host = wp_parse_url(site_url(), PHP_URL_HOST);
1093 $referrer_host = wp_parse_url($referrer, PHP_URL_HOST);
1094
1095 if ($referrer_host === $site_host) {
1096 }
1097
1098 } else {
1099 }
1100
1101 $this->create_analytics_tables();
1102
1103 global $wpdb;
1104 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
1105 $table_visitors = $wpdb->prefix . 'presslearn_visitors';
1106
1107 if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") != $table_pageviews) {
1108 $this->create_analytics_tables();
1109 if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") != $table_pageviews) {
1110 wp_send_json_error('데이터베이스 �
1111 �이블을 생성할 수 없습니다.');
1112 wp_die();
1113 }
1114 }
1115
1116 $result = $wpdb->insert(
1117 $table_pageviews,
1118 array(
1119 'url' => $url,
1120 'title' => $title,
1121 'visitor_id' => $visitor_id,
1122 'referrer' => $referrer,
1123 'user_agent' => $user_agent,
1124 'country' => $country,
1125 'ip' => $ip,
1126 'created_at' => current_time('mysql')
1127 )
1128 );
1129
1130 if ($wpdb->last_error) {
1131 wp_send_json_error('데이터베이스 오류: ' . $wpdb->last_error);
1132 wp_die();
1133 } else {
1134 error_log('Pageview record inserted successfully: ' . $result);
1135
1136 $post_id = url_to_postid($url);
1137 if ($post_id > 0) {
1138 $cache_date = current_time('Y-m-d');
1139 wp_cache_delete("presslearn_visitors_{$post_id}_{$cache_date}", 'presslearn_analytics');
1140 wp_cache_delete("presslearn_today_{$post_id}_{$cache_date}", 'presslearn_analytics');
1141 wp_cache_delete("presslearn_week_{$post_id}_{$cache_date}", 'presslearn_analytics');
1142 wp_cache_delete("presslearn_month_{$post_id}_{$cache_date}", 'presslearn_analytics');
1143
1144 delete_post_meta($post_id, '_presslearn_post_views');
1145 }
1146 }
1147
1148 $visitor = $wpdb->get_row($wpdb->prepare(
1149 "SELECT * FROM $table_visitors WHERE visitor_id = %s",
1150 $visitor_id
1151 ));
1152
1153 if ($visitor) {
1154 $wpdb->update(
1155 $table_visitors,
1156 array(
1157 'last_visit' => current_time('mysql'),
1158 'visits' => $visitor->visits + 1
1159 ),
1160 array('visitor_id' => $visitor_id)
1161 );
1162 } else {
1163 $wpdb->insert(
1164 $table_visitors,
1165 array(
1166 'visitor_id' => $visitor_id,
1167 'first_visit' => current_time('mysql'),
1168 'last_visit' => current_time('mysql')
1169 )
1170 );
1171 }
1172
1173 if (!empty($referrer)) {
1174 $referrer_host = wp_parse_url($referrer, PHP_URL_HOST);
1175 error_log('Referrer host: ' . $referrer_host);
1176
1177 if (!empty($referrer_host)) {
1178 $table_referrers = $wpdb->prefix . 'presslearn_referrers';
1179
1180 if ($wpdb->get_var("SHOW TABLES LIKE '$table_referrers'") != $table_referrers) {
1181 $this->create_analytics_tables();
1182 }
1183
1184 $existing_referrer = $wpdb->get_row($wpdb->prepare(
1185 "SELECT * FROM $table_referrers WHERE referrer_host = %s",
1186 $referrer_host
1187 ));
1188
1189 if ($existing_referrer) {
1190 $wpdb->update(
1191 $table_referrers,
1192 array(
1193 'count' => $existing_referrer->count + 1,
1194 'last_visit' => current_time('mysql')
1195 ),
1196 array('id' => $existing_referrer->id)
1197 );
1198 } else {
1199 $wpdb->insert(
1200 $table_referrers,
1201 array(
1202 'referrer_host' => $referrer_host,
1203 'referrer_url' => $referrer,
1204 'count' => 1,
1205 'last_visit' => current_time('mysql')
1206 )
1207 );
1208 }
1209
1210 if ($wpdb->last_error) {
1211 error_log('Referrer insert/update error: ' . $wpdb->last_error);
1212 } else {
1213 error_log('Referrer record processed for: ' . $referrer_host);
1214 }
1215 }
1216 }
1217
1218 wp_send_json_success();
1219 wp_die();
1220 }
1221
1222 public function create_analytics_tables() {
1223 global $wpdb;
1224 $charset_collate = $wpdb->get_charset_collate();
1225
1226 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
1227 $table_visitors = $wpdb->prefix . 'presslearn_visitors';
1228 $table_referrers = $wpdb->prefix . 'presslearn_referrers';
1229
1230 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1231
1232 $wpdb->suppress_errors();
1233
1234 $tables_created = true;
1235
1236 if($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") != $table_pageviews) {
1237 $sql = "CREATE TABLE IF NOT EXISTS $table_pageviews (
1238 id bigint(20) NOT NULL AUTO_INCREMENT,
1239 url varchar(255) NOT NULL,
1240 title text NOT NULL,
1241 visitor_id varchar(32) NOT NULL,
1242 referrer text,
1243 user_agent text,
1244 country varchar(50),
1245 ip varchar(100),
1246 created_at datetime DEFAULT CURRENT_TIMESTAMP,
1247 PRIMARY KEY (id),
1248 KEY visitor_id (visitor_id),
1249 KEY url (url),
1250 KEY created_at (created_at)
1251 ) $charset_collate;";
1252
1253 $result = dbDelta($sql);
1254 if (empty($result)) {
1255 $tables_created = false;
1256 error_log('Error creating presslearn_pageviews table');
1257 }
1258 }
1259
1260 if($wpdb->get_var("SHOW TABLES LIKE '$table_visitors'") != $table_visitors) {
1261 $sql = "CREATE TABLE IF NOT EXISTS $table_visitors (
1262 id bigint(20) NOT NULL AUTO_INCREMENT,
1263 visitor_id varchar(32) NOT NULL,
1264 first_visit datetime DEFAULT CURRENT_TIMESTAMP,
1265 last_visit datetime DEFAULT CURRENT_TIMESTAMP,
1266 visits int(11) DEFAULT 1,
1267 PRIMARY KEY (id),
1268 UNIQUE KEY visitor_id (visitor_id),
1269 KEY first_visit (first_visit),
1270 KEY last_visit (last_visit)
1271 ) $charset_collate;";
1272
1273 $result = dbDelta($sql);
1274 if (empty($result)) {
1275 $tables_created = false;
1276 error_log('Error creating presslearn_visitors table');
1277 }
1278 }
1279
1280 if($wpdb->get_var("SHOW TABLES LIKE '$table_referrers'") != $table_referrers) {
1281 $sql = "CREATE TABLE IF NOT EXISTS $table_referrers (
1282 id bigint(20) NOT NULL AUTO_INCREMENT,
1283 referrer_host varchar(255),
1284 referrer_url text,
1285 count int(11) DEFAULT 1,
1286 last_visit datetime DEFAULT CURRENT_TIMESTAMP,
1287 PRIMARY KEY (id),
1288 KEY referrer_host (referrer_host),
1289 KEY last_visit (last_visit)
1290 ) $charset_collate;";
1291
1292 $result = dbDelta($sql);
1293 if (empty($result)) {
1294 $tables_created = false;
1295 error_log('Error creating presslearn_referrers table');
1296 }
1297 }
1298
1299 return $tables_created;
1300 }
1301
1302 public function get_visitor_ip_for_protection() {
1303 $use_cloudflare = get_option('presslearn_click_protection_use_cloudflare', 'no');
1304
1305 $ip = '';
1306
1307 if ($use_cloudflare === 'yes' && isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
1308 $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_CF_CONNECTING_IP']));
1309 }
1310 else {
1311 if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
1312 $ip = sanitize_text_field(wp_unslash($_SERVER['HTTP_CLIENT_IP']));
1313 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
1314 $ip_list = explode(',', sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR'])));
1315 $ip = trim($ip_list[0]);
1316 } else {
1317 $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
1318 }
1319 }
1320
1321 return $ip;
1322 }
1323
1324 public function add_admin_bar_menu($wp_admin_bar) {
1325 if (!$this->is_activated) {
1326 return;
1327 }
1328
1329 $wp_admin_bar->add_node(array(
1330 'id' => 'presslearn-menu',
1331 'title' => 'AL Pack',
1332 'href' => admin_url('admin.php?page=presslearn-settings'),
1333 'meta' => array(
1334 'title' => 'AL Pack'
1335 )
1336 ));
1337
1338 $wp_admin_bar->add_node(array(
1339 'id' => 'presslearn-settings',
1340 'parent' => 'presslearn-menu',
1341 'title' => '대시보드',
1342 'href' => admin_url('admin.php?page=presslearn-settings')
1343 ));
1344
1345 $wp_admin_bar->add_node(array(
1346 'id' => 'presslearn-analytics',
1347 'parent' => 'presslearn-menu',
1348 'title' => '씬 애널리틱스',
1349 'href' => admin_url('admin.php?page=presslearn-analytics')
1350 ));
1351
1352 $wp_admin_bar->add_node(array(
1353 'id' => 'presslearn-scroll-depth',
1354 'parent' => 'presslearn-menu',
1355 'title' => '스마트 스크롤',
1356 'href' => admin_url('admin.php?page=presslearn-scroll-depth')
1357 ));
1358
1359 $wp_admin_bar->add_node(array(
1360 'id' => 'presslearn-click-protection',
1361 'parent' => 'presslearn-menu',
1362 'title' => '애드 프로�
1363 �터',
1364 'href' => admin_url('admin.php?page=presslearn-click-protection')
1365 ));
1366
1367 $wp_admin_bar->add_node(array(
1368 'id' => 'presslearn-ad-clicker',
1369 'parent' => 'presslearn-menu',
1370 'title' => '애드클리커',
1371 'href' => admin_url('admin.php?page=presslearn-ad-clicker')
1372 ));
1373
1374 $wp_admin_bar->add_node(array(
1375 'id' => 'presslearn-dynamic-banner',
1376 'parent' => 'presslearn-menu',
1377 'title' => '다이나믹 배너',
1378 'href' => admin_url('admin.php?page=presslearn-dynamic-banner')
1379 ));
1380
1381 $wp_admin_bar->add_node(array(
1382 'id' => 'presslearn-social-share',
1383 'parent' => 'presslearn-menu',
1384 'title' => '소�
1385 � 공유',
1386 'href' => admin_url('admin.php?page=presslearn-social-share')
1387 ));
1388
1389 $wp_admin_bar->add_node(array(
1390 'id' => 'presslearn-quick-button',
1391 'parent' => 'presslearn-menu',
1392 'title' => '빠른 버튼 생성',
1393 'href' => admin_url('admin.php?page=presslearn-quick-button')
1394 ));
1395 }
1396 }
1397
1398 function presslearn_plugin() {
1399 return PressLearn_Plugin::get_instance();
1400 }
1401
1402 presslearn_plugin();
1403
1404 add_action('wp_ajax_presslearn_get_allowed_ips', 'presslearn_get_allowed_ips');
1405 add_action('wp_ajax_presslearn_add_allowed_ip', 'presslearn_add_allowed_ip');
1406 add_action('wp_ajax_presslearn_delete_allowed_ip', 'presslearn_delete_allowed_ip');
1407 add_action('wp_ajax_presslearn_get_blocked_ips', 'presslearn_get_blocked_ips');
1408 add_action('wp_ajax_presslearn_add_blocked_ip', 'presslearn_add_blocked_ip');
1409 add_action('wp_ajax_presslearn_delete_blocked_ip', 'presslearn_delete_blocked_ip');
1410 add_action('wp_ajax_presslearn_delete_analytics_data', 'presslearn_delete_analytics_data');
1411
1412 function presslearn_get_allowed_ips() {
1413 check_ajax_referer('presslearn_ip_nonce', 'nonce');
1414
1415 if (current_user_can('manage_options')) {
1416 $allowed_ips = get_option('presslearn_click_protection_allowed_ips', array());
1417
1418 wp_send_json_success(array(
1419 'ips' => $allowed_ips
1420 ));
1421 }
1422
1423 wp_send_json_error(array('message' => '권한이 없습니다.'));
1424 wp_die();
1425 }
1426
1427 function presslearn_add_allowed_ip() {
1428 check_ajax_referer('presslearn_ip_nonce', 'nonce');
1429
1430 if (current_user_can('manage_options')) {
1431 $ip = isset($_POST['ip']) ? sanitize_text_field(wp_unslash($_POST['ip'])) : '';
1432
1433 if (empty($ip) || !filter_var($ip, FILTER_VALIDATE_IP)) {
1434 wp_send_json_error(array('message' => '유효하지 않은 IP 주소�
1435 니다.'));
1436 wp_die();
1437 }
1438
1439 $allowed_ips = get_option('presslearn_click_protection_allowed_ips', array());
1440
1441 foreach ($allowed_ips as $item) {
1442 if ($item['ip'] === $ip) {
1443 wp_send_json_error(array('message' => '이미 등록된 IP 주소�
1444 니다.'));
1445 wp_die();
1446 }
1447 }
1448
1449 $allowed_ips[] = array(
1450 'ip' => $ip,
1451 'date' => current_time('Y-m-d')
1452 );
1453
1454 update_option('presslearn_click_protection_allowed_ips', $allowed_ips);
1455
1456 wp_send_json_success(array(
1457 'message' => 'IP가 성공적으로 추가되었습니다.',
1458 'ips' => $allowed_ips
1459 ));
1460 }
1461
1462 wp_die();
1463 }
1464
1465 function presslearn_delete_allowed_ip() {
1466 check_ajax_referer('presslearn_ip_nonce', 'nonce');
1467
1468 if (current_user_can('manage_options')) {
1469 $ip = isset($_POST['ip']) ? sanitize_text_field(wp_unslash($_POST['ip'])) : '';
1470
1471 if (empty($ip)) {
1472 wp_send_json_error(array('message' => '삭제할 IP 주소가 지정되지 않았습니다.'));
1473 wp_die();
1474 }
1475
1476 $allowed_ips = get_option('presslearn_click_protection_allowed_ips', array());
1477
1478 foreach ($allowed_ips as $key => $item) {
1479 if ($item['ip'] === $ip) {
1480 unset($allowed_ips[$key]);
1481 break;
1482 }
1483 }
1484
1485 $allowed_ips = array_values($allowed_ips);
1486
1487 update_option('presslearn_click_protection_allowed_ips', $allowed_ips);
1488
1489 wp_send_json_success(array(
1490 'message' => 'IP가 성공적으로 삭제되었습니다.',
1491 'ips' => $allowed_ips
1492 ));
1493 }
1494
1495 wp_die();
1496 }
1497
1498 function presslearn_get_blocked_ips() {
1499 check_ajax_referer('presslearn_ip_nonce', 'nonce');
1500
1501 if (current_user_can('manage_options')) {
1502 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
1503
1504 wp_send_json_success(array(
1505 'ips' => $blocked_ips
1506 ));
1507 }
1508
1509 wp_send_json_error(array('message' => '권한이 없습니다.'));
1510 wp_die();
1511 }
1512
1513 function presslearn_add_blocked_ip() {
1514 check_ajax_referer('presslearn_ip_nonce', 'nonce');
1515
1516 if (current_user_can('manage_options')) {
1517 $ip = isset($_POST['ip']) ? sanitize_text_field(wp_unslash($_POST['ip'])) : '';
1518
1519 if (empty($ip) || !filter_var($ip, FILTER_VALIDATE_IP)) {
1520 wp_send_json_error(array('message' => '유효하지 않은 IP 주소�
1521 니다.'));
1522 wp_die();
1523 }
1524
1525 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
1526
1527 foreach ($blocked_ips as $item) {
1528 if ($item['ip'] === $ip) {
1529 wp_send_json_error(array('message' => '이미 차단된 IP 주소�
1530 니다.'));
1531 wp_die();
1532 }
1533 }
1534
1535 $current_date = current_time('Y-m-d');
1536
1537 $block_expiry_days = get_option('presslearn_click_protection_block_expiry_days', 30);
1538 $expires = $block_expiry_days > 0 ? gmdate('Y-m-d', strtotime("+{$block_expiry_days} days")) : '';
1539
1540 $blocked_ips[] = array(
1541 'ip' => $ip,
1542 'date' => $current_date,
1543 'block_date' => $current_date,
1544 'reason' => '수동 차단',
1545 'expires' => $expires
1546 );
1547
1548 update_option('presslearn_click_protection_blocked_ips', $blocked_ips);
1549
1550 wp_send_json_success(array(
1551 'message' => 'IP가 성공적으로 차단되었습니다.',
1552 'ips' => $blocked_ips
1553 ));
1554 }
1555
1556 wp_die();
1557 }
1558
1559 function presslearn_delete_blocked_ip() {
1560 check_ajax_referer('presslearn_ip_nonce', 'nonce');
1561
1562 if (current_user_can('manage_options')) {
1563 $ip = isset($_POST['ip']) ? sanitize_text_field(wp_unslash($_POST['ip'])) : '';
1564
1565 if (empty($ip)) {
1566 wp_send_json_error(array('message' => '삭제할 IP 주소가 지정되지 않았습니다.'));
1567 wp_die();
1568 }
1569
1570 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
1571
1572 foreach ($blocked_ips as $key => $item) {
1573 if ($item['ip'] === $ip) {
1574 unset($blocked_ips[$key]);
1575 break;
1576 }
1577 }
1578
1579 $blocked_ips = array_values($blocked_ips);
1580
1581 update_option('presslearn_click_protection_blocked_ips', $blocked_ips);
1582
1583 wp_send_json_success(array(
1584 'message' => 'IP 차단이 성공적으로 해제되었습니다.',
1585 'ips' => $blocked_ips
1586 ));
1587 }
1588
1589 wp_die();
1590 }
1591
1592 add_action('init', 'presslearn_setup_cron_for_ip_unblock');
1593
1594 function presslearn_setup_cron_for_ip_unblock() {
1595 if (!wp_next_scheduled('presslearn_check_blocked_ips_expiry')) {
1596 wp_schedule_event(strtotime('tomorrow midnight'), 'daily', 'presslearn_check_blocked_ips_expiry');
1597 }
1598 }
1599
1600 add_action('presslearn_check_blocked_ips_expiry', 'presslearn_check_and_remove_expired_blocked_ips');
1601
1602 function presslearn_check_and_remove_expired_blocked_ips() {
1603 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
1604 if (empty($blocked_ips)) {
1605 return;
1606 }
1607
1608 $block_expiry_days = get_option('presslearn_click_protection_block_expiry_days', 30);
1609
1610 $current_date = new DateTime(current_time('Y-m-d'));
1611 $updated = false;
1612
1613 $new_blocked_ips = array();
1614
1615 foreach ($blocked_ips as $item) {
1616 $block_date = isset($item['block_date']) ? $item['block_date'] : $item['date'];
1617
1618 $block_date_obj = new DateTime($block_date);
1619
1620 $interval = $current_date->diff($block_date_obj);
1621 $days_since_blocked = $interval->days;
1622
1623 if ($days_since_blocked < $block_expiry_days) {
1624 $new_blocked_ips[] = $item;
1625 } else {
1626 $updated = true;
1627 }
1628 }
1629
1630 if ($updated) {
1631 update_option('presslearn_click_protection_blocked_ips', $new_blocked_ips);
1632 }
1633 }
1634
1635 register_deactivation_hook(__FILE__, 'presslearn_clear_cron_for_ip_unblock');
1636
1637 function presslearn_clear_cron_for_ip_unblock() {
1638 $timestamp = wp_next_scheduled('presslearn_check_blocked_ips_expiry');
1639 if ($timestamp) {
1640 wp_unschedule_event($timestamp, 'presslearn_check_blocked_ips_expiry');
1641 }
1642 }
1643
1644 function presslearn_block_ads_for_blocked_ips() {
1645 if (is_admin()) {
1646 return;
1647 }
1648
1649 $click_protection_enabled = get_option('presslearn_click_protection_enabled', 'no');
1650 if ($click_protection_enabled !== 'yes') {
1651 return;
1652 }
1653
1654 $use_cloudflare = get_option('presslearn_click_protection_use_cloudflare', 'no');
1655
1656 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
1657 if (empty($blocked_ips)) {
1658 return;
1659 }
1660
1661 $user_ip = presslearn_plugin()->get_visitor_ip_for_protection();
1662
1663 $is_blocked = false;
1664
1665 foreach ($blocked_ips as $item) {
1666 if ($item['ip'] === $user_ip) {
1667 $is_blocked = true;
1668 break;
1669 }
1670 }
1671
1672 if (!$is_blocked) {
1673 return;
1674 }
1675
1676 setcookie('pl_ad_blocked', '1', time() + 86400, '/');
1677
1678 wp_register_style('presslearn-ad-block-css', false);
1679 wp_enqueue_style('presslearn-ad-block-css');
1680
1681 $ad_block_css = "
1682 #google_esf,
1683 .adsbygoogle,
1684 iframe[id^=\"google_ads_\"],
1685 ins.adsbygoogle,
1686 ins.adsbygoogle-noablate,
1687 iframe[id^=\"aswift_\"],
1688 div[id^=\"aswift_\"],
1689 [data-ad-status],
1690 [data-adsbygoogle-status],
1691 [data-google-query-id],
1692 [data-google-container-id],
1693 [data-ad-format],
1694 ins[class*=\"adsbygoogle\"] {
1695 display: none !important;
1696 visibility: hidden !important;
1697 opacity: 0 !important;
1698 width: 0 !important;
1699 height: 0 !important;
1700 position: absolute !important;
1701 left: -9999px !important;
1702 top: -9999px !important;
1703 pointer-events: none !important;
1704 max-width: 0 !important;
1705 max-height: 0 !important;
1706 overflow: hidden !important;
1707 }
1708
1709 .right-side-rail-edge,
1710 .right-side-rail-dismiss-btn,
1711 [data-side-rail-status] {
1712 display: none !important;
1713 visibility: hidden !important;
1714 opacity: 0 !important;
1715 }
1716 ";
1717
1718 wp_add_inline_style('presslearn-ad-block-css', $ad_block_css);
1719
1720 wp_register_script('presslearn-ad-block-js', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
1721 wp_enqueue_script('presslearn-ad-block-js');
1722
1723 $ad_block_script = "
1724 (function() {
1725 function preventAdLoad() {
1726
1727 window.adsbygoogle = [];
1728 window.google_ad_status = 1;
1729
1730 var adScripts = document.querySelectorAll('script[src*=\"pagead2.googlesyndication.com\"], script[src*=\"googleads\"], script[src*=\"adsbygoogle\"]');
1731 adScripts.forEach(function(script) {
1732 if (script && script.parentNode) {
1733 script.parentNode.removeChild(script);
1734 }
1735 });
1736 }
1737
1738 preventAdLoad();
1739 })();
1740
1741 document.addEventListener('DOMContentLoaded', function() {
1742
1743 function removeAdsElements() {
1744 const esfElements = document.querySelectorAll('#google_esf');
1745 esfElements.forEach(element => {
1746 element.style.display = 'none !important';
1747 if (element.parentNode) {
1748 element.parentNode.removeChild(element);
1749 }
1750 });
1751
1752 const adsSelectors = [
1753 '#adsbygoogle',
1754 '.adsbygoogle',
1755 'ins.adsbygoogle',
1756 'ins.adsbygoogle-noablate',
1757 'iframe[id^=\"google_ads_\"]',
1758 'iframe[id^=\"aswift_\"]',
1759 'div[id^=\"aswift_\"]',
1760 '[data-ad-status]',
1761 '[data-adsbygoogle-status]',
1762 '[data-google-query-id]',
1763 '[data-google-container-id]',
1764 '[data-ad-format]'
1765 ];
1766
1767 adsSelectors.forEach(selector => {
1768 const elements = document.querySelectorAll(selector);
1769 elements.forEach(element => {
1770 element.style.display = 'none !important';
1771 if (element.parentNode) {
1772 element.parentNode.removeChild(element);
1773 }
1774 });
1775 });
1776
1777 const styleElement = document.createElement('style');
1778 styleElement.textContent =
1779 '#google_esf, ' +
1780 '#adsbygoogle,' +
1781 '.adsbygoogle,' +
1782 'ins.adsbygoogle,' +
1783 'ins.adsbygoogle-noablate,' +
1784 'iframe[id^=\"google_ads_\"],' +
1785 'iframe[id^=\"aswift_\"],' +
1786 'div[id^=\"aswift_\"],' +
1787 '[data-ad-status],' +
1788 '[data-adsbygoogle-status],' +
1789 '[data-google-query-id],' +
1790 '[data-google-container-id],' +
1791 '[data-ad-format] { ' +
1792 'display: none !important; ' +
1793 'visibility: hidden !important;' +
1794 'opacity: 0 !important;' +
1795 'pointer-events: none !important;' +
1796 'width: 0px !important;' +
1797 'height: 0px !important;' +
1798 'position: absolute !important;' +
1799 'top: -9999px !important;' +
1800 'left: -9999px !important;' +
1801 '}';
1802 document.head.appendChild(styleElement);
1803 }
1804
1805 if (document.readyState === 'loading') {
1806 document.addEventListener('DOMContentLoaded', removeAdsElements);
1807 } else {
1808 removeAdsElements();
1809 }
1810
1811 const adObserver = new MutationObserver(function(mutations) {
1812 mutations.forEach(function(mutation) {
1813 if (mutation.addedNodes && mutation.addedNodes.length > 0) {
1814 for (let i = 0; i < mutation.addedNodes.length; i++) {
1815 const node = mutation.addedNodes[i];
1816 if (node.id === 'google_esf' || node.id === 'adsbygoogle') {
1817 node.style.display = 'none !important';
1818 if (node.parentNode) {
1819 node.parentNode.removeChild(node);
1820 }
1821 }
1822 }
1823 }
1824 });
1825 });
1826
1827 adObserver.observe(document.documentElement, {
1828 childList: true,
1829 subtree: true
1830 });
1831 });
1832 ";
1833
1834 wp_add_inline_script('presslearn-ad-block-js', $ad_block_script);
1835 }
1836
1837 add_action('wp_body_open', 'presslearn_block_ads_for_blocked_ips', 1);
1838 add_action('wp_footer', 'presslearn_check_blocked_status', 1);
1839
1840 function presslearn_check_blocked_status() {
1841 if (is_admin()) {
1842 return;
1843 }
1844
1845 $click_protection_enabled = get_option('presslearn_click_protection_enabled', 'no');
1846 if ($click_protection_enabled !== 'yes') {
1847 return;
1848 }
1849
1850 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
1851 if (empty($blocked_ips)) {
1852 return;
1853 }
1854
1855 $user_ip = presslearn_plugin()->get_visitor_ip_for_protection();
1856 $is_blocked = false;
1857
1858 foreach ($blocked_ips as $item) {
1859 if ($item['ip'] === $user_ip) {
1860 $is_blocked = true;
1861 break;
1862 }
1863 }
1864
1865 if (!$is_blocked) {
1866 return;
1867 }
1868
1869 wp_register_script('presslearn-blocked-status-js', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
1870 wp_enqueue_script('presslearn-blocked-status-js');
1871
1872 $blocked_status_script = "
1873 (function() {
1874
1875 function removeAds() {
1876 var selectors = [
1877 '#google_esf',
1878 '.adsbygoogle',
1879 'ins.adsbygoogle',
1880 'ins.adsbygoogle-noablate',
1881 'iframe[id^=\"google_ads_\"]',
1882 'iframe[id^=\"aswift_\"]',
1883 'div[id^=\"aswift_\"]',
1884 '[data-ad-status]',
1885 '[data-adsbygoogle-status]',
1886 '[data-google-query-id]',
1887 '[data-google-container-id]',
1888 '[data-ad-format]',
1889 'ins[class*=\"adsbygoogle\"],
1890 .right-side-rail-edge,
1891 .right-side-rail-dismiss-btn,
1892 '[data-side-rail-status]'
1893 ];
1894
1895 selectors.forEach(function(selector) {
1896 var elements = document.querySelectorAll(selector);
1897 elements.forEach(function(element) {
1898 if (element && element.parentNode) {
1899 element.parentNode.removeChild(element);
1900 }
1901 });
1902 });
1903 }
1904
1905 removeAds();
1906 setTimeout(removeAds, 1000);
1907 })();
1908 ";
1909
1910 wp_add_inline_script('presslearn-blocked-status-js', $blocked_status_script);
1911 }
1912
1913 function presslearn_add_ad_protection_script() {
1914 if (is_admin()) {
1915 return;
1916 }
1917
1918 $click_protection_enabled = get_option('presslearn_click_protection_enabled', 'no');
1919 if ($click_protection_enabled !== 'yes') {
1920 return;
1921 }
1922
1923 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
1924 $user_ip = presslearn_plugin()->get_visitor_ip_for_protection();
1925
1926 $allowed_ips = get_option('presslearn_click_protection_allowed_ips', array());
1927 $is_allowed = false;
1928
1929 foreach ($allowed_ips as $item) {
1930 if ($item['ip'] === $user_ip) {
1931 $is_allowed = true;
1932 break;
1933 }
1934 }
1935
1936 $is_blocked = false;
1937 foreach ($blocked_ips as $item) {
1938 if ($item['ip'] === $user_ip) {
1939 $is_blocked = true;
1940 break;
1941 }
1942 }
1943
1944 if ($is_allowed) {
1945 return;
1946 }
1947
1948 if ($is_blocked) {
1949 presslearn_block_ads_for_blocked_ips();
1950 return;
1951 }
1952
1953 $max_click_count = intval(get_option('presslearn_max_click_count', 10));
1954
1955 wp_register_style('presslearn-protection-modal-css', false);
1956 wp_enqueue_style('presslearn-protection-modal-css');
1957
1958 $modal_css = "
1959 .pl-modal-overlay {
1960 display: none;
1961 position: fixed;
1962 top: 0;
1963 left: 0;
1964 width: 100%;
1965 height: 100%;
1966 background-color: rgba(0, 0, 0, 0.7);
1967 z-index: 999999;
1968 justify-content: center;
1969 align-items: center;
1970 overflow: hidden;
1971 }
1972
1973 .pl-modal {
1974 background: white;
1975 padding: 30px;
1976 border-radius: 8px;
1977 max-width: 500px;
1978 width: 90%;
1979 text-align: center;
1980 box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
1981 position: relative;
1982 }
1983
1984 .pl-modal h2 {
1985 margin-top: 0;
1986 font-size: 24px;
1987 color: #d32f2f;
1988 }
1989
1990 .pl-modal p {
1991 margin: 15px 0;
1992 font-size: 16px;
1993 line-height: 1.5;
1994 }
1995
1996 .pl-modal-close {
1997 display: inline-block;
1998 background: #d32f2f;
1999 color: white;
2000 padding: 10px 20px;
2001 margin-top: 20px;
2002 border-radius: 4px;
2003 cursor: pointer;
2004 font-weight: bold;
2005 border: none;
2006 }
2007
2008 .pl-modal-close:hover {
2009 background: #b71c1c;
2010 }
2011
2012 .pl-blocked-ad-notice {
2013 display: block;
2014 padding: 15px;
2015 background-color: #fff8f8;
2016 border: 1px solid #ffdddd;
2017 text-align: center;
2018 font-size: 14px;
2019 color: #d32f2f;
2020 margin: 15px 0;
2021 border-radius: 4px;
2022 font-weight: bold;
2023 }
2024
2025 body.pl-modal-open {
2026 overflow: hidden;
2027 }
2028 ";
2029
2030 wp_add_inline_style('presslearn-protection-modal-css', $modal_css);
2031
2032 add_action('wp_footer', function() {
2033 ?>
2034 <div class="pl-modal-overlay" id="pl-block-modal">
2035 <div class="pl-modal">
2036 <h2><?php echo esc_html(get_option('presslearn_modal_title', '광고 차단 알림')); ?></h2>
2037 <p><?php echo esc_html(get_option('presslearn_modal_message', '광고 클릭 제한을 초과하여 광고가 차단되었습니다.')); ?></p>
2038 <p><?php echo esc_html(get_option('presslearn_modal_submessage', '단시간에 반복적인 광고 클릭은 시스�
2039 �에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.')); ?></p>
2040 <button class="pl-modal-close" id="pl-modal-close"><?php echo esc_html(get_option('presslearn_modal_button_text', '확인')); ?></button>
2041 </div>
2042 </div>
2043 <?php
2044 });
2045
2046 wp_register_script('presslearn-protection-script-js', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
2047 wp_enqueue_script('presslearn-protection-script-js');
2048
2049 $protection_script = "
2050 (function() {
2051 function getStorageItem(name, defaultValue) {
2052 try {
2053 const item = localStorage.getItem(name);
2054 return item !== null ? item : defaultValue;
2055 } catch (e) {
2056 return defaultValue;
2057 }
2058 }
2059
2060 function setStorageItem(name, value) {
2061 try {
2062 localStorage.setItem(name, value);
2063 return true;
2064 } catch (e) {
2065 return false;
2066 }
2067 }
2068
2069 const maxClickCount = " . esc_js($max_click_count) . ";
2070
2071 const clickCount = getStorageItem('adsenseClickCount') ?
2072 parseInt(getStorageItem('adsenseClickCount')) : 0;
2073
2074 if (clickCount >= maxClickCount) {
2075 removeAllAds();
2076 }
2077
2078 function isAdsenseAd(element) {
2079 if (!element) return false;
2080
2081 if (element.tagName === 'IFRAME' && element.src &&
2082 element.src.includes('google')) {
2083 return true;
2084 }
2085
2086 if (element.tagName === 'INS' &&
2087 element.hasAttribute('data-ad-client') &&
2088 element.getAttribute('data-ad-client').includes('pub-')) {
2089 return true;
2090 }
2091
2092 if (element.tagName === 'DIV' &&
2093 (element.id === 'google_vignette' ||
2094 element.id === 'google_anchor' ||
2095 element.className.includes('google-auto-placed') ||
2096 element.hasAttribute('data-vignette-loaded') ||
2097 element.hasAttribute('data-anchor-status'))) {
2098 return true;
2099 }
2100
2101 if (element.tagName === 'IFRAME' &&
2102 (element.id.includes('google_ads_iframe') ||
2103 element.hasAttribute('data-google-container-id') ||
2104 (element.src && (element.src.includes('googleads') ||
2105 element.src.includes('doubleclick'))))) {
2106 return true;
2107 }
2108
2109 return false;
2110 }
2111
2112 function removeAllAds() {
2113 const selectors = [
2114 '#google_esf',
2115 '.adsbygoogle',
2116 'ins.adsbygoogle',
2117 'ins.adsbygoogle-noablate',
2118 'iframe[id^=\"google_ads_\"]',
2119 'iframe[id^=\"aswift_\"]',
2120 'div[id^=\"aswift_\"]',
2121 '[data-ad-status]',
2122 '[data-adsbygoogle-status]',
2123 '[data-google-query-id]',
2124 '[data-google-container-id]',
2125 '[data-ad-format]',
2126 '#google_vignette',
2127 '#google_anchor',
2128 '.google-auto-placed',
2129 '[data-vignette-loaded]',
2130 '[data-anchor-status]',
2131 'iframe[id*=\"google_ads_iframe\"]',
2132 'iframe[src*=\"googleads\"]',
2133 'iframe[src*=\"doubleclick\"]',
2134 'div[id^=\"google_ads_iframe\"]',
2135 'div.right-side-rail-edge',
2136 'div[data-side-rail-status]'
2137 ];
2138
2139 const style = document.createElement('style');
2140 style.textContent =
2141 '#google_esf, ' +
2142 '.adsbygoogle,' +
2143 'iframe[id^=\"google_ads_\"],' +
2144 'ins.adsbygoogle,' +
2145 'ins.adsbygoogle-noablate,' +
2146 'iframe[id^=\"aswift_\"],' +
2147 'div[id^=\"aswift_\"],' +
2148 '[data-ad-status],' +
2149 '[data-adsbygoogle-status],' +
2150 '[data-google-query-id],' +
2151 '[data-google-container-id],' +
2152 '[data-ad-format],' +
2153 '#google_vignette,' +
2154 '#google_anchor,' +
2155 '.google-auto-placed,' +
2156 '[data-vignette-loaded],' +
2157 '[data-anchor-status],' +
2158 'iframe[id*=\"google_ads_iframe\"],' +
2159 'iframe[src*=\"googleads\"],' +
2160 'iframe[src*=\"doubleclick\"],' +
2161 'div[id^=\"google_ads_iframe\"],' +
2162 'div.right-side-rail-edge,' +
2163 'div[data-side-rail-status] {' +
2164 'display: none !important;' +
2165 'visibility: hidden !important;' +
2166 'opacity: 0 !important;' +
2167 'width: 0 !important;' +
2168 'height: 0 !important;' +
2169 'position: absolute !important;' +
2170 'left: -9999px !important;' +
2171 'top: -9999px !important;' +
2172 '}';
2173 document.head.appendChild(style);
2174
2175 selectors.forEach(selector => {
2176 document.querySelectorAll(selector).forEach(element => {
2177 if (element && element.parentNode) {
2178 element.parentNode.removeChild(element);
2179 }
2180 });
2181 });
2182 }
2183
2184 function blockCurrentIP() {
2185 const formData = new FormData();
2186 formData.append('action', 'presslearn_block_current_ip');
2187 formData.append('nonce', '" . esc_js(wp_create_nonce('presslearn_block_ip_nonce')) . "');
2188
2189 fetch('" . esc_url(admin_url('admin-ajax.php')) . "', {
2190 method: 'POST',
2191 credentials: 'same-origin',
2192 body: formData
2193 });
2194 }
2195
2196 function showBlockModal() {
2197 removeAllAds();
2198
2199 const modal = document.getElementById('pl-block-modal');
2200 modal.style.display = 'flex';
2201 document.body.classList.add('pl-modal-open');
2202 }
2203
2204 document.getElementById('pl-modal-close').addEventListener('click', function() {
2205 const modal = document.getElementById('pl-block-modal');
2206 modal.style.display = 'none';
2207 document.body.classList.remove('pl-modal-open');
2208 removeAllAds();
2209 });
2210
2211 function addClickCount() {
2212 let clickCount = getStorageItem('adsenseClickCount') ?
2213 parseInt(getStorageItem('adsenseClickCount')) : 0;
2214
2215 if (clickCount < maxClickCount) {
2216 clickCount++;
2217 setStorageItem('adsenseClickCount', clickCount.toString());
2218
2219 setStorageItem('lastClickTime', Date.now().toString());
2220 }
2221
2222 if (clickCount >= maxClickCount) {
2223 removeAllAds();
2224
2225 blockCurrentIP();
2226
2227 showBlockModal();
2228
2229 setStorageItem('adsenseClickCount', '0');
2230 }
2231 }
2232
2233 window.addEventListener('blur', function() {
2234 const activeElement = document.activeElement;
2235
2236 if (isAdsenseAd(activeElement)) {
2237 if (window.location.href.includes('#google_vignette')) {
2238 return;
2239 }
2240
2241 addClickCount();
2242
2243 setTimeout(function() {
2244 activeElement.blur();
2245 }, 1);
2246 }
2247 });
2248
2249 document.addEventListener('click', function(e) {
2250 const target = e.target;
2251
2252 let currentElement = target;
2253 for (let i = 0; i < 5; i++) {
2254 if (!currentElement) break;
2255
2256 if (isAdsenseAd(currentElement)) {
2257 addClickCount();
2258 break;
2259 }
2260
2261 currentElement = currentElement.parentElement;
2262 }
2263 }, true);
2264
2265 window.addEventListener('message', function(event) {
2266 try {
2267 if (typeof event.data === 'string' &&
2268 (event.data.includes('google_ads') ||
2269 event.data.includes('doubleclick') ||
2270 event.data.includes('GoogleAdServingTest'))) {
2271
2272 const lastClickTime = getStorageItem('lastClickTime', '0');
2273 const now = Date.now();
2274
2275 if (now - parseInt(lastClickTime) < 2000) {
2276 addClickCount();
2277 }
2278 }
2279 } catch (e) {}
2280 });
2281 })();
2282 ";
2283
2284 wp_add_inline_script('presslearn-protection-script-js', $protection_script);
2285 }
2286
2287 add_action('wp_body_open', 'presslearn_add_ad_protection_script', 1);
2288
2289 function presslearn_block_current_ip_ajax() {
2290 check_ajax_referer('presslearn_block_ip_nonce', 'nonce');
2291
2292 $click_protection_enabled = get_option('presslearn_click_protection_enabled', 'no');
2293 if ($click_protection_enabled !== 'yes') {
2294 wp_send_json_error(array('message' => '애드 프로�
2295 �터가 비활성화되어 있습니다.'));
2296 wp_die();
2297 }
2298
2299 $user_ip = presslearn_plugin()->get_visitor_ip_for_protection();
2300
2301 $allowed_ips = get_option('presslearn_click_protection_allowed_ips', array());
2302 foreach ($allowed_ips as $item) {
2303 if ($item['ip'] === $user_ip) {
2304 wp_send_json_error(array('message' => '허용된 IP�
2305 니다.'));
2306 wp_die();
2307 }
2308 }
2309
2310 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
2311 $is_already_blocked = false;
2312
2313 foreach ($blocked_ips as $item) {
2314 if ($item['ip'] === $user_ip) {
2315 $is_already_blocked = true;
2316 break;
2317 }
2318 }
2319
2320 if (!$is_already_blocked) {
2321 $current_date = current_time('Y-m-d');
2322
2323 $block_expiry_days = get_option('presslearn_click_protection_block_expiry_days', 30);
2324
2325 $blocked_ips[] = array(
2326 'ip' => $user_ip,
2327 'date' => $current_date,
2328 'block_date' => $current_date,
2329 'reason' => '광고 클릭 제한 초과',
2330 'expires' => $block_expiry_days > 0 ? gmdate('Y-m-d', strtotime("+{$block_expiry_days} days")) : ''
2331 );
2332
2333 update_option('presslearn_click_protection_blocked_ips', $blocked_ips);
2334
2335 wp_send_json_success(array(
2336 'message' => 'IP가 성공적으로 차단되었습니다.',
2337 'blocked_ip' => $user_ip,
2338 'block_date' => $current_date,
2339 'is_new' => true
2340 ));
2341 } else {
2342 wp_send_json_success(array(
2343 'message' => '이미 차단된 IP�
2344 니다.',
2345 'blocked_ip' => $user_ip,
2346 'is_new' => false
2347 ));
2348 }
2349
2350 wp_die();
2351 }
2352
2353 add_action('wp_ajax_presslearn_block_current_ip', 'presslearn_block_current_ip_ajax');
2354 add_action('wp_ajax_nopriv_presslearn_block_current_ip', 'presslearn_block_current_ip_ajax');
2355
2356 add_action('wp_head', 'presslearn_add_adclicker_script', 1);
2357
2358 add_action('wp_ajax_presslearn_get_blocked_logs', 'presslearn_get_blocked_logs');
2359
2360 function presslearn_get_blocked_logs() {
2361 check_ajax_referer('presslearn_ip_nonce', 'nonce');
2362
2363 if (current_user_can('manage_options')) {
2364 $blocked_ips = get_option('presslearn_click_protection_blocked_ips', array());
2365 $period = isset($_POST['period']) ? sanitize_text_field(wp_unslash($_POST['period'])) : '30';
2366
2367 if ($period !== 'all' && !empty($blocked_ips)) {
2368 $filtered_logs = array();
2369 $cutoff_date = gmdate('Y-m-d', strtotime("-{$period} days"));
2370
2371 foreach ($blocked_ips as $item) {
2372 $block_date = isset($item['block_date']) ? $item['block_date'] : $item['date'];
2373 if ($block_date >= $cutoff_date) {
2374 $filtered_logs[] = $item;
2375 }
2376 }
2377
2378 $blocked_ips = $filtered_logs;
2379 }
2380
2381 usort($blocked_ips, function($a, $b) {
2382 $date_a = isset($a['block_date']) ? $a['block_date'] : $a['date'];
2383 $date_b = isset($b['block_date']) ? $b['block_date'] : $b['date'];
2384 return strtotime($date_b) - strtotime($date_a);
2385 });
2386
2387 wp_send_json_success(array(
2388 'logs' => $blocked_ips
2389 ));
2390 }
2391
2392 wp_send_json_error(array('message' => '권한이 없습니다.'));
2393 wp_die();
2394 }
2395
2396 function presslearn_add_adclicker_script() {
2397 if (!function_exists('presslearn_plugin') || !presslearn_plugin()->is_plugin_activated()) {
2398 return;
2399 }
2400
2401 $adclicker_enabled = get_option('presslearn_ad_clicker_enabled', 'no');
2402 if ($adclicker_enabled !== 'yes') {
2403 return;
2404 }
2405
2406 if (!is_single()) {
2407 return;
2408 }
2409
2410 global $post;
2411 $post_adclicker_enabled = get_post_meta($post->ID, '_presslearn_adclicker_enabled', true);
2412
2413 if ($post_adclicker_enabled === '') {
2414 $post_adclicker_enabled = 'yes';
2415 }
2416
2417 if ($post_adclicker_enabled === 'no') {
2418 return;
2419 }
2420
2421 $adclicker_button_text = get_post_meta($post->ID, '_presslearn_adclicker_button_text', true);
2422 if (empty($adclicker_button_text)) {
2423 $adclicker_button_text = '광고보고 콘�
2424 �츠 계속 읽기';
2425 }
2426
2427 $adclicker_ad_link = get_post_meta($post->ID, '_presslearn_adclicker_ad_link', true);
2428
2429 $adclicker_frequency = get_option('presslearn_adclicker_frequency', 'once');
2430 $adclicker_overlay_color = get_option('presslearn_adclicker_overlay_color', '#000000');
2431 $adclicker_overlay_range = get_option('presslearn_adclicker_overlay_range', 100);
2432 $adclicker_display_time = get_option('presslearn_adclicker_display_time', 'null');
2433 $adclicker_button_color = get_option('presslearn_adclicker_button_color', '#2196F3');
2434 $adclicker_button_text_color = get_option('presslearn_adclicker_button_text_color', '#ffffff');
2435
2436 wp_register_style('presslearn-adclicker-css', false);
2437 wp_enqueue_style('presslearn-adclicker-css');
2438
2439 $adclicker_css = "
2440 .pl-adclicker-overlay {
2441 display: none;
2442 position: fixed;
2443 bottom: 0;
2444 left: 0;
2445 width: 100%;
2446 height: " . esc_attr($adclicker_overlay_range) . "vh;
2447 background: linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 0%, " . esc_attr($adclicker_overlay_color) . " 100%);
2448 z-index: 999999;
2449 }
2450
2451 .pl-adclicker-close-button {
2452 display: none;
2453 position: fixed;
2454 bottom: 60px;
2455 left: 50%;
2456 transform: translateX(-50%);
2457 padding: 15px 30px;
2458 background-color: " . esc_attr($adclicker_button_color) . ";
2459 color: " . esc_attr($adclicker_button_text_color) . ";
2460 border: none;
2461 border-radius: 8px;
2462 font-size: 20px;
2463 font-weight: bold;
2464 cursor: pointer;
2465 z-index: 1000001;
2466 text-decoration: none;
2467 text-align: center;
2468 }
2469
2470 .pl-adclicker-close-button:hover,
2471 .pl-adclicker-close-button:focus,
2472 .pl-adclicker-close-button:active {
2473 background-color: " . esc_attr($adclicker_button_color) . ";
2474 color: " . esc_attr($adclicker_button_text_color) . ";
2475 text-decoration: none;
2476 outline: none;
2477 }
2478
2479 .pl-back-message {
2480 display: none;
2481 position: fixed;
2482 bottom: 40px;
2483 left: 50%;
2484 transform: translateX(-50%);
2485 font-size: 12px;
2486 color: " . esc_attr($adclicker_button_text_color) . ";
2487 opacity: 0.8;
2488 z-index: 1000001;
2489 }
2490
2491 @media screen and (max-width: 768px) {
2492 .pl-adclicker-close-button {
2493 width: 80%;
2494 }
2495 .pl-back-message {
2496 bottom: 30px;
2497 }
2498 }
2499
2500 .pl-countdown-label {
2501 display: none;
2502 position: absolute;
2503 top: -10px;
2504 right: -10px;
2505 width: 30px;
2506 height: 30px;
2507 border-radius: 50%;
2508 background-color: #ff3b30;
2509 color: white;
2510 font-size: 14px;
2511 font-weight: bold;
2512 text-align: center;
2513 line-height: 30px;
2514 z-index: 1000002;
2515 }
2516
2517 body.pl-adclicker-open {
2518 overflow: hidden;
2519 }
2520
2521 .presslearn-ai-icon {
2522 display: inline-block;
2523 width: 16px;
2524 height: 16px;
2525 background-image: url('" . esc_url(PRESSLEARN_PLUGIN_URL) . "assets/images/icons-meta.png');
2526 background-repeat: no-repeat;
2527 background-size: contain;
2528 vertical-align: middle;
2529 margin-left: 8px;
2530 position: relative;
2531 top: -1px;
2532 }
2533
2534 #presslearn_ai_writer .postbox-header .hndle {
2535 display: flex !important;
2536 justify-content: flex-start !important;
2537 align-items: center !important;
2538 }
2539
2540 .presslearn-ai-title-container {
2541 display: flex;
2542 align-items: center;
2543 }
2544 ";
2545
2546 wp_add_inline_style('presslearn-adclicker-css', $adclicker_css);
2547
2548 wp_register_script('presslearn-adclicker-js', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
2549 wp_enqueue_script('presslearn-adclicker-js');
2550
2551 $adclicker_js = "
2552 (function() {
2553 function getAdClickerStorage(name, defaultValue) {
2554 try {
2555 const item = localStorage.getItem('adclicker_' + name);
2556 return item !== null ? item : defaultValue;
2557 } catch (e) {
2558 return defaultValue;
2559 }
2560 }
2561
2562 function setAdClickerStorage(name, value) {
2563 try {
2564 localStorage.setItem('adclicker_' + name, value);
2565 return true;
2566 } catch (e) {
2567 return false;
2568 }
2569 }
2570
2571 function showAdClicker() {
2572 const overlay = document.getElementById('pl-adclicker-overlay');
2573 const closeButton = document.getElementById('pl-adclicker-close-button');
2574 const countdownLabel = document.getElementById('pl-countdown-label');
2575 const backMessage = document.getElementById('pl-back-message');
2576
2577 overlay.style.display = 'block';
2578 closeButton.style.display = 'block';
2579 backMessage.style.display = 'block';
2580 document.body.classList.add('pl-adclicker-open');
2581
2582 const displayTime = '" . esc_js($adclicker_display_time) . "';
2583 if (displayTime !== 'null') {
2584 let timeLeft = parseInt(displayTime);
2585 countdownLabel.textContent = timeLeft;
2586 countdownLabel.style.display = 'block';
2587
2588 const countdownInterval = setInterval(function() {
2589 timeLeft--;
2590 countdownLabel.textContent = timeLeft;
2591
2592 if (timeLeft <= 0) {
2593 clearInterval(countdownInterval);
2594 countdownLabel.textContent = '✕';
2595 }
2596 }, 1000);
2597 }
2598 }
2599
2600 function hideAdClicker() {
2601 const overlay = document.getElementById('pl-adclicker-overlay');
2602 const closeButton = document.getElementById('pl-adclicker-close-button');
2603 const countdownLabel = document.getElementById('pl-countdown-label');
2604 const backMessage = document.getElementById('pl-back-message');
2605
2606 overlay.style.display = 'none';
2607 closeButton.style.display = 'none';
2608 countdownLabel.style.display = 'none';
2609 backMessage.style.display = 'none';
2610 document.body.classList.remove('pl-adclicker-open');
2611
2612 const frequency = '" . esc_js($adclicker_frequency) . "';
2613 if (frequency === 'once') {
2614 setAdClickerStorage('shown', 'true');
2615 } else if (frequency === '5min') {
2616 const now = new Date().getTime();
2617 setAdClickerStorage('last_shown', now.toString());
2618 }
2619 }
2620
2621 document.addEventListener('DOMContentLoaded', function() {
2622 const closeButton = document.getElementById('pl-adclicker-close-button');
2623 if (closeButton) {
2624 closeButton.addEventListener('click', function(e) {
2625 const adLink = this.getAttribute('data-ad-link');
2626
2627 if (e.target.tagName.toLowerCase() !== 'a') {
2628 e.preventDefault();
2629 hideAdClicker();
2630 }
2631 });
2632 }
2633
2634 const frequency = '" . esc_js($adclicker_frequency) . "';
2635 let shouldShow = false;
2636
2637 if (frequency === 'once') {
2638 shouldShow = getAdClickerStorage('shown', '') !== 'true';
2639 } else if (frequency === '5min') {
2640 const lastShown = parseInt(getAdClickerStorage('last_shown', '0'));
2641 const now = new Date().getTime();
2642 const fiveMinutes = 5 * 60 * 1000;
2643 shouldShow = (now - lastShown) > fiveMinutes;
2644 } else if (frequency === 'loop') {
2645 shouldShow = true;
2646 }
2647
2648 if (shouldShow) {
2649 setTimeout(function() {
2650 showAdClicker();
2651 }, 1000);
2652 }
2653 });
2654 })();
2655 ";
2656
2657 wp_add_inline_script('presslearn-adclicker-js', $adclicker_js);
2658
2659 add_action('wp_footer', function() use ($adclicker_ad_link, $adclicker_button_text) {
2660 ?>
2661 <div class="pl-adclicker-overlay" id="pl-adclicker-overlay"></div>
2662 <div class="pl-adclicker-close-button" id="pl-adclicker-close-button" data-ad-link="<?php echo esc_attr($adclicker_ad_link); ?>">
2663 <?php if ($adclicker_ad_link): ?>
2664 <a href="<?php echo esc_url($adclicker_ad_link); ?>" target="_blank" style="color: inherit; text-decoration: inherit; display: block;"><?php echo esc_html($adclicker_button_text); ?></a>
2665 <?php else: ?>
2666 <?php echo esc_html($adclicker_button_text); ?>
2667 <?php endif; ?>
2668 <span class="pl-countdown-label" id="pl-countdown-label"></span>
2669 </div>
2670 <div class="pl-back-message" id="pl-back-message"><?php echo esc_html('원치않으시면 뒤로가기를 해주세요'); ?></div>
2671 <?php
2672 });
2673 }
2674
2675 add_action('wp_body_open', 'presslearn_add_adclicker_script', 1);
2676
2677
2678 function presslearn_add_adclicker_metabox() {
2679 $adclicker_enabled = get_option('presslearn_ad_clicker_enabled', 'no');
2680 if ($adclicker_enabled !== 'yes') {
2681 return;
2682 }
2683
2684 add_meta_box(
2685 'presslearn_adclicker_settings',
2686 '<span class="presslearn-ai-title-container"><span class="presslearn-ai-icon"></span>애드클리커 설정</span>',
2687 'presslearn_render_adclicker_metabox',
2688 'post',
2689 'side',
2690 'default'
2691 );
2692 }
2693 add_action('add_meta_boxes', 'presslearn_add_adclicker_metabox');
2694
2695 function presslearn_render_adclicker_metabox($post) {
2696 wp_nonce_field('presslearn_adclicker_metabox_nonce', 'presslearn_adclicker_metabox_nonce');
2697
2698 $adclicker_enabled = get_post_meta($post->ID, '_presslearn_adclicker_enabled', true);
2699 $adclicker_button_text = get_post_meta($post->ID, '_presslearn_adclicker_button_text', true);
2700 $adclicker_ad_link = get_post_meta($post->ID, '_presslearn_adclicker_ad_link', true);
2701
2702 if ($adclicker_enabled === '') {
2703 $adclicker_enabled = 'yes';
2704 }
2705
2706 if (empty($adclicker_button_text)) {
2707 $adclicker_button_text = '광고보고 콘�
2708 �츠 계속 읽기';
2709 }
2710
2711 ?>
2712 <p>
2713 <label for="presslearn_adclicker_enabled"> 게시글에서 애드클리커 동작 여부:</label><br>
2714 <select name="presslearn_adclicker_enabled" id="presslearn_adclicker_enabled" class="widefat" style="box-sizing: border-box;">
2715 <option value="yes" <?php selected($adclicker_enabled, 'yes'); ?>></option>
2716 <option value="no" <?php selected($adclicker_enabled, 'no'); ?>>아니오</option>
2717 </select>
2718 </p>
2719
2720 <p>
2721 <label for="presslearn_adclicker_button_text">애드클리커 버튼 �
2722 �스트:</label><br>
2723 <input type="text" name="presslearn_adclicker_button_text" id="presslearn_adclicker_button_text"
2724 class="widefat" value="<?php echo esc_attr($adclicker_button_text); ?>">
2725 </p>
2726
2727 <p>
2728 <label for="presslearn_adclicker_ad_link">광고 링크 URL:</label><br>
2729 <input type="url" name="presslearn_adclicker_ad_link" id="presslearn_adclicker_ad_link"
2730 class="widefat" value="<?php echo esc_url($adclicker_ad_link); ?>" placeholder="https://...">
2731 <small>버튼 클릭 이동할 광고 링크</small>
2732 </p>
2733 <?php
2734 }
2735
2736 function presslearn_save_adclicker_metabox_data($post_id) {
2737 if (!isset($_POST['presslearn_adclicker_metabox_nonce'])) {
2738 return;
2739 }
2740
2741 if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['presslearn_adclicker_metabox_nonce'])), 'presslearn_adclicker_metabox_nonce')) {
2742 return;
2743 }
2744
2745 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
2746 return;
2747 }
2748
2749 if (isset($_POST['post_type']) && sanitize_text_field(wp_unslash($_POST['post_type'])) === 'post') {
2750 if (!current_user_can('edit_post', $post_id)) {
2751 return;
2752 }
2753 }
2754
2755 if (isset($_POST['presslearn_adclicker_enabled'])) {
2756 $adclicker_enabled = sanitize_text_field(wp_unslash($_POST['presslearn_adclicker_enabled']));
2757 if ($adclicker_enabled === 'yes' || $adclicker_enabled === 'no') {
2758 update_post_meta($post_id, '_presslearn_adclicker_enabled', $adclicker_enabled);
2759 }
2760 }
2761
2762 if (isset($_POST['presslearn_adclicker_button_text'])) {
2763 $adclicker_button_text = sanitize_text_field(wp_unslash($_POST['presslearn_adclicker_button_text']));
2764 update_post_meta($post_id, '_presslearn_adclicker_button_text', $adclicker_button_text);
2765 }
2766
2767 if (isset($_POST['presslearn_adclicker_ad_link'])) {
2768 $adclicker_ad_link = esc_url_raw(wp_unslash($_POST['presslearn_adclicker_ad_link']));
2769 update_post_meta($post_id, '_presslearn_adclicker_ad_link', $adclicker_ad_link);
2770 }
2771 }
2772 add_action('save_post', 'presslearn_save_adclicker_metabox_data');
2773
2774 add_action('wp_ajax_presslearn_upload_banner', 'presslearn_handle_banner_upload');
2775 add_action('wp_ajax_nopriv_presslearn_upload_banner', 'presslearn_handle_banner_upload');
2776
2777 function presslearn_handle_banner_upload() {
2778 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
2779 if ($dynamic_banner_enabled !== 'yes') {
2780 wp_send_json_error(array('message' => '다이나믹 배너 기능이 활성화되어 있지 않습니다.'));
2781 wp_die();
2782 }
2783
2784 check_ajax_referer('presslearn_upload_banner_nonce', 'nonce');
2785
2786 if (!current_user_can('manage_options')) {
2787 wp_send_json_error(array('message' => '파일 �
2788 로드 권한이 없습니다.'));
2789 wp_die();
2790 }
2791
2792 if (!function_exists('wp_handle_upload')) {
2793 require_once(ABSPATH . 'wp-admin/includes/file.php');
2794 }
2795
2796 if (!isset($_FILES['banner_image'])) {
2797 wp_send_json_error(array('message' => '�
2798 로드할 파일이 없습니다.'));
2799 wp_die();
2800 }
2801
2802 $file = $_FILES['banner_image'];
2803
2804 $allowed_types = array('image/jpeg', 'image/png', 'image/gif', 'image/webp');
2805 $file_type = sanitize_mime_type($file['type']);
2806 if (!in_array($file_type, $allowed_types)) {
2807 wp_send_json_error(array('message' => '허용되지 않는 파일 형식�
2808 니다. JPG, PNG, GIF, WEBP 이미지만 �
2809 로드 가능합니다.'));
2810 wp_die();
2811 }
2812
2813 $upload_dir = wp_upload_dir();
2814
2815 $banner_type = isset($_POST['banner_type']) ? sanitize_text_field(wp_unslash($_POST['banner_type'])) : 'normal';
2816
2817 $upload_path = $upload_dir['path'];
2818 if ($banner_type === 'cover') {
2819 $upload_path = trailingslashit($upload_dir['path']) . 'cover_banners';
2820 if (!file_exists($upload_path)) {
2821 wp_mkdir_p($upload_path);
2822 }
2823 }
2824
2825 $file_name = wp_unique_filename($upload_path, sanitize_file_name($file['name']));
2826
2827 $upload_overrides = array(
2828 'test_form' => false,
2829 'test_size' => true,
2830 'test_upload' => true,
2831 'mimes' => array(
2832 'jpg|jpeg|jpe' => 'image/jpeg',
2833 'png' => 'image/png',
2834 'gif' => 'image/gif',
2835 'webp' => 'image/webp'
2836 )
2837 );
2838
2839 $movefile = wp_handle_upload($file, $upload_overrides);
2840
2841 if ($movefile && !isset($movefile['error'])) {
2842 wp_send_json_success(array(
2843 'url' => esc_url_raw($movefile['url']),
2844 'message' => '이미지가 성공적으로 �
2845 로드되었습니다.'
2846 ));
2847 } else {
2848 wp_send_json_error(array(
2849 'message' => isset($movefile['error']) ? esc_html($movefile['error']) : '파일 �
2850 로드 오류가 발생했습니다.'
2851 ));
2852 }
2853
2854 wp_die();
2855 }
2856
2857 add_action('init', 'presslearn_setup_cron_for_ip_unblock');
2858
2859 add_action('wp_ajax_presslearn_add_campaign', 'presslearn_add_campaign');
2860 add_action('wp_ajax_presslearn_get_campaigns', 'presslearn_get_campaigns');
2861 add_action('wp_ajax_presslearn_delete_campaign', 'presslearn_delete_campaign');
2862 add_action('wp_ajax_presslearn_get_campaign', 'presslearn_get_campaign');
2863 add_action('wp_ajax_presslearn_update_campaign', 'presslearn_update_campaign');
2864
2865 function presslearn_add_campaign() {
2866 if (!current_user_can('manage_options')) {
2867 wp_send_json_error(array('message' => '권한이 없습니다.'));
2868 wp_die();
2869 }
2870
2871 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
2872 if ($dynamic_banner_enabled !== 'yes') {
2873 wp_send_json_error(array('message' => '다이나믹 배너 기능이 활성화되어 있지 않습니다.'));
2874 wp_die();
2875 }
2876
2877 check_ajax_referer('presslearn_campaign_nonce', 'nonce');
2878
2879 $campaign_data = isset($_POST['campaign_data']) ? wp_unslash($_POST['campaign_data']) : array();
2880
2881 if (empty($campaign_data) || !is_array($campaign_data)) {
2882 wp_send_json_error(array('message' => '유효하지 않은 캠페인 데이터�
2883 니다.'));
2884 wp_die();
2885 }
2886
2887 if (empty($campaign_data['name'])) {
2888 wp_send_json_error(array('message' => '캠페인 이름은 필수 항목�
2889 니다.'));
2890 wp_die();
2891 }
2892
2893 if ($campaign_data['type'] === 'custom') {
2894 if (empty($campaign_data['banner_url']) || empty($campaign_data['link']) ||
2895 empty($campaign_data['width']) || empty($campaign_data['height'])) {
2896 wp_send_json_error(array('message' => '배너 URL, 링크 URL, 가로/세로 크기는 필수 항목�
2897 니다.'));
2898 wp_die();
2899 }
2900 } else if ($campaign_data['type'] === 'iframe') {
2901 if (empty($campaign_data['iframe_code']) || empty($campaign_data['width']) || empty($campaign_data['height'])) {
2902 wp_send_json_error(array('message' => 'iframe 코드, 가로/세로 크기는 필수 항목�
2903 니다.'));
2904 wp_die();
2905 }
2906 } else {
2907 wp_send_json_error(array('message' => '유효하지 않은 배너 유형�
2908 니다.'));
2909 wp_die();
2910 }
2911
2912 global $wpdb;
2913 $table_name = $wpdb->prefix . 'presslearn_banners';
2914
2915 $data = array(
2916 'name' => sanitize_text_field($campaign_data['name']),
2917 'type' => sanitize_text_field($campaign_data['type']),
2918 'width' => intval($campaign_data['width']),
2919 'height' => intval($campaign_data['height']),
2920 'status' => 1,
2921 'created_at' => current_time('mysql')
2922 );
2923
2924 if ($campaign_data['type'] === 'custom') {
2925 $data['banner_url'] = esc_url_raw($campaign_data['banner_url']);
2926 $data['link'] = esc_url_raw($campaign_data['link']);
2927 if (!empty($campaign_data['cover_banner_url'])) {
2928 $data['cover_banner_url'] = esc_url_raw($campaign_data['cover_banner_url']);
2929 }
2930 } else if ($campaign_data['type'] === 'iframe') {
2931 $data['iframe_code'] = stripslashes($campaign_data['iframe_code']);
2932 if (!empty($campaign_data['cover_banner_url'])) {
2933 $data['cover_banner_url'] = esc_url_raw($campaign_data['cover_banner_url']);
2934 }
2935 }
2936
2937 $result = $wpdb->insert($table_name, $data);
2938
2939 if ($result === false) {
2940 wp_send_json_error(array('message' => '캠페인 추가 중 오류가 발생했습니다: ' . $wpdb->last_error));
2941 wp_die();
2942 }
2943
2944 $campaign_id = $wpdb->insert_id;
2945
2946 wp_send_json_success(array(
2947 'id' => $campaign_id,
2948 'message' => '캠페인이 성공적으로 추가되었습니다.',
2949 'shortcode' => $campaign_data['type'] === 'custom' ?
2950 '[presslearn_banner id="' . $campaign_id . '"]' :
2951 '[presslearn_iframe id="' . $campaign_id . '"]'
2952 ));
2953
2954 wp_die();
2955 }
2956
2957 function presslearn_get_campaigns() {
2958 if (!current_user_can('manage_options')) {
2959 wp_send_json_error(array('message' => '권한이 없습니다.'));
2960 wp_die();
2961 }
2962
2963 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
2964 if ($dynamic_banner_enabled !== 'yes') {
2965 wp_send_json_error(array('message' => '다이나믹 배너 기능이 활성화되어 있지 않습니다.'));
2966 wp_die();
2967 }
2968
2969 check_ajax_referer('presslearn_campaign_nonce', 'nonce');
2970
2971 global $wpdb;
2972 $table_name = $wpdb->prefix . 'presslearn_banners';
2973
2974 $campaigns = $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC", ARRAY_A);
2975
2976 if ($campaigns === null) {
2977 wp_send_json_error(array('message' => '캠페인 목록을 가져오는 중 오류가 발생했습니다: ' . $wpdb->last_error));
2978 wp_die();
2979 }
2980
2981 foreach ($campaigns as &$campaign) {
2982 $campaign['shortcode'] = $campaign['type'] === 'custom' ?
2983 '[presslearn_banner id="' . $campaign['id'] . '"]' :
2984 '[presslearn_iframe id="' . $campaign['id'] . '"]';
2985 }
2986
2987 wp_send_json_success(array('campaigns' => $campaigns));
2988 wp_die();
2989 }
2990
2991 function presslearn_delete_campaign() {
2992 if (!current_user_can('manage_options')) {
2993 wp_send_json_error(array('message' => '권한이 없습니다.'));
2994 wp_die();
2995 }
2996
2997 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
2998 if ($dynamic_banner_enabled !== 'yes') {
2999 wp_send_json_error(array('message' => '다이나믹 배너 기능이 활성화되어 있지 않습니다.'));
3000 wp_die();
3001 }
3002
3003 check_ajax_referer('presslearn_campaign_nonce', 'nonce');
3004
3005 $campaign_id = isset($_POST['id']) ? intval($_POST['id']) : 0;
3006
3007 if ($campaign_id <= 0) {
3008 wp_send_json_error(array('message' => '유효하지 않은 캠페인 ID�
3009 니다.'));
3010 wp_die();
3011 }
3012
3013 global $wpdb;
3014 $table_name = $wpdb->prefix . 'presslearn_banners';
3015
3016 $result = $wpdb->delete($table_name, array('id' => $campaign_id), array('%d'));
3017
3018 if ($result === false) {
3019 wp_send_json_error(array('message' => '캠페인 삭제 오류가 발생했습니다: ' . $wpdb->last_error));
3020 wp_die();
3021 }
3022
3023 wp_send_json_success(array('message' => '캠페인이 성공적으로 삭제되었습니다.'));
3024 wp_die();
3025 }
3026
3027 function presslearn_get_campaign() {
3028 if (!current_user_can('manage_options')) {
3029 wp_send_json_error(array('message' => '권한이 없습니다.'));
3030 wp_die();
3031 }
3032
3033 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
3034 if ($dynamic_banner_enabled !== 'yes') {
3035 wp_send_json_error(array('message' => '다이나믹 배너 기능이 활성화되어 있지 않습니다.'));
3036 wp_die();
3037 }
3038
3039 check_ajax_referer('presslearn_campaign_nonce', 'nonce');
3040
3041 $campaign_id = isset($_POST['id']) ? intval($_POST['id']) : 0;
3042
3043 if ($campaign_id <= 0) {
3044 wp_send_json_error(array('message' => '유효하지 않은 캠페인 ID�
3045 니다.'));
3046 wp_die();
3047 }
3048
3049 global $wpdb;
3050 $table_name = $wpdb->prefix . 'presslearn_banners';
3051
3052 $campaign = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE id = %d", $campaign_id), ARRAY_A);
3053
3054 if ($campaign === null) {
3055 wp_send_json_error(array('message' => '캠페인 정보를 가져오는 중 오류가 발생했습니다: ' . $wpdb->last_error));
3056 wp_die();
3057 }
3058
3059 wp_send_json_success(array('campaign' => $campaign));
3060 wp_die();
3061 }
3062
3063 function presslearn_update_campaign() {
3064 if (!current_user_can('manage_options')) {
3065 wp_send_json_error(array('message' => '권한이 없습니다.'));
3066 wp_die();
3067 }
3068
3069 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
3070 if ($dynamic_banner_enabled !== 'yes') {
3071 wp_send_json_error(array('message' => '다이나믹 배너 기능이 활성화되어 있지 않습니다.'));
3072 wp_die();
3073 }
3074
3075 check_ajax_referer('presslearn_campaign_nonce', 'nonce');
3076
3077 $campaign_data = isset($_POST['campaign_data']) ? wp_unslash($_POST['campaign_data']) : array();
3078
3079 if (empty($campaign_data) || !is_array($campaign_data) || empty($campaign_data['id'])) {
3080 wp_send_json_error(array('message' => '유효하지 않은 캠페인 데이터�
3081 니다.'));
3082 wp_die();
3083 }
3084
3085 $campaign_id = intval($campaign_data['id']);
3086
3087 if (empty($campaign_data['name'])) {
3088 wp_send_json_error(array('message' => '캠페인 이름은 필수 항목�
3089 니다.'));
3090 wp_die();
3091 }
3092
3093 if ($campaign_data['type'] === 'custom') {
3094 if (empty($campaign_data['banner_url']) || empty($campaign_data['link']) ||
3095 empty($campaign_data['width']) || empty($campaign_data['height'])) {
3096 wp_send_json_error(array('message' => '배너 URL, 링크 URL, 가로/세로 크기는 필수 항목�
3097 니다.'));
3098 wp_die();
3099 }
3100 } else if ($campaign_data['type'] === 'iframe') {
3101 if (empty($campaign_data['iframe_code']) || empty($campaign_data['width']) || empty($campaign_data['height'])) {
3102 wp_send_json_error(array('message' => 'iframe 코드, 가로/세로 크기는 필수 항목�
3103 니다.'));
3104 wp_die();
3105 }
3106 } else {
3107 wp_send_json_error(array('message' => '유효하지 않은 배너 유형�
3108 니다.'));
3109 wp_die();
3110 }
3111
3112 global $wpdb;
3113 $table_name = $wpdb->prefix . 'presslearn_banners';
3114
3115 $data = array(
3116 'name' => sanitize_text_field($campaign_data['name']),
3117 'type' => sanitize_text_field($campaign_data['type']),
3118 'width' => intval($campaign_data['width']),
3119 'height' => intval($campaign_data['height']),
3120 'status' => 1,
3121 'updated_at' => current_time('mysql')
3122 );
3123
3124 if ($campaign_data['type'] === 'custom') {
3125 $data['banner_url'] = esc_url_raw($campaign_data['banner_url']);
3126 $data['link'] = esc_url_raw($campaign_data['link']);
3127 $data['iframe_code'] = '';
3128
3129 if (!empty($campaign_data['cover_banner_url'])) {
3130 $data['cover_banner_url'] = esc_url_raw($campaign_data['cover_banner_url']);
3131 } else {
3132 $data['cover_banner_url'] = '';
3133 }
3134 } else if ($campaign_data['type'] === 'iframe') {
3135 $data['iframe_code'] = stripslashes($campaign_data['iframe_code']);
3136 $data['banner_url'] = '';
3137 $data['link'] = '';
3138
3139 if (!empty($campaign_data['cover_banner_url'])) {
3140 $data['cover_banner_url'] = esc_url_raw($campaign_data['cover_banner_url']);
3141 } else {
3142 $data['cover_banner_url'] = '';
3143 }
3144 }
3145
3146 $result = $wpdb->update(
3147 $table_name,
3148 $data,
3149 array('id' => $campaign_id),
3150 array('%s', '%s', '%d', '%d', '%d', '%s', '%s', '%s', '%s'),
3151 array('%d')
3152 );
3153
3154 if ($result === false) {
3155 wp_send_json_error(array('message' => '캠페인 수정 오류가 발생했습니다: ' . $wpdb->last_error));
3156 wp_die();
3157 }
3158
3159 wp_send_json_success(array(
3160 'message' => '캠페인이 성공적으로 수정되었습니다.',
3161 'shortcode' => $campaign_data['type'] === 'custom' ?
3162 '[presslearn_banner id="' . $campaign_id . '"]' :
3163 '[presslearn_iframe id="' . $campaign_id . '"]'
3164 ));
3165
3166 wp_die();
3167 }
3168
3169 function presslearn_register_banner_shortcodes() {
3170 add_shortcode('presslearn_banner', 'presslearn_banner_shortcode');
3171 add_shortcode('presslearn_iframe', 'presslearn_iframe_shortcode');
3172
3173 wp_register_style('presslearn-banner-styles', false);
3174 wp_enqueue_style('presslearn-banner-styles');
3175
3176 $custom_css = "
3177 .pl-dynamic-area {
3178 display: inline-block;
3179 position: relative;
3180 overflow: hidden;
3181 }
3182 .pl-dynamic-cover {
3183 position: absolute;
3184 top: 0;
3185 left: -40px;
3186 width: 100%;
3187 height: 100%;
3188 display: none;
3189 z-index: 1;
3190 touch-action: pan-x;
3191 user-select: none;
3192 cursor: grab;
3193 }
3194 .pl-dynamic-cover.enable {
3195 display: block !important;
3196 animation: sliding 1.5s ease-in-out infinite;
3197 }
3198 .pl-dynamic-cover.dragging {
3199 animation: none !important;
3200 cursor: grabbing;
3201 }
3202 .pl-dynamic-cover::after {
3203 content: attr(data-message);
3204 position: absolute;
3205 right: 15px;
3206 top: 50%;
3207 transform: translateY(-50%);
3208 background: rgba(0,0,0,0.7);
3209 color: white;
3210 padding: 8px 12px;
3211 border-radius: 20px;
3212 display: flex;
3213 align-items: center;
3214 justify-content: center;
3215 font-size: 14px;
3216 transition: opacity 0.3s;
3217 }
3218 .pl-dynamic-cover img {
3219 max-width: 100%;
3220 height: auto;
3221 }
3222 @keyframes sliding {
3223 0% {
3224 transform: translate3d(-7%, 0, 0);
3225 }
3226
3227 20% {
3228 transform: translate3d(-10%, 0, 0);
3229 }
3230
3231 40% {
3232 transform: translate3d(-5%, 0, 0);
3233 }
3234
3235 60% {
3236 transform: translate3d(-10%, 0, 0);
3237 }
3238
3239 80% {
3240 transform: translate3d(-5%, 0, 0);
3241 }
3242
3243 100% {
3244 transform: translate3d(-7%, 0, 0);
3245 }
3246 }
3247 ";
3248
3249 wp_add_inline_style('presslearn-banner-styles', $custom_css);
3250
3251 wp_register_script('presslearn-banner-script', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
3252 wp_enqueue_script('presslearn-banner-script');
3253
3254 $script = "
3255 document.addEventListener('DOMContentLoaded', function() {
3256 let startX = 0;
3257 let isDragging = false;
3258 let currentCover = null;
3259 let parentWidth = 0;
3260
3261 document.addEventListener('touchstart', function(e) {
3262 const target = e.target.closest('.pl-dynamic-cover');
3263 if (target && target.classList.contains('enable')) {
3264 e.preventDefault();
3265 startX = e.touches[0].clientX;
3266 isDragging = true;
3267 currentCover = target;
3268 parentWidth = target.parentElement.offsetWidth;
3269
3270 currentCover.classList.add('dragging');
3271 }
3272 });
3273
3274 document.addEventListener('mousedown', function(e) {
3275 const target = e.target.closest('.pl-dynamic-cover');
3276 if (target && target.classList.contains('enable')) {
3277 e.preventDefault();
3278 startX = e.clientX;
3279 isDragging = true;
3280 currentCover = target;
3281 parentWidth = target.parentElement.offsetWidth;
3282
3283 currentCover.classList.add('dragging');
3284 }
3285 });
3286
3287 document.addEventListener('touchmove', function(e) {
3288 if (!isDragging || !currentCover) return;
3289
3290 const currentX = e.touches[0].clientX;
3291 const diff = currentX - startX;
3292
3293 if (diff < 0) {
3294 currentCover.style.transform = 'translate3d(' + (diff/3) + 'px, 0, 0)';
3295
3296 const threshold = parentWidth * 0.5;
3297 if (Math.abs(diff) > threshold) {
3298 currentCover.classList.remove('enable', 'dragging');
3299 currentCover.style.transform = '';
3300 isDragging = false;
3301 currentCover = null;
3302 }
3303 }
3304 });
3305
3306 document.addEventListener('mousemove', function(e) {
3307 if (!isDragging || !currentCover) return;
3308
3309 const currentX = e.clientX;
3310 const diff = currentX - startX;
3311
3312 if (diff < 0) {
3313 currentCover.style.transform = 'translate3d(' + (diff/3) + 'px, 0, 0)';
3314
3315 const threshold = parentWidth * 0.5;
3316 if (Math.abs(diff) > threshold) {
3317 currentCover.classList.remove('enable', 'dragging');
3318 currentCover.style.transform = '';
3319 isDragging = false;
3320 currentCover = null;
3321 }
3322 }
3323 });
3324
3325 document.addEventListener('touchend', function() {
3326 if (currentCover) {
3327 currentCover.classList.remove('dragging');
3328 currentCover.style.transform = '';
3329 isDragging = false;
3330 currentCover = null;
3331 }
3332 });
3333
3334 document.addEventListener('mouseup', function() {
3335 if (currentCover) {
3336 currentCover.classList.remove('dragging');
3337 currentCover.style.transform = '';
3338 isDragging = false;
3339 currentCover = null;
3340 }
3341 });
3342 });
3343 ";
3344
3345 wp_add_inline_script('presslearn-banner-script', $script);
3346 }
3347 add_action('init', 'presslearn_register_banner_shortcodes');
3348
3349 function presslearn_banner_shortcode($atts) {
3350 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
3351 if ($dynamic_banner_enabled !== 'yes') {
3352 return '';
3353 }
3354
3355 $atts = shortcode_atts(array(
3356 'id' => 0,
3357 ), $atts, 'presslearn_banner');
3358
3359 $banner_id = intval($atts['id']);
3360
3361 if ($banner_id <= 0) {
3362 return '';
3363 }
3364
3365 global $wpdb;
3366 $table_name = $wpdb->prefix . 'presslearn_banners';
3367
3368 $banner = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE id = %d AND type = 'custom' AND status = 1", $banner_id), ARRAY_A);
3369
3370 if ($banner === null || empty($banner)) {
3371 return '';
3372 }
3373
3374 $banner_url = esc_url($banner['banner_url']);
3375 $cover_banner_url = !empty($banner['cover_banner_url']) ? esc_url($banner['cover_banner_url']) : '';
3376
3377 $link_url = esc_url($banner['link']);
3378 $width = intval($banner['width']);
3379 $height = intval($banner['height']);
3380
3381 if (empty($cover_banner_url)) {
3382 return '
3383 <div class="pl-dynamic-area">
3384 <div class="pl-dynamic-area-item">
3385 <a href="' . esc_url($link_url) . '" target="_blank" rel="nofollow noopener">
3386 <img src="' . esc_url($banner_url) . '" alt="' . esc_attr($banner['name']) . '" width="' . esc_attr($width) . '" height="' . esc_attr($height) . '" style="max-width:100%;height:auto;display:block;" />
3387 </a>
3388 </div>
3389 </div>
3390 ';
3391 }
3392
3393 return '
3394 <div class="pl-dynamic-area">
3395 <div class="pl-dynamic-area-item">
3396 <a href="' . esc_url($link_url) . '" target="_blank" rel="nofollow noopener">
3397 <img src="' . esc_url($banner_url) . '" alt="' . esc_attr($banner['name']) . '" width="' . esc_attr($width) . '" height="' . esc_attr($height) . '" style="max-width:100%;height:auto;display:block;" />
3398 </a>
3399 </div>
3400 <div class="pl-dynamic-cover enable" data-message="밀어서 제거">
3401 <img src="' . esc_url($cover_banner_url) . '" alt="' . esc_attr($banner['name']) . '" width="' . esc_attr($width) . '" height="' . esc_attr($height) . '" style="max-width:100%;height:auto;display:block;" draggable="true" />
3402 </div>
3403 </div>
3404 ';
3405 }
3406
3407
3408 function presslearn_iframe_shortcode($atts) {
3409 $dynamic_banner_enabled = get_option('presslearn_dynamic_banner_enabled', 'no');
3410 if ($dynamic_banner_enabled !== 'yes') {
3411 return '';
3412 }
3413
3414 $atts = shortcode_atts(array(
3415 'id' => 0,
3416 ), $atts, 'presslearn_iframe');
3417
3418 $banner_id = intval($atts['id']);
3419
3420 if ($banner_id <= 0) {
3421 return '';
3422 }
3423
3424 global $wpdb;
3425 $table_name = $wpdb->prefix . 'presslearn_banners';
3426
3427 $banner = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE id = %d AND type = 'iframe' AND status = 1", $banner_id), ARRAY_A);
3428
3429 if ($banner === null || empty($banner)) {
3430 return '';
3431 }
3432
3433 $iframe_code = $banner['iframe_code'];
3434 $width = intval($banner['width']);
3435 $height = intval($banner['height']);
3436 $cover_banner_url = !empty($banner['cover_banner_url']) ? esc_url($banner['cover_banner_url']) : '';
3437
3438 $iframe_code = stripslashes($iframe_code);
3439
3440 $iframe_code = preg_replace('/width\s*=\s*(["\']?)([^"\'\s>]*)(["\']?)/', 'width="' . esc_attr($width) . 'px"', $iframe_code);
3441 $iframe_code = preg_replace('/height\s*=\s*(["\']?)([^"\'\s>]*)(["\']?)/', 'height="' . esc_attr($height) . 'px"', $iframe_code);
3442
3443 if (strpos($iframe_code, 'style=') !== false) {
3444 $iframe_code = preg_replace('/style\s*=\s*(["\'])(.*?)(["\'])/', 'style=${1}max-width:100%;${2}${3}', $iframe_code);
3445 } else {
3446 $iframe_code = str_replace('<iframe', '<iframe style="max-width:100%;"', $iframe_code);
3447 }
3448
3449 if (empty($cover_banner_url)) {
3450 $safe_iframe_code = presslearn_sanitize_iframe($iframe_code);
3451 return '<div class="pl-dynamic-area"><div class="presslearn-iframe-container" style="width:' . esc_attr($width) . 'px;max-width:100%;margin:0 auto;">' . $safe_iframe_code . '</div></div>';
3452 }
3453
3454 $safe_iframe_code = presslearn_sanitize_iframe($iframe_code);
3455
3456 return '
3457 <div class="pl-dynamic-area">
3458 <div class="pl-dynamic-area-item">
3459 <div class="presslearn-iframe-container" style="width:' . esc_attr($width) . 'px;max-width:100%;margin:0 auto;">' . $safe_iframe_code . '</div>
3460 </div>
3461 <div class="pl-dynamic-cover enable" data-message="밀어서 제거">
3462 <img src="' . esc_url($cover_banner_url) . '" alt="' . esc_attr($banner['name']) . '" width="' . esc_attr($width) . '" height="' . esc_attr($height) . '" style="max-width:100%;height:auto;display:block;" draggable="true" />
3463 </div>
3464 </div>
3465 ';
3466 }
3467
3468 function presslearn_sanitize_iframe($iframe_code) {
3469 if (empty($iframe_code)) {
3470 return '';
3471 }
3472
3473 if (!preg_match('/<iframe[^>]*>/i', $iframe_code)) {
3474 return '';
3475 }
3476
3477 $iframe_code = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $iframe_code);
3478 $iframe_code = preg_replace('/<style[^>]*>.*?<\/style>/is', '', $iframe_code);
3479 $iframe_code = preg_replace('/\s*on\w+\s*=\s*["\'][^"\']*["\']/i', '', $iframe_code);
3480 $iframe_code = preg_replace('/\s*javascript\s*:/i', '', $iframe_code);
3481
3482 if (preg_match('/<iframe[^>]*>.*?<\/iframe>/is', $iframe_code, $matches)) {
3483 $iframe_tag = $matches[0];
3484 } else if (preg_match('/<iframe[^>]*\/?>/i', $iframe_code, $matches)) {
3485 $iframe_tag = $matches[0];
3486 if (!preg_match('/\/\s*>$/', $iframe_tag)) {
3487 $iframe_tag .= '</iframe>';
3488 }
3489 } else {
3490 return '';
3491 }
3492
3493 $trusted_domains = array(
3494 'ads-partners.coupang.com',
3495 'partner.googleadservices.com',
3496 'googleads.g.doubleclick.net',
3497 'www.googletagmanager.com',
3498 'youtube.com',
3499 'www.youtube.com',
3500 'player.vimeo.com',
3501 'cdnjs.cloudflare.com',
3502 'fonts.googleapis.com'
3503 );
3504
3505 if (preg_match('/src\s*=\s*["\']([^"\']*)["\']/', $iframe_tag, $src_matches)) {
3506 $src_url = $src_matches[1];
3507 $parsed_url = parse_url($src_url);
3508
3509 if (!empty($parsed_url['host'])) {
3510 $is_trusted = false;
3511 foreach ($trusted_domains as $trusted_domain) {
3512 if ($parsed_url['host'] === $trusted_domain ||
3513 substr($parsed_url['host'], -strlen('.' . $trusted_domain)) === '.' . $trusted_domain) {
3514 $is_trusted = true;
3515 break;
3516 }
3517 }
3518
3519 if (!$is_trusted && !current_user_can('manage_options')) {
3520 return '';
3521 }
3522 }
3523 }
3524
3525 $allowed_attributes = array(
3526 'src', 'width', 'height', 'frameborder', 'scrolling',
3527 'allowfullscreen', 'loading', 'title', 'name', 'id',
3528 'class', 'style', 'referrerpolicy', 'browsingtopics'
3529 );
3530
3531 $iframe_tag = preg_replace_callback(
3532 '/(\w+)\s*=\s*["\']([^"\']*)["\']/',
3533 function($matches) use ($allowed_attributes) {
3534 if (in_array(strtolower($matches[1]), $allowed_attributes)) {
3535 return $matches[1] . '="' . esc_attr($matches[2]) . '"';
3536 }
3537 return '';
3538 },
3539 $iframe_tag
3540 );
3541
3542 return $iframe_tag;
3543 }
3544
3545 function presslearn_add_analytics_column($columns) {
3546 $columns['presslearn_analytics'] = '<span class="dashicons dashicons-chart-bar" style="font-size: 16px; vertical-align: text-top;"></span> 통계';
3547 return $columns;
3548 }
3549 add_filter('manage_posts_columns', 'presslearn_add_analytics_column');
3550 add_filter('manage_pages_columns', 'presslearn_add_analytics_column');
3551
3552 function presslearn_analytics_column_content($column, $post_id) {
3553 if ($column !== 'presslearn_analytics') {
3554 return;
3555 }
3556
3557 global $wpdb;
3558 $permalink = get_permalink($post_id);
3559 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
3560
3561 if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") != $table_pageviews) {
3562 ?>
3563 <div class="presslearn-analytics-stats">
3564 <span class="presslearn-views">0 </span>
3565 <span class="presslearn-visitors">0 방문</span>
3566 </div>
3567 <?php
3568 return;
3569 }
3570
3571 $cache_time = get_option('presslearn_analytics_cache_time', 300);
3572 $cache_date = current_time('Y-m-d');
3573 $cache_key_visitors = "presslearn_visitors_{$post_id}_{$cache_date}";
3574 $cache_key_today = "presslearn_today_{$post_id}_{$cache_date}";
3575 $cache_key_week = "presslearn_week_{$post_id}_{$cache_date}";
3576 $cache_key_month = "presslearn_month_{$post_id}_{$cache_date}";
3577
3578 $total_views = get_post_meta($post_id, '_presslearn_post_views', true);
3579 if (empty($total_views)) {
3580 $total_views = $wpdb->get_var($wpdb->prepare(
3581 "SELECT COUNT(*) FROM $table_pageviews WHERE url = %s",
3582 $permalink
3583 ));
3584 $total_views = intval($total_views);
3585
3586 update_post_meta($post_id, '_presslearn_post_views', $total_views);
3587 }
3588
3589 $total_visitors = wp_cache_get($cache_key_visitors, 'presslearn_analytics');
3590 if (false === $total_visitors) {
3591 $total_visitors = $wpdb->get_var($wpdb->prepare(
3592 "SELECT COUNT(DISTINCT visitor_id) FROM $table_pageviews WHERE url = %s",
3593 $permalink
3594 ));
3595 $total_visitors = intval($total_visitors);
3596 wp_cache_set($cache_key_visitors, $total_visitors, 'presslearn_analytics', $cache_time);
3597 }
3598
3599 $today_views = wp_cache_get($cache_key_today, 'presslearn_analytics');
3600 if (false === $today_views) {
3601 $today_views = $wpdb->get_var($wpdb->prepare(
3602 "SELECT COUNT(*) FROM $table_pageviews WHERE url = %s AND DATE(created_at) = CURDATE()",
3603 $permalink
3604 ));
3605 $today_views = intval($today_views);
3606 wp_cache_set($cache_key_today, $today_views, 'presslearn_analytics', $cache_time);
3607 }
3608
3609 $week_views = wp_cache_get($cache_key_week, 'presslearn_analytics');
3610 if (false === $week_views) {
3611 $week_views = $wpdb->get_var($wpdb->prepare(
3612 "SELECT COUNT(*) FROM $table_pageviews WHERE url = %s AND created_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)",
3613 $permalink
3614 ));
3615 $week_views = intval($week_views);
3616 wp_cache_set($cache_key_week, $week_views, 'presslearn_analytics', $cache_time);
3617 }
3618
3619 $month_views = wp_cache_get($cache_key_month, 'presslearn_analytics');
3620 if (false === $month_views) {
3621 $month_views = $wpdb->get_var($wpdb->prepare(
3622 "SELECT COUNT(*) FROM $table_pageviews WHERE url = %s AND created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)",
3623 $permalink
3624 ));
3625 $month_views = intval($month_views);
3626 wp_cache_set($cache_key_month, $month_views, 'presslearn_analytics', $cache_time);
3627 }
3628
3629 ?>
3630 <div class="presslearn-analytics-stats">
3631 <div class="presslearn-stats-row">
3632 <span class="presslearn-total">
3633 <span class="dashicons dashicons-chart-bar" style="font-size: 16px; color: #2196F3; opacity: 0.8;"></span>
3634 <?php echo esc_html(number_format($total_views)); ?>
3635 </span>
3636 </div>
3637
3638 <div class="presslearn-stats-periods">
3639 <div class="presslearn-period today" title="<?php echo esc_attr('오늘 조회수'); ?>">
3640 <span><?php echo esc_html('오늘'); ?></span> <?php echo esc_html(number_format($today_views)); ?>
3641 </div>
3642 <div class="presslearn-period week" title="<?php echo esc_attr('최근 7일 조회수'); ?>">
3643 <span><?php echo esc_html('7일'); ?></span> <?php echo esc_html(number_format($week_views)); ?>
3644 </div>
3645 <div class="presslearn-period month" title="<?php echo esc_attr('최근 30일 조회수'); ?>">
3646 <span><?php echo esc_html('30일'); ?></span> <?php echo esc_html(number_format($month_views)); ?>
3647 </div>
3648 </div>
3649 </div>
3650 <?php
3651 }
3652 add_action('manage_posts_custom_column', 'presslearn_analytics_column_content', 10, 2);
3653 add_action('manage_pages_custom_column', 'presslearn_analytics_column_content', 10, 2);
3654
3655 function presslearn_analytics_column_sortable($columns) {
3656 $columns['presslearn_analytics'] = 'presslearn_analytics';
3657 return $columns;
3658 }
3659 add_filter('manage_edit-post_sortable_columns', 'presslearn_analytics_column_sortable');
3660 add_filter('manage_edit-page_sortable_columns', 'presslearn_analytics_column_sortable');
3661
3662 function presslearn_analytics_column_orderby($query) {
3663 if (!is_admin()) {
3664 return;
3665 }
3666
3667 $orderby = $query->get('orderby');
3668
3669 if ($orderby == 'presslearn_analytics') {
3670 global $wpdb;
3671 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
3672
3673 if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") != $table_pageviews) {
3674 return;
3675 }
3676
3677 $query->set('meta_key', '_presslearn_post_views');
3678 $query->set('orderby', 'meta_value_num');
3679 }
3680 }
3681 add_action('pre_get_posts', 'presslearn_analytics_column_orderby');
3682
3683 function presslearn_schedule_post_views_update() {
3684 if (!wp_next_scheduled('presslearn_daily_post_views_update')) {
3685 wp_schedule_event(strtotime('today 00:00:00'), 'daily', 'presslearn_daily_post_views_update');
3686 }
3687 }
3688 add_action('wp', 'presslearn_schedule_post_views_update');
3689
3690 function presslearn_add_analytics_column_styles() {
3691 wp_register_style('presslearn-analytics-column-css', false);
3692 wp_enqueue_style('presslearn-analytics-column-css');
3693
3694 $analytics_column_css = "
3695 .presslearn-analytics-stats {
3696 display: block;
3697 line-height: 1.5;
3698 text-align: left;
3699 }
3700
3701 .presslearn-stats-row {
3702 display: flex;
3703 align-items: center;
3704 margin-bottom: 5px
3705 }
3706
3707 .presslearn-label {
3708 font-size: 13px;
3709 color: #666;
3710 margin-right: 5px;
3711 }
3712
3713 .presslearn-total {
3714 font-size: 16px;
3715 font-weight: bold;
3716 color: #2196F3;
3717 display: flex;
3718 align-items: center;
3719 }
3720
3721 .presslearn-total .dashicons {
3722 margin-right: 3px;
3723 }
3724
3725 .presslearn-unit {
3726 font-size: 12px;
3727 font-weight: normal;
3728 color: #666;
3729 margin-left: 1px;
3730 }
3731
3732 .presslearn-stats-periods {
3733 display: flex;
3734 flex-wrap: wrap;
3735 gap: 5px;
3736 flex-flow: column;
3737 }
3738
3739 .presslearn-period {
3740 display: flex;
3741 align-items: center;
3742 justify-content: space-between;
3743 font-size: 11px;
3744 padding: 2px 6px;
3745 border-radius: 5px;
3746 white-space: nowrap;
3747 }
3748
3749 .presslearn-period .dashicons {
3750 margin-right: 2px;
3751 }
3752
3753 .presslearn-period.today {
3754 background-color: #E8F5E9;
3755 color: #4CAF50;
3756 }
3757
3758 .presslearn-period.week {
3759 background-color: #E3F2FD;
3760 color: #2196F3;
3761 }
3762
3763 .presslearn-period.month {
3764 background-color: #EDE7F6;
3765 color: #673AB7;
3766 }
3767
3768 .column-presslearn_analytics {
3769 width: 165px;
3770 }
3771 ";
3772
3773 wp_add_inline_style('presslearn-analytics-column-css', $analytics_column_css);
3774 }
3775 add_action('admin_head', 'presslearn_add_analytics_column_styles');
3776
3777 function presslearn_update_post_views() {
3778 global $wpdb;
3779 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
3780
3781 if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") != $table_pageviews) {
3782 return;
3783 }
3784
3785 $args = array(
3786 'post_type' => array('post', 'page'),
3787 'posts_per_page' => -1,
3788 'post_status' => 'publish'
3789 );
3790 $posts = get_posts($args);
3791
3792 foreach ($posts as $post) {
3793 $permalink = get_permalink($post->ID);
3794
3795 $views = $wpdb->get_var($wpdb->prepare(
3796 "SELECT COUNT(*) FROM $table_pageviews WHERE url = %s",
3797 $permalink
3798 ));
3799
3800 update_post_meta($post->ID, '_presslearn_post_views', $views);
3801 }
3802 }
3803 add_action('presslearn_daily_post_views_update', 'presslearn_update_post_views');
3804
3805 register_activation_hook(__FILE__, 'presslearn_update_post_views');
3806
3807 function presslearn_button_animation_styles() {
3808 if (!function_exists('presslearn_plugin') || !presslearn_plugin()->is_plugin_activated()) {
3809 return;
3810 }
3811
3812 $quick_button_enabled = get_option('presslearn_quick_button_enabled', 'no');
3813 if ($quick_button_enabled !== 'yes') {
3814 return;
3815 }
3816
3817 wp_register_style('presslearn-button-animation-css', false);
3818 wp_enqueue_style('presslearn-button-animation-css');
3819
3820 $animation_styles = '
3821 .presslearn-button {
3822 transition: all 0.3s ease;
3823 }
3824
3825 @keyframes presslearn-pulse {
3826 0% { transform: scale(1); }
3827 50% { transform: scale(1.05); }
3828 100% { transform: scale(1); }
3829 }
3830
3831 .presslearn-button-animation-pulse:hover {
3832 animation: presslearn-pulse 1s infinite;
3833 }
3834
3835 .presslearn-button-animation-zoom:hover {
3836 transform: scale(1.1);
3837 }
3838
3839 .presslearn-button-animation-fade:hover {
3840 opacity: 0.8;
3841 }
3842
3843 @keyframes presslearn-shake {
3844 0%, 100% { transform: translateX(0); }
3845 10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
3846 20%, 40%, 60%, 80% { transform: translateX(5px); }
3847 }
3848
3849 .presslearn-button-animation-shake:hover {
3850 animation: presslearn-shake 0.5s;
3851 }';
3852
3853 wp_add_inline_style('presslearn-button-animation-css', $animation_styles);
3854
3855 wp_register_script('presslearn-button-animation-js', false, array(), PRESSLEARN_PLUGIN_VERSION, true);
3856 wp_enqueue_script('presslearn-button-animation-js');
3857
3858 $animation_script = '
3859 document.addEventListener("DOMContentLoaded", function() {
3860 const buttons = document.querySelectorAll(".presslearn-button");
3861
3862 buttons.forEach(function(button) {
3863 const originalColor = button.style.backgroundColor;
3864 const hoverColor = button.getAttribute("data-hover-color");
3865
3866 if (hoverColor && hoverColor !== originalColor) {
3867 button.addEventListener("mouseenter", function() {
3868 this.style.backgroundColor = hoverColor;
3869 });
3870
3871 button.addEventListener("mouseleave", function() {
3872 this.style.backgroundColor = originalColor;
3873 });
3874 }
3875 });
3876 });';
3877
3878 wp_add_inline_script('presslearn-button-animation-js', $animation_script);
3879 }
3880 add_action('wp_body_open', 'presslearn_button_animation_styles');
3881
3882 function presslearn_button_animation_admin_styles() {
3883 if (!function_exists('presslearn_plugin') || !presslearn_plugin()->is_plugin_activated()) {
3884 return;
3885 }
3886
3887 $quick_button_enabled = get_option('presslearn_quick_button_enabled', 'no');
3888 if ($quick_button_enabled !== 'yes') {
3889 return;
3890 }
3891
3892 wp_register_style('presslearn-button-animation-admin-css', false);
3893 wp_enqueue_style('presslearn-button-animation-admin-css');
3894
3895 $admin_animation_styles = '
3896 .editor-styles-wrapper .presslearn-button {
3897 transition: all 0.3s ease;
3898 }
3899
3900 @keyframes presslearn-pulse {
3901 0% { transform: scale(1); }
3902 50% { transform: scale(1.05); }
3903 100% { transform: scale(1); }
3904 }
3905
3906 .editor-styles-wrapper .presslearn-button-animation-pulse:hover {
3907 animation: presslearn-pulse 1s infinite;
3908 }
3909
3910 .editor-styles-wrapper .presslearn-button-animation-zoom:hover {
3911 transform: scale(1.1);
3912 }
3913
3914 .editor-styles-wrapper .presslearn-button-animation-fade:hover {
3915 opacity: 0.8;
3916 }
3917
3918 @keyframes presslearn-shake {
3919 0%, 100% { transform: translateX(0); }
3920 10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
3921 20%, 40%, 60%, 80% { transform: translateX(5px); }
3922 }
3923
3924 .editor-styles-wrapper .presslearn-button-animation-shake:hover {
3925 animation: presslearn-shake 0.5s;
3926 }';
3927
3928 wp_add_inline_style('presslearn-button-animation-admin-css', $admin_animation_styles);
3929 }
3930 add_action('admin_enqueue_scripts', 'presslearn_button_animation_admin_styles');
3931
3932 function presslearn_delete_analytics_data() {
3933 if (!current_user_can('manage_options')) {
3934 wp_die('권한이 없습니다.');
3935 }
3936
3937 check_ajax_referer('presslearn_delete_analytics_data_nonce', 'nonce');
3938
3939 global $wpdb;
3940 $table_pageviews = $wpdb->prefix . 'presslearn_pageviews';
3941 $table_visitors = $wpdb->prefix . 'presslearn_visitors';
3942 $table_referrers = $wpdb->prefix . 'presslearn_referrers';
3943
3944 $tables_exist = true;
3945
3946 if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") != $table_pageviews) {
3947 $tables_exist = false;
3948 }
3949
3950 if ($wpdb->get_var("SHOW TABLES LIKE '$table_visitors'") != $table_visitors) {
3951 $tables_exist = false;
3952 }
3953
3954 if ($wpdb->get_var("SHOW TABLES LIKE '$table_referrers'") != $table_referrers) {
3955 $tables_exist = false;
3956 }
3957
3958 if (!$tables_exist) {
3959 wp_send_json_error(array('message' => '�
3960 �이블이 존재하지 않습니다.'));
3961 return;
3962 }
3963
3964 $wpdb->query("TRUNCATE TABLE $table_pageviews");
3965 $wpdb->query("TRUNCATE TABLE $table_visitors");
3966 $wpdb->query("TRUNCATE TABLE $table_referrers");
3967
3968 $wpdb->query("UPDATE $wpdb->posts SET presslearn_post_views = 0 WHERE presslearn_post_views > 0");
3969
3970 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_alpack_%'");
3971 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_alpack_%'");
3972
3973 wp_cache_flush();
3974
3975 wp_send_json_success(array('message' => '모든 통계 데이터와 캐시가 성공적으로 삭제되었습니다.'));
3976 }