221 lines
9.0 KiB
PHP
221 lines
9.0 KiB
PHP
<?php
|
||
add_action('wp_footer', 'display_sql_queries_in_footer', 9999);
|
||
|
||
function display_sql_queries_in_footer() {
|
||
if (!current_user_can('administrator')) {
|
||
return;
|
||
}
|
||
|
||
global $wpdb;
|
||
|
||
if (empty($wpdb->queries)) {
|
||
echo '<div style="background: #fff; padding: 20px; margin: 20px; border: 1px solid #ccc; font-family: monospace; font-size: 14px; position: relative; z-index: 99999;">';
|
||
echo '<p>Нет данных о запросах. Убедитесь, что в wp-config.php добавлена строка:</p>';
|
||
echo '<code style="background: #f4f4f4; padding: 5px; display: block;">define( \'SAVEQUERIES\', true );</code>';
|
||
echo '</div>';
|
||
return;
|
||
}
|
||
|
||
$queries = $wpdb->queries;
|
||
$total_time = 0;
|
||
foreach ($queries as $query) {
|
||
$total_time += $query[1];
|
||
}
|
||
|
||
echo '<div id="sql-debug-panel" style="background: #fff; padding: 20px; margin: 20px; border: 1px solid #ccc; font-family: monospace; font-size: 14px; position: relative; z-index: 99999;">';
|
||
|
||
// Панель управления сортировкой
|
||
echo '<div style="margin-bottom: 20px; padding: 10px; background: #f5f5f5; border-radius: 5px;">';
|
||
echo '<h3 style="margin-top: 0; display: inline-block; margin-right: 20px;">SQL Запросы</h3>';
|
||
echo '<button onclick="sortQueries(\'time-desc\')" style="margin-right: 10px; padding: 5px 10px; background: #e74c3c; color: white; border: none; border-radius: 3px; cursor: pointer;">Самые медленные</button>';
|
||
echo '<button onclick="sortQueries(\'time-asc\')" style="margin-right: 10px; padding: 5px 10px; background: #27ae60; color: white; border: none; border-radius: 3px; cursor: pointer;">Самые быстрые</button>';
|
||
echo '<button onclick="sortQueries(\'default\')" style="margin-right: 10px; padding: 5px 10px; background: #3498db; color: white; border: none; border-radius: 3px; cursor: pointer;">По умолчанию</button>';
|
||
echo '<span style="margin-left: 20px; font-weight: bold;">Всего запросов: ' . count($queries) . '</span>';
|
||
echo '</div>';
|
||
|
||
echo '<table id="sql-queries-table" style="width: 100%; border-collapse: collapse; margin-top: 15px;">';
|
||
echo '<thead>';
|
||
echo '<tr style="background: #2c3e50; color: #fff; cursor: pointer;">';
|
||
echo '<th style="padding: 8px; border: 1px solid #ddd; text-align: left;" onclick="sortQueries(\'time-desc\')">Время ⬇</th>';
|
||
echo '<th style="padding: 8px; border: 1px solid #ddd; text-align: left;">Запрос</th>';
|
||
echo '<th style="padding: 8px; border: 1px solid #ddd; text-align: left;">Вызвавший код</th>';
|
||
echo '</tr>';
|
||
echo '</thead>';
|
||
echo '<tbody>';
|
||
|
||
foreach ($queries as $query) {
|
||
$time = number_format($query[1] * 1000, 2);
|
||
$time_seconds = $query[1];
|
||
|
||
$color = '#27ae60';
|
||
if ($query[1] > 0.1) $color = '#f39c12';
|
||
if ($query[1] > 0.5) $color = '#e74c3c';
|
||
|
||
echo '<tr class="sql-query-row">';
|
||
echo '<td style="padding: 8px; border: 1px solid #ddd; color: ' . $color . '; font-weight: bold;" data-time="' . $time_seconds . '">' . $time . ' ms</td>';
|
||
echo '<td style="padding: 8px; border: 1px solid #ddd; word-break: break-all;">' . htmlspecialchars($query[0]) . '</td>';
|
||
echo '<td style="padding: 8px; border: 1px solid #ddd; font-size: 12px; color: #666;">' . $query[2] . '</td>';
|
||
echo '</tr>';
|
||
}
|
||
|
||
echo '</tbody>';
|
||
echo '</table>';
|
||
|
||
echo '<div style="margin-top: 15px; padding: 10px; background: #f8f9fa; border-left: 4px solid #3498db;">';
|
||
echo 'Общее время SQL запросов: <strong>' . number_format($total_time * 1000, 2) . ' ms</strong><br>';
|
||
echo 'Среднее время на запрос: <strong>' . number_format(($total_time / count($queries)) * 1000, 2) . ' ms</strong>';
|
||
echo '</div>';
|
||
|
||
echo '</div>';
|
||
|
||
// Добавляем JavaScript для сортировки
|
||
echo '
|
||
<script>
|
||
function sortQueries(sortType) {
|
||
const table = document.getElementById("sql-queries-table");
|
||
const tbody = table.querySelector("tbody");
|
||
const rows = Array.from(tbody.querySelectorAll("tr.sql-query-row"));
|
||
|
||
// Сбрасываем классы активной сортировки у заголовков
|
||
const headers = table.querySelectorAll("th");
|
||
headers.forEach(header => {
|
||
header.innerHTML = header.innerHTML.replace(" ⬇", "").replace(" ⬆", "");
|
||
});
|
||
|
||
// Добавляем индикатор сортировки
|
||
if (sortType === "time-desc") {
|
||
headers[0].innerHTML = "Время ⬇";
|
||
} else if (sortType === "time-asc") {
|
||
headers[0].innerHTML = "Время ⬆";
|
||
}
|
||
|
||
rows.sort((a, b) => {
|
||
const timeA = parseFloat(a.querySelector("td[data-time]").getAttribute("data-time"));
|
||
const timeB = parseFloat(b.querySelector("td[data-time]").getAttribute("data-time"));
|
||
|
||
switch(sortType) {
|
||
case "time-desc":
|
||
return timeB - timeA; // Самые медленные first
|
||
case "time-asc":
|
||
return timeA - timeB; // Самые быстрые first
|
||
case "default":
|
||
return 0; // Оригинальный порядок
|
||
default:
|
||
return 0;
|
||
}
|
||
});
|
||
|
||
// Очищаем и перезаполняем tbody
|
||
while (tbody.firstChild) {
|
||
tbody.removeChild(tbody.firstChild);
|
||
}
|
||
|
||
rows.forEach(row => {
|
||
tbody.appendChild(row);
|
||
});
|
||
}
|
||
|
||
// Добавляем поиск по запросам
|
||
function addSearchFeature() {
|
||
const panel = document.getElementById("sql-debug-panel");
|
||
const searchHtml = \`
|
||
<div style="margin-bottom: 15px;">
|
||
<input type="text" id="sql-search" placeholder="Поиск по запросам..."
|
||
style="padding: 8px; width: 300px; border: 1px solid #ddd; border-radius: 3px;">
|
||
<button onclick="filterQueries()" style="padding: 8px 15px; background: #3498db; color: white; border: none; border-radius: 3px; cursor: pointer;">Поиск</button>
|
||
<button onclick="clearSearch()" style="padding: 8px 15px; background: #95a5a6; color: white; border: none; border-radius: 3px; cursor: pointer;">Очистить</button>
|
||
</div>
|
||
\`;
|
||
|
||
const controlsDiv = panel.querySelector("div");
|
||
controlsDiv.insertAdjacentHTML("afterend", searchHtml);
|
||
}
|
||
|
||
function filterQueries() {
|
||
const searchTerm = document.getElementById("sql-search").value.toLowerCase();
|
||
const rows = document.querySelectorAll("tr.sql-query-row");
|
||
|
||
rows.forEach(row => {
|
||
const queryText = row.querySelector("td:nth-child(2)").textContent.toLowerCase();
|
||
const callerText = row.querySelector("td:nth-child(3)").textContent.toLowerCase();
|
||
|
||
if (queryText.includes(searchTerm) || callerText.includes(searchTerm)) {
|
||
row.style.display = "";
|
||
} else {
|
||
row.style.display = "none";
|
||
}
|
||
});
|
||
}
|
||
|
||
function clearSearch() {
|
||
document.getElementById("sql-search").value = "";
|
||
const rows = document.querySelectorAll("tr.sql-query-row");
|
||
rows.forEach(row => {
|
||
row.style.display = "";
|
||
});
|
||
}
|
||
|
||
// Инициализируем поиск при загрузке
|
||
document.addEventListener("DOMContentLoaded", function() {
|
||
addSearchFeature();
|
||
});
|
||
</script>
|
||
';
|
||
}
|
||
|
||
|
||
// Добавляем стили и скрипты
|
||
add_action('wp_enqueue_scripts', 'add_sql_debug_styles');
|
||
|
||
function add_sql_debug_styles() {
|
||
if (!current_user_can('administrator')) {
|
||
return;
|
||
}
|
||
|
||
wp_enqueue_style('sql-debug-style', false);
|
||
echo '
|
||
<style>
|
||
#sql-debug-panel {
|
||
max-height: 600px;
|
||
overflow-y: auto;
|
||
position: fixed;
|
||
bottom: 20px;
|
||
right: 20px;
|
||
width: 90%;
|
||
max-width: 1200px;
|
||
box-shadow: 0 0 20px rgba(0,0,0,0.3);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.sql-query-row:hover {
|
||
background-color: #f8f9fa !important;
|
||
}
|
||
|
||
.sort-btn {
|
||
margin-right: 10px;
|
||
padding: 8px 15px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.sort-btn:hover {
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.sort-desc { background: #e74c3c; color: white; }
|
||
.sort-asc { background: #27ae60; color: white; }
|
||
.sort-default { background: #3498db; color: white; }
|
||
|
||
#sql-search {
|
||
padding: 8px;
|
||
width: 300px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
margin-right: 10px;
|
||
}
|
||
</style>
|
||
';
|
||
} |