-
-
Save dexit/0e2fd680b0880de338ed5fcf63cb490a to your computer and use it in GitHub Desktop.
WordPress Post Inspector [SnipSnip.pro] - displays post metadata, SEO information, and WordPress data in a floating panel with admin controls and configuration options. - https://snipsnip.pro/s/884
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Title: Enhanced WordPress Post Inspector with Admin Controls [SnipSnip.pro] | |
* Description: A comprehensive debugging tool that displays post metadata, SEO information, and WordPress data in a floating panel. Features configurable position, admin settings, light/dark themes, enhanced data extraction, and security controls for developers. | |
* Version: 3.2.1 | |
* Author: Brandon Pfeiffer | |
* Last Updated: 2025-07-01 | |
* Blog URL: https://snipsnip.pro/s/884 | |
* Gist URL: https://gist.github.com/brandonjp/025592669bce65f7031a00f8b04d5c97 | |
* Code Snippets Cloud: https://codesnippets.cloud/snippet/brandonjp/WordPress-Post-541 | |
* Requirements: WordPress 5.0+, Admin user role | |
* License: GPL v2 or later | |
* | |
* Features: | |
* - Floating inspector panel with configurable position | |
* - Admin settings page with full controls | |
* - Light/dark theme support | |
* - Enhanced data extraction with multiple fallback methods | |
* - Control buttons (refresh, copy, hide) | |
* - Security and permission controls | |
* - Query parameter trigger support | |
* - Post meta data extraction and display | |
* - Mobile responsive design | |
* - Browser compatibility with fallback support | |
* | |
* Installation: Add to Code Snippets Pro and activate | |
* | |
* Changelog: | |
* 3.2.1 - Fixed compatibility issues with saved settings, ensured query parameter defaults | |
* 3.2.0 - Enhanced browser compatibility, improved data extraction, query parameter support | |
* 3.0.0 - Complete rewrite with admin controls and configuration options | |
* 2.0.0 - Added class-based architecture and security improvements | |
* 1.0.0 - Initial version with basic functionality | |
*/ | |
// Prevent direct access | |
if (!defined('ABSPATH')) { | |
exit; | |
} | |
/** | |
* WordPress Post Inspector Enhanced Class | |
*/ | |
class WP_Post_Inspector_Enhanced { | |
const VERSION = '3.2.1'; | |
const OPTION_NAME = 'wp_post_inspector_enhanced_settings'; | |
private $settings; | |
/** | |
* Constructor | |
*/ | |
public function __construct() { | |
$this->load_settings(); | |
$this->init_hooks(); | |
} | |
/** | |
* Load settings with defaults | |
*/ | |
private function load_settings() { | |
$defaults = array( | |
'enabled' => true, | |
'position' => 'bottom-left', | |
'delay' => 2000, | |
'width' => 400, | |
'height' => 500, | |
'theme' => 'light', | |
'admin_only' => true, | |
'query_param_enabled' => false, | |
'query_param_name' => 'inspect', | |
'query_param_value' => 'yes', | |
'show_sections' => array( | |
'post_info' => true, | |
'wp_data' => true, | |
'meta_tags' => true, | |
'structured_data' => true, | |
'post_meta' => true | |
) | |
); | |
// Force reset if there are database conflicts | |
$saved_settings = get_option(self::OPTION_NAME, array()); | |
// If saved settings don't have the new keys, reset to ensure compatibility | |
if (!isset($saved_settings['query_param_enabled']) || !isset($saved_settings['post_meta'])) { | |
delete_option(self::OPTION_NAME); | |
$saved_settings = array(); | |
} | |
$saved_settings = get_option(self::OPTION_NAME, array()); | |
$this->settings = wp_parse_args($saved_settings, $defaults); | |
} | |
/** | |
* Initialize WordPress hooks | |
*/ | |
private function init_hooks() { | |
// Admin hooks | |
add_action('admin_menu', array($this, 'add_admin_menu')); | |
add_action('admin_init', array($this, 'register_settings')); | |
// Frontend hooks | |
if ($this->get_setting('enabled')) { | |
add_action('wp_enqueue_scripts', array($this, 'maybe_enqueue_inspector')); | |
} | |
// AJAX hooks for post meta data | |
add_action('wp_ajax_wp_post_inspector_get_meta', array($this, 'ajax_get_post_meta')); | |
add_action('wp_ajax_nopriv_wp_post_inspector_get_meta', array($this, 'ajax_get_post_meta')); | |
} | |
/** | |
* Get setting value | |
*/ | |
private function get_setting($key, $default = null) { | |
return isset($this->settings[$key]) ? $this->settings[$key] : $default; | |
} | |
/** | |
* Check if user can view inspector | |
*/ | |
private function can_view_inspector() { | |
if (!is_user_logged_in()) { | |
return false; | |
} | |
if ($this->get_setting('admin_only')) { | |
return current_user_can('manage_options'); | |
} | |
return current_user_can('edit_posts'); | |
} | |
/** | |
* Maybe enqueue inspector on frontend | |
*/ | |
public function maybe_enqueue_inspector() { | |
// Only load on frontend | |
if (is_admin() || wp_doing_ajax()) { | |
return; | |
} | |
// Check permissions | |
if (!$this->can_view_inspector()) { | |
return; | |
} | |
// Check query parameter if enabled | |
if ($this->get_setting('query_param_enabled')) { | |
$param_name = $this->get_setting('query_param_name', 'inspect'); | |
$param_value = $this->get_setting('query_param_value', 'yes'); | |
if (!isset($_GET[$param_name]) || $_GET[$param_name] !== $param_value) { | |
return; | |
} | |
} | |
add_action('wp_footer', array($this, 'output_inspector'), 999); | |
} | |
/** | |
* Output the inspector | |
*/ | |
public function output_inspector() { | |
$position = $this->get_setting('position'); | |
$width = $this->get_setting('width'); | |
$height = $this->get_setting('height'); | |
$delay = $this->get_setting('delay'); | |
$theme = $this->get_setting('theme'); | |
$show_sections = $this->get_setting('show_sections'); | |
// Get position styles | |
$position_css = $this->get_position_css($position); | |
// Get theme colors | |
$colors = $this->get_theme_colors($theme); | |
// Convert PHP settings to JavaScript | |
$js_config = array( | |
'delay' => $delay, | |
'showSections' => $show_sections, | |
'ajaxUrl' => admin_url('admin-ajax.php'), | |
'nonce' => wp_create_nonce('wp_post_inspector_meta') | |
); | |
?> | |
<style id="wp-post-inspector-enhanced-styles"> | |
#wp-post-inspector-enhanced { | |
position: fixed; | |
<?php echo $position_css; ?> | |
width: <?php echo $width; ?>px; | |
max-height: <?php echo $height; ?>px; | |
background: <?php echo $colors['background']; ?>; | |
border: 1px solid <?php echo $colors['border']; ?>; | |
border-radius: 8px; | |
box-shadow: 0 4px 12px rgba(0,0,0,0.15); | |
z-index: 999999; | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
font-size: 12px; | |
overflow: hidden; | |
transition: all 0.3s ease; | |
opacity: 0; | |
transform: translateY(20px); | |
color: <?php echo $colors['text']; ?>; | |
} | |
#wp-post-inspector-enhanced.show { | |
opacity: 1; | |
transform: translateY(0); | |
} | |
#wp-post-inspector-enhanced.collapsed { | |
height: 40px; | |
} | |
#wp-post-inspector-enhanced-header { | |
background: <?php echo $colors['header_bg']; ?>; | |
color: <?php echo $colors['header_text']; ?>; | |
padding: 8px 12px; | |
cursor: pointer; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
user-select: none; | |
font-weight: 600; | |
} | |
#wp-post-inspector-enhanced-header:hover { | |
background: <?php echo $colors['header_hover']; ?>; | |
} | |
#wp-post-inspector-enhanced-toggle { | |
font-size: 14px; | |
font-weight: bold; | |
} | |
#wp-post-inspector-enhanced-content { | |
max-height: <?php echo ($height - 80); ?>px; | |
overflow-y: auto; | |
padding: 0; | |
} | |
#wp-post-inspector-enhanced table { | |
width: 100%; | |
border-collapse: collapse; | |
margin: 0; | |
} | |
#wp-post-inspector-enhanced th, | |
#wp-post-inspector-enhanced td { | |
padding: 6px 8px; | |
text-align: left; | |
border-bottom: 1px solid <?php echo $colors['border']; ?>; | |
word-wrap: break-word; | |
max-width: 200px; | |
} | |
#wp-post-inspector-enhanced th { | |
background: <?php echo $colors['th_bg']; ?>; | |
font-weight: 600; | |
width: 30%; | |
font-size: 11px; | |
} | |
#wp-post-inspector-enhanced td { | |
font-size: 11px; | |
font-family: monospace; | |
} | |
#wp-post-inspector-enhanced tr:hover { | |
background: <?php echo $colors['row_hover']; ?>; | |
} | |
.wp-inspector-enhanced-section { | |
background: <?php echo $colors['section_bg']; ?> !important; | |
font-weight: bold !important; | |
color: <?php echo $colors['section_text']; ?> !important; | |
} | |
.wp-inspector-enhanced-empty { | |
color: <?php echo $colors['empty_text']; ?>; | |
font-style: italic; | |
} | |
.wp-inspector-enhanced-json { | |
max-height: 100px; | |
overflow-y: auto; | |
background: <?php echo $colors['json_bg']; ?>; | |
padding: 4px; | |
border-radius: 3px; | |
white-space: pre-wrap; | |
font-size: 10px; | |
} | |
.wp-inspector-enhanced-controls { | |
padding: 8px; | |
background: <?php echo $colors['controls_bg']; ?>; | |
border-top: 1px solid <?php echo $colors['border']; ?>; | |
font-size: 10px; | |
} | |
.wp-inspector-enhanced-controls button { | |
background: <?php echo $colors['button_bg']; ?>; | |
color: <?php echo $colors['button_text']; ?>; | |
border: 1px solid <?php echo $colors['button_border']; ?>; | |
padding: 4px 8px; | |
margin-right: 4px; | |
border-radius: 3px; | |
cursor: pointer; | |
font-size: 10px; | |
} | |
.wp-inspector-enhanced-controls button:hover { | |
background: <?php echo $colors['button_hover']; ?>; | |
} | |
@media (max-width: 768px) { | |
#wp-post-inspector-enhanced { | |
width: calc(100vw - 40px) !important; | |
max-width: 350px; | |
} | |
} | |
</style> | |
<div id="wp-post-inspector-enhanced"> | |
<div id="wp-post-inspector-enhanced-header"> | |
<span>WP Post Inspector Enhanced v<?php echo self::VERSION; ?></span> | |
<span id="wp-post-inspector-enhanced-toggle">−</span> | |
</div> | |
<div id="wp-post-inspector-enhanced-content"> | |
<table> | |
<tbody id="wp-post-inspector-enhanced-table"></tbody> | |
</table> | |
<div class="wp-inspector-enhanced-controls"> | |
<button onclick="wpPostInspectorEnhanced.refresh()">Refresh</button> | |
<button onclick="wpPostInspectorEnhanced.copy()">Copy Data</button> | |
<button onclick="wpPostInspectorEnhanced.hide()">Hide</button> | |
</div> | |
</div> | |
</div> | |
<script id="wp-post-inspector-enhanced-script"> | |
(function() { | |
'use strict'; | |
var config = <?php echo json_encode($js_config); ?>; | |
var inspectorPanel = null; | |
var isCollapsed = false; | |
function initPostInspector() { | |
setTimeout(function() { | |
inspectorPanel = document.getElementById('wp-post-inspector-enhanced'); | |
if (!inspectorPanel) return; | |
setupEventListeners(); | |
populateInspectorData(); | |
showPanel(); | |
}, config.delay); | |
} | |
function setupEventListeners() { | |
var header = document.getElementById('wp-post-inspector-enhanced-header'); | |
var toggle = document.getElementById('wp-post-inspector-enhanced-toggle'); | |
if (header && toggle) { | |
header.addEventListener('click', function() { | |
isCollapsed = !isCollapsed; | |
inspectorPanel.classList.toggle('collapsed', isCollapsed); | |
toggle.textContent = isCollapsed ? '+' : '−'; | |
}); | |
} | |
} | |
function extractPostInfo() { | |
var postData = {}; | |
var bodyClasses = document.body.className; | |
// Post ID extraction | |
var postIdMatch = bodyClasses.match(/postid-(\d+)/); | |
if (postIdMatch) { | |
postData['Post ID'] = postIdMatch[1]; | |
} | |
var article = document.querySelector('article[id*="post-"]'); | |
if (article && !postData['Post ID']) { | |
var articleIdMatch = article.id.match(/post-(\d+)/); | |
if (articleIdMatch) { | |
postData['Post ID'] = articleIdMatch[1]; | |
} | |
} | |
// Post slug | |
var url = window.location.pathname; | |
var slugMatch = url.match(/\/([^\/]+)\/?$/); | |
if (slugMatch && slugMatch[1] !== '' && !slugMatch[1].match(/^\d+$/)) { | |
postData['Post Slug'] = slugMatch[1]; | |
} | |
// Post type | |
var postTypeMatch = bodyClasses.match(/single-([a-zA-Z_-]+)/); | |
if (postTypeMatch) { | |
postData['Post Type'] = postTypeMatch[1]; | |
} | |
// Title | |
var titleElement = document.querySelector('h1.entry-title, h1.post-title, .entry-header h1, article h1'); | |
if (titleElement) { | |
postData['Post Title'] = titleElement.textContent.trim(); | |
} | |
// Author | |
var authorElement = document.querySelector('.author .fn, .by-author, .entry-author, [rel="author"]'); | |
if (authorElement) { | |
postData['Author'] = authorElement.textContent.trim(); | |
} | |
// Published date | |
var dateElement = document.querySelector('time[datetime], .entry-date, .published'); | |
if (dateElement) { | |
postData['Published'] = dateElement.getAttribute('datetime') || dateElement.textContent.trim(); | |
} | |
// Categories and tags | |
var categories = []; | |
var tags = []; | |
bodyClasses.split(' ').forEach(function(className) { | |
if (className.indexOf('category-') === 0) { | |
categories.push(className.replace('category-', '')); | |
} | |
if (className.indexOf('tag-') === 0) { | |
tags.push(className.replace('tag-', '')); | |
} | |
}); | |
if (categories.length > 0) { | |
postData['Categories'] = categories.join(', '); | |
} | |
if (tags.length > 0) { | |
postData['Tags'] = tags.join(', '); | |
} | |
return postData; | |
} | |
function extractMetaTags() { | |
var metaData = {}; | |
// Open Graph tags | |
var ogTags = document.querySelectorAll('meta[property^="og:"]'); | |
for (var i = 0; i < ogTags.length; i++) { | |
var property = ogTags[i].getAttribute('property'); | |
var content = ogTags[i].getAttribute('content'); | |
if (content) { | |
metaData[property] = content; | |
} | |
} | |
// Twitter tags | |
var twitterTags = document.querySelectorAll('meta[name^="twitter:"]'); | |
for (var i = 0; i < twitterTags.length; i++) { | |
var name = twitterTags[i].getAttribute('name'); | |
var content = twitterTags[i].getAttribute('content'); | |
if (content) { | |
metaData[name] = content; | |
} | |
} | |
// Standard meta tags | |
var standardTags = ['description', 'keywords', 'author']; | |
for (var i = 0; i < standardTags.length; i++) { | |
var tag = document.querySelector('meta[name="' + standardTags[i] + '"]'); | |
if (tag && tag.getAttribute('content')) { | |
metaData[standardTags[i]] = tag.getAttribute('content'); | |
} | |
} | |
return metaData; | |
} | |
function extractStructuredData() { | |
var structuredData = {}; | |
var jsonLdScripts = document.querySelectorAll('script[type="application/ld+json"]'); | |
for (var i = 0; i < jsonLdScripts.length; i++) { | |
try { | |
var data = JSON.parse(jsonLdScripts[i].textContent); | |
structuredData['JSON-LD ' + (i + 1)] = JSON.stringify(data, null, 2); | |
} catch (e) { | |
structuredData['JSON-LD ' + (i + 1)] = 'Invalid JSON'; | |
} | |
} | |
return structuredData; | |
} | |
function extractWPSpecificData() { | |
var wpData = {}; | |
wpData['Current URL'] = window.location.href; | |
wpData['User Agent'] = navigator.userAgent; | |
wpData['Viewport'] = window.innerWidth + 'x' + window.innerHeight; | |
var restLink = document.querySelector('link[rel="https://api.w.org/"]'); | |
if (restLink) { | |
wpData['REST API'] = restLink.getAttribute('href'); | |
} | |
var commentPostId = document.querySelector('input[name="comment_post_ID"]'); | |
if (commentPostId) { | |
wpData['Comment Post ID'] = commentPostId.value; | |
} | |
var wpVersion = document.querySelector('meta[name="generator"][content*="WordPress"]'); | |
if (wpVersion) { | |
wpData['WP Version'] = wpVersion.getAttribute('content'); | |
} | |
wpData['Body Classes'] = document.body.className; | |
return wpData; | |
} | |
function extractPostMeta(callback) { | |
// Extract post ID first | |
var postId = null; | |
var bodyClasses = document.body.className; | |
var postIdMatch = bodyClasses.match(/postid-(\d+)/); | |
if (postIdMatch) { | |
postId = postIdMatch[1]; | |
} | |
if (!postId) { | |
var article = document.querySelector('article[id*="post-"]'); | |
if (article) { | |
var articleIdMatch = article.id.match(/post-(\d+)/); | |
if (articleIdMatch) { | |
postId = articleIdMatch[1]; | |
} | |
} | |
} | |
if (!postId) { | |
callback({}); | |
return; | |
} | |
// Make AJAX request to get post meta | |
var xhr = new XMLHttpRequest(); | |
xhr.open('POST', config.ajaxUrl, true); | |
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState === 4) { | |
if (xhr.status === 200) { | |
try { | |
var response = JSON.parse(xhr.responseText); | |
if (response.success) { | |
callback(response.data); | |
} else { | |
callback({}); | |
} | |
} catch (e) { | |
callback({}); | |
} | |
} else { | |
callback({}); | |
} | |
} | |
}; | |
var params = 'action=wp_post_inspector_get_meta&post_id=' + postId + '&nonce=' + config.nonce; | |
xhr.send(params); | |
} | |
function populateInspectorData() { | |
var tableBody = document.getElementById('wp-post-inspector-enhanced-table'); | |
if (!tableBody) return; | |
tableBody.innerHTML = ''; | |
// Add loading indicator for post meta if enabled | |
if (config.showSections['post_meta']) { | |
var loadingRow = document.createElement('tr'); | |
var loadingCell = document.createElement('td'); | |
loadingCell.colSpan = 2; | |
loadingCell.className = 'wp-inspector-enhanced-section'; | |
loadingCell.textContent = 'Post Meta Data (Loading...)'; | |
loadingRow.appendChild(loadingCell); | |
tableBody.appendChild(loadingRow); | |
} | |
var sections = [ | |
{ key: 'post_info', title: 'Post Information', data: extractPostInfo() }, | |
{ key: 'wp_data', title: 'WordPress Data', data: extractWPSpecificData() }, | |
{ key: 'meta_tags', title: 'Meta Tags', data: extractMetaTags() }, | |
{ key: 'structured_data', title: 'Structured Data', data: extractStructuredData() } | |
]; | |
for (var i = 0; i < sections.length; i++) { | |
var section = sections[i]; | |
if (config.showSections[section.key] && Object.keys(section.data).length > 0) { | |
addSectionToTable(tableBody, section.title, section.data); | |
} | |
} | |
// Load post meta data asynchronously | |
if (config.showSections['post_meta']) { | |
extractPostMeta(function(postMetaData) { | |
// Remove loading indicator | |
var loadingRows = tableBody.querySelectorAll('tr'); | |
for (var i = 0; i < loadingRows.length; i++) { | |
var cell = loadingRows[i].querySelector('td'); | |
if (cell && cell.textContent.indexOf('Loading...') !== -1) { | |
tableBody.removeChild(loadingRows[i]); | |
break; | |
} | |
} | |
// Add post meta section | |
if (Object.keys(postMetaData).length > 0) { | |
addSectionToTable(tableBody, 'Post Meta Data', postMetaData); | |
} | |
// Check if we need the no data message | |
checkNoDataMessage(); | |
}); | |
} else { | |
// Check if we need the no data message | |
checkNoDataMessage(); | |
} | |
function checkNoDataMessage() { | |
if (tableBody.children.length === 0) { | |
var noDataRow = document.createElement('tr'); | |
var noDataCell = document.createElement('td'); | |
noDataCell.colSpan = 2; | |
noDataCell.className = 'wp-inspector-enhanced-empty'; | |
noDataCell.textContent = 'No data found or all sections disabled'; | |
noDataRow.appendChild(noDataCell); | |
tableBody.appendChild(noDataRow); | |
} | |
} | |
} | |
function addSectionToTable(tableBody, title, data) { | |
// Section header | |
var sectionRow = document.createElement('tr'); | |
var sectionCell = document.createElement('td'); | |
sectionCell.colSpan = 2; | |
sectionCell.className = 'wp-inspector-enhanced-section'; | |
sectionCell.textContent = title; | |
sectionRow.appendChild(sectionCell); | |
tableBody.appendChild(sectionRow); | |
// Data rows | |
var keys = Object.keys(data); | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
var value = data[key]; | |
var row = document.createElement('tr'); | |
var keyCell = document.createElement('th'); | |
var valueCell = document.createElement('td'); | |
keyCell.textContent = key; | |
if (key.indexOf('JSON-LD') === 0 && typeof value === 'string' && value.length > 100) { | |
var jsonDiv = document.createElement('div'); | |
jsonDiv.className = 'wp-inspector-enhanced-json'; | |
jsonDiv.textContent = value; | |
valueCell.appendChild(jsonDiv); | |
} else { | |
valueCell.textContent = value || 'N/A'; | |
if (!value) { | |
valueCell.className = 'wp-inspector-enhanced-empty'; | |
} | |
} | |
row.appendChild(keyCell); | |
row.appendChild(valueCell); | |
tableBody.appendChild(row); | |
} | |
} | |
function showPanel() { | |
if (inspectorPanel) { | |
inspectorPanel.classList.add('show'); | |
} | |
} | |
function hidePanel() { | |
if (inspectorPanel) { | |
inspectorPanel.style.display = 'none'; | |
} | |
} | |
function copyData() { | |
var sections = [ | |
{ title: 'Post Information', data: extractPostInfo() }, | |
{ title: 'WordPress Data', data: extractWPSpecificData() }, | |
{ title: 'Meta Tags', data: extractMetaTags() }, | |
{ title: 'Structured Data', data: extractStructuredData() } | |
]; | |
// Add post meta data if available | |
if (config.showSections['post_meta']) { | |
extractPostMeta(function(postMetaData) { | |
if (Object.keys(postMetaData).length > 0) { | |
sections.push({ title: 'Post Meta Data', data: postMetaData }); | |
} | |
performCopy(sections); | |
}); | |
return; | |
} | |
performCopy(sections); | |
} | |
function performCopy(sections) { | |
var copyText = 'WordPress Post Inspector Enhanced Data\n'; | |
copyText += '=====================================\n\n'; | |
for (var i = 0; i < sections.length; i++) { | |
var section = sections[i]; | |
var keys = Object.keys(section.data); | |
if (keys.length > 0) { | |
copyText += section.title + ':\n'; | |
copyText += Array(section.title.length + 2).join('-') + '\n'; | |
for (var j = 0; j < keys.length; j++) { | |
copyText += keys[j] + ': ' + section.data[keys[j]] + '\n'; | |
} | |
copyText += '\n'; | |
} | |
} | |
if (navigator.clipboard && navigator.clipboard.writeText) { | |
navigator.clipboard.writeText(copyText).then(function() { | |
alert('Inspector data copied to clipboard!'); | |
}).catch(function() { | |
alert('Failed to copy data to clipboard'); | |
}); | |
} else { | |
// Fallback for older browsers | |
var textArea = document.createElement('textarea'); | |
textArea.value = copyText; | |
document.body.appendChild(textArea); | |
textArea.select(); | |
try { | |
document.execCommand('copy'); | |
alert('Inspector data copied to clipboard!'); | |
} catch (err) { | |
alert('Failed to copy data to clipboard'); | |
} | |
document.body.removeChild(textArea); | |
} | |
} | |
// Global API | |
window.wpPostInspectorEnhanced = { | |
refresh: populateInspectorData, | |
hide: hidePanel, | |
copy: copyData, | |
show: showPanel | |
}; | |
// Initialize | |
if (document.readyState === 'loading') { | |
document.addEventListener('DOMContentLoaded', initPostInspector); | |
} else { | |
initPostInspector(); | |
} | |
})(); | |
</script> | |
<?php | |
} | |
/** | |
* Get position CSS | |
*/ | |
private function get_position_css($position) { | |
switch ($position) { | |
case 'top-left': | |
return 'top: 20px; left: 20px;'; | |
case 'top-right': | |
return 'top: 20px; right: 20px;'; | |
case 'bottom-right': | |
return 'bottom: 20px; right: 20px;'; | |
case 'bottom-left': | |
default: | |
return 'bottom: 20px; left: 20px;'; | |
} | |
} | |
/** | |
* Get theme colors | |
*/ | |
private function get_theme_colors($theme) { | |
$colors = array( | |
'light' => array( | |
'background' => '#fff', | |
'text' => '#333', | |
'border' => '#ccc', | |
'header_bg' => '#23282d', | |
'header_text' => '#fff', | |
'header_hover' => '#32373c', | |
'th_bg' => '#f8f9fa', | |
'row_hover' => '#f0f8ff', | |
'section_bg' => '#e8f4f8', | |
'section_text' => '#0073aa', | |
'empty_text' => '#999', | |
'json_bg' => '#f4f4f4', | |
'controls_bg' => '#f8f9fa', | |
'button_bg' => '#0073aa', | |
'button_text' => '#fff', | |
'button_border' => '#0073aa', | |
'button_hover' => '#005a87' | |
), | |
'dark' => array( | |
'background' => '#1e1e1e', | |
'text' => '#e0e0e0', | |
'border' => '#444', | |
'header_bg' => '#0073aa', | |
'header_text' => '#fff', | |
'header_hover' => '#005a87', | |
'th_bg' => '#2a2a2a', | |
'row_hover' => '#2a2a2a', | |
'section_bg' => '#0073aa', | |
'section_text' => '#fff', | |
'empty_text' => '#888', | |
'json_bg' => '#2a2a2a', | |
'controls_bg' => '#2a2a2a', | |
'button_bg' => '#0073aa', | |
'button_text' => '#fff', | |
'button_border' => '#0073aa', | |
'button_hover' => '#005a87' | |
) | |
); | |
return isset($colors[$theme]) ? $colors[$theme] : $colors['light']; | |
} | |
/** | |
* AJAX handler to get post meta data | |
*/ | |
public function ajax_get_post_meta() { | |
// Verify nonce | |
if (!wp_verify_nonce($_POST['nonce'], 'wp_post_inspector_meta')) { | |
wp_send_json_error('Invalid nonce'); | |
return; | |
} | |
// Check permissions | |
if (!$this->can_view_inspector()) { | |
wp_send_json_error('Insufficient permissions'); | |
return; | |
} | |
$post_id = intval($_POST['post_id']); | |
if (!$post_id || !get_post($post_id)) { | |
wp_send_json_error('Invalid post ID'); | |
return; | |
} | |
// Get all post meta | |
$post_meta = get_post_meta($post_id); | |
$filtered_meta = array(); | |
// Filter and format meta data | |
foreach ($post_meta as $key => $values) { | |
// Skip private meta keys (starting with _) unless they're common ones | |
if (strpos($key, '_') === 0) { | |
$common_private_keys = array( | |
'_edit_last', | |
'_edit_lock', | |
'_wp_page_template', | |
'_thumbnail_id', | |
'_wp_attachment_metadata', | |
'_wp_attached_file' | |
); | |
if (!in_array($key, $common_private_keys)) { | |
continue; | |
} | |
} | |
// Handle single vs multiple values | |
if (count($values) === 1) { | |
$value = $values[0]; | |
// Try to unserialize if it looks like serialized data | |
if (is_serialized($value)) { | |
$unserialized = maybe_unserialize($value); | |
if (is_array($unserialized) || is_object($unserialized)) { | |
$value = json_encode($unserialized, JSON_PRETTY_PRINT); | |
} | |
} | |
$filtered_meta[$key] = $value; | |
} else { | |
$filtered_meta[$key] = implode(', ', $values); | |
} | |
} | |
// Limit output if too many meta keys | |
if (count($filtered_meta) > 50) { | |
$filtered_meta = array_slice($filtered_meta, 0, 50, true); | |
$filtered_meta['_truncated'] = '... (' . (count($post_meta) - 50) . ' more meta keys not shown)'; | |
} | |
wp_send_json_success($filtered_meta); | |
} | |
/** | |
* Add admin menu | |
*/ | |
public function add_admin_menu() { | |
add_options_page( | |
'Post Inspector Enhanced Settings', | |
'Post Inspector Enhanced', | |
'manage_options', | |
'wp-post-inspector-enhanced', | |
array($this, 'admin_page') | |
); | |
} | |
/** | |
* Register settings | |
*/ | |
public function register_settings() { | |
register_setting('wp_post_inspector_enhanced_settings', self::OPTION_NAME); | |
} | |
/** | |
* Admin page | |
*/ | |
public function admin_page() { | |
if (!current_user_can('manage_options')) { | |
wp_die(__('You do not have sufficient permissions to access this page.')); | |
} | |
// Handle form submission | |
if (isset($_POST['submit'])) { | |
$new_settings = array(); | |
$new_settings['enabled'] = isset($_POST[self::OPTION_NAME]['enabled']); | |
$new_settings['position'] = sanitize_text_field($_POST[self::OPTION_NAME]['position']); | |
$new_settings['delay'] = intval($_POST[self::OPTION_NAME]['delay']); | |
$new_settings['width'] = intval($_POST[self::OPTION_NAME]['width']); | |
$new_settings['height'] = intval($_POST[self::OPTION_NAME]['height']); | |
$new_settings['theme'] = sanitize_text_field($_POST[self::OPTION_NAME]['theme']); | |
$new_settings['admin_only'] = isset($_POST[self::OPTION_NAME]['admin_only']); | |
$new_settings['query_param_enabled'] = isset($_POST[self::OPTION_NAME]['query_param_enabled']); | |
$new_settings['query_param_name'] = sanitize_text_field($_POST[self::OPTION_NAME]['query_param_name']); | |
$new_settings['query_param_value'] = sanitize_text_field($_POST[self::OPTION_NAME]['query_param_value']); | |
$new_settings['show_sections'] = array( | |
'post_info' => isset($_POST[self::OPTION_NAME]['show_sections']['post_info']), | |
'wp_data' => isset($_POST[self::OPTION_NAME]['show_sections']['wp_data']), | |
'meta_tags' => isset($_POST[self::OPTION_NAME]['show_sections']['meta_tags']), | |
'structured_data' => isset($_POST[self::OPTION_NAME]['show_sections']['structured_data']), | |
'post_meta' => isset($_POST[self::OPTION_NAME]['show_sections']['post_meta']) | |
); | |
update_option(self::OPTION_NAME, $new_settings); | |
$this->settings = $new_settings; | |
echo '<div class="notice notice-success is-dismissible"><p>Settings saved successfully!</p></div>'; | |
} | |
$settings = $this->settings; | |
?> | |
<div class="wrap"> | |
<h1>WordPress Post Inspector Enhanced Settings</h1> | |
<form method="post" action=""> | |
<?php wp_nonce_field('update-options'); ?> | |
<table class="form-table"> | |
<tr> | |
<th scope="row">Enable Inspector</th> | |
<td> | |
<label for="enabled"> | |
<input type="checkbox" id="enabled" name="<?php echo self::OPTION_NAME; ?>[enabled]" value="1" <?php checked($settings['enabled'], true); ?> /> | |
Enable the post inspector on frontend pages | |
</label> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Position</th> | |
<td> | |
<select name="<?php echo self::OPTION_NAME; ?>[position]"> | |
<option value="bottom-left" <?php selected($settings['position'], 'bottom-left'); ?>>Bottom Left</option> | |
<option value="bottom-right" <?php selected($settings['position'], 'bottom-right'); ?>>Bottom Right</option> | |
<option value="top-left" <?php selected($settings['position'], 'top-left'); ?>>Top Left</option> | |
<option value="top-right" <?php selected($settings['position'], 'top-right'); ?>>Top Right</option> | |
</select> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Display Delay (ms)</th> | |
<td> | |
<input type="number" name="<?php echo self::OPTION_NAME; ?>[delay]" value="<?php echo $settings['delay']; ?>" min="0" max="10000" step="100" /> | |
<p class="description">Delay before inspector appears (in milliseconds)</p> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Panel Width (px)</th> | |
<td> | |
<input type="number" name="<?php echo self::OPTION_NAME; ?>[width]" value="<?php echo $settings['width']; ?>" min="300" max="800" step="10" /> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Panel Height (px)</th> | |
<td> | |
<input type="number" name="<?php echo self::OPTION_NAME; ?>[height]" value="<?php echo $settings['height']; ?>" min="300" max="800" step="10" /> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Theme</th> | |
<td> | |
<select name="<?php echo self::OPTION_NAME; ?>[theme]"> | |
<option value="light" <?php selected($settings['theme'], 'light'); ?>>Light Theme</option> | |
<option value="dark" <?php selected($settings['theme'], 'dark'); ?>>Dark Theme</option> | |
</select> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Access Control</th> | |
<td> | |
<label for="admin_only"> | |
<input type="checkbox" id="admin_only" name="<?php echo self::OPTION_NAME; ?>[admin_only]" value="1" <?php checked($settings['admin_only'], true); ?> /> | |
Only show to administrators | |
</label> | |
<p class="description">If unchecked, will show to any user who can edit posts</p> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Query Parameter Trigger</th> | |
<td> | |
<label for="query_param_enabled"> | |
<input type="checkbox" id="query_param_enabled" name="<?php echo self::OPTION_NAME; ?>[query_param_enabled]" value="1" <?php checked($settings['query_param_enabled'], true); ?> /> | |
Only show inspector when specific query parameter is present | |
</label> | |
<p class="description">When enabled, inspector will only appear when the URL contains the specified parameter</p> | |
<br> | |
<label for="query_param_name">Parameter Name:</label> | |
<input type="text" id="query_param_name" name="<?php echo self::OPTION_NAME; ?>[query_param_name]" value="<?php echo esc_attr($settings['query_param_name']); ?>" placeholder="inspect" style="width: 150px;" /> | |
<br><br> | |
<label for="query_param_value">Parameter Value:</label> | |
<input type="text" id="query_param_value" name="<?php echo self::OPTION_NAME; ?>[query_param_value]" value="<?php echo esc_attr($settings['query_param_value']); ?>" placeholder="yes" style="width: 150px;" /> | |
<p class="description">Example: If name is "inspect" and value is "yes", use URL like: <code>yoursite.com/page/?inspect=yes</code></p> | |
</td> | |
</tr> | |
<tr> | |
<th scope="row">Sections to Display</th> | |
<td> | |
<fieldset> | |
<label for="show_post_info"> | |
<input type="checkbox" id="show_post_info" name="<?php echo self::OPTION_NAME; ?>[show_sections][post_info]" value="1" <?php checked($settings['show_sections']['post_info'], true); ?> /> | |
Post Information | |
</label><br> | |
<label for="show_wp_data"> | |
<input type="checkbox" id="show_wp_data" name="<?php echo self::OPTION_NAME; ?>[show_sections][wp_data]" value="1" <?php checked($settings['show_sections']['wp_data'], true); ?> /> | |
WordPress Data | |
</label><br> | |
<label for="show_meta_tags"> | |
<input type="checkbox" id="show_meta_tags" name="<?php echo self::OPTION_NAME; ?>[show_sections][meta_tags]" value="1" <?php checked($settings['show_sections']['meta_tags'], true); ?> /> | |
Meta Tags | |
</label><br> | |
<label for="show_structured_data"> | |
<input type="checkbox" id="show_structured_data" name="<?php echo self::OPTION_NAME; ?>[show_sections][structured_data]" value="1" <?php checked($settings['show_sections']['structured_data'], true); ?> /> | |
Structured Data | |
</label><br> | |
<label for="show_post_meta"> | |
<input type="checkbox" id="show_post_meta" name="<?php echo self::OPTION_NAME; ?>[show_sections][post_meta]" value="1" <?php checked($settings['show_sections']['post_meta'], true); ?> /> | |
Post Meta Data | |
</label> | |
</fieldset> | |
</td> | |
</tr> | |
</table> | |
<p class="submit"> | |
<input type="submit" name="submit" id="submit" class="button-primary" value="Save Changes" /> | |
</p> | |
</form> | |
<div class="card" style="margin-top: 20px;"> | |
<h2>Current Status</h2> | |
<p><strong>Inspector Status:</strong> | |
<span style="color: <?php echo $settings['enabled'] ? '#00a32a' : '#d63638'; ?>;"> | |
<?php echo $settings['enabled'] ? 'Active' : 'Disabled'; ?> | |
</span> | |
</p> | |
<p><strong>Access Level:</strong> <?php echo $settings['admin_only'] ? 'Administrators Only' : 'All Users Who Can Edit Posts'; ?></p> | |
<p><strong>Query Parameter:</strong> <?php echo $settings['query_param_enabled'] ? 'Enabled (?'.$settings['query_param_name'].'='.$settings['query_param_value'].')' : 'Disabled (Always show)'; ?></p> | |
<p><strong>Active Sections:</strong> <?php echo count(array_filter($settings['show_sections'])); ?> of 5 sections enabled</p> | |
</div> | |
</div> | |
<?php | |
} | |
} | |
// Initialize the plugin | |
new WP_Post_Inspector_Enhanced(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment