Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save stingray82/8d60d8ee553befca92dc119fcd45e4b4 to your computer and use it in GitHub Desktop.

Select an option

Save stingray82/8d60d8ee553befca92dc119fcd45e4b4 to your computer and use it in GitHub Desktop.
Devkit - Addons & Mods
<?php
/**
* Deletes all transients (including site-wide transients) from the database.
* This technically didn't ever use DevKit as it was written before the option was added to devkit.
*/
add_action( 'init', function () {
if ( get_option( 'enable_transients_admin_bar', null ) === null ) {
add_option( 'enable_transients_admin_bar', 1 );
}
});
// Delete all transients
function delete_all_transients() {
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_%'");
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_site_transient_%'");
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
}
// Add Tools > Delete All Transients submenu
function add_delete_transients_menu_item() {
add_submenu_page(
'tools.php',
'Delete All Transients',
'Delete All Transients',
'manage_options',
'delete-all-transients',
'delete_all_transients_page'
);
}
add_action('admin_menu', 'add_delete_transients_menu_item');
// Settings registration
function register_delete_transients_settings() {
register_setting('delete_transients_settings_group', 'enable_transients_admin_bar');
}
add_action('admin_init', 'register_delete_transients_settings');
// Settings page content
function delete_all_transients_page() {
?>
<div class="wrap">
<h1>Delete All Transients</h1>
<form method="post" action="">
<?php wp_nonce_field('delete_all_transients_action', 'delete_all_transients_nonce'); ?>
<input type="hidden" name="delete_all_transients" value="1" />
<p>Click the button below to delete all transients from the database.</p>
<input type="submit" class="button button-primary" value="Delete All Transients" />
</form>
<hr>
<form method="post" action="options.php">
<?php
settings_fields('delete_transients_settings_group');
do_settings_sections('delete_transients_settings_group');
?>
<label>
<input type="checkbox" name="enable_transients_admin_bar" value="1" <?php checked( get_option( 'enable_transients_admin_bar', 1 ), 1 ); ?> />
Enable Admin Bar Button to Delete Transients
</label><br><br>
<?php submit_button('Save Settings'); ?>
</form>
</div>
<?php
}
// Handle form submission on settings page
function handle_delete_all_transients() {
if (isset($_POST['delete_all_transients']) && check_admin_referer('delete_all_transients_action', 'delete_all_transients_nonce')) {
delete_all_transients();
wp_redirect(admin_url('tools.php?transients-deleted=1'));
exit;
}
}
add_action('admin_init', 'handle_delete_all_transients');
// Admin notice
function display_delete_transients_success_message() {
if (isset($_GET['transients-deleted']) && $_GET['transients-deleted'] == 1) {
echo '<div class="notice notice-success is-dismissible"><p>All transients have been successfully deleted.</p></div>';
}
}
add_action('admin_notices', 'display_delete_transients_success_message');
// Add Admin Bar Button
function add_transient_clear_button_to_admin_bar($wp_admin_bar) {
if (!current_user_can('manage_options')) return;
if (!get_option('enable_transients_admin_bar', 1)) return;
$wp_admin_bar->add_node([
'id' => 'delete_transients_button',
'title' => 'Delete Transients',
'href' => wp_nonce_url(admin_url('tools.php?delete-transients-from-bar=1'), 'delete_transients_admin_bar', 'transient_bar_nonce'),
'meta' => ['title' => 'Delete all transients now']
]);
}
add_action('admin_bar_menu', 'add_transient_clear_button_to_admin_bar', 100);
// Handle Admin Bar Button Action
function handle_admin_bar_transient_deletion() {
if (isset($_GET['delete-transients-from-bar']) && current_user_can('manage_options')) {
if (check_admin_referer('delete_transients_admin_bar', 'transient_bar_nonce')) {
delete_all_transients();
$redirect_url = wp_get_referer() ? add_query_arg('transients-deleted', '1', wp_get_referer()) : admin_url('tools.php?transients-deleted=1');
wp_redirect($redirect_url);
exit;
}
}
}
add_action('admin_init', 'handle_admin_bar_transient_deletion');
// ==UserScript==
// @name WP Devkit Error Log Helper
// @namespace http://tampermonkey.net/
// @version 0.3
// @description Click-to-copy error log entries + auto reload button
// @author stingray82
// @match *://*/wp-admin/admin.php*
// @run-at document-end
// @grant GM_addStyle
// ==/UserScript==
(function () {
'use strict';
// Only run on the Devkit error log tab
if (!/page=devkit/.test(location.search) || !/tab=error-log/.test(location.search)) {
return;
}
// --- Styles for visual feedback on copy ---
GM_addStyle(`
.error-log code.tm-clickable-row {
cursor: pointer;
display: block; /* each <code> becomes its own row */
width: 100%;
padding: 0 4px;
margin: 1px 0; /* small gap between rows */
transition: background-color 0.15s ease, box-shadow 0.15s ease;
}
.error-log code.tm-copied {
box-shadow: 0 0 0 2px #4ade80;
border-radius: 4px;
background-color: rgba(74, 222, 128, 0.15);
}
`);
// Check if a <code> line is the *start* of a log entry
function isEntryHeader(codeEl) {
if (!codeEl) return false;
const text = codeEl.innerText.replace(/^\s+/, ''); // trim left
// [28-Nov-2025 ...]
return /^\[\d{2}-[A-Za-z]{3}-\d{4}/.test(text);
}
// --- Click-to-copy using event delegation ---
function initClickToCopy() {
const container = document.querySelector('.error-log');
if (!container) return;
// Give lines pointer + title
container.querySelectorAll('code').forEach(code => {
code.classList.add('tm-clickable-row');
if (!code.title) {
code.title = 'Click to copy this log entry';
}
});
// Only attach the event listener once
if (container.dataset.tmClickHandler === '1') return;
container.dataset.tmClickHandler = '1';
container.addEventListener('click', (e) => {
const clicked = e.target.closest('code');
if (!clicked || !container.contains(clicked)) return;
const allCodes = Array.from(container.querySelectorAll('code'));
const clickedIndex = allCodes.indexOf(clicked);
if (clickedIndex === -1) return;
// 1) Walk backwards from clicked to find the header of this entry
let startIdx = clickedIndex;
while (startIdx > 0 && !isEntryHeader(allCodes[startIdx])) {
startIdx--;
}
// If we never hit a header, just consider the clicked line as start
if (!isEntryHeader(allCodes[startIdx])) {
startIdx = clickedIndex;
}
// 2) From startIdx, collect lines until the *next* header (not included)
const blockLines = [];
const blockEls = [];
for (let i = startIdx; i < allCodes.length; i++) {
const el = allCodes[i];
// If this is a new header and it's not the first line, stop *before* it
if (i > startIdx && isEntryHeader(el)) {
break;
}
const lineText = el.innerText.replace(/\s+$/, ''); // trim right
blockLines.push(lineText);
blockEls.push(el);
}
const fullText = blockLines.join('\n');
copyText(fullText);
flashCopied(blockEls);
});
}
function copyText(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).catch(() => fallbackCopy(text));
} else {
fallbackCopy(text);
}
}
function fallbackCopy(text) {
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.top = '-9999px';
document.body.appendChild(ta);
ta.select();
try {
document.execCommand('copy');
} catch (e) {
console.warn('Copy failed:', e);
}
document.body.removeChild(ta);
}
function flashCopied(els) {
els.forEach(el => el.classList.add('tm-copied'));
setTimeout(() => {
els.forEach(el => el.classList.remove('tm-copied'));
}, 300);
}
// Run once on load
initClickToCopy();
// Re-run whenever the log area changes (e.g. reload button updates it)
if ('MutationObserver' in window) {
const observer = new MutationObserver(() => {
initClickToCopy();
});
observer.observe(document.body, { childList: true, subtree: true });
} else {
// Fallback: poll occasionally
setInterval(initClickToCopy, 2000);
}
// --- Auto reload button (same as previous working version) ---
let autoReloadInterval = null;
function createAutoReloadButton() {
const reloadBtn = document.querySelector('#reload-log');
if (!reloadBtn) return;
// Don’t add twice
if (document.querySelector('#tm-auto-reload-log')) return;
const autoBtn = document.createElement('button');
autoBtn.id = 'tm-auto-reload-log';
autoBtn.className = 'button-secondary';
autoBtn.textContent = 'Auto reload (off)';
autoBtn.style.marginLeft = '8px';
autoBtn.addEventListener('click', () => {
if (autoReloadInterval) {
// Turn OFF
clearInterval(autoReloadInterval);
autoReloadInterval = null;
autoBtn.textContent = 'Auto reload (off)';
} else {
// Turn ON – click once immediately, then every 10 seconds
reloadBtn.click();
autoReloadInterval = setInterval(() => {
reloadBtn.click();
}, 10000); // 10,000 ms = 10 seconds
autoBtn.textContent = 'Auto reload (10s)';
}
});
// Insert right after the existing reload button
reloadBtn.parentNode.insertBefore(autoBtn, reloadBtn.nextSibling);
}
createAutoReloadButton();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment