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>
|
|||
|
|
';
|
|||
|
|
}
|