Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dexit/0e2fd680b0880de338ed5fcf63cb490a to your computer and use it in GitHub Desktop.
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
<?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