文件操作 - wordpress_manager.js.twig
返回文件管理
返回主菜单
删除本文件
文件: /usr/local/cwpsrv/var/services/users/cwp_theme/original/js/modules/wordpress_manager.js.twig
编辑文件内容
/* WordPress Manager Module JS */ var wpm_installations = []; var wpm_wp_cli = false; var wpm_domains = []; try { wpm_installations = JSON.parse('{{ mod.installations|default([])|json_encode|raw|escape("js") }}'); wpm_wp_cli = {{ mod.wp_cli|default(false) ? 'true' : 'false' }}; wpm_domains = JSON.parse('{{ mod.domains|default([])|json_encode|raw|escape("js") }}'); wpm_csrf_token = '{{ mod.csrf_token|default("")|escape("js") }}'; } catch(e) { console.error("WPM JSON parse error", e); } var uchip = null; var wpmCurrentPath = ''; var wpmInstallStep = 1; $(document).ready(function() { {% if mod.isie == 1 %} uchip = new $.Uchip(); {% else %} uchip = new Uchip(); {% endif %} var updateCount = 0; wpm_installations.forEach(function(inst) { if (inst.core_update) updateCount++; if (inst.plugin_updates > 0) updateCount += inst.plugin_updates; if (inst.theme_updates > 0) updateCount += inst.theme_updates; }); $('#wpm-updates-count').text(updateCount); wpmPopulateDomains(); // Close toolbar dropdowns when clicking outside $(document).on('click', function(e) { if (!$(e.target).closest('.wpm-toolbar-dropdown').length) { $('.wpm-toolbar-dropdown').removeClass('open'); } }); }); // --- AJAX via uchip (git_manager pattern) --- function wpmAjax(action, data, success, error) { data.csrf_token = wpm_csrf_token; uchip.call('module=wordpress_manager&acc=' + action, { data: $.param(data), callback: function(resp_data) { if (resp_data.csrf_token) { wpm_csrf_token = resp_data.csrf_token; } if (resp_data.result === 'success') { resp_data.success = true; if (success) success(resp_data); } else { if (error) error(resp_data); else noti_bubble(resp_data.message || 'Error', 'Error', 'error', true, false, '3000', true); } } }); } // --- Populate Domain Select --- function wpmPopulateDomains() { var select = $('#wpm-domain-select'); if (!select.length) return; select.find('option:not(:first)').remove(); if (typeof wpm_domains !== 'undefined' && Array.isArray(wpm_domains) && wpm_domains.length > 0) { wpm_domains.forEach(function(d) { var domain = (typeof d === 'object') ? (d.domain || d.name || '') : d; var path = (typeof d === 'object') ? (d.path || d.docroot || d.documentroot || '') : ''; if (domain) { select.append('<option value="' + domain + '" data-path="' + path + '">' + domain + '</option>'); } }); } else { wpmAjax('list_domains', {}, function(res) { if (res.domains && Array.isArray(res.domains)) { wpm_domains = res.domains; wpmPopulateDomains(); } }); } } // --- Password helpers --- function wpmTogglePassVisibility(inputId) { var input = document.getElementById(inputId); if (!input) return; var icon = document.getElementById(inputId + '-eye'); if (input.type === 'password') { input.type = 'text'; if (icon) { icon.classList.remove('fa-eye'); icon.classList.add('fa-eye-slash'); } } else { input.type = 'password'; if (icon) { icon.classList.remove('fa-eye-slash'); icon.classList.add('fa-eye'); } } } function wpmGeneratePassword() { var chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!@#$%&*'; var pass = ''; for (var i = 0; i < 16; i++) { pass += chars.charAt(Math.floor(Math.random() * chars.length)); } var input = document.getElementById('wpm-admin-pass'); if (input) { input.value = pass; input.type = 'text'; } var icon = document.getElementById('wpm-admin-pass-eye'); if (icon) { icon.classList.remove('fa-eye'); icon.classList.add('fa-eye-slash'); } } function wpmGenerateDbPassword() { var chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!@#$%&*'; var pass = ''; for (var i = 0; i < 16; i++) { pass += chars.charAt(Math.floor(Math.random() * chars.length)); } var input = document.getElementById('wpm-db-pass'); if (input) { input.value = pass; input.type = 'text'; } var icon = document.getElementById('wpm-db-pass-eye'); if (icon) { icon.classList.remove('fa-eye'); icon.classList.add('fa-eye-slash'); } } // --- Install Modal --- function wpmOpenInstall() { wpmInstallStep = 1; wpmUpdateInstallSteps(); $('#wpm-install-form')[0].reset(); $('#wpm-install-form .form-group').removeClass('has-error'); $('#wpm-modal-install').modal('show'); } function wpmValidateStep(step) { var valid = true; var container = $('#wpm-step-' + step); container.find('.form-group').removeClass('has-error'); if (step === 1) { if (!$('#wpm-domain-select').val()) { $('#wpm-domain-select').closest('.form-group').addClass('has-error'); valid = false; } } if (step === 2) { var title = $('[name="wpsitetitle"]'); if (!title.val().trim()) { title.closest('.form-group').addClass('has-error'); valid = false; } } if (step === 3) { var user = $('[name="wpadminuser"]'); if (!user.val().trim()) { user.closest('.form-group').addClass('has-error'); valid = false; } var pass = $('[name="wpadminpass"]'); if (!pass.val().trim()) { pass.closest('.form-group').addClass('has-error'); valid = false; } var email = $('[name="wpadminemail"]'); var emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!email.val().trim() || !emailRe.test(email.val())) { email.closest('.form-group').addClass('has-error'); valid = false; } } if (step === 4) { var prefix = $('[name="wpdbprefix"]'); var prefixRe = /^[a-zA-Z0-9_]+$/; if (prefix.val() && !prefixRe.test(prefix.val())) { prefix.closest('.form-group').addClass('has-error'); valid = false; } } return valid; } function wpmInstallNext() { if (wpmInstallStep >= 4) return; if (!wpmValidateStep(wpmInstallStep)) return; wpmInstallStep++; wpmUpdateInstallSteps(); } function wpmInstallPrev() { if (wpmInstallStep <= 1) return; $('#wpm-step-' + wpmInstallStep).find('.form-group').removeClass('has-error'); wpmInstallStep--; wpmUpdateInstallSteps(); } function wpmUpdateInstallSteps() { $('.wpm-step').removeClass('active'); $('.wpm-step-content').removeClass('active'); $('.wpm-step[data-step="' + wpmInstallStep + '"]').addClass('active'); $('#wpm-step-' + wpmInstallStep).addClass('active'); $('#wpm-install-prev').toggle(wpmInstallStep > 1); $('#wpm-install-next').toggle(wpmInstallStep < 4); $('#wpm-install-submit').toggle(wpmInstallStep === 4); } function wpmDoInstall() { if (!wpmValidateStep(wpmInstallStep)) return; var formData = $('#wpm-install-form').serializeArray(); var dompath = $('#wpm-domain-select option:selected').data('path') || $('#wpm-domain-select').val(); var data = {dompath: dompath}; formData.forEach(function(field) { data[field.name] = field.value; }); $('#wpm-modal-install').modal('hide'); $('#wpm-modal-progress').modal('show'); wpmAjax('install', data, function(res) { $('#wpm-modal-progress').modal('hide'); noti_bubble('{{langmod.WPM_SUCCESS_INSTALL|default("WordPress installed successfully!")}}', 'Success', 'success', true, false, '3000', true); setTimeout(function() { location.reload(); }, 1000); }, function(err) { $('#wpm-modal-progress').modal('hide'); noti_bubble(err.message || 'Installation failed', 'Error', 'error', true, false, '3000', true); }); } // --- Remove --- function wpmOpenLogin(url, domain, path) { if (!path) { if (url) { window.open(url, '_blank'); } else { noti_bubble('URL not available for this installation', 'Error', 'error', true, false, '3000', true); } return; } noti_bubble('Generating secure login link...', 'Info', 'info', true, false, '3000', true); wpmAjax('sso_login', { path: path, url: url }, function(res) { if (res.token) { window.open(res.token, '_blank'); } else { noti_bubble(res.message || 'Failed to generate secure login link', 'Error', 'error', true, false, '3000', true); if (url) window.open(url + '/wp-admin', '_blank'); } }, function(err) { noti_bubble(err.message || 'Error communicating with server', 'Error', 'error', true, false, '3000', true); if (url) window.open(url, '_blank'); }); } function wpmConfirmRemove(btn) { var card = $(btn).closest('.wpm-card'); wpmCurrentPath = card.data('path'); $('#wpm-remove-domain').text(card.data('domain')); $('#wpm-modal-remove').data('wpbd', card.data('wpbd')).modal('show'); } function wpmDoRemove() { var removeDb = $('#wpm-remove-db').is(':checked') ? '1' : '0'; var wpbd = $('#wpm-modal-remove').data('wpbd'); $('#wpm-modal-remove').modal('hide'); wpmAjax('remove', {path: wpmCurrentPath, remove_db: removeDb, wpbd: wpbd}, function(res) { noti_bubble('{{langmod.WPM_SUCCESS_REMOVE|default("WordPress removed")}}', 'Success', 'success', true, false, '3000', true); setTimeout(function() { location.reload(); }, 1000); }); } // --- Login --- // --- Toolbar Dropdown --- function wpmToggleDropdown(btn) { var dropdown = $(btn).closest('.wpm-toolbar-dropdown'); var wasOpen = dropdown.hasClass('open'); // Close all dropdowns first $('.wpm-toolbar-dropdown').removeClass('open'); if (!wasOpen) { dropdown.addClass('open'); } } // --- Preview --- function wpmOpenPreview(url, domain, path) { if (url) { window.open(url, '_blank'); } else { noti_bubble('URL not available for this installation', 'Error', 'error', true, false, '3000', true); } } // --- Updates --- function wpmCheckUpdates(path, btn) { $(btn).find('i').addClass('fa-spin'); wpmAjax('check_updates', {path: path}, function(res) { $(btn).find('i').removeClass('fa-spin'); var msg = []; if (res.core) msg.push('Core: ' + res.core.version); if (res.plugins && res.plugins.length > 0) msg.push(res.plugins.length + ' plugin(s)'); if (res.themes && res.themes.length > 0) msg.push(res.themes.length + ' theme(s)'); if (msg.length > 0) { noti_bubble('Updates: ' + msg.join(', '), 'Updates Available', 'warning', true, false, '4000', true); } else { noti_bubble('Everything is up to date!', 'Success', 'success', true, false, '3000', true); } }); } // --- Security --- function wpmOpenSecurity(path) { wpmCurrentPath = path; $('#wpm-modal-security').modal('show'); $('#wpm-security-body').html('<div style="text-align:center;padding:30px;"><i class="fa fa-circle-o-notch fa-spin"></i> Loading...</div>'); wpmAjax('security_status', {path: path}, function(res) { var score = res.score || 0; var scoreColor = score >= 80 ? '#27ae60' : score >= 40 ? '#f39c12' : '#e74c3c'; var checks = [ {key: 'file_editing_disabled', measure: 'file_edit', label: 'Disable File Editor'}, {key: 'xmlrpc_disabled', measure: 'xmlrpc', label: 'Disable XML-RPC'}, {key: 'version_hidden', measure: 'version_hide', label: 'Hide WP Version'}, {key: 'directory_listing_disabled', measure: 'directory_listing', label: 'Disable Directory Listing'}, {key: 'user_enumeration_blocked', measure: 'user_enum', label: 'Block User Enumeration'}, ]; var html = '<div class="wpm-security-score"><div class="score-num" style="color:' + scoreColor + '">' + score + '%</div><div class="score-label">Security Score</div></div>'; html += '<ul class="wpm-security-checklist">'; for (var i = 0; i < checks.length; i++) { var c = checks[i]; var on = res[c.key] ? true : false; html += '<li class="wpm-security-check"><div><strong>' + c.label + '</strong></div>'; html += '<button class="btn btn-xs ' + (on ? 'btn-success' : 'btn-default') + '" onclick="wpmToggleSecurity(\'' + c.measure + '\',' + !on + ')">' + (on ? 'ON' : 'OFF') + '</button></li>'; } html += '</ul>'; html += '<div class="wpm-modal-actions">'; html += '<button class="btn btn-default btn-xs" onclick="wpmRotateSalts()"><i class="fa fa-key"></i> Rotate Salts</button> '; html += '<button class="btn btn-default btn-xs" onclick="wpmResetAdminPass()"><i class="fa fa-lock"></i> Reset Pass</button> '; html += '<button class="btn btn-default btn-xs" onclick="wpmVerifyCore()"><i class="fa fa-check-circle"></i> Verify Core</button>'; html += '</div>'; $('#wpm-security-body').html(html); }); } function wpmToggleSecurity(measure, enable) { wpmAjax('toggle_security', {path: wpmCurrentPath, measure: measure, enabled: enable ? '1' : '0'}, function(res) { wpmOpenSecurity(wpmCurrentPath); }); } function wpmApplyHardening() { wpmAjax('apply_hardening', {path: wpmCurrentPath}, function(res) { noti_bubble('{{langmod.WPM_SUCCESS_HARDENING|default("Hardening applied!")}}', 'Success', 'success', true, false, '3000', true); wpmOpenSecurity(wpmCurrentPath); }); } function wpmRotateSalts() { wpmAjax('rotate_salts', {path: wpmCurrentPath}, function(res) { noti_bubble(res.message, 'Success', 'success', true, false, '3000', true); }); } function wpmResetAdminPass() { var p = prompt('Enter new admin password:'); if (!p) return; wpmAjax('reset_admin_pass', {path: wpmCurrentPath, new_password: p}, function(res) { noti_bubble(res.message, 'Success', 'success', true, false, '3000', true); }); } function wpmVerifyCore() { wpmAjax('verify_core', {path: wpmCurrentPath}, function(res) { noti_bubble(res.message, 'Success', 'success', true, false, '3000', true); }); } // --- Plugins --- // --- Backup --- function wpmBackup(path) { wpmCurrentPath = path; $('#wpm-modal-backup').modal('show'); wpmLoadBackups(); } function wpmLoadBackups() { wpmAjax('list_backups', {}, function(res) { if (!res.backups || res.backups.length === 0) { $('#wpm-backup-list').html('<tr><td colspan="4" class="text-center text-muted">No backups yet.</td></tr>'); return; } var html = ''; for (var i = 0; i < res.backups.length; i++) { var b = res.backups[i]; html += '<tr>'; html += '<td><i class="fa fa-archive"></i> ' + b.file + '<br><small class="text-muted">' + b.created_at + '</small></td>'; html += '<td>Backup</td>'; html += '<td>' + b.size + '</td>'; html += '<td>'; html += '<button class="btn btn-warning btn-xs" onclick="wpmRestoreBackup(\'' + b.file + '\')" title="Restore Backup"><i class="fa fa-undo"></i></button> '; html += '<button class="btn btn-danger btn-xs" onclick="wpmDeleteBackup(\'' + b.file + '\')" title="Delete Backup"><i class="fa fa-trash"></i></button>'; html += '</td></tr>'; } $('#wpm-backup-list').html(html); }); } function wpmCreateBackup() { $('#wpm-backup-body').html('<div style="text-align:center;padding:30px;"><i class="fa fa-circle-o-notch fa-spin"></i> Creating backup...</div>'); wpmAjax('create_backup', {path: wpmCurrentPath}, function(res) { noti_bubble('{{langmod.WPM_SUCCESS_BACKUP|default("Backup created")}}', 'Success', 'success', true, false, '3000', true); wpmLoadBackups(); }); } function wpmDeleteBackup(file) { $('#wpm-backup-delete-name').text(file); $('#wpm-modal-backup-delete').data('file', file).modal('show'); } function wpmConfirmDeleteBackup() { var file = $('#wpm-modal-backup-delete').data('file'); $('#wpm-modal-backup-delete').modal('hide'); wpmAjax('delete_backup', {backup_file: file}, function(res) { wpmLoadBackups(); }); } function wpmRestoreBackup(file) { $('#wpm-backup-restore-name').text(file); $('#wpm-modal-backup-restore').data('file', file).modal('show'); } function wpmConfirmRestoreBackup() { var file = $('#wpm-modal-backup-restore').data('file'); $('#wpm-modal-backup-restore').modal('hide'); noti_bubble('{{langmod.WPM_RESTORING|default("Restoring backup...")}}', 'Info', 'info', true, false, '3000', true); wpmAjax('restore_backup', {backup_file: file, target_path: wpmCurrentPath}, function(res) { noti_bubble('{{langmod.WPM_SUCCESS_RESTORE|default("Backup restored")}}', 'Success', 'success', true, false, '3000', true); wpmLoadBackups(); }); } // --- Clone --- function wpmOpenClone(path, domain, wpbd) { wpmCurrentPath = path; $('#wpm-clone-source').val(domain + ' (' + path + ')'); $('#wpm-clone-domain').val('').html('<option value="">Select domain...</option>'); function populateCloneDomains(domains) { if (!Array.isArray(domains)) return; domains.forEach(function(d) { var dom = (typeof d === 'object') ? (d.domain || d.name || '') : d; var dir = (typeof d === 'object') ? (d.path || d.docroot || d.documentroot || '') : ''; if (dom) { $('#wpm-clone-domain').append('<option value="' + dom + '" data-path="' + dir + '">' + dom + '</option>'); } }); } if (typeof wpm_domains !== 'undefined' && Array.isArray(wpm_domains) && wpm_domains.length > 0) { populateCloneDomains(wpm_domains); } else { wpmAjax('list_domains', {}, function(res) { if (res.domains && Array.isArray(res.domains)) { wpm_domains = res.domains; populateCloneDomains(wpm_domains); wpmPopulateDomains(); } }); } $('#wpm-modal-clone').modal('show'); } function wpmDoClone() { var targetDomain = $('#wpm-clone-domain').val(); var targetDir = $('#wpm-clone-dir').val(); if (!targetDomain) return; $('#wpm-modal-clone').modal('hide'); $('#wpm-modal-progress').modal('show'); wpmAjax('clone_installation', {source_path: wpmCurrentPath, target_domain: targetDomain, target_dir: targetDir}, function(res) { $('#wpm-modal-progress').modal('hide'); noti_bubble('{{langmod.WPM_SUCCESS_CLONE|default("Cloned successfully!")}}', 'Success', 'success', true, false, '3000', true); setTimeout(function() { location.reload(); }, 1000); }, function(err) { $('#wpm-modal-progress').modal('hide'); noti_bubble(err.message || 'Clone failed', 'Error', 'error', true, false, '3000', true); }); } // --- Vulnerability Scan (A3) --- function wpmOpenSyncStagingToProd(stagingPath, stagingDomain, prodPath, prodDomain) { wpmSyncDirection = 'staging_to_prod'; wpmSyncStagingPath = stagingPath; wpmSyncProdPath = prodPath; $('#wpm-sync-title').text('Sync Staging to Production'); $('#wpm-sync-source').val(stagingDomain + ' (' + stagingPath + ')'); $('#wpm-sync-target').val(prodDomain + ' (' + prodPath + ')'); $('input[name="sync_mode"][value="full"]').prop('checked', true); $('#wpm-modal-sync').modal('show'); } function wpmOpenSyncProdToStaging(prodPath, prodDomain, stagingPath, stagingDomain) { wpmSyncDirection = 'prod_to_staging'; wpmSyncStagingPath = stagingPath; wpmSyncProdPath = prodPath; $('#wpm-sync-title').text('Sync Production to Staging'); $('#wpm-sync-source').val(prodDomain + ' (' + prodPath + ')'); $('#wpm-sync-target').val(stagingDomain + ' (' + stagingPath + ')'); $('input[name="sync_mode"][value="full"]').prop('checked', true); $('#wpm-modal-sync').modal('show'); } function wpmDoSync() { var mode = $('input[name="sync_mode"]:checked').val() || 'full'; var action, data; if (wpmSyncDirection === 'staging_to_prod') { action = 'sync_staging_prod'; data = {staging_path: wpmSyncStagingPath, prod_path: wpmSyncProdPath, mode: mode}; } else { action = 'sync_prod_staging'; data = {prod_path: wpmSyncProdPath, staging_path: wpmSyncStagingPath, mode: mode}; } $('#wpm-modal-sync').modal('hide'); $('#wpm-modal-progress').modal('show'); wpmAjax(action, data, function(res) { $('#wpm-modal-progress').modal('hide'); noti_bubble(res.message || 'Sync completed', 'Success', 'success', true, false, '3000', true); setTimeout(function() { location.reload(); }, 1000); }, function(err) { $('#wpm-modal-progress').modal('hide'); noti_bubble(err.message || 'Sync failed', 'Error', 'error', true, false, '3000', true); }); } // --- Backup Schedule --- var wpmSchedulePath = ''; var wpmScheduleDomain = ''; var wpmCurrentSchedule = null; function wpmOpenSchedule(path, domain) { wpmSchedulePath = path; wpmScheduleDomain = domain; wpmCurrentSchedule = null; $('#wpm-schedule-save-btn').hide(); $('#wpm-modal-schedule').modal('show'); wpmLoadSchedule(); } function wpmLoadSchedule() { $('#wpm-schedule-body').html('<div style="text-align:center;padding:30px;"><div class="wpm-spinner"></div><p>Loading schedule...</p></div>'); wpmAjax('list_backup_schedules', {path: wpmSchedulePath}, function(res) { if (!res.schedules || res.schedules.length === 0) { wpmRenderScheduleForm(null); } else { wpmRenderScheduleForm(res.schedules[0]); } }); } function wpmRenderScheduleForm(schedule) { wpmCurrentSchedule = schedule; var html = ''; if (schedule) { var statusClass = schedule.enabled ? 'wpm-schedule-status-enabled' : 'wpm-schedule-status-disabled'; var statusText = schedule.enabled ? 'Enabled' : 'Disabled'; html += '<div class="wpm-schedule-info">'; html += '<div class="wpm-info-label">Status</div>'; html += '<div><span class="wpm-schedule-status ' + statusClass + '">' + statusText + '</span></div>'; html += '<div class="wpm-schedule-last-run">'; if (schedule.last_run) { html += '<i class="fa fa-clock-o"></i> Last run: ' + schedule.last_run; if (schedule.last_status) { var statusColor = schedule.last_status === 'success' ? '#27ae60' : '#e74c3c'; html += ' <span style="color:' + statusColor + '">(' + schedule.last_status + ')</span>'; } } else { html += '<i class="fa fa-clock-o"></i> Never run'; } html += '</div>'; html += '</div>'; } html += '<div class="wpm-schedule-form">'; if (schedule) { html += '<div class="form-group">'; html += '<label>Frequency</label>'; html += '<select name="sch_frequency" class="form-control" onchange="wpmScheduleFrequencyChanged()">'; html += '<option value="daily"' + (schedule.frequency === 'daily' ? ' selected' : '') + '>Daily</option>'; html += '<option value="weekly"' + (schedule.frequency === 'weekly' ? ' selected' : '') + '>Weekly</option>'; html += '<option value="monthly"' + (schedule.frequency === 'monthly' ? ' selected' : '') + '>Monthly</option>'; html += '</select>'; html += '</div>'; html += '<div class="form-group">'; html += '<label>Time (Hour)</label>'; html += '<select name="sch_hour" class="form-control">'; for (var h = 0; h < 24; h++) { var hStr = (h < 10 ? '0' : '') + h + ':00'; html += '<option value="' + h + '"' + (schedule.hour === h ? ' selected' : '') + '>' + hStr + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group">'; html += '<label>Time (Minute)</label>'; html += '<select name="sch_minute" class="form-control">'; for (var m = 0; m < 60; m += 5) { var mStr = (m < 10 ? '0' : '') + m; html += '<option value="' + m + '"' + (schedule.minute === m ? ' selected' : '') + '>' + mStr + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group" id="wpm-sch-day-group" style="display:' + (schedule.frequency === 'weekly' ? 'block' : 'none') + '">'; html += '<label>Day of Week</label>'; html += '<select name="sch_day_of_week" class="form-control">'; var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; for (var d = 0; d < 7; d++) { html += '<option value="' + d + '"' + (schedule.day_of_week === d ? ' selected' : '') + '>' + days[d] + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group" id="wpm-sch-dom-group" style="display:' + (schedule.frequency === 'monthly' ? 'block' : 'none') + '">'; html += '<label>Day of Month</label>'; html += '<select name="sch_day_of_month" class="form-control">'; for (var dm = 1; dm <= 28; dm++) { html += '<option value="' + dm + '"' + (schedule.day_of_month === dm ? ' selected' : '') + '>' + dm + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group">'; html += '<label>Retention (keep last N backups)</label>'; html += '<input type="number" name="sch_retention" class="form-control" value="' + schedule.retention_count + '" min="1" max="365">'; html += '<span class="help-block">Oldest backups exceeding this count will be deleted automatically.</span>'; html += '</div>'; html += '<div class="wpm-schedule-actions">'; html += '<button class="btn btn-primary btn-xs" onclick="wpmSaveSchedule()"><i class="fa fa-save"></i> Save Changes</button> '; html += '<button class="btn btn-xs ' + (schedule.enabled ? 'btn-warning' : 'btn-success') + '" onclick="wpmToggleSchedule(\'' + schedule.id + '\',' + !schedule.enabled + ')">'; html += '<i class="fa ' + (schedule.enabled ? 'fa-pause' : 'fa-play') + '"></i> ' + (schedule.enabled ? 'Disable' : 'Enable') + '</button> '; html += '<button class="btn btn-default btn-xs" onclick="wpmViewScheduleLogs(\'' + schedule.id + '\')"><i class="fa fa-list-alt"></i> Logs</button> '; html += '<button class="btn btn-danger btn-xs" onclick="wpmDeleteSchedule(\'' + schedule.id + '\')"><i class="fa fa-trash"></i> Delete</button>'; html += '</div>'; } else { html += '<div class="wpm-no-schedule">'; html += '<i class="fa fa-calendar"></i>'; html += '<h4>No Schedule</h4>'; html += '<p class="text-muted">Create an automatic backup schedule for this site.</p>'; html += '</div>'; html += '<div class="form-group">'; html += '<label>Frequency</label>'; html += '<select name="sch_frequency" class="form-control" onchange="wpmScheduleFrequencyChanged()">'; html += '<option value="daily">Daily</option>'; html += '<option value="weekly">Weekly</option>'; html += '<option value="monthly">Monthly</option>'; html += '</select>'; html += '</div>'; html += '<div class="form-group">'; html += '<label>Time (Hour)</label>'; html += '<select name="sch_hour" class="form-control">'; for (var h = 0; h < 24; h++) { var hStr2 = (h < 10 ? '0' : '') + h + ':00'; var sel = (h === 3) ? ' selected' : ''; html += '<option value="' + h + '"' + sel + '>' + hStr2 + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group">'; html += '<label>Time (Minute)</label>'; html += '<select name="sch_minute" class="form-control">'; for (var m2 = 0; m2 < 60; m2 += 5) { var mStr2 = (m2 < 10 ? '0' : '') + m2; html += '<option value="' + m2 + '">' + mStr2 + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group" id="wpm-sch-day-group" style="display:none">'; html += '<label>Day of Week</label>'; html += '<select name="sch_day_of_week" class="form-control">'; var days2 = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; for (var d2 = 0; d2 < 7; d2++) { html += '<option value="' + d2 + '">' + days2[d2] + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group" id="wpm-sch-dom-group" style="display:none">'; html += '<label>Day of Month</label>'; html += '<select name="sch_day_of_month" class="form-control">'; for (var dm2 = 1; dm2 <= 28; dm2++) { html += '<option value="' + dm2 + '">' + dm2 + '</option>'; } html += '</select>'; html += '</div>'; html += '<div class="form-group">'; html += '<label>Retention (keep last N backups)</label>'; html += '<input type="number" name="sch_retention" class="form-control" value="7" min="1" max="365">'; html += '<span class="help-block">Oldest backups exceeding this count will be deleted automatically.</span>'; html += '</div>'; html += '<div style="text-align:center;padding-top:10px;">'; html += '<button class="btn btn-primary" onclick="wpmSaveSchedule()"><i class="fa fa-calendar-plus-o"></i> Create Schedule</button>'; html += '</div>'; } html += '</div>'; $('#wpm-schedule-body').html(html); } function wpmScheduleFrequencyChanged() { var freq = $('[name="sch_frequency"]').val(); $('#wpm-sch-day-group').toggle(freq === 'weekly'); $('#wpm-sch-dom-group').toggle(freq === 'monthly'); } function wpmSaveSchedule() { var data = { path: wpmSchedulePath, domain: wpmScheduleDomain, frequency: $('[name="sch_frequency"]').val(), hour: $('[name="sch_hour"]').val(), minute: $('[name="sch_minute"]').val(), day_of_week: $('[name="sch_day_of_week"]').val(), day_of_month: $('[name="sch_day_of_month"]').val(), retention_count: $('[name="sch_retention"]').val() }; var action = wpmCurrentSchedule ? 'update_backup_schedule' : 'create_backup_schedule'; if (wpmCurrentSchedule) { data.schedule_id = wpmCurrentSchedule.id; } $('#wpm-schedule-body').html('<div style="text-align:center;padding:30px;"><div class="wpm-spinner"></div><p>Saving schedule...</p></div>'); wpmAjax(action, data, function(res) { noti_bubble(res.message, 'Success', 'success', true, false, '3000', true); wpmLoadSchedule(); }, function(err) { noti_bubble(err.message || 'Error saving schedule', 'Error', 'error', true, false, '3000', true); wpmLoadSchedule(); }); } function wpmToggleSchedule(id, enable) { wpmAjax('toggle_backup_schedule', {schedule_id: id, enabled: enable ? '1' : '0'}, function(res) { noti_bubble(res.message, 'Success', 'success', true, false, '3000', true); wpmLoadSchedule(); }); } function wpmDeleteSchedule(id) { if (!confirm('Are you sure you want to delete this backup schedule?')) return; wpmAjax('delete_backup_schedule', {schedule_id: id}, function(res) { noti_bubble(res.message, 'Success', 'success', true, false, '3000', true); wpmLoadSchedule(); }); } function wpmViewScheduleLogs(id) { $('#wpm-modal-schedule-logs').modal('show'); $('#wpm-schedule-logs-body').html('<div style="text-align:center;padding:30px;"><div class="wpm-spinner"></div><p>Loading logs...</p></div>'); wpmAjax('list_backup_logs', {schedule_id: id, limit: 100}, function(res) { if (!res.logs || res.logs.length === 0) { $('#wpm-schedule-logs-body').html('<div class="wpm-no-schedule"><i class="fa fa-list-alt"></i><h4>No Logs</h4><p class="text-muted">No execution logs yet for this schedule.</p></div>'); return; } var html = '<table class="table table-striped table-bordered wpm-schedule-logs-table"><thead><tr><th>Timestamp</th><th>Action</th><th>Status</th><th>Details</th></tr></thead><tbody>'; for (var i = 0; i < res.logs.length; i++) { var log = res.logs[i]; var statusBadge = log.status === 'success' ? '<span class="label label-success">' + log.status + '</span>' : '<span class="label label-danger">' + log.status + '</span>'; html += '<tr>'; html += '<td>' + (log.timestamp || '') + '</td>'; html += '<td>' + (log.action || '') + '</td>'; html += '<td>' + statusBadge + '</td>'; html += '<td>' + (log.message || '') + '</td>'; html += '</tr>'; } html += '</tbody></table>'; $('#wpm-schedule-logs-body').html(html); }); } // function wpmOpenThemes(path) { wpmCurrentPath = path; $('#wpm-modal-plugins').modal('show'); // Switch to themes tab $('.wpm-modal-tabs a[href="#wpm-tab-themes"]').tab('show'); wpmLoadThemes(path); wpmLoadPlugins(path); $('#wpm-theme-search-input').val(''); } function wpmLoadPlugins(path) { // Clear existing content $('#wpm-plugins-body').html('<div style="text-align:center;padding:20px;"><i class="fa fa-circle-o-notch fa-spin" style="font-size:24px;color:#cbd5e0;"></i><p style="margin-top:10px;color:#718096;">Loading plugins...</p></div>'); // Load plugins list wpmAjax('list_plugins', { path: path }, function(res) { if (res.success && res.plugins) { displayPlugins(res.plugins, path); } else { $('#wpm-plugins-body').html('<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> Error loading plugins: ' + (res.message || 'Unknown error') + '</div>'); } }); } function displayPlugins(plugins, path) { if (plugins.length === 0) { $('#wpm-plugins-body').html('<div class="alert alert-info"><i class="fa fa-info-circle"></i> No plugins installed</div>'); return; } let html = '<div class="wpm-item-list">'; plugins.forEach(function(plugin) { const isActive = plugin.active ? 'wpm-item-active' : ''; const statusIcon = plugin.active ? '<i class="fa fa-check-circle" style="color:#27ae60;"></i>' : '<i class="fa fa-times-circle" style="color:#e74c3c;"></i>'; html += ` <div class="wpm-item-card ${isActive}"> <div class="wpm-item-info"> <div class="wpm-item-name"> ${plugin.name} <span class="label ${plugin.active ? 'label-success' : 'label-default'}">${plugin.active ? 'Active' : 'Inactive'}</span> </div> <div class="wpm-item-meta"> <span class="label"><i class="fa fa-info-circle"></i> Version: ${plugin.version || 'Unknown'}</span> <span class="label"><i class="fa fa-download"></i> Author: ${plugin.author || 'Unknown'}</span> </div> </div> <div class="wpm-item-actions"> <button class="btn btn-xs btn-${plugin.active ? 'warning' : 'success'}" onclick="wpmTogglePlugin('${path}', '${plugin.slug}', ${!plugin.active})"> <i class="fa fa-${plugin.active ? 'power-off' : 'play'}"></i> ${plugin.active ? 'Deactivate' : 'Activate'} </button> <button class="btn btn-xs btn-default" onclick="wpmShowPluginDetails('${path}', '${plugin.slug}')"> <i class="fa fa-eye"></i> Details </button> </div> </div> `; }); html += '</div>'; $('#wpm-plugins-body').html(html); } function wpmLoadThemes(path) { // Clear existing content $('#wpm-themes-body').html('<div style="text-align:center;padding:20px;"><i class="fa fa-circle-o-notch fa-spin" style="font-size:24px;color:#cbd5e0;"></i><p style="margin-top:10px;color:#718096;">Loading themes...</p></div>'); // Load themes list wpmAjax('list_themes', { path: path }, function(res) { if (res.success && res.themes) { displayThemes(res.themes, path); } else { $('#wpm-themes-body').html('<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> Error loading themes: ' + (res.message || 'Unknown error') + '</div>'); } }); } function displayThemes(themes, path) { if (themes.length === 0) { $('#wpm-themes-body').html('<div class="alert alert-info"><i class="fa fa-info-circle"></i> No themes installed</div>'); return; } let html = '<div class="wpm-item-list">'; themes.forEach(function(theme) { const isActive = theme.active ? 'wpm-item-active' : ''; const statusIcon = theme.active ? '<i class="fa fa-check-circle" style="color:#27ae60;"></i>' : '<i class="fa fa-times-circle" style="color:#e74c3c;"></i>'; html += ` <div class="wpm-item-card ${isActive}"> <div class="wpm-item-info"> <div class="wpm-item-name"> ${theme.name} <span class="label ${theme.active ? 'label-success' : 'label-default'}">${theme.active ? 'Active' : 'Inactive'}</span> </div> <div class="wpm-item-meta"> <span class="label"><i class="fa fa-info-circle"></i> Version: ${theme.version || 'Unknown'}</span> <span class="label"><i class="fa fa-download"></i> Author: ${theme.author || 'Unknown'}</span> </div> </div> <div class="wpm-item-actions"> <button class="btn btn-xs btn-${theme.active ? 'warning' : 'success'}" onclick="wpmToggleTheme('${path}', '${theme.name}', ${!theme.active})"> <i class="fa fa-${theme.active ? 'power-off' : 'play'}"></i> ${theme.active ? 'Deactivate' : 'Activate'} </button> <button class="btn btn-xs btn-default" onclick="wpmShowThemeDetails('${path}', '${theme.name}')"> <i class="fa fa-eye"></i> Details </button> </div> </div> `; }); html += '</div>'; $('#wpm-themes-body').html(html); } function wpmSearchThemes(query) { wpmAjax('search_themes', { path: wpmCurrentPath, query: query }, function(res) { if (res.success && res.themes) { displayThemes(res.themes, wpmCurrentPath); } else { $('#wpm-themes-body').html('<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> Error searching themes: ' + (res.message || 'Unknown error') + '</div>'); } }); } function wpmToggleTheme(path, name, activate) { const action = activate ? 'activate_theme' : 'deactivate_theme'; const message = activate ? 'Activating...' : 'Deactivating...'; wpmNotify.info(message); wpmAjax(action, { path: path, slug: name, name: name, theme: name }, function(res) { if (res.success) { wpmNotify.success('Theme ' + (activate ? 'activated' : 'deactivated') + ' successfully'); wpmLoadThemes(path); } else { wpmNotify.error('Failed to ' + (activate ? 'activate' : 'deactivate') + ' theme: ' + (res.message || 'Unknown error')); } }); } function wpmShowThemeDetails(path, name) { wpmNotify.info('Showing theme details for: ' + name); // TODO: Implement theme details view } function wpmSearchPlugins(query) { wpmAjax('search_plugins', { path: wpmCurrentPath, query: query }, function(res) { if (res.success && res.plugins) { displayPlugins(res.plugins, wpmCurrentPath); } else { $('#wpm-plugins-body').html('<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> Error searching plugins: ' + (res.message || 'Unknown error') + '</div>'); } }); } function wpmTogglePlugin(path, slug, activate) { const action = activate ? 'activate_plugin' : 'deactivate_plugin'; const message = activate ? 'Activating...' : 'Deactivating...'; wpmNotify.info(message); wpmAjax(action, { path: path, slug: slug }, function(res) { if (res.success) { wpmNotify.success('Plugin ' + (activate ? 'activated' : 'deactivated') + ' successfully'); wpmLoadPlugins(path); } else { wpmNotify.error('Failed to ' + (activate ? 'activate' : 'deactivate') + ' plugin: ' + (res.message || 'Unknown error')); } }); } function wpmShowPluginDetails(path, slug) { wpmCurrentPath = path; $('#wpm-modal-plugin-details').modal('show'); $('#wpm-plugin-details-body').html('<div style="text-align:center;padding:30px;"><i class="fa fa-circle-o-notch fa-spin"></i> Loading...</div>'); wpmAjax('plugin_details', {path: path, slug: slug}, function(res) { var p = res.plugin || {}; var isActive = p.active; var statusLabel = isActive ? '<span class="label label-success">Active</span>' : '<span class="label label-default">Inactive</span>'; function row(label, value) { if (value === undefined || value === null || value === '') return ''; return '<tr><th style="width:35%;text-align:right;color:#7f8c8d;">' + label + '</th>' + '<td>' + value + '</td></tr>'; } var updateBadge = p.update_available ? ' <span class="label label-warning">Update ' + (p.update_version || '') + '</span>' : ''; var autoUpdateBadge = p.auto_update ? ' <span class="label label-info">Auto-update ON</span>' : ''; var networkBadge = p.network_active ? ' <span class="label label-primary">Network</span>' : ''; var html = '<div style="padding:10px;">'; html += '<h4 style="margin-top:0;">' + (p.title || p.name || slug) + ' ' + statusLabel + updateBadge + autoUpdateBadge + networkBadge + '</h4>'; html += '<table class="table table-condensed" style="margin-top:15px;">'; html += row('Slug', p.slug); html += row('Version', p.version); html += row('Author', p.author); html += row('Status', p.status); html += row('Path', p.path ? '<code>' + p.path + '</code>' : ''); html += '</table>'; if (p.description) { html += '<div style="margin-top:15px;"><strong style="color:#7f8c8d;">Description</strong>' + '<p style="margin-top:5px;color:#34495e;">' + p.description + '</p></div>'; } html += '<div class="wpm-modal-actions" style="margin-top:20px;text-align:right;">'; html += '<button class="btn btn-xs btn-' + (isActive ? 'warning' : 'success') + '" onclick="wpmTogglePlugin(\'' + path + '\',\'' + slug + '\',' + !isActive + ');$(\'#wpm-modal-plugin-details\').modal(\'hide\');">' + '<i class="fa fa-' + (isActive ? 'power-off' : 'play') + '"></i> ' + (isActive ? 'Deactivate' : 'Activate') + '</button> '; html += '<button class="btn btn-xs btn-default" data-dismiss="modal">Close</button>'; html += '</div>'; html += '</div>'; $('#wpm-plugin-details-body').html(html); }, function(err) { $('#wpm-plugin-details-body').html('<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> ' + (err.message || 'Error loading plugin details') + '</div>'); }); } // ============================================================ // CACHE MANAGEMENT // ============================================================ function wpmOpenCache(path) { $('#wpm-modal-cache').modal('show'); wpmLoadCacheStatus(path); } function wpmLoadCacheStatus(path) { $('#wpm-cache-status').html('<p class="text-muted"><i class="fa fa-circle-o-notch fa-spin"></i> Loading cache status...</p>'); // Check if cache is enabled wpmAjax('get_cache_status', { path: path }, function(res) { if (res.success && res.status) { const status = res.status; let html = ''; if (status.object_cache) { html += ` <div class="panel panel-default"> <div class="panel-heading"> <h4 class="panel-title"> <i class="fa fa-database"></i> Object Cache (${status.object_cache_type}) </h4> </div> <div class="panel-body"> <div class="row"> <div class="col-md-6"> <small class="text-muted">Status: <strong>Enabled</strong></small> </div> <div class="col-md-6 text-right"> <button class="btn btn-warning btn-sm" onclick="wpmFlushCache()"> <i class="fa fa-eraser"></i> Flush Cache </button> </div> </div> </div> </div> `; } if (status.page_cache) { html += ` <div class="panel panel-default"> <div class="panel-heading"> <h4 class="panel-title"> <i class="fa fa-file-text-o"></i> Page Cache (${status.page_cache_plugin}) </h4> </div> <div class="panel-body"> <div class="row"> <div class="col-md-6"> <small class="text-muted">Status: <strong>Enabled</strong></small> </div> <div class="col-md-6 text-right"> <button class="btn btn-warning btn-sm" onclick="wpmFlushCache()"> <i class="fa fa-eraser"></i> Flush Cache </button> </div> </div> </div> </div> `; } if (html === '') { html = '<div class="alert alert-info"><i class="fa fa-info-circle"></i> No cache enabled</div>'; } $('#wpm-cache-status').html(html); } else { $('#wpm-cache-status').html('<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> Error loading cache status: ' + (res.message || 'Unknown error') + '</div>'); } }); } function wpmFlushCache() { wpmNotify.info('Flushing cache...'); wpmAjax('flush_cache', { path: wpmCurrentPath }, function(res) { if (res.success) { wpmNotify.success('Cache flushed successfully'); wpmLoadCacheStatus(wpmCurrentPath); } else { wpmNotify.error('Failed to flush cache: ' + (res.message || 'Unknown error')); } }); } // ============================================================ // DATABASE TOOLS // ============================================================ function wpmOpenDbTools(path) { wpmCurrentPath = path; $('#wpm-modal-dbtools').modal('show'); wpmLoadDbInfo(path); } function wpmLoadDbInfo(path) { $('#wpm-db-info').html('<p class="text-muted"><i class="fa fa-circle-o-notch fa-spin"></i> Loading database info...</p>'); // Get database info wpmAjax('get_db_info', { path: path }, function(res) { if (res.result === 'success' && res) { const info = res; let html = ` <div class="panel panel-default" style="margin-bottom:0;"> <div class="panel-heading" style="padding: 8px 15px;"> <h4 class="panel-title" style="font-size: 13px;"><i class="fa fa-database"></i> Database Information</h4> </div> <div class="panel-body" style="padding: 12px 15px;"> <div class="row"> <div class="col-md-6" style="margin-bottom:8px;"> <small class="text-muted">Database Name:</small> <p style="margin-top:2px; margin-bottom:0; font-size:14px; color:#2d3748;"><strong>${info.db_name || 'Unknown'}</strong></p> </div> <div class="col-md-6" style="margin-bottom:8px;"> <small class="text-muted">Tables:</small> <p style="margin-top:2px; margin-bottom:0; font-size:14px; color:#2d3748;"><strong>${info.table_count || 0}</strong></p> </div> <div class="col-md-6" style="margin-bottom:8px;"> <small class="text-muted">Total Size:</small> <p style="margin-top:2px; margin-bottom:0; font-size:14px; color:#2d3748;"><strong>${info.total_size || 'Unknown'}</strong></p> </div> <div class="col-md-6" style="margin-bottom:8px;"> <small class="text-muted">Overhead:</small> <p style="margin-top:2px; margin-bottom:0; font-size:14px; color:#2d3748;"><strong>${info.total_overhead || '0 B'}</strong></p> </div> </div> </div> </div> `; $('#wpm-db-info').html(html); } else { $('#wpm-db-info').html('<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> Error loading database info: ' + (res.message || 'Unknown error') + '</div>'); } }); } function wpmOptimizeDb() { wpmNotify.info('Optimizing database...'); wpmAjax('optimize_db', { path: wpmCurrentPath }, function(res) { if (res.success) { wpmNotify.success('Database optimized successfully'); } else { wpmNotify.error('Failed to optimize database: ' + (res.message || 'Unknown error')); } }); } function wpmRepairDb() { wpmNotify.info('Repairing database...'); wpmAjax('repair_db', { path: wpmCurrentPath }, function(res) { if (res.success) { wpmNotify.success('Database repaired successfully'); } else { wpmNotify.error('Failed to repair database: ' + (res.message || 'Unknown error')); } }); } function wpmDoSearchReplace() { const from = $('#wpm-sr-from').val(); const to = $('#wpm-sr-to').val(); if (!from || !to) { wpmNotify.error('Please enter both find and replace values'); return; } wpmNotify.info('Running search and replace...'); wpmAjax('search_replace_db', { path: wpmCurrentPath, search: from, replace: to }, function(res) { if (res.success) { wpmNotify.success('Search and replace completed successfully'); } else { wpmNotify.error('Failed to run search and replace: ' + (res.message || 'Unknown error')); } }); } // ============================================================ // PASSWORD PROTECTION // ============================================================ function wpmOpenProtection(path) { wpmCurrentPath = path; $('#wpm-modal-protection').modal('show'); wpmLoadProtection(path); } function wpmLoadProtection(path) { $('#wpm-users-list').html('<p class="text-muted"><i class="fa fa-circle-o-notch fa-spin"></i> Loading users...</p>'); // Get password protection status wpmAjax('get_password_protection', { path: path }, function(res) { if (res.success && res.status) { const status = res.status; const enabled = status.enabled || false; // Update checkbox $('#wpm-protect-enabled').prop('checked', enabled); // Show/hide credentials section if (enabled) { $('#wpm-protect-creds').show(); $('#wpm-protect-user').val(status.user || ''); $('#wpm-protect-pass').val(''); } else { $('#wpm-protect-creds').hide(); } // List WordPress users wpmAjax('list_users', { path: path }, function(res) { if (res.success && res.users) { let html = ''; res.users.forEach(function(user) { html += ` <div style="margin-bottom:8px;padding:8px;border-bottom:1px solid #f0f0f0;"> <strong>${user.login}</strong> (${user.email || 'No email'}) </div> `; }); html += `<small class="text-muted">Total users: ${res.users.length}</small>`; $('#wpm-users-list').html(html); } else { $('#wpm-users-list').html('<p class="text-muted">No users found</p>'); } }); } else { wpmNotify.error('Failed to load password protection status: ' + (res.message || 'Unknown error')); } }); } function wpmSaveProtection() { const enabled = $('#wpm-protect-enabled').prop('checked'); const user = $('#wpm-protect-user').val(); const pass = $('#wpm-protect-pass').val(); wpmNotify.info('Saving password protection settings...'); wpmAjax('toggle_password_protection', { path: wpmCurrentPath, enabled: enabled ? '1' : '0', auth_user: user, auth_pass: pass }, function(res) { if (res.success) { wpmNotify.success('Password protection settings saved successfully'); wpmLoadProtection(wpmCurrentPath); } else { wpmNotify.error('Failed to save password protection settings: ' + (res.message || 'Unknown error')); } }); } // ============================================================ // FILES MANAGER // ============================================================ function wpmOpenFiles(path) { wpmCurrentPath = path; $('#wpm-modal-files').modal('show'); wpmLoadFiles(path); } function wpmLoadFiles(path) { // Load configuration wpmAjax('get_config', { path: path }, function(res) { if (res.content !== undefined) { $('#wpm-config-editor').val(res.content); } }); // Load .htaccess wpmAjax('get_htaccess', { path: path }, function(res) { if (res.content !== undefined) { $('#wpm-htaccess-editor').val(res.content); } }); // Load error log wpmAjax('get_error_log', { path: path }, function(res) { if (res.content !== undefined && res.content !== '') { $('#wpm-error-log').text(res.content); } else { $('#wpm-error-log').html('<div class="text-center text-muted">No errors in log</div>'); } }); } function wpmSaveConfig() { const content = $('#wpm-config-editor').val(); wpmNotify.info('Saving wp-config.php...'); wpmAjax('save_config', { path: wpmCurrentPath, content: content }, function(res) { if (res.success) { wpmNotify.success('wp-config.php saved successfully'); } else { wpmNotify.error('Failed to save wp-config.php: ' + (res.message || 'Unknown error')); } }); } function wpmSaveHtaccess() { const content = $('#wpm-htaccess-editor').val(); wpmNotify.info('Saving .htaccess...'); wpmAjax('save_htaccess', { path: wpmCurrentPath, content: content }, function(res) { if (res.success) { wpmNotify.success('.htaccess saved successfully'); } else { wpmNotify.error('Failed to save .htaccess: ' + (res.message || 'Unknown error')); } }); } function wpmClearErrorLog() { wpmNotify.info('Clearing error log...'); wpmAjax('clear_error_log', { path: wpmCurrentPath }, function(res) { if (res.success) { wpmNotify.success('Error log cleared successfully'); $('#wpm-error-log').html('<div class="text-center text-muted">Log cleared</div>'); } else { wpmNotify.error('Failed to clear error log: ' + (res.message || 'Unknown error')); } }); } // ============================================================ // VULNERABILITIES // ============================================================ function wpmOpenVulnerabilities(path) { wpmCurrentPath = path; $('#wpm-modal-vulnerabilities').modal('show'); wpmLoadVulnerabilities(path); } function wpmLoadVulnerabilities(path) { $('#wpm-vulnerabilities-body').html('<div style="text-align:center;padding:20px;"><i class="fa fa-circle-o-notch fa-spin" style="font-size:24px;color:#cbd5e0;"></i><p style="margin-top:10px;color:#718096;">Scanning for vulnerabilities...</p></div>'); wpmAjax('scan_vulnerabilities', { path: path }, function(res) { if (res.success && res.vulnerabilities) { displayVulnerabilities(res.vulnerabilities); } else { $('#wpm-vulnerabilities-body').html('<div class="alert alert-info"><i class="fa fa-info-circle"></i> No vulnerabilities found</div>'); } }); } function displayVulnerabilities(vulnerabilities) { if (vulnerabilities.length === 0) { $('#wpm-vulnerabilities-body').html('<div class="alert alert-success"><i class="fa fa-check-circle"></i> No vulnerabilities found</div>'); return; } let html = ''; vulnerabilities.forEach(function(vuln) { const severityClass = 'wpm-vuln-sev-' + vuln.severity; html += ` <div class="${severityClass}"> <div style="display:flex;justify-content:space-between;padding:10px;border-bottom:1px solid #e8e8e8;"> <strong>${vuln.name}</strong> <span class="wpm-vuln-count wpm-vuln-${vuln.severity}">${vuln.severity.toUpperCase()}</span> </div> <div style="padding:10px;"> <small style="color:#718096;">${vuln.description}</small> <br> <small style="color:#718096;">Package: ${vuln.package}</small> <br> <small style="color:#718096;">Affected Version: ${vuln.version}</small> ${vuln.fix_version ? '<br><small style="color:#1ab394;">Fixed in: ' + vuln.fix_version + '</small>' : ''} </div> </div> `; }); $('#wpm-vulnerabilities-body').html(html); } // ============================================================ // DEV/SEO // ============================================================ function wpmOpenDevSeo(path) { wpmCurrentPath = path; $('#wpm-modal-devseo').modal('show'); wpmLoadDevSeo(path); } function wpmLoadDevSeo(path) { wpmAjax('get_devseo_status', { path: path }, function(res) { if (res.success && res.status) { const status = res.status; // Unbind previous change events to prevent multiple calls $('#wpm-devseo-cron').off('change'); $('#wpm-devseo-debug').off('change'); $('#wpm-devseo-seo').off('change'); // Set checkboxes based on status $('#wpm-devseo-cron').prop('checked', status.cron || false); $('#wpm-devseo-debug').prop('checked', status.debug || false); $('#wpm-devseo-seo').prop('checked', status.seo !== false); // Bind new change events to trigger AJAX updates immediately $('#wpm-devseo-cron').on('change', function() { wpmToggleSystemCron(path, $(this).is(':checked')); }); $('#wpm-devseo-debug').on('change', function() { wpmToggleDebugMode(path, $(this).is(':checked')); }); $('#wpm-devseo-seo').on('change', function() { wpmToggleSearchEngine(path, $(this).is(':checked')); }); } else { noti_bubble(res.message || 'Error loading Dev/SEO settings', 'Error', 'error', true, false, '3000', true); } }); } // ============================================================ // CLONE // ============================================================ const wpmNotify = { success: function(msg) { noti_bubble(msg, 'Success', 'success', true, false, '3000', true); }, error: function(msg) { noti_bubble(msg, 'Error', 'error', true, false, '3000', true); }, info: function(msg) { noti_bubble(msg, 'Info', 'info', true, false, '3000', true); } }; function wpmOpenPlugins(path) { wpmCurrentPath = path; $('#wpm-modal-plugins').modal('show'); $('.wpm-modal-tabs a[href="#wpm-tab-plugins"]').tab('show'); wpmLoadPlugins(path); wpmLoadThemes(path); } function wpmScanInstallations() { var btn = $('#wpm-btn-scan-main'); var origHtml = btn.html(); btn.html('<i class="fa fa-circle-o-notch fa-spin"></i> Scanning...').prop('disabled', true); noti_bubble('Scanning for existing WordPress installations...', 'Info', 'info', true, false, '3000', true); wpmAjax('scan_installations', {}, function(res) { btn.html(origHtml).prop('disabled', false); if (res.result === 'success') { if (res.found > 0) { noti_bubble('Found ' + res.found + ' new WordPress installations!', 'Success', 'success', true, false, '3000', true); setTimeout(function() { location.reload(); }, 1500); } else { noti_bubble('No new installations found.', 'Info', 'info', true, false, '3000', true); } } else { noti_bubble(res.message || 'Error during scan.', 'Error', 'error', true, false, '3000', true); } }, function(err) { btn.html(origHtml).prop('disabled', false); noti_bubble('Error communicating with server.', 'Error', 'error', true, false, '3000', true); }); }
修改文件时间
将文件时间修改为当前时间的前一年
删除文件