Changeset 3289104
- Timestamp:
- 05/07/2025 11:43:22 AM (10 months ago)
- Location:
- structure-viewer
- Files:
-
- 12 added
- 7 edited
-
assets/screenshot-2.jpg (modified) (previous)
-
assets/screenshot-3.jpg (modified) (previous)
-
tags/1.1 (added)
-
tags/1.1/assets (added)
-
tags/1.1/assets/css (added)
-
tags/1.1/assets/css/sv-styles.css (added)
-
tags/1.1/assets/js (added)
-
tags/1.1/assets/js/sv-scripts.js (added)
-
tags/1.1/includes (added)
-
tags/1.1/includes/admin.php (added)
-
tags/1.1/includes/helpers.php (added)
-
tags/1.1/includes/scanner.php (added)
-
tags/1.1/readme.txt (added)
-
tags/1.1/structure-viewer.php (added)
-
trunk/assets/js/sv-scripts.js (modified) (1 diff)
-
trunk/includes/admin.php (modified) (3 diffs)
-
trunk/includes/scanner.php (modified) (6 diffs)
-
trunk/readme.txt (modified) (5 diffs)
-
trunk/structure-viewer.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
structure-viewer/trunk/assets/js/sv-scripts.js
r3286634 r3289104 56 56 } 57 57 }); 58 59 // Export structure as text file 60 $('.sv-container').on('click', '.sv-export', function(e) { 61 e.preventDefault(); 62 var $button = $(this); 63 var item = $button.data('item'); 64 var type = $button.data('type'); 65 66 $.ajax({ 67 url: ajaxurl, 68 type: 'POST', 69 data: { 70 action: 'structureviewer_export', 71 nonce: structureviewerSettings.nonce, 72 item: item, 73 type: type 74 }, 75 success: function(response) { 76 if (response.success) { 77 var blob = new Blob([response.data.data], { type: 'text/plain' }); 78 var url = window.URL.createObjectURL(blob); 79 var a = document.createElement('a'); 80 a.href = url; 81 a.download = response.data.filename; 82 document.body.appendChild(a); 83 a.click(); 84 window.URL.revokeObjectURL(url); 85 a.remove(); 86 } else { 87 alert('Export failed: ' + response.data); 88 } 89 }, 90 error: function() { 91 alert('Export failed: Server error.'); 92 } 93 }); 94 }); 58 95 }); 59 96 })(jQuery); -
structure-viewer/trunk/includes/admin.php
r3286634 r3289104 19 19 // Render the admin page 20 20 function structureviewer_admin_page() { 21 // Check user capabilities22 21 if (!current_user_can('manage_options')) { 23 22 wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'structure-viewer')); 24 23 } 25 24 26 // Add nonce verification for form27 25 if (!isset($_GET['sv_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['sv_nonce'])), 'sv_form_action')) { 28 $type = 'plugin'; // Default to plugin if nonce fails26 $type = 'plugin'; 29 27 $item = ''; 30 28 } else { 31 // Sanitize GET parameters32 29 $type = isset($_GET['psv_type']) ? sanitize_text_field(wp_unslash($_GET['psv_type'])) : 'plugin'; 33 30 $item = isset($_GET['psv_item']) ? sanitize_text_field(wp_unslash($_GET['psv_item'])) : ''; 34 31 } 35 32 36 // Validate type37 33 if (!in_array($type, ['plugin', 'theme'], true)) { 38 $type = 'plugin'; // Default to plugin if invalid34 $type = 'plugin'; 39 35 } 40 36 ?> … … 86 82 jQuery(document).ready(function($) { 87 83 $('#sv-type').on('change', function() { 88 $('#sv-item').val(''); // Reset item selection89 this.form.submit(); // Submit form to reload page84 $('#sv-item').val(''); 85 this.form.submit(); 90 86 }); 91 87 }); … … 95 91 <?php 96 92 } 97 ?> -
structure-viewer/trunk/includes/scanner.php
r3286634 r3289104 17 17 if ($selected_item) { 18 18 $item_path = realpath($items_dir . '/' . $selected_item); 19 // Ensure the path is within the allowed directory20 19 if ($item_path === false || strpos($item_path, realpath($items_dir)) !== 0 || !is_dir($item_path)) { 21 20 echo '<p>' . esc_html__('No plugins or themes found or invalid selection.', 'structure-viewer') . '</p>'; … … 42 41 $tree_class = $selected_item ? 'sv-tree-' . esc_attr(sanitize_html_class($item_folder)) : ''; 43 42 $heading_class = $selected_item ? 'sv-plugin-heading' : ''; 44 43 45 44 if ($selected_item) { 46 45 echo '<div class="sv-plugin-heading">'; … … 48 47 echo '<div class="sv-controls" data-tree-class="' . esc_attr($tree_class) . '">'; 49 48 echo '<button class="button sv-expand-all">' . esc_html__('Expand All', 'structure-viewer') . '</button> '; 50 echo '<button class="button sv-collapse-all">' . esc_html__('Collapse', 'structure-viewer') . '</button>'; 49 echo '<button class="button sv-collapse-all">' . esc_html__('Collapse', 'structure-viewer') . '</button> '; 50 echo '<button class="button sv-export" data-item="' . esc_attr($item_folder) . '" data-type="' . esc_attr($type) . '">' . esc_html__('Export', 'structure-viewer') . '</button>'; 51 51 echo '</div>'; 52 52 echo '</div>'; … … 54 54 echo '<h1 class="' . esc_attr($heading_class) . '">' . esc_html($item_name) . ' (' . ($type === 'plugin' ? esc_html__('Plugin', 'structure-viewer') : esc_html__('Theme', 'structure-viewer')) . ')</h1>'; 55 55 } 56 56 57 57 echo '<ul class="sv-tree' . ($tree_class ? ' ' . esc_attr($tree_class) : '') . '">'; 58 58 structureviewer_scan_directory($item_path, $item_path, 0, $item_folder, $type); … … 62 62 } 63 63 64 // Function to build structure as a text string mimicking the tree view 65 function structureviewer_build_structure_text($base_path, $current_path, $depth = 0, $item_folder = '', $type = 'plugin') { 66 $base_path = realpath($base_path); 67 $current_path = realpath($current_path); 68 if ($base_path === false || $current_path === false || strpos($current_path, $base_path) !== 0) { 69 return ''; 70 } 71 72 $items = glob($current_path . '/*'); 73 if (empty($items)) { 74 return ''; 75 } 76 77 $structure = ''; 78 $folders = []; 79 $files = []; 80 foreach ($items as $item) { 81 if (is_dir($item)) { 82 $folders[] = $item; 83 } else { 84 $files[] = $item; 85 } 86 } 87 88 sort($folders); 89 sort($files); 90 $items = array_merge($folders, $files); 91 92 foreach ($items as $item) { 93 $item = realpath($item); 94 if ($item === false || strpos($item, $base_path) !== 0) { 95 continue; 96 } 97 98 $item_name = basename($item); 99 $is_dir = is_dir($item); 100 101 // Add indentation and prefix 102 $indent = str_repeat(' ', $depth); 103 $prefix = $depth > 0 ? '- ' : ''; 104 $structure .= $indent . $prefix . $item_name . "\n"; 105 106 if ($is_dir) { 107 $structure .= structureviewer_build_structure_text($base_path, $item, $depth + 1, $item_folder, $type); 108 } 109 } 110 111 return $structure; 112 } 113 114 // AJAX handler for exporting structure as text 115 add_action('wp_ajax_structureviewer_export', 'structureviewer_export_structure'); 116 function structureviewer_export_structure() { 117 check_ajax_referer(STRUCTUREVIEWER_NONCE, 'nonce'); 118 119 $type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : 'plugin'; 120 $item = isset($_POST['item']) ? structureviewer_sanitize_item_name($_POST['item']) : ''; 121 122 if (!in_array($type, ['plugin', 'theme'], true) || empty($item)) { 123 wp_send_json_error('Invalid parameters.'); 124 } 125 126 $items_dir = ($type === 'plugin') ? WP_PLUGIN_DIR : get_theme_root(); 127 $item_path = realpath($items_dir . '/' . $item); 128 129 if ($item_path === false || strpos($item_path, realpath($items_dir)) !== 0 || !is_dir($item_path)) { 130 wp_send_json_error('Invalid item path.'); 131 } 132 133 $item_data_list = ($type === 'plugin') ? structureviewer_get_plugin_data_list([$item_path]) : structureviewer_get_theme_data_list([$item_path]); 134 $item_folder = basename($item_path); 135 $item_name = isset($item_data_list[$item_folder]['Name']) ? $item_data_list[$item_folder]['Name'] : $item_folder; 136 137 // Build the text structure 138 $structure_text = $item_name . ' (' . ($type === 'plugin' ? 'Plugin' : 'Theme') . ")\n"; 139 $structure_text .= structureviewer_build_structure_text($item_path, $item_path, 0, $item_folder, $type); 140 141 wp_send_json_success([ 142 'filename' => 'structure-' . sanitize_file_name($item_name) . '.txt', 143 'data' => $structure_text 144 ]); 145 } 146 64 147 // Recursively scan directory and display structure 65 148 function structureviewer_scan_directory($base_path, $current_path, $depth = 0, $item_folder = '', $type = 'plugin') { 66 // Validate paths to prevent directory traversal67 149 $base_path = realpath($base_path); 68 150 $current_path = realpath($current_path); … … 128 210 return ''; 129 211 } 130 // Remove any path separators or relative paths131 212 $item_name = str_replace(['/', '\\', '..', '.'], '', $item_name); 132 213 return sanitize_text_field($item_name); -
structure-viewer/trunk/readme.txt
r3286634 r3289104 4 4 Requires at least: 5.0 5 5 Tested up to: 6.8.1 6 Stable tag: 1. 06 Stable tag: 1.1 7 7 Requires PHP: 7.0 8 8 License: GPLv2 or later … … 15 15 == Description == 16 16 17 Structure Viewer is a lightweight developer tool for WordPress that lets you explore the file and folder structure of installed plugins and themes directly from the admin dashboard. Featuring an intuitive, tree-like view with expandable folders and clickable file links, it’s perfect for developers and site admins looking to debug, audit, or understand the organization of WordPress extensions. Use it to export structures a nd share with AI tools like Grok or ChatGPT—enabling AI to analyze plugin/theme layouts (e.g., WooCommerce) and assist with precise customizations, such as modifying key files like `includes/class-wc-cart.php`. Secure, optimized, and accessible under Tools > Structure Viewer, this plugin simplifies development workflows. Developed by Blincks.17 Structure Viewer is a lightweight developer tool for WordPress that lets you explore the file and folder structure of installed plugins and themes directly from the admin dashboard. Featuring an intuitive, tree-like view with expandable folders and clickable file links, it’s perfect for developers and site admins looking to debug, audit, or understand the organization of WordPress extensions. Use it to export structures as a text file and share with AI tools like Grok or ChatGPT—enabling AI to analyze plugin/theme layouts (e.g., WooCommerce) and assist with precise customizations, such as modifying key files like `includes/class-wc-cart.php`. Secure, optimized, and accessible under Tools > Structure Viewer, this plugin simplifies development workflows. Developed by Blincks. 18 18 19 19 ### Use Cases: … … 21 21 - **Learning Plugin Architecture**: Explore the file organization of complex plugins like Elementor to understand their structure, aiding in faster learning and custom development. 22 22 - **Auditing for Security**: Review the file structure of a third-party theme to check for suspicious files or directories, ensuring no malicious code is present. 23 - **AI-Assisted Customization**: Export a plugin’s structure (e.g., Yoast SEO) a nd provide it to an AI tool to analyze files like `includes/class-yoast.php`, enabling tailored modifications such as tweaking SEO metadata handling.23 - **AI-Assisted Customization**: Export a plugin’s structure (e.g., Yoast SEO) as a text file and provide it to an AI tool to analyze files like `includes/class-yoast.php`, enabling tailored modifications such as tweaking SEO metadata handling. 24 24 - **Documentation and Collaboration**: Share the folder structure of a custom theme with a team to streamline collaborative development or document its organization for future reference. 25 25 … … 59 59 Yes, Structure Viewer includes security measures such as input validation, output escaping, directory traversal prevention, and proper capability checks to ensure only authorized users can access the tool. 60 60 61 = How do I export the structure? = 62 When viewing a specific plugin or theme, click the "Export" button to download its structure as a text file, which can be shared or analyzed further. 63 61 64 == Changelog == 65 66 = 1.1 = 67 * Added export functionality to download the structure as a text file. 62 68 63 69 = 1.0 = … … 67 73 == Upgrade Notice == 68 74 75 = 1.1 = 76 This update adds the ability to export the file structure as a text file, making it easier to share or analyze with other tools. 77 69 78 == Additional Information == 70 79 -
structure-viewer/trunk/structure-viewer.php
r3286634 r3289104 3 3 Plugin Name: Structure Viewer 4 4 Description: Displays the file and folder structure of installed WordPress plugins and themes. Developed by Blincks. 5 Version: 1. 05 Version: 1.1 6 6 Author: Blincks 7 7 Author URI: https://www.blincks.com … … 36 36 $css_version = file_exists($css_path) ? filemtime($css_path) : '2.0'; 37 37 wp_enqueue_style( 38 'structureviewer-styles', // Updated handle with prefix38 'structureviewer-styles', 39 39 STRUCTUREVIEWER_PLUGIN_URL . 'assets/css/sv-styles.css', 40 40 [], … … 46 46 $js_version = file_exists($js_path) ? filemtime($js_path) : '2.0'; 47 47 wp_enqueue_script( 48 'structureviewer-scripts', // Updated handle with prefix48 'structureviewer-scripts', 49 49 STRUCTUREVIEWER_PLUGIN_URL . 'assets/js/sv-scripts.js', 50 50 ['jquery'], … … 53 53 ); 54 54 55 // Localize script with nonce for potential future AJAX55 // Localize script with nonce and AJAX URL for export 56 56 wp_localize_script('structureviewer-scripts', 'structureviewerSettings', [ 57 'nonce' => wp_create_nonce(STRUCTUREVIEWER_NONCE) 57 'nonce' => wp_create_nonce(STRUCTUREVIEWER_NONCE), 58 'ajaxurl' => admin_url('admin-ajax.php') 58 59 ]); 59 60 }
Note: See TracChangeset
for help on using the changeset viewer.