Última actividad 1 month ago

urocibg revisó este gist 1 month ago. Ir a la revisión

2 files changed, 1031 insertions

database.png(archivo creado)

Binary file changes are not shown

gistfile1.txt(archivo creado)

@@ -0,0 +1,1031 @@
1 + <?php
2 + /**
3 + * Plugin Name: Database Optimizer Pro
4 + * Plugin URI: https://fedia.eu
5 + * Description: Професионален инструмент за оптимизация на WordPress база данни с модерен интерфейс
6 + * Version: 2.0.0
7 + * Author: Fedya Serafiev
8 + * Author URI: https://fedia.eu
9 + * License: GPL v2 or later
10 + * Text Domain: db-optimizer-pro
11 + */
12 +
13 + if (!defined('ABSPATH')) {
14 + exit;
15 + }
16 +
17 + class DB_Optimizer_Pro {
18 +
19 + private $plugin_slug = 'db-optimizer-pro';
20 + private $version = '2.0.0';
21 +
22 + public function __construct() {
23 + add_action('admin_menu', array($this, 'add_admin_menu'));
24 + add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
25 + add_action('admin_footer', array($this, 'output_admin_scripts'));
26 + add_action('wp_ajax_dbop_scan_database', array($this, 'ajax_scan_database'));
27 + add_action('wp_ajax_dbop_clean_items', array($this, 'ajax_clean_items'));
28 + add_action('wp_ajax_dbop_optimize_tables', array($this, 'ajax_optimize_tables'));
29 + add_action('wp_ajax_dbop_get_stats', array($this, 'ajax_get_stats'));
30 + }
31 +
32 + public function add_admin_menu() {
33 + add_menu_page(
34 + 'Database Optimizer Pro',
35 + 'DB Optimizer',
36 + 'manage_options',
37 + $this->plugin_slug,
38 + array($this, 'render_admin_page'),
39 + 'dashicons-database-view',
40 + 80
41 + );
42 + }
43 +
44 + public function enqueue_admin_assets($hook) {
45 + if (strpos($hook, $this->plugin_slug) === false) {
46 + return;
47 + }
48 +
49 + // Enqueue jQuery (already included in WordPress)
50 + wp_enqueue_script('jquery');
51 +
52 + // Enqueue inline styles
53 + wp_register_style($this->plugin_slug . '-inline', false);
54 + wp_enqueue_style($this->plugin_slug . '-inline');
55 + wp_add_inline_style($this->plugin_slug . '-inline', $this->get_styles());
56 + }
57 +
58 + public function output_admin_scripts() {
59 + global $pagenow;
60 +
61 + if (isset($_GET['page']) && $_GET['page'] === $this->plugin_slug) {
62 + ?>
63 + <script type="text/javascript">
64 + jQuery(document).ready(function($) {
65 + // Define AJAX object
66 + var dbopAjax = {
67 + ajax_url: '<?php echo admin_url('admin-ajax.php'); ?>',
68 + nonce: '<?php echo wp_create_nonce('dbop_nonce'); ?>'
69 + };
70 +
71 + var scanData = {};
72 +
73 + // Tab switching
74 + $('.dbop-tab').on('click', function(e) {
75 + e.preventDefault();
76 + const tab = $(this).data('tab');
77 + $('.dbop-tab').removeClass('active');
78 + $(this).addClass('active');
79 + $('.dbop-tab-content').removeClass('active');
80 + $('#tab-' + tab).addClass('active');
81 + });
82 +
83 + // Scan database
84 + $('#dbop-scan-btn').on('click', function() {
85 + const btn = $(this);
86 + btn.prop('disabled', true).html('<span class="dbop-loading"></span> Сканиране...');
87 +
88 + console.log('Sending AJAX request...');
89 +
90 + $.ajax({
91 + url: dbopAjax.ajax_url,
92 + type: 'POST',
93 + dataType: 'json',
94 + data: {
95 + action: 'dbop_scan_database',
96 + nonce: dbopAjax.nonce
97 + },
98 + success: function(response) {
99 + console.log('AJAX Response:', response);
100 + if (response.success) {
101 + scanData = response.data;
102 + displayScanResults(response.data);
103 + showAlert('success', 'Сканирането завърши успешно!');
104 + } else {
105 + showAlert('error', response.data?.message || 'Грешка при сканиране');
106 + }
107 + },
108 + error: function(xhr, status, error) {
109 + console.error('AJAX Error:', error);
110 + showAlert('error', 'AJAX грешка: ' + error);
111 + },
112 + complete: function() {
113 + btn.prop('disabled', false).html('🔍 Сканирай база данни');
114 + }
115 + });
116 + });
117 +
118 + // Clean items
119 + $(document).on('click', '.dbop-clean-btn', function() {
120 + const type = $(this).data('type');
121 + const btn = $(this);
122 +
123 + if (!confirm('Сигурни ли сте, че искате да изтриете тези елементи?')) {
124 + return;
125 + }
126 +
127 + btn.prop('disabled', true).html('<span class="dbop-loading"></span>');
128 +
129 + $.ajax({
130 + url: dbopAjax.ajax_url,
131 + type: 'POST',
132 + dataType: 'json',
133 + data: {
134 + action: 'dbop_clean_items',
135 + nonce: dbopAjax.nonce,
136 + type: type
137 + },
138 + success: function(response) {
139 + if (response.success) {
140 + showAlert('success', 'Почистването завърши успешно! Изтрити: ' + response.data.deleted);
141 + $('#dbop-scan-btn').click();
142 + } else {
143 + showAlert('error', response.data?.message || 'Грешка при почистване');
144 + }
145 + },
146 + error: function(xhr, status, error) {
147 + showAlert('error', 'AJAX грешка: ' + error);
148 + },
149 + complete: function() {
150 + btn.prop('disabled', false).html('🗑️ Изтрий');
151 + }
152 + });
153 + });
154 +
155 + // Optimize tables
156 + $('#dbop-optimize-btn').on('click', function() {
157 + const btn = $(this);
158 +
159 + if (!confirm('Искате ли да оптимизирате всички таблици?')) {
160 + return;
161 + }
162 +
163 + btn.prop('disabled', true).html('<span class="dbop-loading"></span> Оптимизация...');
164 +
165 + $.ajax({
166 + url: dbopAjax.ajax_url,
167 + type: 'POST',
168 + dataType: 'json',
169 + data: {
170 + action: 'dbop_optimize_tables',
171 + nonce: dbopAjax.nonce
172 + },
173 + success: function(response) {
174 + if (response.success) {
175 + showAlert('success', 'Таблиците са оптимизирани успешно!');
176 + updateStats(response.data.stats);
177 + } else {
178 + showAlert('error', response.data?.message || 'Грешка при оптимизация');
179 + }
180 + },
181 + error: function(xhr, status, error) {
182 + showAlert('error', 'AJAX грешка: ' + error);
183 + },
184 + complete: function() {
185 + btn.prop('disabled', false).html('⚡ Оптимизирай таблици');
186 + }
187 + });
188 + });
189 +
190 + // Get initial stats
191 + function loadInitialStats() {
192 + $.ajax({
193 + url: dbopAjax.ajax_url,
194 + type: 'POST',
195 + dataType: 'json',
196 + data: {
197 + action: 'dbop_get_stats',
198 + nonce: dbopAjax.nonce
199 + },
200 + success: function(response) {
201 + if (response.success) {
202 + updateStatsUI(response.data);
203 + }
204 + }
205 + });
206 + }
207 +
208 + // Call on page load
209 + loadInitialStats();
210 +
211 + function displayScanResults(data) {
212 + let html = '';
213 +
214 + const items = [
215 + { key: 'orphaned_postmeta', icon: '🗂️', title: 'Orphaned Post Meta', desc: 'Мета данни без съответен пост' },
216 + { key: 'orphaned_commentmeta', icon: '💬', title: 'Orphaned Comment Meta', desc: 'Мета данни без съответен коментар' },
217 + { key: 'orphaned_usermeta', icon: '👤', title: 'Orphaned User Meta', desc: 'Мета данни без съответен потребител' },
218 + { key: 'orphaned_termmeta', icon: '🏷️', title: 'Orphaned Term Meta', desc: 'Мета данни без съответен термин' },
219 + { key: 'expired_transients', icon: '⏱️', title: 'Expired Transients', desc: 'Изтекли временни данни' },
220 + { key: 'post_revisions', icon: '📝', title: 'Post Revisions', desc: 'Ревизии на публикации' },
221 + { key: 'auto_drafts', icon: '📄', title: 'Auto Drafts', desc: 'Автоматични чернови' },
222 + { key: 'trashed_posts', icon: '🗑️', title: 'Trashed Posts', desc: 'Изтрити публикации в кошчето' },
223 + { key: 'spam_comments', icon: '⚠️', title: 'Spam Comments', desc: 'Спам коментари' },
224 + { key: 'trashed_comments', icon: '💬', title: 'Trashed Comments', desc: 'Изтрити коментари' }
225 + ];
226 +
227 + items.forEach(item => {
228 + if (data[item.key] > 0) {
229 + html += createResultItem(item.key, item.icon + ' ' + item.title, item.desc, data[item.key]);
230 + }
231 + });
232 +
233 + if (html === '') {
234 + html = '<div class="dbop-alert dbop-alert-success">✅ Базата данни е чиста! Няма елементи за почистване.</div>';
235 + }
236 +
237 + $('#dbop-results').html(html);
238 + }
239 +
240 + function createResultItem(type, title, description, count) {
241 + return `
242 + <div class="dbop-result-item">
243 + <div class="dbop-result-info">
244 + <div class="dbop-result-title">${title}</div>
245 + <div class="dbop-result-description">${description}</div>
246 + </div>
247 + <div style="display: flex; align-items: center;">
248 + <span class="dbop-result-count">${count}</span>
249 + <button class="dbop-btn dbop-btn-danger dbop-clean-btn" data-type="${type}">🗑️ Изтрий</button>
250 + </div>
251 + </div>
252 + `;
253 + }
254 +
255 + function updateStatsUI(stats) {
256 + $('#stat-db-size').text(stats.db_size || '0 MB');
257 + $('#stat-tables').text(stats.total_tables || '0');
258 + $('#stat-overhead').text(stats.overhead || '0 MB');
259 + }
260 +
261 + function updateStats(stats) {
262 + // Update stats after optimization
263 + if (stats) {
264 + $('#stat-db-size').text(stats.db_size || '0 MB');
265 + $('#stat-tables').text(stats.total_tables || '0');
266 + $('#stat-overhead').text(stats.overhead || '0 MB');
267 + }
268 + }
269 +
270 + function showAlert(type, message) {
271 + const alertClass = 'dbop-alert-' + type;
272 + const icon = type === 'success' ? '✅' : (type === 'warning' ? '⚠️' : '❌');
273 + const alert = `<div class="dbop-alert ${alertClass}">${icon} ${message}</div>`;
274 +
275 + $('.dbop-main-card').prepend(alert);
276 +
277 + setTimeout(function() {
278 + $('.dbop-alert').first().fadeOut(function() {
279 + $(this).remove();
280 + });
281 + }, 5000);
282 + }
283 +
284 + // Initialize tabs
285 + $('.dbop-tab[data-tab="cleaner"]').addClass('active');
286 + $('#tab-cleaner').addClass('active');
287 + });
288 + </script>
289 + <?php
290 + }
291 + }
292 +
293 + private function get_styles() {
294 + return "
295 + .dbop-container {
296 + max-width: 1400px;
297 + margin: 20px auto;
298 + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
299 + }
300 +
301 + .dbop-header {
302 + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
303 + color: white;
304 + padding: 40px;
305 + border-radius: 16px;
306 + margin-bottom: 30px;
307 + box-shadow: 0 10px 40px rgba(102, 126, 234, 0.3);
308 + }
309 +
310 + .dbop-header h1 {
311 + margin: 0 0 10px 0;
312 + font-size: 32px;
313 + font-weight: 700;
314 + }
315 +
316 + .dbop-header p {
317 + margin: 0;
318 + opacity: 0.9;
319 + font-size: 16px;
320 + }
321 +
322 + .dbop-grid {
323 + display: grid;
324 + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
325 + gap: 20px;
326 + margin-bottom: 30px;
327 + }
328 +
329 + .dbop-card {
330 + background: white;
331 + border-radius: 12px;
332 + padding: 25px;
333 + box-shadow: 0 2px 12px rgba(0,0,0,0.08);
334 + transition: all 0.3s ease;
335 + border: 1px solid #e5e7eb;
336 + }
337 +
338 + .dbop-card:hover {
339 + transform: translateY(-4px);
340 + box-shadow: 0 8px 24px rgba(0,0,0,0.12);
341 + }
342 +
343 + .dbop-card h3 {
344 + margin-top: 0;
345 + margin-bottom: 10px;
346 + color: #374151;
347 + font-size: 16px;
348 + font-weight: 600;
349 + }
350 +
351 + .dbop-stat-value {
352 + font-size: 32px;
353 + font-weight: 700;
354 + color: #111827;
355 + margin: 10px 0;
356 + }
357 +
358 + .dbop-card p {
359 + font-size: 13px;
360 + color: #9ca3af;
361 + margin: 0;
362 + }
363 +
364 + .dbop-main-card {
365 + background: white;
366 + border-radius: 12px;
367 + padding: 30px;
368 + box-shadow: 0 2px 12px rgba(0,0,0,0.08);
369 + border: 1px solid #e5e7eb;
370 + margin-bottom: 30px;
371 + }
372 +
373 + .dbop-actions {
374 + display: flex;
375 + gap: 15px;
376 + margin-bottom: 30px;
377 + flex-wrap: wrap;
378 + }
379 +
380 + .dbop-btn {
381 + padding: 12px 24px;
382 + border: none;
383 + border-radius: 8px;
384 + font-size: 14px;
385 + font-weight: 600;
386 + cursor: pointer;
387 + transition: all 0.3s ease;
388 + display: inline-flex;
389 + align-items: center;
390 + justify-content: center;
391 + gap: 8px;
392 + min-height: 44px;
393 + }
394 +
395 + .dbop-btn-primary {
396 + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
397 + color: white;
398 + }
399 +
400 + .dbop-btn-primary:hover:not(:disabled) {
401 + transform: translateY(-2px);
402 + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
403 + }
404 +
405 + .dbop-btn-secondary {
406 + background: #f3f4f6;
407 + color: #374151;
408 + }
409 +
410 + .dbop-btn-secondary:hover:not(:disabled) {
411 + background: #e5e7eb;
412 + }
413 +
414 + .dbop-btn-danger {
415 + background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
416 + color: white;
417 + }
418 +
419 + .dbop-btn-danger:hover:not(:disabled) {
420 + transform: translateY(-2px);
421 + box-shadow: 0 6px 20px rgba(239, 68, 68, 0.4);
422 + }
423 +
424 + .dbop-btn:disabled {
425 + opacity: 0.5;
426 + cursor: not-allowed;
427 + transform: none !important;
428 + }
429 +
430 + .dbop-results {
431 + margin-top: 30px;
432 + }
433 +
434 + .dbop-result-item {
435 + background: #f9fafb;
436 + border-left: 4px solid #667eea;
437 + padding: 15px 20px;
438 + margin-bottom: 12px;
439 + border-radius: 8px;
440 + display: flex;
441 + justify-content: space-between;
442 + align-items: center;
443 + transition: all 0.2s ease;
444 + }
445 +
446 + .dbop-result-item:hover {
447 + background: #f3f4f6;
448 + }
449 +
450 + .dbop-result-info {
451 + flex: 1;
452 + }
453 +
454 + .dbop-result-title {
455 + font-weight: 600;
456 + color: #111827;
457 + margin-bottom: 4px;
458 + }
459 +
460 + .dbop-result-description {
461 + font-size: 13px;
462 + color: #6b7280;
463 + }
464 +
465 + .dbop-result-count {
466 + background: #667eea;
467 + color: white;
468 + padding: 6px 12px;
469 + border-radius: 20px;
470 + font-weight: 600;
471 + font-size: 14px;
472 + margin-right: 10px;
473 + }
474 +
475 + .dbop-loading {
476 + display: inline-block;
477 + width: 16px;
478 + height: 16px;
479 + border: 2px solid rgba(255,255,255,0.3);
480 + border-top-color: white;
481 + border-radius: 50%;
482 + animation: spin 0.8s linear infinite;
483 + }
484 +
485 + @keyframes spin {
486 + to { transform: rotate(360deg); }
487 + }
488 +
489 + .dbop-alert {
490 + padding: 15px 20px;
491 + border-radius: 8px;
492 + margin-bottom: 20px;
493 + display: flex;
494 + align-items: flex-start;
495 + gap: 12px;
496 + }
497 +
498 + .dbop-alert-success {
499 + background: #ecfdf5;
500 + color: #065f46;
501 + border: 1px solid #a7f3d0;
502 + }
503 +
504 + .dbop-alert-warning {
505 + background: #fef3c7;
506 + color: #92400e;
507 + border: 1px solid #fde68a;
508 + }
509 +
510 + .dbop-alert-error {
511 + background: #fee2e2;
512 + color: #991b1b;
513 + border: 1px solid #fecaca;
514 + }
515 +
516 + .dbop-alert-info {
517 + background: #eff6ff;
518 + color: #1e40af;
519 + border: 1px solid #bfdbfe;
520 + }
521 +
522 + .dbop-tabs {
523 + display: flex;
524 + gap: 10px;
525 + margin-bottom: 25px;
526 + border-bottom: 2px solid #e5e7eb;
527 + flex-wrap: wrap;
528 + }
529 +
530 + .dbop-tab {
531 + padding: 12px 20px;
532 + background: none;
533 + border: none;
534 + color: #6b7280;
535 + font-weight: 600;
536 + cursor: pointer;
537 + position: relative;
538 + transition: all 0.3s ease;
539 + border-radius: 6px 6px 0 0;
540 + }
541 +
542 + .dbop-tab:hover {
543 + color: #667eea;
544 + background: #f3f4f6;
545 + }
546 +
547 + .dbop-tab.active {
548 + color: #667eea;
549 + }
550 +
551 + .dbop-tab.active::after {
552 + content: '';
553 + position: absolute;
554 + bottom: -2px;
555 + left: 0;
556 + right: 0;
557 + height: 2px;
558 + background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
559 + }
560 +
561 + .dbop-tab-content {
562 + display: none;
563 + }
564 +
565 + .dbop-tab-content.active {
566 + display: block;
567 + }
568 +
569 + @media (max-width: 768px) {
570 + .dbop-grid {
571 + grid-template-columns: 1fr;
572 + }
573 +
574 + .dbop-actions {
575 + flex-direction: column;
576 + }
577 +
578 + .dbop-btn {
579 + width: 100%;
580 + }
581 +
582 + .dbop-header {
583 + padding: 25px;
584 + }
585 +
586 + .dbop-header h1 {
587 + font-size: 24px;
588 + }
589 + }
590 + ";
591 + }
592 +
593 + public function render_admin_page() {
594 + global $wpdb;
595 +
596 + // Get initial database stats
597 + $stats = $this->get_database_stats();
598 + ?>
599 + <div class="dbop-container">
600 + <div class="dbop-header">
601 + <h1>🚀 Database Optimizer Pro</h1>
602 + <p>Професионален инструмент за оптимизация и почистване на WordPress база данни</p>
603 + </div>
604 +
605 + <div class="dbop-grid">
606 + <div class="dbop-card">
607 + <h3>Размер на БД</h3>
608 + <div class="dbop-stat-value" id="stat-db-size"><?php echo esc_html($stats['db_size']); ?></div>
609 + <p>Общ размер на базата данни</p>
610 + </div>
611 +
612 + <div class="dbop-card">
613 + <h3>Таблици</h3>
614 + <div class="dbop-stat-value" id="stat-tables"><?php echo (int)$stats['total_tables']; ?></div>
615 + <p>Общо таблици в БД</p>
616 + </div>
617 +
618 + <div class="dbop-card">
619 + <h3>Overhead</h3>
620 + <div class="dbop-stat-value" id="stat-overhead"><?php echo esc_html($stats['overhead']); ?></div>
621 + <p>Неизползвано място в таблици</p>
622 + </div>
623 +
624 + <div class="dbop-card">
625 + <h3>Оптимизации</h3>
626 + <div class="dbop-stat-value"><?php echo (int)get_option('dbop_optimization_count', 0); ?></div>
627 + <p>Брой оптимизации</p>
628 + </div>
629 + </div>
630 +
631 + <div class="dbop-main-card">
632 + <nav class="dbop-tabs">
633 + <button class="dbop-tab active" data-tab="cleaner">🧹 Почистване</button>
634 + <button class="dbop-tab" data-tab="optimizer">⚡ Оптимизация</button>
635 + <button class="dbop-tab" data-tab="info">ℹ️ Информация</button>
636 + </nav>
637 +
638 + <div id="tab-cleaner" class="dbop-tab-content active">
639 + <div class="dbop-actions">
640 + <button id="dbop-scan-btn" class="dbop-btn dbop-btn-primary">
641 + 🔍 Сканирай база данни
642 + </button>
643 + </div>
644 +
645 + <div id="dbop-results">
646 + <div class="dbop-alert dbop-alert-warning">
647 + ⚠️ Натиснете "Сканирай база данни" за да започнете анализ
648 + </div>
649 + </div>
650 + </div>
651 +
652 + <div id="tab-optimizer" class="dbop-tab-content">
653 + <div class="dbop-actions">
654 + <button id="dbop-optimize-btn" class="dbop-btn dbop-btn-primary">
655 + ⚡ Оптимизирай таблици
656 + </button>
657 + </div>
658 +
659 + <div class="dbop-alert dbop-alert-info">
660 + ℹ️ Оптимизацията ще подобри производителността на базата данни чрез реорганизация на таблиците
661 + </div>
662 + </div>
663 +
664 + <div id="tab-info" class="dbop-tab-content">
665 + <h3>За плъгина</h3>
666 + <p>Database Optimizer Pro е професионален инструмент за поддръжка на WordPress база данни.</p>
667 +
668 + <h4>Функции:</h4>
669 + <ul>
670 + <li>✅ Почистване на orphaned metadata</li>
671 + <li>✅ Изтриване на изтекли transients</li>
672 + <li>✅ Премахване на ревизии и автосъхранения</li>
673 + <li>✅ Изчистване на спам и изтрити коментари</li>
674 + <li>✅ Оптимизация на всички таблици</li>
675 + <li>✅ Подробна статистика и визуализация</li>
676 + </ul>
677 +
678 + <div class="dbop-alert dbop-alert-warning">
679 + ⚠️ Препоръчително: Направете backup на базата данни преди да извършвате операции!
680 + </div>
681 + </div>
682 + </div>
683 +
684 + <div class="dbop-alert dbop-alert-info">
685 + 💡 <strong>Pro Tip:</strong> Редовната поддръжка на базата данни подобрява производителността на сайта.
686 + </div>
687 + </div>
688 + <?php
689 + }
690 +
691 + private function get_database_stats() {
692 + global $wpdb;
693 +
694 + $db_size = $wpdb->get_var("
695 + SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2)
696 + FROM information_schema.tables
697 + WHERE table_schema = DATABASE()
698 + ") . ' MB';
699 +
700 + $total_tables = $wpdb->get_var("
701 + SELECT COUNT(*)
702 + FROM information_schema.tables
703 + WHERE table_schema = DATABASE()
704 + ");
705 +
706 + $overhead = $wpdb->get_var("
707 + SELECT ROUND(SUM(data_free) / 1024 / 1024, 2)
708 + FROM information_schema.tables
709 + WHERE table_schema = DATABASE()
710 + AND ENGINE = 'InnoDB'
711 + ") . ' MB';
712 +
713 + return array(
714 + 'db_size' => $db_size,
715 + 'total_tables' => $total_tables,
716 + 'overhead' => $overhead
717 + );
718 + }
719 +
720 + public function ajax_scan_database() {
721 + check_ajax_referer('dbop_nonce', 'nonce');
722 +
723 + if (!current_user_can('manage_options')) {
724 + wp_send_json_error(array('message' => 'Недостатъчни права'));
725 + }
726 +
727 + global $wpdb;
728 +
729 + $data = array(
730 + 'orphaned_postmeta' => $this->count_orphaned_postmeta(),
731 + 'orphaned_commentmeta' => $this->count_orphaned_commentmeta(),
732 + 'orphaned_usermeta' => $this->count_orphaned_usermeta(),
733 + 'orphaned_termmeta' => $this->count_orphaned_termmeta(),
734 + 'expired_transients' => $this->count_expired_transients(),
735 + 'post_revisions' => $this->count_post_revisions(),
736 + 'auto_drafts' => $this->count_auto_drafts(),
737 + 'trashed_posts' => $this->count_trashed_posts(),
738 + 'spam_comments' => $this->count_spam_comments(),
739 + 'trashed_comments' => $this->count_trashed_comments()
740 + );
741 +
742 + wp_send_json_success($data);
743 + }
744 +
745 + public function ajax_clean_items() {
746 + check_ajax_referer('dbop_nonce', 'nonce');
747 +
748 + if (!current_user_can('manage_options')) {
749 + wp_send_json_error(array('message' => 'Недостатъчни права'));
750 + }
751 +
752 + $type = sanitize_text_field($_POST['type']);
753 + $deleted = 0;
754 +
755 + switch ($type) {
756 + case 'orphaned_postmeta':
757 + $deleted = $this->clean_orphaned_postmeta();
758 + break;
759 + case 'orphaned_commentmeta':
760 + $deleted = $this->clean_orphaned_commentmeta();
761 + break;
762 + case 'orphaned_usermeta':
763 + $deleted = $this->clean_orphaned_usermeta();
764 + break;
765 + case 'orphaned_termmeta':
766 + $deleted = $this->clean_orphaned_termmeta();
767 + break;
768 + case 'expired_transients':
769 + $deleted = $this->clean_expired_transients();
770 + break;
771 + case 'post_revisions':
772 + $deleted = $this->clean_post_revisions();
773 + break;
774 + case 'auto_drafts':
775 + $deleted = $this->clean_auto_drafts();
776 + break;
777 + case 'trashed_posts':
778 + $deleted = $this->clean_trashed_posts();
779 + break;
780 + case 'spam_comments':
781 + $deleted = $this->clean_spam_comments();
782 + break;
783 + case 'trashed_comments':
784 + $deleted = $this->clean_trashed_comments();
785 + break;
786 + }
787 +
788 + wp_send_json_success(array('deleted' => $deleted));
789 + }
790 +
791 + public function ajax_optimize_tables() {
792 + check_ajax_referer('dbop_nonce', 'nonce');
793 +
794 + if (!current_user_can('manage_options')) {
795 + wp_send_json_error(array('message' => 'Недостатъчни права'));
796 + }
797 +
798 + global $wpdb;
799 + $optimized = 0;
800 +
801 + $tables = $wpdb->get_results("SHOW TABLES", ARRAY_N);
802 +
803 + foreach ($tables as $table) {
804 + $table_name = $table[0];
805 + $result = $wpdb->query("OPTIMIZE TABLE `{$table_name}`");
806 + if ($result !== false) {
807 + $optimized++;
808 + }
809 + }
810 +
811 + // Update optimization count
812 + $count = get_option('dbop_optimization_count', 0);
813 + update_option('dbop_optimization_count', $count + 1);
814 +
815 + wp_send_json_success(array(
816 + 'optimized' => $optimized,
817 + 'stats' => $this->get_database_stats()
818 + ));
819 + }
820 +
821 + public function ajax_get_stats() {
822 + check_ajax_referer('dbop_nonce', 'nonce');
823 +
824 + if (!current_user_can('manage_options')) {
825 + wp_send_json_error(array('message' => 'Недостатъчни права'));
826 + }
827 +
828 + wp_send_json_success($this->get_database_stats());
829 + }
830 +
831 + // Count methods
832 + private function count_orphaned_postmeta() {
833 + global $wpdb;
834 + return (int)$wpdb->get_var("
835 + SELECT COUNT(*)
836 + FROM {$wpdb->postmeta} pm
837 + LEFT JOIN {$wpdb->posts} p ON pm.post_id = p.ID
838 + WHERE p.ID IS NULL
839 + ");
840 + }
841 +
842 + private function count_orphaned_commentmeta() {
843 + global $wpdb;
844 + return (int)$wpdb->get_var("
845 + SELECT COUNT(*)
846 + FROM {$wpdb->commentmeta} cm
847 + LEFT JOIN {$wpdb->comments} c ON cm.comment_id = c.comment_ID
848 + WHERE c.comment_ID IS NULL
849 + ");
850 + }
851 +
852 + private function count_orphaned_usermeta() {
853 + global $wpdb;
854 + return (int)$wpdb->get_var("
855 + SELECT COUNT(*)
856 + FROM {$wpdb->usermeta} um
857 + LEFT JOIN {$wpdb->users} u ON um.user_id = u.ID
858 + WHERE u.ID IS NULL
859 + ");
860 + }
861 +
862 + private function count_orphaned_termmeta() {
863 + global $wpdb;
864 + return (int)$wpdb->get_var("
865 + SELECT COUNT(*)
866 + FROM {$wpdb->termmeta} tm
867 + LEFT JOIN {$wpdb->terms} t ON tm.term_id = t.term_id
868 + WHERE t.term_id IS NULL
869 + ");
870 + }
871 +
872 + private function count_expired_transients() {
873 + global $wpdb;
874 + return (int)$wpdb->get_var("
875 + SELECT COUNT(*)
876 + FROM {$wpdb->options}
877 + WHERE option_name LIKE '_transient_timeout_%'
878 + AND option_value < UNIX_TIMESTAMP()
879 + ");
880 + }
881 +
882 + private function count_post_revisions() {
883 + global $wpdb;
884 + return (int)$wpdb->get_var("
885 + SELECT COUNT(*)
886 + FROM {$wpdb->posts}
887 + WHERE post_type = 'revision'
888 + ");
889 + }
890 +
891 + private function count_auto_drafts() {
892 + global $wpdb;
893 + return (int)$wpdb->get_var("
894 + SELECT COUNT(*)
895 + FROM {$wpdb->posts}
896 + WHERE post_status = 'auto-draft'
897 + ");
898 + }
899 +
900 + private function count_trashed_posts() {
901 + global $wpdb;
902 + return (int)$wpdb->get_var("
903 + SELECT COUNT(*)
904 + FROM {$wpdb->posts}
905 + WHERE post_status = 'trash'
906 + ");
907 + }
908 +
909 + private function count_spam_comments() {
910 + global $wpdb;
911 + return (int)$wpdb->get_var("
912 + SELECT COUNT(*)
913 + FROM {$wpdb->comments}
914 + WHERE comment_approved = 'spam'
915 + ");
916 + }
917 +
918 + private function count_trashed_comments() {
919 + global $wpdb;
920 + return (int)$wpdb->get_var("
921 + SELECT COUNT(*)
922 + FROM {$wpdb->comments}
923 + WHERE comment_approved = 'trash'
924 + ");
925 + }
926 +
927 + // Clean methods
928 + private function clean_orphaned_postmeta() {
929 + global $wpdb;
930 + return (int)$wpdb->query("
931 + DELETE pm FROM {$wpdb->postmeta} pm
932 + LEFT JOIN {$wpdb->posts} p ON pm.post_id = p.ID
933 + WHERE p.ID IS NULL
934 + ");
935 + }
936 +
937 + private function clean_orphaned_commentmeta() {
938 + global $wpdb;
939 + return (int)$wpdb->query("
940 + DELETE cm FROM {$wpdb->commentmeta} cm
941 + LEFT JOIN {$wpdb->comments} c ON cm.comment_id = c.comment_ID
942 + WHERE c.comment_ID IS NULL
943 + ");
944 + }
945 +
946 + private function clean_orphaned_usermeta() {
947 + global $wpdb;
948 + return (int)$wpdb->query("
949 + DELETE um FROM {$wpdb->usermeta} um
950 + LEFT JOIN {$wpdb->users} u ON um.user_id = u.ID
951 + WHERE u.ID IS NULL
952 + ");
953 + }
954 +
955 + private function clean_orphaned_termmeta() {
956 + global $wpdb;
957 + return (int)$wpdb->query("
958 + DELETE tm FROM {$wpdb->termmeta} tm
959 + LEFT JOIN {$wpdb->terms} t ON tm.term_id = t.term_id
960 + WHERE t.term_id IS NULL
961 + ");
962 + }
963 +
964 + private function clean_expired_transients() {
965 + global $wpdb;
966 +
967 + $time = time();
968 + $transients = $wpdb->get_col("
969 + SELECT option_name
970 + FROM {$wpdb->options}
971 + WHERE option_name LIKE '_transient_timeout_%'
972 + AND option_value < {$time}
973 + ");
974 +
975 + $deleted = 0;
976 +
977 + foreach ($transients as $transient) {
978 + $key = str_replace('_transient_timeout_', '', $transient);
979 + delete_transient($key);
980 + $deleted++;
981 + }
982 +
983 + return $deleted;
984 + }
985 +
986 + private function clean_post_revisions() {
987 + global $wpdb;
988 + return (int)$wpdb->query("
989 + DELETE FROM {$wpdb->posts}
990 + WHERE post_type = 'revision'
991 + ");
992 + }
993 +
994 + private function clean_auto_drafts() {
995 + global $wpdb;
996 + return (int)$wpdb->query("
997 + DELETE FROM {$wpdb->posts}
998 + WHERE post_status = 'auto-draft'
999 + ");
1000 + }
1001 +
1002 + private function clean_trashed_posts() {
1003 + global $wpdb;
1004 + return (int)$wpdb->query("
1005 + DELETE FROM {$wpdb->posts}
1006 + WHERE post_status = 'trash'
1007 + ");
1008 + }
1009 +
1010 + private function clean_spam_comments() {
1011 + global $wpdb;
1012 + return (int)$wpdb->query("
1013 + DELETE FROM {$wpdb->comments}
1014 + WHERE comment_approved = 'spam'
1015 + ");
1016 + }
1017 +
1018 + private function clean_trashed_comments() {
1019 + global $wpdb;
1020 + return (int)$wpdb->query("
1021 + DELETE FROM {$wpdb->comments}
1022 + WHERE comment_approved = 'trash'
1023 + ");
1024 + }
1025 + }
1026 +
1027 + // Initialize the plugin
1028 + function db_optimizer_pro_init() {
1029 + new DB_Optimizer_Pro();
1030 + }
1031 + add_action('plugins_loaded', 'db_optimizer_pro_init');
Siguiente Anterior